1 /*========================== begin_copyright_notice ============================
2
3 Copyright (C) 2020-2021 Intel Corporation
4
5 SPDX-License-Identifier: MIT
6
7 ============================= end_copyright_notice ===========================*/
8
9 //
10 /// GenXInstCombineCleanupPass
11 /// --------------------------
12 ///
13 /// For switch instructions llvm 7.0 instcombine aggressively shrikns the type
14 /// of the condition variable. This can introduce types which are unsupported
15 /// in GenX IR (like i2, i27, etc)
16 /// The pass tries to detect such switch instructions and modify them to use
17 /// the original condition instead of a truncated one.
18 /// The idea is to do it using a standard llvm passes, so we just try to do the
19 /// opposite to inst combine change and expect irbuilder folding or other passes
20 /// to change code as it was before.
21
22 #define DEBUG_TYPE "GENX_INSTCOMBCLEANUP"
23
24 #include "GenX.h"
25 #include "llvm/IR/Constants.h"
26 #include "llvm/IR/Function.h"
27 #include "llvm/IR/IRBuilder.h"
28 #include "llvm/IR/InstIterator.h"
29 #include "llvm/IR/Instructions.h"
30 #include "llvm/Pass.h"
31 #include "llvm/Support/Debug.h"
32 #include "Probe/Assertion.h"
33
34 using namespace llvm;
35 using namespace genx;
36
37 namespace {
38
39 class GenXInstCombineCleanup : public FunctionPass {
40 public:
41 static char ID;
42
GenXInstCombineCleanup()43 explicit GenXInstCombineCleanup() : FunctionPass(ID) { }
44
getPassName() const45 StringRef getPassName() const override { return "GenX InstCombineCleanup"; }
46 void getAnalysisUsage(AnalysisUsage &AU) const override;
47 bool runOnFunction(Function &F) override;
48 };
49
50 } // end anonymous namespace
51
52 char GenXInstCombineCleanup::ID = 0;
53 namespace llvm { void initializeGenXInstCombineCleanupPass(PassRegistry &); }
54 INITIALIZE_PASS_BEGIN(GenXInstCombineCleanup, "GenXInstCombineCleanup", "GenXInstCombineCleanup", false, false)
55 INITIALIZE_PASS_END(GenXInstCombineCleanup, "GenXInstCombineCleanup", "GenXInstCombineCleanup", false, false)
56
createGenXInstCombineCleanup()57 FunctionPass *llvm::createGenXInstCombineCleanup()
58 {
59 initializeGenXInstCombineCleanupPass(*PassRegistry::getPassRegistry());
60 return new GenXInstCombineCleanup();
61 }
62
getAnalysisUsage(AnalysisUsage & AU) const63 void GenXInstCombineCleanup::getAnalysisUsage(AnalysisUsage &AU) const
64 {
65 AU.setPreservesCFG();
66 }
67
typeMustBeChanged(Type * Ty)68 bool typeMustBeChanged(Type *Ty) {
69 IGC_ASSERT(Ty);
70 if (!Ty->isIntegerTy())
71 return false;
72 unsigned Size = Ty->getPrimitiveSizeInBits();
73 // Possible sizes are 1, 8, 16, 32, ... (2 and 4 must be excluded)
74 if (isPowerOf2_32(Size) && !(genx::BoolBits < Size && Size < genx::ByteBits))
75 return false;
76 return true;
77 }
78
runOnFunction(Function & F)79 bool GenXInstCombineCleanup::runOnFunction(Function &F)
80 {
81 bool Modified = false;
82
83 #if (LLVM_VERSION_MAJOR <= 7)
84 LLVM_DEBUG(dbgs() << "running GenXInstCombineCleanup on " << F.getName() << "\n");
85
86 LLVMContext &Ctx = F.getContext();
87 IRBuilder<> Builder(Ctx);
88
89 for (auto I = inst_begin(F), E = inst_end(F); I != E; ++I) {
90 auto Switch = dyn_cast<SwitchInst>(&*I);
91 if (!Switch)
92 continue;
93
94 auto Cond = Switch->getCondition();
95 Type *CondTy = Cond->getType();
96 if (!typeMustBeChanged(CondTy))
97 continue;
98
99 unsigned CondSize = CondTy->getPrimitiveSizeInBits();
100 IGC_ASSERT_MESSAGE(CondSize != genx::BoolBits,
101 "CondSize == 1 is not expected here. See typeMustBeChanged");
102 // Round up to the next power of 2 skipping i2 and i4 (i3 -> i8, i2 -> i8,
103 // etc)
104 unsigned Size =
105 CondSize < genx::ByteBits ? genx::ByteBits : NextPowerOf2(CondSize);
106
107 Type *NewTy = Type::getIntNTy(Ctx, Size);
108
109 Builder.SetInsertPoint(Switch);
110 Value *NewCond =
111 Builder.CreateSExt(Cond, NewTy, Switch->getName() + ".condSExt");
112 Switch->setCondition(NewCond);
113
114 for (auto Case : Switch->cases()) {
115 APInt UpdatedCase = Case.getCaseValue()->getValue().sext(Size);
116 Case.setValue(ConstantInt::get(Ctx, UpdatedCase));
117 }
118
119 Modified = true;
120 }
121 #endif
122
123 return Modified;
124 }
125
126