| //=== WebAssemblyExceptionInfoTest.cpp - WebAssebmlyExceptionInfo unit tests =// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "WebAssemblyExceptionInfo.h" | |
| #include "llvm/CodeGen/MIRParser/MIRParser.h" | |
| #include "llvm/CodeGen/MachineDominanceFrontier.h" | |
| #include "llvm/CodeGen/MachineDominators.h" | |
| #include "llvm/CodeGen/MachineModuleInfo.h" | |
| #include "llvm/Support/SourceMgr.h" | |
| #include "llvm/Support/TargetRegistry.h" | |
| #include "llvm/Support/TargetSelect.h" | |
| #include "llvm/Target/TargetMachine.h" | |
| #include "gtest/gtest.h" | |
| using namespace llvm; | |
| namespace { | |
| std::unique_ptr<TargetMachine> createTargetMachine() { | |
| auto TT(Triple::normalize("wasm32-unknown-unknown")); | |
| std::string CPU(""); | |
| std::string FS(""); | |
| LLVMInitializeWebAssemblyTargetInfo(); | |
| LLVMInitializeWebAssemblyTarget(); | |
| LLVMInitializeWebAssemblyTargetMC(); | |
| std::string Error; | |
| const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error); | |
| assert(TheTarget); | |
| return std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine( | |
| TT, CPU, FS, TargetOptions(), None, None, CodeGenOpt::Default)); | |
| } | |
| std::unique_ptr<Module> parseMIR(LLVMContext &Context, | |
| std::unique_ptr<MIRParser> &MIR, | |
| const TargetMachine &TM, StringRef MIRCode, | |
| const char *FuncName, MachineModuleInfo &MMI) { | |
| SMDiagnostic Diagnostic; | |
| std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode); | |
| MIR = createMIRParser(std::move(MBuffer), Context); | |
| if (!MIR) | |
| return nullptr; | |
| std::unique_ptr<Module> M = MIR->parseIRModule(); | |
| if (!M) | |
| return nullptr; | |
| M->setDataLayout(TM.createDataLayout()); | |
| if (MIR->parseMachineFunctions(*M, MMI)) | |
| return nullptr; | |
| return M; | |
| } | |
| } // namespace | |
| TEST(WebAssemblyExceptionInfoTest, TEST0) { | |
| std::unique_ptr<TargetMachine> TM = createTargetMachine(); | |
| ASSERT_TRUE(TM); | |
| StringRef MIRString = R"MIR( | |
| --- | | |
| target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" | |
| target triple = "wasm32-unknown-unknown" | |
| declare i32 @__gxx_wasm_personality_v0(...) | |
| define hidden void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { | |
| unreachable | |
| } | |
| ... | |
| --- | |
| name: test0 | |
| liveins: | |
| - { reg: '$arguments' } | |
| - { reg: '$value_stack' } | |
| body: | | |
| bb.0: | |
| successors: %bb.1, %bb.2 | |
| liveins: $arguments, $value_stack | |
| BR %bb.1, implicit-def dead $arguments | |
| bb.1: | |
| ; predecessors: %bb.0 | |
| successors: %bb.7 | |
| liveins: $value_stack | |
| BR %bb.7, implicit-def $arguments | |
| bb.2 (landing-pad): | |
| ; predecessors: %bb.0 | |
| successors: %bb.3, %bb.9 | |
| liveins: $value_stack | |
| CATCH_ALL implicit-def $arguments | |
| CLEANUPRET implicit-def dead $arguments | |
| bb.3 (landing-pad): | |
| ; predecessors: %bb.2 | |
| successors: %bb.4, %bb.6 | |
| liveins: $value_stack | |
| CATCH_ALL implicit-def $arguments | |
| BR_IF %bb.4, %58:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack | |
| BR %bb.6, implicit-def $arguments | |
| bb.4: | |
| ; predecessors: %bb.3 | |
| successors: %bb.5, %bb.8 | |
| liveins: $value_stack | |
| BR %bb.5, implicit-def dead $arguments | |
| bb.5: | |
| ; predecessors: %bb.4 | |
| successors: %bb.7 | |
| liveins: $value_stack | |
| CATCHRET %bb.7, %bb.0, implicit-def dead $arguments | |
| bb.6: | |
| ; predecessors: %bb.3 | |
| successors: %bb.10, %bb.9 | |
| liveins: $value_stack | |
| BR %bb.10, implicit-def dead $arguments | |
| bb.7: | |
| ; predecessors: %bb.5, %bb.1 | |
| liveins: $value_stack | |
| RETURN_VOID implicit-def $arguments | |
| bb.8 (landing-pad): | |
| ; predecessors: %bb.4 | |
| successors: %bb.9 | |
| liveins: $value_stack | |
| CATCH_ALL implicit-def $arguments | |
| CLEANUPRET implicit-def dead $arguments | |
| bb.9 (landing-pad): | |
| ; predecessors: %bb.2, %bb.6, %bb.8 | |
| liveins: $value_stack | |
| CATCH_ALL implicit-def $arguments | |
| CLEANUPRET implicit-def dead $arguments | |
| bb.10: | |
| ; predecessors: %bb.6 | |
| liveins: $value_stack | |
| UNREACHABLE implicit-def $arguments | |
| )MIR"; | |
| LLVMContext Context; | |
| std::unique_ptr<MIRParser> MIR; | |
| MachineModuleInfo MMI(TM.get()); | |
| std::unique_ptr<Module> M = | |
| parseMIR(Context, MIR, *TM, MIRString, "test0", MMI); | |
| ASSERT_TRUE(M); | |
| Function *F = M->getFunction("test0"); | |
| auto *MF = MMI.getMachineFunction(*F); | |
| ASSERT_TRUE(MF); | |
| WebAssemblyExceptionInfo WEI; | |
| MachineDominatorTree MDT; | |
| MachineDominanceFrontier MDF; | |
| MDT.runOnMachineFunction(*MF); | |
| MDF.getBase().analyze(MDT.getBase()); | |
| WEI.recalculate(MDT, MDF); | |
| // Exception info structure: | |
| // |- bb2 (ehpad), bb3, bb4, bb5, bb6, bb8, bb9, bb10 | |
| // |- bb3 (ehpad), bb4, bb5, bb6, bb8, bb10 | |
| // |- bb8 (ehpad) | |
| // |- bb9 (ehpad) | |
| auto *MBB2 = MF->getBlockNumbered(2); | |
| auto *WE0 = WEI.getExceptionFor(MBB2); | |
| ASSERT_TRUE(WE0); | |
| EXPECT_EQ(WE0->getEHPad(), MBB2); | |
| EXPECT_EQ(WE0->getParentException(), nullptr); | |
| EXPECT_EQ(WE0->getExceptionDepth(), (unsigned)1); | |
| auto *MBB3 = MF->getBlockNumbered(3); | |
| auto *WE0_0 = WEI.getExceptionFor(MBB3); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB3); | |
| EXPECT_EQ(WE0_0->getParentException(), WE0); | |
| EXPECT_EQ(WE0_0->getExceptionDepth(), (unsigned)2); | |
| auto *MBB4 = MF->getBlockNumbered(4); | |
| WE0_0 = WEI.getExceptionFor(MBB4); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB3); | |
| auto *MBB5 = MF->getBlockNumbered(5); | |
| WE0_0 = WEI.getExceptionFor(MBB5); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB3); | |
| auto *MBB6 = MF->getBlockNumbered(6); | |
| WE0_0 = WEI.getExceptionFor(MBB6); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB3); | |
| auto *MBB10 = MF->getBlockNumbered(10); | |
| WE0_0 = WEI.getExceptionFor(MBB10); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB3); | |
| auto *MBB8 = MF->getBlockNumbered(8); | |
| auto *WE0_0_0 = WEI.getExceptionFor(MBB8); | |
| ASSERT_TRUE(WE0_0_0); | |
| EXPECT_EQ(WE0_0_0->getEHPad(), MBB8); | |
| EXPECT_EQ(WE0_0_0->getParentException(), WE0_0); | |
| EXPECT_EQ(WE0_0_0->getExceptionDepth(), (unsigned)3); | |
| auto *MBB9 = MF->getBlockNumbered(9); | |
| auto *WE0_1 = WEI.getExceptionFor(MBB9); | |
| ASSERT_TRUE(WE0_1); | |
| EXPECT_EQ(WE0_1->getEHPad(), MBB9); | |
| EXPECT_EQ(WE0_1->getParentException(), WE0); | |
| EXPECT_EQ(WE0_1->getExceptionDepth(), (unsigned)2); | |
| } | |
| TEST(WebAssemblyExceptionInfoTest, TEST1) { | |
| std::unique_ptr<TargetMachine> TM = createTargetMachine(); | |
| ASSERT_TRUE(TM); | |
| StringRef MIRString = R"MIR( | |
| --- | | |
| target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" | |
| target triple = "wasm32-unknown-unknown" | |
| declare i32 @__gxx_wasm_personality_v0(...) | |
| define hidden void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { | |
| unreachable | |
| } | |
| ... | |
| --- | |
| name: test1 | |
| liveins: | |
| - { reg: '$arguments' } | |
| - { reg: '$value_stack' } | |
| body: | | |
| bb.0: | |
| successors: %bb.9, %bb.1 | |
| liveins: $arguments, $value_stack | |
| BR %bb.9, implicit-def dead $arguments | |
| bb.1 (landing-pad): | |
| ; predecessors: %bb.0 | |
| successors: %bb.2, %bb.8 | |
| liveins: $value_stack | |
| %52:i32 = CATCH_I32 0, implicit-def dead $arguments | |
| BR_IF %bb.2, %32:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack | |
| BR %bb.8, implicit-def $arguments | |
| bb.2: | |
| ; predecessors: %bb.1 | |
| successors: %bb.7, %bb.3, %bb.11 | |
| liveins: $value_stack | |
| BR %bb.7, implicit-def dead $arguments | |
| bb.3 (landing-pad): | |
| ; predecessors: %bb.2 | |
| successors: %bb.4, %bb.6 | |
| liveins: $value_stack | |
| CATCH_ALL implicit-def $arguments | |
| BR_IF %bb.4, %43:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack | |
| BR %bb.6, implicit-def $arguments | |
| bb.4: | |
| ; predecessors: %bb.3 | |
| successors: %bb.5, %bb.10 | |
| liveins: $value_stack | |
| BR %bb.5, implicit-def dead $arguments | |
| bb.5: | |
| ; predecessors: %bb.4 | |
| successors: %bb.7(0x80000000); %bb.7(200.00%) | |
| liveins: $value_stack | |
| CATCHRET %bb.7, %bb.1, implicit-def dead $arguments | |
| bb.6: | |
| ; predecessors: %bb.3 | |
| successors: %bb.12, %bb.11 | |
| liveins: $value_stack | |
| BR %bb.12, implicit-def dead $arguments | |
| bb.7: | |
| ; predecessors: %bb.2, %bb.5 | |
| successors: %bb.9(0x80000000); %bb.9(200.00%) | |
| liveins: $value_stack | |
| CATCHRET %bb.9, %bb.0, implicit-def dead $arguments | |
| bb.8: | |
| ; predecessors: %bb.1 | |
| liveins: $value_stack | |
| UNREACHABLE implicit-def $arguments | |
| bb.9: | |
| ; predecessors: %bb.0, %bb.7 | |
| liveins: $value_stack | |
| RETURN_VOID implicit-def $arguments | |
| bb.10 (landing-pad): | |
| ; predecessors: %bb.4 | |
| successors: %bb.11 | |
| liveins: $value_stack | |
| CATCH_ALL implicit-def $arguments | |
| CLEANUPRET implicit-def dead $arguments | |
| bb.11 (landing-pad): | |
| ; predecessors: %bb.2, %bb.6, %bb.10 | |
| liveins: $value_stack | |
| CATCH_ALL implicit-def $arguments | |
| CLEANUPRET implicit-def dead $arguments | |
| bb.12: | |
| ; predecessors: %bb.6 | |
| liveins: $value_stack | |
| UNREACHABLE implicit-def $arguments | |
| )MIR"; | |
| LLVMContext Context; | |
| std::unique_ptr<MIRParser> MIR; | |
| MachineModuleInfo MMI(TM.get()); | |
| std::unique_ptr<Module> M = | |
| parseMIR(Context, MIR, *TM, MIRString, "test1", MMI); | |
| ASSERT_TRUE(M); | |
| Function *F = M->getFunction("test1"); | |
| auto *MF = MMI.getMachineFunction(*F); | |
| ASSERT_TRUE(MF); | |
| WebAssemblyExceptionInfo WEI; | |
| MachineDominatorTree MDT; | |
| MachineDominanceFrontier MDF; | |
| MDT.runOnMachineFunction(*MF); | |
| MDF.getBase().analyze(MDT.getBase()); | |
| WEI.recalculate(MDT, MDF); | |
| // Exception info structure: | |
| // |- bb1 (ehpad), bb2, bb3, bb4, bb5, bb6, bb7, bb8, bb10, bb11, bb12 | |
| // |- bb3 (ehpad), bb4, bb5, bb6, bb10, bb12 | |
| // |- bb10 (ehpad) | |
| // |- bb11 (ehpad) | |
| auto *MBB1 = MF->getBlockNumbered(1); | |
| auto *WE0 = WEI.getExceptionFor(MBB1); | |
| ASSERT_TRUE(WE0); | |
| EXPECT_EQ(WE0->getEHPad(), MBB1); | |
| EXPECT_EQ(WE0->getParentException(), nullptr); | |
| EXPECT_EQ(WE0->getExceptionDepth(), (unsigned)1); | |
| auto *MBB2 = MF->getBlockNumbered(2); | |
| WE0 = WEI.getExceptionFor(MBB2); | |
| ASSERT_TRUE(WE0); | |
| EXPECT_EQ(WE0->getEHPad(), MBB1); | |
| auto *MBB7 = MF->getBlockNumbered(7); | |
| WE0 = WEI.getExceptionFor(MBB7); | |
| ASSERT_TRUE(WE0); | |
| EXPECT_EQ(WE0->getEHPad(), MBB1); | |
| auto *MBB8 = MF->getBlockNumbered(8); | |
| WE0 = WEI.getExceptionFor(MBB8); | |
| ASSERT_TRUE(WE0); | |
| EXPECT_EQ(WE0->getEHPad(), MBB1); | |
| auto *MBB3 = MF->getBlockNumbered(3); | |
| auto *WE0_0 = WEI.getExceptionFor(MBB3); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB3); | |
| EXPECT_EQ(WE0_0->getParentException(), WE0); | |
| EXPECT_EQ(WE0_0->getExceptionDepth(), (unsigned)2); | |
| auto *MBB4 = MF->getBlockNumbered(4); | |
| WE0_0 = WEI.getExceptionFor(MBB4); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB3); | |
| auto *MBB5 = MF->getBlockNumbered(5); | |
| WE0_0 = WEI.getExceptionFor(MBB5); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB3); | |
| auto *MBB6 = MF->getBlockNumbered(6); | |
| WE0_0 = WEI.getExceptionFor(MBB6); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB3); | |
| auto *MBB12 = MF->getBlockNumbered(12); | |
| WE0_0 = WEI.getExceptionFor(MBB12); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB3); | |
| auto *MBB10 = MF->getBlockNumbered(10); | |
| auto *WE0_0_0 = WEI.getExceptionFor(MBB10); | |
| ASSERT_TRUE(WE0_0_0); | |
| EXPECT_EQ(WE0_0_0->getEHPad(), MBB10); | |
| EXPECT_EQ(WE0_0_0->getParentException(), WE0_0); | |
| EXPECT_EQ(WE0_0_0->getExceptionDepth(), (unsigned)3); | |
| auto *MBB11 = MF->getBlockNumbered(11); | |
| auto *WE0_1 = WEI.getExceptionFor(MBB11); | |
| ASSERT_TRUE(WE0_1); | |
| EXPECT_EQ(WE0_1->getEHPad(), MBB11); | |
| EXPECT_EQ(WE0_1->getParentException(), WE0); | |
| EXPECT_EQ(WE0_1->getExceptionDepth(), (unsigned)2); | |
| } | |
| // Terminate pad test | |
| TEST(WebAssemblyExceptionInfoTest, TEST2) { | |
| std::unique_ptr<TargetMachine> TM = createTargetMachine(); | |
| ASSERT_TRUE(TM); | |
| StringRef MIRString = R"MIR( | |
| --- | | |
| target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" | |
| target triple = "wasm32-unknown-unknown" | |
| declare i32 @__gxx_wasm_personality_v0(...) | |
| declare void @_ZSt9terminatev() | |
| declare void @__clang_call_terminate(i8*) | |
| define hidden void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { | |
| unreachable | |
| } | |
| ... | |
| --- | |
| name: test2 | |
| liveins: | |
| - { reg: '$arguments' } | |
| - { reg: '$value_stack' } | |
| body: | | |
| bb.0: | |
| successors: %bb.3, %bb.1 | |
| BR %bb.3, implicit-def dead $arguments | |
| bb.1 (landing-pad): | |
| ; predecessors: %bb.0 | |
| successors: %bb.2, %bb.4 | |
| %3:i32 = CATCH_I32 0, implicit-def dead $arguments | |
| BR %bb.2, implicit-def dead $arguments | |
| bb.2: | |
| ; predecessors: %bb.1 | |
| successors: %bb.3(0x80000000); %bb.3(200.00%) | |
| CATCHRET %bb.3, %bb.0, implicit-def dead $arguments | |
| bb.3: | |
| ; predecessors: %bb.0, %bb.2 | |
| RETURN_VOID implicit-def $arguments | |
| bb.4 (landing-pad): | |
| ; predecessors: %bb.1 | |
| successors: %bb.5, %bb.6 | |
| CATCH_ALL implicit-def $arguments | |
| BR %bb.5, implicit-def dead $arguments | |
| bb.5: | |
| ; predecessors: %bb.4 | |
| CLEANUPRET implicit-def dead $arguments | |
| bb.6 (landing-pad): | |
| ; predecessors: %bb.4 | |
| successors: %bb.7(0x80000000); %bb.7(200.00%) | |
| %6:i32 = CATCH_I32 0, implicit-def dead $arguments | |
| CALL_VOID @__clang_call_terminate, %7:i32, implicit-def $arguments | |
| UNREACHABLE implicit-def $arguments | |
| bb.7 (landing-pad): | |
| ; predecessors: %bb.6 | |
| CATCH_ALL implicit-def $arguments | |
| CALL_VOID @_ZSt9terminatev, implicit-def $arguments | |
| UNREACHABLE implicit-def $arguments | |
| )MIR"; | |
| LLVMContext Context; | |
| std::unique_ptr<MIRParser> MIR; | |
| MachineModuleInfo MMI(TM.get()); | |
| std::unique_ptr<Module> M = | |
| parseMIR(Context, MIR, *TM, MIRString, "test2", MMI); | |
| ASSERT_TRUE(M); | |
| Function *F = M->getFunction("test2"); | |
| auto *MF = MMI.getMachineFunction(*F); | |
| ASSERT_TRUE(MF); | |
| WebAssemblyExceptionInfo WEI; | |
| MachineDominatorTree MDT; | |
| MachineDominanceFrontier MDF; | |
| MDT.runOnMachineFunction(*MF); | |
| MDF.getBase().analyze(MDT.getBase()); | |
| WEI.recalculate(MDT, MDF); | |
| // Exception info structure: | |
| // |- bb1 (ehpad), bb2, bb4, bb5, bb6, bb7 | |
| // |- bb4 (ehpad), bb5, bb6, bb7 | |
| // |- bb6 (ehpad), bb7 | |
| // | |
| // Here, bb6 is a terminate pad with a 'catch' instruction, and bb7 is a | |
| // terminate pad with a 'catch_all' instruction, In this case we put bb6 and | |
| // bb7 into one exception. | |
| auto *MBB1 = MF->getBlockNumbered(1); | |
| auto *WE0 = WEI.getExceptionFor(MBB1); | |
| ASSERT_TRUE(WE0); | |
| EXPECT_EQ(WE0->getEHPad(), MBB1); | |
| EXPECT_EQ(WE0->getParentException(), nullptr); | |
| EXPECT_EQ(WE0->getExceptionDepth(), (unsigned)1); | |
| auto *MBB2 = MF->getBlockNumbered(2); | |
| WE0 = WEI.getExceptionFor(MBB2); | |
| ASSERT_TRUE(WE0); | |
| EXPECT_EQ(WE0->getEHPad(), MBB1); | |
| auto *MBB4 = MF->getBlockNumbered(4); | |
| auto *WE0_0 = WEI.getExceptionFor(MBB4); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB4); | |
| EXPECT_EQ(WE0_0->getParentException(), WE0); | |
| EXPECT_EQ(WE0_0->getExceptionDepth(), (unsigned)2); | |
| auto *MBB5 = MF->getBlockNumbered(5); | |
| WE0_0 = WEI.getExceptionFor(MBB5); | |
| ASSERT_TRUE(WE0_0); | |
| EXPECT_EQ(WE0_0->getEHPad(), MBB4); | |
| auto *MBB6 = MF->getBlockNumbered(6); | |
| auto *WE0_0_0 = WEI.getExceptionFor(MBB6); | |
| ASSERT_TRUE(WE0_0_0); | |
| EXPECT_EQ(WE0_0_0->getEHPad(), MBB6); | |
| EXPECT_EQ(WE0_0_0->getParentException(), WE0_0); | |
| EXPECT_EQ(WE0_0_0->getExceptionDepth(), (unsigned)3); | |
| auto *MBB7 = MF->getBlockNumbered(7); | |
| WE0_0_0 = WEI.getExceptionFor(MBB7); | |
| ASSERT_TRUE(WE0_0_0); | |
| EXPECT_EQ(WE0_0_0->getEHPad(), MBB6); | |
| } |