aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/WebAssembly
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-03 14:10:23 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-07-03 14:10:23 +0000
commit145449b1e420787bb99721a429341fa6be3adfb6 (patch)
tree1d56ae694a6de602e348dd80165cf881a36600ed /llvm/lib/Target/WebAssembly
parentecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff)
Diffstat (limited to 'llvm/lib/Target/WebAssembly')
-rw-r--r--llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp18
-rw-r--r--llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp95
-rw-r--r--llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h9
-rw-r--r--llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp2
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp2
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp1
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp6
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h5
-rw-r--r--llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h4
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssembly.h4
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssembly.td4
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp205
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h4
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp2
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp1
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyFixBrTableDefaults.cpp2
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp54
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp46
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h4
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td22
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td16
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td16
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td8
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td6
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td131
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp4
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp74
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp210
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyMCLowerPrePass.cpp3
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp14
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h13
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyNullifyDebugValueLists.cpp1
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp7
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp126
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp3
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.cpp2
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.h1
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h1
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp42
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h2
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp4
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h2
42 files changed, 525 insertions, 651 deletions
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 56689d3ee06b..7bafa53af2af 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -24,6 +24,7 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCSectionWasm.h"
@@ -374,7 +375,7 @@ public:
auto Type = WebAssembly::parseType(Lexer.getTok().getString());
if (!Type)
return error("unknown type: ", Lexer.getTok());
- Types.push_back(Type.getValue());
+ Types.push_back(*Type);
Parser.Lex();
if (!isNext(AsmToken::Comma))
break;
@@ -670,11 +671,12 @@ public:
} else {
// Assume this identifier is a label.
const MCExpr *Val;
+ SMLoc Start = Id.getLoc();
SMLoc End;
if (Parser.parseExpression(Val, End))
return error("Cannot parse symbol: ", Lexer.getTok());
Operands.push_back(std::make_unique<WebAssemblyOperand>(
- WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(),
+ WebAssemblyOperand::Symbol, Start, End,
WebAssemblyOperand::SymOp{Val}));
if (checkForP2AlignIfLoadStore(Operands, Name))
return true;
@@ -815,8 +817,7 @@ public:
// Now set this symbol with the correct type.
auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
- WasmSym->setGlobalType(
- wasm::WasmGlobalType{uint8_t(Type.getValue()), Mutable});
+ WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(*Type), Mutable});
// And emit the directive again.
TOut.emitGlobalType(WasmSym);
return expect(AsmToken::EndOfStatement, "EOL");
@@ -846,7 +847,7 @@ public:
// symbol
auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
- wasm::WasmTableType Type = {uint8_t(ElemType.getValue()), Limits};
+ wasm::WasmTableType Type = {uint8_t(*ElemType), Limits};
WasmSym->setTableType(Type);
TOut.emitTableType(WasmSym);
return expect(AsmToken::EndOfStatement, "EOL");
@@ -1016,7 +1017,7 @@ public:
Inst.setOpcode(Opc64);
}
}
- if (!SkipTypeCheck && TC.typeCheck(IDLoc, Inst))
+ if (!SkipTypeCheck && TC.typeCheck(IDLoc, Inst, Operands))
return true;
Out.emitInstruction(Inst, getSTI());
if (CurrentState == EndFunction) {
@@ -1094,14 +1095,15 @@ public:
auto *WS =
getContext().getWasmSection(SecName, SectionKind::getText(), 0, Group,
MCContext::GenericSectionID, nullptr);
- getStreamer().SwitchSection(WS);
+ getStreamer().switchSection(WS);
// Also generate DWARF for this section if requested.
if (getContext().getGenDwarfForAssembly())
getContext().addGenDwarfSection(WS);
}
void onEndOfFunction(SMLoc ErrorLoc) {
- TC.endOfFunction(ErrorLoc);
+ if (!SkipTypeCheck)
+ TC.endOfFunction(ErrorLoc);
// Reset the type checker state.
TC.Clear();
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
index 128ce5c4fec0..ec72c1de0503 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
@@ -86,14 +86,12 @@ bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc,
Optional<wasm::ValType> EVT) {
if (Stack.empty()) {
return typeError(ErrorLoc,
- EVT.hasValue()
- ? StringRef("empty stack while popping ") +
- WebAssembly::typeToString(EVT.getValue())
- : StringRef(
- "empty stack while popping value"));
+ EVT ? StringRef("empty stack while popping ") +
+ WebAssembly::typeToString(EVT.getValue())
+ : StringRef("empty stack while popping value"));
}
auto PVT = Stack.pop_back_val();
- if (EVT.hasValue() && EVT.getValue() != PVT) {
+ if (EVT && EVT.getValue() != PVT) {
return typeError(
ErrorLoc, StringRef("popped ") + WebAssembly::typeToString(PVT) +
", expected " +
@@ -102,6 +100,19 @@ bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc,
return false;
}
+bool WebAssemblyAsmTypeCheck::popRefType(SMLoc ErrorLoc) {
+ if (Stack.empty()) {
+ return typeError(ErrorLoc, StringRef("empty stack while popping reftype"));
+ }
+ auto PVT = Stack.pop_back_val();
+ if (!WebAssembly::isRefType(PVT)) {
+ return typeError(ErrorLoc, StringRef("popped ") +
+ WebAssembly::typeToString(PVT) +
+ ", expected reftype");
+ }
+ return false;
+}
+
bool WebAssemblyAsmTypeCheck::getLocal(SMLoc ErrorLoc, const MCInst &Inst,
wasm::ValType &Type) {
auto Local = static_cast<size_t>(Inst.getOperand(0).getImm());
@@ -160,7 +171,7 @@ bool WebAssemblyAsmTypeCheck::getGlobal(SMLoc ErrorLoc, const MCInst &Inst,
if (getSymRef(ErrorLoc, Inst, SymRef))
return true;
auto WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol());
- switch (WasmSym->getType().getValueOr(wasm::WASM_SYMBOL_TYPE_DATA)) {
+ switch (WasmSym->getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA)) {
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
Type = static_cast<wasm::ValType>(WasmSym->getGlobalType().Type);
break;
@@ -182,6 +193,20 @@ bool WebAssemblyAsmTypeCheck::getGlobal(SMLoc ErrorLoc, const MCInst &Inst,
return false;
}
+bool WebAssemblyAsmTypeCheck::getTable(SMLoc ErrorLoc, const MCInst &Inst,
+ wasm::ValType &Type) {
+ const MCSymbolRefExpr *SymRef;
+ if (getSymRef(ErrorLoc, Inst, SymRef))
+ return true;
+ auto WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol());
+ if (WasmSym->getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA) !=
+ wasm::WASM_SYMBOL_TYPE_TABLE)
+ return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +
+ " missing .tabletype");
+ Type = static_cast<wasm::ValType>(WasmSym->getTableType().ElemType);
+ return false;
+}
+
bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc) {
// Check the return types.
for (auto RVT : llvm::reverse(ReturnTypes)) {
@@ -196,35 +221,58 @@ bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc) {
return false;
}
-bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst) {
+bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst,
+ OperandVector &Operands) {
auto Opc = Inst.getOpcode();
auto Name = GetMnemonic(Opc);
dumpTypeStack("typechecking " + Name + ": ");
wasm::ValType Type;
if (Name == "local.get") {
- if (getLocal(ErrorLoc, Inst, Type))
+ if (getLocal(Operands[1]->getStartLoc(), Inst, Type))
return true;
Stack.push_back(Type);
} else if (Name == "local.set") {
- if (getLocal(ErrorLoc, Inst, Type))
+ if (getLocal(Operands[1]->getStartLoc(), Inst, Type))
return true;
if (popType(ErrorLoc, Type))
return true;
} else if (Name == "local.tee") {
- if (getLocal(ErrorLoc, Inst, Type))
+ if (getLocal(Operands[1]->getStartLoc(), Inst, Type))
return true;
if (popType(ErrorLoc, Type))
return true;
Stack.push_back(Type);
} else if (Name == "global.get") {
- if (getGlobal(ErrorLoc, Inst, Type))
+ if (getGlobal(Operands[1]->getStartLoc(), Inst, Type))
return true;
Stack.push_back(Type);
} else if (Name == "global.set") {
- if (getGlobal(ErrorLoc, Inst, Type))
+ if (getGlobal(Operands[1]->getStartLoc(), Inst, Type))
+ return true;
+ if (popType(ErrorLoc, Type))
+ return true;
+ } else if (Name == "table.get") {
+ if (getTable(Operands[1]->getStartLoc(), Inst, Type))
+ return true;
+ if (popType(ErrorLoc, wasm::ValType::I32))
+ return true;
+ Stack.push_back(Type);
+ } else if (Name == "table.set") {
+ if (getTable(Operands[1]->getStartLoc(), Inst, Type))
return true;
if (popType(ErrorLoc, Type))
return true;
+ if (popType(ErrorLoc, wasm::ValType::I32))
+ return true;
+ } else if (Name == "table.fill") {
+ if (getTable(Operands[1]->getStartLoc(), Inst, Type))
+ return true;
+ if (popType(ErrorLoc, wasm::ValType::I32))
+ return true;
+ if (popType(ErrorLoc, Type))
+ return true;
+ if (popType(ErrorLoc, wasm::ValType::I32))
+ return true;
} else if (Name == "drop") {
if (popType(ErrorLoc, {}))
return true;
@@ -245,33 +293,36 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst) {
return true;
} else if (Name == "call" || Name == "return_call") {
const MCSymbolRefExpr *SymRef;
- if (getSymRef(ErrorLoc, Inst, SymRef))
+ if (getSymRef(Operands[1]->getStartLoc(), Inst, SymRef))
return true;
auto WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol());
auto Sig = WasmSym->getSignature();
if (!Sig || WasmSym->getType() != wasm::WASM_SYMBOL_TYPE_FUNCTION)
- return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +
- " missing .functype");
+ return typeError(Operands[1]->getStartLoc(), StringRef("symbol ") +
+ WasmSym->getName() +
+ " missing .functype");
if (checkSig(ErrorLoc, *Sig)) return true;
if (Name == "return_call" && endOfFunction(ErrorLoc))
return true;
} else if (Name == "catch") {
const MCSymbolRefExpr *SymRef;
- if (getSymRef(ErrorLoc, Inst, SymRef))
+ if (getSymRef(Operands[1]->getStartLoc(), Inst, SymRef))
return true;
const auto *WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol());
const auto *Sig = WasmSym->getSignature();
if (!Sig || WasmSym->getType() != wasm::WASM_SYMBOL_TYPE_TAG)
- return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +
- " missing .tagtype");
+ return typeError(Operands[1]->getStartLoc(), StringRef("symbol ") +
+ WasmSym->getName() +
+ " missing .tagtype");
// catch instruction pushes values whose types are specified in the tag's
// "params" part
Stack.insert(Stack.end(), Sig->Params.begin(), Sig->Params.end());
- } else if (Name == "ref.null") {
- auto VT = static_cast<wasm::ValType>(Inst.getOperand(0).getImm());
- Stack.push_back(VT);
} else if (Name == "unreachable") {
Unreachable = true;
+ } else if (Name == "ref.is_null") {
+ if (popRefType(ErrorLoc))
+ return true;
+ Stack.push_back(wasm::ValType::I32);
} else {
// The current instruction is a stack instruction which doesn't have
// explicit operands that indicate push/pop types, so we get those from
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
index 2b07faf67a18..3be966b5739c 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
@@ -16,9 +16,10 @@
#ifndef LLVM_LIB_TARGET_WEBASSEMBLY_ASMPARSER_TYPECHECK_H
#define LLVM_LIB_TARGET_WEBASSEMBLY_ASMPARSER_TYPECHECK_H
-#include "llvm/MC/MCParser/MCAsmParser.h"
-#include "llvm/MC/MCInstrInfo.h"
#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCSymbol.h"
namespace llvm {
@@ -38,12 +39,14 @@ class WebAssemblyAsmTypeCheck final {
void dumpTypeStack(Twine Msg);
bool typeError(SMLoc ErrorLoc, const Twine &Msg);
bool popType(SMLoc ErrorLoc, 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);
bool checkSig(SMLoc ErrorLoc, const wasm::WasmSignature &Sig);
bool getSymRef(SMLoc ErrorLoc, const MCInst &Inst,
const MCSymbolRefExpr *&SymRef);
bool getGlobal(SMLoc ErrorLoc, const MCInst &Inst, wasm::ValType &Type);
+ bool getTable(SMLoc ErrorLoc, const MCInst &Inst, wasm::ValType &Type);
public:
WebAssemblyAsmTypeCheck(MCAsmParser &Parser, const MCInstrInfo &MII, bool is64);
@@ -52,7 +55,7 @@ public:
void localDecl(const SmallVector<wasm::ValType, 4> &Locals);
void setLastSig(const wasm::WasmSignature &Sig) { LastSig = Sig; }
bool endOfFunction(SMLoc ErrorLoc);
- bool typeCheck(SMLoc ErrorLoc, const MCInst &Inst);
+ bool typeCheck(SMLoc ErrorLoc, const MCInst &Inst, OperandVector &Operands);
void Clear() {
Stack.clear();
diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index 5d38145559da..ae65a9dc2a4e 100644
--- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -17,8 +17,8 @@
#include "TargetInfo/WebAssemblyTargetInfo.h"
#include "Utils/WebAssemblyTypeUtilities.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDecoderOps.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
-#include "llvm/MC/MCFixedLenDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp
index d8122950e061..5727708a84ad 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp
@@ -52,6 +52,4 @@ WebAssemblyMCAsmInfo::WebAssemblyMCAsmInfo(const Triple &T,
// we make sure this info is set correctly.
if (WebAssembly::WasmEnableEH || WebAssembly::WasmEnableSjLj)
ExceptionsType = ExceptionHandling::Wasm;
-
- // TODO: UseIntegratedAssembler?
}
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp
index 8f670ec88897..f52545a65dbb 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp
@@ -62,7 +62,6 @@ static MCInstPrinter *createMCInstPrinter(const Triple & /*T*/,
}
static MCCodeEmitter *createCodeEmitter(const MCInstrInfo &MCII,
- const MCRegisterInfo & /*MRI*/,
MCContext &Ctx) {
return createWebAssemblyMCCodeEmitter(MCII);
}
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
index 397b9b0ee9da..2da219d54c73 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
@@ -58,8 +58,6 @@ void WebAssemblyTargetAsmStreamer::emitLocal(ArrayRef<wasm::ValType> Types) {
}
}
-void WebAssemblyTargetAsmStreamer::emitEndFunc() { OS << "\t.endfunc\n"; }
-
void WebAssemblyTargetAsmStreamer::emitFunctionType(const MCSymbolWasm *Sym) {
assert(Sym->isFunction());
OS << "\t.functype\t" << Sym->getName() << " ";
@@ -136,10 +134,6 @@ void WebAssemblyTargetWasmStreamer::emitLocal(ArrayRef<wasm::ValType> Types) {
}
}
-void WebAssemblyTargetWasmStreamer::emitEndFunc() {
- llvm_unreachable(".end_func is not needed for direct wasm output");
-}
-
void WebAssemblyTargetWasmStreamer::emitIndIdx(const MCExpr *Value) {
llvm_unreachable(".indidx encoding not yet implemented");
}
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
index c0ad63c8dd50..522f6356c28b 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
@@ -32,8 +32,6 @@ public:
/// .local
virtual void emitLocal(ArrayRef<wasm::ValType> Types) = 0;
- /// .endfunc
- virtual void emitEndFunc() = 0;
/// .functype
virtual void emitFunctionType(const MCSymbolWasm *Sym) = 0;
/// .indidx
@@ -66,7 +64,6 @@ public:
WebAssemblyTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
void emitLocal(ArrayRef<wasm::ValType> Types) override;
- void emitEndFunc() override;
void emitFunctionType(const MCSymbolWasm *Sym) override;
void emitIndIdx(const MCExpr *Value) override;
void emitGlobalType(const MCSymbolWasm *Sym) override;
@@ -83,7 +80,6 @@ public:
explicit WebAssemblyTargetWasmStreamer(MCStreamer &S);
void emitLocal(ArrayRef<wasm::ValType> Types) override;
- void emitEndFunc() override;
void emitFunctionType(const MCSymbolWasm *Sym) override {}
void emitIndIdx(const MCExpr *Value) override;
void emitGlobalType(const MCSymbolWasm *Sym) override {}
@@ -104,7 +100,6 @@ public:
: WebAssemblyTargetStreamer(S) {}
void emitLocal(ArrayRef<wasm::ValType>) override {}
- void emitEndFunc() override {}
void emitFunctionType(const MCSymbolWasm *) override {}
void emitIndIdx(const MCExpr *) override {}
void emitGlobalType(const MCSymbolWasm *) override {}
diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
index cdb95d48398d..8fc67d37925c 100644
--- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
+++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
@@ -80,6 +80,10 @@ inline bool isRefType(const Type *Ty) {
return isFuncrefType(Ty) || isExternrefType(Ty);
}
+inline bool isRefType(wasm::ValType Type) {
+ return Type == wasm::ValType::EXTERNREF || Type == wasm::ValType::FUNCREF;
+}
+
// Convert StringRef to ValType / HealType / BlockType
Optional<wasm::ValType> parseType(StringRef Type);
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h
index 803786e0c9c2..aee8f160f38d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -26,7 +26,6 @@ class FunctionPass;
// LLVM IR passes.
ModulePass *createWebAssemblyLowerEmscriptenEHSjLj();
-ModulePass *createWebAssemblyLowerGlobalDtors();
ModulePass *createWebAssemblyAddMissingPrototypes();
ModulePass *createWebAssemblyFixFunctionBitcasts();
FunctionPass *createWebAssemblyOptimizeReturned();
@@ -41,7 +40,6 @@ FunctionPass *createWebAssemblySetP2AlignOperands();
// Late passes.
FunctionPass *createWebAssemblyReplacePhysRegs();
FunctionPass *createWebAssemblyNullifyDebugValueLists();
-FunctionPass *createWebAssemblyPrepareForLiveIntervals();
FunctionPass *createWebAssemblyOptimizeLiveIntervals();
FunctionPass *createWebAssemblyMemIntrinsicResults();
FunctionPass *createWebAssemblyRegStackify();
@@ -61,14 +59,12 @@ ModulePass *createWebAssemblyMCLowerPrePass();
// PassRegistry initialization declarations.
void initializeWebAssemblyAddMissingPrototypesPass(PassRegistry &);
void initializeWebAssemblyLowerEmscriptenEHSjLjPass(PassRegistry &);
-void initializeLowerGlobalDtorsPass(PassRegistry &);
void initializeFixFunctionBitcastsPass(PassRegistry &);
void initializeOptimizeReturnedPass(PassRegistry &);
void initializeWebAssemblyArgumentMovePass(PassRegistry &);
void initializeWebAssemblySetP2AlignOperandsPass(PassRegistry &);
void initializeWebAssemblyReplacePhysRegsPass(PassRegistry &);
void initializeWebAssemblyNullifyDebugValueListsPass(PassRegistry &);
-void initializeWebAssemblyPrepareForLiveIntervalsPass(PassRegistry &);
void initializeWebAssemblyOptimizeLiveIntervalsPass(PassRegistry &);
void initializeWebAssemblyMemIntrinsicResultsPass(PassRegistry &);
void initializeWebAssemblyRegStackifyPass(PassRegistry &);
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td
index a529c6217189..b83dcf3a8e65 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.td
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.td
@@ -67,6 +67,10 @@ def FeatureReferenceTypes :
SubtargetFeature<"reference-types", "HasReferenceTypes", "true",
"Enable reference types">;
+def FeatureExtendedConst :
+ SubtargetFeature<"extended-const", "HasExtendedConst", "true",
+ "Enable extended const expressions">;
+
//===----------------------------------------------------------------------===//
// Architectures.
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index bf326e5106be..57d51634e849 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -180,30 +180,30 @@ void WebAssemblyAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
MCSymbolWasm *Sym = cast<MCSymbolWasm>(getSymbol(GV));
if (!Sym->getType()) {
- const WebAssemblyTargetLowering &TLI = *Subtarget->getTargetLowering();
SmallVector<MVT, 1> VTs;
Type *GlobalVT = GV->getValueType();
- computeLegalValueVTs(TLI, GV->getParent()->getContext(),
- GV->getParent()->getDataLayout(), GlobalVT, VTs);
+ if (Subtarget) {
+ // Subtarget is only set when a function is defined, because
+ // each function can declare a different subtarget. For example,
+ // on ARM a compilation unit might have a function on ARM and
+ // another on Thumb. Therefore only if Subtarget is non-null we
+ // can actually calculate the legal VTs.
+ const WebAssemblyTargetLowering &TLI = *Subtarget->getTargetLowering();
+ computeLegalValueVTs(TLI, GV->getParent()->getContext(),
+ GV->getParent()->getDataLayout(), GlobalVT, VTs);
+ }
WebAssembly::wasmSymbolSetType(Sym, GlobalVT, VTs);
}
- // If the GlobalVariable refers to a table, we handle it here instead of
- // in emitExternalDecls
- if (Sym->isTable()) {
- getTargetStreamer()->emitTableType(Sym);
- return;
- }
-
emitVisibility(Sym, GV->getVisibility(), !GV->isDeclaration());
+ emitSymbolType(Sym);
if (GV->hasInitializer()) {
assert(getSymbolPreferLocal(*GV) == Sym);
emitLinkage(GV, Sym);
- getTargetStreamer()->emitGlobalType(Sym);
OutStreamer->emitLabel(Sym);
// TODO: Actually emit the initializer value. Otherwise the global has the
// default value for its type (0, ref.null, etc).
- OutStreamer->AddBlankLine();
+ OutStreamer->addBlankLine();
}
}
@@ -211,7 +211,7 @@ MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) {
auto *WasmSym = cast<MCSymbolWasm>(GetExternalSymbolSymbol(Name));
// May be called multiple times, so early out.
- if (WasmSym->getType().hasValue())
+ if (WasmSym->getType())
return WasmSym;
const WebAssemblySubtarget &Subtarget = getSubtarget();
@@ -271,31 +271,52 @@ MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) {
return WasmSym;
}
-void WebAssemblyAsmPrinter::emitExternalDecls(const Module &M) {
+void WebAssemblyAsmPrinter::emitSymbolType(const MCSymbolWasm *Sym) {
+ Optional<wasm::WasmSymbolType> WasmTy = Sym->getType();
+ if (!WasmTy)
+ return;
+
+ switch (*WasmTy) {
+ case wasm::WASM_SYMBOL_TYPE_GLOBAL:
+ getTargetStreamer()->emitGlobalType(Sym);
+ break;
+ case wasm::WASM_SYMBOL_TYPE_TAG:
+ getTargetStreamer()->emitTagType(Sym);
+ break;
+ case wasm::WASM_SYMBOL_TYPE_TABLE:
+ getTargetStreamer()->emitTableType(Sym);
+ break;
+ default:
+ break; // We only handle globals, tags and tables here
+ }
+}
+
+void WebAssemblyAsmPrinter::emitDecls(const Module &M) {
if (signaturesEmitted)
return;
signaturesEmitted = true;
// Normally symbols for globals get discovered as the MI gets lowered,
- // but we need to know about them ahead of time.
+ // but we need to know about them ahead of time. This will however,
+ // only find symbols that have been used. Unused symbols from globals will
+ // not be found here.
MachineModuleInfoWasm &MMIW = MMI->getObjFileInfo<MachineModuleInfoWasm>();
for (const auto &Name : MMIW.MachineSymbolsUsed) {
- getOrCreateWasmSymbol(Name.getKey());
+ auto *WasmSym = cast<MCSymbolWasm>(getOrCreateWasmSymbol(Name.getKey()));
+ if (WasmSym->isFunction()) {
+ // TODO(wvo): is there any case where this overlaps with the call to
+ // emitFunctionType in the loop below?
+ getTargetStreamer()->emitFunctionType(WasmSym);
+ }
}
for (auto &It : OutContext.getSymbols()) {
- // Emit .globaltype, .tagtype, or .tabletype declarations.
+ // Emit .globaltype, .tagtype, or .tabletype declarations for extern
+ // declarations, i.e. those that have only been declared (but not defined)
+ // in the current module
auto Sym = cast<MCSymbolWasm>(It.getValue());
- if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL) {
- // .globaltype already handled by emitGlobalVariable for defined
- // variables; here we make sure the types of external wasm globals get
- // written to the file.
- if (Sym->isUndefined())
- getTargetStreamer()->emitGlobalType(Sym);
- } else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_TAG)
- getTargetStreamer()->emitTagType(Sym);
- else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_TABLE)
- getTargetStreamer()->emitTableType(Sym);
+ if (!Sym->isDefined())
+ emitSymbolType(Sym);
}
DenseSet<MCSymbol *> InvokeSymbols;
@@ -303,55 +324,56 @@ void WebAssemblyAsmPrinter::emitExternalDecls(const Module &M) {
if (F.isIntrinsic())
continue;
- // Emit function type info for all undefined functions
- if (F.isDeclarationForLinker()) {
- SmallVector<MVT, 4> Results;
- SmallVector<MVT, 4> Params;
- computeSignatureVTs(F.getFunctionType(), &F, F, TM, Params, Results);
- // At this point these MCSymbols may or may not have been created already
- // and thus also contain a signature, but we need to get the signature
- // anyway here in case it is an invoke that has not yet been created. We
- // will discard it later if it turns out not to be necessary.
- auto Signature = signatureFromMVTs(Results, Params);
- bool InvokeDetected = false;
- auto *Sym = getMCSymbolForFunction(
- &F, WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj,
- Signature.get(), InvokeDetected);
+ // Emit function type info for all functions. This will emit duplicate
+ // information for defined functions (which already have function type
+ // info emitted alongside their definition), but this is necessary in
+ // order to enable the single-pass WebAssemblyAsmTypeCheck to succeed.
+ SmallVector<MVT, 4> Results;
+ SmallVector<MVT, 4> Params;
+ computeSignatureVTs(F.getFunctionType(), &F, F, TM, Params, Results);
+ // At this point these MCSymbols may or may not have been created already
+ // and thus also contain a signature, but we need to get the signature
+ // anyway here in case it is an invoke that has not yet been created. We
+ // will discard it later if it turns out not to be necessary.
+ auto Signature = signatureFromMVTs(Results, Params);
+ bool InvokeDetected = false;
+ auto *Sym = getMCSymbolForFunction(
+ &F, WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj,
+ Signature.get(), InvokeDetected);
- // Multiple functions can be mapped to the same invoke symbol. For
- // example, two IR functions '__invoke_void_i8*' and '__invoke_void_i32'
- // are both mapped to '__invoke_vi'. We keep them in a set once we emit an
- // Emscripten EH symbol so we don't emit the same symbol twice.
- if (InvokeDetected && !InvokeSymbols.insert(Sym).second)
- continue;
+ // Multiple functions can be mapped to the same invoke symbol. For
+ // example, two IR functions '__invoke_void_i8*' and '__invoke_void_i32'
+ // are both mapped to '__invoke_vi'. We keep them in a set once we emit an
+ // Emscripten EH symbol so we don't emit the same symbol twice.
+ if (InvokeDetected && !InvokeSymbols.insert(Sym).second)
+ continue;
- Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
- if (!Sym->getSignature()) {
- Sym->setSignature(Signature.get());
- addSignature(std::move(Signature));
- } else {
- // This symbol has already been created and had a signature. Discard it.
- Signature.reset();
- }
+ Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
+ if (!Sym->getSignature()) {
+ Sym->setSignature(Signature.get());
+ addSignature(std::move(Signature));
+ } else {
+ // This symbol has already been created and had a signature. Discard it.
+ Signature.reset();
+ }
- getTargetStreamer()->emitFunctionType(Sym);
+ getTargetStreamer()->emitFunctionType(Sym);
- if (F.hasFnAttribute("wasm-import-module")) {
- StringRef Name =
- F.getFnAttribute("wasm-import-module").getValueAsString();
- Sym->setImportModule(storeName(Name));
- getTargetStreamer()->emitImportModule(Sym, Name);
- }
- if (F.hasFnAttribute("wasm-import-name")) {
- // If this is a converted Emscripten EH/SjLj symbol, we shouldn't use
- // the original function name but the converted symbol name.
- StringRef Name =
- InvokeDetected
- ? Sym->getName()
- : F.getFnAttribute("wasm-import-name").getValueAsString();
- Sym->setImportName(storeName(Name));
- getTargetStreamer()->emitImportName(Sym, Name);
- }
+ if (F.hasFnAttribute("wasm-import-module")) {
+ StringRef Name =
+ F.getFnAttribute("wasm-import-module").getValueAsString();
+ Sym->setImportModule(storeName(Name));
+ getTargetStreamer()->emitImportModule(Sym, Name);
+ }
+ if (F.hasFnAttribute("wasm-import-name")) {
+ // If this is a converted Emscripten EH/SjLj symbol, we shouldn't use
+ // the original function name but the converted symbol name.
+ StringRef Name =
+ InvokeDetected
+ ? Sym->getName()
+ : F.getFnAttribute("wasm-import-name").getValueAsString();
+ Sym->setImportName(storeName(Name));
+ getTargetStreamer()->emitImportName(Sym, Name);
}
if (F.hasFnAttribute("wasm-export-name")) {
@@ -362,9 +384,12 @@ void WebAssemblyAsmPrinter::emitExternalDecls(const Module &M) {
}
}
}
-
+
void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {
- emitExternalDecls(M);
+ // This is required to emit external declarations (like .functypes) when
+ // no functions are defined in the compilation unit and therefore,
+ // emitDecls() is not called until now.
+ emitDecls(M);
// When a function's address is taken, a TABLE_INDEX relocation is emitted
// against the function symbol at the use site. However the relocation
@@ -401,13 +426,13 @@ void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {
if (!Name || !Contents)
continue;
- OutStreamer->PushSection();
+ OutStreamer->pushSection();
std::string SectionName = (".custom_section." + Name->getString()).str();
MCSectionWasm *MySection =
OutContext.getWasmSection(SectionName, SectionKind::getMetadata());
- OutStreamer->SwitchSection(MySection);
+ OutStreamer->switchSection(MySection);
OutStreamer->emitBytes(Contents->getString());
- OutStreamer->PopSection();
+ OutStreamer->popSection();
}
}
@@ -445,8 +470,8 @@ void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {
if (FieldCount != 0) {
MCSectionWasm *Producers = OutContext.getWasmSection(
".custom_section.producers", SectionKind::getMetadata());
- OutStreamer->PushSection();
- OutStreamer->SwitchSection(Producers);
+ OutStreamer->pushSection();
+ OutStreamer->switchSection(Producers);
OutStreamer->emitULEB128IntValue(FieldCount);
for (auto &Producers : {std::make_pair("language", &Languages),
std::make_pair("processed-by", &Tools)}) {
@@ -462,7 +487,7 @@ void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {
OutStreamer->emitBytes(Producer.second);
}
}
- OutStreamer->PopSection();
+ OutStreamer->popSection();
}
}
@@ -518,8 +543,8 @@ void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) {
// Emit features and linkage policies into the "target_features" section
MCSectionWasm *FeaturesSection = OutContext.getWasmSection(
".custom_section.target_features", SectionKind::getMetadata());
- OutStreamer->PushSection();
- OutStreamer->SwitchSection(FeaturesSection);
+ OutStreamer->pushSection();
+ OutStreamer->switchSection(FeaturesSection);
OutStreamer->emitULEB128IntValue(EmittedFeatures.size());
for (auto &F : EmittedFeatures) {
@@ -528,10 +553,11 @@ void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) {
OutStreamer->emitBytes(F.Name);
}
- OutStreamer->PopSection();
+ OutStreamer->popSection();
}
void WebAssemblyAsmPrinter::emitConstantPool() {
+ emitDecls(*MMI->getModule());
assert(MF->getConstantPool()->getConstants().empty() &&
"WebAssembly disables constant pools");
}
@@ -540,17 +566,6 @@ void WebAssemblyAsmPrinter::emitJumpTableInfo() {
// Nothing to do; jump tables are incorporated into the instruction stream.
}
-void WebAssemblyAsmPrinter::emitLinkage(const GlobalValue *GV, MCSymbol *Sym)
- const {
- AsmPrinter::emitLinkage(GV, Sym);
- // This gets called before the function label and type are emitted.
- // We use it to emit signatures of external functions.
- // FIXME casts!
- const_cast<WebAssemblyAsmPrinter *>(this)
- ->emitExternalDecls(*MMI->getModule());
-}
-
-
void WebAssemblyAsmPrinter::emitFunctionBodyStart() {
const Function &F = MF->getFunction();
SmallVector<MVT, 1> ResultVTs;
@@ -612,7 +627,7 @@ void WebAssemblyAsmPrinter::emitInstruction(const MachineInstr *MI) {
// function body.
if (isVerbose()) {
OutStreamer->AddComment("fallthrough-return");
- OutStreamer->AddBlankLine();
+ OutStreamer->addBlankLine();
}
break;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
index 6b2f2000a0bd..65d6ee415180 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
@@ -66,10 +66,10 @@ public:
void emitEndOfAsmFile(Module &M) override;
void EmitProducerInfo(Module &M);
void EmitTargetFeatures(Module &M);
+ void emitSymbolType(const MCSymbolWasm *Sym);
void emitGlobalVariable(const GlobalVariable *GV) override;
void emitJumpTableInfo() override;
void emitConstantPool() override;
- void emitLinkage(const GlobalValue *, MCSymbol *) const override;
void emitFunctionBodyStart() override;
void emitInstruction(const MachineInstr *MI) override;
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
@@ -84,7 +84,7 @@ public:
wasm::WasmSignature *Sig,
bool &InvokeDetected);
MCSymbol *getOrCreateWasmSymbol(StringRef Name);
- void emitExternalDecls(const Module &M);
+ void emitDecls(const Module &M);
};
} // end namespace llvm
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index 17e867e4c7d8..02e873a0f9a6 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
@@ -1716,7 +1716,7 @@ void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
// Rewrite MBB operands to be depth immediates.
SmallVector<MachineOperand, 4> Ops(MI.operands());
while (MI.getNumOperands() > 0)
- MI.RemoveOperand(MI.getNumOperands() - 1);
+ MI.removeOperand(MI.getNumOperands() - 1);
for (auto MO : Ops) {
if (MO.isMBB()) {
if (MI.getOpcode() == WebAssembly::DELEGATE)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp
index b94981245f8b..81fe5395a6de 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp
@@ -14,6 +14,7 @@
#include "WebAssemblyExceptionInfo.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "Utils/WebAssemblyUtilities.h"
+#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/CodeGen/MachineDominanceFrontier.h"
#include "llvm/CodeGen/MachineDominators.h"
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixBrTableDefaults.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixBrTableDefaults.cpp
index 5bdec89f1125..fa5b4a508fa5 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFixBrTableDefaults.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixBrTableDefaults.cpp
@@ -130,7 +130,7 @@ MachineBasicBlock *fixBrTableDefault(MachineInstr &MI, MachineBasicBlock *MBB,
return nullptr;
// Remove the dummy default target and install the real one.
- MI.RemoveOperand(MI.getNumExplicitOperands() - 1);
+ MI.removeOperand(MI.getNumExplicitOperands() - 1);
MI.addOperand(MF, MachineOperand::CreateMBB(TBB));
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp
index 1ceae59dc993..83e71d731bfa 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp
@@ -55,6 +55,7 @@
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "WebAssembly.h"
#include "WebAssemblySubtarget.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
@@ -221,10 +222,8 @@ private:
assert(!Enterers.count(MBB));
if (Blocks.insert(MBB).second) {
for (auto *Pred : MBB->predecessors()) {
- if (!AddedToWorkList.count(Pred)) {
+ if (AddedToWorkList.insert(Pred).second)
WorkList.push_back(Pred);
- AddedToWorkList.insert(Pred);
- }
}
}
}
@@ -491,6 +490,46 @@ FunctionPass *llvm::createWebAssemblyFixIrreducibleControlFlow() {
return new WebAssemblyFixIrreducibleControlFlow();
}
+// Test whether the given register has an ARGUMENT def.
+static bool hasArgumentDef(unsigned Reg, const MachineRegisterInfo &MRI) {
+ for (const auto &Def : MRI.def_instructions(Reg))
+ if (WebAssembly::isArgument(Def.getOpcode()))
+ return true;
+ return false;
+}
+
+// Add a register definition with IMPLICIT_DEFs for every register to cover for
+// register uses that don't have defs in every possible path.
+// TODO: This is fairly heavy-handed; find a better approach.
+static void addImplicitDefs(MachineFunction &MF) {
+ const MachineRegisterInfo &MRI = MF.getRegInfo();
+ const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
+ MachineBasicBlock &Entry = *MF.begin();
+ for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) {
+ Register Reg = Register::index2VirtReg(I);
+
+ // Skip unused registers.
+ if (MRI.use_nodbg_empty(Reg))
+ continue;
+
+ // Skip registers that have an ARGUMENT definition.
+ if (hasArgumentDef(Reg, MRI))
+ continue;
+
+ BuildMI(Entry, Entry.begin(), DebugLoc(),
+ TII.get(WebAssembly::IMPLICIT_DEF), Reg);
+ }
+
+ // Move ARGUMENT_* instructions to the top of the entry block, so that their
+ // liveness reflects the fact that these really are live-in values.
+ for (MachineInstr &MI : llvm::make_early_inc_range(Entry)) {
+ if (WebAssembly::isArgument(MI.getOpcode())) {
+ MI.removeFromParent();
+ Entry.insert(Entry.begin(), &MI);
+ }
+ }
+}
+
bool WebAssemblyFixIrreducibleControlFlow::runOnMachineFunction(
MachineFunction &MF) {
LLVM_DEBUG(dbgs() << "********** Fixing Irreducible Control Flow **********\n"
@@ -505,8 +544,15 @@ bool WebAssemblyFixIrreducibleControlFlow::runOnMachineFunction(
if (LLVM_UNLIKELY(processRegion(&*MF.begin(), AllBlocks, MF))) {
// We rewrote part of the function; recompute relevant things.
- MF.getRegInfo().invalidateLiveness();
MF.RenumberBlocks();
+ // Now we've inserted dispatch blocks, some register uses can have incoming
+ // paths without a def. For example, before this pass register %a was
+ // defined in BB1 and used in BB2, and there was only one path from BB1 and
+ // BB2. But if this pass inserts a dispatch block having multiple
+ // predecessors between the two BBs, now there are paths to BB2 without
+ // visiting BB1, and %a's use in BB2 is not dominated by its def. Adding
+ // IMPLICIT_DEFs to all regs is one simple way to fix it.
+ addImplicitDefs(MF);
return true;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index a221f37cfd94..2636acaf1604 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -19,6 +19,8 @@
#include "WebAssemblySubtarget.h"
#include "WebAssemblyTargetMachine.h"
#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
@@ -159,22 +161,17 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
setTargetDAGCombine(ISD::VECTOR_SHUFFLE);
// Combine extends of extract_subvectors into widening ops
- setTargetDAGCombine(ISD::SIGN_EXTEND);
- setTargetDAGCombine(ISD::ZERO_EXTEND);
+ setTargetDAGCombine({ISD::SIGN_EXTEND, ISD::ZERO_EXTEND});
// Combine int_to_fp or fp_extend of extract_vectors and vice versa into
// conversions ops
- setTargetDAGCombine(ISD::SINT_TO_FP);
- setTargetDAGCombine(ISD::UINT_TO_FP);
- setTargetDAGCombine(ISD::FP_EXTEND);
- setTargetDAGCombine(ISD::EXTRACT_SUBVECTOR);
+ setTargetDAGCombine({ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_EXTEND,
+ ISD::EXTRACT_SUBVECTOR});
// Combine fp_to_{s,u}int_sat or fp_round of concat_vectors or vice versa
// into conversion ops
- setTargetDAGCombine(ISD::FP_TO_SINT_SAT);
- setTargetDAGCombine(ISD::FP_TO_UINT_SAT);
- setTargetDAGCombine(ISD::FP_ROUND);
- setTargetDAGCombine(ISD::CONCAT_VECTORS);
+ setTargetDAGCombine({ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT,
+ ISD::FP_ROUND, ISD::CONCAT_VECTORS});
setTargetDAGCombine(ISD::TRUNCATE);
@@ -577,7 +574,7 @@ LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
// Move the function pointer to the end of the arguments for indirect calls
if (IsIndirect) {
auto FnPtr = CallParams.getOperand(0);
- CallParams.RemoveOperand(0);
+ CallParams.removeOperand(0);
// For funcrefs, call_indirect is done through __funcref_call_table and the
// funcref is always installed in slot 0 of the table, therefore instead of having
@@ -909,6 +906,30 @@ WebAssemblyTargetLowering::getPreferredVectorAction(MVT VT) const {
return TargetLoweringBase::getPreferredVectorAction(VT);
}
+bool WebAssemblyTargetLowering::shouldSimplifyDemandedVectorElts(
+ SDValue Op, const TargetLoweringOpt &TLO) const {
+ // ISel process runs DAGCombiner after legalization; this step is called
+ // SelectionDAG optimization phase. This post-legalization combining process
+ // runs DAGCombiner on each node, and if there was a change to be made,
+ // re-runs legalization again on it and its user nodes to make sure
+ // everythiing is in a legalized state.
+ //
+ // The legalization calls lowering routines, and we do our custom lowering for
+ // build_vectors (LowerBUILD_VECTOR), which converts undef vector elements
+ // into zeros. But there is a set of routines in DAGCombiner that turns unused
+ // (= not demanded) nodes into undef, among which SimplifyDemandedVectorElts
+ // turns unused vector elements into undefs. But this routine does not work
+ // with our custom LowerBUILD_VECTOR, which turns undefs into zeros. This
+ // combination can result in a infinite loop, in which undefs are converted to
+ // zeros in legalization and back to undefs in combining.
+ //
+ // So after DAG is legalized, we prevent SimplifyDemandedVectorElts from
+ // running for build_vectors.
+ if (Op.getOpcode() == ISD::BUILD_VECTOR && TLO.LegalOps && TLO.LegalTys)
+ return false;
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// WebAssembly Lowering private implementation.
//===----------------------------------------------------------------------===//
@@ -2110,8 +2131,7 @@ SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op,
auto GetMostCommon = [](auto &Counts) {
auto CommonIt =
- std::max_element(Counts.begin(), Counts.end(),
- [](auto A, auto B) { return A.second < B.second; });
+ std::max_element(Counts.begin(), Counts.end(), llvm::less_second());
assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector");
return *CommonIt;
};
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
index f7b460f61dbb..d86f2e59e3d2 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
@@ -113,6 +113,10 @@ private:
report_fatal_error("llvm.clear_cache is not supported on wasm");
}
+ bool
+ shouldSimplifyDemandedVectorElts(SDValue Op,
+ const TargetLoweringOpt &TLO) const override;
+
// Custom lowering hooks.
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
SDValue LowerFrameIndex(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
index 42183d1645e1..ed80ed39f09c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
@@ -15,7 +15,7 @@ let UseNamedOperandTable = 1 in
multiclass ATOMIC_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
list<dag> pattern_r, string asmstr_r,
string asmstr_s, bits<32> atomic_op,
- string is64 = "false"> {
+ bit is64 = false> {
defm "" : I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r, asmstr_s,
!or(0xfe00, !and(0xff, atomic_op)), is64>,
Requires<[HasAtomics]>;
@@ -38,13 +38,13 @@ defm MEMORY_ATOMIC_NOTIFY_A32 :
(ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$count),
(outs), (ins P2Align:$p2align, offset32_op:$off), [],
"memory.atomic.notify \t$dst, ${off}(${addr})${p2align}, $count",
- "memory.atomic.notify \t${off}${p2align}", 0x00, "false">;
+ "memory.atomic.notify \t${off}${p2align}", 0x00, false>;
defm MEMORY_ATOMIC_NOTIFY_A64 :
ATOMIC_I<(outs I32:$dst),
(ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$count),
(outs), (ins P2Align:$p2align, offset64_op:$off), [],
"memory.atomic.notify \t$dst, ${off}(${addr})${p2align}, $count",
- "memory.atomic.notify \t${off}${p2align}", 0x00, "true">;
+ "memory.atomic.notify \t${off}${p2align}", 0x00, true>;
let mayLoad = 1 in {
defm MEMORY_ATOMIC_WAIT32_A32 :
ATOMIC_I<(outs I32:$dst),
@@ -52,28 +52,28 @@ defm MEMORY_ATOMIC_WAIT32_A32 :
I64:$timeout),
(outs), (ins P2Align:$p2align, offset32_op:$off), [],
"memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
- "memory.atomic.wait32 \t${off}${p2align}", 0x01, "false">;
+ "memory.atomic.wait32 \t${off}${p2align}", 0x01, false>;
defm MEMORY_ATOMIC_WAIT32_A64 :
ATOMIC_I<(outs I32:$dst),
(ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$exp,
I64:$timeout),
(outs), (ins P2Align:$p2align, offset64_op:$off), [],
"memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
- "memory.atomic.wait32 \t${off}${p2align}", 0x01, "true">;
+ "memory.atomic.wait32 \t${off}${p2align}", 0x01, true>;
defm MEMORY_ATOMIC_WAIT64_A32 :
ATOMIC_I<(outs I32:$dst),
(ins P2Align:$p2align, offset32_op:$off, I32:$addr, I64:$exp,
I64:$timeout),
(outs), (ins P2Align:$p2align, offset32_op:$off), [],
"memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
- "memory.atomic.wait64 \t${off}${p2align}", 0x02, "false">;
+ "memory.atomic.wait64 \t${off}${p2align}", 0x02, false>;
defm MEMORY_ATOMIC_WAIT64_A64 :
ATOMIC_I<(outs I32:$dst),
(ins P2Align:$p2align, offset64_op:$off, I64:$addr, I64:$exp,
I64:$timeout),
(outs), (ins P2Align:$p2align, offset64_op:$off), [],
"memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
- "memory.atomic.wait64 \t${off}${p2align}", 0x02, "true">;
+ "memory.atomic.wait64 \t${off}${p2align}", 0x02, true>;
} // mayLoad = 1
} // hasSideEffects = 1
@@ -469,13 +469,13 @@ multiclass WebAssemblyBinRMW<WebAssemblyRegClass rc, string name,
(ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
(outs), (ins P2Align:$p2align, offset32_op:$off), [],
!strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"),
- !strconcat(name, "\t${off}${p2align}"), atomic_op, "false">;
+ !strconcat(name, "\t${off}${p2align}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
(ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val),
(outs), (ins P2Align:$p2align, offset64_op:$off), [],
!strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"),
- !strconcat(name, "\t${off}${p2align}"), atomic_op, "true">;
+ !strconcat(name, "\t${off}${p2align}"), atomic_op, true>;
}
defm ATOMIC_RMW_ADD_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.add", 0x1e>;
@@ -767,14 +767,14 @@ multiclass WebAssemblyTerRMW<WebAssemblyRegClass rc, string name,
rc:$new_),
(outs), (ins P2Align:$p2align, offset32_op:$off), [],
!strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"),
- !strconcat(name, "\t${off}${p2align}"), atomic_op, "false">;
+ !strconcat(name, "\t${off}${p2align}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
(ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$exp,
rc:$new_),
(outs), (ins P2Align:$p2align, offset64_op:$off), [],
!strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"),
- !strconcat(name, "\t${off}${p2align}"), atomic_op, "true">;
+ !strconcat(name, "\t${off}${p2align}"), atomic_op, true>;
}
defm ATOMIC_RMW_CMPXCHG_I32 :
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td
index 4dc0c9a46c38..f2e73dd19d6b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td
@@ -14,12 +14,12 @@
// WebAssembly Instruction Format.
// We instantiate 2 of these for every actual instruction (register based
// and stack based), see below.
-class WebAssemblyInst<bits<32> inst, string asmstr, string stack, string is64>
+class WebAssemblyInst<bits<32> inst, string asmstr, bit stack, bit is64>
: StackRel, RegisterRel, Wasm64Rel, Instruction {
bits<32> Inst = inst; // Instruction encoding.
- string StackBased = stack;
+ bit StackBased = stack;
string BaseName = NAME;
- string IsWasm64 = is64;
+ bit IsWasm64 = is64;
string Wasm32Name = !subst("_A64", "_A32", NAME);
let Namespace = "WebAssembly";
let Pattern = [];
@@ -30,8 +30,8 @@ class WebAssemblyInst<bits<32> inst, string asmstr, string stack, string is64>
}
// Normal instructions. Default instantiation of a WebAssemblyInst.
-class NI<dag oops, dag iops, list<dag> pattern, string stack,
- string asmstr = "", bits<32> inst = -1, string is64 = "false">
+class NI<dag oops, dag iops, list<dag> pattern, bit stack,
+ string asmstr = "", bits<32> inst = -1, bit is64 = false>
: WebAssemblyInst<inst, asmstr, stack, is64> {
dag OutOperandList = oops;
dag InOperandList = iops;
@@ -54,11 +54,11 @@ class NI<dag oops, dag iops, list<dag> pattern, string stack,
// there is always an equivalent pair of instructions.
multiclass I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
list<dag> pattern_r, string asmstr_r = "", string asmstr_s = "",
- bits<32> inst = -1, string is64 = "false"> {
+ bits<32> inst = -1, bit is64 = false> {
let isCodeGenOnly = 1 in
- def "" : NI<oops_r, iops_r, pattern_r, "false", asmstr_r, inst, is64>;
+ def "" : NI<oops_r, iops_r, pattern_r, false, asmstr_r, inst, is64>;
let BaseName = NAME in
- def _S : NI<oops_s, iops_s, [], "true", asmstr_s, inst, is64>;
+ def _S : NI<oops_s, iops_s, [], true, asmstr_s, inst, is64>;
}
// For instructions that have no register ops, so both sets are the same.
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 3fb0af1d47a0..134a0efc6822 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -66,6 +66,10 @@ def HasReferenceTypes :
Predicate<"Subtarget->hasReferenceTypes()">,
AssemblerPredicate<(all_of FeatureReferenceTypes), "reference-types">;
+def HasExtendedConst :
+ Predicate<"Subtarget->hasExtendedConst()">,
+ AssemblerPredicate<(all_of FeatureExtendedConst), "extended-const">;
+
//===----------------------------------------------------------------------===//
// WebAssembly-specific DAG Node Types.
//===----------------------------------------------------------------------===//
@@ -221,8 +225,8 @@ def getStackOpcode : InstrMapping {
let FilterClass = "StackRel";
let RowFields = ["BaseName"];
let ColFields = ["StackBased"];
- let KeyCol = ["false"];
- let ValueCols = [["true"]];
+ let KeyCol = ["0"];
+ let ValueCols = [["1"]];
}
//===----------------------------------------------------------------------===//
@@ -234,8 +238,8 @@ def getRegisterOpcode : InstrMapping {
let FilterClass = "RegisterRel";
let RowFields = ["BaseName"];
let ColFields = ["StackBased"];
- let KeyCol = ["true"];
- let ValueCols = [["false"]];
+ let KeyCol = ["1"];
+ let ValueCols = [["0"]];
}
//===----------------------------------------------------------------------===//
@@ -247,8 +251,8 @@ def getWasm64Opcode : InstrMapping {
let FilterClass = "Wasm64Rel";
let RowFields = ["Wasm32Name"];
let ColFields = ["IsWasm64"];
- let KeyCol = ["false"];
- let ValueCols = [["true"]];
+ let KeyCol = ["0"];
+ let ValueCols = [["1"]];
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td
index a70f62dde845..d5bb9e9e48b4 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td
@@ -47,13 +47,13 @@ multiclass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode,
(ins P2Align:$p2align, offset32_op:$off, I32:$addr),
(outs), (ins P2Align:$p2align, offset32_op:$off),
[], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"),
- !strconcat(Name, "\t${off}${p2align}"), Opcode, "false">,
+ !strconcat(Name, "\t${off}${p2align}"), Opcode, false>,
Requires<reqs>;
defm "_A64": I<(outs rc:$dst),
(ins P2Align:$p2align, offset64_op:$off, I64:$addr),
(outs), (ins P2Align:$p2align, offset64_op:$off),
[], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"),
- !strconcat(Name, "\t${off}${p2align}"), Opcode, "true">,
+ !strconcat(Name, "\t${off}${p2align}"), Opcode, true>,
Requires<reqs>;
}
}
@@ -244,7 +244,7 @@ multiclass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode,
(outs),
(ins P2Align:$p2align, offset32_op:$off), [],
!strconcat(Name, "\t${off}(${addr})${p2align}, $val"),
- !strconcat(Name, "\t${off}${p2align}"), Opcode, "false">,
+ !strconcat(Name, "\t${off}${p2align}"), Opcode, false>,
Requires<reqs>;
let mayStore = 1, UseNamedOperandTable = 1 in
defm "_A64" : I<(outs),
@@ -252,7 +252,7 @@ multiclass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode,
(outs),
(ins P2Align:$p2align, offset64_op:$off), [],
!strconcat(Name, "\t${off}(${addr})${p2align}, $val"),
- !strconcat(Name, "\t${off}${p2align}"), Opcode, "true">,
+ !strconcat(Name, "\t${off}${p2align}"), Opcode, true>,
Requires<reqs>;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td
index 76a88caafc47..608963d58863 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td
@@ -27,6 +27,12 @@ multiclass REF_I<WebAssemblyRegClass rc, ValueType vt, string ht> {
vt#".select\t$dst, $lhs, $rhs, $cond",
vt#".select", 0x1b>,
Requires<[HasReferenceTypes]>;
+ defm REF_IS_NULL_#rc
+ : I<(outs I32:$dst), (ins rc:$ref), (outs), (ins),
+ [(set I32:$dst, (!cast<Intrinsic>("int_wasm_ref_is_null_" # ht) rc:$ref))],
+ "ref.is_null\t$ref",
+ "ref.is_null", 0xd1>,
+ Requires<[HasReferenceTypes]>;
}
defm "" : REF_I<FUNCREF, funcref, "func">;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
index 5bb12c7fbdc7..ed3cc7ed1c53 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
@@ -1229,9 +1229,9 @@ def trunc_sat_zero_s :
SDNode<"WebAssemblyISD::TRUNC_SAT_ZERO_S", trunc_sat_zero_t>;
def trunc_sat_zero_u :
SDNode<"WebAssemblyISD::TRUNC_SAT_ZERO_U", trunc_sat_zero_t>;
-defm "" : SIMDConvert<I32x4, F64x2, trunc_sat_zero_s, "trunc_sat_zero_f64x2_s",
+defm "" : SIMDConvert<I32x4, F64x2, trunc_sat_zero_s, "trunc_sat_f64x2_s_zero",
0xfc>;
-defm "" : SIMDConvert<I32x4, F64x2, trunc_sat_zero_u, "trunc_sat_zero_f64x2_u",
+defm "" : SIMDConvert<I32x4, F64x2, trunc_sat_zero_u, "trunc_sat_f64x2_u_zero",
0xfd>;
// Integer to floating point: convert
@@ -1307,7 +1307,7 @@ defm "" : SIMDConvert<I32x4, I16x8, int_wasm_extadd_pairwise_unsigned,
def demote_t : SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisVec<1>]>;
def demote_zero : SDNode<"WebAssemblyISD::DEMOTE_ZERO", demote_t>;
defm "" : SIMDConvert<F32x4, F64x2, demote_zero,
- "demote_zero_f64x2", 0x5e>;
+ "demote_f64x2_zero", 0x5e>;
def promote_t : SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisVec<1>]>;
def promote_low : SDNode<"WebAssemblyISD::PROMOTE_LOW", promote_t>;
@@ -1334,7 +1334,37 @@ defm Q15MULR_SAT_S :
SIMDBinary<I16x8, int_wasm_q15mulr_sat_signed, "q15mulr_sat_s", 0x82>;
//===----------------------------------------------------------------------===//
-// Fused Multiply- Add and Subtract (FMA/FMS)
+// Relaxed swizzle
+//===----------------------------------------------------------------------===//
+
+defm RELAXED_SWIZZLE :
+ RELAXED_I<(outs V128:$dst), (ins V128:$src, V128:$mask), (outs), (ins),
+ [(set (v16i8 V128:$dst),
+ (int_wasm_relaxed_swizzle (v16i8 V128:$src), (v16i8 V128:$mask)))],
+ "i8x16.relaxed_swizzle\t$dst, $src, $mask", "i8x16.relaxed_swizzle", 0x100>;
+
+//===----------------------------------------------------------------------===//
+// Relaxed floating-point to int conversions
+//===----------------------------------------------------------------------===//
+
+multiclass RelaxedConvert<Vec vec, Vec arg, SDPatternOperator op, string name, bits<32> simdop> {
+ defm op#_#vec :
+ RELAXED_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins),
+ [(set (vec.vt V128:$dst), (vec.vt (op (arg.vt V128:$vec))))],
+ vec.prefix#"."#name#"\t$dst, $vec", vec.prefix#"."#name, simdop>;
+}
+
+defm "" : RelaxedConvert<I32x4, F32x4, int_wasm_relaxed_trunc_signed,
+ "relaxed_trunc_f32x4_s", 0x101>;
+defm "" : RelaxedConvert<I32x4, F32x4, int_wasm_relaxed_trunc_unsigned,
+ "relaxed_trunc_f32x4_u", 0x102>;
+defm "" : RelaxedConvert<I32x4, F64x2, int_wasm_relaxed_trunc_signed_zero,
+ "relaxed_trunc_f64x2_s_zero", 0x103>;
+defm "" : RelaxedConvert<I32x4, F64x2, int_wasm_relaxed_trunc_unsigned_zero,
+ "relaxed_trunc_f64x2_u_zero", 0x104>;
+
+//===----------------------------------------------------------------------===//
+// Relaxed Fused Multiply- Add and Subtract (FMA/FMS)
//===----------------------------------------------------------------------===//
multiclass SIMDFM<Vec vec, bits<32> simdopA, bits<32> simdopS> {
@@ -1342,16 +1372,18 @@ multiclass SIMDFM<Vec vec, bits<32> simdopA, bits<32> simdopS> {
RELAXED_I<(outs V128:$dst), (ins V128:$a, V128:$b, V128:$c), (outs), (ins),
[(set (vec.vt V128:$dst), (int_wasm_fma
(vec.vt V128:$a), (vec.vt V128:$b), (vec.vt V128:$c)))],
- vec.prefix#".fma\t$dst, $a, $b, $c", vec.prefix#".fma", simdopA>;
+ vec.prefix#".relaxed_fma\t$dst, $a, $b, $c",
+ vec.prefix#".relaxed_fma", simdopA>;
defm FMS_#vec :
RELAXED_I<(outs V128:$dst), (ins V128:$a, V128:$b, V128:$c), (outs), (ins),
[(set (vec.vt V128:$dst), (int_wasm_fms
(vec.vt V128:$a), (vec.vt V128:$b), (vec.vt V128:$c)))],
- vec.prefix#".fms\t$dst, $a, $b, $c", vec.prefix#".fms", simdopS>;
+ vec.prefix#".relaxed_fms\t$dst, $a, $b, $c",
+ vec.prefix#".relaxed_fms", simdopS>;
}
-defm "" : SIMDFM<F32x4, 0xaf, 0xb0>;
-defm "" : SIMDFM<F64x2, 0xcf, 0xd0>;
+defm "" : SIMDFM<F32x4, 0x105, 0x106>;
+defm "" : SIMDFM<F64x2, 0x107, 0x108>;
//===----------------------------------------------------------------------===//
// Laneselect
@@ -1362,58 +1394,61 @@ multiclass SIMDLANESELECT<Vec vec, bits<32> op> {
RELAXED_I<(outs V128:$dst), (ins V128:$a, V128:$b, V128:$c), (outs), (ins),
[(set (vec.vt V128:$dst), (int_wasm_laneselect
(vec.vt V128:$a), (vec.vt V128:$b), (vec.vt V128:$c)))],
- vec.prefix#".laneselect\t$dst, $a, $b, $c", vec.prefix#".laneselect", op>;
+ vec.prefix#".relaxed_laneselect\t$dst, $a, $b, $c",
+ vec.prefix#".relaxed_laneselect", op>;
}
-defm "" : SIMDLANESELECT<I8x16, 0xb2>;
-defm "" : SIMDLANESELECT<I16x8, 0xb3>;
-defm "" : SIMDLANESELECT<I32x4, 0xd2>;
-defm "" : SIMDLANESELECT<I64x2, 0xd3>;
-
-
-//===----------------------------------------------------------------------===//
-// Relaxed swizzle
-//===----------------------------------------------------------------------===//
-
-defm RELAXED_SWIZZLE :
- RELAXED_I<(outs V128:$dst), (ins V128:$src, V128:$mask), (outs), (ins),
- [(set (v16i8 V128:$dst),
- (int_wasm_relaxed_swizzle (v16i8 V128:$src), (v16i8 V128:$mask)))],
- "i8x16.relaxed_swizzle\t$dst, $src, $mask", "i8x16.relaxed_swizzle", 162>;
+defm "" : SIMDLANESELECT<I8x16, 0x109>;
+defm "" : SIMDLANESELECT<I16x8, 0x10a>;
+defm "" : SIMDLANESELECT<I32x4, 0x10b>;
+defm "" : SIMDLANESELECT<I64x2, 0x10c>;
//===----------------------------------------------------------------------===//
// Relaxed floating-point min and max.
//===----------------------------------------------------------------------===//
-multiclass SIMD_RELAXED_FMINMAX<Vec vec, bits<32> simdopMin, bits<32> simdopMax> {
- defm RELAXED_FMIN_#vec :
- RELAXED_I<(outs V128:$dst), (ins V128:$a, V128:$b), (outs), (ins),
- [(set (vec.vt V128:$dst), (int_wasm_relaxed_min
- (vec.vt V128:$a), (vec.vt V128:$b)))],
- vec.prefix#".relaxed_min\t$dst, $a, $b", vec.prefix#".relaxed_min", simdopMin>;
- defm RELAXED_FMAX_#vec :
- RELAXED_I<(outs V128:$dst), (ins V128:$a, V128:$b), (outs), (ins),
- [(set (vec.vt V128:$dst), (int_wasm_relaxed_max
- (vec.vt V128:$a), (vec.vt V128:$b)))],
- vec.prefix#".relaxed_max\t$dst, $a, $b", vec.prefix#".relaxed_max", simdopMax>;
+multiclass RelaxedBinary<Vec vec, SDPatternOperator node, string name,
+ bits<32> simdop> {
+ defm _#vec : RELAXED_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs),
+ (outs), (ins),
+ [(set (vec.vt V128:$dst),
+ (node (vec.vt V128:$lhs), (vec.vt V128:$rhs)))],
+ vec.prefix#"."#name#"\t$dst, $lhs, $rhs",
+ vec.prefix#"."#name, simdop>;
}
-defm "" : SIMD_RELAXED_FMINMAX<F32x4, 0xb4, 0xe2>;
-defm "" : SIMD_RELAXED_FMINMAX<F64x2, 0xd4, 0xee>;
+defm SIMD_RELAXED_FMIN :
+ RelaxedBinary<F32x4, int_wasm_relaxed_min, "relaxed_min", 0x10d>;
+defm SIMD_RELAXED_FMAX :
+ RelaxedBinary<F32x4, int_wasm_relaxed_max, "relaxed_max", 0x10e>;
+defm SIMD_RELAXED_FMIN :
+ RelaxedBinary<F64x2, int_wasm_relaxed_min, "relaxed_min", 0x10f>;
+defm SIMD_RELAXED_FMAX :
+ RelaxedBinary<F64x2, int_wasm_relaxed_max, "relaxed_max", 0x110>;
//===----------------------------------------------------------------------===//
-// Relaxed floating-point to int conversions
+// Relaxed rounding q15 multiplication
//===----------------------------------------------------------------------===//
-multiclass SIMD_RELAXED_CONVERT<Vec vec, Vec arg, SDPatternOperator op, string name, bits<32> simdop> {
- defm op#_#vec :
- RELAXED_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins),
- [(set (vec.vt V128:$dst), (vec.vt (op (arg.vt V128:$vec))))],
- vec.prefix#"."#name#"\t$dst, $vec", vec.prefix#"."#name, simdop>;
-}
+defm RELAXED_Q15MULR_S :
+ RelaxedBinary<I16x8, int_wasm_relaxed_q15mulr_signed, "relaxed_q15mulr_s",
+ 0x111>;
+
+//===----------------------------------------------------------------------===//
+// Relaxed integer dot product
+//===----------------------------------------------------------------------===//
-defm "" : SIMD_RELAXED_CONVERT<I32x4, F32x4, int_wasm_relaxed_trunc_signed, "relaxed_trunc_f32x4_s", 0xa5>;
-defm "" : SIMD_RELAXED_CONVERT<I32x4, F32x4, int_wasm_relaxed_trunc_unsigned, "relaxed_trunc_f32x4_u", 0xa6>;
+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
+ (v16i8 V128:$lhs), (v16i8 V128:$rhs)))],
+ "i16x8.dot_i8x16_i7x16_s\t$dst, $lhs, $rhs",
+ "i16x8.dot_i8x16_i7x16_s", 0x112>;
-defm "" : SIMD_RELAXED_CONVERT<I32x4, F64x2, int_wasm_relaxed_trunc_zero_signed, "relaxed_trunc_f64x2_s_zero", 0xc5>;
-defm "" : SIMD_RELAXED_CONVERT<I32x4, F64x2, int_wasm_relaxed_trunc_zero_unsigned, "relaxed_trunc_f64x2_u_zero", 0xc6>;
+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
+ (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>;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
index 309fcaf340eb..d16bb6b6648a 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
@@ -16,6 +16,7 @@
#include "WebAssembly.h"
#include "WebAssemblySubtarget.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/WasmEHFuncInfo.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -72,9 +73,8 @@ WebAssemblyLateEHPrepare::getMatchingEHPad(MachineInstr *MI) {
MachineBasicBlock *EHPad = nullptr;
while (!WL.empty()) {
MachineBasicBlock *MBB = WL.pop_back_val();
- if (Visited.count(MBB))
+ if (!Visited.insert(MBB).second)
continue;
- Visited.insert(MBB);
if (MBB->isEHPad()) {
if (EHPad && EHPad != MBB)
return nullptr;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index b6c43be03aba..2db4bd822349 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -406,8 +406,9 @@ static bool canThrow(const Value *V) {
return true;
}
-// Get a global variable with the given name. If it doesn't exist declare it,
-// which will generate an import and assume that it will exist at link time.
+// Get a thread-local global variable with the given name. If it doesn't exist
+// declare it, which will generate an import and assume that it will exist at
+// link time.
static GlobalVariable *getGlobalVariable(Module &M, Type *Ty,
WebAssemblyTargetMachine &TM,
const char *Name) {
@@ -415,16 +416,11 @@ static GlobalVariable *getGlobalVariable(Module &M, Type *Ty,
if (!GV)
report_fatal_error(Twine("unable to create global: ") + Name);
- // If the target supports TLS, make this variable thread-local. We can't just
- // unconditionally make it thread-local and depend on
- // CoalesceFeaturesAndStripAtomics to downgrade it, because stripping TLS has
- // the side effect of disallowing the object from being linked into a
- // shared-memory module, which we don't want to be responsible for.
- auto *Subtarget = TM.getSubtargetImpl();
- auto TLS = Subtarget->hasAtomics() && Subtarget->hasBulkMemory()
- ? GlobalValue::LocalExecTLSModel
- : GlobalValue::NotThreadLocal;
- GV->setThreadLocalMode(TLS);
+ // Variables created by this function are thread local. If the target does not
+ // support TLS, we depend on CoalesceFeaturesAndStripAtomics to downgrade it
+ // to non-thread-local ones, in which case we don't allow this object to be
+ // linked with other objects using shared memory.
+ GV->setThreadLocalMode(GlobalValue::GeneralDynamicTLSModel);
return GV;
}
@@ -556,7 +552,7 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
Optional<unsigned> NEltArg;
std::tie(SizeArg, NEltArg) = FnAttrs.getAllocSizeArgs();
SizeArg += 1;
- if (NEltArg.hasValue())
+ if (NEltArg)
NEltArg = NEltArg.getValue() + 1;
FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
}
@@ -1064,22 +1060,16 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
nullifySetjmp(F);
}
- if (!Changed) {
- // Delete unused global variables and functions
- if (ResumeF)
- ResumeF->eraseFromParent();
- if (EHTypeIDF)
- EHTypeIDF->eraseFromParent();
- if (EmLongjmpF)
- EmLongjmpF->eraseFromParent();
- if (SaveSetjmpF)
- SaveSetjmpF->eraseFromParent();
- if (TestSetjmpF)
- TestSetjmpF->eraseFromParent();
- return false;
- }
+ // Delete unused global variables and functions
+ for (auto *V : {ThrewGV, ThrewValueGV})
+ if (V && V->use_empty())
+ V->eraseFromParent();
+ for (auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
+ SaveSetjmpF, TestSetjmpF, WasmLongjmpF, CatchF})
+ if (V && V->use_empty())
+ V->eraseFromParent();
- return true;
+ return Changed;
}
bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
@@ -1324,9 +1314,14 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
BasicBlock *BB = CB->getParent();
if (BB->getParent() != &F) // in other function
continue;
- if (CB->getOperandBundle(LLVMContext::OB_funclet))
- report_fatal_error(
- "setjmp within a catch clause is not supported in Wasm EH");
+ if (CB->getOperandBundle(LLVMContext::OB_funclet)) {
+ std::string S;
+ raw_string_ostream SS(S);
+ SS << "In function " + F.getName() +
+ ": setjmp within a catch clause is not supported in Wasm EH:\n";
+ SS << *CB;
+ report_fatal_error(StringRef(SS.str()));
+ }
CallInst *CI = nullptr;
// setjmp cannot throw. So if it is an invoke, lower it to a call
@@ -1502,10 +1497,16 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
for (unsigned I = 0; I < BBs.size(); I++) {
BasicBlock *BB = BBs[I];
for (Instruction &I : *BB) {
- if (isa<InvokeInst>(&I))
- report_fatal_error("When using Wasm EH with Emscripten SjLj, there is "
- "a restriction that `setjmp` function call and "
- "exception cannot be used within the same function");
+ if (isa<InvokeInst>(&I)) {
+ std::string S;
+ raw_string_ostream SS(S);
+ SS << "In function " << F.getName()
+ << ": When using Wasm EH with Emscripten SjLj, there is a "
+ "restriction that `setjmp` function call and exception cannot be "
+ "used within the same function:\n";
+ SS << I;
+ report_fatal_error(StringRef(SS.str()));
+ }
auto *CI = dyn_cast<CallInst>(&I);
if (!CI)
continue;
@@ -1829,7 +1830,8 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
if (auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
break;
- } else if (auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
+ }
+ if (auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
// getCleanupRetUnwindDest() can return nullptr when
// 1. This cleanuppad's matching cleanupret uwninds to caller
// 2. There is no matching cleanupret because it ends with
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp
deleted file mode 100644
index ca6f3f194645..000000000000
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
-//===-- WebAssemblyLowerGlobalDtors.cpp - Lower @llvm.global_dtors --------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Lower @llvm.global_dtors.
-///
-/// WebAssembly doesn't have a builtin way to invoke static destructors.
-/// Implement @llvm.global_dtors by creating wrapper functions that are
-/// registered in @llvm.global_ctors and which contain a call to
-/// `__cxa_atexit` to register their destructor functions.
-///
-//===----------------------------------------------------------------------===//
-
-#include "WebAssembly.h"
-#include "llvm/ADT/MapVector.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Pass.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Transforms/Utils/ModuleUtils.h"
-#include <map>
-
-using namespace llvm;
-
-#define DEBUG_TYPE "wasm-lower-global-dtors"
-
-namespace {
-class LowerGlobalDtors final : public ModulePass {
- StringRef getPassName() const override {
- return "WebAssembly Lower @llvm.global_dtors";
- }
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesCFG();
- ModulePass::getAnalysisUsage(AU);
- }
-
- bool runOnModule(Module &M) override;
-
-public:
- static char ID;
- LowerGlobalDtors() : ModulePass(ID) {}
-};
-} // End anonymous namespace
-
-char LowerGlobalDtors::ID = 0;
-INITIALIZE_PASS(LowerGlobalDtors, DEBUG_TYPE,
- "Lower @llvm.global_dtors for WebAssembly", false, false)
-
-ModulePass *llvm::createWebAssemblyLowerGlobalDtors() {
- return new LowerGlobalDtors();
-}
-
-bool LowerGlobalDtors::runOnModule(Module &M) {
- LLVM_DEBUG(dbgs() << "********** Lower Global Destructors **********\n");
-
- GlobalVariable *GV = M.getGlobalVariable("llvm.global_dtors");
- if (!GV || !GV->hasInitializer())
- return false;
-
- const ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
- if (!InitList)
- return false;
-
- // Validate @llvm.global_dtor's type.
- auto *ETy = dyn_cast<StructType>(InitList->getType()->getElementType());
- if (!ETy || ETy->getNumElements() != 3 ||
- !ETy->getTypeAtIndex(0U)->isIntegerTy() ||
- !ETy->getTypeAtIndex(1U)->isPointerTy() ||
- !ETy->getTypeAtIndex(2U)->isPointerTy())
- return false; // Not (int, ptr, ptr).
-
- // Collect the contents of @llvm.global_dtors, ordered by priority. Within a
- // priority, sequences of destructors with the same associated object are
- // recorded so that we can register them as a group.
- std::map<
- uint16_t,
- std::vector<std::pair<Constant *, std::vector<Constant *>>>
- > DtorFuncs;
- for (Value *O : InitList->operands()) {
- auto *CS = dyn_cast<ConstantStruct>(O);
- if (!CS)
- continue; // Malformed.
-
- auto *Priority = dyn_cast<ConstantInt>(CS->getOperand(0));
- if (!Priority)
- continue; // Malformed.
- uint16_t PriorityValue = Priority->getLimitedValue(UINT16_MAX);
-
- Constant *DtorFunc = CS->getOperand(1);
- if (DtorFunc->isNullValue())
- break; // Found a null terminator, skip the rest.
-
- Constant *Associated = CS->getOperand(2);
- Associated = cast<Constant>(Associated->stripPointerCasts());
-
- auto &AtThisPriority = DtorFuncs[PriorityValue];
- if (AtThisPriority.empty() || AtThisPriority.back().first != Associated) {
- std::vector<Constant *> NewList;
- NewList.push_back(DtorFunc);
- AtThisPriority.push_back(std::make_pair(Associated, NewList));
- } else {
- AtThisPriority.back().second.push_back(DtorFunc);
- }
- }
- if (DtorFuncs.empty())
- return false;
-
- // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
- LLVMContext &C = M.getContext();
- PointerType *VoidStar = Type::getInt8PtrTy(C);
- Type *AtExitFuncArgs[] = {VoidStar};
- FunctionType *AtExitFuncTy =
- FunctionType::get(Type::getVoidTy(C), AtExitFuncArgs,
- /*isVarArg=*/false);
-
- FunctionCallee AtExit = M.getOrInsertFunction(
- "__cxa_atexit",
- FunctionType::get(Type::getInt32Ty(C),
- {PointerType::get(AtExitFuncTy, 0), VoidStar, VoidStar},
- /*isVarArg=*/false));
-
- // Declare __dso_local.
- Constant *DsoHandle = M.getNamedValue("__dso_handle");
- if (!DsoHandle) {
- Type *DsoHandleTy = Type::getInt8Ty(C);
- GlobalVariable *Handle = new GlobalVariable(
- M, DsoHandleTy, /*isConstant=*/true,
- GlobalVariable::ExternalWeakLinkage, nullptr, "__dso_handle");
- Handle->setVisibility(GlobalVariable::HiddenVisibility);
- DsoHandle = Handle;
- }
-
- // For each unique priority level and associated symbol, generate a function
- // to call all the destructors at that level, and a function to register the
- // first function with __cxa_atexit.
- for (auto &PriorityAndMore : DtorFuncs) {
- uint16_t Priority = PriorityAndMore.first;
- uint64_t Id = 0;
- auto &AtThisPriority = PriorityAndMore.second;
- for (auto &AssociatedAndMore : AtThisPriority) {
- Constant *Associated = AssociatedAndMore.first;
- auto ThisId = Id++;
-
- Function *CallDtors = Function::Create(
- AtExitFuncTy, Function::PrivateLinkage,
- "call_dtors" +
- (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority))
- : Twine()) +
- (AtThisPriority.size() > 1 ? Twine("$") + Twine(ThisId)
- : Twine()) +
- (!Associated->isNullValue() ? (Twine(".") + Associated->getName())
- : Twine()),
- &M);
- BasicBlock *BB = BasicBlock::Create(C, "body", CallDtors);
- FunctionType *VoidVoid = FunctionType::get(Type::getVoidTy(C),
- /*isVarArg=*/false);
-
- for (auto Dtor : reverse(AssociatedAndMore.second))
- CallInst::Create(VoidVoid, Dtor, "", BB);
- ReturnInst::Create(C, BB);
-
- Function *RegisterCallDtors = Function::Create(
- VoidVoid, Function::PrivateLinkage,
- "register_call_dtors" +
- (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority))
- : Twine()) +
- (AtThisPriority.size() > 1 ? Twine("$") + Twine(ThisId)
- : Twine()) +
- (!Associated->isNullValue() ? (Twine(".") + Associated->getName())
- : Twine()),
- &M);
- BasicBlock *EntryBB = BasicBlock::Create(C, "entry", RegisterCallDtors);
- BasicBlock *FailBB = BasicBlock::Create(C, "fail", RegisterCallDtors);
- BasicBlock *RetBB = BasicBlock::Create(C, "return", RegisterCallDtors);
-
- Value *Null = ConstantPointerNull::get(VoidStar);
- Value *Args[] = {CallDtors, Null, DsoHandle};
- Value *Res = CallInst::Create(AtExit, Args, "call", EntryBB);
- Value *Cmp = new ICmpInst(*EntryBB, ICmpInst::ICMP_NE, Res,
- Constant::getNullValue(Res->getType()));
- BranchInst::Create(FailBB, RetBB, Cmp, EntryBB);
-
- // If `__cxa_atexit` hits out-of-memory, trap, so that we don't misbehave.
- // This should be very rare, because if the process is running out of
- // memory before main has even started, something is wrong.
- CallInst::Create(Intrinsic::getDeclaration(&M, Intrinsic::trap), "",
- FailBB);
- new UnreachableInst(C, FailBB);
-
- ReturnInst::Create(C, RetBB);
-
- // Now register the registration function with @llvm.global_ctors.
- appendToGlobalCtors(M, RegisterCallDtors, Priority, Associated);
- }
- }
-
- // Now that we've lowered everything, remove @llvm.global_dtors.
- GV->eraseFromParent();
-
- return true;
-}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCLowerPrePass.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCLowerPrePass.cpp
index 37ac8e75f4b7..21f6fd37d402 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCLowerPrePass.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCLowerPrePass.cpp
@@ -65,6 +65,9 @@ ModulePass *llvm::createWebAssemblyMCLowerPrePass() {
// for all functions before AsmPrinter. If this way of doing things is ever
// suboptimal, we could opt to make it a MachineFunctionPass and instead use
// something like createBarrierNoopPass() to enforce ordering.
+//
+// The information stored here is essential for emitExternalDecls in the Wasm
+// AsmPrinter
bool WebAssemblyMCLowerPrePass::runOnModule(Module &M) {
auto *MMIWP = getAnalysisIfAvailable<MachineModuleInfoWrapperPass>();
if (!MMIWP)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp
index ea80e96d50de..96284687971c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp
@@ -24,6 +24,16 @@ using namespace llvm;
WebAssemblyFunctionInfo::~WebAssemblyFunctionInfo() = default; // anchor.
+MachineFunctionInfo *WebAssemblyFunctionInfo::clone(
+ BumpPtrAllocator &Allocator, MachineFunction &DestMF,
+ const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB)
+ const {
+ WebAssemblyFunctionInfo *Clone =
+ DestMF.cloneInfo<WebAssemblyFunctionInfo>(*this);
+ Clone->MF = &DestMF;
+ return Clone;
+}
+
void WebAssemblyFunctionInfo::initWARegs(MachineRegisterInfo &MRI) {
assert(WARegs.empty());
unsigned Reg = UnusedReg;
@@ -153,7 +163,7 @@ void WebAssemblyFunctionInfo::initializeBaseYamlFields(
addResult(WebAssembly::parseMVT(VT.Value));
if (WasmEHInfo) {
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/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
index 413d0d1dc554..619617049bb2 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
@@ -31,7 +31,7 @@ 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;
+ const MachineFunction *MF;
std::vector<MVT> Params;
std::vector<MVT> Results;
@@ -70,11 +70,16 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
WasmEHFuncInfo *WasmEHInfo = nullptr;
public:
- explicit WebAssemblyFunctionInfo(MachineFunction &MF)
- : MF(MF), WasmEHInfo(MF.getWasmEHFuncInfo()) {}
+ explicit WebAssemblyFunctionInfo(MachineFunction &MF_)
+ : MF(&MF_), WasmEHInfo(MF_.getWasmEHFuncInfo()) {}
~WebAssemblyFunctionInfo() override;
- const MachineFunction &getMachineFunction() const { return MF; }
+ MachineFunctionInfo *
+ clone(BumpPtrAllocator &Allocator, MachineFunction &DestMF,
+ const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB)
+ const override;
+
+ const MachineFunction &getMachineFunction() const { return *MF; }
void initializeBaseYamlFields(const yaml::WebAssemblyFunctionInfo &YamlMFI);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyNullifyDebugValueLists.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyNullifyDebugValueLists.cpp
index 62fa089a94d4..5d8c58dcc334 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyNullifyDebugValueLists.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyNullifyDebugValueLists.cpp
@@ -16,6 +16,7 @@
#include "WebAssembly.h"
#include "WebAssemblySubtarget.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
using namespace llvm;
#define DEBUG_TYPE "wasm-nullify-dbg-value-lists"
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp
index 6a6cac6d956f..d542ddb45c2e 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp
@@ -49,6 +49,11 @@ class WebAssemblyOptimizeLiveIntervals final : public MachineFunctionPass {
MachineFunctionPass::getAnalysisUsage(AU);
}
+ MachineFunctionProperties getRequiredProperties() const override {
+ return MachineFunctionProperties().set(
+ MachineFunctionProperties::Property::TracksLiveness);
+ }
+
bool runOnMachineFunction(MachineFunction &MF) override;
public:
@@ -102,7 +107,7 @@ bool WebAssemblyOptimizeLiveIntervals::runOnMachineFunction(
SplitLIs.clear();
}
- // In PrepareForLiveIntervals, we conservatively inserted IMPLICIT_DEF
+ // In FixIrreducibleControlFlow, we conservatively inserted IMPLICIT_DEF
// instructions to satisfy LiveIntervals' requirement that all uses be
// dominated by defs. Now that LiveIntervals has computed which of these
// defs are actually needed and which are dead, remove the dead ones.
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp
deleted file mode 100644
index 5682cadc1a64..000000000000
--- a/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-//===- WebAssemblyPrepareForLiveIntervals.cpp - Prepare for LiveIntervals -===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Fix up code to meet LiveInterval's requirements.
-///
-/// Some CodeGen passes don't preserve LiveInterval's requirements, because
-/// they run after register allocation and it isn't important. However,
-/// WebAssembly runs LiveIntervals in a late pass. This pass transforms code
-/// to meet LiveIntervals' requirements; primarily, it ensures that all
-/// virtual register uses have definitions (IMPLICIT_DEF definitions if
-/// nothing else).
-///
-//===----------------------------------------------------------------------===//
-
-#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
-#include "Utils/WebAssemblyUtilities.h"
-#include "WebAssembly.h"
-#include "WebAssemblyMachineFunctionInfo.h"
-#include "WebAssemblySubtarget.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/Passes.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace llvm;
-
-#define DEBUG_TYPE "wasm-prepare-for-live-intervals"
-
-namespace {
-class WebAssemblyPrepareForLiveIntervals final : public MachineFunctionPass {
-public:
- static char ID; // Pass identification, replacement for typeid
- WebAssemblyPrepareForLiveIntervals() : MachineFunctionPass(ID) {}
-
-private:
- StringRef getPassName() const override {
- return "WebAssembly Prepare For LiveIntervals";
- }
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesCFG();
- MachineFunctionPass::getAnalysisUsage(AU);
- }
-
- bool runOnMachineFunction(MachineFunction &MF) override;
-};
-} // end anonymous namespace
-
-char WebAssemblyPrepareForLiveIntervals::ID = 0;
-INITIALIZE_PASS(WebAssemblyPrepareForLiveIntervals, DEBUG_TYPE,
- "Fix up code for LiveIntervals", false, false)
-
-FunctionPass *llvm::createWebAssemblyPrepareForLiveIntervals() {
- return new WebAssemblyPrepareForLiveIntervals();
-}
-
-// Test whether the given register has an ARGUMENT def.
-static bool hasArgumentDef(unsigned Reg, const MachineRegisterInfo &MRI) {
- for (const auto &Def : MRI.def_instructions(Reg))
- if (WebAssembly::isArgument(Def.getOpcode()))
- return true;
- return false;
-}
-
-bool WebAssemblyPrepareForLiveIntervals::runOnMachineFunction(
- MachineFunction &MF) {
- LLVM_DEBUG({
- dbgs() << "********** Prepare For LiveIntervals **********\n"
- << "********** Function: " << MF.getName() << '\n';
- });
-
- bool Changed = false;
- MachineRegisterInfo &MRI = MF.getRegInfo();
- const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
- MachineBasicBlock &Entry = *MF.begin();
-
- assert(!mustPreserveAnalysisID(LiveIntervalsID) &&
- "LiveIntervals shouldn't be active yet!");
-
- // We don't preserve SSA form.
- MRI.leaveSSA();
-
- // BranchFolding and perhaps other passes don't preserve IMPLICIT_DEF
- // instructions. LiveIntervals requires that all paths to virtual register
- // uses provide a definition. Insert IMPLICIT_DEFs in the entry block to
- // conservatively satisfy this.
- //
- // TODO: This is fairly heavy-handed; find a better approach.
- //
- for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) {
- Register Reg = Register::index2VirtReg(I);
-
- // Skip unused registers.
- if (MRI.use_nodbg_empty(Reg))
- continue;
-
- // Skip registers that have an ARGUMENT definition.
- if (hasArgumentDef(Reg, MRI))
- continue;
-
- BuildMI(Entry, Entry.begin(), DebugLoc(),
- TII.get(WebAssembly::IMPLICIT_DEF), Reg);
- Changed = true;
- }
-
- // Move ARGUMENT_* instructions to the top of the entry block, so that their
- // liveness reflects the fact that these really are live-in values.
- for (MachineInstr &MI : llvm::make_early_inc_range(Entry)) {
- if (WebAssembly::isArgument(MI.getOpcode())) {
- MI.removeFromParent();
- Entry.insert(Entry.begin(), &MI);
- }
- }
-
- // Ok, we're now ready to run the LiveIntervals analysis again.
- MF.getProperties().set(MachineFunctionProperties::Property::TracksLiveness);
-
- return Changed;
-}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp
index 71f0bd28e1be..1e2bee7a5c73 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp
@@ -72,9 +72,6 @@ bool WebAssemblyReplacePhysRegs::runOnMachineFunction(MachineFunction &MF) {
assert(!mustPreserveAnalysisID(LiveIntervalsID) &&
"LiveIntervals shouldn't be active yet!");
- // We don't preserve SSA or liveness.
- MRI.leaveSSA();
- MRI.invalidateLiveness();
for (unsigned PReg = WebAssembly::NoRegister + 1;
PReg < WebAssembly::NUM_TARGET_REGS; ++PReg) {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.cpp
index 16e05150c64e..74af4c8873f7 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.cpp
@@ -44,7 +44,7 @@ SDValue WebAssemblySelectionDAGInfo::EmitTargetCodeForMemmove(
SDValue WebAssemblySelectionDAGInfo::EmitTargetCodeForMemset(
SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Val,
- SDValue Size, Align Alignment, bool IsVolatile,
+ SDValue Size, Align Alignment, bool IsVolatile, bool AlwaysInline,
MachinePointerInfo DstPtrInfo) const {
auto &ST = DAG.getMachineFunction().getSubtarget<WebAssemblySubtarget>();
if (!ST.hasBulkMemory())
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.h b/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.h
index f4d2132fd3af..fd517b238715 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.h
@@ -37,6 +37,7 @@ public:
SDValue EmitTargetCodeForMemset(SelectionDAG &DAG, const SDLoc &DL,
SDValue Chain, SDValue Op1, SDValue Op2,
SDValue Op3, Align Alignment, bool IsVolatile,
+ bool AlwaysInline,
MachinePointerInfo DstPtrInfo) const override;
};
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
index b553c8150652..780694980523 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
@@ -48,6 +48,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
bool HasMutableGlobals = false;
bool HasTailCall = false;
bool HasReferenceTypes = false;
+ bool HasExtendedConst = false;
/// What processor and OS we're targeting.
Triple TargetTriple;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index 482837178f3d..76f036358ae8 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -25,11 +25,12 @@
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Function.h"
+#include "llvm/InitializePasses.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Scalar.h"
-#include "llvm/Transforms/Scalar/LowerAtomic.h"
+#include "llvm/Transforms/Scalar/LowerAtomicPass.h"
#include "llvm/Transforms/Utils.h"
using namespace llvm;
@@ -56,13 +57,12 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyTarget() {
auto &PR = *PassRegistry::getPassRegistry();
initializeWebAssemblyAddMissingPrototypesPass(PR);
initializeWebAssemblyLowerEmscriptenEHSjLjPass(PR);
- initializeLowerGlobalDtorsPass(PR);
+ initializeLowerGlobalDtorsLegacyPassPass(PR);
initializeFixFunctionBitcastsPass(PR);
initializeOptimizeReturnedPass(PR);
initializeWebAssemblyArgumentMovePass(PR);
initializeWebAssemblySetP2AlignOperandsPass(PR);
initializeWebAssemblyReplacePhysRegsPass(PR);
- initializeWebAssemblyPrepareForLiveIntervalsPass(PR);
initializeWebAssemblyOptimizeLiveIntervalsPass(PR);
initializeWebAssemblyMemIntrinsicResultsPass(PR);
initializeWebAssemblyRegStackifyPass(PR);
@@ -87,7 +87,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyTarget() {
static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM,
const Triple &TT) {
- if (!RM.hasValue()) {
+ if (!RM) {
// Default to static relocation model. This should always be more optimial
// than PIC since the static linker can determine all global addresses and
// assume direct function calls.
@@ -203,11 +203,12 @@ public:
bool StrippedAtomics = false;
bool StrippedTLS = false;
- if (!Features[WebAssembly::FeatureAtomics])
+ if (!Features[WebAssembly::FeatureAtomics]) {
StrippedAtomics = stripAtomics(M);
-
- if (!Features[WebAssembly::FeatureBulkMemory])
StrippedTLS = stripThreadLocals(M);
+ } else if (!Features[WebAssembly::FeatureBulkMemory]) {
+ StrippedTLS |= stripThreadLocals(M);
+ }
if (StrippedAtomics && !StrippedTLS)
stripThreadLocals(M);
@@ -320,6 +321,7 @@ public:
FunctionPass *createTargetRegisterAllocator(bool) override;
void addIRPasses() override;
+ void addISelPrepare() override;
bool addInstSelector() override;
void addPostRegAlloc() override;
bool addGCPasses() override { return false; }
@@ -335,7 +337,7 @@ public:
} // end anonymous namespace
TargetTransformInfo
-WebAssemblyTargetMachine::getTargetTransformInfo(const Function &F) {
+WebAssemblyTargetMachine::getTargetTransformInfo(const Function &F) const {
return TargetTransformInfo(WebAssemblyTTIImpl(this, F));
}
@@ -407,17 +409,11 @@ static void basicCheckForEHAndSjLj(TargetMachine *TM) {
//===----------------------------------------------------------------------===//
void WebAssemblyPassConfig::addIRPasses() {
- // Lower atomics and TLS if necessary
- addPass(new CoalesceFeaturesAndStripAtomics(&getWebAssemblyTargetMachine()));
-
- // This is a no-op if atomics are not used in the module
- addPass(createAtomicExpandPass());
-
// Add signatures to prototype-less function declarations
addPass(createWebAssemblyAddMissingPrototypes());
// Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls.
- addPass(createWebAssemblyLowerGlobalDtors());
+ addPass(createLowerGlobalDtorsLegacyPass());
// Fix function bitcasts, as WebAssembly requires caller and callee signatures
// to match.
@@ -455,6 +451,16 @@ void WebAssemblyPassConfig::addIRPasses() {
TargetPassConfig::addIRPasses();
}
+void WebAssemblyPassConfig::addISelPrepare() {
+ // Lower atomics and TLS if necessary
+ addPass(new CoalesceFeaturesAndStripAtomics(&getWebAssemblyTargetMachine()));
+
+ // This is a no-op if atomics are not used in the module
+ addPass(createAtomicExpandPass());
+
+ TargetPassConfig::addISelPrepare();
+}
+
bool WebAssemblyPassConfig::addInstSelector() {
(void)TargetPassConfig::addInstSelector();
addPass(
@@ -517,9 +523,6 @@ void WebAssemblyPassConfig::addPreEmitPass() {
// Preparations and optimizations related to register stackification.
if (getOptLevel() != CodeGenOpt::None) {
- // LiveIntervals isn't commonly run this late. Re-establish preconditions.
- addPass(createWebAssemblyPrepareForLiveIntervals());
-
// Depend on LiveIntervals and perform some optimizations on it.
addPass(createWebAssemblyOptimizeLiveIntervals());
@@ -588,8 +591,7 @@ yaml::MachineFunctionInfo *WebAssemblyTargetMachine::convertFuncInfoToYAML(
bool WebAssemblyTargetMachine::parseMachineFunctionInfo(
const yaml::MachineFunctionInfo &MFI, PerFunctionMIParsingState &PFS,
SMDiagnostic &Error, SMRange &SourceRange) const {
- const auto &YamlMFI =
- reinterpret_cast<const yaml::WebAssemblyFunctionInfo &>(MFI);
+ const auto &YamlMFI = static_cast<const yaml::WebAssemblyFunctionInfo &>(MFI);
MachineFunction &MF = PFS.MF;
MF.getInfo<WebAssemblyFunctionInfo>()->initializeBaseYamlFields(YamlMFI);
return false;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h
index 29e968bfe8eb..5d5378f76567 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h
@@ -46,7 +46,7 @@ public:
return TLOF.get();
}
- TargetTransformInfo getTargetTransformInfo(const Function &F) override;
+ TargetTransformInfo getTargetTransformInfo(const Function &F) const override;
bool usesPhysRegsForValues() const override { return false; }
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp
index f1ebcbc6fc51..62f7155e794a 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp
@@ -139,3 +139,7 @@ void WebAssemblyTTIImpl::getUnrollingPreferences(
// becomes "fall through" to default value of 2.
UP.BEInsns = 2;
}
+
+bool WebAssemblyTTIImpl::supportsTailCalls() const {
+ return getST()->hasTailCall();
+}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h b/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h
index 50036f7f7e98..fde58a9587b6 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h
@@ -74,6 +74,8 @@ public:
bool areInlineCompatible(const Function *Caller,
const Function *Callee) const;
+
+ bool supportsTailCalls() const;
};
} // end namespace llvm