From d530f68d4572fe30f24353e2e3f7b26a54f2f994 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 24 May 2016 23:47:41 +0000 Subject: [PATCH] [WebAssembly] Put __stack_pointer in the offset field of loads and stores. Instead of this: i32.const $push10=, __stack_pointer i32.load $push11=, 0($pop10) Emit this: i32.const $push10=, 0 i32.load $push11=, __stack_pointer($pop10) It's not currently clear which is better, though there's a chance the second form may be better at overall compression. We can revisit this when we have more data; for now it makes sense to make PEI consistent with isel. Differential Revision: http://reviews.llvm.org/D20411 llvm-svn: 270635 --- .../WebAssembly/WebAssemblyFrameLowering.cpp | 20 ++--- llvm/test/CodeGen/WebAssembly/byval.ll | 22 +++--- llvm/test/CodeGen/WebAssembly/reg-stackify.ll | 4 +- llvm/test/CodeGen/WebAssembly/userstack.ll | 79 ++++++++++--------- 4 files changed, 63 insertions(+), 62 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 5902d8f9741d..24112d527c7c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -87,18 +87,18 @@ static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF, MachineRegisterInfo &MRI = MF.getRegInfo(); const TargetRegisterClass *PtrRC = MRI.getTargetRegisterInfo()->getPointerRegClass(MF); - unsigned SPAddr = MRI.createVirtualRegister(PtrRC); + unsigned Zero = MRI.createVirtualRegister(PtrRC); unsigned Drop = MRI.createVirtualRegister(PtrRC); const auto *TII = MF.getSubtarget().getInstrInfo(); - BuildMI(MBB, InsertAddr, DL, TII->get(WebAssembly::CONST_I32), SPAddr) - .addExternalSymbol(SPSymbol); + BuildMI(MBB, InsertAddr, DL, TII->get(WebAssembly::CONST_I32), Zero) + .addImm(0); auto *MMO = new MachineMemOperand(MachinePointerInfo(MF.getPSVManager() .getExternalSymbolCallEntry(ES)), MachineMemOperand::MOStore, 4, 4); BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::STORE_I32), Drop) - .addImm(0) - .addReg(SPAddr) + .addExternalSymbol(SPSymbol) + .addReg(Zero) .addImm(2) // p2align .addReg(SrcReg) .addMemOperand(MMO); @@ -137,20 +137,20 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, const TargetRegisterClass *PtrRC = MRI.getTargetRegisterInfo()->getPointerRegClass(MF); - unsigned SPAddr = MRI.createVirtualRegister(PtrRC); + unsigned Zero = MRI.createVirtualRegister(PtrRC); unsigned SPReg = MRI.createVirtualRegister(PtrRC); const char *ES = "__stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPAddr) - .addExternalSymbol(SPSymbol); + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), Zero) + .addImm(0); auto *LoadMMO = new MachineMemOperand(MachinePointerInfo(MF.getPSVManager() .getExternalSymbolCallEntry(ES)), MachineMemOperand::MOLoad, 4, 4); // Load the SP value. BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), StackSize ? SPReg : (unsigned)WebAssembly::SP32) - .addImm(0) // offset - .addReg(SPAddr) // addr + .addExternalSymbol(SPSymbol) + .addReg(Zero) // addr .addImm(2) // p2align .addMemOperand(LoadMMO); diff --git a/llvm/test/CodeGen/WebAssembly/byval.ll b/llvm/test/CodeGen/WebAssembly/byval.ll index bc8f1eb8ad6c..ebbf50313a58 100644 --- a/llvm/test/CodeGen/WebAssembly/byval.ll +++ b/llvm/test/CodeGen/WebAssembly/byval.ll @@ -23,14 +23,14 @@ declare void @ext_byval_func_empty(%EmptyStruct* byval) ; CHECK-LABEL: byval_arg define void @byval_arg(%SmallStruct* %ptr) { ; CHECK: .param i32 - ; CHECK: i32.const $push[[L4:.+]]=, __stack_pointer + ; CHECK: i32.const $push[[L4:.+]]=, 0 ; Subtract 16 from SP (SP is 16-byte aligned) - ; CHECK: i32.const $push[[L1:.+]]=, __stack_pointer - ; CHECK-NEXT: i32.load $push[[L2:.+]]=, 0($pop[[L1]]) + ; CHECK: i32.const $push[[L1:.+]]=, 0 + ; CHECK-NEXT: i32.load $push[[L2:.+]]=, __stack_pointer($pop[[L1]]) ; CHECK-NEXT: i32.const $push[[L3:.+]]=, 16 ; CHECK-NEXT: i32.sub $push[[L10:.+]]=, $pop[[L2]], $pop[[L3]] ; Ensure SP is stored back before the call - ; CHECK-NEXT: i32.store $push[[L12:.+]]=, 0($pop[[L4]]), $pop[[L10]]{{$}} + ; CHECK-NEXT: i32.store $push[[L12:.+]]=, __stack_pointer($pop[[L4]]), $pop[[L10]]{{$}} ; CHECK-NEXT: tee_local $push[[L11:.+]]=, $[[SP:.+]]=, $pop[[L12]]{{$}} ; Copy the SmallStruct argument to the stack (SP+12, original SP-4) ; CHECK-NEXT: i32.load $push[[L0:.+]]=, 0($0) @@ -41,10 +41,10 @@ define void @byval_arg(%SmallStruct* %ptr) { ; CHECK-NEXT: call ext_byval_func@FUNCTION, $pop[[ARG]]{{$}} call void @ext_byval_func(%SmallStruct* byval %ptr) ; Restore the stack - ; CHECK-NEXT: i32.const $push[[L7:.+]]=, __stack_pointer + ; CHECK-NEXT: i32.const $push[[L7:.+]]=, 0 ; CHECK-NEXT: i32.const $push[[L6:.+]]=, 16 ; CHECK-NEXT: i32.add $push[[L8:.+]]=, $[[SP]], $pop[[L6]] - ; CHECK-NEXT: i32.store {{.*}}=, 0($pop[[L7]]), $pop[[L8]] + ; CHECK-NEXT: i32.store {{.*}}=, __stack_pointer($pop[[L7]]), $pop[[L8]] ; CHECK-NEXT: return ret void } @@ -55,7 +55,7 @@ define void @byval_arg_align8(%SmallStruct* %ptr) { ; Don't check the entire SP sequence, just enough to get the alignment. ; CHECK: i32.const $push[[L1:.+]]=, 16 ; CHECK-NEXT: i32.sub $push[[L10:.+]]=, {{.+}}, $pop[[L1]] - ; CHECK-NEXT: i32.store $push[[L12:.+]]=, 0($pop{{.+}}), $pop[[L10]]{{$}} + ; CHECK-NEXT: i32.store $push[[L12:.+]]=, __stack_pointer($pop{{.+}}), $pop[[L10]]{{$}} ; CHECK-NEXT: tee_local $push[[L11:.+]]=, $[[SP:.+]]=, $pop[[L12]]{{$}} ; Copy the SmallStruct argument to the stack (SP+8, original SP-8) ; CHECK-NEXT: i32.load $push[[L0:.+]]=, 0($0){{$}} @@ -113,12 +113,12 @@ define void @byval_empty_callee(%EmptyStruct* byval %ptr) { ; Call memcpy for "big" byvals. ; CHECK-LABEL: big_byval: -; CHECK: i32.const $push[[L4:.+]]=, __stack_pointer -; CHECK: i32.const $push[[L1:.+]]=, __stack_pointer -; CHECK-NEXT: i32.load $push[[L2:.+]]=, 0($pop[[L1]]) +; CHECK: i32.const $push[[L4:.+]]=, 0 +; CHECK: i32.const $push[[L1:.+]]=, 0 +; CHECK-NEXT: i32.load $push[[L2:.+]]=, __stack_pointer($pop[[L1]]) ; CHECK-NEXT: i32.const $push[[L3:.+]]=, 131072 ; CHECK-NEXT: i32.sub $push[[L8:.+]]=, $pop[[L2]], $pop[[L3]] -; CHECK-NEXT: i32.store $push[[L12:.+]]=, 0($pop[[L4]]), $pop[[L8]]{{$}} +; CHECK-NEXT: i32.store $push[[L12:.+]]=, __stack_pointer($pop[[L4]]), $pop[[L8]]{{$}} ; CHECK-NEXT: i32.const $push[[L0:.+]]=, 131072 ; CHECK-NEXT: i32.call $push[[L11:.+]]=, memcpy@FUNCTION, $pop{{.+}}, ${{.+}}, $pop{{.+}} ; CHECK-NEXT: tee_local $push[[L9:.+]]=, $[[SP:.+]]=, $pop[[L11]]{{$}} diff --git a/llvm/test/CodeGen/WebAssembly/reg-stackify.ll b/llvm/test/CodeGen/WebAssembly/reg-stackify.ll index 2f70a561fee8..23cbd03aa080 100644 --- a/llvm/test/CodeGen/WebAssembly/reg-stackify.ll +++ b/llvm/test/CodeGen/WebAssembly/reg-stackify.ll @@ -449,8 +449,8 @@ bb10: ; preds = %bb9, %bb ; CHECK-LABEL: stackpointer_dependency: ; CHECK: call {{.+}}, stackpointer_callee@FUNCTION, -; CHECK: i32.const $push[[L0:.+]]=, __stack_pointer -; CHECK-NEXT: i32.store $drop=, 0($pop[[L0]]), +; CHECK: i32.const $push[[L0:.+]]=, 0 +; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop[[L0]]), declare i32 @stackpointer_callee(i8* readnone, i8* readnone) declare i8* @llvm.frameaddress(i32) define i32 @stackpointer_dependency(i8* readnone) { diff --git a/llvm/test/CodeGen/WebAssembly/userstack.ll b/llvm/test/CodeGen/WebAssembly/userstack.ll index ee2bbfb66284..66ac2cce7079 100644 --- a/llvm/test/CodeGen/WebAssembly/userstack.ll +++ b/llvm/test/CodeGen/WebAssembly/userstack.ll @@ -10,29 +10,29 @@ declare void @ext_func_i32(i32* %ptr) ; Check that there is an extra local for the stack pointer. ; CHECK: .local i32{{$}} define void @alloca32() noredzone { - ; CHECK: i32.const $push[[L4:.+]]=, __stack_pointer{{$}} - ; CHECK: i32.const $push[[L1:.+]]=, __stack_pointer{{$}} - ; CHECK-NEXT: i32.load $push[[L2:.+]]=, 0($pop[[L1]]) + ; CHECK: i32.const $push[[L4:.+]]=, 0{{$}} + ; CHECK: i32.const $push[[L1:.+]]=, 0{{$}} + ; CHECK-NEXT: i32.load $push[[L2:.+]]=, __stack_pointer($pop[[L1]]) ; CHECK-NEXT: i32.const $push[[L3:.+]]=, 16 ; CHECK-NEXT: i32.sub $push[[L8:.+]]=, $pop[[L2]], $pop[[L3]] - ; CHECK-NEXT: i32.store $push[[L10:.+]]=, 0($pop[[L4]]), $pop[[L8]]{{$}} + ; CHECK-NEXT: i32.store $push[[L10:.+]]=, __stack_pointer($pop[[L4]]), $pop[[L8]]{{$}} ; CHECK-NEXT: tee_local $push[[L9:.+]]=, $[[SP:.+]]=, $pop[[L10]]{{$}} %retval = alloca i32 ; CHECK: i32.const $push[[L0:.+]]=, 0 ; CHECK: i32.store {{.*}}=, 12($pop[[L9]]), $pop[[L0]] store i32 0, i32* %retval - ; CHECK: i32.const $push[[L6:.+]]=, __stack_pointer + ; CHECK: i32.const $push[[L6:.+]]=, 0 ; CHECK-NEXT: i32.const $push[[L5:.+]]=, 16 ; CHECK-NEXT: i32.add $push[[L7:.+]]=, $[[SP]], $pop[[L5]] - ; CHECK-NEXT: i32.store $drop=, 0($pop[[L6]]), $pop[[L7]] + ; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop[[L6]]), $pop[[L7]] ret void } ; CHECK-LABEL: alloca3264: ; CHECK: .local i32{{$}} define void @alloca3264() { - ; CHECK: i32.const $push[[L2:.+]]=, __stack_pointer - ; CHECK-NEXT: i32.load $push[[L3:.+]]=, 0($pop[[L2]]) + ; CHECK: i32.const $push[[L2:.+]]=, 0{{$}} + ; CHECK-NEXT: i32.load $push[[L3:.+]]=, __stack_pointer($pop[[L2]]) ; CHECK-NEXT: i32.const $push[[L4:.+]]=, 16 ; CHECK-NEXT: i32.sub $push[[L6:.+]]=, $pop[[L3]], $pop[[L4]] ; CHECK-NEXT: tee_local $push[[L5:.+]]=, $[[SP:.+]]=, $pop[[L6]] @@ -51,12 +51,12 @@ define void @alloca3264() { ; CHECK-LABEL: allocarray: ; CHECK: .local i32{{$}} define void @allocarray() { - ; CHECK: i32.const $push[[L7:.+]]=, __stack_pointer - ; CHECK: i32.const $push[[L4:.+]]=, __stack_pointer - ; CHECK-NEXT: i32.load $push[[L5:.+]]=, 0($pop[[L4]]) + ; CHECK: i32.const $push[[L7:.+]]=, 0{{$}} + ; CHECK: i32.const $push[[L4:.+]]=, 0{{$}} + ; CHECK-NEXT: i32.load $push[[L5:.+]]=, __stack_pointer($pop[[L4]]) ; CHECK-NEXT: i32.const $push[[L6:.+]]=, 144{{$}} ; CHECK-NEXT: i32.sub $push[[L11:.+]]=, $pop[[L5]], $pop[[L6]] - ; CHECK-NEXT: i32.store ${{.+}}=, 0($pop[[L7]]), $pop[[L11]] + ; CHECK-NEXT: i32.store ${{.+}}=, __stack_pointer($pop[[L7]]), $pop[[L11]] %r = alloca [33 x i32] ; CHECK: i32.const $push{{.+}}=, 24 @@ -69,10 +69,10 @@ define void @allocarray() { %p2 = getelementptr [33 x i32], [33 x i32]* %r, i32 0, i32 3 store i32 1, i32* %p2 - ; CHECK: i32.const $push[[L10:.+]]=, __stack_pointer + ; CHECK: i32.const $push[[L10:.+]]=, 0{{$}} ; CHECK-NEXT: i32.const $push[[L8:.+]]=, 144 ; CHECK-NEXT: i32.add $push[[L19:.+]]=, $[[SP]], $pop[[L8]] - ; CHECK-NEXT: i32.store $drop=, 0($pop[[L10]]), $pop[[L9]] + ; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop[[L10]]), $pop[[L9]] ret void } @@ -106,12 +106,12 @@ define void @non_mem_use(i8** %addr) { ; CHECK-LABEL: allocarray_inbounds: ; CHECK: .local i32{{$}} define void @allocarray_inbounds() { - ; CHECK: i32.const $push[[L6:.+]]=, __stack_pointer - ; CHECK: i32.const $push[[L3:.+]]=, __stack_pointer - ; CHECK-NEXT: i32.load $push[[L4:.+]]=, 0($pop[[L3]]) + ; CHECK: i32.const $push[[L6:.+]]=, 0{{$}} + ; CHECK: i32.const $push[[L3:.+]]=, 0{{$}} + ; CHECK-NEXT: i32.load $push[[L4:.+]]=, __stack_pointer($pop[[L3]]) ; CHECK-NEXT: i32.const $push[[L5:.+]]=, 32{{$}} ; CHECK-NEXT: i32.sub $push[[L10:.+]]=, $pop[[L4]], $pop[[L5]] - ; CHECK-NEXT: i32.store ${{.+}}=, 0($pop[[L6]]), $pop[[L10]]{{$}} + ; CHECK-NEXT: i32.store ${{.+}}=, __stack_pointer($pop[[L6]]), $pop[[L10]]{{$}} %r = alloca [5 x i32] ; CHECK: i32.const $push[[L3:.+]]=, 1 ; CHECK-DAG: i32.store $push{{.*}}=, 24(${{.+}}), $pop[[L3]] @@ -122,36 +122,37 @@ define void @allocarray_inbounds() { %p2 = getelementptr inbounds [5 x i32], [5 x i32]* %r, i32 0, i32 3 store i32 1, i32* %p2 call void @ext_func(i64* null); - ; CHECK: i32.const $push[[L6:.+]]=, __stack_pointer - ; CHECK-NEXT: i32.const $push[[L5:.+]]=, 32 + ; CHECK: call ext_func + ; CHECK: i32.const $push[[L6:.+]]=, 0{{$}} + ; CHECK-NEXT: i32.const $push[[L5:.+]]=, 32{{$}} ; CHECK-NEXT: i32.add $push[[L7:.+]]=, ${{.+}}, $pop[[L5]] - ; CHECK-NEXT: i32.store $drop=, 0($pop[[L6]]), $pop[[L7]] + ; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop[[L6]]), $pop[[L7]] ret void } ; CHECK-LABEL: dynamic_alloca: define void @dynamic_alloca(i32 %alloc) { - ; CHECK: i32.const $push[[L7:.+]]=, __stack_pointer - ; CHECK: i32.const $push[[L1:.+]]=, __stack_pointer - ; CHECK-NEXT: i32.load $push[[L13:.+]]=, 0($pop[[L1]]) + ; CHECK: i32.const $push[[L7:.+]]=, 0{{$}} + ; CHECK: i32.const $push[[L1:.+]]=, 0{{$}} + ; CHECK-NEXT: i32.load $push[[L13:.+]]=, __stack_pointer($pop[[L1]]) ; CHECK-NEXT: tee_local $push[[L12:.+]]=, [[SP:.+]], $pop[[L13]]{{$}} ; Target independent codegen bumps the stack pointer. ; CHECK: i32.sub ; Check that SP is written back to memory after decrement - ; CHECK: i32.store $drop=, 0($pop{{.+}}), + ; CHECK: i32.store $drop=, __stack_pointer($pop{{.+}}), %r = alloca i32, i32 %alloc ; Target-independent codegen also calculates the store addr ; CHECK: call ext_func_i32@FUNCTION call void @ext_func_i32(i32* %r) - ; CHECK: i32.const $push[[L3:.+]]=, __stack_pointer - ; CHECK: i32.store $drop=, 0($pop[[L3]]), $pop{{.+}} + ; CHECK: i32.const $push[[L3:.+]]=, 0{{$}} + ; CHECK: i32.store $drop=, __stack_pointer($pop[[L3]]), $pop{{.+}} ret void } ; CHECK-LABEL: dynamic_alloca_redzone: define void @dynamic_alloca_redzone(i32 %alloc) { - ; CHECK: i32.const $push[[L8:.+]]=, __stack_pointer - ; CHECK-NEXT: i32.load $push[[L13:.+]]=, 0($pop[[L1]]) + ; CHECK: i32.const $push[[L8:.+]]=, 0{{$}} + ; CHECK-NEXT: i32.load $push[[L13:.+]]=, __stack_pointer($pop[[L1]]) ; CHECK-NEXT: tee_local $push[[L12:.+]]=, [[SP:.+]], $pop[[L13]]{{$}} ; CHECK-NEXT: copy_local [[FP:.+]]=, $pop[[L12]]{{$}} ; Target independent codegen bumps the stack pointer @@ -169,18 +170,18 @@ define void @dynamic_alloca_redzone(i32 %alloc) { ; CHECK-LABEL: dynamic_static_alloca: define void @dynamic_static_alloca(i32 %alloc) noredzone { ; Decrement SP in the prolog by the static amount and writeback to memory. - ; CHECK: i32.const $push[[L7:.+]]=, __stack_pointer - ; CHECK: i32.const $push[[L8:.+]]=, __stack_pointer - ; CHECK: i32.const $push[[L9:.+]]=, __stack_pointer - ; CHECK-NEXT: i32.load $push[[L10:.+]]=, 0($pop[[L9]]) + ; CHECK: i32.const $push[[L7:.+]]=, 0{{$}} + ; CHECK: i32.const $push[[L8:.+]]=, 0{{$}} + ; CHECK: i32.const $push[[L9:.+]]=, 0{{$}} + ; CHECK-NEXT: i32.load $push[[L10:.+]]=, __stack_pointer($pop[[L9]]) ; CHECK-NEXT: i32.const $push[[L11:.+]]=, 16 ; CHECK-NEXT: i32.sub $push[[L20:.+]]=, $pop[[L10]], $pop[[L11]] ; CHECK-NEXT: tee_local $push[[L19:.+]]=, $[[FP:.+]]=, $pop[[L20]] - ; CHECK: i32.store $push[[L0:.+]]=, 0($pop{{.+}}), $pop{{.+}} + ; CHECK: i32.store $push[[L0:.+]]=, __stack_pointer($pop{{.+}}), $pop{{.+}} ; Decrement SP in the body by the dynamic amount. ; CHECK: i32.sub ; Writeback to memory. - ; CHECK: i32.store $drop=, 0($pop{{.+}}), $pop{{.+}} + ; CHECK: i32.store $drop=, __stack_pointer($pop{{.+}}), $pop{{.+}} %r1 = alloca i32 %r = alloca i32, i32 %alloc store i32 0, i32* %r @@ -214,13 +215,13 @@ declare i8* @llvm.frameaddress(i32) ; Test __builtin_frame_address(0). ; CHECK-LABEL: frameaddress_0: -; CHECK: i32.const $push[[L0:.+]]=, __stack_pointer -; CHECK-NEXT: i32.load $push[[L3:.+]]=, 0($pop[[L0]]) +; CHECK: i32.const $push[[L0:.+]]=, 0{{$}} +; CHECK-NEXT: i32.load $push[[L3:.+]]=, __stack_pointer($pop[[L0]]) ; CHECK-NEXT: copy_local $push[[L4:.+]]=, $pop[[L3]]{{$}} ; CHECK-NEXT: tee_local $push[[L2:.+]]=, $[[FP:.+]]=, $pop[[L4]]{{$}} ; CHECK-NEXT: call use_i8_star@FUNCTION, $pop[[L2]] -; CHECK-NEXT: i32.const $push[[L1:.+]]=, __stack_pointer -; CHECK-NEXT: i32.store $drop=, 0($pop[[L1]]), $[[FP]] +; CHECK-NEXT: i32.const $push[[L1:.+]]=, 0{{$}} +; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop[[L1]]), $[[FP]] define void @frameaddress_0() { %t = call i8* @llvm.frameaddress(i32 0) call void @use_i8_star(i8* %t)