Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp @@ -64,6 +64,11 @@ const MachineFrameInfo &MFI = MF.getFrameInfo(); int64_t FrameOffset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex); + assert(MFI.getObjectSize(FrameIndex) != 0 && + "We assume that variable-sized objects have already been lowered, " + "and don't use FrameIndex operands."); + unsigned FrameRegister = getFrameRegister(MF); + // If this is the address operand of a load or store, make it relative to SP // and fold the frame offset directly in. if (MI.mayLoadOrStore() && FIOperandNum == WebAssembly::MemOpAddressOperandNo) { @@ -73,7 +78,7 @@ if (static_cast(Offset) <= std::numeric_limits::max()) { MI.getOperand(FIOperandNum - 1).setImm(Offset); MI.getOperand(FIOperandNum) - .ChangeToRegister(WebAssembly::SP32, /*IsDef=*/false); + .ChangeToRegister(FrameRegister, /*IsDef=*/false); return; } } @@ -94,7 +99,7 @@ MachineOperand &ImmMO = Def->getOperand(1); ImmMO.setImm(ImmMO.getImm() + uint32_t(FrameOffset)); MI.getOperand(FIOperandNum) - .ChangeToRegister(WebAssembly::SP32, /*IsDef=*/false); + .ChangeToRegister(FrameRegister, /*IsDef=*/false); return; } } @@ -104,7 +109,7 @@ // Otherwise create an i32.add SP, offset and make it the operand. const auto *TII = MF.getSubtarget().getInstrInfo(); - unsigned FIRegOperand = WebAssembly::SP32; + unsigned FIRegOperand = FrameRegister; if (FrameOffset) { // Create i32.add SP, offset and make it the operand. const TargetRegisterClass *PtrRC = @@ -116,7 +121,7 @@ FIRegOperand = MRI.createVirtualRegister(PtrRC); BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::ADD_I32), FIRegOperand) - .addReg(WebAssembly::SP32) + .addReg(FrameRegister) .addReg(OffsetOp); } MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*IsDef=*/false); Index: llvm/trunk/test/CodeGen/WebAssembly/userstack.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/userstack.ll +++ llvm/trunk/test/CodeGen/WebAssembly/userstack.ll @@ -173,21 +173,62 @@ ; 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[[L11:.+]]=, 0{{$}} - ; CHECK: i32.const $push[[L8:.+]]=, 0{{$}} - ; CHECK-NEXT: i32.load $push[[L9:.+]]=, __stack_pointer($pop[[L8]]) - ; CHECK-NEXT: i32.const $push[[L10:.+]]=, 16 - ; CHECK-NEXT: i32.sub $push[[L20:.+]]=, $pop[[L9]], $pop[[L10]] - ; CHECK-NEXT: tee_local $push[[L19:.+]]=, $[[FP:.+]]=, $pop[[L20]] - ; CHECK: i32.store $drop=, __stack_pointer($pop{{.+}}), $pop{{.+}} + ; CHECK: i32.const $push[[L13:.+]]=, 0{{$}} + ; CHECK: i32.const $push[[L10:.+]]=, 0{{$}} + ; CHECK-NEXT: i32.load $push[[L11:.+]]=, __stack_pointer($pop[[L10]]) + ; CHECK-NEXT: i32.const $push[[L12:.+]]=, 16 + ; CHECK-NEXT: i32.sub $push[[L23:.+]]=, $pop[[L11]], $pop[[L12]] + ; CHECK-NEXT: tee_local $push[[L22:.+]]=, $[[SP:.+]]=, $pop[[L23]] + ; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop{{.+}}), $pop[[L22]] + + ; Alloc and write to a static alloca + ; CHECK: copy_local $push[[L21:.+]]=, $[[SP]] + ; CHECK-NEXT: tee_local $push[[pushedFP:.+]]=, $[[FP:.+]]=, $pop[[L21]] + ; CHECK-NEXT: i32.const $push[[L0:.+]]=, 101 + ; CHECK-NEXT: i32.store $drop=, [[static_offset:.+]]($pop[[pushedFP]]), $pop[[L0]] + %static = alloca i32 + store volatile i32 101, i32* %static + + ; Decrement SP in the body by the dynamic amount. + ; CHECK: i32.sub + ; CHECK: tee_local $push{{.+}}=, $[[dynamic_local:.+]]=, $pop{{.+}} + ; CHECK: i32.store {{.*}} __stack_pointer + %dynamic = alloca i32, i32 %alloc + + ; Ensure we don't modify the frame pointer after assigning it. + ; CHECK-NOT: $[[FP]]= + + ; Ensure the static address doesn't change after modifying the stack pointer. + ; CHECK: i32.const $push[[L7:.+]]=, 102 + ; CHECK-NEXT: i32.store $drop=, [[static_offset]]($[[FP]]), $pop[[L7]] + ; CHECK-NEXT: i32.const $push[[L8:.+]]=, 103 + ; CHECK-NEXT: i32.store $drop=, 0($[[dynamic_local]]), $pop[[L8]] + store volatile i32 102, i32* %static + store volatile i32 103, i32* %dynamic + ; Decrement SP in the body by the dynamic amount. ; CHECK: i32.sub + ; CHECK: tee_local $push{{.+}}=, $[[dynamic2_local:.+]]=, $pop{{.+}} + %dynamic.2 = alloca i32, i32 %alloc + + ; CHECK-NOT: $[[FP]]= + + ; Ensure neither the static nor dynamic address changes after the second + ; modification of the stack pointer. + ; CHECK: i32.const $push[[L9:.+]]=, 104 + ; CHECK-NEXT: i32.store $drop=, [[static_offset]]($[[FP]]), $pop[[L9]] + ; CHECK-NEXT: i32.const $push[[L10:.+]]=, 105 + ; CHECK-NEXT: i32.store $drop=, 0($[[dynamic_local]]), $pop[[L10]] + ; CHECK-NEXT: i32.const $push[[L11:.+]]=, 106 + ; CHECK-NEXT: i32.store $drop=, 0($[[dynamic2_local]]), $pop[[L11]] + store volatile i32 104, i32* %static + store volatile i32 105, i32* %dynamic + store volatile i32 106, i32* %dynamic.2 + ; Writeback to memory. - ; CHECK: i32.store $drop=, __stack_pointer($pop{{.+}}), $pop{{.+}} - %r1 = alloca i32 - %r = alloca i32, i32 %alloc - store i32 0, i32* %r - ; CHEC: i32.store $drop=, 0($pop{{.+}}), $pop{{.+}} + ; CHECK: i32.const $push[[L17:.+]]=, 16 + ; CHECK-NEXT: i32.add $push[[L18:.+]]=, $[[FP]], $pop[[L17]] + ; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop{{.+}}), $pop[[L18]] ret void }