Index: cfe/trunk/include/clang/Basic/BuiltinsWebAssembly.def =================================================================== --- cfe/trunk/include/clang/Basic/BuiltinsWebAssembly.def +++ cfe/trunk/include/clang/Basic/BuiltinsWebAssembly.def @@ -31,6 +31,7 @@ // Thread-local storage TARGET_BUILTIN(__builtin_wasm_tls_size, "z", "nc", "bulk-memory") +TARGET_BUILTIN(__builtin_wasm_tls_base, "v*", "n", "bulk-memory") // Floating point min/max BUILTIN(__builtin_wasm_min_f32, "fff", "nc") Index: cfe/trunk/lib/CodeGen/CGBuiltin.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGBuiltin.cpp +++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp @@ -13924,6 +13924,10 @@ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_size, ResultType); return Builder.CreateCall(Callee); } + case WebAssembly::BI__builtin_wasm_tls_base: { + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_base); + return Builder.CreateCall(Callee); + } case WebAssembly::BI__builtin_wasm_throw: { Value *Tag = EmitScalarExpr(E->getArg(0)); Value *Obj = EmitScalarExpr(E->getArg(1)); Index: cfe/trunk/test/CodeGen/builtins-wasm.c =================================================================== --- cfe/trunk/test/CodeGen/builtins-wasm.c +++ cfe/trunk/test/CodeGen/builtins-wasm.c @@ -44,6 +44,11 @@ // WEBASSEMBLY64: call i64 @llvm.wasm.tls.size.i64() } +void *tls_base() { + return __builtin_wasm_tls_base(); + // WEBASSEMBLY: call i8* @llvm.wasm.tls.base() +} + void throw(void *obj) { return __builtin_wasm_throw(0, obj); // WEBASSEMBLY32: call void @llvm.wasm.throw(i32 0, i8* %{{.*}}) Index: llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td =================================================================== --- llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td +++ llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td @@ -133,4 +133,9 @@ [], [IntrNoMem, IntrSpeculatable]>; +def int_wasm_tls_base : + Intrinsic<[llvm_ptr_ty], + [], + [IntrReadMem]>; + } // TargetPrefix = "wasm" Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -227,6 +227,23 @@ } break; } + case ISD::INTRINSIC_W_CHAIN: { + 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, + CurDAG->getTargetExternalSymbol("__tls_base", PtrVT), + Node->getOperand(0)); + ReplaceNode(Node, TLSBase); + return; + } + } + break; + } default: break; Index: llvm/trunk/test/CodeGen/WebAssembly/tls-general-dynamic.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/tls-general-dynamic.ll +++ llvm/trunk/test/CodeGen/WebAssembly/tls-general-dynamic.ll @@ -75,6 +75,15 @@ ret i32 %1 } +; CHECK-LABEL: tls_base: +; CHECK-NEXT: .functype tls_base () -> (i32) +define i8* @tls_base() { +; CHECK-NEXT: global.get __tls_base +; CHECK-NEXT: return + %1 = call i8* @llvm.wasm.tls.base() + ret i8* %1 +} + ; CHECK: .type tls,@object ; TLS-NEXT: .section .tbss.tls,"",@ ; NO-TLS-NEXT: .section .bss.tls,"",@ @@ -84,3 +93,4 @@ @tls = internal thread_local global i32 0 declare i32 @llvm.wasm.tls.size.i32() +declare i8* @llvm.wasm.tls.base()