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