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