[PATCH] D64537: [WebAssembly] Implement thread-local storage for non-PIC cases

Guanzhong Chen via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 11 11:15:49 PDT 2019


quantum marked 20 inline comments as done.
quantum added a comment.

I'll clean up the table gen stuff.



================
Comment at: clang/include/clang/Basic/BuiltinsWebAssembly.def:33
+// Thread-local storage
+TARGET_BUILTIN(__builtin_wasm_tls_size, "z", "nc", "bulk-memory")
+
----------------
aheejin wrote:
> Why is it `c`(const)? According to [[ https://github.com/llvm/llvm-project/blob/e6695821e592f95bffe1340b28be7bcfcce04284/clang/include/clang/Basic/Builtins.h#L104-L108 | this comment ]], this is true if this function has no side effects and doesn't read memory, i.e., the result should be only dependent on its arguments. Can't wasm globals be memory locations in machines?
I was thinking that since the global is immutable, so the value is always a constant.


================
Comment at: lld/test/wasm/tls.ll:57
+;   memory.init 0, 0
+;   end
+
----------------
aheejin wrote:
> Hmm, I think there might be a way to actually print disassembly results. There are '*.test' files in test directory, in which we have some examples. For example, [[ https://github.com/llvm/llvm-project/blob/master/lld/test/wasm/export-table.test | this test ]] has a sequence of commands you want to run, and you can put input files in a separate directory. That test uses `obj2yaml`, but can we possibly use `llvm-objdump` or something to disassemble?
We already know that we can do something like

    Run: obj2yaml %t.wasm | sed -n '/Body:/{s/^\s*Body:\s*//;s/../0x& /gp}'  | llvm-mc -disassemble -triple=wasm32

to compare the actual assembly. As for `llvm-objdump`, it seems to be unable to disassemble the WASM properly:


```
.../tools/lld/test/wasm/Output/tls.ll.tmp.wasm:	file format WASM


Disassembly of section CODE:

00000000 CODE:
        # 4 functions in section.
       1: 02 00                        	block   	invalid_type
       3: 0b                           	end
       4: 10 00                        	call	0
       6: 20 00                        	local.get	0
       8: 24 01                        	global.set	1
       a: 20 00                        	local.get	0
       c: 41 00                        	i32.const	0
       e: 41 08                        	i32.const	8
      10: fc 08 00 00                  	memory.init	0, 0
      14: 0b                           	end
      15: 0f                           	return
      16: 00                           	llvm-objdump: lib/Target/WebAssembly/WebAssemblyGenAsmWriter.inc:2032: void llvm::WebAssemblyInstPrinter::printInstruction(const llvm::MCInst *, llvm::raw_ostream &): Assertion `Bits != 0 && "Cannot print this instruction."' failed.

```


================
Comment at: lld/wasm/Driver.cpp:543
+      "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN,
+      make<SyntheticFunction>(I32ArgSignature, "__wasm_init_tls"));
+
----------------
aheejin wrote:
> Does this TLS thing work when `Config->Shared == true`, i.e., do we create TLS globals even when this is a library?
Since TLS is module specific (we can't allocate memory for other modules), we must in fact generate this symbol for every module. Shared library support will not be implemented in this diff, however.


================
Comment at: lld/wasm/Writer.cpp:431
+    error("'bulk-memory' feature must be used in order to use thread-local "
+          "storage");
+
----------------
aheejin wrote:
> Should we check for "mutable-global" feature too?
Do we need to? I thought it's always available since we use it for the stack pointer.


================
Comment at: lld/wasm/Writer.cpp:514
       if (G->getGlobalType()->Mutable) {
         // Only the __stack_pointer should ever be create as mutable.
+        assert(G == WasmSym::StackPointer || G == WasmSym::TLSBase);
----------------
aheejin wrote:
> Now `__tls_base` is also mutable, I think we should fix the comment
Will do.


================
Comment at: lld/wasm/Writer.cpp:769
+  std::string BodyContent;
+  {
+    raw_string_ostream OS(BodyContent);
----------------
aheejin wrote:
> Any reason for the new block scope?
Yes, the `raw_string_ostream` must destruct by the end of the scope. This is the pattern used in other functions above.


================
Comment at: lld/wasm/Writer.cpp:777
+      break;
+    }
+
----------------
aheejin wrote:
> Is it guaranteed that there's only one TLS segment?
Yes, all the TLS input segments will be merged into `.tdata`.


================
Comment at: llvm/include/llvm/IR/IntrinsicsWebAssembly.td:134
+            [],
+            [IntrNoMem, IntrSpeculatable]>;
+
----------------
aheejin wrote:
> - Why is it speculatable?
> - I'm not sure if it's `InstNoMem`, because wasm globals can be memory locations after all. What do other people think?
@tlively suggested that I do this. It should be speculatable because it has no side effects (since it returns a constant). As for `InstrNoMem`, I am not sure if globals are memory, and whether reading a constant counts as memory access.


================
Comment at: llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp:1095
+WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op,
+                                                 SelectionDAG &DAG) const {
+  SDLoc DL(Op);
----------------
aheejin wrote:
> If you do the conversion in `WebAssemblyISelDAGToDAG.cpp`, you don't need to create `WebAssemblyISD` node,  `SDTypeProfile`, and `SDNode` for every single instruction you want to generate. This `WebAssemblyISelLowering.cpp` is a part of legalization so it cannot generate machine instructions directly, whereas `WebAssemblyISelDAGToDAG.cpp` is a part of instruction selection so you have direct access to machine instructions. I think moving routines there can be cleaner?
It seems most other architectures do it in `*TargetLowering`, so I decided to do the same.


================
Comment at: llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp:1109
+      WebAssemblyISD::CONST_I32, DL, VT,
+      DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(), 0));
+
----------------
aheejin wrote:
> Does this offset work when there are non-thread-local globals too?
Yes, the linker handles the offsets. All thread locals are grouped together by the linker.


================
Comment at: llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp:192
       Stripped |= stripAtomics(M);
-      Stripped |= stripThreadLocals(M);
     }
----------------
aheejin wrote:
> Looks like this feature requires both bulk memory and mutable global. Shouldn't we strip thread locals if either is not enabled?
Do we want to do that? I think having your thread locals vanish if you didn't pass `-mbulk-memory` is surprising. It might make more sense to strip thread locals if `-pthread` is not passed.


================
Comment at: llvm/test/CodeGen/WebAssembly/target-features-tls.ll:23
 ; ATOMICS-NEXT: .ascii "atomics"
 ; ATOMICS-NEXT: .tbss.foo,"",@
----------------
aheejin wrote:
> Is thread local feature still dependent on atomics? If not, do we still need to test this with both atomics on and off? This now looks rather dependent on bulk memory and mutable global. Should we test this feature with those options instead? (I can be mistaken, so please let me know if so)
On second thought, this test is somewhat meaningless now, since the thread local is always created regardless of whether atomics are enabled. What does @tlively think?


================
Comment at: llvm/test/CodeGen/WebAssembly/tls.ll:16
+  ; O2-NEXT: i32.const tls
+  ; O2-NEXT: i32.add
+  ; O2-NEXT: return
----------------
aheejin wrote:
> If the only difference of O0 and O2 results is the order of `global.get` and `i32.const`, you can use [[ https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-dag-directive | `CHECK-DAG` ]] directive, like
> ```
> ; CHECK-DAG: global.get __tls_base
> ; CHECK-DAG: i32.const tls
> ...
> ```
> 
> The same for other functions too. Maybe we don't need separate O0 and O2 testing in this file.
Will do. I didn't know `CHECK-DAG` existed.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64537/new/

https://reviews.llvm.org/D64537





More information about the cfe-commits mailing list