Skip to content

Commit

Permalink
[CIR][CodeGen] builtins: adds __sync_bool/val_compare_and_swap (#656)
Browse files Browse the repository at this point in the history
This PR adds support for ` __sync_bool_compare_and_swap` and `
__sync_val_compare_and_swap`.
  • Loading branch information
gitoleg authored and lanza committed Nov 3, 2024
1 parent f58a3c5 commit 2b67ca6
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 0 deletions.
37 changes: 37 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<mlir::cir::AtomicCmpXchg>(
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));
Expand Down Expand Up @@ -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: {
Expand Down
92 changes: 92 additions & 0 deletions clang/test/CIR/CodeGen/atomic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<!s32i>>, !cir.ptr<!s32i>
// CHECK: %[[CMP:.*]] = cir.load {{.*}} : !cir.ptr<!s32i>, !s32i
// CHECK: %[[UPD:.*]] = cir.load {{.*}} : !cir.ptr<!s32i>, !s32i
// CHECK: %[[OLD:.*]], %[[RES:.*]] = cir.atomic.cmp_xchg(%[[PTR]] : !cir.ptr<!s32i>, %[[CMP]] : !s32i, %[[UPD]] : !s32i, success = seq_cst, failure = seq_cst) : (!s32i, !cir.bool)
// CHECK: cir.store %[[RES]], {{.*}} : !cir.bool, !cir.ptr<!cir.bool>

// 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, {{.*}} : !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, {{.*}} : !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, {{.*}} : !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<!s32i>>, !cir.ptr<!s32i>
// CHECK: %[[CMP:.*]] = cir.load {{.*}} : !cir.ptr<!s32i>, !s32i
// CHECK: %[[UPD:.*]] = cir.load {{.*}} : !cir.ptr<!s32i>, !s32i
// CHECK: %[[OLD:.*]], %[[RES:.*]] = cir.atomic.cmp_xchg(%[[PTR]] : !cir.ptr<!s32i>, %[[CMP]] : !s32i, %[[UPD]] : !s32i, success = seq_cst, failure = seq_cst) : (!s32i, !cir.bool)
// CHECK: cir.store %[[OLD]], {{.*}} : !s32i, !cir.ptr<!s32i>

// 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, {{.*}} : !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, {{.*}} : !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, {{.*}} : !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);
}

0 comments on commit 2b67ca6

Please sign in to comment.