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 @@ -80,9 +80,6 @@ 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); @@ -126,42 +123,6 @@ return; } - case ISD::GlobalTLSAddress: { - const auto *GA = cast(Node); - - if (!MF.getSubtarget().hasBulkMemory()) - report_fatal_error("cannot use thread-local storage without bulk memory", - false); - - // Currently Emscripten does not support dynamic linking with threads. - // Therefore, if we have thread-local storage, only the local-exec model - // is possible. - // TODO: remove this and implement proper TLS models once Emscripten - // supports dynamic linking with threads. - if (GA->getGlobal()->getThreadLocalMode() != - GlobalValue::LocalExecTLSModel && - !Subtarget->getTargetTriple().isOSEmscripten()) { - report_fatal_error("only -ftls-model=local-exec is supported for now on " - "non-Emscripten OSes: variable " + - GA->getGlobal()->getName(), - false); - } - - SDValue TLSBaseSym = CurDAG->getTargetExternalSymbol("__tls_base", PtrVT); - SDValue TLSOffsetSym = CurDAG->getTargetGlobalAddress( - GA->getGlobal(), DL, PtrVT, GA->getOffset(), - WebAssemblyII::MO_TLS_BASE_REL); - - 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; - } - case ISD::INTRINSIC_WO_CHAIN: { unsigned IntNo = cast(Node->getOperand(0))->getZExtValue(); switch (IntNo) { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -69,6 +69,7 @@ computeRegisterProperties(Subtarget->getRegisterInfo()); setOperationAction(ISD::GlobalAddress, MVTPtr, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVTPtr, Custom); setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom); setOperationAction(ISD::JumpTable, MVTPtr, Custom); setOperationAction(ISD::BlockAddress, MVTPtr, Custom); @@ -1170,6 +1171,8 @@ return LowerFrameIndex(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::GlobalTLSAddress: + return LowerGlobalTLSAddress(Op, DAG); case ISD::ExternalSymbol: return LowerExternalSymbol(Op, DAG); case ISD::JumpTable: @@ -1278,6 +1281,49 @@ return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT); } +SDValue +WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + const auto *GA = cast(Op); + MVT PtrVT = getPointerTy(DAG.getDataLayout()); + + MachineFunction &MF = DAG.getMachineFunction(); + if (!MF.getSubtarget().hasBulkMemory()) + report_fatal_error("cannot use thread-local storage without bulk memory", + false); + + const GlobalValue *GV = GA->getGlobal(); + + // Currently Emscripten does not support dynamic linking with threads. + // Therefore, if we have thread-local storage, only the local-exec model + // is possible. + // TODO: remove this and implement proper TLS models once Emscripten + // supports dynamic linking with threads. + if (GV->getThreadLocalMode() != GlobalValue::LocalExecTLSModel && + !Subtarget->getTargetTriple().isOSEmscripten()) { + report_fatal_error("only -ftls-model=local-exec is supported for now on " + "non-Emscripten OSes: variable " + + GV->getName(), + false); + } + + auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 + : WebAssembly::GLOBAL_GET_I32; + const char *BaseName = MF.createExternalSymbolName("__tls_base"); + + SDValue BaseAddr( + DAG.getMachineNode(GlobalGet, DL, PtrVT, + DAG.getTargetExternalSymbol(BaseName, PtrVT)), + 0); + + SDValue TLSOffset = DAG.getTargetGlobalAddress( + GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL); + SDValue SymAddr = DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, TLSOffset); + + return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr); +} + SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -352,6 +352,11 @@ def : Pat<(i64 (WebAssemblywrapperPIC tglobaladdr:$addr)), (CONST_I64 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr64]>; +def : Pat<(i32 (WebAssemblywrapper tglobaltlsaddr:$addr)), + (CONST_I32 tglobaltlsaddr:$addr)>, Requires<[HasAddr32]>; +def : Pat<(i64 (WebAssemblywrapper tglobaltlsaddr:$addr)), + (CONST_I64 tglobaltlsaddr:$addr)>, Requires<[HasAddr64]>; + def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)), (GLOBAL_GET_I32 texternalsym:$addr)>, Requires<[IsPIC, HasAddr32]>;