Skip to content

Conversation

laxmansole
Copy link
Contributor

@laxmansole laxmansole commented Jul 29, 2025

Backends like NVPTX use -1 to indicate true and 0 to indicate false for boolean values. Machine instruction #DBG_VALUE also uses -1 to indicate a true boolean constant.

However, during the DWARF generation, booleans are treated as unsigned variables, and the DWARF attributes DW_AT_const_value(0xffffffffffffffff) is emitted for the True value.

This leads to the debugger printing 255 instead of "true" for boolean variables.

This change emits the attribute DW_AT_const_value(1) instead of DW_AT_const_value(0xffffffffffffffff).

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot
Copy link
Member

llvmbot commented Jul 29, 2025

@llvm/pr-subscribers-backend-nvptx

Author: Laxman (laxmansole)

Changes

For boolean values, -1 is assigned to indicate True and 0 to indicate False.
However, during the DWARF generation, booleans are treated as unsigned variables, and the debug_loc expression, like DW_OP_lit0; DW_OP_not or the attribute DW_AT_const_value(0xffffffffffffffff) is emitted for the True value.

This leads to the debugger printing 255 instead of "true" for boolean variables.

This change emits DW_OP_lit1 instead of DW_OP_lot0;DW_OP_not and the attribute DW_AT_const_value(1) instead of DW_AT_const_value(0xffffffffffffffff).


Full diff: https://github.com/llvm/llvm-project/pull/151225.diff

6 Files Affected:

  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp (+32-2)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (+4-2)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp (+9)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h (+3)
  • (added) llvm/test/DebugInfo/NVPTX/debug-bool-const-location.ll (+51)
  • (added) llvm/test/DebugInfo/NVPTX/debug-bool-const-value.ll (+37)
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index 5577a7d298177..f1be286c0a746 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -247,6 +247,13 @@ void DwarfCompileUnit::addLocationAttribute(
   DIELoc *Loc = nullptr;
   std::optional<unsigned> NVPTXAddressSpace;
   std::unique_ptr<DIEDwarfExpression> DwarfExpr;
+
+  // Check if this variable is of boolean type
+  bool isBoolean = false;
+  if (GV && GV->getType())
+    if (auto *BasicType = dyn_cast<DIBasicType>(GV->getType()))
+      isBoolean = BasicType->getEncoding() == dwarf::DW_ATE_boolean;
+
   for (const auto &GE : GlobalExprs) {
     const GlobalVariable *Global = GE.Var;
     const DIExpression *Expr = GE.Expr;
@@ -257,11 +264,17 @@ void DwarfCompileUnit::addLocationAttribute(
     // DW_AT_const_value(X).
     if (GlobalExprs.size() == 1 && Expr && Expr->isConstant()) {
       addToAccelTable = true;
+
+      // Determine the value to use, normalizing booleans to 0 or 1
+      int64_t valueToUse = Expr->getElement(1);
+      if (isBoolean)
+        valueToUse = valueToUse ? 1 : 0;
+
       addConstantValue(
           *VariableDIE,
           DIExpression::SignedOrUnsignedConstant::UnsignedConstant ==
               *Expr->isConstant(),
-          Expr->getElement(1));
+          valueToUse);
       break;
     }
 
@@ -820,6 +833,22 @@ void DwarfCompileUnit::applyConcreteDbgVariableAttributes(
   }
   if (!DVal->isVariadic()) {
     const DbgValueLocEntry *Entry = DVal->getLocEntries().begin();
+
+    // Helper function to handle boolean constant values with type safety
+    auto addConstantValueWithBooleanNormalization =
+        [&](DIE &VariableDie, uint64_t intValue, const DIType *Type) {
+          if (auto *BasicType = dyn_cast_or_null<DIBasicType>(Type)) {
+            if (BasicType->getEncoding() == dwarf::DW_ATE_boolean) {
+              // Normalize boolean values: any non-zero becomes 1, zero stays 0
+              uint64_t normalizedBoolValue = (intValue) ? 1 : 0;
+              addConstantValue(VariableDie, normalizedBoolValue, Type);
+              return;
+            }
+          }
+          // For non-boolean types, use the original constant value
+          addConstantValue(VariableDie, intValue, Type);
+        };
+
     if (Entry->isLocation()) {
       addVariableAddress(DV, VariableDie, Entry->getLoc());
     } else if (Entry->isInt()) {
@@ -836,7 +865,8 @@ void DwarfCompileUnit::applyConcreteDbgVariableAttributes(
           addUInt(VariableDie, dwarf::DW_AT_LLVM_tag_offset,
                   dwarf::DW_FORM_data1, *DwarfExpr.TagOffset);
       } else
-        addConstantValue(VariableDie, Entry->getInt(), DV.getType());
+        addConstantValueWithBooleanNormalization(VariableDie, Entry->getInt(),
+                                                 DV.getType());
     } else if (Entry->isConstantFP()) {
       addConstantFPValue(VariableDie, Entry->getConstantFP());
     } else if (Entry->isConstantInt()) {
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 71888332a6620..6d4c9c05e3aba 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -3100,8 +3100,10 @@ void DwarfDebug::emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
                             &AP](const DbgValueLocEntry &Entry,
                                  DIExpressionCursor &Cursor) -> bool {
     if (Entry.isInt()) {
-      if (BT && (BT->getEncoding() == dwarf::DW_ATE_signed ||
-                 BT->getEncoding() == dwarf::DW_ATE_signed_char))
+      if (BT && (BT->getEncoding() == dwarf::DW_ATE_boolean))
+        DwarfExpr.addBooleanConstant(Entry.getInt());
+      else if (BT && (BT->getEncoding() == dwarf::DW_ATE_signed ||
+                      BT->getEncoding() == dwarf::DW_ATE_signed_char))
         DwarfExpr.addSignedConstant(Entry.getInt());
       else
         DwarfExpr.addUnsignedConstant(Entry.getInt());
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
index e684054ffa3e4..8a30714db2fdf 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
@@ -194,6 +194,15 @@ void DwarfExpression::addStackValue() {
     emitOp(dwarf::DW_OP_stack_value);
 }
 
+void DwarfExpression::addBooleanConstant(int64_t Value) {
+  assert(isImplicitLocation() || isUnknownLocation());
+  LocationKind = Implicit;
+  if (Value == 0)
+    emitOp(dwarf::DW_OP_lit0);
+  else
+    emitOp(dwarf::DW_OP_lit1);
+}
+
 void DwarfExpression::addSignedConstant(int64_t Value) {
   assert(isImplicitLocation() || isUnknownLocation());
   LocationKind = Implicit;
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
index 06809ab263875..700e0ec5813ee 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
@@ -229,6 +229,9 @@ class DwarfExpression {
   /// This needs to be called last to commit any pending changes.
   void finalize();
 
+  /// Emit a boolean constant.
+  void addBooleanConstant(int64_t Value);
+
   /// Emit a signed constant.
   void addSignedConstant(int64_t Value);
 
diff --git a/llvm/test/DebugInfo/NVPTX/debug-bool-const-location.ll b/llvm/test/DebugInfo/NVPTX/debug-bool-const-location.ll
new file mode 100644
index 0000000000000..f073d51e7ef99
--- /dev/null
+++ b/llvm/test/DebugInfo/NVPTX/debug-bool-const-location.ll
@@ -0,0 +1,51 @@
+; RUN: llc < %s -asm-verbose -mattr=+ptx76  -O0| FileCheck %s
+; RUN: %if ptxas %{ llc < %s -asm-verbose -mattr=+ptx76  -O0 | %ptxas-verify %}
+
+target triple = "nvptx64-nvidia-cuda"
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
+
+; CHECK: {{.*}}section {{.*}}debug_loc
+; CHECK: .b8 48{{.*}} DW_OP_lit0
+; CHECK: .b8 49{{.*}} DW_OP_lit1
+; CHECK: .b8 144{{.*}} DW_OP_regx
+
+define void @foo(i8 %"arg.arg") !dbg !5
+{
+entry:
+  %".4" = alloca i1
+  %".5" = icmp eq i8 %"arg.arg", 0
+  %arg = alloca i1
+  br i1 %".5", label %"entry.if", label %"entry.else"
+entry.if:
+  store i1 false, i1* %arg
+  call void @"llvm.dbg.value"(metadata i1 false , metadata !9, metadata !10), !dbg !6
+  br label %"entry.endif"
+entry.else:
+  store i1 true, i1* %arg
+  call void @"llvm.dbg.value"(metadata i1 true , metadata !9, metadata !10), !dbg !7
+  br label %"entry.endif"
+entry.endif:
+  %".11" = load i1, i1* %arg
+  store i1 %".11", i1* %".4", !dbg !8
+  call void @"llvm.dbg.value"(metadata i1 %".11" , metadata !9, metadata !10), !dbg !8
+  ret void, !dbg !8
+}
+
+declare void @"llvm.dbg.value"(metadata %".1", metadata %".2", metadata %".3")
+
+!llvm.dbg.cu = !{ !2 }
+!llvm.module.flags = !{ !11, !12 }
+!nvvm.annotations = !{}
+
+!1 = !DIFile(directory: "/source/dir", filename: "test.cu")
+!2 = distinct !DICompileUnit(emissionKind: FullDebug, file: !1, isOptimized: false, language: DW_LANG_C_plus_plus, runtimeVersion: 0)
+!3 = !DIBasicType(encoding: DW_ATE_boolean, name: "bool", size: 8)
+!4 = !DISubroutineType(types: !{null})
+!5 = distinct !DISubprogram(file: !1, isDefinition: true, isLocal: false, isOptimized: false, line: 5, linkageName: "foo", name: "foo", scope: !1, scopeLine: 5, type: !4, unit: !2)
+!6 = !DILocation(column: 1, line: 5, scope: !5)
+!7 = !DILocation(column: 1, line: 7, scope: !5)
+!8 = !DILocation(column: 1, line: 8, scope: !5)
+!9 = !DILocalVariable(arg: 0, file: !1, line: 5, name: "arg", scope: !5, type: !3)
+!10 = !DIExpression()
+!11 = !{ i32 2, !"Dwarf Version", i32 4 }
+!12 = !{ i32 2, !"Debug Info Version", i32 3 }
\ No newline at end of file
diff --git a/llvm/test/DebugInfo/NVPTX/debug-bool-const-value.ll b/llvm/test/DebugInfo/NVPTX/debug-bool-const-value.ll
new file mode 100644
index 0000000000000..002a7a801c746
--- /dev/null
+++ b/llvm/test/DebugInfo/NVPTX/debug-bool-const-value.ll
@@ -0,0 +1,37 @@
+; RUN: llc < %s -asm-verbose -mattr=+ptx76 | FileCheck %s
+; RUN: %if ptxas %{ llc < %s -asm-verbose -mattr=+ptx76 | %ptxas-verify %}
+
+target triple = "nvptx64-nvidia-cuda"
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
+
+; CHECK: {{.*}}section {{.*}}debug_info
+; CHECK: {{.*}}DW_TAG_variable
+; CHECK-NEXT: {{.*}} DW_AT_address_class
+; CHECK-NEXT: .b8 1{{.*}} DW_AT_const_value
+; CHECK-NEXT: {{.*}} DW_AT_name
+
+define void @test() !dbg !5
+{
+entry:
+  %arg = alloca i1
+  store i1 true, i1* %arg, !dbg !6
+  call void @"llvm.dbg.value"(metadata i1 true, metadata !7, metadata !8), !dbg !6
+  ret void, !dbg !6
+}
+
+declare void @"llvm.dbg.value"(metadata %".1", metadata %".2", metadata %".3")
+
+!llvm.dbg.cu = !{ !2 }
+!llvm.module.flags = !{ !9, !10 }
+!nvvm.annotations = !{}
+
+!1 = !DIFile(directory: "/source/dir", filename: "test.cu")
+!2 = distinct !DICompileUnit(emissionKind: FullDebug, file: !1, isOptimized: false, language: DW_LANG_C_plus_plus, runtimeVersion: 0)
+!3 = !DIBasicType(encoding: DW_ATE_boolean, name: "bool", size: 8)
+!4 = !DISubroutineType(types: !{null})
+!5 = distinct !DISubprogram(file: !1, isDefinition: true, isLocal: false, isOptimized: false, line: 5, linkageName: "test", name: "test", scope: !1, scopeLine: 5, type: !4, unit: !2)
+!6 = !DILocation(column: 1, line: 5, scope: !5)
+!7 = !DILocalVariable(arg: 0, file: !1, line: 5, name: "arg", scope: !5, type: !3)
+!8 = !DIExpression()
+!9 = !{ i32 2, !"Dwarf Version", i32 4 }
+!10 = !{ i32 2, !"Debug Info Version", i32 3 }
\ No newline at end of file

@llvmbot
Copy link
Member

llvmbot commented Jul 29, 2025

@llvm/pr-subscribers-debuginfo

Author: Laxman (laxmansole)

Changes

For boolean values, -1 is assigned to indicate True and 0 to indicate False.
However, during the DWARF generation, booleans are treated as unsigned variables, and the debug_loc expression, like DW_OP_lit0; DW_OP_not or the attribute DW_AT_const_value(0xffffffffffffffff) is emitted for the True value.

This leads to the debugger printing 255 instead of "true" for boolean variables.

This change emits DW_OP_lit1 instead of DW_OP_lot0;DW_OP_not and the attribute DW_AT_const_value(1) instead of DW_AT_const_value(0xffffffffffffffff).


Full diff: https://github.com/llvm/llvm-project/pull/151225.diff

6 Files Affected:

  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp (+32-2)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (+4-2)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp (+9)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h (+3)
  • (added) llvm/test/DebugInfo/NVPTX/debug-bool-const-location.ll (+51)
  • (added) llvm/test/DebugInfo/NVPTX/debug-bool-const-value.ll (+37)
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index 5577a7d298177..f1be286c0a746 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -247,6 +247,13 @@ void DwarfCompileUnit::addLocationAttribute(
   DIELoc *Loc = nullptr;
   std::optional<unsigned> NVPTXAddressSpace;
   std::unique_ptr<DIEDwarfExpression> DwarfExpr;
+
+  // Check if this variable is of boolean type
+  bool isBoolean = false;
+  if (GV && GV->getType())
+    if (auto *BasicType = dyn_cast<DIBasicType>(GV->getType()))
+      isBoolean = BasicType->getEncoding() == dwarf::DW_ATE_boolean;
+
   for (const auto &GE : GlobalExprs) {
     const GlobalVariable *Global = GE.Var;
     const DIExpression *Expr = GE.Expr;
@@ -257,11 +264,17 @@ void DwarfCompileUnit::addLocationAttribute(
     // DW_AT_const_value(X).
     if (GlobalExprs.size() == 1 && Expr && Expr->isConstant()) {
       addToAccelTable = true;
+
+      // Determine the value to use, normalizing booleans to 0 or 1
+      int64_t valueToUse = Expr->getElement(1);
+      if (isBoolean)
+        valueToUse = valueToUse ? 1 : 0;
+
       addConstantValue(
           *VariableDIE,
           DIExpression::SignedOrUnsignedConstant::UnsignedConstant ==
               *Expr->isConstant(),
-          Expr->getElement(1));
+          valueToUse);
       break;
     }
 
@@ -820,6 +833,22 @@ void DwarfCompileUnit::applyConcreteDbgVariableAttributes(
   }
   if (!DVal->isVariadic()) {
     const DbgValueLocEntry *Entry = DVal->getLocEntries().begin();
+
+    // Helper function to handle boolean constant values with type safety
+    auto addConstantValueWithBooleanNormalization =
+        [&](DIE &VariableDie, uint64_t intValue, const DIType *Type) {
+          if (auto *BasicType = dyn_cast_or_null<DIBasicType>(Type)) {
+            if (BasicType->getEncoding() == dwarf::DW_ATE_boolean) {
+              // Normalize boolean values: any non-zero becomes 1, zero stays 0
+              uint64_t normalizedBoolValue = (intValue) ? 1 : 0;
+              addConstantValue(VariableDie, normalizedBoolValue, Type);
+              return;
+            }
+          }
+          // For non-boolean types, use the original constant value
+          addConstantValue(VariableDie, intValue, Type);
+        };
+
     if (Entry->isLocation()) {
       addVariableAddress(DV, VariableDie, Entry->getLoc());
     } else if (Entry->isInt()) {
@@ -836,7 +865,8 @@ void DwarfCompileUnit::applyConcreteDbgVariableAttributes(
           addUInt(VariableDie, dwarf::DW_AT_LLVM_tag_offset,
                   dwarf::DW_FORM_data1, *DwarfExpr.TagOffset);
       } else
-        addConstantValue(VariableDie, Entry->getInt(), DV.getType());
+        addConstantValueWithBooleanNormalization(VariableDie, Entry->getInt(),
+                                                 DV.getType());
     } else if (Entry->isConstantFP()) {
       addConstantFPValue(VariableDie, Entry->getConstantFP());
     } else if (Entry->isConstantInt()) {
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 71888332a6620..6d4c9c05e3aba 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -3100,8 +3100,10 @@ void DwarfDebug::emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
                             &AP](const DbgValueLocEntry &Entry,
                                  DIExpressionCursor &Cursor) -> bool {
     if (Entry.isInt()) {
-      if (BT && (BT->getEncoding() == dwarf::DW_ATE_signed ||
-                 BT->getEncoding() == dwarf::DW_ATE_signed_char))
+      if (BT && (BT->getEncoding() == dwarf::DW_ATE_boolean))
+        DwarfExpr.addBooleanConstant(Entry.getInt());
+      else if (BT && (BT->getEncoding() == dwarf::DW_ATE_signed ||
+                      BT->getEncoding() == dwarf::DW_ATE_signed_char))
         DwarfExpr.addSignedConstant(Entry.getInt());
       else
         DwarfExpr.addUnsignedConstant(Entry.getInt());
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
index e684054ffa3e4..8a30714db2fdf 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
@@ -194,6 +194,15 @@ void DwarfExpression::addStackValue() {
     emitOp(dwarf::DW_OP_stack_value);
 }
 
+void DwarfExpression::addBooleanConstant(int64_t Value) {
+  assert(isImplicitLocation() || isUnknownLocation());
+  LocationKind = Implicit;
+  if (Value == 0)
+    emitOp(dwarf::DW_OP_lit0);
+  else
+    emitOp(dwarf::DW_OP_lit1);
+}
+
 void DwarfExpression::addSignedConstant(int64_t Value) {
   assert(isImplicitLocation() || isUnknownLocation());
   LocationKind = Implicit;
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
index 06809ab263875..700e0ec5813ee 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
@@ -229,6 +229,9 @@ class DwarfExpression {
   /// This needs to be called last to commit any pending changes.
   void finalize();
 
+  /// Emit a boolean constant.
+  void addBooleanConstant(int64_t Value);
+
   /// Emit a signed constant.
   void addSignedConstant(int64_t Value);
 
diff --git a/llvm/test/DebugInfo/NVPTX/debug-bool-const-location.ll b/llvm/test/DebugInfo/NVPTX/debug-bool-const-location.ll
new file mode 100644
index 0000000000000..f073d51e7ef99
--- /dev/null
+++ b/llvm/test/DebugInfo/NVPTX/debug-bool-const-location.ll
@@ -0,0 +1,51 @@
+; RUN: llc < %s -asm-verbose -mattr=+ptx76  -O0| FileCheck %s
+; RUN: %if ptxas %{ llc < %s -asm-verbose -mattr=+ptx76  -O0 | %ptxas-verify %}
+
+target triple = "nvptx64-nvidia-cuda"
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
+
+; CHECK: {{.*}}section {{.*}}debug_loc
+; CHECK: .b8 48{{.*}} DW_OP_lit0
+; CHECK: .b8 49{{.*}} DW_OP_lit1
+; CHECK: .b8 144{{.*}} DW_OP_regx
+
+define void @foo(i8 %"arg.arg") !dbg !5
+{
+entry:
+  %".4" = alloca i1
+  %".5" = icmp eq i8 %"arg.arg", 0
+  %arg = alloca i1
+  br i1 %".5", label %"entry.if", label %"entry.else"
+entry.if:
+  store i1 false, i1* %arg
+  call void @"llvm.dbg.value"(metadata i1 false , metadata !9, metadata !10), !dbg !6
+  br label %"entry.endif"
+entry.else:
+  store i1 true, i1* %arg
+  call void @"llvm.dbg.value"(metadata i1 true , metadata !9, metadata !10), !dbg !7
+  br label %"entry.endif"
+entry.endif:
+  %".11" = load i1, i1* %arg
+  store i1 %".11", i1* %".4", !dbg !8
+  call void @"llvm.dbg.value"(metadata i1 %".11" , metadata !9, metadata !10), !dbg !8
+  ret void, !dbg !8
+}
+
+declare void @"llvm.dbg.value"(metadata %".1", metadata %".2", metadata %".3")
+
+!llvm.dbg.cu = !{ !2 }
+!llvm.module.flags = !{ !11, !12 }
+!nvvm.annotations = !{}
+
+!1 = !DIFile(directory: "/source/dir", filename: "test.cu")
+!2 = distinct !DICompileUnit(emissionKind: FullDebug, file: !1, isOptimized: false, language: DW_LANG_C_plus_plus, runtimeVersion: 0)
+!3 = !DIBasicType(encoding: DW_ATE_boolean, name: "bool", size: 8)
+!4 = !DISubroutineType(types: !{null})
+!5 = distinct !DISubprogram(file: !1, isDefinition: true, isLocal: false, isOptimized: false, line: 5, linkageName: "foo", name: "foo", scope: !1, scopeLine: 5, type: !4, unit: !2)
+!6 = !DILocation(column: 1, line: 5, scope: !5)
+!7 = !DILocation(column: 1, line: 7, scope: !5)
+!8 = !DILocation(column: 1, line: 8, scope: !5)
+!9 = !DILocalVariable(arg: 0, file: !1, line: 5, name: "arg", scope: !5, type: !3)
+!10 = !DIExpression()
+!11 = !{ i32 2, !"Dwarf Version", i32 4 }
+!12 = !{ i32 2, !"Debug Info Version", i32 3 }
\ No newline at end of file
diff --git a/llvm/test/DebugInfo/NVPTX/debug-bool-const-value.ll b/llvm/test/DebugInfo/NVPTX/debug-bool-const-value.ll
new file mode 100644
index 0000000000000..002a7a801c746
--- /dev/null
+++ b/llvm/test/DebugInfo/NVPTX/debug-bool-const-value.ll
@@ -0,0 +1,37 @@
+; RUN: llc < %s -asm-verbose -mattr=+ptx76 | FileCheck %s
+; RUN: %if ptxas %{ llc < %s -asm-verbose -mattr=+ptx76 | %ptxas-verify %}
+
+target triple = "nvptx64-nvidia-cuda"
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
+
+; CHECK: {{.*}}section {{.*}}debug_info
+; CHECK: {{.*}}DW_TAG_variable
+; CHECK-NEXT: {{.*}} DW_AT_address_class
+; CHECK-NEXT: .b8 1{{.*}} DW_AT_const_value
+; CHECK-NEXT: {{.*}} DW_AT_name
+
+define void @test() !dbg !5
+{
+entry:
+  %arg = alloca i1
+  store i1 true, i1* %arg, !dbg !6
+  call void @"llvm.dbg.value"(metadata i1 true, metadata !7, metadata !8), !dbg !6
+  ret void, !dbg !6
+}
+
+declare void @"llvm.dbg.value"(metadata %".1", metadata %".2", metadata %".3")
+
+!llvm.dbg.cu = !{ !2 }
+!llvm.module.flags = !{ !9, !10 }
+!nvvm.annotations = !{}
+
+!1 = !DIFile(directory: "/source/dir", filename: "test.cu")
+!2 = distinct !DICompileUnit(emissionKind: FullDebug, file: !1, isOptimized: false, language: DW_LANG_C_plus_plus, runtimeVersion: 0)
+!3 = !DIBasicType(encoding: DW_ATE_boolean, name: "bool", size: 8)
+!4 = !DISubroutineType(types: !{null})
+!5 = distinct !DISubprogram(file: !1, isDefinition: true, isLocal: false, isOptimized: false, line: 5, linkageName: "test", name: "test", scope: !1, scopeLine: 5, type: !4, unit: !2)
+!6 = !DILocation(column: 1, line: 5, scope: !5)
+!7 = !DILocalVariable(arg: 0, file: !1, line: 5, name: "arg", scope: !5, type: !3)
+!8 = !DIExpression()
+!9 = !{ i32 2, !"Dwarf Version", i32 4 }
+!10 = !{ i32 2, !"Debug Info Version", i32 3 }
\ No newline at end of file

@laxmansole
Copy link
Contributor Author

CC: @enferex

@laxmansole
Copy link
Contributor Author

CC: @jmorse

@Michael137 Michael137 requested a review from dwblaikie August 6, 2025 08:46
@Michael137
Copy link
Member

Michael137 commented Aug 6, 2025

This leads to the debugger printing 255 instead of "true" for boolean variables.

Do you have an example/Github issue of this? Shouldn't the debugger know how to present booleans in a particular language, regardless of which non-zero value was used to indicate truthness?

@dwblaikie
Copy link
Collaborator

This leads to the debugger printing 255 instead of "true" for boolean variables.

Do you have an example/Github issue of this? Shouldn't the debugger know how to present booleans in a particular language, regardless of which non-zero value was used to indicate truthness?

Arguable - it's UB to have a bool that isn't 0 or 1 (-fsanitize=bool catches this, for instance - there's some neat term for these sort of "corrupted" bools, but I forget what it is) so I'd expect a debugger to show the actual value and say something about the value being invalid. This'd help the developer understand why boolean tests (if (x) or if (!x)) don't work necessarily work as expected.

So, yeah, I think it is important we describe the value as 0 or 1 if it is 0 or 1, conceptually, at least.

@dwblaikie
Copy link
Collaborator

(but yeah, still would be good to see a bug/etc)

@laxmansole
Copy link
Contributor Author

(but yeah, still would be good to see a bug/etc)

We encountered this issue with cuda-gdb. I won't be able to share the high-level source, but I have added shorter LLVM IR lit tests that generate this DWARF.

@laxmansole laxmansole requested a review from Michael137 August 11, 2025 18:40
@laxmansole
Copy link
Contributor Author

ping

@@ -820,6 +833,22 @@ void DwarfCompileUnit::applyConcreteDbgVariableAttributes(
}
if (!DVal->isVariadic()) {
const DbgValueLocEntry *Entry = DVal->getLocEntries().begin();

// Helper function to handle boolean constant values with type safety
auto addConstantValueWithBooleanNormalization =
Copy link
Member

@Michael137 Michael137 Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered putting this boolean normalization into addConstantValue? That way, any other place where we emit booleans with out-of-range constants would benefit from this. Some of the overloads don't take a DIType though, so might not be as simple as I imagine?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure if adding boolean normalization for the APInt or ConstantInt versions made sense, so I only modified the affected call sites.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess what's confusing me is:

  1. Who is assigning -1 to indicate true?
  2. There seem to be two independent changes in this PR:
  • emit DW_OP_lit for boolean constants when computing debug values. This seems very reasonable since it makes the DWARF expression simpler (and works regardless of how the true/false values are represented?)
  • Don't emit DW_OP_constu (-1) values for booleans. That also seems reasonable, but what I'm curious about where this -1 comes from? And then, if you do this kind of normalization for booleans here, why not any other place where DW_AT_const_value is emitted for booleans? You don't strictly have to but I think we can split these two changes into separate PRs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who is assigning -1 to indicate true?

/// Enum that describes how the target represents true/false values.
enum BooleanContent {
UndefinedBooleanContent, // Only bit 0 counts, the rest can hold garbage.
ZeroOrOneBooleanContent, // All bits zero except for bit 0.
ZeroOrNegativeOneBooleanContent // All bits equal to bit 0.
};

There is a target-dependent setBooleanContents.

While creating #DBG_VALUE, the true/1 gets signed extednded to 0xffffffffffffffff i.e. -1(Line 736 below)

MachineOperand GetMOForConstDbgOp(const SDDbgOperand &Op) {
const Value *V = Op.getConst();
if (const ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
if (CI->getBitWidth() > 64)
return MachineOperand::CreateCImm(CI);
return MachineOperand::CreateImm(CI->getSExtValue());
}
if (const ConstantFP *CF = dyn_cast<ConstantFP>(V))
return MachineOperand::CreateFPImm(CF);
// Note: This assumes that all nullptr constants are zero-valued.
if (isa<ConstantPointerNull>(V))
return MachineOperand::CreateImm(0);
// Undef or unhandled value type, so return an undef operand.
return MachineOperand::CreateReg(
/* Reg */ 0U, /* isDef */ false, /* isImp */ false,
/* isKill */ false, /* isDead */ false,
/* isUndef */ false, /* isEarlyClobber */ false,
/* SubReg */ 0, /* isDebug */ true);
}

And then, if you do this kind of normalization for booleans here, why not any other place where DW_AT_const_value is emitted for booleans?

I checked all the call sites for addConstantValue and found that this is the most relevant one. Alternatively, as you suggested, I could add this normalization to addConstantValue, but we don't have DIType in all overloaded functions.

I think we can split these two changes into separate PRs

Sure. Let me spilt these into two separate PRs- current one for the changes in DwarfCompileUnit.cpp and another one for the changes to emit DW_OP_lit0/1 for booleans.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emit DW_OP_lit for boolean constants when computing debug values.

Created a separate PR #155539 for these changes

@laxmansole laxmansole force-pushed the user/lsole/boolean_constants_as_literals branch from 5810b2f to f9104e6 Compare August 21, 2025 02:01
@laxmansole laxmansole force-pushed the user/lsole/boolean_constants_as_literals branch from f9104e6 to a3fbfa6 Compare August 25, 2025 20:26
@laxmansole laxmansole force-pushed the user/lsole/boolean_constants_as_literals branch from a3fbfa6 to 859a086 Compare August 27, 2025 02:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants