Path: blob/main/contrib/llvm-project/llvm/lib/Target/AVR/AVRShiftExpand.cpp
35266 views
//===- AVRShift.cpp - Shift Expansion Pass --------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8/// \file9/// Expand non-8-bit and non-16-bit shift instructions (shl, lshr, ashr) to10/// inline loops, just like avr-gcc. This must be done in IR because otherwise11/// the type legalizer will turn 32-bit shifts into (non-existing) library calls12/// such as __ashlsi3.13//14//===----------------------------------------------------------------------===//1516#include "AVR.h"17#include "llvm/IR/IRBuilder.h"18#include "llvm/IR/InstIterator.h"1920using namespace llvm;2122namespace {2324class AVRShiftExpand : public FunctionPass {25public:26static char ID;2728AVRShiftExpand() : FunctionPass(ID) {}2930bool runOnFunction(Function &F) override;3132StringRef getPassName() const override { return "AVR Shift Expansion"; }3334private:35void expand(BinaryOperator *BI);36};3738} // end of anonymous namespace3940char AVRShiftExpand::ID = 0;4142INITIALIZE_PASS(AVRShiftExpand, "avr-shift-expand", "AVR Shift Expansion",43false, false)4445Pass *llvm::createAVRShiftExpandPass() { return new AVRShiftExpand(); }4647bool AVRShiftExpand::runOnFunction(Function &F) {48SmallVector<BinaryOperator *, 1> ShiftInsts;49auto &Ctx = F.getContext();50for (Instruction &I : instructions(F)) {51if (!I.isShift())52// Only expand shift instructions (shl, lshr, ashr).53continue;54if (I.getType() == Type::getInt8Ty(Ctx) || I.getType() == Type::getInt16Ty(Ctx))55// Only expand non-8-bit and non-16-bit shifts, since those are expanded56// directly during isel.57continue;58if (isa<ConstantInt>(I.getOperand(1)))59// Only expand when the shift amount is not known.60// Known shift amounts are (currently) better expanded inline.61continue;62ShiftInsts.push_back(cast<BinaryOperator>(&I));63}6465// The expanding itself needs to be done separately as expand() will remove66// these instructions. Removing instructions while iterating over a basic67// block is not a great idea.68for (auto *I : ShiftInsts) {69expand(I);70}7172// Return whether this function expanded any shift instructions.73return ShiftInsts.size() > 0;74}7576void AVRShiftExpand::expand(BinaryOperator *BI) {77auto &Ctx = BI->getContext();78IRBuilder<> Builder(BI);79Type *InputTy = cast<Instruction>(BI)->getType();80Type *Int8Ty = Type::getInt8Ty(Ctx);81Value *Int8Zero = ConstantInt::get(Int8Ty, 0);8283// Split the current basic block at the point of the existing shift84// instruction and insert a new basic block for the loop.85BasicBlock *BB = BI->getParent();86Function *F = BB->getParent();87BasicBlock *EndBB = BB->splitBasicBlock(BI, "shift.done");88BasicBlock *LoopBB = BasicBlock::Create(Ctx, "shift.loop", F, EndBB);8990// Truncate the shift amount to i8, which is trivially lowered to a single91// AVR register.92Builder.SetInsertPoint(&BB->back());93Value *ShiftAmount = Builder.CreateTrunc(BI->getOperand(1), Int8Ty);9495// Replace the unconditional branch that splitBasicBlock created with a96// conditional branch.97Value *Cmp1 = Builder.CreateICmpEQ(ShiftAmount, Int8Zero);98Builder.CreateCondBr(Cmp1, EndBB, LoopBB);99BB->back().eraseFromParent();100101// Create the loop body starting with PHI nodes.102Builder.SetInsertPoint(LoopBB);103PHINode *ShiftAmountPHI = Builder.CreatePHI(Int8Ty, 2);104ShiftAmountPHI->addIncoming(ShiftAmount, BB);105PHINode *ValuePHI = Builder.CreatePHI(InputTy, 2);106ValuePHI->addIncoming(BI->getOperand(0), BB);107108// Subtract the shift amount by one, as we're shifting one this loop109// iteration.110Value *ShiftAmountSub =111Builder.CreateSub(ShiftAmountPHI, ConstantInt::get(Int8Ty, 1));112ShiftAmountPHI->addIncoming(ShiftAmountSub, LoopBB);113114// Emit the actual shift instruction. The difference is that this shift115// instruction has a constant shift amount, which can be emitted inline116// without a library call.117Value *ValueShifted;118switch (BI->getOpcode()) {119case Instruction::Shl:120ValueShifted = Builder.CreateShl(ValuePHI, ConstantInt::get(InputTy, 1));121break;122case Instruction::LShr:123ValueShifted = Builder.CreateLShr(ValuePHI, ConstantInt::get(InputTy, 1));124break;125case Instruction::AShr:126ValueShifted = Builder.CreateAShr(ValuePHI, ConstantInt::get(InputTy, 1));127break;128default:129llvm_unreachable("asked to expand an instruction that is not a shift");130}131ValuePHI->addIncoming(ValueShifted, LoopBB);132133// Branch to either the loop again (if there is more to shift) or to the134// basic block after the loop (if all bits are shifted).135Value *Cmp2 = Builder.CreateICmpEQ(ShiftAmountSub, Int8Zero);136Builder.CreateCondBr(Cmp2, EndBB, LoopBB);137138// Collect the resulting value. This is necessary in the IR but won't produce139// any actual instructions.140Builder.SetInsertPoint(BI);141PHINode *Result = Builder.CreatePHI(InputTy, 2);142Result->addIncoming(BI->getOperand(0), BB);143Result->addIncoming(ValueShifted, LoopBB);144145// Replace the original shift instruction.146BI->replaceAllUsesWith(Result);147BI->eraseFromParent();148}149150151