[llvm] [SPIRV] Emit NonSemantic DebugValue (PR #224158)
Diego Novillo via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 22 07:00:00 PDT 2026
================
@@ -259,6 +260,100 @@ unsigned SPIRVNonSemanticDebugHandler::toNSDISrcLang(unsigned DwarfSrcLang) {
}
}
+// Whether \p BT is a SPIR-V OpTypeBool.
+static bool isBooleanType(const DIBasicType *BT) {
+ return BT->getEncoding() == dwarf::DW_ATE_boolean;
+}
+
+// \p Value truncated to the width of \p BT, or 0 or 1 for a boolean.
+static uint64_t constantBits(uint64_t Value, const DIBasicType *BT) {
+ // A boolean is one of two values and a DIBasicType may give it no size, so
+ // masking to its width would turn every true into a false.
+ if (isBooleanType(BT))
+ return Value != 0;
+ unsigned Width = BT->getSizeInBits();
+ return Width >= 64 ? Value : Value & ((uint64_t(1) << Width) - 1);
+}
+
+// \p Value truncated to the width of \p BT. APInt::getZExtValue() asserts
+// above 64 bits, so the truncation comes first.
+static uint64_t constantBits(const APInt &Value, const DIBasicType *BT) {
+ unsigned Width = isBooleanType(BT) ? 1 : BT->getSizeInBits();
+ return constantBits(Value.getActiveBits() > 64
+ ? Value.trunc(std::min(Width, 64u)).getZExtValue()
+ : Value.getZExtValue(),
+ BT);
+}
+
+// \p CI as a 64-bit value, truncated to the width of \p BT. A one-bit constant
+// is zero extended, widths 2 through 64 are sign extended, and anything wider
+// is truncated.
+static uint64_t constantBits(const ConstantInt *CI, const DIBasicType *BT) {
+ const APInt &Value = CI->getValue();
+ if (Value.getBitWidth() > 64)
+ return constantBits(Value, BT);
+ if (Value.getBitWidth() == 1)
+ return constantBits(Value.getZExtValue(), BT);
+ return constantBits(static_cast<uint64_t>(Value.getSExtValue()), BT);
+}
+
+// The DIBasicType that \p Ty resolves to through any typedefs, or null.
+//
+// This accepts: a boolean of any size, and a 16, 32 or 64-bit integer or float.
+// Anything else gives null, including a type reached through a cv-qualifier.
+static const DIBasicType *stripToScalarType(const DIType *Ty) {
+ // Only a typedef is looked through. A cv-qualified type is not emitted as a
+ // DebugType, so emitDebugLocalVariable() cannot name it and the variable
+ // gets no DebugLocalVariable.
+ while (const auto *DT = dyn_cast_or_null<DIDerivedType>(Ty)) {
+ if (DT->getTag() != dwarf::DW_TAG_typedef)
+ return nullptr;
+ Ty = DT->getBaseType();
+ }
+
+ const auto *BT = dyn_cast_or_null<DIBasicType>(Ty);
+ if (!BT)
+ return nullptr;
+
+ // OpTypeBool carries no width, so a boolean of any size is accepted.
+ if (isBooleanType(BT))
+ return BT;
+
+ unsigned Size = BT->getSizeInBits();
+ switch (BT->getEncoding()) {
+ case dwarf::DW_ATE_signed:
+ case dwarf::DW_ATE_unsigned:
+ case dwarf::DW_ATE_signed_char:
+ case dwarf::DW_ATE_unsigned_char:
+ case dwarf::DW_ATE_float:
+ return Size == 16 || Size == 32 || Size == 64 ? BT : nullptr;
----------------
dnovillo wrote:
Because those are the widths I can name without changing what the module requires. 32 needs no capability, 16 and 64 are reused only when the module already declares the type, and `OpTypeBool` carries no width so a boolean of any size is fine.
You did find a problem with the logic, though: 8 is gated exactly like 16, and the backend already emits `OpTypeInt 8 0` whenever an `i8` appears. We were dropping `char` assignments in that case. Added, with a test.
https://github.com/llvm/llvm-project/pull/224158
More information about the llvm-commits
mailing list