diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -62,6 +62,11 @@ const char *Linker = Args.MakeArgString(getLinkerPath(Args)); ArgStringList CmdArgs; + if (getToolChain().getTriple().isArch64Bit()) + CmdArgs.push_back("-m wasm64"); + else + CmdArgs.push_back("-m wasm32"); + if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("--strip-all"); diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -36,6 +36,7 @@ bool importMemory; bool sharedMemory; bool importTable; + bool is64; bool mergeDataSegments; bool pie; bool printGcSections; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -378,6 +378,18 @@ config->exportDynamic = args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, config->shared); + // Parse wasm32/64. + config->is64 = false; + if (auto *arg = args.getLastArg(OPT_m)) { + StringRef s = arg->getValue(); + if (s == "wasm32") + config->is64 = false; + else if (s == "wasm64") + config->is64 = true; + else + error("'" + s + "' not a valid target"); + } + // --threads= takes a positive integer and provides the default value for // --thinlto-jobs=. if (auto *arg = args.getLastArg(OPT_threads)) { @@ -498,9 +510,15 @@ static GlobalSymbol *createGlobalVariable(StringRef name, bool isMutable, int value) { llvm::wasm::WasmGlobal wasmGlobal; - wasmGlobal.Type = {WASM_TYPE_I32, isMutable}; - wasmGlobal.InitExpr.Value.Int32 = value; - wasmGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST; + if (config->is64) { + wasmGlobal.Type = {WASM_TYPE_I64, isMutable}; + wasmGlobal.InitExpr.Value.Int64 = value; + wasmGlobal.InitExpr.Opcode = WASM_OPCODE_I64_CONST; + } else { + wasmGlobal.Type = {WASM_TYPE_I32, isMutable}; + wasmGlobal.InitExpr.Value.Int32 = value; + wasmGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST; + } wasmGlobal.SymbolName = name; return symtab->addSyntheticGlobal(name, WASM_SYMBOL_VISIBILITY_HIDDEN, make(wasmGlobal, nullptr)); @@ -513,9 +531,13 @@ static WasmSignature nullSignature = {{}, {}}; static WasmSignature i32ArgSignature = {{}, {ValType::I32}}; + static WasmSignature i64ArgSignature = {{}, {ValType::I64}}; static llvm::wasm::WasmGlobalType globalTypeI32 = {WASM_TYPE_I32, false}; + static llvm::wasm::WasmGlobalType globalTypeI64 = {WASM_TYPE_I64, false}; static llvm::wasm::WasmGlobalType mutableGlobalTypeI32 = {WASM_TYPE_I32, true}; + static llvm::wasm::WasmGlobalType mutableGlobalTypeI64 = {WASM_TYPE_I64, + true}; WasmSym::callCtors = symtab->addSyntheticFunction( "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, make(nullSignature, "__wasm_call_ctors")); @@ -530,15 +552,16 @@ if (config->isPic) { - WasmSym::stackPointer = - createUndefinedGlobal("__stack_pointer", &mutableGlobalTypeI32); + WasmSym::stackPointer = createUndefinedGlobal( + "__stack_pointer", + config->is64 ? &mutableGlobalTypeI64 : &mutableGlobalTypeI32); // For PIC code, we import two global variables (__memory_base and // __table_base) from the environment and use these as the offset at // which to load our static data and function table. // See: // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md - WasmSym::memoryBase = - createUndefinedGlobal("__memory_base", &globalTypeI32); + WasmSym::memoryBase = createUndefinedGlobal( + "__memory_base", config->is64 ? &globalTypeI64 : &globalTypeI32); WasmSym::tableBase = createUndefinedGlobal("__table_base", &globalTypeI32); WasmSym::memoryBase->markLive(); WasmSym::tableBase->markLive(); @@ -563,7 +586,9 @@ WasmSym::tlsAlign = createGlobalVariable("__tls_align", false, 1); WasmSym::initTLS = symtab->addSyntheticFunction( "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, - make(i32ArgSignature, "__wasm_init_tls")); + make(config->is64 ? i64ArgSignature + : i32ArgSignature, + "__wasm_init_tls")); } } diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp --- a/lld/wasm/InputChunks.cpp +++ b/lld/wasm/InputChunks.cpp @@ -32,6 +32,18 @@ llvm_unreachable("unknown reloc type"); } +bool relocIs64(uint8_t relocType) { + switch (relocType) { + case R_WASM_MEMORY_ADDR_LEB64: + case R_WASM_MEMORY_ADDR_SLEB64: + case R_WASM_MEMORY_ADDR_REL_SLEB64: + case R_WASM_MEMORY_ADDR_I64: + return true; + default: + return false; + } +} + std::string toString(const wasm::InputChunk *c) { return (toString(c->file) + ":(" + c->getName() + ")").str(); } @@ -323,12 +335,17 @@ LLVM_DEBUG(dbgs() << "generating runtime relocations: " << getName() << " count=" << relocations.size() << "\n"); + auto WASM_OPCODE_PTR_CONST = + config->is64 ? WASM_OPCODE_I64_CONST : WASM_OPCODE_I32_CONST; + auto WASM_OPCODE_PTR_ADD = + config->is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD; + // TODO(sbc): Encode the relocations in the data section and write a loop // here to apply them. uint32_t segmentVA = outputSeg->startVA + outputSegmentOffset; for (const WasmRelocation &rel : relocations) { - uint32_t offset = rel.Offset - getInputSectionOffset(); - uint32_t outputOffset = segmentVA + offset; + uint64_t offset = rel.Offset - getInputSectionOffset(); + uint64_t outputOffset = segmentVA + offset; LLVM_DEBUG(dbgs() << "gen reloc: type=" << relocTypeToString(rel.Type) << " addend=" << rel.Addend << " index=" << rel.Index @@ -339,9 +356,17 @@ writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base"); // Add the offset of the relocation - writeU8(os, WASM_OPCODE_I32_CONST, "I32_CONST"); + writeU8(os, WASM_OPCODE_PTR_CONST, "CONST"); writeSleb128(os, outputOffset, "offset"); - writeU8(os, WASM_OPCODE_I32_ADD, "ADD"); + writeU8(os, WASM_OPCODE_PTR_ADD, "ADD"); + + auto is64 = relocIs64(rel.Type); + auto WASM_OPCODE_RELOC_CONST = + is64 ? WASM_OPCODE_I64_CONST : WASM_OPCODE_I32_CONST; + auto WASM_OPCODE_RELOC_ADD = + is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD; + auto WASM_OPCODE_RELOC_STORE = + is64 ? WASM_OPCODE_I64_STORE : WASM_OPCODE_I32_STORE; Symbol *sym = file->getSymbol(rel); // Now figure out what we want to store @@ -349,9 +374,9 @@ writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); writeUleb128(os, sym->getGOTIndex(), "global index"); if (rel.Addend) { - writeU8(os, WASM_OPCODE_I32_CONST, "CONST"); + writeU8(os, WASM_OPCODE_RELOC_CONST, "CONST"); writeSleb128(os, rel.Addend, "addend"); - writeU8(os, WASM_OPCODE_I32_ADD, "ADD"); + writeU8(os, WASM_OPCODE_RELOC_ADD, "ADD"); } } else { const GlobalSymbol* baseSymbol = WasmSym::memoryBase; @@ -359,13 +384,13 @@ baseSymbol = WasmSym::tableBase; writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); writeUleb128(os, baseSymbol->getGlobalIndex(), "base"); - writeU8(os, WASM_OPCODE_I32_CONST, "CONST"); + writeU8(os, WASM_OPCODE_RELOC_CONST, "CONST"); writeSleb128(os, file->calcNewValue(rel), "offset"); - writeU8(os, WASM_OPCODE_I32_ADD, "ADD"); + writeU8(os, WASM_OPCODE_RELOC_ADD, "ADD"); } // Store that value at the virtual address - writeU8(os, WASM_OPCODE_I32_STORE, "I32_STORE"); + writeU8(os, WASM_OPCODE_RELOC_STORE, "I32_STORE"); writeUleb128(os, 2, "align"); writeUleb128(os, 0, "offset"); } diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -62,6 +62,8 @@ def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"">, HelpText<"Add a directory to the library search path">; +def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; + def mllvm: S<"mllvm">, HelpText<"Options to pass to LLVM">; def no_color_diagnostics: F<"no-color-diagnostics">, @@ -179,7 +181,6 @@ def: J<"entry=">, Alias; def: Flag<["-"], "E">, Alias, HelpText<"Alias for --export-dynamic">; def: Flag<["-"], "i">, Alias; -def: Flag<["-"], "m">, Alias; def: Flag<["-"], "r">, Alias; def: Flag<["-"], "s">, Alias, HelpText<"Alias for --strip-all">; def: Flag<["-"], "S">, Alias, HelpText<"Alias for --strip-debug">; diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -253,11 +253,13 @@ WASM_OPCODE_GLOBAL_GET = 0x23, WASM_OPCODE_GLOBAL_SET = 0x24, WASM_OPCODE_I32_STORE = 0x36, + WASM_OPCODE_I64_STORE = 0x37, WASM_OPCODE_I32_CONST = 0x41, WASM_OPCODE_I64_CONST = 0x42, WASM_OPCODE_F32_CONST = 0x43, WASM_OPCODE_F64_CONST = 0x44, WASM_OPCODE_I32_ADD = 0x6a, + WASM_OPCODE_I64_ADD = 0x7c, }; // Opcodes used in synthetic functions. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -434,9 +434,12 @@ // GetExternalSymbolSymbol does, since if there's no code that // refers to this symbol, we have to set it here. SPSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); - // FIXME: need to check subtarget to see if its wasm64, but we - // can't cast to WebAssemblySubtarget here. - SPSym->setGlobalType(wasm::WasmGlobalType{wasm::WASM_TYPE_I32, true}); + SPSym->setGlobalType(wasm::WasmGlobalType{ + uint8_t(Asm->getSubtargetInfo().getTargetTriple().getArch() == + Triple::wasm64 + ? wasm::WASM_TYPE_I64 + : wasm::WASM_TYPE_I32), + true}); DIELoc *Loc = new (DIEValueAllocator) DIELoc; addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_WASM_location); addSInt(*Loc, dwarf::DW_FORM_sdata, FrameBase.Location.WasmLoc.Kind); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h @@ -53,6 +53,15 @@ MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const; + unsigned getSPReg(const MachineFunction &MF) const; + unsigned getFPReg(const MachineFunction &MF) const; + unsigned getOpcConst(const MachineFunction &MF) const; + unsigned getOpcAdd(const MachineFunction &MF) const; + unsigned getOpcSub(const MachineFunction &MF) const; + unsigned getOpcAnd(const MachineFunction &MF) const; + unsigned getOpcGlobGet(const MachineFunction &MF) const; + unsigned getOpcGlobSet(const MachineFunction &MF) const; + private: bool hasBP(const MachineFunction &MF) const; bool needsSPForLocalFrame(const MachineFunction &MF) const; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -87,8 +87,8 @@ } // In function with EH pads, we need to make a copy of the value of -// __stack_pointer global in SP32 register, in order to use it when restoring -// __stack_pointer after an exception is caught. +// __stack_pointer global in SP32/64 register, in order to use it when +// restoring __stack_pointer after an exception is caught. bool WebAssemblyFrameLowering::needsPrologForEH( const MachineFunction &MF) const { auto EHType = MF.getTarget().getMCAsmInfo()->getExceptionHandlingType(); @@ -123,6 +123,57 @@ return needsSPForLocalFrame(MF) && !CanUseRedZone; } +unsigned WebAssemblyFrameLowering::getSPReg(const MachineFunction &MF) const { + return MF.getSubtarget().hasAddr64() + ? WebAssembly::SP64 + : WebAssembly::SP32; +} + +unsigned WebAssemblyFrameLowering::getFPReg(const MachineFunction &MF) const { + return MF.getSubtarget().hasAddr64() + ? WebAssembly::FP64 + : WebAssembly::FP32; +} + +unsigned +WebAssemblyFrameLowering::getOpcConst(const MachineFunction &MF) const { + return MF.getSubtarget().hasAddr64() + ? WebAssembly::CONST_I64 + : WebAssembly::CONST_I32; +} + +unsigned WebAssemblyFrameLowering::getOpcAdd(const MachineFunction &MF) const { + return MF.getSubtarget().hasAddr64() + ? WebAssembly::ADD_I64 + : WebAssembly::ADD_I32; +} + +unsigned WebAssemblyFrameLowering::getOpcSub(const MachineFunction &MF) const { + return MF.getSubtarget().hasAddr64() + ? WebAssembly::SUB_I64 + : WebAssembly::SUB_I32; +} + +unsigned WebAssemblyFrameLowering::getOpcAnd(const MachineFunction &MF) const { + return MF.getSubtarget().hasAddr64() + ? WebAssembly::AND_I64 + : WebAssembly::AND_I32; +} + +unsigned +WebAssemblyFrameLowering::getOpcGlobGet(const MachineFunction &MF) const { + return MF.getSubtarget().hasAddr64() + ? WebAssembly::GLOBAL_GET_I64 + : WebAssembly::GLOBAL_GET_I32; +} + +unsigned +WebAssemblyFrameLowering::getOpcGlobSet(const MachineFunction &MF) const { + return MF.getSubtarget().hasAddr64() + ? WebAssembly::GLOBAL_SET_I64 + : WebAssembly::GLOBAL_SET_I32; +} + void WebAssemblyFrameLowering::writeSPToGlobal( unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const { @@ -130,7 +181,8 @@ const char *ES = "__stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); - BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::GLOBAL_SET_I32)) + + BuildMI(MBB, InsertStore, DL, TII->get(getOpcGlobSet(MF))) .addExternalSymbol(SPSymbol) .addReg(SrcReg); } @@ -141,11 +193,12 @@ MachineBasicBlock::iterator I) const { assert(!I->getOperand(0).getImm() && (hasFP(MF) || hasBP(MF)) && "Call frame pseudos should only be used for dynamic stack adjustment"); - const auto *TII = MF.getSubtarget().getInstrInfo(); + auto &ST = MF.getSubtarget(); + const auto *TII = ST.getInstrInfo(); if (I->getOpcode() == TII->getCallFrameDestroyOpcode() && needsSPWriteback(MF)) { DebugLoc DL = I->getDebugLoc(); - writeSPToGlobal(WebAssembly::SP32, MF, MBB, I, DL); + writeSPToGlobal(getSPReg(MF), MF, MBB, I, DL); } return MBB.erase(I); } @@ -161,7 +214,8 @@ return; uint64_t StackSize = MFI.getStackSize(); - const auto *TII = MF.getSubtarget().getInstrInfo(); + auto &ST = MF.getSubtarget(); + const auto *TII = ST.getInstrInfo(); auto &MRI = MF.getRegInfo(); auto InsertPt = MBB.begin(); @@ -172,13 +226,13 @@ const TargetRegisterClass *PtrRC = MRI.getTargetRegisterInfo()->getPointerRegClass(MF); - unsigned SPReg = WebAssembly::SP32; + unsigned SPReg = getSPReg(MF); if (StackSize) SPReg = MRI.createVirtualRegister(PtrRC); const char *ES = "__stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::GLOBAL_GET_I32), SPReg) + BuildMI(MBB, InsertPt, DL, TII->get(getOpcGlobGet(MF)), SPReg) .addExternalSymbol(SPSymbol); bool HasBP = hasBP(MF); @@ -192,32 +246,30 @@ if (StackSize) { // Subtract the frame size Register OffsetReg = MRI.createVirtualRegister(PtrRC); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg) + BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), OffsetReg) .addImm(StackSize); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::SUB_I32), - WebAssembly::SP32) + BuildMI(MBB, InsertPt, DL, TII->get(getOpcSub(MF)), getSPReg(MF)) .addReg(SPReg) .addReg(OffsetReg); } if (HasBP) { Register BitmaskReg = MRI.createVirtualRegister(PtrRC); Align Alignment = MFI.getMaxAlign(); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), BitmaskReg) - .addImm((int)~(Alignment.value() - 1)); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::AND_I32), - WebAssembly::SP32) - .addReg(WebAssembly::SP32) + BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), BitmaskReg) + .addImm((int64_t) ~(Alignment.value() - 1)); + BuildMI(MBB, InsertPt, DL, TII->get(getOpcAnd(MF)), getSPReg(MF)) + .addReg(getSPReg(MF)) .addReg(BitmaskReg); } if (hasFP(MF)) { // Unlike most conventional targets (where FP points to the saved FP), // FP points to the bottom of the fixed-size locals, so we can use positive // offsets in load/store instructions. - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), WebAssembly::FP32) - .addReg(WebAssembly::SP32); + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), getFPReg(MF)) + .addReg(getSPReg(MF)); } if (StackSize && needsSPWriteback(MF)) { - writeSPToGlobal(WebAssembly::SP32, MF, MBB, InsertPt, DL); + writeSPToGlobal(getSPReg(MF), MF, MBB, InsertPt, DL); } } @@ -226,7 +278,8 @@ uint64_t StackSize = MF.getFrameInfo().getStackSize(); if (!needsSP(MF) || !needsSPWriteback(MF)) return; - const auto *TII = MF.getSubtarget().getInstrInfo(); + auto &ST = MF.getSubtarget(); + const auto *TII = ST.getInstrInfo(); auto &MRI = MF.getRegInfo(); auto InsertPt = MBB.getFirstTerminator(); DebugLoc DL; @@ -237,6 +290,7 @@ // Restore the stack pointer. If we had fixed-size locals, add the offset // subtracted in the prolog. unsigned SPReg = 0; + unsigned SPFPReg = hasFP(MF) ? getFPReg(MF) : getSPReg(MF); if (hasBP(MF)) { auto FI = MF.getInfo(); SPReg = FI->getBasePointerVreg(); @@ -244,16 +298,17 @@ const TargetRegisterClass *PtrRC = MRI.getTargetRegisterInfo()->getPointerRegClass(MF); Register OffsetReg = MRI.createVirtualRegister(PtrRC); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg) + BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), OffsetReg) .addImm(StackSize); - // In the epilog we don't need to write the result back to the SP32 physreg - // because it won't be used again. We can use a stackified register instead. + // In the epilog we don't need to write the result back to the SP32/64 + // physreg because it won't be used again. We can use a stackified register + // instead. SPReg = MRI.createVirtualRegister(PtrRC); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), SPReg) - .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32) + BuildMI(MBB, InsertPt, DL, TII->get(getOpcAdd(MF)), SPReg) + .addReg(SPFPReg) .addReg(OffsetReg); } else { - SPReg = hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32; + SPReg = SPFPReg; } writeSPToGlobal(SPReg, MF, MBB, InsertPt, DL); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -77,6 +77,13 @@ return; } + MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); + auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 + : WebAssembly::GLOBAL_GET_I32; + auto ConstIns = + PtrVT == MVT::i64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; + auto AddIns = PtrVT == MVT::i64 ? WebAssembly::ADD_I64 : WebAssembly::ADD_I32; + // Few custom selection stuff. SDLoc DL(Node); MachineFunction &MF = CurDAG->getMachineFunction(); @@ -140,20 +147,16 @@ false); } - MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); - assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); - SDValue TLSBaseSym = CurDAG->getTargetExternalSymbol("__tls_base", PtrVT); SDValue TLSOffsetSym = CurDAG->getTargetGlobalAddress( GA->getGlobal(), DL, PtrVT, GA->getOffset(), 0); - MachineSDNode *TLSBase = CurDAG->getMachineNode(WebAssembly::GLOBAL_GET_I32, - DL, MVT::i32, TLSBaseSym); - MachineSDNode *TLSOffset = CurDAG->getMachineNode( - WebAssembly::CONST_I32, DL, MVT::i32, TLSOffsetSym); - MachineSDNode *TLSAddress = - CurDAG->getMachineNode(WebAssembly::ADD_I32, DL, MVT::i32, - SDValue(TLSBase, 0), SDValue(TLSOffset, 0)); + MachineSDNode *TLSBase = + CurDAG->getMachineNode(GlobalGetIns, DL, PtrVT, TLSBaseSym); + MachineSDNode *TLSOffset = + CurDAG->getMachineNode(ConstIns, DL, PtrVT, TLSOffsetSym); + MachineSDNode *TLSAddress = CurDAG->getMachineNode( + AddIns, DL, PtrVT, SDValue(TLSBase, 0), SDValue(TLSOffset, 0)); ReplaceNode(Node, TLSAddress); return; } @@ -162,22 +165,16 @@ unsigned IntNo = cast(Node->getOperand(0))->getZExtValue(); switch (IntNo) { case Intrinsic::wasm_tls_size: { - MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); - assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); - MachineSDNode *TLSSize = CurDAG->getMachineNode( - WebAssembly::GLOBAL_GET_I32, DL, PtrVT, - CurDAG->getTargetExternalSymbol("__tls_size", MVT::i32)); + GlobalGetIns, DL, PtrVT, + CurDAG->getTargetExternalSymbol("__tls_size", PtrVT)); ReplaceNode(Node, TLSSize); return; } case Intrinsic::wasm_tls_align: { - MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); - assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); - MachineSDNode *TLSAlign = CurDAG->getMachineNode( - WebAssembly::GLOBAL_GET_I32, DL, PtrVT, - CurDAG->getTargetExternalSymbol("__tls_align", MVT::i32)); + GlobalGetIns, DL, PtrVT, + CurDAG->getTargetExternalSymbol("__tls_align", PtrVT)); ReplaceNode(Node, TLSAlign); return; } @@ -188,11 +185,8 @@ unsigned IntNo = cast(Node->getOperand(1))->getZExtValue(); switch (IntNo) { case Intrinsic::wasm_tls_base: { - MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); - assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); - MachineSDNode *TLSBase = CurDAG->getMachineNode( - WebAssembly::GLOBAL_GET_I32, DL, MVT::i32, MVT::Other, + GlobalGetIns, DL, PtrVT, MVT::Other, CurDAG->getTargetExternalSymbol("__tls_base", PtrVT), Node->getOperand(0)); ReplaceNode(Node, TLSBase); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -408,8 +408,8 @@ ++InsertPos; if (InsertPos->getOpcode() == WebAssembly::CATCH) ++InsertPos; - FrameLowering->writeSPToGlobal(WebAssembly::SP32, MF, MBB, InsertPos, - MBB.begin()->getDebugLoc()); + FrameLowering->writeSPToGlobal(FrameLowering->getSPReg(MF), MF, MBB, + InsertPos, MBB.begin()->getDebugLoc()); } return Changed; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -81,8 +81,9 @@ strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0; WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); WasmSym->setGlobalType(wasm::WasmGlobalType{ - uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64 - : wasm::WASM_TYPE_I32), + uint8_t(Subtarget.hasAddr64() && strcmp(Name, "__table_base") != 0 + ? wasm::WASM_TYPE_I64 + : wasm::WASM_TYPE_I32), Mutable}); return WasmSym; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -248,7 +248,8 @@ } // Check for writes to __stack_pointer global. - if (MI.getOpcode() == WebAssembly::GLOBAL_SET_I32 && + if ((MI.getOpcode() == WebAssembly::GLOBAL_SET_I32 || + MI.getOpcode() == WebAssembly::GLOBAL_SET_I64) && strcmp(MI.getOperand(0).getSymbolName(), "__stack_pointer") == 0) StackPointer = true; diff --git a/llvm/test/MC/WebAssembly/stack-ptr.ll b/llvm/test/MC/WebAssembly/stack-ptr.ll --- a/llvm/test/MC/WebAssembly/stack-ptr.ll +++ b/llvm/test/MC/WebAssembly/stack-ptr.ll @@ -1,6 +1,5 @@ -; RUN: llc -filetype=obj %s -o - | obj2yaml | FileCheck %s - -target triple = "wasm32-unknown-unknown" +; RUN: llc --mtriple=wasm32-unknown-unknown -filetype=obj %s -o - | obj2yaml | FileCheck --check-prefixes CHECK,CHK32 %s +; RUN: llc --mtriple=wasm64-unknown-unknown -filetype=obj %s -o - | obj2yaml | FileCheck --check-prefixes CHECK,CHK64 %s ; Function that uses explict stack, and should generate a reference to ; __stack_pointer, along with the corresponding reloction entry. @@ -15,7 +14,8 @@ ; CHECK: - Module: env ; CHECK: Field: __stack_pointer ; CHECK: Kind: GLOBAL -; CHECK: GlobalType: I32 +; CHK32: GlobalType: I32 +; CHK64: GlobalType: I64 ; CHECK: GlobalMutable: true ; CHECK: - Type: CODE ; CHECK: Relocations: diff --git a/llvm/test/MC/WebAssembly/wasm64.s b/llvm/test/MC/WebAssembly/wasm64.s --- a/llvm/test/MC/WebAssembly/wasm64.s +++ b/llvm/test/MC/WebAssembly/wasm64.s @@ -51,6 +51,11 @@ i64.const 0 f32.store .L.str # relocatable offset! + ### 64-bit SP + + global.get __stack_pointer + drop + end_function .section .rodata..L.str,"",@ @@ -62,7 +67,7 @@ .size .L.str, 24 .globaltype myglob64, i64 - + .globaltype __stack_pointer, i64 # CHECK: .functype test (i64) -> () @@ -155,6 +160,11 @@ # BIN-NEXT: Kind: GLOBAL # BIN-NEXT: GlobalType: I64 # BIN-NEXT: GlobalMutable: true +# BIN-NEXT: - Module: env +# BIN-NEXT: Field: __stack_pointer +# BIN-NEXT: Kind: GLOBAL +# BIN-NEXT: GlobalType: I64 +# BIN-NEXT: GlobalMutable: true # BIN-NEXT: - Type: FUNCTION # BIN-NEXT: FunctionTypes: [ 0 ] # BIN-NEXT: - Type: DATACOUNT @@ -179,12 +189,15 @@ # BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB64 # BIN-NEXT: Index: 1 # BIN-NEXT: Offset: 0x00000078 +# BIN-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB +# BIN-NEXT: Index: 3 +# BIN-NEXT: Offset: 0x00000083 # BIN-NEXT: Functions: # BIN-NEXT: - Index: 0 # BIN-NEXT: Locals: # BIN-NEXT: - Type: I64 # BIN-NEXT: Count: 1 -# BIN-NEXT: Body: 42002A02001A20002A02001A42808080808080808080002A02001A2380808080002A02001A42002A02808080808080808080001A4300000000420038020043000000002000380200430000000042808080808080808080003802004300000000238080808000380200430000000042003802808080808080808080000B +# BIN-NEXT: Body: 42002A02001A20002A02001A42808080808080808080002A02001A2380808080002A02001A42002A02808080808080808080001A4300000000420038020043000000002000380200430000000042808080808080808080003802004300000000238080808000380200430000000042003802808080808080808080002381808080001A0B # BIN-NEXT: - Type: DATA # BIN-NEXT: Relocations: # BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_I64 @@ -217,6 +230,11 @@ # BIN-NEXT: Name: myglob64 # BIN-NEXT: Flags: [ UNDEFINED ] # BIN-NEXT: Global: 0 +# BIN-NEXT: - Index: 3 +# BIN-NEXT: Kind: GLOBAL +# BIN-NEXT: Name: __stack_pointer +# BIN-NEXT: Flags: [ UNDEFINED ] +# BIN-NEXT: Global: 1 # BIN-NEXT: SegmentInfo: # BIN-NEXT: - Index: 0 # BIN-NEXT: Name: .rodata..L.str diff --git a/mypatch.patch b/mypatch.patch new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@