[llvm] 698dd11 - AMDGPU: Use the addrspacecast nonnull flag in codegen (#220926)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 8 02:14:08 PDT 2026
Author: Matt Arsenault
Date: 2026-09-08T11:14:02+02:00
New Revision: 698dd11893fca65681f8cd84b39ff49d29ddcd1e
URL: https://github.com/llvm/llvm-project/commit/698dd11893fca65681f8cd84b39ff49d29ddcd1e
DIFF: https://github.com/llvm/llvm-project/commit/698dd11893fca65681f8cd84b39ff49d29ddcd1e.diff
LOG: AMDGPU: Use the addrspacecast nonnull flag in codegen (#220926)
Plumb the nonnull flag through to the backend so a flagged addrspacecast
lowers without the runtime null check, matching what
llvm.amdgcn.addrspacecast.nonnull already provides.
Add the NonNull MIFlag with MIR printer/parser support (including the
MIRPrinter path and update_mir_test_checks) so it round-trips on
G_ADDRSPACE_CAST, and preserve it through SelectionDAG vector
scalarization and splitting.
Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>
Added:
llvm/test/CodeGen/AMDGPU/addrspacecast-nonnull.ll
llvm/test/CodeGen/MIR/AMDGPU/addrspacecast-nonnull.mir
Modified:
llvm/include/llvm/CodeGen/MachineInstr.h
llvm/include/llvm/CodeGen/SelectionDAG.h
llvm/include/llvm/CodeGen/SelectionDAGNodes.h
llvm/lib/CodeGen/MIRParser/MILexer.cpp
llvm/lib/CodeGen/MIRParser/MILexer.h
llvm/lib/CodeGen/MIRParser/MIParser.cpp
llvm/lib/CodeGen/MIRPrinter.cpp
llvm/lib/CodeGen/MachineInstr.cpp
llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
llvm/lib/Target/AMDGPU/SIISelLowering.cpp
llvm/utils/UpdateTestChecks/mir.py
Removed:
################################################################################
diff --git a/llvm/include/llvm/CodeGen/MachineInstr.h b/llvm/include/llvm/CodeGen/MachineInstr.h
index b04018e43bbe0..87e40501b3f3c 100644
--- a/llvm/include/llvm/CodeGen/MachineInstr.h
+++ b/llvm/include/llvm/CodeGen/MachineInstr.h
@@ -128,7 +128,9 @@ class MachineInstr
SameSign = 1 << 21, // Both operands have the same sign.
InBounds = 1 << 22, // Pointer arithmetic remains inbounds.
// Implies NoUSWrap.
- LRSplit = 1 << 23 // Instruction for live range split.
+ LRSplit = 1 << 23, // Instruction for live range split.
+ NonNull = 1 << 24 // Address space cast source is not the null
+ // value of the source address space.
};
private:
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index c1acf6aaf5b6f..b00fdb2ef05c5 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -1746,7 +1746,8 @@ class SelectionDAG {
/// Return an AddrSpaceCastSDNode.
LLVM_ABI SDValue getAddrSpaceCast(const SDLoc &dl, EVT VT, SDValue Ptr,
- unsigned SrcAS, unsigned DestAS);
+ unsigned SrcAS, unsigned DestAS,
+ const SDNodeFlags Flags = SDNodeFlags());
/// Return a freeze using the SDLoc of the value operand.
LLVM_ABI SDValue getFreeze(SDValue V);
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
index 0fa4385c53bcc..667c98f086827 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -424,13 +424,17 @@ struct SDNodeFlags {
// Call does not require convergence guarantees.
NoConvergent = 1 << 16,
+ // ISD::ADDRSPACECAST where the source is known not to be the null value of
+ // the source address space, so the result is poison if the source is null.
+ NonNull = 1 << 17,
+
// NOTE: Please update LargestValue in LLVM_DECLARE_ENUM_AS_BITMASK below
// the class definition when adding new flags.
PoisonGeneratingFlags = NoUnsignedWrap | NoSignedWrap | Exact | Disjoint |
- NonNeg | NoNaNs | NoInfs | SameSign | InBounds,
+ NonNeg | NoNaNs | NoInfs | SameSign | InBounds | NonNull,
FastMathFlags = NoNaNs | NoInfs | NoSignedZeros | AllowReciprocal |
- AllowContract | ApproximateFuncs | AllowReassociation,
+ AllowContract | ApproximateFuncs | AllowReassociation,
};
/// Default constructor turns off all optimization flags.
@@ -465,6 +469,7 @@ struct SDNodeFlags {
void setUnpredictable(bool b) { setFlag<Unpredictable>(b); }
void setInBounds(bool b) { setFlag<InBounds>(b); }
void setNoConvergent(bool b) { setFlag<NoConvergent>(b); }
+ void setNonNull(bool b) { setFlag<NonNull>(b); }
// These are accessors for each flag.
bool hasNoUnsignedWrap() const { return Flags & NoUnsignedWrap; }
@@ -484,6 +489,7 @@ struct SDNodeFlags {
bool hasUnpredictable() const { return Flags & Unpredictable; }
bool hasInBounds() const { return Flags & InBounds; }
bool hasNoConvergent() const { return Flags & NoConvergent; }
+ bool hasNonNull() const { return Flags & NonNull; }
bool operator==(const SDNodeFlags &Other) const {
return Flags == Other.Flags;
@@ -492,8 +498,7 @@ struct SDNodeFlags {
void operator|=(const SDNodeFlags &OtherFlags) { Flags |= OtherFlags.Flags; }
};
-LLVM_DECLARE_ENUM_AS_BITMASK(decltype(SDNodeFlags::None),
- SDNodeFlags::NoConvergent);
+LLVM_DECLARE_ENUM_AS_BITMASK(decltype(SDNodeFlags::None), SDNodeFlags::NonNull);
inline SDNodeFlags operator|(SDNodeFlags LHS, SDNodeFlags RHS) {
LHS |= RHS;
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
index 67fbc00edd9db..0851c42c7777f 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
@@ -218,6 +218,7 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
.Case("disjoint", MIToken::kw_disjoint)
.Case("samesign", MIToken::kw_samesign)
.Case("inbounds", MIToken::kw_inbounds)
+ .Case("nonnull", MIToken::kw_nonnull)
.Case("nofpexcept", MIToken::kw_nofpexcept)
.Case("unpredictable", MIToken::kw_unpredictable)
.Case("debug-location", MIToken::kw_debug_location)
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h
index f5947bfe59b9d..0e28ee3635a87 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.h
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.h
@@ -79,6 +79,7 @@ struct MIToken {
kw_disjoint,
kw_samesign,
kw_inbounds,
+ kw_nonnull,
kw_debug_location,
kw_debug_instr_number,
kw_dbg_instr_ref,
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index ef4927e2c4ee3..4b951785e9c41 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -1389,6 +1389,7 @@ bool MIParser::parseInstruction(unsigned &OpCode, unsigned &Flags) {
Token.is(MIToken::kw_nusw) ||
Token.is(MIToken::kw_samesign) ||
Token.is(MIToken::kw_inbounds) ||
+ Token.is(MIToken::kw_nonnull) ||
Token.is(MIToken::kw_lr_split)) {
// clang-format on
// Mine frame and fast math flags
@@ -1432,6 +1433,8 @@ bool MIParser::parseInstruction(unsigned &OpCode, unsigned &Flags) {
Flags |= MachineInstr::SameSign;
if (Token.is(MIToken::kw_inbounds))
Flags |= MachineInstr::InBounds;
+ if (Token.is(MIToken::kw_nonnull))
+ Flags |= MachineInstr::NonNull;
if (Token.is(MIToken::kw_lr_split))
Flags |= MachineInstr::LRSplit;
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index 8acd6f14ebc2e..5a4aa4910c0d3 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -894,6 +894,8 @@ static void printMI(raw_ostream &OS, MFPrintState &State,
OS << "inbounds ";
if (MI.getFlag(MachineInstr::LRSplit))
OS << "lr-split ";
+ if (MI.getFlag(MachineInstr::NonNull))
+ OS << "nonnull ";
// NOTE: Please add new MIFlags also to the MI_FLAGS_STR in
// llvm/utils/UpdateTestChecks/mir.py.
diff --git a/llvm/lib/CodeGen/MachineInstr.cpp b/llvm/lib/CodeGen/MachineInstr.cpp
index a3dce5513deef..3ed2ea5e20dc6 100644
--- a/llvm/lib/CodeGen/MachineInstr.cpp
+++ b/llvm/lib/CodeGen/MachineInstr.cpp
@@ -621,6 +621,11 @@ uint32_t MachineInstr::copyFlagsFromInstruction(const Instruction &I) {
if (ICmp->hasSameSign())
MIFlags |= MachineInstr::MIFlag::SameSign;
+ // Copy the nonnull flag.
+ if (const auto *ASC = dyn_cast<AddrSpaceCastInst>(&I))
+ if (ASC->hasNonNull())
+ MIFlags |= MachineInstr::MIFlag::NonNull;
+
// Copy the exact flag.
if (const PossiblyExactOperator *PE = dyn_cast<PossiblyExactOperator>(&I))
if (PE->isExact())
@@ -1899,6 +1904,8 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST,
OS << "inbounds ";
if (getFlag(MachineInstr::LRSplit))
OS << "lr-split ";
+ if (getFlag(MachineInstr::NonNull))
+ OS << "nonnull ";
// Print the opcode name.
if (TII)
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
index 0215f8f5e00c0..e997e350deb92 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -663,7 +663,8 @@ SDValue DAGTypeLegalizer::ScalarizeVecRes_ADDRSPACECAST(SDNode *N) {
auto *AddrSpaceCastN = cast<AddrSpaceCastSDNode>(N);
unsigned SrcAS = AddrSpaceCastN->getSrcAddressSpace();
unsigned DestAS = AddrSpaceCastN->getDestAddressSpace();
- return DAG.getAddrSpaceCast(DL, DestVT, Op, SrcAS, DestAS);
+ return DAG.getAddrSpaceCast(DL, DestVT, Op, SrcAS, DestAS,
+ AddrSpaceCastN->getFlags());
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_SCALAR_TO_VECTOR(SDNode *N) {
@@ -2991,8 +2992,9 @@ void DAGTypeLegalizer::SplitVecRes_ADDRSPACECAST(SDNode *N, SDValue &Lo,
auto *AddrSpaceCastN = cast<AddrSpaceCastSDNode>(N);
unsigned SrcAS = AddrSpaceCastN->getSrcAddressSpace();
unsigned DestAS = AddrSpaceCastN->getDestAddressSpace();
- Lo = DAG.getAddrSpaceCast(dl, LoVT, Lo, SrcAS, DestAS);
- Hi = DAG.getAddrSpaceCast(dl, HiVT, Hi, SrcAS, DestAS);
+ SDNodeFlags Flags = AddrSpaceCastN->getFlags();
+ Lo = DAG.getAddrSpaceCast(dl, LoVT, Lo, SrcAS, DestAS, Flags);
+ Hi = DAG.getAddrSpaceCast(dl, HiVT, Hi, SrcAS, DestAS, Flags);
}
void DAGTypeLegalizer::SplitVecRes_UnaryOpWithTwoResults(SDNode *N,
@@ -6325,9 +6327,9 @@ SDValue DAGTypeLegalizer::WidenVecRes_ADDRSPACECAST(SDNode *N) {
InOp = DAG.getInsertSubvector(DL, DAG.getPOISON(InWidenVT), InOp, 0);
}
- return DAG.getAddrSpaceCast(DL, WidenVT, InOp,
- AddrSpaceCastN->getSrcAddressSpace(),
- AddrSpaceCastN->getDestAddressSpace());
+ return DAG.getAddrSpaceCast(
+ DL, WidenVT, InOp, AddrSpaceCastN->getSrcAddressSpace(),
+ AddrSpaceCastN->getDestAddressSpace(), AddrSpaceCastN->getFlags());
}
SDValue DAGTypeLegalizer::WidenVecRes_BITCAST(SDNode *N) {
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 94686c2a65ff3..eadbe60742f3e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -2500,7 +2500,8 @@ SDValue SelectionDAG::getBitcast(EVT VT, SDValue V) {
}
SDValue SelectionDAG::getAddrSpaceCast(const SDLoc &dl, EVT VT, SDValue Ptr,
- unsigned SrcAS, unsigned DestAS) {
+ unsigned SrcAS, unsigned DestAS,
+ const SDNodeFlags Flags) {
SDVTList VTs = getVTList(VT);
SDValue Ops[] = {Ptr};
SDNodeKey ID(ISD::ADDRSPACECAST, VTs, Ops);
@@ -2508,11 +2509,14 @@ SDValue SelectionDAG::getAddrSpaceCast(const SDLoc &dl, EVT VT, SDValue Ptr,
ID.AddInteger(DestAS);
FoldingSetInsertToken InsertToken;
- if (SDNode *E = lookupNode(ID, dl, InsertToken))
+ if (SDNode *E = lookupNode(ID, dl, InsertToken)) {
+ E->intersectFlagsWith(Flags);
return SDValue(E, 0);
+ }
auto *N = newSDNode<AddrSpaceCastSDNode>(dl.getIROrder(), dl.getDebugLoc(),
VTs, SrcAS, DestAS);
+ N->setFlags(Flags);
createOperands(N, Ops);
CSEMap.insert(N, InsertToken);
@@ -14349,9 +14353,9 @@ SDValue SelectionDAG::UnrollVectorOp(SDNode *N, unsigned ResNE) {
}
case ISD::ADDRSPACECAST: {
const auto *ASC = cast<AddrSpaceCastSDNode>(N);
- Scalars.push_back(getAddrSpaceCast(dl, EltVT, Operands[0],
- ASC->getSrcAddressSpace(),
- ASC->getDestAddressSpace()));
+ Scalars.push_back(
+ getAddrSpaceCast(dl, EltVT, Operands[0], ASC->getSrcAddressSpace(),
+ ASC->getDestAddressSpace(), ASC->getFlags()));
break;
}
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index f34f1c7e9c969..794a4e6e1b537 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4176,8 +4176,12 @@ void SelectionDAGBuilder::visitAddrSpaceCast(const User &I) {
unsigned SrcAS = SV->getType()->getPointerAddressSpace();
unsigned DestAS = I.getType()->getPointerAddressSpace();
- if (!TM.isNoopAddrSpaceCast(SrcAS, DestAS))
- N = DAG.getAddrSpaceCast(getCurSDLoc(), DestVT, N, SrcAS, DestAS);
+ if (!TM.isNoopAddrSpaceCast(SrcAS, DestAS)) {
+ SDNodeFlags Flags;
+ if (const auto *ASC = dyn_cast<AddrSpaceCastInst>(&I))
+ Flags.setNonNull(ASC->hasNonNull());
+ N = DAG.getAddrSpaceCast(getCurSDLoc(), DestVT, N, SrcAS, DestAS, Flags);
+ }
setValue(&I, N);
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index c6a8fe568064d..32e0cafd9f71c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -740,6 +740,9 @@ void SDNode::print_details(raw_ostream &OS, const SelectionDAG *G) const {
if (getFlags().hasNonNeg())
OS << " nneg";
+ if (getFlags().hasNonNull())
+ OS << " nonnull";
+
if (getFlags().hasNoNaNs())
OS << " nnan";
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
index faa0d3994fcd0..c4a7c77f6968f 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
@@ -2556,6 +2556,11 @@ bool AMDGPULegalizerInfo::legalizeAddrSpaceCast(
const AMDGPUTargetMachine &TM
= static_cast<const AMDGPUTargetMachine &>(MF.getTarget());
+ // The source is known non-null for llvm.amdgcn.addrspacecast.nonnull or a
+ // G_ADDRSPACE_CAST carrying the nonnull flag; otherwise we need to guess.
+ const bool IsNonNull =
+ isa<GIntrinsic>(MI) || MI.getFlag(MachineInstr::MIFlag::NonNull);
+
if (TM.isNoopAddrSpaceCast(SrcAS, DestAS)) {
MI.setDesc(B.getTII().get(TargetOpcode::G_BITCAST));
return true;
@@ -2583,9 +2588,7 @@ bool AMDGPULegalizerInfo::legalizeAddrSpaceCast(
return B.buildExtract(Dst, Src, 0).getReg(0);
};
- // For llvm.amdgcn.addrspacecast.nonnull we can always assume non-null, for
- // G_ADDRSPACE_CAST we need to guess.
- if (isa<GIntrinsic>(MI) || isKnownNonNull(Src, MRI, TM, SrcAS)) {
+ if (IsNonNull || isKnownNonNull(Src, MRI, TM, SrcAS)) {
castFlatToLocalOrPrivate(Dst);
MI.eraseFromParent();
return true;
@@ -2655,9 +2658,7 @@ bool AMDGPULegalizerInfo::legalizeAddrSpaceCast(
return B.buildMergeLikeInstr(Dst, {SrcAsInt, ApertureReg}).getReg(0);
};
- // For llvm.amdgcn.addrspacecast.nonnull we can always assume non-null, for
- // G_ADDRSPACE_CAST we need to guess.
- if (isa<GIntrinsic>(MI) || isKnownNonNull(Src, MRI, TM, SrcAS)) {
+ if (IsNonNull || isKnownNonNull(Src, MRI, TM, SrcAS)) {
castLocalOrPrivateToFlat(Dst);
MI.eraseFromParent();
return true;
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 1ec23da794bca..3bad6d330c0ad 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -9419,6 +9419,7 @@ SDValue SITargetLowering::lowerADDRSPACECAST(SDValue Op,
SrcAS = ASC->getSrcAddressSpace();
Src = ASC->getOperand(0);
DestAS = ASC->getDestAddressSpace();
+ IsNonNull = ASC->getFlags().hasNonNull();
} else {
assert(Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN &&
Op.getConstantOperandVal(0) ==
diff --git a/llvm/test/CodeGen/AMDGPU/addrspacecast-nonnull.ll b/llvm/test/CodeGen/AMDGPU/addrspacecast-nonnull.ll
new file mode 100644
index 0000000000000..afefa784fabbb
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/addrspacecast-nonnull.ll
@@ -0,0 +1,299 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
+; RUN: llc -global-isel=0 -mtriple=amdgpu9.00-amd-amdhsa < %s | FileCheck --check-prefixes=CHECK,DAGISEL %s
+; RUN: llc -global-isel=1 -mtriple=amdgpu9.00-amd-amdhsa < %s | FileCheck --check-prefixes=CHECK,GISEL %s
+
+; The nonnull flag on addrspacecast allows the target to skip the null check
+; that maps a source null pointer to the destination null pointer.
+
+define void @local_to_flat(ptr addrspace(3) %ptr) {
+; CHECK-LABEL: local_to_flat:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_mov_b64 s[4:5], src_shared_base
+; CHECK-NEXT: v_mov_b32_e32 v1, s5
+; CHECK-NEXT: v_mov_b32_e32 v2, 7
+; CHECK-NEXT: flat_store_dword v[0:1], v2
+; CHECK-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ %1 = addrspacecast nonnull ptr addrspace(3) %ptr to ptr
+ store volatile i32 7, ptr %1, align 4
+ ret void
+}
+
+define void @private_to_flat(ptr addrspace(5) %ptr) {
+; CHECK-LABEL: private_to_flat:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_mov_b64 s[4:5], src_private_base
+; CHECK-NEXT: v_mov_b32_e32 v1, s5
+; CHECK-NEXT: v_mov_b32_e32 v2, 7
+; CHECK-NEXT: flat_store_dword v[0:1], v2
+; CHECK-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ %1 = addrspacecast nonnull ptr addrspace(5) %ptr to ptr
+ store volatile i32 7, ptr %1, align 4
+ ret void
+}
+
+define void @flat_to_local(ptr %ptr) {
+; CHECK-LABEL: flat_to_local:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: v_mov_b32_e32 v1, 7
+; CHECK-NEXT: ds_write_b32 v0, v1
+; CHECK-NEXT: s_waitcnt lgkmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ %1 = addrspacecast nonnull ptr %ptr to ptr addrspace(3)
+ store volatile i32 7, ptr addrspace(3) %1, align 4
+ ret void
+}
+
+define void @flat_to_private(ptr %ptr) {
+; CHECK-LABEL: flat_to_private:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: v_mov_b32_e32 v1, 7
+; CHECK-NEXT: buffer_store_dword v1, v0, s[0:3], 0 offen
+; CHECK-NEXT: s_waitcnt vmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ %1 = addrspacecast nonnull ptr %ptr to ptr addrspace(5)
+ store volatile i32 7, ptr addrspace(5) %1, align 4
+ ret void
+}
+
+; The nonnull flag must survive scalarization of a vector addrspacecast, so no
+; per-element null check is emitted.
+define <2 x ptr> @local_to_flat_vector(<2 x ptr addrspace(3)> %ptr) {
+; CHECK-LABEL: local_to_flat_vector:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_mov_b64 s[4:5], src_shared_base
+; CHECK-NEXT: v_mov_b32_e32 v2, v1
+; CHECK-NEXT: v_mov_b32_e32 v1, s5
+; CHECK-NEXT: v_mov_b32_e32 v3, s5
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ %1 = addrspacecast nonnull <2 x ptr addrspace(3)> %ptr to <2 x ptr>
+ ret <2 x ptr> %1
+}
+
+; The nonnull flag must also survive vector type-legalization that splits the
+; addrspacecast (v32 splits repeatedly).
+define <32 x ptr> @local_to_flat_vector_split(<32 x ptr addrspace(3)> %ptr) {
+; DAGISEL-LABEL: local_to_flat_vector_split:
+; DAGISEL: ; %bb.0:
+; DAGISEL-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; DAGISEL-NEXT: buffer_store_dword v30, v0, s[0:3], 0 offen offset:232
+; DAGISEL-NEXT: buffer_store_dword v29, v0, s[0:3], 0 offen offset:224
+; DAGISEL-NEXT: buffer_store_dword v28, v0, s[0:3], 0 offen offset:216
+; DAGISEL-NEXT: buffer_store_dword v27, v0, s[0:3], 0 offen offset:208
+; DAGISEL-NEXT: buffer_store_dword v26, v0, s[0:3], 0 offen offset:200
+; DAGISEL-NEXT: buffer_load_dword v26, off, s[0:3], s32 offset:4
+; DAGISEL-NEXT: s_nop 0
+; DAGISEL-NEXT: buffer_load_dword v27, off, s[0:3], s32
+; DAGISEL-NEXT: s_mov_b64 s[4:5], src_shared_base
+; DAGISEL-NEXT: buffer_store_dword v25, v0, s[0:3], 0 offen offset:192
+; DAGISEL-NEXT: buffer_store_dword v24, v0, s[0:3], 0 offen offset:184
+; DAGISEL-NEXT: buffer_store_dword v23, v0, s[0:3], 0 offen offset:176
+; DAGISEL-NEXT: buffer_store_dword v22, v0, s[0:3], 0 offen offset:168
+; DAGISEL-NEXT: buffer_store_dword v21, v0, s[0:3], 0 offen offset:160
+; DAGISEL-NEXT: buffer_store_dword v20, v0, s[0:3], 0 offen offset:152
+; DAGISEL-NEXT: buffer_store_dword v19, v0, s[0:3], 0 offen offset:144
+; DAGISEL-NEXT: buffer_store_dword v18, v0, s[0:3], 0 offen offset:136
+; DAGISEL-NEXT: buffer_store_dword v17, v0, s[0:3], 0 offen offset:128
+; DAGISEL-NEXT: buffer_store_dword v16, v0, s[0:3], 0 offen offset:120
+; DAGISEL-NEXT: buffer_store_dword v15, v0, s[0:3], 0 offen offset:112
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:104
+; DAGISEL-NEXT: v_mov_b32_e32 v14, s5
+; DAGISEL-NEXT: buffer_store_dword v13, v0, s[0:3], 0 offen offset:96
+; DAGISEL-NEXT: buffer_store_dword v12, v0, s[0:3], 0 offen offset:88
+; DAGISEL-NEXT: buffer_store_dword v11, v0, s[0:3], 0 offen offset:80
+; DAGISEL-NEXT: buffer_store_dword v10, v0, s[0:3], 0 offen offset:72
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:252
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:244
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:236
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:228
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:220
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:212
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:204
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:196
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:188
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:180
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:172
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:164
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:156
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:148
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:140
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:132
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:124
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:116
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:108
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:100
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:92
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:84
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:76
+; DAGISEL-NEXT: s_waitcnt vmcnt(40)
+; DAGISEL-NEXT: buffer_store_dword v26, v0, s[0:3], 0 offen offset:248
+; DAGISEL-NEXT: s_waitcnt vmcnt(40)
+; DAGISEL-NEXT: buffer_store_dword v27, v0, s[0:3], 0 offen offset:240
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:68
+; DAGISEL-NEXT: buffer_store_dword v9, v0, s[0:3], 0 offen offset:64
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:60
+; DAGISEL-NEXT: buffer_store_dword v8, v0, s[0:3], 0 offen offset:56
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:52
+; DAGISEL-NEXT: buffer_store_dword v7, v0, s[0:3], 0 offen offset:48
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:44
+; DAGISEL-NEXT: buffer_store_dword v6, v0, s[0:3], 0 offen offset:40
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:36
+; DAGISEL-NEXT: buffer_store_dword v5, v0, s[0:3], 0 offen offset:32
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:28
+; DAGISEL-NEXT: buffer_store_dword v4, v0, s[0:3], 0 offen offset:24
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:20
+; DAGISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:16
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:12
+; DAGISEL-NEXT: buffer_store_dword v2, v0, s[0:3], 0 offen offset:8
+; DAGISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:4
+; DAGISEL-NEXT: buffer_store_dword v1, v0, s[0:3], 0 offen
+; DAGISEL-NEXT: s_waitcnt vmcnt(0)
+; DAGISEL-NEXT: s_setpc_b64 s[30:31]
+;
+; GISEL-LABEL: local_to_flat_vector_split:
+; GISEL: ; %bb.0:
+; GISEL-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GISEL-NEXT: buffer_store_dword v1, v0, s[0:3], 0 offen
+; GISEL-NEXT: buffer_store_dword v2, v0, s[0:3], 0 offen offset:8
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:16
+; GISEL-NEXT: buffer_store_dword v4, v0, s[0:3], 0 offen offset:24
+; GISEL-NEXT: buffer_load_dword v1, off, s[0:3], s32
+; GISEL-NEXT: s_mov_b64 s[4:5], src_shared_base
+; GISEL-NEXT: buffer_load_dword v2, off, s[0:3], s32 offset:4
+; GISEL-NEXT: v_mov_b32_e32 v3, s5
+; GISEL-NEXT: buffer_store_dword v5, v0, s[0:3], 0 offen offset:32
+; GISEL-NEXT: buffer_store_dword v6, v0, s[0:3], 0 offen offset:40
+; GISEL-NEXT: buffer_store_dword v7, v0, s[0:3], 0 offen offset:48
+; GISEL-NEXT: buffer_store_dword v8, v0, s[0:3], 0 offen offset:56
+; GISEL-NEXT: buffer_store_dword v9, v0, s[0:3], 0 offen offset:64
+; GISEL-NEXT: buffer_store_dword v10, v0, s[0:3], 0 offen offset:72
+; GISEL-NEXT: buffer_store_dword v11, v0, s[0:3], 0 offen offset:80
+; GISEL-NEXT: buffer_store_dword v12, v0, s[0:3], 0 offen offset:88
+; GISEL-NEXT: buffer_store_dword v13, v0, s[0:3], 0 offen offset:96
+; GISEL-NEXT: buffer_store_dword v14, v0, s[0:3], 0 offen offset:104
+; GISEL-NEXT: buffer_store_dword v15, v0, s[0:3], 0 offen offset:112
+; GISEL-NEXT: buffer_store_dword v16, v0, s[0:3], 0 offen offset:120
+; GISEL-NEXT: buffer_store_dword v17, v0, s[0:3], 0 offen offset:128
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:4
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:12
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:20
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:28
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:36
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:44
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:52
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:60
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:68
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:76
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:84
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:92
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:100
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:108
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:116
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:124
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:132
+; GISEL-NEXT: buffer_store_dword v18, v0, s[0:3], 0 offen offset:136
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:140
+; GISEL-NEXT: buffer_store_dword v19, v0, s[0:3], 0 offen offset:144
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:148
+; GISEL-NEXT: buffer_store_dword v20, v0, s[0:3], 0 offen offset:152
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:156
+; GISEL-NEXT: buffer_store_dword v21, v0, s[0:3], 0 offen offset:160
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:164
+; GISEL-NEXT: buffer_store_dword v22, v0, s[0:3], 0 offen offset:168
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:172
+; GISEL-NEXT: buffer_store_dword v23, v0, s[0:3], 0 offen offset:176
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:180
+; GISEL-NEXT: buffer_store_dword v24, v0, s[0:3], 0 offen offset:184
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:188
+; GISEL-NEXT: buffer_store_dword v25, v0, s[0:3], 0 offen offset:192
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:196
+; GISEL-NEXT: buffer_store_dword v26, v0, s[0:3], 0 offen offset:200
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:204
+; GISEL-NEXT: buffer_store_dword v27, v0, s[0:3], 0 offen offset:208
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:212
+; GISEL-NEXT: buffer_store_dword v28, v0, s[0:3], 0 offen offset:216
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:220
+; GISEL-NEXT: buffer_store_dword v29, v0, s[0:3], 0 offen offset:224
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:228
+; GISEL-NEXT: buffer_store_dword v30, v0, s[0:3], 0 offen offset:232
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:236
+; GISEL-NEXT: s_waitcnt vmcnt(57)
+; GISEL-NEXT: buffer_store_dword v1, v0, s[0:3], 0 offen offset:240
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:244
+; GISEL-NEXT: s_waitcnt vmcnt(58)
+; GISEL-NEXT: buffer_store_dword v2, v0, s[0:3], 0 offen offset:248
+; GISEL-NEXT: buffer_store_dword v3, v0, s[0:3], 0 offen offset:252
+; GISEL-NEXT: s_waitcnt vmcnt(0)
+; GISEL-NEXT: s_setpc_b64 s[30:31]
+ %1 = addrspacecast nonnull <32 x ptr addrspace(3)> %ptr to <32 x ptr>
+ ret <32 x ptr> %1
+}
+
+; Two nonnull casts of the same flat source to
diff erent destination address
+; spaces must not be CSEd together despite sharing an operand and the flag.
+define void @nonnull_casts_
diff erent_dest(i64 %i) {
+; CHECK-LABEL: nonnull_casts_
diff erent_dest:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: v_mov_b32_e32 v1, 7
+; CHECK-NEXT: ds_write_b32 v0, v1
+; CHECK-NEXT: v_mov_b32_e32 v1, 8
+; CHECK-NEXT: buffer_store_dword v1, v0, s[0:3], 0 offen
+; CHECK-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ %flat = inttoptr i64 %i to ptr
+ %local = addrspacecast nonnull ptr %flat to ptr addrspace(3)
+ %priv = addrspacecast nonnull ptr %flat to ptr addrspace(5)
+ store volatile i32 7, ptr addrspace(3) %local, align 4
+ store volatile i32 8, ptr addrspace(5) %priv, align 4
+ ret void
+}
+
+; The inverted case: nonnull casts to flat from two
diff erent source address
+; spaces. Each source has its own null value, so the casts are distinct.
+define void @nonnull_casts_
diff erent_src(i32 %i) {
+; DAGISEL-LABEL: nonnull_casts_
diff erent_src:
+; DAGISEL: ; %bb.0:
+; DAGISEL-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; DAGISEL-NEXT: s_mov_b64 s[4:5], src_shared_base
+; DAGISEL-NEXT: s_mov_b64 s[6:7], src_private_base
+; DAGISEL-NEXT: v_mov_b32_e32 v1, s5
+; DAGISEL-NEXT: v_mov_b32_e32 v4, 7
+; DAGISEL-NEXT: v_mov_b32_e32 v2, v0
+; DAGISEL-NEXT: v_mov_b32_e32 v3, s7
+; DAGISEL-NEXT: flat_store_dword v[0:1], v4
+; DAGISEL-NEXT: s_waitcnt vmcnt(0)
+; DAGISEL-NEXT: v_mov_b32_e32 v0, 8
+; DAGISEL-NEXT: flat_store_dword v[2:3], v0
+; DAGISEL-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; DAGISEL-NEXT: s_setpc_b64 s[30:31]
+;
+; GISEL-LABEL: nonnull_casts_
diff erent_src:
+; GISEL: ; %bb.0:
+; GISEL-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GISEL-NEXT: s_mov_b64 s[4:5], src_shared_base
+; GISEL-NEXT: s_mov_b64 s[6:7], src_private_base
+; GISEL-NEXT: v_mov_b32_e32 v1, s5
+; GISEL-NEXT: v_mov_b32_e32 v4, 7
+; GISEL-NEXT: v_mov_b32_e32 v3, s7
+; GISEL-NEXT: v_mov_b32_e32 v2, v0
+; GISEL-NEXT: flat_store_dword v[0:1], v4
+; GISEL-NEXT: s_waitcnt vmcnt(0)
+; GISEL-NEXT: v_mov_b32_e32 v0, 8
+; GISEL-NEXT: flat_store_dword v[2:3], v0
+; GISEL-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GISEL-NEXT: s_setpc_b64 s[30:31]
+ %local = inttoptr i32 %i to ptr addrspace(3)
+ %priv = inttoptr i32 %i to ptr addrspace(5)
+ %flat.local = addrspacecast nonnull ptr addrspace(3) %local to ptr
+ %flat.priv = addrspacecast nonnull ptr addrspace(5) %priv to ptr
+ store volatile i32 7, ptr %flat.local, align 4
+ store volatile i32 8, ptr %flat.priv, align 4
+ ret void
+}
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/addrspacecast-nonnull.mir b/llvm/test/CodeGen/MIR/AMDGPU/addrspacecast-nonnull.mir
new file mode 100644
index 0000000000000..d30f7f44cf937
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/addrspacecast-nonnull.mir
@@ -0,0 +1,23 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgpu7.00-amd-amdhsa -run-pass=none -o - %s | FileCheck %s
+
+# Check that the nonnull MIFlag on G_ADDRSPACE_CAST round-trips through the MIR
+# printer and parser.
+
+---
+name: nonnull_addrspacecast
+body: |
+ bb.0:
+ liveins: $vgpr0
+ ; CHECK-LABEL: name: nonnull_addrspacecast
+ ; CHECK: liveins: $vgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
+ ; CHECK-NEXT: [[INTTOPTR:%[0-9]+]]:_(p3) = G_INTTOPTR [[COPY]](s32)
+ ; CHECK-NEXT: [[ADDRSPACE_CAST:%[0-9]+]]:_(p0) = nonnull G_ADDRSPACE_CAST [[INTTOPTR]](p3)
+ ; CHECK-NEXT: $vgpr0_vgpr1 = COPY [[ADDRSPACE_CAST]](p0)
+ %0:_(s32) = COPY $vgpr0
+ %1:_(p3) = G_INTTOPTR %0
+ %2:_(p0) = nonnull G_ADDRSPACE_CAST %1
+ $vgpr0_vgpr1 = COPY %2
+...
diff --git a/llvm/utils/UpdateTestChecks/mir.py b/llvm/utils/UpdateTestChecks/mir.py
index e5f381edcb343..ff143177e65d9 100644
--- a/llvm/utils/UpdateTestChecks/mir.py
+++ b/llvm/utils/UpdateTestChecks/mir.py
@@ -21,7 +21,8 @@
MI_FLAGS_STR = (
r"(frame-setup |frame-destroy |nnan |ninf |nsz |arcp |contract |afn "
r"|reassoc |nuw |nsw |exact |nofpexcept |nomerge |unpredictable "
- r"|noconvergent |nneg |disjoint |nusw |samesign |inbounds |lr-split )*"
+ r"|noconvergent |nneg |disjoint |nusw |samesign |inbounds |lr-split "
+ r"|nonnull )*"
)
VREG_DEF_FLAGS_STR = r"(?:dead |undef )*"
More information about the llvm-commits
mailing list