HexagonOptimizeSZextends.cpp revision 292941
1//===- HexagonOptimizeSZextends.cpp - Remove unnecessary argument extends -===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Pass that removes sign extends for function parameters. These parameters
11// are already sign extended by the caller per Hexagon's ABI
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/CodeGen/MachineFunctionAnalysis.h"
16#include "llvm/CodeGen/StackProtector.h"
17#include "llvm/IR/Function.h"
18#include "llvm/IR/Instructions.h"
19#include "llvm/IR/IntrinsicInst.h"
20#include "llvm/Pass.h"
21#include "llvm/Transforms/Scalar.h"
22
23#include "Hexagon.h"
24
25using namespace llvm;
26
27namespace llvm {
28  FunctionPass *createHexagonOptimizeSZextends();
29  void initializeHexagonOptimizeSZextendsPass(PassRegistry&);
30}
31
32namespace {
33  struct HexagonOptimizeSZextends : public FunctionPass {
34  public:
35    static char ID;
36    HexagonOptimizeSZextends() : FunctionPass(ID) {
37      initializeHexagonOptimizeSZextendsPass(*PassRegistry::getPassRegistry());
38    }
39    bool runOnFunction(Function &F) override;
40
41    const char *getPassName() const override {
42      return "Remove sign extends";
43    }
44
45    void getAnalysisUsage(AnalysisUsage &AU) const override {
46      AU.addRequired<MachineFunctionAnalysis>();
47      AU.addPreserved<MachineFunctionAnalysis>();
48      AU.addPreserved<StackProtector>();
49      FunctionPass::getAnalysisUsage(AU);
50    }
51
52    bool intrinsicAlreadySextended(Intrinsic::ID IntID);
53  };
54}
55
56char HexagonOptimizeSZextends::ID = 0;
57
58INITIALIZE_PASS(HexagonOptimizeSZextends, "reargs",
59                "Remove Sign and Zero Extends for Args", false, false)
60
61bool HexagonOptimizeSZextends::intrinsicAlreadySextended(Intrinsic::ID IntID) {
62  switch(IntID) {
63    case llvm::Intrinsic::hexagon_A2_addh_l16_sat_ll:
64      return true;
65    default:
66      break;
67  }
68  return false;
69}
70
71bool HexagonOptimizeSZextends::runOnFunction(Function &F) {
72  unsigned Idx = 1;
73  // Try to optimize sign extends in formal parameters. It's relying on
74  // callee already sign extending the values. I'm not sure if our ABI
75  // requires callee to sign extend though.
76  for (auto &Arg : F.args()) {
77    if (F.getAttributes().hasAttribute(Idx, Attribute::SExt)) {
78      if (!isa<PointerType>(Arg.getType())) {
79        for (auto UI = Arg.use_begin(); UI != Arg.use_end();) {
80          if (isa<SExtInst>(*UI)) {
81            Instruction* Use = cast<Instruction>(*UI);
82            SExtInst* SI = new SExtInst(&Arg, Use->getType());
83            assert (EVT::getEVT(SI->getType()) ==
84                    (EVT::getEVT(Use->getType())));
85            ++UI;
86            Use->replaceAllUsesWith(SI);
87            Instruction* First = &F.getEntryBlock().front();
88            SI->insertBefore(First);
89            Use->eraseFromParent();
90          } else {
91            ++UI;
92          }
93        }
94      }
95    }
96    ++Idx;
97  }
98
99  // Try to remove redundant sext operations on Hexagon. The hardware
100  // already sign extends many 16 bit intrinsic operations to 32 bits.
101  // For example:
102  // %34 = tail call i32 @llvm.hexagon.A2.addh.l16.sat.ll(i32 %x, i32 %y)
103  // %sext233 = shl i32 %34, 16
104  // %conv52 = ashr exact i32 %sext233, 16
105  for (auto &B : F) {
106    for (auto &I : B) {
107      // Look for arithmetic shift right by 16.
108      BinaryOperator *Ashr = dyn_cast<BinaryOperator>(&I);
109      if (!(Ashr && Ashr->getOpcode() == Instruction::AShr))
110        continue;
111      Value *AshrOp1 = Ashr->getOperand(1);
112      ConstantInt *C = dyn_cast<ConstantInt>(AshrOp1);
113      // Right shifted by 16.
114      if (!(C && C->getSExtValue() == 16))
115        continue;
116
117      // The first operand of Ashr comes from logical shift left.
118      Instruction *Shl = dyn_cast<Instruction>(Ashr->getOperand(0));
119      if (!(Shl && Shl->getOpcode() == Instruction::Shl))
120        continue;
121      Value *Intr = Shl->getOperand(0);
122      Value *ShlOp1 = Shl->getOperand(1);
123      C = dyn_cast<ConstantInt>(ShlOp1);
124      // Left shifted by 16.
125      if (!(C && C->getSExtValue() == 16))
126        continue;
127
128      // The first operand of Shl comes from an intrinsic.
129      if (IntrinsicInst *I = dyn_cast<IntrinsicInst>(Intr)) {
130        if (!intrinsicAlreadySextended(I->getIntrinsicID()))
131          continue;
132        // All is well. Replace all uses of AShr with I.
133        for (auto UI = Ashr->user_begin(), UE = Ashr->user_end();
134             UI != UE; ++UI) {
135          const Use &TheUse = UI.getUse();
136          if (Instruction *J = dyn_cast<Instruction>(TheUse.getUser())) {
137            J->replaceUsesOfWith(Ashr, I);
138          }
139        }
140      }
141    }
142  }
143
144  return true;
145}
146
147
148FunctionPass *llvm::createHexagonOptimizeSZextends() {
149  return new HexagonOptimizeSZextends();
150}
151