mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
Revert "[WebAssembly] Implementation of global.get/set for reftypes in LLVM IR"
This reverts commit 4facbf213c51e4add2e8c19b08d5e58ad71c72de. ``` ******************** FAIL: LLVM :: CodeGen/WebAssembly/funcref-call.ll (44466 of 44468) ******************** TEST 'LLVM :: CodeGen/WebAssembly/funcref-call.ll' FAILED ******************** Script: -- : 'RUN: at line 1'; /builddirs/llvm-project/build-Clang12/bin/llc < /repositories/llvm-project/llvm/test/CodeGen/WebAssembly/funcref-call.ll --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | /builddirs/llvm-project/build-Clang12/bin/FileCheck /repositories/llvm-project/llvm/test/CodeGen/WebAssembly/funcref-call.ll -- Exit Code: 2 Command Output (stderr): -- llc: /repositories/llvm-project/llvm/include/llvm/Support/LowLevelTypeImpl.h:44: static llvm::LLT llvm::LLT::scalar(unsigned int): Assertion `SizeInBits > 0 && "invalid scalar size"' failed. ```
This commit is contained in:
parent
e346ccc104
commit
5bd901b404
@ -350,7 +350,7 @@ public:
|
|||||||
/// Return the in-memory pointer type for the given address space, defaults to
|
/// Return the in-memory pointer type for the given address space, defaults to
|
||||||
/// the pointer type from the data layout. FIXME: The default needs to be
|
/// the pointer type from the data layout. FIXME: The default needs to be
|
||||||
/// removed once all the code is updated.
|
/// removed once all the code is updated.
|
||||||
virtual MVT getPointerMemTy(const DataLayout &DL, uint32_t AS = 0) const {
|
MVT getPointerMemTy(const DataLayout &DL, uint32_t AS = 0) const {
|
||||||
return MVT::getIntegerVT(DL.getPointerSizeInBits(AS));
|
return MVT::getIntegerVT(DL.getPointerSizeInBits(AS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,12 +120,6 @@ namespace llvm {
|
|||||||
return changeExtendedTypeToInteger();
|
return changeExtendedTypeToInteger();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test if the given EVT has zero size, this will fail if called on a
|
|
||||||
/// scalable type
|
|
||||||
bool isZeroSized() const {
|
|
||||||
return !isScalableVector() && getSizeInBits() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Test if the given EVT is simple (as opposed to being extended).
|
/// Test if the given EVT is simple (as opposed to being extended).
|
||||||
bool isSimple() const {
|
bool isSimple() const {
|
||||||
return V.SimpleTy != MVT::INVALID_SIMPLE_VALUE_TYPE;
|
return V.SimpleTy != MVT::INVALID_SIMPLE_VALUE_TYPE;
|
||||||
@ -213,9 +207,7 @@ namespace llvm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if the bit size is a multiple of 8.
|
/// Return true if the bit size is a multiple of 8.
|
||||||
bool isByteSized() const {
|
bool isByteSized() const { return getSizeInBits().isKnownMultipleOf(8); }
|
||||||
return !isZeroSized() && getSizeInBits().isKnownMultipleOf(8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return true if the size is a power-of-two number of bytes.
|
/// Return true if the size is a power-of-two number of bytes.
|
||||||
bool isRound() const {
|
bool isRound() const {
|
||||||
|
@ -6465,10 +6465,6 @@ bool CodeGenPrepare::optimizeLoadExt(LoadInst *Load) {
|
|||||||
|
|
||||||
EVT LoadResultVT = TLI->getValueType(*DL, Load->getType());
|
EVT LoadResultVT = TLI->getValueType(*DL, Load->getType());
|
||||||
unsigned BitWidth = LoadResultVT.getSizeInBits();
|
unsigned BitWidth = LoadResultVT.getSizeInBits();
|
||||||
// If the BitWidth is 0, do not try to optimize the type
|
|
||||||
if (BitWidth == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
APInt DemandBits(BitWidth, 0);
|
APInt DemandBits(BitWidth, 0);
|
||||||
APInt WidestAndBits(BitWidth, 0);
|
APInt WidestAndBits(BitWidth, 0);
|
||||||
|
|
||||||
|
@ -1180,7 +1180,7 @@ void MachineMemOperand::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
|||||||
<< "unknown-address";
|
<< "unknown-address";
|
||||||
}
|
}
|
||||||
MachineOperand::printOperandOffset(OS, getOffset());
|
MachineOperand::printOperandOffset(OS, getOffset());
|
||||||
if (getSize() > 0 && getAlign() != getSize())
|
if (getAlign() != getSize())
|
||||||
OS << ", align " << getAlign().value();
|
OS << ", align " << getAlign().value();
|
||||||
if (getAlign() != getBaseAlign())
|
if (getAlign() != getBaseAlign())
|
||||||
OS << ", basealign " << getBaseAlign().value();
|
OS << ", basealign " << getBaseAlign().value();
|
||||||
|
@ -23174,10 +23174,6 @@ bool DAGCombiner::parallelizeChainedStores(StoreSDNode *St) {
|
|||||||
if (BasePtr.getBase().isUndef())
|
if (BasePtr.getBase().isUndef())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Do not handle stores to opaque types
|
|
||||||
if (St->getMemoryVT().isZeroSized())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// BaseIndexOffset assumes that offsets are fixed-size, which
|
// BaseIndexOffset assumes that offsets are fixed-size, which
|
||||||
// is not valid for scalable vectors where the offsets are
|
// is not valid for scalable vectors where the offsets are
|
||||||
// scaled by `vscale`, so bail out early.
|
// scaled by `vscale`, so bail out early.
|
||||||
|
@ -1710,7 +1710,7 @@ bool TargetLoweringBase::allowsMemoryAccessForAlignment(
|
|||||||
// For example, the ABI alignment may change based on software platform while
|
// For example, the ABI alignment may change based on software platform while
|
||||||
// this function should only be affected by hardware implementation.
|
// this function should only be affected by hardware implementation.
|
||||||
Type *Ty = VT.getTypeForEVT(Context);
|
Type *Ty = VT.getTypeForEVT(Context);
|
||||||
if (VT.isZeroSized() || Alignment >= DL.getABITypeAlign(Ty)) {
|
if (Alignment >= DL.getABITypeAlign(Ty)) {
|
||||||
// Assume that an access that meets the ABI-specified alignment is fast.
|
// Assume that an access that meets the ABI-specified alignment is fast.
|
||||||
if (Fast != nullptr)
|
if (Fast != nullptr)
|
||||||
*Fast = true;
|
*Fast = true;
|
||||||
|
@ -198,10 +198,6 @@ Type *EVT::getTypeForEVT(LLVMContext &Context) const {
|
|||||||
case MVT::ppcf128: return Type::getPPC_FP128Ty(Context);
|
case MVT::ppcf128: return Type::getPPC_FP128Ty(Context);
|
||||||
case MVT::x86mmx: return Type::getX86_MMXTy(Context);
|
case MVT::x86mmx: return Type::getX86_MMXTy(Context);
|
||||||
case MVT::x86amx: return Type::getX86_AMXTy(Context);
|
case MVT::x86amx: return Type::getX86_AMXTy(Context);
|
||||||
case MVT::externref:
|
|
||||||
return PointerType::get(StructType::create(Context), 10);
|
|
||||||
case MVT::funcref:
|
|
||||||
return PointerType::get(StructType::create(Context), 20);
|
|
||||||
case MVT::v1i1:
|
case MVT::v1i1:
|
||||||
return FixedVectorType::get(Type::getInt1Ty(Context), 1);
|
return FixedVectorType::get(Type::getInt1Ty(Context), 1);
|
||||||
case MVT::v2i1:
|
case MVT::v2i1:
|
||||||
|
@ -116,31 +116,6 @@ MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(
|
|||||||
return Sym;
|
return Sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol(
|
|
||||||
MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
|
|
||||||
StringRef Name = "__funcref_call_table";
|
|
||||||
MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
|
|
||||||
if (Sym) {
|
|
||||||
if (!Sym->isFunctionTable())
|
|
||||||
Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
|
|
||||||
} else {
|
|
||||||
Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
|
|
||||||
|
|
||||||
// Setting Weak ensure only one table is left after linking when multiple
|
|
||||||
// modules define the table.
|
|
||||||
Sym->setWeak(true);
|
|
||||||
|
|
||||||
wasm::WasmLimits Limits = {0, 1, 1};
|
|
||||||
wasm::WasmTableType TableType = {wasm::WASM_TYPE_FUNCREF, Limits};
|
|
||||||
Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
|
|
||||||
Sym->setTableType(TableType);
|
|
||||||
}
|
|
||||||
// MVP object files can't have symtab entries for tables.
|
|
||||||
if (!(Subtarget && Subtarget->hasReferenceTypes()))
|
|
||||||
Sym->setOmitFromLinkingSection();
|
|
||||||
return Sym;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find a catch instruction from an EH pad.
|
// Find a catch instruction from an EH pad.
|
||||||
MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {
|
MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {
|
||||||
assert(EHPad->isEHPad());
|
assert(EHPad->isEHPad());
|
||||||
|
@ -68,12 +68,6 @@ MCSymbolWasm *
|
|||||||
getOrCreateFunctionTableSymbol(MCContext &Ctx,
|
getOrCreateFunctionTableSymbol(MCContext &Ctx,
|
||||||
const WebAssemblySubtarget *Subtarget);
|
const WebAssemblySubtarget *Subtarget);
|
||||||
|
|
||||||
/// Returns the __funcref_call_table, for use in funcref calls when lowered to
|
|
||||||
/// table.set + call_indirect.
|
|
||||||
MCSymbolWasm *
|
|
||||||
getOrCreateFuncrefCallTableSymbol(MCContext &Ctx,
|
|
||||||
const WebAssemblySubtarget *Subtarget);
|
|
||||||
|
|
||||||
/// Find a catch instruction from an EH pad. Returns null if no catch
|
/// Find a catch instruction from an EH pad. Returns null if no catch
|
||||||
/// instruction found or the catch is in an invalid location.
|
/// instruction found or the catch is in an invalid location.
|
||||||
MachineInstr *findCatch(MachineBasicBlock *EHPad);
|
MachineInstr *findCatch(MachineBasicBlock *EHPad);
|
||||||
|
@ -130,12 +130,9 @@ private:
|
|||||||
case MVT::i64:
|
case MVT::i64:
|
||||||
case MVT::f32:
|
case MVT::f32:
|
||||||
case MVT::f64:
|
case MVT::f64:
|
||||||
return VT;
|
|
||||||
case MVT::funcref:
|
case MVT::funcref:
|
||||||
case MVT::externref:
|
case MVT::externref:
|
||||||
if (Subtarget->hasReferenceTypes())
|
return VT;
|
||||||
return VT;
|
|
||||||
break;
|
|
||||||
case MVT::f16:
|
case MVT::f16:
|
||||||
return MVT::f32;
|
return MVT::f32;
|
||||||
case MVT::v16i8:
|
case MVT::v16i8:
|
||||||
|
@ -48,4 +48,3 @@ HANDLE_NODETYPE(MEMORY_FILL)
|
|||||||
HANDLE_MEM_NODETYPE(LOAD_SPLAT)
|
HANDLE_MEM_NODETYPE(LOAD_SPLAT)
|
||||||
HANDLE_MEM_NODETYPE(GLOBAL_GET)
|
HANDLE_MEM_NODETYPE(GLOBAL_GET)
|
||||||
HANDLE_MEM_NODETYPE(GLOBAL_SET)
|
HANDLE_MEM_NODETYPE(GLOBAL_SET)
|
||||||
HANDLE_MEM_NODETYPE(TABLE_SET)
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
||||||
#include "WebAssembly.h"
|
#include "WebAssembly.h"
|
||||||
#include "WebAssemblyISelLowering.h"
|
|
||||||
#include "WebAssemblyTargetMachine.h"
|
#include "WebAssemblyTargetMachine.h"
|
||||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||||
#include "llvm/CodeGen/SelectionDAGISel.h"
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
||||||
@ -48,32 +47,11 @@ public:
|
|||||||
return "WebAssembly Instruction Selection";
|
return "WebAssembly Instruction Selection";
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkForInvalidNodes(const Function &F) {
|
|
||||||
// This function will check for uses of ptrtoint on reference types and
|
|
||||||
// report a fatal error if these are found.
|
|
||||||
for (const BasicBlock &BB : F) {
|
|
||||||
for (const Instruction &I : BB) {
|
|
||||||
if (const PtrToIntInst *PTI = dyn_cast<const PtrToIntInst>(&I)) {
|
|
||||||
const Value *V = PTI->getPointerOperand();
|
|
||||||
if (WebAssemblyTargetLowering::isFuncrefType(V->getType()) ||
|
|
||||||
WebAssemblyTargetLowering::isExternrefType(V->getType()))
|
|
||||||
report_fatal_error("ptrtoint not allowed on reference types");
|
|
||||||
} else if (const IntToPtrInst *ITP = dyn_cast<const IntToPtrInst>(&I)) {
|
|
||||||
if (WebAssemblyTargetLowering::isFuncrefType(ITP->getDestTy()) ||
|
|
||||||
WebAssemblyTargetLowering::isExternrefType(ITP->getDestTy()))
|
|
||||||
report_fatal_error("inttoptr not allowed on reference types");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool runOnMachineFunction(MachineFunction &MF) override {
|
bool runOnMachineFunction(MachineFunction &MF) override {
|
||||||
LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"
|
LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"
|
||||||
"********** Function: "
|
"********** Function: "
|
||||||
<< MF.getName() << '\n');
|
<< MF.getName() << '\n');
|
||||||
|
|
||||||
checkForInvalidNodes(MF.getFunction());
|
|
||||||
|
|
||||||
Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
|
Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
|
||||||
|
|
||||||
return SelectionDAGISel::runOnMachineFunction(MF);
|
return SelectionDAGISel::runOnMachineFunction(MF);
|
||||||
@ -85,7 +63,6 @@ public:
|
|||||||
|
|
||||||
bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
|
bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
|
||||||
std::vector<SDValue> &OutOps) override;
|
std::vector<SDValue> &OutOps) override;
|
||||||
bool SelectExternRefAddr(const SDValue &Addr, const SDValue &Base);
|
|
||||||
|
|
||||||
// Include the pieces autogenerated from the target description.
|
// Include the pieces autogenerated from the target description.
|
||||||
#include "WebAssemblyGenDAGISel.inc"
|
#include "WebAssemblyGenDAGISel.inc"
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
#include "WebAssemblyISelLowering.h"
|
#include "WebAssemblyISelLowering.h"
|
||||||
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
||||||
#include "Utils/WebAssemblyTypeUtilities.h"
|
|
||||||
#include "Utils/WebAssemblyUtilities.h"
|
#include "Utils/WebAssemblyUtilities.h"
|
||||||
#include "WebAssemblyMachineFunctionInfo.h"
|
#include "WebAssemblyMachineFunctionInfo.h"
|
||||||
#include "WebAssemblySubtarget.h"
|
#include "WebAssemblySubtarget.h"
|
||||||
@ -67,10 +66,6 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
|
|||||||
addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
|
addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
|
||||||
addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
|
addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
|
||||||
}
|
}
|
||||||
if (Subtarget->hasReferenceTypes()) {
|
|
||||||
addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass);
|
|
||||||
addRegisterClass(MVT::funcref, &WebAssembly::FUNCREFRegClass);
|
|
||||||
}
|
|
||||||
// Compute derived properties from the register classes.
|
// Compute derived properties from the register classes.
|
||||||
computeRegisterProperties(Subtarget->getRegisterInfo());
|
computeRegisterProperties(Subtarget->getRegisterInfo());
|
||||||
|
|
||||||
@ -87,12 +82,6 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
|
|||||||
setOperationAction(ISD::STORE, T, Custom);
|
setOperationAction(ISD::STORE, T, Custom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Subtarget->hasReferenceTypes()) {
|
|
||||||
for (auto T : {MVT::externref, MVT::funcref}) {
|
|
||||||
setOperationAction(ISD::LOAD, T, Custom);
|
|
||||||
setOperationAction(ISD::STORE, T, Custom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
|
setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
|
||||||
setOperationAction(ISD::GlobalTLSAddress, MVTPtr, Custom);
|
setOperationAction(ISD::GlobalTLSAddress, MVTPtr, Custom);
|
||||||
@ -479,16 +468,6 @@ LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
|
|||||||
bool IsIndirect = CallParams.getOperand(0).isReg();
|
bool IsIndirect = CallParams.getOperand(0).isReg();
|
||||||
bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS;
|
bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS;
|
||||||
|
|
||||||
bool IsFuncrefCall = false;
|
|
||||||
if (IsIndirect) {
|
|
||||||
Register Reg = CallParams.getOperand(0).getReg();
|
|
||||||
const MachineFunction *MF = BB->getParent();
|
|
||||||
const MachineRegisterInfo &MRI = MF->getRegInfo();
|
|
||||||
const TargetRegisterClass *TRC = MRI.getRegClass(Reg);
|
|
||||||
IsFuncrefCall = (TRC == &WebAssembly::FUNCREFRegClass);
|
|
||||||
assert(!IsFuncrefCall || Subtarget->hasReferenceTypes());
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned CallOp;
|
unsigned CallOp;
|
||||||
if (IsIndirect && IsRetCall) {
|
if (IsIndirect && IsRetCall) {
|
||||||
CallOp = WebAssembly::RET_CALL_INDIRECT;
|
CallOp = WebAssembly::RET_CALL_INDIRECT;
|
||||||
@ -532,11 +511,8 @@ LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
|
|||||||
// Placeholder for the type index.
|
// Placeholder for the type index.
|
||||||
MIB.addImm(0);
|
MIB.addImm(0);
|
||||||
// The table into which this call_indirect indexes.
|
// The table into which this call_indirect indexes.
|
||||||
MCSymbolWasm *Table = IsFuncrefCall
|
MCSymbolWasm *Table =
|
||||||
? WebAssembly::getOrCreateFuncrefCallTableSymbol(
|
WebAssembly::getOrCreateFunctionTableSymbol(MF.getContext(), Subtarget);
|
||||||
MF.getContext(), Subtarget)
|
|
||||||
: WebAssembly::getOrCreateFunctionTableSymbol(
|
|
||||||
MF.getContext(), Subtarget);
|
|
||||||
if (Subtarget->hasReferenceTypes()) {
|
if (Subtarget->hasReferenceTypes()) {
|
||||||
MIB.addSym(Table);
|
MIB.addSym(Table);
|
||||||
} else {
|
} else {
|
||||||
@ -555,39 +531,6 @@ LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
|
|||||||
CallParams.eraseFromParent();
|
CallParams.eraseFromParent();
|
||||||
CallResults.eraseFromParent();
|
CallResults.eraseFromParent();
|
||||||
|
|
||||||
// If this is a funcref call, to avoid hidden GC roots, we need to clear the
|
|
||||||
// table slot with ref.null upon call_indirect return.
|
|
||||||
//
|
|
||||||
// This generates the following code, which comes right after a call_indirect
|
|
||||||
// of a funcref:
|
|
||||||
//
|
|
||||||
// i32.const 0
|
|
||||||
// ref.null func
|
|
||||||
// table.set __funcref_call_table
|
|
||||||
if (IsIndirect && IsFuncrefCall) {
|
|
||||||
MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol(
|
|
||||||
MF.getContext(), Subtarget);
|
|
||||||
Register RegZero =
|
|
||||||
MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
|
|
||||||
MachineInstr *Const0 =
|
|
||||||
BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
|
|
||||||
BB->insertAfter(MIB.getInstr()->getIterator(), Const0);
|
|
||||||
|
|
||||||
Register RegFuncref =
|
|
||||||
MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass);
|
|
||||||
MachineInstr *RefNull =
|
|
||||||
BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref)
|
|
||||||
.addImm(static_cast<int32_t>(WebAssembly::HeapType::Funcref));
|
|
||||||
BB->insertAfter(Const0->getIterator(), RefNull);
|
|
||||||
|
|
||||||
MachineInstr *TableSet =
|
|
||||||
BuildMI(MF, DL, TII.get(WebAssembly::TABLE_SET_FUNCREF))
|
|
||||||
.addSym(Table)
|
|
||||||
.addReg(RegZero)
|
|
||||||
.addReg(RegFuncref);
|
|
||||||
BB->insertAfter(RefNull->getIterator(), TableSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
return BB;
|
return BB;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1111,33 +1054,6 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
|
|||||||
InTys.push_back(In.VT);
|
InTys.push_back(In.VT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lastly, if this is a call to a funcref we need to add an instruction
|
|
||||||
// table.set to the chain and transform the call.
|
|
||||||
if (CLI.CB && isFuncrefType(CLI.CB->getCalledOperand()->getType())) {
|
|
||||||
// In the absence of function references proposal where a funcref call is
|
|
||||||
// lowered to call_ref, using reference types we generate a table.set to set
|
|
||||||
// the funcref to a special table used solely for this purpose, followed by
|
|
||||||
// a call_indirect. Here we just generate the table set, and return the
|
|
||||||
// SDValue of the table.set so that LowerCall can finalize the lowering by
|
|
||||||
// generating the call_indirect.
|
|
||||||
SDValue Chain = Ops[0];
|
|
||||||
|
|
||||||
MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol(
|
|
||||||
MF.getContext(), Subtarget);
|
|
||||||
SDValue Sym = DAG.getMCSymbol(Table, PtrVT);
|
|
||||||
SDValue TableSlot = DAG.getConstant(0, DL, MVT::i32);
|
|
||||||
SDValue TableSetOps[] = {Chain, Sym, TableSlot, Callee};
|
|
||||||
SDValue TableSet = DAG.getMemIntrinsicNode(
|
|
||||||
WebAssemblyISD::TABLE_SET, DL, DAG.getVTList(MVT::Other), TableSetOps,
|
|
||||||
MVT::funcref,
|
|
||||||
// Machine Mem Operand args
|
|
||||||
MachinePointerInfo(WasmAddressSpace::FUNCREF),
|
|
||||||
CLI.CB->getCalledOperand()->getPointerAlignment(DAG.getDataLayout()),
|
|
||||||
MachineMemOperand::MOStore);
|
|
||||||
|
|
||||||
Ops[0] = TableSet; // The new chain is the TableSet itself
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CLI.IsTailCall) {
|
if (CLI.IsTailCall) {
|
||||||
// ret_calls do not return values to the current frame
|
// ret_calls do not return values to the current frame
|
||||||
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
||||||
@ -1369,16 +1285,6 @@ static Optional<unsigned> IsWebAssemblyLocal(SDValue Op, SelectionDAG &DAG) {
|
|||||||
return WebAssemblyFrameLowering::getLocalForStackObject(MF, FI->getIndex());
|
return WebAssemblyFrameLowering::getLocalForStackObject(MF, FI->getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebAssemblyTargetLowering::isFuncrefType(const Type *Ty) {
|
|
||||||
return isa<PointerType>(Ty) &&
|
|
||||||
Ty->getPointerAddressSpace() == WasmAddressSpace::FUNCREF;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WebAssemblyTargetLowering::isExternrefType(const Type *Ty) {
|
|
||||||
return isa<PointerType>(Ty) &&
|
|
||||||
Ty->getPointerAddressSpace() == WasmAddressSpace::EXTERNREF;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op,
|
SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op,
|
||||||
SelectionDAG &DAG) const {
|
SelectionDAG &DAG) const {
|
||||||
SDLoc DL(Op);
|
SDLoc DL(Op);
|
||||||
|
@ -45,36 +45,6 @@ public:
|
|||||||
WebAssemblyTargetLowering(const TargetMachine &TM,
|
WebAssemblyTargetLowering(const TargetMachine &TM,
|
||||||
const WebAssemblySubtarget &STI);
|
const WebAssemblySubtarget &STI);
|
||||||
|
|
||||||
enum WasmAddressSpace : unsigned {
|
|
||||||
// WebAssembly uses the following address spaces:
|
|
||||||
// AS 0 : is the default address space for values in linear memory
|
|
||||||
DEFAULT = 0,
|
|
||||||
// AS 1 : is a non-integral address space for global variables
|
|
||||||
GLOBAL = 1,
|
|
||||||
// AS 10 : is a non-integral address space for externref values
|
|
||||||
EXTERNREF = 10,
|
|
||||||
// AS 20 : is a non-integral address space for funcref values
|
|
||||||
FUNCREF = 20,
|
|
||||||
};
|
|
||||||
|
|
||||||
MVT getPointerTy(const DataLayout &DL, uint32_t AS = 0) const override {
|
|
||||||
if (AS == WasmAddressSpace::EXTERNREF)
|
|
||||||
return MVT::externref;
|
|
||||||
if (AS == WasmAddressSpace::FUNCREF)
|
|
||||||
return MVT::funcref;
|
|
||||||
return TargetLowering::getPointerTy(DL, AS);
|
|
||||||
}
|
|
||||||
MVT getPointerMemTy(const DataLayout &DL, uint32_t AS = 0) const override {
|
|
||||||
if (AS == WasmAddressSpace::EXTERNREF)
|
|
||||||
return MVT::externref;
|
|
||||||
if (AS == WasmAddressSpace::FUNCREF)
|
|
||||||
return MVT::funcref;
|
|
||||||
return TargetLowering::getPointerMemTy(DL, AS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isFuncrefType(const Type *Ty);
|
|
||||||
static bool isExternrefType(const Type *Ty);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Keep a pointer to the WebAssemblySubtarget around so that we can make the
|
/// Keep a pointer to the WebAssemblySubtarget around so that we can make the
|
||||||
/// right decision when generating code for different targets.
|
/// right decision when generating code for different targets.
|
||||||
|
@ -11,16 +11,15 @@
|
|||||||
/// Instructions that handle tables
|
/// Instructions that handle tables
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
|
||||||
multiclass TABLE<WebAssemblyRegClass rt> {
|
multiclass TABLE<WebAssemblyRegClass rt> {
|
||||||
let mayLoad = 1 in
|
defm TABLE_GET_#rt : I<(outs rt:$res), (ins table32_op:$table),
|
||||||
defm TABLE_GET_#rt : I<(outs rt:$res), (ins table32_op:$table, I32:$i),
|
|
||||||
(outs), (ins table32_op:$table),
|
(outs), (ins table32_op:$table),
|
||||||
[],
|
[],
|
||||||
"table.get\t$res, $table, $i",
|
"table.get\t$res, $table",
|
||||||
"table.get\t$table",
|
"table.get\t$table",
|
||||||
0x25>;
|
0x25>;
|
||||||
|
|
||||||
let mayStore = 1 in
|
|
||||||
defm TABLE_SET_#rt : I<(outs), (ins table32_op:$table, I32:$i, rt:$val),
|
defm TABLE_SET_#rt : I<(outs), (ins table32_op:$table, I32:$i, rt:$val),
|
||||||
(outs), (ins table32_op:$table),
|
(outs), (ins table32_op:$table),
|
||||||
[],
|
[],
|
||||||
@ -47,17 +46,6 @@ multiclass TABLE<WebAssemblyRegClass rt> {
|
|||||||
defm "" : TABLE<FUNCREF>, Requires<[HasReferenceTypes]>;
|
defm "" : TABLE<FUNCREF>, Requires<[HasReferenceTypes]>;
|
||||||
defm "" : TABLE<EXTERNREF>, Requires<[HasReferenceTypes]>;
|
defm "" : TABLE<EXTERNREF>, Requires<[HasReferenceTypes]>;
|
||||||
|
|
||||||
def wasm_table_set_t : SDTypeProfile<0, 3, []>;
|
|
||||||
def wasm_table_set : SDNode<"WebAssemblyISD::TABLE_SET", wasm_table_set_t,
|
|
||||||
[SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
|
|
||||||
|
|
||||||
def : Pat<(wasm_table_set i32:$table, i32:$idx, funcref:$r),
|
|
||||||
(TABLE_SET_FUNCREF i32:$table, i32:$idx, funcref:$r)>,
|
|
||||||
Requires<[HasReferenceTypes]>;
|
|
||||||
def : Pat<(wasm_table_set i32:$table, i32:$idx, externref:$r),
|
|
||||||
(TABLE_SET_EXTERNREF i32:$table, i32:$idx, externref:$r)>,
|
|
||||||
Requires<[HasReferenceTypes]>;
|
|
||||||
|
|
||||||
defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table),
|
defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table),
|
||||||
(outs), (ins table32_op:$table),
|
(outs), (ins table32_op:$table),
|
||||||
[],
|
[],
|
||||||
|
@ -217,10 +217,6 @@ static wasm::ValType getType(const TargetRegisterClass *RC) {
|
|||||||
return wasm::ValType::F64;
|
return wasm::ValType::F64;
|
||||||
if (RC == &WebAssembly::V128RegClass)
|
if (RC == &WebAssembly::V128RegClass)
|
||||||
return wasm::ValType::V128;
|
return wasm::ValType::V128;
|
||||||
if (RC == &WebAssembly::EXTERNREFRegClass)
|
|
||||||
return wasm::ValType::EXTERNREF;
|
|
||||||
if (RC == &WebAssembly::FUNCREFRegClass)
|
|
||||||
return wasm::ValType::FUNCREF;
|
|
||||||
llvm_unreachable("Unexpected register class");
|
llvm_unreachable("Unexpected register class");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,8 +121,8 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine(
|
|||||||
Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT)
|
Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT)
|
||||||
: LLVMTargetMachine(T,
|
: LLVMTargetMachine(T,
|
||||||
TT.isArch64Bit()
|
TT.isArch64Bit()
|
||||||
? "e-m:e-p:64:64-i64:64-n32:64-S128-ni:1:10:20"
|
? "e-m:e-p:64:64-i64:64-n32:64-S128-ni:1"
|
||||||
: "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20",
|
: "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1",
|
||||||
TT, CPU, FS, Options, getEffectiveRelocModel(RM, TT),
|
TT, CPU, FS, Options, getEffectiveRelocModel(RM, TT),
|
||||||
getEffectiveCodeModel(CM, CodeModel::Large), OL),
|
getEffectiveCodeModel(CM, CodeModel::Large), OL),
|
||||||
TLOF(new WebAssemblyTargetObjectFile()) {
|
TLOF(new WebAssemblyTargetObjectFile()) {
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
|
|
||||||
|
|
||||||
%extern = type opaque
|
|
||||||
%externref = type %extern addrspace(10)* ;; addrspace 10 is nonintegral
|
|
||||||
|
|
||||||
@externref_global = local_unnamed_addr addrspace(1) global %externref undef
|
|
||||||
|
|
||||||
define %externref @return_externref_global() {
|
|
||||||
;; this generates a global.get of @externref_global
|
|
||||||
%ref = load %externref, %externref addrspace(1)* @externref_global
|
|
||||||
ret %externref %ref
|
|
||||||
}
|
|
||||||
|
|
||||||
; CHECK-LABEL: return_externref_global:
|
|
||||||
; CHECK-NEXT: functype return_externref_global () -> (externref)
|
|
||||||
; CHECK-NEXT: global.get externref_global
|
|
||||||
; CHECK-NEXT: end_function
|
|
||||||
|
|
||||||
; CHECK: .globl externref_global
|
|
@ -1,20 +0,0 @@
|
|||||||
; RUN: llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s | FileCheck %s
|
|
||||||
|
|
||||||
%extern = type opaque
|
|
||||||
%externref = type %extern addrspace(10)* ;; addrspace 10 is nonintegral
|
|
||||||
|
|
||||||
@externref_global = local_unnamed_addr addrspace(1) global %externref undef
|
|
||||||
|
|
||||||
define void @set_externref_global(%externref %g) {
|
|
||||||
;; this generates a global.set of @externref.global
|
|
||||||
store %externref %g, %externref addrspace(1)* @externref_global
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
; CHECK-LABEL: set_externref_global:
|
|
||||||
; CHECK-NEXT: functype set_externref_global (externref) -> ()
|
|
||||||
; CHECK-NEXT: local.get 0
|
|
||||||
; CHECK-NEXT: global.set externref_global
|
|
||||||
; CHECK-NEXT: end_function
|
|
||||||
|
|
||||||
; CHECK: .globl externref_global
|
|
@ -1,11 +0,0 @@
|
|||||||
; RUN: not --crash llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
|
|
||||||
|
|
||||||
%extern = type opaque
|
|
||||||
%externref = type %extern addrspace(10)*
|
|
||||||
|
|
||||||
define %externref @int_to_externref(i32 %i) {
|
|
||||||
%ref = inttoptr i32 %i to %externref
|
|
||||||
ret %externref %ref
|
|
||||||
}
|
|
||||||
|
|
||||||
; CHECK-ERROR: LLVM ERROR: inttoptr not allowed on reference types
|
|
@ -1,11 +0,0 @@
|
|||||||
; RUN: not --crash llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
|
|
||||||
|
|
||||||
%extern = type opaque
|
|
||||||
%externref = type %extern addrspace(10)*
|
|
||||||
|
|
||||||
define i32 @externref_to_int(%externref %ref) {
|
|
||||||
%i = ptrtoint %externref %ref to i32
|
|
||||||
ret i32 %i
|
|
||||||
}
|
|
||||||
|
|
||||||
; CHECK-ERROR: LLVM ERROR: ptrtoint not allowed on reference types
|
|
@ -1,21 +0,0 @@
|
|||||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
|
|
||||||
|
|
||||||
%extern = type opaque
|
|
||||||
%externref = type %extern addrspace(10)* ;; addrspace 10 is nonintegral
|
|
||||||
|
|
||||||
@externref_global = local_unnamed_addr addrspace(1) global %externref undef
|
|
||||||
|
|
||||||
define %extern @return_extern_undef() {
|
|
||||||
; Returning a ref.null or an uninitialized externref would make
|
|
||||||
; more sense if the return type would be %externref. However, in
|
|
||||||
; this case this is an %extern value, which really is an opaque
|
|
||||||
; type and should never really happen.
|
|
||||||
ret %extern undef
|
|
||||||
}
|
|
||||||
|
|
||||||
; CHECK-LABEL: return_extern_undef:
|
|
||||||
; CHECK-NEXT: functype return_extern_undef () -> ()
|
|
||||||
; CHECK-NEXT: end_function
|
|
||||||
|
|
||||||
; CHECK: .globl externref_global
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
; RUN: not llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
|
|
||||||
|
|
||||||
%extern = type opaque
|
|
||||||
%externref = type %extern addrspace(10)*
|
|
||||||
|
|
||||||
define void @load_extern(%externref %ref) {
|
|
||||||
%e = load %extern, %externref %ref
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
; CHECK-ERROR: error: loading unsized types is not allowed
|
|
@ -1,11 +0,0 @@
|
|||||||
; RUN: not llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
|
|
||||||
|
|
||||||
%extern = type opaque
|
|
||||||
%externref = type %extern addrspace(10)*
|
|
||||||
|
|
||||||
define void @store_extern(%externref %ref) {
|
|
||||||
store %extern undef, %externref %ref
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
; CHECK-ERROR: error: storing unsized types is not allowed
|
|
@ -1,23 +0,0 @@
|
|||||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
|
|
||||||
|
|
||||||
%func = type void ()
|
|
||||||
%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
|
|
||||||
|
|
||||||
define void @call_funcref(%funcref %ref) {
|
|
||||||
call addrspace(20) void %ref()
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
; CHECK-LABEL: call_funcref:
|
|
||||||
; CHECK-NEXT: functype call_funcref (funcref) -> ()
|
|
||||||
; CHECK-NEXT: i32.const 0
|
|
||||||
; CHECK-NEXT: local.get 0
|
|
||||||
; CHECK-NEXT: table.set __funcref_call_table
|
|
||||||
; CHECK-NEXT: local.get 0
|
|
||||||
; CHECK-NEXT: call_indirect __funcref_call_table, () -> ()
|
|
||||||
; CHECK-NEXT: i32.const 0
|
|
||||||
; CHECK-NEXT: ref.null func
|
|
||||||
; CHECK-NEXT: table.set __funcref_call_table
|
|
||||||
; CHECK-NEXT: end_function
|
|
||||||
|
|
||||||
; CHECK: .tabletype __funcref_call_table, funcref
|
|
@ -1,19 +0,0 @@
|
|||||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
|
|
||||||
|
|
||||||
%func = type opaque
|
|
||||||
%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
|
|
||||||
|
|
||||||
@funcref_global = local_unnamed_addr addrspace(1) global %funcref undef
|
|
||||||
|
|
||||||
define %funcref @return_funcref_global() {
|
|
||||||
;; this generates a global.get of @funcref_global
|
|
||||||
%ref = load %funcref, %funcref addrspace(1)* @funcref_global
|
|
||||||
ret %funcref %ref
|
|
||||||
}
|
|
||||||
|
|
||||||
; CHECK-LABEL: return_funcref_global:
|
|
||||||
; CHECK-NEXT: .functype return_funcref_global () -> (funcref)
|
|
||||||
; CHECK-NEXT: global.get funcref_global
|
|
||||||
; CHECK-NEXT: end_function
|
|
||||||
|
|
||||||
; CHECK: .globl funcref_global
|
|
@ -1,20 +0,0 @@
|
|||||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
|
|
||||||
|
|
||||||
%func = type opaque
|
|
||||||
%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
|
|
||||||
|
|
||||||
@funcref_global = local_unnamed_addr addrspace(1) global %funcref undef
|
|
||||||
|
|
||||||
define void @set_funcref_global(%funcref %g) {
|
|
||||||
;; this generates a global.set of @funcref_global
|
|
||||||
store %funcref %g, %funcref addrspace(1)* @funcref_global
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
; CHECK-LABEL: set_funcref_global:
|
|
||||||
; CHECK-NEXT: functype set_funcref_global (funcref) -> ()
|
|
||||||
; CHECK-NEXT: local.get 0
|
|
||||||
; CHECK-NEXT: global.set funcref_global
|
|
||||||
; CHECK-NEXT: end_function
|
|
||||||
|
|
||||||
; CHECK: .globl funcref_global
|
|
Loading…
Reference in New Issue
Block a user