1 //=== WebAssemblyExceptionInfoTest.cpp - WebAssemblyExceptionInfo unit tests =//
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 #include "WebAssemblyExceptionInfo.h"
10 #include "llvm/CodeGen/MIRParser/MIRParser.h"
11 #include "llvm/CodeGen/MachineDominanceFrontier.h"
12 #include "llvm/CodeGen/MachineDominators.h"
13 #include "llvm/CodeGen/MachineModuleInfo.h"
14 #include "llvm/Support/SourceMgr.h"
15 #include "llvm/Support/TargetRegistry.h"
16 #include "llvm/Support/TargetSelect.h"
17 #include "llvm/Target/TargetMachine.h"
18 #include "gtest/gtest.h"
19 
20 using namespace llvm;
21 
22 namespace {
23 
createTargetMachine()24 std::unique_ptr<LLVMTargetMachine> createTargetMachine() {
25   auto TT(Triple::normalize("wasm32-unknown-unknown"));
26   std::string CPU("");
27   std::string FS("");
28 
29   LLVMInitializeWebAssemblyTargetInfo();
30   LLVMInitializeWebAssemblyTarget();
31   LLVMInitializeWebAssemblyTargetMC();
32 
33   std::string Error;
34   const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
35   assert(TheTarget);
36 
37   return std::unique_ptr<LLVMTargetMachine>(static_cast<LLVMTargetMachine*>(
38       TheTarget->createTargetMachine(TT, CPU, FS, TargetOptions(), None, None,
39                                      CodeGenOpt::Default)));
40 }
41 
parseMIR(LLVMContext & Context,std::unique_ptr<MIRParser> & MIR,const TargetMachine & TM,StringRef MIRCode,const char * FuncName,MachineModuleInfo & MMI)42 std::unique_ptr<Module> parseMIR(LLVMContext &Context,
43                                  std::unique_ptr<MIRParser> &MIR,
44                                  const TargetMachine &TM, StringRef MIRCode,
45                                  const char *FuncName, MachineModuleInfo &MMI) {
46   SMDiagnostic Diagnostic;
47   std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
48   MIR = createMIRParser(std::move(MBuffer), Context);
49   if (!MIR)
50     return nullptr;
51 
52   std::unique_ptr<Module> M = MIR->parseIRModule();
53   if (!M)
54     return nullptr;
55 
56   M->setDataLayout(TM.createDataLayout());
57 
58   if (MIR->parseMachineFunctions(*M, MMI))
59     return nullptr;
60 
61   return M;
62 }
63 
64 } // namespace
65 
TEST(WebAssemblyExceptionInfoTest,TEST0)66 TEST(WebAssemblyExceptionInfoTest, TEST0) {
67   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
68   ASSERT_TRUE(TM);
69 
70   StringRef MIRString = R"MIR(
71 --- |
72   target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
73   target triple = "wasm32-unknown-unknown"
74 
75   declare i32 @__gxx_wasm_personality_v0(...)
76 
77   define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
78     unreachable
79   }
80 
81 ...
82 ---
83 name: test0
84 liveins:
85   - { reg: '$arguments' }
86   - { reg: '$value_stack' }
87 body: |
88   bb.0:
89     successors: %bb.1, %bb.2
90     liveins: $arguments, $value_stack
91     BR %bb.1, implicit-def dead $arguments
92 
93   bb.1:
94   ; predecessors: %bb.0
95     successors: %bb.7
96     liveins: $value_stack
97     BR %bb.7, implicit-def $arguments
98 
99   bb.2 (landing-pad):
100   ; predecessors: %bb.0
101     successors: %bb.3, %bb.9
102     liveins: $value_stack
103     %0:exnref = CATCH implicit-def $arguments
104     CLEANUPRET implicit-def dead $arguments
105 
106   bb.3 (landing-pad):
107   ; predecessors: %bb.2
108     successors: %bb.4, %bb.6
109     liveins: $value_stack
110     %1:exnref = CATCH implicit-def $arguments
111     BR_IF %bb.4, %58:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
112     BR %bb.6, implicit-def $arguments
113 
114   bb.4:
115   ; predecessors: %bb.3
116     successors: %bb.5, %bb.8
117     liveins: $value_stack
118     BR %bb.5, implicit-def dead $arguments
119 
120   bb.5:
121   ; predecessors: %bb.4
122     successors: %bb.7
123     liveins: $value_stack
124     CATCHRET %bb.7, %bb.0, implicit-def dead $arguments
125 
126   bb.6:
127   ; predecessors: %bb.3
128     successors: %bb.10, %bb.9
129     liveins: $value_stack
130     BR %bb.10, implicit-def dead $arguments
131 
132   bb.7:
133   ; predecessors: %bb.5, %bb.1
134     liveins: $value_stack
135     RETURN implicit-def $arguments
136 
137   bb.8 (landing-pad):
138   ; predecessors: %bb.4
139     successors: %bb.9
140     liveins: $value_stack
141     %2:exnref = CATCH implicit-def $arguments
142     CLEANUPRET implicit-def dead $arguments
143 
144   bb.9 (landing-pad):
145   ; predecessors: %bb.2, %bb.6, %bb.8
146     liveins: $value_stack
147     %3:exnref = CATCH implicit-def $arguments
148     CLEANUPRET implicit-def dead $arguments
149 
150   bb.10:
151   ; predecessors: %bb.6
152     liveins: $value_stack
153     UNREACHABLE implicit-def $arguments
154 )MIR";
155 
156   LLVMContext Context;
157   std::unique_ptr<MIRParser> MIR;
158   MachineModuleInfo MMI(TM.get());
159   std::unique_ptr<Module> M =
160       parseMIR(Context, MIR, *TM, MIRString, "test0", MMI);
161   ASSERT_TRUE(M);
162 
163   Function *F = M->getFunction("test0");
164   auto *MF = MMI.getMachineFunction(*F);
165   ASSERT_TRUE(MF);
166 
167   WebAssemblyExceptionInfo WEI;
168   MachineDominatorTree MDT;
169   MachineDominanceFrontier MDF;
170   MDT.runOnMachineFunction(*MF);
171   MDF.getBase().analyze(MDT.getBase());
172   WEI.recalculate(MDT, MDF);
173 
174   // Exception info structure:
175   // |- bb2 (ehpad), bb3, bb4, bb5, bb6, bb8, bb9, bb10
176   //   |- bb3 (ehpad), bb4, bb5, bb6, bb8, bb10
177   //     |- bb8 (ehpad)
178   //   |- bb9 (ehpad)
179 
180   auto *MBB2 = MF->getBlockNumbered(2);
181   auto *WE0 = WEI.getExceptionFor(MBB2);
182   ASSERT_TRUE(WE0);
183   EXPECT_EQ(WE0->getEHPad(), MBB2);
184   EXPECT_EQ(WE0->getParentException(), nullptr);
185   EXPECT_EQ(WE0->getExceptionDepth(), (unsigned)1);
186 
187   auto *MBB3 = MF->getBlockNumbered(3);
188   auto *WE0_0 = WEI.getExceptionFor(MBB3);
189   ASSERT_TRUE(WE0_0);
190   EXPECT_EQ(WE0_0->getEHPad(), MBB3);
191   EXPECT_EQ(WE0_0->getParentException(), WE0);
192   EXPECT_EQ(WE0_0->getExceptionDepth(), (unsigned)2);
193 
194   auto *MBB4 = MF->getBlockNumbered(4);
195   WE0_0 = WEI.getExceptionFor(MBB4);
196   ASSERT_TRUE(WE0_0);
197   EXPECT_EQ(WE0_0->getEHPad(), MBB3);
198 
199   auto *MBB5 = MF->getBlockNumbered(5);
200   WE0_0 = WEI.getExceptionFor(MBB5);
201   ASSERT_TRUE(WE0_0);
202   EXPECT_EQ(WE0_0->getEHPad(), MBB3);
203 
204   auto *MBB6 = MF->getBlockNumbered(6);
205   WE0_0 = WEI.getExceptionFor(MBB6);
206   ASSERT_TRUE(WE0_0);
207   EXPECT_EQ(WE0_0->getEHPad(), MBB3);
208 
209   auto *MBB10 = MF->getBlockNumbered(10);
210   WE0_0 = WEI.getExceptionFor(MBB10);
211   ASSERT_TRUE(WE0_0);
212   EXPECT_EQ(WE0_0->getEHPad(), MBB3);
213 
214   auto *MBB8 = MF->getBlockNumbered(8);
215   auto *WE0_0_0 = WEI.getExceptionFor(MBB8);
216   ASSERT_TRUE(WE0_0_0);
217   EXPECT_EQ(WE0_0_0->getEHPad(), MBB8);
218   EXPECT_EQ(WE0_0_0->getParentException(), WE0_0);
219   EXPECT_EQ(WE0_0_0->getExceptionDepth(), (unsigned)3);
220 
221   auto *MBB9 = MF->getBlockNumbered(9);
222   auto *WE0_1 = WEI.getExceptionFor(MBB9);
223   ASSERT_TRUE(WE0_1);
224   EXPECT_EQ(WE0_1->getEHPad(), MBB9);
225   EXPECT_EQ(WE0_1->getParentException(), WE0);
226   EXPECT_EQ(WE0_1->getExceptionDepth(), (unsigned)2);
227 }
228 
TEST(WebAssemblyExceptionInfoTest,TEST1)229 TEST(WebAssemblyExceptionInfoTest, TEST1) {
230   std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
231   ASSERT_TRUE(TM);
232 
233   StringRef MIRString = R"MIR(
234 --- |
235   target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
236   target triple = "wasm32-unknown-unknown"
237 
238   declare i32 @__gxx_wasm_personality_v0(...)
239 
240   define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
241     unreachable
242   }
243 
244 ...
245 ---
246 name: test1
247 liveins:
248   - { reg: '$arguments' }
249   - { reg: '$value_stack' }
250 body: |
251   bb.0:
252     successors: %bb.9, %bb.1
253     liveins: $arguments, $value_stack
254     BR %bb.9, implicit-def dead $arguments
255 
256   bb.1 (landing-pad):
257   ; predecessors: %bb.0
258     successors: %bb.2, %bb.8
259     liveins: $value_stack
260     %0:exnref = CATCH implicit-def $arguments
261     BR_IF %bb.2, %32:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
262     BR %bb.8, implicit-def $arguments
263 
264   bb.2:
265   ; predecessors: %bb.1
266     successors: %bb.7, %bb.3, %bb.11
267     liveins: $value_stack
268     BR %bb.7, implicit-def dead $arguments
269 
270   bb.3 (landing-pad):
271   ; predecessors: %bb.2
272     successors: %bb.4, %bb.6
273     liveins: $value_stack
274     %1:exnref = CATCH implicit-def $arguments
275     BR_IF %bb.4, %43:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
276     BR %bb.6, implicit-def $arguments
277 
278   bb.4:
279   ; predecessors: %bb.3
280     successors: %bb.5, %bb.10
281     liveins: $value_stack
282     BR %bb.5, implicit-def dead $arguments
283 
284   bb.5:
285   ; predecessors: %bb.4
286     successors: %bb.7(0x80000000); %bb.7(200.00%)
287     liveins: $value_stack
288     CATCHRET %bb.7, %bb.1, implicit-def dead $arguments
289 
290   bb.6:
291   ; predecessors: %bb.3
292     successors: %bb.12, %bb.11
293     liveins: $value_stack
294     BR %bb.12, implicit-def dead $arguments
295 
296   bb.7:
297   ; predecessors: %bb.2, %bb.5
298     successors: %bb.9(0x80000000); %bb.9(200.00%)
299     liveins: $value_stack
300     CATCHRET %bb.9, %bb.0, implicit-def dead $arguments
301 
302   bb.8:
303   ; predecessors: %bb.1
304     liveins: $value_stack
305     UNREACHABLE implicit-def $arguments
306 
307   bb.9:
308   ; predecessors: %bb.0, %bb.7
309     liveins: $value_stack
310     RETURN implicit-def $arguments
311 
312   bb.10 (landing-pad):
313   ; predecessors: %bb.4
314     successors: %bb.11
315     liveins: $value_stack
316     %2:exnref = CATCH implicit-def $arguments
317     CLEANUPRET implicit-def dead $arguments
318 
319   bb.11 (landing-pad):
320   ; predecessors: %bb.2, %bb.6, %bb.10
321     liveins: $value_stack
322     %3:exnref = CATCH implicit-def $arguments
323     CLEANUPRET implicit-def dead $arguments
324 
325   bb.12:
326   ; predecessors: %bb.6
327     liveins: $value_stack
328     UNREACHABLE implicit-def $arguments
329 )MIR";
330 
331   LLVMContext Context;
332   std::unique_ptr<MIRParser> MIR;
333   MachineModuleInfo MMI(TM.get());
334   std::unique_ptr<Module> M =
335       parseMIR(Context, MIR, *TM, MIRString, "test1", MMI);
336   ASSERT_TRUE(M);
337 
338   Function *F = M->getFunction("test1");
339   auto *MF = MMI.getMachineFunction(*F);
340   ASSERT_TRUE(MF);
341 
342   WebAssemblyExceptionInfo WEI;
343   MachineDominatorTree MDT;
344   MachineDominanceFrontier MDF;
345   MDT.runOnMachineFunction(*MF);
346   MDF.getBase().analyze(MDT.getBase());
347   WEI.recalculate(MDT, MDF);
348 
349   // Exception info structure:
350   // |- bb1 (ehpad), bb2, bb3, bb4, bb5, bb6, bb7, bb8, bb10, bb11, bb12
351   //   |- bb3 (ehpad), bb4, bb5, bb6, bb10, bb12
352   //     |- bb10 (ehpad)
353   //   |- bb11 (ehpad)
354 
355   auto *MBB1 = MF->getBlockNumbered(1);
356   auto *WE0 = WEI.getExceptionFor(MBB1);
357   ASSERT_TRUE(WE0);
358   EXPECT_EQ(WE0->getEHPad(), MBB1);
359   EXPECT_EQ(WE0->getParentException(), nullptr);
360   EXPECT_EQ(WE0->getExceptionDepth(), (unsigned)1);
361 
362   auto *MBB2 = MF->getBlockNumbered(2);
363   WE0 = WEI.getExceptionFor(MBB2);
364   ASSERT_TRUE(WE0);
365   EXPECT_EQ(WE0->getEHPad(), MBB1);
366 
367   auto *MBB7 = MF->getBlockNumbered(7);
368   WE0 = WEI.getExceptionFor(MBB7);
369   ASSERT_TRUE(WE0);
370   EXPECT_EQ(WE0->getEHPad(), MBB1);
371 
372   auto *MBB8 = MF->getBlockNumbered(8);
373   WE0 = WEI.getExceptionFor(MBB8);
374   ASSERT_TRUE(WE0);
375   EXPECT_EQ(WE0->getEHPad(), MBB1);
376 
377   auto *MBB3 = MF->getBlockNumbered(3);
378   auto *WE0_0 = WEI.getExceptionFor(MBB3);
379   ASSERT_TRUE(WE0_0);
380   EXPECT_EQ(WE0_0->getEHPad(), MBB3);
381   EXPECT_EQ(WE0_0->getParentException(), WE0);
382   EXPECT_EQ(WE0_0->getExceptionDepth(), (unsigned)2);
383 
384   auto *MBB4 = MF->getBlockNumbered(4);
385   WE0_0 = WEI.getExceptionFor(MBB4);
386   ASSERT_TRUE(WE0_0);
387   EXPECT_EQ(WE0_0->getEHPad(), MBB3);
388 
389   auto *MBB5 = MF->getBlockNumbered(5);
390   WE0_0 = WEI.getExceptionFor(MBB5);
391   ASSERT_TRUE(WE0_0);
392   EXPECT_EQ(WE0_0->getEHPad(), MBB3);
393 
394   auto *MBB6 = MF->getBlockNumbered(6);
395   WE0_0 = WEI.getExceptionFor(MBB6);
396   ASSERT_TRUE(WE0_0);
397   EXPECT_EQ(WE0_0->getEHPad(), MBB3);
398 
399   auto *MBB12 = MF->getBlockNumbered(12);
400   WE0_0 = WEI.getExceptionFor(MBB12);
401   ASSERT_TRUE(WE0_0);
402   EXPECT_EQ(WE0_0->getEHPad(), MBB3);
403 
404   auto *MBB10 = MF->getBlockNumbered(10);
405   auto *WE0_0_0 = WEI.getExceptionFor(MBB10);
406   ASSERT_TRUE(WE0_0_0);
407   EXPECT_EQ(WE0_0_0->getEHPad(), MBB10);
408   EXPECT_EQ(WE0_0_0->getParentException(), WE0_0);
409   EXPECT_EQ(WE0_0_0->getExceptionDepth(), (unsigned)3);
410 
411   auto *MBB11 = MF->getBlockNumbered(11);
412   auto *WE0_1 = WEI.getExceptionFor(MBB11);
413   ASSERT_TRUE(WE0_1);
414   EXPECT_EQ(WE0_1->getEHPad(), MBB11);
415   EXPECT_EQ(WE0_1->getParentException(), WE0);
416   EXPECT_EQ(WE0_1->getExceptionDepth(), (unsigned)2);
417 }
418