1*6aa9e746SAyke van Laethem //===- AVRShift.cpp - Shift Expansion Pass --------------------------------===//
2*6aa9e746SAyke van Laethem //
3*6aa9e746SAyke van Laethem // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*6aa9e746SAyke van Laethem // See https://llvm.org/LICENSE.txt for license information.
5*6aa9e746SAyke van Laethem // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*6aa9e746SAyke van Laethem //
7*6aa9e746SAyke van Laethem //===----------------------------------------------------------------------===//
8*6aa9e746SAyke van Laethem //
9*6aa9e746SAyke van Laethem /// \file
10*6aa9e746SAyke van Laethem /// Expand 32-bit shift instructions (shl, lshr, ashr) to inline loops, just
11*6aa9e746SAyke van Laethem /// like avr-gcc. This must be done in IR because otherwise the type legalizer
12*6aa9e746SAyke van Laethem /// will turn 32-bit shifts into (non-existing) library calls such as __ashlsi3.
13*6aa9e746SAyke van Laethem //
14*6aa9e746SAyke van Laethem //===----------------------------------------------------------------------===//
15*6aa9e746SAyke van Laethem 
16*6aa9e746SAyke van Laethem #include "AVR.h"
17*6aa9e746SAyke van Laethem #include "llvm/IR/IRBuilder.h"
18*6aa9e746SAyke van Laethem #include "llvm/IR/InstIterator.h"
19*6aa9e746SAyke van Laethem 
20*6aa9e746SAyke van Laethem using namespace llvm;
21*6aa9e746SAyke van Laethem 
22*6aa9e746SAyke van Laethem namespace {
23*6aa9e746SAyke van Laethem 
24*6aa9e746SAyke van Laethem class AVRShiftExpand : public FunctionPass {
25*6aa9e746SAyke van Laethem public:
26*6aa9e746SAyke van Laethem   static char ID;
27*6aa9e746SAyke van Laethem 
AVRShiftExpand()28*6aa9e746SAyke van Laethem   AVRShiftExpand() : FunctionPass(ID) {}
29*6aa9e746SAyke van Laethem 
30*6aa9e746SAyke van Laethem   bool runOnFunction(Function &F) override;
31*6aa9e746SAyke van Laethem 
getPassName() const32*6aa9e746SAyke van Laethem   StringRef getPassName() const override { return "AVR Shift Expansion"; }
33*6aa9e746SAyke van Laethem 
34*6aa9e746SAyke van Laethem private:
35*6aa9e746SAyke van Laethem   void expand(BinaryOperator *BI);
36*6aa9e746SAyke van Laethem };
37*6aa9e746SAyke van Laethem 
38*6aa9e746SAyke van Laethem } // end of anonymous namespace
39*6aa9e746SAyke van Laethem 
40*6aa9e746SAyke van Laethem char AVRShiftExpand::ID = 0;
41*6aa9e746SAyke van Laethem 
42*6aa9e746SAyke van Laethem INITIALIZE_PASS(AVRShiftExpand, "avr-shift-expand", "AVR Shift Expansion",
43*6aa9e746SAyke van Laethem                 false, false)
44*6aa9e746SAyke van Laethem 
createAVRShiftExpandPass()45*6aa9e746SAyke van Laethem Pass *llvm::createAVRShiftExpandPass() { return new AVRShiftExpand(); }
46*6aa9e746SAyke van Laethem 
runOnFunction(Function & F)47*6aa9e746SAyke van Laethem bool AVRShiftExpand::runOnFunction(Function &F) {
48*6aa9e746SAyke van Laethem   SmallVector<BinaryOperator *, 1> ShiftInsts;
49*6aa9e746SAyke van Laethem   auto &Ctx = F.getContext();
50*6aa9e746SAyke van Laethem   for (Instruction &I : instructions(F)) {
51*6aa9e746SAyke van Laethem     if (!I.isShift())
52*6aa9e746SAyke van Laethem       // Only expand shift instructions (shl, lshr, ashr).
53*6aa9e746SAyke van Laethem       continue;
54*6aa9e746SAyke van Laethem     if (I.getType() != Type::getInt32Ty(Ctx))
55*6aa9e746SAyke van Laethem       // Only expand plain i32 types.
56*6aa9e746SAyke van Laethem       continue;
57*6aa9e746SAyke van Laethem     if (isa<ConstantInt>(I.getOperand(1)))
58*6aa9e746SAyke van Laethem       // Only expand when the shift amount is not known.
59*6aa9e746SAyke van Laethem       // Known shift amounts are (currently) better expanded inline.
60*6aa9e746SAyke van Laethem       continue;
61*6aa9e746SAyke van Laethem     ShiftInsts.push_back(cast<BinaryOperator>(&I));
62*6aa9e746SAyke van Laethem   }
63*6aa9e746SAyke van Laethem 
64*6aa9e746SAyke van Laethem   // The expanding itself needs to be done separately as expand() will remove
65*6aa9e746SAyke van Laethem   // these instructions. Removing instructions while iterating over a basic
66*6aa9e746SAyke van Laethem   // block is not a great idea.
67*6aa9e746SAyke van Laethem   for (auto *I : ShiftInsts) {
68*6aa9e746SAyke van Laethem     expand(I);
69*6aa9e746SAyke van Laethem   }
70*6aa9e746SAyke van Laethem 
71*6aa9e746SAyke van Laethem   // Return whether this function expanded any shift instructions.
72*6aa9e746SAyke van Laethem   return ShiftInsts.size() > 0;
73*6aa9e746SAyke van Laethem }
74*6aa9e746SAyke van Laethem 
expand(BinaryOperator * BI)75*6aa9e746SAyke van Laethem void AVRShiftExpand::expand(BinaryOperator *BI) {
76*6aa9e746SAyke van Laethem   auto &Ctx = BI->getContext();
77*6aa9e746SAyke van Laethem   IRBuilder<> Builder(BI);
78*6aa9e746SAyke van Laethem   Type *Int32Ty = Type::getInt32Ty(Ctx);
79*6aa9e746SAyke van Laethem   Type *Int8Ty = Type::getInt8Ty(Ctx);
80*6aa9e746SAyke van Laethem   Value *Int8Zero = ConstantInt::get(Int8Ty, 0);
81*6aa9e746SAyke van Laethem 
82*6aa9e746SAyke van Laethem   // Split the current basic block at the point of the existing shift
83*6aa9e746SAyke van Laethem   // instruction and insert a new basic block for the loop.
84*6aa9e746SAyke van Laethem   BasicBlock *BB = BI->getParent();
85*6aa9e746SAyke van Laethem   Function *F = BB->getParent();
86*6aa9e746SAyke van Laethem   BasicBlock *EndBB = BB->splitBasicBlock(BI, "shift.done");
87*6aa9e746SAyke van Laethem   BasicBlock *LoopBB = BasicBlock::Create(Ctx, "shift.loop", F, EndBB);
88*6aa9e746SAyke van Laethem 
89*6aa9e746SAyke van Laethem   // Truncate the shift amount to i8, which is trivially lowered to a single
90*6aa9e746SAyke van Laethem   // AVR register.
91*6aa9e746SAyke van Laethem   Builder.SetInsertPoint(&BB->back());
92*6aa9e746SAyke van Laethem   Value *ShiftAmount = Builder.CreateTrunc(BI->getOperand(1), Int8Ty);
93*6aa9e746SAyke van Laethem 
94*6aa9e746SAyke van Laethem   // Replace the unconditional branch that splitBasicBlock created with a
95*6aa9e746SAyke van Laethem   // conditional branch.
96*6aa9e746SAyke van Laethem   Value *Cmp1 = Builder.CreateICmpEQ(ShiftAmount, Int8Zero);
97*6aa9e746SAyke van Laethem   Builder.CreateCondBr(Cmp1, EndBB, LoopBB);
98*6aa9e746SAyke van Laethem   BB->back().eraseFromParent();
99*6aa9e746SAyke van Laethem 
100*6aa9e746SAyke van Laethem   // Create the loop body starting with PHI nodes.
101*6aa9e746SAyke van Laethem   Builder.SetInsertPoint(LoopBB);
102*6aa9e746SAyke van Laethem   PHINode *ShiftAmountPHI = Builder.CreatePHI(Int8Ty, 2);
103*6aa9e746SAyke van Laethem   ShiftAmountPHI->addIncoming(ShiftAmount, BB);
104*6aa9e746SAyke van Laethem   PHINode *ValuePHI = Builder.CreatePHI(Int32Ty, 2);
105*6aa9e746SAyke van Laethem   ValuePHI->addIncoming(BI->getOperand(0), BB);
106*6aa9e746SAyke van Laethem 
107*6aa9e746SAyke van Laethem   // Subtract the shift amount by one, as we're shifting one this loop
108*6aa9e746SAyke van Laethem   // iteration.
109*6aa9e746SAyke van Laethem   Value *ShiftAmountSub =
110*6aa9e746SAyke van Laethem       Builder.CreateSub(ShiftAmountPHI, ConstantInt::get(Int8Ty, 1));
111*6aa9e746SAyke van Laethem   ShiftAmountPHI->addIncoming(ShiftAmountSub, LoopBB);
112*6aa9e746SAyke van Laethem 
113*6aa9e746SAyke van Laethem   // Emit the actual shift instruction. The difference is that this shift
114*6aa9e746SAyke van Laethem   // instruction has a constant shift amount, which can be emitted inline
115*6aa9e746SAyke van Laethem   // without a library call.
116*6aa9e746SAyke van Laethem   Value *ValueShifted;
117*6aa9e746SAyke van Laethem   switch (BI->getOpcode()) {
118*6aa9e746SAyke van Laethem   case Instruction::Shl:
119*6aa9e746SAyke van Laethem     ValueShifted = Builder.CreateShl(ValuePHI, ConstantInt::get(Int32Ty, 1));
120*6aa9e746SAyke van Laethem     break;
121*6aa9e746SAyke van Laethem   case Instruction::LShr:
122*6aa9e746SAyke van Laethem     ValueShifted = Builder.CreateLShr(ValuePHI, ConstantInt::get(Int32Ty, 1));
123*6aa9e746SAyke van Laethem     break;
124*6aa9e746SAyke van Laethem   case Instruction::AShr:
125*6aa9e746SAyke van Laethem     ValueShifted = Builder.CreateAShr(ValuePHI, ConstantInt::get(Int32Ty, 1));
126*6aa9e746SAyke van Laethem     break;
127*6aa9e746SAyke van Laethem   default:
128*6aa9e746SAyke van Laethem     llvm_unreachable("asked to expand an instruction that is not a shift");
129*6aa9e746SAyke van Laethem   }
130*6aa9e746SAyke van Laethem   ValuePHI->addIncoming(ValueShifted, LoopBB);
131*6aa9e746SAyke van Laethem 
132*6aa9e746SAyke van Laethem   // Branch to either the loop again (if there is more to shift) or to the
133*6aa9e746SAyke van Laethem   // basic block after the loop (if all bits are shifted).
134*6aa9e746SAyke van Laethem   Value *Cmp2 = Builder.CreateICmpEQ(ShiftAmountSub, Int8Zero);
135*6aa9e746SAyke van Laethem   Builder.CreateCondBr(Cmp2, EndBB, LoopBB);
136*6aa9e746SAyke van Laethem 
137*6aa9e746SAyke van Laethem   // Collect the resulting value. This is necessary in the IR but won't produce
138*6aa9e746SAyke van Laethem   // any actual instructions.
139*6aa9e746SAyke van Laethem   Builder.SetInsertPoint(BI);
140*6aa9e746SAyke van Laethem   PHINode *Result = Builder.CreatePHI(Int32Ty, 2);
141*6aa9e746SAyke van Laethem   Result->addIncoming(BI->getOperand(0), BB);
142*6aa9e746SAyke van Laethem   Result->addIncoming(ValueShifted, LoopBB);
143*6aa9e746SAyke van Laethem 
144*6aa9e746SAyke van Laethem   // Replace the original shift instruction.
145*6aa9e746SAyke van Laethem   BI->replaceAllUsesWith(Result);
146*6aa9e746SAyke van Laethem   BI->eraseFromParent();
147*6aa9e746SAyke van Laethem }
148