diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h --- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h +++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h @@ -111,6 +111,15 @@ const BasicBlock *BB; int Number; + + /// The call frame size on entry to this basic block due to call frame setup + /// instructions in a predecessor. This is usually zero, unless basic blocks + /// are split in the middle of a call sequence. + /// + /// This information is only maintained until PrologEpilogInserter eliminates + /// call frame pseudos. + unsigned CallFrameSize = 0; + MachineFunction *xParent; Instructions Insts; @@ -1148,6 +1157,11 @@ int getNumber() const { return Number; } void setNumber(int N) { Number = N; } + /// Return the call frame size on entry to this basic block. + unsigned getCallFrameSize() const { return CallFrameSize; } + /// Set the call frame size on entry to this basic block. + void setCallFrameSize(unsigned N) { CallFrameSize = N; } + /// Return the MCSymbol for this basic block. MCSymbol *getSymbol() const; diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h --- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h +++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h @@ -2115,6 +2115,9 @@ return false; } + // Get the call frame size just before MI. + unsigned getCallFrameSizeAt(MachineInstr &MI) const; + private: mutable std::unique_ptr Formatter; unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode; diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h --- a/llvm/lib/CodeGen/MIRParser/MILexer.h +++ b/llvm/lib/CodeGen/MIRParser/MILexer.h @@ -135,6 +135,7 @@ kw_unknown_address, kw_ir_block_address_taken, kw_machine_block_address_taken, + kw_call_frame_size, // Metadata types. kw_distinct, diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp --- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp +++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp @@ -281,6 +281,7 @@ .Case("ir-block-address-taken", MIToken::kw_ir_block_address_taken) .Case("machine-block-address-taken", MIToken::kw_machine_block_address_taken) + .Case("call-frame-size", MIToken::kw_call_frame_size) .Default(MIToken::Identifier); } diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp --- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp @@ -501,6 +501,7 @@ bool parseAddrspace(unsigned &Addrspace); bool parseSectionID(std::optional &SID); bool parseBBID(std::optional &BBID); + bool parseCallFrameSize(unsigned &CallFrameSize); bool parseOperandsOffset(MachineOperand &Op); bool parseIRValue(const Value *&V); bool parseMemoryOperandFlag(MachineMemOperand::Flags &Flags); @@ -676,6 +677,18 @@ return false; } +// Parse basic block call frame size. +bool MIParser::parseCallFrameSize(unsigned &CallFrameSize) { + assert(Token.is(MIToken::kw_call_frame_size)); + lex(); + unsigned Value = 0; + if (getUnsigned(Value)) + return error("Unknown call frame size"); + CallFrameSize = Value; + lex(); + return false; +} + bool MIParser::parseBasicBlockDefinition( DenseMap &MBBSlots) { assert(Token.is(MIToken::MachineBasicBlockLabel)); @@ -693,6 +706,7 @@ std::optional SectionID; uint64_t Alignment = 0; std::optional BBID; + unsigned CallFrameSize = 0; BasicBlock *BB = nullptr; if (consumeIfPresent(MIToken::lparen)) { do { @@ -737,6 +751,10 @@ if (parseBBID(BBID)) return true; break; + case MIToken::kw_call_frame_size: + if (parseCallFrameSize(CallFrameSize)) + return true; + break; default: break; } @@ -781,6 +799,7 @@ MF.setBBSectionsType(BasicBlockSection::Labels); MBB->setBBID(BBID.value()); } + MBB->setCallFrameSize(CallFrameSize); return false; } diff --git a/llvm/lib/CodeGen/MachineBasicBlock.cpp b/llvm/lib/CodeGen/MachineBasicBlock.cpp --- a/llvm/lib/CodeGen/MachineBasicBlock.cpp +++ b/llvm/lib/CodeGen/MachineBasicBlock.cpp @@ -570,6 +570,11 @@ os << "bb_id " << *getBBID(); hasAttributes = true; } + if (CallFrameSize != 0) { + os << (hasAttributes ? ", " : " ("); + os << "call-frame-size " << CallFrameSize; + hasAttributes = true; + } } if (hasAttributes) @@ -1099,6 +1104,7 @@ DebugLoc DL; // FIXME: this is nowhere MachineBasicBlock *NMBB = MF->CreateMachineBasicBlock(); + NMBB->setCallFrameSize(Succ->getCallFrameSize()); // Is there an indirect jump with jump table? bool ChangedIndirectJump = false; diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp --- a/llvm/lib/CodeGen/MachineVerifier.cpp +++ b/llvm/lib/CodeGen/MachineVerifier.cpp @@ -3398,6 +3398,15 @@ BBState.ExitIsSetup = BBState.EntryIsSetup; } + if ((int)MBB->getCallFrameSize() != -BBState.EntryValue) { + report("Call frame size on entry does not match value computed from " + "predecessor", + MBB); + errs() << "Call frame size on entry " << MBB->getCallFrameSize() + << " does not match value computed from predecessor " + << -BBState.EntryValue << '\n'; + } + // Update stack state by checking contents of MBB. for (const auto &I : *MBB) { if (I.getOpcode() == FrameSetupOpcode) { diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -17,7 +17,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" -#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -381,13 +380,18 @@ MFI.setAdjustsStack(AdjustsStack); MFI.setMaxCallFrameSize(MaxCallFrameSize); - for (MachineBasicBlock::iterator I : FrameSDOps) { + if (TFI->canSimplifyCallFramePseudos(MF)) { // If call frames are not being included as part of the stack frame, and // the target doesn't indicate otherwise, remove the call frame pseudos // here. The sub/add sp instruction pairs are still inserted, but we don't // need to track the SP adjustment for frame index elimination. - if (TFI->canSimplifyCallFramePseudos(MF)) + for (MachineBasicBlock::iterator I : FrameSDOps) TFI->eliminateCallFramePseudoInstr(MF, *I->getParent(), I); + + // We can't track the call frame size after call frame pseudos have been + // eliminated. Set it to zero everywhere to keep MachineVerifier happy. + for (MachineBasicBlock &MBB : MF) + MBB.setCallFrameSize(0); } } @@ -1341,34 +1345,16 @@ FrameIndexEliminationScavenging = (RS && !FrameIndexVirtualScavenging) || TRI->requiresFrameIndexReplacementScavenging(MF); - // Store SPAdj at exit of a basic block. - SmallVector SPState; - SPState.resize(MF.getNumBlockIDs()); - df_iterator_default_set Reachable; - - // Iterate over the reachable blocks in DFS order. - for (auto DFI = df_ext_begin(&MF, Reachable), DFE = df_ext_end(&MF, Reachable); - DFI != DFE; ++DFI) { - int SPAdj = 0; - // Check the exit state of the DFS stack predecessor. - if (DFI.getPathLength() >= 2) { - MachineBasicBlock *StackPred = DFI.getPath(DFI.getPathLength() - 2); - assert(Reachable.count(StackPred) && - "DFS stack predecessor is already visited.\n"); - SPAdj = SPState[StackPred->getNumber()]; - } - MachineBasicBlock *BB = *DFI; - replaceFrameIndices(BB, MF, SPAdj); - SPState[BB->getNumber()] = SPAdj; - } + for (auto &MBB : MF) { + int SPAdj = TFI.alignSPAdjust(MBB.getCallFrameSize()); + if (TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp) + SPAdj = -SPAdj; - // Handle the unreachable blocks. - for (auto &BB : MF) { - if (Reachable.count(&BB)) - // Already handled in DFS traversal. - continue; - int SPAdj = 0; - replaceFrameIndices(&BB, MF, SPAdj); + replaceFrameIndices(&MBB, MF, SPAdj); + + // We can't track the call frame size after call frame pseudos have been + // eliminated. Set it to zero everywhere to keep MachineVerifier happy. + MBB.setCallFrameSize(0); } } diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp --- a/llvm/lib/CodeGen/TargetInstrInfo.cpp +++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp @@ -1450,6 +1450,22 @@ return std::nullopt; } +// Get the call frame size just before MI. +unsigned TargetInstrInfo::getCallFrameSizeAt(MachineInstr &MI) const { + // Search backwards from MI for the most recent call frame instruction. + MachineBasicBlock *MBB = MI.getParent(); + for (auto &AdjI : reverse(make_range(MBB->instr_begin(), MI.getIterator()))) { + if (AdjI.getOpcode() == getCallFrameSetupOpcode()) + return getFrameTotalSize(AdjI); + if (AdjI.getOpcode() == getCallFrameDestroyOpcode()) + return 0; + } + + // If none was found, use the call frame size from the start of the basic + // block. + return MBB->getCallFrameSize(); +} + /// Both DefMI and UseMI must be valid. By default, call directly to the /// itinerary. This may be overriden by the target. int TargetInstrInfo::getOperandLatency(const InstrItineraryData *ItinData, diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -11485,6 +11485,11 @@ MF->insert(It, loopMBB); MF->insert(It, exitMBB); + // Set the call frame size on entry to the new basic blocks. + unsigned CallFrameSize = TII->getCallFrameSizeAt(MI); + loopMBB->setCallFrameSize(CallFrameSize); + exitMBB->setCallFrameSize(CallFrameSize); + // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, std::next(MachineBasicBlock::iterator(MI)), BB->end()); @@ -12081,6 +12086,11 @@ F->insert(It, copy0MBB); F->insert(It, sinkMBB); + // Set the call frame size on entry to the new basic blocks. + unsigned CallFrameSize = TII->getCallFrameSizeAt(MI); + copy0MBB->setCallFrameSize(CallFrameSize); + sinkMBB->setCallFrameSize(CallFrameSize); + // Check whether CPSR is live past the tMOVCCr_pseudo. const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); if (!MI.killsRegister(ARM::CPSR) && diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp --- a/llvm/lib/Target/AVR/AVRISelLowering.cpp +++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp @@ -2440,6 +2440,11 @@ MF->insert(I, trueMBB); MF->insert(I, falseMBB); + // Set the call frame size on entry to the new basic blocks. + unsigned CallFrameSize = TII.getCallFrameSizeAt(MI); + trueMBB->setCallFrameSize(CallFrameSize); + falseMBB->setCallFrameSize(CallFrameSize); + // Transfer remaining instructions and all successors of the current // block to the block which will contain the Phi node for the // select. diff --git a/llvm/lib/Target/M68k/M68kISelLowering.cpp b/llvm/lib/Target/M68k/M68kISelLowering.cpp --- a/llvm/lib/Target/M68k/M68kISelLowering.cpp +++ b/llvm/lib/Target/M68k/M68kISelLowering.cpp @@ -3204,6 +3204,11 @@ F->insert(It, Copy0MBB); F->insert(It, SinkMBB); + // Set the call frame size on entry to the new basic blocks. + unsigned CallFrameSize = TII->getCallFrameSizeAt(MI); + Copy0MBB->setCallFrameSize(CallFrameSize); + SinkMBB->setCallFrameSize(CallFrameSize); + // If the CCR register isn't dead in the terminator, then claim that it's // live into the sink and copy blocks. const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -37244,6 +37244,11 @@ F->insert(It, FalseMBB); F->insert(It, SinkMBB); + // Set the call frame size on entry to the new basic blocks. + unsigned CallFrameSize = TII->getCallFrameSizeAt(MI); + FalseMBB->setCallFrameSize(CallFrameSize); + SinkMBB->setCallFrameSize(CallFrameSize); + // If the EFLAGS register isn't dead in the terminator, then claim that it's // live into the sink and copy blocks. const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); diff --git a/llvm/test/CodeGen/ARM/2013-06-03-ByVal-2Kbytes.ll b/llvm/test/CodeGen/ARM/2013-06-03-ByVal-2Kbytes.ll --- a/llvm/test/CodeGen/ARM/2013-06-03-ByVal-2Kbytes.ll +++ b/llvm/test/CodeGen/ARM/2013-06-03-ByVal-2Kbytes.ll @@ -1,4 +1,6 @@ ; RUN: llc < %s -mcpu=cortex-a15 | FileCheck %s +; RUN: llc < %s -mcpu=cortex-a15 -stop-after=finalize-isel -o %t.mir +; RUN: llc %t.mir -mcpu=cortex-a15 -start-after=finalize-isel -o - | FileCheck %s ; ModuleID = 'attri_16.c' target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32-S64" target triple = "armv4t--linux-gnueabihf" diff --git a/llvm/test/CodeGen/ARM/no-register-coalescing-in-returnsTwice.mir b/llvm/test/CodeGen/ARM/no-register-coalescing-in-returnsTwice.mir --- a/llvm/test/CodeGen/ARM/no-register-coalescing-in-returnsTwice.mir +++ b/llvm/test/CodeGen/ARM/no-register-coalescing-in-returnsTwice.mir @@ -121,7 +121,7 @@ %61:gpr = COPY killed %29 %62:gpr = COPY killed %4 %63:gpr = COPY killed %27 - bb.2: + bb.2 (call-frame-size 72): %35:gpr = COPY killed %63 %33:gpr = COPY killed %62 %31:gpr = COPY killed %61 @@ -134,7 +134,7 @@ %62:gpr = COPY killed %32 %63:gpr = COPY killed %34 Bcc %bb.2, 1, killed $cpsr - bb.3: + bb.3 (call-frame-size 72): successors: %28:gpr = ADDri %stack.1.jb1, 0, 14, $noreg, $noreg $r0 = COPY killed %28 diff --git a/llvm/test/CodeGen/MIR/ARM/call-frame-size.mir b/llvm/test/CodeGen/MIR/ARM/call-frame-size.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/MIR/ARM/call-frame-size.mir @@ -0,0 +1,25 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 2 +# RUN: llc -march=arm -run-pass none -o - %s | FileCheck %s +# This test ensures that the MIR parser parses machine functions correctly. + +--- +name: callframesize +body: | + ; CHECK-LABEL: name: callframesize + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.1(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: ADJCALLSTACKDOWN 100, 0, 14 /* CC::al */, $noreg, implicit-def $sp, implicit $sp + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1 (call-frame-size 100): + ; CHECK-NEXT: successors: %bb.2(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: ADJCALLSTACKUP 100, 0, 14 /* CC::al */, $noreg, implicit-def $sp, implicit $sp + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.2: + bb.0: + ADJCALLSTACKDOWN 100, 0, 14, $noreg, implicit-def $sp, implicit $sp + bb.1 (call-frame-size 100): + ADJCALLSTACKUP 100, 0, 14, $noreg, implicit-def $sp, implicit $sp + bb.2: +... diff --git a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp --- a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp +++ b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp @@ -225,6 +225,8 @@ DstMF->CreateMachineBasicBlock(SrcMBB.getBasicBlock()); Src2DstMBB[&SrcMBB] = DstMBB; + DstMBB->setCallFrameSize(SrcMBB.getCallFrameSize()); + if (SrcMBB.isIRBlockAddressTaken()) DstMBB->setAddressTakenIRBlock(SrcMBB.getAddressTakenIRBlock()); if (SrcMBB.isMachineBlockAddressTaken())