1 /*========================== begin_copyright_notice ============================
2
3 Copyright (C) 2017-2021 Intel Corporation
4
5 SPDX-License-Identifier: MIT
6
7 ============================= end_copyright_notice ===========================*/
8
9 #include <vector>
10
11 #include "Compiler/Optimizer/OpenCLPasses/BreakConstantExpr/BreakConstantExpr.hpp"
12 #include "Compiler/IGCPassSupport.h"
13 #include "Compiler/CodeGenPublic.h"
14 #include "common/LLVMWarningsPush.hpp"
15 #include <llvm/IR/Function.h>
16 #include <llvm/IR/Instructions.h>
17 #include <llvm/IR/Constants.h>
18 #include <llvm/IR/IntrinsicInst.h>
19 #include <llvm/IR/Metadata.h>
20 #include <llvm/IR/InstIterator.h>
21 #include "common/LLVMWarningsPop.hpp"
22 #include "Probe/Assertion.h"
23
24 using namespace llvm;
25 using namespace IGC;
26
27 // Register pass to igc-opt
28 #define PASS_FLAG "igc-break-const-expr"
29 #define PASS_DESCRIPTION "Break constant expressions into instruction sequences"
30 #define PASS_CFG_ONLY false
31 #define PASS_ANALYSIS false
32 IGC_INITIALIZE_PASS_BEGIN(BreakConstantExpr, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)
33 IGC_INITIALIZE_PASS_END(BreakConstantExpr, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)
34
35 char BreakConstantExpr::ID = 0;
36
BreakConstantExpr()37 BreakConstantExpr::BreakConstantExpr() : FunctionPass(ID)
38 {
39 initializeBreakConstantExprPass(*PassRegistry::getPassRegistry());
40 }
41
runOnFunction(Function & F)42 bool BreakConstantExpr::runOnFunction(Function& F)
43 {
44 bool changed = false;
45 // Go over all the instructions in the function
46 for (inst_iterator it = inst_begin(F), e = inst_end(F); it != e; ++it)
47 {
48 Instruction* pInst = &*it;
49 if (DbgDeclareInst * DbgDclInst = dyn_cast<DbgDeclareInst>(pInst)) {
50 // For DbgDeclareInst, the operand is a metadata that might
51 // contain a constant expression.
52 Value* op = DbgDclInst->getAddress();
53 // If the debug adress is a constant expression, recursively break it up.
54 if (ConstantExpr * expr = dyn_cast_or_null<ConstantExpr>(op))
55 {
56 breakExpressions(expr, 0, pInst);
57 changed = true;
58 }
59 continue;
60 }
61 #if 0
62 //Disable handling of llvm.dbg.value instruction as it needs
63 //proper handling of metadata.
64 if (DbgValueInst * DbgValInst = dyn_cast<DbgValueInst>(pInst)) {
65 // For DbgValueInst, the operand is a metadata that might
66 // contain a constant expression.
67 Value* op = DbgValInst->getValue();
68 // If the debug value operand is a constant expression, recursively break it up.
69 if (ConstantExpr * expr = dyn_cast_or_null<ConstantExpr>(op))
70 {
71 breakExpressions(expr, 0, pInst);
72 changed = true;
73 }
74 continue;
75 }
76 #endif
77
78 // And all the operands of each instruction
79 int numOperands = it->getNumOperands();
80 for (int i = 0; i < numOperands; ++i)
81 {
82 Value* op = it->getOperand(i);
83
84 // If the operand is a constant expression, recursively break it up.
85 if (ConstantExpr * expr = dyn_cast<ConstantExpr>(op))
86 {
87 breakExpressions(expr, i, pInst);
88 changed = true;
89 }
90 else if (ConstantVector * cvec = dyn_cast<ConstantVector>(op))
91 {
92 changed |= breakExpressionsInVector(cvec, i, pInst);
93 }
94 else if (ConstantStruct *CS = dyn_cast<ConstantStruct>(op))
95 {
96 breakConstantStruct(CS, i, pInst);
97 changed = true;
98 }
99 }
100 }
101 return changed;
102 }
103
replaceConstantWith(llvm::Constant * exprOrVec,llvm::Instruction * newInst,int operandIndex,llvm::Instruction * user)104 void BreakConstantExpr::replaceConstantWith(llvm::Constant* exprOrVec, llvm::Instruction* newInst, int operandIndex, llvm::Instruction* user)
105 {
106 if (PHINode* phi = dyn_cast<PHINode>(user))
107 {
108 newInst->insertBefore(phi->getIncomingBlock(operandIndex)->getTerminator());
109 user->setOperand(operandIndex, newInst);
110 }
111 else if (dyn_cast<DbgInfoIntrinsic>(user))
112 {
113 newInst->insertBefore(user);
114 // For debug info intrinsic, the operand is a metadata that
115 // contains the constant expression.
116 if (auto* DDI = dyn_cast<DbgDeclareInst>(user))
117 {
118 MetadataAsValue* MAV = MetadataAsValue::get(user->getContext(), ValueAsMetadata::get(newInst));
119 user->setOperand(operandIndex, MAV);
120 }
121 else
122 {
123 user->setOperand(operandIndex, newInst);
124 }
125 }
126 else
127 {
128 newInst->insertBefore(user);
129 user->replaceUsesOfWith(exprOrVec, newInst);
130 }
131 if (exprOrVec->use_empty())
132 {
133 exprOrVec->destroyConstant();
134 }
135 }
136
breakExpressions(llvm::ConstantExpr * expr,int operandIndex,llvm::Instruction * user)137 void BreakConstantExpr::breakExpressions(llvm::ConstantExpr* expr, int operandIndex, llvm::Instruction* user)
138 {
139 // Create a new instruction, and insert it at the appropriate point.
140 Instruction* newInst = expr->getAsInstruction();
141 newInst->setDebugLoc(user->getDebugLoc());
142
143 replaceConstantWith(expr, newInst, operandIndex, user);
144
145 // Thew new instruction may itself reference constant expressions.
146 // So, recursively process all of its arguments.
147 int numOperands = newInst->getNumOperands();
148 for (int i = 0; i < numOperands; ++i)
149 {
150 Value* op = newInst->getOperand(i);
151 ConstantExpr* innerExpr = dyn_cast<ConstantExpr>(op);
152 if (innerExpr)
153 {
154 breakExpressions(innerExpr, i, newInst);
155 }
156 else if (ConstantVector * cvec = dyn_cast<ConstantVector>(op))
157 {
158 breakExpressionsInVector(cvec, i, newInst);
159 }
160 }
161 }
162
breakExpressionsInVector(llvm::ConstantVector * cvec,int operandIndex,llvm::Instruction * user)163 bool BreakConstantExpr::breakExpressionsInVector(llvm::ConstantVector* cvec, int operandIndex, llvm::Instruction* user)
164 {
165 bool hasConstantExpression = false;
166 for (unsigned elemIdx = 0; elemIdx < cvec->getNumOperands(); ++elemIdx)
167 {
168 if (isa<ConstantExpr>(cvec->getOperand(elemIdx)))
169 {
170 hasConstantExpression = true;
171 break;
172 }
173 }
174
175 if (hasConstantExpression)
176 {
177 Value* currVec = UndefValue::get(cvec->getType());
178 const unsigned vecSize = cvec->getNumOperands();
179
180 for (unsigned elemIdx = 0; elemIdx < vecSize; ++elemIdx)
181 {
182 Value* op = cvec->getOperand(elemIdx);
183 Instruction* newInst = InsertElementInst::Create(
184 currVec,
185 op,
186 ConstantInt::get(Type::getInt32Ty(user->getContext()), elemIdx));
187
188 if (elemIdx < cvec->getNumOperands() - 1)
189 {
190 if (PHINode * phi = dyn_cast<PHINode>(user))
191 {
192 newInst->insertBefore(phi->getIncomingBlock(operandIndex)->getTerminator());
193 }
194 else
195 {
196 newInst->insertBefore(user);
197 }
198 }
199 else
200 {
201 // cvec can be destroyed inside!
202 replaceConstantWith(cvec, newInst, operandIndex, user);
203 }
204
205 if (ConstantExpr * expr = dyn_cast<ConstantExpr>(op))
206 {
207 breakExpressions(expr, 1, newInst);
208 }
209
210 currVec = newInst;
211 }
212 }
213
214 return hasConstantExpression;
215 }
216
breakConstantStruct(ConstantStruct * cs,int operandIndex,Instruction * user)217 void BreakConstantExpr::breakConstantStruct(ConstantStruct* cs,
218 int operandIndex,
219 Instruction *user)
220 {
221 StructType *structType = cs->getType();
222 IRBuilder<> B(user);
223 Value *newStruct = UndefValue::get(structType);
224
225 // Create a structure from scratch, replace every constant operand by an
226 // instruction.
227 for (unsigned i = 0; i < cs->getNumOperands(); ++i)
228 {
229 Value *constStructOp = cs->getOperand(i);
230 Value *newStructOp = constStructOp;
231
232 // TODO: Handle more cases, such as ConstantStruct, ConstantVector, etc.
233 if (ConstantExpr *c = dyn_cast<ConstantExpr>(constStructOp))
234 {
235 Instruction *newInst = c->getAsInstruction();
236 newInst->setDebugLoc(user->getDebugLoc());
237 newStructOp = newInst;
238
239 if (PHINode * phi = dyn_cast<PHINode>(user))
240 {
241 newInst->insertBefore(phi->getIncomingBlock(operandIndex)->
242 getTerminator());
243 }
244 else
245 {
246 newInst->insertBefore(user);
247 }
248 }
249
250 newStruct = B.CreateInsertValue(newStruct, newStructOp, i);
251 }
252
253 user->replaceUsesOfWith(cs, newStruct);
254
255 if (cs->use_empty())
256 {
257 cs->destroyConstant();
258 }
259 }
260