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 { |
27 | struct HexagonOptimizeSZextends : public FunctionPass { |
28 | public: |
29 | static char ID; |
30 | HexagonOptimizeSZextends() : FunctionPass(ID) {} |
31 | bool runOnFunction(Function &F) override; |
32 | |
33 | StringRef getPassName() const override { return "Remove sign extends" ; } |
34 | |
35 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
36 | AU.addPreserved<StackProtector>(); |
37 | FunctionPass::getAnalysisUsage(AU); |
38 | } |
39 | |
40 | bool intrinsicAlreadySextended(Intrinsic::ID IntID); |
41 | }; |
42 | } |
43 | |
44 | char HexagonOptimizeSZextends::ID = 0; |
45 | |
46 | INITIALIZE_PASS(HexagonOptimizeSZextends, "reargs" , |
47 | "Remove Sign and Zero Extends for Args" , false, false) |
48 | |
49 | bool HexagonOptimizeSZextends::intrinsicAlreadySextended(Intrinsic::ID IntID) { |
50 | switch(IntID) { |
51 | case llvm::Intrinsic::hexagon_A2_addh_l16_sat_ll: |
52 | return true; |
53 | default: |
54 | break; |
55 | } |
56 | return false; |
57 | } |
58 | |
59 | bool HexagonOptimizeSZextends::runOnFunction(Function &F) { |
60 | if (skipFunction(F)) |
61 | return false; |
62 | |
63 | unsigned Idx = 0; |
64 | // Try to optimize sign extends in formal parameters. It's relying on |
65 | // callee already sign extending the values. I'm not sure if our ABI |
66 | // requires callee to sign extend though. |
67 | for (auto &Arg : F.args()) { |
68 | if (F.getAttributes().hasParamAttr(ArgNo: Idx, Kind: Attribute::SExt)) { |
69 | if (!isa<PointerType>(Val: Arg.getType())) { |
70 | for (Use &U : llvm::make_early_inc_range(Range: Arg.uses())) { |
71 | if (isa<SExtInst>(Val: U)) { |
72 | Instruction* Use = cast<Instruction>(Val&: U); |
73 | SExtInst* SI = new SExtInst(&Arg, Use->getType()); |
74 | assert (EVT::getEVT(SI->getType()) == |
75 | (EVT::getEVT(Use->getType()))); |
76 | Use->replaceAllUsesWith(V: SI); |
77 | BasicBlock::iterator First = F.getEntryBlock().begin(); |
78 | SI->insertBefore(InsertPos: First); |
79 | Use->eraseFromParent(); |
80 | } |
81 | } |
82 | } |
83 | } |
84 | ++Idx; |
85 | } |
86 | |
87 | // Try to remove redundant sext operations on Hexagon. The hardware |
88 | // already sign extends many 16 bit intrinsic operations to 32 bits. |
89 | // For example: |
90 | // %34 = tail call i32 @llvm.hexagon.A2.addh.l16.sat.ll(i32 %x, i32 %y) |
91 | // %sext233 = shl i32 %34, 16 |
92 | // %conv52 = ashr exact i32 %sext233, 16 |
93 | for (auto &B : F) { |
94 | for (auto &I : B) { |
95 | // Look for arithmetic shift right by 16. |
96 | BinaryOperator *Ashr = dyn_cast<BinaryOperator>(Val: &I); |
97 | if (!(Ashr && Ashr->getOpcode() == Instruction::AShr)) |
98 | continue; |
99 | Value *AshrOp1 = Ashr->getOperand(i_nocapture: 1); |
100 | ConstantInt *C = dyn_cast<ConstantInt>(Val: AshrOp1); |
101 | // Right shifted by 16. |
102 | if (!(C && C->getSExtValue() == 16)) |
103 | continue; |
104 | |
105 | // The first operand of Ashr comes from logical shift left. |
106 | Instruction *Shl = dyn_cast<Instruction>(Val: Ashr->getOperand(i_nocapture: 0)); |
107 | if (!(Shl && Shl->getOpcode() == Instruction::Shl)) |
108 | continue; |
109 | Value *Intr = Shl->getOperand(i: 0); |
110 | Value *ShlOp1 = Shl->getOperand(i: 1); |
111 | C = dyn_cast<ConstantInt>(Val: ShlOp1); |
112 | // Left shifted by 16. |
113 | if (!(C && C->getSExtValue() == 16)) |
114 | continue; |
115 | |
116 | // The first operand of Shl comes from an intrinsic. |
117 | if (IntrinsicInst *I = dyn_cast<IntrinsicInst>(Val: Intr)) { |
118 | if (!intrinsicAlreadySextended(IntID: I->getIntrinsicID())) |
119 | continue; |
120 | // All is well. Replace all uses of AShr with I. |
121 | for (auto UI = Ashr->user_begin(), UE = Ashr->user_end(); |
122 | UI != UE; ++UI) { |
123 | const Use &TheUse = UI.getUse(); |
124 | if (Instruction *J = dyn_cast<Instruction>(Val: TheUse.getUser())) { |
125 | J->replaceUsesOfWith(From: Ashr, To: I); |
126 | } |
127 | } |
128 | } |
129 | } |
130 | } |
131 | |
132 | return true; |
133 | } |
134 | |
135 | |
136 | FunctionPass *llvm::createHexagonOptimizeSZextends() { |
137 | return new HexagonOptimizeSZextends(); |
138 | } |
139 | |