Index: lld/test/wasm/Inputs/call-ret32.s =================================================================== --- lld/test/wasm/Inputs/call-ret32.s +++ lld/test/wasm/Inputs/call-ret32.s @@ -1,3 +1,5 @@ +.functype ret32 (f32) -> (i32) + .globl call_ret32 call_ret32: .functype call_ret32 () -> (i32) @@ -12,5 +14,3 @@ ret32_address: .int32 ret32 .size ret32_address, 4 - - .functype ret32 (f32) -> (i32) Index: lld/test/wasm/Inputs/ctor-lib.s =================================================================== --- lld/test/wasm/Inputs/ctor-lib.s +++ lld/test/wasm/Inputs/ctor-lib.s @@ -1,3 +1,5 @@ + .functype def () -> () + .section .text.lib_func,"",@ .globl lib_func lib_func: Index: lld/test/wasm/Inputs/ctor-setup-call-def.s =================================================================== --- lld/test/wasm/Inputs/ctor-setup-call-def.s +++ lld/test/wasm/Inputs/ctor-setup-call-def.s @@ -1,6 +1,8 @@ # Like Inputs/ctor-setup.s, except it calls `def` instead of `lib_func`, # so it pulls in the .o file containing `ctor`. +.functype def () -> () + .section .text._start,"",@ .globl _start _start: @@ -17,5 +19,3 @@ .section .init_array,"",@ .p2align 2 .int32 setup - -.functype def () -> () Index: lld/test/wasm/Inputs/ctor-setup.s =================================================================== --- lld/test/wasm/Inputs/ctor-setup.s +++ lld/test/wasm/Inputs/ctor-setup.s @@ -1,6 +1,8 @@ # Like Inputs/ctor-start.s, except it calls `lib_func` from a ctor # instead of from `_start`. +.functype lib_func () -> () + .globl _start _start: .functype _start () -> () @@ -16,4 +18,3 @@ .p2align 2 .int32 setup - .functype lib_func () -> () Index: lld/test/wasm/Inputs/ctor-start.s =================================================================== --- lld/test/wasm/Inputs/ctor-start.s +++ lld/test/wasm/Inputs/ctor-start.s @@ -1,7 +1,8 @@ +.functype lib_func () -> () + .globl _start _start: .functype _start () -> () call lib_func end_function - .functype lib_func () -> () Index: lld/test/wasm/Inputs/hello.s =================================================================== --- lld/test/wasm/Inputs/hello.s +++ lld/test/wasm/Inputs/hello.s @@ -2,6 +2,8 @@ # void puts(const char*); # void hello() { puts("hello\n"); } + .functype puts (i32) -> () + .globl hello hello: .functype hello () -> () @@ -14,5 +16,3 @@ hello_str: .asciz "hello\n" .size hello_str, 7 - - .functype puts (i32) -> () Index: lld/test/wasm/Inputs/import-attributes.s =================================================================== --- lld/test/wasm/Inputs/import-attributes.s +++ lld/test/wasm/Inputs/import-attributes.s @@ -1,8 +1,9 @@ +.functype foo () -> () + .globl call_foo call_foo: .functype call_foo () -> () call foo end_function - .functype foo () -> () .import_module foo, baz Index: lld/test/wasm/Inputs/sig_mismatch.s =================================================================== --- lld/test/wasm/Inputs/sig_mismatch.s +++ lld/test/wasm/Inputs/sig_mismatch.s @@ -8,5 +8,6 @@ .globl call_foo call_foo: .functype call_foo () -> (i32) + f32.const 0.0 call foo end_function Index: lld/test/wasm/Inputs/undefined-globals.s =================================================================== --- lld/test/wasm/Inputs/undefined-globals.s +++ lld/test/wasm/Inputs/undefined-globals.s @@ -2,10 +2,10 @@ .globl unused_undef_global .globl used_undef_global +.globaltype unused_undef_global, i64, immutable +.globaltype used_undef_global, i64, immutable + use_undef_global: .functype use_undef_global () -> (i64) global.get used_undef_global end_function - -.globaltype unused_undef_global, i64, immutable -.globaltype used_undef_global, i64, immutable Index: lld/test/wasm/bsymbolic.s =================================================================== --- lld/test/wasm/bsymbolic.s +++ lld/test/wasm/bsymbolic.s @@ -100,6 +100,7 @@ // SYMBOLIC-NEXT: - Type: EXPORT .globl foo + foo: .functype foo () -> () end_function Index: lld/test/wasm/comdat-sections.s =================================================================== --- lld/test/wasm/comdat-sections.s +++ lld/test/wasm/comdat-sections.s @@ -4,6 +4,7 @@ # RUN: wasm-ld -o %t.wasm %t.o %t1.o %t2.o # RUN: obj2yaml %t.wasm | FileCheck %s + .functype foo () -> () .globl _start .type _start,@function @@ -12,8 +13,6 @@ call foo end_function - .functype foo () -> () - # Check that we got 1 copy of each of the .debug_foo sections from the 2 object # files, and that they came from the same object. Index: lld/test/wasm/ctor_return_value.s =================================================================== --- lld/test/wasm/ctor_return_value.s +++ lld/test/wasm/ctor_return_value.s @@ -2,6 +2,8 @@ # RUN: wasm-ld %t.o -o %t.wasm # RUN: obj2yaml %t.wasm | FileCheck %s + .functype __wasm_call_ctors () -> () + .globl myctor myctor: .functype myctor () -> (i32) Index: lld/test/wasm/debuginfo-undefined-global.s =================================================================== --- lld/test/wasm/debuginfo-undefined-global.s +++ lld/test/wasm/debuginfo-undefined-global.s @@ -7,6 +7,8 @@ # foo which is not otherwise used and will not be marked a live in the output. # Verify the tombstone value is written to debug_info section. +.globaltype foo, i32 + .globl _start _start: .functype _start () -> () @@ -15,7 +17,6 @@ .section .debug_info,"",@ .int32 foo -.globaltype foo, i32 foo: # CHECK: - Type: CUSTOM Index: lld/test/wasm/demangle.s =================================================================== --- lld/test/wasm/demangle.s +++ lld/test/wasm/demangle.s @@ -8,6 +8,8 @@ # CHECK-NODEMANGLE: error: {{.*}}.o: undefined symbol: _Z3fooi +.functype _Z3fooi (i32) -> () + .globl _start _start: .functype _start () -> () @@ -15,4 +17,3 @@ call _Z3fooi end_function -.functype _Z3fooi (i32) -> () Index: lld/test/wasm/early-exit-for-bad-paths.s =================================================================== --- lld/test/wasm/early-exit-for-bad-paths.s +++ lld/test/wasm/early-exit-for-bad-paths.s @@ -22,6 +22,8 @@ # RUN: not wasm-ld %t.o -o / 2>&1 | FileCheck %s -check-prefixes=ROOT,CHECK # ROOT: error: cannot open output file / +.functype undefined_symbol () -> () + _start: .functype _start () -> () call undefined_symbol Index: lld/test/wasm/entry-signature.s =================================================================== --- lld/test/wasm/entry-signature.s +++ lld/test/wasm/entry-signature.s @@ -5,4 +5,5 @@ .globl _start _start: .functype _start (i64) -> (f32) + f32.const 0.0 end_function Index: lld/test/wasm/export-all.s =================================================================== --- lld/test/wasm/export-all.s +++ lld/test/wasm/export-all.s @@ -2,6 +2,8 @@ # RUN: wasm-ld --export-all -o %t.wasm %t.o # RUN: obj2yaml %t.wasm | FileCheck %s +.globaltype __stack_pointer, i32 + .globl _start _start: @@ -15,8 +17,6 @@ i32.const 42 end_function -.globaltype __stack_pointer, i32 - # CHECK: - Type: EXPORT # CHECK-NEXT: Exports: # CHECK-NEXT: - Name: memory Index: lld/test/wasm/export-optional.s =================================================================== --- lld/test/wasm/export-optional.s +++ lld/test/wasm/export-optional.s @@ -8,6 +8,7 @@ .globl _start _start: .functype _start () -> () + i32.const 0 i32.load foo drop end_function Index: lld/test/wasm/gc-imports.s =================================================================== --- lld/test/wasm/gc-imports.s +++ lld/test/wasm/gc-imports.s @@ -7,7 +7,8 @@ .functype use_undef_global () -> (i64) foo: - .functype foo () -> () + .functype foo (i64) -> (i64) + local.get 0 call unused_undef_function end_function @@ -16,7 +17,9 @@ _start: .functype _start () -> () call used_undef_function + drop call use_undef_global + drop end_function # RUN: obj2yaml %t1.wasm | FileCheck %s Index: lld/test/wasm/import-attribute-mismatch.s =================================================================== --- lld/test/wasm/import-attribute-mismatch.s +++ lld/test/wasm/import-attribute-mismatch.s @@ -2,13 +2,14 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %S/Inputs/import-attributes.s -o %t2.o # RUN: not wasm-ld --export call_foo --allow-undefined -o %t.wasm %t1.o %t2.o 2>&1 | FileCheck %s +.functype foo () -> () + .globl _start _start: .functype _start () -> () call foo end_function -.functype foo () -> () .import_module foo, bar # CHECK: wasm-ld: error: import module mismatch for symbol: foo Index: lld/test/wasm/map-file.s =================================================================== --- lld/test/wasm/map-file.s +++ lld/test/wasm/map-file.s @@ -8,7 +8,7 @@ wasm_global: bar: - .functype bar () -> () + .functype bar () -> (i32) i32.const somedata end_function @@ -34,27 +34,27 @@ .int32 bar # CHECK: Addr Off Size Out In Symbol -# CHECK-NEXT: - 8 a TYPE -# CHECK-NEXT: - 12 6 FUNCTION -# CHECK-NEXT: - 18 7 TABLE -# CHECK-NEXT: - 1f 5 MEMORY -# CHECK-NEXT: - 24 f GLOBAL +# CHECK-NEXT: - 8 e TYPE +# CHECK-NEXT: - 16 6 FUNCTION +# CHECK-NEXT: - 1c 7 TABLE +# CHECK-NEXT: - 23 5 MEMORY +# CHECK-NEXT: - 28 f GLOBAL # CHECK-NEXT: 0 0 0 __stack_pointer # CHECK-NEXT: 1 0 0 wasm_global -# CHECK-NEXT: - 33 15 EXPORT -# CHECK-NEXT: - 48 26 CODE -# CHECK-NEXT: - 49 9 {{.*}}{{/|\\}}map-file.s.tmp1.o:(bar) -# CHECK-NEXT: - 49 9 bar -# CHECK-NEXT: - 52 b {{.*}}{{/|\\}}map-file.s.tmp1.o:(write_global) -# CHECK-NEXT: - 52 b write_global -# CHECK-NEXT: - 5d f {{.*}}{{/|\\}}map-file.s.tmp1.o:(_start) -# CHECK-NEXT: - 5d f _start -# CHECK-NEXT: - 6e d DATA -# CHECK-NEXT: 400 6f 4 .data -# CHECK-NEXT: 400 75 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.data.somedata) -# CHECK-NEXT: 400 75 4 somedata -# CHECK-NEXT: - 7b 12 CUSTOM(.debug_info) -# CHECK-NEXT: - 8d 50 CUSTOM(name) +# CHECK-NEXT: - 37 15 EXPORT +# CHECK-NEXT: - 4c 26 CODE +# CHECK-NEXT: - 4d 9 {{.*}}{{/|\\}}map-file.s.tmp1.o:(bar) +# CHECK-NEXT: - 4d 9 bar +# CHECK-NEXT: - 56 b {{.*}}{{/|\\}}map-file.s.tmp1.o:(write_global) +# CHECK-NEXT: - 56 b write_global +# CHECK-NEXT: - 61 f {{.*}}{{/|\\}}map-file.s.tmp1.o:(_start) +# CHECK-NEXT: - 61 f _start +# CHECK-NEXT: - 72 d DATA +# CHECK-NEXT: 400 73 4 .data +# CHECK-NEXT: 400 79 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.data.somedata) +# CHECK-NEXT: 400 79 4 somedata +# CHECK-NEXT: - 7f 12 CUSTOM(.debug_info) +# CHECK-NEXT: - 91 50 CUSTOM(name) # RUN: not wasm-ld %t1.o -o /dev/null -Map=/ 2>&1 \ # RUN: | FileCheck -check-prefix=FAIL %s Index: lld/test/wasm/multivalue-return-func-types.s =================================================================== --- lld/test/wasm/multivalue-return-func-types.s +++ lld/test/wasm/multivalue-return-func-types.s @@ -9,23 +9,6 @@ .globl fn_i64_f64_i32_f32 -_start: - .functype _start () -> () - call fn_i32 - drop - call fn_i32_i32 - drop - drop - call fn_i32_i64 - drop - drop - call fn_i64_f64_i32_f32 - drop - drop - drop - drop - end_function - fn_i32: .functype fn_i32 () -> (i32) i32.const 1 @@ -51,6 +34,23 @@ f32.const 1.0 end_function +_start: + .functype _start () -> () + call fn_i32 + drop + call fn_i32_i32 + drop + drop + call fn_i32_i64 + drop + drop + call fn_i64_f64_i32_f32 + drop + drop + drop + drop + end_function + # CHECK: - Type: TYPE # CHECK-NEXT: Signatures: Index: lld/test/wasm/mutable-globals.s =================================================================== --- lld/test/wasm/mutable-globals.s +++ lld/test/wasm/mutable-globals.s @@ -2,6 +2,8 @@ # RUN: not wasm-ld %t.o -o %t.wasm 2>&1 | FileCheck %s # RUN: wasm-ld --features=mutable-globals %t.o -o %t.wasm +.globaltype foo, i32 + .globl _start _start: .functype _start () -> () @@ -9,7 +11,6 @@ global.set foo end_function -.globaltype foo, i32 .import_module foo, env .import_name foo, foo Index: lld/test/wasm/name-section-mangling.s =================================================================== --- lld/test/wasm/name-section-mangling.s +++ lld/test/wasm/name-section-mangling.s @@ -11,6 +11,12 @@ .globl _Z3fooi .weak _Z3bari +.functype _Z3bari (i32) -> () + +_Z3fooi: + .functype _Z3fooi (i32) -> () + end_function + _start: .functype _start () -> () i32.const 1 @@ -19,12 +25,6 @@ call _Z3bari end_function -_Z3fooi: - .functype _Z3fooi (i32) -> () - end_function - -.functype _Z3bari (i32) -> () - # CHECK: - Type: EXPORT # CHECK-NEXT: Exports: # CHECK-NEXT: - Name: memory Index: lld/test/wasm/relocatable-comdat.s =================================================================== --- lld/test/wasm/relocatable-comdat.s +++ lld/test/wasm/relocatable-comdat.s @@ -8,7 +8,9 @@ .type _start,@function _start: .functype _start () -> () + i32.const 0 i32.load foo + drop end_function Index: lld/test/wasm/relocation-bad-tls.s =================================================================== --- lld/test/wasm/relocation-bad-tls.s +++ lld/test/wasm/relocation-bad-tls.s @@ -6,6 +6,8 @@ .functype _start () -> () i32.const foo@TLSREL i32.const bar@TLSREL + drop + drop end_function .section .data,"",@ Index: lld/test/wasm/shared.s =================================================================== --- lld/test/wasm/shared.s +++ lld/test/wasm/shared.s @@ -2,6 +2,13 @@ # RUN: wasm-ld --experimental-pic -shared -o %t.wasm %t.o # RUN: obj2yaml %t.wasm | FileCheck %s +.functype func_external () -> () + +# Linker-synthesized globals +.globaltype __stack_pointer, i32 +.globaltype __table_base, i32, immutable +.globaltype __memory_base, i32, immutable + .section .data.data,"",@ data: .p2align 2 @@ -116,13 +123,6 @@ .int8 15 .ascii "mutable-globals" -.functype func_external () -> () - -# Linker-synthesized globals -.globaltype __stack_pointer, i32 -.globaltype __table_base, i32, immutable -.globaltype __memory_base, i32, immutable - # check for dylink section at start # CHECK: Sections: Index: lld/test/wasm/shared64.s =================================================================== --- lld/test/wasm/shared64.s +++ lld/test/wasm/shared64.s @@ -2,6 +2,13 @@ # RUN: wasm-ld -mwasm64 --experimental-pic -shared -o %t.wasm %t.o # RUN: obj2yaml %t.wasm | FileCheck %s +.functype func_external () -> () + +# Linker-synthesized globals +.globaltype __stack_pointer, i64 +.globaltype __table_base, i64, immutable +.globaltype __memory_base, i64, immutable + .section .data.data,"",@ data: .p2align 2 @@ -29,8 +36,8 @@ .section .data.data_addr_external,"",@ data_addr_external: - .int32 data_external - .size data_addr_external, 4 + .int64 data_external + .size data_addr_external, 8 # .. including addends @@ -72,12 +79,12 @@ end_function get_func_address: - .functype get_func_address () -> (i32) + .functype get_func_address () -> (i64) global.get func_external@GOT end_function get_data_address: - .functype get_data_address () -> (i32) + .functype get_data_address () -> (i64) global.get data_external@GOT end_function @@ -116,19 +123,12 @@ .int8 15 .ascii "mutable-globals" -.functype func_external () -> () - -# Linker-synthesized globals -.globaltype __stack_pointer, i64 -.globaltype __table_base, i64, immutable -.globaltype __memory_base, i64, immutable - # check for dylink section at start # CHECK: Sections: # CHECK-NEXT: - Type: CUSTOM # CHECK-NEXT: Name: dylink -# CHECK-NEXT: MemorySize: 24 +# CHECK-NEXT: MemorySize: 28 # CHECK-NEXT: MemoryAlignment: 2 # CHECK-NEXT: TableSize: 2 # CHECK-NEXT: TableAlignment: 0 @@ -224,7 +224,7 @@ # CHECK-NEXT: Body: 10020B # CHECK-NEXT: - Index: 2 # CHECK-NEXT: Locals: [] -# CHECK-NEXT: Body: 230142047C2305360200230142087C230241016A3602002301420C7C230141006A360200230142107C2306360200230142147C230741046A3602000B +# CHECK-NEXT: Body: 230142047C2305360200230142087C230241016A3602002301420C7C230141006A360200230142107C2306370200230142187C230741046A3602000B # check the data segment initialized with __memory_base global as offset @@ -235,4 +235,4 @@ # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: GLOBAL_GET # CHECK-NEXT: Index: 1 -# CHECK-NEXT: Content: '020000000000000001000000000000000000000000000000' +# CHECK-NEXT: Content: '02000000000000000100000000000000000000000000000000000000' Index: lld/test/wasm/signature-mismatch-relocatable.s =================================================================== --- lld/test/wasm/signature-mismatch-relocatable.s +++ lld/test/wasm/signature-mismatch-relocatable.s @@ -8,6 +8,8 @@ # function was seen first and the defined function was referenced within the # the defining file (see %S/Inputs/sig_mismatch.s). +.functype foo (i32, i64, i32) -> (i32) + .globl _start _start: .functype _start () -> () @@ -15,10 +17,9 @@ i64.const 2 i32.const 3 call foo + drop end_function -.functype foo (i32, i64, i32) -> (i32) - # CHECK: - Type: CUSTOM # CHECK-NEXT: Name: linking # CHECK-NEXT: Version: 2 Index: lld/test/wasm/undefined-data.s =================================================================== --- lld/test/wasm/undefined-data.s +++ lld/test/wasm/undefined-data.s @@ -6,6 +6,7 @@ .globl _start _start: .functype _start () -> (i32) + i32.const 0 i32.load data_external end_function Index: lld/test/wasm/undefined-weak-call.s =================================================================== --- lld/test/wasm/undefined-weak-call.s +++ lld/test/wasm/undefined-weak-call.s @@ -7,6 +7,11 @@ # Check that calling an undefined weak function generates an appropriate stub # that will fail at runtime with "unreachable". +.functype weakFunc1 () -> () +.functype weakFunc2 () -> () +.functype weakFunc3 (i32) -> () +.functype weakFunc4 () -> () + .globl callWeakFuncs callWeakFuncs: @@ -24,10 +29,6 @@ .weak weakFunc2 .weak weakFunc3 .weak weakFunc4 -.functype weakFunc1 () -> () -.functype weakFunc2 () -> () -.functype weakFunc3 (i32) -> () -.functype weakFunc4 () -> () # CHECK-GC: removing unused section {{.*}}:(weakFunc4) Index: lld/test/wasm/unresolved-symbols.s =================================================================== --- lld/test/wasm/unresolved-symbols.s +++ lld/test/wasm/unresolved-symbols.s @@ -32,7 +32,7 @@ # IGNORE-NEXT: Body: 000B # IGNORE-NEXT: - Index: 1 # IGNORE-NEXT: Locals: [] -# IGNORE-NEXT: Body: 1080808080001082808080001083808080000B +# IGNORE-NEXT: Body: 1080808080001082808080001083808080001A1A0B # IGNORE-NEXT: - Index: 2 # IGNORE-NEXT: Locals: [] # IGNORE-NEXT: Body: 4180808080000F0B @@ -69,12 +69,18 @@ # RUN: wasm-ld -r %t1.o -o %t4.wasm --unresolved-symbols=report-all # RUN: llvm-readobj %t4.wasm > /dev/null 2>&1 +.functype undef () -> () +.functype get_data_addr () -> (i32) +.functype get_func_addr () -> (i32) + .globl _start _start: .functype _start () -> () call undef call get_data_addr call get_func_addr + drop + drop end_function .globl get_data_addr @@ -90,5 +96,3 @@ i32.const undef return end_function - -.functype undef () -> () Index: lld/test/wasm/weak-and-strong-undef.s =================================================================== --- lld/test/wasm/weak-and-strong-undef.s +++ lld/test/wasm/weak-and-strong-undef.s @@ -9,10 +9,10 @@ # CHECK: undefined symbol: foo +.functype foo () -> () + _start: .globl _start .functype _start () -> () call foo end_function - -.functype foo () -> () Index: lld/test/wasm/weak-symbols.s =================================================================== --- lld/test/wasm/weak-symbols.s +++ lld/test/wasm/weak-symbols.s @@ -4,6 +4,8 @@ # RUN: wasm-ld --export-dynamic -o %t.wasm %t.o %t1.o %t2.o # RUN: obj2yaml %t.wasm | FileCheck %s +.functype weakFn () -> (i32) + .globl _start _start: .functype _start () -> () @@ -11,7 +13,6 @@ drop end_function -.functype weakFn () -> (i32) .size weakGlobal, 4 # CHECK: --- !WASM Index: lld/test/wasm/weak-undefined-pic.s =================================================================== --- lld/test/wasm/weak-undefined-pic.s +++ lld/test/wasm/weak-undefined-pic.s @@ -12,6 +12,8 @@ # RUN: wasm-ld --unresolved-symbols=ignore-all %t.o -o %t2.wasm # RUN: obj2yaml %t2.wasm | FileCheck %s +.functype foo () -> (i32) + .globl get_foo_addr get_foo_addr: .functype get_foo_addr () -> (i32) @@ -20,12 +22,11 @@ .globl _start _start: - .functype _start () -> () + .functype _start () -> (i32) call get_foo_addr end_function .weak foo -.functype foo () -> (i32) # Verify that we do not generate dynamic relocations for the GOT entry. Index: lld/test/wasm/weak-undefined.s =================================================================== --- lld/test/wasm/weak-undefined.s +++ lld/test/wasm/weak-undefined.s @@ -5,6 +5,8 @@ # Test that undefined weak externals (global_var) and (foo) don't cause # link failures and resolve to zero. +.functype foo () -> (i32) + .globl get_address_of_foo get_address_of_foo: .functype get_address_of_foo () -> (i32) @@ -30,7 +32,6 @@ .weak foo .weak global_var -.functype foo () -> (i32) # CHECK: --- !WASM Index: llvm/include/llvm/CodeGen/MachineModuleInfo.h =================================================================== --- llvm/include/llvm/CodeGen/MachineModuleInfo.h +++ llvm/include/llvm/CodeGen/MachineModuleInfo.h @@ -185,7 +185,7 @@ /// Machine Function map. void deleteMachineFunctionFor(Function &F); - /// Keep track of various per-function pieces of information for backends + /// Keep track of various per-module pieces of information for backends /// that would like to do so. template Ty &getObjFileInfo() { Index: llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h =================================================================== --- llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h +++ llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h @@ -15,6 +15,7 @@ #define LLVM_CODEGEN_MACHINEMODULEINFOIMPLS_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringSet.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include @@ -101,6 +102,17 @@ SymbolListTy GetGVStubList() { return getSortedStubs(GVStubs); } }; +/// MachineModuleInfoWasm - This is a MachineModuleInfoImpl implementation +/// for Wasm targets. +class MachineModuleInfoWasm : public MachineModuleInfoImpl { + virtual void anchor(); // Out of line virtual method. + +public: + MachineModuleInfoWasm(const MachineModuleInfo &) {} + + StringSet<> MachineSymbolsUsed; +}; + } // end namespace llvm #endif // LLVM_CODEGEN_MACHINEMODULEINFOIMPLS_H Index: llvm/include/llvm/MC/MCTargetOptions.h =================================================================== --- llvm/include/llvm/MC/MCTargetOptions.h +++ llvm/include/llvm/MC/MCTargetOptions.h @@ -45,6 +45,7 @@ bool MCFatalWarnings : 1; bool MCNoWarn : 1; bool MCNoDeprecatedWarn : 1; + bool MCNoTypeCheck : 1; bool MCSaveTempLabels : 1; bool MCUseDwarfDirectory : 1; bool MCIncrementalLinkerCompatible : 1; Index: llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h =================================================================== --- llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h +++ llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h @@ -40,6 +40,8 @@ bool getNoDeprecatedWarn(); +bool getNoTypeCheck(); + std::string getABIName(); /// Create this object with static storage to register mc-related command Index: llvm/lib/CodeGen/MachineModuleInfoImpls.cpp =================================================================== --- llvm/lib/CodeGen/MachineModuleInfoImpls.cpp +++ llvm/lib/CodeGen/MachineModuleInfoImpls.cpp @@ -25,6 +25,7 @@ void MachineModuleInfoMachO::anchor() {} void MachineModuleInfoELF::anchor() {} void MachineModuleInfoCOFF::anchor() {} +void MachineModuleInfoWasm::anchor() {} using PairTy = std::pair; static int SortSymbolPair(const PairTy *LHS, const PairTy *RHS) { Index: llvm/lib/MC/MCTargetOptions.cpp =================================================================== --- llvm/lib/MC/MCTargetOptions.cpp +++ llvm/lib/MC/MCTargetOptions.cpp @@ -13,7 +13,8 @@ MCTargetOptions::MCTargetOptions() : MCRelaxAll(false), MCNoExecStack(false), MCFatalWarnings(false), - MCNoWarn(false), MCNoDeprecatedWarn(false), MCSaveTempLabels(false), + MCNoWarn(false), MCNoDeprecatedWarn(false), + MCNoTypeCheck(false), MCSaveTempLabels(false), MCUseDwarfDirectory(false), MCIncrementalLinkerCompatible(false), ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false), PreserveAsmComments(true), Dwarf64(false) {} Index: llvm/lib/MC/MCTargetOptionsCommandFlags.cpp =================================================================== --- llvm/lib/MC/MCTargetOptionsCommandFlags.cpp +++ llvm/lib/MC/MCTargetOptionsCommandFlags.cpp @@ -43,6 +43,7 @@ MCOPT(bool, FatalWarnings) MCOPT(bool, NoWarn) MCOPT(bool, NoDeprecatedWarn) +MCOPT(bool, NoTypeCheck) MCOPT(std::string, ABIName) llvm::mc::RegisterMCTargetOptionsFlags::RegisterMCTargetOptionsFlags() { @@ -90,6 +91,10 @@ "no-deprecated-warn", cl::desc("Suppress all deprecated warnings")); MCBINDOPT(NoDeprecatedWarn); + static cl::opt NoTypeCheck( + "no-type-check", cl::desc("Suppress type errors (Wasm)")); + MCBINDOPT(NoTypeCheck); + static cl::opt ABIName( "target-abi", cl::Hidden, cl::desc("The name of the ABI to be targeted from the backend."), @@ -110,5 +115,6 @@ Options.MCFatalWarnings = getFatalWarnings(); Options.MCNoWarn = getNoWarn(); Options.MCNoDeprecatedWarn = getNoDeprecatedWarn(); + Options.MCNoTypeCheck = getNoTypeCheck(); return Options; } Index: llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp =================================================================== --- llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -31,6 +31,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolWasm.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; @@ -38,6 +39,7 @@ #define DEBUG_TYPE "wasm-asm-parser" static const char *getSubtargetFeatureName(uint64_t Val); +static StringRef GetMnemonic(unsigned Opc); namespace { @@ -225,17 +227,46 @@ Else, Undefined, }; - std::vector NestingStack; + struct Nested { + NestingType NT; + wasm::WasmSignature Sig; + }; + std::vector NestingStack; + wasm::WasmSignature LastSig; MCSymbolWasm *DefaultFunctionTable = nullptr; MCSymbol *LastFunctionLabel = nullptr; + bool is64 = false; + + // Type Checker: + struct TypeStack { + SmallVector Stack; + }; + TypeStack TS; + std::map TypedLabels; + std::vector LocalTypes; + std::vector ReturnTypes; + bool TypeErrorThisFunction = false; + bool SkipTypeCheck = false; + public: WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) : MCTargetAsmParser(Options, STI, MII), Parser(Parser), Lexer(Parser.getLexer()) { setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + is64 = getSTI().getTargetTriple().isArch64Bit(); + // Don't type check if -no-type-check was set. + if (Options.MCNoTypeCheck) + SkipTypeCheck = true; + // Don't type check if this is inline asm, since that is a naked sequence of + // instructions without a function/locals decl. + auto &SM = Parser.getSourceManager(); + auto BufferName = + SM.getBufferInfo(SM.getMainFileID()).Buffer->getBufferIdentifier(); + if (BufferName == "") + SkipTypeCheck = true; } void Initialize(MCAsmParser &Parser) override { @@ -300,15 +331,16 @@ } } - void push(NestingType NT) { NestingStack.push_back(NT); } + void push(NestingType NT) { NestingStack.push_back({NT}); } bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) { if (NestingStack.empty()) return error(Twine("End of block construct with no start: ") + Ins); auto Top = NestingStack.back(); - if (Top != NT1 && Top != NT2) + if (Top.NT != NT1 && Top.NT != NT2) return error(Twine("Block construct type mismatch, expected: ") + - nestingString(Top).second + ", instead got: " + Ins); + nestingString(Top.NT).second + ", instead got: " + Ins); + LastSig = Top.Sig; NestingStack.pop_back(); return false; } @@ -317,7 +349,7 @@ auto Err = !NestingStack.empty(); while (!NestingStack.empty()) { error(Twine("Unmatched block construct(s) at function end: ") + - nestingString(NestingStack.back()).first); + nestingString(NestingStack.back().NT).first); NestingStack.pop_back(); } return Err; @@ -446,6 +478,11 @@ void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc, WebAssembly::BlockType BT) { + if (BT != WebAssembly::BlockType::Void) { + wasm::WasmSignature Sig({static_cast(BT)}, {}); + LastSig = Sig; + NestingStack.back().Sig = Sig; + } Operands.push_back(std::make_unique( WebAssemblyOperand::Integer, NameLoc, NameLoc, WebAssemblyOperand::IntOp{static_cast(BT)})); @@ -612,6 +649,8 @@ return true; // Got signature as block type, don't need more ExpectBlockType = false; + LastSig = *Signature.get(); + if (ExpectBlockType) NestingStack.back().Sig = LastSig; auto &Ctx = getContext(); // The "true" here will cause this to be a nameless symbol. MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true); @@ -855,6 +894,8 @@ auto Signature = std::make_unique(); if (parseSignature(Signature.get())) return true; + LocalTypes.assign(Signature->Params.begin(), Signature->Params.end()); + ReturnTypes.assign(Signature->Returns.begin(), Signature->Returns.end()); WasmSym->setSignature(Signature.get()); addSignature(std::move(Signature)); WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); @@ -922,6 +963,7 @@ SmallVector Locals; if (parseRegTypeList(Locals)) return true; + LocalTypes.insert(LocalTypes.end(), Locals.begin(), Locals.end()); TOut.emitLocal(Locals); CurrentState = FunctionLocals; return expect(AsmToken::EndOfStatement, "EOL"); @@ -967,6 +1009,191 @@ } } + void DumpTypeStack(Twine Msg) { + LLVM_DEBUG({ + std::string s; + for (auto VT : TS.Stack) { + s += WebAssembly::typeToString(VT); + s += " "; + } + dbgs() << Msg << s << '\n'; + }); + } + + bool TypeError(SMLoc ErrorLoc, const Twine &Msg) { + // Once you get one type error in a function, it will likely trigger more + // which are mostly not helpful. + if (TypeErrorThisFunction) + return true; + TypeErrorThisFunction = true; + DumpTypeStack("current stack: "); + return Parser.Error(ErrorLoc, Msg); + } + + bool PopType(SMLoc ErrorLoc, Optional EVT) { + if (TS.Stack.empty()) { + return TypeError(ErrorLoc, + EVT.hasValue() + ? StringRef("empty stack while popping ") + + WebAssembly::typeToString(EVT.getValue()) + : StringRef( + "empty stack while popping value")); + } + auto PVT = TS.Stack.back(); + TS.Stack.pop_back(); + if (EVT.hasValue() && EVT.getValue() != PVT) { + return TypeError( + ErrorLoc, StringRef("popped ") + WebAssembly::typeToString(PVT) + + ", expected " + + WebAssembly::typeToString(EVT.getValue())); + } + return false; + } + + bool GetLocal(SMLoc ErrorLoc, const MCInst &Inst, wasm::ValType &Type) { + auto Local = Inst.getOperand(0).getImm(); + if (static_cast(Local) > LocalTypes.size()) + return TypeError(ErrorLoc, StringRef("no local type specified for index ") + + std::to_string(Local)); + Type = LocalTypes[Local]; + return false; + } + + bool CheckEnd(SMLoc ErrorLoc) { + if (LastSig.Returns.size() > TS.Stack.size()) + return TypeError(ErrorLoc, "end: insufficient values on the type stack"); + for (size_t i = 0; i < LastSig.Returns.size(); i++) { + auto EVT = LastSig.Returns[i]; + auto PVT = TS.Stack[TS.Stack.size() - LastSig.Returns.size() + i]; + if (PVT != EVT) + return TypeError( + ErrorLoc, StringRef("end got ") + WebAssembly::typeToString(PVT) + + ", expected " + WebAssembly::typeToString(EVT)); + } + return false; + } + + bool CheckSig(SMLoc ErrorLoc, const wasm::WasmSignature& Sig) { + for (auto VT : llvm::reverse(Sig.Params)) + if (PopType(ErrorLoc, VT)) return true; + TS.Stack.insert(TS.Stack.end(), Sig.Returns.begin(), Sig.Returns.end()); + return false; + } + + bool GetSymRef(SMLoc ErrorLoc, const MCInst &Inst, + const MCSymbolRefExpr *&SymRef) { + auto Op = Inst.getOperand(0); + if (!Op.isExpr()) + return TypeError(ErrorLoc, StringRef("expected expression operand")); + SymRef = dyn_cast(Op.getExpr()); + if (!SymRef) + return TypeError(ErrorLoc, StringRef("expected symbol operand")); + return false; + } + + bool GetGlobal(SMLoc ErrorLoc, const MCInst &Inst, wasm::ValType &Type) { + const MCSymbolRefExpr *SymRef; + if (GetSymRef(ErrorLoc, Inst, SymRef)) + return true; + auto WasmSym = cast(&SymRef->getSymbol()); + switch (WasmSym->getType().getValueOr(wasm::WASM_SYMBOL_TYPE_DATA)) { + case wasm::WASM_SYMBOL_TYPE_GLOBAL: + Type = static_cast(WasmSym->getGlobalType().Type); + break; + case wasm::WASM_SYMBOL_TYPE_FUNCTION: + case wasm::WASM_SYMBOL_TYPE_DATA: + if (SymRef->getKind() == MCSymbolRefExpr::VK_GOT) { + Type = is64 ? wasm::ValType::I64 : wasm::ValType::I32; + break; + } + // FALL-THROUGH: + default: + return TypeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + + " missing .globaltype"); + } + return false; + } + + bool TypeCheck(SMLoc ErrorLoc, const MCInst &Inst) { + auto Opc = Inst.getOpcode(); + auto Name = GetMnemonic(Opc); + DumpTypeStack("typechecking " + Name + ": "); + wasm::ValType Type; + if (Name == "local.get") { + if (GetLocal(ErrorLoc, Inst, Type)) + return true; + TS.Stack.push_back(Type); + } else if (Name == "local.set") { + if (GetLocal(ErrorLoc, Inst, Type)) + return true; + if (PopType(ErrorLoc, Type)) + return true; + } else if (Name == "local.tee") { + if (GetLocal(ErrorLoc, Inst, Type)) + return true; + if (PopType(ErrorLoc, Type)) + return true; + TS.Stack.push_back(Type); + } else if (Name == "global.get") { + if (GetGlobal(ErrorLoc, Inst, Type)) + return true; + TS.Stack.push_back(Type); + } else if (Name == "global.set") { + if (GetGlobal(ErrorLoc, Inst, Type)) + return true; + if (PopType(ErrorLoc, Type)) + return true; + } else if (Name == "drop") { + if (PopType(ErrorLoc, {})) + return true; + } else if (Name == "end_block" || Name == "end_loop" || Name == "end_if" || + Name == "else") { + if (CheckEnd(ErrorLoc)) + return true; + } else if (Name == "call_indirect" || Name == "return_call_indirect") { + // Function value. + if (PopType(ErrorLoc, wasm::ValType::I32)) return true; + if (CheckSig(ErrorLoc, LastSig)) return true; + } else if (Name == "call" || Name == "return_call") { + const MCSymbolRefExpr *SymRef; + if (GetSymRef(ErrorLoc, Inst, SymRef)) + return true; + auto WasmSym = cast(&SymRef->getSymbol()); + auto Sig = WasmSym->getSignature(); + if (!Sig || WasmSym->getType() != wasm::WASM_SYMBOL_TYPE_FUNCTION) + return TypeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + + " missing .functype"); + if (CheckSig(ErrorLoc, *Sig)) return true; + } else if (Name == "ref.null") { + auto VT = static_cast(Inst.getOperand(0).getImm()); + TS.Stack.push_back(VT); + } else { + // The current instruction is a stack instruction which doesn't have + // explicit operands that indicate push/pop types, so we get those from + // the register version of the same instruction. + auto RegOpc = WebAssembly::getRegisterOpcode(Opc); + assert(RegOpc != -1 && "Failed to get register version of MC instruction"); + const auto &II = MII.get(RegOpc); + // First pop all the uses off the stack and check them. + for (unsigned I = II.getNumOperands(); I > II.getNumDefs(); I--) { + const auto &Op = II.OpInfo[I - 1]; + if (Op.OperandType == MCOI::OPERAND_REGISTER) { + auto VT = WebAssembly::regClassToValType(Op.RegClass); + if (PopType(ErrorLoc, VT)) + return true; + } + } + // Now push all the defs onto the stack. + for (unsigned I = 0; I < II.getNumDefs(); I++) { + const auto &Op = II.OpInfo[I]; + assert(Op.OperandType == MCOI::OPERAND_REGISTER && "Register expected"); + auto VT = WebAssembly::regClassToValType(Op.RegClass); + TS.Stack.push_back(VT); + } + } + return false; + } + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, @@ -986,7 +1213,7 @@ if (Op0.getImm() == -1) Op0.setImm(Align); } - if (getSTI().getTargetTriple().isArch64Bit()) { + if (is64) { // Upgrade 32-bit loads/stores to 64-bit. These mostly differ by having // an offset64 arg instead of offset32, but to the assembler matcher // they're both immediates so don't get selected for. @@ -996,9 +1223,11 @@ Inst.setOpcode(Opc64); } } + if (!SkipTypeCheck && TypeCheck(IDLoc, Inst)) + return true; Out.emitInstruction(Inst, getSTI()); if (CurrentState == EndFunction) { - onEndOfFunction(); + onEndOfFunction(IDLoc); } else { CurrentState = Instructions; } @@ -1078,7 +1307,22 @@ getContext().addGenDwarfSection(WS); } - void onEndOfFunction() { + void onEndOfFunction(SMLoc ErrorLoc) { + // Check the return types. + for (auto RVT : llvm::reverse(ReturnTypes)) { + PopType(ErrorLoc, RVT); + } + if (!TS.Stack.empty()) { + TypeError(ErrorLoc, + std::to_string(TS.Stack.size()) + + " superfluous return values"); + } + // Reset the type checker state. + TS.Stack.clear(); + TypedLabels.clear(); + LocalTypes.clear(); + ReturnTypes.clear(); + TypeErrorThisFunction = false; // Automatically output a .size directive, so it becomes optional for the // user. if (!LastFunctionLabel) return; @@ -1105,3 +1349,14 @@ #define GET_SUBTARGET_FEATURE_NAME #define GET_MATCHER_IMPLEMENTATION #include "WebAssemblyGenAsmMatcher.inc" + +static StringRef GetMnemonic(unsigned Opc) { + // FIXME: linear search! + for (auto &ME : MatchTable0) { + if (ME.Opcode == Opc) { + return ME.getMnemonic(); + } + } + assert(false && "mnemonic not found"); + return StringRef(); +} Index: llvm/lib/Target/WebAssembly/CMakeLists.txt =================================================================== --- llvm/lib/Target/WebAssembly/CMakeLists.txt +++ llvm/lib/Target/WebAssembly/CMakeLists.txt @@ -38,6 +38,7 @@ WebAssemblyLowerGlobalDtors.cpp WebAssemblyMachineFunctionInfo.cpp WebAssemblyMCInstLower.cpp + WebAssemblyMCLowerPrePass.cpp WebAssemblyOptimizeLiveIntervals.cpp WebAssemblyOptimizeReturned.cpp WebAssemblyPeephole.cpp Index: llvm/lib/Target/WebAssembly/TargetInfo/WebAssemblyTargetInfo.h =================================================================== --- llvm/lib/Target/WebAssembly/TargetInfo/WebAssemblyTargetInfo.h +++ llvm/lib/Target/WebAssembly/TargetInfo/WebAssemblyTargetInfo.h @@ -24,6 +24,7 @@ namespace WebAssembly { int getStackOpcode(unsigned short Opcode); +int getRegisterOpcode(unsigned short Opcode); int getWasm64Opcode(unsigned short Opcode); } // namespace WebAssembly Index: llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h =================================================================== --- llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h +++ llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h @@ -73,6 +73,9 @@ // Convert a MVT into its corresponding wasm ValType. wasm::ValType toValType(MVT Type); +// Convert a register class to a wasm ValType. +wasm::ValType regClassToValType(unsigned RC); + } // end namespace WebAssembly } // end namespace llvm Index: llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp =================================================================== --- llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp +++ llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp @@ -14,6 +14,10 @@ #include "WebAssemblyTypeUtilities.h" #include "llvm/ADT/StringSwitch.h" +// Get register classes enum. +#define GET_REGINFO_ENUM +#include "WebAssemblyGenRegisterInfo.inc" + using namespace llvm; Optional WebAssembly::parseType(StringRef Type) { @@ -149,3 +153,24 @@ llvm_unreachable("unexpected type"); } } + +wasm::ValType WebAssembly::regClassToValType(unsigned RC) { + switch (RC) { + case WebAssembly::I32RegClassID: + return wasm::ValType::I32; + case WebAssembly::I64RegClassID: + return wasm::ValType::I64; + case WebAssembly::F32RegClassID: + return wasm::ValType::F32; + case WebAssembly::F64RegClassID: + return wasm::ValType::F64; + case WebAssembly::V128RegClassID: + return wasm::ValType::V128; + case WebAssembly::FUNCREFRegClassID: + return wasm::ValType::FUNCREF; + case WebAssembly::EXTERNREFRegClassID: + return wasm::ValType::EXTERNREF; + default: + llvm_unreachable("unexpected type"); + } +} Index: llvm/lib/Target/WebAssembly/WebAssembly.h =================================================================== --- llvm/lib/Target/WebAssembly/WebAssembly.h +++ llvm/lib/Target/WebAssembly/WebAssembly.h @@ -54,6 +54,7 @@ FunctionPass *createWebAssemblyRegNumbering(); FunctionPass *createWebAssemblyDebugFixup(); FunctionPass *createWebAssemblyPeephole(); +FunctionPass *createWebAssemblyMCLowerPrePass(); // PassRegistry initialization declarations. void initializeWebAssemblyAddMissingPrototypesPass(PassRegistry &); @@ -80,6 +81,7 @@ void initializeWebAssemblyRegNumberingPass(PassRegistry &); void initializeWebAssemblyDebugFixupPass(PassRegistry &); void initializeWebAssemblyPeepholePass(PassRegistry &); +void initializeWebAssemblyMCLowerPrePassPass(PassRegistry &); namespace WebAssembly { enum TargetIndex { Index: llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h +++ llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h @@ -25,6 +25,7 @@ // TODO: Do the uniquing of Signatures here instead of ObjectFileWriter? std::vector> Signatures; std::vector> Names; + bool signaturesEmitted = false; StringRef storeName(StringRef Name) { std::unique_ptr N = std::make_unique(Name); @@ -68,6 +69,7 @@ void emitGlobalVariable(const GlobalVariable *GV) override; void emitJumpTableInfo() override; void emitConstantPool() override; + void emitLinkage(const GlobalValue *, MCSymbol *) const override; void emitFunctionBodyStart() override; void emitInstruction(const MachineInstr *MI) override; bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, @@ -81,6 +83,8 @@ MCSymbolWasm *getMCSymbolForFunction(const Function *F, bool EnableEmEH, wasm::WasmSignature *Sig, bool &InvokeDetected); + MCSymbol *SetWasmSymType(StringRef Name); + void emitExternalDecls(const Module &M); }; } // end namespace llvm Index: llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -23,6 +23,7 @@ #include "WebAssemblyMCInstLower.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblyRegisterInfo.h" +#include "WebAssemblyRuntimeLibcallSignatures.h" #include "WebAssemblyTargetMachine.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" @@ -207,7 +208,72 @@ } } -void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) { +MCSymbol *WebAssemblyAsmPrinter::SetWasmSymType(StringRef Name) { + auto *WasmSym = cast(GetExternalSymbolSymbol(Name)); + const WebAssemblySubtarget &Subtarget = getSubtarget(); + + // Except for certain known symbols, all symbols used by CodeGen are + // functions. It's OK to hardcode knowledge of specific symbols here; this + // method is precisely there for fetching the signatures of known + // Clang-provided symbols. + if (Name == "__stack_pointer" || Name == "__tls_base" || + Name == "__memory_base" || Name == "__table_base" || + Name == "__tls_size" || Name == "__tls_align") { + bool Mutable = + Name == "__stack_pointer" || Name == "__tls_base"; + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); + WasmSym->setGlobalType(wasm::WasmGlobalType{ + uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64 + : wasm::WASM_TYPE_I32), + Mutable}); + return WasmSym; + } + + SmallVector Returns; + SmallVector Params; + if (Name == "__cpp_exception") { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT); + // We can't confirm its signature index for now because there can be + // imported exceptions. Set it to be 0 for now. + WasmSym->setEventType( + {wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION, /* SigIndex */ 0}); + // We may have multiple C++ compilation units to be linked together, each of + // which defines the exception symbol. To resolve them, we declare them as + // weak. + WasmSym->setWeak(true); + WasmSym->setExternal(true); + + // All C++ exceptions are assumed to have a single i32 (for wasm32) or i64 + // (for wasm64) param type and void return type. The reaon is, all C++ + // exception values are pointers, and to share the type section with + // functions, exceptions are assumed to have void return type. + Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64 + : wasm::ValType::I32); + } else { // Function symbols + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + getLibcallSignature(Subtarget, Name, Returns, Params); + } + auto Signature = std::make_unique(std::move(Returns), + std::move(Params)); + WasmSym->setSignature(Signature.get()); + addSignature(std::move(Signature)); + + return WasmSym; +} + +void WebAssemblyAsmPrinter::emitExternalDecls(const Module &M) { + if (signaturesEmitted) + return; + signaturesEmitted = true; + + // Normally symbols for globals get discovered as the MI gets lowered, + // but we need to know about them ahead of time. + // FIXME: this potentially causes SetWasmSymType to be run twice. + MachineModuleInfoWasm &MMIW = MMI->getObjFileInfo(); + for (const auto &Name : MMIW.MachineSymbolsUsed) { + SetWasmSymType(Name.getKey()); + } + for (auto &It : OutContext.getSymbols()) { // Emit .globaltype, .eventtype, or .tabletype declarations. auto Sym = cast(It.getValue()); @@ -224,14 +290,10 @@ } DenseSet InvokeSymbols; - bool HasAddressTakenFunction = false; for (const auto &F : M) { if (F.isIntrinsic()) continue; - if (F.hasAddressTaken()) - HasAddressTakenFunction = true; - // Emit function type info for all undefined functions if (F.isDeclarationForLinker()) { SmallVector Results; @@ -289,6 +351,10 @@ getTargetStreamer()->emitExportName(Sym, Name); } } +} + +void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) { + emitExternalDecls(M); // When a function's address is taken, a TABLE_INDEX relocation is emitted // against the function symbol at the use site. However the relocation @@ -296,13 +362,17 @@ // define a new kind of reloc against both the function and the table, so // that the linker can see that the function symbol keeps the table alive, // but for now manually mark the table as live. - if (HasAddressTakenFunction) { - MCSymbolWasm *FunctionTable = - WebAssembly::getOrCreateFunctionTableSymbol(OutContext, Subtarget); - OutStreamer->emitSymbolAttribute(FunctionTable, MCSA_NoDeadStrip); + for (const auto &F : M) { + if (F.hasAddressTaken()) { + MCSymbolWasm *FunctionTable = + WebAssembly::getOrCreateFunctionTableSymbol(OutContext, Subtarget); + OutStreamer->emitSymbolAttribute(FunctionTable, MCSA_NoDeadStrip); + break; + } } for (const auto &G : M.globals()) { + auto S = G.getName(); if (!G.hasInitializer() && G.hasExternalLinkage() && !WebAssembly::isWasmVarAddressSpace(G.getAddressSpace()) && G.getValueType()->isSized()) { @@ -452,6 +522,16 @@ // Nothing to do; jump tables are incorporated into the instruction stream. } +void WebAssemblyAsmPrinter::emitLinkage(const GlobalValue *GV, MCSymbol *Sym) + const { + AsmPrinter::emitLinkage(GV, Sym); + // This gets called before the function label and type are emitted. + // We use it to emit signatures of external functions. + // FIXME casts! + ((WebAssemblyAsmPrinter *)this)->emitExternalDecls(*MMI->getModule()); +} + + void WebAssemblyAsmPrinter::emitFunctionBodyStart() { const Function &F = MF->getFunction(); SmallVector ResultVTs; Index: llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td +++ llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td @@ -15,7 +15,7 @@ // We instantiate 2 of these for every actual instruction (register based // and stack based), see below. class WebAssemblyInst inst, string asmstr, string stack, string is64> - : StackRel, Wasm64Rel, Instruction { + : StackRel, RegisterRel, Wasm64Rel, Instruction { bits<32> Inst = inst; // Instruction encoding. string StackBased = stack; string BaseName = NAME; Index: llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -226,6 +226,19 @@ let ValueCols = [["true"]]; } +//===----------------------------------------------------------------------===// +// WebAssembly Stack to Register instruction mapping +//===----------------------------------------------------------------------===// + +class RegisterRel; +def getRegisterOpcode : InstrMapping { + let FilterClass = "RegisterRel"; + let RowFields = ["BaseName"]; + let ColFields = ["StackBased"]; + let KeyCol = ["true"]; + let ValueCols = [["false"]]; +} + //===----------------------------------------------------------------------===// // WebAssembly 32 to 64-bit instruction mapping //===----------------------------------------------------------------------===// Index: llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td +++ llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td @@ -13,10 +13,10 @@ multiclass TABLE { - defm TABLE_GET_#rt : I<(outs rt:$res), (ins table32_op:$table), + defm TABLE_GET_#rt : I<(outs rt:$res), (ins table32_op:$table, I32:$i), (outs), (ins table32_op:$table), [], - "table.get\t$res, $table", + "table.get\t$res, $table, $i", "table.get\t$table", 0x25>; Index: llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -18,7 +18,6 @@ #include "Utils/WebAssemblyUtilities.h" #include "WebAssemblyAsmPrinter.h" #include "WebAssemblyMachineFunctionInfo.h" -#include "WebAssemblyRuntimeLibcallSignatures.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/IR/Constants.h" @@ -92,57 +91,7 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol( const MachineOperand &MO) const { - const char *Name = MO.getSymbolName(); - auto *WasmSym = cast(Printer.GetExternalSymbolSymbol(Name)); - const WebAssemblySubtarget &Subtarget = Printer.getSubtarget(); - - // Except for certain known symbols, all symbols used by CodeGen are - // functions. It's OK to hardcode knowledge of specific symbols here; this - // method is precisely there for fetching the signatures of known - // Clang-provided symbols. - if (strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0 || - strcmp(Name, "__memory_base") == 0 || strcmp(Name, "__table_base") == 0 || - strcmp(Name, "__tls_size") == 0 || strcmp(Name, "__tls_align") == 0) { - bool Mutable = - 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), - Mutable}); - return WasmSym; - } - - SmallVector Returns; - SmallVector Params; - if (strcmp(Name, "__cpp_exception") == 0) { - WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT); - // We can't confirm its signature index for now because there can be - // imported exceptions. Set it to be 0 for now. - WasmSym->setEventType( - {wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION, /* SigIndex */ 0}); - // We may have multiple C++ compilation units to be linked together, each of - // which defines the exception symbol. To resolve them, we declare them as - // weak. - WasmSym->setWeak(true); - WasmSym->setExternal(true); - - // All C++ exceptions are assumed to have a single i32 (for wasm32) or i64 - // (for wasm64) param type and void return type. The reaon is, all C++ - // exception values are pointers, and to share the type section with - // functions, exceptions are assumed to have void return type. - Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64 - : wasm::ValType::I32); - } else { // Function symbols - WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); - getLibcallSignature(Subtarget, Name, Returns, Params); - } - auto Signature = - std::make_unique(std::move(Returns), std::move(Params)); - WasmSym->setSignature(Signature.get()); - Printer.addSignature(std::move(Signature)); - - return WasmSym; + return Printer.SetWasmSymType(MO.getSymbolName()); } MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO, Index: llvm/lib/Target/WebAssembly/WebAssemblyMCLowerPrePass.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/WebAssembly/WebAssemblyMCLowerPrePass.cpp @@ -0,0 +1,86 @@ +//===-- WebAssemblyMCLowerPrePass.cpp - Prepare for MC lower --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Some information in MC lowering / asm printing gets generated as +/// instructions get emitted, but may be necessary at the start, such as for +/// .globaltype declarations. This pass collects this information. +/// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "Utils/WebAssemblyUtilities.h" +#include "WebAssembly.h" +#include "WebAssemblyMachineFunctionInfo.h" +#include "WebAssemblySubtarget.h" +#include "llvm/ADT/SCCIterator.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "wasm-mclower-prepass" + +namespace { +class WebAssemblyMCLowerPrePass final : public MachineFunctionPass { + StringRef getPassName() const override { + return "WebAssembly MC Lower Pre Pass"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + MachineFunctionPass::getAnalysisUsage(AU); + } + + bool runOnMachineFunction(MachineFunction &MF) override; + +public: + static char ID; // Pass identification, replacement for typeid + WebAssemblyMCLowerPrePass() : MachineFunctionPass(ID) {} +}; +} // end anonymous namespace + +char WebAssemblyMCLowerPrePass::ID = 0; +INITIALIZE_PASS( + WebAssemblyMCLowerPrePass, DEBUG_TYPE, + "Collects information ahead of time for MC lowering", + false, false) + +FunctionPass *llvm::createWebAssemblyMCLowerPrePass() { + return new WebAssemblyMCLowerPrePass(); +} + +bool WebAssemblyMCLowerPrePass::runOnMachineFunction(MachineFunction &MF) { + LLVM_DEBUG(dbgs() << "********** MC Lower Pre Pass **********\n" + "********** Function: " + << MF.getName() << '\n'); + + MachineModuleInfo &MMI = MF.getMMI(); + MachineModuleInfoWasm &MMIW = MMI.getObjFileInfo(); + + for (MachineBasicBlock &MBB : MF) { + for (auto &MI : MBB) { + // FIXME: what should all be filtered out beyond these? + if (MI.isDebugInstr() || MI.isInlineAsm()) + continue; + for (MachineOperand &MO : MI.uses()) { + if (MO.isSymbol()) { + MMIW.MachineSymbolsUsed.insert(MO.getSymbolName()); + } + } + } + } + + return true; +} Index: llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.h =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.h +++ llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.h @@ -28,7 +28,7 @@ SmallVectorImpl &Params); extern void getLibcallSignature(const WebAssemblySubtarget &Subtarget, - const char *Name, + StringRef Name, SmallVectorImpl &Rets, SmallVectorImpl &Params); Index: llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp +++ llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp @@ -889,14 +889,15 @@ // TODO: If the RTLIB::Libcall-taking flavor of GetSignature remains unsed // other than here, just roll its logic into this version. void llvm::getLibcallSignature(const WebAssemblySubtarget &Subtarget, - const char *Name, + StringRef Name, SmallVectorImpl &Rets, SmallVectorImpl &Params) { auto &Map = LibcallNameMap->Map; auto Val = Map.find(Name); #ifndef NDEBUG if (Val == Map.end()) { - auto message = std::string("unexpected runtime library name: ") + Name; + auto message = std::string("unexpected runtime library name: ") + + std::string(Name); llvm_unreachable(message.c_str()); } #endif Index: llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -87,6 +87,7 @@ initializeWebAssemblyRegNumberingPass(PR); initializeWebAssemblyDebugFixupPass(PR); initializeWebAssemblyPeepholePass(PR); + initializeWebAssemblyMCLowerPrePassPass(PR); } //===----------------------------------------------------------------------===// @@ -503,6 +504,9 @@ // Fix debug_values whose defs have been stackified. if (!WasmDisableExplicitLocals) addPass(createWebAssemblyDebugFixup()); + + // Collect information to prepare for MC lowering / asm printing. + addPass(createWebAssemblyMCLowerPrePass()); } yaml::MachineFunctionInfo * Index: llvm/test/CodeGen/WebAssembly/exception.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/exception.ll +++ llvm/test/CodeGen/WebAssembly/exception.ll @@ -9,6 +9,8 @@ @_ZTIi = external dso_local constant i8* +; CHECK: .eventtype __cpp_exception i32 + ; CHECK-LABEL: test_throw: ; CHECK: throw __cpp_exception, $0 ; CHECK-NOT: unreachable @@ -372,4 +374,3 @@ attributes #1 = { noreturn } ; CHECK: __cpp_exception: -; CHECK: .eventtype __cpp_exception i32 Index: llvm/test/CodeGen/WebAssembly/global-get.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/global-get.ll +++ llvm/test/CodeGen/WebAssembly/global-get.ll @@ -70,10 +70,12 @@ ; CHECK: .globaltype f64_global, f64 ; CHECK-LABEL: f64_global: +; FIXME: are we still expecting these to be emitted? + ; CHECK-NOT: .global i32_external_used -; CHECK: .globaltype i32_external_used, i32 +; CHECK-NOT: .globaltype i32_external_used, i32 ; CHECK-NOT: i32_external_used: ; CHECK-NOT: .global i32_external_unused -; CHECK: .globaltype i32_external_unused, i32 +; CHECK-NOT: .globaltype i32_external_unused, i32 ; CHECK-NOT: i32_external_unused: Index: llvm/test/CodeGen/WebAssembly/i128-returned.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/i128-returned.ll +++ llvm/test/CodeGen/WebAssembly/i128-returned.ll @@ -13,7 +13,8 @@ ret i128 %r } +; CHECK: .functype bar (i32, i64, i64) -> () + ; CHECK-LABEL: foo: ; CHECK-NEXT: .functype foo (i32, i64, i64) -> () -; CHECK: .functype bar (i32, i64, i64) -> () Index: llvm/test/CodeGen/WebAssembly/indirect-import.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/indirect-import.ll +++ llvm/test/CodeGen/WebAssembly/indirect-import.ll @@ -6,6 +6,14 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32" +; CHECK: .functype extern_fd (f64) -> (f32) +; CHECK: .functype extern_vj (i64) -> () +; CHECK: .functype extern_v () -> () +; CHECK: .functype extern_ijidf (i64, i32, f64, f32) -> (i32) +; CHECK: .functype extern_struct (i32) -> () +; CHECK: .functype extern_sret (i32) -> () +; CHECK: .functype extern_i128ret (i32, i64) -> () + %struct.big = type { float, double, i32 } ; Function Attrs: nounwind @@ -70,10 +78,3 @@ attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="none" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } -; CHECK: .functype extern_fd (f64) -> (f32) -; CHECK: .functype extern_vj (i64) -> () -; CHECK: .functype extern_v () -> () -; CHECK: .functype extern_ijidf (i64, i32, f64, f32) -> (i32) -; CHECK: .functype extern_struct (i32) -> () -; CHECK: .functype extern_sret (i32) -> () -; CHECK: .functype extern_i128ret (i32, i64) -> () Index: llvm/test/CodeGen/WebAssembly/load-store-pic.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/load-store-pic.ll +++ llvm/test/CodeGen/WebAssembly/load-store-pic.ll @@ -11,6 +11,8 @@ @external_global = external global i32 @external_global_array = external global [10 x i32] +; PIC: .globaltype __memory_base, [[PTR]] + declare i32 @foo(); ; For hidden symbols PIC code needs to offset all loads and stores @@ -128,5 +130,3 @@ store i32 %n, i32* %1 ret void } - -; PIC: .globaltype __memory_base, [[PTR]] Index: llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll +++ llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll @@ -6,6 +6,20 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" +; EH: .functype invoke_vi (i32, i32) -> () +; EH: .import_module invoke_vi, env +; EH: .import_name invoke_vi, invoke_vi +; EH-NOT: .functype __invoke_void_i32 +; EH-NOT: .import_module __invoke_void_i32 +; EH-NOT: .import_name __invoke_void_i32 + +; SJLJ: .functype emscripten_longjmp (i32, i32) -> () +; SJLJ: .import_module emscripten_longjmp, env +; SJLJ: .import_name emscripten_longjmp, emscripten_longjmp +; SJLJ-NOT: .functype emscripten_longjmp_jmpbuf +; SJLJ-NOT: .import_module emscripten_longjmp_jmpbuf +; SJLJ-NOT: .import_name emscripten_longjmp_jmpbuf + %struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] } define void @exception() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { @@ -87,18 +101,4 @@ attributes #1 = { noreturn } attributes #2 = { nounwind } -; EH: .functype invoke_vi (i32, i32) -> () -; EH: .import_module invoke_vi, env -; EH: .import_name invoke_vi, invoke_vi -; EH-NOT: .functype __invoke_void_i32 -; EH-NOT: .import_module __invoke_void_i32 -; EH-NOT: .import_name __invoke_void_i32 - -; SJLJ: .functype emscripten_longjmp (i32, i32) -> () -; SJLJ: .import_module emscripten_longjmp, env -; SJLJ: .import_name emscripten_longjmp, emscripten_longjmp -; SJLJ-NOT: .functype emscripten_longjmp_jmpbuf -; SJLJ-NOT: .import_module emscripten_longjmp_jmpbuf -; SJLJ-NOT: .import_name emscripten_longjmp_jmpbuf - ; WASM-EH-EM-EH: LLVM ERROR: -exception-model=wasm not allowed with -enable-emscripten-cxx-exceptions Index: llvm/test/CodeGen/WebAssembly/lower-global-dtors.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/lower-global-dtors.ll +++ llvm/test/CodeGen/WebAssembly/lower-global-dtors.ll @@ -51,6 +51,8 @@ { i32, void ()*, i8* } { i32 65535, void ()* @after_the_null, i8* null } ] +; CHECK-LABEL: .functype __cxa_atexit (i32, i32, i32) -> (i32){{$}} + ; CHECK-LABEL: .Lcall_dtors.0: ; CHECK-NEXT: .functype .Lcall_dtors.0 (i32) -> (){{$}} ; CHECK-NEXT: call orig_dtor0{{$}} @@ -186,8 +188,6 @@ ; CHECK-LABEL: .weak __dso_handle -; CHECK-LABEL: .functype __cxa_atexit (i32, i32, i32) -> (i32){{$}} - ; We shouldn't make use of a .fini_array section. ; FINI-NOT: fini_array Index: llvm/test/CodeGen/WebAssembly/userstack.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/userstack.ll +++ llvm/test/CodeGen/WebAssembly/userstack.ll @@ -4,6 +4,8 @@ declare void @ext_func(i64* %ptr) declare void @ext_func_i32(i32* %ptr) +; CHECK: .globaltype __stack_pointer, i[[PTR]]{{$}} + ; CHECK-LABEL: alloca32: ; Check that there is an extra local for the stack pointer. ; CHECK: .local i[[PTR]]{{$}} @@ -344,6 +346,4 @@ ret i8 %5 } -; CHECK: .globaltype __stack_pointer, i[[PTR]]{{$}} - ; TODO: test over-aligned alloca Index: llvm/test/MC/WebAssembly/alias-offset.s =================================================================== --- llvm/test/MC/WebAssembly/alias-offset.s +++ llvm/test/MC/WebAssembly/alias-offset.s @@ -21,14 +21,16 @@ .section .text,"",@ main: .functype main () -> () + i32.const 0 i32.const sym_a i32.store sym_b end_function # CHECK-LABEL:
: # CHECK-EMPTY: -# CHECK-NEXT: 3: 41 84 80 80 80 00 i32.const 4 -# CHECK-NEXT: 00000004: R_WASM_MEMORY_ADDR_SLEB sym_a+0 -# CHECK-NEXT: 9: 36 02 88 80 80 80 00 i32.store 8 -# CHECK-NEXT: 0000000b: R_WASM_MEMORY_ADDR_LEB sym_b+0 -# CHECK-NEXT: 10: 0b end +# CHECK-NEXT: 3: 41 00 i32.const 0 +# CHECK-NEXT: 5: 41 84 80 80 80 00 i32.const 4 +# CHECK-NEXT: 00000006: R_WASM_MEMORY_ADDR_SLEB sym_a+0 +# CHECK-NEXT: b: 36 02 88 80 80 80 00 i32.store 8 +# CHECK-NEXT: 0000000d: R_WASM_MEMORY_ADDR_LEB sym_b+0 +# CHECK-NEXT: 12: 0b end Index: llvm/test/MC/WebAssembly/annotations.s =================================================================== --- llvm/test/MC/WebAssembly/annotations.s +++ llvm/test/MC/WebAssembly/annotations.s @@ -1,4 +1,4 @@ -# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+exception-handling < %s | FileCheck %s +# RUN: llvm-mc -no-type-check -triple=wasm32-unknown-unknown -mattr=+exception-handling < %s | FileCheck %s # Tests if block/loop/try/catch/end/branch/rethrow instructions are correctly # printed with their annotations. Index: llvm/test/MC/WebAssembly/assembler-binary.ll =================================================================== --- llvm/test/MC/WebAssembly/assembler-binary.ll +++ llvm/test/MC/WebAssembly/assembler-binary.ll @@ -24,11 +24,11 @@ ; ASM: .text ; ASM: .file "assembler-binary.ll" ; ASM: .globl foo +; ASM: .functype bar () -> () ; ASM: foo: ; ASM-NEXT: .functype foo (i32) -> () ; ASM-NEXT: call bar ; ASM-NEXT: end_function -; ASM: .functype bar () -> () ; CHECK: --- !WASM Index: llvm/test/MC/WebAssembly/atomics-encodings.s =================================================================== --- llvm/test/MC/WebAssembly/atomics-encodings.s +++ llvm/test/MC/WebAssembly/atomics-encodings.s @@ -1,4 +1,4 @@ -# RUN: llvm-mc -show-encoding -triple=wasm32-unknown-unknown -mattr=+atomics < %s | FileCheck %s +# RUN: llvm-mc -no-type-check -show-encoding -triple=wasm32-unknown-unknown -mattr=+atomics < %s | FileCheck %s main: .functype main () -> () Index: llvm/test/MC/WebAssembly/bad-fixup-expr.s =================================================================== --- llvm/test/MC/WebAssembly/bad-fixup-expr.s +++ llvm/test/MC/WebAssembly/bad-fixup-expr.s @@ -32,7 +32,7 @@ .text .section .text.main,"",@ main: - .functype main () -> (i32) + .functype main () -> (i32, i32, i32, i32, i32) // Expressions involving symbols within the same sections can be evaluated // prior to writing the object file. // CHECK-NOT: foo Index: llvm/test/MC/WebAssembly/basic-assembly.s =================================================================== --- llvm/test/MC/WebAssembly/basic-assembly.s +++ llvm/test/MC/WebAssembly/basic-assembly.s @@ -2,6 +2,9 @@ # Check that it converts to .o without errors, but don't check any output: # RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+reference-types,+atomics,+simd128,+nontrapping-fptoint,+exception-handling -o %t.o < %s +.functype something1 () -> () +.functype something2 (i64) -> (i32, f64) +.globaltype __stack_pointer, i32 empty_func: .functype empty_func () -> () @@ -18,31 +21,37 @@ local.get 2 local.set 2 # Immediates: - i32.const -1 - f64.const 0x1.999999999999ap1 f32.const -1.0 + drop f32.const -infinity - f32.const nan + drop v128.const 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + drop v128.const 0, 1, 2, 3, 4, 5, 6, 7 - # Indirect addressing: + drop local.get 0 + f64.const 0x1.999999999999ap1 + # Indirect addressing: f64.store 1234:p2align=4 + i32.const -1 + f64.const nan f64.store 1234 # Natural alignment (3) # Loops, conditionals, binary ops, calls etc: - block i32 + block f32 + f32.const 2.0 i32.const 1 local.get 0 i32.ge_s br_if 0 # 0: down to label0 .LBB0_1: - loop i32 # label1: + loop void # label1: call something1 i64.const 1234 call something2 i32.const 0 call_indirect (i32, f64) -> () i32.const 1 + i32.const 2 i32.add local.tee 0 local.get 0 @@ -51,18 +60,16 @@ .LBB0_2: end_loop end_block # label0: - local.get 4 - local.get 5 + drop + block i32 + block void + block void block void - block i64 - block f32 - block f64 block () -> (i32, i32) i32.const 1 i32.const 2 end_block drop - drop br_table {0, 1, 2} # 2 entries, default end_block # first entry jumps here. i32.const 1 @@ -78,14 +85,21 @@ end_if else end_if + drop + local.get 4 + local.get 5 f32x4.add + drop # Test correct parsing of instructions with / and : in them: # TODO: enable once instruction has been added. #i32x4.trunc_sat_f32x4_s + f32.const 1.0 i32.trunc_f32_s try i32.atomic.load 0 + i32.const 0 memory.atomic.notify 0 + drop .LBB0_3: catch __cpp_exception local.set 0 @@ -97,6 +111,7 @@ .LBB0_4: #i32.trunc_sat_f32_s global.get __stack_pointer + global.set __stack_pointer end_function .section .rodata..L.str,"",@ @@ -115,7 +130,6 @@ .int32 test0 .ident "clang version 9.0.0 (trunk 364502) (llvm/trunk 364571)" - .globaltype __stack_pointer, i32 .tabletype empty_eref_table, externref empty_eref_table: @@ -125,6 +139,8 @@ # CHECK: .text +# CHECK: .globaltype __stack_pointer, i32 + # CHECK-LABEL: empty_func: # CHECK-NEXT: .functype empty_func () -> () # CHECK-NEXT: end_function @@ -135,29 +151,35 @@ # CHECK-NEXT: .local f32, f64 # CHECK-NEXT: local.get 2 # CHECK-NEXT: local.set 2 -# CHECK-NEXT: i32.const -1 -# CHECK-NEXT: f64.const 0x1.999999999999ap1 # CHECK-NEXT: f32.const -0x1p0 +# CHECK-NEXT: drop # CHECK-NEXT: f32.const -infinity -# CHECK-NEXT: f32.const nan +# CHECK-NEXT: drop # CHECK-NEXT: v128.const 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +# CHECK-NEXT: drop # CHECK-NEXT: v128.const 0, 1, 2, 3, 4, 5, 6, 7 +# CHECK-NEXT: drop # CHECK-NEXT: local.get 0 +# CHECK-NEXT: f64.const 0x1.999999999999ap1 # CHECK-NEXT: f64.store 1234:p2align=4 +# CHECK-NEXT: i32.const -1 +# CHECK-NEXT: f64.const nan # CHECK-NEXT: f64.store 1234 -# CHECK-NEXT: block i32 +# CHECK-NEXT: block f32 +# CHECK-NEXT: f32.const 0x1p1 # CHECK-NEXT: i32.const 1 # CHECK-NEXT: local.get 0 # CHECK-NEXT: i32.ge_s # CHECK-NEXT: br_if 0 # 0: down to label0 # CHECK-NEXT: .LBB0_1: -# CHECK-NEXT: loop i32 # label1: +# CHECK-NEXT: loop # label1: # CHECK-NEXT: call something1 # CHECK-NEXT: i64.const 1234 # CHECK-NEXT: call something2 # CHECK-NEXT: i32.const 0 # CHECK-NEXT: call_indirect __indirect_function_table, (i32, f64) -> () # CHECK-NEXT: i32.const 1 +# CHECK-NEXT: i32.const 2 # CHECK-NEXT: i32.add # CHECK-NEXT: local.tee 0 # CHECK-NEXT: local.get 0 @@ -166,18 +188,16 @@ # CHECK-NEXT: .LBB0_2: # CHECK-NEXT: end_loop # CHECK-NEXT: end_block # label0: -# CHECK-NEXT: local.get 4 -# CHECK-NEXT: local.get 5 +# CHECK-NEXT: drop +# CHECK-NEXT: block i32 +# CHECK-NEXT: block +# CHECK-NEXT: block # CHECK-NEXT: block -# CHECK-NEXT: block i64 -# CHECK-NEXT: block f32 -# CHECK-NEXT: block f64 # CHECK-NEXT: block () -> (i32, i32) # CHECK-NEXT: i32.const 1 # CHECK-NEXT: i32.const 2 # CHECK-NEXT: end_block # CHECK-NEXT: drop -# CHECK-NEXT: drop # CHECK-NEXT: br_table {0, 1, 2} # 1: down to label4 # CHECK-NEXT: # 2: down to label3 # CHECK-NEXT: end_block # label5: @@ -194,11 +214,18 @@ # CHECK-NEXT: end_if # CHECK-NEXT: else # CHECK-NEXT: end_if +# CHECK-NEXT: drop +# CHECK-NEXT: local.get 4 +# CHECK-NEXT: local.get 5 # CHECK-NEXT: f32x4.add +# CHECK-NEXT: drop +# CHECK-NEXT: f32.const 0x1p0 # CHECK-NEXT: i32.trunc_f32_s # CHECK-NEXT: try # CHECK-NEXT: i32.atomic.load 0 +# CHECK-NEXT: i32.const 0 # CHECK-NEXT: memory.atomic.notify 0 +# CHECK-NEXT: drop # CHECK-NEXT: .LBB0_3: # CHECK-NEXT: catch __cpp_exception # CHECK-NEXT: local.set 0 @@ -209,6 +236,7 @@ # CHECK-NEXT: throw 0 # CHECK-NEXT: .LBB0_4: # CHECK-NEXT: global.get __stack_pointer +# CHECK-NEXT: global.set __stack_pointer # CHECK-NEXT: end_function # CHECK: .section .rodata..L.str,"",@ @@ -225,8 +253,6 @@ # CHECK-NEXT: .p2align 2 # CHECK-NEXT: .int32 test0 -# CHECK: .globaltype __stack_pointer, i32 - # CHECK: .tabletype empty_eref_table, externref # CHECK-NEXT: empty_eref_table: Index: llvm/test/MC/WebAssembly/bulk-memory-encodings.s =================================================================== --- llvm/test/MC/WebAssembly/bulk-memory-encodings.s +++ llvm/test/MC/WebAssembly/bulk-memory-encodings.s @@ -1,5 +1,5 @@ -# RUN: llvm-mc -show-encoding -triple=wasm32-unknown-unknown -mattr=+bulk-memory < %s | FileCheck %s -# RUN: llvm-mc -show-encoding -triple=wasm64-unknown-unknown -mattr=+bulk-memory < %s | FileCheck %s +# RUN: llvm-mc -show-encoding -no-type-check -triple=wasm32-unknown-unknown -mattr=+bulk-memory < %s | FileCheck %s +# RUN: llvm-mc -show-encoding -no-type-check -triple=wasm64-unknown-unknown -mattr=+bulk-memory < %s | FileCheck %s main: .functype main () -> () Index: llvm/test/MC/WebAssembly/data-section-combined.s =================================================================== --- llvm/test/MC/WebAssembly/data-section-combined.s +++ llvm/test/MC/WebAssembly/data-section-combined.s @@ -3,7 +3,7 @@ # RUN: llvm-mc -triple=wasm32-unknown-unknown < %s | FileCheck %s test0: - .functype test0 () -> (i32) + .functype test0 () -> (i32, i32) i32.const a i32.const b end_function Index: llvm/test/MC/WebAssembly/globals.s =================================================================== --- llvm/test/MC/WebAssembly/globals.s +++ llvm/test/MC/WebAssembly/globals.s @@ -16,11 +16,14 @@ end_function write_global: - .functype write_global (i32) -> () + .functype write_global (i32, i64, f32, f64) -> () local.get 0 global.set foo_global + local.get 1 global.set global2 + local.get 2 global.set global3 + local.get 3 global.set global4 end_function Index: llvm/test/MC/WebAssembly/import-module.s =================================================================== --- llvm/test/MC/WebAssembly/import-module.s +++ llvm/test/MC/WebAssembly/import-module.s @@ -1,14 +1,15 @@ # RUN: llvm-mc -triple=wasm32 < %s | FileCheck %s -check-prefix=CHECK-ASM # RUN: llvm-mc -triple=wasm32 -filetype=obj -o - < %s | obj2yaml | FileCheck %s +.functype foo () -> () +.functype plain () -> () + test: .functype test () -> () call foo call plain end_function - .functype foo () -> () - .functype plain () -> () .import_module foo, bar .import_name foo, qux Index: llvm/test/MC/WebAssembly/null-output.s =================================================================== --- llvm/test/MC/WebAssembly/null-output.s +++ llvm/test/MC/WebAssembly/null-output.s @@ -5,6 +5,7 @@ .type main,@function main: .functype main (i32, i32) -> (i32) + local.get 0 end_function .Lfunc_end0: .size main, .Lfunc_end0-main Index: llvm/test/MC/WebAssembly/objdump.s =================================================================== --- llvm/test/MC/WebAssembly/objdump.s +++ llvm/test/MC/WebAssembly/objdump.s @@ -2,13 +2,13 @@ # RUN: llvm-objdump --triple=wasm32-unknown-unknown -d %t.o | FileCheck %s test0: - .functype test0 (i32, i64) -> (i32) + .functype test0 (i32, i64) -> (f32) .local f32, f64, v128, v128 local.get 2 end_function test1: - .functype test1 (i32, i64) -> (i32) + .functype test1 (i32, i64) -> (i64) .local i32, i64, funcref local.get 3 end_function Index: llvm/test/MC/WebAssembly/reference-types.s =================================================================== --- llvm/test/MC/WebAssembly/reference-types.s +++ llvm/test/MC/WebAssembly/reference-types.s @@ -16,12 +16,14 @@ # CHECK-NEXT: .functype ref_sig_test_funcref (funcref) -> (funcref) ref_sig_test_funcref: .functype ref_sig_test_funcref (funcref) -> (funcref) + local.get 0 end_function # CHECK-LABEL: ref_sig_test_externref: # CHECK-NEXT: .functype ref_sig_test_externref (externref) -> (externref) ref_sig_test_externref: .functype ref_sig_test_externref (externref) -> (externref) + local.get 0 end_function # CHECK-LABEL: ref_select_test: @@ -45,9 +47,11 @@ # CHECK: block funcref # CHECK: block externref ref_block_test: - .functype ref_block_test () -> () + .functype ref_block_test () -> (externref, funcref) block funcref block externref + ref.null extern end_block + ref.null func end_block end_function Index: llvm/test/MC/WebAssembly/reloc-pic.s =================================================================== --- llvm/test/MC/WebAssembly/reloc-pic.s +++ llvm/test/MC/WebAssembly/reloc-pic.s @@ -5,6 +5,11 @@ # against the corrsponding function or data symbol and that the corresponding # data symbols are imported as a wasm globals. +.functype default_func () -> (i32) + +.globaltype __memory_base, i32 +.globaltype __table_base, i32 + load_default_data: .functype load_default_data () -> (i32) global.get default_data@GOT @@ -44,7 +49,6 @@ #.hidden hidden_func #.hidden hidden_data .size default_data, 4 -.functype default_func () -> (i32) # CHECK: --- !WASM # CHECK-NEXT: FileHeader: @@ -68,6 +72,16 @@ # CHECK-NEXT: Kind: FUNCTION # CHECK-NEXT: SigIndex: 0 # CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: __memory_base +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: __table_base +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: env # CHECK-NEXT: Field: __indirect_function_table # CHECK-NEXT: Kind: TABLE # CHECK-NEXT: Table: @@ -103,13 +117,13 @@ # CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB # CHECK-NEXT: Index: 3 # CHECK-NEXT: Offset: 0x10 -# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB +# CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB # CHECK-NEXT: Index: 5 # CHECK-NEXT: Offset: 0x1C # CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_REL_SLEB # CHECK-NEXT: Index: 6 # CHECK-NEXT: Offset: 0x22 -# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB +# CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB # CHECK-NEXT: Index: 8 # CHECK-NEXT: Offset: 0x2C # CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_REL_SLEB @@ -118,16 +132,16 @@ # CHECK-NEXT: Functions: # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Locals: [] -# CHECK-NEXT: Body: 2380808080002802000B +# CHECK-NEXT: Body: 2382808080002802000B # CHECK-NEXT: - Index: 2 # CHECK-NEXT: Locals: [] -# CHECK-NEXT: Body: 2381808080002802000B +# CHECK-NEXT: Body: 2383808080002802000B # CHECK-NEXT: - Index: 3 # CHECK-NEXT: Locals: [] # CHECK-NEXT: Body: 2380808080004180808080006A0B # CHECK-NEXT: - Index: 4 # CHECK-NEXT: Locals: [] -# CHECK-NEXT: Body: 2380808080004180808080006A0B +# CHECK-NEXT: Body: 2381808080004180808080006A0B # CHECK-NEXT: - Index: 5 # CHECK-NEXT: Locals: [] # CHECK-NEXT: Body: 41000B @@ -168,9 +182,10 @@ # CHECK-NEXT: Flags: [ BINDING_LOCAL ] # CHECK-NEXT: Function: 3 # CHECK-NEXT: - Index: 5 -# CHECK-NEXT: Kind: DATA +# CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: Name: __memory_base # CHECK-NEXT: Flags: [ UNDEFINED ] +# CHECK-NEXT: Global: 0 # CHECK-NEXT: - Index: 6 # CHECK-NEXT: Kind: DATA # CHECK-NEXT: Name: .L.hidden_data @@ -183,9 +198,10 @@ # CHECK-NEXT: Flags: [ BINDING_LOCAL ] # CHECK-NEXT: Function: 4 # CHECK-NEXT: - Index: 8 -# CHECK-NEXT: Kind: DATA +# CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: Name: __table_base # CHECK-NEXT: Flags: [ UNDEFINED ] +# CHECK-NEXT: Global: 1 # CHECK-NEXT: - Index: 9 # CHECK-NEXT: Kind: FUNCTION # CHECK-NEXT: Name: hidden_func Index: llvm/test/MC/WebAssembly/reloc-pic64.s =================================================================== --- llvm/test/MC/WebAssembly/reloc-pic64.s +++ llvm/test/MC/WebAssembly/reloc-pic64.s @@ -5,6 +5,11 @@ # against the corrsponding function or data symbol and that the corresponding # data symbols are imported as a wasm globals. +.functype default_func () -> (i32) + +.globaltype __memory_base, i64 +.globaltype __table_base, i64 + load_default_data: .functype load_default_data () -> (i32) global.get default_data@GOT @@ -44,7 +49,6 @@ #.hidden hidden_func #.hidden hidden_data .size default_data, 4 -.functype default_func () -> (i32) # CHECK: --- !WASM # CHECK-NEXT: FileHeader: @@ -73,6 +77,16 @@ # CHECK-NEXT: Kind: FUNCTION # CHECK-NEXT: SigIndex: 0 # CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: __memory_base +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I64 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: __table_base +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I64 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: env # CHECK-NEXT: Field: __indirect_function_table # CHECK-NEXT: Kind: TABLE # CHECK-NEXT: Table: @@ -108,31 +122,31 @@ # CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB # CHECK-NEXT: Index: 3 # CHECK-NEXT: Offset: 0x10 -# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB +# CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB # CHECK-NEXT: Index: 5 # CHECK-NEXT: Offset: 0x1C -# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_REL_SLEB +# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_REL_SLEB64 # CHECK-NEXT: Index: 6 # CHECK-NEXT: Offset: 0x22 -# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB +# CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB # CHECK-NEXT: Index: 8 # CHECK-NEXT: Offset: 0x31 -# CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_REL_SLEB +# CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_REL_SLEB64 # CHECK-NEXT: Index: 9 # CHECK-NEXT: Offset: 0x37 # CHECK-NEXT: Functions: # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Locals: [] -# CHECK-NEXT: Body: 2380808080002802000B +# CHECK-NEXT: Body: 2382808080002802000B # CHECK-NEXT: - Index: 2 # CHECK-NEXT: Locals: [] -# CHECK-NEXT: Body: 2381808080002802000B +# CHECK-NEXT: Body: 2383808080002802000B # CHECK-NEXT: - Index: 3 # CHECK-NEXT: Locals: [] # CHECK-NEXT: Body: 23808080800042808080808080808080007C0B # CHECK-NEXT: - Index: 4 # CHECK-NEXT: Locals: [] -# CHECK-NEXT: Body: 23808080800042808080808080808080007C0B +# CHECK-NEXT: Body: 23818080800042808080808080808080007C0B # CHECK-NEXT: - Index: 5 # CHECK-NEXT: Locals: [] # CHECK-NEXT: Body: 41000B @@ -173,9 +187,10 @@ # CHECK-NEXT: Flags: [ BINDING_LOCAL ] # CHECK-NEXT: Function: 3 # CHECK-NEXT: - Index: 5 -# CHECK-NEXT: Kind: DATA +# CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: Name: __memory_base # CHECK-NEXT: Flags: [ UNDEFINED ] +# CHECK-NEXT: Global: 0 # CHECK-NEXT: - Index: 6 # CHECK-NEXT: Kind: DATA # CHECK-NEXT: Name: .L.hidden_data @@ -188,9 +203,10 @@ # CHECK-NEXT: Flags: [ BINDING_LOCAL ] # CHECK-NEXT: Function: 4 # CHECK-NEXT: - Index: 8 -# CHECK-NEXT: Kind: DATA +# CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: Name: __table_base # CHECK-NEXT: Flags: [ UNDEFINED ] +# CHECK-NEXT: Global: 1 # CHECK-NEXT: - Index: 9 # CHECK-NEXT: Kind: FUNCTION # CHECK-NEXT: Name: hidden_func Index: llvm/test/MC/WebAssembly/simd-encodings.s =================================================================== --- llvm/test/MC/WebAssembly/simd-encodings.s +++ llvm/test/MC/WebAssembly/simd-encodings.s @@ -1,4 +1,4 @@ -# RUN: llvm-mc -show-encoding -triple=wasm32-unknown-unknown -mattr=+simd128 < %s | FileCheck %s +# RUN: llvm-mc -no-type-check -show-encoding -triple=wasm32-unknown-unknown -mattr=+simd128 < %s | FileCheck %s main: .functype main () -> () Index: llvm/test/MC/WebAssembly/tail-call-encodings.s =================================================================== --- llvm/test/MC/WebAssembly/tail-call-encodings.s +++ llvm/test/MC/WebAssembly/tail-call-encodings.s @@ -15,8 +15,10 @@ end_function foo2: - .functype foo2 () -> () + .functype foo2 () -> (i32) + i32.const 0 + i32.const 0 # REF: return_call_indirect __indirect_function_table, (i32) -> (i32) # encoding: [0x13, # CHECK: return_call_indirect (i32) -> (i32) # encoding: [0x13, # CHECK-NEXT: fixup A - offset: 1, value: .Ltypeindex0@TYPEINDEX, kind: fixup_uleb128_i32 Index: llvm/test/MC/WebAssembly/tls.s =================================================================== --- llvm/test/MC/WebAssembly/tls.s +++ llvm/test/MC/WebAssembly/tls.s @@ -2,12 +2,15 @@ # RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -o %t.o < %s # RUN: obj2yaml %t.o | FileCheck %s --check-prefix=CHECK-OBJ +.globaltype __tls_base, i32 + tls_store: .functype tls_store (i32) -> () # CHECK: global.get __tls_base # CHECK-NEXT: i32.const tls1@TLSREL # CHECK-NEXT: i32.add # CHECK-NEXT: i32.store 0 + local.get 0 global.get __tls_base i32.const tls1@TLSREL i32.add @@ -28,12 +31,12 @@ # CHECK-OBJ: - Type: CODE # CHECK-OBJ-NEXT: Relocations: -# CHECK-OBJ-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB +# CHECK-OBJ-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB # CHECK-OBJ-NEXT: Index: 1 -# CHECK-OBJ-NEXT: Offset: 0x4 +# CHECK-OBJ-NEXT: Offset: 0x6 # CHECK-OBJ-NEXT: - Type: R_WASM_MEMORY_ADDR_TLS_SLEB # CHECK-OBJ-NEXT: Index: 2 -# CHECK-OBJ-NEXT: Offset: 0xA +# CHECK-OBJ-NEXT: Offset: 0xC # CHECK-OBJ: - Type: CUSTOM # CHECK-OBJ-NEXT: Name: linking @@ -45,9 +48,10 @@ # CHECK-OBJ-NEXT: Flags: [ BINDING_LOCAL ] # CHECK-OBJ-NEXT: Function: 0 # CHECK-OBJ-NEXT: - Index: 1 -# CHECK-OBJ-NEXT: Kind: DATA +# CHECK-OBJ-NEXT: Kind: GLOBAL # CHECK-OBJ-NEXT: Name: __tls_base # CHECK-OBJ-NEXT: Flags: [ UNDEFINED ] +# CHECK-OBJ-NEXT: Global: 0 # CHECK-OBJ-NEXT: - Index: 2 # CHECK-OBJ-NEXT: Kind: DATA # CHECK-OBJ-NEXT: Name: tls1 Index: llvm/test/MC/WebAssembly/type-index.s =================================================================== --- llvm/test/MC/WebAssembly/type-index.s +++ llvm/test/MC/WebAssembly/type-index.s @@ -6,13 +6,15 @@ test0: .functype test0 (i32) -> (i32) - call_indirect (f64) -> (f64) + f64.const 1.0 + local.get 0 + call_indirect (f64) -> (i32) end_function # CHECK: .text # CHECK-LABEL: test0: # CHECK-NEXT: .functype test0 (i32) -> (i32) -# CHECK-NEXT: call_indirect __indirect_function_table, (f64) -> (f64) +# CHECK: call_indirect __indirect_function_table, (f64) -> (i32) # CHECK-NEXT: end_function # BIN: --- !WASM @@ -30,7 +32,7 @@ # BIN-NEXT: ParamTypes: # BIN-NEXT: - F64 # BIN-NEXT: ReturnTypes: -# BIN-NEXT: - F64 +# BIN-NEXT: - I32 # BIN-NEXT: - Type: IMPORT # BIN-NEXT: Imports: # BIN-NEXT: - Module: env @@ -52,14 +54,14 @@ # BIN-NEXT: Relocations: # BIN-NEXT: - Type: R_WASM_TYPE_INDEX_LEB # BIN-NEXT: Index: 1 -# BIN-NEXT: Offset: 0x4 +# BIN-NEXT: Offset: 0xF # BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB # BIN-NEXT: Index: 1 -# BIN-NEXT: Offset: 0x9 +# BIN-NEXT: Offset: 0x14 # BIN-NEXT: Functions: # BIN-NEXT: - Index: 0 # BIN-NEXT: Locals: [] -# BIN-NEXT: Body: 11818080800080808080000B +# BIN-NEXT: Body: 44000000000000F03F200011818080800080808080000B # BIN-NEXT: - Type: CUSTOM # BIN-NEXT: Name: linking # BIN-NEXT: Version: 2 Index: llvm/test/MC/WebAssembly/wasm64.s =================================================================== --- llvm/test/MC/WebAssembly/wasm64.s +++ llvm/test/MC/WebAssembly/wasm64.s @@ -3,6 +3,9 @@ # Most of our other tests are for wasm32, this one adds some wasm64 specific tests. +.globaltype myglob64, i64 +.globaltype __stack_pointer, i64 + test: .functype test (i64) -> () .local i64 @@ -31,24 +34,24 @@ ### basic stores - f32.const 0.0 i64.const 0 # get i64 from constant. + f32.const 0.0 f32.store 0 - f32.const 0.0 local.get 0 # get i64 from local. + f32.const 0.0 f32.store 0 - f32.const 0.0 i64.const .L.str # get i64 relocatable. + f32.const 0.0 f32.store 0 - f32.const 0.0 global.get myglob64 # get i64 from global + f32.const 0.0 f32.store 0 - f32.const 0.0 i64.const 0 + f32.const 0.0 f32.store .L.str # relocatable offset! ### 64-bit SP @@ -66,9 +69,8 @@ .int64 .L.str # relocatable inside data. .size .L.str, 24 - .globaltype myglob64, i64 - .globaltype __stack_pointer, i64 +# CHECK: .globaltype myglob64, i64 # CHECK: .functype test (i64) -> () # CHECK-NEXT: .local i64 @@ -95,24 +97,24 @@ # CHECK-NEXT: drop -# CHECK: f32.const 0x0p0 -# CHECK-NEXT: i64.const 0 +# CHECK: i64.const 0 +# CHECK-NEXT: f32.const 0x0p0 # CHECK-NEXT: f32.store 0 -# CHECK: f32.const 0x0p0 -# CHECK-NEXT: local.get 0 +# CHECK: local.get 0 +# CHECK-NEXT: f32.const 0x0p0 # CHECK-NEXT: f32.store 0 -# CHECK: f32.const 0x0p0 -# CHECK-NEXT: i64.const .L.str +# CHECK: i64.const .L.str +# CHECK-NEXT: f32.const 0x0p0 # CHECK-NEXT: f32.store 0 -# CHECK: f32.const 0x0p0 -# CHECK-NEXT: global.get myglob64 +# CHECK: global.get myglob64 +# CHECK-NEXT: f32.const 0x0p0 # CHECK-NEXT: f32.store 0 -# CHECK: f32.const 0x0p0 -# CHECK-NEXT: i64.const 0 +# CHECK: i64.const 0 +# CHECK-NEXT: f32.const 0x0p0 # CHECK-NEXT: f32.store .L.str @@ -127,8 +129,6 @@ # CHECK-NEXT: .int64 .L.str # CHECK-NEXT: .size .L.str, 24 -# CHECK: .globaltype myglob64, i64 - # BIN: --- !WASM @@ -176,10 +176,10 @@ # BIN-NEXT: Offset: 0x2F # BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB64 # BIN-NEXT: Index: 1 -# BIN-NEXT: Offset: 0x54 +# BIN-NEXT: Offset: 0x4F # BIN-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB # BIN-NEXT: Index: 2 -# BIN-NEXT: Offset: 0x67 +# BIN-NEXT: Offset: 0x62 # BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB64 # BIN-NEXT: Index: 1 # BIN-NEXT: Offset: 0x78 @@ -191,7 +191,7 @@ # BIN-NEXT: Locals: # BIN-NEXT: - Type: I64 # BIN-NEXT: Count: 1 -# BIN-NEXT: Body: 42002A02001A20002A02001A42808080808080808080002A02001A2380808080002A02001A42002A02808080808080808080001A4300000000420038020043000000002000380200430000000042808080808080808080003802004300000000238080808000380200430000000042003802808080808080808080002381808080001A0B +# BIN-NEXT: Body: 42002A02001A20002A02001A42808080808080808080002A02001A2380808080002A02001A42002A02808080808080808080001A4200430000000038020020004300000000380200428080808080808080800043000000003802002380808080004300000000380200420043000000003802808080808080808080002381808080001A0B # BIN-NEXT: - Type: DATA # BIN-NEXT: Relocations: # BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_I64 Index: llvm/test/MC/WebAssembly/weak-alias.s =================================================================== --- llvm/test/MC/WebAssembly/weak-alias.s +++ llvm/test/MC/WebAssembly/weak-alias.s @@ -5,6 +5,8 @@ # 'bar_alias' is weak alias of global variable 'bar' # Generates two exports of the same function, one of them weak +.functype foo_alias () -> (i32) + foo: .hidden foo .globl foo Index: llvm/utils/gn/secondary/llvm/lib/Target/WebAssembly/BUILD.gn =================================================================== --- llvm/utils/gn/secondary/llvm/lib/Target/WebAssembly/BUILD.gn +++ llvm/utils/gn/secondary/llvm/lib/Target/WebAssembly/BUILD.gn @@ -53,6 +53,7 @@ "WebAssemblyLowerEmscriptenEHSjLj.cpp", "WebAssemblyLowerGlobalDtors.cpp", "WebAssemblyMCInstLower.cpp", + "WebAssemblyMCLowerPrePass.cpp", "WebAssemblyMachineFunctionInfo.cpp", "WebAssemblyMemIntrinsicResults.cpp", "WebAssemblyOptimizeLiveIntervals.cpp",