LLVM 24.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 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.
14//
15//===----------------------------------------------------------------------===//
16
17#include "AVR.h"
18#include "llvm/IR/Analysis.h"
19#include "llvm/IR/IRBuilder.h"
21#include "llvm/IR/PassManager.h"
22
23using namespace llvm;
24
25namespace {
26
27class AVRShiftExpandLegacy : public FunctionPass {
28public:
29 static char ID;
30
31 AVRShiftExpandLegacy() : FunctionPass(ID) {}
32
33 bool runOnFunction(Function &F) override;
34
35 StringRef getPassName() const override { return "AVR Shift Expansion"; }
36};
37
38} // end of anonymous namespace
39
40char AVRShiftExpandLegacy::ID = 0;
41
42INITIALIZE_PASS(AVRShiftExpandLegacy, "avr-shift-expand", "AVR Shift Expansion",
43 false, false)
44
46 return new AVRShiftExpandLegacy();
47}
48
50 auto &Ctx = BI->getContext();
51 IRBuilder<> Builder(BI);
52 Type *InputTy = cast<Instruction>(BI)->getType();
53 Type *Int8Ty = Type::getInt8Ty(Ctx);
54 Value *Int8Zero = ConstantInt::get(Int8Ty, 0);
55
56 // Split the current basic block at the point of the existing shift
57 // instruction and insert a new basic block for the loop.
58 BasicBlock *BB = BI->getParent();
59 Function *F = BB->getParent();
60 BasicBlock *EndBB = BB->splitBasicBlock(BI, "shift.done");
61 BasicBlock *LoopBB = BasicBlock::Create(Ctx, "shift.loop", F, EndBB);
62
63 // Truncate the shift amount to i8, which is trivially lowered to a single
64 // AVR register.
65 Builder.SetInsertPoint(&BB->back());
66 Value *ShiftAmount = Builder.CreateTrunc(BI->getOperand(1), Int8Ty);
67
68 // Replace the unconditional branch that splitBasicBlock created with a
69 // conditional branch.
70 Value *Cmp1 = Builder.CreateICmpEQ(ShiftAmount, Int8Zero);
71 Builder.CreateCondBr(Cmp1, EndBB, LoopBB);
72 BB->back().eraseFromParent();
73
74 // Create the loop body starting with PHI nodes.
75 Builder.SetInsertPoint(LoopBB);
76 PHINode *ShiftAmountPHI = Builder.CreatePHI(Int8Ty, 2);
77 ShiftAmountPHI->addIncoming(ShiftAmount, BB);
78 PHINode *ValuePHI = Builder.CreatePHI(InputTy, 2);
79 ValuePHI->addIncoming(BI->getOperand(0), BB);
80
81 // Subtract the shift amount by one, as we're shifting one this loop
82 // iteration.
83 Value *ShiftAmountSub =
84 Builder.CreateSub(ShiftAmountPHI, ConstantInt::get(Int8Ty, 1));
85 ShiftAmountPHI->addIncoming(ShiftAmountSub, LoopBB);
86
87 // Emit the actual shift instruction. The difference is that this shift
88 // instruction has a constant shift amount, which can be emitted inline
89 // without a library call.
90 Value *ValueShifted;
91 switch (BI->getOpcode()) {
92 case Instruction::Shl:
93 ValueShifted = Builder.CreateShl(ValuePHI, ConstantInt::get(InputTy, 1));
94 break;
95 case Instruction::LShr:
96 ValueShifted = Builder.CreateLShr(ValuePHI, ConstantInt::get(InputTy, 1));
97 break;
98 case Instruction::AShr:
99 ValueShifted = Builder.CreateAShr(ValuePHI, ConstantInt::get(InputTy, 1));
100 break;
101 default:
102 llvm_unreachable("asked to expand an instruction that is not a shift");
103 }
104 ValuePHI->addIncoming(ValueShifted, LoopBB);
105
106 // Branch to either the loop again (if there is more to shift) or to the
107 // basic block after the loop (if all bits are shifted).
108 Value *Cmp2 = Builder.CreateICmpEQ(ShiftAmountSub, Int8Zero);
109 Builder.CreateCondBr(Cmp2, EndBB, LoopBB);
110
111 // Collect the resulting value. This is necessary in the IR but won't produce
112 // any actual instructions.
113 Builder.SetInsertPoint(BI);
114 PHINode *Result = Builder.CreatePHI(InputTy, 2);
115 Result->addIncoming(BI->getOperand(0), BB);
116 Result->addIncoming(ValueShifted, LoopBB);
117
118 // Replace the original shift instruction.
119 BI->replaceAllUsesWith(Result);
120 BI->eraseFromParent();
121}
122
125 auto &Ctx = F.getContext();
126 for (Instruction &I : instructions(F)) {
127 if (!I.isShift())
128 // Only expand shift instructions (shl, lshr, ashr).
129 continue;
130 if (I.getType() == Type::getInt8Ty(Ctx) ||
131 I.getType() == Type::getInt16Ty(Ctx))
132 // Only expand non-8-bit and non-16-bit shifts, since those are expanded
133 // directly during isel.
134 continue;
135 if (isa<ConstantInt>(I.getOperand(1)))
136 // Only expand when the shift amount is not known.
137 // Known shift amounts are (currently) better expanded inline.
138 continue;
139 ShiftInsts.push_back(cast<BinaryOperator>(&I));
140 }
141
142 // The expanding itself needs to be done separately as expand() will remove
143 // these instructions. Removing instructions while iterating over a basic
144 // block is not a great idea.
145 for (auto *I : ShiftInsts) {
147 }
148
149 // Return whether this function expanded any shift instructions.
150 return ShiftInsts.size() > 0;
151}
152
153bool AVRShiftExpandLegacy::runOnFunction(Function &F) {
155}
156
static bool expandShiftsInFunction(Function &F)
static void expandBinaryOperator(BinaryOperator *BI)
Expand Atomic instructions
static bool runOnFunction(Function &F, bool PostInlining)
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
FunctionAnalysisManager FAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
LLVM Basic Block Representation.
Definition BasicBlock.h:62
LLVM_ABI BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="")
Split the basic block into two basic blocks at the specified instruction.
const Function * getParent() const
Return the enclosing method, or null if none.
Definition BasicBlock.h:213
const Instruction & back() const
Definition BasicBlock.h:465
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition BasicBlock.h:206
BinaryOps getOpcode() const
Definition InstrTypes.h:409
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2909
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
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:97
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:297
static LLVM_ABI IntegerType * getInt16Ty(LLVMContext &C)
Definition Type.cpp:298
Value * getOperand(unsigned i) const
Definition User.h:207
LLVM Value Representation.
Definition Value.h:75
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:549
LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.h:260
const ParentTy * getParent() const
Definition ilist_node.h:34
Pass manager infrastructure for declaring and invalidating analyses.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
Pass * createAVRShiftExpandLegacyPass()
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.