/src/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- WebAssemblyLowerBrUnless.cpp - Lower br_unless --------------------===// |
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 | | /// \file |
10 | | /// This file lowers br_unless into br_if with an inverted condition. |
11 | | /// |
12 | | /// br_unless is not currently in the spec, but it's very convenient for LLVM |
13 | | /// to use. This pass allows LLVM to use it, for now. |
14 | | /// |
15 | | //===----------------------------------------------------------------------===// |
16 | | |
17 | | #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" |
18 | | #include "WebAssembly.h" |
19 | | #include "WebAssemblyMachineFunctionInfo.h" |
20 | | #include "WebAssemblySubtarget.h" |
21 | | #include "llvm/CodeGen/MachineFunctionPass.h" |
22 | | #include "llvm/CodeGen/MachineInstrBuilder.h" |
23 | | #include "llvm/Support/Debug.h" |
24 | | #include "llvm/Support/raw_ostream.h" |
25 | | using namespace llvm; |
26 | | |
27 | | #define DEBUG_TYPE "wasm-lower-br_unless" |
28 | | |
29 | | namespace { |
30 | | class WebAssemblyLowerBrUnless final : public MachineFunctionPass { |
31 | 101 | StringRef getPassName() const override { |
32 | 101 | return "WebAssembly Lower br_unless"; |
33 | 101 | } |
34 | | |
35 | 101 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
36 | 101 | AU.setPreservesCFG(); |
37 | 101 | MachineFunctionPass::getAnalysisUsage(AU); |
38 | 101 | } |
39 | | |
40 | | bool runOnMachineFunction(MachineFunction &MF) override; |
41 | | |
42 | | public: |
43 | | static char ID; // Pass identification, replacement for typeid |
44 | 101 | WebAssemblyLowerBrUnless() : MachineFunctionPass(ID) {} |
45 | | }; |
46 | | } // end anonymous namespace |
47 | | |
48 | | char WebAssemblyLowerBrUnless::ID = 0; |
49 | | INITIALIZE_PASS(WebAssemblyLowerBrUnless, DEBUG_TYPE, |
50 | | "Lowers br_unless into inverted br_if", false, false) |
51 | | |
52 | 101 | FunctionPass *llvm::createWebAssemblyLowerBrUnless() { |
53 | 101 | return new WebAssemblyLowerBrUnless(); |
54 | 101 | } |
55 | | |
56 | 6.72k | bool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) { |
57 | 6.72k | LLVM_DEBUG(dbgs() << "********** Lowering br_unless **********\n" |
58 | 6.72k | "********** Function: " |
59 | 6.72k | << MF.getName() << '\n'); |
60 | | |
61 | 6.72k | auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); |
62 | 6.72k | const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); |
63 | 6.72k | auto &MRI = MF.getRegInfo(); |
64 | | |
65 | 11.5k | for (auto &MBB : MF) { |
66 | 102k | for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) { |
67 | 102k | if (MI.getOpcode() != WebAssembly::BR_UNLESS) |
68 | 101k | continue; |
69 | | |
70 | 195 | Register Cond = MI.getOperand(1).getReg(); |
71 | 195 | bool Inverted = false; |
72 | | |
73 | | // Attempt to invert the condition in place. |
74 | 195 | if (MFI.isVRegStackified(Cond)) { |
75 | 195 | assert(MRI.hasOneDef(Cond)); |
76 | 0 | MachineInstr *Def = MRI.getVRegDef(Cond); |
77 | 195 | switch (Def->getOpcode()) { |
78 | 0 | using namespace WebAssembly; |
79 | 8 | case EQ_I32: |
80 | 8 | Def->setDesc(TII.get(NE_I32)); |
81 | 8 | Inverted = true; |
82 | 8 | break; |
83 | 4 | case NE_I32: |
84 | 4 | Def->setDesc(TII.get(EQ_I32)); |
85 | 4 | Inverted = true; |
86 | 4 | break; |
87 | 11 | case GT_S_I32: |
88 | 11 | Def->setDesc(TII.get(LE_S_I32)); |
89 | 11 | Inverted = true; |
90 | 11 | break; |
91 | 10 | case GE_S_I32: |
92 | 10 | Def->setDesc(TII.get(LT_S_I32)); |
93 | 10 | Inverted = true; |
94 | 10 | break; |
95 | 8 | case LT_S_I32: |
96 | 8 | Def->setDesc(TII.get(GE_S_I32)); |
97 | 8 | Inverted = true; |
98 | 8 | break; |
99 | 5 | case LE_S_I32: |
100 | 5 | Def->setDesc(TII.get(GT_S_I32)); |
101 | 5 | Inverted = true; |
102 | 5 | break; |
103 | 12 | case GT_U_I32: |
104 | 12 | Def->setDesc(TII.get(LE_U_I32)); |
105 | 12 | Inverted = true; |
106 | 12 | break; |
107 | 4 | case GE_U_I32: |
108 | 4 | Def->setDesc(TII.get(LT_U_I32)); |
109 | 4 | Inverted = true; |
110 | 4 | break; |
111 | 14 | case LT_U_I32: |
112 | 14 | Def->setDesc(TII.get(GE_U_I32)); |
113 | 14 | Inverted = true; |
114 | 14 | break; |
115 | 3 | case LE_U_I32: |
116 | 3 | Def->setDesc(TII.get(GT_U_I32)); |
117 | 3 | Inverted = true; |
118 | 3 | break; |
119 | 0 | case EQ_I64: |
120 | 0 | Def->setDesc(TII.get(NE_I64)); |
121 | 0 | Inverted = true; |
122 | 0 | break; |
123 | 0 | case NE_I64: |
124 | 0 | Def->setDesc(TII.get(EQ_I64)); |
125 | 0 | Inverted = true; |
126 | 0 | break; |
127 | 0 | case GT_S_I64: |
128 | 0 | Def->setDesc(TII.get(LE_S_I64)); |
129 | 0 | Inverted = true; |
130 | 0 | break; |
131 | 0 | case GE_S_I64: |
132 | 0 | Def->setDesc(TII.get(LT_S_I64)); |
133 | 0 | Inverted = true; |
134 | 0 | break; |
135 | 0 | case LT_S_I64: |
136 | 0 | Def->setDesc(TII.get(GE_S_I64)); |
137 | 0 | Inverted = true; |
138 | 0 | break; |
139 | 0 | case LE_S_I64: |
140 | 0 | Def->setDesc(TII.get(GT_S_I64)); |
141 | 0 | Inverted = true; |
142 | 0 | break; |
143 | 0 | case GT_U_I64: |
144 | 0 | Def->setDesc(TII.get(LE_U_I64)); |
145 | 0 | Inverted = true; |
146 | 0 | break; |
147 | 0 | case GE_U_I64: |
148 | 0 | Def->setDesc(TII.get(LT_U_I64)); |
149 | 0 | Inverted = true; |
150 | 0 | break; |
151 | 0 | case LT_U_I64: |
152 | 0 | Def->setDesc(TII.get(GE_U_I64)); |
153 | 0 | Inverted = true; |
154 | 0 | break; |
155 | 0 | case LE_U_I64: |
156 | 0 | Def->setDesc(TII.get(GT_U_I64)); |
157 | 0 | Inverted = true; |
158 | 0 | break; |
159 | 0 | case EQ_F32: |
160 | 0 | Def->setDesc(TII.get(NE_F32)); |
161 | 0 | Inverted = true; |
162 | 0 | break; |
163 | 0 | case NE_F32: |
164 | 0 | Def->setDesc(TII.get(EQ_F32)); |
165 | 0 | Inverted = true; |
166 | 0 | break; |
167 | 0 | case EQ_F64: |
168 | 0 | Def->setDesc(TII.get(NE_F64)); |
169 | 0 | Inverted = true; |
170 | 0 | break; |
171 | 0 | case NE_F64: |
172 | 0 | Def->setDesc(TII.get(EQ_F64)); |
173 | 0 | Inverted = true; |
174 | 0 | break; |
175 | 0 | case EQZ_I32: { |
176 | | // Invert an eqz by replacing it with its operand. |
177 | 0 | Cond = Def->getOperand(1).getReg(); |
178 | 0 | Def->eraseFromParent(); |
179 | 0 | Inverted = true; |
180 | 0 | break; |
181 | 0 | } |
182 | 116 | default: |
183 | 116 | break; |
184 | 195 | } |
185 | 195 | } |
186 | | |
187 | | // If we weren't able to invert the condition in place. Insert an |
188 | | // instruction to invert it. |
189 | 195 | if (!Inverted) { |
190 | 116 | Register Tmp = MRI.createVirtualRegister(&WebAssembly::I32RegClass); |
191 | 116 | BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(WebAssembly::EQZ_I32), Tmp) |
192 | 116 | .addReg(Cond); |
193 | 116 | MFI.stackifyVReg(MRI, Tmp); |
194 | 116 | Cond = Tmp; |
195 | 116 | Inverted = true; |
196 | 116 | } |
197 | | |
198 | | // The br_unless condition has now been inverted. Insert a br_if and |
199 | | // delete the br_unless. |
200 | 195 | assert(Inverted); |
201 | 0 | BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(WebAssembly::BR_IF)) |
202 | 195 | .add(MI.getOperand(0)) |
203 | 195 | .addReg(Cond); |
204 | 195 | MBB.erase(&MI); |
205 | 195 | } |
206 | 11.5k | } |
207 | | |
208 | 6.72k | return true; |
209 | 6.72k | } |