diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Analysis/BodyFarm.cpp | 120 |
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) { |