aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Analysis/BodyFarm.cpp120
1 files changed, 110 insertions, 10 deletions
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
index 217f607d56..c01d4e6fcb 100644
--- a/lib/Analysis/BodyFarm.cpp
+++ b/lib/Analysis/BodyFarm.cpp
@@ -22,6 +22,113 @@ using namespace clang;
typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
+static bool isDispatchBlock(QualType Ty) {
+ // Is it a block pointer?
+ const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
+ if (!BPT)
+ return false;
+
+ // Check if the block pointer type takes no arguments and
+ // returns void.
+ const FunctionProtoType *FT =
+ BPT->getPointeeType()->getAs<FunctionProtoType>();
+ if (!FT || !FT->getResultType()->isVoidType() ||
+ FT->getNumArgs() != 0)
+ return false;
+
+ return true;
+}
+
+/// Create a fake body for dispatch_once.
+static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
+ // Check if we have at least two parameters.
+ if (D->param_size() != 2)
+ return 0;
+
+ // Check if the first parameter is a pointer to integer type.
+ const ParmVarDecl *Predicate = D->getParamDecl(0);
+ QualType PredicateQPtrTy = Predicate->getType();
+ const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
+ if (!PredicatePtrTy)
+ return 0;
+ QualType PredicateTy = PredicatePtrTy->getPointeeType();
+ if (!PredicateTy->isIntegerType())
+ return 0;
+
+ // Check if the second parameter is the proper block type.
+ const ParmVarDecl *Block = D->getParamDecl(1);
+ QualType Ty = Block->getType();
+ if (!isDispatchBlock(Ty))
+ return 0;
+
+ // Everything checks out. Create a fakse body that checks the predicate,
+ // sets it, and calls the block. Basically, an AST dump of:
+ //
+ // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
+ // if (!*predicate) {
+ // *predicate = 1;
+ // block();
+ // }
+ // }
+
+ // (1) Create the call.
+ DeclRefExpr *DR = DeclRefExpr::CreateEmpty(C, false, false, false, false);
+ DR->setDecl(const_cast<ParmVarDecl*>(Block));
+ DR->setType(Ty);
+ DR->setValueKind(VK_LValue);
+ ImplicitCastExpr *ICE = ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
+ DR, 0, VK_RValue);
+ CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
+ VK_RValue, SourceLocation());
+
+ // (2) Create the assignment to the predicate.
+ IntegerLiteral *IL =
+ IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
+ C.IntTy, SourceLocation());
+ ICE = ImplicitCastExpr::Create(C, PredicateTy, CK_IntegralCast, IL, 0,
+ VK_RValue);
+ DR = DeclRefExpr::CreateEmpty(C, false, false, false, false);
+ DR->setDecl(const_cast<ParmVarDecl*>(Predicate));
+ DR->setType(PredicateQPtrTy);
+ DR->setValueKind(VK_LValue);
+ ImplicitCastExpr *LValToRval =
+ ImplicitCastExpr::Create(C, PredicateQPtrTy, CK_LValueToRValue, DR,
+ 0, VK_RValue);
+ UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_Deref, PredicateTy,
+ VK_LValue, OK_Ordinary,
+ SourceLocation());
+ BinaryOperator *B = new (C) BinaryOperator(UO, ICE, BO_Assign,
+ PredicateTy, VK_RValue,
+ OK_Ordinary,
+ SourceLocation());
+ // (3) Create the compound statement.
+ Stmt *Stmts[2];
+ Stmts[0] = B;
+ Stmts[1] = CE;
+ CompoundStmt *CS = new (C) CompoundStmt(C, Stmts, 2, SourceLocation(),
+ SourceLocation());
+
+ // (4) Create the 'if' condition.
+ DR = DeclRefExpr::CreateEmpty(C, false, false, false, false);
+ DR->setDecl(const_cast<ParmVarDecl*>(Predicate));
+ DR->setType(PredicateQPtrTy);
+ DR->setValueKind(VK_LValue);
+ LValToRval = ImplicitCastExpr::Create(C, PredicateQPtrTy, CK_LValueToRValue,
+ DR, 0, VK_RValue);
+ UO = new (C) UnaryOperator(LValToRval, UO_Deref, PredicateTy,
+ VK_LValue, OK_Ordinary,
+ SourceLocation());
+ LValToRval = ImplicitCastExpr::Create(C, PredicateTy, CK_LValueToRValue,
+ UO, 0, VK_RValue);
+ UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
+ VK_RValue, OK_Ordinary, SourceLocation());
+
+ // (5) Create the 'if' statement.
+ IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
+ return If;
+}
+
+
/// Create a fake body for dispatch_sync.
static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
@@ -32,16 +139,7 @@ static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
// Check if the second parameter is a block.
const ParmVarDecl *PV = D->getParamDecl(1);
QualType Ty = PV->getType();
- const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
- if (!BPT)
- return 0;
-
- // Check if the block pointer type takes no arguments and
- // returns void.
- const FunctionProtoType *FT =
- BPT->getPointeeType()->getAs<FunctionProtoType>();
- if (!FT || !FT->getResultType()->isVoidType() ||
- FT->getNumArgs() != 0)
+ if (!isDispatchBlock(Ty))
return 0;
// Everything checks out. Create a fake body that just calls the block.
@@ -53,6 +151,7 @@ static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
//
DeclRefExpr *DR = DeclRefExpr::CreateEmpty(C, false, false, false, false);
DR->setDecl(const_cast<ParmVarDecl*>(PV));
+ DR->setType(Ty);
DR->setValueKind(VK_LValue);
ImplicitCastExpr *ICE = ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
DR, 0, VK_RValue);
@@ -80,6 +179,7 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
FunctionFarmer FF =
llvm::StringSwitch<FunctionFarmer>(Name)
.Case("dispatch_sync", create_dispatch_sync)
+ .Case("dispatch_once", create_dispatch_once)
.Default(NULL);
if (FF) {