mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
1bf9d7e37d
This patch makes sure shift instructions such as this one: %result = shl i32 %n, %amount are expanded just before the IR to SelectionDAG conversion to a loop so that calls to non-existing library functions such as __ashlsi3 are avoided. The generated code is currently pretty bad but there's a lot of room for improvement: the shift itself can be done in just four instructions. Differential Revision: https://reviews.llvm.org/D96677
148 lines
5.1 KiB
C++
148 lines
5.1 KiB
C++
//===- AVRShift.cpp - Shift Expansion Pass --------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
/// \file
|
|
/// Expand 32-bit shift instructions (shl, lshr, ashr) to inline loops, just
|
|
/// like avr-gcc. This must be done in IR because otherwise the type legalizer
|
|
/// will turn 32-bit shifts into (non-existing) library calls such as __ashlsi3.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "AVR.h"
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/IR/InstIterator.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
class AVRShiftExpand : public FunctionPass {
|
|
public:
|
|
static char ID;
|
|
|
|
AVRShiftExpand() : FunctionPass(ID) {}
|
|
|
|
bool runOnFunction(Function &F) override;
|
|
|
|
StringRef getPassName() const override { return "AVR Shift Expansion"; }
|
|
|
|
private:
|
|
void expand(BinaryOperator *BI);
|
|
};
|
|
|
|
} // end of anonymous namespace
|
|
|
|
char AVRShiftExpand::ID = 0;
|
|
|
|
INITIALIZE_PASS(AVRShiftExpand, "avr-shift-expand", "AVR Shift Expansion",
|
|
false, false)
|
|
|
|
Pass *llvm::createAVRShiftExpandPass() { return new AVRShiftExpand(); }
|
|
|
|
bool AVRShiftExpand::runOnFunction(Function &F) {
|
|
SmallVector<BinaryOperator *, 1> ShiftInsts;
|
|
auto &Ctx = F.getContext();
|
|
for (Instruction &I : instructions(F)) {
|
|
if (!I.isShift())
|
|
// Only expand shift instructions (shl, lshr, ashr).
|
|
continue;
|
|
if (I.getType() != Type::getInt32Ty(Ctx))
|
|
// Only expand plain i32 types.
|
|
continue;
|
|
if (isa<ConstantInt>(I.getOperand(1)))
|
|
// Only expand when the shift amount is not known.
|
|
// Known shift amounts are (currently) better expanded inline.
|
|
continue;
|
|
ShiftInsts.push_back(cast<BinaryOperator>(&I));
|
|
}
|
|
|
|
// The expanding itself needs to be done separately as expand() will remove
|
|
// these instructions. Removing instructions while iterating over a basic
|
|
// block is not a great idea.
|
|
for (auto *I : ShiftInsts) {
|
|
expand(I);
|
|
}
|
|
|
|
// Return whether this function expanded any shift instructions.
|
|
return ShiftInsts.size() > 0;
|
|
}
|
|
|
|
void AVRShiftExpand::expand(BinaryOperator *BI) {
|
|
auto &Ctx = BI->getContext();
|
|
IRBuilder<> Builder(BI);
|
|
Type *Int32Ty = Type::getInt32Ty(Ctx);
|
|
Type *Int8Ty = Type::getInt8Ty(Ctx);
|
|
Value *Int8Zero = ConstantInt::get(Int8Ty, 0);
|
|
|
|
// Split the current basic block at the point of the existing shift
|
|
// instruction and insert a new basic block for the loop.
|
|
BasicBlock *BB = BI->getParent();
|
|
Function *F = BB->getParent();
|
|
BasicBlock *EndBB = BB->splitBasicBlock(BI, "shift.done");
|
|
BasicBlock *LoopBB = BasicBlock::Create(Ctx, "shift.loop", F, EndBB);
|
|
|
|
// Truncate the shift amount to i8, which is trivially lowered to a single
|
|
// AVR register.
|
|
Builder.SetInsertPoint(&BB->back());
|
|
Value *ShiftAmount = Builder.CreateTrunc(BI->getOperand(1), Int8Ty);
|
|
|
|
// Replace the unconditional branch that splitBasicBlock created with a
|
|
// conditional branch.
|
|
Value *Cmp1 = Builder.CreateICmpEQ(ShiftAmount, Int8Zero);
|
|
Builder.CreateCondBr(Cmp1, EndBB, LoopBB);
|
|
BB->back().eraseFromParent();
|
|
|
|
// Create the loop body starting with PHI nodes.
|
|
Builder.SetInsertPoint(LoopBB);
|
|
PHINode *ShiftAmountPHI = Builder.CreatePHI(Int8Ty, 2);
|
|
ShiftAmountPHI->addIncoming(ShiftAmount, BB);
|
|
PHINode *ValuePHI = Builder.CreatePHI(Int32Ty, 2);
|
|
ValuePHI->addIncoming(BI->getOperand(0), BB);
|
|
|
|
// Subtract the shift amount by one, as we're shifting one this loop
|
|
// iteration.
|
|
Value *ShiftAmountSub =
|
|
Builder.CreateSub(ShiftAmountPHI, ConstantInt::get(Int8Ty, 1));
|
|
ShiftAmountPHI->addIncoming(ShiftAmountSub, LoopBB);
|
|
|
|
// Emit the actual shift instruction. The difference is that this shift
|
|
// instruction has a constant shift amount, which can be emitted inline
|
|
// without a library call.
|
|
Value *ValueShifted;
|
|
switch (BI->getOpcode()) {
|
|
case Instruction::Shl:
|
|
ValueShifted = Builder.CreateShl(ValuePHI, ConstantInt::get(Int32Ty, 1));
|
|
break;
|
|
case Instruction::LShr:
|
|
ValueShifted = Builder.CreateLShr(ValuePHI, ConstantInt::get(Int32Ty, 1));
|
|
break;
|
|
case Instruction::AShr:
|
|
ValueShifted = Builder.CreateAShr(ValuePHI, ConstantInt::get(Int32Ty, 1));
|
|
break;
|
|
default:
|
|
llvm_unreachable("asked to expand an instruction that is not a shift");
|
|
}
|
|
ValuePHI->addIncoming(ValueShifted, LoopBB);
|
|
|
|
// Branch to either the loop again (if there is more to shift) or to the
|
|
// basic block after the loop (if all bits are shifted).
|
|
Value *Cmp2 = Builder.CreateICmpEQ(ShiftAmountSub, Int8Zero);
|
|
Builder.CreateCondBr(Cmp2, EndBB, LoopBB);
|
|
|
|
// Collect the resulting value. This is necessary in the IR but won't produce
|
|
// any actual instructions.
|
|
Builder.SetInsertPoint(BI);
|
|
PHINode *Result = Builder.CreatePHI(Int32Ty, 2);
|
|
Result->addIncoming(BI->getOperand(0), BB);
|
|
Result->addIncoming(ValueShifted, LoopBB);
|
|
|
|
// Replace the original shift instruction.
|
|
BI->replaceAllUsesWith(Result);
|
|
BI->eraseFromParent();
|
|
}
|