forked from OSchip/llvm-project
149 lines
4.7 KiB
C++
149 lines
4.7 KiB
C++
//===- HexagonOptimizeSZextends.cpp - Remove unnecessary argument extends -===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Pass that removes sign extends for function parameters. These parameters
|
|
// are already sign extended by the caller per Hexagon's ABI
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/CodeGen/StackProtector.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
#include "llvm/IR/IntrinsicsHexagon.h"
|
|
#include "llvm/Pass.h"
|
|
#include "llvm/Transforms/Scalar.h"
|
|
|
|
#include "Hexagon.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace llvm {
|
|
FunctionPass *createHexagonOptimizeSZextends();
|
|
void initializeHexagonOptimizeSZextendsPass(PassRegistry&);
|
|
}
|
|
|
|
namespace {
|
|
struct HexagonOptimizeSZextends : public FunctionPass {
|
|
public:
|
|
static char ID;
|
|
HexagonOptimizeSZextends() : FunctionPass(ID) {
|
|
initializeHexagonOptimizeSZextendsPass(*PassRegistry::getPassRegistry());
|
|
}
|
|
bool runOnFunction(Function &F) override;
|
|
|
|
StringRef getPassName() const override { return "Remove sign extends"; }
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.addPreserved<StackProtector>();
|
|
FunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
|
|
bool intrinsicAlreadySextended(Intrinsic::ID IntID);
|
|
};
|
|
}
|
|
|
|
char HexagonOptimizeSZextends::ID = 0;
|
|
|
|
INITIALIZE_PASS(HexagonOptimizeSZextends, "reargs",
|
|
"Remove Sign and Zero Extends for Args", false, false)
|
|
|
|
bool HexagonOptimizeSZextends::intrinsicAlreadySextended(Intrinsic::ID IntID) {
|
|
switch(IntID) {
|
|
case llvm::Intrinsic::hexagon_A2_addh_l16_sat_ll:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool HexagonOptimizeSZextends::runOnFunction(Function &F) {
|
|
if (skipFunction(F))
|
|
return false;
|
|
|
|
unsigned Idx = 1;
|
|
// Try to optimize sign extends in formal parameters. It's relying on
|
|
// callee already sign extending the values. I'm not sure if our ABI
|
|
// requires callee to sign extend though.
|
|
for (auto &Arg : F.args()) {
|
|
if (F.getAttributes().hasAttribute(Idx, Attribute::SExt)) {
|
|
if (!isa<PointerType>(Arg.getType())) {
|
|
for (auto UI = Arg.use_begin(); UI != Arg.use_end();) {
|
|
if (isa<SExtInst>(*UI)) {
|
|
Instruction* Use = cast<Instruction>(*UI);
|
|
SExtInst* SI = new SExtInst(&Arg, Use->getType());
|
|
assert (EVT::getEVT(SI->getType()) ==
|
|
(EVT::getEVT(Use->getType())));
|
|
++UI;
|
|
Use->replaceAllUsesWith(SI);
|
|
Instruction* First = &F.getEntryBlock().front();
|
|
SI->insertBefore(First);
|
|
Use->eraseFromParent();
|
|
} else {
|
|
++UI;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
++Idx;
|
|
}
|
|
|
|
// Try to remove redundant sext operations on Hexagon. The hardware
|
|
// already sign extends many 16 bit intrinsic operations to 32 bits.
|
|
// For example:
|
|
// %34 = tail call i32 @llvm.hexagon.A2.addh.l16.sat.ll(i32 %x, i32 %y)
|
|
// %sext233 = shl i32 %34, 16
|
|
// %conv52 = ashr exact i32 %sext233, 16
|
|
for (auto &B : F) {
|
|
for (auto &I : B) {
|
|
// Look for arithmetic shift right by 16.
|
|
BinaryOperator *Ashr = dyn_cast<BinaryOperator>(&I);
|
|
if (!(Ashr && Ashr->getOpcode() == Instruction::AShr))
|
|
continue;
|
|
Value *AshrOp1 = Ashr->getOperand(1);
|
|
ConstantInt *C = dyn_cast<ConstantInt>(AshrOp1);
|
|
// Right shifted by 16.
|
|
if (!(C && C->getSExtValue() == 16))
|
|
continue;
|
|
|
|
// The first operand of Ashr comes from logical shift left.
|
|
Instruction *Shl = dyn_cast<Instruction>(Ashr->getOperand(0));
|
|
if (!(Shl && Shl->getOpcode() == Instruction::Shl))
|
|
continue;
|
|
Value *Intr = Shl->getOperand(0);
|
|
Value *ShlOp1 = Shl->getOperand(1);
|
|
C = dyn_cast<ConstantInt>(ShlOp1);
|
|
// Left shifted by 16.
|
|
if (!(C && C->getSExtValue() == 16))
|
|
continue;
|
|
|
|
// The first operand of Shl comes from an intrinsic.
|
|
if (IntrinsicInst *I = dyn_cast<IntrinsicInst>(Intr)) {
|
|
if (!intrinsicAlreadySextended(I->getIntrinsicID()))
|
|
continue;
|
|
// All is well. Replace all uses of AShr with I.
|
|
for (auto UI = Ashr->user_begin(), UE = Ashr->user_end();
|
|
UI != UE; ++UI) {
|
|
const Use &TheUse = UI.getUse();
|
|
if (Instruction *J = dyn_cast<Instruction>(TheUse.getUser())) {
|
|
J->replaceUsesOfWith(Ashr, I);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
FunctionPass *llvm::createHexagonOptimizeSZextends() {
|
|
return new HexagonOptimizeSZextends();
|
|
}
|