xref: /llvm-project/llvm/lib/Target/AVR/AVRShiftExpand.cpp (revision 4e831753b9cf8745e9bf251f775f2399c9ef4138)
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