16aa9e746SAyke van Laethem //===- AVRShift.cpp - Shift Expansion Pass --------------------------------===//
26aa9e746SAyke van Laethem //
36aa9e746SAyke van Laethem // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46aa9e746SAyke van Laethem // See https://llvm.org/LICENSE.txt for license information.
56aa9e746SAyke van Laethem // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66aa9e746SAyke van Laethem //
76aa9e746SAyke van Laethem //===----------------------------------------------------------------------===//
86aa9e746SAyke van Laethem //
96aa9e746SAyke van Laethem /// \file
10*4e831753SPatryk Wychowaniec /// Expand non-8-bit and non-16-bit shift instructions (shl, lshr, ashr) to
11*4e831753SPatryk Wychowaniec /// inline loops, just like avr-gcc. This must be done in IR because otherwise
12*4e831753SPatryk Wychowaniec /// the type legalizer will turn 32-bit shifts into (non-existing) library calls
13*4e831753SPatryk Wychowaniec /// such as __ashlsi3.
146aa9e746SAyke van Laethem //
156aa9e746SAyke van Laethem //===----------------------------------------------------------------------===//
166aa9e746SAyke van Laethem
176aa9e746SAyke van Laethem #include "AVR.h"
186aa9e746SAyke van Laethem #include "llvm/IR/IRBuilder.h"
196aa9e746SAyke van Laethem #include "llvm/IR/InstIterator.h"
206aa9e746SAyke van Laethem
216aa9e746SAyke van Laethem using namespace llvm;
226aa9e746SAyke van Laethem
236aa9e746SAyke van Laethem namespace {
246aa9e746SAyke van Laethem
256aa9e746SAyke van Laethem class AVRShiftExpand : public FunctionPass {
266aa9e746SAyke van Laethem public:
276aa9e746SAyke van Laethem static char ID;
286aa9e746SAyke van Laethem
AVRShiftExpand()296aa9e746SAyke van Laethem AVRShiftExpand() : FunctionPass(ID) {}
306aa9e746SAyke van Laethem
316aa9e746SAyke van Laethem bool runOnFunction(Function &F) override;
326aa9e746SAyke van Laethem
getPassName() const336aa9e746SAyke van Laethem StringRef getPassName() const override { return "AVR Shift Expansion"; }
346aa9e746SAyke van Laethem
356aa9e746SAyke van Laethem private:
366aa9e746SAyke van Laethem void expand(BinaryOperator *BI);
376aa9e746SAyke van Laethem };
386aa9e746SAyke van Laethem
396aa9e746SAyke van Laethem } // end of anonymous namespace
406aa9e746SAyke van Laethem
416aa9e746SAyke van Laethem char AVRShiftExpand::ID = 0;
426aa9e746SAyke van Laethem
436aa9e746SAyke van Laethem INITIALIZE_PASS(AVRShiftExpand, "avr-shift-expand", "AVR Shift Expansion",
446aa9e746SAyke van Laethem false, false)
456aa9e746SAyke van Laethem
createAVRShiftExpandPass()466aa9e746SAyke van Laethem Pass *llvm::createAVRShiftExpandPass() { return new AVRShiftExpand(); }
476aa9e746SAyke van Laethem
runOnFunction(Function & F)486aa9e746SAyke van Laethem bool AVRShiftExpand::runOnFunction(Function &F) {
496aa9e746SAyke van Laethem SmallVector<BinaryOperator *, 1> ShiftInsts;
506aa9e746SAyke van Laethem auto &Ctx = F.getContext();
516aa9e746SAyke van Laethem for (Instruction &I : instructions(F)) {
526aa9e746SAyke van Laethem if (!I.isShift())
536aa9e746SAyke van Laethem // Only expand shift instructions (shl, lshr, ashr).
546aa9e746SAyke van Laethem continue;
55*4e831753SPatryk Wychowaniec if (I.getType() == Type::getInt8Ty(Ctx) || I.getType() == Type::getInt16Ty(Ctx))
56*4e831753SPatryk Wychowaniec // Only expand non-8-bit and non-16-bit shifts, since those are expanded
57*4e831753SPatryk Wychowaniec // directly during isel.
586aa9e746SAyke van Laethem continue;
596aa9e746SAyke van Laethem if (isa<ConstantInt>(I.getOperand(1)))
606aa9e746SAyke van Laethem // Only expand when the shift amount is not known.
616aa9e746SAyke van Laethem // Known shift amounts are (currently) better expanded inline.
626aa9e746SAyke van Laethem continue;
636aa9e746SAyke van Laethem ShiftInsts.push_back(cast<BinaryOperator>(&I));
646aa9e746SAyke van Laethem }
656aa9e746SAyke van Laethem
666aa9e746SAyke van Laethem // The expanding itself needs to be done separately as expand() will remove
676aa9e746SAyke van Laethem // these instructions. Removing instructions while iterating over a basic
686aa9e746SAyke van Laethem // block is not a great idea.
696aa9e746SAyke van Laethem for (auto *I : ShiftInsts) {
706aa9e746SAyke van Laethem expand(I);
716aa9e746SAyke van Laethem }
726aa9e746SAyke van Laethem
736aa9e746SAyke van Laethem // Return whether this function expanded any shift instructions.
746aa9e746SAyke van Laethem return ShiftInsts.size() > 0;
756aa9e746SAyke van Laethem }
766aa9e746SAyke van Laethem
expand(BinaryOperator * BI)776aa9e746SAyke van Laethem void AVRShiftExpand::expand(BinaryOperator *BI) {
786aa9e746SAyke van Laethem auto &Ctx = BI->getContext();
796aa9e746SAyke van Laethem IRBuilder<> Builder(BI);
80*4e831753SPatryk Wychowaniec Type *InputTy = cast<Instruction>(BI)->getType();
816aa9e746SAyke van Laethem Type *Int8Ty = Type::getInt8Ty(Ctx);
826aa9e746SAyke van Laethem Value *Int8Zero = ConstantInt::get(Int8Ty, 0);
836aa9e746SAyke van Laethem
846aa9e746SAyke van Laethem // Split the current basic block at the point of the existing shift
856aa9e746SAyke van Laethem // instruction and insert a new basic block for the loop.
866aa9e746SAyke van Laethem BasicBlock *BB = BI->getParent();
876aa9e746SAyke van Laethem Function *F = BB->getParent();
886aa9e746SAyke van Laethem BasicBlock *EndBB = BB->splitBasicBlock(BI, "shift.done");
896aa9e746SAyke van Laethem BasicBlock *LoopBB = BasicBlock::Create(Ctx, "shift.loop", F, EndBB);
906aa9e746SAyke van Laethem
916aa9e746SAyke van Laethem // Truncate the shift amount to i8, which is trivially lowered to a single
926aa9e746SAyke van Laethem // AVR register.
936aa9e746SAyke van Laethem Builder.SetInsertPoint(&BB->back());
946aa9e746SAyke van Laethem Value *ShiftAmount = Builder.CreateTrunc(BI->getOperand(1), Int8Ty);
956aa9e746SAyke van Laethem
966aa9e746SAyke van Laethem // Replace the unconditional branch that splitBasicBlock created with a
976aa9e746SAyke van Laethem // conditional branch.
986aa9e746SAyke van Laethem Value *Cmp1 = Builder.CreateICmpEQ(ShiftAmount, Int8Zero);
996aa9e746SAyke van Laethem Builder.CreateCondBr(Cmp1, EndBB, LoopBB);
1006aa9e746SAyke van Laethem BB->back().eraseFromParent();
1016aa9e746SAyke van Laethem
1026aa9e746SAyke van Laethem // Create the loop body starting with PHI nodes.
1036aa9e746SAyke van Laethem Builder.SetInsertPoint(LoopBB);
1046aa9e746SAyke van Laethem PHINode *ShiftAmountPHI = Builder.CreatePHI(Int8Ty, 2);
1056aa9e746SAyke van Laethem ShiftAmountPHI->addIncoming(ShiftAmount, BB);
106*4e831753SPatryk Wychowaniec PHINode *ValuePHI = Builder.CreatePHI(InputTy, 2);
1076aa9e746SAyke van Laethem ValuePHI->addIncoming(BI->getOperand(0), BB);
1086aa9e746SAyke van Laethem
1096aa9e746SAyke van Laethem // Subtract the shift amount by one, as we're shifting one this loop
1106aa9e746SAyke van Laethem // iteration.
1116aa9e746SAyke van Laethem Value *ShiftAmountSub =
1126aa9e746SAyke van Laethem Builder.CreateSub(ShiftAmountPHI, ConstantInt::get(Int8Ty, 1));
1136aa9e746SAyke van Laethem ShiftAmountPHI->addIncoming(ShiftAmountSub, LoopBB);
1146aa9e746SAyke van Laethem
1156aa9e746SAyke van Laethem // Emit the actual shift instruction. The difference is that this shift
1166aa9e746SAyke van Laethem // instruction has a constant shift amount, which can be emitted inline
1176aa9e746SAyke van Laethem // without a library call.
1186aa9e746SAyke van Laethem Value *ValueShifted;
1196aa9e746SAyke van Laethem switch (BI->getOpcode()) {
1206aa9e746SAyke van Laethem case Instruction::Shl:
121*4e831753SPatryk Wychowaniec ValueShifted = Builder.CreateShl(ValuePHI, ConstantInt::get(InputTy, 1));
1226aa9e746SAyke van Laethem break;
1236aa9e746SAyke van Laethem case Instruction::LShr:
124*4e831753SPatryk Wychowaniec ValueShifted = Builder.CreateLShr(ValuePHI, ConstantInt::get(InputTy, 1));
1256aa9e746SAyke van Laethem break;
1266aa9e746SAyke van Laethem case Instruction::AShr:
127*4e831753SPatryk Wychowaniec ValueShifted = Builder.CreateAShr(ValuePHI, ConstantInt::get(InputTy, 1));
1286aa9e746SAyke van Laethem break;
1296aa9e746SAyke van Laethem default:
1306aa9e746SAyke van Laethem llvm_unreachable("asked to expand an instruction that is not a shift");
1316aa9e746SAyke van Laethem }
1326aa9e746SAyke van Laethem ValuePHI->addIncoming(ValueShifted, LoopBB);
1336aa9e746SAyke van Laethem
1346aa9e746SAyke van Laethem // Branch to either the loop again (if there is more to shift) or to the
1356aa9e746SAyke van Laethem // basic block after the loop (if all bits are shifted).
1366aa9e746SAyke van Laethem Value *Cmp2 = Builder.CreateICmpEQ(ShiftAmountSub, Int8Zero);
1376aa9e746SAyke van Laethem Builder.CreateCondBr(Cmp2, EndBB, LoopBB);
1386aa9e746SAyke van Laethem
1396aa9e746SAyke van Laethem // Collect the resulting value. This is necessary in the IR but won't produce
1406aa9e746SAyke van Laethem // any actual instructions.
1416aa9e746SAyke van Laethem Builder.SetInsertPoint(BI);
142*4e831753SPatryk Wychowaniec PHINode *Result = Builder.CreatePHI(InputTy, 2);
1436aa9e746SAyke van Laethem Result->addIncoming(BI->getOperand(0), BB);
1446aa9e746SAyke van Laethem Result->addIncoming(ValueShifted, LoopBB);
1456aa9e746SAyke van Laethem
1466aa9e746SAyke van Laethem // Replace the original shift instruction.
1476aa9e746SAyke van Laethem BI->replaceAllUsesWith(Result);
1486aa9e746SAyke van Laethem BI->eraseFromParent();
1496aa9e746SAyke van Laethem }
150