diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-12-25 22:30:44 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-12-25 22:30:44 +0000 | 
| commit | 77fc4c146f0870ffb09c1afb823ccbe742c5e6ff (patch) | |
| tree | 5c0eb39553003b9c75a901af6bc4ddabd6f2f28c /llvm/lib/Target/WebAssembly | |
| parent | f65dcba83ce5035ab88a85fe17628b447eb56e1b (diff) | |
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)  | 
