1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "ReduceOperands.h"
10 #include "llvm/IR/Constants.h"
11 #include "llvm/IR/InstIterator.h"
12 #include "llvm/IR/InstrTypes.h"
13 #include "llvm/IR/Operator.h"
14 #include "llvm/IR/PatternMatch.h"
15 #include "llvm/IR/Type.h"
16 
17 using namespace llvm;
18 using namespace PatternMatch;
19 
20 static void
21 extractOperandsFromModule(Oracle &O, Module &Program,
22                           function_ref<Value *(Use &)> ReduceValue) {
23   for (auto &F : Program.functions()) {
24     for (auto &I : instructions(&F)) {
25       for (auto &Op : I.operands()) {
26         Value *Reduced = ReduceValue(Op);
27         if (Reduced && !O.shouldKeep())
28           Op.set(Reduced);
29       }
30     }
31   }
32 }
33 
34 static bool isOne(Use &Op) {
35   auto *C = dyn_cast<Constant>(Op);
36   return C && C->isOneValue();
37 }
38 
39 static bool isZero(Use &Op) {
40   auto *C = dyn_cast<Constant>(Op);
41   return C && C->isNullValue();
42 }
43 
44 static bool isZeroOrOneFP(Value *Op) {
45   const APFloat *C;
46   return match(Op, m_APFloat(C)) &&
47          ((C->isZero() && !C->isNegative()) || C->isExactlyValue(1.0));
48 }
49 
50 static bool shouldReduceOperand(Use &Op) {
51   Type *Ty = Op->getType();
52   if (Ty->isLabelTy() || Ty->isMetadataTy())
53     return false;
54   // TODO: be more precise about which GEP operands we can reduce (e.g. array
55   // indexes)
56   if (isa<GEPOperator>(Op.getUser()))
57     return false;
58   if (auto *CB = dyn_cast<CallBase>(Op.getUser())) {
59     if (&CB->getCalledOperandUse() == &Op)
60       return false;
61   }
62   return true;
63 }
64 
65 void llvm::reduceOperandsOneDeltaPass(TestRunner &Test) {
66   errs() << "*** Reducing Operands to one...\n";
67   auto ReduceValue = [](Use &Op) -> Value * {
68     if (!shouldReduceOperand(Op))
69       return nullptr;
70 
71     Type *Ty = Op->getType();
72     if (auto *IntTy = dyn_cast<IntegerType>(Ty)) {
73       // Don't replace existing ones and zeroes.
74       return (isOne(Op) || isZero(Op)) ? nullptr : ConstantInt::get(IntTy, 1);
75     }
76 
77     if (Ty->isFloatingPointTy())
78       return isZeroOrOneFP(Op) ? nullptr : ConstantFP::get(Ty, 1.0);
79 
80     if (VectorType *VT = dyn_cast<VectorType>(Ty)) {
81       if (isZeroOrOneFP(Op))
82         return nullptr;
83 
84       return ConstantVector::getSplat(
85           VT->getElementCount(), ConstantFP::get(VT->getElementType(), 1.0));
86     }
87 
88     return nullptr;
89   };
90   runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
91     extractOperandsFromModule(O, Program, ReduceValue);
92   });
93 }
94 
95 void llvm::reduceOperandsZeroDeltaPass(TestRunner &Test) {
96   errs() << "*** Reducing Operands to zero...\n";
97   auto ReduceValue = [](Use &Op) -> Value * {
98     if (!shouldReduceOperand(Op))
99       return nullptr;
100     // Don't replace existing zeroes.
101     return isZero(Op) ? nullptr : Constant::getNullValue(Op->getType());
102   };
103   runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
104     extractOperandsFromModule(O, Program, ReduceValue);
105   });
106 }
107