LLVM 17.0.0git
AVRShiftExpand.cpp
Go to the documentation of this file.
1//===- AVRShift.cpp - Shift Expansion Pass --------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// Expand 32-bit shift instructions (shl, lshr, ashr) to inline loops, just
11/// like avr-gcc. This must be done in IR because otherwise the type legalizer
12/// will turn 32-bit shifts into (non-existing) library calls such as __ashlsi3.
13//
14//===----------------------------------------------------------------------===//
15
16#include "AVR.h"
17#include "llvm/IR/IRBuilder.h"
19
20using namespace llvm;
21
22namespace {
23
24class AVRShiftExpand : public FunctionPass {
25public:
26 static char ID;
27
28 AVRShiftExpand() : FunctionPass(ID) {}
29
30 bool runOnFunction(Function &F) override;
31
32 StringRef getPassName() const override { return "AVR Shift Expansion"; }
33
34private:
35 void expand(BinaryOperator *BI);
36};
37
38} // end of anonymous namespace
39
40char AVRShiftExpand::ID = 0;
41
42INITIALIZE_PASS(AVRShiftExpand, "avr-shift-expand", "AVR Shift Expansion",
43 false, false)
44
45Pass *llvm::createAVRShiftExpandPass() { return new AVRShiftExpand(); }
46
47bool AVRShiftExpand::runOnFunction(Function &F) {
49 auto &Ctx = F.getContext();
50 for (Instruction &I : instructions(F)) {
51 if (!I.isShift())
52 // Only expand shift instructions (shl, lshr, ashr).
53 continue;
54 if (I.getType() != Type::getInt32Ty(Ctx))
55 // Only expand plain i32 types.
56 continue;
57 if (isa<ConstantInt>(I.getOperand(1)))
58 // Only expand when the shift amount is not known.
59 // Known shift amounts are (currently) better expanded inline.
60 continue;
61 ShiftInsts.push_back(cast<BinaryOperator>(&I));
62 }
63
64 // The expanding itself needs to be done separately as expand() will remove
65 // these instructions. Removing instructions while iterating over a basic
66 // block is not a great idea.
67 for (auto *I : ShiftInsts) {
68 expand(I);
69 }
70
71 // Return whether this function expanded any shift instructions.
72 return ShiftInsts.size() > 0;
73}
74
75void AVRShiftExpand::expand(BinaryOperator *BI) {
76 auto &Ctx = BI->getContext();
79 Type *Int8Ty = Type::getInt8Ty(Ctx);
80 Value *Int8Zero = ConstantInt::get(Int8Ty, 0);
81
82 // Split the current basic block at the point of the existing shift
83 // instruction and insert a new basic block for the loop.
84 BasicBlock *BB = BI->getParent();
85 Function *F = BB->getParent();
86 BasicBlock *EndBB = BB->splitBasicBlock(BI, "shift.done");
87 BasicBlock *LoopBB = BasicBlock::Create(Ctx, "shift.loop", F, EndBB);
88
89 // Truncate the shift amount to i8, which is trivially lowered to a single
90 // AVR register.
91 Builder.SetInsertPoint(&BB->back());
92 Value *ShiftAmount = Builder.CreateTrunc(BI->getOperand(1), Int8Ty);
93
94 // Replace the unconditional branch that splitBasicBlock created with a
95 // conditional branch.
96 Value *Cmp1 = Builder.CreateICmpEQ(ShiftAmount, Int8Zero);
97 Builder.CreateCondBr(Cmp1, EndBB, LoopBB);
98 BB->back().eraseFromParent();
99
100 // Create the loop body starting with PHI nodes.
101 Builder.SetInsertPoint(LoopBB);
102 PHINode *ShiftAmountPHI = Builder.CreatePHI(Int8Ty, 2);
103 ShiftAmountPHI->addIncoming(ShiftAmount, BB);
104 PHINode *ValuePHI = Builder.CreatePHI(Int32Ty, 2);
105 ValuePHI->addIncoming(BI->getOperand(0), BB);
106
107 // Subtract the shift amount by one, as we're shifting one this loop
108 // iteration.
109 Value *ShiftAmountSub =
110 Builder.CreateSub(ShiftAmountPHI, ConstantInt::get(Int8Ty, 1));
111 ShiftAmountPHI->addIncoming(ShiftAmountSub, LoopBB);
112
113 // Emit the actual shift instruction. The difference is that this shift
114 // instruction has a constant shift amount, which can be emitted inline
115 // without a library call.
116 Value *ValueShifted;
117 switch (BI->getOpcode()) {
118 case Instruction::Shl:
119 ValueShifted = Builder.CreateShl(ValuePHI, ConstantInt::get(Int32Ty, 1));
120 break;
121 case Instruction::LShr:
122 ValueShifted = Builder.CreateLShr(ValuePHI, ConstantInt::get(Int32Ty, 1));
123 break;
124 case Instruction::AShr:
125 ValueShifted = Builder.CreateAShr(ValuePHI, ConstantInt::get(Int32Ty, 1));
126 break;
127 default:
128 llvm_unreachable("asked to expand an instruction that is not a shift");
129 }
130 ValuePHI->addIncoming(ValueShifted, LoopBB);
131
132 // Branch to either the loop again (if there is more to shift) or to the
133 // basic block after the loop (if all bits are shifted).
134 Value *Cmp2 = Builder.CreateICmpEQ(ShiftAmountSub, Int8Zero);
135 Builder.CreateCondBr(Cmp2, EndBB, LoopBB);
136
137 // Collect the resulting value. This is necessary in the IR but won't produce
138 // any actual instructions.
139 Builder.SetInsertPoint(BI);
140 PHINode *Result = Builder.CreatePHI(Int32Ty, 2);
141 Result->addIncoming(BI->getOperand(0), BB);
142 Result->addIncoming(ValueShifted, LoopBB);
143
144 // Replace the original shift instruction.
145 BI->replaceAllUsesWith(Result);
146 BI->eraseFromParent();
147}
assume Assume Builder
static Expected< BitVector > expand(StringRef S, StringRef Original)
Definition: GlobPattern.cpp:26
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
print must be executed print the must be executed context for all instructions
IntegerType * Int32Ty
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
LLVM Basic Block Representation.
Definition: BasicBlock.h:56
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:105
BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="", bool Before=false)
Split the basic block into two basic blocks at the specified instruction.
Definition: BasicBlock.cpp:401
const Function * getParent() const
Return the enclosing method, or null if none.
Definition: BasicBlock.h:112
const Instruction & back() const
Definition: BasicBlock.h:328
BinaryOps getOpcode() const
Definition: InstrTypes.h:391
static Constant * get(Type *Ty, uint64_t V, bool IsSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
Definition: Constants.cpp:888
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:308
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2558
const BasicBlock * getParent() const
Definition: Instruction.h:90
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Definition: Instruction.cpp:82
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
Pass interface - Implemented by all 'passes'.
Definition: Pass.h:91
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static IntegerType * getInt8Ty(LLVMContext &C)
static IntegerType * getInt32Ty(LLVMContext &C)
Value * getOperand(unsigned i) const
Definition: User.h:169
LLVM Value Representation.
Definition: Value.h:74
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:532
LLVMContext & getContext() const
All values hold a context through their type.
Definition: Value.cpp:994
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
Pass * createAVRShiftExpandPass()