Author: adams381 Date: 2026-06-25T12:50:43-05:00 New Revision: bc3eb524b2d1dcc3e48161cd2eb80a2364fdc097
URL: https://github.com/llvm/llvm-project/commit/bc3eb524b2d1dcc3e48161cd2eb80a2364fdc097 DIFF: https://github.com/llvm/llvm-project/commit/bc3eb524b2d1dcc3e48161cd2eb80a2364fdc097.diff LOG: [CIR] Lower __atomic_is_lock_free / __c11_atomic_is_lock_free (#205862) `__atomic_is_lock_free` and `__c11_atomic_is_lock_free` were routed to `errorNYI` in CIRGen, so `std::atomic<T>::is_lock_free()` failed to compile under `-fclangir` whenever the query wasn't constant-folded -- which is what the libcxx atomics lock-free tests hit. This mirrors classic CodeGen (`CGBuiltin.cpp`): emit a call to the runtime entry `bool __atomic_is_lock_free(size_t size, void *ptr)`. `__atomic_is_lock_free` forwards its pointer argument; `__c11_atomic_is_lock_free` passes a null pointer, since an `_Atomic` object is always suitably aligned. `__atomic_test_and_set` / `__atomic_clear` stay NYI. The lowered call omits the `noundef`/`zeroext` argument and return attributes classic emits, and the declaration picks up `dso_local`. That's the existing CIR libcall attribute gap, so the test uses split `LLVMCIR`/`OGCG` prefixes where the two diverge and a shared skeleton where they match. Added: clang/test/CIR/CodeGen/builtin-atomic-is-lock-free.c Modified: clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 50529a61068d5..ba2dd2dccc63b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -261,6 +261,30 @@ static void emitAtomicFenceOp(CIRGenFunction &cgf, const CallExpr *expr, emitAtomicOpCallBackFn); } +// Emit a runtime call to bool __atomic_is_lock_free(size_t size, void *ptr). +// For the __c11 builtin the pointer is null, since an _Atomic object is always +// suitably aligned. +static RValue emitAtomicIsLockFree(CIRGenFunction &cgf, const CallExpr *e, + unsigned builtinID) { + CIRGenBuilderTy &builder = cgf.getBuilder(); + mlir::Location loc = cgf.getLoc(e->getExprLoc()); + + mlir::Type sizeTy = cgf.convertType(cgf.getContext().getSizeType()); + mlir::Value size = cgf.emitScalarExpr(e->getArg(0)); + mlir::Value ptr; + if (builtinID == Builtin::BI__atomic_is_lock_free) + ptr = builder.createBitcast(cgf.emitScalarExpr(e->getArg(1)), + builder.getVoidPtrTy()); + else + ptr = builder.getNullPtr(builder.getVoidPtrTy(), loc); + + cir::FuncOp func = cgf.cgm.createRuntimeFunction( + cir::FuncType::get({sizeTy, builder.getVoidPtrTy()}, builder.getBoolTy()), + "__atomic_is_lock_free"); + return RValue::get( + builder.createCallOp(loc, func, mlir::ValueRange{size, ptr}).getResult()); +} + namespace { struct WidthAndSignedness { unsigned width; @@ -2182,6 +2206,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, } case Builtin::BI__c11_atomic_is_lock_free: case Builtin::BI__atomic_is_lock_free: + return emitAtomicIsLockFree(*this, e, builtinID); case Builtin::BI__atomic_test_and_set: case Builtin::BI__atomic_clear: return errorBuiltinNYI(*this, e, builtinID); diff --git a/clang/test/CIR/CodeGen/builtin-atomic-is-lock-free.c b/clang/test/CIR/CodeGen/builtin-atomic-is-lock-free.c new file mode 100644 index 0000000000000..2792f595275a6 --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin-atomic-is-lock-free.c @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefixes=LLVM,LLVMCIR --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefixes=LLVM,OGCG --input-file=%t.ll %s + +typedef struct { char buf[24]; } Big; + +int test_atomic(Big *p) { return __atomic_is_lock_free(sizeof(Big), p); } + +int test_c11(void) { return __c11_atomic_is_lock_free(sizeof(Big)); } + +int test_atomic_var(unsigned long n, void *p) { + return __atomic_is_lock_free(n, p); +} + +// CIR-DAG: cir.func private dso_local @__atomic_is_lock_free(!u64i, !cir.ptr<!void>) -> !cir.bool + +// CIR-LABEL: cir.func{{.*}} @test_atomic( +// CIR: %[[SZ:.*]] = cir.const #cir.int<24> : !u64i +// CIR: %[[P:.*]] = cir.load{{.*}} : !cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big> +// CIR: %[[VP:.*]] = cir.cast bitcast %[[P]] : !cir.ptr<!rec_Big> -> !cir.ptr<!void> +// CIR: cir.call @__atomic_is_lock_free(%[[SZ]], %[[VP]]) : (!u64i, !cir.ptr<!void>) -> !cir.bool + +// CIR-LABEL: cir.func{{.*}} @test_c11( +// CIR: %[[SZ2:.*]] = cir.const #cir.int<24> : !u64i +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void> +// CIR: cir.call @__atomic_is_lock_free(%[[SZ2]], %[[NULL]]) : (!u64i, !cir.ptr<!void>) -> !cir.bool + +// CIR-LABEL: cir.func{{.*}} @test_atomic_var( +// CIR: cir.call @__atomic_is_lock_free(%{{.*}}, %{{.*}}) : (!u64i, !cir.ptr<!void>) -> !cir.bool + +// LLVM-LABEL: define dso_local i32 @test_atomic( +// LLVMCIR: call i1 @__atomic_is_lock_free(i64 24, ptr %{{.*}}) +// OGCG: call zeroext i1 @__atomic_is_lock_free(i64 noundef 24, ptr noundef %{{.*}}) +// LLVM: zext i1 %{{.*}} to i32 + +// LLVM-LABEL: define dso_local i32 @test_c11( +// LLVMCIR: call i1 @__atomic_is_lock_free(i64 24, ptr null) +// OGCG: call zeroext i1 @__atomic_is_lock_free(i64 noundef 24, ptr noundef null) +// LLVM: zext i1 %{{.*}} to i32 + +// LLVM-LABEL: define dso_local i32 @test_atomic_var( +// LLVMCIR: call i1 @__atomic_is_lock_free(i64 %{{.*}}, ptr %{{.*}}) +// OGCG: call zeroext i1 @__atomic_is_lock_free(i64 noundef %{{.*}}, ptr noundef %{{.*}}) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
