https://github.com/maryammo created https://github.com/llvm/llvm-project/pull/202362
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. >From 3686e3bf765b8ebbc41b2c712d7ae7bbfe104dc4 Mon Sep 17 00:00:00 2001 From: Maryam Moghadas <[email protected]> Date: Fri, 5 Jun 2026 20:18:38 +0000 Subject: [PATCH] [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 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@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@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@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@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@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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
