llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangir

Author: Cyrus Ding (dingcyrus)

<details>
<summary>Changes</summary>

  Add CIR codegen support for five legacy __sync_* builtins that
  previously emitted "Not Yet Implemented" errors:

    __sync_val_compare_and_swap  -&gt;  cir.atomic.cmpxchg (seq_cst)
    __sync_bool_compare_and_swap -&gt;  cir.atomic.cmpxchg + cmp (seq_cst)
    __sync_swap                  -&gt;  cir.atomic.xchg (seq_cst)
    __sync_lock_test_and_set     -&gt;  cir.atomic.xchg (acquire)
    __sync_lock_release          -&gt;  cir.store 0 (release)

  Both unsuffixed and size-suffixed forms (_1, _2, _4, _8, _16) are
  handled, covering 30 builtin variants in total.

  The existing emitBinaryAtomic / emitBinaryAtomicPost infrastructure
  already handled the arithmetic __sync_* family (fetch_and_add, etc.).
  This patch adds the remaining compare-and-swap, exchange, and
  lock-release helpers: emitAtomicCmpXchgValue, emitAtomicCmpXchgBool,
  emitAtomicXchg, and emitAtomicLockRelease.

  Also fix a cosmetic issue in errorBuiltinNYI: the diagnostic
  hardcoded "X86" in the message even for target-independent builtins
  such as __sync_* compiled with --target=aarch64.  Replace
  "unimplemented X86 builtin call" with "unimplemented builtin call".

  AI assistance was used for code review analysis and local build verification. 

  Fixes #<!-- -->214445.

---
Full diff: https://github.com/llvm/llvm-project/pull/214606.diff


1 Files Affected:

- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+86-4) 


``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index afb13572df5bf..8d6484bbbb9ef 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -247,6 +247,72 @@ static RValue emitBinaryAtomicPost(CIRGenFunction &cgf,
   return RValue::get(result);
 }
 
+/// Emit a `cir.atomic.cmpxchg` for __sync_val_compare_and_swap_N.
+/// Returns the old value (type matches the pointee of ptr).
+static mlir::Value emitAtomicCmpXchgValue(CIRGenFunction &cgf,
+                                          const CallExpr *e,
+                                          cir::MemOrder succOrder,
+                                          cir::MemOrder failOrder) {
+  Address destAddr = checkAtomicAlignment(cgf, e);
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+  mlir::Value destValue = destAddr.emitRawPointer();
+  mlir::Value expected = cgf.emitScalarExpr(e->getArg(1));
+  mlir::Value desired = cgf.emitScalarExpr(e->getArg(2));
+
+  auto cmpxchg = cir::AtomicCmpXchgOp::create(
+      builder, cgf.getLoc(e->getSourceRange()), destValue, expected, desired,
+      succOrder, failOrder, cir::SyncScopeKind::System,
+      /*alignment=*/nullptr, /*weak=*/false, /*is_volatile=*/false);
+  return cmpxchg.getOld();
+}
+
+/// Emit a `cir.atomic.cmpxchg` for __sync_bool_compare_and_swap_N.
+/// Returns a boolean: true if the exchange succeeded (old == expected).
+static RValue emitAtomicCmpXchgBool(CIRGenFunction &cgf, const CallExpr *e) {
+  mlir::Value old = emitAtomicCmpXchgValue(cgf, e, 
cir::MemOrder::SequentiallyConsistent,
+                                           
cir::MemOrder::SequentiallyConsistent);
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+  // __sync_bool_compare_and_swap returns true on success.
+  // The classic llvm/cmpxchg produces {old, success}. We only have old here,
+  // so compare old == expected.
+  mlir::Value expected = cgf.emitScalarExpr(e->getArg(1));
+  mlir::Value cmp = builder.createCompare(
+      cgf.getLoc(e->getSourceRange()), cir::CmpOpKind::eq, old, expected);
+  mlir::Value result = builder.createIntCast(cmp, 
cgf.convertType(e->getType()));
+  return RValue::get(result);
+}
+
+/// Emit a `cir.atomic.xchg` for __sync_swap_N and __sync_lock_test_and_set_N.
+static mlir::Value emitAtomicXchg(CIRGenFunction &cgf, const CallExpr *e,
+                                  cir::MemOrder ordering) {
+  Address destAddr = checkAtomicAlignment(cgf, e);
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+  mlir::Value destValue = destAddr.emitRawPointer();
+  mlir::Value val = cgf.emitScalarExpr(e->getArg(1));
+
+  auto xchg = cir::AtomicXchgOp::create(
+      builder, cgf.getLoc(e->getSourceRange()), destValue, val, ordering,
+      cir::SyncScopeKind::System, /*is_volatile=*/false);
+  return xchg.getResult();
+}
+
+/// Emit a release store of 0 for __sync_lock_release_N.
+static void emitAtomicLockRelease(CIRGenFunction &cgf, const CallExpr *e) {
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+  Address destAddr = checkAtomicAlignment(cgf, e);
+  mlir::Location loc = cgf.getLoc(e->getSourceRange());
+  mlir::Type pointeeTy = destAddr.getType();
+  mlir::Value zero = builder.getConstant(
+      loc, cir::IntAttr::get(pointeeTy, 0));
+  auto orderAttr = cir::MemOrderAttr::get(
+      &cgf.getMLIRContext(), cir::MemOrder::Release);
+  auto scopeAttr = cir::SyncScopeKindAttr::get(
+      &cgf.getMLIRContext(), cir::SyncScopeKind::System);
+  builder.createStore(loc, zero, destAddr, /*isVolatile=*/false,
+                      /*isNontemporal=*/false,
+                      /*align=*/mlir::IntegerAttr{}, scopeAttr, orderAttr);
+}
+
 static void emitAtomicFenceOp(CIRGenFunction &cgf, const CallExpr *expr,
                               cir::SyncScopeKind syncScope) {
   CIRGenBuilderTy &builder = cgf.getBuilder();
@@ -432,11 +498,11 @@ static RValue errorBuiltinNYI(CIRGenFunction &cgf, const 
CallExpr *e,
   if (cgf.getContext().BuiltinInfo.isLibFunction(builtinID)) {
     cgf.cgm.errorNYI(
         e->getSourceRange(),
-        std::string("unimplemented X86 library function builtin call: ") +
+        std::string("unimplemented library function builtin call: ") +
             cgf.getContext().BuiltinInfo.getName(builtinID));
   } else {
     cgf.cgm.errorNYI(e->getSourceRange(),
-                     std::string("unimplemented X86 builtin call: ") +
+                     std::string("unimplemented builtin call: ") +
                          cgf.getContext().BuiltinInfo.getName(builtinID));
   }
 
@@ -2048,11 +2114,19 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
   case Builtin::BI__sync_xor_and_fetch:
   case Builtin::BI__sync_nand_and_fetch:
   case Builtin::BI__sync_val_compare_and_swap:
+    return RValue::get(emitAtomicCmpXchgValue(
+        *this, e, cir::MemOrder::SequentiallyConsistent,
+        cir::MemOrder::SequentiallyConsistent));
   case Builtin::BI__sync_bool_compare_and_swap:
+    return emitAtomicCmpXchgBool(*this, e);
   case Builtin::BI__sync_lock_test_and_set:
+    return RValue::get(emitAtomicXchg(*this, e, cir::MemOrder::Acquire));
   case Builtin::BI__sync_lock_release:
+    emitAtomicLockRelease(*this, e);
+    return RValue::get(nullptr);
   case Builtin::BI__sync_swap:
-    return errorBuiltinNYI(*this, e, builtinID);
+    return RValue::get(emitAtomicXchg(
+        *this, e, cir::MemOrder::SequentiallyConsistent));
   case Builtin::BI__sync_fetch_and_add_1:
   case Builtin::BI__sync_fetch_and_add_2:
   case Builtin::BI__sync_fetch_and_add_4:
@@ -2141,27 +2215,35 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
   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(emitAtomicCmpXchgValue(
+        *this, e, cir::MemOrder::SequentiallyConsistent,
+        cir::MemOrder::SequentiallyConsistent));
   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 emitAtomicCmpXchgBool(*this, e);
   case Builtin::BI__sync_swap_1:
   case Builtin::BI__sync_swap_2:
   case Builtin::BI__sync_swap_4:
   case Builtin::BI__sync_swap_8:
   case Builtin::BI__sync_swap_16:
+    return RValue::get(emitAtomicXchg(
+        *this, e, cir::MemOrder::SequentiallyConsistent));
   case Builtin::BI__sync_lock_test_and_set_1:
   case Builtin::BI__sync_lock_test_and_set_2:
   case Builtin::BI__sync_lock_test_and_set_4:
   case Builtin::BI__sync_lock_test_and_set_8:
   case Builtin::BI__sync_lock_test_and_set_16:
+    return RValue::get(emitAtomicXchg(*this, e, cir::MemOrder::Acquire));
   case Builtin::BI__sync_lock_release_1:
   case Builtin::BI__sync_lock_release_2:
   case Builtin::BI__sync_lock_release_4:
   case Builtin::BI__sync_lock_release_8:
   case Builtin::BI__sync_lock_release_16:
-    return errorBuiltinNYI(*this, e, builtinID);
+    emitAtomicLockRelease(*this, e);
+    return RValue::get(nullptr);
   case Builtin::BI__sync_synchronize: {
     // We assume this is supposed to correspond to a C++0x-style
     // sequentially-consistent fence (i.e. this is only usable for

``````````

</details>


https://github.com/llvm/llvm-project/pull/214606
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to