[llvm-branch-commits] [clang] [KeyInstr][Clang] Scalar init atom (PR #134633)
https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/134633 >From 8534d6e34772867640665bfa3ad3547babd1a12d Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Tue, 1 Apr 2025 14:50:41 +0100 Subject: [PATCH 1/2] [KeyInstr][Clang] Scalar init atom This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. The Key Instructions project is introduced, including a "quick summary" section at the top which adds context for this PR, here: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed. The Clang-side work is demoed here: https://github.com/llvm/llvm-project/pull/130943 --- clang/lib/CodeGen/CGDecl.cpp | 1 + clang/lib/CodeGen/CGExpr.cpp | 2 ++ .../DebugInfo/KeyInstructions/init-scalar.c | 19 +++ 3 files changed, 22 insertions(+) create mode 100644 clang/test/DebugInfo/KeyInstructions/init-scalar.c diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 4a8f7f6a42ecb..d02f2ad09d2f1 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1925,6 +1925,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { const VarDecl &D = *emission.Variable; auto DL = ApplyDebugLocation::CreateDefaultArtificial(*this, D.getLocation()); + ApplyAtomGroup Grp(getDebugInfo()); QualType type = D.getType(); // If this local has an initializer, emit it now. diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 708002a7f9ab3..1e426586620a2 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -,6 +,8 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr, } llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile); + addInstToCurrentSourceAtom(Store, Value); + if (isNontemporal) { llvm::MDNode *Node = llvm::MDNode::get(Store->getContext(), diff --git a/clang/test/DebugInfo/KeyInstructions/init-scalar.c b/clang/test/DebugInfo/KeyInstructions/init-scalar.c new file mode 100644 index 0..c212c2a4fd623 --- /dev/null +++ b/clang/test/DebugInfo/KeyInstructions/init-scalar.c @@ -0,0 +1,19 @@ +// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +void a() { +// CHECK: store i32 0, ptr %A{{.*}}, !dbg [[G1R1:!.*]] +int A = 0; +// CHECK: %add = add {{.*}}, !dbg [[G2R2:!.*]] +// CHECK: store i32 %add, ptr %B, align 4, !dbg [[G2R1:!.*]] +int B = 2 * A + 1; +// CHECK-TODO: ret{{.*}}, !dbg [[G3R1:!.*]] +} + +// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) +// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2) +// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) +// CHECK-TODO: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1) >From 2935186830de115687e4841e0d4c3fba4161a177 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Wed, 21 May 2025 10:21:18 +0100 Subject: [PATCH 2/2] use %clang_cc1 in test --- clang/test/DebugInfo/KeyInstructions/init-scalar.c | 6 ++ 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/clang/test/DebugInfo/KeyInstructions/init-scalar.c b/clang/test/DebugInfo/KeyInstructions/init-scalar.c index c212c2a4fd623..a86c029e47e8c 100644 --- a/clang/test/DebugInfo/KeyInstructions/init-scalar.c +++ b/clang/test/DebugInfo/KeyInstructions/init-scalar.c @@ -1,7 +1,7 @@ -// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm -o - \ +// RUN: %clang_cc1 -gkey-instructions -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - \ // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank -// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o - \ +// RUN: %clang_cc1 -gkey-instructions -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - \ // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank void a() { @@ -10,10 +10,8 @@ void a() { // CHECK: %add = add {{.*}}, !dbg [[G2R2:!.*]] // CHECK: store i32 %add, ptr %B, align 4, !dbg [[G2R1:!.*]] int B = 2 * A + 1; -// CHECK-TODO: ret{{.*}}, !dbg [[G3R1:!.*]] } // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) // CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2) // CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) -// CHECK-TODO: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1) ___
[llvm-branch-commits] [clang] [KeyInstr][Clang] Scalar init atom (PR #134633)
@@ -0,0 +1,19 @@ +// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +void a() { +// CHECK: store i32 0, ptr %A{{.*}}, !dbg [[G1R1:!.*]] +int A = 0; +// CHECK: %add = add {{.*}}, !dbg [[G2R2:!.*]] +// CHECK: store i32 %add, ptr %B, align 4, !dbg [[G2R1:!.*]] +int B = 2 * A + 1; +// CHECK-TODO: ret{{.*}}, !dbg [[G3R1:!.*]] OCHyams wrote: Removed the CHECK-TODOs, to avoid confusion. The checks get added later on and aren't needed for this patch. https://github.com/llvm/llvm-project/pull/134633 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [flang][OpenMP] use attribute for delayed privatization barrier (PR #140092)
tblah wrote: ping for review https://github.com/llvm/llvm-project/pull/140092 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Scalar init atom (PR #134633)
@@ -0,0 +1,19 @@ +// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank OCHyams wrote: Done. https://github.com/llvm/llvm-project/pull/134633 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Scalar init atom (PR #134633)
OCHyams wrote: > Looks good with a test tweak and question. My understanding of what's going > on here is that: > > * Assignment-expressions that store a scalar to memory are added to the > "current" source atom, > * For source constructs that haven't been instrumented yet, that's > potentially a no-op as the atom group will be zero, > * In this scenario of the initialization of an automatic variable, the group > is set, and so the store gets the group number and rank. That's right. > I suppose this is a good way of decoupling the code that identifies the > source construct that is "interesting" into the thing that calls > ApplyAtomGroup, and the code that actually instruments instructions into the > helper functions. That's got the upside that we don't have to > think-about-and-manipulate the AST past an "interesting" construct; with the > downside that things can leak out: > > * "Uncovered" stores that aren't in an atom group, or that /would/ be in a > "better" atom group but leak into an "outer" construct (as it were) > * Unexpectedly multiple stores entering an atom group?, It's possible yep. OTOH, there are times we want to do that on purposes (aggregate init), so it's an important use case. > * Atom groups that unexpectedly don't cover anything. This is indeed a fear, as there's many ways to create a store/store-like-intrinsic that don't go through the instrumented functions. This current stack takes the approach of trying to instrument every one of those sites. Another approach is to do it inside the builder class so that all call sites are automatically covered. Then instead of "opt in" we'd need a mechanism for some call sites to "opt out" which feels overall probably safer. I was going to play around with the idea once all these patches land, as we'll have good test coverage by then. > ...and thinking about all those different scenarios that can pop up, this > feels like a _good_ abstraction that avoids having to think about that. Maybe > we don't cover every single construct / combination that's expressible, but > this is all strictly an improvement in stepping anyway. --- I've addressed the inline comments (which have been eaten by github) - how does this look now? https://github.com/llvm/llvm-project/pull/134633 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] AMDGPU: Fix tracking subreg defs when folding through reg_sequence (PR #140608)
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/140608 >From 4ec9c56a126192e016127e5fa5aa4416d26bcac8 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Thu, 15 May 2025 10:51:39 +0200 Subject: [PATCH] AMDGPU: Fix tracking subreg defs when folding through reg_sequence We weren't fully respecting the type of a def of an immediate vs. the type at the use point. Refactor the folding logic to track the value to fold, as well as a subregister to apply to the underlying value. This is similar to how PeepholeOpt tracks subregisters (though only for pure copy-like instructions, no constants). Fixes #139317 --- llvm/lib/Target/AMDGPU/SIFoldOperands.cpp | 406 +++--- ...issue139317-bad-opsel-reg-sequence-fold.ll | 3 +- .../si-fold-operands-subreg-imm.gfx942.mir| 8 +- .../AMDGPU/si-fold-operands-subreg-imm.mir| 4 +- 4 files changed, 250 insertions(+), 171 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp index 9bbc8e75fd31b..eb7fb94e25f5c 100644 --- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp +++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp @@ -25,52 +25,151 @@ using namespace llvm; namespace { -struct FoldCandidate { - MachineInstr *UseMI; +/// Track a value we may want to fold into downstream users, applying +/// subregister extracts along the way. +struct FoldableDef { union { -MachineOperand *OpToFold; +MachineOperand *OpToFold = nullptr; uint64_t ImmToFold; int FrameIndexToFold; }; - int ShrinkOpcode; - unsigned UseOpNo; + + /// Register class of the originally defined value. + const TargetRegisterClass *DefRC = nullptr; + + /// Track the original defining instruction for the value. + const MachineInstr *DefMI = nullptr; + + /// Subregister to apply to the value at the use point. + unsigned DefSubReg = AMDGPU::NoSubRegister; + + /// Kind of value stored in the union. MachineOperand::MachineOperandType Kind; - bool Commuted; - FoldCandidate(MachineInstr *MI, unsigned OpNo, MachineOperand *FoldOp, -bool Commuted_ = false, -int ShrinkOp = -1) : -UseMI(MI), OpToFold(nullptr), ShrinkOpcode(ShrinkOp), UseOpNo(OpNo), -Kind(FoldOp->getType()), -Commuted(Commuted_) { -if (FoldOp->isImm()) { - ImmToFold = FoldOp->getImm(); -} else if (FoldOp->isFI()) { - FrameIndexToFold = FoldOp->getIndex(); + FoldableDef() = delete; + FoldableDef(MachineOperand &FoldOp, const TargetRegisterClass *DefRC, + unsigned DefSubReg = AMDGPU::NoSubRegister) + : DefRC(DefRC), DefSubReg(DefSubReg), Kind(FoldOp.getType()) { + +if (FoldOp.isImm()) { + ImmToFold = FoldOp.getImm(); +} else if (FoldOp.isFI()) { + FrameIndexToFold = FoldOp.getIndex(); } else { - assert(FoldOp->isReg() || FoldOp->isGlobal()); - OpToFold = FoldOp; + assert(FoldOp.isReg() || FoldOp.isGlobal()); + OpToFold = &FoldOp; } + +DefMI = FoldOp.getParent(); } - FoldCandidate(MachineInstr *MI, unsigned OpNo, int64_t FoldImm, -bool Commuted_ = false, int ShrinkOp = -1) - : UseMI(MI), ImmToFold(FoldImm), ShrinkOpcode(ShrinkOp), UseOpNo(OpNo), -Kind(MachineOperand::MO_Immediate), Commuted(Commuted_) {} + FoldableDef(int64_t FoldImm, const TargetRegisterClass *DefRC, + unsigned DefSubReg = AMDGPU::NoSubRegister) + : ImmToFold(FoldImm), DefRC(DefRC), DefSubReg(DefSubReg), +Kind(MachineOperand::MO_Immediate) {} + + /// Copy the current def and apply \p SubReg to the value. + FoldableDef getWithSubReg(const SIRegisterInfo &TRI, unsigned SubReg) const { +FoldableDef Copy(*this); +Copy.DefSubReg = TRI.composeSubRegIndices(DefSubReg, SubReg); +return Copy; + } + + bool isReg() const { return Kind == MachineOperand::MO_Register; } + + Register getReg() const { +assert(isReg()); +return OpToFold->getReg(); + } + + unsigned getSubReg() const { +assert(isReg()); +return OpToFold->getSubReg(); + } + + bool isImm() const { return Kind == MachineOperand::MO_Immediate; } bool isFI() const { return Kind == MachineOperand::MO_FrameIndex; } - bool isImm() const { -return Kind == MachineOperand::MO_Immediate; + int getFI() const { +assert(isFI()); +return FrameIndexToFold; } - bool isReg() const { -return Kind == MachineOperand::MO_Register; + bool isGlobal() const { return OpToFold->isGlobal(); } + + /// Return the effective immediate value defined by this instruction, after + /// application of any subregister extracts which may exist between the use + /// and def instruction. + std::optional getEffectiveImmVal() const { +assert(isImm()); +return SIInstrInfo::extractSubregFromImm(ImmToFold, DefSubReg); } - bool isGlobal() const { return Kind == MachineOperand::MO_GlobalAddress; } + /// Check if it is legal to fold this effective value into
[llvm-branch-commits] [llvm] AMDGPU: Add baseline tests for #139317 (PR #140607)
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/140607 >From ad698bf9bb2558de0934c04390a246950c83da81 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Wed, 14 May 2025 08:50:59 +0200 Subject: [PATCH] AMDGPU: Add baseline tests for #139317 --- .../CodeGen/AMDGPU/fold-imm-copy-agpr.mir | 135 + llvm/test/CodeGen/AMDGPU/fold-imm-copy.mir| 513 ++ .../AMDGPU/fold-short-64-bit-literals.mir | 392 - ...issue139317-bad-opsel-reg-sequence-fold.ll | 66 +++ .../si-fold-operands-subreg-imm.gfx942.mir| 202 +++ .../AMDGPU/si-fold-operands-subreg-imm.mir| 26 + 6 files changed, 1329 insertions(+), 5 deletions(-) create mode 100644 llvm/test/CodeGen/AMDGPU/fold-imm-copy-agpr.mir create mode 100644 llvm/test/CodeGen/AMDGPU/issue139317-bad-opsel-reg-sequence-fold.ll create mode 100644 llvm/test/CodeGen/AMDGPU/si-fold-operands-subreg-imm.gfx942.mir diff --git a/llvm/test/CodeGen/AMDGPU/fold-imm-copy-agpr.mir b/llvm/test/CodeGen/AMDGPU/fold-imm-copy-agpr.mir new file mode 100644 index 0..a079ee1296f41 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/fold-imm-copy-agpr.mir @@ -0,0 +1,135 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5 +# RUN: llc -mtriple=amdgcn -mcpu=gfx90a -run-pass=si-fold-operands %s -o - | FileCheck -check-prefix=GCN %s + +--- +name: v_mov_b64_pseudo_imm_0_copy_to_areg_64 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_imm_0_copy_to_areg_64 +; GCN: [[V_MOV_B:%[0-9]+]]:vreg_64_align2 = V_MOV_B64_PSEUDO 0, implicit $exec +; GCN-NEXT: [[COPY:%[0-9]+]]:areg_64_align2 = COPY [[V_MOV_B]] +; GCN-NEXT: $agpr0_agpr1 = COPY [[COPY]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO 0, implicit $exec +%1:areg_64_align2 = COPY %0 +$agpr0_agpr1 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_imm_neg1_copy_to_areg_64 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_imm_neg1_copy_to_areg_64 +; GCN: [[V_MOV_B:%[0-9]+]]:vreg_64_align2 = V_MOV_B64_PSEUDO -1, implicit $exec +; GCN-NEXT: [[COPY:%[0-9]+]]:areg_64_align2 = COPY [[V_MOV_B]] +; GCN-NEXT: $agpr0_agpr1 = COPY [[COPY]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO -1, implicit $exec +%1:areg_64_align2 = COPY %0 +$agpr0_agpr1 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_literal_copy_to_areg_64 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_literal_copy_to_areg_64 +; GCN: [[V_MOV_B:%[0-9]+]]:vreg_64_align2 = V_MOV_B64_PSEUDO 999, implicit $exec +; GCN-NEXT: [[COPY:%[0-9]+]]:areg_64_align2 = COPY [[V_MOV_B]] +; GCN-NEXT: $agpr0_agpr1 = COPY [[COPY]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO 999, implicit $exec +%1:areg_64_align2 = COPY %0 +$agpr0_agpr1 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_imm_0_copy_sub0_to_agpr_32 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_imm_0_copy_sub0_to_agpr_32 +; GCN: [[V_ACCVGPR_WRITE_B32_e64_:%[0-9]+]]:agpr_32 = V_ACCVGPR_WRITE_B32_e64 0, implicit $exec +; GCN-NEXT: $agpr0 = COPY [[V_ACCVGPR_WRITE_B32_e64_]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO 0, implicit $exec +%1:agpr_32 = COPY %0.sub0 +$agpr0 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_imm_0_copy_sub1_to_agpr_32 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_imm_0_copy_sub1_to_agpr_32 +; GCN: [[V_ACCVGPR_WRITE_B32_e64_:%[0-9]+]]:agpr_32 = V_ACCVGPR_WRITE_B32_e64 0, implicit $exec +; GCN-NEXT: $agpr0 = COPY [[V_ACCVGPR_WRITE_B32_e64_]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO 0, implicit $exec +%1:agpr_32 = COPY %0.sub1 +$agpr0 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_lit_copy_sub0_to_agpr_32 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_lit_copy_sub0_to_agpr_32 +; GCN: [[V_MOV_B:%[0-9]+]]:vreg_64_align2 = V_MOV_B64_PSEUDO 4290672329592, implicit $exec +; GCN-NEXT: [[COPY:%[0-9]+]]:agpr_32 = COPY [[V_MOV_B]].sub0 +; GCN-NEXT: $agpr0 = COPY [[COPY]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO 4290672329592, implicit $exec +%1:agpr_32 = COPY %0.sub0 +$agpr0 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_lit_copy_sub1_to_agpr_32 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_lit_copy_sub1_to_agpr_32 +; GCN: [[V_MOV_B:%[0-9]+]]:vreg_64_align2 = V_MOV_B64_PSEUDO 4290672329592, implicit $exec +; GCN-NEXT: [[COPY:%[0-9]+]]:agpr_32 = COPY [[V_MOV_B]].sub1 +; GCN-NEXT: $agpr0 = COPY [[CO
[llvm-branch-commits] [llvm] AMDGPU: Remove redundant operand folding checks (PR #140587)
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/140587 >From 82fd0c72c28b7bb3694d58fe4b9b885ec320d914 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 19 May 2025 20:02:54 +0200 Subject: [PATCH 1/2] AMDGPU: Remove redundant operand folding checks This was pre-filtering out a specific situation from being added to the fold candidate list. The operand legality will ultimately be checked with isOperandLegal before the fold is performed, so I don't see the plus in pre-filtering this one case. --- llvm/lib/Target/AMDGPU/SIFoldOperands.cpp | 18 .../AMDGPU/fold-operands-frame-index.mir | 101 ++ 2 files changed, 101 insertions(+), 18 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp index b62230d4dc28c..9bbc8e75fd31b 100644 --- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp +++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp @@ -778,24 +778,6 @@ bool SIFoldOperandsImpl::tryAddToFoldList( return true; } - // Check the case where we might introduce a second constant operand to a - // scalar instruction - if (TII->isSALU(MI->getOpcode())) { -const MCInstrDesc &InstDesc = MI->getDesc(); -const MCOperandInfo &OpInfo = InstDesc.operands()[OpNo]; - -// Fine if the operand can be encoded as an inline constant -if (!OpToFold->isReg() && !TII->isInlineConstant(*OpToFold, OpInfo)) { - // Otherwise check for another constant - for (unsigned i = 0, e = InstDesc.getNumOperands(); i != e; ++i) { -auto &Op = MI->getOperand(i); -if (OpNo != i && !Op.isReg() && -!TII->isInlineConstant(Op, InstDesc.operands()[i])) - return false; - } -} - } - appendFoldCandidate(FoldList, MI, OpNo, OpToFold); return true; } diff --git a/llvm/test/CodeGen/AMDGPU/fold-operands-frame-index.mir b/llvm/test/CodeGen/AMDGPU/fold-operands-frame-index.mir index 4417f205646ee..7fad2f466bc9f 100644 --- a/llvm/test/CodeGen/AMDGPU/fold-operands-frame-index.mir +++ b/llvm/test/CodeGen/AMDGPU/fold-operands-frame-index.mir @@ -573,3 +573,104 @@ body: | S_ENDPGM 0, implicit %2 ... + +--- +name:no_fold_multiple_fi_s_cselect_b32 +tracksRegLiveness: true +stack: + - { id: 0, size: 64, alignment: 4 } + - { id: 1, size: 32, alignment: 4 } +body: | + bb.0: +; CHECK-LABEL: name: no_fold_multiple_fi_s_cselect_b32 +; CHECK: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 %stack.1 +; CHECK-NEXT: [[S_CSELECT_B32_:%[0-9]+]]:sreg_32 = S_CSELECT_B32 killed [[S_MOV_B32_]], %stack.0, implicit undef $scc +; CHECK-NEXT: S_ENDPGM 0, implicit [[S_CSELECT_B32_]] +%0:sreg_32 = S_MOV_B32 %stack.0 +%1:sreg_32 = S_MOV_B32 %stack.1 +%2:sreg_32 = S_CSELECT_B32 killed %1, killed %0, implicit undef $scc +S_ENDPGM 0, implicit %2 + +... + +--- +name:no_fold_multiple_fi_v_cndmask_b32_e64 +tracksRegLiveness: true +stack: + - { id: 0, size: 64, alignment: 4 } + - { id: 1, size: 32, alignment: 4 } +body: | + bb.0: +liveins: $sgpr8_sgpr9 +; GFX9-LABEL: name: no_fold_multiple_fi_v_cndmask_b32_e64 +; GFX9: liveins: $sgpr8_sgpr9 +; GFX9-NEXT: {{ $}} +; GFX9-NEXT: [[COPY:%[0-9]+]]:sreg_64_xexec = COPY $sgpr8_sgpr9 +; GFX9-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 %stack.0, implicit $exec +; GFX9-NEXT: [[V_MOV_B32_e32_1:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 %stack.1, implicit $exec +; GFX9-NEXT: [[V_CNDMASK_B32_e64_:%[0-9]+]]:vgpr_32 = V_CNDMASK_B32_e64 0, killed [[V_MOV_B32_e32_]], 0, killed [[V_MOV_B32_e32_1]], [[COPY]], implicit $exec +; GFX9-NEXT: S_ENDPGM 0, implicit [[V_CNDMASK_B32_e64_]] +; +; GFX10-LABEL: name: no_fold_multiple_fi_v_cndmask_b32_e64 +; GFX10: liveins: $sgpr8_sgpr9 +; GFX10-NEXT: {{ $}} +; GFX10-NEXT: [[COPY:%[0-9]+]]:sreg_64_xexec = COPY $sgpr8_sgpr9 +; GFX10-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 %stack.1, implicit $exec +; GFX10-NEXT: [[V_CNDMASK_B32_e64_:%[0-9]+]]:vgpr_32 = V_CNDMASK_B32_e64 0, %stack.0, 0, killed [[V_MOV_B32_e32_]], [[COPY]], implicit $exec +; GFX10-NEXT: S_ENDPGM 0, implicit [[V_CNDMASK_B32_e64_]] +; +; GFX12-LABEL: name: no_fold_multiple_fi_v_cndmask_b32_e64 +; GFX12: liveins: $sgpr8_sgpr9 +; GFX12-NEXT: {{ $}} +; GFX12-NEXT: [[COPY:%[0-9]+]]:sreg_64_xexec = COPY $sgpr8_sgpr9 +; GFX12-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 %stack.1, implicit $exec +; GFX12-NEXT: [[V_CNDMASK_B32_e64_:%[0-9]+]]:vgpr_32 = V_CNDMASK_B32_e64 0, %stack.0, 0, killed [[V_MOV_B32_e32_]], [[COPY]], implicit $exec +; GFX12-NEXT: S_ENDPGM 0, implicit [[V_CNDMASK_B32_e64_]] +%0:sreg_64_xexec = COPY $sgpr8_sgpr9 +%1:vgpr_32 = V_MOV_B32_e32 %stack.0, implicit $exec +%2:vgpr_32 = V_MOV_B32_e32 %stack.1, implicit $exec +%3:vgpr_32 = V_CNDMASK_B32_e64 0, killed %1, 0, killed %2, %0, implicit $exec +
[llvm-branch-commits] [llvm] AMDGPU: Fix tracking subreg defs when folding through reg_sequence (PR #140608)
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/140608 >From 4ec9c56a126192e016127e5fa5aa4416d26bcac8 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Thu, 15 May 2025 10:51:39 +0200 Subject: [PATCH] AMDGPU: Fix tracking subreg defs when folding through reg_sequence We weren't fully respecting the type of a def of an immediate vs. the type at the use point. Refactor the folding logic to track the value to fold, as well as a subregister to apply to the underlying value. This is similar to how PeepholeOpt tracks subregisters (though only for pure copy-like instructions, no constants). Fixes #139317 --- llvm/lib/Target/AMDGPU/SIFoldOperands.cpp | 406 +++--- ...issue139317-bad-opsel-reg-sequence-fold.ll | 3 +- .../si-fold-operands-subreg-imm.gfx942.mir| 8 +- .../AMDGPU/si-fold-operands-subreg-imm.mir| 4 +- 4 files changed, 250 insertions(+), 171 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp index 9bbc8e75fd31b..eb7fb94e25f5c 100644 --- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp +++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp @@ -25,52 +25,151 @@ using namespace llvm; namespace { -struct FoldCandidate { - MachineInstr *UseMI; +/// Track a value we may want to fold into downstream users, applying +/// subregister extracts along the way. +struct FoldableDef { union { -MachineOperand *OpToFold; +MachineOperand *OpToFold = nullptr; uint64_t ImmToFold; int FrameIndexToFold; }; - int ShrinkOpcode; - unsigned UseOpNo; + + /// Register class of the originally defined value. + const TargetRegisterClass *DefRC = nullptr; + + /// Track the original defining instruction for the value. + const MachineInstr *DefMI = nullptr; + + /// Subregister to apply to the value at the use point. + unsigned DefSubReg = AMDGPU::NoSubRegister; + + /// Kind of value stored in the union. MachineOperand::MachineOperandType Kind; - bool Commuted; - FoldCandidate(MachineInstr *MI, unsigned OpNo, MachineOperand *FoldOp, -bool Commuted_ = false, -int ShrinkOp = -1) : -UseMI(MI), OpToFold(nullptr), ShrinkOpcode(ShrinkOp), UseOpNo(OpNo), -Kind(FoldOp->getType()), -Commuted(Commuted_) { -if (FoldOp->isImm()) { - ImmToFold = FoldOp->getImm(); -} else if (FoldOp->isFI()) { - FrameIndexToFold = FoldOp->getIndex(); + FoldableDef() = delete; + FoldableDef(MachineOperand &FoldOp, const TargetRegisterClass *DefRC, + unsigned DefSubReg = AMDGPU::NoSubRegister) + : DefRC(DefRC), DefSubReg(DefSubReg), Kind(FoldOp.getType()) { + +if (FoldOp.isImm()) { + ImmToFold = FoldOp.getImm(); +} else if (FoldOp.isFI()) { + FrameIndexToFold = FoldOp.getIndex(); } else { - assert(FoldOp->isReg() || FoldOp->isGlobal()); - OpToFold = FoldOp; + assert(FoldOp.isReg() || FoldOp.isGlobal()); + OpToFold = &FoldOp; } + +DefMI = FoldOp.getParent(); } - FoldCandidate(MachineInstr *MI, unsigned OpNo, int64_t FoldImm, -bool Commuted_ = false, int ShrinkOp = -1) - : UseMI(MI), ImmToFold(FoldImm), ShrinkOpcode(ShrinkOp), UseOpNo(OpNo), -Kind(MachineOperand::MO_Immediate), Commuted(Commuted_) {} + FoldableDef(int64_t FoldImm, const TargetRegisterClass *DefRC, + unsigned DefSubReg = AMDGPU::NoSubRegister) + : ImmToFold(FoldImm), DefRC(DefRC), DefSubReg(DefSubReg), +Kind(MachineOperand::MO_Immediate) {} + + /// Copy the current def and apply \p SubReg to the value. + FoldableDef getWithSubReg(const SIRegisterInfo &TRI, unsigned SubReg) const { +FoldableDef Copy(*this); +Copy.DefSubReg = TRI.composeSubRegIndices(DefSubReg, SubReg); +return Copy; + } + + bool isReg() const { return Kind == MachineOperand::MO_Register; } + + Register getReg() const { +assert(isReg()); +return OpToFold->getReg(); + } + + unsigned getSubReg() const { +assert(isReg()); +return OpToFold->getSubReg(); + } + + bool isImm() const { return Kind == MachineOperand::MO_Immediate; } bool isFI() const { return Kind == MachineOperand::MO_FrameIndex; } - bool isImm() const { -return Kind == MachineOperand::MO_Immediate; + int getFI() const { +assert(isFI()); +return FrameIndexToFold; } - bool isReg() const { -return Kind == MachineOperand::MO_Register; + bool isGlobal() const { return OpToFold->isGlobal(); } + + /// Return the effective immediate value defined by this instruction, after + /// application of any subregister extracts which may exist between the use + /// and def instruction. + std::optional getEffectiveImmVal() const { +assert(isImm()); +return SIInstrInfo::extractSubregFromImm(ImmToFold, DefSubReg); } - bool isGlobal() const { return Kind == MachineOperand::MO_GlobalAddress; } + /// Check if it is legal to fold this effective value into
[llvm-branch-commits] [llvm] AMDGPU: Remove redundant operand folding checks (PR #140587)
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/140587 >From 82fd0c72c28b7bb3694d58fe4b9b885ec320d914 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 19 May 2025 20:02:54 +0200 Subject: [PATCH 1/2] AMDGPU: Remove redundant operand folding checks This was pre-filtering out a specific situation from being added to the fold candidate list. The operand legality will ultimately be checked with isOperandLegal before the fold is performed, so I don't see the plus in pre-filtering this one case. --- llvm/lib/Target/AMDGPU/SIFoldOperands.cpp | 18 .../AMDGPU/fold-operands-frame-index.mir | 101 ++ 2 files changed, 101 insertions(+), 18 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp index b62230d4dc28c..9bbc8e75fd31b 100644 --- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp +++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp @@ -778,24 +778,6 @@ bool SIFoldOperandsImpl::tryAddToFoldList( return true; } - // Check the case where we might introduce a second constant operand to a - // scalar instruction - if (TII->isSALU(MI->getOpcode())) { -const MCInstrDesc &InstDesc = MI->getDesc(); -const MCOperandInfo &OpInfo = InstDesc.operands()[OpNo]; - -// Fine if the operand can be encoded as an inline constant -if (!OpToFold->isReg() && !TII->isInlineConstant(*OpToFold, OpInfo)) { - // Otherwise check for another constant - for (unsigned i = 0, e = InstDesc.getNumOperands(); i != e; ++i) { -auto &Op = MI->getOperand(i); -if (OpNo != i && !Op.isReg() && -!TII->isInlineConstant(Op, InstDesc.operands()[i])) - return false; - } -} - } - appendFoldCandidate(FoldList, MI, OpNo, OpToFold); return true; } diff --git a/llvm/test/CodeGen/AMDGPU/fold-operands-frame-index.mir b/llvm/test/CodeGen/AMDGPU/fold-operands-frame-index.mir index 4417f205646ee..7fad2f466bc9f 100644 --- a/llvm/test/CodeGen/AMDGPU/fold-operands-frame-index.mir +++ b/llvm/test/CodeGen/AMDGPU/fold-operands-frame-index.mir @@ -573,3 +573,104 @@ body: | S_ENDPGM 0, implicit %2 ... + +--- +name:no_fold_multiple_fi_s_cselect_b32 +tracksRegLiveness: true +stack: + - { id: 0, size: 64, alignment: 4 } + - { id: 1, size: 32, alignment: 4 } +body: | + bb.0: +; CHECK-LABEL: name: no_fold_multiple_fi_s_cselect_b32 +; CHECK: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 %stack.1 +; CHECK-NEXT: [[S_CSELECT_B32_:%[0-9]+]]:sreg_32 = S_CSELECT_B32 killed [[S_MOV_B32_]], %stack.0, implicit undef $scc +; CHECK-NEXT: S_ENDPGM 0, implicit [[S_CSELECT_B32_]] +%0:sreg_32 = S_MOV_B32 %stack.0 +%1:sreg_32 = S_MOV_B32 %stack.1 +%2:sreg_32 = S_CSELECT_B32 killed %1, killed %0, implicit undef $scc +S_ENDPGM 0, implicit %2 + +... + +--- +name:no_fold_multiple_fi_v_cndmask_b32_e64 +tracksRegLiveness: true +stack: + - { id: 0, size: 64, alignment: 4 } + - { id: 1, size: 32, alignment: 4 } +body: | + bb.0: +liveins: $sgpr8_sgpr9 +; GFX9-LABEL: name: no_fold_multiple_fi_v_cndmask_b32_e64 +; GFX9: liveins: $sgpr8_sgpr9 +; GFX9-NEXT: {{ $}} +; GFX9-NEXT: [[COPY:%[0-9]+]]:sreg_64_xexec = COPY $sgpr8_sgpr9 +; GFX9-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 %stack.0, implicit $exec +; GFX9-NEXT: [[V_MOV_B32_e32_1:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 %stack.1, implicit $exec +; GFX9-NEXT: [[V_CNDMASK_B32_e64_:%[0-9]+]]:vgpr_32 = V_CNDMASK_B32_e64 0, killed [[V_MOV_B32_e32_]], 0, killed [[V_MOV_B32_e32_1]], [[COPY]], implicit $exec +; GFX9-NEXT: S_ENDPGM 0, implicit [[V_CNDMASK_B32_e64_]] +; +; GFX10-LABEL: name: no_fold_multiple_fi_v_cndmask_b32_e64 +; GFX10: liveins: $sgpr8_sgpr9 +; GFX10-NEXT: {{ $}} +; GFX10-NEXT: [[COPY:%[0-9]+]]:sreg_64_xexec = COPY $sgpr8_sgpr9 +; GFX10-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 %stack.1, implicit $exec +; GFX10-NEXT: [[V_CNDMASK_B32_e64_:%[0-9]+]]:vgpr_32 = V_CNDMASK_B32_e64 0, %stack.0, 0, killed [[V_MOV_B32_e32_]], [[COPY]], implicit $exec +; GFX10-NEXT: S_ENDPGM 0, implicit [[V_CNDMASK_B32_e64_]] +; +; GFX12-LABEL: name: no_fold_multiple_fi_v_cndmask_b32_e64 +; GFX12: liveins: $sgpr8_sgpr9 +; GFX12-NEXT: {{ $}} +; GFX12-NEXT: [[COPY:%[0-9]+]]:sreg_64_xexec = COPY $sgpr8_sgpr9 +; GFX12-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 %stack.1, implicit $exec +; GFX12-NEXT: [[V_CNDMASK_B32_e64_:%[0-9]+]]:vgpr_32 = V_CNDMASK_B32_e64 0, %stack.0, 0, killed [[V_MOV_B32_e32_]], [[COPY]], implicit $exec +; GFX12-NEXT: S_ENDPGM 0, implicit [[V_CNDMASK_B32_e64_]] +%0:sreg_64_xexec = COPY $sgpr8_sgpr9 +%1:vgpr_32 = V_MOV_B32_e32 %stack.0, implicit $exec +%2:vgpr_32 = V_MOV_B32_e32 %stack.1, implicit $exec +%3:vgpr_32 = V_CNDMASK_B32_e64 0, killed %1, 0, killed %2, %0, implicit $exec +
[llvm-branch-commits] [llvm] AMDGPU: Add baseline tests for #139317 (PR #140607)
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/140607 >From ad698bf9bb2558de0934c04390a246950c83da81 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Wed, 14 May 2025 08:50:59 +0200 Subject: [PATCH] AMDGPU: Add baseline tests for #139317 --- .../CodeGen/AMDGPU/fold-imm-copy-agpr.mir | 135 + llvm/test/CodeGen/AMDGPU/fold-imm-copy.mir| 513 ++ .../AMDGPU/fold-short-64-bit-literals.mir | 392 - ...issue139317-bad-opsel-reg-sequence-fold.ll | 66 +++ .../si-fold-operands-subreg-imm.gfx942.mir| 202 +++ .../AMDGPU/si-fold-operands-subreg-imm.mir| 26 + 6 files changed, 1329 insertions(+), 5 deletions(-) create mode 100644 llvm/test/CodeGen/AMDGPU/fold-imm-copy-agpr.mir create mode 100644 llvm/test/CodeGen/AMDGPU/issue139317-bad-opsel-reg-sequence-fold.ll create mode 100644 llvm/test/CodeGen/AMDGPU/si-fold-operands-subreg-imm.gfx942.mir diff --git a/llvm/test/CodeGen/AMDGPU/fold-imm-copy-agpr.mir b/llvm/test/CodeGen/AMDGPU/fold-imm-copy-agpr.mir new file mode 100644 index 0..a079ee1296f41 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/fold-imm-copy-agpr.mir @@ -0,0 +1,135 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5 +# RUN: llc -mtriple=amdgcn -mcpu=gfx90a -run-pass=si-fold-operands %s -o - | FileCheck -check-prefix=GCN %s + +--- +name: v_mov_b64_pseudo_imm_0_copy_to_areg_64 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_imm_0_copy_to_areg_64 +; GCN: [[V_MOV_B:%[0-9]+]]:vreg_64_align2 = V_MOV_B64_PSEUDO 0, implicit $exec +; GCN-NEXT: [[COPY:%[0-9]+]]:areg_64_align2 = COPY [[V_MOV_B]] +; GCN-NEXT: $agpr0_agpr1 = COPY [[COPY]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO 0, implicit $exec +%1:areg_64_align2 = COPY %0 +$agpr0_agpr1 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_imm_neg1_copy_to_areg_64 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_imm_neg1_copy_to_areg_64 +; GCN: [[V_MOV_B:%[0-9]+]]:vreg_64_align2 = V_MOV_B64_PSEUDO -1, implicit $exec +; GCN-NEXT: [[COPY:%[0-9]+]]:areg_64_align2 = COPY [[V_MOV_B]] +; GCN-NEXT: $agpr0_agpr1 = COPY [[COPY]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO -1, implicit $exec +%1:areg_64_align2 = COPY %0 +$agpr0_agpr1 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_literal_copy_to_areg_64 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_literal_copy_to_areg_64 +; GCN: [[V_MOV_B:%[0-9]+]]:vreg_64_align2 = V_MOV_B64_PSEUDO 999, implicit $exec +; GCN-NEXT: [[COPY:%[0-9]+]]:areg_64_align2 = COPY [[V_MOV_B]] +; GCN-NEXT: $agpr0_agpr1 = COPY [[COPY]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO 999, implicit $exec +%1:areg_64_align2 = COPY %0 +$agpr0_agpr1 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_imm_0_copy_sub0_to_agpr_32 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_imm_0_copy_sub0_to_agpr_32 +; GCN: [[V_ACCVGPR_WRITE_B32_e64_:%[0-9]+]]:agpr_32 = V_ACCVGPR_WRITE_B32_e64 0, implicit $exec +; GCN-NEXT: $agpr0 = COPY [[V_ACCVGPR_WRITE_B32_e64_]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO 0, implicit $exec +%1:agpr_32 = COPY %0.sub0 +$agpr0 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_imm_0_copy_sub1_to_agpr_32 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_imm_0_copy_sub1_to_agpr_32 +; GCN: [[V_ACCVGPR_WRITE_B32_e64_:%[0-9]+]]:agpr_32 = V_ACCVGPR_WRITE_B32_e64 0, implicit $exec +; GCN-NEXT: $agpr0 = COPY [[V_ACCVGPR_WRITE_B32_e64_]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO 0, implicit $exec +%1:agpr_32 = COPY %0.sub1 +$agpr0 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_lit_copy_sub0_to_agpr_32 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_lit_copy_sub0_to_agpr_32 +; GCN: [[V_MOV_B:%[0-9]+]]:vreg_64_align2 = V_MOV_B64_PSEUDO 4290672329592, implicit $exec +; GCN-NEXT: [[COPY:%[0-9]+]]:agpr_32 = COPY [[V_MOV_B]].sub0 +; GCN-NEXT: $agpr0 = COPY [[COPY]] +; GCN-NEXT: S_ENDPGM 0 +%0:vreg_64_align2 = V_MOV_B64_PSEUDO 4290672329592, implicit $exec +%1:agpr_32 = COPY %0.sub0 +$agpr0 = COPY %1 +S_ENDPGM 0 + +... + +--- +name: v_mov_b64_pseudo_lit_copy_sub1_to_agpr_32 +tracksRegLiveness: true +body: | + bb.0: +; GCN-LABEL: name: v_mov_b64_pseudo_lit_copy_sub1_to_agpr_32 +; GCN: [[V_MOV_B:%[0-9]+]]:vreg_64_align2 = V_MOV_B64_PSEUDO 4290672329592, implicit $exec +; GCN-NEXT: [[COPY:%[0-9]+]]:agpr_32 = COPY [[V_MOV_B]].sub1 +; GCN-NEXT: $agpr0 = COPY [[CO
[llvm-branch-commits] [llvm] AMDGPU: Remove redundant operand folding checks (PR #140587)
arsenm wrote: Had to fix regression demonstrated in #140784 by avoiding folding a second frame index into an instruction that already uses one https://github.com/llvm/llvm-project/pull/140587 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir] Unique property constraints where possible (PR #140849)
https://github.com/krzysz00 created https://github.com/llvm/llvm-project/pull/140849 Now that `Property` is a `PropConstraint`, hook it up to the same constraint-uniquing machinery that other types of constraints use. This will primarily save on code size for types, like enums, that have inherent constraints which are shared across many operations. >From 3705acd6c9334f76bf95877fcd8e878a015b9955 Mon Sep 17 00:00:00 2001 From: Krzysztof Drewniak Date: Tue, 20 May 2025 22:38:34 -0700 Subject: [PATCH] [mlir] Unique property constraints where possible Now that `Property` is a `PropConstraint`, hook it up to the same constraint-uniquing machinery that other types of constraints use. This will primarily save on code size for types, like enums, that have inherent constraints which are shared across many operations. --- mlir/include/mlir/TableGen/CodeGenHelpers.h | 21 ++ mlir/include/mlir/TableGen/Property.h | 24 +++--- mlir/lib/TableGen/CodeGenHelpers.cpp | 64 mlir/lib/TableGen/Property.cpp| 18 +++-- .../mlir-tblgen/op-properties-predicates.td | 61 +++ mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp | 74 +++ 6 files changed, 201 insertions(+), 61 deletions(-) diff --git a/mlir/include/mlir/TableGen/CodeGenHelpers.h b/mlir/include/mlir/TableGen/CodeGenHelpers.h index 465240907a3de..cf14f65b93ed2 100644 --- a/mlir/include/mlir/TableGen/CodeGenHelpers.h +++ b/mlir/include/mlir/TableGen/CodeGenHelpers.h @@ -153,6 +153,23 @@ class StaticVerifierFunctionEmitter { std::optional getAttrConstraintFn(const Constraint &constraint) const; + /// Get the name of the static function used for the given property + /// constraint. These functions are in the form: + /// + /// LogicalResult(Operation *op, T property, StringRef propName); + /// + /// where T is the interface type specified in the constraint. + /// If a uniqued constraint was not found, this function returns std::nullopt. + /// The uniqued constraints cannot be used in the context of an OpAdaptor. + /// + /// Pattern constraints have the form: + /// + /// LogicalResult(PatternRewriter &rewriter, Operation *op, T property, + /// StringRef failureStr); + /// + std::optional + getPropConstraintFn(const Constraint &constraint) const; + /// Get the name of the static function used for the given successor /// constraint. These functions are in the form: /// @@ -175,6 +192,8 @@ class StaticVerifierFunctionEmitter { void emitTypeConstraints(); /// Emit static attribute constraint functions. void emitAttrConstraints(); + /// Emit static property constraint functions. + void emitPropConstraints(); /// Emit static successor constraint functions. void emitSuccessorConstraints(); /// Emit static region constraint functions. @@ -212,6 +231,8 @@ class StaticVerifierFunctionEmitter { ConstraintMap typeConstraints; /// The set of attribute constraints used in the current file. ConstraintMap attrConstraints; + /// The set of property constraints used in the current file. + ConstraintMap propConstraints; /// The set of successor constraints used in the current file. ConstraintMap successorConstraints; /// The set of region constraints used in the current file. diff --git a/mlir/include/mlir/TableGen/Property.h b/mlir/include/mlir/TableGen/Property.h index 386159191ef1f..6af96f077efe5 100644 --- a/mlir/include/mlir/TableGen/Property.h +++ b/mlir/include/mlir/TableGen/Property.h @@ -29,14 +29,26 @@ class Dialect; class Type; class Pred; +// Wrapper class providing helper methods for accesing property constraint +// values. +class PropConstraint : public Constraint { + using Constraint::Constraint; + +public: + static bool classof(const Constraint *c) { return c->getKind() == CK_Prop; } + + StringRef getInterfaceType() const; +}; + // Wrapper class providing helper methods for accessing MLIR Property defined // in TableGen. This class should closely reflect what is defined as class // `Property` in TableGen. -class Property { +class Property : public PropConstraint { public: - explicit Property(const llvm::Record *record); + explicit Property(const llvm::Record *def); explicit Property(const llvm::DefInit *init); - Property(StringRef summary, StringRef description, StringRef storageType, + Property(const llvm::Record *maybeDef, StringRef summary, + StringRef description, StringRef storageType, StringRef interfaceType, StringRef convertFromStorageCall, StringRef assignToStorageCall, StringRef convertToAttributeCall, StringRef convertFromAttributeCall, StringRef parserCall, @@ -131,13 +143,7 @@ class Property { // property constraints, this function is added for future-proofing) Property getBaseProperty() const; - // Returns the TableGen definition this Property was constructed from. - const llvm::Record &getDef() const { retu
[llvm-branch-commits] [llvm] [NFCI] Avoid adding duplicated SpecialCaseList::Sections. (PR #140821)
vitalybuka wrote: But why? We don't use uniqueness any how. We will need to O(N_globs) lookups either way. I propose to keep all sections as-is, in original order (or reversed), so we can interate them in reverse (or straight) order up to the first match. https://github.com/llvm/llvm-project/pull/140821 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] AMDGPU: Handle folding vector splats of inline split f64 inline immediates (PR #140878)
https://github.com/arsenm ready_for_review https://github.com/llvm/llvm-project/pull/140878 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] AMDGPU: Handle folding vector splats of inline split f64 inline immediates (PR #140878)
llvmbot wrote: @llvm/pr-subscribers-backend-amdgpu Author: Matt Arsenault (arsenm) Changes Recognize a reg_sequence with 32-bit elements that produce a 64-bit splat value. This enables folding f64 constants into mfma operands --- Full diff: https://github.com/llvm/llvm-project/pull/140878.diff 2 Files Affected: - (modified) llvm/lib/Target/AMDGPU/SIFoldOperands.cpp (+70-33) - (modified) llvm/test/CodeGen/AMDGPU/llvm.amdgcn.mfma.gfx90a.ll (+6-35) ``diff diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp index eb7fb94e25f5c..70e3974bb22b4 100644 --- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp +++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp @@ -227,12 +227,12 @@ class SIFoldOperandsImpl { getRegSeqInit(SmallVectorImpl> &Defs, Register UseReg) const; - std::pair + std::pair isRegSeqSplat(MachineInstr &RegSeg) const; - MachineOperand *tryFoldRegSeqSplat(MachineInstr *UseMI, unsigned UseOpIdx, - MachineOperand *SplatVal, - const TargetRegisterClass *SplatRC) const; + bool tryFoldRegSeqSplat(MachineInstr *UseMI, unsigned UseOpIdx, + int64_t SplatVal, + const TargetRegisterClass *SplatRC) const; bool tryToFoldACImm(const FoldableDef &OpToFold, MachineInstr *UseMI, unsigned UseOpIdx, @@ -967,15 +967,15 @@ const TargetRegisterClass *SIFoldOperandsImpl::getRegSeqInit( return getRegSeqInit(*Def, Defs); } -std::pair +std::pair SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq) const { SmallVector, 32> Defs; const TargetRegisterClass *SrcRC = getRegSeqInit(RegSeq, Defs); if (!SrcRC) return {}; - // TODO: Recognize 64-bit splats broken into 32-bit pieces (i.e. recognize - // every other other element is 0 for 64-bit immediates) + bool TryToMatchSplat64 = false; + int64_t Imm; for (unsigned I = 0, E = Defs.size(); I != E; ++I) { const MachineOperand *Op = Defs[I].first; @@ -987,38 +987,75 @@ SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq) const { Imm = SubImm; continue; } -if (Imm != SubImm) + +if (Imm != SubImm) { + if (I == 1 && (E & 1) == 0) { +// If we have an even number of inputs, there's a chance this is a +// 64-bit element splat broken into 32-bit pieces. +TryToMatchSplat64 = true; +break; + } + return {}; // Can only fold splat constants +} + } + + if (!TryToMatchSplat64) +return {Defs[0].first->getImm(), SrcRC}; + + // Fallback to recognizing 64-bit splats broken into 32-bit pieces + // (i.e. recognize every other other element is 0 for 64-bit immediates) + int64_t SplatVal64; + for (unsigned I = 0, E = Defs.size(); I != E; I += 2) { +const MachineOperand *Op0 = Defs[I].first; +const MachineOperand *Op1 = Defs[I + 1].first; + +if (!Op0->isImm() || !Op1->isImm()) + return {}; + +unsigned SubReg0 = Defs[I].second; +unsigned SubReg1 = Defs[I + 1].second; + +// Assume we're going to generally encounter reg_sequences with sorted +// subreg indexes, so reject any that aren't consecutive. +if (TRI->getChannelFromSubReg(SubReg0) + 1 != +TRI->getChannelFromSubReg(SubReg1)) + return {}; + +int64_t MergedVal = Make_64(Op1->getImm(), Op0->getImm()); +if (I == 0) + SplatVal64 = MergedVal; +else if (SplatVal64 != MergedVal) + return {}; } - return {Defs[0].first, SrcRC}; + const TargetRegisterClass *RC64 = TRI->getSubRegisterClass( + MRI->getRegClass(RegSeq.getOperand(0).getReg()), AMDGPU::sub0_sub1); + + return {SplatVal64, RC64}; } -MachineOperand *SIFoldOperandsImpl::tryFoldRegSeqSplat( -MachineInstr *UseMI, unsigned UseOpIdx, MachineOperand *SplatVal, +bool SIFoldOperandsImpl::tryFoldRegSeqSplat( +MachineInstr *UseMI, unsigned UseOpIdx, int64_t SplatVal, const TargetRegisterClass *SplatRC) const { const MCInstrDesc &Desc = UseMI->getDesc(); if (UseOpIdx >= Desc.getNumOperands()) -return nullptr; +return false; // Filter out unhandled pseudos. if (!AMDGPU::isSISrcOperand(Desc, UseOpIdx)) -return nullptr; +return false; int16_t RCID = Desc.operands()[UseOpIdx].RegClass; if (RCID == -1) -return nullptr; +return false; + + const TargetRegisterClass *OpRC = TRI->getRegClass(RCID); // Special case 0/-1, since when interpreted as a 64-bit element both halves - // have the same bits. Effectively this code does not handle 64-bit element - // operands correctly, as the incoming 64-bit constants are already split into - // 32-bit sequence elements. - // - // TODO: We should try to figure out how to interpret the reg_sequence as a - // split 64-bit splat constant, or use 64-bit pseudos for materializing f64 - // constants. - if (SplatVal->getImm() != 0 && SplatVal->getImm() != -1) { -
[llvm-branch-commits] [llvm] AMDGPU: Handle folding vector splats of inline split f64 inline immediates (PR #140878)
https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/140878 Recognize a reg_sequence with 32-bit elements that produce a 64-bit splat value. This enables folding f64 constants into mfma operands >From b68d880b7872cd90d3aa79419800cfc505305b76 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 19 May 2025 21:51:06 +0200 Subject: [PATCH] AMDGPU: Handle folding vector splats of inline split f64 inline immediates Recognize a reg_sequence with 32-bit elements that produce a 64-bit splat value. This enables folding f64 constants into mfma operands --- llvm/lib/Target/AMDGPU/SIFoldOperands.cpp | 103 -- .../CodeGen/AMDGPU/llvm.amdgcn.mfma.gfx90a.ll | 41 +-- 2 files changed, 76 insertions(+), 68 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp index eb7fb94e25f5c..70e3974bb22b4 100644 --- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp +++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp @@ -227,12 +227,12 @@ class SIFoldOperandsImpl { getRegSeqInit(SmallVectorImpl> &Defs, Register UseReg) const; - std::pair + std::pair isRegSeqSplat(MachineInstr &RegSeg) const; - MachineOperand *tryFoldRegSeqSplat(MachineInstr *UseMI, unsigned UseOpIdx, - MachineOperand *SplatVal, - const TargetRegisterClass *SplatRC) const; + bool tryFoldRegSeqSplat(MachineInstr *UseMI, unsigned UseOpIdx, + int64_t SplatVal, + const TargetRegisterClass *SplatRC) const; bool tryToFoldACImm(const FoldableDef &OpToFold, MachineInstr *UseMI, unsigned UseOpIdx, @@ -967,15 +967,15 @@ const TargetRegisterClass *SIFoldOperandsImpl::getRegSeqInit( return getRegSeqInit(*Def, Defs); } -std::pair +std::pair SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq) const { SmallVector, 32> Defs; const TargetRegisterClass *SrcRC = getRegSeqInit(RegSeq, Defs); if (!SrcRC) return {}; - // TODO: Recognize 64-bit splats broken into 32-bit pieces (i.e. recognize - // every other other element is 0 for 64-bit immediates) + bool TryToMatchSplat64 = false; + int64_t Imm; for (unsigned I = 0, E = Defs.size(); I != E; ++I) { const MachineOperand *Op = Defs[I].first; @@ -987,38 +987,75 @@ SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq) const { Imm = SubImm; continue; } -if (Imm != SubImm) + +if (Imm != SubImm) { + if (I == 1 && (E & 1) == 0) { +// If we have an even number of inputs, there's a chance this is a +// 64-bit element splat broken into 32-bit pieces. +TryToMatchSplat64 = true; +break; + } + return {}; // Can only fold splat constants +} + } + + if (!TryToMatchSplat64) +return {Defs[0].first->getImm(), SrcRC}; + + // Fallback to recognizing 64-bit splats broken into 32-bit pieces + // (i.e. recognize every other other element is 0 for 64-bit immediates) + int64_t SplatVal64; + for (unsigned I = 0, E = Defs.size(); I != E; I += 2) { +const MachineOperand *Op0 = Defs[I].first; +const MachineOperand *Op1 = Defs[I + 1].first; + +if (!Op0->isImm() || !Op1->isImm()) + return {}; + +unsigned SubReg0 = Defs[I].second; +unsigned SubReg1 = Defs[I + 1].second; + +// Assume we're going to generally encounter reg_sequences with sorted +// subreg indexes, so reject any that aren't consecutive. +if (TRI->getChannelFromSubReg(SubReg0) + 1 != +TRI->getChannelFromSubReg(SubReg1)) + return {}; + +int64_t MergedVal = Make_64(Op1->getImm(), Op0->getImm()); +if (I == 0) + SplatVal64 = MergedVal; +else if (SplatVal64 != MergedVal) + return {}; } - return {Defs[0].first, SrcRC}; + const TargetRegisterClass *RC64 = TRI->getSubRegisterClass( + MRI->getRegClass(RegSeq.getOperand(0).getReg()), AMDGPU::sub0_sub1); + + return {SplatVal64, RC64}; } -MachineOperand *SIFoldOperandsImpl::tryFoldRegSeqSplat( -MachineInstr *UseMI, unsigned UseOpIdx, MachineOperand *SplatVal, +bool SIFoldOperandsImpl::tryFoldRegSeqSplat( +MachineInstr *UseMI, unsigned UseOpIdx, int64_t SplatVal, const TargetRegisterClass *SplatRC) const { const MCInstrDesc &Desc = UseMI->getDesc(); if (UseOpIdx >= Desc.getNumOperands()) -return nullptr; +return false; // Filter out unhandled pseudos. if (!AMDGPU::isSISrcOperand(Desc, UseOpIdx)) -return nullptr; +return false; int16_t RCID = Desc.operands()[UseOpIdx].RegClass; if (RCID == -1) -return nullptr; +return false; + + const TargetRegisterClass *OpRC = TRI->getRegClass(RCID); // Special case 0/-1, since when interpreted as a 64-bit element both halves - // have the same bits. Effectively this code does not handle 64-bit element - // operands correctly, as the incoming 64-bit constants are alrea
[llvm-branch-commits] [llvm] AMDGPU: Handle folding vector splats of inline split f64 inline immediates (PR #140878)
arsenm wrote: > [!WARNING] > This pull request is not mergeable via GitHub because a downstack PR is > open. Once all requirements are satisfied, merge this PR as a stack href="https://app.graphite.dev/github/pr/llvm/llvm-project/140878?utm_source=stack-comment-downstack-mergeability-warning"; > >on Graphite. > https://graphite.dev/docs/merge-pull-requests";>Learn more * **#140878** https://app.graphite.dev/github/pr/llvm/llvm-project/140878?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> 👈 https://app.graphite.dev/github/pr/llvm/llvm-project/140878?utm_source=stack-comment-view-in-graphite"; target="_blank">(View in Graphite) * **#140608** https://app.graphite.dev/github/pr/llvm/llvm-project/140608?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * **#140607** https://app.graphite.dev/github/pr/llvm/llvm-project/140607?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * **#140587** https://app.graphite.dev/github/pr/llvm/llvm-project/140587?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * **#140580** https://app.graphite.dev/github/pr/llvm/llvm-project/140580?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * `main` This stack of pull requests is managed by https://graphite.dev?utm-source=stack-comment";>Graphite. Learn more about https://stacking.dev/?utm_source=stack-comment";>stacking. https://github.com/llvm/llvm-project/pull/140878 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [HLSL][RootSignature] Implement `ResourceRange` as an `IntervalMap` (PR #140957)
llvmbot wrote: @llvm/pr-subscribers-hlsl Author: Finn Plummer (inbelic) Changes A resource range consists of a closed interval, `[a;b]`, denoting which shader registers it is bound to. For instance: - `CBV(b1)` corresponds to the resource range of `[1;1]` - `CBV(b0, numDescriptors = 3)` likewise to `[0;2]` We want to provide an error diagnostic that there is an overlap in the required registers for each of the resources (an overlap in the resource ranges). The goal of this pr is to implement a structure to model a set of resource ranges and provide an api to detect any overlap over a set of resource ranges. `ResourceRange` models this by implementing an `IntervalMap` to denote a mapping from an interval of registers back to a resource range. It allows for a new `ResourceRange` to be added to the mapping and it will report the first overlap that it denotes. - Implements `ResourceRange` as an `IntervalMap` - Adds unit testing of the various `insert` scenarios Note: it was also considered to implement this as an `IntervalTree`, this would allow reporting of a diagnostic for each overlap that is encountered, as opposed to just the first. However, error generation of just reporting the first error is already rather verbose, and adding the additional diagnostics only made this worse. Part 1 of https://github.com/llvm/llvm-project/issues/129942 --- Full diff: https://github.com/llvm/llvm-project/pull/140957.diff 4 Files Affected: - (modified) llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h (+56) - (modified) llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp (+61) - (modified) llvm/unittests/Frontend/CMakeLists.txt (+1) - (added) llvm/unittests/Frontend/HLSLRootSignatureRangesTest.cpp (+177) ``diff diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h index 98fa5f09429e3..3e5054566052b 100644 --- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h +++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h @@ -15,6 +15,7 @@ #define LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/IntervalMap.h" #include "llvm/Support/DXILABI.h" #include "llvm/Support/raw_ostream.h" #include @@ -198,6 +199,61 @@ class MetadataBuilder { SmallVector GeneratedMetadata; }; +// RangeInfo holds the information to correctly construct a ResourceRange +// and retains this information to be used for displaying a better diagnostic +struct RangeInfo { + const static uint32_t Unbounded = static_cast(-1); + + uint32_t LowerBound; + uint32_t UpperBound; +}; + +class ResourceRange { +public: + using IMap = llvm::IntervalMap>; + +private: + IMap Intervals; + +public: + ResourceRange(IMap::Allocator &Allocator) : Intervals(IMap(Allocator)) {} + + // Returns a reference to the first RangeInfo that overlaps with + // [Info.LowerBound;Info.UpperBound], or, std::nullopt if there is no overlap + std::optional getOverlapping(const RangeInfo &Info) const; + + // Return the mapped RangeInfo at X or nullptr if no mapping exists + const RangeInfo *lookup(uint32_t X) const; + + // Insert the required (sub-)intervals such that the interval of [a;b] = + // [Info.LowerBound, Info.UpperBound] is covered and points to a valid + // RangeInfo &. + // + // For instance consider the following chain of inserting RangeInfos with the + // intervals denoting the Lower/Upper-bounds: + // + // A = [0;2] + // insert(A) -> false + // intervals: [0;2] -> &A + // B = [5;7] + // insert(B) -> false + // intervals: [0;2] -> &A, [5;7] -> &B + // C = [4;7] + // insert(C) -> true + // intervals: [0;2] -> &A, [4;7] -> &C + // D = [1;5] + // insert(D) -> true + // intervals: [0;2] -> &A, [3;3] -> &D, [4;7] -> &C + // E = [0;unbounded] + // insert(E) -> true + // intervals: [0;unbounded] -> E + // + // Returns if the first overlapping range when inserting + // (same return as getOverlapping) + std::optional insert(const RangeInfo &Info); +}; + } // namespace rootsig } // namespace hlsl } // namespace llvm diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp index abf076944b273..76fe09e4dc3ee 100644 --- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp +++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp @@ -222,6 +222,67 @@ MDNode *MetadataBuilder::BuildDescriptorTableClause( }); } +std::optional +ResourceRange::getOverlapping(const RangeInfo &Info) const { + IMap::const_iterator Interval = Intervals.find(Info.LowerBound); + if (!Interval.valid() || Info.UpperBound < Interval.start()) +return std::nullopt; + return Interval.value(); +} + +const RangeInfo *ResourceRange::lookup(uint32_t X) const { + return Intervals.lookup(X, nullptr); +} + +std::optional ResourceRange::insert(const RangeInfo &Info) { + uint32_t LowerBound = Info.LowerBound; + uint32_t UpperBound = Info.UpperBound; + + std::o
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Add parsing of Register in params for RootDescriptors (PR #140148)
https://github.com/inbelic edited https://github.com/llvm/llvm-project/pull/140148 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Add parsing of Register in params for RootDescriptors (PR #140148)
https://github.com/inbelic edited https://github.com/llvm/llvm-project/pull/140148 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Add parsing of optional parameters for RootDescriptor (PR #140151)
https://github.com/inbelic edited https://github.com/llvm/llvm-project/pull/140151 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Add parsing of flags to RootDescriptor (PR #140152)
https://github.com/inbelic edited https://github.com/llvm/llvm-project/pull/140152 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [SelectionDAGBuilder] Use address width when lowering ptrtoaddr (PR #139423)
https://github.com/arsenm approved this pull request. https://github.com/llvm/llvm-project/pull/139423 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Add parsing of Register in params for RootDescriptors (PR #140148)
https://github.com/joaosaffran approved this pull request. https://github.com/llvm/llvm-project/pull/140148 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [SelectionDAGBuilder] Use address width when lowering ptrtoaddr (PR #139423)
@@ -3878,7 +3878,18 @@ void SelectionDAGBuilder::visitSIToFP(const User &I) { } void SelectionDAGBuilder::visitPtrToAddr(const User &I) { - visitPtrToInt(I); + const auto &TLI = DAG.getTargetLoweringInfo(); + const DataLayout &DL = DAG.getDataLayout(); + LLVMContext &Ctx = *DAG.getContext(); + // ptrtoaddr is equivalent to a truncate of ptrtoint to address/index width + SDValue N = getValue(I.getOperand(0)); + Type *PtrTy = I.getOperand(0)->getType(); + EVT AddrVT = EVT::getIntegerVT(Ctx, DL.getPointerAddressSizeInBits(PtrTy)); + if (auto *VTy = dyn_cast(PtrTy)) +AddrVT = EVT::getVectorVT(Ctx, AddrVT, VTy->getElementCount()); + N = DAG.getPtrExtOrTrunc(N, getCurSDLoc(), AddrVT); arsenm wrote: The LangRef says that it's always zero extend, but DAG.getPtrExtOrTrunc's comment suggests it may decide to be another extension some day? https://github.com/llvm/llvm-project/pull/139423 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [HLSL] Diagnose overlapping resource bindings (PR #140982)
https://github.com/hekota created https://github.com/llvm/llvm-project/pull/140982 Adds reporting of overlapping binding errors to `DXILPostOptimizationValidation` pass. Only runs when `DXILResourceBindingAnalysis` detects there is an overlapping binding. Fixes #110723 Depends on #140635, #140645, #140981 >From dc8a3fa961fe05fecd7718ad24d19437d8c4484e Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Wed, 21 May 2025 19:06:38 -0700 Subject: [PATCH] [HLSL] Diagnose overlapping resource bindings --- llvm/include/llvm/Analysis/DXILResource.h | 7 ++- .../DXILPostOptimizationValidation.cpp| 59 --- .../DirectX/Binding/binding-overlap-1.ll | 17 ++ .../DirectX/Binding/binding-overlap-2.ll | 17 ++ .../DirectX/Binding/binding-overlap-3.ll | 44 ++ .../typed-uav-load-additional-formats.ll | 4 +- 6 files changed, 136 insertions(+), 12 deletions(-) create mode 100644 llvm/test/CodeGen/DirectX/Binding/binding-overlap-1.ll create mode 100644 llvm/test/CodeGen/DirectX/Binding/binding-overlap-2.ll create mode 100644 llvm/test/CodeGen/DirectX/Binding/binding-overlap-3.ll diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h index a274e2294561e..f6e924041da11 100644 --- a/llvm/include/llvm/Analysis/DXILResource.h +++ b/llvm/include/llvm/Analysis/DXILResource.h @@ -355,6 +355,9 @@ class ResourceInfo { return std::tie(RecordID, Space, LowerBound, Size) < std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHS.Size); } +bool overlapsWith(const ResourceBinding &RHS) const { + return Space == RHS.Space && LowerBound + Size - 1 >= RHS.LowerBound; +} }; private: @@ -393,8 +396,8 @@ class ResourceInfo { getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const; bool operator==(const ResourceInfo &RHS) const { -return std::tie(Binding, HandleTy, Symbol) == - std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol); +return std::tie(Binding, HandleTy, Symbol, Name) == + std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol, RHS.Name); } bool operator!=(const ResourceInfo &RHS) const { return !(*this == RHS); } bool operator<(const ResourceInfo &RHS) const { diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp index 1dc0c2fb13c11..c0bb6a61e8a24 100644 --- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp +++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp @@ -9,6 +9,7 @@ #include "DXILPostOptimizationValidation.h" #include "DXILShaderFlags.h" #include "DirectX.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Analysis/DXILMetadataAnalysis.h" #include "llvm/Analysis/DXILResource.h" #include "llvm/IR/DiagnosticInfo.h" @@ -50,15 +51,55 @@ static void reportInvalidDirection(Module &M, DXILResourceMap &DRM) { } } -} // namespace +static void reportOverlappingError(Module &M, ResourceInfo R1, + ResourceInfo R2) { + SmallString<64> Message; + raw_svector_ostream OS(Message); + OS << "resource " << R1.getName() << " at register " + << R1.getBinding().LowerBound << " overlaps with resource " << R2.getName() + << " at register " << R2.getBinding().LowerBound << ", space " + << R2.getBinding().Space; + M.getContext().diagnose(DiagnosticInfoGeneric(Message)); +} -PreservedAnalyses -DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) { - DXILResourceMap &DRM = MAM.getResult(M); +static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) { + if (DRM.empty()) +return; + for (auto ResList : + {DRM.srvs(), DRM.uavs(), DRM.cbuffers(), DRM.samplers()}) { +if (ResList.empty()) + continue; +const ResourceInfo *PrevRI = &*ResList.begin(); +for (auto *I = ResList.begin() + 1; I != ResList.end(); ++I) { + const ResourceInfo *RI = &*I; + if (PrevRI->getBinding().overlapsWith(RI->getBinding())) { +reportOverlappingError(M, *PrevRI, *RI); +continue; + } + PrevRI = RI; +} + } +} + +static void reportErrors(Module &M, DXILResourceMap &DRM, + DXILResourceBindingInfo &DRBI) { if (DRM.hasInvalidCounterDirection()) reportInvalidDirection(M, DRM); + if (DRBI.hasOverlappingBinding()) +reportOverlappingBinding(M, DRM); + + assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in " + "DXILResourceImplicitBinding pass"); +} +} // namespace + +PreservedAnalyses +DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) { + DXILResourceMap &DRM = MAM.getResult(M); + DXILResourceBindingInfo &DRBI = MAM.getResult(M); + reportErrors(M, DRM, DRBI); return PreservedAnalyses::all(); } @@ -68,10 +109,9 @@ class DXILPostOptimizationValidationLegacy : public ModulePass {
[llvm-branch-commits] [llvm] [HLSL] Diagnose overlapping resource bindings (PR #140982)
llvmbot wrote: @llvm/pr-subscribers-backend-directx Author: Helena Kotas (hekota) Changes Adds reporting of overlapping binding errors to `DXILPostOptimizationValidation` pass. Only runs when `DXILResourceBindingAnalysis` detects there is an overlapping binding. Fixes #110723 Depends on #140635, #140645, #140981 --- Full diff: https://github.com/llvm/llvm-project/pull/140982.diff 6 Files Affected: - (modified) llvm/include/llvm/Analysis/DXILResource.h (+5-2) - (modified) llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp (+51-8) - (added) llvm/test/CodeGen/DirectX/Binding/binding-overlap-1.ll (+17) - (added) llvm/test/CodeGen/DirectX/Binding/binding-overlap-2.ll (+17) - (added) llvm/test/CodeGen/DirectX/Binding/binding-overlap-3.ll (+44) - (modified) llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll (+2-2) ``diff diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h index a274e2294561e..f6e924041da11 100644 --- a/llvm/include/llvm/Analysis/DXILResource.h +++ b/llvm/include/llvm/Analysis/DXILResource.h @@ -355,6 +355,9 @@ class ResourceInfo { return std::tie(RecordID, Space, LowerBound, Size) < std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHS.Size); } +bool overlapsWith(const ResourceBinding &RHS) const { + return Space == RHS.Space && LowerBound + Size - 1 >= RHS.LowerBound; +} }; private: @@ -393,8 +396,8 @@ class ResourceInfo { getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const; bool operator==(const ResourceInfo &RHS) const { -return std::tie(Binding, HandleTy, Symbol) == - std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol); +return std::tie(Binding, HandleTy, Symbol, Name) == + std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol, RHS.Name); } bool operator!=(const ResourceInfo &RHS) const { return !(*this == RHS); } bool operator<(const ResourceInfo &RHS) const { diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp index 1dc0c2fb13c11..c0bb6a61e8a24 100644 --- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp +++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp @@ -9,6 +9,7 @@ #include "DXILPostOptimizationValidation.h" #include "DXILShaderFlags.h" #include "DirectX.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Analysis/DXILMetadataAnalysis.h" #include "llvm/Analysis/DXILResource.h" #include "llvm/IR/DiagnosticInfo.h" @@ -50,15 +51,55 @@ static void reportInvalidDirection(Module &M, DXILResourceMap &DRM) { } } -} // namespace +static void reportOverlappingError(Module &M, ResourceInfo R1, + ResourceInfo R2) { + SmallString<64> Message; + raw_svector_ostream OS(Message); + OS << "resource " << R1.getName() << " at register " + << R1.getBinding().LowerBound << " overlaps with resource " << R2.getName() + << " at register " << R2.getBinding().LowerBound << ", space " + << R2.getBinding().Space; + M.getContext().diagnose(DiagnosticInfoGeneric(Message)); +} -PreservedAnalyses -DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) { - DXILResourceMap &DRM = MAM.getResult(M); +static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) { + if (DRM.empty()) +return; + for (auto ResList : + {DRM.srvs(), DRM.uavs(), DRM.cbuffers(), DRM.samplers()}) { +if (ResList.empty()) + continue; +const ResourceInfo *PrevRI = &*ResList.begin(); +for (auto *I = ResList.begin() + 1; I != ResList.end(); ++I) { + const ResourceInfo *RI = &*I; + if (PrevRI->getBinding().overlapsWith(RI->getBinding())) { +reportOverlappingError(M, *PrevRI, *RI); +continue; + } + PrevRI = RI; +} + } +} + +static void reportErrors(Module &M, DXILResourceMap &DRM, + DXILResourceBindingInfo &DRBI) { if (DRM.hasInvalidCounterDirection()) reportInvalidDirection(M, DRM); + if (DRBI.hasOverlappingBinding()) +reportOverlappingBinding(M, DRM); + + assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in " + "DXILResourceImplicitBinding pass"); +} +} // namespace + +PreservedAnalyses +DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) { + DXILResourceMap &DRM = MAM.getResult(M); + DXILResourceBindingInfo &DRBI = MAM.getResult(M); + reportErrors(M, DRM, DRBI); return PreservedAnalyses::all(); } @@ -68,10 +109,9 @@ class DXILPostOptimizationValidationLegacy : public ModulePass { bool runOnModule(Module &M) override { DXILResourceMap &DRM = getAnalysis().getResourceMap(); - -if (DRM.hasInvalidCounterDirection()) - reportInvalidDirection(M, DRM); - +DXILResourceBindingInfo &DRBI = +getAnalysis().getBindingInf
[llvm-branch-commits] [llvm] [HLSL] Diagnose overlapping resource bindings (PR #140982)
https://github.com/hekota edited https://github.com/llvm/llvm-project/pull/140982 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Implement validation of resource ranges for `RootDescriptors` (PR #140962)
llvmbot wrote: @llvm/pr-subscribers-hlsl Author: Finn Plummer (inbelic) Changes As was established [previously](https://github.com/llvm/llvm-project/pull/140957), we created a structure to model a resource range and to detect an overlap in a given set of these. However, a resource range only overlaps with another resource range if they have: - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler) - equivalent resource name-space - overlapping shader visibility For instance, the following don't overlap even though they have the same register range: - `CBV(b0)` and `SRV(t0)` (different resource class) - `CBV(b0, space = 0)` and `CBV(b0, space = 1)` (different space) - `CBV(b0, visibility = Pixel)` and `CBV(b0, visibility = Domain)` (non-overlapping visibility) The first two clauses are naturally modelled by a mapping, `map; +def err_hlsl_resource_range_overlap: Error< + "resource ranges %select{t|u|b|s}0[%1;%2] and %select{t|u|b|s}3[%4;%5] " + "overlap within space = %6 and visibility = " + "%select{All|Vertex|Hull|Domain|Geometry|Pixel|Amplification|Mesh}7">; + // Layout randomization diagnostics. def err_non_designated_init_used : Error< "a randomized struct can only be initialized with a designated initializer">; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 15182bb27bbdf..a161236d8baa0 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -119,6 +119,8 @@ class SemaHLSL : public SemaBase { bool IsCompAssign); void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc); + // Returns true when D is invalid and a diagnostic was produced + bool handleRootSignatureDecl(HLSLRootSignatureDecl *D, SourceLocation Loc); void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL); void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index e6daa67fcee95..cc53f25c766b0 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Frontend/HLSL/HLSLRootSignature.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DXILABI.h" #include "llvm/Support/ErrorHandling.h" @@ -951,6 +952,101 @@ void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str()); } +namespace { + +// A resource range overlaps with another resource range if they have: +// - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler) +// - equivalent resource space +// - overlapping visbility +class ResourceRanges { +public: + // KeyT: 32-lsb denotes resource space, and 32-msb denotes resource type enum + using KeyT = uint64_t; + + constexpr static KeyT getKey(const llvm::hlsl::rootsig::RangeInfo &Info) { +uint64_t SpacePack
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Implement validation of resource ranges for `RootDescriptors` (PR #140962)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Finn Plummer (inbelic) Changes As was established [previously](https://github.com/llvm/llvm-project/pull/140957), we created a structure to model a resource range and to detect an overlap in a given set of these. However, a resource range only overlaps with another resource range if they have: - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler) - equivalent resource name-space - overlapping shader visibility For instance, the following don't overlap even though they have the same register range: - `CBV(b0)` and `SRV(t0)` (different resource class) - `CBV(b0, space = 0)` and `CBV(b0, space = 1)` (different space) - `CBV(b0, visibility = Pixel)` and `CBV(b0, visibility = Domain)` (non-overlapping visibility) The first two clauses are naturally modelled by a mapping, `map; +def err_hlsl_resource_range_overlap: Error< + "resource ranges %select{t|u|b|s}0[%1;%2] and %select{t|u|b|s}3[%4;%5] " + "overlap within space = %6 and visibility = " + "%select{All|Vertex|Hull|Domain|Geometry|Pixel|Amplification|Mesh}7">; + // Layout randomization diagnostics. def err_non_designated_init_used : Error< "a randomized struct can only be initialized with a designated initializer">; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 15182bb27bbdf..a161236d8baa0 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -119,6 +119,8 @@ class SemaHLSL : public SemaBase { bool IsCompAssign); void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc); + // Returns true when D is invalid and a diagnostic was produced + bool handleRootSignatureDecl(HLSLRootSignatureDecl *D, SourceLocation Loc); void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL); void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index e6daa67fcee95..cc53f25c766b0 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Frontend/HLSL/HLSLRootSignature.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DXILABI.h" #include "llvm/Support/ErrorHandling.h" @@ -951,6 +952,101 @@ void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str()); } +namespace { + +// A resource range overlaps with another resource range if they have: +// - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler) +// - equivalent resource space +// - overlapping visbility +class ResourceRanges { +public: + // KeyT: 32-lsb denotes resource space, and 32-msb denotes resource type enum + using KeyT = uint64_t; + + constexpr static KeyT getKey(const llvm::hlsl::rootsig::RangeInfo &Info) { +uint64_t SpacePac
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Implement validation of resource ranges for `RootDescriptors` (PR #140962)
https://github.com/inbelic created https://github.com/llvm/llvm-project/pull/140962 As was established [previously](https://github.com/llvm/llvm-project/pull/140957), we created a structure to model a resource range and to detect an overlap in a given set of these. However, a resource range only overlaps with another resource range if they have: - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler) - equivalent resource name-space - overlapping shader visibility For instance, the following don't overlap even though they have the same register range: - `CBV(b0)` and `SRV(t0)` (different resource class) - `CBV(b0, space = 0)` and `CBV(b0, space = 1)` (different space) - `CBV(b0, visibility = Pixel)` and `CBV(b0, visibility = Domain)` (non-overlapping visibility) The first two clauses are naturally modelled by a mapping, `maphttps://github.com/llvm/llvm-project/issues/129942 >From 630dae06367b0281f3b2587b7a076accc9e51da5 Mon Sep 17 00:00:00 2001 From: Finn Plummer Date: Wed, 21 May 2025 00:12:04 + Subject: [PATCH] [HLSL][RootSignature] Plug into the thing --- .../clang/Basic/DiagnosticSemaKinds.td| 5 + clang/include/clang/Sema/SemaHLSL.h | 2 + clang/lib/Sema/SemaHLSL.cpp | 98 +++ .../RootSignature-resource-ranges-err.hlsl| 26 + .../RootSignature-resource-ranges.hlsl| 22 + .../llvm/Frontend/HLSL/HLSLRootSignature.h| 8 +- 6 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaHLSL/RootSignature-resource-ranges-err.hlsl create mode 100644 clang/test/SemaHLSL/RootSignature-resource-ranges.hlsl diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f0bd5a1174020..b1026e733ec37 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12967,6 +12967,11 @@ def err_hlsl_expect_arg_const_int_one_or_neg_one: Error< def err_invalid_hlsl_resource_type: Error< "invalid __hlsl_resource_t type attributes">; +def err_hlsl_resource_range_overlap: Error< + "resource ranges %select{t|u|b|s}0[%1;%2] and %select{t|u|b|s}3[%4;%5] " + "overlap within space = %6 and visibility = " + "%select{All|Vertex|Hull|Domain|Geometry|Pixel|Amplification|Mesh}7">; + // Layout randomization diagnostics. def err_non_designated_init_used : Error< "a randomized struct can only be initialized with a designated initializer">; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 15182bb27bbdf..a161236d8baa0 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -119,6 +119,8 @@ class SemaHLSL : public SemaBase { bool IsCompAssign); void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc); + // Returns true when D is invalid and a diagnostic was produced + bool handleRootSignatureDecl(HLSLRootSignatureDecl *D, SourceLocation Loc); void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL); void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index e6daa67fcee95..cc53f25c766b0 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Frontend/HLSL/HLSLRootSignature.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DXILABI.h" #include "llvm/Support/ErrorHandling.h" @@ -951,6 +952,101 @@ void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str()); } +namespace { + +// A resource range overlaps with another resource range if they have: +// - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler) +// - equivalent resource space +// - overlapping visbility +class ResourceRanges { +public: + // KeyT: 32-lsb denotes resource space, and 32-msb denotes resource type enum + using KeyT = uint64_t; + + constexpr static KeyT getKey(const llvm::hlsl::rootsig::RangeInfo &Info) { +uint64_t SpacePacked = (uint64_t)Info.Space; +uint64_t ClassPacked = (uint64_t)llvm::to_underlying(Info.Class); +return (ClassPacked << 32) | SpacePacked; + } + + static const unsigned NumVisEnums = 8; +// (unsigned)llvm::hlsl::rootsig::ShaderVisibility::NumEnums; + +private: + llvm::hlsl::rootsig::ResourceRange::IMap::Allocator Allocator; + + using MapT = llvm::SmallDenseMap; + + MapT RangeMaps[NumVisEnums]; + +public: + // Returns std::nullopt if there was no collision. Otherwise, it will + // return the RangeInfo of the collision + std::optional addRange(const llvm::hlsl::rootsig::RangeInfo &Info) { +MapT &VisRangeMap = RangeMaps[llvm::to_underlying(Info.Vis)]; +
[llvm-branch-commits] [llvm] [HLSL][RootSignature] Implement `ResourceRange` as an `IntervalMap` (PR #140957)
https://github.com/inbelic edited https://github.com/llvm/llvm-project/pull/140957 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Implement validation of resource ranges for `RootDescriptors` (PR #140962)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff HEAD~1 HEAD --extensions h,cpp -- clang/include/clang/Sema/SemaHLSL.h clang/lib/Sema/SemaHLSL.cpp llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h `` View the diff from clang-format here. ``diff diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index cc53f25c7..25a64e4b5 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -970,7 +970,7 @@ public: } static const unsigned NumVisEnums = 8; -// (unsigned)llvm::hlsl::rootsig::ShaderVisibility::NumEnums; + // (unsigned)llvm::hlsl::rootsig::ShaderVisibility::NumEnums; private: llvm::hlsl::rootsig::ResourceRange::IMap::Allocator Allocator; @@ -982,25 +982,27 @@ private: public: // Returns std::nullopt if there was no collision. Otherwise, it will // return the RangeInfo of the collision - std::optional addRange(const llvm::hlsl::rootsig::RangeInfo &Info) { + std::optional + addRange(const llvm::hlsl::rootsig::RangeInfo &Info) { MapT &VisRangeMap = RangeMaps[llvm::to_underlying(Info.Vis)]; -auto [It, _] = VisRangeMap.insert({getKey(Info), llvm::hlsl::rootsig::ResourceRange(Allocator)}); +auto [It, _] = VisRangeMap.insert( +{getKey(Info), llvm::hlsl::rootsig::ResourceRange(Allocator)}); auto Res = It->second.insert(Info); if (Res.has_value()) return Res; MutableArrayRef Maps = - Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All - ? MutableArrayRef{RangeMaps}.drop_front() - : MutableArrayRef{RangeMaps}.take_front(); +Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All +? MutableArrayRef{RangeMaps}.drop_front() +: MutableArrayRef{RangeMaps}.take_front(); for (MapT &CurMap : Maps) { auto CurIt = CurMap.find(getKey(Info)); if (CurIt != CurMap.end()) if (auto Overlapping = CurIt->second.getOverlapping(Info)) - return Overlapping; + return Overlapping; } - + return std::nullopt; } }; @@ -1015,15 +1017,15 @@ bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D, llvm::SmallVector Infos; for (const auto &Elem : Elements) { if (const auto *Param = -std::get_if(&Elem)) { - llvm::hlsl::rootsig::RangeInfo Info; - Info.LowerBound = Param->Reg.Number; - Info.UpperBound = Info.LowerBound; // use inclusive ranges [] +std::get_if(&Elem)) { + llvm::hlsl::rootsig::RangeInfo Info; + Info.LowerBound = Param->Reg.Number; + Info.UpperBound = Info.LowerBound; // use inclusive ranges [] - Info.Class = Param->Type; - Info.Space = Param->Space; - Info.Vis = Param->Visibility; - Infos.push_back(Info); + Info.Class = Param->Type; + Info.Space = Param->Space; + Info.Vis = Param->Visibility; + Infos.push_back(Info); } } @@ -1032,14 +1034,16 @@ bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D, bool HadOverlap = false; for (const llvm::hlsl::rootsig::RangeInfo &Info : Infos) if (auto MaybeOverlappingInfo = Ranges.addRange(Info)) { - const llvm::hlsl::rootsig::RangeInfo *OInfo = MaybeOverlappingInfo.value(); + const llvm::hlsl::rootsig::RangeInfo *OInfo = + MaybeOverlappingInfo.value(); auto CommonVis = Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All - ? OInfo->Vis : Info.Vis; + ? OInfo->Vis + : Info.Vis; Diag(Loc, diag::err_hlsl_resource_range_overlap) -<< llvm::to_underlying(Info.Class) << Info.LowerBound << Info.UpperBound -<< llvm::to_underlying(OInfo->Class) << OInfo->LowerBound << OInfo->UpperBound -<< Info.Space << CommonVis; + << llvm::to_underlying(Info.Class) << Info.LowerBound + << Info.UpperBound << llvm::to_underlying(OInfo->Class) + << OInfo->LowerBound << OInfo->UpperBound << Info.Space << CommonVis; HadOverlap = true; } `` https://github.com/llvm/llvm-project/pull/140962 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [clang] Introduce CallGraphSection option (PR #117037)
https://github.com/arsenm commented: Should get documentation change for the flag https://github.com/llvm/llvm-project/pull/117037 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [clang] Introduce CallGraphSection option (PR #117037)
@@ -467,6 +467,7 @@ static bool initTargetOptions(const CompilerInstance &CI, Options.StackUsageOutput = CodeGenOpts.StackUsageOutput; Options.EmitAddrsig = CodeGenOpts.Addrsig; Options.ForceDwarfFrameSection = CodeGenOpts.ForceDwarfFrameSection; + Options.EmitCallGraphSection = CodeGenOpts.CallGraphSection; arsenm wrote: TargetOptions :( https://github.com/llvm/llvm-project/pull/117037 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Implement validation of resource ranges for `RootDescriptors` (PR #140962)
https://github.com/inbelic edited https://github.com/llvm/llvm-project/pull/140962 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [IR] Introduce the `ptrtoaddr` instruction (PR #139357)
@@ -110,6 +110,7 @@ typedef enum { LLVMFPTrunc= 37, LLVMFPExt = 38, LLVMPtrToInt = 39, + LLVMPtrToAddr = 69, arichardson wrote: fneg and callbr also break the ordering - I think the intention in this file is to have them match the grouping in Instruction https://github.com/llvm/llvm-project/pull/139357 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Add parsing of Register in params for RootParams (PR #140148)
https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/140148 >From 994bc35f7eb1707097511a121d2a5a0b6f42637c Mon Sep 17 00:00:00 2001 From: Finn Plummer Date: Thu, 15 May 2025 19:49:44 + Subject: [PATCH 1/2] [HLSL][RootSignature] Add parsing of Register in params for RootParams - defines the `parseRootParamParams` infastructure for parsing the params of a RootParam - defines the register type to illustrate use - add tests to demonstrate functionality --- .../clang/Parse/ParseHLSLRootSignature.h | 6 +++ clang/lib/Parse/ParseHLSLRootSignature.cpp| 42 +++ .../Parse/ParseHLSLRootSignatureTest.cpp | 13 -- .../llvm/Frontend/HLSL/HLSLRootSignature.h| 1 + 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h index b96416ab6c6c4..92b8e7389426a 100644 --- a/clang/include/clang/Parse/ParseHLSLRootSignature.h +++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h @@ -89,6 +89,12 @@ class RootSignatureParser { }; std::optional parseRootConstantParams(); + struct ParsedRootParamParams { +std::optional Reg; + }; + std::optional + parseRootParamParams(RootSignatureToken::Kind RegType); + struct ParsedClauseParams { std::optional Reg; std::optional NumDescriptors; diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp index 3ed60442eaa14..de7c2452b3fd4 100644 --- a/clang/lib/Parse/ParseHLSLRootSignature.cpp +++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp @@ -176,20 +176,37 @@ std::optional RootSignatureParser::parseRootParam() { return std::nullopt; RootParam Param; + TokenKind ExpectedReg; switch (ParamKind) { default: llvm_unreachable("Switch for consumed token was not provided"); case TokenKind::kw_CBV: Param.Type = ParamType::CBuffer; +ExpectedReg = TokenKind::bReg; break; case TokenKind::kw_SRV: Param.Type = ParamType::SRV; +ExpectedReg = TokenKind::tReg; break; case TokenKind::kw_UAV: Param.Type = ParamType::UAV; +ExpectedReg = TokenKind::uReg; break; } + auto Params = parseRootParamParams(ExpectedReg); + if (!Params.has_value()) +return std::nullopt; + + // Check mandatory parameters were provided + if (!Params->Reg.has_value()) { +getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_missing_param) +<< ExpectedReg; +return std::nullopt; + } + + Param.Reg = Params->Reg.value(); + if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_hlsl_unexpected_end_of_params, /*param of=*/TokenKind::kw_RootConstants)) @@ -398,6 +415,31 @@ RootSignatureParser::parseRootConstantParams() { return Params; } +std::optional +RootSignatureParser::parseRootParamParams(TokenKind RegType) { + assert(CurToken.TokKind == TokenKind::pu_l_paren && + "Expects to only be invoked starting at given token"); + + ParsedRootParamParams Params; + do { +// ( `b` | `t` | `u`) POS_INT +if (tryConsumeExpectedToken(RegType)) { + if (Params.Reg.has_value()) { +getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_repeat_param) +<< CurToken.TokKind; +return std::nullopt; + } + auto Reg = parseRegister(); + if (!Reg.has_value()) +return std::nullopt; + Params.Reg = Reg; +} + + } while (tryConsumeExpectedToken(TokenKind::pu_comma)); + + return Params; +} + std::optional RootSignatureParser::parseDescriptorTableClauseParams(TokenKind RegType) { assert(CurToken.TokKind == TokenKind::pu_l_paren && diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp index 876dcd17f0389..0f32523493a53 100644 --- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp +++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp @@ -346,9 +346,9 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootFlagsTest) { TEST_F(ParseHLSLRootSignatureTest, ValidParseRootParamsTest) { const llvm::StringLiteral Source = R"cc( -CBV(), -SRV(), -UAV() +CBV(b0), +SRV(t42), +UAV(u34893247) )cc"; TrivialModuleLoader ModLoader; @@ -368,15 +368,20 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootParamsTest) { RootElement Elem = Elements[0]; ASSERT_TRUE(std::holds_alternative(Elem)); - ASSERT_EQ(std::get(Elem).Type, ParamType::CBuffer); + ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::BReg); + ASSERT_EQ(std::get(Elem).Reg.Number, 0u); Elem = Elements[1]; ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ParamType::SRV); + ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::TReg); + ASSERT_EQ(std::get(Elem).Reg.Number, 42u); Elem = Elements[2]; ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std:
[llvm-branch-commits] [clang] [clang] Introduce CallGraphSection option (PR #117037)
@@ -0,0 +1,5 @@ +// RUN: %clang -### -S -fcall-graph-section %s 2>&1 | FileCheck --check-prefix=CALL-GRAPH-SECTION %s +// RUN: %clang -### -S -fcall-graph-section -fno-call-graph-section %s 2>&1 | FileCheck --check-prefix=NO-CALL-GRAPH-SECTION %s arsenm wrote: ```suggestion // RUN: %clang -### -fcall-graph-section %s 2>&1 | FileCheck --check-prefix=CALL-GRAPH-SECTION %s // RUN: %clang -### -fcall-graph-section -fno-call-graph-section %s 2>&1 | FileCheck --check-prefix=NO-CALL-GRAPH-SECTION %s ``` Don't really care about the output type if you aren't using it https://github.com/llvm/llvm-project/pull/117037 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [clang] Introduce CallGraphSection option (PR #117037)
https://github.com/arsenm edited https://github.com/llvm/llvm-project/pull/117037 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [IR] Introduce the `ptrtoaddr` instruction (PR #139357)
@@ -7,9 +7,9 @@ define i32 @nested(i32 %src) #0 { ; CHECK-SAME: i32 [[A0:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: [[BB15160:.*:]] ; CHECK-NEXT:[[T1:%.*]] = call token @llvm.experimental.convergence.entry() -; CHECK-NEXT:%"vl77672llvm.experimental.convergence.anchor()" = call token @llvm.experimental.convergence.anchor() -; CHECK-NEXT:%"op68297(vl77672)" = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[A0]]) [ "convergencectrl"(token %"vl77672llvm.experimental.convergence.anchor()") ] -; CHECK-NEXT:ret i32 %"op68297(vl77672)" +; CHECK-NEXT:%"vl14659llvm.experimental.convergence.anchor()" = call token @llvm.experimental.convergence.anchor() +; CHECK-NEXT:%"op15516(vl14659)" = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[A0]]) [ "convergencectrl"(token %"vl14659llvm.experimental.convergence.anchor()") ] +; CHECK-NEXT:ret i32 %"op15516(vl14659)" arichardson wrote: I believe this is because all the other instruction kind numbers after the casts changed to the overall hash value is different. I can do the same thing as the C API and allocate the next unused value but e.g. freeze didn't do this either. https://github.com/llvm/llvm-project/pull/139357 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [IR] Introduce the `ptrtoaddr` instruction (PR #139357)
@@ -0,0 +1,14 @@ +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s arichardson wrote: I copied this from another test so assumed there was a reason for it but not sure what that would be. https://github.com/llvm/llvm-project/pull/139357 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [GISelValueTracking] Use representation size for G_PTRTOINT src width (PR #139608)
arichardson wrote: Thanks for the review, I'll update this to use a new baseline test that does not depend on the new ptrtoaddr. https://github.com/llvm/llvm-project/pull/139608 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] CodeGen: Fix implementation of __builtin_trivially_relocate. (PR #140312)
https://github.com/pcc updated https://github.com/llvm/llvm-project/pull/140312 >From 1399ec4fdf8fe08000b590844f4e24c31a310a01 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Wed, 21 May 2025 16:20:57 -0700 Subject: [PATCH] Add test with variable count Created using spr 1.3.6-beta.1 --- .../CodeGenCXX/cxx2c-trivially-relocatable.cpp | 14 ++ 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/clang/test/CodeGenCXX/cxx2c-trivially-relocatable.cpp b/clang/test/CodeGenCXX/cxx2c-trivially-relocatable.cpp index 63f3ba8e74ed5..465e539d363e8 100644 --- a/clang/test/CodeGenCXX/cxx2c-trivially-relocatable.cpp +++ b/clang/test/CodeGenCXX/cxx2c-trivially-relocatable.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -std=c++26 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s +typedef __SIZE_TYPE__ size_t; + struct S trivially_relocatable_if_eligible { S(const S&); ~S(); @@ -8,9 +10,13 @@ struct S trivially_relocatable_if_eligible { }; // CHECK: @_Z4testP1SS0_ -// CHECK: call void @llvm.memmove.p0.p0.i64({{.*}}, i64 8 -// CHECK-NOT: __builtin -// CHECK: ret -void test(S* source, S* dest) { +void test(S* source, S* dest, size_t count) { +// CHECK: call void @llvm.memmove.p0.p0.i64({{.*}}, i64 8 +// CHECK-NOT: __builtin __builtin_trivially_relocate(dest, source, 1); +// CHECK: [[A:%.*]] = load i64, ptr %count.addr +// CHECK: [[M:%.*]] = mul i64 [[A]], 8 +// CHECK: call void @llvm.memmove.p0.p0.i64({{.*}}, i64 [[M]] +__builtin_trivially_relocate(dest, source, count); +// CHECK: ret }; ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] CodeGen: Fix implementation of __builtin_trivially_relocate. (PR #140312)
@@ -8,7 +8,7 @@ struct S trivially_relocatable_if_eligible { }; // CHECK: @_Z4testP1SS0_ -// CHECK: call void @llvm.memmove.p0.p0.i64 +// CHECK: call void @llvm.memmove.p0.p0.i64({{.*}}, i64 8 pcc wrote: Done https://github.com/llvm/llvm-project/pull/140312 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] c5c50f0 - Revert "[llvm] add GenericFloatingPointPredicateUtils (#140254)"
Author: ronlieb Date: 2025-05-21T19:30:12-04:00 New Revision: c5c50f0c35141a7d219d38a8196f19ec2ca6c433 URL: https://github.com/llvm/llvm-project/commit/c5c50f0c35141a7d219d38a8196f19ec2ca6c433 DIFF: https://github.com/llvm/llvm-project/commit/c5c50f0c35141a7d219d38a8196f19ec2ca6c433.diff LOG: Revert "[llvm] add GenericFloatingPointPredicateUtils (#140254)" This reverts commit d00d74bb2564103ae3cb5ac6b6ffecf7e1cc2238. Added: Modified: llvm/include/llvm/Analysis/ValueTracking.h llvm/lib/Analysis/CMakeLists.txt llvm/lib/Analysis/InstructionSimplify.cpp llvm/lib/Analysis/ValueTracking.cpp llvm/lib/CodeGen/CMakeLists.txt llvm/lib/CodeGen/CodeGenPrepare.cpp llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp llvm/unittests/Analysis/ValueTrackingTest.cpp Removed: llvm/include/llvm/ADT/GenericFloatingPointPredicateUtils.h llvm/include/llvm/Analysis/FloatingPointPredicateUtils.h llvm/include/llvm/CodeGen/MachineFloatingPointPredicateUtils.h llvm/lib/Analysis/FloatingPointPredicateUtils.cpp llvm/lib/CodeGen/MachineFloatingPointPredicateUtils.cpp diff --git a/llvm/include/llvm/ADT/GenericFloatingPointPredicateUtils.h b/llvm/include/llvm/ADT/GenericFloatingPointPredicateUtils.h deleted file mode 100644 index 49c5fe0aed6e1..0 --- a/llvm/include/llvm/ADT/GenericFloatingPointPredicateUtils.h +++ /dev/null @@ -1,479 +0,0 @@ -//===- llvm/Support/GenericFloatingPointPredicateUtils.h -*- C++-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===--===// -/// -/// \file -/// Utilities for dealing with flags related to floating point properties and -/// mode controls. -/// -//===--===/ - -#ifndef LLVM_ADT_GENERICFLOATINGPOINTPREDICATEUTILS_H -#define LLVM_ADT_GENERICFLOATINGPOINTPREDICATEUTILS_H - -#include "llvm/ADT/APFloat.h" -#include "llvm/ADT/FloatingPointMode.h" -#include "llvm/IR/Instructions.h" -#include - -namespace llvm { - -template class GenericFloatingPointPredicateUtils { - using ValueRefT = typename ContextT::ValueRefT; - using FunctionT = typename ContextT::FunctionT; - - constexpr static ValueRefT Invalid = {}; - -private: - static DenormalMode queryDenormalMode(const FunctionT &F, ValueRefT Val); - - static bool lookThroughFAbs(const FunctionT &F, ValueRefT LHS, - ValueRefT &Src); - - static std::optional matchConstantFloat(const FunctionT &F, - ValueRefT Val); - - /// Return the return value for fcmpImpliesClass for a compare that produces - /// an exact class test. - static std::tuple - exactClass(ValueRefT V, FPClassTest M) { -return {V, M, ~M}; - } - -public: - /// Returns a pair of values, which if passed to llvm.is.fpclass, returns the - /// same result as an fcmp with the given operands. - static std::pair - fcmpToClassTest(FCmpInst::Predicate Pred, const FunctionT &F, ValueRefT LHS, - ValueRefT RHS, bool LookThroughSrc) { -std::optional ConstRHS = matchConstantFloat(F, RHS); -if (!ConstRHS) - return {Invalid, fcAllFlags}; - -return fcmpToClassTest(Pred, F, LHS, *ConstRHS, LookThroughSrc); - } - - static std::pair - fcmpToClassTest(FCmpInst::Predicate Pred, const FunctionT &F, ValueRefT LHS, - const APFloat &ConstRHS, bool LookThroughSrc) { - -auto [Src, ClassIfTrue, ClassIfFalse] = -fcmpImpliesClass(Pred, F, LHS, ConstRHS, LookThroughSrc); - -if (Src && ClassIfTrue == ~ClassIfFalse) - return {Src, ClassIfTrue}; - -return {Invalid, fcAllFlags}; - } - - /// Compute the possible floating-point classes that \p LHS could be based on - /// fcmp \Pred \p LHS, \p RHS. - /// - /// \returns { TestedValue, ClassesIfTrue, ClassesIfFalse } - /// - /// If the compare returns an exact class test, ClassesIfTrue == - /// ~ClassesIfFalse - /// - /// This is a less exact version of fcmpToClassTest (e.g. fcmpToClassTest will - /// only succeed for a test of x > 0 implies positive, but not x > 1). - /// - /// If \p LookThroughSrc is true, consider the input value when computing the - /// mask. This may look through sign bit operations. - /// - /// If \p LookThroughSrc is false, ignore the source value (i.e. the first - /// pair element will always be LHS. - /// - static std::tuple - fcmpImpliesClass(CmpInst::Predicate Pred, const FunctionT &F, ValueRefT LHS, - FPClassTest RHSClass, bool LookThroughSrc) { -assert(RHSClass != fcNone); -ValueRefT Src = LHS; - -if (Pred == FCmpInst::FCMP_TRUE) - return exactClass(Src,
[llvm-branch-commits] [clang] [KeyInstr] Complex assignment atoms (PR #134638)
https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/134638 >From fd282a63fd709cdcdcdc2dacef58144dbf9b15c1 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 3 Apr 2025 13:36:59 +0100 Subject: [PATCH] [KeyInstr] Complex assignment atoms This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. The Key Instructions project is introduced, including a "quick summary" section at the top which adds context for this PR, here: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed. The Clang-side work is demoed here: https://github.com/llvm/llvm-project/pull/130943 --- clang/lib/CodeGen/CGExprComplex.cpp | 10 - .../test/DebugInfo/KeyInstructions/complex.c | 40 +++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 clang/test/DebugInfo/KeyInstructions/complex.c diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index f556594f4a9ec..600f61f1b325f 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -461,8 +461,12 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, LValue lvalue, Address RealPtr = CGF.emitAddrOfRealComponent(Ptr, lvalue.getType()); Address ImagPtr = CGF.emitAddrOfImagComponent(Ptr, lvalue.getType()); - Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified()); - Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified()); + auto *R = + Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified()); + CGF.addInstToCurrentSourceAtom(R, Val.first); + auto *I = + Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified()); + CGF.addInstToCurrentSourceAtom(I, Val.second); } @@ -1209,6 +1213,7 @@ LValue ComplexExprEmitter:: EmitCompoundAssignLValue(const CompoundAssignOperator *E, ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&), RValue &Val) { + ApplyAtomGroup Grp(CGF.getDebugInfo()); TestAndClearIgnoreReal(); TestAndClearIgnoreImag(); QualType LHSTy = E->getLHS()->getType(); @@ -1356,6 +1361,7 @@ LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E, } ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) { + ApplyAtomGroup Grp(CGF.getDebugInfo()); ComplexPairTy Val; LValue LV = EmitBinAssignLValue(E, Val); diff --git a/clang/test/DebugInfo/KeyInstructions/complex.c b/clang/test/DebugInfo/KeyInstructions/complex.c new file mode 100644 index 0..b97314e815bdc --- /dev/null +++ b/clang/test/DebugInfo/KeyInstructions/complex.c @@ -0,0 +1,40 @@ + +// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +_Complex float ci; +void test() { +// CHECK: %ci.real = load float, ptr @ci{{.*}}, !dbg [[G1R2:!.*]] +// CHECK: %ci.imag = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G1R2]] +// CHECK: store float %ci.real, ptr %lc.realp{{.*}}, !dbg [[G1R1:!.*]] +// CHECK: store float %ci.imag, ptr %lc.imagp{{.*}}, !dbg [[G1R1]] + _Complex float lc = ci; + +// CHECK: %ci.real1 = load float, ptr @ci{{.*}}, !dbg [[G2R2:!.*]] +// CHECK: %ci.imag2 = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R2]] +// CHECK: store float %ci.real1, ptr @ci{{.*}}, !dbg [[G2R1:!.*]] +// CHECK: store float %ci.imag2, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R1]] + ci = ci; + +// CHECK: %add.r = fadd float %ci.real5, %ci.real3, !dbg [[G3R2:!.*]] +// CHECK: %add.i = fadd float %ci.imag6, %ci.imag4, !dbg [[G3R2]] +// CHECK: store float %add.r, ptr @ci{{.*}}, !dbg [[G3R1:!.*]] +// CHECK: store float %add.i, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G3R1]] + ci += ci; + +// CHECK: %add = fadd float %0, %1, !dbg [[G4R2:!.*]] +// CHECK: store float %add, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G4R1:!.*]] + __imag ci = __imag ci + __imag ci; +} + +// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2) +// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) +// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2) +// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) +// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGroup:
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assignment atom group (PR #134637)
https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/134637 >From 3b4ca1b09a659e575e022109fd8c607c9df3864f Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Wed, 2 Apr 2025 18:01:48 +0100 Subject: [PATCH 1/6] [KeyInstr][Clang] Assignment atom group This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. The Key Instructions project is introduced, including a "quick summary" section at the top which adds context for this PR, here: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed. The Clang-side work is demoed here: https://github.com/llvm/llvm-project/pull/130943 --- clang/lib/CodeGen/CGExpr.cpp| 9 + clang/test/DebugInfo/KeyInstructions/assign.cpp | 9 + 2 files changed, 18 insertions(+) create mode 100644 clang/test/DebugInfo/KeyInstructions/assign.cpp diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 1e426586620a2..9681fd9325fa7 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5985,6 +5985,15 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { assert(E->getOpcode() == BO_Assign && "unexpected binary l-value"); + // This covers both LHS and RHS expressions, though nested RHS + // expressions may get subsequently separately grouped. + // FIXME(OCH): Not clear yet if we've got fine enough control + // to pick and choose when we need to. Currently looks ok: + // a = b = c -> Two atoms. + // x = new(1) -> One atom (for both addr store and value store). + // Complex and agg assignment -> One atom. + ApplyAtomGroup Grp(getDebugInfo()); + // Note that in all of these cases, __block variables need the RHS // evaluated first just in case the variable gets moved by the RHS. diff --git a/clang/test/DebugInfo/KeyInstructions/assign.cpp b/clang/test/DebugInfo/KeyInstructions/assign.cpp new file mode 100644 index 0..b09137430156f --- /dev/null +++ b/clang/test/DebugInfo/KeyInstructions/assign.cpp @@ -0,0 +1,9 @@ +// RUN: %clang -gkey-instructions %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +unsigned long long g; +void fun() { g = 0; } + +// CHECK: store i64 0, ptr @g{{.*}}, !dbg [[G1R1:!.*]] + +// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) >From b6274d2afefac7c4546ba5b295b01ce2a3fa74d9 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Wed, 2 Apr 2025 18:27:59 +0100 Subject: [PATCH 2/6] [KeyInstr][Clang] Multiple assignment (x = y = z) --- clang/lib/CodeGen/CGExprScalar.cpp | 1 + .../test/DebugInfo/KeyInstructions/assign.cpp | 18 -- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 5d618658bc615..1cc5c147c595b 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -5067,6 +5067,7 @@ llvm::Value *CodeGenFunction::EmitWithOriginalRHSBitfieldAssignment( } Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { + ApplyAtomGroup Grp(CGF.getDebugInfo()); bool Ignore = TestAndClearIgnoreResultAssign(); Value *RHS; diff --git a/clang/test/DebugInfo/KeyInstructions/assign.cpp b/clang/test/DebugInfo/KeyInstructions/assign.cpp index b09137430156f..d50062d21935b 100644 --- a/clang/test/DebugInfo/KeyInstructions/assign.cpp +++ b/clang/test/DebugInfo/KeyInstructions/assign.cpp @@ -2,8 +2,22 @@ // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank unsigned long long g; -void fun() { g = 0; } - +void fun() { // CHECK: store i64 0, ptr @g{{.*}}, !dbg [[G1R1:!.*]] +g = 0; + +// Treat the two assignments as two atoms. +// +// FIXME: Because of the atomGroup implementation the load can only be +// associated with one of the two stores, despite being a good backup +// loction for both. +// CHECK-NEXT: %0 = load i64, ptr @g{{.*}}, !dbg [[G2R2:!.*]] +// CHECK-NEXT: store i64 %0, ptr @g{{.*}}, !dbg [[G3R1:!.*]] +// CHECK-NEXT: store i64 %0, ptr @g{{.*}}, !dbg [[G2R1:!.*]] +g = g = g; +} // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) +// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2) +// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1) +// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) >From 0ce86c40443015f1f84d7e75dc60cf3e6fe6f7fa Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 3 Apr 2025 11:05:29 +0100 Subject: [PATCH 3/6] Compound assign --- clang/lib/CodeGen/CGExprScalar.cpp| 2 ++ .../DebugInfo/KeyInstructions/assign-scal
[llvm-branch-commits] [clang] [KeyInstr] Complex assignment atoms (PR #134638)
https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/134638 >From fd282a63fd709cdcdcdc2dacef58144dbf9b15c1 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 3 Apr 2025 13:36:59 +0100 Subject: [PATCH 1/2] [KeyInstr] Complex assignment atoms This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. The Key Instructions project is introduced, including a "quick summary" section at the top which adds context for this PR, here: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed. The Clang-side work is demoed here: https://github.com/llvm/llvm-project/pull/130943 --- clang/lib/CodeGen/CGExprComplex.cpp | 10 - .../test/DebugInfo/KeyInstructions/complex.c | 40 +++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 clang/test/DebugInfo/KeyInstructions/complex.c diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index f556594f4a9ec..600f61f1b325f 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -461,8 +461,12 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, LValue lvalue, Address RealPtr = CGF.emitAddrOfRealComponent(Ptr, lvalue.getType()); Address ImagPtr = CGF.emitAddrOfImagComponent(Ptr, lvalue.getType()); - Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified()); - Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified()); + auto *R = + Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified()); + CGF.addInstToCurrentSourceAtom(R, Val.first); + auto *I = + Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified()); + CGF.addInstToCurrentSourceAtom(I, Val.second); } @@ -1209,6 +1213,7 @@ LValue ComplexExprEmitter:: EmitCompoundAssignLValue(const CompoundAssignOperator *E, ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&), RValue &Val) { + ApplyAtomGroup Grp(CGF.getDebugInfo()); TestAndClearIgnoreReal(); TestAndClearIgnoreImag(); QualType LHSTy = E->getLHS()->getType(); @@ -1356,6 +1361,7 @@ LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E, } ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) { + ApplyAtomGroup Grp(CGF.getDebugInfo()); ComplexPairTy Val; LValue LV = EmitBinAssignLValue(E, Val); diff --git a/clang/test/DebugInfo/KeyInstructions/complex.c b/clang/test/DebugInfo/KeyInstructions/complex.c new file mode 100644 index 0..b97314e815bdc --- /dev/null +++ b/clang/test/DebugInfo/KeyInstructions/complex.c @@ -0,0 +1,40 @@ + +// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +_Complex float ci; +void test() { +// CHECK: %ci.real = load float, ptr @ci{{.*}}, !dbg [[G1R2:!.*]] +// CHECK: %ci.imag = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G1R2]] +// CHECK: store float %ci.real, ptr %lc.realp{{.*}}, !dbg [[G1R1:!.*]] +// CHECK: store float %ci.imag, ptr %lc.imagp{{.*}}, !dbg [[G1R1]] + _Complex float lc = ci; + +// CHECK: %ci.real1 = load float, ptr @ci{{.*}}, !dbg [[G2R2:!.*]] +// CHECK: %ci.imag2 = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R2]] +// CHECK: store float %ci.real1, ptr @ci{{.*}}, !dbg [[G2R1:!.*]] +// CHECK: store float %ci.imag2, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R1]] + ci = ci; + +// CHECK: %add.r = fadd float %ci.real5, %ci.real3, !dbg [[G3R2:!.*]] +// CHECK: %add.i = fadd float %ci.imag6, %ci.imag4, !dbg [[G3R2]] +// CHECK: store float %add.r, ptr @ci{{.*}}, !dbg [[G3R1:!.*]] +// CHECK: store float %add.i, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G3R1]] + ci += ci; + +// CHECK: %add = fadd float %0, %1, !dbg [[G4R2:!.*]] +// CHECK: store float %add, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G4R1:!.*]] + __imag ci = __imag ci + __imag ci; +} + +// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2) +// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) +// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2) +// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) +// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGr
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assignment atom group (PR #134637)
https://github.com/OCHyams edited https://github.com/llvm/llvm-project/pull/134637 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [libclc] [libclc] Include isnan implementation for SPIR-V targets (PR #140902)
github-actions[bot] wrote: 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](https://llvm.org/docs/GitHub.html). You can also ask questions in a comment on this PR, on the [LLVM Discord](https://discord.com/invite/xS7Z362) or on the [forums](https://discourse.llvm.org/). https://github.com/llvm/llvm-project/pull/140902 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr] Complex assignment atoms (PR #134638)
https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/134638 >From fd282a63fd709cdcdcdc2dacef58144dbf9b15c1 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 3 Apr 2025 13:36:59 +0100 Subject: [PATCH 1/3] [KeyInstr] Complex assignment atoms This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. The Key Instructions project is introduced, including a "quick summary" section at the top which adds context for this PR, here: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed. The Clang-side work is demoed here: https://github.com/llvm/llvm-project/pull/130943 --- clang/lib/CodeGen/CGExprComplex.cpp | 10 - .../test/DebugInfo/KeyInstructions/complex.c | 40 +++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 clang/test/DebugInfo/KeyInstructions/complex.c diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index f556594f4a9ec..600f61f1b325f 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -461,8 +461,12 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, LValue lvalue, Address RealPtr = CGF.emitAddrOfRealComponent(Ptr, lvalue.getType()); Address ImagPtr = CGF.emitAddrOfImagComponent(Ptr, lvalue.getType()); - Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified()); - Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified()); + auto *R = + Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified()); + CGF.addInstToCurrentSourceAtom(R, Val.first); + auto *I = + Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified()); + CGF.addInstToCurrentSourceAtom(I, Val.second); } @@ -1209,6 +1213,7 @@ LValue ComplexExprEmitter:: EmitCompoundAssignLValue(const CompoundAssignOperator *E, ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&), RValue &Val) { + ApplyAtomGroup Grp(CGF.getDebugInfo()); TestAndClearIgnoreReal(); TestAndClearIgnoreImag(); QualType LHSTy = E->getLHS()->getType(); @@ -1356,6 +1361,7 @@ LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E, } ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) { + ApplyAtomGroup Grp(CGF.getDebugInfo()); ComplexPairTy Val; LValue LV = EmitBinAssignLValue(E, Val); diff --git a/clang/test/DebugInfo/KeyInstructions/complex.c b/clang/test/DebugInfo/KeyInstructions/complex.c new file mode 100644 index 0..b97314e815bdc --- /dev/null +++ b/clang/test/DebugInfo/KeyInstructions/complex.c @@ -0,0 +1,40 @@ + +// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +_Complex float ci; +void test() { +// CHECK: %ci.real = load float, ptr @ci{{.*}}, !dbg [[G1R2:!.*]] +// CHECK: %ci.imag = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G1R2]] +// CHECK: store float %ci.real, ptr %lc.realp{{.*}}, !dbg [[G1R1:!.*]] +// CHECK: store float %ci.imag, ptr %lc.imagp{{.*}}, !dbg [[G1R1]] + _Complex float lc = ci; + +// CHECK: %ci.real1 = load float, ptr @ci{{.*}}, !dbg [[G2R2:!.*]] +// CHECK: %ci.imag2 = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R2]] +// CHECK: store float %ci.real1, ptr @ci{{.*}}, !dbg [[G2R1:!.*]] +// CHECK: store float %ci.imag2, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R1]] + ci = ci; + +// CHECK: %add.r = fadd float %ci.real5, %ci.real3, !dbg [[G3R2:!.*]] +// CHECK: %add.i = fadd float %ci.imag6, %ci.imag4, !dbg [[G3R2]] +// CHECK: store float %add.r, ptr @ci{{.*}}, !dbg [[G3R1:!.*]] +// CHECK: store float %add.i, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G3R1]] + ci += ci; + +// CHECK: %add = fadd float %0, %1, !dbg [[G4R2:!.*]] +// CHECK: store float %add, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G4R1:!.*]] + __imag ci = __imag ci + __imag ci; +} + +// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2) +// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) +// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2) +// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) +// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGr
[llvm-branch-commits] [libclc] [libclc] Include isnan implementation for SPIR-V targets (PR #140902)
https://github.com/karolherbst updated https://github.com/llvm/llvm-project/pull/140902 >From d8ad1f550cf4c32bc07f11a911d0dd7f54d2ba28 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Wed, 21 May 2025 15:57:38 +0200 Subject: [PATCH] [libclc] Include isnan implementation for SPIR-V targets The fma software emulation requires it. Similar to https://github.com/llvm/llvm-project/pull/124614 --- libclc/spirv/lib/SOURCES | 1 + libclc/spirv64/lib/SOURCES | 1 + 2 files changed, 2 insertions(+) diff --git a/libclc/spirv/lib/SOURCES b/libclc/spirv/lib/SOURCES index 854cba614c8bf..2566620161f93 100644 --- a/libclc/spirv/lib/SOURCES +++ b/libclc/spirv/lib/SOURCES @@ -86,5 +86,6 @@ math/fma.cl ../../generic/lib/math/clc_tanpi.cl ../../generic/lib/math/tanpi.cl ../../generic/lib/math/tgamma.cl +../../generic/lib/relational/isnan.cl ../../generic/lib/shared/vload.cl ../../generic/lib/shared/vstore.cl diff --git a/libclc/spirv64/lib/SOURCES b/libclc/spirv64/lib/SOURCES index 854cba614c8bf..2566620161f93 100644 --- a/libclc/spirv64/lib/SOURCES +++ b/libclc/spirv64/lib/SOURCES @@ -86,5 +86,6 @@ math/fma.cl ../../generic/lib/math/clc_tanpi.cl ../../generic/lib/math/tanpi.cl ../../generic/lib/math/tgamma.cl +../../generic/lib/relational/isnan.cl ../../generic/lib/shared/vload.cl ../../generic/lib/shared/vstore.cl ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [libclc] release/20.x: [libclc] Include isnan implementation for SPIR-V targets (PR #140902)
https://github.com/karolherbst edited https://github.com/llvm/llvm-project/pull/140902 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/20.x: [clang-format] Fix the indent of StartOfName after Attr… (PR #141004)
https://github.com/owenca created https://github.com/llvm/llvm-project/pull/141004 …ibuteMacro (#140361) Backport 0cac25bcf5a246eb8a1f02d5041731ae9a6f00e0 >From b05983ec62a831de375e96f9ddb9e87e8043049d Mon Sep 17 00:00:00 2001 From: Owen Pan Date: Wed, 21 May 2025 21:37:54 -0700 Subject: [PATCH] release/20.x: [clang-format] Fix the indent of StartOfName after AttributeMacro (#140361) Backport 0cac25bcf5a246eb8a1f02d5041731ae9a6f00e0 --- clang/lib/Format/ContinuationIndenter.cpp | 4 +++- clang/unittests/Format/FormatTest.cpp | 7 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 6f7d213c0b559..d953348b0258d 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -1452,7 +1452,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { (PreviousNonComment->ClosesTemplateDeclaration || PreviousNonComment->ClosesRequiresClause || (PreviousNonComment->is(TT_AttributeMacro) && - Current.isNot(tok::l_paren)) || + Current.isNot(tok::l_paren) && + !Current.endsSequence(TT_StartOfName, TT_AttributeMacro, + TT_PointerOrReference)) || PreviousNonComment->isOneOf( TT_AttributeRParen, TT_AttributeSquare, TT_FunctionAnnotationRParen, TT_JavaAnnotation, TT_LeadingJavaAnnotation))) || diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 90a79230e9f4c..1afcc75a2e19e 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -12419,6 +12419,13 @@ TEST_F(FormatTest, UnderstandsAttributes) { verifyFormat("SomeType s __unused{InitValue};", CustomAttrs); verifyFormat("SomeType *__capability s(InitValue);", CustomAttrs); verifyFormat("SomeType *__capability s{InitValue};", CustomAttrs); + + auto Style = getLLVMStyleWithColumns(60); + Style.AttributeMacros.push_back("my_fancy_attr"); + Style.PointerAlignment = FormatStyle::PAS_Left; + verifyFormat("void foo(const MyLongTypeName* my_fancy_attr\n" + " testt);", + Style); } TEST_F(FormatTest, UnderstandsPointerQualifiersInCast) { ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/20.x: [clang-format] Fix the indent of StartOfName after Attr… (PR #141004)
llvmbot wrote: @llvm/pr-subscribers-clang-format Author: Owen Pan (owenca) Changes …ibuteMacro (#140361) Backport 0cac25bcf5a246eb8a1f02d5041731ae9a6f00e0 --- Full diff: https://github.com/llvm/llvm-project/pull/141004.diff 2 Files Affected: - (modified) clang/lib/Format/ContinuationIndenter.cpp (+3-1) - (modified) clang/unittests/Format/FormatTest.cpp (+7) ``diff diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 6f7d213c0b559..d953348b0258d 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -1452,7 +1452,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { (PreviousNonComment->ClosesTemplateDeclaration || PreviousNonComment->ClosesRequiresClause || (PreviousNonComment->is(TT_AttributeMacro) && - Current.isNot(tok::l_paren)) || + Current.isNot(tok::l_paren) && + !Current.endsSequence(TT_StartOfName, TT_AttributeMacro, + TT_PointerOrReference)) || PreviousNonComment->isOneOf( TT_AttributeRParen, TT_AttributeSquare, TT_FunctionAnnotationRParen, TT_JavaAnnotation, TT_LeadingJavaAnnotation))) || diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 90a79230e9f4c..1afcc75a2e19e 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -12419,6 +12419,13 @@ TEST_F(FormatTest, UnderstandsAttributes) { verifyFormat("SomeType s __unused{InitValue};", CustomAttrs); verifyFormat("SomeType *__capability s(InitValue);", CustomAttrs); verifyFormat("SomeType *__capability s{InitValue};", CustomAttrs); + + auto Style = getLLVMStyleWithColumns(60); + Style.AttributeMacros.push_back("my_fancy_attr"); + Style.PointerAlignment = FormatStyle::PAS_Left; + verifyFormat("void foo(const MyLongTypeName* my_fancy_attr\n" + " testt);", + Style); } TEST_F(FormatTest, UnderstandsPointerQualifiersInCast) { `` https://github.com/llvm/llvm-project/pull/141004 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/20.x: [clang-format] Fix the indent of StartOfName after Attr… (PR #141004)
https://github.com/owenca milestoned https://github.com/llvm/llvm-project/pull/141004 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/20.x: [clang-format] Handle raw string literals containing JSON code (#140666) (PR #141002)
https://github.com/llvmbot milestoned https://github.com/llvm/llvm-project/pull/141002 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/20.x: [clang-format] Handle raw string literals containing JSON code (#140666) (PR #141002)
https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/141002 Backport 0dfdf7efbfe347517eb4c7f544043a71af4e4a25 Requested by: @owenca >From 3d02c7ce3c8b4c397c3237ed3d5069c829a1808e Mon Sep 17 00:00:00 2001 From: Owen Pan Date: Tue, 20 May 2025 19:15:57 -0700 Subject: [PATCH] [clang-format] Handle raw string literals containing JSON code (#140666) Fix #65400 (cherry picked from commit 0dfdf7efbfe347517eb4c7f544043a71af4e4a25) --- clang/lib/Format/Format.cpp | 6 +++-- clang/tools/clang-format/ClangFormat.cpp | 4 ++-- .../unittests/Format/FormatTestRawStrings.cpp | 22 +++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index b97d8928178b5..aba7db6dd50a8 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -3743,8 +3743,10 @@ reformat(const FormatStyle &Style, StringRef Code, tooling::Replacements Replaces = Formatter(*Env, Style, Status).process().first; // add a replacement to remove the "x = " from the result. -Replaces = Replaces.merge( -tooling::Replacements(tooling::Replacement(FileName, 0, 4, ""))); +if (Code.starts_with("x = ")) { + Replaces = Replaces.merge( + tooling::Replacements(tooling::Replacement(FileName, 0, 4, ""))); +} // apply the reformatting changes and the removal of "x = ". if (applyAllReplacements(Code, Replaces)) return {Replaces, 0}; diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index 28610052b9b74..96eec7c666a38 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -492,8 +492,8 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { // To format JSON insert a variable to trick the code into thinking its // JavaScript. if (IsJson && !FormatStyle->DisableFormat) { -auto Err = Replaces.add(tooling::Replacement( -tooling::Replacement(AssumedFileName, 0, 0, "x = "))); +auto Err = +Replaces.add(tooling::Replacement(AssumedFileName, 0, 0, "x = ")); if (Err) llvm::errs() << "Bad Json variable insertion\n"; } diff --git a/clang/unittests/Format/FormatTestRawStrings.cpp b/clang/unittests/Format/FormatTestRawStrings.cpp index 0615fb1fad4c5..3f09c7b6086e5 100644 --- a/clang/unittests/Format/FormatTestRawStrings.cpp +++ b/clang/unittests/Format/FormatTestRawStrings.cpp @@ -988,6 +988,28 @@ f("aa", )pb");)test", Style)); } + +TEST_F(FormatTestRawStrings, Json) { + auto Style = getLLVMStyle(); + Style.RawStringFormats = { + { + /*Language=*/FormatStyle::LK_Json, + /*Delimiters=*/{"json"}, + /*EnclosingFunctions=*/{}, + /*CanonicalDelimiter=*/"", + /*BasedOnStyle=*/"llvm", + }, + }; + + EXPECT_EQ("json = R\"json({\n" +"\"str\": \"test\"\n" +" })json\";", +format("json = R\"json({\n" + " \"str\": \"test\"\n" + "})json\";", + Style)); +} + } // end namespace } // end namespace format } // end namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/20.x: [clang-format] Handle raw string literals containing JSON code (#140666) (PR #141002)
llvmbot wrote: @mydeveloperday What do you think about merging this PR to the release branch? https://github.com/llvm/llvm-project/pull/141002 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/20.x: [clang-format] Handle raw string literals containing JSON code (#140666) (PR #141002)
llvmbot wrote: @llvm/pr-subscribers-clang-format Author: None (llvmbot) Changes Backport 0dfdf7efbfe347517eb4c7f544043a71af4e4a25 Requested by: @owenca --- Full diff: https://github.com/llvm/llvm-project/pull/141002.diff 3 Files Affected: - (modified) clang/lib/Format/Format.cpp (+4-2) - (modified) clang/tools/clang-format/ClangFormat.cpp (+2-2) - (modified) clang/unittests/Format/FormatTestRawStrings.cpp (+22) ``diff diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index b97d8928178b5..aba7db6dd50a8 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -3743,8 +3743,10 @@ reformat(const FormatStyle &Style, StringRef Code, tooling::Replacements Replaces = Formatter(*Env, Style, Status).process().first; // add a replacement to remove the "x = " from the result. -Replaces = Replaces.merge( -tooling::Replacements(tooling::Replacement(FileName, 0, 4, ""))); +if (Code.starts_with("x = ")) { + Replaces = Replaces.merge( + tooling::Replacements(tooling::Replacement(FileName, 0, 4, ""))); +} // apply the reformatting changes and the removal of "x = ". if (applyAllReplacements(Code, Replaces)) return {Replaces, 0}; diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index 28610052b9b74..96eec7c666a38 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -492,8 +492,8 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { // To format JSON insert a variable to trick the code into thinking its // JavaScript. if (IsJson && !FormatStyle->DisableFormat) { -auto Err = Replaces.add(tooling::Replacement( -tooling::Replacement(AssumedFileName, 0, 0, "x = "))); +auto Err = +Replaces.add(tooling::Replacement(AssumedFileName, 0, 0, "x = ")); if (Err) llvm::errs() << "Bad Json variable insertion\n"; } diff --git a/clang/unittests/Format/FormatTestRawStrings.cpp b/clang/unittests/Format/FormatTestRawStrings.cpp index 0615fb1fad4c5..3f09c7b6086e5 100644 --- a/clang/unittests/Format/FormatTestRawStrings.cpp +++ b/clang/unittests/Format/FormatTestRawStrings.cpp @@ -988,6 +988,28 @@ f("aa", )pb");)test", Style)); } + +TEST_F(FormatTestRawStrings, Json) { + auto Style = getLLVMStyle(); + Style.RawStringFormats = { + { + /*Language=*/FormatStyle::LK_Json, + /*Delimiters=*/{"json"}, + /*EnclosingFunctions=*/{}, + /*CanonicalDelimiter=*/"", + /*BasedOnStyle=*/"llvm", + }, + }; + + EXPECT_EQ("json = R\"json({\n" +"\"str\": \"test\"\n" +" })json\";", +format("json = R\"json({\n" + " \"str\": \"test\"\n" + "})json\";", + Style)); +} + } // end namespace } // end namespace format } // end namespace clang `` https://github.com/llvm/llvm-project/pull/141002 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Implement validation of resource ranges for `RootDescriptors` (PR #140962)
https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/140962 >From bcc056ea5c753c3b1fa83d214c6bd14e90d9ee25 Mon Sep 17 00:00:00 2001 From: Finn Plummer Date: Wed, 21 May 2025 00:12:04 + Subject: [PATCH] [HLSL][RootSignature] Plug into the thing --- .../clang/Basic/DiagnosticSemaKinds.td| 5 + clang/include/clang/Sema/SemaHLSL.h | 2 + clang/lib/Sema/SemaHLSL.cpp | 105 ++ .../RootSignature-resource-ranges-err.hlsl| 26 + .../RootSignature-resource-ranges.hlsl| 22 .../llvm/Frontend/HLSL/HLSLRootSignature.h| 9 +- llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp | 2 + 7 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaHLSL/RootSignature-resource-ranges-err.hlsl create mode 100644 clang/test/SemaHLSL/RootSignature-resource-ranges.hlsl diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f0bd5a1174020..b1026e733ec37 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12967,6 +12967,11 @@ def err_hlsl_expect_arg_const_int_one_or_neg_one: Error< def err_invalid_hlsl_resource_type: Error< "invalid __hlsl_resource_t type attributes">; +def err_hlsl_resource_range_overlap: Error< + "resource ranges %select{t|u|b|s}0[%1;%2] and %select{t|u|b|s}3[%4;%5] " + "overlap within space = %6 and visibility = " + "%select{All|Vertex|Hull|Domain|Geometry|Pixel|Amplification|Mesh}7">; + // Layout randomization diagnostics. def err_non_designated_init_used : Error< "a randomized struct can only be initialized with a designated initializer">; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 15182bb27bbdf..a161236d8baa0 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -119,6 +119,8 @@ class SemaHLSL : public SemaBase { bool IsCompAssign); void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc); + // Returns true when D is invalid and a diagnostic was produced + bool handleRootSignatureDecl(HLSLRootSignatureDecl *D, SourceLocation Loc); void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL); void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index e6daa67fcee95..e46cca89db5a4 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Frontend/HLSL/HLSLRootSignature.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DXILABI.h" #include "llvm/Support/ErrorHandling.h" @@ -951,6 +952,108 @@ void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str()); } +namespace { + +// A resource range overlaps with another resource range if they have: +// - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler) +// - equivalent resource space +// - overlapping visbility +class ResourceRanges { +public: + // KeyT: 32-lsb denotes resource space, and 32-msb denotes resource type enum + using KeyT = uint64_t; + + static const unsigned NumVisEnums = + (unsigned)llvm::hlsl::rootsig::ShaderVisibility::NumEnums; + +private: + llvm::hlsl::rootsig::ResourceRange::IMap::Allocator Allocator; + + // Denotes a mapping of a unique combination of ResourceClass and register + // space to a ResourceRange + using MapT = llvm::SmallDenseMap; + + // Denotes a mapping for each unique visibility + MapT RangeMaps[NumVisEnums]; + + constexpr static KeyT getKey(const llvm::hlsl::rootsig::RangeInfo &Info) { +uint64_t SpacePacked = (uint64_t)Info.Space; +uint64_t ClassPacked = (uint64_t)llvm::to_underlying(Info.Class); +return (ClassPacked << 32) | SpacePacked; + } + +public: + // Returns std::nullopt if there was no collision. Otherwise, it will + // return the RangeInfo of the collision + std::optional + addRange(const llvm::hlsl::rootsig::RangeInfo &Info) { +MapT &VisRangeMap = RangeMaps[llvm::to_underlying(Info.Vis)]; +auto [It, _] = VisRangeMap.insert( +{getKey(Info), llvm::hlsl::rootsig::ResourceRange(Allocator)}); +auto Res = It->second.insert(Info); +if (Res.has_value()) + return Res; + +MutableArrayRef Maps = +Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All +? MutableArrayRef{RangeMaps}.drop_front() +: MutableArrayRef{RangeMaps}.take_front(); + +for (MapT &CurMap : Maps) { + auto CurIt = CurMap.find(getKey(Info)); + if (CurIt != CurMap.end()) +if (auto Overlapping = CurIt->second.getOverlapping(Info)) +
[llvm-branch-commits] [llvm] [HLSL][RootSignature] Implement `ResourceRange` as an `IntervalMap` (PR #140957)
https://github.com/inbelic created https://github.com/llvm/llvm-project/pull/140957 A resource range consists of a closed interval, `[a;b]`, denoting which shader registers it is bound to. For instance: - `CBV(b1)` corresponds to the resource range of `[1;1]` - `CBV(b0, numDescriptors = 3)` likewise to `[0;2]` We want to provide an error diagnostic that there is an overlap in the required registers for each of the resources (an overlap in the resource ranges). The goal of this pr is to implement a structure to model a set of resource ranges and provide an api to detect any overlap over a set of resource ranges. `ResourceRange` models this by implementing an `IntervalMap` to denote a mapping from an interval of registers back to a resource range. It allows for a new `ResourceRange` to be added to the mapping and it will report the first overlap that it denotes. - Implements `ResourceRange` as an `IntervalMap` - Adds unit testing of the various `insert` scenarios Note: it was also considered to implement this as an `IntervalTree`, this would allow reporting of a diagnostic for each overlap that is encountered, as opposed to just the first. However, error generation of just reporting the first error is already rather verbose, and adding the additional diagnostics only made this worse. Part 1 of https://github.com/llvm/llvm-project/issues/129942 >From a3240de319d3ef455b5db83b66b5bd601cecc0b3 Mon Sep 17 00:00:00 2001 From: Finn Plummer Date: Tue, 20 May 2025 19:47:29 + Subject: [PATCH] [HLSL][RootSignature] Implement resource register validation --- .../llvm/Frontend/HLSL/HLSLRootSignature.h| 56 ++ llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp | 61 ++ llvm/unittests/Frontend/CMakeLists.txt| 1 + .../Frontend/HLSLRootSignatureRangesTest.cpp | 177 ++ 4 files changed, 295 insertions(+) create mode 100644 llvm/unittests/Frontend/HLSLRootSignatureRangesTest.cpp diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h index 98fa5f09429e3..3e5054566052b 100644 --- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h +++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h @@ -15,6 +15,7 @@ #define LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/IntervalMap.h" #include "llvm/Support/DXILABI.h" #include "llvm/Support/raw_ostream.h" #include @@ -198,6 +199,61 @@ class MetadataBuilder { SmallVector GeneratedMetadata; }; +// RangeInfo holds the information to correctly construct a ResourceRange +// and retains this information to be used for displaying a better diagnostic +struct RangeInfo { + const static uint32_t Unbounded = static_cast(-1); + + uint32_t LowerBound; + uint32_t UpperBound; +}; + +class ResourceRange { +public: + using IMap = llvm::IntervalMap>; + +private: + IMap Intervals; + +public: + ResourceRange(IMap::Allocator &Allocator) : Intervals(IMap(Allocator)) {} + + // Returns a reference to the first RangeInfo that overlaps with + // [Info.LowerBound;Info.UpperBound], or, std::nullopt if there is no overlap + std::optional getOverlapping(const RangeInfo &Info) const; + + // Return the mapped RangeInfo at X or nullptr if no mapping exists + const RangeInfo *lookup(uint32_t X) const; + + // Insert the required (sub-)intervals such that the interval of [a;b] = + // [Info.LowerBound, Info.UpperBound] is covered and points to a valid + // RangeInfo &. + // + // For instance consider the following chain of inserting RangeInfos with the + // intervals denoting the Lower/Upper-bounds: + // + // A = [0;2] + // insert(A) -> false + // intervals: [0;2] -> &A + // B = [5;7] + // insert(B) -> false + // intervals: [0;2] -> &A, [5;7] -> &B + // C = [4;7] + // insert(C) -> true + // intervals: [0;2] -> &A, [4;7] -> &C + // D = [1;5] + // insert(D) -> true + // intervals: [0;2] -> &A, [3;3] -> &D, [4;7] -> &C + // E = [0;unbounded] + // insert(E) -> true + // intervals: [0;unbounded] -> E + // + // Returns if the first overlapping range when inserting + // (same return as getOverlapping) + std::optional insert(const RangeInfo &Info); +}; + } // namespace rootsig } // namespace hlsl } // namespace llvm diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp index abf076944b273..76fe09e4dc3ee 100644 --- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp +++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp @@ -222,6 +222,67 @@ MDNode *MetadataBuilder::BuildDescriptorTableClause( }); } +std::optional +ResourceRange::getOverlapping(const RangeInfo &Info) const { + IMap::const_iterator Interval = Intervals.find(Info.LowerBound); + if (!Interval.valid() || Info.UpperBound < Interval.start()) +return std::nullopt; + return Interval.value(); +} + +const RangeInfo *ResourceRange::lookup(uint32_t X) const { + retu
[llvm-branch-commits] [llvm] [SPARC] Use op-then-halve instructions when we have VIS3 (PR #135718)
https://github.com/arsenm approved this pull request. https://github.com/llvm/llvm-project/pull/135718 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [HLSL][RootSignature] Implement `ResourceRange` as an `IntervalMap` (PR #140957)
https://github.com/inbelic edited https://github.com/llvm/llvm-project/pull/140957 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [IR] Introduce the `ptrtoaddr` instruction (PR #139357)
@@ -0,0 +1,66 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-linux-gnu -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=CHECK arsenm wrote: ```suggestion ; RUN: llc -mtriple=x86_64-linux-gnu < %s -o - | FileCheck %s --check-prefix=CHECK ``` https://github.com/llvm/llvm-project/pull/139357 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [IR] Introduce the `ptrtoaddr` instruction (PR #139357)
@@ -110,6 +110,7 @@ typedef enum { LLVMFPTrunc= 37, LLVMFPExt = 38, LLVMPtrToInt = 39, + LLVMPtrToAddr = 69, arsenm wrote: I think it would be less confusing to keep these sorted by enum values but I see that's been broken for the last few new instructions (or maybe just freeze?) https://github.com/llvm/llvm-project/pull/139357 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [IR] Introduce the `ptrtoaddr` instruction (PR #139357)
@@ -0,0 +1,66 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-linux-gnu -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=CHECK + +define i1 @ptrtoaddr_1(ptr %p) { +; CHECK-LABEL: ptrtoaddr_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT:movq %rdi, %rax +; CHECK-NEXT:xorb $1, %al +; CHECK-NEXT:# kill: def $al killed $al killed $rax +; CHECK-NEXT:retq +entry: + %addr = ptrtoaddr ptr %p to i1 + %ret = xor i1 %addr, 1 + ret i1 %ret +} + +define i8 @ptrtoaddr_8(ptr %p) { +; CHECK-LABEL: ptrtoaddr_8: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT:movq %rdi, %rax +; CHECK-NEXT:notb %al +; CHECK-NEXT:# kill: def $al killed $al killed $rax +; CHECK-NEXT:retq +entry: + %addr = ptrtoaddr ptr %p to i8 + %ret = xor i8 %addr, -1 + ret i8 %ret +} + +define i16 @ptrtoaddr_16(ptr %p) { +; CHECK-LABEL: ptrtoaddr_16: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT:movq %rdi, %rax +; CHECK-NEXT:notl %eax +; CHECK-NEXT:# kill: def $ax killed $ax killed $rax +; CHECK-NEXT:retq +entry: + %addr = ptrtoaddr ptr %p to i16 + %ret = xor i16 %addr, -1 + ret i16 %ret +} + +define i32 @ptrtoaddr_s32_p0(ptr %p) { +; CHECK-LABEL: ptrtoaddr_s32_p0: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT:movq %rdi, %rax +; CHECK-NEXT:notl %eax +; CHECK-NEXT:# kill: def $eax killed $eax killed $rax +; CHECK-NEXT:retq +entry: + %addr = ptrtoaddr ptr %p to i32 + %ret = xor i32 %addr, -1 + ret i32 %ret +} + +define i64 @ptrtoaddr_s64_p0(ptr %p) { +; CHECK-LABEL: ptrtoaddr_s64_p0: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT:movq %rdi, %rax +; CHECK-NEXT:notq %rax +; CHECK-NEXT:retq +entry: + %addr = ptrtoaddr ptr %p to i64 + %ret = xor i64 %addr, -1 + ret i64 %ret +} arsenm wrote: Test to an integer > 64? https://github.com/llvm/llvm-project/pull/139357 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [IR] Introduce the `ptrtoaddr` instruction (PR #139357)
@@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s arsenm wrote: ```suggestion ; RUN: not llvm-as --disable-output %s 2>&1 | FileCheck %s ``` https://github.com/llvm/llvm-project/pull/139357 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [IR] Introduce the `ptrtoaddr` instruction (PR #139357)
@@ -0,0 +1,14 @@ +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s arsenm wrote: Does it really need to do 2 round trips? I don't think other bitcode tests do this? https://github.com/llvm/llvm-project/pull/139357 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [IR] Introduce the `ptrtoaddr` instruction (PR #139357)
@@ -0,0 +1,66 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=CHECK arsenm wrote: ```suggestion ; RUN: llc -mtriple=x86_64-linux-gnu -global-isel < %s -o - | FileCheck %s --check-prefix=CHECK ``` https://github.com/llvm/llvm-project/pull/139357 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [clang] callee_type metadata for indirect calls (PR #117036)
@@ -2869,9 +2870,23 @@ static void setLinkageForGV(llvm::GlobalValue *GV, const NamedDecl *ND) { GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); } +static bool hasExistingGeneralizedTypeMD(llvm::Function *F) { + llvm::MDNode *MD = F->getMetadata(llvm::LLVMContext::MD_type); + if (!MD) +return false; + return MD->hasGeneralizedMDString(); +} + void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD, llvm::Function *F) { - // Only if we are checking indirect calls. + if (CodeGenOpts.CallGraphSection && !hasExistingGeneralizedTypeMD(F) && + (!F->hasLocalLinkage() || + F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true, +/*IgnoreAssumeLikeCalls=*/true, +/*IgnoreLLVMUsed=*/false))) +F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType())); arsenm wrote: Relying on the IR function properties feels wrong here, can you detect whether this is indirect from the source context? I'm also not sure IgnoreCallbackUses is correct here (IgnoreAssumeLikeCalls is also potentially questionable) https://github.com/llvm/llvm-project/pull/117036 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [IR] Introduce the `ptrtoaddr` instruction (PR #139357)
@@ -7,9 +7,9 @@ define i32 @nested(i32 %src) #0 { ; CHECK-SAME: i32 [[A0:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: [[BB15160:.*:]] ; CHECK-NEXT:[[T1:%.*]] = call token @llvm.experimental.convergence.entry() -; CHECK-NEXT:%"vl77672llvm.experimental.convergence.anchor()" = call token @llvm.experimental.convergence.anchor() -; CHECK-NEXT:%"op68297(vl77672)" = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[A0]]) [ "convergencectrl"(token %"vl77672llvm.experimental.convergence.anchor()") ] -; CHECK-NEXT:ret i32 %"op68297(vl77672)" +; CHECK-NEXT:%"vl14659llvm.experimental.convergence.anchor()" = call token @llvm.experimental.convergence.anchor() +; CHECK-NEXT:%"op15516(vl14659)" = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[A0]]) [ "convergencectrl"(token %"vl14659llvm.experimental.convergence.anchor()") ] +; CHECK-NEXT:ret i32 %"op15516(vl14659)" arsenm wrote: Not sure why this changed https://github.com/llvm/llvm-project/pull/139357 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [llvm] Introduce callee_type metadata (PR #87573)
@@ -0,0 +1,30 @@ +;; Test if the callee_type metadata attached to indirect call sites adhere to the expected format. + +; RUN: not opt -passes=verify < %s 2>&1 | FileCheck %s +define i32 @_Z13call_indirectPFicEc(ptr %func, i8 signext %x) !type !0 { +entry: + %func.addr = alloca ptr, align 8 + %x.addr = alloca i8, align 1 + store ptr %func, ptr %func.addr, align 8 + store i8 %x, ptr %x.addr, align 1 + %fptr = load ptr, ptr %func.addr, align 8 + %x_val = load i8, ptr %x.addr, align 1 + ;; No failures expected for this callee_type metdata. + %call = call i32 %fptr(i8 signext %x_val), !callee_type !1 arsenm wrote: The valid cases belong in test/Assembler https://github.com/llvm/llvm-project/pull/87573 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [llvm] Introduce callee_type metadata (PR #87573)
@@ -0,0 +1,30 @@ +;; Test if the callee_type metadata attached to indirect call sites adhere to the expected format. + +; RUN: not opt -passes=verify < %s 2>&1 | FileCheck %s arsenm wrote: ```suggestion ; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s ``` https://github.com/llvm/llvm-project/pull/87573 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [llvm] Introduce callee_type metadata (PR #87573)
@@ -0,0 +1,21 @@ +;; Test if the callee_type metadata is dropped when it is attached +;; to a direct function call during instcombine. + +; RUN: opt -passes="instcombine" -S < %s | FileCheck %s arsenm wrote: ```suggestion ; RUN: opt -passes=instcombine -S < %s | FileCheck %s ``` https://github.com/llvm/llvm-project/pull/87573 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [llvm] Introduce callee_type metadata (PR #87573)
@@ -0,0 +1,21 @@ +;; Test if the callee_type metadata is dropped when it is attached +;; to a direct function call during instcombine. + +; RUN: opt -passes="instcombine" -S < %s | FileCheck %s + +define i32 @_Z3barv() local_unnamed_addr !type !3 { arsenm wrote: ```suggestion define i32 @_Z3barv() !type !3 { ``` https://github.com/llvm/llvm-project/pull/87573 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [llvm] Introduce callee_type metadata (PR #87573)
@@ -0,0 +1,21 @@ +;; Test if the callee_type metadata is dropped when it is attached +;; to a direct function call during instcombine. + +; RUN: opt -passes="instcombine" -S < %s | FileCheck %s + +define i32 @_Z3barv() local_unnamed_addr !type !3 { +entry: + ; CHECK-LABEL: define i32 @_Z3barv() + ; CHECK-NEXT: entry: + ; CHECK-NOT: !callee_type arsenm wrote: -NOT checks are fragile, use update_test_checks https://github.com/llvm/llvm-project/pull/87573 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [llvm] Introduce callee_type metadata (PR #87573)
@@ -0,0 +1,26 @@ +;; Test if the callee_type metadata is dropped when it is +;; is mapped to a direct function call from an indirect call during inlining. + +; RUN: opt -passes="inline" -S < %s | FileCheck %s + +define i32 @_Z13call_indirectPFicEc(ptr %func, i8 %x) local_unnamed_addr !type !0 { +entry: + %call = call i32 %func(i8 %x), !callee_type !1 + ret i32 %call +} + +define i32 @_Z3barv() local_unnamed_addr !type !3 { +entry: + ; CHECK-LABEL: define i32 @_Z3barv() + ; CHECK-NEXT: entry: + ; CHECK-NOT: !callee_type arsenm wrote: NOT checks are fragile, use update_test_checks https://github.com/llvm/llvm-project/pull/87573 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [llvm] Introduce callee_type metadata (PR #87573)
@@ -0,0 +1,26 @@ +;; Test if the callee_type metadata is dropped when it is +;; is mapped to a direct function call from an indirect call during inlining. + +; RUN: opt -passes="inline" -S < %s | FileCheck %s arsenm wrote: ```suggestion ; RUN: opt -passes=inline -S < %s | FileCheck %s ``` https://github.com/llvm/llvm-project/pull/87573 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] While stmt atom (PR #134645)
https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/134645 >From e3c271ebbf4792bf684acef2af8fbc9df9a9b596 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 3 Apr 2025 18:49:32 +0100 Subject: [PATCH 1/2] [KeyInstr][Clang] While stmt atom See test comment for possible future improvement. This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. The Key Instructions project is introduced, including a "quick summary" section at the top which adds context for this PR, here: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed. The Clang-side work is demoed here: https://github.com/llvm/llvm-project/pull/130943 --- clang/lib/CodeGen/CGStmt.cpp | 9 +- clang/test/DebugInfo/KeyInstructions/while.c | 34 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 clang/test/DebugInfo/KeyInstructions/while.c diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index e46cfb433ab89..d9fd406ad64ee 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -1130,7 +1130,14 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S, if (!Weights && CGM.getCodeGenOpts().OptimizationLevel) BoolCondVal = emitCondLikelihoodViaExpectIntrinsic( BoolCondVal, Stmt::getLikelihood(S.getBody())); -Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock, Weights); +auto *I = Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock, Weights); +// Key Instructions: Emit the condition and branch as separate atoms to +// match existing loop stepping behaviour. FIXME: We could have the branch +// as the backup location for the condition, which would probably be a +// better experience. Explore this later. +if (auto *I = dyn_cast(BoolCondVal)) + addInstToNewSourceAtom(I, nullptr); +addInstToNewSourceAtom(I, nullptr); if (ExitBlock != LoopExit.getBlock()) { EmitBlock(ExitBlock); diff --git a/clang/test/DebugInfo/KeyInstructions/while.c b/clang/test/DebugInfo/KeyInstructions/while.c new file mode 100644 index 0..f1bb91520315a --- /dev/null +++ b/clang/test/DebugInfo/KeyInstructions/while.c @@ -0,0 +1,34 @@ +// RUN: %clang -gkey-instructions -x c++ -std=c++17 %s -gmlt -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -x c %s -gmlt -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// Perennial quesiton: should the `dec` be in its own source atom or not +// (currently it is). + +// We've made the cmp and br separate source atoms for now, to match existing +// behaviour in this case: +// 1. while ( +// 2. int i = --End +// 3. ) { +// 4. useValue(i); +// 5. } +// Without Key Instructions we go: 2, 1[, 4, 2, 1]+ +// Without separating cmp and br with Key Instructions we'd get: +// 1[, 4, 1]+. If we made the cmp higher precedence than the +// br and had them in the same group, we could get: +// 2, [4, 2]+ which might be nicer. FIXME: do that later. + +void a(int A) { +// CHECK: %dec = add nsw i32 %0, -1, !dbg [[G1R2:!.*]] +// CHECK: store i32 %dec, ptr %A.addr{{.*}}, !dbg [[G1R1:!.*]] +// CHECK: %tobool = icmp ne i32 %dec, 0, !dbg [[G2R1:!.*]] +// CHECK: br i1 %tobool, label %while.body, label %while.end, !dbg [[G3R1:!.*]] +while (--A) { }; +} + +// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2) +// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) +// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) +// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1) >From cdd6ff398508e486bd669f9a441e557824699a98 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Wed, 21 May 2025 15:47:54 +0100 Subject: [PATCH 2/2] cc1 --- clang/test/DebugInfo/KeyInstructions/while.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/DebugInfo/KeyInstructions/while.c b/clang/test/DebugInfo/KeyInstructions/while.c index f1bb91520315a..d876bd1d93792 100644 --- a/clang/test/DebugInfo/KeyInstructions/while.c +++ b/clang/test/DebugInfo/KeyInstructions/while.c @@ -1,7 +1,7 @@ -// RUN: %clang -gkey-instructions -x c++ -std=c++17 %s -gmlt -S -emit-llvm -o - \ +// RUN: %clang_cc1 -gkey-instructions -x c++ -std=c++17 %s -debug-info-kind=line-tables-only -emit-llvm -o - \ // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank -// RUN: %clang -gkey-instructions -x c %s -gmlt -S -emit-llvm -o - \ +// RUN: %clang_cc1 -gkey-instructions -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - \ // RUN: | FileCheck %s --implicit-check
[llvm-branch-commits] [clang] [KeyInstr][Clang] For stmt atom (PR #134646)
https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/134646 >From c4b2db1f76d59927fd54bf7901d6cdadf99ec77a Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 3 Apr 2025 19:12:47 +0100 Subject: [PATCH 1/2] [KeyInstr][Clang] For stmt atom This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. The Key Instructions project is introduced, including a "quick summary" section at the top which adds context for this PR, here: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed. The Clang-side work is demoed here: https://github.com/llvm/llvm-project/pull/130943 --- clang/lib/CodeGen/CGStmt.cpp | 18 +-- clang/test/DebugInfo/KeyInstructions/for.c | 37 ++ 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 clang/test/DebugInfo/KeyInstructions/for.c diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index d9fd406ad64ee..65b71c39d86c4 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -1324,6 +1324,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, Continue = getJumpDestInCurrentScope("for.inc"); BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); + llvm::BasicBlock *ForBody = nullptr; if (S.getCond()) { // If the for statement has a condition scope, emit the local variable // declaration. @@ -1348,7 +1349,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, ExitBlock = createBasicBlock("for.cond.cleanup"); // As long as the condition is true, iterate the loop. -llvm::BasicBlock *ForBody = createBasicBlock("for.body"); +ForBody = createBasicBlock("for.body"); // C99 6.8.5p2/p4: The first substatement is executed if the expression // compares unequal to 0. The condition must be a scalar type. @@ -1362,7 +1363,14 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, BoolCondVal = emitCondLikelihoodViaExpectIntrinsic( BoolCondVal, Stmt::getLikelihood(S.getBody())); -Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights); +auto *I = Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights); +// Key Instructions: Emit the condition and branch as separate atoms to +// match existing loop stepping behaviour. FIXME: We could have the branch +// as the backup location for the condition, which would probably be a +// better experience (no jumping to the brace). +if (auto *I = dyn_cast(BoolCondVal)) + addInstToNewSourceAtom(I, nullptr); +addInstToNewSourceAtom(I, nullptr); if (ExitBlock != LoopExit.getBlock()) { EmitBlock(ExitBlock); @@ -1416,6 +1424,12 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, if (CGM.shouldEmitConvergenceTokens()) ConvergenceTokenStack.pop_back(); + + if (ForBody) { +// Key Instructions: We want the for closing brace to be step-able on to +// match existing behaviour. +addInstToNewSourceAtom(ForBody->getTerminator(), nullptr); + } } void diff --git a/clang/test/DebugInfo/KeyInstructions/for.c b/clang/test/DebugInfo/KeyInstructions/for.c new file mode 100644 index 0..3221ece69a717 --- /dev/null +++ b/clang/test/DebugInfo/KeyInstructions/for.c @@ -0,0 +1,37 @@ +// RUN: %clang -gkey-instructions -x c++ %s -gmlt -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -x c %s -gmlt -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// Perennial quesiton: should the inc be its own source atom or not +// (currently it is). + +// FIXME: See do.c and while.c regarding cmp and cond br groups. + +void a(int A) { +// CHECK: entry: +// CHECK: store i32 0, ptr %i{{.*}}, !dbg [[G1R1:!.*]] +// CHECK: for.cond: +// CHECK: %cmp = icmp slt i32 %0, %1, !dbg [[G2R1:!.*]] +// CHECK: br i1 %cmp, label %for.body, label %for.end, !dbg [[G3R1:!.*]] + +// FIXME: Added uncond br group here which is useful for O0, which we're +// no longer targeting. With optimisations loop rotate puts the condition +// into for.inc and simplifycfg smooshes that and for.body together, so +// it's not clear whether it adds any value. +// CHECK: for.body: +// CHECK: br label %for.inc, !dbg [[G5R1:!.*]] + +// CHECK: for.inc: +// CHECK: %inc = add{{.*}}, !dbg [[G4R2:!.*]] +// CHECK: store i32 %inc, ptr %i{{.*}}, !dbg [[G4R1:!.*]] +for (int i = 0; i < A; ++i) { } +} + +// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) +// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) +// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1) +// CHECK: [[G5R1]] = !DILocation
[llvm-branch-commits] [clang] [KeyInstr][Clang] For stmt atom (PR #134646)
https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/134646 >From c4b2db1f76d59927fd54bf7901d6cdadf99ec77a Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 3 Apr 2025 19:12:47 +0100 Subject: [PATCH] [KeyInstr][Clang] For stmt atom This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. The Key Instructions project is introduced, including a "quick summary" section at the top which adds context for this PR, here: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed. The Clang-side work is demoed here: https://github.com/llvm/llvm-project/pull/130943 --- clang/lib/CodeGen/CGStmt.cpp | 18 +-- clang/test/DebugInfo/KeyInstructions/for.c | 37 ++ 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 clang/test/DebugInfo/KeyInstructions/for.c diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index d9fd406ad64ee..65b71c39d86c4 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -1324,6 +1324,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, Continue = getJumpDestInCurrentScope("for.inc"); BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); + llvm::BasicBlock *ForBody = nullptr; if (S.getCond()) { // If the for statement has a condition scope, emit the local variable // declaration. @@ -1348,7 +1349,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, ExitBlock = createBasicBlock("for.cond.cleanup"); // As long as the condition is true, iterate the loop. -llvm::BasicBlock *ForBody = createBasicBlock("for.body"); +ForBody = createBasicBlock("for.body"); // C99 6.8.5p2/p4: The first substatement is executed if the expression // compares unequal to 0. The condition must be a scalar type. @@ -1362,7 +1363,14 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, BoolCondVal = emitCondLikelihoodViaExpectIntrinsic( BoolCondVal, Stmt::getLikelihood(S.getBody())); -Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights); +auto *I = Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights); +// Key Instructions: Emit the condition and branch as separate atoms to +// match existing loop stepping behaviour. FIXME: We could have the branch +// as the backup location for the condition, which would probably be a +// better experience (no jumping to the brace). +if (auto *I = dyn_cast(BoolCondVal)) + addInstToNewSourceAtom(I, nullptr); +addInstToNewSourceAtom(I, nullptr); if (ExitBlock != LoopExit.getBlock()) { EmitBlock(ExitBlock); @@ -1416,6 +1424,12 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, if (CGM.shouldEmitConvergenceTokens()) ConvergenceTokenStack.pop_back(); + + if (ForBody) { +// Key Instructions: We want the for closing brace to be step-able on to +// match existing behaviour. +addInstToNewSourceAtom(ForBody->getTerminator(), nullptr); + } } void diff --git a/clang/test/DebugInfo/KeyInstructions/for.c b/clang/test/DebugInfo/KeyInstructions/for.c new file mode 100644 index 0..3221ece69a717 --- /dev/null +++ b/clang/test/DebugInfo/KeyInstructions/for.c @@ -0,0 +1,37 @@ +// RUN: %clang -gkey-instructions -x c++ %s -gmlt -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -x c %s -gmlt -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// Perennial quesiton: should the inc be its own source atom or not +// (currently it is). + +// FIXME: See do.c and while.c regarding cmp and cond br groups. + +void a(int A) { +// CHECK: entry: +// CHECK: store i32 0, ptr %i{{.*}}, !dbg [[G1R1:!.*]] +// CHECK: for.cond: +// CHECK: %cmp = icmp slt i32 %0, %1, !dbg [[G2R1:!.*]] +// CHECK: br i1 %cmp, label %for.body, label %for.end, !dbg [[G3R1:!.*]] + +// FIXME: Added uncond br group here which is useful for O0, which we're +// no longer targeting. With optimisations loop rotate puts the condition +// into for.inc and simplifycfg smooshes that and for.body together, so +// it's not clear whether it adds any value. +// CHECK: for.body: +// CHECK: br label %for.inc, !dbg [[G5R1:!.*]] + +// CHECK: for.inc: +// CHECK: %inc = add{{.*}}, !dbg [[G4R2:!.*]] +// CHECK: store i32 %inc, ptr %i{{.*}}, !dbg [[G4R1:!.*]] +for (int i = 0; i < A; ++i) { } +} + +// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) +// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) +// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1) +// CHECK: [[G5R1]] = !DILocation({{.
[llvm-branch-commits] [clang] [NFC][KeyInstr][Clang] Add some additional tests (PR #134654)
https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/134654 >From 36537a2ede8874fd806d408b186ea33a7d4e1423 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Mon, 7 Apr 2025 12:18:48 +0100 Subject: [PATCH 1/2] [NFC][KeyInstr][Clang] Add some additional tests This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. The Key Instructions project is introduced, including a "quick summary" section at the top which adds context for this PR, here: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed. The Clang-side work is demoed here: https://github.com/llvm/llvm-project/pull/130943 new.cpp: Check store of addr and value are both added to same atom cast.c: Check we look through casts multi-func.c Check the atom group number is reset between functions --- clang/test/KeyInstructions/cast.c | 19 + clang/test/KeyInstructions/multi-func.c | 18 clang/test/KeyInstructions/new.cpp | 37 + 3 files changed, 74 insertions(+) create mode 100644 clang/test/KeyInstructions/cast.c create mode 100644 clang/test/KeyInstructions/multi-func.c create mode 100644 clang/test/KeyInstructions/new.cpp diff --git a/clang/test/KeyInstructions/cast.c b/clang/test/KeyInstructions/cast.c new file mode 100644 index 0..b89edcc3089fb --- /dev/null +++ b/clang/test/KeyInstructions/cast.c @@ -0,0 +1,19 @@ +// RUN: %clang -gkey-instructions -gno-column-info -x c++ %s -gmlt -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -gno-column-info -x c %s -gmlt -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +float g; +void a() { +// CHECK: %0 = load float, ptr @g{{.*}}, !dbg [[G1R3:!.*]] +// CHECK: %conv = fptosi float %0 to i32{{.*}}, !dbg [[G1R2:!.*]] +// CHECK: store i32 %conv, ptr %a{{.*}}, !dbg [[G1R1:!.*]] +int a = g; +// CHECK: ret{{.*}}, !dbg [[G2R1:!.*]] +} + +// CHECK: [[G1R3]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 3) +// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2) +// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) +// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) diff --git a/clang/test/KeyInstructions/multi-func.c b/clang/test/KeyInstructions/multi-func.c new file mode 100644 index 0..7d441e43444b2 --- /dev/null +++ b/clang/test/KeyInstructions/multi-func.c @@ -0,0 +1,18 @@ +// RUN: %clang -gkey-instructions -gno-column-info -x c++ %s -gmlt -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -gno-column-info -x c %s -gmlt -S -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// Check atomGroup is reset to start at 1 in each function. + +// CHECK: ret{{.*}}, !dbg [[AG:!.*]] +void a() {} + +// CHECK: ret{{.*}}, !dbg [[BG:!.*]] +void b() {} + +// CHECK: [[A:!.*]] = distinct !DISubprogram(name: "a", +// CHECK: [[AG]] = !DILocation({{.*}}, scope: [[A]], atomGroup: 1, atomRank: 1) +// CHECK: [[B:!.*]] = distinct !DISubprogram(name: "b", +// CHECK: [[BG]] = !DILocation({{.*}}, scope: [[B]], atomGroup: 1, atomRank: 1) diff --git a/clang/test/KeyInstructions/new.cpp b/clang/test/KeyInstructions/new.cpp new file mode 100644 index 0..9476e311e746f --- /dev/null +++ b/clang/test/KeyInstructions/new.cpp @@ -0,0 +1,37 @@ +// RUN: %clang -gkey-instructions %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// Check both the addr-store and value-store are part of the same atom. + +void f(int x) { +// CHECK: %call = call noalias noundef nonnull ptr @_Znwm{{.*}}, !dbg [[G1R2_C12:!.*]] +// CHECK: %0 = load i32, ptr %x.addr{{.*}}, !dbg [[G1R2_C20:!.*]] +// CHECK: store i32 %0, ptr %call{{.*}}, !dbg [[G1R1_C12:!.*]] +// CHECK: store ptr %call, ptr %{{.*}}, !dbg [[G1R1_C8:!.*]] + int *n = new int(x); +// CHECK: %call1 = call noalias noundef nonnull ptr @_Znwm{{.*}}, !dbg [[G2R2_C7:!.*]] +// CHECK: %1 = load i32, ptr %x.addr{{.*}}, !dbg [[G2R2_C15:!.*]] +// CHECK: store i32 %1, ptr %call{{.*}}, !dbg [[G2R1_C7:!.*]] +// CHECK: store ptr %call1, ptr %{{.*}}, !dbg [[G2R1_C5:!.*]] + n = new int(x); +// CHECK: %2 = load i32, ptr %x.addr{{.*}}, !dbg [[G3R2:!.*]] +// CHECK: %3 = load ptr, ptr %n +// CHECK: store i32 %2, ptr %3{{.*}}, !dbg [[G3R1:!.*]] + *n = x; +// CHECK: ret void, !dbg [[G4R1:!.*]] +} + +// CHECK: [[G1R2_C12]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2) +// CHECK: [[G1R2_C20]] = !DILocation({{
[llvm-branch-commits] [clang] [KeyInstr][Clang] Agg init atom (PR #134635)
https://github.com/OCHyams edited https://github.com/llvm/llvm-project/pull/134635 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Scalar init atom (PR #134633)
https://github.com/jmorse approved this pull request. LGTM https://github.com/llvm/llvm-project/pull/134633 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Agg init atom (PR #134635)
https://github.com/jmorse approved this pull request. LGTM (horray for graphite cc'ing everyone) https://github.com/llvm/llvm-project/pull/134635 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assign vector element atom (PR #134649)
https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/134649 >From 7c2a67e1b6be8f8431a87f72446d150a81e23ffd Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 3 Apr 2025 21:56:37 +0100 Subject: [PATCH] [KeyInstr][Clang] Assign vector element atom This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. The Key Instructions project is introduced, including a "quick summary" section at the top which adds context for this PR, here: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed. The Clang-side work is demoed here: https://github.com/llvm/llvm-project/pull/130943 --- clang/lib/CodeGen/CGExpr.cpp | 5 +++-- clang/test/DebugInfo/KeyInstructions/agg.c | 8 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index f91e284bfdaa0..c03eef1054f7e 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2507,8 +2507,9 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, Vec = Builder.CreateBitCast(Vec, IRStoreTy); } - Builder.CreateStore(Vec, Dst.getVectorAddress(), - Dst.isVolatileQualified()); + auto *I = Builder.CreateStore(Vec, Dst.getVectorAddress(), +Dst.isVolatileQualified()); + addInstToCurrentSourceAtom(I, Vec); return; } diff --git a/clang/test/DebugInfo/KeyInstructions/agg.c b/clang/test/DebugInfo/KeyInstructions/agg.c index 06c9ebbb63369..f3fa7888610e3 100644 --- a/clang/test/DebugInfo/KeyInstructions/agg.c +++ b/clang/test/DebugInfo/KeyInstructions/agg.c @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -gkey-instructions -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - \ // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank +__attribute__((ext_vector_type(1))) char c; typedef struct { int a, b, c; } Struct; void fun(Struct a) { // CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]] @@ -11,7 +12,14 @@ void fun(Struct a) { // CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G2R1:!.*]] b = a; + +// CHECK: %2 = load <1 x i8>, ptr @c +// CHECK: %vecins = insertelement <1 x i8> %2, i8 0, i32 0, !dbg [[G3R2:!.*]] +// CHECK: store <1 x i8> %vecins, ptr @c{{.*}}, !dbg [[G3R1:!.*]] + c[0] = 0; } // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) // CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) +// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 2) +// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1) ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assignment atom group (PR #134637)
@@ -5985,6 +5985,15 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { jmorse wrote: I wonder whether the comma operator (six or seven lines above here) needs instrumenting -- technically if either lhs/rhs of the comma is an assignment, I guess it'll come back through this function and be given a separate group? https://github.com/llvm/llvm-project/pull/134637 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assignment atom group (PR #134637)
@@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -gkey-instructions -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank jmorse wrote: This test is great; I feel we can make it even greater by testing: ` g += ++h;` Or something like that, where there are stores on both sides of a compound assignment expression. https://github.com/llvm/llvm-project/pull/134637 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assignment atom group (PR #134637)
@@ -0,0 +1,41 @@ + +// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gno-column-info -S -emit-llvm -o - -ftrivial-auto-var-init=pattern \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -x c %s -gmlt -gno-column-info -S -emit-llvm -o - -ftrivial-auto-var-init=pattern \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// The implicit-check-not is important; we don't want the GEPs created for the +// store locations to be included in the atom group. + +int g; +void a() { +// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]] +int A[] = { 1, 2, 3 }; + +// CHECK: store i32 1, ptr %{{.*}}, !dbg [[G2R1:!.*]] +// CHECK: store i32 2, ptr %{{.*}}, !dbg [[G2R1]] +// CHECK: %0 = load i32, ptr @g{{.*}}, !dbg [[G2R2:!.*]] +// CHECK: store i32 %0, ptr %{{.*}}, !dbg [[G2R1]] +int B[] = { 1, 2, g }; + +// CHECK: call void @llvm.memset{{.*}}, !dbg [[G3R1:!.*]] jmorse wrote: Similarly, would be nice to have a more specific memset, and the one below. https://github.com/llvm/llvm-project/pull/134637 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assignment atom group (PR #134637)
@@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -gkey-instructions -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang_cc1 -gkey-instructions -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +unsigned long long g; +void fun() { +// CHECK: store i64 0, ptr @g{{.*}}, !dbg [[G1R1:!.*]] +g = 0; + +// Treat the two assignments as two atoms. jmorse wrote: Duplicate coverage with the `g = g = g` in the test file above? https://github.com/llvm/llvm-project/pull/134637 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assignment atom group (PR #134637)
@@ -5849,6 +5852,7 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { LValue CodeGenFunction::EmitCompoundAssignmentLValue( const CompoundAssignOperator *E) { + ApplyAtomGroup Grp(getDebugInfo()); jmorse wrote: If I enter via a `VisitBin##OP##Assign` function from above I'll get an atom group before calling `EmitCompoundAssign`, then get a second atom group here in `EmitcompoundAssignmentLValue` (which is called by `EmitCompoundAssign`). I would have expected only one atom group to be generated in that, is that wrong? https://github.com/llvm/llvm-project/pull/134637 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assignment atom group (PR #134637)
@@ -5985,6 +5985,15 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { assert(E->getOpcode() == BO_Assign && "unexpected binary l-value"); + // This covers both LHS and RHS expressions, though nested RHS + // expressions may get subsequently separately grouped. jmorse wrote: Opening part of the comment should provide context to the reader that you're doing something debug-info / stepping related. https://github.com/llvm/llvm-project/pull/134637 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assignment atom group (PR #134637)
@@ -0,0 +1,41 @@ + +// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gno-column-info -S -emit-llvm -o - -ftrivial-auto-var-init=pattern \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// RUN: %clang -gkey-instructions -x c %s -gmlt -gno-column-info -S -emit-llvm -o - -ftrivial-auto-var-init=pattern \ +// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank + +// The implicit-check-not is important; we don't want the GEPs created for the +// store locations to be included in the atom group. + +int g; +void a() { +// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]] +int A[] = { 1, 2, 3 }; jmorse wrote: As with a prior review, tying the memcpy down to its destination SSA name would be nice, as it'd be more specific than "there is a memcpy with group 1 rank 1, anywhere". https://github.com/llvm/llvm-project/pull/134637 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assignment atom group (PR #134637)
@@ -5985,6 +5985,15 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { assert(E->getOpcode() == BO_Assign && "unexpected binary l-value"); + // This covers both LHS and RHS expressions, though nested RHS + // expressions may get subsequently separately grouped. + // FIXME(OCH): Not clear yet if we've got fine enough control + // to pick and choose when we need to. Currently looks ok: + // a = b = c -> Two atoms. + // x = new(1) -> One atom (for both addr store and value store). jmorse wrote: Is this TODO still relevant -- it's not clear what's actually to do. https://github.com/llvm/llvm-project/pull/134637 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr][Clang] Assignment atom group (PR #134637)
https://github.com/jmorse edited https://github.com/llvm/llvm-project/pull/134637 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr] Complex assignment atoms (PR #134638)
@@ -1209,6 +1213,7 @@ LValue ComplexExprEmitter:: EmitCompoundAssignLValue(const CompoundAssignOperator *E, ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&), RValue &Val) { + ApplyAtomGroup Grp(CGF.getDebugInfo()); jmorse wrote: This doesn't appear to be symmetrical with the scalar patch, in that `EmitCompoundAssign` gets an atom group for the whole assignment -- should this be the same? https://github.com/llvm/llvm-project/pull/134638 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [KeyInstr] Complex assignment atoms (PR #134638)
@@ -1356,6 +1361,7 @@ LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E, } ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) { + ApplyAtomGroup Grp(CGF.getDebugInfo()); ComplexPairTy Val; LValue LV = EmitBinAssignLValue(E, Val); jmorse wrote: Similarly, if we followed the pattern of the above hunk, we'd put ApplyAtomGroup into `EmitBinAssignLValue` instead. This one covers the load-of-lvalue at the end, wheras for compound assignments the equivalent wouldn't be covered. https://github.com/llvm/llvm-project/pull/134638 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits