mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[LiveDebugValues] Tracking copying value between registers
During the execution of long functions or functions that have a lot of inlined code it could come to the situation where tracked value could be transferred from one register to another. The transfer is recognized only if destination register is a callee saved register and if source register is killed. We do not salvage caller-saved registers since there is a great chance that killed register would outlive it. Patch by Nikola Prica. Differential Revision: https://reviews.llvm.org/D44016 llvm-svn: 336978
This commit is contained in:
parent
6d90906e48
commit
20374872ff
@ -40,6 +40,7 @@
|
||||
#include "llvm/CodeGen/TargetLowering.h"
|
||||
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
||||
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
||||
#include "llvm/CodeGen/RegisterScavenging.h"
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
@ -82,6 +83,7 @@ private:
|
||||
const TargetRegisterInfo *TRI;
|
||||
const TargetInstrInfo *TII;
|
||||
const TargetFrameLowering *TFI;
|
||||
BitVector CalleeSavedRegs;
|
||||
LexicalScopes LS;
|
||||
|
||||
/// Keeps track of lexical scopes associated with a user value's source
|
||||
@ -179,11 +181,11 @@ private:
|
||||
using VarLocMap = UniqueVector<VarLoc>;
|
||||
using VarLocSet = SparseBitVector<>;
|
||||
using VarLocInMBB = SmallDenseMap<const MachineBasicBlock *, VarLocSet>;
|
||||
struct SpillDebugPair {
|
||||
MachineInstr *SpillInst;
|
||||
struct TransferDebugPair {
|
||||
MachineInstr *TransferInst;
|
||||
MachineInstr *DebugInst;
|
||||
};
|
||||
using SpillMap = SmallVector<SpillDebugPair, 4>;
|
||||
using TransferMap = SmallVector<TransferDebugPair, 4>;
|
||||
|
||||
/// This holds the working set of currently open ranges. For fast
|
||||
/// access, this is done both as a set of VarLocIDs, and a map of
|
||||
@ -236,18 +238,23 @@ private:
|
||||
bool isSpillInstruction(const MachineInstr &MI, MachineFunction *MF,
|
||||
unsigned &Reg);
|
||||
int extractSpillBaseRegAndOffset(const MachineInstr &MI, unsigned &Reg);
|
||||
void insertTransferDebugPair(MachineInstr &MI, OpenRangesSet &OpenRanges,
|
||||
TransferMap &Transfers, VarLocMap &VarLocIDs,
|
||||
unsigned OldVarID, unsigned NewReg = 0);
|
||||
|
||||
void transferDebugValue(const MachineInstr &MI, OpenRangesSet &OpenRanges,
|
||||
VarLocMap &VarLocIDs);
|
||||
void transferSpillInst(MachineInstr &MI, OpenRangesSet &OpenRanges,
|
||||
VarLocMap &VarLocIDs, SpillMap &Spills);
|
||||
VarLocMap &VarLocIDs, TransferMap &Transfers);
|
||||
void transferRegisterCopy(MachineInstr &MI, OpenRangesSet &OpenRanges,
|
||||
VarLocMap &VarLocIDs, TransferMap &Transfers);
|
||||
void transferRegisterDef(MachineInstr &MI, OpenRangesSet &OpenRanges,
|
||||
const VarLocMap &VarLocIDs);
|
||||
bool transferTerminatorInst(MachineInstr &MI, OpenRangesSet &OpenRanges,
|
||||
VarLocInMBB &OutLocs, const VarLocMap &VarLocIDs);
|
||||
bool transfer(MachineInstr &MI, OpenRangesSet &OpenRanges,
|
||||
VarLocInMBB &OutLocs, VarLocMap &VarLocIDs, SpillMap &Spills,
|
||||
bool transferSpills);
|
||||
bool process(MachineInstr &MI, OpenRangesSet &OpenRanges,
|
||||
VarLocInMBB &OutLocs, VarLocMap &VarLocIDs,
|
||||
TransferMap &Transfers, bool transferChanges);
|
||||
|
||||
bool join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs,
|
||||
const VarLocMap &VarLocIDs,
|
||||
@ -370,6 +377,54 @@ void LiveDebugValues::transferDebugValue(const MachineInstr &MI,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new TransferDebugPair and insert it in \p Transfers. The VarLoc
|
||||
/// with \p OldVarID should be deleted form \p OpenRanges and replaced with
|
||||
/// new VarLoc. If \p NewReg is different than default zero value then the
|
||||
/// new location will be register location created by the copy like instruction,
|
||||
/// otherwise it is variable's location on the stack.
|
||||
void LiveDebugValues::insertTransferDebugPair(
|
||||
MachineInstr &MI, OpenRangesSet &OpenRanges, TransferMap &Transfers,
|
||||
VarLocMap &VarLocIDs, unsigned OldVarID, unsigned NewReg) {
|
||||
const MachineInstr *DMI = &VarLocIDs[OldVarID].MI;
|
||||
MachineFunction *MF = MI.getParent()->getParent();
|
||||
MachineInstr *NewDMI;
|
||||
if (NewReg) {
|
||||
// Create a DBG_VALUE instruction to describe the Var in its new
|
||||
// register location.
|
||||
NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(),
|
||||
DMI->isIndirectDebugValue(), NewReg,
|
||||
DMI->getDebugVariable(), DMI->getDebugExpression());
|
||||
if (DMI->isIndirectDebugValue())
|
||||
NewDMI->getOperand(1).setImm(DMI->getOperand(1).getImm());
|
||||
LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for register copy: ";
|
||||
NewDMI->print(dbgs(), false, false, false, TII));
|
||||
} else {
|
||||
// Create a DBG_VALUE instruction to describe the Var in its spilled
|
||||
// location.
|
||||
unsigned SpillBase;
|
||||
int SpillOffset = extractSpillBaseRegAndOffset(MI, SpillBase);
|
||||
auto *SpillExpr = DIExpression::prepend(DMI->getDebugExpression(),
|
||||
DIExpression::NoDeref, SpillOffset);
|
||||
NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), true, SpillBase,
|
||||
DMI->getDebugVariable(), SpillExpr);
|
||||
LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for spill: ";
|
||||
NewDMI->print(dbgs(), false, false, false, TII));
|
||||
}
|
||||
|
||||
// The newly created DBG_VALUE instruction NewDMI must be inserted after
|
||||
// MI. Keep track of the pairing.
|
||||
TransferDebugPair MIP = {&MI, NewDMI};
|
||||
Transfers.push_back(MIP);
|
||||
|
||||
// End all previous ranges of Var.
|
||||
OpenRanges.erase(VarLocIDs[OldVarID].Var);
|
||||
|
||||
// Add the VarLoc to OpenRanges.
|
||||
VarLoc VL(*NewDMI, LS);
|
||||
unsigned LocID = VarLocIDs.insert(VL);
|
||||
OpenRanges.insert(LocID, VL.Var);
|
||||
}
|
||||
|
||||
/// A definition of a register may mark the end of a range.
|
||||
void LiveDebugValues::transferRegisterDef(MachineInstr &MI,
|
||||
OpenRangesSet &OpenRanges,
|
||||
@ -464,14 +519,14 @@ bool LiveDebugValues::isSpillInstruction(const MachineInstr &MI,
|
||||
|
||||
/// A spilled register may indicate that we have to end the current range of
|
||||
/// a variable and create a new one for the spill location.
|
||||
/// We don't want to insert any instructions in transfer(), so we just create
|
||||
/// the DBG_VALUE witout inserting it and keep track of it in @Spills.
|
||||
/// We don't want to insert any instructions in process(), so we just create
|
||||
/// the DBG_VALUE without inserting it and keep track of it in \p Transfers.
|
||||
/// It will be inserted into the BB when we're done iterating over the
|
||||
/// instructions.
|
||||
void LiveDebugValues::transferSpillInst(MachineInstr &MI,
|
||||
OpenRangesSet &OpenRanges,
|
||||
VarLocMap &VarLocIDs,
|
||||
SpillMap &Spills) {
|
||||
TransferMap &Transfers) {
|
||||
unsigned Reg;
|
||||
MachineFunction *MF = MI.getMF();
|
||||
if (!isSpillInstruction(MI, MF, Reg))
|
||||
@ -482,33 +537,47 @@ void LiveDebugValues::transferSpillInst(MachineInstr &MI,
|
||||
if (VarLocIDs[ID].isDescribedByReg() == Reg) {
|
||||
LLVM_DEBUG(dbgs() << "Spilling Register " << printReg(Reg, TRI) << '('
|
||||
<< VarLocIDs[ID].Var.getVar()->getName() << ")\n");
|
||||
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a DBG_VALUE instruction to describe the Var in its spilled
|
||||
// location, but don't insert it yet to avoid invalidating the
|
||||
// iterator in our caller.
|
||||
unsigned SpillBase;
|
||||
int SpillOffset = extractSpillBaseRegAndOffset(MI, SpillBase);
|
||||
const MachineInstr *DMI = &VarLocIDs[ID].MI;
|
||||
auto *SpillExpr = DIExpression::prepend(
|
||||
DMI->getDebugExpression(), DIExpression::NoDeref, SpillOffset);
|
||||
MachineInstr *SpDMI =
|
||||
BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), true, SpillBase,
|
||||
DMI->getDebugVariable(), SpillExpr);
|
||||
LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for spill: ";
|
||||
SpDMI->print(dbgs(), false, TII));
|
||||
/// If \p MI is a register copy instruction, that copies a previously tracked
|
||||
/// value from one register to another register that is callee saved, we
|
||||
/// create new DBG_VALUE instruction described with copy destination register.
|
||||
void LiveDebugValues::transferRegisterCopy(MachineInstr &MI,
|
||||
OpenRangesSet &OpenRanges,
|
||||
VarLocMap &VarLocIDs,
|
||||
TransferMap &Transfers) {
|
||||
const MachineOperand *SrcRegOp, *DestRegOp;
|
||||
|
||||
// The newly created DBG_VALUE instruction SpDMI must be inserted after
|
||||
// MI. Keep track of the pairing.
|
||||
SpillDebugPair MIP = {&MI, SpDMI};
|
||||
Spills.push_back(MIP);
|
||||
if (!TII->isCopyInstr(MI, SrcRegOp, DestRegOp) || !SrcRegOp->isKill() ||
|
||||
!DestRegOp->isDef())
|
||||
return;
|
||||
|
||||
// End all previous ranges of Var.
|
||||
OpenRanges.erase(VarLocIDs[ID].Var);
|
||||
auto isCalleSavedReg = [&](unsigned Reg) {
|
||||
for (MCRegAliasIterator RAI(Reg, TRI, true); RAI.isValid(); ++RAI)
|
||||
if (CalleeSavedRegs.test(*RAI))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
// Add the VarLoc to OpenRanges.
|
||||
VarLoc VL(*SpDMI, LS);
|
||||
unsigned SpillLocID = VarLocIDs.insert(VL);
|
||||
OpenRanges.insert(SpillLocID, VL.Var);
|
||||
unsigned SrcReg = SrcRegOp->getReg();
|
||||
unsigned DestReg = DestRegOp->getReg();
|
||||
|
||||
// We want to recognize instructions where destination register is callee
|
||||
// saved register. If register that could be clobbered by the call is
|
||||
// included, there would be a great chance that it is going to be clobbered
|
||||
// soon. It is more likely that previous register location, which is callee
|
||||
// saved, is going to stay unclobbered longer, even if it is killed.
|
||||
if (!isCalleSavedReg(DestReg))
|
||||
return;
|
||||
|
||||
for (unsigned ID : OpenRanges.getVarLocs()) {
|
||||
if (VarLocIDs[ID].isDescribedByReg() == SrcReg) {
|
||||
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID,
|
||||
DestReg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -540,14 +609,16 @@ bool LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
|
||||
}
|
||||
|
||||
/// This routine creates OpenRanges and OutLocs.
|
||||
bool LiveDebugValues::transfer(MachineInstr &MI, OpenRangesSet &OpenRanges,
|
||||
VarLocInMBB &OutLocs, VarLocMap &VarLocIDs,
|
||||
SpillMap &Spills, bool transferSpills) {
|
||||
bool LiveDebugValues::process(MachineInstr &MI, OpenRangesSet &OpenRanges,
|
||||
VarLocInMBB &OutLocs, VarLocMap &VarLocIDs,
|
||||
TransferMap &Transfers, bool transferChanges) {
|
||||
bool Changed = false;
|
||||
transferDebugValue(MI, OpenRanges, VarLocIDs);
|
||||
transferRegisterDef(MI, OpenRanges, VarLocIDs);
|
||||
if (transferSpills)
|
||||
transferSpillInst(MI, OpenRanges, VarLocIDs, Spills);
|
||||
if (transferChanges) {
|
||||
transferRegisterCopy(MI, OpenRanges, VarLocIDs, Transfers);
|
||||
transferSpillInst(MI, OpenRanges, VarLocIDs, Transfers);
|
||||
}
|
||||
Changed = transferTerminatorInst(MI, OpenRanges, OutLocs, VarLocIDs);
|
||||
return Changed;
|
||||
}
|
||||
@ -609,7 +680,7 @@ bool LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
|
||||
for (auto ID : Diff) {
|
||||
// This VarLoc is not found in InLocs i.e. it is not yet inserted. So, a
|
||||
// new range is started for the var from the mbb's beginning by inserting
|
||||
// a new DBG_VALUE. transfer() will end this range however appropriate.
|
||||
// a new DBG_VALUE. process() will end this range however appropriate.
|
||||
const VarLoc &DiffIt = VarLocIDs[ID];
|
||||
const MachineInstr *DMI = &DiffIt.MI;
|
||||
MachineInstr *MI =
|
||||
@ -639,7 +710,7 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
|
||||
OpenRangesSet OpenRanges; // Ranges that are open until end of bb.
|
||||
VarLocInMBB OutLocs; // Ranges that exist beyond bb.
|
||||
VarLocInMBB InLocs; // Ranges that are incoming after joining.
|
||||
SpillMap Spills; // DBG_VALUEs associated with spills.
|
||||
TransferMap Transfers; // DBG_VALUEs associated with spills.
|
||||
|
||||
DenseMap<unsigned int, MachineBasicBlock *> OrderToBB;
|
||||
DenseMap<MachineBasicBlock *, unsigned int> BBToOrder;
|
||||
@ -650,6 +721,8 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
|
||||
std::greater<unsigned int>>
|
||||
Pending;
|
||||
|
||||
enum : bool { dontTransferChanges = false, transferChanges = true };
|
||||
|
||||
// Initialize every mbb with OutLocs.
|
||||
// We are not looking at any spill instructions during the initial pass
|
||||
// over the BBs. The LiveDebugVariables pass has already created DBG_VALUE
|
||||
@ -657,8 +730,8 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
|
||||
// within the BB in which the spill occurs.
|
||||
for (auto &MBB : MF)
|
||||
for (auto &MI : MBB)
|
||||
transfer(MI, OpenRanges, OutLocs, VarLocIDs, Spills,
|
||||
/*transferSpills=*/false);
|
||||
process(MI, OpenRanges, OutLocs, VarLocIDs, Transfers,
|
||||
dontTransferChanges);
|
||||
|
||||
LLVM_DEBUG(printVarLocInMBB(MF, OutLocs, VarLocIDs,
|
||||
"OutLocs after initialization", dbgs()));
|
||||
@ -672,7 +745,7 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
|
||||
++RPONumber;
|
||||
}
|
||||
// This is a standard "union of predecessor outs" dataflow problem.
|
||||
// To solve it, we perform join() and transfer() using the two worklist method
|
||||
// To solve it, we perform join() and process() using the two worklist method
|
||||
// until the ranges converge.
|
||||
// Ranges have converged when both worklists are empty.
|
||||
SmallPtrSet<const MachineBasicBlock *, 16> Visited;
|
||||
@ -694,14 +767,14 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
|
||||
// examine spill instructions to see whether they spill registers that
|
||||
// correspond to user variables.
|
||||
for (auto &MI : *MBB)
|
||||
OLChanged |= transfer(MI, OpenRanges, OutLocs, VarLocIDs, Spills,
|
||||
/*transferSpills=*/true);
|
||||
OLChanged |= process(MI, OpenRanges, OutLocs, VarLocIDs, Transfers,
|
||||
transferChanges);
|
||||
|
||||
// Add any DBG_VALUE instructions necessitated by spills.
|
||||
for (auto &SP : Spills)
|
||||
MBB->insertAfter(MachineBasicBlock::iterator(*SP.SpillInst),
|
||||
SP.DebugInst);
|
||||
Spills.clear();
|
||||
for (auto &TR : Transfers)
|
||||
MBB->insertAfter(MachineBasicBlock::iterator(*TR.TransferInst),
|
||||
TR.DebugInst);
|
||||
Transfers.clear();
|
||||
|
||||
LLVM_DEBUG(printVarLocInMBB(MF, OutLocs, VarLocIDs,
|
||||
"OutLocs after propagating", dbgs()));
|
||||
@ -741,6 +814,8 @@ bool LiveDebugValues::runOnMachineFunction(MachineFunction &MF) {
|
||||
TRI = MF.getSubtarget().getRegisterInfo();
|
||||
TII = MF.getSubtarget().getInstrInfo();
|
||||
TFI = MF.getSubtarget().getFrameLowering();
|
||||
TFI->determineCalleeSaves(MF, CalleeSavedRegs,
|
||||
make_unique<RegScavenger>().get());
|
||||
LS.initialize(MF);
|
||||
|
||||
bool Changed = ExtendRanges(MF);
|
||||
|
147
test/DebugInfo/MIR/ARM/live-debug-values-reg-copy.mir
Normal file
147
test/DebugInfo/MIR/ARM/live-debug-values-reg-copy.mir
Normal file
@ -0,0 +1,147 @@
|
||||
# RUN: llc -run-pass=livedebugvalues %s -o - | FileCheck %s
|
||||
#
|
||||
# This test tests tracking variables value transferring from one register to another.
|
||||
# This example is altered additionally in order to test transferring from one float register
|
||||
# to another. The altered instructions are labeled below.
|
||||
#
|
||||
# CHECK: ![[ARG1:.*]] = !DILocalVariable(name: "arg1"
|
||||
# CHECK: DBG_VALUE debug-use $r4, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location
|
||||
# CHECK: $r5 = MOVr killed $r4, 14, $noreg, $noreg, debug-location
|
||||
# CHECK-NEXT: DBG_VALUE debug-use $r5, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location
|
||||
--- |
|
||||
; ModuleID = 'live-debug-values-reg-copy.ll'
|
||||
source_filename = "live-debug-values-reg-copy.c"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "armv4t--"
|
||||
|
||||
define dso_local arm_aapcscc i32 @foo(i32 %arg1) local_unnamed_addr !dbg !8 {
|
||||
entry:
|
||||
call void @llvm.dbg.value(metadata i32 %arg1, metadata !13, metadata !DIExpression()), !dbg !16
|
||||
%cmp = icmp sgt i32 %arg1, 10, !dbg !16
|
||||
br i1 %cmp, label %if.end, label %if.else, !dbg !16
|
||||
|
||||
if.else: ; preds = %entry
|
||||
%add5 = add nsw i32 %arg1, 10, !dbg !16
|
||||
call void @llvm.dbg.value(metadata i32 %add5, metadata !13, metadata !DIExpression()), !dbg !16
|
||||
%call6 = tail call arm_aapcscc i32 @externFunc2(i32 %add5), !dbg !16
|
||||
%call8 = tail call arm_aapcscc i32 @externFunc(i32 %add5), !dbg !16
|
||||
ret i32 %call6, !dbg !16
|
||||
|
||||
if.end: ; preds = %entry
|
||||
%call = tail call arm_aapcscc i32 @externFunc(i32 %arg1), !dbg !16
|
||||
ret i32 1, !dbg !16
|
||||
}
|
||||
|
||||
declare dso_local arm_aapcscc i32 @externFunc(i32) local_unnamed_addr
|
||||
|
||||
declare dso_local arm_aapcscc i32 @externFunc2(i32) local_unnamed_addr
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.stackprotector(i8*, i8**) #1
|
||||
|
||||
attributes #0 = { nounwind readnone speculatable }
|
||||
attributes #1 = { nounwind }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5, !6}
|
||||
!llvm.ident = !{!7}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "live-debug-values-reg-copy.c", directory: "/")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!5 = !{i32 1, !"wchar_size", i32 4}
|
||||
!6 = !{i32 1, !"min_enum_size", i32 4}
|
||||
!7 = !{!"clang version 7.0.0"}
|
||||
!8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !9, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12)
|
||||
!9 = !DISubroutineType(types: !10)
|
||||
!10 = !{!11, !11}
|
||||
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!12 = !{!13}
|
||||
!13 = !DILocalVariable(name: "arg1", arg: 1, scope: !8, file: !1, line: 4, type: !11)
|
||||
!16 = !DILocation(line: 4, column: 13, scope: !8)
|
||||
|
||||
...
|
||||
---
|
||||
name: foo
|
||||
alignment: 2
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
tracksRegLiveness: false
|
||||
registers:
|
||||
liveins:
|
||||
- { reg: '$r0', virtual-reg: '' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 16
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 4
|
||||
adjustsStack: true
|
||||
hasCalls: true
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
stack:
|
||||
- { id: 0, name: '', type: spill-slot, offset: -4, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '$r11', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 2, name: '', type: spill-slot, offset: -12, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '$r5', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 3, name: '', type: spill-slot, offset: -16, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '$r4', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
constants:
|
||||
body: |
|
||||
bb.0.entry:
|
||||
successors: %bb.1(0x40000000), %bb.2(0x40000000)
|
||||
|
||||
$sp = frame-setup STMDB_UPD $sp, 14, $noreg, killed $r4, killed $r5, killed $r11, killed $lr
|
||||
frame-setup CFI_INSTRUCTION def_cfa_offset 16
|
||||
frame-setup CFI_INSTRUCTION offset $lr, -4
|
||||
frame-setup CFI_INSTRUCTION offset $r11, -8
|
||||
frame-setup CFI_INSTRUCTION offset $r5, -12
|
||||
frame-setup CFI_INSTRUCTION offset $r4, -16
|
||||
DBG_VALUE debug-use $r0, debug-use $noreg, !13, !DIExpression(), debug-location !16
|
||||
DBG_VALUE debug-use $r0, debug-use $noreg, !13, !DIExpression(), debug-location !16
|
||||
CMPri renamable $r0, 10, 14, $noreg, implicit-def $cpsr, debug-location !16
|
||||
Bcc %bb.2, 13, killed $cpsr, debug-location !16
|
||||
|
||||
bb.1.if.end:
|
||||
BL @externFunc, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $r0, implicit-def $sp, implicit-def dead $r0, debug-location !16
|
||||
$r0 = MOVi 1, 14, $noreg, $noreg, debug-location !16
|
||||
$sp = LDMIA_UPD $sp, 14, $noreg, def $r4, def $r5, def $r11, def $lr, debug-location !16
|
||||
BX_RET 14, $noreg, implicit killed $r0, debug-location !16
|
||||
|
||||
bb.2.if.else:
|
||||
renamable $r4 = ADDri killed renamable $r0, 10, 14, $noreg, $noreg, debug-location !16
|
||||
DBG_VALUE debug-use $r4, debug-use $noreg, !13, !DIExpression(), debug-location !16
|
||||
$r0 = MOVr $r4, 14, $noreg, $noreg, debug-location !16
|
||||
BL @externFunc2, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $r0, implicit-def $sp, implicit-def $r0, debug-location !16
|
||||
$r5 = MOVr killed $r0, 14, $noreg, $noreg, debug-location !16
|
||||
$r0 = MOVr $r4, 14, $noreg, $noreg, debug-location !16
|
||||
BL @externFunc, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $r0, implicit-def $sp, implicit-def dead $r0, debug-location !16
|
||||
$r0 = MOVr killed $r5, 14, $noreg, $noreg, debug-location !16
|
||||
; Instruction below is added in order to test moving variable's value from one register to another.
|
||||
$r5 = MOVr killed $r4, 14, $noreg, $noreg, debug-location !16
|
||||
$sp = LDMIA_UPD $sp, 14, $noreg, def $r4, def $r5, def $r11, def $lr, debug-location !16
|
||||
BX_RET 14, $noreg, implicit killed $r0, debug-location !16
|
||||
|
||||
...
|
241
test/DebugInfo/MIR/Mips/live-debug-values-reg-copy.mir
Normal file
241
test/DebugInfo/MIR/Mips/live-debug-values-reg-copy.mir
Normal file
@ -0,0 +1,241 @@
|
||||
# RUN: llc -run-pass=livedebugvalues %s -o - | FileCheck %s
|
||||
#
|
||||
# This test tests tracking variables value transferring from one register to another.
|
||||
# This example is altered additionally in order to test transferring from one float register
|
||||
# to another. The altered instructions are labeled below.
|
||||
#
|
||||
# CHECK: ![[ARG1:.*]] = !DILocalVariable(name: "arg1"
|
||||
# CHECK: ![[ARG2:.*]] = !DILocalVariable(name: "arg2"
|
||||
# CHECK: DBG_VALUE debug-use $s0_64, debug-use $noreg, ![[ARG2]], !DIExpression(), debug-location
|
||||
# CHECK: $s1_64 = OR64 killed $s0_64, $zero_64, debug-location
|
||||
# CHECK-NEXT: DBG_VALUE debug-use $s1_64, debug-use $noreg, ![[ARG2]], !DIExpression(), debug-location
|
||||
# CHECK: DBG_VALUE debug-use $f24, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location
|
||||
# CHECK: $f26 = FMOV_S killed $f24, debug-location
|
||||
# CHECK-NEXT: DBG_VALUE debug-use $f26, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location
|
||||
|
||||
--- |
|
||||
; ModuleID = 'live-debug-values-reg-copy.ll'
|
||||
source_filename = "live-debug-values-reg-copy.c"
|
||||
target datalayout = "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128"
|
||||
target triple = "mips64-octeon-linux"
|
||||
|
||||
define float @foo(float %arg1, i32 signext %arg2) local_unnamed_addr !dbg !8 {
|
||||
entry:
|
||||
call void @llvm.dbg.value(metadata float %arg1, metadata !14, metadata !DIExpression()), !dbg !19
|
||||
call void @llvm.dbg.value(metadata i32 %arg2, metadata !15, metadata !DIExpression()), !dbg !19
|
||||
%conv = fpext float %arg1 to double, !dbg !19
|
||||
%cmp = fcmp ogt double %conv, 1.012310e+01, !dbg !19
|
||||
br i1 %cmp, label %if.then, label %if.else, !dbg !19
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%call = tail call float @externFunc(float %arg1), !dbg !19
|
||||
%call5 = tail call i32 @externFunc3(i32 signext %arg2), !dbg !19
|
||||
%conv6 = sitofp i32 %call5 to float, !dbg !19
|
||||
%add7 = fadd float %conv6, 0x3FF522D0E0000000, !dbg !19
|
||||
br label %if.end, !dbg !19
|
||||
|
||||
if.else: ; preds = %entry
|
||||
%add8 = fadd float %arg1, 1.000000e+01, !dbg !19
|
||||
call void @llvm.dbg.value(metadata float %add8, metadata !14, metadata !DIExpression()), !dbg !19
|
||||
%call9 = tail call float @externFunc2(float %add8), !dbg !19
|
||||
%call10 = tail call i32 @externFunc4(i32 signext %arg2), !dbg !19
|
||||
%conv11 = sitofp i32 %call10 to float, !dbg !19
|
||||
%add12 = fadd float %call9, %conv11, !dbg !19
|
||||
%call14 = tail call float @externFunc(float %add8), !dbg !19
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.else, %if.then
|
||||
%local.0 = phi float [ %add7, %if.then ], [ %add12, %if.else ]
|
||||
ret float %local.0, !dbg !19
|
||||
}
|
||||
|
||||
declare float @externFunc(float) local_unnamed_addr
|
||||
|
||||
declare i32 @externFunc3(i32 signext) local_unnamed_addr
|
||||
|
||||
declare float @externFunc2(float) local_unnamed_addr
|
||||
|
||||
declare i32 @externFunc4(i32 signext) local_unnamed_addr
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.stackprotector(i8*, i8**) #1
|
||||
|
||||
attributes #0 = { nounwind readnone speculatable }
|
||||
attributes #1 = { nounwind }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5, !6}
|
||||
!llvm.ident = !{!7}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "live-debug-values-reg-copy.c", directory: "/")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!5 = !{i32 1, !"wchar_size", i32 4}
|
||||
!6 = !{i32 7, !"PIC Level", i32 2}
|
||||
!7 = !{!"clang version 7.0.0 "}
|
||||
!8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 6, type: !9, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !13)
|
||||
!9 = !DISubroutineType(types: !10)
|
||||
!10 = !{!11, !11, !12}
|
||||
!11 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
|
||||
!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!13 = !{!14, !15}
|
||||
!14 = !DILocalVariable(name: "arg1", arg: 1, scope: !8, file: !1, line: 6, type: !11)
|
||||
!15 = !DILocalVariable(name: "arg2", arg: 2, scope: !8, file: !1, line: 6, type: !12)
|
||||
!19 = !DILocation(line: 6, column: 17, scope: !8)
|
||||
|
||||
...
|
||||
---
|
||||
name: foo
|
||||
alignment: 3
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
tracksRegLiveness: false
|
||||
registers:
|
||||
liveins:
|
||||
- { reg: '$f12', virtual-reg: '' }
|
||||
- { reg: '$a1_64', virtual-reg: '' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 32
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 8
|
||||
adjustsStack: true
|
||||
hasCalls: true
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
stack:
|
||||
- { id: 0, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d25_64', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 1, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d24_64', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 2, name: '', type: spill-slot, offset: -24, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$ra_64', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 3, name: '', type: spill-slot, offset: -32, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$s0_64', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
constants:
|
||||
- id: 0
|
||||
value: 'double 1.012310e+01'
|
||||
alignment: 8
|
||||
isTargetSpecific: false
|
||||
- id: 1
|
||||
value: 'float 1.000000e+01'
|
||||
alignment: 4
|
||||
isTargetSpecific: false
|
||||
- id: 2
|
||||
value: float 0x3FF522D0E0000000
|
||||
alignment: 4
|
||||
isTargetSpecific: false
|
||||
body: |
|
||||
bb.0.entry:
|
||||
successors: %bb.1(0x40000000), %bb.2(0x40000000)
|
||||
|
||||
$sp_64 = DADDiu $sp_64, -32
|
||||
CFI_INSTRUCTION def_cfa_offset 32
|
||||
SDC164 killed $d25_64, $sp_64, 24 :: (store 8 into %stack.0)
|
||||
SDC164 killed $d24_64, $sp_64, 16 :: (store 8 into %stack.1)
|
||||
SD killed $ra_64, $sp_64, 8 :: (store 8 into %stack.2)
|
||||
SD killed $s0_64, $sp_64, 0 :: (store 8 into %stack.3)
|
||||
CFI_INSTRUCTION offset $d26_64, -8
|
||||
CFI_INSTRUCTION offset $d25_64, -4
|
||||
CFI_INSTRUCTION offset $d25_64, -16
|
||||
CFI_INSTRUCTION offset $d24_64, -12
|
||||
CFI_INSTRUCTION offset $ra_64, -24
|
||||
CFI_INSTRUCTION offset $s0_64, -32
|
||||
DBG_VALUE debug-use $f12, debug-use $noreg, !14, !DIExpression(), debug-location !19
|
||||
DBG_VALUE debug-use $a1_64, debug-use $noreg, !15, !DIExpression(), debug-location !19
|
||||
DBG_VALUE debug-use $s0, debug-use $noreg, !15, !DIExpression(), debug-location !19
|
||||
DBG_VALUE debug-use $s0_64, debug-use $noreg, !15, !DIExpression(), debug-location !19
|
||||
DBG_VALUE debug-use $f12, debug-use $noreg, !14, !DIExpression(), debug-location !19
|
||||
renamable $d0_64 = CVT_D64_S renamable $f12, debug-location !19
|
||||
renamable $at_64 = LUi64 target-flags(mips-highest) %const.0
|
||||
renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-higher) %const.0
|
||||
renamable $at_64 = DSLL killed renamable $at_64, 16
|
||||
renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-abs-hi) %const.0
|
||||
renamable $at_64 = DSLL killed renamable $at_64, 16
|
||||
renamable $d1_64 = LDC164 killed renamable $at_64, target-flags(mips-abs-lo) %const.0, debug-location !19 :: (load 8 from constant-pool)
|
||||
FCMP_D64 killed renamable $d0_64, killed renamable $d1_64, 7, implicit-def $fcc0, debug-location !19
|
||||
BC1T killed $fcc0, %bb.2, implicit-def $at, debug-location !19 {
|
||||
$s0_64 = OR64 $a1_64, $zero_64
|
||||
}
|
||||
|
||||
bb.1.if.then:
|
||||
successors: %bb.3(0x80000000)
|
||||
|
||||
JAL @externFunc, csr_n64, implicit-def dead $ra, implicit $f12, implicit-def $sp, implicit-def dead $f0, debug-location !19 {
|
||||
NOP debug-location !19
|
||||
}
|
||||
JAL @externFunc3, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit-def $sp, implicit-def $v0, debug-location !19 {
|
||||
renamable $a0_64 = SLL64_32 renamable $s0, implicit $s0_64, debug-location !19
|
||||
}
|
||||
$f0 = MTC1 killed $v0, debug-location !19
|
||||
$f0 = CVT_S_W killed $f0, debug-location !19
|
||||
; This instruction is inserted additionally in order to test moving from one register to another
|
||||
$s1_64 = OR64 killed $s0_64, $zero_64, debug-location !19
|
||||
renamable $at_64 = LUi64 target-flags(mips-highest) %const.2
|
||||
renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-higher) %const.2
|
||||
renamable $at_64 = DSLL killed renamable $at_64, 16
|
||||
renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-abs-hi) %const.2
|
||||
renamable $at_64 = DSLL killed renamable $at_64, 16
|
||||
renamable $f1 = LWC1 killed renamable $at_64, target-flags(mips-abs-lo) %const.2, debug-location !19 :: (load 4 from constant-pool)
|
||||
J %bb.3, implicit-def dead $at, debug-location !19 {
|
||||
renamable $f0 = FADD_S killed renamable $f0, killed renamable $f1, debug-location !19
|
||||
}
|
||||
|
||||
bb.2.if.else:
|
||||
successors: %bb.3(0x80000000)
|
||||
|
||||
renamable $at_64 = LUi64 target-flags(mips-highest) %const.1
|
||||
renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-higher) %const.1
|
||||
renamable $at_64 = DSLL killed renamable $at_64, 16
|
||||
renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-abs-hi) %const.1
|
||||
renamable $at_64 = DSLL killed renamable $at_64, 16
|
||||
renamable $f0 = LWC1 killed renamable $at_64, target-flags(mips-abs-lo) %const.1, debug-location !19 :: (load 4 from constant-pool)
|
||||
renamable $f24 = FADD_S killed renamable $f12, killed renamable $f0, debug-location !19
|
||||
DBG_VALUE debug-use $f24, debug-use $noreg, !14, !DIExpression(), debug-location !19
|
||||
JAL @externFunc2, csr_n64, implicit-def dead $ra, implicit $f12, implicit-def $sp, implicit-def $f0, debug-location !19 {
|
||||
$f12 = FMOV_S $f24, debug-location !19
|
||||
}
|
||||
$f25 = FMOV_S $f0, debug-location !19
|
||||
JAL @externFunc4, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit-def $sp, implicit-def $v0, debug-location !19 {
|
||||
renamable $a0_64 = SLL64_32 renamable $s0, implicit killed $s0_64, debug-location !19
|
||||
}
|
||||
$s0 = OR $v0, $zero, debug-location !19
|
||||
JAL @externFunc, csr_n64, implicit-def dead $ra, implicit $f12, implicit-def $sp, implicit-def dead $f0, debug-location !19 {
|
||||
$f12 = FMOV_S $f24, debug-location !19
|
||||
}
|
||||
$f0 = MTC1 killed $s0, debug-location !19
|
||||
$f0 = CVT_S_W killed $f0, debug-location !19
|
||||
renamable $f0 = FADD_S renamable $f25, killed renamable $f0, debug-location !19
|
||||
; This instruction is inserted additionally in order to test moving variable's value from one float register to another.
|
||||
$f26 = FMOV_S killed $f24, debug-location !19
|
||||
|
||||
bb.3.if.end:
|
||||
$s0_64 = LD $sp_64, 0, debug-location !19 :: (load 8 from %stack.3)
|
||||
$ra_64 = LD $sp_64, 8, debug-location !19 :: (load 8 from %stack.2)
|
||||
$d24_64 = LDC164 $sp_64, 16, debug-location !19 :: (load 8 from %stack.1)
|
||||
$d25_64 = LDC164 $sp_64, 24, debug-location !19 :: (load 8 from %stack.0)
|
||||
PseudoReturn64 undef $ra_64, implicit $f0, debug-location !19 {
|
||||
$sp_64 = DADDiu $sp_64, 32
|
||||
}
|
||||
|
||||
...
|
190
test/DebugInfo/MIR/X86/live-debug-values-reg-copy.mir
Normal file
190
test/DebugInfo/MIR/X86/live-debug-values-reg-copy.mir
Normal file
@ -0,0 +1,190 @@
|
||||
# RUN: llc -run-pass=livedebugvalues %s -o - | FileCheck %s
|
||||
#
|
||||
# This test tests tracking variables value transferring from one register to another.
|
||||
# This example is altered additionally in order to test transferring from one float register
|
||||
# to another. The altered instructions are labeled below.
|
||||
#
|
||||
# CHECK: ![[ARG1:.*]] = !DILocalVariable(name: "arg1"
|
||||
# CHECK: DBG_VALUE debug-use $ebx, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location
|
||||
# CHECK: $r12d = MOV32rr killed $ebx, implicit-def $r12
|
||||
# CHECK-NEXT: DBG_VALUE debug-use $r12d, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location
|
||||
--- |
|
||||
; ModuleID = 'live-debug-values-reg-copy.ll'
|
||||
source_filename = "live-debug-values-reg-copy.c"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
define dso_local i32 @foo(i32 %arg1) local_unnamed_addr !dbg !7 {
|
||||
entry:
|
||||
%local1 = alloca i32, align 4
|
||||
call void @llvm.dbg.value(metadata i32 %arg1, metadata !12, metadata !DIExpression()), !dbg !15
|
||||
%0 = bitcast i32* %local1 to i8*, !dbg !15
|
||||
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0), !dbg !15
|
||||
call void @init(i32* nonnull %local1), !dbg !15
|
||||
%1 = load i32, i32* %local1, align 4, !dbg !15, !tbaa !20
|
||||
%add = add nsw i32 %1, %arg1, !dbg !15
|
||||
%call = call i32 @coeficient(i32 %add), !dbg !15
|
||||
%cmp = icmp sgt i32 %call, 32, !dbg !15
|
||||
br i1 %cmp, label %if.then, label %if.else, !dbg !15
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%call1 = call i32 @externFunc(i32 %arg1), !dbg !15
|
||||
%2 = load i32, i32* %local1, align 4, !dbg !15, !tbaa !20
|
||||
%add2 = add nsw i32 %2, %call1, !dbg !15
|
||||
br label %if.end, !dbg !15
|
||||
|
||||
if.else: ; preds = %entry
|
||||
%call3 = call i32 @externFunc2(i32 %arg1), !dbg !15
|
||||
%3 = load i32, i32* %local1, align 4, !dbg !15, !tbaa !20
|
||||
%add4 = add nsw i32 %3, %call3, !dbg !15
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.else, %if.then
|
||||
%storemerge = phi i32 [ %add4, %if.else ], [ %add2, %if.then ]
|
||||
%4 = bitcast i32* %local1 to i8*
|
||||
%mul = shl nsw i32 %arg1, 2, !dbg !15
|
||||
%add5 = add nsw i32 %storemerge, %mul, !dbg !15
|
||||
%mul6 = mul nsw i32 %add5, %call, !dbg !15
|
||||
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %4), !dbg !15
|
||||
ret i32 %mul6, !dbg !15
|
||||
}
|
||||
|
||||
; Function Attrs: argmemonly nounwind
|
||||
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #0
|
||||
|
||||
declare dso_local void @init(i32*) local_unnamed_addr
|
||||
|
||||
declare dso_local i32 @coeficient(i32) local_unnamed_addr
|
||||
|
||||
declare dso_local i32 @externFunc(i32) local_unnamed_addr
|
||||
|
||||
declare dso_local i32 @externFunc2(i32) local_unnamed_addr
|
||||
|
||||
; Function Attrs: argmemonly nounwind
|
||||
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #0
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.stackprotector(i8*, i8**) #2
|
||||
|
||||
attributes #0 = { argmemonly nounwind }
|
||||
attributes #1 = { nounwind readnone speculatable }
|
||||
attributes #2 = { nounwind }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5}
|
||||
!llvm.ident = !{!6}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "live-debug-values-reg-copy.c", directory: "/")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!5 = !{i32 1, !"wchar_size", i32 4}
|
||||
!6 = !{!"clang version 7.0.0 "}
|
||||
!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 6, type: !8, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !11)
|
||||
!8 = !DISubroutineType(types: !9)
|
||||
!9 = !{!10, !10}
|
||||
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!11 = !{!12}
|
||||
!12 = !DILocalVariable(name: "arg1", arg: 1, scope: !7, file: !1, line: 6, type: !10)
|
||||
!15 = !DILocation(line: 6, column: 13, scope: !7)
|
||||
!20 = !{!21, !21, i64 0}
|
||||
!21 = !{!"int", !22, i64 0}
|
||||
!22 = !{!"omnipotent char", !23, i64 0}
|
||||
!23 = !{!"Simple C/C++ TBAA"}
|
||||
|
||||
...
|
||||
---
|
||||
name: foo
|
||||
alignment: 4
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
tracksRegLiveness: true
|
||||
registers:
|
||||
liveins:
|
||||
- { reg: '$edi', virtual-reg: '' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 24
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 4
|
||||
adjustsStack: true
|
||||
hasCalls: true
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
- { id: 0, type: spill-slot, offset: -24, size: 8, alignment: 8, stack-id: 0,
|
||||
callee-saved-register: '$rbx', callee-saved-restored: true }
|
||||
- { id: 1, type: spill-slot, offset: -16, size: 8, alignment: 16, stack-id: 0,
|
||||
callee-saved-register: '$rbp', callee-saved-restored: true }
|
||||
stack:
|
||||
- { id: 0, name: local1, type: default, offset: -28, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
constants:
|
||||
body: |
|
||||
bb.0.entry:
|
||||
successors: %bb.1(0x40000000), %bb.2(0x40000000)
|
||||
liveins: $edi, $rbp, $rbx
|
||||
|
||||
frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp
|
||||
CFI_INSTRUCTION def_cfa_offset 16
|
||||
frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp
|
||||
CFI_INSTRUCTION def_cfa_offset 24
|
||||
frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp
|
||||
CFI_INSTRUCTION def_cfa_offset 32
|
||||
CFI_INSTRUCTION offset $rbx, -24
|
||||
CFI_INSTRUCTION offset $rbp, -16
|
||||
DBG_VALUE debug-use $edi, debug-use $noreg, !12, !DIExpression(), debug-location !15
|
||||
$ebx = MOV32rr $edi, implicit-def $rbx
|
||||
DBG_VALUE debug-use $ebx, debug-use $noreg, !12, !DIExpression(), debug-location !15
|
||||
renamable $rdi = LEA64r $rsp, 1, $noreg, 4, $noreg
|
||||
CALL64pcrel32 @init, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, debug-location !15
|
||||
renamable $edi = MOV32rm $rsp, 1, $noreg, 4, $noreg :: (dereferenceable load 4 from %ir.local1, !tbaa !20)
|
||||
renamable $edi = ADD32rr killed renamable $edi, renamable $ebx, implicit-def dead $eflags, debug-location !15
|
||||
CALL64pcrel32 @coeficient, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax, debug-location !15
|
||||
$ebp = MOV32rr $eax, debug-location !15
|
||||
$edi = MOV32rr $ebx, debug-location !15
|
||||
CMP32ri8 renamable $ebp, 33, implicit-def $eflags, debug-location !15
|
||||
JL_1 %bb.2, implicit killed $eflags, debug-location !15
|
||||
|
||||
bb.1.if.then:
|
||||
successors: %bb.3(0x80000000)
|
||||
liveins: $ebp, $edi
|
||||
|
||||
CALL64pcrel32 @externFunc, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax, debug-location !15
|
||||
JMP_1 %bb.3
|
||||
|
||||
bb.2.if.else:
|
||||
successors: %bb.3(0x80000000)
|
||||
liveins: $ebp, $edi
|
||||
|
||||
CALL64pcrel32 @externFunc2, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax, debug-location !15
|
||||
|
||||
bb.3.if.end:
|
||||
liveins: $ebp, $ebx, $eax
|
||||
; Instruction below is added in order to test moving variable's value from one register to another.
|
||||
$r12d = MOV32rr killed $ebx, implicit-def $r12
|
||||
renamable $eax = KILL $eax, implicit-def $rax
|
||||
renamable $eax = ADD32rm renamable $eax, $rsp, 1, $noreg, 4, $noreg, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax :: (dereferenceable load 4 from %ir.local1, !tbaa !20)
|
||||
renamable $eax = LEA64_32r killed renamable $rax, 4, killed renamable $r12, 0, $noreg, debug-location !15
|
||||
renamable $eax = IMUL32rr killed renamable $eax, killed renamable $ebp, implicit-def dead $eflags, debug-location !15
|
||||
$rsp = frame-destroy ADD64ri8 $rsp, 8, implicit-def dead $eflags, debug-location !15
|
||||
$rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !15
|
||||
$rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !15
|
||||
RETQ $eax, debug-location !15
|
||||
|
||||
...
|
Loading…
Reference in New Issue
Block a user