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::reduceOperandsUndefDeltaPass(TestRunner &Test) {
66   errs() << "*** Reducing Operands to undef...\n";
67   auto ReduceValue = [](Use &Op) -> Value * {
68     if (!shouldReduceOperand(Op))
69       return nullptr;
70     // Don't replace existing ConstantData Uses.
71     return isa<ConstantData>(*Op) ? nullptr : UndefValue::get(Op->getType());
72   };
73   runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
74     extractOperandsFromModule(O, Program, ReduceValue);
75   });
76 }
77 
78 void llvm::reduceOperandsOneDeltaPass(TestRunner &Test) {
79   errs() << "*** Reducing Operands to one...\n";
80   auto ReduceValue = [](Use &Op) -> Value * {
81     if (!shouldReduceOperand(Op))
82       return nullptr;
83 
84     Type *Ty = Op->getType();
85     if (auto *IntTy = dyn_cast<IntegerType>(Ty)) {
86       // Don't replace existing ones and zeroes.
87       return (isOne(Op) || isZero(Op)) ? nullptr : ConstantInt::get(IntTy, 1);
88     }
89 
90     if (Ty->isFloatingPointTy())
91       return isZeroOrOneFP(Op) ? nullptr : ConstantFP::get(Ty, 1.0);
92 
93     if (VectorType *VT = dyn_cast<VectorType>(Ty)) {
94       if (isZeroOrOneFP(Op))
95         return nullptr;
96 
97       return ConstantVector::getSplat(
98           VT->getElementCount(), ConstantFP::get(VT->getElementType(), 1.0));
99     }
100 
101     return nullptr;
102   };
103   runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
104     extractOperandsFromModule(O, Program, ReduceValue);
105   });
106 }
107 
108 void llvm::reduceOperandsZeroDeltaPass(TestRunner &Test) {
109   errs() << "*** Reducing Operands to zero...\n";
110   auto ReduceValue = [](Use &Op) -> Value * {
111     if (!shouldReduceOperand(Op))
112       return nullptr;
113     // Don't replace existing zeroes.
114     return isZero(Op) ? nullptr : Constant::getNullValue(Op->getType());
115   };
116   runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
117     extractOperandsFromModule(O, Program, ReduceValue);
118   });
119 }
120