[clang] [z/OS][Clang] Add compare and swap builtin functions (PR #202362)
Maryam Moghadas via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 8 08:11:13 PDT 2026
https://github.com/maryammo updated https://github.com/llvm/llvm-project/pull/202362
>From 3a4525effc98425bfa2aa472237e99fe544a8de9 Mon Sep 17 00:00:00 2001
From: Maryam Moghadas <maryammo at ca.ibm.com>
Date: Fri, 5 Jun 2026 20:18:38 +0000
Subject: [PATCH 1/5] [z/OS][Clang] Add compare and swap builtin functions
---
clang/include/clang/Basic/BuiltinsZOS.td | 27 +++++++
clang/include/clang/Basic/CMakeLists.txt | 4 ++
clang/include/clang/Basic/TargetBuiltins.h | 13 ++--
clang/lib/Basic/Targets/SystemZ.cpp | 22 +++++-
clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp | 71 +++++++++++++++++--
.../test/CodeGen/SystemZ/builtins-zos-cds1.c | 18 +++++
.../test/CodeGen/SystemZ/builtins-zos-cdsg.c | 19 +++++
clang/test/CodeGen/SystemZ/builtins-zos-cs.c | 12 ++++
clang/test/CodeGen/SystemZ/builtins-zos-cs1.c | 12 ++++
clang/test/CodeGen/SystemZ/builtins-zos-csg.c | 17 +++++
10 files changed, 206 insertions(+), 9 deletions(-)
create mode 100644 clang/include/clang/Basic/BuiltinsZOS.td
create mode 100644 clang/test/CodeGen/SystemZ/builtins-zos-cds1.c
create mode 100644 clang/test/CodeGen/SystemZ/builtins-zos-cdsg.c
create mode 100644 clang/test/CodeGen/SystemZ/builtins-zos-cs.c
create mode 100644 clang/test/CodeGen/SystemZ/builtins-zos-cs1.c
create mode 100644 clang/test/CodeGen/SystemZ/builtins-zos-csg.c
diff --git a/clang/include/clang/Basic/BuiltinsZOS.td b/clang/include/clang/Basic/BuiltinsZOS.td
new file mode 100644
index 0000000000000..2089518fd18a8
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsZOS.td
@@ -0,0 +1,27 @@
+//===-- BuiltinsZOS.td - z/OS Builtin function database ---------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the z/OS-specific builtin function database.
+//
+//===----------------------------------------------------------------------===//
+
+include "clang/Basic/BuiltinsBase.td"
+
+class SystemZNoPrefixBuiltin<string prototype> : Builtin {
+ let Spellings = [NAME];
+ let Prototype = prototype;
+}
+
+// compare and swap functions
+let Attributes = [NoThrow] in {
+ def __cs : SystemZNoPrefixBuiltin<"int(unsigned int *, unsigned int *, unsigned int)">;
+ def __cs1 : SystemZNoPrefixBuiltin<"int(void *, void *, void *)">;
+ def __csg : SystemZNoPrefixBuiltin<"int(void *, void *, void *)">;
+ def __cds1 : SystemZNoPrefixBuiltin<"int(void *, void *, void *)">;
+ def __cdsg : SystemZNoPrefixBuiltin<"int(void *, void *, void *)">;
+}
diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt
index d90d326027583..d334c1d41e475 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -146,6 +146,10 @@ clang_tablegen(BuiltinsX86_64.inc -gen-clang-builtins
SOURCE BuiltinsX86_64.td
TARGET ClangBuiltinsX86_64)
+clang_tablegen(BuiltinsZOS.inc -gen-clang-builtins
+ SOURCE BuiltinsZOS.td
+ TARGET ClangBuiltinsZOS)
+
clang_tablegen(BuiltinTemplates.inc -gen-clang-builtin-templates
SOURCE BuiltinTemplates.td
TARGET ClangBuiltinTemplates)
diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h
index 8cf8720f74573..5828aae483026 100644
--- a/clang/include/clang/Basic/TargetBuiltins.h
+++ b/clang/include/clang/Basic/TargetBuiltins.h
@@ -457,13 +457,18 @@ namespace clang {
/// SystemZ builtins
namespace SystemZ {
- enum {
- LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
#define GET_BUILTIN_ENUMERATORS
#include "clang/Basic/BuiltinsSystemZ.inc"
#undef GET_BUILTIN_ENUMERATORS
- LastTSBuiltin
- };
+ FirstZOSBuiltin,
+ LastSystemZBuiltin = FirstZOSBuiltin - 1,
+#define GET_BUILTIN_ENUMERATORS
+#include "clang/Basic/BuiltinsZOS.inc"
+#undef GET_BUILTIN_ENUMERATORS
+ LastTSBuiltin
+ };
}
/// WebAssembly builtins
diff --git a/clang/lib/Basic/Targets/SystemZ.cpp b/clang/lib/Basic/Targets/SystemZ.cpp
index 750629ac94f87..080a961b95d0d 100644
--- a/clang/lib/Basic/Targets/SystemZ.cpp
+++ b/clang/lib/Basic/Targets/SystemZ.cpp
@@ -22,7 +22,9 @@ using namespace clang;
using namespace clang::targets;
static constexpr int NumBuiltins =
- clang::SystemZ::LastTSBuiltin - Builtin::FirstTSBuiltin;
+ clang::SystemZ::LastSystemZBuiltin - Builtin::FirstTSBuiltin + 1;
+static constexpr int NumBuiltinsZOS =
+ clang::SystemZ::LastTSBuiltin - clang::SystemZ::LastSystemZBuiltin - 1;
#define GET_BUILTIN_STR_TABLE
#include "clang/Basic/BuiltinsSystemZ.inc"
@@ -41,6 +43,20 @@ static constexpr Builtin::Info PrefixedBuiltinInfos[] = {
};
static_assert((std::size(BuiltinInfos) + std::size(PrefixedBuiltinInfos)) ==
NumBuiltins);
+namespace clang {
+namespace ZOS {
+#define GET_BUILTIN_STR_TABLE
+#include "clang/Basic/BuiltinsZOS.inc"
+#undef GET_BUILTIN_STR_TABLE
+
+static constexpr Builtin::Info BuiltinInfos[] = {
+#define GET_BUILTIN_INFOS
+#include "clang/Basic/BuiltinsZOS.inc"
+#undef GET_BUILTIN_INFOS
+};
+static_assert((std::size(BuiltinInfos)) == NumBuiltinsZOS);
+} // namespace ZOS
+} // namespace clang
const char *const SystemZTargetInfo::GCCRegNames[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
@@ -216,6 +232,10 @@ void SystemZTargetInfo::getTargetDefines(const LangOptions &Opts,
llvm::SmallVector<Builtin::InfosShard>
SystemZTargetInfo::getTargetBuiltins() const {
+ if (getTriple().isOSzOS())
+ return {{&BuiltinStrings, BuiltinInfos},
+ {&BuiltinStrings, PrefixedBuiltinInfos, "__builtin_s390_"},
+ {&ZOS::BuiltinStrings, ZOS::BuiltinInfos}};
return {{&BuiltinStrings, BuiltinInfos},
{&BuiltinStrings, PrefixedBuiltinInfos, "__builtin_s390_"}};
}
diff --git a/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp b/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
index c33d7581f50b8..1c115baf5cf78 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "CGBuiltin.h"
#include "CodeGenFunction.h"
#include "clang/Basic/TargetBuiltins.h"
#include "llvm/IR/IntrinsicsS390.h"
@@ -36,6 +37,54 @@ static Value *EmitSystemZIntrinsicWithCC(CodeGenFunction &CGF,
return CGF.Builder.CreateExtractValue(Call, 0);
}
+/// For z/OS, the builtin __cs1 has the following signature:
+/// int __cs1(void * Comparand,
+/// void * Destination,
+/// void * Exchange);
+/// Whereas the llvm 'cmpxchg' instruction has the following syntax:
+/// compxchg *Destination, Comparand, Exchange.
+/// So we need to swap Comparand & Destination and dereference Comparand &
+/// Exchange when invoking CreateAtomicCmpXchng. For this reason we can not use
+/// the utility function MakeAtomicCmpXchgValue.
+static Value *EmitAtomicCmpXchgForZOSIntrin(CodeGenFunction &CGF,
+ const CallExpr *E,
+ llvm::Type *IntType, bool HasAddr) {
+
+ CharUnits Alignment =
+ CGF.getContext().toCharUnitsFromBits(IntType->getScalarSizeInBits());
+ llvm::Value *DestinationPtr = CGF.EmitScalarExpr(E->getArg(1));
+ llvm::Value *ComparandPtr = CGF.EmitScalarExpr(E->getArg(0));
+
+ Address DestinationAddr = Address(DestinationPtr, IntType, Alignment);
+ Address ComparandAddr = Address(ComparandPtr, IntType, Alignment);
+
+ llvm::Value *Comparand = CGF.Builder.CreateLoad(ComparandAddr);
+ llvm::Value *Exchange;
+ if (HasAddr) {
+ llvm::Value *ExchangePtr = CGF.EmitScalarExpr(E->getArg(2));
+ Address ExchangeAddr = Address(ExchangePtr, IntType, Alignment);
+ Exchange = CGF.Builder.CreateLoad(ExchangeAddr);
+ } else {
+ Exchange =
+ EmitToInt(CGF, CGF.EmitScalarExpr(E->getArg(2)),
+ E->getArg(2)->getType(), cast<llvm::IntegerType>(IntType));
+ }
+
+ Value *Result = CGF.Builder.CreateAtomicCmpXchg(
+ DestinationAddr, Comparand, Exchange,
+ llvm::AtomicOrdering::SequentiallyConsistent,
+ llvm::AtomicOrdering::SequentiallyConsistent);
+
+ // Store Destination in Comparand.
+ CGF.Builder.CreateStore(CGF.Builder.CreateExtractValue(Result, 0),
+ ComparandAddr);
+
+ // Extract boolean success flag, inverse it and zext it to int.
+ llvm::Value *RetVal =
+ CGF.Builder.CreateNot(CGF.Builder.CreateExtractValue(Result, 1));
+ return CGF.Builder.CreateZExt(RetVal, CGF.ConvertType(E->getType()));
+}
+
Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
switch (BuiltinID) {
@@ -68,11 +117,25 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::s390_ntstg);
return Builder.CreateCall(F, {Data, Address});
}
+ case SystemZ::BI__cs: {
+ return EmitAtomicCmpXchgForZOSIntrin(*this, E, Int32Ty, false);
+ }
+ case SystemZ::BI__cs1: {
+ return EmitAtomicCmpXchgForZOSIntrin(*this, E, Int32Ty, true);
+ }
+ case SystemZ::BI__csg:
+ case SystemZ::BI__cds1: {
+ return EmitAtomicCmpXchgForZOSIntrin(*this, E, Int64Ty, true);
+ }
+ case SystemZ::BI__cdsg: {
+ llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128);
+ return EmitAtomicCmpXchgForZOSIntrin(*this, E, Int128Ty, true);
+ }
- // Vector builtins. Note that most vector builtins are mapped automatically
- // to target-specific LLVM intrinsics. The ones handled specially here can
- // be represented via standard LLVM IR, which is preferable to enable common
- // LLVM optimizations.
+ // Vector builtins. Note that most vector builtins are mapped automatically
+ // to target-specific LLVM intrinsics. The ones handled specially here can
+ // be represented via standard LLVM IR, which is preferable to enable common
+ // LLVM optimizations.
case SystemZ::BI__builtin_s390_vclzb:
case SystemZ::BI__builtin_s390_vclzh:
diff --git a/clang/test/CodeGen/SystemZ/builtins-zos-cds1.c b/clang/test/CodeGen/SystemZ/builtins-zos-cds1.c
new file mode 100644
index 0000000000000..1534ed11ff066
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/builtins-zos-cds1.c
@@ -0,0 +1,18 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -triple s390x-none-zos %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-linux-gnu %s -verify
+
+typedef struct __attribute__((__aligned__(8))) {
+ int a;
+ int b;
+} double_word;
+
+int func(double_word *a, double_word *b, double_word *c) {
+ return __cds1(a, b, c);
+}
+// expected-error at 11 {{call to undeclared function '__cds1'; ISO C99 and later do not support implicit function declarations}}
+
+// CHECK: cmpxchg ptr {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst, align 8
+// CHECK: store i64 {{.*}}, ptr {{.*}}, align 8
+// CHECK: xor i1 {{.*}}, true
+
diff --git a/clang/test/CodeGen/SystemZ/builtins-zos-cdsg.c b/clang/test/CodeGen/SystemZ/builtins-zos-cdsg.c
new file mode 100644
index 0000000000000..9cf0271600af0
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/builtins-zos-cdsg.c
@@ -0,0 +1,19 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -triple s390x-none-zos %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-linux-gnu %s -verify=loz
+
+typedef struct __attribute__((__aligned__(16))) {
+ int a;
+ int b;
+ int c;
+ int d;
+} quadruple_word;
+
+int func(quadruple_word *a, quadruple_word *b, quadruple_word *c) {
+ return __cdsg(a, b, c);
+}
+// loz-error at 13 {{call to undeclared function '__cdsg'; ISO C99 and later do not support implicit function declarations}}
+
+// CHECK: cmpxchg ptr {{.*}}, i128 {{.*}}, i128 {{.*}} seq_cst seq_cst, align 16
+// CHECK: store i128 {{.*}}, ptr {{.*}}, align 16
+// CHECK: xor i1 {{.*}}, true
diff --git a/clang/test/CodeGen/SystemZ/builtins-zos-cs.c b/clang/test/CodeGen/SystemZ/builtins-zos-cs.c
new file mode 100644
index 0000000000000..6877a86dd3c53
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/builtins-zos-cs.c
@@ -0,0 +1,12 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -triple s390x-none-zos %s -emit-llvm -o - | FileCheck -check-prefix=CHECK %s
+// RUN: %clang_cc1 -triple s390x-linux-gnu %s -verify
+
+int func(unsigned int *a, unsigned int *b, unsigned int c) {
+ return __cs(a, b, c);
+}
+// expected-error at 6 {{call to undeclared function '__cs'; ISO C99 and later do not support implicit function declarations}}
+
+// CHECK: cmpxchg ptr {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4
+// CHECK: store i32 {{.*}}, ptr {{.*}}, align 4
+// CHECK: xor i1 {{.*}}, true
diff --git a/clang/test/CodeGen/SystemZ/builtins-zos-cs1.c b/clang/test/CodeGen/SystemZ/builtins-zos-cs1.c
new file mode 100644
index 0000000000000..2f036736d9e22
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/builtins-zos-cs1.c
@@ -0,0 +1,12 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -triple s390x-none-zos %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-linux-gnu %s -verify
+
+int func(int *a, int *b, int *c) {
+ return __cs1(a, b, c);
+}
+// expected-error at 6 {{call to undeclared function '__cs1'; ISO C99 and later do not support implicit function declarations}}
+
+// CHECK: cmpxchg ptr {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4
+// CHECK: store i32 {{.*}}, ptr {{.*}}, align 4
+// CHECK: xor i1 {{.*}}, true
diff --git a/clang/test/CodeGen/SystemZ/builtins-zos-csg.c b/clang/test/CodeGen/SystemZ/builtins-zos-csg.c
new file mode 100644
index 0000000000000..eb2add0b56d62
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/builtins-zos-csg.c
@@ -0,0 +1,17 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -triple s390x-none-zos %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-linux-gnu %s -verify=loz
+
+typedef struct __attribute__((__aligned__(8))) {
+ int a;
+ int b;
+} double_word;
+
+int func(double_word *a, double_word *b, double_word *c) {
+ return __csg(a, b, c);
+}
+// loz-error at 11 {{call to undeclared function '__csg'; ISO C99 and later do not support implicit function declarations}}
+
+// CHECK: cmpxchg ptr {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst, align 8
+// CHECK: store i64 {{.*}}, ptr {{.*}}, align 8
+// CHECK: xor i1 {{.*}}, true
>From 1bce1cbaa8efc6d1fe91e331b6d7d031a37ed3e5 Mon Sep 17 00:00:00 2001
From: Maryam Moghadas <maryammo at ca.ibm.com>
Date: Wed, 10 Jun 2026 16:10:06 +0000
Subject: [PATCH 2/5] Document z/OS CS builtins
---
clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp b/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
index 1c115baf5cf78..cfb75e1e0e568 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
@@ -132,10 +132,10 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
return EmitAtomicCmpXchgForZOSIntrin(*this, E, Int128Ty, true);
}
- // Vector builtins. Note that most vector builtins are mapped automatically
- // to target-specific LLVM intrinsics. The ones handled specially here can
- // be represented via standard LLVM IR, which is preferable to enable common
- // LLVM optimizations.
+ // Vector builtins. Note that most vector builtins are mapped automatically
+ // to target-specific LLVM intrinsics. The ones handled specially here can
+ // be represented via standard LLVM IR, which is preferable to enable common
+ // LLVM optimizations.
case SystemZ::BI__builtin_s390_vclzb:
case SystemZ::BI__builtin_s390_vclzh:
>From 17dcd4462d800ae453083b8fd4e3bb5bf1ae8317 Mon Sep 17 00:00:00 2001
From: Maryam Moghadas <maryammo at ca.ibm.com>
Date: Wed, 10 Jun 2026 19:57:14 +0000
Subject: [PATCH 3/5] Document __cs vs __cs1 difference and apply clang-format
---
clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp b/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
index cfb75e1e0e568..1c115baf5cf78 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
@@ -132,10 +132,10 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
return EmitAtomicCmpXchgForZOSIntrin(*this, E, Int128Ty, true);
}
- // Vector builtins. Note that most vector builtins are mapped automatically
- // to target-specific LLVM intrinsics. The ones handled specially here can
- // be represented via standard LLVM IR, which is preferable to enable common
- // LLVM optimizations.
+ // Vector builtins. Note that most vector builtins are mapped automatically
+ // to target-specific LLVM intrinsics. The ones handled specially here can
+ // be represented via standard LLVM IR, which is preferable to enable common
+ // LLVM optimizations.
case SystemZ::BI__builtin_s390_vclzb:
case SystemZ::BI__builtin_s390_vclzh:
>From f4f2ef9dff3685e42886d17f705b4cad265d1a95 Mon Sep 17 00:00:00 2001
From: Maryam Moghadas <maryammo at ca.ibm.com>
Date: Fri, 19 Jun 2026 21:57:58 +0000
Subject: [PATCH 4/5] Simplify CS codegen, merge builtin tests, fix typos
---
clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp | 10 ++--
.../test/CodeGen/SystemZ/builtins-zos-cds1.c | 18 ------
.../test/CodeGen/SystemZ/builtins-zos-cdsg.c | 19 ------
clang/test/CodeGen/SystemZ/builtins-zos-cs.c | 58 ++++++++++++++++++-
clang/test/CodeGen/SystemZ/builtins-zos-cs1.c | 12 ----
clang/test/CodeGen/SystemZ/builtins-zos-csg.c | 17 ------
6 files changed, 60 insertions(+), 74 deletions(-)
delete mode 100644 clang/test/CodeGen/SystemZ/builtins-zos-cds1.c
delete mode 100644 clang/test/CodeGen/SystemZ/builtins-zos-cdsg.c
delete mode 100644 clang/test/CodeGen/SystemZ/builtins-zos-cs1.c
delete mode 100644 clang/test/CodeGen/SystemZ/builtins-zos-csg.c
diff --git a/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp b/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
index 1c115baf5cf78..2f8a5e62d6e9f 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
@@ -44,7 +44,7 @@ static Value *EmitSystemZIntrinsicWithCC(CodeGenFunction &CGF,
/// Whereas the llvm 'cmpxchg' instruction has the following syntax:
/// compxchg *Destination, Comparand, Exchange.
/// So we need to swap Comparand & Destination and dereference Comparand &
-/// Exchange when invoking CreateAtomicCmpXchng. For this reason we can not use
+/// Exchange when invoking CreateAtomicCmpXchg. For this reason we can not use
/// the utility function MakeAtomicCmpXchgValue.
static Value *EmitAtomicCmpXchgForZOSIntrin(CodeGenFunction &CGF,
const CallExpr *E,
@@ -52,8 +52,8 @@ static Value *EmitAtomicCmpXchgForZOSIntrin(CodeGenFunction &CGF,
CharUnits Alignment =
CGF.getContext().toCharUnitsFromBits(IntType->getScalarSizeInBits());
- llvm::Value *DestinationPtr = CGF.EmitScalarExpr(E->getArg(1));
llvm::Value *ComparandPtr = CGF.EmitScalarExpr(E->getArg(0));
+ llvm::Value *DestinationPtr = CGF.EmitScalarExpr(E->getArg(1));
Address DestinationAddr = Address(DestinationPtr, IntType, Alignment);
Address ComparandAddr = Address(ComparandPtr, IntType, Alignment);
@@ -65,9 +65,7 @@ static Value *EmitAtomicCmpXchgForZOSIntrin(CodeGenFunction &CGF,
Address ExchangeAddr = Address(ExchangePtr, IntType, Alignment);
Exchange = CGF.Builder.CreateLoad(ExchangeAddr);
} else {
- Exchange =
- EmitToInt(CGF, CGF.EmitScalarExpr(E->getArg(2)),
- E->getArg(2)->getType(), cast<llvm::IntegerType>(IntType));
+ Exchange = CGF.EmitScalarExpr(E->getArg(2));
}
Value *Result = CGF.Builder.CreateAtomicCmpXchg(
@@ -79,7 +77,7 @@ static Value *EmitAtomicCmpXchgForZOSIntrin(CodeGenFunction &CGF,
CGF.Builder.CreateStore(CGF.Builder.CreateExtractValue(Result, 0),
ComparandAddr);
- // Extract boolean success flag, inverse it and zext it to int.
+ // Extract boolean success flag, invert it and zext it to int.
llvm::Value *RetVal =
CGF.Builder.CreateNot(CGF.Builder.CreateExtractValue(Result, 1));
return CGF.Builder.CreateZExt(RetVal, CGF.ConvertType(E->getType()));
diff --git a/clang/test/CodeGen/SystemZ/builtins-zos-cds1.c b/clang/test/CodeGen/SystemZ/builtins-zos-cds1.c
deleted file mode 100644
index 1534ed11ff066..0000000000000
--- a/clang/test/CodeGen/SystemZ/builtins-zos-cds1.c
+++ /dev/null
@@ -1,18 +0,0 @@
-// REQUIRES: systemz-registered-target
-// RUN: %clang_cc1 -triple s390x-none-zos %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple s390x-linux-gnu %s -verify
-
-typedef struct __attribute__((__aligned__(8))) {
- int a;
- int b;
-} double_word;
-
-int func(double_word *a, double_word *b, double_word *c) {
- return __cds1(a, b, c);
-}
-// expected-error at 11 {{call to undeclared function '__cds1'; ISO C99 and later do not support implicit function declarations}}
-
-// CHECK: cmpxchg ptr {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst, align 8
-// CHECK: store i64 {{.*}}, ptr {{.*}}, align 8
-// CHECK: xor i1 {{.*}}, true
-
diff --git a/clang/test/CodeGen/SystemZ/builtins-zos-cdsg.c b/clang/test/CodeGen/SystemZ/builtins-zos-cdsg.c
deleted file mode 100644
index 9cf0271600af0..0000000000000
--- a/clang/test/CodeGen/SystemZ/builtins-zos-cdsg.c
+++ /dev/null
@@ -1,19 +0,0 @@
-// REQUIRES: systemz-registered-target
-// RUN: %clang_cc1 -triple s390x-none-zos %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple s390x-linux-gnu %s -verify=loz
-
-typedef struct __attribute__((__aligned__(16))) {
- int a;
- int b;
- int c;
- int d;
-} quadruple_word;
-
-int func(quadruple_word *a, quadruple_word *b, quadruple_word *c) {
- return __cdsg(a, b, c);
-}
-// loz-error at 13 {{call to undeclared function '__cdsg'; ISO C99 and later do not support implicit function declarations}}
-
-// CHECK: cmpxchg ptr {{.*}}, i128 {{.*}}, i128 {{.*}} seq_cst seq_cst, align 16
-// CHECK: store i128 {{.*}}, ptr {{.*}}, align 16
-// CHECK: xor i1 {{.*}}, true
diff --git a/clang/test/CodeGen/SystemZ/builtins-zos-cs.c b/clang/test/CodeGen/SystemZ/builtins-zos-cs.c
index 6877a86dd3c53..d31bb537f210a 100644
--- a/clang/test/CodeGen/SystemZ/builtins-zos-cs.c
+++ b/clang/test/CodeGen/SystemZ/builtins-zos-cs.c
@@ -2,11 +2,65 @@
// RUN: %clang_cc1 -triple s390x-none-zos %s -emit-llvm -o - | FileCheck -check-prefix=CHECK %s
// RUN: %clang_cc1 -triple s390x-linux-gnu %s -verify
-int func(unsigned int *a, unsigned int *b, unsigned int c) {
+int test_cs(unsigned int *a, unsigned int *b, unsigned int c) {
return __cs(a, b, c);
}
-// expected-error at 6 {{call to undeclared function '__cs'; ISO C99 and later do not support implicit function declarations}}
+// expected-error at -2 {{call to undeclared function '__cs'; ISO C99 and later do not support implicit function declarations}}
+// CHECK-LABEL: define{{.*}} @test_cs
// CHECK: cmpxchg ptr {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4
// CHECK: store i32 {{.*}}, ptr {{.*}}, align 4
// CHECK: xor i1 {{.*}}, true
+
+int test_cs1(int *a, int *b, int *c) {
+ return __cs1(a, b, c);
+}
+// expected-error at -2 {{call to undeclared function '__cs1'; ISO C99 and later do not support implicit function declarations}}
+
+// CHECK-LABEL: define{{.*}} @test_cs1
+// CHECK: cmpxchg ptr {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4
+// CHECK: store i32 {{.*}}, ptr {{.*}}, align 4
+// CHECK: xor i1 {{.*}}, true
+
+typedef struct __attribute__((__aligned__(8))) {
+ int a;
+ int b;
+} double_word;
+
+int test_cds1(double_word *a, double_word *b, double_word *c) {
+ return __cds1(a, b, c);
+}
+// expected-error at -2 {{call to undeclared function '__cds1'; ISO C99 and later do not support implicit function declarations}}
+
+// CHECK-LABEL: define{{.*}} @test_cds1
+// CHECK: cmpxchg ptr {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst, align 8
+// CHECK: store i64 {{.*}}, ptr {{.*}}, align 8
+// CHECK: xor i1 {{.*}}, true
+
+typedef struct __attribute__((__aligned__(16))) {
+ int a;
+ int b;
+ int c;
+ int d;
+} quadruple_word;
+
+int test_cdsg(quadruple_word *a, quadruple_word *b, quadruple_word *c) {
+ return __cdsg(a, b, c);
+}
+// expected-error at -2 {{call to undeclared function '__cdsg'; ISO C99 and later do not support implicit function declarations}}
+
+// CHECK-LABEL: define{{.*}} @test_cdsg
+// CHECK: cmpxchg ptr {{.*}}, i128 {{.*}}, i128 {{.*}} seq_cst seq_cst, align 16
+// CHECK: store i128 {{.*}}, ptr {{.*}}, align 16
+// CHECK: xor i1 {{.*}}, true
+
+
+int test_csg(double_word *a, double_word *b, double_word *c) {
+ return __csg(a, b, c);
+}
+// expected-error at -2 {{call to undeclared function '__csg'; ISO C99 and later do not support implicit function declarations}}
+
+// CHECK-LABEL: define{{.*}} @test_csg
+// CHECK: cmpxchg ptr {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst, align 8
+// CHECK: store i64 {{.*}}, ptr {{.*}}, align 8
+// CHECK: xor i1 {{.*}}, true
diff --git a/clang/test/CodeGen/SystemZ/builtins-zos-cs1.c b/clang/test/CodeGen/SystemZ/builtins-zos-cs1.c
deleted file mode 100644
index 2f036736d9e22..0000000000000
--- a/clang/test/CodeGen/SystemZ/builtins-zos-cs1.c
+++ /dev/null
@@ -1,12 +0,0 @@
-// REQUIRES: systemz-registered-target
-// RUN: %clang_cc1 -triple s390x-none-zos %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple s390x-linux-gnu %s -verify
-
-int func(int *a, int *b, int *c) {
- return __cs1(a, b, c);
-}
-// expected-error at 6 {{call to undeclared function '__cs1'; ISO C99 and later do not support implicit function declarations}}
-
-// CHECK: cmpxchg ptr {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4
-// CHECK: store i32 {{.*}}, ptr {{.*}}, align 4
-// CHECK: xor i1 {{.*}}, true
diff --git a/clang/test/CodeGen/SystemZ/builtins-zos-csg.c b/clang/test/CodeGen/SystemZ/builtins-zos-csg.c
deleted file mode 100644
index eb2add0b56d62..0000000000000
--- a/clang/test/CodeGen/SystemZ/builtins-zos-csg.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// REQUIRES: systemz-registered-target
-// RUN: %clang_cc1 -triple s390x-none-zos %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple s390x-linux-gnu %s -verify=loz
-
-typedef struct __attribute__((__aligned__(8))) {
- int a;
- int b;
-} double_word;
-
-int func(double_word *a, double_word *b, double_word *c) {
- return __csg(a, b, c);
-}
-// loz-error at 11 {{call to undeclared function '__csg'; ISO C99 and later do not support implicit function declarations}}
-
-// CHECK: cmpxchg ptr {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst, align 8
-// CHECK: store i64 {{.*}}, ptr {{.*}}, align 8
-// CHECK: xor i1 {{.*}}, true
>From e49e8f84cbbbbe716dfc712c9ca57041ee380ff2 Mon Sep 17 00:00:00 2001
From: Maryam Moghadas <maryammo at ca.ibm.com>
Date: Tue, 7 Jul 2026 21:04:05 +0000
Subject: [PATCH 5/5] Migrate z/OS builtins doc to LanguageExtensions.md
---
clang/docs/LanguageExtensions.md | 34 ++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/clang/docs/LanguageExtensions.md b/clang/docs/LanguageExtensions.md
index 68416e801bd5d..c0b921d058777 100644
--- a/clang/docs/LanguageExtensions.md
+++ b/clang/docs/LanguageExtensions.md
@@ -5538,6 +5538,40 @@ int a = 1;
__builtin_dcbf (&a);
```
+### z/OS Language Extensions
+
+#### z/OS builtins
+
+z/OS supports builtins for compare-and-swap operations that generate the
+corresponding z/OS assembly instructions (CS, CSG, CDSG). These builtins compare
+the value pointed to by oldptr to the value pointed to by curptr. If they are
+equal, the value pointed to by newword (or newword itself for `__cs`) is
+copied into the location pointed to by curptr. If they are unequal, the value
+pointed to by curptr is copied into the location pointed to by oldptr.
+The builtins return 0 if the values are equal, or 1 if they are unequal.
+
+- `int __cs(unsigned int *oldptr, unsigned int *curptr, unsigned int newword)`
+
+ Generates a 4-byte compare-and-swap using the CS instruction.
+ Use `__cs` instead of `__cs1` when the newword arg is an r-value instead
+ of an l-value.
+
+- `int __cs1(void *oldptr, void *curptr, void *newword)`
+
+ Generates a 4-byte compare-and-swap using the CS instruction.
+
+- `int __csg(void *oldptr, void *curptr, void *newword)`
+
+ Generates an 8-byte compare-and-swap using the CSG instruction.
+
+- `int __cds1(void *oldptr, void *curptr, void *newword)`
+
+ Generates an 8-byte compare-and-swap using the CSG instruction.
+
+- `int __cdsg(void *oldptr, void *curptr, void *newword)`
+
+ Generates a 16-byte compare-and-swap using the CDSG instruction.
+
## Extensions for Static Analysis
Clang supports additional attributes that are useful for documenting program
More information about the cfe-commits
mailing list