Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebAssembly Exceptions #4546

Open
etcimon opened this issue Dec 21, 2023 · 8 comments
Open

WebAssembly Exceptions #4546

etcimon opened this issue Dec 21, 2023 · 8 comments
Labels
B-webassembly WASM-related

Comments

@etcimon
Copy link
Contributor

etcimon commented Dec 21, 2023

I tried compiling a simple try/catch wasm32-unknown-wasi .d file with --wasm-enable-eh and I get a crash while writing the object file. Is it supported currently?

Thanks

@JohanEngelen
Copy link
Member

testcase: https://d.godbolt.org/z/fbMborTez

@JohanEngelen
Copy link
Member

I've found the issue.
Reproducer with LLC: https://llvm.godbolt.org/z/3bj1rT794

target datalayout = "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm64-unknown-unknown"

define void @foo() personality ptr @_d_eh_personality {
  unreachable
}

declare i32 @_d_eh_personality(i32, i32, i64, ptr, ptr)
declare i32 @__gxx_wasm_personality_v0(...)

_d_eh_personality is not recognized by LLVM as a "scoped EH personality function"
https://github.com/llvm/llvm-project/blob/9423e459875b0dcdf24975976838d651a92f1bdb/llvm/lib/CodeGen/MachineFunction.cpp#L240-L243
https://github.com/llvm/llvm-project/blob/9423e459875b0dcdf24975976838d651a92f1bdb/llvm/lib/IR/EHPersonalities.cpp#L23-L46

If we'd use __gxx_wasm_personality_v0 as personality function, then there'd be no crash. But I can't find any implementation for that function, or other documentation.

@JohanEngelen JohanEngelen added the B-webassembly WASM-related label Dec 26, 2023
@etcimon
Copy link
Contributor Author

etcimon commented Dec 27, 2023

Here is the stack trace for a simple try/catch

Assertion failed: R == 0 && "Already initialized this value register!", file F:\Development\llvm-project\llvm\include\llvm/CodeGen/FunctionLoweringInfo.h, line 222

Exception Code: 0x80000003
 #0 0x00007ff7b7e688dc HandleAbort F:\Development\llvm-project\llvm\lib\Support\Windows\Signals.inc:419:0
 #1 0x00007ff80f958e05 (C:\Windows\SYSTEM32\ucrtbased.dll+0xa8e05)
 #2 0x00007ff80f95ab29 (C:\Windows\SYSTEM32\ucrtbased.dll+0xaab29)
 #3 0x00007ff80f961025 (C:\Windows\SYSTEM32\ucrtbased.dll+0xb1025)
 #4 0x00007ff80f9608b7 (C:\Windows\SYSTEM32\ucrtbased.dll+0xb08b7)
 #5 0x00007ff80f95e881 (C:\Windows\SYSTEM32\ucrtbased.dll+0xae881)
 #6 0x00007ff80f96158f (C:\Windows\SYSTEM32\ucrtbased.dll+0xb158f)
 #7 0x00007ff7b53dc03d llvm::FunctionLoweringInfo::InitializeRegForValue(class llvm::Value const *) F:\Development\llvm-project\llvm\include\llvm\CodeGen\FunctionLoweringInfo.h:222:0
 #8 0x00007ff7b53499a2 llvm::SelectionDAGBuilder::getValueImpl(class llvm::Value const *) F:\Development\llvm-project\llvm\lib\CodeGen\SelectionDAG\SelectionDAGBuilder.cpp:1784:0
 #9 0x00007ff7b53479d9 llvm::SelectionDAGBuilder::getNonRegisterValue(class llvm::Value const *) F:\Development\llvm-project\llvm\lib\CodeGen\SelectionDAG\SelectionDAGBuilder.cpp:1637:0
#10 0x00007ff7b5343ea2 llvm::SelectionDAGBuilder::CopyValueToVirtualRegister(class llvm::Value const *, unsigned int, enum llvm::ISD::NodeType) F:\Development\llvm-project\llvm\lib\CodeGen\SelectionDAG\SelectionDAGBuilder.cpp:10485:0
#11 0x00007ff7b534b07f llvm::SelectionDAGBuilder::CopyToExportRegsIfNeeded(class llvm::Value const *) F:\Development\llvm-project\llvm\lib\CodeGen\SelectionDAG\SelectionDAGBuilder.cpp:2183:0
#12 0x00007ff7b534477c llvm::SelectionDAGBuilder::visit(class llvm::Instruction const &) F:\Development\llvm-project\llvm\lib\CodeGen\SelectionDAG\SelectionDAGBuilder.cpp:1198:0
#13 0x00007ff7b53f9650 llvm::SelectionDAGISel::SelectBasicBlock(class llvm::ilist_iterator<struct llvm::ilist_detail::node_options<class llvm::Instruction, 1, 0, void>, 0, 1>, class llvm::ilist_iterator<struct llvm::ilist_detail::node_options<class llvm::Instruction, 1, 0, void>, 0, 1>, bool &) F:\Development\llvm-project\llvm\lib\CodeGen\SelectionDAG\SelectionDAGISel.cpp:692:0
#14 0x00007ff7b53f9209 llvm::SelectionDAGISel::SelectAllBasicBlocks(class llvm::Function const &) F:\Development\llvm-project\llvm\lib\CodeGen\SelectionDAG\SelectionDAGISel.cpp:1705:0
#15 0x00007ff7b53eb348 llvm::SelectionDAGISel::runOnMachineFunction(class llvm::MachineFunction &) F:\Development\llvm-project\llvm\lib\CodeGen\SelectionDAG\SelectionDAGISel.cpp:483:0
#16 0x00007ff7b34a6c08 `anonymous namespace'::WebAssemblyDAGToDAGISel::runOnMachineFunction F:\Development\llvm-project\llvm\lib\Target\WebAssembly\WebAssemblyISelDAGToDAG.cpp:61:0
#17 0x00007ff7b5b4f2e4 llvm::MachineFunctionPass::runOnFunction(class llvm::Function &) F:\Development\llvm-project\llvm\lib\CodeGen\MachineFunctionPass.cpp:91:0
#18 0x00007ff7b793f68e llvm::FPPassManager::runOnFunction(class llvm::Function &) F:\Development\llvm-project\llvm\lib\IR\LegacyPassManager.cpp:1435:0
#19 0x00007ff7b793fa67 llvm::FPPassManager::runOnModule(class llvm::Module &) F:\Development\llvm-project\llvm\lib\IR\LegacyPassManager.cpp:1481:0
#20 0x00007ff7b7942885 `anonymous namespace'::MPPassManager::runOnModule F:\Development\llvm-project\llvm\lib\IR\LegacyPassManager.cpp:1550:0
#21 0x00007ff7b7943737 llvm::legacy::PassManagerImpl::run(class llvm::Module &) F:\Development\llvm-project\llvm\lib\IR\LegacyPassManager.cpp:535:0
#22 0x00007ff7b793880c llvm::legacy::PassManager::run(class llvm::Module &) F:\Development\llvm-project\llvm\lib\IR\LegacyPassManager.cpp:1678:0
#23 0x00007ff7b2966741 `anonymous namespace'::codegenModule F:\Development\ldc\driver\toobj.cpp:138:0
#24 0x00007ff7b29674e8 `anonymous namespace'::writeObjectFile F:\Development\ldc\driver\toobj.cpp:293:0
#25 0x00007ff7b296602b writeModule(class llvm::Module *, char const *) F:\Development\ldc\driver\toobj.cpp:488:0
#26 0x00007ff7b2852892 ldc::CodeGenerator::writeAndFreeLLModule(char const *) F:\Development\ldc\driver\codegenerator.cpp:294:0
#27 0x00007ff7b28520d4 ldc::CodeGenerator::~CodeGenerator(void) F:\Development\ldc\driver\codegenerator.cpp:223:0
#28 0x00007ff7b2744c9c codegenModules(struct Array<class Module *> &) F:\Development\ldc\driver\main.cpp:1331:0
#29 0x00007ff7b2472e54 mars_mainBody(struct Param &, struct Array<char const *> &, struct Array<char const *> &) F:\Development\ldc\dmd\main.d:753:0
#30 0x00007ff7b27444eb cppmain(void) F:\Development\ldc\driver\main.cpp:1236:0
#31 0x00007ff7b236874c D main F:\Development\ldc\driver\main.d:27:0
#32 0x00007ff7b265884c rt.dmain2._d_run_main2.runAll.__lambda2 D:\a\ldc\ldc\runtime\druntime\src\rt\dmain2.d:506:0
#33 0x00007ff7b265866e _D2rt6dmain212_d_run_main2UAAamPUQgZiZ7tryExecMFMDFZvZv D:\a\ldc\ldc\runtime\druntime\src\rt\dmain2.d:467:0
#34 0x00007ff7b2658766 _D2rt6dmain212_d_run_main2UAAamPUQgZiZ6runAllMFZv D:\a\ldc\ldc\runtime\druntime\src\rt\dmain2.d:506:0
#35 0x00007ff7b265866e _D2rt6dmain212_d_run_main2UAAamPUQgZiZ7tryExecMFMDFZvZv D:\a\ldc\ldc\runtime\druntime\src\rt\dmain2.d:467:0
#36 0x00007ff7b2658064 _d_run_main2 D:\a\ldc\ldc\runtime\druntime\src\rt\dmain2.d:529:0
#37 0x00007ff7b265859b _d_wrun_main D:\a\ldc\ldc\runtime\druntime\src\rt\dmain2.d:375:0
#38 0x00007ff7b2838f93 args::forwardToDruntime(int, wchar_t const **) F:\Development\ldc\driver\args.cpp:82:0
#39 0x00007ff7b2743c0e wmain F:\Development\ldc\driver\main.cpp:1116:0
#40 0x00007ff7b7ff65a4 invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:90:0
#41 0x00007ff7b7ff65a4 __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288:0
#42 0x00007ff8733c257d (C:\Windows\System32\KERNEL32.DLL+0x1257d)
#43 0x00007ff873acaa58 (C:\Windows\SYSTEM32\ntdll.dll+0x5aa58)```

@etcimon
Copy link
Contributor Author

etcimon commented Dec 27, 2023

I tried compiling with this and it was still giving the same error. Also, changing the function name to the Wasm_CXX __gxx_wasm_personality_v0 name caused an infinite loop.

[..]
      .Case("rust_eh_personality", EHPersonality::Rust)
      .Case("__gxx_wasm_personality_v0", EHPersonality::Wasm_CXX)
      .Case("_d_eh_personality", EHPersonality::DLang)
      .Case("__xlcxx_personality_v1", EHPersonality::XL_CXX)
      .Default(EHPersonality::Unknown);
[..]
  case EHPersonality::Wasm_CXX:
    return "__gxx_wasm_personality_v0";
  case EHPersonality::DLang:
    return "_d_eh_personality";
  case EHPersonality::XL_CXX:
    return "__xlcxx_personality_v1";
  case EHPersonality::Unknown:
[..]
/// Returns true if this personality uses scope-style EH IR instructions:
/// catchswitch, catchpad/ret, and cleanuppad/ret.
inline bool isScopedEHPersonality(EHPersonality Pers) {
  switch (Pers) {
  case EHPersonality::MSVC_CXX:
  case EHPersonality::MSVC_X86SEH:
  case EHPersonality::MSVC_TableSEH:
  case EHPersonality::CoreCLR:
  case EHPersonality::Wasm_CXX:
  case EHPersonality::DLang:
    return true;
  default:
    return false;
  }
  llvm_unreachable("invalid enum");
}

/// Return true if this personality may be safely removed if there
/// are no invoke instructions remaining in the current function.
inline bool isNoOpWithoutInvoke(EHPersonality Pers) {
  switch (Pers) {
  case EHPersonality::Unknown:
  case EHPersonality::DLang:
    return false;
  // All known personalities currently have this behavior
  default:
    return true;
  }
  llvm_unreachable("invalid enum");
}

@etcimon
Copy link
Contributor Author

etcimon commented Dec 27, 2023

More debug info:

Type-legalized selection DAG: %bb.3 '_start:'
SelectionDAG has 4 nodes:
    t0: ch,glue = EntryToken
  t3: ch = CopyToReg t0, Register:i32 %6, Constant:i32<1>
Legalizing: t3: ch = CopyToReg t0, Register:i32 %6, Constant:i32<1>
Trying custom legalization
Could not custom legalize node
Trying to expand node
Cannot expand node
Trying to convert node to libcall
Could not convert node to libcall
Legalizing: t2: i32 = Register %6
Legalizing: t1: i32 = Constant<1>
Legal node: nothing to do
Legalizing: t0: ch,glue = EntryToken
Legal node: nothing to do
Legalized selection DAG: %bb.3 '_start:'
SelectionDAG has 4 nodes:
    t0: ch,glue = EntryToken
  t3: ch = CopyToReg t0, Register:i32 %6, Constant:i32<1>
Legalizing: t3: ch = CopyToReg t0, Register:i32 %6, Constant:i32<1>
Trying custom legalization
Could not custom legalize node
Trying to expand node
Cannot expand node
Trying to convert node to libcall
Could not convert node to libcall
Combining: t3: ch = CopyToReg t0, Register:i32 %6, Constant:i32<1>
Legalizing: t2: i32 = Register %6
Combining: t2: i32 = Register %6
Legalizing: t1: i32 = Constant<1>
Legal node: nothing to do
Combining: t1: i32 = Constant<1>
Legalizing: t0: ch,glue = EntryToken
Legal node: nothing to do
Combining: t0: ch,glue = EntryToken
Optimized legalized selection DAG: %bb.3 '_start:'
SelectionDAG has 4 nodes:
    t0: ch,glue = EntryToken
  t3: ch = CopyToReg t0, Register:i32 %6, Constant:i32<1>
===== Instruction selection begins: %bb.3 ''
ISEL: Starting selection on root node: t3: ch = CopyToReg t0, Register:i32 %6, Constant:i32<1>
ISEL: Starting selection on root node: t2: i32 = Register %6
ISEL: Starting selection on root node: t1: i32 = Constant<1>
ISEL: Starting pattern match
  Initial Opcode index to 14527
  TypeSwitch[i32] from 14528 to 14531
Creating constant: t4: i32 = TargetConstant<1>
  Morphed node: t1: i32 = CONST_I32 TargetConstant:i32<1>
ISEL: Match complete!
ISEL: Starting selection on root node: t0: ch,glue = EntryToken
===== Instruction selection ends:
Selected selection DAG: %bb.3 '_start:'
SelectionDAG has 5 nodes:
    t0: ch,glue = EntryToken
    t1: i32 = CONST_I32 TargetConstant:i32<1>
  t3: ch = CopyToReg t0, Register:i32 %6, t1
********** List Scheduling %bb.3 '' **********
SU(0): t3: ch = CopyToReg t0, Register:i32 %6, t1
  # preds left       : 1
  # succs left       : 0
  # rdefs left       : 0
  Latency            : 1
  Depth              : 1
  Height             : 0
  Predecessors:
    SU(1): Data Latency=1
SU(1): t1: i32 = CONST_I32 TargetConstant:i32<1>
  # preds left       : 0
  # succs left       : 1
  # rdefs left       : 1
  Latency            : 1
  Depth              : 0
  Height             : 1
  Successors:
    SU(0): Data Latency=1
Examining Available:
Height 0: SU(0): t3: ch = CopyToReg t0, Register:i32 %6, t1
*** Scheduling [0]: SU(0): t3: ch = CopyToReg t0, Register:i32 %6, t1
Examining Available:
Height 1: SU(1): t1: i32 = CONST_I32 TargetConstant:i32<1>
*** Scheduling [1]: SU(1): t1: i32 = CONST_I32 TargetConstant:i32<1>
*** Final schedule ***
SU(1): t1: i32 = CONST_I32 TargetConstant:i32<1>
SU(0): t3: ch = CopyToReg t0, Register:i32 %6, t1
FastISel missed (in function: _start)
Assertion failed: R == 0 && "Already initialized this value register!", file F:\Development\llvm-project\llvm\include\llvm/CodeGen/FunctionLoweringInfo.h,
line 222

@etcimon
Copy link
Contributor Author

etcimon commented Dec 27, 2023

When changing to the __gxx_wasm_personality_v0 function, the infinite loop is on the EHPadBB while:

static void findWasmUnwindDestinations(
    FunctionLoweringInfo &FuncInfo, const BasicBlock *EHPadBB,
    BranchProbability Prob,
    SmallVectorImpl<std::pair<MachineBasicBlock *, BranchProbability>>
        &UnwindDests) {
  while (EHPadBB) {
    const Instruction *Pad = EHPadBB->getFirstNonPHI();
    if (isa<CleanupPadInst>(Pad)) {
      // Stop on cleanup pads.
      UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob);
      UnwindDests.back().first->setIsEHScopeEntry();
      break;
    } else if (const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) {
      // Add the catchpad handlers to the possible destinations. We don't
      // continue to the unwind destination of the catchswitch for wasm.
      for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) {
        UnwindDests.emplace_back(FuncInfo.MBBMap[CatchPadBB], Prob);
        UnwindDests.back().first->setIsEHScopeEntry();
      }
      break;
    } else {
      continue;
    }
  }
}

@etcimon
Copy link
Contributor Author

etcimon commented Jan 11, 2024

Seems to be fixed in 1.36.0

@etcimon etcimon closed this as completed Jan 11, 2024
@etcimon etcimon reopened this Jan 11, 2024
@etcimon
Copy link
Contributor Author

etcimon commented Jan 11, 2024

nevermind I didn't have the proper compile flag when testing (has to be in lflags too for dub now)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-webassembly WASM-related
Projects
None yet
Development

No branches or pull requests

2 participants