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
17using namespace llvm;
18using namespace PatternMatch;
19
20static void
21extractOperandsFromModule(Oracle &O, ReducerWorkItem &WorkItem,
22 function_ref<Value *(Use &)> ReduceValue) {
23 Module &Program = WorkItem.getModule();
24
25 for (auto &F : Program.functions()) {
26 for (auto &I : instructions(F: &F)) {
27 if (PHINode *Phi = dyn_cast<PHINode>(Val: &I)) {
28 for (auto &Op : Phi->incoming_values()) {
29 if (Value *Reduced = ReduceValue(Op)) {
30 if (!O.shouldKeep())
31 Phi->setIncomingValueForBlock(BB: Phi->getIncomingBlock(U: Op), V: Reduced);
32 }
33 }
34
35 continue;
36 }
37
38 for (auto &Op : I.operands()) {
39 if (Value *Reduced = ReduceValue(Op)) {
40 if (!O.shouldKeep())
41 Op.set(Reduced);
42 }
43 }
44 }
45 }
46}
47
48static bool isOne(Use &Op) {
49 auto *C = dyn_cast<Constant>(Val&: Op);
50 return C && C->isOneValue();
51}
52
53static bool isZero(Use &Op) {
54 auto *C = dyn_cast<Constant>(Val&: Op);
55 return C && C->isNullValue();
56}
57
58static bool isZeroOrOneFP(Value *Op) {
59 const APFloat *C;
60 return match(V: Op, P: m_APFloat(Res&: C)) && (C->isPosZero() || C->isOne());
61}
62
63static bool shouldReduceOperand(Use &Op) {
64 Type *Ty = Op->getType();
65 if (Ty->isLabelTy() || Ty->isMetadataTy())
66 return false;
67 // TODO: be more precise about which GEP operands we can reduce (e.g. array
68 // indexes)
69 if (isa<GEPOperator>(Val: Op.getUser()))
70 return false;
71 if (auto *CB = dyn_cast<CallBase>(Val: Op.getUser())) {
72 if (&CB->getCalledOperandUse() == &Op)
73 return false;
74 }
75 // lifetime intrinsic argument must be an alloca.
76 if (isa<LifetimeIntrinsic>(Val: Op.getUser()))
77 return false;
78 return true;
79}
80
81static bool switchCaseExists(Use &Op, ConstantInt *CI) {
82 SwitchInst *SI = dyn_cast<SwitchInst>(Val: Op.getUser());
83 if (!SI)
84 return false;
85 return SI->findCaseValue(C: CI) != SI->case_default();
86}
87
88void llvm::reduceOperandsOneDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) {
89 auto ReduceValue = [](Use &Op) -> Value * {
90 if (!shouldReduceOperand(Op))
91 return nullptr;
92
93 Type *Ty = Op->getType();
94 if (auto *IntTy = dyn_cast<IntegerType>(Val: Ty)) {
95 // Don't duplicate an existing switch case.
96 if (switchCaseExists(Op, CI: ConstantInt::get(Ty: IntTy, V: 1)))
97 return nullptr;
98 // Don't replace existing ones and zeroes.
99 return (isOne(Op) || isZero(Op)) ? nullptr : ConstantInt::get(Ty: IntTy, V: 1);
100 }
101
102 if (Ty->isFloatingPointTy())
103 return isZeroOrOneFP(Op) ? nullptr : ConstantFP::get(Ty, V: 1.0);
104
105 if (VectorType *VT = dyn_cast<VectorType>(Val: Ty)) {
106 if (isOne(Op) || isZero(Op) || isZeroOrOneFP(Op))
107 return nullptr;
108
109 Type *ElementType = VT->getElementType();
110 Constant *C;
111 if (ElementType->isFloatingPointTy()) {
112 C = ConstantFP::get(Ty: ElementType, V: 1.0);
113 } else if (IntegerType *IntTy = dyn_cast<IntegerType>(Val: ElementType)) {
114 C = ConstantInt::get(Ty: IntTy, V: 1);
115 } else {
116 return nullptr;
117 }
118 return ConstantVector::getSplat(EC: VT->getElementCount(), Elt: C);
119 }
120
121 return nullptr;
122 };
123 extractOperandsFromModule(O, WorkItem, ReduceValue);
124}
125
126void llvm::reduceOperandsZeroDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) {
127 auto ReduceValue = [](Use &Op) -> Value * {
128 if (!shouldReduceOperand(Op))
129 return nullptr;
130
131 // Avoid introducing 0-sized allocations.
132 if (isa<AllocaInst>(Val: Op.getUser()))
133 return nullptr;
134
135 // Don't duplicate an existing switch case.
136 if (auto *IntTy = dyn_cast<IntegerType>(Val: Op->getType()))
137 if (switchCaseExists(Op, CI: ConstantInt::get(Ty: IntTy, V: 0)))
138 return nullptr;
139
140 if (auto *TET = dyn_cast<TargetExtType>(Val: Op->getType())) {
141 if (isa<ConstantTargetNone, PoisonValue>(Val: Op))
142 return nullptr;
143 if (TET->hasProperty(Prop: TargetExtType::HasZeroInit))
144 return ConstantTargetNone::get(T: TET);
145 return nullptr;
146 }
147
148 // Don't replace existing zeroes.
149 return isZero(Op) ? nullptr : Constant::getNullValue(Ty: Op->getType());
150 };
151 extractOperandsFromModule(O, WorkItem, ReduceValue);
152}
153
154void llvm::reduceOperandsNaNDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) {
155 auto ReduceValue = [](Use &Op) -> Value * {
156 Type *Ty = Op->getType();
157 if (!Ty->isFPOrFPVectorTy())
158 return nullptr;
159
160 // Prefer 0.0 or 1.0 over NaN.
161 //
162 // TODO: Preferring NaN may make more sense because FP operations are more
163 // universally foldable.
164 if (match(V: Op.get(), P: m_NaN()) || isZeroOrOneFP(Op: Op.get()))
165 return nullptr;
166
167 if (VectorType *VT = dyn_cast<VectorType>(Val: Ty)) {
168 return ConstantVector::getSplat(EC: VT->getElementCount(),
169 Elt: ConstantFP::getQNaN(Ty: VT->getElementType()));
170 }
171
172 return ConstantFP::getQNaN(Ty);
173 };
174 extractOperandsFromModule(O, WorkItem, ReduceValue);
175}
176
177void llvm::reduceOperandsPoisonDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) {
178 auto ReduceValue = [](Use &Op) -> Value * {
179 Type *Ty = Op->getType();
180 if (auto *TET = dyn_cast<TargetExtType>(Val: Ty)) {
181 if (isa<ConstantTargetNone, PoisonValue>(Val: Op))
182 return nullptr;
183 return PoisonValue::get(T: TET);
184 }
185
186 return nullptr;
187 };
188
189 extractOperandsFromModule(O, WorkItem, ReduceValue);
190}
191