saiislam created this revision.
saiislam added reviewers: JonChesterfield, sameerds, yaxunl, gregrodgers, 
b-sumner.
Herald added subscribers: cfe-commits, jfb.
Herald added a project: clang.

"__buitlin_memory_fence(<ordering>, <target-scope>)" in clang gets
mapped to "fence [syncscope("<target-scope>")] <ordering>; yields void"
in IR.


Repository:
  rC Clang

https://reviews.llvm.org/D75917

Files:
  clang/include/clang/Basic/Builtins.def
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/lib/Sema/SemaChecking.cpp
  clang/test/CodeGenOpenCL/atomic-ops.cl
  clang/test/SemaOpenCL/atomic-ops.cl

Index: clang/test/SemaOpenCL/atomic-ops.cl
===================================================================
--- clang/test/SemaOpenCL/atomic-ops.cl
+++ clang/test/SemaOpenCL/atomic-ops.cl
@@ -194,3 +194,21 @@
   // The 'expected' pointer shouldn't be NULL.
   (void)__opencl_atomic_compare_exchange_strong(Ap, (void *)0, val, memory_order_relaxed, memory_order_relaxed, memory_scope_work_group); // expected-warning {{null passed to a callee that requires a non-null argument}}
 }
+
+void memory_fence_errors() {
+  __builtin_memory_fence(memory_order_seq_cst + 1, memory_scope_work_group); // expected-error {{memory order argument to fence operation is invalid}}
+
+  __builtin_memory_fence(memory_order_seq_cst, memory_scope_sub_group + 1); // expected-error {{synchronization scope argument to fence operation is invalid}}
+
+  __builtin_memory_fence(memory_scope_work_group); // expected-error {{too few arguments to function call, expected 2}}
+
+  __builtin_memory_fence(2, 2, 2); // expected-error {{too many arguments to function call, expected 2}}
+
+  __builtin_memory_fence("string", memory_scope_work_group); // expected-error {{used type '__constant char [7]' where unsigned is required}}
+
+  __builtin_memory_fence(3.14, memory_scope_work_group); // expected-error {{used type 'double' where unsigned is required}}
+
+  __builtin_memory_fence(memory_order_seq_cst, "string"); // expected-error {{used type '__constant char [7]' where unsigned is required}}
+
+  __builtin_memory_fence(memory_order_seq_cst, 3.14); // expected-error {{used type 'double' where unsigned is required}}
+}
Index: clang/test/CodeGenOpenCL/atomic-ops.cl
===================================================================
--- clang/test/CodeGenOpenCL/atomic-ops.cl
+++ clang/test/CodeGenOpenCL/atomic-ops.cl
@@ -288,4 +288,44 @@
   return __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group);
 }
 
+void test_memory_fence() {
+  // CHECK-LABEL: @test_memory_fence
+
+  // CHECK: fence syncscope("workgroup-one-as") acquire
+  __builtin_memory_fence(memory_order_acquire, memory_scope_work_group);
+
+  // CHECK: fence syncscope("agent-one-as") acquire
+  __builtin_memory_fence(memory_order_acquire, memory_scope_device);
+
+  // CHECK: fence syncscope("one-as") acquire
+  __builtin_memory_fence(memory_order_acquire, memory_scope_all_svm_devices);
+
+  // CHECK: fence syncscope("wavefront-one-as") acquire
+  __builtin_memory_fence(memory_order_acquire, memory_scope_sub_group);
+
+  // CHECK: fence syncscope("workgroup-one-as") release
+  __builtin_memory_fence(memory_order_release,  memory_scope_work_group);
+
+  // CHECK: fence syncscope("agent-one-as") release
+  __builtin_memory_fence(memory_order_release, memory_scope_device);
+
+  // CHECK: fence syncscope("one-as") release
+  __builtin_memory_fence(memory_order_release, memory_scope_all_svm_devices);
+
+  // CHECK: fence syncscope("wavefront-one-as") release
+  __builtin_memory_fence(memory_order_release, memory_scope_sub_group);
+
+  // CHECK: fence syncscope("workgroup") seq_cst
+  __builtin_memory_fence(memory_order_seq_cst,  memory_scope_work_group);
+
+  // CHECK: fence syncscope("agent") seq_cst
+  __builtin_memory_fence(memory_order_seq_cst, memory_scope_device);
+
+  // CHECK: fence seq_cst
+  __builtin_memory_fence(memory_order_seq_cst, memory_scope_all_svm_devices);
+
+  // CHECK: fence syncscope("wavefront") seq_cst
+  __builtin_memory_fence(memory_order_seq_cst, memory_scope_sub_group);
+}
+
 #endif
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -1865,6 +1865,60 @@
                   : "__builtin_frame_address")
           << TheCall->getSourceRange();
     break;
+
+  // Clang builtins to expose llvm fence instruction
+  case Builtin::BI__builtin_memory_fence: {
+    if (checkArgCount(*this, TheCall, 2))
+      return true;
+
+    // Order should be the first argument
+    ExprResult Arg = TheCall->getArg(0);
+    auto ArgExpr = Arg.get();
+    auto Ty = ArgExpr->getType();
+
+    // Check if Order is an unsigned
+    if (!Ty->isIntegerType()) {
+      Diag(ArgExpr->getExprLoc(), diag::err_typecheck_expect_uint) << Ty;
+      return ExprError();
+    }
+
+    Expr::EvalResult ArgResult;
+    ArgExpr->EvaluateAsInt(ArgResult, Context);
+    int ord = ArgResult.Val.getInt().getZExtValue();
+
+    // Check if Order is one of the valid types
+    if (!llvm::isValidAtomicOrderingCABI(ord)) {
+      Diag(ArgExpr->getBeginLoc(),
+           diag::err_memory_fence_has_invalid_memory_order)
+          << ArgExpr->getSourceRange();
+      return ExprError();
+    }
+
+    // Sync scope should be the second argument
+    Arg = TheCall->getArg(1);
+    ArgExpr = Arg.get();
+    Ty = ArgExpr->getType();
+
+    // Check if SyncScope is an unsgined
+    if (!Ty->isIntegerType()) {
+      Diag(ArgExpr->getExprLoc(), diag::err_typecheck_expect_uint) << Ty;
+      return ExprError();
+    }
+
+    ArgExpr->EvaluateAsInt(ArgResult, Context);
+    int scp = ArgResult.Val.getInt().getZExtValue();
+    auto SM = AtomicScopeModel::create(AtomicScopeModelKind::OpenCL);
+    AtomicScopeModel *ScopeModel = SM.get();
+
+    // Check if Scope is one of the valid types
+    if (!ScopeModel->isValid(scp)) {
+      Diag(ArgExpr->getBeginLoc(),
+           diag::err_memory_fence_has_invalid_synch_scope)
+          << ArgExpr->getSourceRange();
+      return ExprError();
+    }
+    break;
+  }
   }
 
   // Since the target specific builtins for each arch overlap, only check those
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -3698,6 +3698,42 @@
   case Builtin::BI__builtin_coro_param:
     return EmitCoroutineIntrinsic(E, Intrinsic::coro_param);
 
+  // Clang builtins to expose llvm fence instruction
+  case Builtin::BI__builtin_memory_fence: {
+    llvm::AtomicOrdering AO;
+    llvm::SyncScope::ID SSID;
+    Value *Order = EmitScalarExpr(E->getArg(0));
+    Value *Scope = EmitScalarExpr(E->getArg(1));
+    auto ScopeModel = AtomicScopeModel::create(AtomicScopeModelKind::OpenCL);
+
+    if ( isa<llvm::ConstantInt>(Order) && isa<llvm::ConstantInt>(Scope) ) {
+      int scp = cast<llvm::ConstantInt>(Scope)->getZExtValue();
+      int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
+      switch (ord) {
+      case 0:  // memory_order_relaxed
+      default: // invalid order
+        break;
+      case 1:  // memory_order_consume
+      case 2:  // memory_order_acquire
+        AO = llvm::AtomicOrdering::Acquire;
+        break;
+      case 3:  // memory_order_release
+        AO = llvm::AtomicOrdering::Release;
+        break;
+      case 4:  // memory_order_acq_rel
+        AO = llvm::AtomicOrdering::AcquireRelease;
+        break;
+      case 5:  // memory_order_seq_cst
+        AO = llvm::AtomicOrdering::SequentiallyConsistent;
+        break;
+      }
+      SSID = getTargetHooks().getLLVMSyncScopeID(getLangOpts(), ScopeModel->map(scp), AO, getLLVMContext());
+      Builder.CreateFence(AO, SSID);
+      return RValue::get(nullptr);
+    }
+    LLVM_FALLTHROUGH;
+  }
+
   // OpenCL v2.0 s6.13.16.2, Built-in pipe read and write functions
   case Builtin::BIread_pipe:
   case Builtin::BIwrite_pipe: {
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6225,6 +6225,8 @@
   "cannot %select{decrement|increment}1 value of type %0">;
 def err_typecheck_expect_int : Error<
   "used type %0 where integer is required">;
+def err_typecheck_expect_uint : Error<
+  "used type %0 where unsigned is required">;
 def err_typecheck_arithmetic_incomplete_type : Error<
   "arithmetic on a pointer to an incomplete type %0">;
 def err_typecheck_pointer_arith_function_type : Error<
@@ -7855,6 +7857,10 @@
   InGroup<DiagGroup<"atomic-memory-ordering">>;
 def err_atomic_op_has_invalid_synch_scope : Error<
   "synchronization scope argument to atomic operation is invalid">;
+def err_memory_fence_has_invalid_memory_order : Error<
+  "memory order argument to fence operation is invalid">;
+def err_memory_fence_has_invalid_synch_scope : Error<
+  "synchronization scope argument to fence operation is invalid">;
 def warn_atomic_implicit_seq_cst : Warning<
   "implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary">,
   InGroup<DiagGroup<"atomic-implicit-seq-cst">>, DefaultIgnore;
Index: clang/include/clang/Basic/Builtins.def
===================================================================
--- clang/include/clang/Basic/Builtins.def
+++ clang/include/clang/Basic/Builtins.def
@@ -1513,6 +1513,9 @@
 BUILTIN(__builtin_coro_suspend, "cIb", "n")
 BUILTIN(__builtin_coro_param, "bv*v*", "n")
 
+// Builtin to expose llvm fence instruction
+BUILTIN(__builtin_memory_fence, "vUiUi", "t")
+
 // OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
 // We need the generic prototype, since the packet type could be anything.
 LANGBUILTIN(read_pipe, "i.", "tn", OCLC20_LANG)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to