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