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