https://github.com/Lancern updated https://github.com/llvm/llvm-project/pull/202671
>From 413e79be89ecbd53ef9e03661c10aa972d073741 Mon Sep 17 00:00:00 2001 From: Sirui Mu <[email protected]> Date: Tue, 9 Jun 2026 22:17:50 +0800 Subject: [PATCH] [CIR] Atomic load and store via library call This call adds support for atomic load/store operations that go through calls to the `__atomic_load` and `__atomic_store` library functions. This could happen when the size of the atomic type is too large or is not a power of 2. Assisted-by: Codex / gpt-5.5 xhigh --- clang/lib/CIR/CodeGen/CIRGenAtomic.cpp | 225 +++++++++++++++++++++++- clang/lib/CIR/CodeGen/CIRGenCall.cpp | 12 ++ clang/lib/CIR/CodeGen/CIRGenTypes.h | 5 + clang/test/CIR/CodeGen/atomic-libcall.c | 172 ++++++++++++++++++ 4 files changed, 409 insertions(+), 5 deletions(-) create mode 100644 clang/test/CIR/CodeGen/atomic-libcall.c diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp index 6ba6bc1c0405a..4498326376694 100644 --- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp @@ -1114,6 +1114,224 @@ void CIRGenFunction::emitAtomicExprWithMemOrder( emitAtomicOpFn); } +static RValue emitAtomicLibCall(CIRGenFunction &cgf, llvm::StringRef funcName, + QualType resultType, CallArgList &args) { + const CIRGenFunctionInfo &fnInfo = + cgf.cgm.getTypes().arrangeBuiltinFunctionCall(resultType, args); + cir::FuncType fnTy = cgf.cgm.getTypes().getFunctionType(fnInfo); + + mlir::NamedAttrList fnAttrs; + assert(!cir::MissingFeatures::opFuncExtraAttrs()); + + cir::FuncOp fn = cgf.cgm.createRuntimeFunction(fnTy, funcName, fnAttrs); + auto callee = CIRGenCallee::forDirect(fn); + return cgf.emitCall(fnInfo, callee, ReturnValueSlot(), args); +} + +static RValue emitLibCallForAtomicExpr(CIRGenFunction &cgf, AtomicExpr *e, + Address atomicPtr, Address dest, + Address val1, uint64_t atomicTySize, + QualType resultTy) { + mlir::Location loc = cgf.getLoc(e->getSourceRange()); + + CallArgList args; + // For non-optimized library calls, the size is the first parameter. + args.add( + RValue::get(cgf.getBuilder().getConstInt(loc, cgf.sizeTy, atomicTySize)), + cgf.getContext().getSizeType()); + + // The atomic address is the second parameter. + // The OpenCL atomic library functions only accept pointer arguments to + // generic address space. + auto castToGenericAddrSpace = [&](mlir::Value v, QualType pt) { + if (!e->isOpenCL()) + return cgf.getBuilder().createPtrBitcast(v, cgf.voidTy); + + assert(!cir::MissingFeatures::openCL()); + cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: openCL"); + return cgf.getBuilder().createPtrBitcast(v, cgf.voidTy); + }; + args.add(RValue::get(castToGenericAddrSpace(atomicPtr.emitRawPointer(), + e->getPtr()->getType())), + cgf.getContext().VoidPtrTy); + + // The next 1-3 parameters are op-dependent. + llvm::StringRef calleeName; + QualType retTy; + bool hasRetTy = false; + switch (e->getOp()) { + case AtomicExpr::AO__c11_atomic_init: + case AtomicExpr::AO__opencl_atomic_init: + llvm_unreachable("Already handled!"); + + // There is only one libcall for compare an exchange, because there is no + // optimisation benefit possible from a libcall version of a weak compare + // and exchange. + // bool __atomic_compare_exchange(size_t size, void *mem, void *expected, + // void *desired, int success, int failure) + case AtomicExpr::AO__atomic_compare_exchange: + case AtomicExpr::AO__atomic_compare_exchange_n: + case AtomicExpr::AO__c11_atomic_compare_exchange_weak: + case AtomicExpr::AO__c11_atomic_compare_exchange_strong: + case AtomicExpr::AO__hip_atomic_compare_exchange_weak: + case AtomicExpr::AO__hip_atomic_compare_exchange_strong: + case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: + case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: + case AtomicExpr::AO__scoped_atomic_compare_exchange: + case AtomicExpr::AO__scoped_atomic_compare_exchange_n: + cgf.cgm.errorNYI( + loc, "emitLibCallForAtomicExpr: atomic compare-and-exchange NYI"); + return RValue::get(nullptr); + + // void __atomic_exchange(size_t size, void *mem, void *val, void *return, + // int order) + case AtomicExpr::AO__atomic_exchange: + case AtomicExpr::AO__atomic_exchange_n: + case AtomicExpr::AO__c11_atomic_exchange: + case AtomicExpr::AO__hip_atomic_exchange: + case AtomicExpr::AO__opencl_atomic_exchange: + case AtomicExpr::AO__scoped_atomic_exchange: + case AtomicExpr::AO__scoped_atomic_exchange_n: + cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: atomic exchange NYI"); + return RValue::get(nullptr); + + // void __atomic_store(size_t size, void *mem, void *val, int order) + case AtomicExpr::AO__atomic_store: + case AtomicExpr::AO__atomic_store_n: + case AtomicExpr::AO__c11_atomic_store: + case AtomicExpr::AO__scoped_atomic_store: + case AtomicExpr::AO__scoped_atomic_store_n: { + calleeName = "__atomic_store"; + retTy = cgf.getContext().VoidTy; + hasRetTy = true; + args.add(RValue::get(castToGenericAddrSpace(val1.emitRawPointer(), + e->getVal1()->getType())), + cgf.getContext().VoidPtrTy); + break; + } + + case AtomicExpr::AO__hip_atomic_store: + case AtomicExpr::AO__opencl_atomic_store: + cgf.cgm.errorNYI(loc, + "emitLibCallForAtomicExpr: atomic store for hip/opencl"); + return RValue::get(nullptr); + + // void __atomic_load(size_t size, void *mem, void *return, int order) + case AtomicExpr::AO__atomic_load: + case AtomicExpr::AO__atomic_load_n: + case AtomicExpr::AO__c11_atomic_load: + case AtomicExpr::AO__scoped_atomic_load: + case AtomicExpr::AO__scoped_atomic_load_n: { + calleeName = "__atomic_load"; + break; + } + + case AtomicExpr::AO__hip_atomic_load: + case AtomicExpr::AO__opencl_atomic_load: + cgf.cgm.errorNYI(loc, + "emitLibCallForAtomicExpr: atomic load for hip/opencl"); + return RValue::get(nullptr); + + case AtomicExpr::AO__atomic_add_fetch: + case AtomicExpr::AO__scoped_atomic_add_fetch: + case AtomicExpr::AO__atomic_fetch_add: + case AtomicExpr::AO__c11_atomic_fetch_add: + case AtomicExpr::AO__hip_atomic_fetch_add: + case AtomicExpr::AO__opencl_atomic_fetch_add: + case AtomicExpr::AO__scoped_atomic_fetch_add: + case AtomicExpr::AO__atomic_and_fetch: + case AtomicExpr::AO__scoped_atomic_and_fetch: + case AtomicExpr::AO__atomic_fetch_and: + case AtomicExpr::AO__c11_atomic_fetch_and: + case AtomicExpr::AO__hip_atomic_fetch_and: + case AtomicExpr::AO__opencl_atomic_fetch_and: + case AtomicExpr::AO__scoped_atomic_fetch_and: + case AtomicExpr::AO__atomic_or_fetch: + case AtomicExpr::AO__scoped_atomic_or_fetch: + case AtomicExpr::AO__atomic_fetch_or: + case AtomicExpr::AO__c11_atomic_fetch_or: + case AtomicExpr::AO__hip_atomic_fetch_or: + case AtomicExpr::AO__opencl_atomic_fetch_or: + case AtomicExpr::AO__scoped_atomic_fetch_or: + case AtomicExpr::AO__atomic_sub_fetch: + case AtomicExpr::AO__scoped_atomic_sub_fetch: + case AtomicExpr::AO__atomic_fetch_sub: + case AtomicExpr::AO__c11_atomic_fetch_sub: + case AtomicExpr::AO__hip_atomic_fetch_sub: + case AtomicExpr::AO__opencl_atomic_fetch_sub: + case AtomicExpr::AO__scoped_atomic_fetch_sub: + case AtomicExpr::AO__atomic_xor_fetch: + case AtomicExpr::AO__scoped_atomic_xor_fetch: + case AtomicExpr::AO__atomic_fetch_xor: + case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__hip_atomic_fetch_xor: + case AtomicExpr::AO__opencl_atomic_fetch_xor: + case AtomicExpr::AO__scoped_atomic_fetch_xor: + case AtomicExpr::AO__atomic_nand_fetch: + case AtomicExpr::AO__atomic_fetch_nand: + case AtomicExpr::AO__c11_atomic_fetch_nand: + case AtomicExpr::AO__scoped_atomic_fetch_nand: + case AtomicExpr::AO__scoped_atomic_nand_fetch: + case AtomicExpr::AO__atomic_min_fetch: + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__c11_atomic_fetch_min: + case AtomicExpr::AO__hip_atomic_fetch_min: + case AtomicExpr::AO__opencl_atomic_fetch_min: + case AtomicExpr::AO__scoped_atomic_fetch_min: + case AtomicExpr::AO__scoped_atomic_min_fetch: + case AtomicExpr::AO__atomic_max_fetch: + case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__c11_atomic_fetch_max: + case AtomicExpr::AO__hip_atomic_fetch_max: + case AtomicExpr::AO__opencl_atomic_fetch_max: + case AtomicExpr::AO__scoped_atomic_fetch_max: + case AtomicExpr::AO__scoped_atomic_max_fetch: + case AtomicExpr::AO__scoped_atomic_fetch_uinc: + case AtomicExpr::AO__scoped_atomic_fetch_udec: + case AtomicExpr::AO__atomic_test_and_set: + case AtomicExpr::AO__atomic_clear: + case AtomicExpr::AO__atomic_fetch_uinc: + case AtomicExpr::AO__atomic_fetch_udec: + llvm_unreachable("Integral atomic operations always become atomicrmw!"); + } + + if (e->isOpenCL()) { + assert(!cir::MissingFeatures::openCL()); + cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: openCL"); + return RValue::get(nullptr); + } + + // By default, assume we return a value of the atomic type. + if (!hasRetTy) { + // Value is returned through parameter before the order. + retTy = cgf.getContext().VoidTy; + args.add(RValue::get(castToGenericAddrSpace(dest.emitRawPointer(), retTy)), + cgf.getContext().VoidPtrTy); + } + + // Order is always the last parameter. + args.add(RValue::get(cgf.emitScalarExpr(e->getOrder())), + cgf.getContext().IntTy); + if (e->isOpenCL()) { + assert(!cir::MissingFeatures::openCL()); + cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: openCL"); + return RValue::get(nullptr); + } + + RValue res = emitAtomicLibCall(cgf, calleeName, retTy, args); + + // The value is returned directly from the libcall. + if (e->isCmpXChg()) + return res; + + if (resultTy->isVoidType()) + return RValue::get(nullptr); + + return cgf.convertTempToRValue( + dest.withElementType(cgf.getBuilder(), cgf.convertTypeForMem(resultTy)), + resultTy, e->getExprLoc()); +} + RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) { QualType atomicTy = e->getPtr()->getType()->getPointeeType(); QualType memTy = atomicTy; @@ -1324,11 +1542,8 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) { // the size-optimized libcall variants, which are only valid up to 16 bytes.) // // See: https://llvm.org/docs/Atomics.html#libcalls-atomic - if (useLibCall) { - assert(!cir::MissingFeatures::atomicUseLibCall()); - cgm.errorNYI(e->getSourceRange(), "emitAtomicExpr: emit atomic lib call"); - return RValue::get(nullptr); - } + if (useLibCall) + return emitLibCallForAtomicExpr(*this, e, ptr, dest, val1, size, resultTy); bool isStore = e->getOp() == AtomicExpr::AO__c11_atomic_store || e->getOp() == AtomicExpr::AO__opencl_atomic_store || diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index f648eff375a77..c3065c8917924 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -1016,6 +1016,18 @@ CIRGenTypes::arrangeFreeFunctionCall(const CallArgList &args, return arrangeFreeFunctionLikeCall(*this, cgm, args, fnType); } +const CIRGenFunctionInfo & +CIRGenTypes::arrangeBuiltinFunctionCall(QualType resultType, + const CallArgList &args) { + llvm::SmallVector<CanQualType, 16> argTypes; + for (const CallArg &arg : args) + argTypes.push_back(astContext.getCanonicalParamType(arg.ty)); + + CanQualType retType = resultType->getCanonicalTypeUnqualified(); + return arrangeCIRFunctionInfo(retType, /*isInstanceMethod=*/false, argTypes, + FunctionType::ExtInfo(), RequiredArgs::All); +} + /// Arrange the argument and result information for a declaration or definition /// of the given C++ non-static member function. The member function must be an /// ordinary function, i.e. not a constructor or destructor. diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h index 15955c517f1f3..a7827f76bd5f2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h @@ -186,6 +186,11 @@ class CIRGenTypes { const CIRGenFunctionInfo & arrangeFunctionDeclaration(const clang::FunctionDecl *fd); + /// A builtin function is a freestanding function using the default + /// C conventions. + const CIRGenFunctionInfo &arrangeBuiltinFunctionCall(QualType resultType, + const CallArgList &args); + /// Return whether a type can be zero-initialized (in the C++ sense) with an /// LLVM zeroinitializer. bool isZeroInitializable(clang::QualType ty); diff --git a/clang/test/CIR/CodeGen/atomic-libcall.c b/clang/test/CIR/CodeGen/atomic-libcall.c new file mode 100644 index 0000000000000..4518dd5e24dda --- /dev/null +++ b/clang/test/CIR/CodeGen/atomic-libcall.c @@ -0,0 +1,172 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +struct Big { + int x[6]; +}; + +void load(struct Big *ptr) { + // CIR-LABEL: @load + // LLVM-LABEL: @load + // OGCG-LABEL: @load + + struct Big b; + __atomic_load(ptr, &b, __ATOMIC_RELAXED); + // CIR: %[[DEST_SLOT:.+]] = cir.alloca "b" align(4) : !cir.ptr<!rec_Big> + // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big> + // CIR-NEXT: %[[PTR_INTPTR:.+]] = cir.cast bitcast %[[PTR]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[DEST_INTPTR:.+]] = cir.cast bitcast %[[DEST_SLOT]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i + // CIR-NEXT: %[[PTR_VOIDPTR:.+]] = cir.cast bitcast %[[PTR_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i + // CIR-NEXT: cir.call @__atomic_load(%[[SIZE]], %[[PTR_VOIDPTR]], %[[DEST_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> () + + // LLVM: %[[DEST:.+]] = alloca %struct.Big, i64 1, align 4 + // LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], ptr noundef %[[DEST]], i32 noundef 0) + + // OGCG: %[[DEST:.+]] = alloca %struct.Big, align 4 + // OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], ptr noundef %[[DEST]], i32 noundef 0) +} + +void scoped_load(struct Big *ptr) { + // CIR-LABEL: @scoped_load + // LLVM-LABEL: @scoped_load + // OGCG-LABEL: @scoped_load + + struct Big b; + __scoped_atomic_load(ptr, &b, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM); + // CIR: %[[DEST_SLOT:.+]] = cir.alloca "b" align(4) : !cir.ptr<!rec_Big> + // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big> + // CIR-NEXT: %[[PTR_INTPTR:.+]] = cir.cast bitcast %[[PTR]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[DEST_INTPTR:.+]] = cir.cast bitcast %[[DEST_SLOT]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i + // CIR-NEXT: %[[PTR_VOIDPTR:.+]] = cir.cast bitcast %[[PTR_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i + // CIR-NEXT: cir.call @__atomic_load(%[[SIZE]], %[[PTR_VOIDPTR]], %[[DEST_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> () + + // LLVM: %[[DEST:.+]] = alloca %struct.Big, i64 1, align 4 + // LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], ptr noundef %[[DEST]], i32 noundef 0) + + // OGCG: %[[DEST:.+]] = alloca %struct.Big, align 4 + // OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], ptr noundef %[[DEST]], i32 noundef 0) +} + +void c11_load(_Atomic(struct Big) *ptr) { + // CIR-LABEL: @c11_load + // LLVM-LABEL: @c11_load + // OGCG-LABEL: @c11_load + + struct Big b = __c11_atomic_load(ptr, __ATOMIC_RELAXED); + // CIR: %[[DEST_SLOT:.+]] = cir.alloca "b" align(4) init : !cir.ptr<!rec_Big> + // CIR-NEXT: %[[TEMP_SLOT:.+]] = cir.alloca "atomic-temp" align(4) : !cir.ptr<!rec_Big> + // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big> + // CIR-NEXT: %[[PTR_INTPTR:.+]] = cir.cast bitcast %[[PTR]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[TEMP_INTPTR:.+]] = cir.cast bitcast %[[TEMP_SLOT]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i + // CIR-NEXT: %[[PTR_VOIDPTR:.+]] = cir.cast bitcast %[[PTR_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[TEMP_VOIDPTR:.+]] = cir.cast bitcast %[[TEMP_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i + // CIR-NEXT: cir.call @__atomic_load(%[[SIZE]], %[[PTR_VOIDPTR]], %[[TEMP_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> () + // CIR-NEXT: %[[TEMP_CAST:.+]] = cir.cast bitcast %[[TEMP_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!rec_Big> + // CIR-NEXT: cir.copy %[[TEMP_CAST]] to %[[DEST_SLOT]] : !cir.ptr<!rec_Big> + + // LLVM: %[[DEST_SLOT:.+]] = alloca %struct.Big, i64 1, align 4 + // LLVM-NEXT: %[[TEMP_SLOT:.+]] = alloca %struct.Big, i64 1, align 4 + // LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], ptr noundef %[[TEMP_SLOT]], i32 noundef 0) + // LLVM-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr %[[DEST_SLOT]], ptr %[[TEMP_SLOT]], i64 24, i1 false) + + // OGCG: %[[DEST_SLOT:.+]] = alloca %struct.Big, align 4 + // OGCG-NEXT: %[[TEMP_SLOT:.+]] = alloca %struct.Big, align 4 + // OGCG: %[[PTR:.+]] = load ptr, ptr %ptr.addr, align 8 + // OGCG-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], ptr noundef %[[TEMP_SLOT]], i32 noundef 0) + // OGCG-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[DEST_SLOT]], ptr align 4 %[[TEMP_SLOT]], i64 24, i1 false) +} + +void store(struct Big *dest, struct Big *val) { + // CIR-LABEL: @store + // LLVM-LABEL: @store + // OGCG-LABEL: @store + + __atomic_store(dest, val, __ATOMIC_RELAXED); + // CIR: %[[DEST_PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big> + // CIR-NEXT: %[[VALUE_PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big> + // CIR-NEXT: %[[DEST_INTPTR:.+]] = cir.cast bitcast %[[DEST_PTR]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[VALUE_INTPTR:.+]] = cir.cast bitcast %[[VALUE_PTR]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i + // CIR-NEXT: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i + // CIR-NEXT: cir.call @__atomic_store(%[[SIZE]], %[[DEST_VOIDPTR]], %[[VALUE_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> () + + // LLVM: %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef %[[DEST]], ptr noundef %[[VALUE]], i32 noundef 0) + + // OGCG: %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef %[[DEST]], ptr noundef %[[VALUE]], i32 noundef 0) +} + +void scoped_store(struct Big *dest, struct Big *val) { + // CIR-LABEL: @scoped_store + // LLVM-LABEL: @scoped_store + // OGCG-LABEL: @scoped_store + + __scoped_atomic_store(dest, val, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM); + // CIR: %[[DEST_PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big> + // CIR-NEXT: %[[VALUE_PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big> + // CIR-NEXT: %[[DEST_INTPTR:.+]] = cir.cast bitcast %[[DEST_PTR]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[VALUE_INTPTR:.+]] = cir.cast bitcast %[[VALUE_PTR]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i + // CIR-NEXT: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i + // CIR-NEXT: cir.call @__atomic_store(%[[SIZE]], %[[DEST_VOIDPTR]], %[[VALUE_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> () + + // LLVM: %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef %[[DEST]], ptr noundef %[[VALUE]], i32 noundef 0) + + // OGCG: %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef %[[DEST]], ptr noundef %[[VALUE]], i32 noundef 0) +} + +void c11_store(_Atomic(struct Big) *dest, struct Big *val) { + // CIR-LABEL: @c11_store + // LLVM-LABEL: @c11_store + // OGCG-LABEL: @c11_store + + __c11_atomic_store(dest, *val, __ATOMIC_RELAXED); + // CIR: %[[DEST_PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big> + // CIR-NEXT: %[[VALUE_PTR:.+]] = cir.load deref align(8) %{{.+}} : !cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big> + // CIR-NEXT: cir.copy %[[VALUE_PTR]] to %[[TEMP_SLOT:.+]] : !cir.ptr<!rec_Big> + // CIR-NEXT: %[[DEST_INTPTR:.+]] = cir.cast bitcast %[[DEST_PTR]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[VALUE_INTPTR:.+]] = cir.cast bitcast %[[TEMP_SLOT]] : !cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>> + // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i + // CIR-NEXT: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void> + // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i + // CIR-NEXT: cir.call @__atomic_store(%[[SIZE]], %[[DEST_VOIDPTR]], %[[VALUE_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> () + + // LLVM: %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr %[[TEMP_SLOT:.+]], ptr %[[VALUE]], i64 24, i1 false) + // LLVM-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef %[[DEST]], ptr noundef %[[TEMP_SLOT]], i32 noundef 0) + + // OGCG: %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[TEMP_SLOT:.+]], ptr align 4 %[[VALUE]], i64 24, i1 false) + // OGCG-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef %[[DEST]], ptr noundef %[[TEMP_SLOT]], i32 noundef 0) +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
