Krzysztof Parzyszek
2013-Sep-25 15:57 UTC
[LLVMdev] Register scavenger and SP/FP adjustments
Hi All, I'm dealing with a problem where the spill/restore instructions inserted during scavenging span an adjustment of the SP/FP register. The result is that despite the base register (SP/FP) being changed between the spill and the restore, both store and load use the same immediate offset. I see code in the PEI (replaceFrameIndices) that is supposed to track the SP/FP adjustment: ---------------------------------------- void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &Fn, int &SPAdj) { const TargetMachine &TM = Fn.getTarget(); assert(TM.getRegisterInfo() && "TM::getRegisterInfo() must be implemented!"); const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo(); const TargetRegisterInfo &TRI = *TM.getRegisterInfo(); const TargetFrameLowering *TFI = TM.getFrameLowering(); bool StackGrowsDown TFI->getStackGrowthDirection() = TargetFrameLowering::StackGrowsDown; int FrameSetupOpcode = TII.getCallFrameSetupOpcode(); int FrameDestroyOpcode = TII.getCallFrameDestroyOpcode(); if (RS && !FrameIndexVirtualScavenging) RS->enterBasicBlock(BB); for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) { if (I->getOpcode() == FrameSetupOpcode || I->getOpcode() == FrameDestroyOpcode) { // Remember how much SP has been adjusted to create the call // frame. int Size = I->getOperand(0).getImm(); if ((!StackGrowsDown && I->getOpcode() == FrameSetupOpcode) || (StackGrowsDown && I->getOpcode() == FrameDestroyOpcode)) Size = -Size; SPAdj += Size; [...] ---------------------------------------- The problem is that it expects frame-setup and frame-destroy opcodes, but at the time it runs (after emitPrologue/emitEpilogue) the frame setup and teardown will be expanded into instruction sequences that can be different for each target, let alone having the immediate value in the 0-th operand. As I see, this code won't work, although I'm not sure what was the original idea behind it. Should this code run before the target specific generation of prolog/epilog? Even then, there won't need to be ADJCALLSTACKUP/DOWN instructions (if it's a leaf function). If it runs where it should, should it instead use some target-specific hook that identifies the actual stack adjustment amount? -Krzysztof -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
CallFrameSetupOpcode is a pseudo opcode like X86::ADJCALLSTACKDOWN64. That means when the code is expected to be called before the pseudo instructions are eliminated. I don't know why it's not the case for you. A quick look at PEI code indicates the pseudo's should not have been removed at the time when replaceFrameIndices are run. Evan On Sep 25, 2013, at 8:57 AM, Krzysztof Parzyszek <kparzysz at codeaurora.org> wrote:> Hi All, > I'm dealing with a problem where the spill/restore instructions inserted during scavenging span an adjustment of the SP/FP register. The result is that despite the base register (SP/FP) being changed between the spill and the restore, both store and load use the same immediate offset. > > I see code in the PEI (replaceFrameIndices) that is supposed to track the SP/FP adjustment: > > ---------------------------------------- > void PEI::replaceFrameIndices(MachineBasicBlock *BB, > MachineFunction &Fn, int &SPAdj) { > const TargetMachine &TM = Fn.getTarget(); > assert(TM.getRegisterInfo() && > "TM::getRegisterInfo() must be implemented!"); > const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo(); > const TargetRegisterInfo &TRI = *TM.getRegisterInfo(); > const TargetFrameLowering *TFI = TM.getFrameLowering(); > bool StackGrowsDown > TFI->getStackGrowthDirection() => TargetFrameLowering::StackGrowsDown; > int FrameSetupOpcode = TII.getCallFrameSetupOpcode(); > int FrameDestroyOpcode = TII.getCallFrameDestroyOpcode(); > > if (RS && !FrameIndexVirtualScavenging) RS->enterBasicBlock(BB); > > for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) { > > if (I->getOpcode() == FrameSetupOpcode || > I->getOpcode() == FrameDestroyOpcode) { > // Remember how much SP has been adjusted to create the call > // frame. > int Size = I->getOperand(0).getImm(); > > if ((!StackGrowsDown && I->getOpcode() == FrameSetupOpcode) || > (StackGrowsDown && I->getOpcode() == FrameDestroyOpcode)) > Size = -Size; > > SPAdj += Size; > > [...] > ---------------------------------------- > > > The problem is that it expects frame-setup and frame-destroy opcodes, but at the time it runs (after emitPrologue/emitEpilogue) the frame setup and teardown will be expanded into instruction sequences that can be different for each target, let alone having the immediate value in the 0-th operand. > > As I see, this code won't work, although I'm not sure what was the original idea behind it. Should this code run before the target specific generation of prolog/epilog? Even then, there won't need to be ADJCALLSTACKUP/DOWN instructions (if it's a leaf function). If it runs where it should, should it instead use some target-specific hook that identifies the actual stack adjustment amount? > > -Krzysztof > > > -- > Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20130926/f44fe118/attachment.html>
Krzysztof Parzyszek
2013-Sep-26 19:00 UTC
[LLVMdev] Register scavenger and SP/FP adjustments
Consider this example: --- ex.ll --- declare void @bar() ; Function Attrs: nounwind optsize define void @main() { entry: %hin = alloca [256 x i32], align 4 %xin = alloca [256 x i32], align 4 call void @bar() ret void } ------------- Freshly built llc: llc -O2 -march=x86 < ex.ll -print-before-all # *** IR Dump Before Prologue/Epilogue Insertion & Frame Finalization ***: # Machine code for function main: Post SSA Frame Objects: fi#0: size=1024, align=4, at location [SP+4] fi#1: size=1024, align=4, at location [SP+4] BB#0: derived from LLVM BB %entry ADJCALLSTACKDOWN32 0, %ESP<imp-def>, %EFLAGS<imp-def,dead>, %ESP<imp-use> CALLpcrel32 <ga:@bar>, <regmask>, %ESP<imp-use>, %ESP<imp-def> ADJCALLSTACKUP32 0, 0, %ESP<imp-def>, %EFLAGS<imp-def,dead>, %ESP<imp-use> RET # End machine code for function main. before replace frame indices # Machine code for function main: Post SSA Frame Objects: fi#0: size=1024, align=4, at location [SP-1024] fi#1: size=1024, align=4, at location [SP-2048] BB#0: derived from LLVM BB %entry %ESP<def,tied1> = SUB32ri %ESP<tied0>, 2060, %EFLAGS<imp-def,dead>; flags: FrameSetup PROLOG_LABEL <MCSym=.Ltmp0> CALLpcrel32 <ga:@bar>, <regmask>, %ESP<imp-use>, %ESP<imp-def> %ESP<def,tied1> = ADD32ri %ESP<tied0>, 2060, %EFLAGS<imp-def,dead> RET # End machine code for function main. Let's see what happens if we remove the call to "bar". There aren't any pseudocodes that set up the frame to begin with, even though the SP is actually modified. (This is to show that RS has no way of finding out that SP was actually adjusted in such cases.) # *** IR Dump Before Prologue/Epilogue Insertion & Frame Finalization ***: # Machine code for function main: Post SSA Frame Objects: fi#0: size=1024, align=4, at location [SP+4] fi#1: size=1024, align=4, at location [SP+4] BB#0: derived from LLVM BB %entry RET # End machine code for function main. before replace frame indices # Machine code for function main: Post SSA Frame Objects: fi#0: size=1024, align=4, at location [SP-1024] fi#1: size=1024, align=4, at location [SP-2048] BB#0: derived from LLVM BB %entry %ESP<def,tied1> = SUB32ri %ESP<tied0>, 2048, %EFLAGS<imp-def,dead>; flags: FrameSetup PROLOG_LABEL <MCSym=.Ltmp0> %ESP<def,tied1> = ADD32ri %ESP<tied0>, 2048, %EFLAGS<imp-def,dead> RET # End machine code for function main. And here's where the problem becomes more apparent. Compile for Thumb and see that there is a virtual register used in the frame setup: # *** IR Dump Before Prologue/Epilogue Insertion & Frame Finalization ***: # Machine code for function main: Post SSA Frame Objects: fi#0: size=1024, align=4, at location [SP] fi#1: size=1024, align=4, at location [SP] BB#0: derived from LLVM BB %entry tBX_RET pred:14, pred:%noreg # End machine code for function main. before replace frame indices # Machine code for function main: Post SSA Frame Objects: fi#0: size=1024, align=4, at location [SP-1032] fi#1: size=1024, align=4, at location [SP-2056] fi#2: size=4, align=4, at location [SP-4] fi#3: size=4, align=4, at location [SP-8] Constant Pool: cp#0: -2048, align=4 cp#1: 2048, align=4 BB#0: derived from LLVM BB %entry Live Ins: %R4 %LR tPUSH pred:14, pred:%noreg, %R4<kill>, %LR<kill>, %SP<imp-def>, %SP<imp-use>; flags: FrameSetup %vreg0<def> = tLDRpci <cp#0>, pred:14, pred:%noreg; flags: FrameSetup tGPR:%vreg0 %SP<def,tied1> = tADDhirr %SP<tied0>, %vreg0<kill>, pred:14, pred:%noreg; tGPR:%vreg0 %vreg1<def> = tLDRpci <cp#1>, pred:14, pred:%noreg; tGPR:%vreg1 %SP<def,tied1> = tADDhirr %SP<tied0>, %vreg1<kill>, pred:14, pred:%noreg; tGPR:%vreg1 tPOP_RET pred:14, pred:%noreg, %R4<def>, %PC<def>, %SP<imp-def>, %SP<imp-use> # End machine code for function main. On Thumb you can save/restore a register without having to use a spill slot, so the scavenger won't run into problems, but if a target had to spill, we would end up with a register save before the SP update, and restore after the SP update, and the RS would use the same offset in both instructions. I don't have a working testcase (i.e. one that demonstrates the failure) that I can post, but if I cheat the RS into believing that it has to spill, the problem will happen. Here's a sample result of this. Don't mind the FixedStack-1, I explicitly used a base offset of 0 in the code, and this was to illustrate the lack of adjustment in RS: tSTRspi %R1<kill>, %SP, 0, pred:14, pred:%noreg; mem:ST4[FixedStack-1] <- spill to *(SP+0) %R1<def> = tLDRpci <cp#1>, pred:14, pred:%noreg %SP<def,tied1> = tADDhirr %SP<tied0>, %R1<kill>, pred:14, pred:%noreg <- SP = something different %R3<def> = tLDRspi %SP, 0, pred:14, pred:%noreg; mem:LD4[FixedStack-1] %R1<def> = tLDRspi %SP, 0, pred:14, pred:%noreg; mem:LD4[FixedStack-1] <- restore from *(NewSP+0) !! -Krzysztof On 9/26/2013 1:24 PM, Evan Cheng wrote:> CallFrameSetupOpcode is a pseudo opcode like X86::ADJCALLSTACKDOWN64. > That means when the code is expected to be called before the pseudo > instructions are eliminated. I don't know why it's not the case for you. > A quick look at PEI code indicates the pseudo's should not have been > removed at the time when replaceFrameIndices are run. > > Evan > > > On Sep 25, 2013, at 8:57 AM, Krzysztof Parzyszek > <kparzysz at codeaurora.org <mailto:kparzysz at codeaurora.org>> wrote: > >> Hi All, >> I'm dealing with a problem where the spill/restore instructions >> inserted during scavenging span an adjustment of the SP/FP register. >> The result is that despite the base register (SP/FP) being changed >> between the spill and the restore, both store and load use the same >> immediate offset. >> >> I see code in the PEI (replaceFrameIndices) that is supposed to track >> the SP/FP adjustment: >> >> ---------------------------------------- >> void PEI::replaceFrameIndices(MachineBasicBlock *BB, >> MachineFunction &Fn, int &SPAdj) { >> const TargetMachine &TM = Fn.getTarget(); >> assert(TM.getRegisterInfo() && >> "TM::getRegisterInfo() must be implemented!"); >> const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo(); >> const TargetRegisterInfo &TRI = *TM.getRegisterInfo(); >> const TargetFrameLowering *TFI = TM.getFrameLowering(); >> bool StackGrowsDown >> TFI->getStackGrowthDirection() =>> TargetFrameLowering::StackGrowsDown; >> int FrameSetupOpcode = TII.getCallFrameSetupOpcode(); >> int FrameDestroyOpcode = TII.getCallFrameDestroyOpcode(); >> >> if (RS && !FrameIndexVirtualScavenging) RS->enterBasicBlock(BB); >> >> for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) { >> >> if (I->getOpcode() == FrameSetupOpcode || >> I->getOpcode() == FrameDestroyOpcode) { >> // Remember how much SP has been adjusted to create the call >> // frame. >> int Size = I->getOperand(0).getImm(); >> >> if ((!StackGrowsDown && I->getOpcode() == FrameSetupOpcode) || >> (StackGrowsDown && I->getOpcode() == FrameDestroyOpcode)) >> Size = -Size; >> >> SPAdj += Size; >> >> [...] >> ---------------------------------------- >> >> >> The problem is that it expects frame-setup and frame-destroy opcodes, >> but at the time it runs (after emitPrologue/emitEpilogue) the frame >> setup and teardown will be expanded into instruction sequences that >> can be different for each target, let alone having the immediate value >> in the 0-th operand. >> >> As I see, this code won't work, although I'm not sure what was the >> original idea behind it. Should this code run before the target >> specific generation of prolog/epilog? Even then, there won't need to >> be ADJCALLSTACKUP/DOWN instructions (if it's a leaf function). If it >> runs where it should, should it instead use some target-specific hook >> that identifies the actual stack adjustment amount? >> >> -Krzysztof >> >> >> -- >> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, >> hosted by The Linux Foundation >> _______________________________________________ >> LLVM Developers mailing list >> LLVMdev at cs.uiuc.edu >> <mailto:LLVMdev at cs.uiuc.edu>http://llvm.cs.uiuc.edu >> <http://llvm.cs.uiuc.edu/> >> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >-- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation