[llvm] [IR] Allow vector cmpxchg (PR #209386)
Yonah Goldberg via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 14 10:50:27 PDT 2026
https://github.com/YonahGoldberg updated https://github.com/llvm/llvm-project/pull/209386
>From afed1dcdfff8c04e85a7edca796d9ea44202332a Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 10 Jul 2026 01:16:15 +0000
Subject: [PATCH 1/4] Allow cmpxchg with non-integer operands
---
llvm/docs/LangRef.md | 5 +-
llvm/lib/AsmParser/LLParser.cpp | 8 +++
llvm/lib/CodeGen/AtomicExpandPass.cpp | 22 ++++----
llvm/lib/IR/Verifier.cpp | 8 ++-
llvm/test/Assembler/atomic.ll | 16 ++++++
.../Assembler/invalid-cmpxchg-scalable.ll | 25 +++++++++
llvm/test/Bitcode/compatibility.ll | 2 +
.../X86/expand-atomic-cmpxchg-non-integer.ll | 56 +++++++++++++++++++
llvm/unittests/IR/VerifierTest.cpp | 27 +++++++++
9 files changed, 154 insertions(+), 15 deletions(-)
create mode 100644 llvm/test/Assembler/invalid-cmpxchg-scalable.ll
create mode 100644 llvm/test/Transforms/AtomicExpand/X86/expand-atomic-cmpxchg-non-integer.ll
diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index aff4297492445..93256d6bcf55a 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -11997,8 +11997,9 @@ equal, it tries to store a new value into the memory.
There are three arguments to the '`cmpxchg`' instruction: an address
to operate on, a value to compare to the value currently be at that
address, and a new value to place at that address if the compared values
-are equal. The type of `<cmp>` must be an integer or pointer type whose
-bit width is a power of two greater than or equal to eight.
+are equal. The type of `<cmp>` must be an integer type, floating-point type,
+pointer type, or fixed vector of one of these types, whose bit width is a power
+of two greater than or equal to eight.
`<cmp>` and `<new>` must
have the same type, and the type of `<pointer>` must be a pointer to
that type. If the `cmpxchg` is marked as `volatile`, then the
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 38d10587b104e..2c95dee7a0a52 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -9099,6 +9099,14 @@ int LLParser::parseCmpXchg(Instruction *&Inst, PerFunctionState &PFS) {
return error(NewLoc, "compare value and new value type do not match");
if (!New->getType()->isFirstClassType())
return error(NewLoc, "cmpxchg operand must be a first class value");
+ if (Cmp->getType()->isScalableTy())
+ return error(CmpLoc, "cmpxchg operand may not be scalable");
+ if (!Cmp->getType()->isIntOrIntVectorTy() &&
+ !Cmp->getType()->isFPOrFPVectorTy() &&
+ !Cmp->getType()->isPtrOrPtrVectorTy())
+ return error(CmpLoc,
+ "cmpxchg operand must be an integer, floating point, "
+ "pointer, or fixed vector of one of these types");
const Align DefaultAlignment(
PFS.getFunction().getDataLayout().getTypeStoreSize(
diff --git a/llvm/lib/CodeGen/AtomicExpandPass.cpp b/llvm/lib/CodeGen/AtomicExpandPass.cpp
index 6985a7a48147c..5a3d45c62d324 100644
--- a/llvm/lib/CodeGen/AtomicExpandPass.cpp
+++ b/llvm/lib/CodeGen/AtomicExpandPass.cpp
@@ -415,10 +415,8 @@ bool AtomicExpandImpl::processAtomicInstr(Instruction *I) {
return true;
}
- // TODO: when we're ready to make the change at the IR level, we can
- // extend convertCmpXchgToInteger for floating point too.
bool MadeChange = false;
- if (CASI->getCompareOperand()->getType()->isPointerTy()) {
+ if (!CASI->getCompareOperand()->getType()->isIntegerTy()) {
// TODO: add a TLI hook to control this so that each target can
// convert to lowering the original type one at a time.
CASI = convertCmpXchgToIntegerType(CASI);
@@ -1421,11 +1419,10 @@ Value *AtomicExpandImpl::insertRMWLLSCLoop(
return Loaded;
}
-/// Convert an atomic cmpxchg of a non-integral type to an integer cmpxchg of
-/// the equivalent bitwidth. We used to not support pointer cmpxchg in the
-/// IR. As a migration step, we convert back to what use to be the standard
-/// way to represent a pointer cmpxchg so that we can update backends one by
-/// one.
+/// Convert an atomic cmpxchg of a non-integer type to an integer cmpxchg of
+/// the equivalent bitwidth. We used to not support pointer, floating-point, or
+/// vector cmpxchg in the IR. As a migration step, convert back to what used to
+/// be the standard representation so that we can update backends one by one.
AtomicCmpXchgInst *
AtomicExpandImpl::convertCmpXchgToIntegerType(AtomicCmpXchgInst *CI) {
auto *M = CI->getModule();
@@ -1436,8 +1433,10 @@ AtomicExpandImpl::convertCmpXchgToIntegerType(AtomicCmpXchgInst *CI) {
Value *Addr = CI->getPointerOperand();
- Value *NewCmp = Builder.CreatePtrToInt(CI->getCompareOperand(), NewTy);
- Value *NewNewVal = Builder.CreatePtrToInt(CI->getNewValOperand(), NewTy);
+ Value *NewCmp =
+ Builder.CreateBitPreservingCastChain(*DL, CI->getCompareOperand(), NewTy);
+ Value *NewNewVal =
+ Builder.CreateBitPreservingCastChain(*DL, CI->getNewValOperand(), NewTy);
auto *NewCI = Builder.CreateAtomicCmpXchg(
Addr, NewCmp, NewNewVal, CI->getAlign(), CI->getSuccessOrdering(),
@@ -1449,7 +1448,8 @@ AtomicExpandImpl::convertCmpXchgToIntegerType(AtomicCmpXchgInst *CI) {
Value *OldVal = Builder.CreateExtractValue(NewCI, 0);
Value *Succ = Builder.CreateExtractValue(NewCI, 1);
- OldVal = Builder.CreateIntToPtr(OldVal, CI->getCompareOperand()->getType());
+ OldVal = Builder.CreateBitPreservingCastChain(
+ *DL, OldVal, CI->getCompareOperand()->getType());
Value *Res = PoisonValue::get(CI->getType());
Res = Builder.CreateInsertValue(Res, OldVal, 0);
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 0744a91710b2e..f5c257b4577a4 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -4650,8 +4650,12 @@ void Verifier::visitAllocaInst(AllocaInst &AI) {
void Verifier::visitAtomicCmpXchgInst(AtomicCmpXchgInst &CXI) {
Type *ElTy = CXI.getOperand(1)->getType();
- Check(ElTy->isIntOrPtrTy(),
- "cmpxchg operand must have integer or pointer type", ElTy, &CXI);
+ Check((ElTy->isIntOrIntVectorTy() || ElTy->isFPOrFPVectorTy() ||
+ ElTy->isPtrOrPtrVectorTy()) &&
+ !isa<ScalableVectorType>(ElTy),
+ "cmpxchg operand must have integer, floating point, pointer, or fixed "
+ "vector of one of these types",
+ ElTy, &CXI);
checkAtomicMemAccessSize(ElTy, &CXI);
visitInstruction(CXI);
}
diff --git a/llvm/test/Assembler/atomic.ll b/llvm/test/Assembler/atomic.ll
index 609cd33f61b88..981ca280738ef 100644
--- a/llvm/test/Assembler/atomic.ll
+++ b/llvm/test/Assembler/atomic.ll
@@ -80,6 +80,22 @@ define void @f(ptr %x) {
ret void
}
+define void @cmpxchg_non_integer(ptr %x, float %fcmp, float %fnew, <2 x i16> %icmp, <2 x i16> %inew, <2 x half> %vfcmp, <2 x half> %vfnew, <2 x ptr> %pcmp, <2 x ptr> %pnew) {
+ ; CHECK: %atomic.cmpxchg.fp = cmpxchg ptr %x, float %fcmp, float %fnew seq_cst monotonic
+ %atomic.cmpxchg.fp = cmpxchg ptr %x, float %fcmp, float %fnew seq_cst monotonic
+
+ ; CHECK: %atomic.cmpxchg.int.vector = cmpxchg ptr %x, <2 x i16> %icmp, <2 x i16> %inew seq_cst monotonic
+ %atomic.cmpxchg.int.vector = cmpxchg ptr %x, <2 x i16> %icmp, <2 x i16> %inew seq_cst monotonic
+
+ ; CHECK: %atomic.cmpxchg.fp.vector = cmpxchg ptr %x, <2 x half> %vfcmp, <2 x half> %vfnew seq_cst monotonic
+ %atomic.cmpxchg.fp.vector = cmpxchg ptr %x, <2 x half> %vfcmp, <2 x half> %vfnew seq_cst monotonic
+
+ ; CHECK: %atomic.cmpxchg.ptr.vector = cmpxchg ptr %x, <2 x ptr> %pcmp, <2 x ptr> %pnew seq_cst monotonic
+ %atomic.cmpxchg.ptr.vector = cmpxchg ptr %x, <2 x ptr> %pcmp, <2 x ptr> %pnew seq_cst monotonic
+
+ ret void
+}
+
define void @fp_atomics(ptr %x) {
; CHECK: atomicrmw fadd ptr %x, float 1.000000e+00 seq_cst
atomicrmw fadd ptr %x, float 1.0 seq_cst
diff --git a/llvm/test/Assembler/invalid-cmpxchg-scalable.ll b/llvm/test/Assembler/invalid-cmpxchg-scalable.ll
new file mode 100644
index 0000000000000..1d4f135866174
--- /dev/null
+++ b/llvm/test/Assembler/invalid-cmpxchg-scalable.ll
@@ -0,0 +1,25 @@
+; RUN: split-file %s %t --leading-lines
+; RUN: not llvm-as < %t/scalable_int_vector_cmpxchg.ll 2>&1 | FileCheck -check-prefix=ERR0 %s
+; RUN: not llvm-as < %t/scalable_fp_vector_cmpxchg.ll 2>&1 | FileCheck -check-prefix=ERR1 %s
+; RUN: not llvm-as < %t/scalable_ptr_vector_cmpxchg.ll 2>&1 | FileCheck -check-prefix=ERR2 %s
+
+;--- scalable_int_vector_cmpxchg.ll
+define void @scalable_int_vector_cmpxchg(ptr %p, <vscale x 2 x i16> %cmp, <vscale x 2 x i16> %new) {
+; ERR0: error: cmpxchg operand may not be scalable
+ %val_success = cmpxchg ptr %p, <vscale x 2 x i16> %cmp, <vscale x 2 x i16> %new seq_cst monotonic
+ ret void
+}
+
+;--- scalable_fp_vector_cmpxchg.ll
+define void @scalable_fp_vector_cmpxchg(ptr %p, <vscale x 2 x half> %cmp, <vscale x 2 x half> %new) {
+; ERR1: error: cmpxchg operand may not be scalable
+ %val_success = cmpxchg ptr %p, <vscale x 2 x half> %cmp, <vscale x 2 x half> %new seq_cst monotonic
+ ret void
+}
+
+;--- scalable_ptr_vector_cmpxchg.ll
+define void @scalable_ptr_vector_cmpxchg(ptr %p, <vscale x 2 x ptr> %cmp, <vscale x 2 x ptr> %new) {
+; ERR2: error: cmpxchg operand may not be scalable
+ %val_success = cmpxchg ptr %p, <vscale x 2 x ptr> %cmp, <vscale x 2 x ptr> %new seq_cst monotonic
+ ret void
+}
diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll
index 0ac6da0c9ed29..ebbe405e44a21 100644
--- a/llvm/test/Bitcode/compatibility.ll
+++ b/llvm/test/Bitcode/compatibility.ll
@@ -828,6 +828,8 @@ define void @atomics(ptr %word) {
;; Atomic Compare And Exchange w/o alignment
%cmpxchg_no_align.0 = cmpxchg ptr %word, i32 0, i32 4 monotonic monotonic
; CHECK: %cmpxchg_no_align.0 = cmpxchg ptr %word, i32 0, i32 4 monotonic monotonic
+ %cmpxchg_no_align.vector = cmpxchg ptr %word, <2 x i16> <i16 0, i16 1>, <2 x i16> <i16 4, i16 5> monotonic monotonic
+ ; CHECK: %cmpxchg_no_align.vector = cmpxchg ptr %word, <2 x i16> <i16 0, i16 1>, <2 x i16> <i16 4, i16 5> monotonic monotonic
%cmpxchg_no_align.1 = cmpxchg ptr %word, i32 0, i32 5 acq_rel monotonic
; CHECK: %cmpxchg_no_align.1 = cmpxchg ptr %word, i32 0, i32 5 acq_rel monotonic
%cmpxchg_no_align.2 = cmpxchg ptr %word, i32 0, i32 6 acquire monotonic
diff --git a/llvm/test/Transforms/AtomicExpand/X86/expand-atomic-cmpxchg-non-integer.ll b/llvm/test/Transforms/AtomicExpand/X86/expand-atomic-cmpxchg-non-integer.ll
new file mode 100644
index 0000000000000..f7f92da930440
--- /dev/null
+++ b/llvm/test/Transforms/AtomicExpand/X86/expand-atomic-cmpxchg-non-integer.ll
@@ -0,0 +1,56 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -mtriple=x86_64-linux-gnu -passes='require<libcall-lowering-info>,atomic-expand' %s | FileCheck %s
+
+define { float, i1 } @cmpxchg_float(ptr %ptr, float %cmp, float %new) {
+; CHECK-LABEL: @cmpxchg_float(
+; CHECK-SAME: ptr [[PTR:%.*]], float [[CMP:%.*]], float [[NEW:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = bitcast float [[CMP]] to i32
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast float [[NEW]] to i32
+; CHECK-NEXT: [[TMP3:%.*]] = cmpxchg ptr [[PTR]], i32 [[TMP1]], i32 [[TMP2]] seq_cst monotonic, align 4
+; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0
+; CHECK-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1
+; CHECK-NEXT: [[TMP6:%.*]] = bitcast i32 [[TMP4]] to float
+; CHECK-NEXT: [[TMP7:%.*]] = insertvalue { float, i1 } poison, float [[TMP6]], 0
+; CHECK-NEXT: [[TMP8:%.*]] = insertvalue { float, i1 } [[TMP7]], i1 [[TMP5]], 1
+; CHECK-NEXT: ret { float, i1 } [[TMP8]]
+;
+ %result = cmpxchg ptr %ptr, float %cmp, float %new seq_cst monotonic
+ ret { float, i1 } %result
+}
+
+define { <2 x i16>, i1 } @cmpxchg_v2i16(ptr %ptr, <2 x i16> %cmp, <2 x i16> %new) {
+; CHECK-LABEL: @cmpxchg_v2i16(
+; CHECK-SAME: ptr [[PTR:%.*]], <2 x i16> [[CMP:%.*]], <2 x i16> [[NEW:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i16> [[CMP]] to i32
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i16> [[NEW]] to i32
+; CHECK-NEXT: [[TMP3:%.*]] = cmpxchg ptr [[PTR]], i32 [[TMP1]], i32 [[TMP2]] seq_cst monotonic, align 4
+; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0
+; CHECK-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1
+; CHECK-NEXT: [[TMP6:%.*]] = bitcast i32 [[TMP4]] to <2 x i16>
+; CHECK-NEXT: [[TMP7:%.*]] = insertvalue { <2 x i16>, i1 } poison, <2 x i16> [[TMP6]], 0
+; CHECK-NEXT: [[TMP8:%.*]] = insertvalue { <2 x i16>, i1 } [[TMP7]], i1 [[TMP5]], 1
+; CHECK-NEXT: ret { <2 x i16>, i1 } [[TMP8]]
+;
+ %result = cmpxchg ptr %ptr, <2 x i16> %cmp, <2 x i16> %new seq_cst monotonic
+ ret { <2 x i16>, i1 } %result
+}
+
+define { <1 x ptr>, i1 } @cmpxchg_v1ptr(ptr %ptr, <1 x ptr> %cmp, <1 x ptr> %new) {
+; CHECK-LABEL: @cmpxchg_v1ptr(
+; CHECK-SAME: ptr [[PTR:%.*]], <1 x ptr> [[CMP:%.*]], <1 x ptr> [[NEW:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint <1 x ptr> [[CMP]] to <1 x i64>
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast <1 x i64> [[TMP1]] to i64
+; CHECK-NEXT: [[TMP3:%.*]] = ptrtoint <1 x ptr> [[NEW]] to <1 x i64>
+; CHECK-NEXT: [[TMP4:%.*]] = bitcast <1 x i64> [[TMP3]] to i64
+; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg ptr [[PTR]], i64 [[TMP2]], i64 [[TMP4]] seq_cst monotonic, align 8
+; CHECK-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0
+; CHECK-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1
+; CHECK-NEXT: [[TMP8:%.*]] = bitcast i64 [[TMP6]] to <1 x i64>
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr <1 x i64> [[TMP8]] to <1 x ptr>
+; CHECK-NEXT: [[TMP10:%.*]] = insertvalue { <1 x ptr>, i1 } poison, <1 x ptr> [[TMP9]], 0
+; CHECK-NEXT: [[TMP11:%.*]] = insertvalue { <1 x ptr>, i1 } [[TMP10]], i1 [[TMP7]], 1
+; CHECK-NEXT: ret { <1 x ptr>, i1 } [[TMP11]]
+;
+ %result = cmpxchg ptr %ptr, <1 x ptr> %cmp, <1 x ptr> %new seq_cst monotonic
+ ret { <1 x ptr>, i1 } %result
+}
diff --git a/llvm/unittests/IR/VerifierTest.cpp b/llvm/unittests/IR/VerifierTest.cpp
index d680dd250d66e..d40eea6bcbf95 100644
--- a/llvm/unittests/IR/VerifierTest.cpp
+++ b/llvm/unittests/IR/VerifierTest.cpp
@@ -532,6 +532,33 @@ TEST(VerifierTest, AtomicRMWIntVector) {
<< Error;
}
+TEST(VerifierTest, AtomicCmpXchgVector) {
+ LLVMContext C;
+ Module M("M", C);
+ FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false);
+ Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);
+ BasicBlock *Entry = BasicBlock::Create(C, "entry", F);
+ Value *Ptr = PoisonValue::get(PointerType::get(C, 0));
+
+ Type *IntTy = Type::getInt16Ty(C);
+ Constant *CI = ConstantInt::get(IntTy, 0);
+
+ // Invalid scalable type : cmpxchg (<vscale x 2 x i16>)
+ Constant *CV = ConstantVector::getSplat(ElementCount::getScalable(2), CI);
+ new AtomicCmpXchgInst(Ptr, CV, CV, Align(8),
+ AtomicOrdering::SequentiallyConsistent,
+ AtomicOrdering::Monotonic, SyncScope::System, Entry);
+ ReturnInst::Create(C, Entry);
+
+ std::string Error;
+ raw_string_ostream ErrorOS(Error);
+ EXPECT_TRUE(verifyFunction(*F, &ErrorOS));
+ EXPECT_TRUE(StringRef(Error).starts_with(
+ "cmpxchg operand must have integer, floating point, pointer, or fixed "
+ "vector of one of these types"))
+ << Error;
+}
+
TEST(VerifierTest, GetElementPtrInst) {
LLVMContext C;
Module M("M", C);
>From 4bb07d5c69636ad2b99a24d4a403395f34772af6 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 14 Jul 2026 07:16:37 +0000
Subject: [PATCH 2/4] cleanup
---
llvm/docs/LangRef.md | 2 +-
llvm/lib/AsmParser/LLParser.cpp | 4 ++--
llvm/lib/CodeGen/AtomicExpandPass.cpp | 2 +-
llvm/lib/IR/Verifier.cpp | 4 ++--
llvm/test/Assembler/invalid-cmpxchg-scalable.ll | 12 ++++++------
5 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 93256d6bcf55a..2cd6008236bff 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -11998,7 +11998,7 @@ There are three arguments to the '`cmpxchg`' instruction: an address
to operate on, a value to compare to the value currently be at that
address, and a new value to place at that address if the compared values
are equal. The type of `<cmp>` must be an integer type, floating-point type,
-pointer type, or fixed vector of one of these types, whose bit width is a power
+pointer type, or fixed vector of any of these types, whose bit width is a power
of two greater than or equal to eight.
`<cmp>` and `<new>` must
have the same type, and the type of `<pointer>` must be a pointer to
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 2c95dee7a0a52..cec42241887ba 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -9105,8 +9105,8 @@ int LLParser::parseCmpXchg(Instruction *&Inst, PerFunctionState &PFS) {
!Cmp->getType()->isFPOrFPVectorTy() &&
!Cmp->getType()->isPtrOrPtrVectorTy())
return error(CmpLoc,
- "cmpxchg operand must be an integer, floating point, "
- "pointer, or fixed vector of one of these types");
+ "cmpxchg operand must be an integer type, floating-point type,"
+ "pointer type, or fixed vector of any of these types");
const Align DefaultAlignment(
PFS.getFunction().getDataLayout().getTypeStoreSize(
diff --git a/llvm/lib/CodeGen/AtomicExpandPass.cpp b/llvm/lib/CodeGen/AtomicExpandPass.cpp
index 5a3d45c62d324..9701f7e239321 100644
--- a/llvm/lib/CodeGen/AtomicExpandPass.cpp
+++ b/llvm/lib/CodeGen/AtomicExpandPass.cpp
@@ -1420,7 +1420,7 @@ Value *AtomicExpandImpl::insertRMWLLSCLoop(
}
/// Convert an atomic cmpxchg of a non-integer type to an integer cmpxchg of
-/// the equivalent bitwidth. We used to not support pointer, floating-point, or
+/// the equivalent bitwidth. We used to not support pointer, floating-point, and
/// vector cmpxchg in the IR. As a migration step, convert back to what used to
/// be the standard representation so that we can update backends one by one.
AtomicCmpXchgInst *
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index f5c257b4577a4..fd09361b16645 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -4653,8 +4653,8 @@ void Verifier::visitAtomicCmpXchgInst(AtomicCmpXchgInst &CXI) {
Check((ElTy->isIntOrIntVectorTy() || ElTy->isFPOrFPVectorTy() ||
ElTy->isPtrOrPtrVectorTy()) &&
!isa<ScalableVectorType>(ElTy),
- "cmpxchg operand must have integer, floating point, pointer, or fixed "
- "vector of one of these types",
+ "cmpxchg operand must have an integer type, floating-point type,"
+ "pointer type, or a fixed vector of any of these types!",
ElTy, &CXI);
checkAtomicMemAccessSize(ElTy, &CXI);
visitInstruction(CXI);
diff --git a/llvm/test/Assembler/invalid-cmpxchg-scalable.ll b/llvm/test/Assembler/invalid-cmpxchg-scalable.ll
index 1d4f135866174..ffc1405a338da 100644
--- a/llvm/test/Assembler/invalid-cmpxchg-scalable.ll
+++ b/llvm/test/Assembler/invalid-cmpxchg-scalable.ll
@@ -1,25 +1,25 @@
; RUN: split-file %s %t --leading-lines
-; RUN: not llvm-as < %t/scalable_int_vector_cmpxchg.ll 2>&1 | FileCheck -check-prefix=ERR0 %s
-; RUN: not llvm-as < %t/scalable_fp_vector_cmpxchg.ll 2>&1 | FileCheck -check-prefix=ERR1 %s
-; RUN: not llvm-as < %t/scalable_ptr_vector_cmpxchg.ll 2>&1 | FileCheck -check-prefix=ERR2 %s
+; RUN: not llvm-as < %t/scalable_int_vector_cmpxchg.ll 2>&1 | FileCheck %s
+; RUN: not llvm-as < %t/scalable_fp_vector_cmpxchg.ll 2>&1 | FileCheck %s
+; RUN: not llvm-as < %t/scalable_ptr_vector_cmpxchg.ll 2>&1 | FileCheck %s
;--- scalable_int_vector_cmpxchg.ll
define void @scalable_int_vector_cmpxchg(ptr %p, <vscale x 2 x i16> %cmp, <vscale x 2 x i16> %new) {
-; ERR0: error: cmpxchg operand may not be scalable
+; CHECK: error: cmpxchg operand may not be scalable
%val_success = cmpxchg ptr %p, <vscale x 2 x i16> %cmp, <vscale x 2 x i16> %new seq_cst monotonic
ret void
}
;--- scalable_fp_vector_cmpxchg.ll
define void @scalable_fp_vector_cmpxchg(ptr %p, <vscale x 2 x half> %cmp, <vscale x 2 x half> %new) {
-; ERR1: error: cmpxchg operand may not be scalable
+; CHECK: error: cmpxchg operand may not be scalable
%val_success = cmpxchg ptr %p, <vscale x 2 x half> %cmp, <vscale x 2 x half> %new seq_cst monotonic
ret void
}
;--- scalable_ptr_vector_cmpxchg.ll
define void @scalable_ptr_vector_cmpxchg(ptr %p, <vscale x 2 x ptr> %cmp, <vscale x 2 x ptr> %new) {
-; ERR2: error: cmpxchg operand may not be scalable
+; CHECK: error: cmpxchg operand may not be scalable
%val_success = cmpxchg ptr %p, <vscale x 2 x ptr> %cmp, <vscale x 2 x ptr> %new seq_cst monotonic
ret void
}
>From 7f912bdb96cc45c95720be8dfe669afdfe1f2717 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 14 Jul 2026 16:47:02 +0000
Subject: [PATCH 3/4] fix test
---
llvm/test/Assembler/invalid-cmpxchg-scalable.ll | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/test/Assembler/invalid-cmpxchg-scalable.ll b/llvm/test/Assembler/invalid-cmpxchg-scalable.ll
index ffc1405a338da..1d88be0a01cb9 100644
--- a/llvm/test/Assembler/invalid-cmpxchg-scalable.ll
+++ b/llvm/test/Assembler/invalid-cmpxchg-scalable.ll
@@ -1,25 +1,25 @@
; RUN: split-file %s %t --leading-lines
-; RUN: not llvm-as < %t/scalable_int_vector_cmpxchg.ll 2>&1 | FileCheck %s
-; RUN: not llvm-as < %t/scalable_fp_vector_cmpxchg.ll 2>&1 | FileCheck %s
-; RUN: not llvm-as < %t/scalable_ptr_vector_cmpxchg.ll 2>&1 | FileCheck %s
+; RUN: not llvm-as < %t/scalable_int_vector_cmpxchg.ll 2>&1 | FileCheck %s --check-prefix=INT
+; RUN: not llvm-as < %t/scalable_fp_vector_cmpxchg.ll 2>&1 | FileCheck %s --check-prefix=FP
+; RUN: not llvm-as < %t/scalable_ptr_vector_cmpxchg.ll 2>&1 | FileCheck %s --check-prefix=PTR
;--- scalable_int_vector_cmpxchg.ll
define void @scalable_int_vector_cmpxchg(ptr %p, <vscale x 2 x i16> %cmp, <vscale x 2 x i16> %new) {
-; CHECK: error: cmpxchg operand may not be scalable
+; INT: error: cmpxchg operand may not be scalable
%val_success = cmpxchg ptr %p, <vscale x 2 x i16> %cmp, <vscale x 2 x i16> %new seq_cst monotonic
ret void
}
;--- scalable_fp_vector_cmpxchg.ll
define void @scalable_fp_vector_cmpxchg(ptr %p, <vscale x 2 x half> %cmp, <vscale x 2 x half> %new) {
-; CHECK: error: cmpxchg operand may not be scalable
+; FP: error: cmpxchg operand may not be scalable
%val_success = cmpxchg ptr %p, <vscale x 2 x half> %cmp, <vscale x 2 x half> %new seq_cst monotonic
ret void
}
;--- scalable_ptr_vector_cmpxchg.ll
define void @scalable_ptr_vector_cmpxchg(ptr %p, <vscale x 2 x ptr> %cmp, <vscale x 2 x ptr> %new) {
-; CHECK: error: cmpxchg operand may not be scalable
+; PTR: error: cmpxchg operand may not be scalable
%val_success = cmpxchg ptr %p, <vscale x 2 x ptr> %cmp, <vscale x 2 x ptr> %new seq_cst monotonic
ret void
}
>From f2080034449d1611a9595582e05b7a3685a5cacd Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 14 Jul 2026 17:39:41 +0000
Subject: [PATCH 4/4] fix test
---
llvm/unittests/IR/VerifierTest.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/unittests/IR/VerifierTest.cpp b/llvm/unittests/IR/VerifierTest.cpp
index d40eea6bcbf95..08ed87e3a4d64 100644
--- a/llvm/unittests/IR/VerifierTest.cpp
+++ b/llvm/unittests/IR/VerifierTest.cpp
@@ -554,8 +554,8 @@ TEST(VerifierTest, AtomicCmpXchgVector) {
raw_string_ostream ErrorOS(Error);
EXPECT_TRUE(verifyFunction(*F, &ErrorOS));
EXPECT_TRUE(StringRef(Error).starts_with(
- "cmpxchg operand must have integer, floating point, pointer, or fixed "
- "vector of one of these types"))
+ "cmpxchg operand must have an integer type, floating-point type,"
+ "pointer type, or a fixed vector of any of these types!"))
<< Error;
}
More information about the llvm-commits
mailing list