Skip to content

Commit e04ba39

Browse files
committed
Make our DIFlags match LLVMDIFlags in the LLVM-C API
1 parent a42d5ec commit e04ba39

File tree

2 files changed

+96
-117
lines changed

2 files changed

+96
-117
lines changed

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -741,8 +741,11 @@ pub mod debuginfo {
741741
pub type DIEnumerator = DIDescriptor;
742742
pub type DITemplateTypeParameter = DIDescriptor;
743743

744-
// These values **must** match with LLVMRustDIFlags!!
745744
bitflags! {
745+
/// Must match the layout of `LLVMDIFlags` in the LLVM-C API.
746+
///
747+
/// Each value declared here must also be covered by the static
748+
/// assertions in `RustWrapper.cpp` used by `fromRust(LLVMDIFlags)`.
746749
#[repr(transparent)]
747750
#[derive(Clone, Copy, Default)]
748751
pub struct DIFlags: u32 {
@@ -752,7 +755,7 @@ pub mod debuginfo {
752755
const FlagPublic = 3;
753756
const FlagFwdDecl = (1 << 2);
754757
const FlagAppleBlock = (1 << 3);
755-
const FlagBlockByrefStruct = (1 << 4);
758+
const FlagReservedBit4 = (1 << 4);
756759
const FlagVirtual = (1 << 5);
757760
const FlagArtificial = (1 << 6);
758761
const FlagExplicit = (1 << 7);
@@ -763,10 +766,21 @@ pub mod debuginfo {
763766
const FlagStaticMember = (1 << 12);
764767
const FlagLValueReference = (1 << 13);
765768
const FlagRValueReference = (1 << 14);
766-
const FlagExternalTypeRef = (1 << 15);
769+
const FlagReserved = (1 << 15);
770+
const FlagSingleInheritance = (1 << 16);
771+
const FlagMultipleInheritance = (2 << 16);
772+
const FlagVirtualInheritance = (3 << 16);
767773
const FlagIntroducedVirtual = (1 << 18);
768774
const FlagBitField = (1 << 19);
769775
const FlagNoReturn = (1 << 20);
776+
// The bit at (1 << 21) is unused, but was `LLVMDIFlagMainSubprogram`.
777+
const FlagTypePassByValue = (1 << 22);
778+
const FlagTypePassByReference = (1 << 23);
779+
const FlagEnumClass = (1 << 24);
780+
const FlagThunk = (1 << 25);
781+
const FlagNonTrivial = (1 << 26);
782+
const FlagBigEndian = (1 << 27);
783+
const FlagLittleEndian = (1 << 28);
770784
}
771785
}
772786

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

Lines changed: 79 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "llvm-c/Analysis.h"
44
#include "llvm-c/Core.h"
5+
#include "llvm-c/DebugInfo.h"
56
#include "llvm/ADT/ArrayRef.h"
67
#include "llvm/ADT/SmallVector.h"
78
#include "llvm/ADT/Statistic.h"
@@ -676,120 +677,84 @@ template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) {
676677
#define DIArray DINodeArray
677678
#define unwrapDI unwrapDIPtr
678679

679-
// These values **must** match debuginfo::DIFlags! They also *happen*
680-
// to match LLVM, but that isn't required as we do giant sets of
681-
// matching below. The value shouldn't be directly passed to LLVM.
682-
enum class LLVMRustDIFlags : uint32_t {
683-
FlagZero = 0,
684-
FlagPrivate = 1,
685-
FlagProtected = 2,
686-
FlagPublic = 3,
687-
FlagFwdDecl = (1 << 2),
688-
FlagAppleBlock = (1 << 3),
689-
FlagBlockByrefStruct = (1 << 4),
690-
FlagVirtual = (1 << 5),
691-
FlagArtificial = (1 << 6),
692-
FlagExplicit = (1 << 7),
693-
FlagPrototyped = (1 << 8),
694-
FlagObjcClassComplete = (1 << 9),
695-
FlagObjectPointer = (1 << 10),
696-
FlagVector = (1 << 11),
697-
FlagStaticMember = (1 << 12),
698-
FlagLValueReference = (1 << 13),
699-
FlagRValueReference = (1 << 14),
700-
FlagExternalTypeRef = (1 << 15),
701-
FlagIntroducedVirtual = (1 << 18),
702-
FlagBitField = (1 << 19),
703-
FlagNoReturn = (1 << 20),
704-
// Do not add values that are not supported by the minimum LLVM
705-
// version we support! see llvm/include/llvm/IR/DebugInfoFlags.def
706-
};
707-
708-
inline LLVMRustDIFlags operator&(LLVMRustDIFlags A, LLVMRustDIFlags B) {
709-
return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) &
710-
static_cast<uint32_t>(B));
711-
}
712-
713-
inline LLVMRustDIFlags operator|(LLVMRustDIFlags A, LLVMRustDIFlags B) {
714-
return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) |
715-
static_cast<uint32_t>(B));
716-
}
717-
718-
inline LLVMRustDIFlags &operator|=(LLVMRustDIFlags &A, LLVMRustDIFlags B) {
719-
return A = A | B;
720-
}
721-
722-
inline bool isSet(LLVMRustDIFlags F) { return F != LLVMRustDIFlags::FlagZero; }
723-
724-
inline LLVMRustDIFlags visibility(LLVMRustDIFlags F) {
725-
return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(F) & 0x3);
726-
}
727-
728-
static DINode::DIFlags fromRust(LLVMRustDIFlags Flags) {
729-
DINode::DIFlags Result = DINode::DIFlags::FlagZero;
730-
731-
switch (visibility(Flags)) {
732-
case LLVMRustDIFlags::FlagPrivate:
733-
Result |= DINode::DIFlags::FlagPrivate;
734-
break;
735-
case LLVMRustDIFlags::FlagProtected:
736-
Result |= DINode::DIFlags::FlagProtected;
737-
break;
738-
case LLVMRustDIFlags::FlagPublic:
739-
Result |= DINode::DIFlags::FlagPublic;
740-
break;
741-
default:
742-
// The rest are handled below
743-
break;
744-
}
745-
746-
if (isSet(Flags & LLVMRustDIFlags::FlagFwdDecl)) {
747-
Result |= DINode::DIFlags::FlagFwdDecl;
748-
}
749-
if (isSet(Flags & LLVMRustDIFlags::FlagAppleBlock)) {
750-
Result |= DINode::DIFlags::FlagAppleBlock;
751-
}
752-
if (isSet(Flags & LLVMRustDIFlags::FlagVirtual)) {
753-
Result |= DINode::DIFlags::FlagVirtual;
754-
}
755-
if (isSet(Flags & LLVMRustDIFlags::FlagArtificial)) {
756-
Result |= DINode::DIFlags::FlagArtificial;
757-
}
758-
if (isSet(Flags & LLVMRustDIFlags::FlagExplicit)) {
759-
Result |= DINode::DIFlags::FlagExplicit;
760-
}
761-
if (isSet(Flags & LLVMRustDIFlags::FlagPrototyped)) {
762-
Result |= DINode::DIFlags::FlagPrototyped;
763-
}
764-
if (isSet(Flags & LLVMRustDIFlags::FlagObjcClassComplete)) {
765-
Result |= DINode::DIFlags::FlagObjcClassComplete;
766-
}
767-
if (isSet(Flags & LLVMRustDIFlags::FlagObjectPointer)) {
768-
Result |= DINode::DIFlags::FlagObjectPointer;
769-
}
770-
if (isSet(Flags & LLVMRustDIFlags::FlagVector)) {
771-
Result |= DINode::DIFlags::FlagVector;
772-
}
773-
if (isSet(Flags & LLVMRustDIFlags::FlagStaticMember)) {
774-
Result |= DINode::DIFlags::FlagStaticMember;
775-
}
776-
if (isSet(Flags & LLVMRustDIFlags::FlagLValueReference)) {
777-
Result |= DINode::DIFlags::FlagLValueReference;
778-
}
779-
if (isSet(Flags & LLVMRustDIFlags::FlagRValueReference)) {
780-
Result |= DINode::DIFlags::FlagRValueReference;
781-
}
782-
if (isSet(Flags & LLVMRustDIFlags::FlagIntroducedVirtual)) {
783-
Result |= DINode::DIFlags::FlagIntroducedVirtual;
784-
}
785-
if (isSet(Flags & LLVMRustDIFlags::FlagBitField)) {
786-
Result |= DINode::DIFlags::FlagBitField;
787-
}
788-
if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) {
789-
Result |= DINode::DIFlags::FlagNoReturn;
790-
}
791-
792-
return Result;
680+
// FIXME(Zalathar): This is a temporary typedef to avoid churning dozens of
681+
// bindings that are going to be deleted and replaced with their LLVM-C
682+
// equivalents, as part of #134009. After that happens, the remaining bindings
683+
// can be adjusted to use `LLVMDIFlags` instead of relying on this typedef.
684+
typedef LLVMDIFlags LLVMRustDIFlags;
685+
686+
// Statically assert that `LLVMDIFlags` (C) and `DIFlags` (C++) have the same
687+
// layout, at least for the flags we know about. This isn't guaranteed, but is
688+
// likely to remain true, and as long as it is true it makes conversions easy.
689+
namespace {
690+
using DIFlags = DINode::DIFlags;
691+
constexpr bool eq(LLVMDIFlags CFlags, unsigned Value, DIFlags CxxFlags) {
692+
return (CFlags == Value) && (CxxFlags == Value);
693+
}
694+
695+
static_assert(eq(LLVMDIFlagZero, 0, DIFlags::FlagZero));
696+
static_assert(eq(LLVMDIFlagPrivate, 1, DIFlags::FlagPrivate));
697+
static_assert(eq(LLVMDIFlagProtected, 2, DIFlags::FlagProtected));
698+
static_assert(eq(LLVMDIFlagPublic, 3, DIFlags::FlagPublic));
699+
static_assert(eq(LLVMDIFlagFwdDecl, 1 << 2, DIFlags::FlagFwdDecl));
700+
static_assert(eq(LLVMDIFlagAppleBlock, 1 << 3, DIFlags::FlagAppleBlock));
701+
static_assert(eq(LLVMDIFlagReservedBit4, 1 << 4, DIFlags::FlagReservedBit4));
702+
static_assert(eq(LLVMDIFlagVirtual, 1 << 5, DIFlags::FlagVirtual));
703+
static_assert(eq(LLVMDIFlagArtificial, 1 << 6, DIFlags::FlagArtificial));
704+
static_assert(eq(LLVMDIFlagExplicit, 1 << 7, DIFlags::FlagExplicit));
705+
static_assert(eq(LLVMDIFlagPrototyped, 1 << 8, DIFlags::FlagPrototyped));
706+
static_assert(eq(LLVMDIFlagObjcClassComplete, 1 << 9,
707+
DIFlags::FlagObjcClassComplete));
708+
static_assert(eq(LLVMDIFlagObjectPointer, 1 << 10, DIFlags::FlagObjectPointer));
709+
static_assert(eq(LLVMDIFlagVector, 1 << 11, DIFlags::FlagVector));
710+
static_assert(eq(LLVMDIFlagStaticMember, 1 << 12, DIFlags::FlagStaticMember));
711+
static_assert(eq(LLVMDIFlagLValueReference, 1 << 13,
712+
DIFlags::FlagLValueReference));
713+
static_assert(eq(LLVMDIFlagRValueReference, 1 << 14,
714+
DIFlags::FlagRValueReference));
715+
// This flag has been recycled, but the value in the C API hasn't been renamed.
716+
static_assert(eq(LLVMDIFlagReserved, 1 << 15, DIFlags::FlagExportSymbols));
717+
static_assert(eq(LLVMDIFlagSingleInheritance, 1 << 16,
718+
DIFlags::FlagSingleInheritance));
719+
static_assert(eq(LLVMDIFlagMultipleInheritance, 2 << 16,
720+
DIFlags::FlagMultipleInheritance));
721+
static_assert(eq(LLVMDIFlagVirtualInheritance, 3 << 16,
722+
DIFlags::FlagVirtualInheritance));
723+
static_assert(eq(LLVMDIFlagIntroducedVirtual, 1 << 18,
724+
DIFlags::FlagIntroducedVirtual));
725+
static_assert(eq(LLVMDIFlagBitField, 1 << 19, DIFlags::FlagBitField));
726+
static_assert(eq(LLVMDIFlagNoReturn, 1 << 20, DIFlags::FlagNoReturn));
727+
// The bit at (1 << 21) is unused, but was `LLVMDIFlagMainSubprogram`.
728+
static_assert(eq(LLVMDIFlagTypePassByValue, 1 << 22,
729+
DIFlags::FlagTypePassByValue));
730+
static_assert(eq(LLVMDIFlagTypePassByReference, 1 << 23,
731+
DIFlags::FlagTypePassByReference));
732+
static_assert(eq(LLVMDIFlagEnumClass, 1 << 24, DIFlags::FlagEnumClass));
733+
static_assert(eq(LLVMDIFlagThunk, 1 << 25, DIFlags::FlagThunk));
734+
static_assert(eq(LLVMDIFlagNonTrivial, 1 << 26, DIFlags::FlagNonTrivial));
735+
static_assert(eq(LLVMDIFlagBigEndian, 1 << 27, DIFlags::FlagBigEndian));
736+
static_assert(eq(LLVMDIFlagLittleEndian, 1 << 28, DIFlags::FlagLittleEndian));
737+
static_assert(eq(LLVMDIFlagIndirectVirtualBase, (1 << 2) | (1 << 5),
738+
DIFlags::FlagIndirectVirtualBase));
739+
} // namespace
740+
741+
// There are two potential ways to convert `LLVMDIFlags` to `DIFlags`:
742+
// - Check and copy every individual bit/subvalue from input to output.
743+
// - Statically assert that both have the same layout, and cast.
744+
// As long as the static assertions succeed, a cast is easier and faster.
745+
// In the (hopefully) unlikely event that the assertions do fail someday, and
746+
// LLVM doesn't expose its own conversion function, we'll have to switch over
747+
// to copying each bit/subvalue.
748+
static DINode::DIFlags fromRust(LLVMDIFlags Flags) {
749+
// Check that all set bits are covered by the static assertions above.
750+
const unsigned UNKNOWN_BITS = (1 << 31) | (1 << 30) | (1 << 29) | (1 << 21);
751+
if (Flags & UNKNOWN_BITS) {
752+
report_fatal_error("bad LLVMDIFlags");
753+
}
754+
755+
// As long as the static assertions are satisfied and no unknown bits are
756+
// present, we can convert from `LLVMDIFlags` to `DIFlags` with a cast.
757+
return static_cast<DINode::DIFlags>(Flags);
793758
}
794759

795760
// These values **must** match debuginfo::DISPFlags! They also *happen*

0 commit comments

Comments
 (0)