diff options
author | Juan Manuel MARTINEZ CAAMAÑO <juamarti@amd.com> | 2023-03-28 10:04:53 +0200 |
---|---|---|
committer | Juan Manuel MARTINEZ CAAMAÑO <juamarti@amd.com> | 2023-03-28 10:07:32 +0200 |
commit | 488185cca3871a0ef2ec3b9b4c642dc6db6eeea5 (patch) | |
tree | d57b1fb16732a49f2f24c7cd3ff989e28db94f91 /clang/lib/CodeGen/CGDebugInfo.cpp | |
parent | 0608541aa4b5932c092251b846e7b87576e4f2d4 (diff) | |
download | llvm-488185cca3871a0ef2ec3b9b4c642dc6db6eeea5.zip llvm-488185cca3871a0ef2ec3b9b4c642dc6db6eeea5.tar.gz llvm-488185cca3871a0ef2ec3b9b4c642dc6db6eeea5.tar.bz2 |
[Clang][DebugInfo][AMDGPU] Emit zero size bitfields in the debug info to delimit bitfields in different allocation units.
Consider the following sturctures when targetting:
struct foo {
int space[4];
char a : 8;
char b : 8;
char x : 8;
char y : 8;
};
struct bar {
int space[4];
char a : 8;
char b : 8;
char : 0;
char x : 8;
char y : 8;
};
Even if both structs have the same layout in memory, they are handled
differenlty by the AMDGPU ABI.
With the following code:
// clang --target=amdgcn-amd-amdhsa -g -O1 example.c -S
char use_foo(struct foo f) { return f.y; }
char use_bar(struct bar b) { return b.y; }
For use_foo, the 'y' field is passed in v4
; v_ashrrev_i32_e32 v0, 24, v4
; s_setpc_b64 s[30:31]
For use_bar, the 'y' field is passed in v5
; v_bfe_i32 v0, v5, 8, 8
; s_setpc_b64 s[30:31]
To make this distinction, we record a single 0-size bitfield for every member that is preceded
by it.
Reviewed By: probinson
Differential Revision: https://reviews.llvm.org/D144870
Diffstat (limited to 'clang/lib/CodeGen/CGDebugInfo.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGDebugInfo.cpp | 85 |
1 files changed, 81 insertions, 4 deletions
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 0b4c24a..a5d2cf9 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -18,6 +18,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" +#include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclFriend.h" @@ -1483,9 +1484,9 @@ llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty, return F; } -llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl, - llvm::DIScope *RecordTy, - const RecordDecl *RD) { +llvm::DIDerivedType * +CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl, + llvm::DIScope *RecordTy, const RecordDecl *RD) { StringRef Name = BitFieldDecl->getName(); QualType Ty = BitFieldDecl->getType(); SourceLocation Loc = BitFieldDecl->getLocation(); @@ -1516,6 +1517,78 @@ llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl, Flags, DebugType, Annotations); } +llvm::DIDerivedType *CGDebugInfo::createBitFieldSeparatorIfNeeded( + const FieldDecl *BitFieldDecl, const llvm::DIDerivedType *BitFieldDI, + llvm::ArrayRef<llvm::Metadata *> PreviousFieldsDI, const RecordDecl *RD) { + + if (!CGM.getTargetCodeGenInfo().shouldEmitDWARFBitFieldSeparators()) + return nullptr; + + /* + Add a *single* zero-bitfield separator between two non-zero bitfields + separated by one or more zero-bitfields. This is used to distinguish between + structures such the ones below, where the memory layout is the same, but how + the ABI assigns fields to registers differs. + + struct foo { + int space[4]; + char a : 8; // on amdgpu, passed on v4 + char b : 8; + char x : 8; + char y : 8; + }; + struct bar { + int space[4]; + char a : 8; // on amdgpu, passed on v4 + char b : 8; + char : 0; + char x : 8; // passed on v5 + char y : 8; + }; + */ + if (PreviousFieldsDI.empty()) + return nullptr; + + // If we already emitted metadata for a 0-length bitfield, nothing to do here. + auto *PreviousMDEntry = + PreviousFieldsDI.empty() ? nullptr : PreviousFieldsDI.back(); + auto *PreviousMDField = + dyn_cast_or_null<llvm::DIDerivedType>(PreviousMDEntry); + if (!PreviousMDField || !PreviousMDField->isBitField() || + PreviousMDField->getSizeInBits() == 0) + return nullptr; + + auto PreviousBitfield = RD->field_begin(); + std::advance(PreviousBitfield, BitFieldDecl->getFieldIndex() - 1); + + assert(PreviousBitfield->isBitField()); + + ASTContext &Context = CGM.getContext(); + if (!PreviousBitfield->isZeroLengthBitField(Context)) + return nullptr; + + QualType Ty = PreviousBitfield->getType(); + SourceLocation Loc = PreviousBitfield->getLocation(); + llvm::DIFile *VUnit = getOrCreateFile(Loc); + llvm::DIType *DebugType = getOrCreateType(Ty, VUnit); + llvm::DIScope *RecordTy = BitFieldDI->getScope(); + + llvm::DIFile *File = getOrCreateFile(Loc); + unsigned Line = getLineNumber(Loc); + + uint64_t StorageOffsetInBits = + cast<llvm::ConstantInt>(BitFieldDI->getStorageOffsetInBits()) + ->getZExtValue(); + + llvm::DINode::DIFlags Flags = + getAccessFlag(PreviousBitfield->getAccess(), RD); + llvm::DINodeArray Annotations = + CollectBTFDeclTagAnnotations(*PreviousBitfield); + return DBuilder.createBitFieldMemberType( + RecordTy, "", File, Line, 0, StorageOffsetInBits, StorageOffsetInBits, + Flags, DebugType, Annotations); +} + llvm::DIType *CGDebugInfo::createFieldType( StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits, uint32_t AlignInBits, llvm::DIFile *tunit, @@ -1624,7 +1697,11 @@ void CGDebugInfo::CollectRecordNormalField( llvm::DIType *FieldType; if (field->isBitField()) { - FieldType = createBitFieldType(field, RecordTy, RD); + llvm::DIDerivedType *BitFieldType; + FieldType = BitFieldType = createBitFieldType(field, RecordTy, RD); + if (llvm::DIType *Separator = + createBitFieldSeparatorIfNeeded(field, BitFieldType, elements, RD)) + elements.push_back(Separator); } else { auto Align = getDeclAlignIfRequired(field, CGM.getContext()); llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(field); |