diff options
Diffstat (limited to 'llvm/lib/Target/WebAssembly')
24 files changed, 240 insertions, 154 deletions
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 7d1e6c553f81..56689d3ee06b 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -571,7 +571,6 @@ public: // proper nesting. bool ExpectBlockType = false; bool ExpectFuncType = false; - bool ExpectHeapType = false; std::unique_ptr<WebAssemblyOperand> FunctionTable; if (Name == "block") { push(Block); @@ -624,8 +623,6 @@ public: if (parseFunctionTableOperand(&FunctionTable)) return true; ExpectFuncType = true; - } else if (Name == "ref.null") { - ExpectHeapType = true; } if (ExpectFuncType || (ExpectBlockType && Lexer.is(AsmToken::LParen))) { @@ -670,15 +667,6 @@ public: return error("Unknown block type: ", Id); addBlockTypeOperand(Operands, NameLoc, BT); Parser.Lex(); - } else if (ExpectHeapType) { - auto HeapType = WebAssembly::parseHeapType(Id.getString()); - if (HeapType == WebAssembly::HeapType::Invalid) { - return error("Expected a heap type: ", Id); - } - Operands.push_back(std::make_unique<WebAssemblyOperand>( - WebAssemblyOperand::Integer, Id.getLoc(), Id.getEndLoc(), - WebAssemblyOperand::IntOp{static_cast<int64_t>(HeapType)})); - Parser.Lex(); } else { // Assume this identifier is a label. const MCExpr *Val; diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp index a6b5d4252f2f..128ce5c4fec0 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp @@ -112,9 +112,18 @@ bool WebAssemblyAsmTypeCheck::getLocal(SMLoc ErrorLoc, const MCInst &Inst, return false; } -bool WebAssemblyAsmTypeCheck::checkEnd(SMLoc ErrorLoc) { +bool WebAssemblyAsmTypeCheck::checkEnd(SMLoc ErrorLoc, bool PopVals) { if (LastSig.Returns.size() > Stack.size()) return typeError(ErrorLoc, "end: insufficient values on the type stack"); + + if (PopVals) { + for (auto VT : llvm::reverse(LastSig.Returns)) { + if (popType(ErrorLoc, VT)) + return true; + } + return false; + } + for (size_t i = 0; i < LastSig.Returns.size(); i++) { auto EVT = LastSig.Returns[i]; auto PVT = Stack[Stack.size() - LastSig.Returns.size() + i]; @@ -221,7 +230,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst) { return true; } else if (Name == "end_block" || Name == "end_loop" || Name == "end_if" || Name == "else" || Name == "end_try") { - if (checkEnd(ErrorLoc)) + if (checkEnd(ErrorLoc, Name == "else")) return true; if (Name == "end_block") Unreachable = false; diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h index aa35213ccca3..2b07faf67a18 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h @@ -39,7 +39,7 @@ class WebAssemblyAsmTypeCheck final { bool typeError(SMLoc ErrorLoc, const Twine &Msg); bool popType(SMLoc ErrorLoc, Optional<wasm::ValType> EVT); bool getLocal(SMLoc ErrorLoc, const MCInst &Inst, wasm::ValType &Type); - bool checkEnd(SMLoc ErrorLoc); + bool checkEnd(SMLoc ErrorLoc, bool PopVals = false); bool checkSig(SMLoc ErrorLoc, const wasm::WasmSignature &Sig); bool getSymRef(SMLoc ErrorLoc, const MCInst &Inst, const MCSymbolRefExpr *&SymRef); diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp index 2e1e4f061219..5d38145559da 100644 --- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp +++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp @@ -241,28 +241,6 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction( } break; } - // heap_type operands, for e.g. ref.null: - case WebAssembly::OPERAND_HEAPTYPE: { - int64_t Val; - uint64_t PrevSize = Size; - if (!nextLEB(Val, Bytes, Size, true)) - return MCDisassembler::Fail; - if (Val < 0 && Size == PrevSize + 1) { - // The HeapType encoding is like BlockType, in that encodings that - // decode as negative values indicate ValTypes. In practice we expect - // either wasm::ValType::EXTERNREF or wasm::ValType::FUNCREF here. - // - // The positive SLEB values are reserved for future expansion and are - // expected to be type indices in the typed function references - // proposal, and should disassemble as MCSymbolRefExpr as in BlockType - // above. - MI.addOperand(MCOperand::createImm(Val & 0x7f)); - } else { - MI.addOperand( - MCOperand::createImm(int64_t(WebAssembly::HeapType::Invalid))); - } - break; - } // FP operands. case WebAssembly::OPERAND_F32IMM: { if (!parseImmediate<float>(MI, Size, Bytes)) diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp index 2967aaa00ad4..d72bfdbbfb99 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp @@ -366,26 +366,3 @@ void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI, } } } - -void WebAssemblyInstPrinter::printWebAssemblyHeapTypeOperand(const MCInst *MI, - unsigned OpNo, - raw_ostream &O) { - const MCOperand &Op = MI->getOperand(OpNo); - if (Op.isImm()) { - switch (Op.getImm()) { - case long(wasm::ValType::EXTERNREF): - O << "extern"; - break; - case long(wasm::ValType::FUNCREF): - O << "func"; - break; - default: - O << "unsupported_heap_type_value"; - break; - } - } else { - // Typed function references and other subtypes of funcref and externref - // currently unimplemented. - O << "unsupported_heap_type_operand"; - } -} diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h index 7d980c78c3c9..fe104cbca12e 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h @@ -47,8 +47,6 @@ public: raw_ostream &O); void printWebAssemblySignatureOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); - void printWebAssemblyHeapTypeOperand(const MCInst *MI, unsigned OpNo, - raw_ostream &O); // Autogenerated by tblgen. std::pair<const char *, uint64_t> getMnemonic(const MCInst *MI) override; diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp index c3d259e6ff20..d8122950e061 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "WebAssemblyMCAsmInfo.h" +#include "Utils/WebAssemblyUtilities.h" #include "llvm/ADT/Triple.h" using namespace llvm; @@ -44,5 +45,13 @@ WebAssemblyMCAsmInfo::WebAssemblyMCAsmInfo(const Triple &T, SupportsDebugInformation = true; + // When compilation is done on a cpp file by clang, the exception model info + // is stored in LangOptions, which is later used to set the info in + // TargetOptions and then MCAsmInfo in LLVMTargetMachine::initAsmInfo(). But + // this process does not happen when compiling bitcode directly with clang, so + // we make sure this info is set correctly. + if (WebAssembly::WasmEnableEH || WebAssembly::WasmEnableSjLj) + ExceptionsType = ExceptionHandling::Wasm; + // TODO: UseIntegratedAssembler? } diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp index 4961c2ef9529..6e494b9430f7 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp @@ -106,9 +106,6 @@ void WebAssemblyMCCodeEmitter::encodeInstruction( encodeSLEB128(int64_t(MO.getImm()), OS); break; case WebAssembly::OPERAND_SIGNATURE: - case WebAssembly::OPERAND_HEAPTYPE: - OS << uint8_t(MO.getImm()); - break; case WebAssembly::OPERAND_VEC_I8IMM: support::endian::write<uint8_t>(OS, MO.getImm(), support::little); break; diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index d07bfce9abc1..b2f10ca93a4f 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -78,8 +78,6 @@ enum OperandType { OPERAND_BRLIST, /// 32-bit unsigned table number. OPERAND_TABLE, - /// heap type immediate for ref.null. - OPERAND_HEAPTYPE, }; } // end namespace WebAssembly diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp index 6f81431bba2d..0412e524f800 100644 --- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp @@ -41,13 +41,6 @@ Optional<wasm::ValType> WebAssembly::parseType(StringRef Type) { return Optional<wasm::ValType>(); } -WebAssembly::HeapType WebAssembly::parseHeapType(StringRef Type) { - return StringSwitch<WebAssembly::HeapType>(Type) - .Case("extern", WebAssembly::HeapType::Externref) - .Case("func", WebAssembly::HeapType::Funcref) - .Default(WebAssembly::HeapType::Invalid); -} - WebAssembly::BlockType WebAssembly::parseBlockType(StringRef Type) { // Multivalue block types are handled separately in parseSignature return StringSwitch<WebAssembly::BlockType>(Type) diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h index 8d757df27b34..042d51c7d6cb 100644 --- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h +++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h @@ -41,17 +41,9 @@ enum class BlockType : unsigned { Multivalue = 0xffff, }; -/// Used as immediate MachineOperands for heap types, e.g. for ref.null. -enum class HeapType : unsigned { - Invalid = 0x00, - Externref = unsigned(wasm::ValType::EXTERNREF), - Funcref = unsigned(wasm::ValType::FUNCREF), -}; - // Convert StringRef to ValType / HealType / BlockType Optional<wasm::ValType> parseType(StringRef Type); -HeapType parseHeapType(StringRef Type); BlockType parseBlockType(StringRef Type); MVT parseMVT(StringRef Type); diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp index 3da80f4fc875..b87c884c9e4a 100644 --- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp @@ -18,6 +18,31 @@ #include "llvm/MC/MCContext.h" using namespace llvm; +// Exception handling & setjmp-longjmp handling related options. These are +// defined here to be shared between WebAssembly and its subdirectories. + +// Emscripten's asm.js-style exception handling +cl::opt<bool> WebAssembly::WasmEnableEmEH( + "enable-emscripten-cxx-exceptions", + cl::desc("WebAssembly Emscripten-style exception handling"), + cl::init(false)); +// Emscripten's asm.js-style setjmp/longjmp handling +cl::opt<bool> WebAssembly::WasmEnableEmSjLj( + "enable-emscripten-sjlj", + cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"), + cl::init(false)); +// Exception handling using wasm EH instructions +cl::opt<bool> + WebAssembly::WasmEnableEH("wasm-enable-eh", + cl::desc("WebAssembly exception handling"), + cl::init(false)); +// setjmp/longjmp handling using wasm EH instrutions +cl::opt<bool> + WebAssembly::WasmEnableSjLj("wasm-enable-sjlj", + cl::desc("WebAssembly setjmp/longjmp handling"), + cl::init(false)); + +// Function names in libc++abi and libunwind const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch"; const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow"; const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev"; diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.h index f6e96d9b2877..d024185defb4 100644 --- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.h @@ -16,6 +16,7 @@ #define LLVM_LIB_TARGET_WEBASSEMBLY_UTILS_WEBASSEMBLYUTILITIES_H #include "llvm/IR/DerivedTypes.h" +#include "llvm/Support/CommandLine.h" namespace llvm { @@ -70,6 +71,12 @@ inline bool isRefType(const Type *Ty) { bool isChild(const MachineInstr &MI, const WebAssemblyFunctionInfo &MFI); bool mayThrow(const MachineInstr &MI); +// Exception handling / setjmp-longjmp handling command-line options +extern cl::opt<bool> WasmEnableEmEH; // asm.js-style EH +extern cl::opt<bool> WasmEnableEmSjLj; // asm.js-style SjLJ +extern cl::opt<bool> WasmEnableEH; // EH using Wasm EH instructions +extern cl::opt<bool> WasmEnableSjLj; // SjLj using Wasm EH instructions + // Exception-related function names extern const char *const ClangCallTerminateFn; extern const char *const CxaBeginCatchFn; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 0d3f51693261..e3af6b2662ef 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -51,8 +51,6 @@ using namespace llvm; #define DEBUG_TYPE "asm-printer" extern cl::opt<bool> WasmKeepRegisters; -extern cl::opt<bool> WasmEnableEmEH; -extern cl::opt<bool> WasmEnableEmSjLj; //===----------------------------------------------------------------------===// // Helpers. @@ -196,6 +194,13 @@ void WebAssemblyAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { Sym->setGlobalType(wasm::WasmGlobalType{uint8_t(Type), Mutable}); } + // If the GlobalVariable refers to a table, we handle it here instead of + // in emitExternalDecls + if (Sym->isTable()) { + getTargetStreamer()->emitTableType(Sym); + return; + } + emitVisibility(Sym, GV->getVisibility(), !GV->isDeclaration()); if (GV->hasInitializer()) { assert(getSymbolPreferLocal(*GV) == Sym); @@ -315,8 +320,9 @@ void WebAssemblyAsmPrinter::emitExternalDecls(const Module &M) { // will discard it later if it turns out not to be necessary. auto Signature = signatureFromMVTs(Results, Params); bool InvokeDetected = false; - auto *Sym = getMCSymbolForFunction(&F, WasmEnableEmEH || WasmEnableEmSjLj, - Signature.get(), InvokeDetected); + auto *Sym = getMCSymbolForFunction( + &F, WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj, + Signature.get(), InvokeDetected); // Multiple functions can be mapped to the same invoke symbol. For // example, two IR functions '__invoke_void_i8*' and '__invoke_void_i32' diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp index 7832f199a2cc..17e867e4c7d8 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp @@ -1741,7 +1741,7 @@ void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) { void WebAssemblyCFGStackify::cleanupFunctionData(MachineFunction &MF) { if (FakeCallerBB) - MF.DeleteMachineBasicBlock(FakeCallerBB); + MF.deleteMachineBasicBlock(FakeCallerBB); AppendixBB = FakeCallerBB = nullptr; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def index 1fa0ea3867c7..a3a33f4a5b3a 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def @@ -31,6 +31,7 @@ HANDLE_NODETYPE(SWIZZLE) HANDLE_NODETYPE(VEC_SHL) HANDLE_NODETYPE(VEC_SHR_S) HANDLE_NODETYPE(VEC_SHR_U) +HANDLE_NODETYPE(NARROW_U) HANDLE_NODETYPE(EXTEND_LOW_S) HANDLE_NODETYPE(EXTEND_LOW_U) HANDLE_NODETYPE(EXTEND_HIGH_S) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 0df8f3e0e09c..38ed4c73fb93 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -176,6 +176,8 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering( setTargetDAGCombine(ISD::FP_ROUND); setTargetDAGCombine(ISD::CONCAT_VECTORS); + setTargetDAGCombine(ISD::TRUNCATE); + // Support saturating add for i8x16 and i16x8 for (auto Op : {ISD::SADDSAT, ISD::UADDSAT}) for (auto T : {MVT::v16i8, MVT::v8i16}) @@ -644,8 +646,7 @@ LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB, Register RegFuncref = MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass); MachineInstr *RefNull = - BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref) - .addImm(static_cast<int32_t>(WebAssembly::HeapType::Funcref)); + BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref); BB->insertAfter(Const0->getIterator(), RefNull); MachineInstr *TableSet = @@ -2610,6 +2611,114 @@ performVectorTruncZeroCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { return DAG.getNode(Op, SDLoc(N), ResVT, Source); } +// Helper to extract VectorWidth bits from Vec, starting from IdxVal. +static SDValue extractSubVector(SDValue Vec, unsigned IdxVal, SelectionDAG &DAG, + const SDLoc &DL, unsigned VectorWidth) { + EVT VT = Vec.getValueType(); + EVT ElVT = VT.getVectorElementType(); + unsigned Factor = VT.getSizeInBits() / VectorWidth; + EVT ResultVT = EVT::getVectorVT(*DAG.getContext(), ElVT, + VT.getVectorNumElements() / Factor); + + // Extract the relevant VectorWidth bits. Generate an EXTRACT_SUBVECTOR + unsigned ElemsPerChunk = VectorWidth / ElVT.getSizeInBits(); + assert(isPowerOf2_32(ElemsPerChunk) && "Elements per chunk not power of 2"); + + // This is the index of the first element of the VectorWidth-bit chunk + // we want. Since ElemsPerChunk is a power of 2 just need to clear bits. + IdxVal &= ~(ElemsPerChunk - 1); + + // If the input is a buildvector just emit a smaller one. + if (Vec.getOpcode() == ISD::BUILD_VECTOR) + return DAG.getBuildVector(ResultVT, DL, + Vec->ops().slice(IdxVal, ElemsPerChunk)); + + SDValue VecIdx = DAG.getIntPtrConstant(IdxVal, DL); + return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ResultVT, Vec, VecIdx); +} + +// Helper to recursively truncate vector elements in half with NARROW_U. DstVT +// is the expected destination value type after recursion. In is the initial +// input. Note that the input should have enough leading zero bits to prevent +// NARROW_U from saturating results. +static SDValue truncateVectorWithNARROW(EVT DstVT, SDValue In, const SDLoc &DL, + SelectionDAG &DAG) { + EVT SrcVT = In.getValueType(); + + // No truncation required, we might get here due to recursive calls. + if (SrcVT == DstVT) + return In; + + unsigned SrcSizeInBits = SrcVT.getSizeInBits(); + unsigned NumElems = SrcVT.getVectorNumElements(); + if (!isPowerOf2_32(NumElems)) + return SDValue(); + assert(DstVT.getVectorNumElements() == NumElems && "Illegal truncation"); + assert(SrcSizeInBits > DstVT.getSizeInBits() && "Illegal truncation"); + + LLVMContext &Ctx = *DAG.getContext(); + EVT PackedSVT = EVT::getIntegerVT(Ctx, SrcVT.getScalarSizeInBits() / 2); + + // Narrow to the largest type possible: + // vXi64/vXi32 -> i16x8.narrow_i32x4_u and vXi16 -> i8x16.narrow_i16x8_u. + EVT InVT = MVT::i16, OutVT = MVT::i8; + if (SrcVT.getScalarSizeInBits() > 16) { + InVT = MVT::i32; + OutVT = MVT::i16; + } + unsigned SubSizeInBits = SrcSizeInBits / 2; + InVT = EVT::getVectorVT(Ctx, InVT, SubSizeInBits / InVT.getSizeInBits()); + OutVT = EVT::getVectorVT(Ctx, OutVT, SubSizeInBits / OutVT.getSizeInBits()); + + // Split lower/upper subvectors. + SDValue Lo = extractSubVector(In, 0, DAG, DL, SubSizeInBits); + SDValue Hi = extractSubVector(In, NumElems / 2, DAG, DL, SubSizeInBits); + + // 256bit -> 128bit truncate - Narrow lower/upper 128-bit subvectors. + if (SrcVT.is256BitVector() && DstVT.is128BitVector()) { + Lo = DAG.getBitcast(InVT, Lo); + Hi = DAG.getBitcast(InVT, Hi); + SDValue Res = DAG.getNode(WebAssemblyISD::NARROW_U, DL, OutVT, Lo, Hi); + return DAG.getBitcast(DstVT, Res); + } + + // Recursively narrow lower/upper subvectors, concat result and narrow again. + EVT PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems / 2); + Lo = truncateVectorWithNARROW(PackedVT, Lo, DL, DAG); + Hi = truncateVectorWithNARROW(PackedVT, Hi, DL, DAG); + + PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems); + SDValue Res = DAG.getNode(ISD::CONCAT_VECTORS, DL, PackedVT, Lo, Hi); + return truncateVectorWithNARROW(DstVT, Res, DL, DAG); +} + +static SDValue performTruncateCombine(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI) { + auto &DAG = DCI.DAG; + + SDValue In = N->getOperand(0); + EVT InVT = In.getValueType(); + if (!InVT.isSimple()) + return SDValue(); + + EVT OutVT = N->getValueType(0); + if (!OutVT.isVector()) + return SDValue(); + + EVT OutSVT = OutVT.getVectorElementType(); + EVT InSVT = InVT.getVectorElementType(); + // Currently only cover truncate to v16i8 or v8i16. + if (!((InSVT == MVT::i16 || InSVT == MVT::i32 || InSVT == MVT::i64) && + (OutSVT == MVT::i8 || OutSVT == MVT::i16) && OutVT.is128BitVector())) + return SDValue(); + + SDLoc DL(N); + APInt Mask = APInt::getLowBitsSet(InVT.getScalarSizeInBits(), + OutVT.getScalarSizeInBits()); + In = DAG.getNode(ISD::AND, DL, InVT, In, DAG.getConstant(Mask, DL, InVT)); + return truncateVectorWithNARROW(OutVT, In, DL, DAG); +} + SDValue WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { @@ -2626,5 +2735,7 @@ WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N, case ISD::FP_ROUND: case ISD::CONCAT_VECTORS: return performVectorTruncZeroCombine(N, DCI); + case ISD::TRUNCATE: + return performTruncateCombine(N, DCI); } } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index ee9247a8bef9..3fb0af1d47a0 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -202,11 +202,6 @@ def Signature : Operand<i32> { let PrintMethod = "printWebAssemblySignatureOperand"; } -let OperandType = "OPERAND_HEAPTYPE" in -def HeapType : Operand<i32> { - let PrintMethod = "printWebAssemblyHeapTypeOperand"; -} - let OperandType = "OPERAND_TYPEINDEX" in def TypeIndex : Operand<i32>; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td index ef9bd35d004a..76a88caafc47 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td @@ -11,13 +11,14 @@ /// //===----------------------------------------------------------------------===// -multiclass REF_I<WebAssemblyRegClass rc, ValueType vt> { - defm REF_NULL_#rc : I<(outs rc:$res), (ins HeapType:$heaptype), - (outs), (ins HeapType:$heaptype), - [], - "ref.null\t$res, $heaptype", - "ref.null\t$heaptype", - 0xd0>, +multiclass REF_I<WebAssemblyRegClass rc, ValueType vt, string ht> { + defm REF_NULL_#rc : I<(outs rc:$dst), (ins), + (outs), (ins), + [(set rc:$dst, (!cast<Intrinsic>("int_wasm_ref_null_" # ht)))], + "ref.null_" # ht # "$dst", + "ref.null_" # ht, + !cond(!eq(ht, "func") : 0xd070, + !eq(ht, "extern") : 0xd06f)>, Requires<[HasReferenceTypes]>; defm SELECT_#rc: I<(outs rc:$dst), (ins rc:$lhs, rc:$rhs, I32:$cond), (outs), (ins), @@ -28,8 +29,8 @@ multiclass REF_I<WebAssemblyRegClass rc, ValueType vt> { Requires<[HasReferenceTypes]>; } -defm "" : REF_I<FUNCREF, funcref>; -defm "" : REF_I<EXTERNREF, externref>; +defm "" : REF_I<FUNCREF, funcref, "func">; +defm "" : REF_I<EXTERNREF, externref, "extern">; foreach rc = [FUNCREF, EXTERNREF] in { def : Pat<(select (i32 (setne I32:$cond, 0)), rc:$lhs, rc:$rhs), diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td index 30b99c3a69a9..5bb12c7fbdc7 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -1278,6 +1278,14 @@ multiclass SIMDNarrow<Vec vec, bits<32> baseInst> { defm "" : SIMDNarrow<I16x8, 101>; defm "" : SIMDNarrow<I32x4, 133>; +// WebAssemblyISD::NARROW_U +def wasm_narrow_t : SDTypeProfile<1, 2, []>; +def wasm_narrow_u : SDNode<"WebAssemblyISD::NARROW_U", wasm_narrow_t>; +def : Pat<(v16i8 (wasm_narrow_u (v8i16 V128:$left), (v8i16 V128:$right))), + (NARROW_U_I8x16 $left, $right)>; +def : Pat<(v8i16 (wasm_narrow_u (v4i32 V128:$left), (v4i32 V128:$right))), + (NARROW_U_I16x8 $left, $right)>; + // Bitcasts are nops // Matching bitcast t1 to t1 causes strange errors, so avoid repeating types foreach t1 = AllVecs in diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td index e44c2073eaeb..1fd00bf1cbc8 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td @@ -20,7 +20,7 @@ def WebAssemblyTableGet : SDNode<"WebAssemblyISD::TABLE_GET", WebAssemblyTableGe [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; -multiclass TABLE<WebAssemblyRegClass rc> { +multiclass TABLE<WebAssemblyRegClass rc, string suffix> { let mayLoad = 1 in defm TABLE_GET_#rc : I<(outs rc:$res), (ins table32_op:$table, I32:$i), (outs), (ins table32_op:$table), @@ -39,14 +39,14 @@ multiclass TABLE<WebAssemblyRegClass rc> { defm TABLE_GROW_#rc : I<(outs I32:$sz), (ins table32_op:$table, rc:$val, I32:$n), (outs), (ins table32_op:$table), - [], + [(set I32:$sz, (!cast<Intrinsic>("int_wasm_table_grow_" # suffix) (WebAssemblyWrapper tglobaladdr:$table), rc:$val, I32:$n))], "table.grow\t$sz, $table, $val, $n", "table.grow\t$table", 0xfc0f>; defm TABLE_FILL_#rc : I<(outs), (ins table32_op:$table, I32:$i, rc:$val, I32:$n), (outs), (ins table32_op:$table), - [], + [(!cast<Intrinsic>("int_wasm_table_fill_" # suffix) (WebAssemblyWrapper tglobaladdr:$table), I32:$i, rc:$val, I32:$n)], "table.fill\t$table, $i, $val, $n", "table.fill\t$table", 0xfc11>; @@ -62,8 +62,8 @@ multiclass TABLE<WebAssemblyRegClass rc> { } } -defm "" : TABLE<FUNCREF>, Requires<[HasReferenceTypes]>; -defm "" : TABLE<EXTERNREF>, Requires<[HasReferenceTypes]>; +defm "" : TABLE<FUNCREF, "funcref">, Requires<[HasReferenceTypes]>; +defm "" : TABLE<EXTERNREF, "externref">, Requires<[HasReferenceTypes]>; def : Pat<(WebAssemblyTableSet mcsym:$table, i32:$idx, funcref:$r), (TABLE_SET_FUNCREF mcsym:$table, i32:$idx, funcref:$r)>, @@ -71,7 +71,7 @@ def : Pat<(WebAssemblyTableSet mcsym:$table, i32:$idx, funcref:$r), defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table), (outs), (ins table32_op:$table), - [], + [(set I32:$sz, (int_wasm_table_size (WebAssemblyWrapper tglobaladdr:$table)))], "table.size\t$sz, $table", "table.size\t$table", 0xfc10>, @@ -80,7 +80,9 @@ defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table), defm TABLE_COPY : I<(outs), (ins table32_op:$table1, table32_op:$table2, I32:$d, I32:$s, I32:$n), (outs), (ins table32_op:$table1, table32_op:$table2), - [], + [(int_wasm_table_copy (WebAssemblyWrapper tglobaladdr:$table1), + (WebAssemblyWrapper tglobaladdr:$table2), + I32:$d, I32:$s, I32:$n)], "table.copy\t$table1, $table2, $d, $s, $n", "table.copy\t$table1, $table2", 0xfc0e>, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index 4eacc921b6cd..23aaa5160abd 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -267,6 +267,7 @@ /// ///===----------------------------------------------------------------------===// +#include "Utils/WebAssemblyUtilities.h" #include "WebAssembly.h" #include "WebAssemblyTargetMachine.h" #include "llvm/ADT/StringExtras.h" @@ -285,13 +286,6 @@ using namespace llvm; #define DEBUG_TYPE "wasm-lower-em-ehsjlj" -// Emscripten's asm.js-style exception handling -extern cl::opt<bool> WasmEnableEmEH; -// Emscripten's asm.js-style setjmp/longjmp handling -extern cl::opt<bool> WasmEnableEmSjLj; -// Wasm setjmp/longjmp handling using wasm EH instructions -extern cl::opt<bool> WasmEnableSjLj; - static cl::list<std::string> EHAllowlist("emscripten-cxx-exceptions-allowed", cl::desc("The list of function names in which Emscripten-style " @@ -370,8 +364,9 @@ public: static char ID; WebAssemblyLowerEmscriptenEHSjLj() - : ModulePass(ID), EnableEmEH(WasmEnableEmEH), - EnableEmSjLj(WasmEnableEmSjLj), EnableWasmSjLj(WasmEnableSjLj) { + : ModulePass(ID), EnableEmEH(WebAssembly::WasmEnableEmEH), + EnableEmSjLj(WebAssembly::WasmEnableEmSjLj), + EnableWasmSjLj(WebAssembly::WasmEnableSjLj) { assert(!(EnableEmSjLj && EnableWasmSjLj) && "Two SjLj modes cannot be turned on at the same time"); assert(!(EnableEmEH && EnableWasmSjLj) && diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp index 0b953a90aeab..09bccef17ab0 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -40,9 +40,6 @@ cl::opt<bool> " instruction output for test purposes only."), cl::init(false)); -extern cl::opt<bool> WasmEnableEmEH; -extern cl::opt<bool> WasmEnableEmSjLj; - static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI); MCSymbol * @@ -66,9 +63,11 @@ WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { // they reach this point as aggregate Array types with an element type // that is a reference type. wasm::ValType Type; + bool IsTable = false; if (GlobalVT->isArrayTy() && WebAssembly::isRefType(GlobalVT->getArrayElementType())) { MVT VT; + IsTable = true; switch (GlobalVT->getArrayElementType()->getPointerAddressSpace()) { case WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF: VT = MVT::funcref; @@ -85,9 +84,14 @@ WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { } else report_fatal_error("Aggregate globals not yet implemented"); - WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); - WasmSym->setGlobalType( - wasm::WasmGlobalType{uint8_t(Type), /*Mutable=*/true}); + if (IsTable) { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); + WasmSym->setTableType(Type); + } else { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); + WasmSym->setGlobalType( + wasm::WasmGlobalType{uint8_t(Type), /*Mutable=*/true}); + } } return WasmSym; } @@ -105,7 +109,8 @@ WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { bool InvokeDetected = false; auto *WasmSym = Printer.getMCSymbolForFunction( - F, WasmEnableEmEH || WasmEnableEmSjLj, Signature.get(), InvokeDetected); + F, WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj, + Signature.get(), InvokeDetected); WasmSym->setSignature(Signature.get()); Printer.addSignature(std::move(Signature)); WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); @@ -275,11 +280,6 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI, SmallVector<wasm::ValType, 4>()); break; } - } else if (Info.OperandType == WebAssembly::OPERAND_HEAPTYPE) { - assert(static_cast<WebAssembly::HeapType>(MO.getImm()) != - WebAssembly::HeapType::Invalid); - // With typed function references, this will need a case for type - // index operands. Otherwise, fall through. } } MCOp = MCOperand::createImm(MO.getImm()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 7b70d99b5f52..482837178f3d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -14,6 +14,7 @@ #include "WebAssemblyTargetMachine.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "TargetInfo/WebAssemblyTargetInfo.h" +#include "Utils/WebAssemblyUtilities.h" #include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblyTargetObjectFile.h" @@ -24,6 +25,7 @@ #include "llvm/CodeGen/RegAllocRegistry.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/Function.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Transforms/Scalar.h" @@ -33,28 +35,6 @@ using namespace llvm; #define DEBUG_TYPE "wasm" -// Emscripten's asm.js-style exception handling -cl::opt<bool> - WasmEnableEmEH("enable-emscripten-cxx-exceptions", - cl::desc("WebAssembly Emscripten-style exception handling"), - cl::init(false)); - -// Emscripten's asm.js-style setjmp/longjmp handling -cl::opt<bool> WasmEnableEmSjLj( - "enable-emscripten-sjlj", - cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"), - cl::init(false)); - -// Exception handling using wasm EH instructions -cl::opt<bool> WasmEnableEH("wasm-enable-eh", - cl::desc("WebAssembly exception handling"), - cl::init(false)); - -// setjmp/longjmp handling using wasm EH instrutions -cl::opt<bool> WasmEnableSjLj("wasm-enable-sjlj", - cl::desc("WebAssembly setjmp/longjmp handling"), - cl::init(false)); - // A command-line option to keep implicit locals // for the purpose of testing with lit/llc ONLY. // This produces output which is not valid WebAssembly, and is not supported @@ -368,7 +348,23 @@ FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) { return nullptr; // No reg alloc } -static void basicCheckForEHAndSjLj(const TargetMachine *TM) { +using WebAssembly::WasmEnableEH; +using WebAssembly::WasmEnableEmEH; +using WebAssembly::WasmEnableEmSjLj; +using WebAssembly::WasmEnableSjLj; + +static void basicCheckForEHAndSjLj(TargetMachine *TM) { + // Before checking, we make sure TargetOptions.ExceptionModel is the same as + // MCAsmInfo.ExceptionsType. Normally these have to be the same, because clang + // stores the exception model info in LangOptions, which is later transferred + // to TargetOptions and MCAsmInfo. But when clang compiles bitcode directly, + // clang's LangOptions is not used and thus the exception model info is not + // correctly transferred to TargetOptions and MCAsmInfo, so we make sure we + // have the correct exception model in in WebAssemblyMCAsmInfo constructor. + // But in this case TargetOptions is still not updated, so we make sure they + // are the same. + TM->Options.ExceptionModel = TM->getMCAsmInfo()->getExceptionHandlingType(); + // Basic Correctness checking related to -exception-model if (TM->Options.ExceptionModel != ExceptionHandling::None && TM->Options.ExceptionModel != ExceptionHandling::Wasm) |
