From 27e3b8a6e3a5c75a0e23d18a7bb3f32bce851db8 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Mon, 22 Feb 2016 21:57:17 +0000 Subject: [PATCH] [WebAssembly] Fix writeback of stack pointer with dynamic alloca Previously the stack pointer was only written back to memory in the prolog. But this is wrong for dynamic allocas, for which target-independent codegen handles SP updates after the prolog (and possibly even in another BB). Instead update the SP global in ADJCALLSTACKDOWN which is generated after the SP update sequence. This will have further refinements when we add red zone support. llvm-svn: 261579 --- .../WebAssembly/WebAssemblyFrameLowering.cpp | 67 +++++++++++----------- llvm/test/CodeGen/WebAssembly/userstack.ll | 17 ++++-- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index cbf59d1..c5f43d8 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -59,12 +59,39 @@ bool WebAssemblyFrameLowering::hasReservedCallFrame( return !MF.getFrameInfo()->hasVarSizedObjects(); } +static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator &InsertPt, + DebugLoc DL) { + auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer"); + unsigned SPAddr = + MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); + const auto *TII = MF.getSubtarget().getInstrInfo(); + + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPAddr) + .addExternalSymbol(SPSymbol); + auto *MMO = new MachineMemOperand(MachinePointerInfo(), + MachineMemOperand::MOStore, 4, 4); + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32), + WebAssembly::SP32) + .addImm(0) + .addReg(SPAddr) + .addImm(2) // p2align + .addReg(SrcReg) + .addMemOperand(MMO); + MF.getInfo()->stackifyVReg(SPAddr); +} + void WebAssemblyFrameLowering::eliminateCallFramePseudoInstr( MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { - // TODO: can we avoid using call frame pseudos altogether? - assert(!I->getOperand(0).getImm() && - "Stack should not be adjusted around calls"); + assert(!I->getOperand(0).getImm() && hasFP(MF) && + "Call frame pseudos should only be used for dynamic stack adjustment"); + const auto *TII = MF.getSubtarget().getInstrInfo(); + if (I->getOpcode() == TII->getCallFrameDestroyOpcode()) { + DebugLoc DL = I->getDebugLoc(); + writeSPToMemory(WebAssembly::SP32, MF, MBB, I, DL); + } MBB.erase(I); } @@ -125,21 +152,8 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, WebAssembly::FP32) .addReg(WebAssembly::SP32); } - if (StackSize || hasFP(MF)) { - SPAddr = MRI.createVirtualRegister(&WebAssembly::I32RegClass); - // The SP32 register now has the new stacktop. Also write it back to memory. - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPAddr) - .addExternalSymbol(SPSymbol); - auto *MMO = new MachineMemOperand(MachinePointerInfo(), - MachineMemOperand::MOStore, 4, 4); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32), - WebAssembly::SP32) - .addImm(0) - .addReg(SPAddr) - .addImm(2) // p2align - .addReg(WebAssembly::SP32) - .addMemOperand(MMO); - WFI->stackifyVReg(SPAddr); + if (StackSize) { + writeSPToMemory(WebAssembly::SP32, MF, MBB, InsertPt, DL); } } @@ -171,18 +185,7 @@ void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, WFI->stackifyVReg(OffsetReg); } - auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer"); - unsigned SPAddr = MRI.createVirtualRegister(&WebAssembly::I32RegClass); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPAddr) - .addExternalSymbol(SPSymbol); - auto *MMO = new MachineMemOperand(MachinePointerInfo(), - MachineMemOperand::MOStore, 4, 4); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32), - WebAssembly::SP32) - .addImm(0) - .addReg(SPAddr) - .addImm(2) // p2align - .addReg((!StackSize && hasFP(MF)) ? WebAssembly::FP32 : WebAssembly::SP32) - .addMemOperand(MMO); - WFI->stackifyVReg(SPAddr); + writeSPToMemory( + (!StackSize && hasFP(MF)) ? WebAssembly::FP32 : WebAssembly::SP32, MF, + MBB, InsertPt, DL); } diff --git a/llvm/test/CodeGen/WebAssembly/userstack.ll b/llvm/test/CodeGen/WebAssembly/userstack.ll index 1b98073..74edd89 100644 --- a/llvm/test/CodeGen/WebAssembly/userstack.ll +++ b/llvm/test/CodeGen/WebAssembly/userstack.ll @@ -134,8 +134,11 @@ define void @dynamic_alloca(i32 %alloc) { ; CHECK: i32.const $push[[L1:.+]]=, __stack_pointer ; CHECK-NEXT: i32.load [[SP:.+]]=, 0($pop[[L1]]) ; CHECK-NEXT: copy_local [[FP:.+]]=, [[SP]] - ; Target independent codegen bumps the stack pointer - ; CHECK: i32.const $push[[L4:.+]]=, __stack_pointer{{$}} + ; Target independent codegen bumps the stack pointer. + ; CHECK: i32.sub + ; CHECK-NEXT: copy_local [[SP]]=, + ; Check that SP is written back to memory after decrement + ; CHECK-NEXT: i32.const $push[[L4:.+]]=, __stack_pointer{{$}} ; CHECK-NEXT: i32.store $discard=, 0($pop[[L4]]), [[SP]] %r = alloca i32, i32 %alloc ; Target-independent codegen also calculates the store addr @@ -145,9 +148,9 @@ define void @dynamic_alloca(i32 %alloc) { ret void } - ; CHECK-LABEL: dynamic_static_alloca: define void @dynamic_static_alloca(i32 %alloc) { + ; Decrement SP in the prolog by the static amount and writeback to memory. ; CHECK: i32.const $push[[L1:.+]]=, __stack_pointer ; CHECK-NEXT: i32.load $push[[L2:.+]]=, 0($pop[[L1]]) ; CHECK-NEXT: i32.const $push[[L3:.+]]=, 16 @@ -155,6 +158,12 @@ define void @dynamic_static_alloca(i32 %alloc) { ; CHECK-NEXT: copy_local [[FP:.+]]=, [[SP]] ; CHECK-NEXT: i32.const $push[[L4:.+]]=, __stack_pointer ; CHECK-NEXT: i32.store {{.*}}=, 0($pop[[L4]]), [[SP]] + ; Decrement SP in the body by the dynamic amount. + ; CHECK: i32.sub + ; CHECK: copy_local [[SP]]=, + ; Writeback to memory. + ; CHECK-NEXT: i32.const $push[[L4:.+]]=, __stack_pointer + ; CHECK-NEXT: i32.store {{.*}}=, 0($pop[[L4]]), [[SP]] %r1 = alloca i32 %r = alloca i32, i32 %alloc store i32 0, i32* %r @@ -194,8 +203,6 @@ declare i8* @llvm.frameaddress(i32) ; CHECK: i32.const $push[[L1:.+]]=, __stack_pointer ; CHECK-NEXT: i32.load [[SP:.+]]=, 0($pop[[L1]]) ; CHECK-NEXT: copy_local [[FP:.+]]=, [[SP]] -; CHECK-NEXT: i32.const $push[[L2:.+]]=, __stack_pointer{{$}} -; CHECK-NEXT: i32.store $discard=, 0($pop[[L2]]), [[SP]] ; CHECK-NEXT: call use_i8_star@FUNCTION, [[FP]] ; CHECK-NEXT: i32.const $push[[L6:.+]]=, __stack_pointer ; CHECK-NEXT: i32.store [[SP]]=, 0($pop[[L6]]), [[FP]] -- 2.7.4