Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 53 additions & 32 deletions llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,21 @@ bool WebAssemblyAsmTypeCheck::match(StackType TypeA, StackType TypeB) {

std::string WebAssemblyAsmTypeCheck::getTypesString(ArrayRef<StackType> Types,
size_t StartPos) {
SmallVector<std::string, 4> Reverse;
SmallVector<std::string, 4> TypeStrs;
for (auto I = Types.size(); I > StartPos; I--) {
if (std::get_if<Any>(&Types[I - 1]))
Reverse.push_back("any");
TypeStrs.push_back("any");
else if (std::get_if<Ref>(&Types[I - 1]))
Reverse.push_back("ref");
TypeStrs.push_back("ref");
else
Reverse.push_back(
TypeStrs.push_back(
WebAssembly::typeToString(std::get<wasm::ValType>(Types[I - 1])));
}

std::stringstream SS;
SS << "[";
bool First = true;
for (auto It = Reverse.rbegin(); It != Reverse.rend(); ++It) {
for (auto It = TypeStrs.rbegin(); It != TypeStrs.rend(); ++It) {
if (!First)
SS << ", ";
SS << *It;
Expand Down Expand Up @@ -159,15 +159,15 @@ bool WebAssemblyAsmTypeCheck::checkTypes(SMLoc ErrorLoc,
getTypesString(Stack, StackStartPos));
}

bool WebAssemblyAsmTypeCheck::checkAndPopTypes(SMLoc ErrorLoc,
ArrayRef<wasm::ValType> ValTypes,
bool ExactMatch) {
return checkAndPopTypes(ErrorLoc, valTypeToStackType(ValTypes), ExactMatch);
bool WebAssemblyAsmTypeCheck::popTypes(SMLoc ErrorLoc,
ArrayRef<wasm::ValType> ValTypes,
bool ExactMatch) {
return popTypes(ErrorLoc, valTypeToStackType(ValTypes), ExactMatch);
}

bool WebAssemblyAsmTypeCheck::checkAndPopTypes(SMLoc ErrorLoc,
ArrayRef<StackType> Types,
bool ExactMatch) {
bool WebAssemblyAsmTypeCheck::popTypes(SMLoc ErrorLoc,
ArrayRef<StackType> Types,
bool ExactMatch) {
bool Error = checkTypes(ErrorLoc, Types, ExactMatch);
auto NumPops = std::min(Stack.size(), Types.size());
for (size_t I = 0, E = NumPops; I != E; I++)
Expand All @@ -176,7 +176,7 @@ bool WebAssemblyAsmTypeCheck::checkAndPopTypes(SMLoc ErrorLoc,
}

bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc, StackType Type) {
return checkAndPopTypes(ErrorLoc, {Type}, false);
return popTypes(ErrorLoc, {Type});
}

bool WebAssemblyAsmTypeCheck::popRefType(SMLoc ErrorLoc) {
Expand Down Expand Up @@ -207,7 +207,7 @@ bool WebAssemblyAsmTypeCheck::checkBr(SMLoc ErrorLoc, size_t Level) {
StringRef("br: invalid depth ") + std::to_string(Level));
const SmallVector<wasm::ValType, 4> &Expected =
BrStack[BrStack.size() - Level - 1];
return checkTypes(ErrorLoc, Expected, false);
return checkTypes(ErrorLoc, Expected);
return false;
}

Expand All @@ -216,13 +216,13 @@ bool WebAssemblyAsmTypeCheck::checkEnd(SMLoc ErrorLoc, bool PopVals) {
BrStack.pop_back();

if (PopVals)
return checkAndPopTypes(ErrorLoc, LastSig.Returns, false);
return checkTypes(ErrorLoc, LastSig.Returns, false);
return popTypes(ErrorLoc, LastSig.Returns);
return checkTypes(ErrorLoc, LastSig.Returns);
}

bool WebAssemblyAsmTypeCheck::checkSig(SMLoc ErrorLoc,
const wasm::WasmSignature &Sig) {
bool Error = checkAndPopTypes(ErrorLoc, Sig.Params, false);
bool Error = popTypes(ErrorLoc, Sig.Params);
pushTypes(Sig.Returns);
return Error;
}
Expand Down Expand Up @@ -309,7 +309,7 @@ bool WebAssemblyAsmTypeCheck::getSignature(SMLoc ErrorLoc,
}

bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc, bool ExactMatch) {
bool Error = checkAndPopTypes(ErrorLoc, ReturnTypes, ExactMatch);
bool Error = popTypes(ErrorLoc, ReturnTypes, ExactMatch);
Unreachable = true;
return Error;
}
Expand All @@ -326,12 +326,14 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst,
pushType(Type);
return false;
}
pushType(Any{});
return true;
}

if (Name == "local.set") {
if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type))
return popType(ErrorLoc, Type);
popType(ErrorLoc, Any{});
return true;
}

Expand All @@ -341,6 +343,8 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst,
pushType(Type);
return Error;
}
popType(ErrorLoc, Any{});
pushType(Any{});
return true;
}

Expand All @@ -349,12 +353,14 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst,
pushType(Type);
return false;
}
pushType(Any{});
return true;
}

if (Name == "global.set") {
if (!getGlobal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type))
return popType(ErrorLoc, Type);
popType(ErrorLoc, Any{});
return true;
}

Expand All @@ -364,16 +370,21 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst,
pushType(Type);
return Error;
}
pushType(Any{});
return true;
}

if (Name == "table.set") {
bool Error = false;
if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type))
Error |= popType(ErrorLoc, Type);
else
SmallVector<StackType, 2> PopTypes;
PopTypes.push_back(wasm::ValType::I32);
if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
PopTypes.push_back(Type);
} else {
Error = true;
Error |= popType(ErrorLoc, wasm::ValType::I32);
PopTypes.push_back(Any{});
}
Comment on lines +379 to +386
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that given that we are now passing a vector of types, the order of types should be in reverse, because the types in the vector will be popped from the end.

Error |= popTypes(ErrorLoc, PopTypes);
return Error;
}

Expand All @@ -384,22 +395,32 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst,
}

if (Name == "table.grow") {
bool Error = popType(ErrorLoc, wasm::ValType::I32);
if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type))
Error |= popType(ErrorLoc, Type);
else
bool Error = false;
SmallVector<StackType, 2> PopTypes;
if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
PopTypes.push_back(Type);
} else {
Error = true;
PopTypes.push_back(Any{});
}
PopTypes.push_back(wasm::ValType::I32);
Error |= popTypes(ErrorLoc, PopTypes);
pushType(wasm::ValType::I32);
return Error;
}

if (Name == "table.fill") {
bool Error = popType(ErrorLoc, wasm::ValType::I32);
if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type))
Error |= popType(ErrorLoc, Type);
else
bool Error = false;
SmallVector<StackType, 2> PopTypes;
PopTypes.push_back(wasm::ValType::I32);
if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
PopTypes.push_back(Type);
} else {
Error = true;
Error |= popType(ErrorLoc, wasm::ValType::I32);
PopTypes.push_back(Any{});
}
PopTypes.push_back(wasm::ValType::I32);
Error |= popTypes(ErrorLoc, PopTypes);
return Error;
}

Expand Down Expand Up @@ -525,7 +546,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst,
if (Op.OperandType == MCOI::OPERAND_REGISTER)
PopTypes.push_back(WebAssembly::regClassToValType(Op.RegClass));
}
bool Error = checkAndPopTypes(ErrorLoc, PopTypes, false);
bool Error = popTypes(ErrorLoc, PopTypes);
SmallVector<wasm::ValType, 4> PushTypes;
// Now push all the defs onto the stack.
for (unsigned I = 0; I < II.getNumDefs(); I++) {
Expand Down
16 changes: 10 additions & 6 deletions llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,21 @@ class WebAssemblyAsmTypeCheck final {
bool Unreachable = false;
bool Is64;

// checkTypes checks 'Types' against the value stack. popTypes checks 'Types'
// against the value stack and also pops them.
//
// If ExactMatch is true, 'Types' will be compared against not only the top of
// the value stack but the whole remaining value stack
// (TODO: This should be the whole remaining value stack "at the the current
// block level", which has not been implemented yet)
bool checkTypes(SMLoc ErrorLoc, ArrayRef<wasm::ValType> Types,
bool ExactMatch);
bool checkTypes(SMLoc ErrorLoc, ArrayRef<StackType> Types, bool ExactMatch);
bool checkAndPopTypes(SMLoc ErrorLoc, ArrayRef<wasm::ValType> Types,
bool ExactMatch);
bool checkAndPopTypes(SMLoc ErrorLoc, ArrayRef<StackType> Types,
bool ExactMatch);
bool ExactMatch = false);
bool checkTypes(SMLoc ErrorLoc, ArrayRef<StackType> Types,
bool ExactMatch = false);
bool popTypes(SMLoc ErrorLoc, ArrayRef<wasm::ValType> Types,
bool ExactMatch = false);
bool popTypes(SMLoc ErrorLoc, ArrayRef<StackType> Types,
bool ExactMatch = false);
bool popType(SMLoc ErrorLoc, StackType Type);
bool popRefType(SMLoc ErrorLoc);
bool popAnyType(SMLoc ErrorLoc);
Expand Down
60 changes: 40 additions & 20 deletions llvm/test/MC/WebAssembly/type-checker-errors.s
Original file line number Diff line number Diff line change
Expand Up @@ -139,31 +139,30 @@ table_set_missing_tabletype:

table_set_empty_stack_while_popping_1:
.functype table_set_empty_stack_while_popping_1 () -> ()
# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got []
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got []
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, externref] but got []
table.set valid_table
end_function

table_set_empty_stack_while_popping_2:
.functype table_set_empty_stack_while_popping_2 (externref) -> ()
local.get 0
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got []
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, externref] but got [externref]
table.set valid_table
end_function

table_set_type_mismatch_1:
.functype table_set_type_mismatch_1 () -> ()
i32.const 0
ref.null_func
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [externref] but got [funcref]
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, externref] but got [i32, funcref]
table.set valid_table
end_function

table_set_type_mismatch_2:
.functype table_set_type_mismatch_2 () -> ()
f32.const 1.0
ref.null_extern
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32]
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, externref] but got [f32, externref]
table.set valid_table
end_function

Expand All @@ -187,25 +186,22 @@ table_fill_missing_tabletype:

table_fill_empty_stack_while_popping_1:
.functype table_fill_empty_stack_while_popping_1 () -> ()
# CHECK: :[[@LINE+3]]:3: error: type mismatch, expected [i32] but got []
# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got []
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got []
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, externref, i32] but got []
table.fill valid_table
end_function

table_fill_empty_stack_while_popping_2:
.functype table_fill_empty_stack_while_popping_2 (i32) -> ()
local.get 0
# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got []
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got []
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, externref, i32] but got [i32]
table.fill valid_table
end_function

table_fill_empty_stack_while_popping_3:
.functype table_fill_empty_stack_while_popping_3 (i32, externref) -> ()
local.get 1
local.get 0
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got []
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, externref, i32] but got [externref, i32]
table.fill valid_table
end_function

Expand All @@ -214,7 +210,7 @@ table_fill_type_mismatch_1:
i32.const 0
ref.null_extern
ref.null_func
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [funcref]
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, externref, i32] but got [i32, externref, funcref]
table.fill valid_table
end_function

Expand All @@ -223,7 +219,7 @@ table_fill_type_mismatch_2:
i32.const 0
ref.null_func
i32.const 1
# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [externref] but got [funcref]
# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32, externref, i32] but got [i32, funcref, i32]
table.fill valid_table
end_function

Expand All @@ -232,7 +228,7 @@ table_fill_type_mismatch_3:
f32.const 2.0
ref.null_extern
i32.const 1
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32]
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, externref, i32] but got [f32, externref, i32]
table.fill valid_table
end_function

Expand All @@ -241,7 +237,7 @@ table_fill_type_mismatch_4:
i32.const 1
ref.null_exn
i32.const 1
# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [externref] but got [exnref]
# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32, externref, i32] but got [i32, exnref, i32]
table.fill valid_table
end_function

Expand All @@ -256,15 +252,15 @@ table_grow_non_exist_table:
table_grow_type_mismatch_1:
.functype table_grow_type_mismatch_1 (externref, i32) -> (i32)
local.get 1
# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [externref] but got []
# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [externref, i32] but got [i32]
table.grow valid_table
end_function

table_grow_type_mismatch_2:
.functype table_grow_type_mismatch_2 (externref, i32) -> (i32)
local.get 0
local.get 0
# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32] but got [externref]
# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [externref, i32] but got [externref, externref]
table.grow valid_table
end_function

Expand Down Expand Up @@ -883,9 +879,7 @@ multiple_errors_in_function:
# CHECK: :[[@LINE+1]]:13: error: expected expression operand
table.get 1

# CHECK: :[[@LINE+3]]:3: error: type mismatch, expected [i32] but got []
# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got []
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got []
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, externref, i32] but got [any]
table.fill valid_table

f32.const 0.0
Expand All @@ -905,3 +899,29 @@ call_with_multi_param_and_return:
call take_and_return_multi
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [i32, i64, f32, f64]
end_function

.functype callee (f32, i32) -> ()

any_value_on_stack:
.functype any_value_on_stack () -> ()
# This local does not exist so it should error out, but it should put an 'any'
# value on the stack so 'call callee' should not error out again
# CHECK: :[[@LINE+1]]:13: error: no local type specified for index 0
local.get 0
i32.const 0
# CHECK-NOT: :[[@LINE+1]]:3: error: type mismatch
call callee

# But this time 'call callee' should error out
i32.const 0
# CHECK: :[[@LINE+1]]:13: error: no local type specified for index 0
local.get 0
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32, i32] but got [i32, any]
call callee

# CHECK: :[[@LINE+2]]:13: error: no local type specified for index 0
# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got []
local.set 0
drop

end_function
Loading