diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2022-02-05 18:04:23 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2022-02-05 18:05:05 +0000 |
| commit | ecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (patch) | |
| tree | 3a4038f3b7bafaeade9fd6146ea8021237616657 /llvm/lib/Target/WebAssembly | |
| parent | 6f8fc217eaa12bf657be1c6468ed9938d10168b3 (diff) | |
Diffstat (limited to 'llvm/lib/Target/WebAssembly')
11 files changed, 133 insertions, 104 deletions
diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp index 0412e524f800..0f1655718481 100644 --- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp @@ -167,3 +167,41 @@ wasm::ValType WebAssembly::regClassToValType(unsigned RC) { llvm_unreachable("unexpected type"); } } + +void WebAssembly::wasmSymbolSetType(MCSymbolWasm *Sym, const Type *GlobalVT, + const SmallVector<MVT, 1> &VTs) { + assert(!Sym->getType()); + + // Tables are represented as Arrays in LLVM IR therefore + // they reach this point as aggregate Array types with an element type + // that is a reference type. + wasm::ValType Type; + bool IsTable = false; + if (GlobalVT->isArrayTy() && + WebAssembly::isRefType(GlobalVT->getArrayElementType())) { + MVT VT; + IsTable = true; + switch (GlobalVT->getArrayElementType()->getPointerAddressSpace()) { + case WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF: + VT = MVT::funcref; + break; + case WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF: + VT = MVT::externref; + break; + default: + report_fatal_error("unhandled address space type"); + } + Type = WebAssembly::toValType(VT); + } else if (VTs.size() == 1) { + Type = WebAssembly::toValType(VTs[0]); + } else + report_fatal_error("Aggregate globals not yet implemented"); + + if (IsTable) { + Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); + Sym->setTableType(Type); + } else { + Sym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); + Sym->setGlobalType(wasm::WasmGlobalType{uint8_t(Type), /*Mutable=*/true}); + } +} diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h index 042d51c7d6cb..cdb95d48398d 100644 --- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h +++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h @@ -17,6 +17,8 @@ #include "llvm/ADT/Optional.h" #include "llvm/BinaryFormat/Wasm.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/MC/MCSymbolWasm.h" #include "llvm/Support/MachineValueType.h" namespace llvm { @@ -41,6 +43,43 @@ enum class BlockType : unsigned { Multivalue = 0xffff, }; +enum WasmAddressSpace : unsigned { + // Default address space, for pointers to linear memory (stack, heap, data). + WASM_ADDRESS_SPACE_DEFAULT = 0, + // A non-integral address space for pointers to named objects outside of + // linear memory: WebAssembly globals or WebAssembly locals. Loads and stores + // to these pointers are lowered to global.get / global.set or local.get / + // local.set, as appropriate. + WASM_ADDRESS_SPACE_VAR = 1, + // A non-integral address space for externref values + WASM_ADDRESS_SPACE_EXTERNREF = 10, + // A non-integral address space for funcref values + WASM_ADDRESS_SPACE_FUNCREF = 20, +}; + +inline bool isDefaultAddressSpace(unsigned AS) { + return AS == WASM_ADDRESS_SPACE_DEFAULT; +} +inline bool isWasmVarAddressSpace(unsigned AS) { + return AS == WASM_ADDRESS_SPACE_VAR; +} +inline bool isValidAddressSpace(unsigned AS) { + return isDefaultAddressSpace(AS) || isWasmVarAddressSpace(AS); +} +inline bool isFuncrefType(const Type *Ty) { + return isa<PointerType>(Ty) && + Ty->getPointerAddressSpace() == + WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF; +} +inline bool isExternrefType(const Type *Ty) { + return isa<PointerType>(Ty) && + Ty->getPointerAddressSpace() == + WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF; +} +inline bool isRefType(const Type *Ty) { + return isFuncrefType(Ty) || isExternrefType(Ty); +} + // Convert StringRef to ValType / HealType / BlockType Optional<wasm::ValType> parseType(StringRef Type); @@ -68,6 +107,10 @@ wasm::ValType toValType(MVT Type); // Convert a register class to a wasm ValType. wasm::ValType regClassToValType(unsigned RC); +/// Sets a Wasm Symbol Type. +void wasmSymbolSetType(MCSymbolWasm *Sym, const Type *GlobalVT, + const SmallVector<MVT, 1> &VTs); + } // end namespace WebAssembly } // end namespace llvm diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.h index 57e40f6cd8d7..cdfc758db7ac 100644 --- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.h @@ -15,7 +15,6 @@ #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_UTILS_WEBASSEMBLYUTILITIES_H #define LLVM_LIB_TARGET_WEBASSEMBLY_UTILS_WEBASSEMBLYUTILITIES_H -#include "llvm/IR/DerivedTypes.h" #include "llvm/Support/CommandLine.h" namespace llvm { @@ -30,43 +29,6 @@ class WebAssemblySubtarget; namespace WebAssembly { -enum WasmAddressSpace : unsigned { - // Default address space, for pointers to linear memory (stack, heap, data). - WASM_ADDRESS_SPACE_DEFAULT = 0, - // A non-integral address space for pointers to named objects outside of - // linear memory: WebAssembly globals or WebAssembly locals. Loads and stores - // to these pointers are lowered to global.get / global.set or local.get / - // local.set, as appropriate. - WASM_ADDRESS_SPACE_VAR = 1, - // A non-integral address space for externref values - WASM_ADDRESS_SPACE_EXTERNREF = 10, - // A non-integral address space for funcref values - WASM_ADDRESS_SPACE_FUNCREF = 20, -}; - -inline bool isDefaultAddressSpace(unsigned AS) { - return AS == WASM_ADDRESS_SPACE_DEFAULT; -} -inline bool isWasmVarAddressSpace(unsigned AS) { - return AS == WASM_ADDRESS_SPACE_VAR; -} -inline bool isValidAddressSpace(unsigned AS) { - return isDefaultAddressSpace(AS) || isWasmVarAddressSpace(AS); -} -inline bool isFuncrefType(const Type *Ty) { - return isa<PointerType>(Ty) && - Ty->getPointerAddressSpace() == - WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF; -} -inline bool isExternrefType(const Type *Ty) { - return isa<PointerType>(Ty) && - Ty->getPointerAddressSpace() == - WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF; -} -inline bool isRefType(const Type *Ty) { - return isFuncrefType(Ty) || isExternrefType(Ty); -} - bool isChild(const MachineInstr &MI, const WebAssemblyFunctionInfo &MFI); bool mayThrow(const MachineInstr &MI); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index e3af6b2662ef..bf326e5106be 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -181,17 +181,11 @@ void WebAssemblyAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { if (!Sym->getType()) { const WebAssemblyTargetLowering &TLI = *Subtarget->getTargetLowering(); - SmallVector<EVT, 1> VTs; - ComputeValueVTs(TLI, GV->getParent()->getDataLayout(), GV->getValueType(), - VTs); - if (VTs.size() != 1 || - TLI.getNumRegisters(GV->getParent()->getContext(), VTs[0]) != 1) - report_fatal_error("Aggregate globals not yet implemented"); - MVT VT = TLI.getRegisterType(GV->getParent()->getContext(), VTs[0]); - bool Mutable = true; - wasm::ValType Type = WebAssembly::toValType(VT); - Sym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); - Sym->setGlobalType(wasm::WasmGlobalType{uint8_t(Type), Mutable}); + SmallVector<MVT, 1> VTs; + Type *GlobalVT = GV->getValueType(); + 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 diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp index 406edef8ff3f..8ddd414b043a 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -16,6 +16,7 @@ //===----------------------------------------------------------------------===// #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "Utils/WebAssemblyTypeUtilities.h" #include "Utils/WebAssemblyUtilities.h" #include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index c45f7d7176b5..01baa3d9389d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -19,7 +19,7 @@ #include "WebAssemblyFrameLowering.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" -#include "Utils/WebAssemblyUtilities.h" +#include "Utils/WebAssemblyTypeUtilities.h" #include "WebAssembly.h" #include "WebAssemblyInstrInfo.h" #include "WebAssemblyMachineFunctionInfo.h" diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index fe656753889f..b6c43be03aba 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -560,6 +560,9 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) { NEltArg = NEltArg.getValue() + 1; FnAttrs.addAllocSizeAttr(SizeArg, NEltArg); } + // In case the callee has 'noreturn' attribute, We need to remove it, because + // we expect invoke wrappers to return. + FnAttrs.removeAttribute(Attribute::NoReturn); // Reconstruct the AttributesList based on the vector we constructed. AttributeList NewCallAL = AttributeList::get( @@ -630,9 +633,9 @@ static bool canLongjmp(const Value *Callee) { // Exception-catching related functions // - // We intentionally excluded __cxa_end_catch here even though it surely cannot - // longjmp, in order to maintain the unwind relationship from all existing - // catchpads (and calls within them) to catch.dispatch.longjmp. + // We intentionally treat __cxa_end_catch longjmpable in Wasm SjLj even though + // it surely cannot longjmp, in order to maintain the unwind relationship from + // all existing catchpads (and calls within them) to catch.dispatch.longjmp. // // In Wasm EH + Wasm SjLj, we // 1. Make all catchswitch and cleanuppad that unwind to caller unwind to @@ -663,6 +666,8 @@ static bool canLongjmp(const Value *Callee) { // // The comment block in findWasmUnwindDestinations() in // SelectionDAGBuilder.cpp is addressing a similar problem. + if (CalleeName == "__cxa_end_catch") + return WebAssembly::WasmEnableSjLj; if (CalleeName == "__cxa_begin_catch" || CalleeName == "__cxa_allocate_exception" || CalleeName == "__cxa_throw" || CalleeName == "__clang_call_terminate") @@ -869,15 +874,17 @@ static void nullifySetjmp(Function *F) { Function *SetjmpF = M.getFunction("setjmp"); SmallVector<Instruction *, 1> ToErase; - for (User *U : SetjmpF->users()) { - auto *CI = dyn_cast<CallInst>(U); - // FIXME 'invoke' to setjmp can happen when we use Wasm EH + Wasm SjLj, but - // we don't support two being used together yet. - if (!CI) - report_fatal_error("Wasm EH + Wasm SjLj is not fully supported yet"); - BasicBlock *BB = CI->getParent(); + for (User *U : make_early_inc_range(SetjmpF->users())) { + auto *CB = cast<CallBase>(U); + BasicBlock *BB = CB->getParent(); if (BB->getParent() != F) // in other function continue; + CallInst *CI = nullptr; + // setjmp cannot throw. So if it is an invoke, lower it to a call + if (auto *II = dyn_cast<InvokeInst>(CB)) + CI = llvm::changeToCall(II); + else + CI = cast<CallInst>(CB); ToErase.push_back(CI); CI->replaceAllUsesWith(IRB.getInt32(0)); } @@ -1313,10 +1320,13 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) { SmallVector<PHINode *, 4> SetjmpRetPHIs; Function *SetjmpF = M.getFunction("setjmp"); for (auto *U : make_early_inc_range(SetjmpF->users())) { - auto *CB = dyn_cast<CallBase>(U); + auto *CB = cast<CallBase>(U); 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"); CallInst *CI = nullptr; // setjmp cannot throw. So if it is an invoke, lower it to a call @@ -1815,10 +1825,10 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj( BasicBlock *UnwindDest = nullptr; if (auto Bundle = CI->getOperandBundle(LLVMContext::OB_funclet)) { Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]); - while (!UnwindDest && FromPad) { + while (!UnwindDest) { if (auto *CPI = dyn_cast<CatchPadInst>(FromPad)) { UnwindDest = CPI->getCatchSwitch()->getUnwindDest(); - FromPad = nullptr; // stop searching + break; } else if (auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) { // getCleanupRetUnwindDest() can return nullptr when // 1. This cleanuppad's matching cleanupret uwninds to caller @@ -1826,7 +1836,10 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj( // unreachable. // In case of 2, we need to traverse the parent pad chain. UnwindDest = getCleanupRetUnwindDest(CPI); - FromPad = cast<Instruction>(CPI->getParentPad()); + Value *ParentPad = CPI->getParentPad(); + if (isa<ConstantTokenNone>(ParentPad)) + break; + FromPad = cast<Instruction>(ParentPad); } } } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp index 8ff916c28c4e..6fd87f10150d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp @@ -14,7 +14,7 @@ /// //===----------------------------------------------------------------------===// -#include "Utils/WebAssemblyUtilities.h" +#include "Utils/WebAssemblyTypeUtilities.h" #include "WebAssembly.h" #include "WebAssemblySubtarget.h" #include "llvm/IR/InstIterator.h" diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp index 09bccef17ab0..2e6027a5605c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -59,39 +59,7 @@ WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { SmallVector<MVT, 1> VTs; computeLegalValueVTs(CurrentFunc, TM, GlobalVT, VTs); - // Tables are represented as Arrays in LLVM IR therefore - // they reach this point as aggregate Array types with an element type - // that is a reference type. - wasm::ValType Type; - bool IsTable = false; - if (GlobalVT->isArrayTy() && - WebAssembly::isRefType(GlobalVT->getArrayElementType())) { - MVT VT; - IsTable = true; - switch (GlobalVT->getArrayElementType()->getPointerAddressSpace()) { - case WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF: - VT = MVT::funcref; - break; - case WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF: - VT = MVT::externref; - break; - default: - report_fatal_error("unhandled address space type"); - } - Type = WebAssembly::toValType(VT); - } else if (VTs.size() == 1) { - Type = WebAssembly::toValType(VTs[0]); - } else - report_fatal_error("Aggregate globals not yet implemented"); - - if (IsTable) { - WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); - WasmSym->setTableType(Type); - } else { - WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); - WasmSym->setGlobalType( - wasm::WasmGlobalType{uint8_t(Type), /*Mutable=*/true}); - } + WebAssembly::wasmSymbolSetType(WasmSym, GlobalVT, VTs); } return WasmSym; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp index 00b11321fdb2..ea80e96d50de 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp @@ -30,22 +30,28 @@ void WebAssemblyFunctionInfo::initWARegs(MachineRegisterInfo &MRI) { WARegs.resize(MRI.getNumVirtRegs(), Reg); } -void llvm::computeLegalValueVTs(const Function &F, const TargetMachine &TM, +void llvm::computeLegalValueVTs(const WebAssemblyTargetLowering &TLI, + LLVMContext &Ctx, const DataLayout &DL, Type *Ty, SmallVectorImpl<MVT> &ValueVTs) { - const DataLayout &DL(F.getParent()->getDataLayout()); - const WebAssemblyTargetLowering &TLI = - *TM.getSubtarget<WebAssemblySubtarget>(F).getTargetLowering(); SmallVector<EVT, 4> VTs; ComputeValueVTs(TLI, DL, Ty, VTs); for (EVT VT : VTs) { - unsigned NumRegs = TLI.getNumRegisters(F.getContext(), VT); - MVT RegisterVT = TLI.getRegisterType(F.getContext(), VT); + unsigned NumRegs = TLI.getNumRegisters(Ctx, VT); + MVT RegisterVT = TLI.getRegisterType(Ctx, VT); for (unsigned I = 0; I != NumRegs; ++I) ValueVTs.push_back(RegisterVT); } } +void llvm::computeLegalValueVTs(const Function &F, const TargetMachine &TM, + Type *Ty, SmallVectorImpl<MVT> &ValueVTs) { + const DataLayout &DL(F.getParent()->getDataLayout()); + const WebAssemblyTargetLowering &TLI = + *TM.getSubtarget<WebAssemblySubtarget>(F).getTargetLowering(); + computeLegalValueVTs(TLI, F.getContext(), DL, Ty, ValueVTs); +} + void llvm::computeSignatureVTs(const FunctionType *Ty, const Function *TargetFunc, const Function &ContextFunc, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h index 3fa2d0c8a2f2..413d0d1dc554 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h @@ -166,6 +166,10 @@ public: void setWasmEHFuncInfo(WasmEHFuncInfo *Info) { WasmEHInfo = Info; } }; +void computeLegalValueVTs(const WebAssemblyTargetLowering &TLI, + LLVMContext &Ctx, const DataLayout &DL, Type *Ty, + SmallVectorImpl<MVT> &ValueVTs); + void computeLegalValueVTs(const Function &F, const TargetMachine &TM, Type *Ty, SmallVectorImpl<MVT> &ValueVTs); |
