diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -96,25 +96,25 @@ unsigned TargetFlags = MO.getTargetFlags(); switch (TargetFlags) { - case WebAssemblyII::MO_NO_FLAG: - break; - case WebAssemblyII::MO_GOT_TLS: - Kind = MCSymbolRefExpr::VK_WASM_GOT_TLS; - break; - case WebAssemblyII::MO_GOT: - Kind = MCSymbolRefExpr::VK_GOT; - break; - case WebAssemblyII::MO_MEMORY_BASE_REL: - Kind = MCSymbolRefExpr::VK_WASM_MBREL; - break; - case WebAssemblyII::MO_TLS_BASE_REL: - Kind = MCSymbolRefExpr::VK_WASM_TLSREL; - break; - case WebAssemblyII::MO_TABLE_BASE_REL: - Kind = MCSymbolRefExpr::VK_WASM_TBREL; - break; - default: - llvm_unreachable("Unknown target flag on GV operand"); + case WebAssemblyII::MO_NO_FLAG: + break; + case WebAssemblyII::MO_GOT_TLS: + Kind = MCSymbolRefExpr::VK_WASM_GOT_TLS; + break; + case WebAssemblyII::MO_GOT: + Kind = MCSymbolRefExpr::VK_GOT; + break; + case WebAssemblyII::MO_MEMORY_BASE_REL: + Kind = MCSymbolRefExpr::VK_WASM_MBREL; + break; + case WebAssemblyII::MO_TLS_BASE_REL: + Kind = MCSymbolRefExpr::VK_WASM_TLSREL; + break; + case WebAssemblyII::MO_TABLE_BASE_REL: + Kind = MCSymbolRefExpr::VK_WASM_TBREL; + break; + default: + llvm_unreachable("Unknown target flag on GV operand"); } const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx); @@ -291,8 +291,7 @@ auto RegOpcode = OutMI.getOpcode(); auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode); assert(StackOpcode != -1 && "Failed to stackify instruction"); - OutMI.setOpcode(StackOpcode); - + // Remove register operands. for (auto I = OutMI.getNumOperands(); I; --I) { auto &MO = OutMI.getOperand(I - 1); @@ -300,4 +299,11 @@ OutMI.erase(&MO); } } + + // CALL_S should at least have 1 operand, otherwise this code is invalid. + if (StackOpcode == WebAssembly::CALL_S && OutMI.getNumOperands() == 0) { + StackOpcode = WebAssembly::UNREACHABLE; + } + + OutMI.setOpcode(StackOpcode); } diff --git a/llvm/test/CodeGen/WebAssembly/call.ll b/llvm/test/CodeGen/WebAssembly/call.ll --- a/llvm/test/CodeGen/WebAssembly/call.ll +++ b/llvm/test/CodeGen/WebAssembly/call.ll @@ -2,6 +2,7 @@ ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 -mattr=+sign-ext,+simd128 | FileCheck --check-prefixes=CHECK,NO-TAIL %s ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -mattr=+sign-ext,+simd128,+tail-call | FileCheck --check-prefixes=CHECK,SLOW-TAIL %s ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 -mattr=+sign-ext,+simd128,+tail-call | FileCheck --check-prefixes=CHECK,FAST-TAIL %s +; RUN: llc < %s -asm-verbose=false -O1 | FileCheck --check-prefixes=OPT %s ; Test that basic call operations assemble as expected. @@ -236,6 +237,34 @@ ret void } +; OPT-LABEL: call_invalid: +; OPT-NEXT: .functype call_invalid () -> () +; OPT-NEXT: .local i32 +; OPT-NEXT: global.get __stack_pointer +; OPT-NEXT: i32.const 16 +; OPT-NEXT: i32.sub +; OPT-NEXT: local.tee 0 +; OPT-NEXT: global.set __stack_pointer +; OPT-NEXT: local.get 0 +; OPT-NEXT: i32.const 10 +; OPT-NEXT: i32.store 12 +; OPT-NEXT: local.get 0 +; OPT-NEXT: i32.const 12 +; OPT-NEXT: i32.add +; OPT-NEXT: unreachable +; OPT-NEXT: local.get 0 +; OPT-NEXT: i32.const 16 +; OPT-NEXT: i32.add +; OPT-NEXT: global.set __stack_pointer +; OPT-NEXT: end_function +define void @call_invalid() { +entry: + %a = alloca i32, align 4 + store i32 10, ptr %a, align 4 + call void %a() + ret void +} + ; TODO: test the following: ; - More argument combinations. ; - Tail call.