Skip to content

Commit 84162ac

Browse files
committed
Add OpenCL 2.0 atomic builtin functions as Clang builtin
OpenCL 2.0 atomic builtin functions have a scope argument which is ideally represented as synchronization scope argument in LLVM atomic instructions. Clang supports translating Clang atomic builtin functions to LLVM atomic instructions. However it currently does not support synchronization scope of LLVM atomic instructions. Without this, users have to use LLVM assembly code to implement OpenCL atomic builtin functions. This patch adds OpenCL 2.0 atomic builtin functions as Clang builtin functions, which supports generating LLVM atomic instructions with synchronization scope operand. Currently only constant memory scope argument is supported. Support of non-constant memory scope argument will be added later. Differential Revision: https://reviews.llvm.org/D28691 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@310082 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 7777ca0 commit 84162ac

21 files changed

+804
-81
lines changed

docs/LanguageExtensions.rst

+7-1
Original file line numberDiff line numberDiff line change
@@ -1929,7 +1929,13 @@ provided, with values corresponding to the enumerators of C11's
19291929
``memory_order`` enumeration.
19301930
19311931
(Note that Clang additionally provides GCC-compatible ``__atomic_*``
1932-
builtins)
1932+
builtins and OpenCL 2.0 ``__opencl_atomic_*`` builtins. The OpenCL 2.0
1933+
atomic builtins are an explicit form of the corresponding OpenCL 2.0
1934+
builtin function, and are named with a ``__opencl_`` prefix. The macros
1935+
``__OPENCL_MEMORY_SCOPE_WORK_ITEM``, ``__OPENCL_MEMORY_SCOPE_WORK_GROUP``,
1936+
``__OPENCL_MEMORY_SCOPE_DEVICE``, ``__OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES``,
1937+
and ``__OPENCL_MEMORY_SCOPE_SUB_GROUP`` are provided, with values
1938+
corresponding to the enumerators of OpenCL's ``memory_scope`` enumeration.)
19331939
19341940
Low-level ARM exclusive memory builtins
19351941
---------------------------------------

include/clang/AST/Expr.h

+18-5
Original file line numberDiff line numberDiff line change
@@ -5064,9 +5064,11 @@ class PseudoObjectExpr final
50645064

50655065
/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
50665066
/// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the
5067-
/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>.
5068-
/// All of these instructions take one primary pointer and at least one memory
5069-
/// order.
5067+
/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>,
5068+
/// and corresponding __opencl_atomic_* for OpenCL 2.0.
5069+
/// All of these instructions take one primary pointer, at least one memory
5070+
/// order, and one synchronization scope. The C++11 and __c11 atomic AtomicExpr
5071+
/// always take the default synchronization scope.
50705072
class AtomicExpr : public Expr {
50715073
public:
50725074
enum AtomicOp {
@@ -5078,7 +5080,7 @@ class AtomicExpr : public Expr {
50785080
};
50795081

50805082
private:
5081-
enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, WEAK, END_EXPR };
5083+
enum { PTR, ORDER, SCOPE, VAL1, ORDER_FAIL, VAL2, WEAK, END_EXPR };
50825084
Stmt* SubExprs[END_EXPR];
50835085
unsigned NumSubExprs;
50845086
SourceLocation BuiltinLoc, RParenLoc;
@@ -5103,8 +5105,11 @@ class AtomicExpr : public Expr {
51035105
Expr *getOrder() const {
51045106
return cast<Expr>(SubExprs[ORDER]);
51055107
}
5108+
Expr *getScope() const {
5109+
return cast<Expr>(SubExprs[SCOPE]);
5110+
}
51065111
Expr *getVal1() const {
5107-
if (Op == AO__c11_atomic_init)
5112+
if (Op == AO__c11_atomic_init || Op == AO__opencl_atomic_init)
51085113
return cast<Expr>(SubExprs[ORDER]);
51095114
assert(NumSubExprs > VAL1);
51105115
return cast<Expr>(SubExprs[VAL1]);
@@ -5123,6 +5128,7 @@ class AtomicExpr : public Expr {
51235128
assert(NumSubExprs > WEAK);
51245129
return cast<Expr>(SubExprs[WEAK]);
51255130
}
5131+
QualType getValueType() const;
51265132

51275133
AtomicOp getOp() const { return Op; }
51285134
unsigned getNumSubExprs() const { return NumSubExprs; }
@@ -5139,10 +5145,17 @@ class AtomicExpr : public Expr {
51395145
bool isCmpXChg() const {
51405146
return getOp() == AO__c11_atomic_compare_exchange_strong ||
51415147
getOp() == AO__c11_atomic_compare_exchange_weak ||
5148+
getOp() == AO__opencl_atomic_compare_exchange_strong ||
5149+
getOp() == AO__opencl_atomic_compare_exchange_weak ||
51425150
getOp() == AO__atomic_compare_exchange ||
51435151
getOp() == AO__atomic_compare_exchange_n;
51445152
}
51455153

5154+
bool isOpenCL() const {
5155+
return getOp() >= AO__opencl_atomic_init &&
5156+
getOp() <= AO__opencl_atomic_fetch_max;
5157+
}
5158+
51465159
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
51475160
SourceLocation getRParenLoc() const { return RParenLoc; }
51485161

include/clang/Basic/Builtins.def

+15
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,21 @@ BUILTIN(__atomic_signal_fence, "vi", "n")
700700
BUILTIN(__atomic_always_lock_free, "izvCD*", "n")
701701
BUILTIN(__atomic_is_lock_free, "izvCD*", "n")
702702

703+
// OpenCL 2.0 atomic builtins.
704+
ATOMIC_BUILTIN(__opencl_atomic_init, "v.", "t")
705+
ATOMIC_BUILTIN(__opencl_atomic_load, "v.", "t")
706+
ATOMIC_BUILTIN(__opencl_atomic_store, "v.", "t")
707+
ATOMIC_BUILTIN(__opencl_atomic_exchange, "v.", "t")
708+
ATOMIC_BUILTIN(__opencl_atomic_compare_exchange_strong, "v.", "t")
709+
ATOMIC_BUILTIN(__opencl_atomic_compare_exchange_weak, "v.", "t")
710+
ATOMIC_BUILTIN(__opencl_atomic_fetch_add, "v.", "t")
711+
ATOMIC_BUILTIN(__opencl_atomic_fetch_sub, "v.", "t")
712+
ATOMIC_BUILTIN(__opencl_atomic_fetch_and, "v.", "t")
713+
ATOMIC_BUILTIN(__opencl_atomic_fetch_or, "v.", "t")
714+
ATOMIC_BUILTIN(__opencl_atomic_fetch_xor, "v.", "t")
715+
ATOMIC_BUILTIN(__opencl_atomic_fetch_min, "v.", "t")
716+
ATOMIC_BUILTIN(__opencl_atomic_fetch_max, "v.", "t")
717+
703718
#undef ATOMIC_BUILTIN
704719

705720
// Non-overloaded atomic builtins.

include/clang/Basic/DiagnosticSemaKinds.td

+6-2
Original file line numberDiff line numberDiff line change
@@ -6995,8 +6995,8 @@ def err_atomic_op_needs_atomic : Error<
69956995
"address argument to atomic operation must be a pointer to _Atomic "
69966996
"type (%0 invalid)">;
69976997
def err_atomic_op_needs_non_const_atomic : Error<
6998-
"address argument to atomic operation must be a pointer to non-const _Atomic "
6999-
"type (%0 invalid)">;
6998+
"address argument to atomic operation must be a pointer to non-%select{const|constant}0 _Atomic "
6999+
"type (%1 invalid)">;
70007000
def err_atomic_op_needs_non_const_pointer : Error<
70017001
"address argument to atomic operation must be a pointer to non-const "
70027002
"type (%0 invalid)">;
@@ -7012,6 +7012,10 @@ def err_atomic_op_bitwise_needs_atomic_int : Error<
70127012
def warn_atomic_op_has_invalid_memory_order : Warning<
70137013
"memory order argument to atomic operation is invalid">,
70147014
InGroup<DiagGroup<"atomic-memory-ordering">>;
7015+
def err_atomic_op_has_invalid_synch_scope : Error<
7016+
"synchronization scope argument to atomic operation is invalid">;
7017+
def err_atomic_op_has_non_constant_synch_scope : Error<
7018+
"non-constant synchronization scope argument to atomic operation is not supported">;
70157019

70167020
def err_overflow_builtin_must_be_int : Error<
70177021
"operand argument to overflow builtin must be an integer (%0 invalid)">;

include/clang/Basic/SyncScope.h

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===--- SyncScope.h - Atomic synchronization scopes ------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
///
10+
/// \file
11+
/// \brief Provides definitions for the atomic synchronization scopes.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_CLANG_BASIC_SYNCSCOPE_H
16+
#define LLVM_CLANG_BASIC_SYNCSCOPE_H
17+
18+
namespace clang {
19+
20+
/// \brief Defines the synch scope values used by the atomic builtins and
21+
/// expressions.
22+
///
23+
/// The enum values should match the pre-defined macros
24+
/// __OPENCL_MEMORY_SCOPE_*, which are used to define memory_scope_*
25+
/// enums in opencl-c.h.
26+
enum class SyncScope {
27+
OpenCLWorkGroup = 1,
28+
OpenCLDevice = 2,
29+
OpenCLAllSVMDevices = 3,
30+
OpenCLSubGroup = 4,
31+
};
32+
33+
inline bool isValidSyncScopeValue(unsigned Scope) {
34+
return Scope >= static_cast<unsigned>(SyncScope::OpenCLWorkGroup) &&
35+
Scope <= static_cast<unsigned>(SyncScope::OpenCLSubGroup);
36+
}
37+
}
38+
39+
#endif

lib/AST/ASTContext.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -1182,7 +1182,14 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
11821182
ObjCSuperType = QualType();
11831183

11841184
// void * type
1185-
VoidPtrTy = getPointerType(VoidTy);
1185+
if (LangOpts.OpenCLVersion >= 200) {
1186+
auto Q = VoidTy.getQualifiers();
1187+
Q.setAddressSpace(LangAS::opencl_generic);
1188+
VoidPtrTy = getPointerType(getCanonicalType(
1189+
getQualifiedType(VoidTy.getUnqualifiedType(), Q)));
1190+
} else {
1191+
VoidPtrTy = getPointerType(VoidTy);
1192+
}
11861193

11871194
// nullptr type (C++0x 2.14.7)
11881195
InitBuiltinType(NullPtrTy, BuiltinType::NullPtr);

lib/AST/Expr.cpp

+26-5
Original file line numberDiff line numberDiff line change
@@ -3938,12 +3938,17 @@ AtomicExpr::AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args,
39383938
unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
39393939
switch (Op) {
39403940
case AO__c11_atomic_init:
3941+
case AO__opencl_atomic_init:
3942+
return 2;
39413943
case AO__c11_atomic_load:
3944+
case AO__opencl_atomic_load:
39423945
case AO__atomic_load_n:
3943-
return 2;
3946+
return 3;
39443947

39453948
case AO__c11_atomic_store:
39463949
case AO__c11_atomic_exchange:
3950+
case AO__opencl_atomic_store:
3951+
case AO__opencl_atomic_exchange:
39473952
case AO__atomic_load:
39483953
case AO__atomic_store:
39493954
case AO__atomic_store_n:
@@ -3953,6 +3958,13 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
39533958
case AO__c11_atomic_fetch_and:
39543959
case AO__c11_atomic_fetch_or:
39553960
case AO__c11_atomic_fetch_xor:
3961+
case AO__opencl_atomic_fetch_add:
3962+
case AO__opencl_atomic_fetch_sub:
3963+
case AO__opencl_atomic_fetch_and:
3964+
case AO__opencl_atomic_fetch_or:
3965+
case AO__opencl_atomic_fetch_xor:
3966+
case AO__opencl_atomic_fetch_min:
3967+
case AO__opencl_atomic_fetch_max:
39563968
case AO__atomic_fetch_add:
39573969
case AO__atomic_fetch_sub:
39583970
case AO__atomic_fetch_and:
@@ -3965,22 +3977,31 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
39653977
case AO__atomic_or_fetch:
39663978
case AO__atomic_xor_fetch:
39673979
case AO__atomic_nand_fetch:
3968-
return 3;
3980+
return 4;
39693981

39703982
case AO__atomic_exchange:
3971-
return 4;
3983+
return 5;
39723984

39733985
case AO__c11_atomic_compare_exchange_strong:
39743986
case AO__c11_atomic_compare_exchange_weak:
3975-
return 5;
3987+
case AO__opencl_atomic_compare_exchange_strong:
3988+
case AO__opencl_atomic_compare_exchange_weak:
3989+
return 6;
39763990

39773991
case AO__atomic_compare_exchange:
39783992
case AO__atomic_compare_exchange_n:
3979-
return 6;
3993+
return 7;
39803994
}
39813995
llvm_unreachable("unknown atomic op");
39823996
}
39833997

3998+
QualType AtomicExpr::getValueType() const {
3999+
auto T = getPtr()->getType()->castAs<PointerType>()->getPointeeType();
4000+
if (auto AT = T->getAs<AtomicType>())
4001+
return AT->getValueType();
4002+
return T;
4003+
}
4004+
39844005
QualType OMPArraySectionExpr::getBaseOriginalType(const Expr *Base) {
39854006
unsigned ArraySectionCount = 0;
39864007
while (auto *OASE = dyn_cast<OMPArraySectionExpr>(Base->IgnoreParens())) {

lib/AST/StmtPrinter.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -1891,7 +1891,8 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
18911891
// AtomicExpr stores its subexpressions in a permuted order.
18921892
PrintExpr(Node->getPtr());
18931893
if (Node->getOp() != AtomicExpr::AO__c11_atomic_load &&
1894-
Node->getOp() != AtomicExpr::AO__atomic_load_n) {
1894+
Node->getOp() != AtomicExpr::AO__atomic_load_n &&
1895+
Node->getOp() != AtomicExpr::AO__opencl_atomic_load) {
18951896
OS << ", ";
18961897
PrintExpr(Node->getVal1());
18971898
}
@@ -1905,7 +1906,8 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
19051906
OS << ", ";
19061907
PrintExpr(Node->getWeak());
19071908
}
1908-
if (Node->getOp() != AtomicExpr::AO__c11_atomic_init) {
1909+
if (Node->getOp() != AtomicExpr::AO__c11_atomic_init &&
1910+
Node->getOp() != AtomicExpr::AO__opencl_atomic_init) {
19091911
OS << ", ";
19101912
PrintExpr(Node->getOrder());
19111913
}

lib/Basic/Targets/AMDGPU.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple,
328328
PtrDiffType = SignedLong;
329329
IntPtrType = SignedLong;
330330
}
331+
332+
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
331333
}
332334

333335
void AMDGPUTargetInfo::adjust(LangOptions &Opts) {

0 commit comments

Comments
 (0)