[llvm] [CodeGen] [AMDGPU] Support type-aware intrinsic feature checks (PR #205536)
Keshav Vinayak Jha via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 1 07:45:10 PDT 2026
https://github.com/keshavvinayak01 updated https://github.com/llvm/llvm-project/pull/205536
>From a511e6fc396a4cf1d96a0028f122fd7903080231 Mon Sep 17 00:00:00 2001
From: Keshav Vinayak Jha <keshavvinayakjha at gmail.com>
Date: Wed, 24 Jun 2026 14:09:50 +0530
Subject: [PATCH 1/4] [AMDGPU][GlobalISel] Handle constant i32 ballot on wave64
GlobalISel rejected i32 ballot results on wave64 before checking whether the ballot operand was a constant. Allow constant true/false i32 ballots to select to the low 32-bit mask while leaving nonconstant i32 ballots on wave64 unsupported.
Add wave64 coverage for the supported constant cases and the unsupported nonconstant boundary.
Co-authored-by: GPT-5 Codex <noreply at openai.com>
Signed-off-by: Keshav Vinayak Jha <keshavvinayakjha at gmail.com>
---
.../AMDGPU/AMDGPUInstructionSelector.cpp | 34 ++++++++++------
.../llvm.amdgcn.ballot.i32.wave64.ll | 39 +++++++++++++++++++
2 files changed, 62 insertions(+), 11 deletions(-)
create mode 100644 llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.wave64.ll
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
index c85d7124f62bb..dfc661999ab66 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
@@ -1719,39 +1719,51 @@ bool AMDGPUInstructionSelector::selectBallot(MachineInstr &I) const {
Register SrcReg = I.getOperand(2).getReg();
const unsigned BallotSize = MRI->getType(DstReg).getSizeInBits();
const unsigned WaveSize = STI.getWavefrontSize();
+ std::optional<ValueAndVReg> Arg =
+ getIConstantVRegValWithLookThrough(SrcReg, *MRI);
+ if (!Arg && SrcReg.isVirtual()) {
+ MachineInstr *SrcDef = MRI->getVRegDef(SrcReg);
+ if (SrcDef && SrcDef->getOpcode() == AMDGPU::G_AMDGPU_COPY_VCC_SCC)
+ Arg = getIConstantVRegValWithLookThrough(SrcDef->getOperand(1).getReg(),
+ *MRI);
+ }
+ const bool IsI64OnWave32 = BallotSize == 64 && WaveSize == 32;
+ const bool IsConstantI32OnWave64 = Arg && BallotSize == 32 && WaveSize == 64;
// In the common case, the return type matches the wave size.
- // However we also support emitting i64 ballots in wave32 mode.
- if (BallotSize != WaveSize && (BallotSize != 64 || WaveSize != 32))
+ // However we also support emitting i64 ballots in wave32 mode. Constant i32
+ // ballots in wave64 mode do not need the full wave mask.
+ if (BallotSize != WaveSize && !IsI64OnWave32 && !IsConstantI32OnWave64)
return false;
- std::optional<ValueAndVReg> Arg =
- getIConstantVRegValWithLookThrough(SrcReg, *MRI);
-
Register Dst = DstReg;
// i64 ballot on Wave32: new Dst(i32) for WaveSize ballot.
- if (BallotSize != WaveSize) {
+ if (IsI64OnWave32) {
Dst = MRI->createVirtualRegister(TRI.getBoolRC());
}
+ const unsigned DstSize = IsI64OnWave32 ? WaveSize : BallotSize;
+ const TargetRegisterClass &DstRC =
+ DstSize == 64 ? AMDGPU::SReg_64RegClass : AMDGPU::SReg_32RegClass;
if (Arg) {
const int64_t Value = Arg->Value.getZExtValue();
if (Value == 0) {
// Dst = S_MOV 0
- unsigned Opcode = WaveSize == 64 ? AMDGPU::S_MOV_B64 : AMDGPU::S_MOV_B32;
+ unsigned Opcode = DstSize == 64 ? AMDGPU::S_MOV_B64 : AMDGPU::S_MOV_B32;
BuildMI(*BB, &I, DL, TII.get(Opcode), Dst).addImm(0);
} else {
// Dst = COPY EXEC
assert(Value == 1);
- BuildMI(*BB, &I, DL, TII.get(AMDGPU::COPY), Dst).addReg(TRI.getExec());
+ Register Exec = DstSize == 64 ? AMDGPU::EXEC : AMDGPU::EXEC_LO;
+ BuildMI(*BB, &I, DL, TII.get(AMDGPU::COPY), Dst).addReg(Exec);
}
- if (!RBI.constrainGenericRegister(Dst, *TRI.getBoolRC(), *MRI))
+ if (!RBI.constrainGenericRegister(Dst, DstRC, *MRI))
return false;
} else {
if (isLaneMaskFromSameBlock(SrcReg, *MRI, BB)) {
// Dst = COPY SrcReg
BuildMI(*BB, &I, DL, TII.get(AMDGPU::COPY), Dst).addReg(SrcReg);
- if (!RBI.constrainGenericRegister(Dst, *TRI.getBoolRC(), *MRI))
+ if (!RBI.constrainGenericRegister(Dst, DstRC, *MRI))
return false;
} else {
// Dst = S_AND SrcReg, EXEC
@@ -1765,7 +1777,7 @@ bool AMDGPUInstructionSelector::selectBallot(MachineInstr &I) const {
}
// i64 ballot on Wave32: zero-extend i32 ballot to i64.
- if (BallotSize != WaveSize) {
+ if (IsI64OnWave32) {
Register HiReg = MRI->createVirtualRegister(&AMDGPU::SReg_32RegClass);
BuildMI(*BB, &I, DL, TII.get(AMDGPU::S_MOV_B32), HiReg).addImm(0);
BuildMI(*BB, &I, DL, TII.get(AMDGPU::REG_SEQUENCE), DstReg)
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.wave64.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.wave64.ll
new file mode 100644
index 0000000000000..b4e4d9b063ee3
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.wave64.ll
@@ -0,0 +1,39 @@
+; RUN: split-file %s %t
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -global-isel -O3 -verify-machineinstrs < %t/constants.ll | FileCheck %s --check-prefix=CHECK
+; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -global-isel -O3 -verify-machineinstrs < %t/nonconstant.ll 2>&1 | FileCheck %s --check-prefix=ERR
+
+;--- constants.ll
+declare i32 @llvm.amdgcn.ballot.i32(i1)
+declare i32 @llvm.amdgcn.mbcnt.lo(i32, i32)
+
+define i32 @ballot_false_wave64() {
+; CHECK-LABEL: ballot_false_wave64:
+; CHECK: v_mov_b32_e32 v0, 0
+ %ballot = call i32 @llvm.amdgcn.ballot.i32(i1 false)
+ ret i32 %ballot
+}
+
+define i32 @ballot_true_wave64() {
+; CHECK-LABEL: ballot_true_wave64:
+; CHECK: v_mov_b32_e32 v0, exec_lo
+ %ballot = call i32 @llvm.amdgcn.ballot.i32(i1 true)
+ ret i32 %ballot
+}
+
+define i32 @activelane_false() {
+; CHECK-LABEL: activelane_false:
+; CHECK: v_mbcnt_lo_u32_b32 v0, 0, 0
+ %ballot = call i32 @llvm.amdgcn.ballot.i32(i1 false)
+ %lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 %ballot, i32 0)
+ ret i32 %lane
+}
+
+;--- nonconstant.ll
+declare i32 @llvm.amdgcn.ballot.i32(i1)
+
+define amdgpu_cs i32 @nonconstant_i32_ballot_wave64(i32 %x) {
+; ERR: LLVM ERROR: cannot select: %{{[0-9]+}}:sreg_32(s32) = G_INTRINSIC_CONVERGENT intrinsic(@llvm.amdgcn.ballot)
+ %trunc = trunc i32 %x to i1
+ %ballot = call i32 @llvm.amdgcn.ballot.i32(i1 %trunc)
+ ret i32 %ballot
+}
>From c1eb0a0c6db113ec219eba986fe282d90cb3bd70 Mon Sep 17 00:00:00 2001
From: Keshav Vinayak Jha <keshavvinayakjha at gmail.com>
Date: Wed, 1 Jul 2026 00:06:56 +0530
Subject: [PATCH 2/4] [CodeGen] Allow intrinsic feature checks to inspect
overload types
Extend the intrinsic subtarget feature check to receive the overloaded intrinsic function type, so targets can make feature requirements depend on the selected overload.
AMDGPU uses this for llvm.amdgcn.ballot: the i32 overload now requires wavefrontsize32, while the i64 overload remains valid on wave64 targets. This reports a clean unsupported-intrinsic diagnostic instead of reaching instruction selection for an invalid i32 ballot on wave64.
Tests cover rejecting ballot.i32 on wave64 without rejecting the valid ballot overload and wave-size combinations.
Co-authored-by: GPT-5 <noreply at openai.com>
Signed-off-by: Keshav Vinayak Jha <keshavvinayakjha at gmail.com>
---
.../llvm/CodeGen/TargetSubtargetInfo.h | 9 +++++
llvm/include/llvm/IR/DiagnosticInfo.h | 3 +-
llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 18 ++++++---
.../SelectionDAG/SelectionDAGBuilder.cpp | 8 +++-
llvm/lib/CodeGen/TargetSubtargetInfo.cpp | 13 +++++++
llvm/lib/IR/DiagnosticInfo.cpp | 9 +++--
.../AMDGPU/AMDGPUInstructionSelector.cpp | 34 ++++++----------
llvm/lib/Target/AMDGPU/GCNSubtarget.cpp | 12 ++++++
llvm/lib/Target/AMDGPU/GCNSubtarget.h | 4 ++
.../llvm.amdgcn.ballot.i32.wave64.ll | 39 -------------------
.../AMDGPU/llvm.amdgcn.ballot.wave-size.ll | 29 ++++++++++++++
11 files changed, 104 insertions(+), 74 deletions(-)
delete mode 100644 llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.wave64.ll
create mode 100644 llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.wave-size.ll
diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index 54b92a5ac0deb..e8fcef7a61405 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -30,6 +30,7 @@
namespace llvm {
class APInt;
+class FunctionType;
class MachineFunction;
class ScheduleDAGMutation;
class CallLowering;
@@ -91,6 +92,14 @@ class LLVM_ABI TargetSubtargetInfo : public MCSubtargetInfo {
/// \returns true if the target intrinsic \p IntrinsicID is supported by this
/// subtarget.
bool isIntrinsicSupported(unsigned IntrinsicID) const;
+ bool isIntrinsicSupported(unsigned IntrinsicID,
+ const FunctionType *FTy) const;
+
+ /// \returns the target features required by the target intrinsic
+ /// \p IntrinsicID with signature \p FTy.
+ virtual StringRef
+ getRequiredTargetFeaturesForIntrinsic(unsigned IntrinsicID,
+ const FunctionType *FTy) const;
// Interfaces to the major aspects of target machine information:
//
diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h
index da62b62bd8c74..2b67d83892961 100644
--- a/llvm/include/llvm/IR/DiagnosticInfo.h
+++ b/llvm/include/llvm/IR/DiagnosticInfo.h
@@ -1138,7 +1138,8 @@ class LLVM_ABI DiagnosticInfoUnsupportedTargetIntrinsic
public:
DiagnosticInfoUnsupportedTargetIntrinsic(
const Function &Fn, unsigned IntrinsicID,
- const DiagnosticLocation &Loc = DiagnosticLocation());
+ const DiagnosticLocation &Loc = DiagnosticLocation(),
+ StringRef RequiredFeatures = {});
static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_UnsupportedTargetIntrinsic;
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 8b792aaac77c3..518141df6a48e 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -2877,10 +2877,13 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
assert(ID != Intrinsic::not_intrinsic && "unknown intrinsic");
- if (!MF->getSubtarget().isIntrinsicSupported(ID)) {
+ if (!MF->getSubtarget().isIntrinsicSupported(ID, CI.getFunctionType())) {
const Function &Fn = MF->getFunction();
- Fn.getContext().diagnose(
- DiagnosticInfoUnsupportedTargetIntrinsic(Fn, ID, CI.getDebugLoc()));
+ StringRef RequiredFeatures =
+ MF->getSubtarget().getRequiredTargetFeaturesForIntrinsic(
+ ID, CI.getFunctionType());
+ Fn.getContext().diagnose(DiagnosticInfoUnsupportedTargetIntrinsic(
+ Fn, ID, CI.getDebugLoc(), RequiredFeatures));
return false;
}
@@ -2897,10 +2900,13 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
bool IRTranslator::translateIntrinsic(
const CallBase &CB, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder,
ArrayRef<TargetLowering::IntrinsicInfo> TgtMemIntrinsicInfos) {
- if (!MF->getSubtarget().isIntrinsicSupported(ID)) {
+ if (!MF->getSubtarget().isIntrinsicSupported(ID, CB.getFunctionType())) {
const Function &F = MF->getFunction();
- F.getContext().diagnose(
- DiagnosticInfoUnsupportedTargetIntrinsic(F, ID, CB.getDebugLoc()));
+ StringRef RequiredFeatures =
+ MF->getSubtarget().getRequiredTargetFeaturesForIntrinsic(
+ ID, CB.getFunctionType());
+ F.getContext().diagnose(DiagnosticInfoUnsupportedTargetIntrinsic(
+ F, ID, CB.getDebugLoc(), RequiredFeatures));
return false;
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index f5a4e891ce133..ecd02a1663e3d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -5530,10 +5530,14 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
Intrinsic::ID IntrinsicID = static_cast<Intrinsic::ID>(Intrinsic);
if (!DAG.getMachineFunction().getSubtarget().isIntrinsicSupported(
- Intrinsic)) {
+ Intrinsic, I.getFunctionType())) {
SDLoc DL = getCurSDLoc();
+ StringRef RequiredFeatures = DAG.getMachineFunction()
+ .getSubtarget()
+ .getRequiredTargetFeaturesForIntrinsic(
+ Intrinsic, I.getFunctionType());
DAG.getContext()->diagnose(DiagnosticInfoUnsupportedTargetIntrinsic(
- *I.getFunction(), IntrinsicID, DL.getDebugLoc()));
+ *I.getFunction(), IntrinsicID, DL.getDebugLoc(), RequiredFeatures));
// The intrinsic is not available on this subtarget. Preserve the chain for
// side-effecting intrinsics and lower any result to poison so that
diff --git a/llvm/lib/CodeGen/TargetSubtargetInfo.cpp b/llvm/lib/CodeGen/TargetSubtargetInfo.cpp
index f85d456122780..ddbc8258e1023 100644
--- a/llvm/lib/CodeGen/TargetSubtargetInfo.cpp
+++ b/llvm/lib/CodeGen/TargetSubtargetInfo.cpp
@@ -39,6 +39,19 @@ bool TargetSubtargetInfo::isIntrinsicSupported(unsigned IntrinsicID) const {
return It->second;
}
+bool TargetSubtargetInfo::isIntrinsicSupported(unsigned IntrinsicID,
+ const FunctionType *FTy) const {
+ StringRef RequiredFeatures =
+ getRequiredTargetFeaturesForIntrinsic(IntrinsicID, FTy);
+ return RequiredFeatures.empty() || checkFeatureExpression(RequiredFeatures);
+}
+
+StringRef TargetSubtargetInfo::getRequiredTargetFeaturesForIntrinsic(
+ unsigned IntrinsicID, const FunctionType *FTy) const {
+ return Intrinsic::getRequiredTargetFeatures(
+ static_cast<Intrinsic::ID>(IntrinsicID));
+}
+
bool TargetSubtargetInfo::enableAtomicExpand() const {
return true;
}
diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp
index a24b6d0935008..bcea525825aea 100644
--- a/llvm/lib/IR/DiagnosticInfo.cpp
+++ b/llvm/lib/IR/DiagnosticInfo.cpp
@@ -422,12 +422,15 @@ void DiagnosticInfoUnsupported::print(DiagnosticPrinter &DP) const {
DiagnosticInfoUnsupportedTargetIntrinsic::
DiagnosticInfoUnsupportedTargetIntrinsic(const Function &Fn,
unsigned IntrinsicID,
- const DiagnosticLocation &Loc)
+ const DiagnosticLocation &Loc,
+ StringRef RequiredFeaturesOverride)
: DiagnosticInfoWithLocationBase(DK_UnsupportedTargetIntrinsic, DS_Error,
Fn, Loc),
IntrinsicID(IntrinsicID),
- RequiredFeatures(Intrinsic::getRequiredTargetFeatures(
- static_cast<Intrinsic::ID>(IntrinsicID))) {
+ RequiredFeatures(RequiredFeaturesOverride.empty()
+ ? Intrinsic::getRequiredTargetFeatures(
+ static_cast<Intrinsic::ID>(IntrinsicID))
+ : RequiredFeaturesOverride) {
assert(!RequiredFeatures.empty() &&
"intrinsic without required features should be supported");
}
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
index dfc661999ab66..c85d7124f62bb 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
@@ -1719,51 +1719,39 @@ bool AMDGPUInstructionSelector::selectBallot(MachineInstr &I) const {
Register SrcReg = I.getOperand(2).getReg();
const unsigned BallotSize = MRI->getType(DstReg).getSizeInBits();
const unsigned WaveSize = STI.getWavefrontSize();
- std::optional<ValueAndVReg> Arg =
- getIConstantVRegValWithLookThrough(SrcReg, *MRI);
- if (!Arg && SrcReg.isVirtual()) {
- MachineInstr *SrcDef = MRI->getVRegDef(SrcReg);
- if (SrcDef && SrcDef->getOpcode() == AMDGPU::G_AMDGPU_COPY_VCC_SCC)
- Arg = getIConstantVRegValWithLookThrough(SrcDef->getOperand(1).getReg(),
- *MRI);
- }
- const bool IsI64OnWave32 = BallotSize == 64 && WaveSize == 32;
- const bool IsConstantI32OnWave64 = Arg && BallotSize == 32 && WaveSize == 64;
// In the common case, the return type matches the wave size.
- // However we also support emitting i64 ballots in wave32 mode. Constant i32
- // ballots in wave64 mode do not need the full wave mask.
- if (BallotSize != WaveSize && !IsI64OnWave32 && !IsConstantI32OnWave64)
+ // However we also support emitting i64 ballots in wave32 mode.
+ if (BallotSize != WaveSize && (BallotSize != 64 || WaveSize != 32))
return false;
+ std::optional<ValueAndVReg> Arg =
+ getIConstantVRegValWithLookThrough(SrcReg, *MRI);
+
Register Dst = DstReg;
// i64 ballot on Wave32: new Dst(i32) for WaveSize ballot.
- if (IsI64OnWave32) {
+ if (BallotSize != WaveSize) {
Dst = MRI->createVirtualRegister(TRI.getBoolRC());
}
- const unsigned DstSize = IsI64OnWave32 ? WaveSize : BallotSize;
- const TargetRegisterClass &DstRC =
- DstSize == 64 ? AMDGPU::SReg_64RegClass : AMDGPU::SReg_32RegClass;
if (Arg) {
const int64_t Value = Arg->Value.getZExtValue();
if (Value == 0) {
// Dst = S_MOV 0
- unsigned Opcode = DstSize == 64 ? AMDGPU::S_MOV_B64 : AMDGPU::S_MOV_B32;
+ unsigned Opcode = WaveSize == 64 ? AMDGPU::S_MOV_B64 : AMDGPU::S_MOV_B32;
BuildMI(*BB, &I, DL, TII.get(Opcode), Dst).addImm(0);
} else {
// Dst = COPY EXEC
assert(Value == 1);
- Register Exec = DstSize == 64 ? AMDGPU::EXEC : AMDGPU::EXEC_LO;
- BuildMI(*BB, &I, DL, TII.get(AMDGPU::COPY), Dst).addReg(Exec);
+ BuildMI(*BB, &I, DL, TII.get(AMDGPU::COPY), Dst).addReg(TRI.getExec());
}
- if (!RBI.constrainGenericRegister(Dst, DstRC, *MRI))
+ if (!RBI.constrainGenericRegister(Dst, *TRI.getBoolRC(), *MRI))
return false;
} else {
if (isLaneMaskFromSameBlock(SrcReg, *MRI, BB)) {
// Dst = COPY SrcReg
BuildMI(*BB, &I, DL, TII.get(AMDGPU::COPY), Dst).addReg(SrcReg);
- if (!RBI.constrainGenericRegister(Dst, DstRC, *MRI))
+ if (!RBI.constrainGenericRegister(Dst, *TRI.getBoolRC(), *MRI))
return false;
} else {
// Dst = S_AND SrcReg, EXEC
@@ -1777,7 +1765,7 @@ bool AMDGPUInstructionSelector::selectBallot(MachineInstr &I) const {
}
// i64 ballot on Wave32: zero-extend i32 ballot to i64.
- if (IsI64OnWave32) {
+ if (BallotSize != WaveSize) {
Register HiReg = MRI->createVirtualRegister(&AMDGPU::SReg_32RegClass);
BuildMI(*BB, &I, DL, TII.get(AMDGPU::S_MOV_B32), HiReg).addImm(0);
BuildMI(*BB, &I, DL, TII.get(AMDGPU::REG_SEQUENCE), DstReg)
diff --git a/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp b/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
index 23c92b9095e36..de8aaf55d2483 100644
--- a/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
@@ -24,7 +24,9 @@
#include "llvm/CodeGen/GlobalISel/InlineAsmLowering.h"
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
+#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/IntrinsicsAMDGPU.h"
#include "llvm/IR/MDBuilder.h"
#include <algorithm>
@@ -54,6 +56,16 @@ static cl::opt<unsigned>
GCNSubtarget::~GCNSubtarget() = default;
+StringRef GCNSubtarget::getRequiredTargetFeaturesForIntrinsic(
+ unsigned IntrinsicID, const FunctionType *FTy) const {
+ if (FTy && IntrinsicID == Intrinsic::amdgcn_ballot &&
+ FTy->getReturnType()->isIntegerTy(32))
+ return "wavefrontsize32";
+
+ return TargetSubtargetInfo::getRequiredTargetFeaturesForIntrinsic(IntrinsicID,
+ FTy);
+}
+
GCNSubtarget &GCNSubtarget::initializeSubtargetDependencies(const Triple &TT,
StringRef GPU,
StringRef FS) {
diff --git a/llvm/lib/Target/AMDGPU/GCNSubtarget.h b/llvm/lib/Target/AMDGPU/GCNSubtarget.h
index 7e4d9bd20cb2f..b7d8a35d47d94 100644
--- a/llvm/lib/Target/AMDGPU/GCNSubtarget.h
+++ b/llvm/lib/Target/AMDGPU/GCNSubtarget.h
@@ -123,6 +123,10 @@ class GCNSubtarget final : public AMDGPUGenSubtargetInfo,
/// function \p F.
void checkSubtargetFeatures(const Function &F) const;
+ StringRef
+ getRequiredTargetFeaturesForIntrinsic(unsigned IntrinsicID,
+ const FunctionType *FTy) const override;
+
const SIInstrInfo *getInstrInfo() const override { return &InstrInfo; }
const SIFrameLowering *getFrameLowering() const override {
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.wave64.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.wave64.ll
deleted file mode 100644
index b4e4d9b063ee3..0000000000000
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.wave64.ll
+++ /dev/null
@@ -1,39 +0,0 @@
-; RUN: split-file %s %t
-; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -global-isel -O3 -verify-machineinstrs < %t/constants.ll | FileCheck %s --check-prefix=CHECK
-; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -global-isel -O3 -verify-machineinstrs < %t/nonconstant.ll 2>&1 | FileCheck %s --check-prefix=ERR
-
-;--- constants.ll
-declare i32 @llvm.amdgcn.ballot.i32(i1)
-declare i32 @llvm.amdgcn.mbcnt.lo(i32, i32)
-
-define i32 @ballot_false_wave64() {
-; CHECK-LABEL: ballot_false_wave64:
-; CHECK: v_mov_b32_e32 v0, 0
- %ballot = call i32 @llvm.amdgcn.ballot.i32(i1 false)
- ret i32 %ballot
-}
-
-define i32 @ballot_true_wave64() {
-; CHECK-LABEL: ballot_true_wave64:
-; CHECK: v_mov_b32_e32 v0, exec_lo
- %ballot = call i32 @llvm.amdgcn.ballot.i32(i1 true)
- ret i32 %ballot
-}
-
-define i32 @activelane_false() {
-; CHECK-LABEL: activelane_false:
-; CHECK: v_mbcnt_lo_u32_b32 v0, 0, 0
- %ballot = call i32 @llvm.amdgcn.ballot.i32(i1 false)
- %lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 %ballot, i32 0)
- ret i32 %lane
-}
-
-;--- nonconstant.ll
-declare i32 @llvm.amdgcn.ballot.i32(i1)
-
-define amdgpu_cs i32 @nonconstant_i32_ballot_wave64(i32 %x) {
-; ERR: LLVM ERROR: cannot select: %{{[0-9]+}}:sreg_32(s32) = G_INTRINSIC_CONVERGENT intrinsic(@llvm.amdgcn.ballot)
- %trunc = trunc i32 %x to i1
- %ballot = call i32 @llvm.amdgcn.ballot.i32(i1 %trunc)
- ret i32 %ballot
-}
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.wave-size.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.wave-size.ll
new file mode 100644
index 0000000000000..67e406272d1b6
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.wave-size.ll
@@ -0,0 +1,29 @@
+; RUN: split-file %s %t
+; RUN: not llc -global-isel=0 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=null %t/ballot-i32.ll 2>&1 | FileCheck %s --check-prefix=ERR
+; RUN: not llc -global-isel=1 -global-isel-abort=0 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=null %t/ballot-i32.ll 2>&1 | FileCheck %s --check-prefix=ERR
+; RUN: llc -global-isel=0 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=null %t/ballot-i64.ll
+; RUN: llc -global-isel=1 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=null %t/ballot-i64.ll
+; RUN: llc -global-isel=0 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1010 -filetype=null %t/ballot-i32.ll
+; RUN: llc -global-isel=1 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1010 -filetype=null %t/ballot-i32.ll
+
+; ERR: error: {{.*}}: in function {{@?}}ballot_i32{{.*}}: llvm.amdgcn.ballot requires target feature 'wavefrontsize32'
+
+;--- ballot-i32.ll
+declare i32 @llvm.amdgcn.ballot.i32(i1)
+
+define amdgpu_kernel void @ballot_i32(i32 %x, ptr addrspace(1) %out) {
+ %trunc = trunc i32 %x to i1
+ %ballot = call i32 @llvm.amdgcn.ballot.i32(i1 %trunc)
+ store i32 %ballot, ptr addrspace(1) %out
+ ret void
+}
+
+;--- ballot-i64.ll
+declare i64 @llvm.amdgcn.ballot.i64(i1)
+
+define amdgpu_kernel void @ballot_i64(i32 %x, ptr addrspace(1) %out) {
+ %trunc = trunc i32 %x to i1
+ %ballot = call i64 @llvm.amdgcn.ballot.i64(i1 %trunc)
+ store i64 %ballot, ptr addrspace(1) %out
+ ret void
+}
>From 0e4d8439b7d6bc3e746020b19c91a5d50fd31a38 Mon Sep 17 00:00:00 2001
From: Keshav Vinayak Jha <keshavvinayakjha at gmail.com>
Date: Wed, 1 Jul 2026 00:58:00 +0530
Subject: [PATCH 3/4] [CodeGen] Simplify unsupported intrinsic diagnostics
Require callers to pass the resolved required feature string to DiagnosticInfoUnsupportedTargetIntrinsic instead of keeping a fallback path that only sees the intrinsic ID.
Also document why overload-sensitive intrinsic feature checks receive the resolved FunctionType.
Co-authored-by: GPT-5 <noreply at openai.com>
Signed-off-by: Keshav Vinayak Jha <keshavvinayakjha at gmail.com>
---
llvm/include/llvm/CodeGen/TargetSubtargetInfo.h | 3 +++
llvm/include/llvm/IR/DiagnosticInfo.h | 8 ++++----
llvm/lib/IR/DiagnosticInfo.cpp | 8 ++------
3 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index e8fcef7a61405..f9f7cf25fa33d 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -97,6 +97,9 @@ class LLVM_ABI TargetSubtargetInfo : public MCSubtargetInfo {
/// \returns the target features required by the target intrinsic
/// \p IntrinsicID with signature \p FTy.
+ ///
+ /// The intrinsic TargetFeatures table is keyed by intrinsic ID. Targets can
+ /// override this when support also depends on the resolved overload type.
virtual StringRef
getRequiredTargetFeaturesForIntrinsic(unsigned IntrinsicID,
const FunctionType *FTy) const;
diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h
index 2b67d83892961..0cd7299ae6852 100644
--- a/llvm/include/llvm/IR/DiagnosticInfo.h
+++ b/llvm/include/llvm/IR/DiagnosticInfo.h
@@ -1136,10 +1136,10 @@ class LLVM_ABI DiagnosticInfoUnsupportedTargetIntrinsic
StringRef RequiredFeatures;
public:
- DiagnosticInfoUnsupportedTargetIntrinsic(
- const Function &Fn, unsigned IntrinsicID,
- const DiagnosticLocation &Loc = DiagnosticLocation(),
- StringRef RequiredFeatures = {});
+ DiagnosticInfoUnsupportedTargetIntrinsic(const Function &Fn,
+ unsigned IntrinsicID,
+ const DiagnosticLocation &Loc,
+ StringRef RequiredFeatures);
static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_UnsupportedTargetIntrinsic;
diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp
index bcea525825aea..037fd16064158 100644
--- a/llvm/lib/IR/DiagnosticInfo.cpp
+++ b/llvm/lib/IR/DiagnosticInfo.cpp
@@ -423,14 +423,10 @@ DiagnosticInfoUnsupportedTargetIntrinsic::
DiagnosticInfoUnsupportedTargetIntrinsic(const Function &Fn,
unsigned IntrinsicID,
const DiagnosticLocation &Loc,
- StringRef RequiredFeaturesOverride)
+ StringRef RequiredFeatures)
: DiagnosticInfoWithLocationBase(DK_UnsupportedTargetIntrinsic, DS_Error,
Fn, Loc),
- IntrinsicID(IntrinsicID),
- RequiredFeatures(RequiredFeaturesOverride.empty()
- ? Intrinsic::getRequiredTargetFeatures(
- static_cast<Intrinsic::ID>(IntrinsicID))
- : RequiredFeaturesOverride) {
+ IntrinsicID(IntrinsicID), RequiredFeatures(RequiredFeatures) {
assert(!RequiredFeatures.empty() &&
"intrinsic without required features should be supported");
}
>From 9f5798e8727bf155aebe1cb165a84fd13e0c6c5d Mon Sep 17 00:00:00 2001
From: Keshav Vinayak Jha <keshavvinayakjha at gmail.com>
Date: Wed, 1 Jul 2026 20:04:42 +0530
Subject: [PATCH 4/4] [CodeGen] Include intrinsic overload name in diagnostics
Preserve the called intrinsic declaration name in unsupported-target-intrinsic diagnostics so overloaded intrinsics identify the rejected type in the error message.
Update the folded AMDGPU ballot checks to expect the i32 overload name in the wave64 diagnostic.
Co-authored-by: GPT-5 <noreply at openai.com>
Signed-off-by: Keshav Vinayak Jha <keshavvinayakjha at gmail.com>
---
llvm/include/llvm/IR/DiagnosticInfo.h | 3 ++
llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 7 +++--
.../SelectionDAG/SelectionDAGBuilder.cpp | 6 +++-
llvm/lib/IR/DiagnosticInfo.cpp | 10 ++++---
.../GlobalISel/llvm.amdgcn.ballot.i32.ll | 3 ++
.../CodeGen/AMDGPU/llvm.amdgcn.ballot.i32.ll | 3 ++
.../AMDGPU/llvm.amdgcn.ballot.wave-size.ll | 29 -------------------
7 files changed, 25 insertions(+), 36 deletions(-)
delete mode 100644 llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.wave-size.ll
diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h
index 0cd7299ae6852..4067d267df5b9 100644
--- a/llvm/include/llvm/IR/DiagnosticInfo.h
+++ b/llvm/include/llvm/IR/DiagnosticInfo.h
@@ -1133,11 +1133,13 @@ class LLVM_ABI DiagnosticInfoUnsupportedTargetIntrinsic
: public DiagnosticInfoWithLocationBase {
private:
unsigned IntrinsicID;
+ std::string IntrinsicName;
StringRef RequiredFeatures;
public:
DiagnosticInfoUnsupportedTargetIntrinsic(const Function &Fn,
unsigned IntrinsicID,
+ StringRef IntrinsicName,
const DiagnosticLocation &Loc,
StringRef RequiredFeatures);
@@ -1146,6 +1148,7 @@ class LLVM_ABI DiagnosticInfoUnsupportedTargetIntrinsic
}
unsigned getIntrinsicID() const { return IntrinsicID; }
+ StringRef getIntrinsicName() const { return IntrinsicName; }
StringRef getRequiredFeatures() const { return RequiredFeatures; }
std::string getMessage() const;
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 518141df6a48e..7a7e5e49e210a 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -2883,7 +2883,7 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
MF->getSubtarget().getRequiredTargetFeaturesForIntrinsic(
ID, CI.getFunctionType());
Fn.getContext().diagnose(DiagnosticInfoUnsupportedTargetIntrinsic(
- Fn, ID, CI.getDebugLoc(), RequiredFeatures));
+ Fn, ID, F->getName(), CI.getDebugLoc(), RequiredFeatures));
return false;
}
@@ -2905,8 +2905,11 @@ bool IRTranslator::translateIntrinsic(
StringRef RequiredFeatures =
MF->getSubtarget().getRequiredTargetFeaturesForIntrinsic(
ID, CB.getFunctionType());
+ const Function *IntrinsicFn = CB.getCalledFunction();
+ StringRef IntrinsicName =
+ IntrinsicFn ? IntrinsicFn->getName() : Intrinsic::getBaseName(ID);
F.getContext().diagnose(DiagnosticInfoUnsupportedTargetIntrinsic(
- F, ID, CB.getDebugLoc(), RequiredFeatures));
+ F, ID, IntrinsicName, CB.getDebugLoc(), RequiredFeatures));
return false;
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index ecd02a1663e3d..eecf940fd59bd 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -5536,8 +5536,12 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
.getSubtarget()
.getRequiredTargetFeaturesForIntrinsic(
Intrinsic, I.getFunctionType());
+ const Function *IntrinsicFn = I.getCalledFunction();
+ StringRef IntrinsicName = IntrinsicFn ? IntrinsicFn->getName()
+ : Intrinsic::getBaseName(IntrinsicID);
DAG.getContext()->diagnose(DiagnosticInfoUnsupportedTargetIntrinsic(
- *I.getFunction(), IntrinsicID, DL.getDebugLoc(), RequiredFeatures));
+ *I.getFunction(), IntrinsicID, IntrinsicName, DL.getDebugLoc(),
+ RequiredFeatures));
// The intrinsic is not available on this subtarget. Preserve the chain for
// side-effecting intrinsics and lower any result to poison so that
diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp
index 037fd16064158..569e0e0c1374e 100644
--- a/llvm/lib/IR/DiagnosticInfo.cpp
+++ b/llvm/lib/IR/DiagnosticInfo.cpp
@@ -422,19 +422,21 @@ void DiagnosticInfoUnsupported::print(DiagnosticPrinter &DP) const {
DiagnosticInfoUnsupportedTargetIntrinsic::
DiagnosticInfoUnsupportedTargetIntrinsic(const Function &Fn,
unsigned IntrinsicID,
+ StringRef IntrinsicName,
const DiagnosticLocation &Loc,
StringRef RequiredFeatures)
: DiagnosticInfoWithLocationBase(DK_UnsupportedTargetIntrinsic, DS_Error,
Fn, Loc),
- IntrinsicID(IntrinsicID), RequiredFeatures(RequiredFeatures) {
+ IntrinsicID(IntrinsicID), IntrinsicName(IntrinsicName),
+ RequiredFeatures(RequiredFeatures) {
assert(!RequiredFeatures.empty() &&
"intrinsic without required features should be supported");
+ assert(!IntrinsicName.empty() && "intrinsic name should not be empty");
}
std::string DiagnosticInfoUnsupportedTargetIntrinsic::getMessage() const {
- return (Twine(
- Intrinsic::getBaseName(static_cast<Intrinsic::ID>(IntrinsicID))) +
- " requires target feature '" + RequiredFeatures + "'")
+ return (Twine(IntrinsicName) + " requires target feature '" +
+ RequiredFeatures + "'")
.str();
}
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.ll
index 93c8c9e07dede..5e7b56033e3f3 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.ll
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.ballot.i32.ll
@@ -1,6 +1,9 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=amdgcn -mcpu=gfx1010 -global-isel < %s | FileCheck -check-prefixes=CHECK,GFX10 %s
; RUN: llc -mtriple=amdgcn -mcpu=gfx1100 -mattr=-real-true16 -amdgpu-enable-delay-alu=0 -global-isel < %s | FileCheck -check-prefixes=CHECK,GFX11 %s
+; RUN: llvm-extract --func=constant_false -S %s | not llc -mtriple=amdgcn -mcpu=gfx900 -global-isel -global-isel-abort=0 -filetype=null 2>&1 | FileCheck -check-prefix=ERR %s
+
+; ERR: error: {{.*}}: in function {{@?}}constant_false{{.*}}: llvm.amdgcn.ballot.i32 requires target feature 'wavefrontsize32'
declare i32 @llvm.amdgcn.ballot.i32(i1)
declare i32 @llvm.ctpop.i32(i32)
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.i32.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.i32.ll
index 9bcf8c7db29a0..0bc29f0d8615c 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.i32.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.i32.ll
@@ -1,6 +1,9 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=amdgcn -mcpu=gfx1010 -mattr=+wavefrontsize32 < %s | FileCheck -check-prefixes=CHECK,GFX10 %s
; RUN: llc -mtriple=amdgcn -mcpu=gfx1100 -amdgpu-enable-delay-alu=0 -mattr=+wavefrontsize32 < %s | FileCheck -check-prefixes=CHECK,GFX11 %s
+; RUN: llvm-extract --func=constant_false -S %s | not llc -mtriple=amdgcn -mcpu=gfx900 -filetype=null 2>&1 | FileCheck -check-prefix=ERR %s
+
+; ERR: error: {{.*}}: in function {{@?}}constant_false{{.*}}: llvm.amdgcn.ballot.i32 requires target feature 'wavefrontsize32'
declare i32 @llvm.amdgcn.ballot.i32(i1)
declare i32 @llvm.ctpop.i32(i32)
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.wave-size.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.wave-size.ll
deleted file mode 100644
index 67e406272d1b6..0000000000000
--- a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.ballot.wave-size.ll
+++ /dev/null
@@ -1,29 +0,0 @@
-; RUN: split-file %s %t
-; RUN: not llc -global-isel=0 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=null %t/ballot-i32.ll 2>&1 | FileCheck %s --check-prefix=ERR
-; RUN: not llc -global-isel=1 -global-isel-abort=0 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=null %t/ballot-i32.ll 2>&1 | FileCheck %s --check-prefix=ERR
-; RUN: llc -global-isel=0 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=null %t/ballot-i64.ll
-; RUN: llc -global-isel=1 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=null %t/ballot-i64.ll
-; RUN: llc -global-isel=0 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1010 -filetype=null %t/ballot-i32.ll
-; RUN: llc -global-isel=1 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1010 -filetype=null %t/ballot-i32.ll
-
-; ERR: error: {{.*}}: in function {{@?}}ballot_i32{{.*}}: llvm.amdgcn.ballot requires target feature 'wavefrontsize32'
-
-;--- ballot-i32.ll
-declare i32 @llvm.amdgcn.ballot.i32(i1)
-
-define amdgpu_kernel void @ballot_i32(i32 %x, ptr addrspace(1) %out) {
- %trunc = trunc i32 %x to i1
- %ballot = call i32 @llvm.amdgcn.ballot.i32(i1 %trunc)
- store i32 %ballot, ptr addrspace(1) %out
- ret void
-}
-
-;--- ballot-i64.ll
-declare i64 @llvm.amdgcn.ballot.i64(i1)
-
-define amdgpu_kernel void @ballot_i64(i32 %x, ptr addrspace(1) %out) {
- %trunc = trunc i32 %x to i1
- %ballot = call i64 @llvm.amdgcn.ballot.i64(i1 %trunc)
- store i64 %ballot, ptr addrspace(1) %out
- ret void
-}
More information about the llvm-commits
mailing list