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