[clang] [z/OS][Clang] Add compare and swap builtin functions (PR #202362)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 8 08:18:18 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Maryam Moghadas (maryammo)
<details>
<summary>Changes</summary>
Implements the following compare and swap builtins:
int __cs(unsigned int *, unsigned int *, unsigned int), 4 byte compare & swap
int __cs1(void* OP1, void* OP2, void* OP3), 4 byte compare & swap
int __csg(void* OP1, void* OP2, void* OP3), 8 byte compare & swap
int __cds1(void* OP1, void* OP2, void* OP3), 8 byte compare & swap
int __cdsg(void* OP1, void* OP2, void* OP3), 16 byte compare & swap
The implementation utilizes the llvm cmpxchg intrinsic to generate the CS instructions, then it generates a store instruction to store OP2 into OP1, and finally invert the success flag of cmpxchg by an XOR instruction with 1 and return the flag.
---
Full diff: https://github.com/llvm/llvm-project/pull/202362.diff
10 Files Affected:
- (added) clang/include/clang/Basic/BuiltinsZOS.td (+27)
- (modified) clang/include/clang/Basic/CMakeLists.txt (+4)
- (modified) clang/include/clang/Basic/TargetBuiltins.h (+9-4)
- (modified) clang/lib/Basic/Targets/SystemZ.cpp (+21-1)
- (modified) clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp (+67-4)
- (added) clang/test/CodeGen/SystemZ/builtins-zos-cds1.c (+18)
- (added) clang/test/CodeGen/SystemZ/builtins-zos-cdsg.c (+19)
- (added) clang/test/CodeGen/SystemZ/builtins-zos-cs.c (+12)
- (added) clang/test/CodeGen/SystemZ/builtins-zos-cs1.c (+12)
- (added) clang/test/CodeGen/SystemZ/builtins-zos-csg.c (+17)
``````````diff
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 20172622ca424..41e18b0c6cf53 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 9b4613c853206..bd0287d766225 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
``````````
</details>
https://github.com/llvm/llvm-project/pull/202362
More information about the cfe-commits
mailing list