// which are mostly not helpful.
if (TypeErrorThisFunction)
return true;
+ // If we're currently in unreachable code, we surpress errors as well.
+ if (Unreachable)
+ return true;
TypeErrorThisFunction = true;
dumpTypeStack("current stack: ");
return Parser.Error(ErrorLoc, Msg);
return false;
}
-void WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc) {
+bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc) {
// Check the return types.
for (auto RVT : llvm::reverse(ReturnTypes)) {
- popType(ErrorLoc, RVT);
+ if (popType(ErrorLoc, RVT))
+ return true;
}
if (!Stack.empty()) {
- typeError(ErrorLoc,
- std::to_string(Stack.size()) + " superfluous return values");
+ return typeError(ErrorLoc, std::to_string(Stack.size()) +
+ " superfluous return values");
}
- // Reset the type checker state.
- Clear();
+ Unreachable = true;
+ return false;
}
bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst) {
Name == "else" || Name == "end_try") {
if (checkEnd(ErrorLoc))
return true;
+ if (Name == "end_block")
+ Unreachable = false;
+ } else if (Name == "return") {
+ if (endOfFunction(ErrorLoc))
+ return true;
} else if (Name == "call_indirect" || Name == "return_call_indirect") {
// Function value.
if (popType(ErrorLoc, wasm::ValType::I32)) return true;
if (checkSig(ErrorLoc, LastSig)) return true;
+ if (Name == "return_call_indirect" && endOfFunction(ErrorLoc))
+ return true;
} else if (Name == "call" || Name == "return_call") {
const MCSymbolRefExpr *SymRef;
if (getSymRef(ErrorLoc, Inst, SymRef))
return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +
" missing .functype");
if (checkSig(ErrorLoc, *Sig)) return true;
+ if (Name == "return_call" && endOfFunction(ErrorLoc))
+ return true;
} else if (Name == "catch") {
const MCSymbolRefExpr *SymRef;
if (getSymRef(ErrorLoc, Inst, SymRef))
} else if (Name == "ref.null") {
auto VT = static_cast<wasm::ValType>(Inst.getOperand(0).getImm());
Stack.push_back(VT);
+ } else if (Name == "unreachable") {
+ Unreachable = true;
} else {
// The current instruction is a stack instruction which doesn't have
// explicit operands that indicate push/pop types, so we get those from
SmallVector<wasm::ValType, 4> ReturnTypes;
wasm::WasmSignature LastSig;
bool TypeErrorThisFunction = false;
+ bool Unreachable = false;
bool is64;
- void Clear() {
- Stack.clear();
- LocalTypes.clear();
- ReturnTypes.clear();
- TypeErrorThisFunction = false;
- }
-
void dumpTypeStack(Twine Msg);
bool typeError(SMLoc ErrorLoc, const Twine &Msg);
bool popType(SMLoc ErrorLoc, Optional<wasm::ValType> EVT);
void funcDecl(const wasm::WasmSignature &Sig);
void localDecl(const SmallVector<wasm::ValType, 4> &Locals);
void setLastSig(const wasm::WasmSignature &Sig) { LastSig = Sig; }
- void endOfFunction(SMLoc ErrorLoc);
+ bool endOfFunction(SMLoc ErrorLoc);
bool typeCheck(SMLoc ErrorLoc, const MCInst &Inst);
+
+ void Clear() {
+ Stack.clear();
+ LocalTypes.clear();
+ ReturnTypes.clear();
+ TypeErrorThisFunction = false;
+ Unreachable = false;
+ }
};
} // end namespace llvm
-# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types,atomics,+simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+tail-call,+reference-types,atomics,+simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
# Check that it converts to .o without errors, but don't check any output:
-# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+reference-types,+atomics,+simd128,+nontrapping-fptoint,+exception-handling -o %t.o < %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+tail-call,+reference-types,+atomics,+simd128,+nontrapping-fptoint,+exception-handling -o %t.o < %s
.functype something1 () -> ()
.functype something2 (i64) -> (i32, f64)
+.functype something3 () -> (i32)
.globaltype __stack_pointer, i32
empty_func:
else
end_if
drop
+ block void
+ i32.const 2
+ return
+ end_block
+ block void
+ return_call something3
+ end_block
+ block void
+ i32.const 3
+ return_call_indirect () -> (i32)
+ end_block
local.get 4
local.get 5
f32x4.add
# CHECK-NEXT: else
# CHECK-NEXT: end_if
# CHECK-NEXT: drop
+# CHECK-NEXT: block
+# CHECK-NEXT: i32.const 2
+# CHECK-NEXT: return
+# CHECK-NEXT: end_block
+# CHECK-NEXT: block
+# CHECK-NEXT: return_call something3
+# CHECK-NEXT: end_block
+# CHECK-NEXT: block
+# CHECK-NEXT: i32.const 3
+# CHECK-NEXT: return_call_indirect __indirect_function_table, () -> (i32)
+# CHECK-NEXT: end_block
# CHECK-NEXT: local.get 4
# CHECK-NEXT: local.get 5
# CHECK-NEXT: f32x4.add