aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
authorEli Friedman <eli.friedman@gmail.com>2011-10-11 02:20:01 +0000
committerEli Friedman <eli.friedman@gmail.com>2011-10-11 02:20:01 +0000
commit276b061970939293f1abaf694bd3ef05b2cbda79 (patch)
tree95ac74efe0dda24d43635e5d034868d1379b6752 /lib/Sema/SemaChecking.cpp
parentf11dbe9676832e599e046b2ed0f132a6bb858e0a (diff)
Initial implementation of __atomic_* (everything except __atomic_is_lock_free).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141632 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaChecking.cpp')
-rw-r--r--lib/Sema/SemaChecking.cpp170
1 files changed, 170 insertions, 0 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 412ed0ebb5..a9d79bb70a 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -15,6 +15,7 @@
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/AST/ASTContext.h"
@@ -197,6 +198,28 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__sync_lock_release:
case Builtin::BI__sync_swap:
return SemaBuiltinAtomicOverloaded(move(TheCallResult));
+ case Builtin::BI__atomic_load:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Load);
+ case Builtin::BI__atomic_store:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Store);
+ case Builtin::BI__atomic_exchange:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xchg);
+ case Builtin::BI__atomic_compare_exchange_strong:
+ return SemaAtomicOpsOverloaded(move(TheCallResult),
+ AtomicExpr::CmpXchgStrong);
+ case Builtin::BI__atomic_compare_exchange_weak:
+ return SemaAtomicOpsOverloaded(move(TheCallResult),
+ AtomicExpr::CmpXchgWeak);
+ case Builtin::BI__atomic_fetch_add:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Add);
+ case Builtin::BI__atomic_fetch_sub:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Sub);
+ case Builtin::BI__atomic_fetch_and:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::And);
+ case Builtin::BI__atomic_fetch_or:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Or);
+ case Builtin::BI__atomic_fetch_xor:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xor);
case Builtin::BI__builtin_annotation:
if (CheckBuiltinAnnotationString(*this, TheCall->getArg(1)))
return ExprError();
@@ -414,6 +437,153 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
return false;
}
+ExprResult
+Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) {
+ CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
+ DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+ Expr *Ptr, *Order, *Val1, *Val2, *OrderFail;
+
+ // All these operations take one of the following four forms:
+ // T __atomic_load(_Atomic(T)*, int) (loads)
+ // T* __atomic_add(_Atomic(T*)*, ptrdiff_t, int) (pointer add/sub)
+ // int __atomic_compare_exchange_strong(_Atomic(T)*, T*, T, int, int)
+ // (cmpxchg)
+ // T __atomic_exchange(_Atomic(T)*, T, int) (everything else)
+ // where T is an appropriate type, and the int paremeterss are for orderings.
+ unsigned NumVals = 1;
+ unsigned NumOrders = 1;
+ if (Op == AtomicExpr::Load) {
+ NumVals = 0;
+ } else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong) {
+ NumVals = 2;
+ NumOrders = 2;
+ }
+
+ if (TheCall->getNumArgs() < NumVals+NumOrders+1) {
+ Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
+ return ExprError();
+ } else if (TheCall->getNumArgs() > NumVals+NumOrders+1) {
+ Diag(TheCall->getArg(NumVals+NumOrders+1)->getLocStart(),
+ diag::err_typecheck_call_too_many_args)
+ << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
+ return ExprError();
+ }
+
+ // Inspect the first argument of the atomic operation. This should always be
+ // a pointer to an _Atomic type.
+ Ptr = TheCall->getArg(0);
+ Ptr = DefaultFunctionArrayLvalueConversion(Ptr).get();
+ const PointerType *pointerType = Ptr->getType()->getAs<PointerType>();
+ if (!pointerType) {
+ Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ QualType AtomTy = pointerType->getPointeeType();
+ if (!AtomTy->isAtomicType()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+ QualType ValType = AtomTy->getAs<AtomicType>()->getValueType();
+
+ if ((Op == AtomicExpr::Add || Op == AtomicExpr::Sub) &&
+ !ValType->isIntegerType() && !ValType->isPointerType()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ if (!ValType->isIntegerType() &&
+ (Op == AtomicExpr::And || Op == AtomicExpr::Or || Op == AtomicExpr::Xor)){
+ Diag(DRE->getLocStart(), diag::err_atomic_op_logical_needs_atomic_int)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ switch (ValType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ // okay
+ break;
+
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Autoreleasing:
+ Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership)
+ << ValType << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ QualType ResultType = ValType;
+ if (Op == AtomicExpr::Store)
+ ResultType = Context.VoidTy;
+ else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong)
+ ResultType = Context.BoolTy;
+
+ // The first argument --- the pointer --- has a fixed type; we
+ // deduce the types of the rest of the arguments accordingly. Walk
+ // the remaining arguments, converting them to the deduced value type.
+ for (unsigned i = 1; i != NumVals+NumOrders+1; ++i) {
+ ExprResult Arg = TheCall->getArg(i);
+ QualType Ty;
+ if (i < NumVals+1) {
+ // The second argument to a cmpxchg is a pointer to the data which will
+ // be exchanged. The second argument to a pointer add/subtract is the
+ // amount to add/subtract, which must be a ptrdiff_t. The third
+ // argument to a cmpxchg and the second argument in all other cases
+ // is the type of the value.
+ if (i == 1 && (Op == AtomicExpr::CmpXchgWeak ||
+ Op == AtomicExpr::CmpXchgStrong))
+ Ty = Context.getPointerType(ValType.getUnqualifiedType());
+ else if (!ValType->isIntegerType() &&
+ (Op == AtomicExpr::Add || Op == AtomicExpr::Sub))
+ Ty = Context.getPointerDiffType();
+ else
+ Ty = ValType;
+ } else {
+ // The order(s) are always converted to int.
+ Ty = Context.IntTy;
+ }
+ InitializedEntity Entity =
+ InitializedEntity::InitializeParameter(Context, Ty, false);
+ Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
+ if (Arg.isInvalid())
+ return true;
+ TheCall->setArg(i, Arg.get());
+ }
+
+ if (Op == AtomicExpr::Load) {
+ Order = TheCall->getArg(1);
+ return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
+ Ptr, Order, ResultType, Op,
+ TheCall->getRParenLoc(), false,
+ false));
+ } else if (Op != AtomicExpr::CmpXchgWeak && Op != AtomicExpr::CmpXchgStrong) {
+ Val1 = TheCall->getArg(1);
+ Order = TheCall->getArg(2);
+ return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
+ Ptr, Val1, Order, ResultType, Op,
+ TheCall->getRParenLoc(), false,
+ false));
+ } else {
+ Val1 = TheCall->getArg(1);
+ Val2 = TheCall->getArg(2);
+ Order = TheCall->getArg(3);
+ OrderFail = TheCall->getArg(4);
+ return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
+ Ptr, Val1, Val2, Order, OrderFail,
+ ResultType, Op,
+ TheCall->getRParenLoc(), false,
+ false));
+ }
+}
+
+
/// checkBuiltinArgument - Given a call to a builtin function, perform
/// normal type-checking on the given argument, updating the call in
/// place. This is useful when a builtin function requires custom