File: ReduceOperands.cpp

package info (click to toggle)
llvm-toolchain-15 1%3A15.0.6-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,554,644 kB
  • sloc: cpp: 5,922,452; ansic: 1,012,136; asm: 674,362; python: 191,568; objc: 73,855; f90: 42,327; lisp: 31,913; pascal: 11,973; javascript: 10,144; sh: 9,421; perl: 7,447; ml: 5,527; awk: 3,523; makefile: 2,520; xml: 885; cs: 573; fortran: 567
file content (137 lines) | stat: -rw-r--r-- 4,268 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "ReduceOperands.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"

using namespace llvm;
using namespace PatternMatch;

static void
extractOperandsFromModule(Oracle &O, Module &Program,
                          function_ref<Value *(Use &)> ReduceValue) {
  for (auto &F : Program.functions()) {
    for (auto &I : instructions(&F)) {
      for (auto &Op : I.operands()) {
        if (!O.shouldKeep()) {
          if (Value *Reduced = ReduceValue(Op))
            Op.set(Reduced);
        }
      }
    }
  }
}

static bool isOne(Use &Op) {
  auto *C = dyn_cast<Constant>(Op);
  return C && C->isOneValue();
}

static bool isZero(Use &Op) {
  auto *C = dyn_cast<Constant>(Op);
  return C && C->isNullValue();
}

static bool isZeroOrOneFP(Value *Op) {
  const APFloat *C;
  return match(Op, m_APFloat(C)) &&
         ((C->isZero() && !C->isNegative()) || C->isExactlyValue(1.0));
}

static bool shouldReduceOperand(Use &Op) {
  Type *Ty = Op->getType();
  if (Ty->isLabelTy() || Ty->isMetadataTy())
    return false;
  // TODO: be more precise about which GEP operands we can reduce (e.g. array
  // indexes)
  if (isa<GEPOperator>(Op.getUser()))
    return false;
  if (auto *CB = dyn_cast<CallBase>(Op.getUser())) {
    if (&CB->getCalledOperandUse() == &Op)
      return false;
  }
  return true;
}

void llvm::reduceOperandsOneDeltaPass(TestRunner &Test) {
  errs() << "*** Reducing Operands to one...\n";
  auto ReduceValue = [](Use &Op) -> Value * {
    if (!shouldReduceOperand(Op))
      return nullptr;

    Type *Ty = Op->getType();
    if (auto *IntTy = dyn_cast<IntegerType>(Ty)) {
      // Don't replace existing ones and zeroes.
      return (isOne(Op) || isZero(Op)) ? nullptr : ConstantInt::get(IntTy, 1);
    }

    if (Ty->isFloatingPointTy())
      return isZeroOrOneFP(Op) ? nullptr : ConstantFP::get(Ty, 1.0);

    if (VectorType *VT = dyn_cast<VectorType>(Ty)) {
      if (isOne(Op) || isZero(Op) || isZeroOrOneFP(Op))
        return nullptr;

      if (auto *IntTy = dyn_cast<IntegerType>(VT->getElementType()))
        return ConstantVector::getSplat(VT->getElementCount(),
                                        ConstantInt::get(IntTy, 1));

      return ConstantVector::getSplat(
          VT->getElementCount(), ConstantFP::get(VT->getElementType(), 1.0));
    }

    return nullptr;
  };
  runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
    extractOperandsFromModule(O, Program, ReduceValue);
  });
}

void llvm::reduceOperandsZeroDeltaPass(TestRunner &Test) {
  errs() << "*** Reducing Operands to zero...\n";
  auto ReduceValue = [](Use &Op) -> Value * {
    if (!shouldReduceOperand(Op))
      return nullptr;
    // Don't replace existing zeroes.
    return isZero(Op) ? nullptr : Constant::getNullValue(Op->getType());
  };
  runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
    extractOperandsFromModule(O, Program, ReduceValue);
  });
}

void llvm::reduceOperandsNaNDeltaPass(TestRunner &Test) {
  errs() << "*** Reducing Operands to NaN...\n";
  auto ReduceValue = [](Use &Op) -> Value * {
    Type *Ty = Op->getType();
    if (!Ty->isFPOrFPVectorTy())
      return nullptr;

    // Prefer 0.0 or 1.0 over NaN.
    //
    // TODO: Preferring NaN may make more sense because FP operations are more
    // universally foldable.
    if (match(Op.get(), m_NaN()) || isZeroOrOneFP(Op.get()))
      return nullptr;

    if (VectorType *VT = dyn_cast<VectorType>(Ty)) {
      return ConstantVector::getSplat(VT->getElementCount(),
                                      ConstantFP::getQNaN(VT->getElementType()));
    }

    return ConstantFP::getQNaN(Ty);
  };
  runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
    extractOperandsFromModule(O, Program, ReduceValue);
  });
}