summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/MachineBasicBlock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/MachineBasicBlock.cpp')
-rw-r--r--llvm/lib/CodeGen/MachineBasicBlock.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/llvm/lib/CodeGen/MachineBasicBlock.cpp b/llvm/lib/CodeGen/MachineBasicBlock.cpp
index 81597afe6b0..c9976d7f2ff 100644
--- a/llvm/lib/CodeGen/MachineBasicBlock.cpp
+++ b/llvm/lib/CodeGen/MachineBasicBlock.cpp
@@ -35,6 +35,8 @@
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include <algorithm>
+#include <queue>
+#include <set>
using namespace llvm;
#define DEBUG_TYPE "codegen"
@@ -1343,3 +1345,228 @@ MachineBasicBlock::livein_iterator MachineBasicBlock::livein_begin() const {
"Liveness information is accurate");
return LiveIns.begin();
}
+
+void MachineBasicBlock::updateCFIInfo(MachineBasicBlock::iterator Pos) {
+ // Used for calculating outgoing cfa offset when CFI instruction added at Pos
+ // is def_cfa or def_cfa_offset.
+ /* For example:
+ ...
+ .cfi_adjust_cfa_offset 4
+ ...
+ .cfi_adjust_cfa_offset 4
+ ...
+ .cfi_def_cfa_offset 16 <---- newly added CFI instruction at Pos
+ ...
+ .cfi_adjust_cfa_offset 4
+ ...
+ Once def_cfa_offset is inserted, outgoing cfa offset is no longer
+ calculated as incoming offset incremented by the sum of all adjustments
+ (12). It becomes equal to the offset set by the added CFI instruction (16)
+ incremented by the sum of adjustments below it (4). Adjustments above the
+ added def_cfa_offset directive don't have effect below it anymore and
+ therefore don't affect the value of outgoing cfa offset.
+ */
+ int AdjustAmount = 0;
+ // Used to check if outgoing cfa offset should be updated or not (when def_cfa
+ // is inserted).
+ bool ShouldSetOffset = true;
+ // Used to check if outgoing cfa register should be updated or not (when
+ // def_cfa is inserted).
+ bool ShouldSetRegister = true;
+ const std::vector<MCCFIInstruction> CFIInstructions =
+ getParent()->getFrameInstructions();
+ MCCFIInstruction CFI = CFIInstructions[Pos->getOperand(0).getCFIIndex()];
+ // Type of the CFI instruction that was inserted.
+ MCCFIInstruction::OpType CFIType = CFI.getOperation();
+
+ // Check if there are already existing CFI instructions below Pos and see if
+ // outgoing CFI info should be updated or not.
+ for (MachineBasicBlock::reverse_iterator RI = rbegin();
+ RI != Pos.getReverse(); ++RI) {
+ if (RI->isCFIInstruction()) {
+ MCCFIInstruction::OpType RIType =
+ CFIInstructions[RI->getOperand(0).getCFIIndex()].getOperation();
+ switch (RIType) {
+ case MCCFIInstruction::OpAdjustCfaOffset:
+ AdjustAmount +=
+ CFIInstructions[RI->getOperand(0).getCFIIndex()].getOffset();
+ break;
+ case MCCFIInstruction::OpDefCfaOffset:
+ // CFI instruction doesn't affect outgoing cfa offset if there is
+ // already a def_cfa_offset instruction below it.
+ if (CFIType == MCCFIInstruction::OpDefCfaOffset ||
+ CFIType == MCCFIInstruction::OpAdjustCfaOffset)
+ return;
+ if (CFIType == MCCFIInstruction::OpDefCfa) {
+ // CFI instruction doesn't affect outgoing cfa offset and register
+ // if there are both def_cfa_offset and def_cfa_register
+ // instructions below it.
+ if (!ShouldSetRegister) return;
+ ShouldSetOffset = false;
+ }
+ break;
+ case MCCFIInstruction::OpDefCfaRegister:
+ // CFI instruction doesn't affect outgoing cfa register if there is
+ // already a def_cfa_register instruction below it.
+ if (CFIType == MCCFIInstruction::OpDefCfaRegister) return;
+ if (CFIType == MCCFIInstruction::OpDefCfa) {
+ // CFI instruction doesn't affect outgoing cfa offset and register
+ // if there are both def_cfa_offset and def_cfa_register
+ // instructions below it.
+ if (!ShouldSetOffset) return;
+ ShouldSetRegister = false;
+ }
+ break;
+ case MCCFIInstruction::OpDefCfa:
+ // CFI instruction doesn't affect outgoing cfa offset and register if
+ // there is already a def_cfa instruction below it.
+ if (CFIType == MCCFIInstruction::OpDefCfaRegister ||
+ CFIType == MCCFIInstruction::OpDefCfaOffset ||
+ CFIType == MCCFIInstruction::OpDefCfa ||
+ CFIType == MCCFIInstruction::OpAdjustCfaOffset)
+ return;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // Update the outgoing CFI info based on the added CFI instruction.
+ switch (CFIType) {
+ case MCCFIInstruction::OpAdjustCfaOffset:
+ setOutgoingCFAOffset(getOutgoingCFAOffset() + CFI.getOffset());
+ break;
+ case MCCFIInstruction::OpDefCfaOffset:
+ setOutgoingCFAOffset(CFI.getOffset() + AdjustAmount);
+ break;
+ case MCCFIInstruction::OpDefCfaRegister:
+ setOutgoingCFARegister(CFI.getRegister());
+ break;
+ case MCCFIInstruction::OpDefCfa:
+ if (ShouldSetOffset) setOutgoingCFAOffset(CFI.getOffset() + AdjustAmount);
+ if (ShouldSetRegister) setOutgoingCFARegister(CFI.getRegister());
+ break;
+ default:
+ break;
+ }
+}
+
+void MachineBasicBlock::updateCFIInfoSucc() {
+ // Blocks whose successors' CFI info should be updated.
+ std::queue<MachineBasicBlock *> Successors;
+ // Keep track of basic blocks that have already been put in the Successors
+ // queue.
+ std::set<MachineBasicBlock *> ProcessedMBBs;
+ // Start with updating CFI info for direct successors of this block.
+ Successors.push(this);
+ ProcessedMBBs.insert(this);
+
+ // Go through the successors and update their CFI info if needed.
+ while (!Successors.empty()) {
+ MachineBasicBlock *CurrSucc = Successors.front();
+ Successors.pop();
+
+ // Update CFI info for CurrSucc's successors.
+ for (auto Succ : CurrSucc->successors()) {
+ if (ProcessedMBBs.find(Succ) != ProcessedMBBs.end()) continue;
+ if (Succ->getIncomingCFAOffset() == CurrSucc->getOutgoingCFAOffset() &&
+ Succ->getIncomingCFARegister() == CurrSucc->getOutgoingCFARegister())
+ continue;
+ bool ChangedOutgoingInfo = false;
+ // Do not update cfa offset if the existing value matches the new.
+ if (Succ->getIncomingCFAOffset() != CurrSucc->getOutgoingCFAOffset()) {
+ // If the block doesn't have a def_cfa_offset or def_cfa directive,
+ // update its outgoing offset.
+ if (!Succ->hasDefOffset()) {
+ // Succ block doesn't set absolute offset, so the difference between
+ // outgoing and incoming offset remains the same. This difference is
+ // the sum of offsets set by adjust_cfa_offset directives.
+ int AdjustAmount =
+ Succ->getOutgoingCFAOffset() - Succ->getIncomingCFAOffset();
+ Succ->setOutgoingCFAOffset(CurrSucc->getOutgoingCFAOffset() +
+ AdjustAmount);
+ ChangedOutgoingInfo = true;
+ }
+ Succ->setIncomingCFAOffset(CurrSucc->getOutgoingCFAOffset());
+ }
+ // Do not update cfa register if the existing value matches the new.
+ if (Succ->getIncomingCFARegister() !=
+ CurrSucc->getOutgoingCFARegister()) {
+ Succ->setIncomingCFARegister(CurrSucc->getOutgoingCFARegister());
+ // If the block doesn't have a def_cfa_register or def_cfa directive,
+ // update its outgoing register.
+ if (!Succ->hasDefRegister()) {
+ Succ->setOutgoingCFARegister(Succ->getIncomingCFARegister());
+ ChangedOutgoingInfo = true;
+ }
+ }
+ // If Succ's outgoing CFI info has been changed, it's successors should be
+ // updated as well.
+ if (ChangedOutgoingInfo) {
+ Successors.push(Succ);
+ ProcessedMBBs.insert(Succ);
+ }
+ }
+ }
+}
+
+void MachineBasicBlock::recalculateCFIInfo(bool UseExistingIncoming,
+ int NewIncomingOffset,
+ unsigned NewIncomingRegister) {
+ // Outgoing cfa offset set by the block.
+ int SetOffset;
+ // Outgoing cfa register set by the block.
+ unsigned SetRegister;
+ const std::vector<MCCFIInstruction> &Instrs =
+ getParent()->getFrameInstructions();
+
+ // Set initial values to SetOffset and SetRegister. Use existing incoming
+ // values or values passed as arguments.
+ if (!UseExistingIncoming) {
+ // Set new incoming cfa offset and register values.
+ setIncomingCFAOffset(NewIncomingOffset);
+ setIncomingCFARegister(NewIncomingRegister);
+ }
+
+ SetOffset = getIncomingCFAOffset();
+ SetRegister = getIncomingCFARegister();
+
+ setDefOffset(false);
+ setDefRegister(false);
+
+ // Determine cfa offset and register set by the block.
+ for (MachineBasicBlock::iterator MI = begin(); MI != end(); ++MI) {
+ if (MI->isCFIInstruction()) {
+ unsigned CFIIndex = MI->getOperand(0).getCFIIndex();
+ const MCCFIInstruction &CFI = Instrs[CFIIndex];
+ if (CFI.getOperation() == MCCFIInstruction::OpDefCfaRegister) {
+ SetRegister = CFI.getRegister();
+ setDefRegister(true);
+ } else if (CFI.getOperation() == MCCFIInstruction::OpDefCfaOffset) {
+ SetOffset = CFI.getOffset();
+ setDefOffset(true);
+ } else if (CFI.getOperation() == MCCFIInstruction::OpAdjustCfaOffset) {
+ SetOffset = SetOffset + CFI.getOffset();
+ } else if (CFI.getOperation() == MCCFIInstruction::OpDefCfa) {
+ SetRegister = CFI.getRegister();
+ SetOffset = CFI.getOffset();
+ setDefOffset(true);
+ setDefRegister(true);
+ }
+ }
+ }
+
+ // Update outgoing CFI info.
+ setOutgoingCFAOffset(SetOffset);
+ setOutgoingCFARegister(SetRegister);
+}
+
+void MachineBasicBlock::mergeCFIInfo(MachineBasicBlock *MBB) {
+ // Update CFI info. This basic block acquires MBB's outgoing cfa offset and
+ // register values.
+ setOutgoingCFAOffset(MBB->getOutgoingCFAOffset());
+ setOutgoingCFARegister(MBB->getOutgoingCFARegister());
+ setDefOffset(hasDefOffset() || MBB->hasDefOffset());
+ setDefRegister(hasDefRegister() || MBB->hasDefRegister());
+}
OpenPOWER on IntegriCloud