Skip to content

Commit e0d74c0

Browse files
authored
Rollup merge of #135156 - Zalathar:debuginfo-flags, r=cuviper
Make our `DIFlags` match `LLVMDIFlags` in the LLVM-C API In order to be able to use a mixture of LLVM-C and C++ bindings for debuginfo, our Rust-side `DIFlags` needs to have the same layout as LLVM-C's `LLVMDIFlags`, and we also need to be able to convert it to the `DIFlags` accepted by LLVM's C++ API. Internally, LLVM converts between the two types with a simple cast. We can't necessarily rely on that always being true, and LLVM doesn't expose a conversion function, so we have two potential options: - Convert each bit/subvalue individually - Statically assert that doing a cast is actually fine As long as both types do remain the same under the hood (which seems likely), the static-assert-and-cast approach is easier and faster. If the static assertions ever start failing against some future version of LLVM, we'll have to switch over to the convert-each-subvalue approach, which is a bit more error-prone. --- Extracted from #134009, though this PR ended up choosing the static-assert-and-cast approach over the convert-each-subvalue approach.
2 parents df01040 + d10bdaf commit e0d74c0

File tree

3 files changed

+87
-117
lines changed

3 files changed

+87
-117
lines changed

compiler/rustc_codegen_llvm/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ test = false
99
[dependencies]
1010
# tidy-alphabetical-start
1111
bitflags = "2.4.1"
12+
# To avoid duplicate dependencies, this should match the version of gimli used
13+
# by `rustc_codegen_ssa` via its `thorin-dwp` dependency.
1214
gimli = "0.30"
1315
itertools = "0.12"
1416
libc = "0.2"

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+17-3
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

+68-114
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,73 @@ 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+
#define ASSERT_DIFLAG_VALUE(FLAG, VALUE) \
690+
static_assert((LLVMDI##FLAG == (VALUE)) && (DINode::DIFlags::FLAG == (VALUE)))
691+
ASSERT_DIFLAG_VALUE(FlagZero, 0);
692+
ASSERT_DIFLAG_VALUE(FlagPrivate, 1);
693+
ASSERT_DIFLAG_VALUE(FlagProtected, 2);
694+
ASSERT_DIFLAG_VALUE(FlagPublic, 3);
695+
// Bit (1 << 1) is part of the private/protected/public values above.
696+
ASSERT_DIFLAG_VALUE(FlagFwdDecl, 1 << 2);
697+
ASSERT_DIFLAG_VALUE(FlagAppleBlock, 1 << 3);
698+
ASSERT_DIFLAG_VALUE(FlagReservedBit4, 1 << 4);
699+
ASSERT_DIFLAG_VALUE(FlagVirtual, 1 << 5);
700+
ASSERT_DIFLAG_VALUE(FlagArtificial, 1 << 6);
701+
ASSERT_DIFLAG_VALUE(FlagExplicit, 1 << 7);
702+
ASSERT_DIFLAG_VALUE(FlagPrototyped, 1 << 8);
703+
ASSERT_DIFLAG_VALUE(FlagObjcClassComplete, 1 << 9);
704+
ASSERT_DIFLAG_VALUE(FlagObjectPointer, 1 << 10);
705+
ASSERT_DIFLAG_VALUE(FlagVector, 1 << 11);
706+
ASSERT_DIFLAG_VALUE(FlagStaticMember, 1 << 12);
707+
ASSERT_DIFLAG_VALUE(FlagLValueReference, 1 << 13);
708+
ASSERT_DIFLAG_VALUE(FlagRValueReference, 1 << 14);
709+
// Bit (1 << 15) has been recycled, but the C API value hasn't been renamed.
710+
static_assert((LLVMDIFlagReserved == (1 << 15)) &&
711+
(DINode::DIFlags::FlagExportSymbols == (1 << 15)));
712+
ASSERT_DIFLAG_VALUE(FlagSingleInheritance, 1 << 16);
713+
ASSERT_DIFLAG_VALUE(FlagMultipleInheritance, 2 << 16);
714+
ASSERT_DIFLAG_VALUE(FlagVirtualInheritance, 3 << 16);
715+
// Bit (1 << 17) is part of the inheritance values above.
716+
ASSERT_DIFLAG_VALUE(FlagIntroducedVirtual, 1 << 18);
717+
ASSERT_DIFLAG_VALUE(FlagBitField, 1 << 19);
718+
ASSERT_DIFLAG_VALUE(FlagNoReturn, 1 << 20);
719+
// Bit (1 << 21) is unused, but was `LLVMDIFlagMainSubprogram`.
720+
ASSERT_DIFLAG_VALUE(FlagTypePassByValue, 1 << 22);
721+
ASSERT_DIFLAG_VALUE(FlagTypePassByReference, 1 << 23);
722+
ASSERT_DIFLAG_VALUE(FlagEnumClass, 1 << 24);
723+
ASSERT_DIFLAG_VALUE(FlagThunk, 1 << 25);
724+
ASSERT_DIFLAG_VALUE(FlagNonTrivial, 1 << 26);
725+
ASSERT_DIFLAG_VALUE(FlagBigEndian, 1 << 27);
726+
ASSERT_DIFLAG_VALUE(FlagLittleEndian, 1 << 28);
727+
ASSERT_DIFLAG_VALUE(FlagIndirectVirtualBase, (1 << 2) | (1 << 5));
728+
#undef ASSERT_DIFLAG_VALUE
729+
730+
// There are two potential ways to convert `LLVMDIFlags` to `DIFlags`:
731+
// - Check and copy every individual bit/subvalue from input to output.
732+
// - Statically assert that both have the same layout, and cast.
733+
// As long as the static assertions succeed, a cast is easier and faster.
734+
// In the (hopefully) unlikely event that the assertions do fail someday, and
735+
// LLVM doesn't expose its own conversion function, we'll have to switch over
736+
// to copying each bit/subvalue.
737+
static DINode::DIFlags fromRust(LLVMDIFlags Flags) {
738+
// Check that all set bits are covered by the static assertions above.
739+
const unsigned UNKNOWN_BITS = (1 << 31) | (1 << 30) | (1 << 29) | (1 << 21);
740+
if (Flags & UNKNOWN_BITS) {
741+
report_fatal_error("bad LLVMDIFlags");
742+
}
743+
744+
// As long as the static assertions are satisfied and no unknown bits are
745+
// present, we can convert from `LLVMDIFlags` to `DIFlags` with a cast.
746+
return static_cast<DINode::DIFlags>(Flags);
793747
}
794748

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

0 commit comments

Comments
 (0)