blob: 34a8195ac4b4cf8ef4cb39a8ebbff90f839c737c [file] [log] [blame]
Dan Gohmanf0b165a2015-12-05 03:03:35 +00001//===-- WebAssemblyLowerBrUnless.cpp - Lower br_unless --------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Dan Gohmanf0b165a2015-12-05 03:03:35 +00006//
7//===----------------------------------------------------------------------===//
8///
9/// \file
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000010/// This file lowers br_unless into br_if with an inverted condition.
Dan Gohmanf0b165a2015-12-05 03:03:35 +000011///
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
Dan Gohman83947562016-01-20 05:54:22 +000017#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000018#include "WebAssembly.h"
Dan Gohmanf0b165a2015-12-05 03:03:35 +000019#include "WebAssemblyMachineFunctionInfo.h"
20#include "WebAssemblySubtarget.h"
Dan Gohmanf0b165a2015-12-05 03:03:35 +000021#include "llvm/CodeGen/MachineFunctionPass.h"
22#include "llvm/CodeGen/MachineInstrBuilder.h"
23#include "llvm/Support/Debug.h"
24#include "llvm/Support/raw_ostream.h"
25using namespace llvm;
26
27#define DEBUG_TYPE "wasm-lower-br_unless"
28
29namespace {
30class WebAssemblyLowerBrUnless final : public MachineFunctionPass {
Mehdi Amini117296c2016-10-01 02:56:57 +000031 StringRef getPassName() const override {
Dan Gohmanf0b165a2015-12-05 03:03:35 +000032 return "WebAssembly Lower br_unless";
33 }
34
35 void getAnalysisUsage(AnalysisUsage &AU) const override {
36 AU.setPreservesCFG();
37 MachineFunctionPass::getAnalysisUsage(AU);
38 }
39
40 bool runOnMachineFunction(MachineFunction &MF) override;
41
42public:
43 static char ID; // Pass identification, replacement for typeid
44 WebAssemblyLowerBrUnless() : MachineFunctionPass(ID) {}
45};
46} // end anonymous namespace
47
48char WebAssemblyLowerBrUnless::ID = 0;
Jacob Gravelle40926452018-03-30 20:36:58 +000049INITIALIZE_PASS(WebAssemblyLowerBrUnless, DEBUG_TYPE,
50 "Lowers br_unless into inverted br_if", false, false)
51
Dan Gohmanf0b165a2015-12-05 03:03:35 +000052FunctionPass *llvm::createWebAssemblyLowerBrUnless() {
53 return new WebAssemblyLowerBrUnless();
54}
55
56bool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +000057 LLVM_DEBUG(dbgs() << "********** Lowering br_unless **********\n"
58 "********** Function: "
59 << MF.getName() << '\n');
Dan Gohmanf0b165a2015-12-05 03:03:35 +000060
61 auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
62 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
63 auto &MRI = MF.getRegInfo();
64
65 for (auto &MBB : MF) {
Dan Gohman83947562016-01-20 05:54:22 +000066 for (auto MII = MBB.begin(); MII != MBB.end();) {
Dan Gohmanf0b165a2015-12-05 03:03:35 +000067 MachineInstr *MI = &*MII++;
68 if (MI->getOpcode() != WebAssembly::BR_UNLESS)
69 continue;
70
Dan Gohman06b49582016-02-08 21:50:13 +000071 unsigned Cond = MI->getOperand(1).getReg();
Dan Gohmanf0b165a2015-12-05 03:03:35 +000072 bool Inverted = false;
73
74 // Attempt to invert the condition in place.
75 if (MFI.isVRegStackified(Cond)) {
76 assert(MRI.hasOneDef(Cond));
77 MachineInstr *Def = MRI.getVRegDef(Cond);
78 switch (Def->getOpcode()) {
Dan Gohman83947562016-01-20 05:54:22 +000079 using namespace WebAssembly;
Heejin Ahnf208f632018-09-05 01:27:38 +000080 case EQ_I32:
81 Def->setDesc(TII.get(NE_I32));
82 Inverted = true;
83 break;
84 case NE_I32:
85 Def->setDesc(TII.get(EQ_I32));
86 Inverted = true;
87 break;
88 case GT_S_I32:
89 Def->setDesc(TII.get(LE_S_I32));
90 Inverted = true;
91 break;
92 case GE_S_I32:
93 Def->setDesc(TII.get(LT_S_I32));
94 Inverted = true;
95 break;
96 case LT_S_I32:
97 Def->setDesc(TII.get(GE_S_I32));
98 Inverted = true;
99 break;
100 case LE_S_I32:
101 Def->setDesc(TII.get(GT_S_I32));
102 Inverted = true;
103 break;
104 case GT_U_I32:
105 Def->setDesc(TII.get(LE_U_I32));
106 Inverted = true;
107 break;
108 case GE_U_I32:
109 Def->setDesc(TII.get(LT_U_I32));
110 Inverted = true;
111 break;
112 case LT_U_I32:
113 Def->setDesc(TII.get(GE_U_I32));
114 Inverted = true;
115 break;
116 case LE_U_I32:
117 Def->setDesc(TII.get(GT_U_I32));
118 Inverted = true;
119 break;
120 case EQ_I64:
121 Def->setDesc(TII.get(NE_I64));
122 Inverted = true;
123 break;
124 case NE_I64:
125 Def->setDesc(TII.get(EQ_I64));
126 Inverted = true;
127 break;
128 case GT_S_I64:
129 Def->setDesc(TII.get(LE_S_I64));
130 Inverted = true;
131 break;
132 case GE_S_I64:
133 Def->setDesc(TII.get(LT_S_I64));
134 Inverted = true;
135 break;
136 case LT_S_I64:
137 Def->setDesc(TII.get(GE_S_I64));
138 Inverted = true;
139 break;
140 case LE_S_I64:
141 Def->setDesc(TII.get(GT_S_I64));
142 Inverted = true;
143 break;
144 case GT_U_I64:
145 Def->setDesc(TII.get(LE_U_I64));
146 Inverted = true;
147 break;
148 case GE_U_I64:
149 Def->setDesc(TII.get(LT_U_I64));
150 Inverted = true;
151 break;
152 case LT_U_I64:
153 Def->setDesc(TII.get(GE_U_I64));
154 Inverted = true;
155 break;
156 case LE_U_I64:
157 Def->setDesc(TII.get(GT_U_I64));
158 Inverted = true;
159 break;
160 case EQ_F32:
161 Def->setDesc(TII.get(NE_F32));
162 Inverted = true;
163 break;
164 case NE_F32:
165 Def->setDesc(TII.get(EQ_F32));
166 Inverted = true;
167 break;
168 case EQ_F64:
169 Def->setDesc(TII.get(NE_F64));
170 Inverted = true;
171 break;
172 case NE_F64:
173 Def->setDesc(TII.get(EQ_F64));
174 Inverted = true;
175 break;
Dan Gohman580c1022017-11-29 20:20:11 +0000176 case EQZ_I32: {
177 // Invert an eqz by replacing it with its operand.
178 Cond = Def->getOperand(1).getReg();
179 Def->eraseFromParent();
180 Inverted = true;
181 break;
182 }
Heejin Ahnf208f632018-09-05 01:27:38 +0000183 default:
184 break;
Dan Gohmanf0b165a2015-12-05 03:03:35 +0000185 }
186 }
187
188 // If we weren't able to invert the condition in place. Insert an
Dan Gohmane0405332016-10-03 22:43:53 +0000189 // instruction to invert it.
Dan Gohmanf0b165a2015-12-05 03:03:35 +0000190 if (!Inverted) {
Dan Gohmanf0b165a2015-12-05 03:03:35 +0000191 unsigned Tmp = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
Dan Gohman804749c2016-05-16 18:59:34 +0000192 BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::EQZ_I32), Tmp)
193 .addReg(Cond);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000194 MFI.stackifyVReg(Tmp);
Dan Gohmanf0b165a2015-12-05 03:03:35 +0000195 Cond = Tmp;
196 Inverted = true;
197 }
198
199 // The br_unless condition has now been inverted. Insert a br_if and
200 // delete the br_unless.
201 assert(Inverted);
202 BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::BR_IF))
Diana Picus116bbab2017-01-13 09:58:52 +0000203 .add(MI->getOperand(0))
Dan Gohman06b49582016-02-08 21:50:13 +0000204 .addReg(Cond);
Dan Gohmanf0b165a2015-12-05 03:03:35 +0000205 MBB.erase(MI);
206 }
207 }
208
209 return true;
210}