[WebAssembly] replaced .param/.result by .functype
Summary:
This makes it easier/cleaner to generate a single signature from
this directive. Also:
- Adds the symbol name, such that we don't depend on the location
of this directive anymore.
- Actually constructs the signature in the assembler, and make the
assembler own it.
- Refactor the use of MVT vs ValType in the streamer and assembler
to require less conversions overall.
- Changed 700 or so tests to use it.
Reviewers: sbc100, dschuff
Subscribers: jgravelle-google, eraman, aheejin, sunfish, jfb, llvm-commits
Differential Revision: https://reviews.llvm.org/D54652
llvm-svn: 347228
diff --git a/llvm/lib/MC/MCParser/AsmLexer.cpp b/llvm/lib/MC/MCParser/AsmLexer.cpp
index c8d48f0..2b0d20f 100644
--- a/llvm/lib/MC/MCParser/AsmLexer.cpp
+++ b/llvm/lib/MC/MCParser/AsmLexer.cpp
@@ -627,7 +627,6 @@
return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1));
case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1));
case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1));
- case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1));
case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1));
case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1));
case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1));
@@ -646,6 +645,12 @@
return AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2));
}
return AsmToken(AsmToken::Equal, StringRef(TokStart, 1));
+ case '-':
+ if (*CurPtr == '>') {
+ ++CurPtr;
+ return AsmToken(AsmToken::MinusGreater, StringRef(TokStart, 2));
+ }
+ return AsmToken(AsmToken::Minus, StringRef(TokStart, 1));
case '|':
if (*CurPtr == '|') {
++CurPtr;
diff --git a/llvm/lib/MC/MCParser/MCAsmLexer.cpp b/llvm/lib/MC/MCParser/MCAsmLexer.cpp
index 1ed0568..10960fc 100644
--- a/llvm/lib/MC/MCParser/MCAsmLexer.cpp
+++ b/llvm/lib/MC/MCParser/MCAsmLexer.cpp
@@ -85,6 +85,7 @@
case AsmToken::LessGreater: OS << "LessGreater"; break;
case AsmToken::LessLess: OS << "LessLess"; break;
case AsmToken::Minus: OS << "Minus"; break;
+ case AsmToken::MinusGreater: OS << "MinusGreater"; break;
case AsmToken::Percent: OS << "Percent"; break;
case AsmToken::Pipe: OS << "Pipe"; break;
case AsmToken::PipePipe: OS << "PipePipe"; break;
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 703ea2d..bc2ec11 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -133,6 +133,9 @@
MCAsmParser &Parser;
MCAsmLexer &Lexer;
+ // Much like WebAssemblyAsmPrinter in the backend, we have to own these.
+ std::vector<std::unique_ptr<wasm::WasmSignature>> Signatures;
+
public:
WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
const MCInstrInfo &MII, const MCTargetOptions &Options)
@@ -141,6 +144,10 @@
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
}
+ void addSignature(std::unique_ptr<wasm::WasmSignature> &&Sig) {
+ Signatures.push_back(std::move(Sig));
+ }
+
#define GET_ASSEMBLER_HEADER
#include "WebAssemblyGenAsmMatcher.inc"
@@ -168,39 +175,40 @@
return false;
}
-
- std::pair<MVT::SimpleValueType, unsigned>
- ParseRegType(const StringRef &RegType) {
- // Derive type from .param .local decls, or the instruction itself.
- return StringSwitch<std::pair<MVT::SimpleValueType, unsigned>>(RegType)
- .Case("i32", {MVT::i32, wasm::WASM_TYPE_I32})
- .Case("i64", {MVT::i64, wasm::WASM_TYPE_I64})
- .Case("f32", {MVT::f32, wasm::WASM_TYPE_F32})
- .Case("f64", {MVT::f64, wasm::WASM_TYPE_F64})
- .Case("i8x16", {MVT::v16i8, wasm::WASM_TYPE_V128})
- .Case("i16x8", {MVT::v8i16, wasm::WASM_TYPE_V128})
- .Case("i32x4", {MVT::v4i32, wasm::WASM_TYPE_V128})
- .Case("i64x2", {MVT::v2i64, wasm::WASM_TYPE_V128})
- .Case("f32x4", {MVT::v4f32, wasm::WASM_TYPE_V128})
- .Case("f64x2", {MVT::v2f64, wasm::WASM_TYPE_V128})
- // arbitrarily chosen vector type to associate with "v128"
- // FIXME: should these be EVTs to avoid this arbitrary hack? Do we want
- // to accept more specific SIMD register types?
- .Case("v128", {MVT::v16i8, wasm::WASM_TYPE_V128})
- .Default({MVT::INVALID_SIMPLE_VALUE_TYPE, wasm::WASM_TYPE_NORESULT});
+ StringRef ExpectIdent() {
+ if (!Lexer.is(AsmToken::Identifier)) {
+ Error("Expected identifier, got: ", Lexer.getTok());
+ return StringRef();
+ }
+ auto Name = Lexer.getTok().getString();
+ Parser.Lex();
+ return Name;
}
- bool ParseRegTypeList(std::vector<MVT> &Types) {
+ Optional<wasm::ValType> ParseType(const StringRef &Type) {
+ // FIXME: can't use StringSwitch because wasm::ValType doesn't have a
+ // "invalid" value.
+ if (Type == "i32") return wasm::ValType::I32;
+ if (Type == "i64") return wasm::ValType::I64;
+ if (Type == "f32") return wasm::ValType::F32;
+ if (Type == "f64") return wasm::ValType::F64;
+ if (Type == "v128" || Type == "i8x16" || Type == "i16x8" ||
+ Type == "i32x4" || Type == "i64x2" || Type == "f32x4" ||
+ Type == "f64x2") return wasm::ValType::V128;
+ return Optional<wasm::ValType>();
+ }
+
+ bool ParseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {
while (Lexer.is(AsmToken::Identifier)) {
- auto RegType = ParseRegType(Lexer.getTok().getString()).first;
- if (RegType == MVT::INVALID_SIMPLE_VALUE_TYPE)
+ auto Type = ParseType(Lexer.getTok().getString());
+ if (!Type)
return true;
- Types.push_back(RegType);
+ Types.push_back(Type.getValue());
Parser.Lex();
if (!IsNext(AsmToken::Comma))
break;
}
- return Expect(AsmToken::EndOfStatement, "EOL");
+ return false;
}
void ParseSingleInteger(bool IsNegative, OperandVector &Operands) {
@@ -343,44 +351,47 @@
// TODO: any time we return an error, at least one token must have been
// consumed, otherwise this will not signal an error to the caller.
if (DirectiveID.getString() == ".globaltype") {
- if (!Lexer.is(AsmToken::Identifier))
- return Error("Expected symbol name after .globaltype directive, got: ",
- Lexer.getTok());
- auto Name = Lexer.getTok().getString();
- Parser.Lex();
- if (!IsNext(AsmToken::Comma))
- return Error("Expected `,`, got: ", Lexer.getTok());
- if (!Lexer.is(AsmToken::Identifier))
- return Error("Expected type in .globaltype directive, got: ",
- Lexer.getTok());
- auto Type = ParseRegType(Lexer.getTok().getString()).second;
- if (Type == wasm::WASM_TYPE_NORESULT)
- return Error("Unknown type in .globaltype directive: ",
- Lexer.getTok());
- Parser.Lex();
+ auto SymName = ExpectIdent();
+ if (SymName.empty()) return true;
+ if (Expect(AsmToken::Comma, ",")) return true;
+ auto TypeTok = Lexer.getTok();
+ auto TypeName = ExpectIdent();
+ if (TypeName.empty()) return true;
+ auto Type = ParseType(TypeName);
+ if (!Type)
+ return Error("Unknown type in .globaltype directive: ", TypeTok);
// Now set this symbol with the correct type.
auto WasmSym = cast<MCSymbolWasm>(
- TOut.getStreamer().getContext().getOrCreateSymbol(Name));
+ TOut.getStreamer().getContext().getOrCreateSymbol(SymName));
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
- WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(Type), true});
+ WasmSym->setGlobalType(
+ wasm::WasmGlobalType{uint8_t(Type.getValue()), true});
// And emit the directive again.
TOut.emitGlobalType(WasmSym);
return Expect(AsmToken::EndOfStatement, "EOL");
- } else if (DirectiveID.getString() == ".param") {
- std::vector<MVT> Params;
- if (ParseRegTypeList(Params)) return true;
- TOut.emitParam(nullptr /* unused */, Params);
- return false;
- } else if (DirectiveID.getString() == ".result") {
- std::vector<MVT> Results;
- if (ParseRegTypeList(Results)) return true;
- TOut.emitResult(nullptr /* unused */, Results);
- return false;
+ } else if (DirectiveID.getString() == ".functype") {
+ auto SymName = ExpectIdent();
+ if (SymName.empty()) return true;
+ auto WasmSym = cast<MCSymbolWasm>(
+ TOut.getStreamer().getContext().getOrCreateSymbol(SymName));
+ auto Signature = make_unique<wasm::WasmSignature>();
+ if (Expect(AsmToken::LParen, "(")) return true;
+ if (ParseRegTypeList(Signature->Params)) return true;
+ if (Expect(AsmToken::RParen, ")")) return true;
+ if (Expect(AsmToken::MinusGreater, "->")) return true;
+ if (Expect(AsmToken::LParen, "(")) return true;
+ if (ParseRegTypeList(Signature->Returns)) return true;
+ if (Expect(AsmToken::RParen, ")")) return true;
+ WasmSym->setSignature(Signature.get());
+ addSignature(std::move(Signature));
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
+ TOut.emitFunctionType(WasmSym);
+ return Expect(AsmToken::EndOfStatement, "EOL");
} else if (DirectiveID.getString() == ".local") {
- std::vector<MVT> Locals;
+ SmallVector<wasm::ValType, 4> Locals;
if (ParseRegTypeList(Locals)) return true;
TOut.emitLocal(Locals);
- return false;
+ return Expect(AsmToken::EndOfStatement, "EOL");
}
return true; // We didn't process this directive.
}
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
index ada687e..5f06da8 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
@@ -39,43 +39,19 @@
WebAssemblyTargetWasmStreamer::WebAssemblyTargetWasmStreamer(MCStreamer &S)
: WebAssemblyTargetStreamer(S) {}
-static void PrintTypes(formatted_raw_ostream &OS, ArrayRef<MVT> Types) {
+static void PrintTypes(formatted_raw_ostream &OS, ArrayRef<wasm::ValType> Types) {
bool First = true;
- for (MVT Type : Types) {
+ for (auto Type : Types) {
if (First)
First = false;
else
OS << ", ";
- OS << WebAssembly::TypeToString(WebAssembly::toValType(Type));
+ OS << WebAssembly::TypeToString(Type);
}
OS << '\n';
}
-void WebAssemblyTargetAsmStreamer::emitParam(MCSymbol *Symbol,
- ArrayRef<MVT> Types) {
- if (!Types.empty()) {
- OS << "\t.param \t";
-
- // FIXME: Currently this applies to the "current" function; it may
- // be cleaner to specify an explicit symbol as part of the directive.
-
- PrintTypes(OS, Types);
- }
-}
-
-void WebAssemblyTargetAsmStreamer::emitResult(MCSymbol *Symbol,
- ArrayRef<MVT> Types) {
- if (!Types.empty()) {
- OS << "\t.result \t";
-
- // FIXME: Currently this applies to the "current" function; it may
- // be cleaner to specify an explicit symbol as part of the directive.
-
- PrintTypes(OS, Types);
- }
-}
-
-void WebAssemblyTargetAsmStreamer::emitLocal(ArrayRef<MVT> Types) {
+void WebAssemblyTargetAsmStreamer::emitLocal(ArrayRef<wasm::ValType> Types) {
if (!Types.empty()) {
OS << "\t.local \t";
PrintTypes(OS, Types);
@@ -84,19 +60,20 @@
void WebAssemblyTargetAsmStreamer::emitEndFunc() { OS << "\t.endfunc\n"; }
-void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType(
- MCSymbolWasm *Symbol) {
- OS << "\t.functype\t" << Symbol->getName();
- if (Symbol->getSignature()->Returns.empty())
- OS << ", void";
- else {
- assert(Symbol->getSignature()->Returns.size() == 1);
- OS << ", "
- << WebAssembly::TypeToString(Symbol->getSignature()->Returns.front());
+void WebAssemblyTargetAsmStreamer::emitFunctionType(MCSymbolWasm *Symbol) {
+ OS << "\t.functype\t" << Symbol->getName() << " (";
+ auto &Params = Symbol->getSignature()->Params;
+ for (auto &Ty : Params) {
+ if (&Ty != &Params[0]) OS << ", ";
+ OS << WebAssembly::TypeToString(Ty);
}
- for (auto Ty : Symbol->getSignature()->Params)
- OS << ", " << WebAssembly::TypeToString(Ty);
- OS << '\n';
+ OS << ") -> (";
+ auto &Returns = Symbol->getSignature()->Returns;
+ for (auto &Ty : Returns) {
+ if (&Ty != &Returns[0]) OS << ", ";
+ OS << WebAssembly::TypeToString(Ty);
+ }
+ OS << ")\n";
}
void WebAssemblyTargetAsmStreamer::emitGlobalType(MCSymbolWasm *Sym) {
@@ -131,19 +108,9 @@
OS << "\t.indidx \t" << *Value << '\n';
}
-void WebAssemblyTargetWasmStreamer::emitParam(MCSymbol *Symbol,
- ArrayRef<MVT> Types) {
- // The Symbol already has its signature
-}
-
-void WebAssemblyTargetWasmStreamer::emitResult(MCSymbol *Symbol,
- ArrayRef<MVT> Types) {
- // The Symbol already has its signature
-}
-
-void WebAssemblyTargetWasmStreamer::emitLocal(ArrayRef<MVT> Types) {
- SmallVector<std::pair<MVT, uint32_t>, 4> Grouped;
- for (MVT Type : Types) {
+void WebAssemblyTargetWasmStreamer::emitLocal(ArrayRef<wasm::ValType> Types) {
+ SmallVector<std::pair<wasm::ValType, uint32_t>, 4> Grouped;
+ for (auto Type : Types) {
if (Grouped.empty() || Grouped.back().first != Type)
Grouped.push_back(std::make_pair(Type, 1));
else
@@ -153,7 +120,7 @@
Streamer.EmitULEB128IntValue(Grouped.size());
for (auto Pair : Grouped) {
Streamer.EmitULEB128IntValue(Pair.second);
- emitValueType(WebAssembly::toValType(Pair.first));
+ emitValueType(Pair.first);
}
}
@@ -165,8 +132,7 @@
llvm_unreachable(".indidx encoding not yet implemented");
}
-void WebAssemblyTargetWasmStreamer::emitIndirectFunctionType(
- MCSymbolWasm *Symbol) {
+void WebAssemblyTargetWasmStreamer::emitFunctionType(MCSymbolWasm *Symbol) {
// Symbol already has its arguments and result set.
Symbol->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
}
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
index 3f1c6e1..0416aa4 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
@@ -31,16 +31,12 @@
public:
explicit WebAssemblyTargetStreamer(MCStreamer &S);
- /// .param
- virtual void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) = 0;
- /// .result
- virtual void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) = 0;
/// .local
- virtual void emitLocal(ArrayRef<MVT> Types) = 0;
+ virtual void emitLocal(ArrayRef<wasm::ValType> Types) = 0;
/// .endfunc
virtual void emitEndFunc() = 0;
/// .functype
- virtual void emitIndirectFunctionType(MCSymbolWasm *Symbol) = 0;
+ virtual void emitFunctionType(MCSymbolWasm *Symbol) = 0;
/// .indidx
virtual void emitIndIdx(const MCExpr *Value) = 0;
/// .globaltype
@@ -61,11 +57,9 @@
public:
WebAssemblyTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
- void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
- void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
- void emitLocal(ArrayRef<MVT> Types) override;
+ void emitLocal(ArrayRef<wasm::ValType> Types) override;
void emitEndFunc() override;
- void emitIndirectFunctionType(MCSymbolWasm *Symbol) override;
+ void emitFunctionType(MCSymbolWasm *Symbol) override;
void emitIndIdx(const MCExpr *Value) override;
void emitGlobalType(MCSymbolWasm *Sym) override;
void emitEventType(MCSymbolWasm *Sym) override;
@@ -77,11 +71,9 @@
public:
explicit WebAssemblyTargetWasmStreamer(MCStreamer &S);
- void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
- void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
- void emitLocal(ArrayRef<MVT> Types) override;
+ void emitLocal(ArrayRef<wasm::ValType> Types) override;
void emitEndFunc() override;
- void emitIndirectFunctionType(MCSymbolWasm *Symbol) override;
+ void emitFunctionType(MCSymbolWasm *Symbol) override;
void emitIndIdx(const MCExpr *Value) override;
void emitGlobalType(MCSymbolWasm *Sym) override;
void emitEventType(MCSymbolWasm *Sym) override;
@@ -94,15 +86,13 @@
explicit WebAssemblyTargetNullStreamer(MCStreamer &S)
: WebAssemblyTargetStreamer(S) {}
- void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override {}
- void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override {}
- void emitLocal(ArrayRef<MVT> Types) override {}
+ void emitLocal(ArrayRef<wasm::ValType>) override {}
void emitEndFunc() override {}
- void emitIndirectFunctionType(MCSymbolWasm *Symbol) override {}
- void emitIndIdx(const MCExpr *Value) override {}
- void emitGlobalType(MCSymbolWasm *Sym) override {}
- void emitEventType(MCSymbolWasm *Sym) override {}
- void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) override {}
+ void emitFunctionType(MCSymbolWasm *) override {}
+ void emitIndIdx(const MCExpr *) override {}
+ void emitGlobalType(MCSymbolWasm *) override {}
+ void emitEventType(MCSymbolWasm *) override {}
+ void emitImportModule(MCSymbolWasm *, StringRef) override {}
};
} // end namespace llvm
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 66fa91b..afe975a 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -104,7 +104,7 @@
// infer the type from a call). With object files it applies to all
// imports. so fix the names and the tests, or rethink how import
// delcarations work in asm files.
- getTargetStreamer()->emitIndirectFunctionType(Sym);
+ getTargetStreamer()->emitFunctionType(Sym);
if (TM.getTargetTriple().isOSBinFormatWasm() &&
F.hasFnAttribute("wasm-import-module")) {
@@ -166,7 +166,7 @@
addSignature(std::move(Signature));
// FIXME: clean up how params and results are emitted (use signatures)
- getTargetStreamer()->emitParam(CurrentFnSym, ParamVTs);
+ getTargetStreamer()->emitFunctionType(WasmSym);
// Emit the function index.
if (MDNode *Idx = F.getMetadata("wasm.index")) {
@@ -176,8 +176,9 @@
cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));
}
- getTargetStreamer()->emitResult(CurrentFnSym, ResultVTs);
- getTargetStreamer()->emitLocal(MFI->getLocals());
+ SmallVector<wasm::ValType, 16> Locals;
+ ValTypesFromMVTs(MFI->getLocals(), Locals);
+ getTargetStreamer()->emitLocal(Locals);
AsmPrinter::EmitFunctionBodyStart();
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp
index 073706e..0157af0 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp
@@ -64,13 +64,17 @@
Params.push_back(PtrVT);
}
+void llvm::ValTypesFromMVTs(const ArrayRef<MVT> &In,
+ SmallVectorImpl<wasm::ValType> &Out) {
+ for (MVT Ty : In)
+ Out.push_back(WebAssembly::toValType(Ty));
+}
+
std::unique_ptr<wasm::WasmSignature>
llvm::SignatureFromMVTs(const SmallVectorImpl<MVT> &Results,
const SmallVectorImpl<MVT> &Params) {
auto Sig = make_unique<wasm::WasmSignature>();
- for (MVT Ty : Results)
- Sig->Returns.push_back(WebAssembly::toValType(Ty));
- for (MVT Ty : Params)
- Sig->Params.push_back(WebAssembly::toValType(Ty));
+ ValTypesFromMVTs(Results, Sig->Returns);
+ ValTypesFromMVTs(Params, Sig->Params);
return Sig;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
index cde44d2..4be4beb 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
@@ -129,6 +129,9 @@
const TargetMachine &TM, SmallVectorImpl<MVT> &Params,
SmallVectorImpl<MVT> &Results);
+void ValTypesFromMVTs(const ArrayRef<MVT> &In,
+ SmallVectorImpl<wasm::ValType> &Out);
+
std::unique_ptr<wasm::WasmSignature>
SignatureFromMVTs(const SmallVectorImpl<MVT> &Results,
const SmallVectorImpl<MVT> &Params);