Reland "[CodeView] Generate S_DEFRANGE_REGISTER_REL_INDIR" (#189401)
Initially added in #187709. It was reverted in #188833, because [llvm-clang-x86_64-sie-win](https://lab.llvm.org/buildbot/#/builders/46/builds/32873) was failing in `cross-project-tests/debuginfo-tests/dexter-tests/nrvo.cpp`. The test passed for me locally. After checking on another machine, I found that `S_DEFRANGE_REGISTER_REL_INDIR` is only supported by dbgeng/WinDbg from Windows 10.0 Build 19041 (released 2020) onwards. SDKs before this will fail to read the value. That buildbot is on Windows 10.0 Build 17763. I'm not sure if we should make the generation of that record conditional. Debuggers that can't read the record will skip it. They'll still see that there's some local variable, but won't be able to display the value. As far as I know, users of older Windows 10 builds should be able to install a newer Windows SDK and use the WinDbg from that version. But I haven't tested that.
This commit is contained in:
parent
c329cc59d9
commit
91b90652bb
@ -1,7 +1,7 @@
|
|||||||
// This ensures that DW_OP_deref is inserted when necessary, such as when NRVO
|
// This ensures that DW_OP_deref is inserted when necessary, such as when NRVO
|
||||||
// of a string object occurs in C++.
|
// of a string object occurs in C++.
|
||||||
//
|
//
|
||||||
// REQUIRES: system-windows
|
// REQUIRES: system-windows, dbgeng-10-19041
|
||||||
//
|
//
|
||||||
// RUN: %clang_cl /Z7 /Zi %s -o %t
|
// RUN: %clang_cl /Z7 /Zi %s -o %t
|
||||||
// RUN: %dexter --fail-lt 1.0 -w --binary %t --debugger 'dbgeng' -- %s
|
// RUN: %dexter --fail-lt 1.0 -w --binary %t --debugger 'dbgeng' -- %s
|
||||||
@ -36,5 +36,5 @@ int main() {
|
|||||||
get_string2();
|
get_string2();
|
||||||
}
|
}
|
||||||
|
|
||||||
// DexExpectWatchValue('result->i', 3, on_line=ref('readresult1'))
|
// DexExpectWatchValue('result.i', 3, on_line=ref('readresult1'))
|
||||||
// DexExpectWatchValue('result->i', 5, on_line=ref('readresult2'))
|
// DexExpectWatchValue('result.i', 5, on_line=ref('readresult2'))
|
||||||
|
|||||||
@ -401,3 +401,41 @@ llvm_config.feature_config([("--build-mode", {"Debug|RelWithDebInfo": "debug-inf
|
|||||||
# Allow 'REQUIRES: XXX-registered-target' in tests.
|
# Allow 'REQUIRES: XXX-registered-target' in tests.
|
||||||
for arch in config.targets_to_build:
|
for arch in config.targets_to_build:
|
||||||
config.available_features.add(arch.lower() + "-registered-target")
|
config.available_features.add(arch.lower() + "-registered-target")
|
||||||
|
|
||||||
|
|
||||||
|
def find_dbgeng():
|
||||||
|
if platform.system() != "Windows":
|
||||||
|
return None
|
||||||
|
|
||||||
|
for path in os.environ.get("PATH", "").split(os.pathsep):
|
||||||
|
p = os.path.join(path, "dbgeng.dll")
|
||||||
|
if os.path.exists(p) and not os.path.isdir(p):
|
||||||
|
return os.path.abspath(p)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_dbgeng_version():
|
||||||
|
dbgeng = find_dbgeng()
|
||||||
|
if not dbgeng:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
import win32api
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
info = win32api.GetFileVersionInfo(dbgeng, "\\")
|
||||||
|
ms = info["FileVersionMS"]
|
||||||
|
ls = info["FileVersionLS"]
|
||||||
|
return (
|
||||||
|
win32api.HIWORD(ms),
|
||||||
|
win32api.LOWORD(ms),
|
||||||
|
win32api.HIWORD(ls),
|
||||||
|
win32api.LOWORD(ls),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
dbgeng_version = get_dbgeng_version()
|
||||||
|
if dbgeng_version and dbgeng_version >= (10, 0, 19041, 0):
|
||||||
|
config.available_features.add("dbgeng-10-19041")
|
||||||
|
|||||||
@ -3662,6 +3662,10 @@ public:
|
|||||||
LLVM_ABI static void appendOffset(SmallVectorImpl<uint64_t> &Ops,
|
LLVM_ABI static void appendOffset(SmallVectorImpl<uint64_t> &Ops,
|
||||||
int64_t Offset);
|
int64_t Offset);
|
||||||
|
|
||||||
|
LLVM_ABI static bool
|
||||||
|
extractLeadingOffset(ArrayRef<uint64_t> Ops, int64_t &OffsetInBytes,
|
||||||
|
SmallVectorImpl<uint64_t> &RemainingOps);
|
||||||
|
|
||||||
/// If this is a constant offset, extract it. If there is no expression,
|
/// If this is a constant offset, extract it. If there is no expression,
|
||||||
/// return true with an offset of zero.
|
/// return true with an offset of zero.
|
||||||
LLVM_ABI bool extractIfOffset(int64_t &Offset) const;
|
LLVM_ABI bool extractIfOffset(int64_t &Offset) const;
|
||||||
|
|||||||
@ -62,6 +62,7 @@ struct DefRangeRegisterRelHeader;
|
|||||||
struct DefRangeSubfieldRegisterHeader;
|
struct DefRangeSubfieldRegisterHeader;
|
||||||
struct DefRangeRegisterHeader;
|
struct DefRangeRegisterHeader;
|
||||||
struct DefRangeFramePointerRelHeader;
|
struct DefRangeFramePointerRelHeader;
|
||||||
|
struct DefRangeRegisterRelIndirHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
using MCSectionSubPair = std::pair<MCSection *, uint32_t>;
|
using MCSectionSubPair = std::pair<MCSection *, uint32_t>;
|
||||||
@ -978,6 +979,10 @@ public:
|
|||||||
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
|
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
|
||||||
codeview::DefRangeFramePointerRelHeader DRHdr);
|
codeview::DefRangeFramePointerRelHeader DRHdr);
|
||||||
|
|
||||||
|
virtual void emitCVDefRangeDirective(
|
||||||
|
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
|
||||||
|
codeview::DefRangeRegisterRelIndirHeader DRHdr);
|
||||||
|
|
||||||
/// This implements the CodeView '.cv_stringtable' assembler directive.
|
/// This implements the CodeView '.cv_stringtable' assembler directive.
|
||||||
virtual void emitCVStringTableDirective() {}
|
virtual void emitCVStringTableDirective() {}
|
||||||
|
|
||||||
|
|||||||
@ -1274,7 +1274,8 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
|
|||||||
}
|
}
|
||||||
|
|
||||||
CodeViewDebug::LocalVarDef
|
CodeViewDebug::LocalVarDef
|
||||||
CodeViewDebug::createDefRangeMem(uint16_t CVRegister, int Offset) {
|
CodeViewDebug::createDefRangeMem(uint16_t CVRegister, int Offset,
|
||||||
|
int32_t DerefOffset) {
|
||||||
LocalVarDef DR;
|
LocalVarDef DR;
|
||||||
DR.InMemory = -1;
|
DR.InMemory = -1;
|
||||||
DR.DataOffset = Offset;
|
DR.DataOffset = Offset;
|
||||||
@ -1282,6 +1283,7 @@ CodeViewDebug::createDefRangeMem(uint16_t CVRegister, int Offset) {
|
|||||||
DR.IsSubfield = 0;
|
DR.IsSubfield = 0;
|
||||||
DR.StructOffset = 0;
|
DR.StructOffset = 0;
|
||||||
DR.CVRegister = CVRegister;
|
DR.CVRegister = CVRegister;
|
||||||
|
DR.DerefOffset = DerefOffset;
|
||||||
return DR;
|
return DR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1307,16 +1309,23 @@ void CodeViewDebug::collectVariableInfoFromMFTable(
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If the variable has an attached offset expression, extract it.
|
// If the variable has an attached offset expression, extract it.
|
||||||
// FIXME: Try to handle DW_OP_deref as well.
|
|
||||||
int64_t ExprOffset = 0;
|
int64_t ExprOffset = 0;
|
||||||
bool Deref = false;
|
int64_t DerefOffset = LocalVarDef::NoDeref;
|
||||||
if (VI.Expr) {
|
if (VI.Expr) {
|
||||||
// If there is one DW_OP_deref element, use offset of 0 and keep going.
|
SmallVector<uint64_t, 2> FirstRemaining;
|
||||||
if (VI.Expr->getNumElements() == 1 &&
|
if (!VI.Expr->extractLeadingOffset(ExprOffset, FirstRemaining))
|
||||||
VI.Expr->getElement(0) == llvm::dwarf::DW_OP_deref)
|
|
||||||
Deref = true;
|
|
||||||
else if (!VI.Expr->extractIfOffset(ExprOffset))
|
|
||||||
continue;
|
continue;
|
||||||
|
if (!FirstRemaining.empty()) {
|
||||||
|
if (FirstRemaining.front() != dwarf::DW_OP_deref)
|
||||||
|
continue;
|
||||||
|
SmallVector<uint64_t, 1> LastRemaining;
|
||||||
|
if (!DIExpression::extractLeadingOffset(
|
||||||
|
ArrayRef(FirstRemaining).drop_front(), DerefOffset,
|
||||||
|
LastRemaining))
|
||||||
|
continue;
|
||||||
|
if (!LastRemaining.empty())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the frame register used and the offset.
|
// Get the frame register used and the offset.
|
||||||
@ -1329,10 +1338,13 @@ void CodeViewDebug::collectVariableInfoFromMFTable(
|
|||||||
// No encoding currently exists for scalable offsets; bail out.
|
// No encoding currently exists for scalable offsets; bail out.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (DerefOffset < INT32_MIN || DerefOffset > INT32_MAX)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Calculate the label ranges.
|
// Calculate the label ranges.
|
||||||
LocalVarDef DefRange =
|
LocalVarDef DefRange =
|
||||||
createDefRangeMem(CVReg, FrameOffset.getFixed() + ExprOffset);
|
createDefRangeMem(CVReg, FrameOffset.getFixed() + ExprOffset,
|
||||||
|
static_cast<int32_t>(DerefOffset));
|
||||||
|
|
||||||
LocalVariable Var;
|
LocalVariable Var;
|
||||||
Var.DIVar = VI.Var;
|
Var.DIVar = VI.Var;
|
||||||
@ -1344,21 +1356,10 @@ void CodeViewDebug::collectVariableInfoFromMFTable(
|
|||||||
Var.DefRanges[DefRange].emplace_back(Begin, End);
|
Var.DefRanges[DefRange].emplace_back(Begin, End);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Deref)
|
|
||||||
Var.UseReferenceType = true;
|
|
||||||
|
|
||||||
recordLocalVariable(std::move(Var), Scope);
|
recordLocalVariable(std::move(Var), Scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool canUseReferenceType(const DbgVariableLocation &Loc) {
|
|
||||||
return !Loc.LoadChain.empty() && Loc.LoadChain.back() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool needsReferenceType(const DbgVariableLocation &Loc) {
|
|
||||||
return Loc.LoadChain.size() == 2 && Loc.LoadChain.back() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeViewDebug::calculateRanges(
|
void CodeViewDebug::calculateRanges(
|
||||||
LocalVariable &Var, const DbgValueHistoryMap::Entries &Entries) {
|
LocalVariable &Var, const DbgValueHistoryMap::Entries &Entries) {
|
||||||
const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo();
|
const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo();
|
||||||
@ -1387,30 +1388,9 @@ void CodeViewDebug::calculateRanges(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CodeView can only express variables in register and variables in memory
|
// We can only handle a register, an offsetted load of a register, or an
|
||||||
// at a constant offset from a register. However, for variables passed
|
// indirect offsetted load.
|
||||||
// indirectly by pointer, it is common for that pointer to be spilled to a
|
if (!Location->Register || Location->LoadChain.size() > 2)
|
||||||
// stack location. For the special case of one offseted load followed by a
|
|
||||||
// zero offset load (a pointer spilled to the stack), we change the type of
|
|
||||||
// the local variable from a value type to a reference type. This tricks the
|
|
||||||
// debugger into doing the load for us.
|
|
||||||
if (Var.UseReferenceType) {
|
|
||||||
// We're using a reference type. Drop the last zero offset load.
|
|
||||||
if (canUseReferenceType(*Location))
|
|
||||||
Location->LoadChain.pop_back();
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
} else if (needsReferenceType(*Location)) {
|
|
||||||
// This location can't be expressed without switching to a reference type.
|
|
||||||
// Start over using that.
|
|
||||||
Var.UseReferenceType = true;
|
|
||||||
Var.DefRanges.clear();
|
|
||||||
calculateRanges(Var, Entries);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can only handle a register or an offseted load of a register.
|
|
||||||
if (!Location->Register || Location->LoadChain.size() > 1)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Codeview can only express byte-aligned offsets, ensure that we have a
|
// Codeview can only express byte-aligned offsets, ensure that we have a
|
||||||
@ -1427,8 +1407,13 @@ void CodeViewDebug::calculateRanges(
|
|||||||
LocalVarDef DR;
|
LocalVarDef DR;
|
||||||
DR.CVRegister = TRI->getCodeViewRegNum(Location->Register);
|
DR.CVRegister = TRI->getCodeViewRegNum(Location->Register);
|
||||||
DR.InMemory = !Location->LoadChain.empty();
|
DR.InMemory = !Location->LoadChain.empty();
|
||||||
DR.DataOffset =
|
DR.DataOffset = 0;
|
||||||
!Location->LoadChain.empty() ? Location->LoadChain.back() : 0;
|
DR.DerefOffset = LocalVarDef::NoDeref;
|
||||||
|
if (!Location->LoadChain.empty()) {
|
||||||
|
DR.DataOffset = Location->LoadChain[0];
|
||||||
|
if (Location->LoadChain.size() >= 2)
|
||||||
|
DR.DerefOffset = Location->LoadChain[1];
|
||||||
|
}
|
||||||
if (Location->FragmentInfo) {
|
if (Location->FragmentInfo) {
|
||||||
DR.IsSubfield = true;
|
DR.IsSubfield = true;
|
||||||
DR.StructOffset = Location->FragmentInfo->OffsetInBits / 8;
|
DR.StructOffset = Location->FragmentInfo->OffsetInBits / 8;
|
||||||
@ -2743,15 +2728,6 @@ CodeViewDebug::getTypeIndexForThisPtr(const DIDerivedType *PtrTy,
|
|||||||
return recordTypeIndexForDINode(PtrTy, TI, SubroutineTy);
|
return recordTypeIndexForDINode(PtrTy, TI, SubroutineTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeIndex CodeViewDebug::getTypeIndexForReferenceTo(const DIType *Ty) {
|
|
||||||
PointerRecord PR(getTypeIndex(Ty),
|
|
||||||
getPointerSizeInBytes() == 8 ? PointerKind::Near64
|
|
||||||
: PointerKind::Near32,
|
|
||||||
PointerMode::LValueReference, PointerOptions::None,
|
|
||||||
Ty->getSizeInBits() / 8);
|
|
||||||
return TypeTable.writeLeafType(PR);
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeIndex CodeViewDebug::getCompleteTypeIndex(const DIType *Ty) {
|
TypeIndex CodeViewDebug::getCompleteTypeIndex(const DIType *Ty) {
|
||||||
// The null DIType is the void type. Don't try to hash it.
|
// The null DIType is the void type. Don't try to hash it.
|
||||||
if (!Ty)
|
if (!Ty)
|
||||||
@ -2877,9 +2853,7 @@ void CodeViewDebug::emitLocalVariable(const FunctionInfo &FI,
|
|||||||
Flags |= LocalSymFlags::IsOptimizedOut;
|
Flags |= LocalSymFlags::IsOptimizedOut;
|
||||||
|
|
||||||
OS.AddComment("TypeIndex");
|
OS.AddComment("TypeIndex");
|
||||||
TypeIndex TI = Var.UseReferenceType
|
TypeIndex TI = getCompleteTypeIndex(Var.DIVar->getType());
|
||||||
? getTypeIndexForReferenceTo(Var.DIVar->getType())
|
|
||||||
: getCompleteTypeIndex(Var.DIVar->getType());
|
|
||||||
OS.emitInt32(TI.getIndex());
|
OS.emitInt32(TI.getIndex());
|
||||||
OS.AddComment("Flags");
|
OS.AddComment("Flags");
|
||||||
OS.emitInt16(static_cast<uint16_t>(Flags));
|
OS.emitInt16(static_cast<uint16_t>(Flags));
|
||||||
@ -2907,14 +2881,28 @@ void CodeViewDebug::emitLocalVariable(const FunctionInfo &FI,
|
|||||||
Offset += FI.OffsetAdjustment;
|
Offset += FI.OffsetAdjustment;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we can use the chosen frame pointer for the frame and this isn't a
|
|
||||||
// sliced aggregate, use the smaller S_DEFRANGE_FRAMEPOINTER_REL record.
|
|
||||||
// Otherwise, use S_DEFRANGE_REGISTER_REL.
|
|
||||||
EncodedFramePtrReg EncFP = encodeFramePtrReg(RegisterId(Reg), TheCPU);
|
EncodedFramePtrReg EncFP = encodeFramePtrReg(RegisterId(Reg), TheCPU);
|
||||||
if (!DefRange.IsSubfield && EncFP != EncodedFramePtrReg::None &&
|
|
||||||
(bool(Flags & LocalSymFlags::IsParameter)
|
if (DefRange.DerefOffset != LocalVarDef::NoDeref) {
|
||||||
? (EncFP == FI.EncodedParamFramePtrReg)
|
uint16_t RegRelFlags = 0;
|
||||||
: (EncFP == FI.EncodedLocalFramePtrReg))) {
|
if (DefRange.IsSubfield) {
|
||||||
|
RegRelFlags = DefRangeRegisterRelSym::IsSubfieldFlag |
|
||||||
|
(DefRange.StructOffset
|
||||||
|
<< DefRangeRegisterRelSym::OffsetInParentShift);
|
||||||
|
}
|
||||||
|
DefRangeRegisterRelIndirHeader DRHdr;
|
||||||
|
DRHdr.Register = Reg;
|
||||||
|
DRHdr.Flags = RegRelFlags;
|
||||||
|
DRHdr.BasePointerOffset = Offset;
|
||||||
|
DRHdr.OffsetInUdt = DefRange.DerefOffset;
|
||||||
|
OS.emitCVDefRangeDirective(Ranges, DRHdr);
|
||||||
|
} else if (!DefRange.IsSubfield && EncFP != EncodedFramePtrReg::None &&
|
||||||
|
(bool(Flags & LocalSymFlags::IsParameter)
|
||||||
|
? (EncFP == FI.EncodedParamFramePtrReg)
|
||||||
|
: (EncFP == FI.EncodedLocalFramePtrReg))) {
|
||||||
|
// If we can use the chosen frame pointer for the frame and this isn't a
|
||||||
|
// sliced aggregate, use the smaller S_DEFRANGE_FRAMEPOINTER_REL record.
|
||||||
|
// Otherwise, use S_DEFRANGE_REGISTER_REL.
|
||||||
DefRangeFramePointerRelHeader DRHdr;
|
DefRangeFramePointerRelHeader DRHdr;
|
||||||
DRHdr.Offset = Offset;
|
DRHdr.Offset = Offset;
|
||||||
OS.emitCVDefRangeDirective(Ranges, DRHdr);
|
OS.emitCVDefRangeDirective(Ranges, DRHdr);
|
||||||
@ -2932,7 +2920,9 @@ void CodeViewDebug::emitLocalVariable(const FunctionInfo &FI,
|
|||||||
OS.emitCVDefRangeDirective(Ranges, DRHdr);
|
OS.emitCVDefRangeDirective(Ranges, DRHdr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(DefRange.DataOffset == 0 && "unexpected offset into register");
|
assert(DefRange.DataOffset == 0 &&
|
||||||
|
DefRange.DerefOffset == LocalVarDef::NoDeref &&
|
||||||
|
"unexpected offset into register");
|
||||||
if (DefRange.IsSubfield) {
|
if (DefRange.IsSubfield) {
|
||||||
DefRangeSubfieldRegisterHeader DRHdr;
|
DefRangeSubfieldRegisterHeader DRHdr;
|
||||||
DRHdr.Register = DefRange.CVRegister;
|
DRHdr.Register = DefRange.CVRegister;
|
||||||
|
|||||||
@ -72,21 +72,43 @@ public:
|
|||||||
/// location containing the data.
|
/// location containing the data.
|
||||||
uint32_t CVRegister : 16;
|
uint32_t CVRegister : 16;
|
||||||
|
|
||||||
uint64_t static toOpaqueValue(const LocalVarDef DR) {
|
/// Value for `DerefOffset` indicating this is not an indirect load.
|
||||||
uint64_t Val = 0;
|
constexpr static int32_t NoDeref = INT32_MIN;
|
||||||
std::memcpy(&Val, &DR, sizeof(Val));
|
|
||||||
return Val;
|
/// Offset to add after dereferencing `CVRegister + DataOffset` for
|
||||||
|
/// indirect loads. If this is not an indirect load, it's set to NoDeref.
|
||||||
|
int32_t DerefOffset = NoDeref;
|
||||||
|
|
||||||
|
static LocalVarDef emptyValue() {
|
||||||
|
LocalVarDef V;
|
||||||
|
std::memset(&V, 0xff, sizeof(LocalVarDef));
|
||||||
|
return V;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalVarDef static createFromOpaqueValue(uint64_t Val) {
|
static LocalVarDef tombstoneValue() {
|
||||||
LocalVarDef DR;
|
LocalVarDef V;
|
||||||
std::memcpy(&DR, &Val, sizeof(Val));
|
std::memset(&V, 0xff, sizeof(LocalVarDef));
|
||||||
return DR;
|
V.InMemory = 0;
|
||||||
|
return V;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned hashValue() const {
|
||||||
|
uint64_t H = 0;
|
||||||
|
std::memcpy(&H, this, sizeof(uint64_t));
|
||||||
|
static_assert(sizeof(LocalVarDef) == 8 + 4 &&
|
||||||
|
offsetof(LocalVarDef, DerefOffset) == 8);
|
||||||
|
H = hash_combine(H, DerefOffset);
|
||||||
|
return H;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const LocalVarDef &Other) const {
|
||||||
|
return InMemory == Other.InMemory && DataOffset == Other.DataOffset &&
|
||||||
|
IsSubfield == Other.IsSubfield &&
|
||||||
|
StructOffset == Other.StructOffset &&
|
||||||
|
CVRegister == Other.CVRegister && DerefOffset == Other.DerefOffset;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(uint64_t) == sizeof(LocalVarDef));
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MCStreamer &OS;
|
MCStreamer &OS;
|
||||||
BumpPtrAllocator Allocator;
|
BumpPtrAllocator Allocator;
|
||||||
@ -104,7 +126,8 @@ private:
|
|||||||
/// info is being emitted, DebugHandlerBase::Asm may be null.
|
/// info is being emitted, DebugHandlerBase::Asm may be null.
|
||||||
AsmPrinter *CompilerInfoAsm = nullptr;
|
AsmPrinter *CompilerInfoAsm = nullptr;
|
||||||
|
|
||||||
static LocalVarDef createDefRangeMem(uint16_t CVRegister, int Offset);
|
static LocalVarDef createDefRangeMem(uint16_t CVRegister, int Offset,
|
||||||
|
int32_t DerefOffset);
|
||||||
|
|
||||||
/// Similar to DbgVariable in DwarfDebug, but not dwarf-specific.
|
/// Similar to DbgVariable in DwarfDebug, but not dwarf-specific.
|
||||||
struct LocalVariable {
|
struct LocalVariable {
|
||||||
@ -112,7 +135,6 @@ private:
|
|||||||
MapVector<LocalVarDef,
|
MapVector<LocalVarDef,
|
||||||
SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 1>>
|
SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 1>>
|
||||||
DefRanges;
|
DefRanges;
|
||||||
bool UseReferenceType = false;
|
|
||||||
std::optional<APSInt> ConstantValue;
|
std::optional<APSInt> ConstantValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -431,8 +453,6 @@ private:
|
|||||||
getTypeIndexForThisPtr(const DIDerivedType *PtrTy,
|
getTypeIndexForThisPtr(const DIDerivedType *PtrTy,
|
||||||
const DISubroutineType *SubroutineTy);
|
const DISubroutineType *SubroutineTy);
|
||||||
|
|
||||||
codeview::TypeIndex getTypeIndexForReferenceTo(const DIType *Ty);
|
|
||||||
|
|
||||||
codeview::TypeIndex getMemberFunctionType(const DISubprogram *SP,
|
codeview::TypeIndex getMemberFunctionType(const DISubprogram *SP,
|
||||||
const DICompositeType *Class);
|
const DICompositeType *Class);
|
||||||
|
|
||||||
@ -536,21 +556,20 @@ public:
|
|||||||
template <> struct DenseMapInfo<CodeViewDebug::LocalVarDef> {
|
template <> struct DenseMapInfo<CodeViewDebug::LocalVarDef> {
|
||||||
|
|
||||||
static inline CodeViewDebug::LocalVarDef getEmptyKey() {
|
static inline CodeViewDebug::LocalVarDef getEmptyKey() {
|
||||||
return CodeViewDebug::LocalVarDef::createFromOpaqueValue(~0ULL);
|
return CodeViewDebug::LocalVarDef::emptyValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline CodeViewDebug::LocalVarDef getTombstoneKey() {
|
static inline CodeViewDebug::LocalVarDef getTombstoneKey() {
|
||||||
return CodeViewDebug::LocalVarDef::createFromOpaqueValue(~0ULL - 1ULL);
|
return CodeViewDebug::LocalVarDef::tombstoneValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned getHashValue(const CodeViewDebug::LocalVarDef &DR) {
|
static unsigned getHashValue(const CodeViewDebug::LocalVarDef &DR) {
|
||||||
return CodeViewDebug::LocalVarDef::toOpaqueValue(DR) * 37ULL;
|
return DR.hashValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isEqual(const CodeViewDebug::LocalVarDef &LHS,
|
static bool isEqual(const CodeViewDebug::LocalVarDef &LHS,
|
||||||
const CodeViewDebug::LocalVarDef &RHS) {
|
const CodeViewDebug::LocalVarDef &RHS) {
|
||||||
return CodeViewDebug::LocalVarDef::toOpaqueValue(LHS) ==
|
return LHS == RHS;
|
||||||
CodeViewDebug::LocalVarDef::toOpaqueValue(RHS);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -2115,16 +2115,13 @@ bool DIExpression::extractIfOffset(int64_t &Offset) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DIExpression::extractLeadingOffset(
|
bool DIExpression::extractLeadingOffset(
|
||||||
int64_t &OffsetInBytes, SmallVectorImpl<uint64_t> &RemainingOps) const {
|
ArrayRef<uint64_t> Ops, int64_t &OffsetInBytes,
|
||||||
|
SmallVectorImpl<uint64_t> &RemainingOps) {
|
||||||
OffsetInBytes = 0;
|
OffsetInBytes = 0;
|
||||||
RemainingOps.clear();
|
RemainingOps.clear();
|
||||||
|
|
||||||
auto SingleLocEltsOpt = getSingleLocationExpressionElements();
|
auto ExprOpEnd = expr_op_iterator(Ops.end());
|
||||||
if (!SingleLocEltsOpt)
|
auto ExprOpIt = expr_op_iterator(Ops.begin());
|
||||||
return false;
|
|
||||||
|
|
||||||
auto ExprOpEnd = expr_op_iterator(SingleLocEltsOpt->end());
|
|
||||||
auto ExprOpIt = expr_op_iterator(SingleLocEltsOpt->begin());
|
|
||||||
while (ExprOpIt != ExprOpEnd) {
|
while (ExprOpIt != ExprOpEnd) {
|
||||||
uint64_t Op = ExprOpIt->getOp();
|
uint64_t Op = ExprOpIt->getOp();
|
||||||
if (Op == dwarf::DW_OP_deref || Op == dwarf::DW_OP_deref_size ||
|
if (Op == dwarf::DW_OP_deref || Op == dwarf::DW_OP_deref_size ||
|
||||||
@ -2153,6 +2150,18 @@ bool DIExpression::extractLeadingOffset(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DIExpression::extractLeadingOffset(
|
||||||
|
int64_t &OffsetInBytes, SmallVectorImpl<uint64_t> &RemainingOps) const {
|
||||||
|
auto SingleLocEltsOpt = getSingleLocationExpressionElements();
|
||||||
|
if (!SingleLocEltsOpt) {
|
||||||
|
OffsetInBytes = 0;
|
||||||
|
RemainingOps.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return extractLeadingOffset(*SingleLocEltsOpt, OffsetInBytes, RemainingOps);
|
||||||
|
}
|
||||||
|
|
||||||
bool DIExpression::hasAllLocationOps(unsigned N) const {
|
bool DIExpression::hasAllLocationOps(unsigned N) const {
|
||||||
SmallDenseSet<uint64_t, 4> SeenOps;
|
SmallDenseSet<uint64_t, 4> SeenOps;
|
||||||
for (auto ExprOp : expr_ops())
|
for (auto ExprOp : expr_ops())
|
||||||
|
|||||||
@ -360,6 +360,10 @@ public:
|
|||||||
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
|
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
|
||||||
codeview::DefRangeFramePointerRelHeader DRHdr) override;
|
codeview::DefRangeFramePointerRelHeader DRHdr) override;
|
||||||
|
|
||||||
|
void emitCVDefRangeDirective(
|
||||||
|
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
|
||||||
|
codeview::DefRangeRegisterRelIndirHeader DRHdr) override;
|
||||||
|
|
||||||
void emitCVStringTableDirective() override;
|
void emitCVStringTableDirective() override;
|
||||||
void emitCVFileChecksumsDirective() override;
|
void emitCVFileChecksumsDirective() override;
|
||||||
void emitCVFileChecksumOffsetDirective(unsigned FileNo) override;
|
void emitCVFileChecksumOffsetDirective(unsigned FileNo) override;
|
||||||
@ -1944,6 +1948,16 @@ void MCAsmStreamer::emitCVDefRangeDirective(
|
|||||||
EmitEOL();
|
EmitEOL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MCAsmStreamer::emitCVDefRangeDirective(
|
||||||
|
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
|
||||||
|
codeview::DefRangeRegisterRelIndirHeader DRHdr) {
|
||||||
|
PrintCVDefRangePrefix(Ranges);
|
||||||
|
OS << ", reg_rel_indir, ";
|
||||||
|
OS << DRHdr.Register << ", " << DRHdr.Flags << ", " << DRHdr.BasePointerOffset
|
||||||
|
<< ", " << DRHdr.OffsetInUdt;
|
||||||
|
EmitEOL();
|
||||||
|
}
|
||||||
|
|
||||||
void MCAsmStreamer::emitCVStringTableDirective() {
|
void MCAsmStreamer::emitCVStringTableDirective() {
|
||||||
OS << "\t.cv_stringtable";
|
OS << "\t.cv_stringtable";
|
||||||
EmitEOL();
|
EmitEOL();
|
||||||
|
|||||||
@ -545,7 +545,8 @@ private:
|
|||||||
CVDR_DEFRANGE_REGISTER,
|
CVDR_DEFRANGE_REGISTER,
|
||||||
CVDR_DEFRANGE_FRAMEPOINTER_REL,
|
CVDR_DEFRANGE_FRAMEPOINTER_REL,
|
||||||
CVDR_DEFRANGE_SUBFIELD_REGISTER,
|
CVDR_DEFRANGE_SUBFIELD_REGISTER,
|
||||||
CVDR_DEFRANGE_REGISTER_REL
|
CVDR_DEFRANGE_REGISTER_REL,
|
||||||
|
CVDR_DEFRANGE_REGISTER_REL_INDIR
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Maps Codeview def_range types --> CVDefRangeType enum, for
|
/// Maps Codeview def_range types --> CVDefRangeType enum, for
|
||||||
@ -3977,6 +3978,7 @@ void AsmParser::initializeCVDefRangeTypeMap() {
|
|||||||
CVDefRangeTypeMap["frame_ptr_rel"] = CVDR_DEFRANGE_FRAMEPOINTER_REL;
|
CVDefRangeTypeMap["frame_ptr_rel"] = CVDR_DEFRANGE_FRAMEPOINTER_REL;
|
||||||
CVDefRangeTypeMap["subfield_reg"] = CVDR_DEFRANGE_SUBFIELD_REGISTER;
|
CVDefRangeTypeMap["subfield_reg"] = CVDR_DEFRANGE_SUBFIELD_REGISTER;
|
||||||
CVDefRangeTypeMap["reg_rel"] = CVDR_DEFRANGE_REGISTER_REL;
|
CVDefRangeTypeMap["reg_rel"] = CVDR_DEFRANGE_REGISTER_REL;
|
||||||
|
CVDefRangeTypeMap["reg_rel_indir"] = CVDR_DEFRANGE_REGISTER_REL_INDIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// parseDirectiveCVDefRange
|
/// parseDirectiveCVDefRange
|
||||||
@ -4080,6 +4082,37 @@ bool AsmParser::parseDirectiveCVDefRange() {
|
|||||||
getStreamer().emitCVDefRangeDirective(Ranges, DRHdr);
|
getStreamer().emitCVDefRangeDirective(Ranges, DRHdr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CVDR_DEFRANGE_REGISTER_REL_INDIR: {
|
||||||
|
int64_t DRRegister;
|
||||||
|
int64_t DRFlags;
|
||||||
|
int64_t DRBasePointerOffset;
|
||||||
|
int64_t DROffsetInUdt;
|
||||||
|
if (parseToken(AsmToken::Comma, "expected comma before register number in "
|
||||||
|
".cv_def_range directive") ||
|
||||||
|
parseAbsoluteExpression(DRRegister))
|
||||||
|
return Error(Loc, "expected register value");
|
||||||
|
if (parseToken(
|
||||||
|
AsmToken::Comma,
|
||||||
|
"expected comma before flag value in .cv_def_range directive") ||
|
||||||
|
parseAbsoluteExpression(DRFlags))
|
||||||
|
return Error(Loc, "expected flag value");
|
||||||
|
if (parseToken(AsmToken::Comma, "expected comma before base pointer offset "
|
||||||
|
"in .cv_def_range directive") ||
|
||||||
|
parseAbsoluteExpression(DRBasePointerOffset))
|
||||||
|
return Error(Loc, "expected base pointer offset value");
|
||||||
|
if (parseToken(AsmToken::Comma, "expected comma before offset in UDT "
|
||||||
|
"in .cv_def_range directive") ||
|
||||||
|
parseAbsoluteExpression(DROffsetInUdt))
|
||||||
|
return Error(Loc, "expected offset in UDT value");
|
||||||
|
|
||||||
|
codeview::DefRangeRegisterRelIndirHeader DRHdr;
|
||||||
|
DRHdr.Register = DRRegister;
|
||||||
|
DRHdr.Flags = DRFlags;
|
||||||
|
DRHdr.BasePointerOffset = DRBasePointerOffset;
|
||||||
|
DRHdr.OffsetInUdt = DROffsetInUdt;
|
||||||
|
getStreamer().emitCVDefRangeDirective(Ranges, DRHdr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return Error(Loc, "unexpected def_range type in .cv_def_range directive");
|
return Error(Loc, "unexpected def_range type in .cv_def_range directive");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -382,6 +382,15 @@ void MCStreamer::emitCVDefRangeDirective(
|
|||||||
emitCVDefRangeDirective(Ranges, BytePrefix);
|
emitCVDefRangeDirective(Ranges, BytePrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MCStreamer::emitCVDefRangeDirective(
|
||||||
|
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
|
||||||
|
codeview::DefRangeRegisterRelIndirHeader DRHdr) {
|
||||||
|
SmallString<20> BytePrefix;
|
||||||
|
copyBytesForDefRange(BytePrefix, codeview::S_DEFRANGE_REGISTER_REL_INDIR,
|
||||||
|
DRHdr);
|
||||||
|
emitCVDefRangeDirective(Ranges, BytePrefix);
|
||||||
|
}
|
||||||
|
|
||||||
void MCStreamer::emitEHSymAttributes(const MCSymbol *Symbol,
|
void MCStreamer::emitEHSymAttributes(const MCSymbol *Symbol,
|
||||||
MCSymbol *EHSymbol) {
|
MCSymbol *EHSymbol) {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,20 +25,23 @@
|
|||||||
# (DW_OP_plus_uconst, 8, DW_OP_deref)
|
# (DW_OP_plus_uconst, 8, DW_OP_deref)
|
||||||
# CHECK: LocalSym {
|
# CHECK: LocalSym {
|
||||||
# CHECK-NEXT: Kind: S_LOCAL (0x113E)
|
# CHECK-NEXT: Kind: S_LOCAL (0x113E)
|
||||||
# CHECK-NEXT: Type: string& (0x
|
# CHECK-NEXT: Type: string (0x
|
||||||
# CHECK-NEXT: Flags [ (0x0)
|
# CHECK-NEXT: Flags [ (0x0)
|
||||||
# CHECK-NEXT: ]
|
# CHECK-NEXT: ]
|
||||||
# CHECK-NEXT: VarName: Result
|
# CHECK-NEXT: VarName: Result
|
||||||
# CHECK-NEXT: }
|
# CHECK-NEXT: }
|
||||||
# CHECK-NEXT: DefRangeFramePointerRelSym {
|
# CHECK-NEXT: DefRangeRegisterRelIndirSym {
|
||||||
# CHECK-NEXT: Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142)
|
# CHECK-NEXT: Kind: S_DEFRANGE_REGISTER_REL_INDIR (0x1177)
|
||||||
# CHECK-NEXT: Offset: 8
|
# CHECK-NEXT: BaseRegister: VFRAME (0x
|
||||||
|
# CHECK-NEXT: HasSpilledUDTMember: No
|
||||||
|
# CHECK-NEXT: OffsetInParent: 0
|
||||||
|
# CHECK-NEXT: BasePointerOffset: 8
|
||||||
|
# CHECK-NEXT: OffsetInUDT: 0
|
||||||
# CHECK-NEXT: LocalVariableAddrRange {
|
# CHECK-NEXT: LocalVariableAddrRange {
|
||||||
# CHECK-NEXT: OffsetStart: .text+0x5
|
# CHECK-NEXT: OffsetStart: .text+0x5
|
||||||
# CHECK-NEXT: ISectStart: 0x0
|
# CHECK-NEXT: ISectStart: 0x0
|
||||||
# CHECK-NEXT: Range: 0x18
|
# CHECK-NEXT: Range: 0x18
|
||||||
# CHECK-NEXT: }
|
# CHECK-NEXT: }
|
||||||
# CHECK-NEXT: }
|
|
||||||
# (DW_OP_constu, 4, DW_OP_minus)
|
# (DW_OP_constu, 4, DW_OP_minus)
|
||||||
# CHECK: LocalSym {
|
# CHECK: LocalSym {
|
||||||
# CHECK-NEXT: Kind: S_LOCAL (0x113E)
|
# CHECK-NEXT: Kind: S_LOCAL (0x113E)
|
||||||
|
|||||||
212
llvm/test/DebugInfo/COFF/indirect-local.ll
Normal file
212
llvm/test/DebugInfo/COFF/indirect-local.ll
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
; RUN: llc < %s | FileCheck %s --check-prefix=ASM
|
||||||
|
; RUN: llc < %s -filetype=obj | llvm-readobj - --codeview | FileCheck %s --check-prefix=OBJ
|
||||||
|
|
||||||
|
|
||||||
|
; C++ source to regenerate:
|
||||||
|
; struct Foo {
|
||||||
|
; int a;
|
||||||
|
; int b;
|
||||||
|
; int c;
|
||||||
|
; int d;
|
||||||
|
; };
|
||||||
|
;
|
||||||
|
; int main() {
|
||||||
|
; Foo f{1, 2, 3, 4};
|
||||||
|
; auto &[a, b, c, d] = f;
|
||||||
|
; return a;
|
||||||
|
; }
|
||||||
|
; $ clang t.cpp -S -emit-llvm -g -o t.ll -std=c++17
|
||||||
|
|
||||||
|
; ASM-LABEL: .long 241 # Symbol subsection for main
|
||||||
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
||||||
|
; ASM-NEXT: .long 4101 # TypeIndex
|
||||||
|
; ASM-NEXT: .short 0 # Flags
|
||||||
|
; ASM-NEXT: .asciz "f"
|
||||||
|
; ASM-NEXT: .p2align 2, 0x0
|
||||||
|
; ASM-NEXT: .Ltmp{{.*}}:
|
||||||
|
; ASM-NEXT: .cv_def_range .Ltmp0 .Ltmp1, frame_ptr_rel, 16
|
||||||
|
|
||||||
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
||||||
|
; ASM-NEXT: .long 116 # TypeIndex
|
||||||
|
; ASM-NEXT: .short 0 # Flags
|
||||||
|
; ASM-NEXT: .asciz "a"
|
||||||
|
; ASM-NEXT: .p2align 2, 0x0
|
||||||
|
; ASM-NEXT: .Ltmp{{.*}}:
|
||||||
|
; ASM-NEXT: .cv_def_range .Ltmp{{.*}} .Ltmp{{.*}}, reg_rel_indir, 335, 0, 0, 0
|
||||||
|
|
||||||
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
||||||
|
; ASM-NEXT: .long 116 # TypeIndex
|
||||||
|
; ASM-NEXT: .short 0 # Flags
|
||||||
|
; ASM-NEXT: .asciz "b"
|
||||||
|
; ASM-NEXT: .p2align 2, 0x0
|
||||||
|
; ASM-NEXT: .Ltmp{{.*}}:
|
||||||
|
; ASM-NEXT: .cv_def_range .Ltmp{{.*}} .Ltmp{{.*}}, reg_rel_indir, 335, 0, 0, 4
|
||||||
|
|
||||||
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
||||||
|
; ASM-NEXT: .long 116 # TypeIndex
|
||||||
|
; ASM-NEXT: .short 0 # Flags
|
||||||
|
; ASM-NEXT: .asciz "c"
|
||||||
|
; ASM-NEXT: .p2align 2, 0x0
|
||||||
|
; ASM-NEXT: .Ltmp{{.*}}:
|
||||||
|
; ASM-NEXT: .cv_def_range .Ltmp{{.*}} .Ltmp{{.*}}, reg_rel_indir, 335, 0, 0, 8
|
||||||
|
|
||||||
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
||||||
|
; ASM-NEXT: .long 116 # TypeIndex
|
||||||
|
; ASM-NEXT: .short 0 # Flags
|
||||||
|
; ASM-NEXT: .asciz "d"
|
||||||
|
; ASM-NEXT: .p2align 2, 0x0
|
||||||
|
; ASM-NEXT: .Ltmp{{.*}}:
|
||||||
|
; ASM-NEXT: .cv_def_range .Ltmp{{.*}} .Ltmp{{.*}}, reg_rel_indir, 335, 0, 0, 12
|
||||||
|
|
||||||
|
; OBJ: Subsection [
|
||||||
|
; OBJ: SubSectionType: Symbols (0xF1)
|
||||||
|
; OBJ: GlobalProcIdSym {
|
||||||
|
; OBJ: FunctionType: main (0x1002)
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: LocalSym {
|
||||||
|
; OBJ: Kind: S_LOCAL (0x113E)
|
||||||
|
; OBJ: Type: Foo (0x1005)
|
||||||
|
; OBJ: VarName: f
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: DefRangeFramePointerRelSym {
|
||||||
|
; OBJ: Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142)
|
||||||
|
; OBJ: Offset: 16
|
||||||
|
; OBJ: LocalVariableAddrRange {
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: LocalSym {
|
||||||
|
; OBJ: Kind: S_LOCAL (0x113E)
|
||||||
|
; OBJ: Type: int (0x74)
|
||||||
|
; OBJ: Flags [ (0x0)
|
||||||
|
; OBJ: ]
|
||||||
|
; OBJ: VarName: a
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: DefRangeRegisterRelIndirSym {
|
||||||
|
; OBJ: Kind: S_DEFRANGE_REGISTER_REL_INDIR (0x1177)
|
||||||
|
; OBJ: BaseRegister: RSP (0x14F)
|
||||||
|
; OBJ: HasSpilledUDTMember: No
|
||||||
|
; OBJ: OffsetInParent: 0
|
||||||
|
; OBJ: BasePointerOffset: 0
|
||||||
|
; OBJ: OffsetInUDT: 0
|
||||||
|
; OBJ: LocalVariableAddrRange {
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: LocalSym {
|
||||||
|
; OBJ: Kind: S_LOCAL (0x113E)
|
||||||
|
; OBJ: Type: int (0x74)
|
||||||
|
; OBJ: Flags [ (0x0)
|
||||||
|
; OBJ: ]
|
||||||
|
; OBJ: VarName: b
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: DefRangeRegisterRelIndirSym {
|
||||||
|
; OBJ: Kind: S_DEFRANGE_REGISTER_REL_INDIR (0x1177)
|
||||||
|
; OBJ: BaseRegister: RSP (0x14F)
|
||||||
|
; OBJ: HasSpilledUDTMember: No
|
||||||
|
; OBJ: OffsetInParent: 0
|
||||||
|
; OBJ: BasePointerOffset: 0
|
||||||
|
; OBJ: OffsetInUDT: 4
|
||||||
|
; OBJ: LocalVariableAddrRange {
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: LocalSym {
|
||||||
|
; OBJ: Kind: S_LOCAL (0x113E)
|
||||||
|
; OBJ: Type: int (0x74)
|
||||||
|
; OBJ: Flags [ (0x0)
|
||||||
|
; OBJ: ]
|
||||||
|
; OBJ: VarName: c
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: DefRangeRegisterRelIndirSym {
|
||||||
|
; OBJ: Kind: S_DEFRANGE_REGISTER_REL_INDIR (0x1177)
|
||||||
|
; OBJ: BaseRegister: RSP (0x14F)
|
||||||
|
; OBJ: HasSpilledUDTMember: No
|
||||||
|
; OBJ: OffsetInParent: 0
|
||||||
|
; OBJ: BasePointerOffset: 0
|
||||||
|
; OBJ: OffsetInUDT: 8
|
||||||
|
; OBJ: LocalVariableAddrRange {
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: LocalSym {
|
||||||
|
; OBJ: Kind: S_LOCAL (0x113E)
|
||||||
|
; OBJ: Type: int (0x74)
|
||||||
|
; OBJ: Flags [ (0x0)
|
||||||
|
; OBJ: ]
|
||||||
|
; OBJ: VarName: d
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: DefRangeRegisterRelIndirSym {
|
||||||
|
; OBJ: Kind: S_DEFRANGE_REGISTER_REL_INDIR (0x1177)
|
||||||
|
; OBJ: BaseRegister: RSP (0x14F)
|
||||||
|
; OBJ: HasSpilledUDTMember: No
|
||||||
|
; OBJ: OffsetInParent: 0
|
||||||
|
; OBJ: BasePointerOffset: 0
|
||||||
|
; OBJ: OffsetInUDT: 12
|
||||||
|
; OBJ: LocalVariableAddrRange {
|
||||||
|
; OBJ: }
|
||||||
|
; OBJ: }
|
||||||
|
|
||||||
|
; ModuleID = 't.cpp'
|
||||||
|
source_filename = "t.cpp"
|
||||||
|
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
|
||||||
|
target triple = "x86_64-pc-windows-msvc19.50.35725"
|
||||||
|
|
||||||
|
%struct.Foo = type { i32, i32, i32, i32 }
|
||||||
|
|
||||||
|
@__const.main.f = private unnamed_addr constant %struct.Foo { i32 1, i32 2, i32 3, i32 4 }, align 4
|
||||||
|
|
||||||
|
; Function Attrs: mustprogress noinline norecurse nounwind optnone uwtable
|
||||||
|
define dso_local noundef i32 @main() #0 !dbg !9 {
|
||||||
|
%1 = alloca i32, align 4
|
||||||
|
%2 = alloca %struct.Foo, align 4
|
||||||
|
%3 = alloca ptr, align 8
|
||||||
|
store i32 0, ptr %1, align 4
|
||||||
|
#dbg_declare(ptr %2, !14, !DIExpression(), !21)
|
||||||
|
call void @llvm.memcpy.p0.p0.i64(ptr align 4 %2, ptr align 4 @__const.main.f, i64 16, i1 false), !dbg !21
|
||||||
|
#dbg_declare(ptr %3, !22, !DIExpression(DW_OP_deref), !23)
|
||||||
|
#dbg_declare(ptr %3, !24, !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 4), !23)
|
||||||
|
#dbg_declare(ptr %3, !25, !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 8), !23)
|
||||||
|
#dbg_declare(ptr %3, !26, !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 12), !23)
|
||||||
|
store ptr %2, ptr %3, align 8, !dbg !23
|
||||||
|
%4 = load ptr, ptr %3, align 8, !dbg !27, !nonnull !13, !align !28
|
||||||
|
%5 = getelementptr inbounds nuw %struct.Foo, ptr %4, i32 0, i32 0, !dbg !27
|
||||||
|
%6 = load i32, ptr %5, align 4, !dbg !27
|
||||||
|
ret i32 %6, !dbg !27
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
|
||||||
|
declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #1
|
||||||
|
|
||||||
|
attributes #0 = { mustprogress noinline norecurse nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
||||||
|
attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
||||||
|
|
||||||
|
!llvm.dbg.cu = !{!0}
|
||||||
|
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
|
||||||
|
!llvm.ident = !{!8}
|
||||||
|
|
||||||
|
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 21.1.8", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
|
||||||
|
!1 = !DIFile(filename: "t.cpp", directory: "F:\\Dev\\dummy", checksumkind: CSK_MD5, checksum: "e257352cbba404e4548bc4500877ceb0")
|
||||||
|
!2 = !{i32 2, !"CodeView", i32 1}
|
||||||
|
!3 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
!4 = !{i32 1, !"wchar_size", i32 2}
|
||||||
|
!5 = !{i32 8, !"PIC Level", i32 2}
|
||||||
|
!6 = !{i32 7, !"uwtable", i32 2}
|
||||||
|
!7 = !{i32 1, !"MaxTLSAlign", i32 65536}
|
||||||
|
!8 = !{!"clang version 21.1.8"}
|
||||||
|
!9 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 8, type: !10, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13)
|
||||||
|
!10 = !DISubroutineType(types: !11)
|
||||||
|
!11 = !{!12}
|
||||||
|
!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||||
|
!13 = !{}
|
||||||
|
!14 = !DILocalVariable(name: "f", scope: !9, file: !1, line: 9, type: !15)
|
||||||
|
!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 1, size: 128, flags: DIFlagTypePassByValue, elements: !16, identifier: ".?AUFoo@@")
|
||||||
|
!16 = !{!17, !18, !19, !20}
|
||||||
|
!17 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !15, file: !1, line: 2, baseType: !12, size: 32)
|
||||||
|
!18 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !15, file: !1, line: 3, baseType: !12, size: 32, offset: 32)
|
||||||
|
!19 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !15, file: !1, line: 4, baseType: !12, size: 32, offset: 64)
|
||||||
|
!20 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !15, file: !1, line: 5, baseType: !12, size: 32, offset: 96)
|
||||||
|
!21 = !DILocation(line: 9, scope: !9)
|
||||||
|
!22 = !DILocalVariable(name: "a", scope: !9, file: !1, line: 10, type: !12)
|
||||||
|
!23 = !DILocation(line: 10, scope: !9)
|
||||||
|
!24 = !DILocalVariable(name: "b", scope: !9, file: !1, line: 10, type: !12)
|
||||||
|
!25 = !DILocalVariable(name: "c", scope: !9, file: !1, line: 10, type: !12)
|
||||||
|
!26 = !DILocalVariable(name: "d", scope: !9, file: !1, line: 10, type: !12)
|
||||||
|
!27 = !DILocation(line: 11, scope: !9)
|
||||||
|
!28 = !{i64 4}
|
||||||
@ -24,29 +24,34 @@
|
|||||||
|
|
||||||
; ASM-LABEL: .long 241 # Symbol subsection for GetFoo
|
; ASM-LABEL: .long 241 # Symbol subsection for GetFoo
|
||||||
; ASM: .short 4414 # Record kind: S_LOCAL
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
||||||
; ASM-NEXT: .long 4113 # TypeIndex
|
; ASM-NEXT: .long 4109 # TypeIndex
|
||||||
; ASM-NEXT: .short 0 # Flags
|
; ASM-NEXT: .short 0 # Flags
|
||||||
; ASM-NEXT: .asciz "foo"
|
; ASM-NEXT: .asciz "foo"
|
||||||
; ASM-NEXT: .p2align 2
|
; ASM-NEXT: .p2align 2
|
||||||
; ASM-NEXT: .Ltmp
|
; ASM-NEXT: .Ltmp
|
||||||
; ASM: .cv_def_range .Ltmp{{.*}} .Ltmp{{.*}}, frame_ptr_rel, 40
|
; ASM: .cv_def_range .Ltmp{{.*}} .Ltmp{{.*}}, reg_rel_indir, 335, 0, 40, 0
|
||||||
|
|
||||||
; OBJ: Subsection [
|
; OBJ: Subsection [
|
||||||
; OBJ: SubSectionType: Symbols (0xF1)
|
; OBJ: SubSectionType: Symbols (0xF1)
|
||||||
; OBJ: LocalSym {
|
; OBJ: LocalSym {
|
||||||
; OBJ: Kind: S_LOCAL (0x113E)
|
; OBJ: Kind: S_LOCAL (0x113E)
|
||||||
; OBJ: Type: Foo& (0x1011)
|
; OBJ: Type: Foo (0x100D)
|
||||||
; OBJ: Flags [ (0x0)
|
; OBJ: Flags [ (0x0)
|
||||||
; OBJ: ]
|
; OBJ: ]
|
||||||
; OBJ: VarName: foo
|
; OBJ: VarName: foo
|
||||||
; OBJ: }
|
; OBJ: }
|
||||||
; OBJ: DefRangeFramePointerRelSym {
|
; OBJ: DefRangeRegisterRelIndirSym {
|
||||||
; OBJ: Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142)
|
; OBJ: Kind: S_DEFRANGE_REGISTER_REL_INDIR (0x1177)
|
||||||
; OBJ: Offset: 40
|
; OBJ: BaseRegister: RSP (0x14F)
|
||||||
|
; OBJ: HasSpilledUDTMember: No
|
||||||
|
; OBJ: OffsetInParent: 0
|
||||||
|
; OBJ: BasePointerOffset: 40
|
||||||
|
; OBJ: OffsetInUDT: 0
|
||||||
; OBJ: LocalVariableAddrRange {
|
; OBJ: LocalVariableAddrRange {
|
||||||
; OBJ: OffsetStart: .text+0x1D
|
; OBJ: OffsetStart: .text+0x1D
|
||||||
; OBJ: ISectStart: 0x0
|
; OBJ: ISectStart: 0x0
|
||||||
; OBJ: Range: 0x16
|
; OBJ: Range: 0x16
|
||||||
|
; OBJ: }
|
||||||
; OBJ: }
|
; OBJ: }
|
||||||
|
|
||||||
; ModuleID = 't.cpp'
|
; ModuleID = 't.cpp'
|
||||||
|
|||||||
@ -180,8 +180,9 @@
|
|||||||
; ASM-LABEL: .short 4423 # Record kind: S_GPROC32_ID
|
; ASM-LABEL: .short 4423 # Record kind: S_GPROC32_ID
|
||||||
; ASM: .asciz "nested" # Function name
|
; ASM: .asciz "nested" # Function name
|
||||||
; ASM: .short 4414 # Record kind: S_LOCAL
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
||||||
|
; ASM: .long 4123 # TypeIndex
|
||||||
; ASM: .asciz "o"
|
; ASM: .asciz "o"
|
||||||
; ASM: .cv_def_range .Lfunc_begin3 .Lfunc_end3, reg_rel, 330, 0, 0
|
; ASM: .cv_def_range .Lfunc_begin3 .Lfunc_end3, reg_rel_indir, 330, 0, 0, 0
|
||||||
; ASM: .short 4414 # Record kind: S_LOCAL
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
||||||
; ASM: .asciz "p"
|
; ASM: .asciz "p"
|
||||||
; ASM: .cv_def_range [[p_start]] .Lfunc_end3, subfield_reg, 17, 4
|
; ASM: .cv_def_range [[p_start]] .Lfunc_end3, subfield_reg, 17, 4
|
||||||
@ -191,14 +192,15 @@
|
|||||||
; OBJ: DisplayName: nested
|
; OBJ: DisplayName: nested
|
||||||
; OBJ: }
|
; OBJ: }
|
||||||
; OBJ: LocalSym {
|
; OBJ: LocalSym {
|
||||||
; OBJ: Type: Nested&
|
; OBJ: Type: Nested
|
||||||
; OBJ: VarName: o
|
; OBJ: VarName: o
|
||||||
; OBJ: }
|
; OBJ: }
|
||||||
; OBJ: DefRangeRegisterRelSym {
|
; OBJ: DefRangeRegisterRelIndirSym {
|
||||||
; OBJ: BaseRegister: RCX (0x14A)
|
; OBJ: BaseRegister: RCX (0x14A)
|
||||||
; OBJ: HasSpilledUDTMember: No
|
; OBJ: HasSpilledUDTMember: No
|
||||||
; OBJ: OffsetInParent: 0
|
; OBJ: OffsetInParent: 0
|
||||||
; OBJ: BasePointerOffset: 0
|
; OBJ: BasePointerOffset: 0
|
||||||
|
; OBJ: OffsetInUDT: 0
|
||||||
; OBJ: LocalVariableAddrRange {
|
; OBJ: LocalVariableAddrRange {
|
||||||
; OBJ: }
|
; OBJ: }
|
||||||
; OBJ: }
|
; OBJ: }
|
||||||
|
|||||||
@ -49,41 +49,30 @@
|
|||||||
; CHECK: ElementType: int (0x74)
|
; CHECK: ElementType: int (0x74)
|
||||||
; CHECK: IndexType: unsigned long (0x22)
|
; CHECK: IndexType: unsigned long (0x22)
|
||||||
; CHECK: SizeOf: 0
|
; CHECK: SizeOf: 0
|
||||||
; CHECK: Name:
|
; CHECK: Name:
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: Pointer (0x1004) {
|
; CHECK: Array (0x1004) {
|
||||||
; CHECK: TypeLeafKind: LF_POINTER (0x1002)
|
|
||||||
; CHECK: PointeeType: 0x1003
|
|
||||||
; CHECK: PtrType: Near32 (0xA)
|
|
||||||
; CHECK: PtrMode: LValueReference (0x1)
|
|
||||||
; CHECK: IsFlat: 0
|
|
||||||
; CHECK: IsConst: 0
|
|
||||||
; CHECK: IsVolatile: 0
|
|
||||||
; CHECK: IsUnaligned: 0
|
|
||||||
; CHECK: SizeOf: 0
|
|
||||||
; CHECK: }
|
|
||||||
; CHECK: Array (0x1005) {
|
|
||||||
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
||||||
; CHECK: ElementType: char (0x70)
|
; CHECK: ElementType: char (0x70)
|
||||||
; CHECK: IndexType: unsigned long (0x22)
|
; CHECK: IndexType: unsigned long (0x22)
|
||||||
; CHECK: SizeOf: 7
|
; CHECK: SizeOf: 7
|
||||||
; CHECK: Name:
|
; CHECK: Name:
|
||||||
|
; CHECK: }
|
||||||
|
; CHECK: Array (0x1005) {
|
||||||
|
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
||||||
|
; CHECK: ElementType: 0x1004
|
||||||
|
; CHECK: IndexType: unsigned long (0x22)
|
||||||
|
; CHECK: SizeOf: 35
|
||||||
|
; CHECK: Name:
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: Array (0x1006) {
|
; CHECK: Array (0x1006) {
|
||||||
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
||||||
; CHECK: ElementType: 0x1005
|
; CHECK: ElementType: 0x1005
|
||||||
; CHECK: IndexType: unsigned long (0x22)
|
; CHECK: IndexType: unsigned long (0x22)
|
||||||
; CHECK: SizeOf: 35
|
|
||||||
; CHECK: Name:
|
|
||||||
; CHECK: }
|
|
||||||
; CHECK: Array (0x1007) {
|
|
||||||
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
|
||||||
; CHECK: ElementType: 0x1006
|
|
||||||
; CHECK: IndexType: unsigned long (0x22)
|
|
||||||
; CHECK: SizeOf: 70
|
; CHECK: SizeOf: 70
|
||||||
; CHECK: Name:
|
; CHECK: Name:
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: Struct (0x1008) {
|
; CHECK: Struct (0x1007) {
|
||||||
; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
|
; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
|
||||||
; CHECK: MemberCount: 0
|
; CHECK: MemberCount: 0
|
||||||
; CHECK: Properties [ (0x280)
|
; CHECK: Properties [ (0x280)
|
||||||
@ -97,16 +86,16 @@
|
|||||||
; CHECK: Name: incomplete_struct
|
; CHECK: Name: incomplete_struct
|
||||||
; CHECK: LinkageName: .?AUincomplete_struct@@
|
; CHECK: LinkageName: .?AUincomplete_struct@@
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: Array (0x1009) {
|
; CHECK: Array (0x1008) {
|
||||||
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
||||||
; CHECK: ElementType: incomplete_struct (0x1008)
|
; CHECK: ElementType: incomplete_struct (0x1007)
|
||||||
; CHECK: IndexType: unsigned long (0x22)
|
; CHECK: IndexType: unsigned long (0x22)
|
||||||
; CHECK: SizeOf: 12
|
; CHECK: SizeOf: 12
|
||||||
; CHECK: Name:
|
; CHECK: Name:
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: Pointer (0x100A) {
|
; CHECK: Pointer (0x1009) {
|
||||||
; CHECK: TypeLeafKind: LF_POINTER (0x1002)
|
; CHECK: TypeLeafKind: LF_POINTER (0x1002)
|
||||||
; CHECK: PointeeType: 0x1009
|
; CHECK: PointeeType: 0x1008
|
||||||
; CHECK: PtrType: Near32 (0xA)
|
; CHECK: PtrType: Near32 (0xA)
|
||||||
; CHECK: PtrMode: Pointer (0x0)
|
; CHECK: PtrMode: Pointer (0x0)
|
||||||
; CHECK: IsFlat: 0
|
; CHECK: IsFlat: 0
|
||||||
@ -115,7 +104,7 @@
|
|||||||
; CHECK: IsUnaligned: 0
|
; CHECK: IsUnaligned: 0
|
||||||
; CHECK: SizeOf: 4
|
; CHECK: SizeOf: 4
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: FieldList (0x100B) {
|
; CHECK: FieldList (0x100A) {
|
||||||
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
|
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
|
||||||
; CHECK: DataMember {
|
; CHECK: DataMember {
|
||||||
; CHECK: TypeLeafKind: LF_MEMBER (0x150D)
|
; CHECK: TypeLeafKind: LF_MEMBER (0x150D)
|
||||||
@ -125,31 +114,31 @@
|
|||||||
; CHECK: Name: s1
|
; CHECK: Name: s1
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: Struct (0x100C) {
|
; CHECK: Struct (0x100B) {
|
||||||
; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
|
; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
|
||||||
; CHECK: MemberCount: 1
|
; CHECK: MemberCount: 1
|
||||||
; CHECK: Properties [ (0x200)
|
; CHECK: Properties [ (0x200)
|
||||||
; CHECK: HasUniqueName (0x200)
|
; CHECK: HasUniqueName (0x200)
|
||||||
; CHECK: ]
|
; CHECK: ]
|
||||||
; CHECK: FieldList: <field list> (0x100B)
|
; CHECK: FieldList: <field list> (0x100A)
|
||||||
; CHECK: DerivedFrom: 0x0
|
; CHECK: DerivedFrom: 0x0
|
||||||
; CHECK: VShape: 0x0
|
; CHECK: VShape: 0x0
|
||||||
; CHECK: SizeOf: 4
|
; CHECK: SizeOf: 4
|
||||||
; CHECK: Name: incomplete_struct
|
; CHECK: Name: incomplete_struct
|
||||||
; CHECK: LinkageName: .?AUincomplete_struct@@
|
; CHECK: LinkageName: .?AUincomplete_struct@@
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: StringId (0x100D) {
|
; CHECK: StringId (0x100C) {
|
||||||
; CHECK: TypeLeafKind: LF_STRING_ID (0x1605)
|
; CHECK: TypeLeafKind: LF_STRING_ID (0x1605)
|
||||||
; CHECK: Id: 0x0
|
; CHECK: Id: 0x0
|
||||||
; CHECK: StringData: /t.cpp
|
; CHECK: StringData: /t.cpp
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: UdtSourceLine (0x100E) {
|
; CHECK: UdtSourceLine (0x100D) {
|
||||||
; CHECK: TypeLeafKind: LF_UDT_SRC_LINE (0x1606)
|
; CHECK: TypeLeafKind: LF_UDT_SRC_LINE (0x1606)
|
||||||
; CHECK: UDT: incomplete_struct (0x100C)
|
; CHECK: UDT: incomplete_struct (0x100B)
|
||||||
; CHECK: SourceFile: /t.cpp (0x100D)
|
; CHECK: SourceFile: /t.cpp (0x100C)
|
||||||
; CHECK: LineNumber: 4
|
; CHECK: LineNumber: 4
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: Modifier (0x100F) {
|
; CHECK: Modifier (0x100E) {
|
||||||
; CHECK: TypeLeafKind: LF_MODIFIER (0x1001)
|
; CHECK: TypeLeafKind: LF_MODIFIER (0x1001)
|
||||||
; CHECK: ModifiedType: int (0x74)
|
; CHECK: ModifiedType: int (0x74)
|
||||||
; CHECK: Modifiers [ (0x3)
|
; CHECK: Modifiers [ (0x3)
|
||||||
@ -157,12 +146,12 @@
|
|||||||
; CHECK: Volatile (0x2)
|
; CHECK: Volatile (0x2)
|
||||||
; CHECK: ]
|
; CHECK: ]
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: Array (0x1010) {
|
; CHECK: Array (0x100F) {
|
||||||
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
||||||
; CHECK: ElementType: const volatile int (0x100F)
|
; CHECK: ElementType: const volatile int (0x100E)
|
||||||
; CHECK: IndexType: unsigned long (0x22)
|
; CHECK: IndexType: unsigned long (0x22)
|
||||||
; CHECK: SizeOf: 16
|
; CHECK: SizeOf: 16
|
||||||
; CHECK: Name:
|
; CHECK: Name:
|
||||||
; CHECK: }
|
; CHECK: }
|
||||||
; CHECK: ]
|
; CHECK: ]
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user