//=== 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); }