From 2b67ca6c604c8770638de09ab6558e4c4ed75517 Mon Sep 17 00:00:00 2001 From: gitoleg Date: Fri, 7 Jun 2024 20:18:39 +0300 Subject: [PATCH] [CIR][CodeGen] builtins: adds __sync_bool/val_compare_and_swap (#656) This PR adds support for ` __sync_bool_compare_and_swap` and ` __sync_val_compare_and_swap`. --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 37 ++++++++++ clang/test/CIR/CodeGen/atomic.cpp | 92 +++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 71f668196ebb..356b763c32dc 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -245,6 +245,29 @@ static RValue buildBinaryAtomic(CIRGenFunction &CGF, return RValue::get(makeBinaryAtomicValue(CGF, kind, E)); } +static mlir::Value MakeAtomicCmpXchgValue(CIRGenFunction &cgf, + const CallExpr *expr, + bool returnBool) { + QualType typ = returnBool ? expr->getArg(1)->getType() : expr->getType(); + Address destAddr = checkAtomicAlignment(cgf, expr); + auto &builder = cgf.getBuilder(); + + auto intType = builder.getSIntNTy(cgf.getContext().getTypeSize(typ)); + auto cmpVal = cgf.buildScalarExpr(expr->getArg(1)); + auto valueType = cmpVal.getType(); + cmpVal = buildToInt(cgf, cmpVal, typ, intType); + auto newVal = + buildToInt(cgf, cgf.buildScalarExpr(expr->getArg(2)), typ, intType); + + auto op = builder.create( + cgf.getLoc(expr->getSourceRange()), cmpVal.getType(), builder.getBoolTy(), + destAddr.getPointer(), cmpVal, newVal, + mlir::cir::MemOrder::SequentiallyConsistent, + mlir::cir::MemOrder::SequentiallyConsistent); + + return returnBool ? op.getResult(1) : op.getResult(0); +} + RValue CIRGenFunction::buildRotate(const CallExpr *E, bool IsRotateRight) { auto src = buildScalarExpr(E->getArg(0)); auto shiftAmt = buildScalarExpr(E->getArg(1)); @@ -997,6 +1020,20 @@ RValue CIRGenFunction::buildBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return buildBinaryAtomic(*this, mlir::cir::AtomicFetchKind::Add, E); } + case Builtin::BI__sync_val_compare_and_swap_1: + case Builtin::BI__sync_val_compare_and_swap_2: + case Builtin::BI__sync_val_compare_and_swap_4: + case Builtin::BI__sync_val_compare_and_swap_8: + case Builtin::BI__sync_val_compare_and_swap_16: + return RValue::get(MakeAtomicCmpXchgValue(*this, E, false)); + + case Builtin::BI__sync_bool_compare_and_swap_1: + case Builtin::BI__sync_bool_compare_and_swap_2: + case Builtin::BI__sync_bool_compare_and_swap_4: + case Builtin::BI__sync_bool_compare_and_swap_8: + case Builtin::BI__sync_bool_compare_and_swap_16: + return RValue::get(MakeAtomicCmpXchgValue(*this, E, true)); + case Builtin::BI__builtin_add_overflow: case Builtin::BI__builtin_sub_overflow: case Builtin::BI__builtin_mul_overflow: { diff --git a/clang/test/CIR/CodeGen/atomic.cpp b/clang/test/CIR/CodeGen/atomic.cpp index 9afda8ba5120..0b64cda23446 100644 --- a/clang/test/CIR/CodeGen/atomic.cpp +++ b/clang/test/CIR/CodeGen/atomic.cpp @@ -378,4 +378,96 @@ void inc_short(short* a, short b) { // LLVM: atomicrmw add ptr {{.*}}, i8 {{.*}} seq_cst, align 1 void inc_byte(char* a, char b) { char c = __sync_fetch_and_add(a, b); +} + + +// CHECK-LABEL: @_Z12cmp_bool_int +// CHECK: %[[PTR:.*]] = cir.load {{.*}} : !cir.ptr>, !cir.ptr +// CHECK: %[[CMP:.*]] = cir.load {{.*}} : !cir.ptr, !s32i +// CHECK: %[[UPD:.*]] = cir.load {{.*}} : !cir.ptr, !s32i +// CHECK: %[[OLD:.*]], %[[RES:.*]] = cir.atomic.cmp_xchg(%[[PTR]] : !cir.ptr, %[[CMP]] : !s32i, %[[UPD]] : !s32i, success = seq_cst, failure = seq_cst) : (!s32i, !cir.bool) +// CHECK: cir.store %[[RES]], {{.*}} : !cir.bool, !cir.ptr + +// LLVM-LABEL: @_Z12cmp_bool_int +// LLVM: %[[PTR:.*]] = load ptr +// LLVM: %[[CMP:.*]] = load i32 +// LLVM: %[[UPD:.*]] = load i32 +// LLVM: %[[RES:.*]] = cmpxchg ptr %[[PTR]], i32 %[[CMP]], i32 %[[UPD]] seq_cst seq_cst +// LLVM: %[[TMP:.*]] = extractvalue { i32, i1 } %[[RES]], 1 +// LLVM: %[[EXT:.*]] = zext i1 %[[TMP]] to i8 +// LLVM: store i8 %[[EXT]], ptr {{.*}} +void cmp_bool_int(int* p, int x, int u) { + bool r = __sync_bool_compare_and_swap(p, x, u); +} + +// CHECK-LABEL: @_Z13cmp_bool_long +// CHECK: cir.atomic.cmp_xchg({{.*}} : !cir.ptr, {{.*}} : !s64i, {{.*}} : !s64i, success = seq_cst, failure = seq_cst) : (!s64i, !cir.bool) + +// LLVM-LABEL: @_Z13cmp_bool_long +// LLVM: cmpxchg ptr {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst +void cmp_bool_long(long* p, long x, long u) { + bool r = __sync_bool_compare_and_swap(p, x, u); +} + +// CHECK-LABEL: @_Z14cmp_bool_short +// CHECK: cir.atomic.cmp_xchg({{.*}} : !cir.ptr, {{.*}} : !s16i, {{.*}} : !s16i, success = seq_cst, failure = seq_cst) : (!s16i, !cir.bool) + +// LLVM-LABEL: @_Z14cmp_bool_short +// LLVM: cmpxchg ptr {{.*}}, i16 {{.*}}, i16 {{.*}} seq_cst seq_cst +void cmp_bool_short(short* p, short x, short u) { + bool r = __sync_bool_compare_and_swap(p, x, u); +} + +// CHECK-LABEL: @_Z13cmp_bool_byte +// CHECK: cir.atomic.cmp_xchg({{.*}} : !cir.ptr, {{.*}} : !s8i, {{.*}} : !s8i, success = seq_cst, failure = seq_cst) : (!s8i, !cir.bool) + +// LLVM-LABEL: @_Z13cmp_bool_byte +// LLVM: cmpxchg ptr {{.*}}, i8 {{.*}}, i8 {{.*}} seq_cst seq_cst +void cmp_bool_byte(char* p, char x, char u) { + bool r = __sync_bool_compare_and_swap(p, x, u); +} + +// CHECK-LABEL: @_Z11cmp_val_int +// CHECK: %[[PTR:.*]] = cir.load {{.*}} : !cir.ptr>, !cir.ptr +// CHECK: %[[CMP:.*]] = cir.load {{.*}} : !cir.ptr, !s32i +// CHECK: %[[UPD:.*]] = cir.load {{.*}} : !cir.ptr, !s32i +// CHECK: %[[OLD:.*]], %[[RES:.*]] = cir.atomic.cmp_xchg(%[[PTR]] : !cir.ptr, %[[CMP]] : !s32i, %[[UPD]] : !s32i, success = seq_cst, failure = seq_cst) : (!s32i, !cir.bool) +// CHECK: cir.store %[[OLD]], {{.*}} : !s32i, !cir.ptr + +// LLVM-LABEL: @_Z11cmp_val_int +// LLVM: %[[PTR:.*]] = load ptr +// LLVM: %[[CMP:.*]] = load i32 +// LLVM: %[[UPD:.*]] = load i32 +// LLVM: %[[RES:.*]] = cmpxchg ptr %[[PTR]], i32 %[[CMP]], i32 %[[UPD]] seq_cst seq_cst +// LLVM: %[[TMP:.*]] = extractvalue { i32, i1 } %[[RES]], 0 +// LLVM: store i32 %[[TMP]], ptr {{.*}} +void cmp_val_int(int* p, int x, int u) { + int r = __sync_val_compare_and_swap(p, x, u); +} + +// CHECK-LABEL: @_Z12cmp_val_long +// CHECK: cir.atomic.cmp_xchg({{.*}} : !cir.ptr, {{.*}} : !s64i, {{.*}} : !s64i, success = seq_cst, failure = seq_cst) : (!s64i, !cir.bool) + +// LLVM-LABEL: @_Z12cmp_val_long +// LLVM: cmpxchg ptr {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst +void cmp_val_long(long* p, long x, long u) { + long r = __sync_val_compare_and_swap(p, x, u); +} + +// CHECK-LABEL: @_Z13cmp_val_short +// CHECK: cir.atomic.cmp_xchg({{.*}} : !cir.ptr, {{.*}} : !s16i, {{.*}} : !s16i, success = seq_cst, failure = seq_cst) : (!s16i, !cir.bool) + +// LLVM-LABEL: @_Z13cmp_val_short +// LLVM: cmpxchg ptr {{.*}}, i16 {{.*}}, i16 {{.*}} seq_cst seq_cst +void cmp_val_short(short* p, short x, short u) { + short r = __sync_val_compare_and_swap(p, x, u); +} + +// CHECK-LABEL: @_Z12cmp_val_byte +// CHECK: cir.atomic.cmp_xchg({{.*}} : !cir.ptr, {{.*}} : !s8i, {{.*}} : !s8i, success = seq_cst, failure = seq_cst) : (!s8i, !cir.bool) + +// LLVM-LABEL: @_Z12cmp_val_byte +// LLVM: cmpxchg ptr {{.*}}, i8 {{.*}}, i8 {{.*}} seq_cst seq_cst +void cmp_val_byte(char* p, char x, char u) { + char r = __sync_val_compare_and_swap(p, x, u); } \ No newline at end of file