diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2023-04-14 21:41:27 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2023-07-23 17:38:08 +0000 |
| commit | 320d4fb58b6b1c6a0c7ffeab3d4672d1479d5e17 (patch) | |
| tree | 4b5e279a6f091bb6bdc639752cf4139dfd7053a4 /contrib/llvm-project/llvm/lib/Target/WebAssembly | |
| parent | 814cfa6ad43c73de9b8030f241f516dad3f669ef (diff) | |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/WebAssembly')
47 files changed, 814 insertions, 1217 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 7bafa53af2af..1cba0843f891 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -210,6 +210,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { // guarantee that correct order. enum ParserState { FileStart, + FunctionLabel, FunctionStart, FunctionLocals, Instructions, @@ -273,11 +274,11 @@ public: #include "WebAssemblyGenAsmMatcher.inc" // TODO: This is required to be implemented, but appears unused. - bool ParseRegister(unsigned & /*RegNo*/, SMLoc & /*StartLoc*/, + bool parseRegister(MCRegister & /*RegNo*/, SMLoc & /*StartLoc*/, SMLoc & /*EndLoc*/) override { - llvm_unreachable("ParseRegister is not implemented."); + llvm_unreachable("parseRegister is not implemented."); } - OperandMatchResultTy tryParseRegister(unsigned & /*RegNo*/, + OperandMatchResultTy tryParseRegister(MCRegister & /*RegNo*/, SMLoc & /*StartLoc*/, SMLoc & /*EndLoc*/) override { llvm_unreachable("tryParseRegister is not implemented."); @@ -287,8 +288,8 @@ public: return Parser.Error(Tok.getLoc(), Msg + Tok.getString()); } - bool error(const Twine &Msg) { - return Parser.Error(Lexer.getTok().getLoc(), Msg); + bool error(const Twine &Msg, SMLoc Loc = SMLoc()) { + return Parser.Error(Loc.isValid() ? Loc : Lexer.getTok().getLoc(), Msg); } void addSignature(std::unique_ptr<wasm::WasmSignature> &&Sig) { @@ -336,11 +337,12 @@ public: return false; } - bool ensureEmptyNestingStack() { + bool ensureEmptyNestingStack(SMLoc Loc = SMLoc()) { auto Err = !NestingStack.empty(); while (!NestingStack.empty()) { error(Twine("Unmatched block construct(s) at function end: ") + - nestingString(NestingStack.back().NT).first); + nestingString(NestingStack.back().NT).first, + Loc); NestingStack.pop_back(); } return Err; @@ -835,7 +837,8 @@ public: auto ElemTypeName = expectIdent(); if (ElemTypeName.empty()) return true; - Optional<wasm::ValType> ElemType = WebAssembly::parseType(ElemTypeName); + std::optional<wasm::ValType> ElemType = + WebAssembly::parseType(ElemTypeName); if (!ElemType) return error("Unknown type in .tabletype directive: ", ElemTypeTok); @@ -864,12 +867,24 @@ public: return true; auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName)); if (WasmSym->isDefined()) { - // This .functype indicates a start of a function. - if (ensureEmptyNestingStack()) - return true; + // We push 'Function' either when a label is parsed or a .functype + // directive is parsed. The reason it is not easy to do this uniformly + // in a single place is, + // 1. We can't do this at label parsing time only because there are + // cases we don't have .functype directive before a function label, + // in which case we don't know if the label is a function at the time + // of parsing. + // 2. We can't do this at .functype parsing time only because we want to + // detect a function started with a label and not ended correctly + // without encountering a .functype directive after the label. + if (CurrentState != FunctionLabel) { + // This .functype indicates a start of a function. + if (ensureEmptyNestingStack()) + return true; + push(Function); + } CurrentState = FunctionStart; LastFunctionLabel = WasmSym; - push(Function); } auto Signature = std::make_unique<wasm::WasmSignature>(); if (parseSignature(Signature.get())) @@ -1057,7 +1072,7 @@ public: llvm_unreachable("Implement any new match types added!"); } - void doBeforeLabelEmit(MCSymbol *Symbol) override { + void doBeforeLabelEmit(MCSymbol *Symbol, SMLoc IDLoc) override { // Code below only applies to labels in text sections. auto CWS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first); if (!CWS || !CWS->getKind().isText()) @@ -1067,7 +1082,7 @@ public: // Unlike other targets, we don't allow data in text sections (labels // declared with .type @object). if (WasmSym->getType() == wasm::WASM_SYMBOL_TYPE_DATA) { - Parser.Error(Parser.getTok().getLoc(), + Parser.Error(IDLoc, "Wasm doesn\'t support data symbols in text sections"); return; } @@ -1099,6 +1114,22 @@ public: // Also generate DWARF for this section if requested. if (getContext().getGenDwarfForAssembly()) getContext().addGenDwarfSection(WS); + + if (WasmSym->isFunction()) { + // We give the location of the label (IDLoc) here, because otherwise the + // lexer's next location will be used, which can be confusing. For + // example: + // + // test0: ; This function does not end properly + // ... + // + // test1: ; We would like to point to this line for error + // ... . Not this line, which can contain any instruction + ensureEmptyNestingStack(IDLoc); + CurrentState = FunctionLabel; + LastFunctionLabel = Symbol; + push(Function); + } } void onEndOfFunction(SMLoc ErrorLoc) { @@ -1106,17 +1137,6 @@ public: TC.endOfFunction(ErrorLoc); // Reset the type checker state. TC.Clear(); - - // Automatically output a .size directive, so it becomes optional for the - // user. - if (!LastFunctionLabel) return; - auto TempSym = getContext().createLinkerPrivateTempSymbol(); - getStreamer().emitLabel(TempSym); - auto Start = MCSymbolRefExpr::create(LastFunctionLabel, getContext()); - auto End = MCSymbolRefExpr::create(TempSym, getContext()); - auto Expr = - MCBinaryExpr::create(MCBinaryExpr::Sub, End, Start, getContext()); - getStreamer().emitELFSize(LastFunctionLabel, Expr); } void onEndOfFile() override { ensureEmptyNestingStack(); } diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp index d31715e367ec..b323b265b562 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp @@ -74,27 +74,27 @@ bool WebAssemblyAsmTypeCheck::typeError(SMLoc ErrorLoc, const Twine &Msg) { // which are mostly not helpful. if (TypeErrorThisFunction) return true; - // If we're currently in unreachable code, we surpress errors as well. + // If we're currently in unreachable code, we suppress errors completely. if (Unreachable) - return true; + return false; TypeErrorThisFunction = true; dumpTypeStack("current stack: "); return Parser.Error(ErrorLoc, Msg); } bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc, - Optional<wasm::ValType> EVT) { + std::optional<wasm::ValType> EVT) { if (Stack.empty()) { return typeError(ErrorLoc, EVT ? StringRef("empty stack while popping ") + - WebAssembly::typeToString(EVT.value()) + WebAssembly::typeToString(*EVT) : StringRef("empty stack while popping value")); } auto PVT = Stack.pop_back_val(); - if (EVT && EVT.value() != PVT) { - return typeError( - ErrorLoc, StringRef("popped ") + WebAssembly::typeToString(PVT) + - ", expected " + WebAssembly::typeToString(EVT.value())); + if (EVT && *EVT != PVT) { + return typeError(ErrorLoc, + StringRef("popped ") + WebAssembly::typeToString(PVT) + + ", expected " + WebAssembly::typeToString(*EVT)); } return false; } @@ -184,7 +184,7 @@ bool WebAssemblyAsmTypeCheck::getGlobal(SMLoc ErrorLoc, const MCInst &Inst, default: break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; default: return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + " missing .globaltype"); @@ -331,7 +331,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, const auto &II = MII.get(RegOpc); // First pop all the uses off the stack and check them. for (unsigned I = II.getNumOperands(); I > II.getNumDefs(); I--) { - const auto &Op = II.OpInfo[I - 1]; + const auto &Op = II.operands()[I - 1]; if (Op.OperandType == MCOI::OPERAND_REGISTER) { auto VT = WebAssembly::regClassToValType(Op.RegClass); if (popType(ErrorLoc, VT)) @@ -340,7 +340,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, } // Now push all the defs onto the stack. for (unsigned I = 0; I < II.getNumDefs(); I++) { - const auto &Op = II.OpInfo[I]; + const auto &Op = II.operands()[I]; assert(Op.OperandType == MCOI::OPERAND_REGISTER && "Register expected"); auto VT = WebAssembly::regClassToValType(Op.RegClass); Stack.push_back(VT); diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h index 3be966b5739c..9c190e6beae7 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h @@ -38,7 +38,7 @@ class WebAssemblyAsmTypeCheck final { void dumpTypeStack(Twine Msg); bool typeError(SMLoc ErrorLoc, const Twine &Msg); - bool popType(SMLoc ErrorLoc, Optional<wasm::ValType> EVT); + bool popType(SMLoc ErrorLoc, std::optional<wasm::ValType> EVT); bool popRefType(SMLoc ErrorLoc); bool getLocal(SMLoc ErrorLoc, const MCInst &Inst, wasm::ValType &Type); bool checkEnd(SMLoc ErrorLoc, bool PopVals = false); diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp index ae65a9dc2a4e..1f07b1619b49 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp @@ -45,10 +45,9 @@ class WebAssemblyDisassembler final : public MCDisassembler { DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t Address, raw_ostream &CStream) const override; - Optional<DecodeStatus> onSymbolStart(SymbolInfoTy &Symbol, uint64_t &Size, - ArrayRef<uint8_t> Bytes, - uint64_t Address, - raw_ostream &CStream) const override; + std::optional<DecodeStatus> + onSymbolStart(SymbolInfoTy &Symbol, uint64_t &Size, ArrayRef<uint8_t> Bytes, + uint64_t Address, raw_ostream &CStream) const override; public: WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, @@ -121,29 +120,31 @@ bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) { return true; } -Optional<MCDisassembler::DecodeStatus> WebAssemblyDisassembler::onSymbolStart( - SymbolInfoTy &Symbol, uint64_t &Size, ArrayRef<uint8_t> Bytes, - uint64_t Address, raw_ostream &CStream) const { +std::optional<MCDisassembler::DecodeStatus> +WebAssemblyDisassembler::onSymbolStart(SymbolInfoTy &Symbol, uint64_t &Size, + ArrayRef<uint8_t> Bytes, + uint64_t Address, + raw_ostream &CStream) const { Size = 0; if (Address == 0) { // Start of a code section: we're parsing only the function count. int64_t FunctionCount; if (!nextLEB(FunctionCount, Bytes, Size, false)) - return None; + return std::nullopt; outs() << " # " << FunctionCount << " functions in section."; } else { // Parse the start of a single function. int64_t BodySize, LocalEntryCount; if (!nextLEB(BodySize, Bytes, Size, false) || !nextLEB(LocalEntryCount, Bytes, Size, false)) - return None; + return std::nullopt; if (LocalEntryCount) { outs() << " .local "; for (int64_t I = 0; I < LocalEntryCount; I++) { int64_t Count, Type; if (!nextLEB(Count, Bytes, Size, false) || !nextLEB(Type, Bytes, Size, false)) - return None; + return std::nullopt; for (int64_t J = 0; J < Count; J++) { if (I || J) outs() << ", "; diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp index d72bfdbbfb99..b925519e6162 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp @@ -39,10 +39,10 @@ WebAssemblyInstPrinter::WebAssemblyInstPrinter(const MCAsmInfo &MAI, : MCInstPrinter(MAI, MII, MRI) {} void WebAssemblyInstPrinter::printRegName(raw_ostream &OS, - unsigned RegNo) const { - assert(RegNo != WebAssemblyFunctionInfo::UnusedReg); + MCRegister Reg) const { + assert(Reg.id() != WebAssemblyFunctionInfo::UnusedReg); // Note that there's an implicit local.get/local.set here! - OS << "$" << RegNo; + OS << "$" << Reg.id(); } void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address, @@ -240,7 +240,7 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address, // See if this operand denotes a basic block target. if (I < NumFixedOperands) { // A non-variable_ops operand, check its type. - if (Desc.OpInfo[I].OperandType != WebAssembly::OPERAND_BASIC_BLOCK) + if (Desc.operands()[I].OperandType != WebAssembly::OPERAND_BASIC_BLOCK) continue; } else { // A variable_ops operand, which currently can be immediates (used in diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h index fe104cbca12e..c81c3a3d9ffa 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h @@ -35,7 +35,7 @@ public: WebAssemblyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, const MCRegisterInfo &MRI); - void printRegName(raw_ostream &OS, unsigned RegNo) const override; + void printRegName(raw_ostream &OS, MCRegister Reg) const override; void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, const MCSubtargetInfo &STI, raw_ostream &OS) override; @@ -51,7 +51,7 @@ public: // Autogenerated by tblgen. std::pair<const char *, uint64_t> getMnemonic(const MCInst *MI) override; void printInstruction(const MCInst *MI, uint64_t Address, raw_ostream &O); - static const char *getRegisterName(unsigned RegNo); + static const char *getRegisterName(MCRegister Reg); }; } // end namespace llvm diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp index 6e494b9430f7..cd692f4dda33 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp @@ -92,7 +92,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction( } else if (MO.isImm()) { if (I < Desc.getNumOperands()) { - const MCOperandInfo &Info = Desc.OpInfo[I]; + const MCOperandInfo &Info = Desc.operands()[I]; LLVM_DEBUG(dbgs() << "Encoding immediate: type=" << int(Info.OperandType) << "\n"); switch (Info.OperandType) { @@ -134,7 +134,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction( uint64_t D = MO.getDFPImm(); support::endian::write<uint64_t>(OS, D, support::little); } else if (MO.isExpr()) { - const MCOperandInfo &Info = Desc.OpInfo[I]; + const MCOperandInfo &Info = Desc.operands()[I]; llvm::MCFixupKind FixupKind; size_t PaddedSize = 5; switch (Info.OperandType) { diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index b5b12200505b..476955e434f2 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -416,6 +416,72 @@ inline bool isCatch(unsigned Opc) { } } +inline bool isLocalGet(unsigned Opc) { + switch (Opc) { + case WebAssembly::LOCAL_GET_I32: + case WebAssembly::LOCAL_GET_I32_S: + case WebAssembly::LOCAL_GET_I64: + case WebAssembly::LOCAL_GET_I64_S: + case WebAssembly::LOCAL_GET_F32: + case WebAssembly::LOCAL_GET_F32_S: + case WebAssembly::LOCAL_GET_F64: + case WebAssembly::LOCAL_GET_F64_S: + case WebAssembly::LOCAL_GET_V128: + case WebAssembly::LOCAL_GET_V128_S: + case WebAssembly::LOCAL_GET_FUNCREF: + case WebAssembly::LOCAL_GET_FUNCREF_S: + case WebAssembly::LOCAL_GET_EXTERNREF: + case WebAssembly::LOCAL_GET_EXTERNREF_S: + return true; + default: + return false; + } +} + +inline bool isLocalSet(unsigned Opc) { + switch (Opc) { + case WebAssembly::LOCAL_SET_I32: + case WebAssembly::LOCAL_SET_I32_S: + case WebAssembly::LOCAL_SET_I64: + case WebAssembly::LOCAL_SET_I64_S: + case WebAssembly::LOCAL_SET_F32: + case WebAssembly::LOCAL_SET_F32_S: + case WebAssembly::LOCAL_SET_F64: + case WebAssembly::LOCAL_SET_F64_S: + case WebAssembly::LOCAL_SET_V128: + case WebAssembly::LOCAL_SET_V128_S: + case WebAssembly::LOCAL_SET_FUNCREF: + case WebAssembly::LOCAL_SET_FUNCREF_S: + case WebAssembly::LOCAL_SET_EXTERNREF: + case WebAssembly::LOCAL_SET_EXTERNREF_S: + return true; + default: + return false; + } +} + +inline bool isLocalTee(unsigned Opc) { + switch (Opc) { + case WebAssembly::LOCAL_TEE_I32: + case WebAssembly::LOCAL_TEE_I32_S: + case WebAssembly::LOCAL_TEE_I64: + case WebAssembly::LOCAL_TEE_I64_S: + case WebAssembly::LOCAL_TEE_F32: + case WebAssembly::LOCAL_TEE_F32_S: + case WebAssembly::LOCAL_TEE_F64: + case WebAssembly::LOCAL_TEE_F64_S: + case WebAssembly::LOCAL_TEE_V128: + case WebAssembly::LOCAL_TEE_V128_S: + case WebAssembly::LOCAL_TEE_FUNCREF: + case WebAssembly::LOCAL_TEE_FUNCREF_S: + case WebAssembly::LOCAL_TEE_EXTERNREF: + case WebAssembly::LOCAL_TEE_EXTERNREF_S: + return true; + default: + return false; + } +} + } // end namespace WebAssembly } // end namespace llvm diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp index f380b2582c65..998905402b39 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp @@ -21,7 +21,7 @@ using namespace llvm; -Optional<wasm::ValType> WebAssembly::parseType(StringRef Type) { +std::optional<wasm::ValType> WebAssembly::parseType(StringRef Type) { // FIXME: can't use StringSwitch because wasm::ValType doesn't have a // "invalid" value. if (Type == "i32") @@ -39,7 +39,7 @@ Optional<wasm::ValType> WebAssembly::parseType(StringRef Type) { return wasm::ValType::FUNCREF; if (Type == "externref") return wasm::ValType::EXTERNREF; - return Optional<wasm::ValType>(); + return std::nullopt; } WebAssembly::BlockType WebAssembly::parseBlockType(StringRef Type) { diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h index 86211700c70a..33f3bf31595d 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h @@ -15,7 +15,6 @@ #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_UTILS_WEBASSEMBLYTYPEUTILITIES_H #define LLVM_LIB_TARGET_WEBASSEMBLY_UTILS_WEBASSEMBLYTYPEUTILITIES_H -#include "llvm/ADT/Optional.h" #include "llvm/BinaryFormat/Wasm.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/MC/MCSymbolWasm.h" @@ -89,7 +88,7 @@ inline bool isRefType(wasm::ValType Type) { // Convert StringRef to ValType / HealType / BlockType -Optional<wasm::ValType> parseType(StringRef Type); +std::optional<wasm::ValType> parseType(StringRef Type); BlockType parseBlockType(StringRef Type); MVT parseMVT(StringRef Type); diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp index 277bbee83a6f..a1e0db692390 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp @@ -58,7 +58,7 @@ bool WebAssembly::isChild(const MachineInstr &MI, if (!MO.isReg() || MO.isImplicit() || !MO.isDef()) return false; Register Reg = MO.getReg(); - return Register::isVirtualRegister(Reg) && MFI.isVRegStackified(Reg); + return Reg.isVirtual() && MFI.isVRegStackified(Reg); } bool WebAssembly::mayThrow(const MachineInstr &MI) { diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssembly.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssembly.h index aee8f160f38d..53be8f5b67b4 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssembly.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssembly.h @@ -57,31 +57,32 @@ FunctionPass *createWebAssemblyPeephole(); ModulePass *createWebAssemblyMCLowerPrePass(); // PassRegistry initialization declarations. -void initializeWebAssemblyAddMissingPrototypesPass(PassRegistry &); -void initializeWebAssemblyLowerEmscriptenEHSjLjPass(PassRegistry &); void initializeFixFunctionBitcastsPass(PassRegistry &); void initializeOptimizeReturnedPass(PassRegistry &); +void initializeWebAssemblyAddMissingPrototypesPass(PassRegistry &); void initializeWebAssemblyArgumentMovePass(PassRegistry &); -void initializeWebAssemblySetP2AlignOperandsPass(PassRegistry &); -void initializeWebAssemblyReplacePhysRegsPass(PassRegistry &); -void initializeWebAssemblyNullifyDebugValueListsPass(PassRegistry &); -void initializeWebAssemblyOptimizeLiveIntervalsPass(PassRegistry &); -void initializeWebAssemblyMemIntrinsicResultsPass(PassRegistry &); -void initializeWebAssemblyRegStackifyPass(PassRegistry &); -void initializeWebAssemblyRegColoringPass(PassRegistry &); -void initializeWebAssemblyFixBrTableDefaultsPass(PassRegistry &); -void initializeWebAssemblyFixIrreducibleControlFlowPass(PassRegistry &); -void initializeWebAssemblyLateEHPreparePass(PassRegistry &); -void initializeWebAssemblyExceptionInfoPass(PassRegistry &); void initializeWebAssemblyCFGSortPass(PassRegistry &); void initializeWebAssemblyCFGStackifyPass(PassRegistry &); +void initializeWebAssemblyDAGToDAGISelPass(PassRegistry &); +void initializeWebAssemblyDebugFixupPass(PassRegistry &); +void initializeWebAssemblyExceptionInfoPass(PassRegistry &); void initializeWebAssemblyExplicitLocalsPass(PassRegistry &); +void initializeWebAssemblyFixBrTableDefaultsPass(PassRegistry &); +void initializeWebAssemblyFixIrreducibleControlFlowPass(PassRegistry &); +void initializeWebAssemblyLateEHPreparePass(PassRegistry &); void initializeWebAssemblyLowerBrUnlessPass(PassRegistry &); -void initializeWebAssemblyRegNumberingPass(PassRegistry &); -void initializeWebAssemblyDebugFixupPass(PassRegistry &); -void initializeWebAssemblyPeepholePass(PassRegistry &); -void initializeWebAssemblyMCLowerPrePassPass(PassRegistry &); +void initializeWebAssemblyLowerEmscriptenEHSjLjPass(PassRegistry &); void initializeWebAssemblyLowerRefTypesIntPtrConvPass(PassRegistry &); +void initializeWebAssemblyMCLowerPrePassPass(PassRegistry &); +void initializeWebAssemblyMemIntrinsicResultsPass(PassRegistry &); +void initializeWebAssemblyNullifyDebugValueListsPass(PassRegistry &); +void initializeWebAssemblyOptimizeLiveIntervalsPass(PassRegistry &); +void initializeWebAssemblyPeepholePass(PassRegistry &); +void initializeWebAssemblyRegColoringPass(PassRegistry &); +void initializeWebAssemblyRegNumberingPass(PassRegistry &); +void initializeWebAssemblyRegStackifyPass(PassRegistry &); +void initializeWebAssemblyReplacePhysRegsPass(PassRegistry &); +void initializeWebAssemblySetP2AlignOperandsPass(PassRegistry &); namespace WebAssembly { enum TargetIndex { diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssembly.td b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssembly.td index b83dcf3a8e65..7531d36a74a6 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssembly.td +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssembly.td @@ -97,7 +97,13 @@ def WebAssemblyInstrInfo : InstrInfo; def : ProcessorModel<"mvp", NoSchedModel, []>; // Generic processor: latest stable version. -def : ProcessorModel<"generic", NoSchedModel, []>; +// +// This includes features that have achieved phase 4 of the standards process, +// and that are expected to work for most users in the current time, with +// consideration given to available support in relevant engines and tools, and +// the importance of the features. +def : ProcessorModel<"generic", NoSchedModel, + [FeatureSignExt, FeatureMutableGlobals]>; // Latest and greatest experimental version of WebAssembly. Bugs included! def : ProcessorModel<"bleeding-edge", NoSchedModel, diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index bcb6cf1b4e1d..60b1b3f5fc27 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -70,7 +70,7 @@ MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const { std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) { Register RegNo = MO.getReg(); - assert(Register::isVirtualRegister(RegNo) && + assert(RegNo.isVirtual() && "Unlowered physical register encountered during assembly printing"); assert(!MFI->isVRegStackified(RegNo)); unsigned WAReg = MFI->getWAReg(RegNo); @@ -272,7 +272,7 @@ MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) { } void WebAssemblyAsmPrinter::emitSymbolType(const MCSymbolWasm *Sym) { - Optional<wasm::WasmSymbolType> WasmTy = Sym->getType(); + std::optional<wasm::WasmSymbolType> WasmTy = Sym->getType(); if (!WasmTy) return; diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp index 2257d1562513..497ab5440678 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp @@ -235,7 +235,7 @@ static void sortBlocks(MachineFunction &MF, const MachineLoopInfo &MLI, // any blocks deferred because the header didn't dominate them. for (Entry &E : Entries) if (E.TheRegion->contains(MBB) && --E.NumBlocksLeft == 0) - for (auto DeferredBlock : E.Deferred) + for (auto *DeferredBlock : E.Deferred) Ready.push(DeferredBlock); while (!Entries.empty() && Entries.back().NumBlocksLeft == 0) Entries.pop_back(); @@ -348,14 +348,14 @@ static void sortBlocks(MachineFunction &MF, const MachineLoopInfo &MLI, if (Region->isLoop()) { // Loop header. The loop predecessor should be sorted above, and the // other predecessors should be backedges below. - for (auto Pred : MBB.predecessors()) + for (auto *Pred : MBB.predecessors()) assert( (Pred->getNumber() < MBB.getNumber() || Region->contains(Pred)) && "Loop header predecessors must be loop predecessors or " "backedges"); } else { // Exception header. All predecessors should be sorted above. - for (auto Pred : MBB.predecessors()) + for (auto *Pred : MBB.predecessors()) assert(Pred->getNumber() < MBB.getNumber() && "Non-loop-header predecessors should be topologically sorted"); } @@ -364,7 +364,7 @@ static void sortBlocks(MachineFunction &MF, const MachineLoopInfo &MLI, } else { // Not a region header. All predecessors should be sorted above. - for (auto Pred : MBB.predecessors()) + for (auto *Pred : MBB.predecessors()) assert(Pred->getNumber() < MBB.getNumber() && "Non-loop-header predecessors should be topologically sorted"); assert(OnStack.count(SRI.getRegionFor(&MBB)) && diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp index d2eb4b29e9fd..70c187af73a5 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp @@ -792,7 +792,7 @@ static void unstackifyVRegsUsedInSplitBB(MachineBasicBlock &MBB, for (auto &MI : Split) { for (auto &MO : MI.explicit_uses()) { - if (!MO.isReg() || Register::isPhysicalRegister(MO.getReg())) + if (!MO.isReg() || MO.getReg().isPhysical()) continue; if (MachineInstr *Def = MRI.getUniqueVRegDef(MO.getReg())) if (Def->getParent() == &MBB) @@ -1501,7 +1501,7 @@ void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) { std::next(WebAssembly::findCatch(EHPad)->getReverseIterator()); if (NextIt != EHPad->rend()) Worklist.push_back(NextIt); - LLVM_FALLTHROUGH; + [[fallthrough]]; } case WebAssembly::END_BLOCK: case WebAssembly::END_LOOP: diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp index e06e359fc592..9a6acd157a74 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp @@ -59,6 +59,24 @@ FunctionPass *llvm::createWebAssemblyDebugFixup() { return new WebAssemblyDebugFixup(); } +// At this very end of the compilation pipeline, if any DBG_VALUEs with +// registers remain, it means they are dangling info which we failed to update +// when their corresponding def instruction was transformed/moved/splitted etc. +// Because Wasm cannot access values in LLVM virtual registers in the debugger, +// these dangling DBG_VALUEs in effect kill the effect of any previous DBG_VALUE +// associated with the variable, which will appear as "optimized out". +static void nullifyDanglingDebugValues(MachineBasicBlock &MBB, + const TargetInstrInfo *TII) { + for (auto &MI : llvm::make_early_inc_range(MBB)) { + if (MI.isDebugValue() && MI.getDebugOperand(0).isReg() && + !MI.isUndefDebugValue()) { + LLVM_DEBUG(dbgs() << "Warning: dangling DBG_VALUE nullified: " << MI + << "\n"); + MI.getDebugOperand(0).setReg(Register()); + } + } +} + bool WebAssemblyDebugFixup::runOnMachineFunction(MachineFunction &MF) { LLVM_DEBUG(dbgs() << "********** Debug Fixup **********\n" "********** Function: " @@ -135,6 +153,8 @@ bool WebAssemblyDebugFixup::runOnMachineFunction(MachineFunction &MF) { } assert(Stack.empty() && "WebAssemblyDebugFixup: Stack not empty at end of basic block!"); + + nullifyDanglingDebugValues(MBB, TII); } return true; diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp index 81fe5395a6de..7e63b6b97632 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp @@ -80,7 +80,7 @@ void WebAssemblyExceptionInfo::recalculate( const MachineDominanceFrontier &MDF) { // Postorder traversal of the dominator tree. SmallVector<std::unique_ptr<WebAssemblyException>, 8> Exceptions; - for (auto DomNode : post_order(&MDT)) { + for (auto *DomNode : post_order(&MDT)) { MachineBasicBlock *EHPad = DomNode->getBlock(); if (!EHPad->isEHPad()) continue; @@ -238,7 +238,7 @@ void WebAssemblyExceptionInfo::recalculate( } // Add BBs to exceptions' block vector - for (auto DomNode : post_order(&MDT)) { + for (auto *DomNode : post_order(&MDT)) { MachineBasicBlock *MBB = DomNode->getBlock(); WebAssemblyException *WE = getExceptionFor(MBB); for (; WE; WE = WE->getParentException()) diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.h index e330188d2382..3c0add4b53d7 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.h @@ -15,7 +15,6 @@ #define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYEXCEPTIONINFO_H #include "WebAssembly.h" -#include "llvm/ADT/SetVector.h" #include "llvm/CodeGen/MachineFunctionPass.h" namespace llvm { diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp index 8ddd414b043a..1bb2d6bf9e79 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -388,7 +388,7 @@ void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) { : &WebAssembly::I32RegClass); unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg) + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), Reg) .addImm(0); Addr.setReg(Reg); } @@ -460,12 +460,12 @@ unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V, } Register Imm = createResultReg(&WebAssembly::I32RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::CONST_I32), Imm) .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits())); Register Result = createResultReg(&WebAssembly::I32RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::AND_I32), Result) .addReg(Reg) .addReg(Imm); @@ -490,18 +490,18 @@ unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V, } Register Imm = createResultReg(&WebAssembly::I32RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::CONST_I32), Imm) .addImm(32 - MVT(From).getSizeInBits()); Register Left = createResultReg(&WebAssembly::I32RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::SHL_I32), Left) .addReg(Reg) .addReg(Imm); Register Right = createResultReg(&WebAssembly::I32RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::SHR_S_I32), Right) .addReg(Left) .addReg(Imm); @@ -519,7 +519,7 @@ unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V, Reg = zeroExtendToI32(Reg, V, From); Register Result = createResultReg(&WebAssembly::I64RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::I64_EXTEND_U_I32), Result) .addReg(Reg); return Result; @@ -541,7 +541,7 @@ unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V, Reg = signExtendToI32(Reg, V, From); Register Result = createResultReg(&WebAssembly::I64RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::I64_EXTEND_S_I32), Result) .addReg(Reg); return Result; @@ -580,7 +580,7 @@ unsigned WebAssemblyFastISel::notValue(unsigned Reg) { assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass); Register NotReg = createResultReg(&WebAssembly::I32RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::EQZ_I32), NotReg) .addReg(Reg); return NotReg; @@ -588,7 +588,7 @@ unsigned WebAssemblyFastISel::notValue(unsigned Reg) { unsigned WebAssemblyFastISel::copyValue(unsigned Reg) { Register ResultReg = createResultReg(MRI.getRegClass(Reg)); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(WebAssembly::COPY), + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::COPY), ResultReg) .addReg(Reg); return ResultReg; @@ -604,7 +604,7 @@ unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) { : &WebAssembly::I32RegClass); unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) .addFrameIndex(SI->second); return ResultReg; } @@ -623,7 +623,7 @@ unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) { : &WebAssembly::I32RegClass); unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) .addGlobalAddress(GV); return ResultReg; } @@ -717,7 +717,7 @@ bool WebAssemblyFastISel::fastLowerArguments() { return false; } Register ResultReg = createResultReg(RC); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) .addImm(I); updateValueMap(&Arg, ResultReg); @@ -859,7 +859,7 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) { return false; } - auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); + auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc)); if (!IsVoid) MIB.addReg(ResultReg, RegState::Define); @@ -886,7 +886,7 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) { // as 64-bit for uniformity with other pointer types. // See also: WebAssemblyISelLowering.cpp: LowerCallResults if (Subtarget->hasAddr64()) { - auto Wrap = BuildMI(*FuncInfo.MBB, std::prev(FuncInfo.InsertPt), DbgLoc, + auto Wrap = BuildMI(*FuncInfo.MBB, std::prev(FuncInfo.InsertPt), MIMD, TII.get(WebAssembly::I32_WRAP_I64)); Register Reg32 = createResultReg(&WebAssembly::I32RegClass); Wrap.addReg(Reg32, RegState::Define); @@ -961,7 +961,7 @@ bool WebAssemblyFastISel::selectSelect(const Instruction *I) { } Register ResultReg = createResultReg(RC); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) .addReg(TrueReg) .addReg(FalseReg) .addReg(CondReg); @@ -979,7 +979,7 @@ bool WebAssemblyFastISel::selectTrunc(const Instruction *I) { if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) { Register Result = createResultReg(&WebAssembly::I32RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::I32_WRAP_I64), Result) .addReg(Reg); Reg = Result; @@ -1077,7 +1077,7 @@ bool WebAssemblyFastISel::selectICmp(const Instruction *I) { return false; Register ResultReg = createResultReg(&WebAssembly::I32RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) .addReg(LHS) .addReg(RHS); updateValueMap(ICmp, ResultReg); @@ -1138,7 +1138,7 @@ bool WebAssemblyFastISel::selectFCmp(const Instruction *I) { } Register ResultReg = createResultReg(&WebAssembly::I32RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) .addReg(LHS) .addReg(RHS); @@ -1231,7 +1231,7 @@ bool WebAssemblyFastISel::selectLoad(const Instruction *I) { materializeLoadStoreOperands(Addr); Register ResultReg = createResultReg(RC); - auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), + auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg); addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load)); @@ -1260,7 +1260,7 @@ bool WebAssemblyFastISel::selectStore(const Instruction *I) { switch (getSimpleType(Store->getValueOperand()->getType())) { case MVT::i1: VTIsi1 = true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case MVT::i8: Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32; break; @@ -1291,7 +1291,7 @@ bool WebAssemblyFastISel::selectStore(const Instruction *I) { if (VTIsi1) ValueReg = maskI1Value(ValueReg, Store->getValueOperand()); - auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); + auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc)); addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store)); @@ -1319,7 +1319,7 @@ bool WebAssemblyFastISel::selectBr(const Instruction *I) { if (Not) Opc = WebAssembly::BR_UNLESS; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)) + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc)) .addMBB(TBB) .addReg(CondReg); @@ -1334,7 +1334,7 @@ bool WebAssemblyFastISel::selectRet(const Instruction *I) { const auto *Ret = cast<ReturnInst>(I); if (Ret->getNumOperands() == 0) { - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::RETURN)); return true; } @@ -1379,14 +1379,14 @@ bool WebAssemblyFastISel::selectRet(const Instruction *I) { if (Reg == 0) return false; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::RETURN)) .addReg(Reg); return true; } bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) { - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::UNREACHABLE)); return true; } diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp index 2a4349e02f1b..b3fe110a092b 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp @@ -141,7 +141,7 @@ static Function *createWrapper(Function *F, FunctionType *Ty) { if (CastInst::isBitOrNoopPointerCastable(ArgType, ParamType, DL)) { Instruction *PtrCast = CastInst::CreateBitOrPointerCast(AI, ParamType, "cast"); - BB->getInstList().push_back(PtrCast); + PtrCast->insertInto(BB, BB->end()); Args.push_back(PtrCast); } else if (ArgType->isStructTy() || ParamType->isStructTy()) { LLVM_DEBUG(dbgs() << "createWrapper: struct param type in bitcast: " @@ -181,7 +181,7 @@ static Function *createWrapper(Function *F, FunctionType *Ty) { DL)) { Instruction *Cast = CastInst::CreateBitOrPointerCast(Call, RtnType, "cast"); - BB->getInstList().push_back(Cast); + Cast->insertInto(BB, BB->end()); ReturnInst::Create(M->getContext(), Cast, BB); } else if (RtnType->isStructTy() || ExpectedRtnType->isStructTy()) { LLVM_DEBUG(dbgs() << "createWrapper: struct return type in bitcast: " diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp index 83e71d731bfa..6c46673c36bf 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp @@ -343,7 +343,7 @@ void WebAssemblyFixIrreducibleControlFlow::makeSingleEntryLoop( BlockVector SortedEntries = getSortedEntries(Entries); #ifndef NDEBUG - for (auto Block : SortedEntries) + for (auto *Block : SortedEntries) assert(Block->getNumber() != -1); if (SortedEntries.size() > 1) { for (auto I = SortedEntries.begin(), E = SortedEntries.end() - 1; I != E; diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 01baa3d9389d..e60f1397b993 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -50,7 +50,7 @@ using namespace llvm; // SelectionDAGISel::runOnMachineFunction. We have to do it in two places // because we want to do it while building the selection DAG for uses of alloca, // but not all alloca instructions are used so we have to follow up afterwards. -Optional<unsigned> +std::optional<unsigned> WebAssemblyFrameLowering::getLocalForStackObject(MachineFunction &MF, int FrameIndex) { MachineFrameInfo &MFI = MF.getFrameInfo(); @@ -62,9 +62,8 @@ WebAssemblyFrameLowering::getLocalForStackObject(MachineFunction &MF, // If not allocated in the object address space, this object will be in // linear memory. const AllocaInst *AI = MFI.getObjectAllocation(FrameIndex); - if (!AI || - !WebAssembly::isWasmVarAddressSpace(AI->getType()->getAddressSpace())) - return None; + if (!AI || !WebAssembly::isWasmVarAddressSpace(AI->getAddressSpace())) + return std::nullopt; // Otherwise, allocate this object in the named value stack, outside of linear // memory. diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h index d30a3fa52d73..528b33e34bee 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h @@ -55,9 +55,9 @@ public: const DebugLoc &DL) const; // Returns the index of the WebAssembly local to which the stack object - // FrameIndex in MF should be allocated, or None. - static Optional<unsigned> getLocalForStackObject(MachineFunction &MF, - int FrameIndex); + // FrameIndex in MF should be allocated, or std::nullopt. + static std::optional<unsigned> getLocalForStackObject(MachineFunction &MF, + int FrameIndex); static unsigned getSPReg(const MachineFunction &MF); static unsigned getFPReg(const MachineFunction &MF); diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISD.def b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISD.def index a3a33f4a5b3a..b8954f4693f0 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISD.def +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISD.def @@ -46,7 +46,6 @@ HANDLE_NODETYPE(MEMORY_COPY) HANDLE_NODETYPE(MEMORY_FILL) // Memory intrinsics -HANDLE_MEM_NODETYPE(LOAD_SPLAT) HANDLE_MEM_NODETYPE(GLOBAL_GET) HANDLE_MEM_NODETYPE(GLOBAL_SET) HANDLE_MEM_NODETYPE(TABLE_GET) diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp index 7e75989d3def..df79e55ce4b6 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -29,6 +29,7 @@ using namespace llvm; #define DEBUG_TYPE "wasm-isel" +#define PASS_NAME "WebAssembly Instruction Selection" //===--------------------------------------------------------------------===// /// WebAssembly-specific code to select WebAssembly machine instructions for @@ -41,14 +42,13 @@ class WebAssemblyDAGToDAGISel final : public SelectionDAGISel { const WebAssemblySubtarget *Subtarget; public: + static char ID; + + WebAssemblyDAGToDAGISel() = delete; + WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &TM, CodeGenOpt::Level OptLevel) - : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) { - } - - StringRef getPassName() const override { - return "WebAssembly Instruction Selection"; - } + : SelectionDAGISel(ID, TM, OptLevel), Subtarget(nullptr) {} bool runOnMachineFunction(MachineFunction &MF) override { LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n" @@ -67,14 +67,26 @@ public: bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) override; + bool SelectAddrOperands32(SDValue Op, SDValue &Offset, SDValue &Addr); + bool SelectAddrOperands64(SDValue Op, SDValue &Offset, SDValue &Addr); + // Include the pieces autogenerated from the target description. #include "WebAssemblyGenDAGISel.inc" private: // add select functions here... + + bool SelectAddrOperands(MVT AddrType, unsigned ConstOpc, SDValue Op, + SDValue &Offset, SDValue &Addr); + bool SelectAddrAddOperands(MVT OffsetType, SDValue N, SDValue &Offset, + SDValue &Addr); }; } // end anonymous namespace +char WebAssemblyDAGToDAGISel::ID; + +INITIALIZE_PASS(WebAssemblyDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false) + void WebAssemblyDAGToDAGISel::PreprocessISelDAG() { // Stack objects that should be allocated to locals are hoisted to WebAssembly // locals when they are first used. However for those without uses, we hoist @@ -281,6 +293,102 @@ bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand( return true; } +bool WebAssemblyDAGToDAGISel::SelectAddrAddOperands(MVT OffsetType, SDValue N, + SDValue &Offset, + SDValue &Addr) { + assert(N.getNumOperands() == 2 && "Attempting to fold in a non-binary op"); + + // WebAssembly constant offsets are performed as unsigned with infinite + // precision, so we need to check for NoUnsignedWrap so that we don't fold an + // offset for an add that needs wrapping. + if (N.getOpcode() == ISD::ADD && !N.getNode()->getFlags().hasNoUnsignedWrap()) + return false; + + // Folds constants in an add into the offset. + for (size_t i = 0; i < 2; ++i) { + SDValue Op = N.getOperand(i); + SDValue OtherOp = N.getOperand(i == 0 ? 1 : 0); + + if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op)) { + Offset = + CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), OffsetType); + Addr = OtherOp; + return true; + } + } + return false; +} + +bool WebAssemblyDAGToDAGISel::SelectAddrOperands(MVT AddrType, + unsigned ConstOpc, SDValue N, + SDValue &Offset, + SDValue &Addr) { + SDLoc DL(N); + + // Fold target global addresses into the offset. + if (!TM.isPositionIndependent()) { + SDValue Op(N); + if (Op.getOpcode() == WebAssemblyISD::Wrapper) + Op = Op.getOperand(0); + + if (Op.getOpcode() == ISD::TargetGlobalAddress) { + Offset = Op; + Addr = SDValue( + CurDAG->getMachineNode(ConstOpc, DL, AddrType, + CurDAG->getTargetConstant(0, DL, AddrType)), + 0); + return true; + } + } + + // Fold anything inside an add into the offset. + if (N.getOpcode() == ISD::ADD && + SelectAddrAddOperands(AddrType, N, Offset, Addr)) + return true; + + // Likewise, treat an 'or' node as an 'add' if the or'ed bits are known to be + // zero and fold them into the offset too. + if (N.getOpcode() == ISD::OR) { + bool OrIsAdd; + if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) { + OrIsAdd = + CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue()); + } else { + KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0); + KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0); + OrIsAdd = (~Known0.Zero & ~Known1.Zero) == 0; + } + + if (OrIsAdd && SelectAddrAddOperands(AddrType, N, Offset, Addr)) + return true; + } + + // Fold constant addresses into the offset. + if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) { + Offset = CurDAG->getTargetConstant(CN->getZExtValue(), DL, AddrType); + Addr = SDValue( + CurDAG->getMachineNode(ConstOpc, DL, AddrType, + CurDAG->getTargetConstant(0, DL, AddrType)), + 0); + return true; + } + + // Else it's a plain old load/store with no offset. + Offset = CurDAG->getTargetConstant(0, DL, AddrType); + Addr = N; + return true; +} + +bool WebAssemblyDAGToDAGISel::SelectAddrOperands32(SDValue Op, SDValue &Offset, + SDValue &Addr) { + return SelectAddrOperands(MVT::i32, WebAssembly::CONST_I32, Op, Offset, Addr); +} + +bool WebAssemblyDAGToDAGISel::SelectAddrOperands64(SDValue Op, SDValue &Offset, + SDValue &Addr) { + return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64, Op, Offset, Addr); +} + /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready /// for instruction scheduling. FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine &TM, diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index ab6d6b4f7ef1..94544800a6fb 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -194,6 +194,11 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering( MVT::v2f64}) setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom); + // Support splatting + for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, + MVT::v2f64}) + setOperationAction(ISD::SPLAT_VECTOR, T, Legal); + // Custom lowering since wasm shifts must have a scalar shift amount for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL}) for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) @@ -751,12 +756,12 @@ WebAssemblyTargetLowering::getRegForInlineAsmConstraint( return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); } -bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const { +bool WebAssemblyTargetLowering::isCheapToSpeculateCttz(Type *Ty) const { // Assume ctz is a relatively cheap operation. return true; } -bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const { +bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz(Type *Ty) const { // Assume clz is a relatively cheap operation. return true; } @@ -781,7 +786,7 @@ bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL, bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses( EVT /*VT*/, unsigned /*AddrSpace*/, Align /*Align*/, - MachineMemOperand::Flags /*Flags*/, bool *Fast) const { + MachineMemOperand::Flags /*Flags*/, unsigned *Fast) const { // WebAssembly supports unaligned accesses, though it should be declared // with the p2align attribute on loads and stores which do so, and there // may be a performance impact. We tell LLVM they're "fast" because @@ -789,7 +794,7 @@ bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses( // of constants, etc.), WebAssembly implementations will either want the // unaligned access or they'll split anyway. if (Fast) - *Fast = true; + *Fast = 1; return true; } @@ -1449,88 +1454,16 @@ static bool IsWebAssemblyGlobal(SDValue Op) { return false; } -static Optional<unsigned> IsWebAssemblyLocal(SDValue Op, SelectionDAG &DAG) { +static std::optional<unsigned> IsWebAssemblyLocal(SDValue Op, + SelectionDAG &DAG) { const FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Op); if (!FI) - return None; + return std::nullopt; auto &MF = DAG.getMachineFunction(); return WebAssemblyFrameLowering::getLocalForStackObject(MF, FI->getIndex()); } -static bool IsWebAssemblyTable(SDValue Op) { - const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op); - if (GA && WebAssembly::isWasmVarAddressSpace(GA->getAddressSpace())) { - const GlobalValue *Value = GA->getGlobal(); - const Type *Ty = Value->getValueType(); - - if (Ty->isArrayTy() && WebAssembly::isRefType(Ty->getArrayElementType())) - return true; - } - return false; -} - -// This function will accept as Op any access to a table, so Op can -// be the actual table or an offset into the table. -static bool IsWebAssemblyTableWithOffset(SDValue Op) { - if (Op->getOpcode() == ISD::ADD && Op->getNumOperands() == 2) - return (Op->getOperand(1).getSimpleValueType() == MVT::i32 && - IsWebAssemblyTableWithOffset(Op->getOperand(0))) || - (Op->getOperand(0).getSimpleValueType() == MVT::i32 && - IsWebAssemblyTableWithOffset(Op->getOperand(1))); - - return IsWebAssemblyTable(Op); -} - -// Helper for table pattern matching used in LowerStore and LowerLoad -bool WebAssemblyTargetLowering::MatchTableForLowering(SelectionDAG &DAG, - const SDLoc &DL, - const SDValue &Base, - GlobalAddressSDNode *&GA, - SDValue &Idx) const { - // We expect the following graph for a load of the form: - // table[<var> + <constant offset>] - // - // Case 1: - // externref = load t1 - // t1: i32 = add t2, i32:<constant offset> - // t2: i32 = add tX, table - // - // This is in some cases simplified to just: - // Case 2: - // externref = load t1 - // t1: i32 = add t2, i32:tX - // - // So, unfortunately we need to check for both cases and if we are in the - // first case extract the table GlobalAddressNode and build a new node tY - // that's tY: i32 = add i32:<constant offset>, i32:tX - // - if (IsWebAssemblyTable(Base)) { - GA = cast<GlobalAddressSDNode>(Base); - Idx = DAG.getConstant(0, DL, MVT::i32); - } else { - GA = dyn_cast<GlobalAddressSDNode>(Base->getOperand(0)); - if (GA) { - // We are in Case 2 above. - Idx = Base->getOperand(1); - assert(GA->getNumValues() == 1); - } else { - // This might be Case 1 above (or an error) - SDValue V = Base->getOperand(0); - GA = dyn_cast<GlobalAddressSDNode>(V->getOperand(1)); - - if (V->getOpcode() != ISD::ADD || V->getNumOperands() != 2 || !GA) - return false; - - SDValue IdxV = DAG.getNode(ISD::ADD, DL, MVT::i32, Base->getOperand(1), - V->getOperand(0)); - Idx = IdxV; - } - } - - return true; -} - SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); @@ -1539,26 +1472,6 @@ SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op, const SDValue &Base = SN->getBasePtr(); const SDValue &Offset = SN->getOffset(); - if (IsWebAssemblyTableWithOffset(Base)) { - if (!Offset->isUndef()) - report_fatal_error( - "unexpected offset when loading from webassembly table", false); - - SDValue Idx; - GlobalAddressSDNode *GA; - - if (!MatchTableForLowering(DAG, DL, Base, GA, Idx)) - report_fatal_error("failed pattern matching for lowering table store", - false); - - SDVTList Tys = DAG.getVTList(MVT::Other); - SDValue TableSetOps[] = {SN->getChain(), SDValue(GA, 0), Idx, Value}; - SDValue TableSet = - DAG.getMemIntrinsicNode(WebAssemblyISD::TABLE_SET, DL, Tys, TableSetOps, - SN->getMemoryVT(), SN->getMemOperand()); - return TableSet; - } - if (IsWebAssemblyGlobal(Base)) { if (!Offset->isUndef()) report_fatal_error("unexpected offset when storing to webassembly global", @@ -1570,7 +1483,7 @@ SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op, SN->getMemoryVT(), SN->getMemOperand()); } - if (Optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { + if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { if (!Offset->isUndef()) report_fatal_error("unexpected offset when storing to webassembly local", false); @@ -1581,6 +1494,11 @@ SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op, return DAG.getNode(WebAssemblyISD::LOCAL_SET, DL, Tys, Ops); } + if (WebAssembly::isWasmVarAddressSpace(SN->getAddressSpace())) + report_fatal_error( + "Encountered an unlowerable store to the wasm_var address space", + false); + return Op; } @@ -1591,26 +1509,6 @@ SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op, const SDValue &Base = LN->getBasePtr(); const SDValue &Offset = LN->getOffset(); - if (IsWebAssemblyTableWithOffset(Base)) { - if (!Offset->isUndef()) - report_fatal_error( - "unexpected offset when loading from webassembly table", false); - - GlobalAddressSDNode *GA; - SDValue Idx; - - if (!MatchTableForLowering(DAG, DL, Base, GA, Idx)) - report_fatal_error("failed pattern matching for lowering table load", - false); - - SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other); - SDValue TableGetOps[] = {LN->getChain(), SDValue(GA, 0), Idx}; - SDValue TableGet = - DAG.getMemIntrinsicNode(WebAssemblyISD::TABLE_GET, DL, Tys, TableGetOps, - LN->getMemoryVT(), LN->getMemOperand()); - return TableGet; - } - if (IsWebAssemblyGlobal(Base)) { if (!Offset->isUndef()) report_fatal_error( @@ -1622,7 +1520,7 @@ SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op, LN->getMemoryVT(), LN->getMemOperand()); } - if (Optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { + if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { if (!Offset->isUndef()) report_fatal_error( "unexpected offset when loading from webassembly local", false); @@ -1636,6 +1534,11 @@ SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op, return Result; } + if (WebAssembly::isWasmVarAddressSpace(LN->getAddressSpace())) + report_fatal_error( + "Encountered an unlowerable load from the wasm_var address space", + false); + return Op; } @@ -1845,7 +1748,7 @@ SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op, const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs; // Add an operand for each case. - for (auto MBB : MBBs) + for (auto *MBB : MBBs) Ops.push_back(DAG.getBasicBlock(MBB)); // Add the first MBB as a dummy default target for now. This will be replaced @@ -2263,18 +2166,8 @@ SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op, return IsConstant(Lane); }; } else { - // Use a splat, but possibly a load_splat - LoadSDNode *SplattedLoad; - if ((SplattedLoad = dyn_cast<LoadSDNode>(SplatValue)) && - SplattedLoad->getMemoryVT() == VecT.getVectorElementType()) { - Result = DAG.getMemIntrinsicNode( - WebAssemblyISD::LOAD_SPLAT, DL, DAG.getVTList(VecT), - {SplattedLoad->getChain(), SplattedLoad->getBasePtr(), - SplattedLoad->getOffset()}, - SplattedLoad->getMemoryVT(), SplattedLoad->getMemOperand()); - } else { - Result = DAG.getSplatBuildVector(VecT, DL, SplatValue); - } + // Use a splat (which might be selected as a load splat) + Result = DAG.getSplatBuildVector(VecT, DL, SplatValue); IsLaneConstructed = [&SplatValue](size_t _, const SDValue &Lane) { return Lane == SplatValue; }; @@ -2312,8 +2205,10 @@ WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, // Expand mask indices to byte indices and materialize them as operands for (int M : Mask) { for (size_t J = 0; J < LaneBytes; ++J) { - // Lower undefs (represented by -1 in mask) to zero - uint64_t ByteIndex = M == -1 ? 0 : (uint64_t)M * LaneBytes + J; + // Lower undefs (represented by -1 in mask) to {0..J}, which use a + // whole lane of vector input, to allow further reduction at VM. E.g. + // match an 8x16 byte shuffle to an equivalent cheaper 32x4 shuffle. + uint64_t ByteIndex = M == -1 ? J : (uint64_t)M * LaneBytes + J; Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32); } } @@ -2345,11 +2240,16 @@ WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op, SelectionDAG &DAG) const { // Allow constant lane indices, expand variable lane indices SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode(); - if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef()) - return Op; - else - // Perform default expansion - return SDValue(); + if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef()) { + // Ensure the index type is i32 to match the tablegen patterns + uint64_t Idx = cast<ConstantSDNode>(IdxNode)->getZExtValue(); + SmallVector<SDValue, 3> Ops(Op.getNode()->ops()); + Ops[Op.getNumOperands() - 1] = + DAG.getConstant(Idx, SDLoc(IdxNode), MVT::i32); + return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), Ops); + } + // Perform default expansion + return SDValue(); } static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG) { @@ -2456,6 +2356,32 @@ performVECTOR_SHUFFLECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { return DAG.getBitcast(DstType, NewShuffle); } +/// Convert ({u,s}itofp vec) --> ({u,s}itofp ({s,z}ext vec)) so it doesn't get +/// split up into scalar instructions during legalization, and the vector +/// extending instructions are selected in performVectorExtendCombine below. +static SDValue +performVectorExtendToFPCombine(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI) { + auto &DAG = DCI.DAG; + assert(N->getOpcode() == ISD::UINT_TO_FP || + N->getOpcode() == ISD::SINT_TO_FP); + + EVT InVT = N->getOperand(0)->getValueType(0); + EVT ResVT = N->getValueType(0); + MVT ExtVT; + if (ResVT == MVT::v4f32 && (InVT == MVT::v4i16 || InVT == MVT::v4i8)) + ExtVT = MVT::v4i32; + else if (ResVT == MVT::v2f64 && (InVT == MVT::v2i16 || InVT == MVT::v2i8)) + ExtVT = MVT::v2i32; + else + return SDValue(); + + unsigned Op = + N->getOpcode() == ISD::UINT_TO_FP ? ISD::ZERO_EXTEND : ISD::SIGN_EXTEND; + SDValue Conv = DAG.getNode(Op, SDLoc(N), ExtVT, N->getOperand(0)); + return DAG.getNode(N->getOpcode(), SDLoc(N), ResVT, Conv); +} + static SDValue performVectorExtendCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { auto &DAG = DCI.DAG; @@ -2741,6 +2667,9 @@ WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N, case ISD::SIGN_EXTEND: case ISD::ZERO_EXTEND: return performVectorExtendCombine(N, DCI); + case ISD::UINT_TO_FP: + case ISD::SINT_TO_FP: + return performVectorExtendToFPCombine(N, DCI); case ISD::FP_TO_SINT_SAT: case ISD::FP_TO_UINT_SAT: case ISD::FP_ROUND: diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h index d86f2e59e3d2..f70f85fe6ddd 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h @@ -65,14 +65,14 @@ private: std::pair<unsigned, const TargetRegisterClass *> getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const override; - bool isCheapToSpeculateCttz() const override; - bool isCheapToSpeculateCtlz() const override; + bool isCheapToSpeculateCttz(Type *Ty) const override; + bool isCheapToSpeculateCtlz(Type *Ty) const override; bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AS, Instruction *I = nullptr) const override; bool allowsMisalignedMemoryAccesses(EVT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags, - bool *Fast) const override; + unsigned *Fast) const override; bool isIntDivCheap(EVT VT, AttributeList Attr) const override; bool isVectorLoadExtDesirable(SDValue ExtVal) const override; bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td index ed80ed39f09c..2dbcdd50fb8d 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td @@ -77,129 +77,29 @@ defm MEMORY_ATOMIC_WAIT64_A64 : } // mayLoad = 1 } // hasSideEffects = 1 -// Select notifys with no constant offset. -def NotifyPatNoOffset_A32 : - Pat<(i32 (int_wasm_memory_atomic_notify I32:$addr, I32:$count)), - (MEMORY_ATOMIC_NOTIFY_A32 0, 0, I32:$addr, I32:$count)>, +def NotifyPat_A32 : + Pat<(i32 (int_wasm_memory_atomic_notify (AddrOps32 offset32_op:$offset, I32:$addr), I32:$count)), + (MEMORY_ATOMIC_NOTIFY_A32 0, $offset, $addr, $count)>, Requires<[HasAddr32, HasAtomics]>; -def NotifyPatNoOffset_A64 : - Pat<(i32 (int_wasm_memory_atomic_notify I64:$addr, I32:$count)), - (MEMORY_ATOMIC_NOTIFY_A64 0, 0, I64:$addr, I32:$count)>, +def NotifyPat_A64 : + Pat<(i32 (int_wasm_memory_atomic_notify (AddrOps64 offset64_op:$offset, I64:$addr), I32:$count)), + (MEMORY_ATOMIC_NOTIFY_A64 0, $offset, $addr, $count)>, Requires<[HasAddr64, HasAtomics]>; -// Select notifys with a constant offset. -// Pattern with address + immediate offset -multiclass NotifyPatImmOff<PatFrag operand, string inst> { - def : Pat<(i32 (int_wasm_memory_atomic_notify (operand I32:$addr, imm:$off), - I32:$count)), - (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, I32:$count)>, - Requires<[HasAddr32, HasAtomics]>; - def : Pat<(i32 (int_wasm_memory_atomic_notify (operand I64:$addr, imm:$off), - I32:$count)), - (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, I32:$count)>, - Requires<[HasAddr64, HasAtomics]>; +multiclass WaitPat<ValueType ty, Intrinsic kind, string inst> { + def WaitPat_A32 : + Pat<(i32 (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$exp, I64:$timeout)), + (!cast<NI>(inst#_A32) 0, $offset, $addr, $exp, $timeout)>, + Requires<[HasAddr32, HasAtomics]>; + def WaitPat_A64 : + Pat<(i32 (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$exp, I64:$timeout)), + (!cast<NI>(inst#_A64) 0, $offset, $addr, $exp, $timeout)>, + Requires<[HasAddr64, HasAtomics]>; } -defm : NotifyPatImmOff<regPlusImm, "MEMORY_ATOMIC_NOTIFY">; -defm : NotifyPatImmOff<or_is_add, "MEMORY_ATOMIC_NOTIFY">; -// Select notifys with just a constant offset. -def NotifyPatOffsetOnly_A32 : - Pat<(i32 (int_wasm_memory_atomic_notify imm:$off, I32:$count)), - (MEMORY_ATOMIC_NOTIFY_A32 0, imm:$off, (CONST_I32 0), I32:$count)>, - Requires<[HasAddr32, HasAtomics]>; -def NotifyPatOffsetOnly_A64 : - Pat<(i32 (int_wasm_memory_atomic_notify imm:$off, I32:$count)), - (MEMORY_ATOMIC_NOTIFY_A64 0, imm:$off, (CONST_I64 0), I32:$count)>, - Requires<[HasAddr64, HasAtomics]>; - -def NotifyPatGlobalAddrOffOnly_A32 : - Pat<(i32 (int_wasm_memory_atomic_notify (WebAssemblyWrapper tglobaladdr:$off), - I32:$count)), - (MEMORY_ATOMIC_NOTIFY_A32 0, tglobaladdr:$off, (CONST_I32 0), I32:$count) - >, - Requires<[HasAddr32, HasAtomics, IsNotPIC]>; -def NotifyPatGlobalAddrOffOnly_A64 : - Pat<(i32 (int_wasm_memory_atomic_notify (WebAssemblyWrapper tglobaladdr:$off), - I32:$count)), - (MEMORY_ATOMIC_NOTIFY_A64 0, tglobaladdr:$off, (CONST_I64 0), I32:$count) - >, - Requires<[HasAddr64, HasAtomics, IsNotPIC]>; - -// Select waits with no constant offset. -multiclass WaitPatNoOffset<ValueType ty, Intrinsic kind, - string inst> { - def : Pat<(i32 (kind I32:$addr, ty:$exp, I64:$timeout)), - (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$exp, I64:$timeout)>, - Requires<[HasAddr32, HasAtomics]>; - def : Pat<(i32 (kind I64:$addr, ty:$exp, I64:$timeout)), - (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$exp, I64:$timeout)>, - Requires<[HasAddr64, HasAtomics]>; -} -defm : WaitPatNoOffset<i32, int_wasm_memory_atomic_wait32, - "MEMORY_ATOMIC_WAIT32">; -defm : WaitPatNoOffset<i64, int_wasm_memory_atomic_wait64, - "MEMORY_ATOMIC_WAIT64">; -defm : WaitPatNoOffset<i32, int_wasm_memory_atomic_wait32, - "MEMORY_ATOMIC_WAIT32">; -defm : WaitPatNoOffset<i64, int_wasm_memory_atomic_wait64, - "MEMORY_ATOMIC_WAIT64">; - -// Select waits with a constant offset. - -// Pattern with address + immediate offset -multiclass WaitPatImmOff<ValueType ty, Intrinsic kind, PatFrag operand, - string inst> { - def : Pat<(i32 (kind (operand I32:$addr, imm:$off), ty:$exp, I64:$timeout)), - (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$exp, - I64:$timeout)>, - Requires<[HasAddr32, HasAtomics]>; - def : Pat<(i32 (kind (operand I64:$addr, imm:$off), ty:$exp, I64:$timeout)), - (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$exp, - I64:$timeout)>, - Requires<[HasAddr64, HasAtomics]>; -} -defm : WaitPatImmOff<i32, int_wasm_memory_atomic_wait32, regPlusImm, - "MEMORY_ATOMIC_WAIT32">; -defm : WaitPatImmOff<i32, int_wasm_memory_atomic_wait32, or_is_add, - "MEMORY_ATOMIC_WAIT32">; -defm : WaitPatImmOff<i64, int_wasm_memory_atomic_wait64, regPlusImm, - "MEMORY_ATOMIC_WAIT64">; -defm : WaitPatImmOff<i64, int_wasm_memory_atomic_wait64, or_is_add, - "MEMORY_ATOMIC_WAIT64">; - -// Select waits with just a constant offset. -multiclass WaitPatOffsetOnly<ValueType ty, Intrinsic kind, string inst> { - def : Pat<(i32 (kind imm:$off, ty:$exp, I64:$timeout)), - (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$exp, - I64:$timeout)>, - Requires<[HasAddr32, HasAtomics]>; - def : Pat<(i32 (kind imm:$off, ty:$exp, I64:$timeout)), - (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$exp, - I64:$timeout)>, - Requires<[HasAddr64, HasAtomics]>; -} -defm : WaitPatOffsetOnly<i32, int_wasm_memory_atomic_wait32, - "MEMORY_ATOMIC_WAIT32">; -defm : WaitPatOffsetOnly<i64, int_wasm_memory_atomic_wait64, - "MEMORY_ATOMIC_WAIT64">; - -multiclass WaitPatGlobalAddrOffOnly<ValueType ty, Intrinsic kind, string inst> { - def : Pat<(i32 (kind (WebAssemblyWrapper tglobaladdr:$off), ty:$exp, - I64:$timeout)), - (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$exp, - I64:$timeout)>, - Requires<[HasAddr32, HasAtomics, IsNotPIC]>; - def : Pat<(i32 (kind (WebAssemblyWrapper tglobaladdr:$off), ty:$exp, - I64:$timeout)), - (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$exp, - I64:$timeout)>, - Requires<[HasAddr64, HasAtomics, IsNotPIC]>; -} -defm : WaitPatGlobalAddrOffOnly<i32, int_wasm_memory_atomic_wait32, - "MEMORY_ATOMIC_WAIT32">; -defm : WaitPatGlobalAddrOffOnly<i64, int_wasm_memory_atomic_wait64, - "MEMORY_ATOMIC_WAIT64">; +defm : WaitPat<i32, int_wasm_memory_atomic_wait32, "MEMORY_ATOMIC_WAIT32">; +defm : WaitPat<i64, int_wasm_memory_atomic_wait64, "MEMORY_ATOMIC_WAIT64">; //===----------------------------------------------------------------------===// // Atomic fences @@ -226,25 +126,9 @@ multiclass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> { defm ATOMIC_LOAD_I32 : AtomicLoad<I32, "i32.atomic.load", 0x10>; defm ATOMIC_LOAD_I64 : AtomicLoad<I64, "i64.atomic.load", 0x11>; -// Select loads with no constant offset. -defm : LoadPatNoOffset<i32, atomic_load_32, "ATOMIC_LOAD_I32">; -defm : LoadPatNoOffset<i64, atomic_load_64, "ATOMIC_LOAD_I64">; - -// Select loads with a constant offset. - -// Pattern with address + immediate offset -defm : LoadPatImmOff<i32, atomic_load_32, regPlusImm, "ATOMIC_LOAD_I32">; -defm : LoadPatImmOff<i64, atomic_load_64, regPlusImm, "ATOMIC_LOAD_I64">; -defm : LoadPatImmOff<i32, atomic_load_32, or_is_add, "ATOMIC_LOAD_I32">; -defm : LoadPatImmOff<i64, atomic_load_64, or_is_add, "ATOMIC_LOAD_I64">; - -// Select loads with just a constant offset. -defm : LoadPatOffsetOnly<i32, atomic_load_32, "ATOMIC_LOAD_I32">; -defm : LoadPatOffsetOnly<i64, atomic_load_64, "ATOMIC_LOAD_I64">; - -defm : LoadPatGlobalAddrOffOnly<i32, atomic_load_32, "ATOMIC_LOAD_I32">; -defm : LoadPatGlobalAddrOffOnly<i64, atomic_load_64, "ATOMIC_LOAD_I64">; - +// Select loads +defm : LoadPat<i32, atomic_load_32, "ATOMIC_LOAD_I32">; +defm : LoadPat<i64, atomic_load_64, "ATOMIC_LOAD_I64">; // Extending loads. Note that there are only zero-extending atomic loads, no // sign-extending loads. @@ -283,54 +167,18 @@ def sext_aload_8_64 : def sext_aload_16_64 : PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_16 node:$addr)))>; -// Select zero-extending loads with no constant offset. -defm : LoadPatNoOffset<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">; -defm : LoadPatNoOffset<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">; -defm : LoadPatNoOffset<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">; +// Select zero-extending loads +defm : LoadPat<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">; +defm : LoadPat<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">; +defm : LoadPat<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">; -// Select sign-extending loads with no constant offset -defm : LoadPatNoOffset<i32, atomic_load_8, "ATOMIC_LOAD8_U_I32">; -defm : LoadPatNoOffset<i32, atomic_load_16, "ATOMIC_LOAD16_U_I32">; -defm : LoadPatNoOffset<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">; -defm : LoadPatNoOffset<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">; +// Select sign-extending loads +defm : LoadPat<i32, atomic_load_8, "ATOMIC_LOAD8_U_I32">; +defm : LoadPat<i32, atomic_load_16, "ATOMIC_LOAD16_U_I32">; +defm : LoadPat<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">; +defm : LoadPat<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">; // 32->64 sext load gets selected as i32.atomic.load, i64.extend_i32_s -// Zero-extending loads with constant offset -defm : LoadPatImmOff<i64, zext_aload_8_64, regPlusImm, "ATOMIC_LOAD8_U_I64">; -defm : LoadPatImmOff<i64, zext_aload_16_64, regPlusImm, "ATOMIC_LOAD16_U_I64">; -defm : LoadPatImmOff<i64, zext_aload_32_64, regPlusImm, "ATOMIC_LOAD32_U_I64">; -defm : LoadPatImmOff<i64, zext_aload_8_64, or_is_add, "ATOMIC_LOAD8_U_I64">; -defm : LoadPatImmOff<i64, zext_aload_16_64, or_is_add, "ATOMIC_LOAD16_U_I64">; -defm : LoadPatImmOff<i64, zext_aload_32_64, or_is_add, "ATOMIC_LOAD32_U_I64">; - -// Sign-extending loads with constant offset -defm : LoadPatImmOff<i32, atomic_load_8, regPlusImm, "ATOMIC_LOAD8_U_I32">; -defm : LoadPatImmOff<i32, atomic_load_16, regPlusImm, "ATOMIC_LOAD16_U_I32">; -defm : LoadPatImmOff<i32, atomic_load_8, or_is_add, "ATOMIC_LOAD8_U_I32">; -defm : LoadPatImmOff<i32, atomic_load_16, or_is_add, "ATOMIC_LOAD16_U_I32">; -defm : LoadPatImmOff<i64, sext_aload_8_64, regPlusImm, "ATOMIC_LOAD8_U_I64">; -defm : LoadPatImmOff<i64, sext_aload_16_64, regPlusImm, "ATOMIC_LOAD16_U_I64">; -defm : LoadPatImmOff<i64, sext_aload_8_64, or_is_add, "ATOMIC_LOAD8_U_I64">; -defm : LoadPatImmOff<i64, sext_aload_16_64, or_is_add, "ATOMIC_LOAD16_U_I64">; -// No 32->64 patterns, just use i32.atomic.load and i64.extend_s/i64 - -// Extending loads with just a constant offset -defm : LoadPatOffsetOnly<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">; -defm : LoadPatOffsetOnly<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">; -defm : LoadPatOffsetOnly<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">; -defm : LoadPatOffsetOnly<i32, atomic_load_8, "ATOMIC_LOAD8_U_I32">; -defm : LoadPatOffsetOnly<i32, atomic_load_16, "ATOMIC_LOAD16_U_I32">; -defm : LoadPatOffsetOnly<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">; -defm : LoadPatOffsetOnly<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">; - -defm : LoadPatGlobalAddrOffOnly<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">; -defm : LoadPatGlobalAddrOffOnly<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">; -defm : LoadPatGlobalAddrOffOnly<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">; -defm : LoadPatGlobalAddrOffOnly<i32, atomic_load_8, "ATOMIC_LOAD8_U_I32">; -defm : LoadPatGlobalAddrOffOnly<i32, atomic_load_16, "ATOMIC_LOAD16_U_I32">; -defm : LoadPatGlobalAddrOffOnly<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">; -defm : LoadPatGlobalAddrOffOnly<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">; - //===----------------------------------------------------------------------===// // Atomic stores @@ -349,57 +197,16 @@ defm ATOMIC_STORE_I64 : AtomicStore<I64, "i64.atomic.store", 0x18>; // store: (store $val, $ptr) // atomic_store: (store $ptr, $val) - -// Select stores with no constant offset. -multiclass AStorePatNoOffset<ValueType ty, PatFrag kind, string inst> { - def : Pat<(kind I32:$addr, ty:$val), - (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$val)>, +multiclass AStorePat<ValueType ty, PatFrag kind, string inst> { + def : Pat<(kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$val), + (!cast<NI>(inst#_A32) 0, $offset, $addr, $val)>, Requires<[HasAddr32, HasAtomics]>; - def : Pat<(kind I64:$addr, ty:$val), - (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$val)>, + def : Pat<(kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$val), + (!cast<NI>(inst#_A64) 0, $offset, $addr, $val)>, Requires<[HasAddr64, HasAtomics]>; } -defm : AStorePatNoOffset<i32, atomic_store_32, "ATOMIC_STORE_I32">; -defm : AStorePatNoOffset<i64, atomic_store_64, "ATOMIC_STORE_I64">; - -// Select stores with a constant offset. - -// Pattern with address + immediate offset -multiclass AStorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, - string inst> { - def : Pat<(kind (operand I32:$addr, imm:$off), ty:$val), - (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$val)>, - Requires<[HasAddr32, HasAtomics]>; - def : Pat<(kind (operand I64:$addr, imm:$off), ty:$val), - (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$val)>, - Requires<[HasAddr64, HasAtomics]>; -} -defm : AStorePatImmOff<i32, atomic_store_32, regPlusImm, "ATOMIC_STORE_I32">; -defm : AStorePatImmOff<i64, atomic_store_64, regPlusImm, "ATOMIC_STORE_I64">; - -// Select stores with just a constant offset. -multiclass AStorePatOffsetOnly<ValueType ty, PatFrag kind, string inst> { - def : Pat<(kind imm:$off, ty:$val), - (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$val)>, - Requires<[HasAddr32, HasAtomics]>; - def : Pat<(kind imm:$off, ty:$val), - (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$val)>, - Requires<[HasAddr64, HasAtomics]>; -} -defm : AStorePatOffsetOnly<i32, atomic_store_32, "ATOMIC_STORE_I32">; -defm : AStorePatOffsetOnly<i64, atomic_store_64, "ATOMIC_STORE_I64">; - -multiclass AStorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, string inst> { - def : Pat<(kind (WebAssemblyWrapper tglobaladdr:$off), ty:$val), - (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>, - Requires<[HasAddr32, HasAtomics, IsNotPIC]>; - def : Pat<(kind (WebAssemblyWrapper tglobaladdr:$off), ty:$val), - (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$val)>, - Requires<[HasAddr64, HasAtomics, IsNotPIC]>; -} -defm : AStorePatGlobalAddrOffOnly<i32, atomic_store_32, "ATOMIC_STORE_I32">; -defm : AStorePatGlobalAddrOffOnly<i64, atomic_store_64, "ATOMIC_STORE_I64">; - +defm : AStorePat<i32, atomic_store_32, "ATOMIC_STORE_I32">; +defm : AStorePat<i64, atomic_store_64, "ATOMIC_STORE_I64">; // Truncating stores. defm ATOMIC_STORE8_I32 : AtomicStore<I32, "i32.atomic.store8", 0x19>; @@ -420,43 +227,12 @@ def trunc_astore_8_64 : trunc_astore_64<atomic_store_8>; def trunc_astore_16_64 : trunc_astore_64<atomic_store_16>; def trunc_astore_32_64 : trunc_astore_64<atomic_store_32>; - // Truncating stores with no constant offset -defm : AStorePatNoOffset<i32, atomic_store_8, "ATOMIC_STORE8_I32">; -defm : AStorePatNoOffset<i32, atomic_store_16, "ATOMIC_STORE16_I32">; -defm : AStorePatNoOffset<i64, trunc_astore_8_64, "ATOMIC_STORE8_I64">; -defm : AStorePatNoOffset<i64, trunc_astore_16_64, "ATOMIC_STORE16_I64">; -defm : AStorePatNoOffset<i64, trunc_astore_32_64, "ATOMIC_STORE32_I64">; - -// Truncating stores with a constant offset -defm : AStorePatImmOff<i32, atomic_store_8, regPlusImm, "ATOMIC_STORE8_I32">; -defm : AStorePatImmOff<i32, atomic_store_16, regPlusImm, "ATOMIC_STORE16_I32">; -defm : AStorePatImmOff<i64, trunc_astore_8_64, regPlusImm, "ATOMIC_STORE8_I64">; -defm : AStorePatImmOff<i64, trunc_astore_16_64, regPlusImm, - "ATOMIC_STORE16_I64">; -defm : AStorePatImmOff<i64, trunc_astore_32_64, regPlusImm, - "ATOMIC_STORE32_I64">; -defm : AStorePatImmOff<i32, atomic_store_8, or_is_add, "ATOMIC_STORE8_I32">; -defm : AStorePatImmOff<i32, atomic_store_16, or_is_add, "ATOMIC_STORE16_I32">; -defm : AStorePatImmOff<i64, trunc_astore_8_64, or_is_add, "ATOMIC_STORE8_I64">; -defm : AStorePatImmOff<i64, trunc_astore_16_64, or_is_add, - "ATOMIC_STORE16_I64">; -defm : AStorePatImmOff<i64, trunc_astore_32_64, or_is_add, - "ATOMIC_STORE32_I64">; - -// Truncating stores with just a constant offset -defm : AStorePatOffsetOnly<i32, atomic_store_8, "ATOMIC_STORE8_I32">; -defm : AStorePatOffsetOnly<i32, atomic_store_16, "ATOMIC_STORE16_I32">; -defm : AStorePatOffsetOnly<i64, trunc_astore_8_64, "ATOMIC_STORE8_I64">; -defm : AStorePatOffsetOnly<i64, trunc_astore_16_64, "ATOMIC_STORE16_I64">; -defm : AStorePatOffsetOnly<i64, trunc_astore_32_64, "ATOMIC_STORE32_I64">; - -defm : AStorePatGlobalAddrOffOnly<i32, atomic_store_8, "ATOMIC_STORE8_I32">; -defm : AStorePatGlobalAddrOffOnly<i32, atomic_store_16, "ATOMIC_STORE16_I32">; -defm : AStorePatGlobalAddrOffOnly<i64, trunc_astore_8_64, "ATOMIC_STORE8_I64">; -defm : AStorePatGlobalAddrOffOnly<i64, trunc_astore_16_64, "ATOMIC_STORE16_I64">; -defm : AStorePatGlobalAddrOffOnly<i64, trunc_astore_32_64, "ATOMIC_STORE32_I64">; - +defm : AStorePat<i32, atomic_store_8, "ATOMIC_STORE8_I32">; +defm : AStorePat<i32, atomic_store_16, "ATOMIC_STORE16_I32">; +defm : AStorePat<i64, trunc_astore_8_64, "ATOMIC_STORE8_I64">; +defm : AStorePat<i64, trunc_astore_16_64, "ATOMIC_STORE16_I64">; +defm : AStorePat<i64, trunc_astore_32_64, "ATOMIC_STORE32_I64">; //===----------------------------------------------------------------------===// // Atomic binary read-modify-writes @@ -558,64 +334,20 @@ defm ATOMIC_RMW16_U_XCHG_I64 : defm ATOMIC_RMW32_U_XCHG_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw32.xchg_u", 0x47>; -// Select binary RMWs with no constant offset. -multiclass BinRMWPatNoOffset<ValueType ty, PatFrag kind, string inst> { - def : Pat<(ty (kind I32:$addr, ty:$val)), - (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$val)>, +multiclass BinRMWPat<ValueType ty, PatFrag kind, string inst> { + def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$val)), + (!cast<NI>(inst#_A32) 0, $offset, $addr, $val)>, Requires<[HasAddr32, HasAtomics]>; - def : Pat<(ty (kind I64:$addr, ty:$val)), - (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$val)>, + def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$val)), + (!cast<NI>(inst#_A64) 0, $offset, $addr, $val)>, Requires<[HasAddr64, HasAtomics]>; } -// Select binary RMWs with a constant offset. - -// Pattern with address + immediate offset -multiclass BinRMWPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, - string inst> { - def : Pat<(ty (kind (operand I32:$addr, imm:$off), ty:$val)), - (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$val)>, - Requires<[HasAddr32, HasAtomics]>; - def : Pat<(ty (kind (operand I64:$addr, imm:$off), ty:$val)), - (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$val)>, - Requires<[HasAddr64, HasAtomics]>; -} - -// Select binary RMWs with just a constant offset. -multiclass BinRMWPatOffsetOnly<ValueType ty, PatFrag kind, string inst> { - def : Pat<(ty (kind imm:$off, ty:$val)), - (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$val)>, - Requires<[HasAddr32, HasAtomics]>; - def : Pat<(ty (kind imm:$off, ty:$val)), - (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$val)>, - Requires<[HasAddr64, HasAtomics]>; -} - -multiclass BinRMWPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, string inst> { - def : Pat<(ty (kind (WebAssemblyWrapper tglobaladdr:$off), ty:$val)), - (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>, - Requires<[HasAddr32, HasAtomics, IsNotPIC]>; - def : Pat<(ty (kind (WebAssemblyWrapper tglobaladdr:$off), ty:$val)), - (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$val)>, - Requires<[HasAddr64, HasAtomics, IsNotPIC]>; -} - // Patterns for various addressing modes. multiclass BinRMWPattern<PatFrag rmw_32, PatFrag rmw_64, string inst_32, string inst_64> { - defm : BinRMWPatNoOffset<i32, rmw_32, inst_32>; - defm : BinRMWPatNoOffset<i64, rmw_64, inst_64>; - - defm : BinRMWPatImmOff<i32, rmw_32, regPlusImm, inst_32>; - defm : BinRMWPatImmOff<i64, rmw_64, regPlusImm, inst_64>; - defm : BinRMWPatImmOff<i32, rmw_32, or_is_add, inst_32>; - defm : BinRMWPatImmOff<i64, rmw_64, or_is_add, inst_64>; - - defm : BinRMWPatOffsetOnly<i32, rmw_32, inst_32>; - defm : BinRMWPatOffsetOnly<i64, rmw_64, inst_64>; - - defm : BinRMWPatGlobalAddrOffOnly<i32, rmw_32, inst_32>; - defm : BinRMWPatGlobalAddrOffOnly<i64, rmw_64, inst_64>; + defm : BinRMWPat<i32, rmw_32, inst_32>; + defm : BinRMWPat<i64, rmw_64, inst_64>; } defm : BinRMWPattern<atomic_load_add_32, atomic_load_add_64, @@ -661,66 +393,17 @@ class sext_bin_rmw_16_64<PatFrag kind> : sext_bin_rmw_8_64<kind>; multiclass BinRMWTruncExtPattern< PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32, string inst8_32, string inst16_32, string inst8_64, string inst16_64, string inst32_64> { - // Truncating-extending binary RMWs with no constant offset - defm : BinRMWPatNoOffset<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>; - defm : BinRMWPatNoOffset<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>; - defm : BinRMWPatNoOffset<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>; - defm : BinRMWPatNoOffset<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>; - defm : BinRMWPatNoOffset<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>; - - defm : BinRMWPatNoOffset<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>; - defm : BinRMWPatNoOffset<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>; - defm : BinRMWPatNoOffset<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>; - defm : BinRMWPatNoOffset<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>; - - // Truncating-extending binary RMWs with a constant offset - defm : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>; - defm : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, regPlusImm, - inst16_32>; - defm : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>; - defm : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, regPlusImm, - inst16_64>; - defm : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, regPlusImm, - inst32_64>; - defm : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>; - defm : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>; - defm : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>; - defm : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>; - defm : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, or_is_add, inst32_64>; - - defm : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>; - defm : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, regPlusImm, - inst16_32>; - defm : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>; - defm : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, regPlusImm, - inst16_64>; - defm : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>; - defm : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>; - defm : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>; - defm : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>; - - // Truncating-extending binary RMWs with just a constant offset - defm : BinRMWPatOffsetOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>; - defm : BinRMWPatOffsetOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>; - defm : BinRMWPatOffsetOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>; - defm : BinRMWPatOffsetOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>; - defm : BinRMWPatOffsetOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>; - - defm : BinRMWPatOffsetOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>; - defm : BinRMWPatOffsetOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>; - defm : BinRMWPatOffsetOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>; - defm : BinRMWPatOffsetOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>; - - defm : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>; - defm : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>; - defm : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>; - defm : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>; - defm : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>; - - defm : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>; - defm : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>; - defm : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>; - defm : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>; + // Truncating-extending binary RMWs + defm : BinRMWPat<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>; + defm : BinRMWPat<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>; + defm : BinRMWPat<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>; + defm : BinRMWPat<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>; + defm : BinRMWPat<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>; + + defm : BinRMWPat<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>; + defm : BinRMWPat<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>; + defm : BinRMWPat<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>; + defm : BinRMWPat<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>; } defm : BinRMWTruncExtPattern< @@ -792,70 +475,17 @@ defm ATOMIC_RMW16_U_CMPXCHG_I64 : defm ATOMIC_RMW32_U_CMPXCHG_I64 : WebAssemblyTerRMW<I64, "i64.atomic.rmw32.cmpxchg_u", 0x4e>; -// Select ternary RMWs with no constant offset. -multiclass TerRMWPatNoOffset<ValueType ty, PatFrag kind, string inst> { - def : Pat<(ty (kind I32:$addr, ty:$exp, ty:$new)), - (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$exp, ty:$new)>, +multiclass TerRMWPat<ValueType ty, PatFrag kind, string inst> { + def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$exp, ty:$new)), + (!cast<NI>(inst#_A32) 0, $offset, $addr, $exp, $new)>, Requires<[HasAddr32, HasAtomics]>; - def : Pat<(ty (kind I64:$addr, ty:$exp, ty:$new)), - (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$exp, ty:$new)>, + def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$exp, ty:$new)), + (!cast<NI>(inst#_A64) 0, $offset, $addr, $exp, $new)>, Requires<[HasAddr64, HasAtomics]>; } -// Select ternary RMWs with a constant offset. - -// Pattern with address + immediate offset -multiclass TerRMWPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, - string inst> { - def : Pat<(ty (kind (operand I32:$addr, imm:$off), ty:$exp, ty:$new)), - (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$exp, ty:$new)>, - Requires<[HasAddr32, HasAtomics]>; - def : Pat<(ty (kind (operand I64:$addr, imm:$off), ty:$exp, ty:$new)), - (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$exp, ty:$new)>, - Requires<[HasAddr64, HasAtomics]>; -} - -// Select ternary RMWs with just a constant offset. -multiclass TerRMWPatOffsetOnly<ValueType ty, PatFrag kind, string inst> { - def : Pat<(ty (kind imm:$off, ty:$exp, ty:$new)), - (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$exp, - ty:$new)>; - def : Pat<(ty (kind imm:$off, ty:$exp, ty:$new)), - (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$exp, - ty:$new)>; -} - -multiclass TerRMWPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, string inst> { - def : Pat<(ty (kind (WebAssemblyWrapper tglobaladdr:$off), ty:$exp, ty:$new)), - (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$exp, - ty:$new)>, - Requires<[HasAddr32, HasAtomics, IsNotPIC]>; - def : Pat<(ty (kind (WebAssemblyWrapper tglobaladdr:$off), ty:$exp, ty:$new)), - (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$exp, - ty:$new)>, - Requires<[HasAddr64, HasAtomics, IsNotPIC]>; -} - -// Patterns for various addressing modes. -multiclass TerRMWPattern<PatFrag rmw_32, PatFrag rmw_64, string inst_32, - string inst_64> { - defm : TerRMWPatNoOffset<i32, rmw_32, inst_32>; - defm : TerRMWPatNoOffset<i64, rmw_64, inst_64>; - - defm : TerRMWPatImmOff<i32, rmw_32, regPlusImm, inst_32>; - defm : TerRMWPatImmOff<i64, rmw_64, regPlusImm, inst_64>; - defm : TerRMWPatImmOff<i32, rmw_32, or_is_add, inst_32>; - defm : TerRMWPatImmOff<i64, rmw_64, or_is_add, inst_64>; - - defm : TerRMWPatOffsetOnly<i32, rmw_32, inst_32>; - defm : TerRMWPatOffsetOnly<i64, rmw_64, inst_64>; - - defm : TerRMWPatGlobalAddrOffOnly<i32, rmw_32, inst_32>; - defm : TerRMWPatGlobalAddrOffOnly<i64, rmw_64, inst_64>; -} - -defm : TerRMWPattern<atomic_cmp_swap_32, atomic_cmp_swap_64, - "ATOMIC_RMW_CMPXCHG_I32", "ATOMIC_RMW_CMPXCHG_I64">; +defm : TerRMWPat<i32, atomic_cmp_swap_32, "ATOMIC_RMW_CMPXCHG_I32">; +defm : TerRMWPat<i64, atomic_cmp_swap_64, "ATOMIC_RMW_CMPXCHG_I64">; // Truncating & zero-extending ternary RMW patterns. // DAG legalization & optimization before instruction selection may introduce @@ -893,75 +523,13 @@ class sext_ter_rmw_8_64<PatFrag kind> : class sext_ter_rmw_16_64<PatFrag kind> : sext_ter_rmw_8_64<kind>; // 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_i32_s -// Patterns for various addressing modes for truncating-extending ternary RMWs. -multiclass TerRMWTruncExtPattern< - PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32, - string inst8_32, string inst16_32, string inst8_64, string inst16_64, - string inst32_64> { - // Truncating-extending ternary RMWs with no constant offset - defm : TerRMWPatNoOffset<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>; - defm : TerRMWPatNoOffset<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>; - defm : TerRMWPatNoOffset<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>; - defm : TerRMWPatNoOffset<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>; - defm : TerRMWPatNoOffset<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>; - - defm : TerRMWPatNoOffset<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>; - defm : TerRMWPatNoOffset<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>; - defm : TerRMWPatNoOffset<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>; - defm : TerRMWPatNoOffset<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>; - - // Truncating-extending ternary RMWs with a constant offset - defm : TerRMWPatImmOff<i32, zext_ter_rmw_8_32<rmw_8>, regPlusImm, inst8_32>; - defm : TerRMWPatImmOff<i32, zext_ter_rmw_16_32<rmw_16>, regPlusImm, - inst16_32>; - defm : TerRMWPatImmOff<i64, zext_ter_rmw_8_64<rmw_8>, regPlusImm, inst8_64>; - defm : TerRMWPatImmOff<i64, zext_ter_rmw_16_64<rmw_16>, regPlusImm, - inst16_64>; - defm : TerRMWPatImmOff<i64, zext_ter_rmw_32_64<rmw_32>, regPlusImm, - inst32_64>; - defm : TerRMWPatImmOff<i32, zext_ter_rmw_8_32<rmw_8>, or_is_add, inst8_32>; - defm : TerRMWPatImmOff<i32, zext_ter_rmw_16_32<rmw_16>, or_is_add, inst16_32>; - defm : TerRMWPatImmOff<i64, zext_ter_rmw_8_64<rmw_8>, or_is_add, inst8_64>; - defm : TerRMWPatImmOff<i64, zext_ter_rmw_16_64<rmw_16>, or_is_add, inst16_64>; - defm : TerRMWPatImmOff<i64, zext_ter_rmw_32_64<rmw_32>, or_is_add, inst32_64>; - - defm : TerRMWPatImmOff<i32, sext_ter_rmw_8_32<rmw_8>, regPlusImm, inst8_32>; - defm : TerRMWPatImmOff<i32, sext_ter_rmw_16_32<rmw_16>, regPlusImm, - inst16_32>; - defm : TerRMWPatImmOff<i64, sext_ter_rmw_8_64<rmw_8>, regPlusImm, inst8_64>; - defm : TerRMWPatImmOff<i64, sext_ter_rmw_16_64<rmw_16>, regPlusImm, - inst16_64>; - defm : TerRMWPatImmOff<i32, sext_ter_rmw_8_32<rmw_8>, or_is_add, inst8_32>; - defm : TerRMWPatImmOff<i32, sext_ter_rmw_16_32<rmw_16>, or_is_add, inst16_32>; - defm : TerRMWPatImmOff<i64, sext_ter_rmw_8_64<rmw_8>, or_is_add, inst8_64>; - defm : TerRMWPatImmOff<i64, sext_ter_rmw_16_64<rmw_16>, or_is_add, inst16_64>; - - // Truncating-extending ternary RMWs with just a constant offset - defm : TerRMWPatOffsetOnly<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>; - defm : TerRMWPatOffsetOnly<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>; - defm : TerRMWPatOffsetOnly<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>; - defm : TerRMWPatOffsetOnly<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>; - defm : TerRMWPatOffsetOnly<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>; - - defm : TerRMWPatOffsetOnly<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>; - defm : TerRMWPatOffsetOnly<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>; - defm : TerRMWPatOffsetOnly<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>; - defm : TerRMWPatOffsetOnly<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>; - - defm : TerRMWPatGlobalAddrOffOnly<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>; - defm : TerRMWPatGlobalAddrOffOnly<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>; - defm : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>; - defm : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>; - defm : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>; - - defm : TerRMWPatGlobalAddrOffOnly<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>; - defm : TerRMWPatGlobalAddrOffOnly<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>; - defm : TerRMWPatGlobalAddrOffOnly<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>; - defm : TerRMWPatGlobalAddrOffOnly<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>; -} +defm : TerRMWPat<i32, zext_ter_rmw_8_32<atomic_cmp_swap_8>, "ATOMIC_RMW8_U_CMPXCHG_I32">; +defm : TerRMWPat<i32, zext_ter_rmw_16_32<atomic_cmp_swap_16>, "ATOMIC_RMW16_U_CMPXCHG_I32">; +defm : TerRMWPat<i64, zext_ter_rmw_8_64<atomic_cmp_swap_8>, "ATOMIC_RMW8_U_CMPXCHG_I64">; +defm : TerRMWPat<i64, zext_ter_rmw_16_64<atomic_cmp_swap_16>, "ATOMIC_RMW16_U_CMPXCHG_I64">; +defm : TerRMWPat<i64, zext_ter_rmw_32_64<atomic_cmp_swap_32>, "ATOMIC_RMW32_U_CMPXCHG_I64">; -defm : TerRMWTruncExtPattern< - atomic_cmp_swap_8, atomic_cmp_swap_16, atomic_cmp_swap_32, - "ATOMIC_RMW8_U_CMPXCHG_I32", "ATOMIC_RMW16_U_CMPXCHG_I32", - "ATOMIC_RMW8_U_CMPXCHG_I64", "ATOMIC_RMW16_U_CMPXCHG_I64", - "ATOMIC_RMW32_U_CMPXCHG_I64">; +defm : TerRMWPat<i32, sext_ter_rmw_8_32<atomic_cmp_swap_8>, "ATOMIC_RMW8_U_CMPXCHG_I32">; +defm : TerRMWPat<i32, sext_ter_rmw_16_32<atomic_cmp_swap_16>, "ATOMIC_RMW16_U_CMPXCHG_I32">; +defm : TerRMWPat<i64, sext_ter_rmw_8_64<atomic_cmp_swap_8>, "ATOMIC_RMW8_U_CMPXCHG_I64">; +defm : TerRMWPat<i64, sext_ter_rmw_16_64<atomic_cmp_swap_16>, "ATOMIC_RMW16_U_CMPXCHG_I64">; diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp index d7720604d6dc..b2dd656ccdda 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -197,10 +197,37 @@ WebAssemblyInstrInfo::getSerializableTargetIndices() const { {WebAssembly::TI_OPERAND_STACK, "wasm-operand-stack"}, {WebAssembly::TI_GLOBAL_RELOC, "wasm-global-reloc"}, {WebAssembly::TI_LOCAL_INDIRECT, "wasm-local-indirect"}}; - return makeArrayRef(TargetIndices); + return ArrayRef(TargetIndices); } const MachineOperand & WebAssemblyInstrInfo::getCalleeOperand(const MachineInstr &MI) const { return WebAssembly::getCalleeOp(MI); } + +// This returns true when the instruction defines a value of a TargetIndex +// operand that can be tracked by offsets. For Wasm, this returns true for only +// local.set/local.tees. This is currently used by LiveDebugValues analysis. +// +// These are not included: +// - In theory we need to add global.set here too, but we don't have global +// indices at this point because they are relocatable and we address them by +// names until linking, so we don't have 'offsets' (which are used to store +// local/global indices) to deal with in LiveDebugValues. And we don't +// associate debug info in values in globals anyway. +// - All other value-producing instructions, i.e. instructions with defs, can +// define values in the Wasm stack, which is represented by TI_OPERAND_STACK +// TargetIndex. But they don't have offset info within the instruction itself, +// and debug info analysis for them is handled separately in +// WebAssemblyDebugFixup pass, so we don't worry about them here. +bool WebAssemblyInstrInfo::isExplicitTargetIndexDef(const MachineInstr &MI, + int &Index, + int64_t &Offset) const { + unsigned Opc = MI.getOpcode(); + if (WebAssembly::isLocalSet(Opc) || WebAssembly::isLocalTee(Opc)) { + Index = WebAssembly::TI_LOCAL; + Offset = MI.explicit_uses().begin()->getImm(); + return true; + } + return false; +} diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h index 29d700bdf83f..c1e1a790c60e 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h @@ -69,6 +69,9 @@ public: getSerializableTargetIndices() const override; const MachineOperand &getCalleeOperand(const MachineInstr &MI) const override; + + bool isExplicitTargetIndexDef(const MachineInstr &MI, int &Index, + int64_t &Offset) const override; }; } // end namespace llvm diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td index d5bb9e9e48b4..01c0909af72e 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td @@ -19,25 +19,19 @@ // local types. These memory-only types instead zero- or sign-extend into local // types when loading, and truncate when storing. -// WebAssembly constant offsets are performed as unsigned with infinite -// precision, so we need to check for NoUnsignedWrap so that we don't fold an -// offset for an add that needs wrapping. -def regPlusImm : PatFrag<(ops node:$addr, node:$off), - (add node:$addr, node:$off), - [{ return N->getFlags().hasNoUnsignedWrap(); }]>; - -// Treat an 'or' node as an 'add' if the or'ed bits are known to be zero. -def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{ - if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1))) - return CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue()); - - KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0); - KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0); - return (~Known0.Zero & ~Known1.Zero) == 0; -}]>; - -// We don't need a regPlusES because external symbols never have constant -// offsets folded into them, so we can just use add. +// Address Operands + +// These patterns match the static (offset) and dynamic (address stack operand) +// operands for loads and stores, based on a combination of target global +// addresses and constants. +// For example, +// (load (add tga, x)) -> load offset=tga, addr=x +// (store v, tga) -> store v, offset=tga, addr=0 +// (load (add const, x)) -> load offset=const, addr=x +// (store v, const) -> store v, offset=const, addr=0 +// (load x) -> load offset=0, addr=x +def AddrOps32 : ComplexPattern<i32, 2, "SelectAddrOperands32">; +def AddrOps64 : ComplexPattern<i64, 2, "SelectAddrOperands64">; // Defines atomic and non-atomic loads, regular and extending. multiclass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode, @@ -66,70 +60,6 @@ defm LOAD_I64 : WebAssemblyLoad<I64, "i64.load", 0x29, []>; defm LOAD_F32 : WebAssemblyLoad<F32, "f32.load", 0x2a, []>; defm LOAD_F64 : WebAssemblyLoad<F64, "f64.load", 0x2b, []>; -// Select loads with no constant offset. -multiclass LoadPatNoOffset<ValueType ty, SDPatternOperator kind, string inst> { - def : Pat<(ty (kind I32:$addr)), (!cast<NI>(inst # "_A32") 0, 0, I32:$addr)>, - Requires<[HasAddr32]>; - def : Pat<(ty (kind (i64 I64:$addr))), (!cast<NI>(inst # "_A64") 0, 0, I64:$addr)>, - Requires<[HasAddr64]>; -} - -defm : LoadPatNoOffset<i32, load, "LOAD_I32">; -defm : LoadPatNoOffset<i64, load, "LOAD_I64">; -defm : LoadPatNoOffset<f32, load, "LOAD_F32">; -defm : LoadPatNoOffset<f64, load, "LOAD_F64">; - -// Select loads with a constant offset. - -// Pattern with address + immediate offset -multiclass LoadPatImmOff<ValueType ty, SDPatternOperator kind, PatFrag operand, - string inst> { - def : Pat<(ty (kind (operand I32:$addr, imm:$off))), - (!cast<NI>(inst # "_A32") 0, imm:$off, I32:$addr)>, - Requires<[HasAddr32]>; - def : Pat<(ty (kind (operand I64:$addr, imm:$off))), - (!cast<NI>(inst # "_A64") 0, imm:$off, I64:$addr)>, - Requires<[HasAddr64]>; -} - -defm : LoadPatImmOff<i32, load, regPlusImm, "LOAD_I32">; -defm : LoadPatImmOff<i64, load, regPlusImm, "LOAD_I64">; -defm : LoadPatImmOff<f32, load, regPlusImm, "LOAD_F32">; -defm : LoadPatImmOff<f64, load, regPlusImm, "LOAD_F64">; -defm : LoadPatImmOff<i32, load, or_is_add, "LOAD_I32">; -defm : LoadPatImmOff<i64, load, or_is_add, "LOAD_I64">; -defm : LoadPatImmOff<f32, load, or_is_add, "LOAD_F32">; -defm : LoadPatImmOff<f64, load, or_is_add, "LOAD_F64">; - -// Select loads with just a constant offset. -multiclass LoadPatOffsetOnly<ValueType ty, SDPatternOperator kind, string inst> { - def : Pat<(ty (kind imm:$off)), - (!cast<NI>(inst # "_A32") 0, imm:$off, (CONST_I32 0))>, - Requires<[HasAddr32]>; - def : Pat<(ty (kind imm:$off)), - (!cast<NI>(inst # "_A64") 0, imm:$off, (CONST_I64 0))>, - Requires<[HasAddr64]>; -} - -defm : LoadPatOffsetOnly<i32, load, "LOAD_I32">; -defm : LoadPatOffsetOnly<i64, load, "LOAD_I64">; -defm : LoadPatOffsetOnly<f32, load, "LOAD_F32">; -defm : LoadPatOffsetOnly<f64, load, "LOAD_F64">; - -multiclass LoadPatGlobalAddrOffOnly<ValueType ty, SDPatternOperator kind, string inst> { - def : Pat<(ty (kind (WebAssemblyWrapper tglobaladdr:$off))), - (!cast<NI>(inst # "_A32") 0, tglobaladdr:$off, (CONST_I32 0))>, - Requires<[IsNotPIC, HasAddr32]>; - def : Pat<(ty (kind (WebAssemblyWrapper tglobaladdr:$off))), - (!cast<NI>(inst # "_A64") 0, tglobaladdr:$off, (CONST_I64 0))>, - Requires<[IsNotPIC, HasAddr64]>; -} - -defm : LoadPatGlobalAddrOffOnly<i32, load, "LOAD_I32">; -defm : LoadPatGlobalAddrOffOnly<i64, load, "LOAD_I64">; -defm : LoadPatGlobalAddrOffOnly<f32, load, "LOAD_F32">; -defm : LoadPatGlobalAddrOffOnly<f64, load, "LOAD_F64">; - // Extending load. defm LOAD8_S_I32 : WebAssemblyLoad<I32, "i32.load8_s", 0x2c, []>; defm LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.load8_u", 0x2d, []>; @@ -142,98 +72,44 @@ defm LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.load16_u", 0x33, []>; defm LOAD32_S_I64 : WebAssemblyLoad<I64, "i64.load32_s", 0x34, []>; defm LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.load32_u", 0x35, []>; -// Select extending loads with no constant offset. -defm : LoadPatNoOffset<i32, sextloadi8, "LOAD8_S_I32">; -defm : LoadPatNoOffset<i32, zextloadi8, "LOAD8_U_I32">; -defm : LoadPatNoOffset<i32, sextloadi16, "LOAD16_S_I32">; -defm : LoadPatNoOffset<i32, zextloadi16, "LOAD16_U_I32">; -defm : LoadPatNoOffset<i64, sextloadi8, "LOAD8_S_I64">; -defm : LoadPatNoOffset<i64, zextloadi8, "LOAD8_U_I64">; -defm : LoadPatNoOffset<i64, sextloadi16, "LOAD16_S_I64">; -defm : LoadPatNoOffset<i64, zextloadi16, "LOAD16_U_I64">; -defm : LoadPatNoOffset<i64, sextloadi32, "LOAD32_S_I64">; -defm : LoadPatNoOffset<i64, zextloadi32, "LOAD32_U_I64">; +// Pattern matching -// Select extending loads with a constant offset. -defm : LoadPatImmOff<i32, sextloadi8, regPlusImm, "LOAD8_S_I32">; -defm : LoadPatImmOff<i32, zextloadi8, regPlusImm, "LOAD8_U_I32">; -defm : LoadPatImmOff<i32, sextloadi16, regPlusImm, "LOAD16_S_I32">; -defm : LoadPatImmOff<i32, zextloadi16, regPlusImm, "LOAD16_U_I32">; -defm : LoadPatImmOff<i64, sextloadi8, regPlusImm, "LOAD8_S_I64">; -defm : LoadPatImmOff<i64, zextloadi8, regPlusImm, "LOAD8_U_I64">; -defm : LoadPatImmOff<i64, sextloadi16, regPlusImm, "LOAD16_S_I64">; -defm : LoadPatImmOff<i64, zextloadi16, regPlusImm, "LOAD16_U_I64">; -defm : LoadPatImmOff<i64, sextloadi32, regPlusImm, "LOAD32_S_I64">; -defm : LoadPatImmOff<i64, zextloadi32, regPlusImm, "LOAD32_U_I64">; +multiclass LoadPat<ValueType ty, SDPatternOperator kind, string Name> { + def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr))), + (!cast<NI>(Name # "_A32") 0, + offset32_op:$offset, + I32:$addr)>, + Requires<[HasAddr32]>; -defm : LoadPatImmOff<i32, sextloadi8, or_is_add, "LOAD8_S_I32">; -defm : LoadPatImmOff<i32, zextloadi8, or_is_add, "LOAD8_U_I32">; -defm : LoadPatImmOff<i32, sextloadi16, or_is_add, "LOAD16_S_I32">; -defm : LoadPatImmOff<i32, zextloadi16, or_is_add, "LOAD16_U_I32">; -defm : LoadPatImmOff<i64, sextloadi8, or_is_add, "LOAD8_S_I64">; -defm : LoadPatImmOff<i64, zextloadi8, or_is_add, "LOAD8_U_I64">; -defm : LoadPatImmOff<i64, sextloadi16, or_is_add, "LOAD16_S_I64">; -defm : LoadPatImmOff<i64, zextloadi16, or_is_add, "LOAD16_U_I64">; -defm : LoadPatImmOff<i64, sextloadi32, or_is_add, "LOAD32_S_I64">; -defm : LoadPatImmOff<i64, zextloadi32, or_is_add, "LOAD32_U_I64">; - -// Select extending loads with just a constant offset. -defm : LoadPatOffsetOnly<i32, sextloadi8, "LOAD8_S_I32">; -defm : LoadPatOffsetOnly<i32, zextloadi8, "LOAD8_U_I32">; -defm : LoadPatOffsetOnly<i32, sextloadi16, "LOAD16_S_I32">; -defm : LoadPatOffsetOnly<i32, zextloadi16, "LOAD16_U_I32">; - -defm : LoadPatOffsetOnly<i64, sextloadi8, "LOAD8_S_I64">; -defm : LoadPatOffsetOnly<i64, zextloadi8, "LOAD8_U_I64">; -defm : LoadPatOffsetOnly<i64, sextloadi16, "LOAD16_S_I64">; -defm : LoadPatOffsetOnly<i64, zextloadi16, "LOAD16_U_I64">; -defm : LoadPatOffsetOnly<i64, sextloadi32, "LOAD32_S_I64">; -defm : LoadPatOffsetOnly<i64, zextloadi32, "LOAD32_U_I64">; - -defm : LoadPatGlobalAddrOffOnly<i32, sextloadi8, "LOAD8_S_I32">; -defm : LoadPatGlobalAddrOffOnly<i32, zextloadi8, "LOAD8_U_I32">; -defm : LoadPatGlobalAddrOffOnly<i32, sextloadi16, "LOAD16_S_I32">; -defm : LoadPatGlobalAddrOffOnly<i32, zextloadi16, "LOAD16_U_I32">; -defm : LoadPatGlobalAddrOffOnly<i64, sextloadi8, "LOAD8_S_I64">; -defm : LoadPatGlobalAddrOffOnly<i64, zextloadi8, "LOAD8_U_I64">; -defm : LoadPatGlobalAddrOffOnly<i64, sextloadi16, "LOAD16_S_I64">; -defm : LoadPatGlobalAddrOffOnly<i64, zextloadi16, "LOAD16_U_I64">; -defm : LoadPatGlobalAddrOffOnly<i64, sextloadi32, "LOAD32_S_I64">; -defm : LoadPatGlobalAddrOffOnly<i64, zextloadi32, "LOAD32_U_I64">; - -// Resolve "don't care" extending loads to zero-extending loads. This is -// somewhat arbitrary, but zero-extending is conceptually simpler. - -// Select "don't care" extending loads with no constant offset. -defm : LoadPatNoOffset<i32, extloadi8, "LOAD8_U_I32">; -defm : LoadPatNoOffset<i32, extloadi16, "LOAD16_U_I32">; -defm : LoadPatNoOffset<i64, extloadi8, "LOAD8_U_I64">; -defm : LoadPatNoOffset<i64, extloadi16, "LOAD16_U_I64">; -defm : LoadPatNoOffset<i64, extloadi32, "LOAD32_U_I64">; - -// Select "don't care" extending loads with a constant offset. -defm : LoadPatImmOff<i32, extloadi8, regPlusImm, "LOAD8_U_I32">; -defm : LoadPatImmOff<i32, extloadi16, regPlusImm, "LOAD16_U_I32">; -defm : LoadPatImmOff<i64, extloadi8, regPlusImm, "LOAD8_U_I64">; -defm : LoadPatImmOff<i64, extloadi16, regPlusImm, "LOAD16_U_I64">; -defm : LoadPatImmOff<i64, extloadi32, regPlusImm, "LOAD32_U_I64">; -defm : LoadPatImmOff<i32, extloadi8, or_is_add, "LOAD8_U_I32">; -defm : LoadPatImmOff<i32, extloadi16, or_is_add, "LOAD16_U_I32">; -defm : LoadPatImmOff<i64, extloadi8, or_is_add, "LOAD8_U_I64">; -defm : LoadPatImmOff<i64, extloadi16, or_is_add, "LOAD16_U_I64">; -defm : LoadPatImmOff<i64, extloadi32, or_is_add, "LOAD32_U_I64">; + def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr))), + (!cast<NI>(Name # "_A64") 0, + offset64_op:$offset, + I64:$addr)>, + Requires<[HasAddr64]>; +} -// Select "don't care" extending loads with just a constant offset. -defm : LoadPatOffsetOnly<i32, extloadi8, "LOAD8_U_I32">; -defm : LoadPatOffsetOnly<i32, extloadi16, "LOAD16_U_I32">; -defm : LoadPatOffsetOnly<i64, extloadi8, "LOAD8_U_I64">; -defm : LoadPatOffsetOnly<i64, extloadi16, "LOAD16_U_I64">; -defm : LoadPatOffsetOnly<i64, extloadi32, "LOAD32_U_I64">; -defm : LoadPatGlobalAddrOffOnly<i32, extloadi8, "LOAD8_U_I32">; -defm : LoadPatGlobalAddrOffOnly<i32, extloadi16, "LOAD16_U_I32">; -defm : LoadPatGlobalAddrOffOnly<i64, extloadi8, "LOAD8_U_I64">; -defm : LoadPatGlobalAddrOffOnly<i64, extloadi16, "LOAD16_U_I64">; -defm : LoadPatGlobalAddrOffOnly<i64, extloadi32, "LOAD32_U_I64">; +defm : LoadPat<i32, load, "LOAD_I32">; +defm : LoadPat<i64, load, "LOAD_I64">; +defm : LoadPat<f32, load, "LOAD_F32">; +defm : LoadPat<f64, load, "LOAD_F64">; + +defm : LoadPat<i32, sextloadi8, "LOAD8_S_I32">; +defm : LoadPat<i32, sextloadi16, "LOAD16_S_I32">; +defm : LoadPat<i64, sextloadi8, "LOAD8_S_I64">; +defm : LoadPat<i64, sextloadi16, "LOAD16_S_I64">; +defm : LoadPat<i64, sextloadi32, "LOAD32_S_I64">; + +defm : LoadPat<i32, zextloadi8, "LOAD8_U_I32">; +defm : LoadPat<i32, zextloadi16, "LOAD16_U_I32">; +defm : LoadPat<i64, zextloadi8, "LOAD8_U_I64">; +defm : LoadPat<i64, zextloadi16, "LOAD16_U_I64">; +defm : LoadPat<i64, zextloadi32, "LOAD32_U_I64">; + +defm : LoadPat<i32, extloadi8, "LOAD8_U_I32">; +defm : LoadPat<i32, extloadi16, "LOAD16_U_I32">; +defm : LoadPat<i64, extloadi8, "LOAD8_U_I64">; +defm : LoadPat<i64, extloadi16, "LOAD16_U_I64">; +defm : LoadPat<i64, extloadi32, "LOAD32_U_I64">; // Defines atomic and non-atomic stores, regular and truncating multiclass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode, @@ -263,69 +139,25 @@ defm STORE_I64 : WebAssemblyStore<I64, "i64.store", 0x37>; defm STORE_F32 : WebAssemblyStore<F32, "f32.store", 0x38>; defm STORE_F64 : WebAssemblyStore<F64, "f64.store", 0x39>; -// Select stores with no constant offset. -multiclass StorePatNoOffset<ValueType ty, PatFrag node, string inst> { - def : Pat<(node ty:$val, I32:$addr), - (!cast<NI>(inst # "_A32") 0, 0, I32:$addr, ty:$val)>, - Requires<[HasAddr32]>; - def : Pat<(node ty:$val, I64:$addr), - (!cast<NI>(inst # "_A64") 0, 0, I64:$addr, ty:$val)>, - Requires<[HasAddr64]>; -} - -defm : StorePatNoOffset<i32, store, "STORE_I32">; -defm : StorePatNoOffset<i64, store, "STORE_I64">; -defm : StorePatNoOffset<f32, store, "STORE_F32">; -defm : StorePatNoOffset<f64, store, "STORE_F64">; - -// Select stores with a constant offset. -multiclass StorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, - string inst> { - def : Pat<(kind ty:$val, (operand I32:$addr, imm:$off)), - (!cast<NI>(inst # "_A32") 0, imm:$off, I32:$addr, ty:$val)>, - Requires<[HasAddr32]>; - def : Pat<(kind ty:$val, (operand I64:$addr, imm:$off)), - (!cast<NI>(inst # "_A64") 0, imm:$off, I64:$addr, ty:$val)>, - Requires<[HasAddr64]>; -} - -defm : StorePatImmOff<i32, store, regPlusImm, "STORE_I32">; -defm : StorePatImmOff<i64, store, regPlusImm, "STORE_I64">; -defm : StorePatImmOff<f32, store, regPlusImm, "STORE_F32">; -defm : StorePatImmOff<f64, store, regPlusImm, "STORE_F64">; -defm : StorePatImmOff<i32, store, or_is_add, "STORE_I32">; -defm : StorePatImmOff<i64, store, or_is_add, "STORE_I64">; -defm : StorePatImmOff<f32, store, or_is_add, "STORE_F32">; -defm : StorePatImmOff<f64, store, or_is_add, "STORE_F64">; - -// Select stores with just a constant offset. -multiclass StorePatOffsetOnly<ValueType ty, PatFrag kind, string inst> { - def : Pat<(kind ty:$val, imm:$off), - (!cast<NI>(inst # "_A32") 0, imm:$off, (CONST_I32 0), ty:$val)>, - Requires<[HasAddr32]>; - def : Pat<(kind ty:$val, imm:$off), - (!cast<NI>(inst # "_A64") 0, imm:$off, (CONST_I64 0), ty:$val)>, - Requires<[HasAddr64]>; +multiclass StorePat<ValueType ty, SDPatternOperator kind, string Name> { + def : Pat<(kind ty:$val, (AddrOps32 offset32_op:$offset, I32:$addr)), + (!cast<NI>(Name # "_A32") 0, + offset32_op:$offset, + I32:$addr, + ty:$val)>, + Requires<[HasAddr32]>; + def : Pat<(kind ty:$val, (AddrOps64 offset64_op:$offset, I64:$addr)), + (!cast<NI>(Name # "_A64") 0, + offset64_op:$offset, + I64:$addr, + ty:$val)>, + Requires<[HasAddr64]>; } -defm : StorePatOffsetOnly<i32, store, "STORE_I32">; -defm : StorePatOffsetOnly<i64, store, "STORE_I64">; -defm : StorePatOffsetOnly<f32, store, "STORE_F32">; -defm : StorePatOffsetOnly<f64, store, "STORE_F64">; -multiclass StorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, string inst> { - def : Pat<(kind ty:$val, (WebAssemblyWrapper tglobaladdr:$off)), - (!cast<NI>(inst # "_A32") 0, tglobaladdr:$off, (CONST_I32 0), - ty:$val)>, - Requires<[IsNotPIC, HasAddr32]>; - def : Pat<(kind ty:$val, (WebAssemblyWrapper tglobaladdr:$off)), - (!cast<NI>(inst # "_A64") 0, tglobaladdr:$off, (CONST_I64 0), - ty:$val)>, - Requires<[IsNotPIC, HasAddr64]>; -} -defm : StorePatGlobalAddrOffOnly<i32, store, "STORE_I32">; -defm : StorePatGlobalAddrOffOnly<i64, store, "STORE_I64">; -defm : StorePatGlobalAddrOffOnly<f32, store, "STORE_F32">; -defm : StorePatGlobalAddrOffOnly<f64, store, "STORE_F64">; +defm : StorePat<i32, store, "STORE_I32">; +defm : StorePat<i64, store, "STORE_I64">; +defm : StorePat<f32, store, "STORE_F32">; +defm : StorePat<f64, store, "STORE_F64">; // Truncating store. defm STORE8_I32 : WebAssemblyStore<I32, "i32.store8", 0x3a>; @@ -334,36 +166,11 @@ defm STORE8_I64 : WebAssemblyStore<I64, "i64.store8", 0x3c>; defm STORE16_I64 : WebAssemblyStore<I64, "i64.store16", 0x3d>; defm STORE32_I64 : WebAssemblyStore<I64, "i64.store32", 0x3e>; -// Select truncating stores with no constant offset. -defm : StorePatNoOffset<i32, truncstorei8, "STORE8_I32">; -defm : StorePatNoOffset<i32, truncstorei16, "STORE16_I32">; -defm : StorePatNoOffset<i64, truncstorei8, "STORE8_I64">; -defm : StorePatNoOffset<i64, truncstorei16, "STORE16_I64">; -defm : StorePatNoOffset<i64, truncstorei32, "STORE32_I64">; - -// Select truncating stores with a constant offset. -defm : StorePatImmOff<i32, truncstorei8, regPlusImm, "STORE8_I32">; -defm : StorePatImmOff<i32, truncstorei16, regPlusImm, "STORE16_I32">; -defm : StorePatImmOff<i64, truncstorei8, regPlusImm, "STORE8_I64">; -defm : StorePatImmOff<i64, truncstorei16, regPlusImm, "STORE16_I64">; -defm : StorePatImmOff<i64, truncstorei32, regPlusImm, "STORE32_I64">; -defm : StorePatImmOff<i32, truncstorei8, or_is_add, "STORE8_I32">; -defm : StorePatImmOff<i32, truncstorei16, or_is_add, "STORE16_I32">; -defm : StorePatImmOff<i64, truncstorei8, or_is_add, "STORE8_I64">; -defm : StorePatImmOff<i64, truncstorei16, or_is_add, "STORE16_I64">; -defm : StorePatImmOff<i64, truncstorei32, or_is_add, "STORE32_I64">; - -// Select truncating stores with just a constant offset. -defm : StorePatOffsetOnly<i32, truncstorei8, "STORE8_I32">; -defm : StorePatOffsetOnly<i32, truncstorei16, "STORE16_I32">; -defm : StorePatOffsetOnly<i64, truncstorei8, "STORE8_I64">; -defm : StorePatOffsetOnly<i64, truncstorei16, "STORE16_I64">; -defm : StorePatOffsetOnly<i64, truncstorei32, "STORE32_I64">; -defm : StorePatGlobalAddrOffOnly<i32, truncstorei8, "STORE8_I32">; -defm : StorePatGlobalAddrOffOnly<i32, truncstorei16, "STORE16_I32">; -defm : StorePatGlobalAddrOffOnly<i64, truncstorei8, "STORE8_I64">; -defm : StorePatGlobalAddrOffOnly<i64, truncstorei16, "STORE16_I64">; -defm : StorePatGlobalAddrOffOnly<i64, truncstorei32, "STORE32_I64">; +defm : StorePat<i32, truncstorei8, "STORE8_I32">; +defm : StorePat<i32, truncstorei16, "STORE16_I32">; +defm : StorePat<i64, truncstorei8, "STORE8_I64">; +defm : StorePat<i64, truncstorei16, "STORE16_I64">; +defm : StorePat<i64, truncstorei32, "STORE32_I64">; multiclass MemoryOps<WebAssemblyRegClass rc, string B> { // Current memory size. diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td index ed3cc7ed1c53..ad2ec40b8b31 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -54,15 +54,6 @@ def ImmI#SIZE : ImmLeaf<i32, foreach SIZE = [2, 4, 8, 16, 32] in def LaneIdx#SIZE : ImmLeaf<i32, "return 0 <= Imm && Imm < "#SIZE#";">; -// Create vector with identical lanes: splat -def splat2 : PatFrag<(ops node:$x), (build_vector $x, $x)>; -def splat4 : PatFrag<(ops node:$x), (build_vector $x, $x, $x, $x)>; -def splat8 : PatFrag<(ops node:$x), (build_vector $x, $x, $x, $x, - $x, $x, $x, $x)>; -def splat16 : PatFrag<(ops node:$x), - (build_vector $x, $x, $x, $x, $x, $x, $x, $x, - $x, $x, $x, $x, $x, $x, $x, $x)>; - class Vec { ValueType vt; ValueType int_vt; @@ -70,6 +61,7 @@ class Vec { WebAssemblyRegClass lane_rc; int lane_bits; ImmLeaf lane_idx; + SDPatternOperator lane_load; PatFrag splat; string prefix; Vec split; @@ -82,7 +74,8 @@ def I8x16 : Vec { let lane_rc = I32; let lane_bits = 8; let lane_idx = LaneIdx16; - let splat = splat16; + let lane_load = extloadi8; + let splat = PatFrag<(ops node:$x), (v16i8 (splat_vector (i8 $x)))>; let prefix = "i8x16"; } @@ -93,7 +86,8 @@ def I16x8 : Vec { let lane_rc = I32; let lane_bits = 16; let lane_idx = LaneIdx8; - let splat = splat8; + let lane_load = extloadi16; + let splat = PatFrag<(ops node:$x), (v8i16 (splat_vector (i16 $x)))>; let prefix = "i16x8"; let split = I8x16; } @@ -105,7 +99,8 @@ def I32x4 : Vec { let lane_rc = I32; let lane_bits = 32; let lane_idx = LaneIdx4; - let splat = splat4; + let lane_load = load; + let splat = PatFrag<(ops node:$x), (v4i32 (splat_vector (i32 $x)))>; let prefix = "i32x4"; let split = I16x8; } @@ -117,7 +112,8 @@ def I64x2 : Vec { let lane_rc = I64; let lane_bits = 64; let lane_idx = LaneIdx2; - let splat = splat2; + let lane_load = load; + let splat = PatFrag<(ops node:$x), (v2i64 (splat_vector (i64 $x)))>; let prefix = "i64x2"; let split = I32x4; } @@ -129,7 +125,8 @@ def F32x4 : Vec { let lane_rc = F32; let lane_bits = 32; let lane_idx = LaneIdx4; - let splat = splat4; + let lane_load = load; + let splat = PatFrag<(ops node:$x), (v4f32 (splat_vector (f32 $x)))>; let prefix = "f32x4"; } @@ -140,7 +137,8 @@ def F64x2 : Vec { let lane_rc = F64; let lane_bits = 64; let lane_idx = LaneIdx2; - let splat = splat2; + let lane_load = load; + let splat = PatFrag<(ops node:$x), (v2f64 (splat_vector (f64 $x)))>; let prefix = "f64x2"; } @@ -167,11 +165,7 @@ defm LOAD_V128_A64 : // Def load patterns from WebAssemblyInstrMemory.td for vector types foreach vec = AllVecs in { -defm : LoadPatNoOffset<vec.vt, load, "LOAD_V128">; -defm : LoadPatImmOff<vec.vt, load, regPlusImm, "LOAD_V128">; -defm : LoadPatImmOff<vec.vt, load, or_is_add, "LOAD_V128">; -defm : LoadPatOffsetOnly<vec.vt, load, "LOAD_V128">; -defm : LoadPatGlobalAddrOffOnly<vec.vt, load, "LOAD_V128">; +defm : LoadPat<vec.vt, load, "LOAD_V128">; } // v128.loadX_splat @@ -199,18 +193,11 @@ defm "" : SIMDLoadSplat<16, 8>; defm "" : SIMDLoadSplat<32, 9>; defm "" : SIMDLoadSplat<64, 10>; -def wasm_load_splat_t : SDTypeProfile<1, 1, [SDTCisPtrTy<1>]>; -def wasm_load_splat : SDNode<"WebAssemblyISD::LOAD_SPLAT", wasm_load_splat_t, - [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; -def load_splat : PatFrag<(ops node:$addr), (wasm_load_splat node:$addr)>; - foreach vec = AllVecs in { -defvar inst = "LOAD"#vec.lane_bits#"_SPLAT"; -defm : LoadPatNoOffset<vec.vt, load_splat, inst>; -defm : LoadPatImmOff<vec.vt, load_splat, regPlusImm, inst>; -defm : LoadPatImmOff<vec.vt, load_splat, or_is_add, inst>; -defm : LoadPatOffsetOnly<vec.vt, load_splat, inst>; -defm : LoadPatGlobalAddrOffOnly<vec.vt, load_splat, inst>; + defvar inst = "LOAD"#vec.lane_bits#"_SPLAT"; + defm : LoadPat<vec.vt, + PatFrag<(ops node:$addr), (splat_vector (vec.lane_vt (vec.lane_load node:$addr)))>, + inst>; } // Load and extend @@ -255,11 +242,7 @@ foreach exts = [["sextloadvi", "_S"], ["extloadvi", "_U"]] in { defvar loadpat = !cast<PatFrag>(exts[0]#vec.split.lane_bits); defvar inst = "LOAD_EXTEND"#exts[1]#"_"#vec; -defm : LoadPatNoOffset<vec.vt, loadpat, inst>; -defm : LoadPatImmOff<vec.vt, loadpat, regPlusImm, inst>; -defm : LoadPatImmOff<vec.vt, loadpat, or_is_add, inst>; -defm : LoadPatOffsetOnly<vec.vt, loadpat, inst>; -defm : LoadPatGlobalAddrOffOnly<vec.vt, loadpat, inst>; +defm : LoadPat<vec.vt, loadpat, inst>; } // Load lane into zero vector @@ -285,25 +268,19 @@ defm "" : SIMDLoadZero<I32x4, 0x5c>; defm "" : SIMDLoadZero<I64x2, 0x5d>; // Use load_zero to load scalars into vectors as well where possible. -// TODO: i32, i16, and i8 scalars -def load_scalar : - PatFrag<(ops node:$addr), (scalar_to_vector (i64 (load $addr)))>; -defm : LoadPatNoOffset<v2i64, load_scalar, "LOAD_ZERO_I64x2">; -defm : LoadPatImmOff<v2i64, load_scalar, regPlusImm, "LOAD_ZERO_I64x2">; -defm : LoadPatImmOff<v2i64, load_scalar, or_is_add, "LOAD_ZERO_I64x2">; -defm : LoadPatOffsetOnly<v2i64, load_scalar, "LOAD_ZERO_I64x2">; -defm : LoadPatGlobalAddrOffOnly<v2i64, load_scalar, "LOAD_ZERO_I64x2">; +// TODO: i16, and i8 scalars +foreach vec = [I32x4, I64x2] in { + defvar inst = "LOAD_ZERO_"#vec; + defvar pat = PatFrag<(ops node:$addr), (scalar_to_vector (vec.lane_vt (load $addr)))>; + defm : LoadPat<vec.vt, pat, inst>; +} // TODO: f32x4 and f64x2 as well foreach vec = [I32x4, I64x2] in { defvar inst = "LOAD_ZERO_"#vec; defvar pat = PatFrag<(ops node:$ptr), (vector_insert (vec.splat (vec.lane_vt 0)), (vec.lane_vt (load $ptr)), 0)>; - defm : LoadPatNoOffset<vec.vt, pat, inst>; - defm : LoadPatImmOff<vec.vt, pat, regPlusImm, inst>; - defm : LoadPatImmOff<vec.vt, pat, or_is_add, inst>; - defm : LoadPatOffsetOnly<vec.vt, pat, inst>; - defm : LoadPatGlobalAddrOffOnly<vec.vt, pat, inst>; + defm : LoadPat<vec.vt, pat, inst>; } // Load lane @@ -384,11 +361,7 @@ defm STORE_V128_A64 : // Def store patterns from WebAssemblyInstrMemory.td for vector types foreach vec = AllVecs in { -defm : StorePatNoOffset<vec.vt, store, "STORE_V128">; -defm : StorePatImmOff<vec.vt, store, regPlusImm, "STORE_V128">; -defm : StorePatImmOff<vec.vt, store, or_is_add, "STORE_V128">; -defm : StorePatOffsetOnly<vec.vt, store, "STORE_V128">; -defm : StorePatGlobalAddrOffOnly<vec.vt, store, "STORE_V128">; +defm : StorePat<vec.vt, store, "STORE_V128">; } // Store lane @@ -417,13 +390,16 @@ defm "" : SIMDStoreLane<I16x8, 0x59>; defm "" : SIMDStoreLane<I32x4, 0x5a>; defm "" : SIMDStoreLane<I64x2, 0x5b>; -// Select stores with no constant offset. -multiclass StoreLanePatNoOffset<Vec vec, SDPatternOperator kind> { - def : Pat<(kind (i32 I32:$addr), (vec.vt V128:$vec), (i32 vec.lane_idx:$idx)), - (!cast<NI>("STORE_LANE_"#vec#"_A32") 0, 0, imm:$idx, $addr, $vec)>, +multiclass StoreLanePat<Vec vec, SDPatternOperator kind> { + def : Pat<(kind (AddrOps32 offset32_op:$offset, I32:$addr), + (vec.vt V128:$vec), + (i32 vec.lane_idx:$idx)), + (!cast<NI>("STORE_LANE_"#vec#"_A32") 0, $offset, imm:$idx, $addr, $vec)>, Requires<[HasAddr32]>; - def : Pat<(kind (i64 I64:$addr), (vec.vt V128:$vec), (i32 vec.lane_idx:$idx)), - (!cast<NI>("STORE_LANE_"#vec#"_A64") 0, 0, imm:$idx, $addr, $vec)>, + def : Pat<(kind (AddrOps64 offset64_op:$offset, I64:$addr), + (vec.vt V128:$vec), + (i32 vec.lane_idx:$idx)), + (!cast<NI>("STORE_LANE_"#vec#"_A64") 0, $offset, imm:$idx, $addr, $vec)>, Requires<[HasAddr64]>; } @@ -442,10 +418,10 @@ def store64_lane : // TODO: floating point lanes as well let AddedComplexity = 1 in { -defm : StoreLanePatNoOffset<I8x16, store8_lane>; -defm : StoreLanePatNoOffset<I16x8, store16_lane>; -defm : StoreLanePatNoOffset<I32x4, store32_lane>; -defm : StoreLanePatNoOffset<I64x2, store64_lane>; +defm : StoreLanePat<I8x16, store8_lane>; +defm : StoreLanePat<I16x8, store16_lane>; +defm : StoreLanePat<I32x4, store32_lane>; +defm : StoreLanePat<I64x2, store64_lane>; } //===----------------------------------------------------------------------===// @@ -507,6 +483,17 @@ defm "" : ConstVec<F64x2, (build_vector (f64 fpimm:$i0), (f64 fpimm:$i1)), "$i0, $i1">; +// Match splat(x) -> const.v128(x, ..., x) +foreach vec = AllVecs in { + defvar numEls = !div(vec.vt.Size, vec.lane_bits); + defvar isFloat = !or(!eq(vec.lane_vt, f32), !eq(vec.lane_vt, f64)); + defvar immKind = !if(isFloat, fpimm, imm); + def : Pat<(vec.splat (vec.lane_vt immKind:$x)), + !dag(!cast<NI>("CONST_V128_"#vec), + !listsplat((vec.lane_vt immKind:$x), numEls), + ?)>; +} + // Shuffle lanes: shuffle defm SHUFFLE : SIMD_I<(outs V128:$dst), @@ -811,6 +798,20 @@ def : Pat<(vec.vt (or (and (vec.vt V128:$c), (vec.vt V128:$v1)), (and (vnot V128:$c), (vec.vt V128:$v2)))), (BITSELECT $v1, $v2, $c)>; +// Bitselect is also equivalent to ((v1 ^ v2) & c) ^ v2 +foreach vec = IntVecs in +def : Pat<(vec.vt (xor (and (xor (vec.vt V128:$v1), (vec.vt V128:$v2)), + (vec.vt V128:$c)), + (vec.vt V128:$v2))), + (BITSELECT $v1, $v2, $c)>; + +// Same pattern with `c` negated so `a` and `b` get swapped. +foreach vec = IntVecs in +def : Pat<(vec.vt (xor (and (xor (vec.vt V128:$v1), (vec.vt V128:$v2)), + (vnot (vec.vt V128:$c))), + (vec.vt V128:$v2))), + (BITSELECT $v2, $v1, $c)>; + // Also implement vselect in terms of bitselect foreach vec = AllVecs in def : Pat<(vec.vt (vselect @@ -1364,26 +1365,26 @@ defm "" : RelaxedConvert<I32x4, F64x2, int_wasm_relaxed_trunc_unsigned_zero, "relaxed_trunc_f64x2_u_zero", 0x104>; //===----------------------------------------------------------------------===// -// Relaxed Fused Multiply- Add and Subtract (FMA/FMS) +// Relaxed (Negative) Multiply-Add (madd/nmadd) //===----------------------------------------------------------------------===// -multiclass SIMDFM<Vec vec, bits<32> simdopA, bits<32> simdopS> { - defm FMA_#vec : +multiclass SIMDMADD<Vec vec, bits<32> simdopA, bits<32> simdopS> { + defm MADD_#vec : RELAXED_I<(outs V128:$dst), (ins V128:$a, V128:$b, V128:$c), (outs), (ins), - [(set (vec.vt V128:$dst), (int_wasm_fma + [(set (vec.vt V128:$dst), (int_wasm_relaxed_madd (vec.vt V128:$a), (vec.vt V128:$b), (vec.vt V128:$c)))], - vec.prefix#".relaxed_fma\t$dst, $a, $b, $c", - vec.prefix#".relaxed_fma", simdopA>; - defm FMS_#vec : + vec.prefix#".relaxed_madd\t$dst, $a, $b, $c", + vec.prefix#".relaxed_madd", simdopA>; + defm NMADD_#vec : RELAXED_I<(outs V128:$dst), (ins V128:$a, V128:$b, V128:$c), (outs), (ins), - [(set (vec.vt V128:$dst), (int_wasm_fms + [(set (vec.vt V128:$dst), (int_wasm_relaxed_nmadd (vec.vt V128:$a), (vec.vt V128:$b), (vec.vt V128:$c)))], - vec.prefix#".relaxed_fms\t$dst, $a, $b, $c", - vec.prefix#".relaxed_fms", simdopS>; + vec.prefix#".relaxed_nmadd\t$dst, $a, $b, $c", + vec.prefix#".relaxed_nmadd", simdopS>; } -defm "" : SIMDFM<F32x4, 0x105, 0x106>; -defm "" : SIMDFM<F64x2, 0x107, 0x108>; +defm "" : SIMDMADD<F32x4, 0x105, 0x106>; +defm "" : SIMDMADD<F64x2, 0x107, 0x108>; //===----------------------------------------------------------------------===// // Laneselect @@ -1392,7 +1393,7 @@ defm "" : SIMDFM<F64x2, 0x107, 0x108>; multiclass SIMDLANESELECT<Vec vec, bits<32> op> { defm LANESELECT_#vec : RELAXED_I<(outs V128:$dst), (ins V128:$a, V128:$b, V128:$c), (outs), (ins), - [(set (vec.vt V128:$dst), (int_wasm_laneselect + [(set (vec.vt V128:$dst), (int_wasm_relaxed_laneselect (vec.vt V128:$a), (vec.vt V128:$b), (vec.vt V128:$c)))], vec.prefix#".relaxed_laneselect\t$dst, $a, $b, $c", vec.prefix#".relaxed_laneselect", op>; @@ -1440,15 +1441,27 @@ defm RELAXED_Q15MULR_S : defm RELAXED_DOT : RELAXED_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), (outs), (ins), - [(set (v8i16 V128:$dst), (int_wasm_dot_i8x16_i7x16_signed + [(set (v8i16 V128:$dst), (int_wasm_relaxed_dot_i8x16_i7x16_signed (v16i8 V128:$lhs), (v16i8 V128:$rhs)))], - "i16x8.dot_i8x16_i7x16_s\t$dst, $lhs, $rhs", - "i16x8.dot_i8x16_i7x16_s", 0x112>; + "i16x8.relaxed_dot_i8x16_i7x16_s\t$dst, $lhs, $rhs", + "i16x8.relaxed_dot_i8x16_i7x16_s", 0x112>; defm RELAXED_DOT_ADD : RELAXED_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs, V128:$acc), (outs), (ins), - [(set (v4i32 V128:$dst), (int_wasm_dot_i8x16_i7x16_add_signed + [(set (v4i32 V128:$dst), (int_wasm_relaxed_dot_i8x16_i7x16_add_signed (v16i8 V128:$lhs), (v16i8 V128:$rhs), (v4i32 V128:$acc)))], - "i32x4.dot_i8x16_i7x16_add_s\t$dst, $lhs, $rhs, $acc", - "i32x4.dot_i8x16_i7x16_add_s", 0x113>; + "i32x4.relaxed_dot_i8x16_i7x16_add_s\t$dst, $lhs, $rhs, $acc", + "i32x4.relaxed_dot_i8x16_i7x16_add_s", 0x113>; + +//===----------------------------------------------------------------------===// +// Relaxed BFloat16 dot product +//===----------------------------------------------------------------------===// + +defm RELAXED_DOT_BFLOAT : + RELAXED_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs, V128:$acc), + (outs), (ins), + [(set (v4f32 V128:$dst), (int_wasm_relaxed_dot_bf16x8_add_f32 + (v8i16 V128:$lhs), (v8i16 V128:$rhs), (v4f32 V128:$acc)))], + "f32x4.relaxed_dot_bf16x8_add_f32\t$dst, $lhs, $rhs, $acc", + "f32x4.relaxed_dot_bf16x8_add_f32", 0x114>; diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td index 1fd00bf1cbc8..069ce5e3bc94 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td @@ -24,7 +24,7 @@ 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), - [], + [(set rc:$res, (!cast<Intrinsic>("int_wasm_table_get_" # suffix) (WebAssemblyWrapper tglobaladdr:$table), I32:$i))], "table.get\t$res, $table, $i", "table.get\t$table", 0x25>; @@ -32,7 +32,7 @@ multiclass TABLE<WebAssemblyRegClass rc, string suffix> { let mayStore = 1 in defm TABLE_SET_#rc : I<(outs), (ins table32_op:$table, I32:$i, rc:$val), (outs), (ins table32_op:$table), - [], + [(!cast<Intrinsic>("int_wasm_table_set_" # suffix) (WebAssemblyWrapper tglobaladdr:$table), I32:$i, rc:$val)], "table.set\t$table, $i, $val", "table.set\t$table", 0x26>; diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index 7a1a769c6b16..5faa098b94ad 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -545,15 +545,13 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) { ArgAttributes.push_back(InvokeAL.getParamAttrs(I)); AttrBuilder FnAttrs(CI->getContext(), InvokeAL.getFnAttrs()); - if (FnAttrs.contains(Attribute::AllocSize)) { + if (auto Args = FnAttrs.getAllocSizeArgs()) { // The allocsize attribute (if any) referes to parameters by index and needs // to be adjusted. - unsigned SizeArg; - Optional<unsigned> NEltArg; - std::tie(SizeArg, NEltArg) = FnAttrs.getAllocSizeArgs(); + auto [SizeArg, NEltArg] = *Args; SizeArg += 1; if (NEltArg) - NEltArg = NEltArg.value() + 1; + NEltArg = *NEltArg + 1; FnAttrs.addAllocSizeAttr(SizeArg, NEltArg); } // In case the callee has 'noreturn' attribute, We need to remove it, because @@ -775,7 +773,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp( // Output parameter assignment Label = LabelPHI; EndBB = EndBB1; - LongjmpResult = IRB.CreateCall(GetTempRet0F, None, "longjmp_result"); + LongjmpResult = IRB.CreateCall(GetTempRet0F, std::nullopt, "longjmp_result"); } void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) { @@ -1227,9 +1225,9 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) { // Create a call to __cxa_find_matching_catch_N function Function *FMCF = getFindMatchingCatch(M, FMCArgs.size()); CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc"); - Value *Undef = UndefValue::get(LPI->getType()); - Value *Pair0 = IRB.CreateInsertValue(Undef, FMCI, 0, "pair0"); - Value *TempRet0 = IRB.CreateCall(GetTempRet0F, None, "tempret0"); + Value *Poison = PoisonValue::get(LPI->getType()); + Value *Pair0 = IRB.CreateInsertValue(Poison, FMCI, 0, "pair0"); + Value *TempRet0 = IRB.CreateCall(GetTempRet0F, std::nullopt, "tempret0"); Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1"); LPI->replaceAllUsesWith(Pair1); @@ -1290,9 +1288,11 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) { "setjmpTableSize", Entry->getTerminator()); SetjmpTableSize->setDebugLoc(FirstDL); // setjmpTable = (int *) malloc(40); - Instruction *SetjmpTable = CallInst::CreateMalloc( - SetjmpTableSize, IRB.getInt32Ty(), IRB.getInt32Ty(), IRB.getInt32(40), - nullptr, nullptr, "setjmpTable"); + Type *IntPtrTy = getAddrIntType(&M); + Constant *size = ConstantInt::get(IntPtrTy, 40); + Instruction *SetjmpTable = + CallInst::CreateMalloc(SetjmpTableSize, IntPtrTy, IRB.getInt32Ty(), size, + nullptr, nullptr, "setjmpTable"); SetjmpTable->setDebugLoc(FirstDL); // CallInst::CreateMalloc may return a bitcast instruction if the result types // mismatch. We need to set the debug loc for the original call too. @@ -1355,7 +1355,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) { Instruction *NewSetjmpTable = IRB.CreateCall(SaveSetjmpF, Args, "setjmpTable"); Instruction *NewSetjmpTableSize = - IRB.CreateCall(GetTempRet0F, None, "setjmpTableSize"); + IRB.CreateCall(GetTempRet0F, std::nullopt, "setjmpTableSize"); SetjmpTableInsts.push_back(NewSetjmpTable); SetjmpTableSizeInsts.push_back(NewSetjmpTableSize); ToErase.push_back(CI); @@ -1630,7 +1630,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj( // Create switch instruction IRB.SetInsertPoint(EndBB); - IRB.SetCurrentDebugLocation(EndBB->getInstList().back().getDebugLoc()); + IRB.SetCurrentDebugLocation(EndBB->back().getDebugLoc()); SwitchInst *SI = IRB.CreateSwitch(Label, Tail, SetjmpRetPHIs.size()); // -1 means no longjmp happened, continue normally (will hit the default // switch case). 0 means a longjmp that is not ours to handle, needs a diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp index e8b3542df12f..85ece58f98b3 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -194,7 +194,7 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI, case MachineOperand::MO_Immediate: { unsigned DescIndex = I - NumVariadicDefs; if (DescIndex < Desc.NumOperands) { - const MCOperandInfo &Info = Desc.OpInfo[DescIndex]; + const MCOperandInfo &Info = Desc.operands()[DescIndex]; if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) { SmallVector<wasm::ValType, 4> Returns; SmallVector<wasm::ValType, 4> Params; diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp index 96284687971c..7207fbeb305a 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp @@ -28,10 +28,9 @@ MachineFunctionInfo *WebAssemblyFunctionInfo::clone( BumpPtrAllocator &Allocator, MachineFunction &DestMF, const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) const { - WebAssemblyFunctionInfo *Clone = - DestMF.cloneInfo<WebAssemblyFunctionInfo>(*this); - Clone->MF = &DestMF; - return Clone; + // TODO: Implement cloning for WasmEHFuncInfo. This will have invalid block + // references. + return DestMF.cloneInfo<WebAssemblyFunctionInfo>(*this); } void WebAssemblyFunctionInfo::initWARegs(MachineRegisterInfo &MRI) { @@ -122,11 +121,8 @@ llvm::signatureFromMVTs(const SmallVectorImpl<MVT> &Results, } yaml::WebAssemblyFunctionInfo::WebAssemblyFunctionInfo( - const llvm::WebAssemblyFunctionInfo &MFI) + const llvm::MachineFunction &MF, const llvm::WebAssemblyFunctionInfo &MFI) : CFGStackified(MFI.isCFGStackified()) { - auto *EHInfo = MFI.getWasmEHFuncInfo(); - const llvm::MachineFunction &MF = MFI.getMachineFunction(); - for (auto VT : MFI.getParams()) Params.push_back(EVT(VT).getEVTString()); for (auto VT : MFI.getResults()) @@ -134,7 +130,8 @@ yaml::WebAssemblyFunctionInfo::WebAssemblyFunctionInfo( // MFI.getWasmEHFuncInfo() is non-null only for functions with the // personality function. - if (EHInfo) { + + if (auto *EHInfo = MF.getWasmEHFuncInfo()) { // SrcToUnwindDest can contain stale mappings in case BBs are removed in // optimizations, in case, for example, they are unreachable. We should not // include their info. @@ -155,15 +152,19 @@ void yaml::WebAssemblyFunctionInfo::mappingImpl(yaml::IO &YamlIO) { } void WebAssemblyFunctionInfo::initializeBaseYamlFields( - const yaml::WebAssemblyFunctionInfo &YamlMFI) { + MachineFunction &MF, const yaml::WebAssemblyFunctionInfo &YamlMFI) { CFGStackified = YamlMFI.CFGStackified; for (auto VT : YamlMFI.Params) addParam(WebAssembly::parseMVT(VT.Value)); for (auto VT : YamlMFI.Results) addResult(WebAssembly::parseMVT(VT.Value)); - if (WasmEHInfo) { + + // FIXME: WasmEHInfo is defined in the MachineFunction, but serialized + // here. Either WasmEHInfo should be moved out of MachineFunction, or the + // serialization handling should be moved to MachineFunction. + if (WasmEHFuncInfo *WasmEHInfo = MF.getWasmEHFuncInfo()) { for (auto KV : YamlMFI.SrcToUnwindDest) - WasmEHInfo->setUnwindDest(MF->getBlockNumbered(KV.first), - MF->getBlockNumbered(KV.second)); + WasmEHInfo->setUnwindDest(MF.getBlockNumbered(KV.first), + MF.getBlockNumbered(KV.second)); } } diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h index 619617049bb2..7622164449a5 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h @@ -31,8 +31,6 @@ struct WebAssemblyFunctionInfo; /// This class is derived from MachineFunctionInfo and contains private /// WebAssembly-specific information for each MachineFunction. class WebAssemblyFunctionInfo final : public MachineFunctionInfo { - const MachineFunction *MF; - std::vector<MVT> Params; std::vector<MVT> Results; std::vector<MVT> Locals; @@ -66,12 +64,9 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo { // Function properties. bool CFGStackified = false; - // Catchpad unwind destination info for wasm EH. - WasmEHFuncInfo *WasmEHInfo = nullptr; - public: - explicit WebAssemblyFunctionInfo(MachineFunction &MF_) - : MF(&MF_), WasmEHInfo(MF_.getWasmEHFuncInfo()) {} + explicit WebAssemblyFunctionInfo(const Function &F, + const TargetSubtargetInfo *STI) {} ~WebAssemblyFunctionInfo() override; MachineFunctionInfo * @@ -79,9 +74,8 @@ public: const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) const override; - const MachineFunction &getMachineFunction() const { return *MF; } - - void initializeBaseYamlFields(const yaml::WebAssemblyFunctionInfo &YamlMFI); + void initializeBaseYamlFields(MachineFunction &MF, + const yaml::WebAssemblyFunctionInfo &YamlMFI); void addParam(MVT VT) { Params.push_back(VT); } const std::vector<MVT> &getParams() const { return Params; } @@ -166,9 +160,6 @@ public: bool isCFGStackified() const { return CFGStackified; } void setCFGStackified(bool Value = true) { CFGStackified = Value; } - - WasmEHFuncInfo *getWasmEHFuncInfo() const { return WasmEHInfo; } - void setWasmEHFuncInfo(WasmEHFuncInfo *Info) { WasmEHInfo = Info; } }; void computeLegalValueVTs(const WebAssemblyTargetLowering &TLI, @@ -205,7 +196,8 @@ struct WebAssemblyFunctionInfo final : public yaml::MachineFunctionInfo { BBNumberMap SrcToUnwindDest; WebAssemblyFunctionInfo() = default; - WebAssemblyFunctionInfo(const llvm::WebAssemblyFunctionInfo &MFI); + WebAssemblyFunctionInfo(const llvm::MachineFunction &MF, + const llvm::WebAssemblyFunctionInfo &MFI); void mappingImpl(yaml::IO &YamlIO) override; ~WebAssemblyFunctionInfo() = default; diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index f9ef45bfb41c..4b24f7fdb118 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -336,12 +336,17 @@ static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use, // instruction in which the current value is used, we cannot // stackify. Stackifying in this case would require that def moving below the // current def in the stack, which cannot be achieved, even with locals. + // Also ensure we don't sink the def past any other prior uses. for (const auto &SubsequentDef : drop_begin(DefI->defs())) { - for (const auto &PriorUse : UseI->uses()) { - if (&PriorUse == Use) - break; - if (PriorUse.isReg() && SubsequentDef.getReg() == PriorUse.getReg()) - return false; + auto I = std::next(MachineBasicBlock::const_iterator(DefI)); + auto E = std::next(MachineBasicBlock::const_iterator(UseI)); + for (; I != E; ++I) { + for (const auto &PriorUse : I->uses()) { + if (&PriorUse == Use) + break; + if (PriorUse.isReg() && SubsequentDef.getReg() == PriorUse.getReg()) + return false; + } } } @@ -370,7 +375,7 @@ static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use, !Insert->readsRegister(Reg)) continue; - if (Register::isPhysicalRegister(Reg)) { + if (Reg.isPhysical()) { // Ignore ARGUMENTS; it's just used to keep the ARGUMENT_* instructions // from moving down, and we've already checked for that. if (Reg == WebAssembly::ARGUMENTS) @@ -466,8 +471,7 @@ static bool oneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse, if (!MO.isReg()) return false; Register DefReg = MO.getReg(); - if (!Register::isVirtualRegister(DefReg) || - !MFI.isVRegStackified(DefReg)) + if (!DefReg.isVirtual() || !MFI.isVRegStackified(DefReg)) return false; assert(MRI.hasOneNonDBGUse(DefReg)); const MachineOperand &NewUse = *MRI.use_nodbg_begin(DefReg); @@ -842,7 +846,7 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { assert(Use.isUse() && "explicit_uses() should only iterate over uses"); assert(!Use.isImplicit() && "explicit_uses() should only iterate over explicit operands"); - if (Register::isPhysicalRegister(Reg)) + if (Reg.isPhysical()) continue; // Identify the definition for this register at this point. diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp index 6b6394a58339..4ca262e248f7 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp @@ -50,7 +50,7 @@ WebAssemblyRegisterInfo::getReservedRegs(const MachineFunction & /*MF*/) const { return Reserved; } -void WebAssemblyRegisterInfo::eliminateFrameIndex( +bool WebAssemblyRegisterInfo::eliminateFrameIndex( MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, RegScavenger * /*RS*/) const { assert(SPAdj == 0); @@ -82,7 +82,7 @@ void WebAssemblyRegisterInfo::eliminateFrameIndex( MI.getOperand(OffsetOperandNum).setImm(Offset); MI.getOperand(FIOperandNum) .ChangeToRegister(FrameRegister, /*isDef=*/false); - return; + return false; } } @@ -92,7 +92,7 @@ void WebAssemblyRegisterInfo::eliminateFrameIndex( MachineOperand &OtherMO = MI.getOperand(3 - FIOperandNum); if (OtherMO.isReg()) { Register OtherMOReg = OtherMO.getReg(); - if (Register::isVirtualRegister(OtherMOReg)) { + if (OtherMOReg.isVirtual()) { MachineInstr *Def = MF.getRegInfo().getUniqueVRegDef(OtherMOReg); // TODO: For now we just opportunistically do this in the case where // the CONST_I32/64 happens to have exactly one def and one use. We @@ -105,7 +105,7 @@ void WebAssemblyRegisterInfo::eliminateFrameIndex( ImmMO.setImm(ImmMO.getImm() + uint32_t(FrameOffset)); MI.getOperand(FIOperandNum) .ChangeToRegister(FrameRegister, /*isDef=*/false); - return; + return false; } } } @@ -133,6 +133,7 @@ void WebAssemblyRegisterInfo::eliminateFrameIndex( .addReg(OffsetOp); } MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*isDef=*/false); + return false; } Register diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.h index 7880eb217dbf..d875e4b93603 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.h @@ -34,7 +34,7 @@ public: // Code Generation virtual methods. const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override; BitVector getReservedRegs(const MachineFunction &MF) const override; - void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, + bool eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, unsigned FIOperandNum, RegScavenger *RS = nullptr) const override; diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp index 0b3e534315d5..4fe339ce5293 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp @@ -71,6 +71,7 @@ enum RuntimeLibcallSignature { i64_i64_func_i64_i64_i64_i64_iPTR, i64_i64_i64_i64_func_i64_i64_i64_i64, i64_i64_func_i64_i64_i32, + iPTR_func_i32, iPTR_func_iPTR_i32_iPTR, iPTR_func_iPTR_iPTR_iPTR, f32_func_f32_f32_f32, @@ -329,7 +330,7 @@ struct RuntimeLibcallSignatureTable { Table[RTLIB::STACKPROTECTOR_CHECK_FAIL] = func; // Return address handling - Table[RTLIB::RETURN_ADDRESS] = i32_func_i32; + Table[RTLIB::RETURN_ADDRESS] = iPTR_func_i32; // Element-wise Atomic memory // TODO: Fix these when we implement atomic support @@ -785,6 +786,10 @@ void llvm::getLibcallSignature(const WebAssemblySubtarget &Subtarget, Params.push_back(wasm::ValType::I64); Params.push_back(wasm::ValType::I32); break; + case iPTR_func_i32: + Rets.push_back(PtrTy); + Params.push_back(wasm::ValType::I32); + break; case iPTR_func_iPTR_i32_iPTR: Rets.push_back(PtrTy); Params.push_back(PtrTy); diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp index 89ae45722e42..a453e7388e27 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp @@ -62,7 +62,7 @@ static void rewriteP2Align(MachineInstr &MI, unsigned OperandNo) { assert((*MI.memoperands_begin())->getSize() == (UINT64_C(1) << WebAssembly::GetDefaultP2Align(MI.getOpcode())) && "Default p2align value should be natural"); - assert(MI.getDesc().OpInfo[OperandNo].OperandType == + assert(MI.getDesc().operands()[OperandNo].OperandType == WebAssembly::OPERAND_P2ALIGN && "Load and store instructions should have a p2align operand"); uint64_t P2Align = Log2((*MI.memoperands_begin())->getAlign()); diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 76f036358ae8..630c786a3dc7 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -32,6 +32,7 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/LowerAtomicPass.h" #include "llvm/Transforms/Utils.h" +#include <optional> using namespace llvm; #define DEBUG_TYPE "wasm" @@ -79,13 +80,16 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyTarget() { initializeWebAssemblyDebugFixupPass(PR); initializeWebAssemblyPeepholePass(PR); initializeWebAssemblyMCLowerPrePassPass(PR); + initializeWebAssemblyLowerRefTypesIntPtrConvPass(PR); + initializeWebAssemblyFixBrTableDefaultsPass(PR); + initializeWebAssemblyDAGToDAGISelPass(PR); } //===----------------------------------------------------------------------===// // WebAssembly Lowering public interface. //===----------------------------------------------------------------------===// -static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM, +static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM, const Triple &TT) { if (!RM) { // Default to static relocation model. This should always be more optimial @@ -108,8 +112,8 @@ static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM, /// WebAssemblyTargetMachine::WebAssemblyTargetMachine( const Target &T, const Triple &TT, StringRef CPU, StringRef FS, - const TargetOptions &Options, Optional<Reloc::Model> RM, - Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT) + const TargetOptions &Options, std::optional<Reloc::Model> RM, + std::optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT) : LLVMTargetMachine( T, TT.isArch64Bit() @@ -323,6 +327,7 @@ public: void addIRPasses() override; void addISelPrepare() override; bool addInstSelector() override; + void addOptimizedRegAlloc() override; void addPostRegAlloc() override; bool addGCPasses() override { return false; } void addPreEmitPass() override; @@ -336,6 +341,13 @@ public: }; } // end anonymous namespace +MachineFunctionInfo *WebAssemblyTargetMachine::createMachineFunctionInfo( + BumpPtrAllocator &Allocator, const Function &F, + const TargetSubtargetInfo *STI) const { + return WebAssemblyFunctionInfo::create<WebAssemblyFunctionInfo>(Allocator, F, + STI); +} + TargetTransformInfo WebAssemblyTargetMachine::getTargetTransformInfo(const Function &F) const { return TargetTransformInfo(WebAssemblyTTIImpl(this, F)); @@ -412,7 +424,7 @@ void WebAssemblyPassConfig::addIRPasses() { // Add signatures to prototype-less function declarations addPass(createWebAssemblyAddMissingPrototypes()); - // Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls. + // Lower .llvm.global_dtors into .llvm.global_ctors with __cxa_atexit calls. addPass(createLowerGlobalDtorsLegacyPass()); // Fix function bitcasts, as WebAssembly requires caller and callee signatures @@ -480,18 +492,31 @@ bool WebAssemblyPassConfig::addInstSelector() { return false; } +void WebAssemblyPassConfig::addOptimizedRegAlloc() { + // Currently RegisterCoalesce degrades wasm debug info quality by a + // significant margin. As a quick fix, disable this for -O1, which is often + // used for debugging large applications. Disabling this increases code size + // of Emscripten core benchmarks by ~5%, which is acceptable for -O1, which is + // usually not used for production builds. + // TODO Investigate why RegisterCoalesce degrades debug info quality and fix + // it properly + if (getOptLevel() == CodeGenOpt::Less) + disablePass(&RegisterCoalescerID); + TargetPassConfig::addOptimizedRegAlloc(); +} + void WebAssemblyPassConfig::addPostRegAlloc() { // TODO: The following CodeGen passes don't currently support code containing // virtual registers. Consider removing their restrictions and re-enabling // them. // These functions all require the NoVRegs property. + disablePass(&MachineLateInstrsCleanupID); disablePass(&MachineCopyPropagationID); disablePass(&PostRAMachineSinkingID); disablePass(&PostRASchedulerID); disablePass(&FuncletLayoutID); disablePass(&StackMapLivenessID); - disablePass(&LiveDebugValuesID); disablePass(&PatchableFunctionID); disablePass(&ShrinkWrapID); @@ -585,7 +610,7 @@ WebAssemblyTargetMachine::createDefaultFuncInfoYAML() const { yaml::MachineFunctionInfo *WebAssemblyTargetMachine::convertFuncInfoToYAML( const MachineFunction &MF) const { const auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>(); - return new yaml::WebAssemblyFunctionInfo(*MFI); + return new yaml::WebAssemblyFunctionInfo(MF, *MFI); } bool WebAssemblyTargetMachine::parseMachineFunctionInfo( @@ -593,6 +618,6 @@ bool WebAssemblyTargetMachine::parseMachineFunctionInfo( SMDiagnostic &Error, SMRange &SourceRange) const { const auto &YamlMFI = static_cast<const yaml::WebAssemblyFunctionInfo &>(MFI); MachineFunction &MF = PFS.MF; - MF.getInfo<WebAssemblyFunctionInfo>()->initializeBaseYamlFields(YamlMFI); + MF.getInfo<WebAssemblyFunctionInfo>()->initializeBaseYamlFields(MF, YamlMFI); return false; } diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h index 5d5378f76567..04bf2de81fe6 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h @@ -17,6 +17,7 @@ #include "WebAssemblySubtarget.h" #include "llvm/Target/TargetMachine.h" +#include <optional> namespace llvm { @@ -27,9 +28,9 @@ class WebAssemblyTargetMachine final : public LLVMTargetMachine { public: WebAssemblyTargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, - Optional<Reloc::Model> RM, - Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, - bool JIT); + std::optional<Reloc::Model> RM, + std::optional<CodeModel::Model> CM, + CodeGenOpt::Level OL, bool JIT); ~WebAssemblyTargetMachine() override; @@ -46,6 +47,10 @@ public: return TLOF.get(); } + MachineFunctionInfo * + createMachineFunctionInfo(BumpPtrAllocator &Allocator, const Function &F, + const TargetSubtargetInfo *STI) const override; + TargetTransformInfo getTargetTransformInfo(const Function &F) const override; bool usesPhysRegsForValues() const override { return false; } diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp index 62f7155e794a..9a434d9b1db5 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp @@ -52,14 +52,13 @@ TypeSize WebAssemblyTTIImpl::getRegisterBitWidth( InstructionCost WebAssemblyTTIImpl::getArithmeticInstrCost( unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, - TTI::OperandValueKind Opd1Info, TTI::OperandValueKind Opd2Info, - TTI::OperandValueProperties Opd1PropInfo, - TTI::OperandValueProperties Opd2PropInfo, ArrayRef<const Value *> Args, + TTI::OperandValueInfo Op1Info, TTI::OperandValueInfo Op2Info, + ArrayRef<const Value *> Args, const Instruction *CxtI) { InstructionCost Cost = BasicTTIImplBase<WebAssemblyTTIImpl>::getArithmeticInstrCost( - Opcode, Ty, CostKind, Opd1Info, Opd2Info, Opd1PropInfo, Opd2PropInfo); + Opcode, Ty, CostKind, Op1Info, Op2Info); if (auto *VTy = dyn_cast<VectorType>(Ty)) { switch (Opcode) { @@ -68,9 +67,8 @@ InstructionCost WebAssemblyTTIImpl::getArithmeticInstrCost( case Instruction::Shl: // SIMD128's shifts currently only accept a scalar shift count. For each // element, we'll need to extract, op, insert. The following is a rough - // approxmation. - if (Opd2Info != TTI::OK_UniformValue && - Opd2Info != TTI::OK_UniformConstantValue) + // approximation. + if (!Op2Info.isUniform()) Cost = cast<FixedVectorType>(VTy)->getNumElements() * (TargetTransformInfo::TCC_Basic + @@ -82,11 +80,12 @@ InstructionCost WebAssemblyTTIImpl::getArithmeticInstrCost( return Cost; } -InstructionCost WebAssemblyTTIImpl::getVectorInstrCost(unsigned Opcode, - Type *Val, - unsigned Index) { - InstructionCost Cost = - BasicTTIImplBase::getVectorInstrCost(Opcode, Val, Index); +InstructionCost +WebAssemblyTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val, + TTI::TargetCostKind CostKind, + unsigned Index, Value *Op0, Value *Op1) { + InstructionCost Cost = BasicTTIImplBase::getVectorInstrCost( + Opcode, Val, CostKind, Index, Op0, Op1); // SIMD128's insert/extract currently only take constant indices. if (Index == -1u) diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h index fde58a9587b6..a803fe5c1bbe 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h @@ -61,14 +61,14 @@ public: TypeSize getRegisterBitWidth(TargetTransformInfo::RegisterKind K) const; InstructionCost getArithmeticInstrCost( unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, - TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue, - TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue, - TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None, - TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None, + TTI::OperandValueInfo Op1Info = {TTI::OK_AnyValue, TTI::OP_None}, + TTI::OperandValueInfo Op2Info = {TTI::OK_AnyValue, TTI::OP_None}, ArrayRef<const Value *> Args = ArrayRef<const Value *>(), const Instruction *CxtI = nullptr); + using BaseT::getVectorInstrCost; InstructionCost getVectorInstrCost(unsigned Opcode, Type *Val, - unsigned Index); + TTI::TargetCostKind CostKind, + unsigned Index, Value *Op0, Value *Op1); /// @} |
