diff options
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 58ae3acf498..60a2e505d88 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -258,6 +258,192 @@ static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, return false; } +/// Returns readable name for a call. +static StringRef getFunctionName(CallExpr *Call) { + return cast<FunctionDecl>(Call->getCalleeDecl())->getName(); +} + +/// Returns OpenCL access qual. +// TODO: Refine OpenCLImageAccessAttr to OpenCLAccessAttr since pipe can use +// it too +static OpenCLImageAccessAttr *getOpenCLArgAccess(const Decl *D) { + if (D->hasAttr<OpenCLImageAccessAttr>()) + return D->getAttr<OpenCLImageAccessAttr>(); + return nullptr; +} + +/// Returns true if pipe element type is different from the pointer. +static bool checkOpenCLPipeArg(Sema &S, CallExpr *Call) { + const Expr *Arg0 = Call->getArg(0); + // First argument type should always be pipe. + if (!Arg0->getType()->isPipeType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg) + << getFunctionName(Call) << Arg0->getSourceRange(); + return true; + } + OpenCLImageAccessAttr *AccessQual = + getOpenCLArgAccess(cast<DeclRefExpr>(Arg0)->getDecl()); + // Validates the access qualifier is compatible with the call. + // OpenCL v2.0 s6.13.16 - The access qualifiers for pipe should only be + // read_only and write_only, and assumed to be read_only if no qualifier is + // specified. + bool isValid = true; + bool ReadOnly = getFunctionName(Call).find("read") != StringRef::npos; + if (ReadOnly) + isValid = AccessQual == nullptr || AccessQual->isReadOnly(); + else + isValid = AccessQual != nullptr && AccessQual->isWriteOnly(); + if (!isValid) { + const char *AM = ReadOnly ? "read_only" : "write_only"; + S.Diag(Arg0->getLocStart(), + diag::err_opencl_builtin_pipe_invalid_access_modifier) + << AM << Arg0->getSourceRange(); + return true; + } + + return false; +} + +/// Returns true if pipe element type is different from the pointer. +static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { + const Expr *Arg0 = Call->getArg(0); + const Expr *ArgIdx = Call->getArg(Idx); + const PipeType *PipeTy = cast<PipeType>(Arg0->getType()); + const Type *EltTy = PipeTy->getElementType().getTypePtr(); + const PointerType *ArgTy = + dyn_cast<PointerType>(ArgIdx->getType().getTypePtr()); + // The Idx argument should be a pointer and the type of the pointer and + // the type of pipe element should also be the same. + if (!ArgTy || EltTy != ArgTy->getPointeeType().getTypePtr()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << getFunctionName(Call) + << S.Context.getPointerType(PipeTy->getElementType()) + << ArgIdx->getSourceRange(); + return true; + } + return false; +} + +// \brief Performs semantic analysis for the read/write_pipe call. +// \param S Reference to the semantic analyzer. +// \param Call A pointer to the builtin call. +// \return True if a semantic error has been found, false otherwise. +static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { + // Two kinds of read/write pipe + // From OpenCL C Specification 6.13.16.2 the built-in read/write + // functions have following forms. + switch (Call->getNumArgs()) { + case 2: { + if (checkOpenCLPipeArg(S, Call)) + return true; + // The call with 2 arguments should be + // read/write_pipe(pipe T, T*) + // check packet type T + if (checkOpenCLPipePacketType(S, Call, 1)) + return true; + } break; + + case 4: { + if (checkOpenCLPipeArg(S, Call)) + return true; + // The call with 4 arguments should be + // read/write_pipe(pipe T, reserve_id_t, uint, T*) + // check reserve_id_t + if (!Call->getArg(1)->getType()->isReserveIDT()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << getFunctionName(Call) << S.Context.OCLReserveIDTy + << Call->getArg(1)->getSourceRange(); + return true; + } + + // check the index + const Expr *Arg2 = Call->getArg(2); + if (!Arg2->getType()->isIntegerType() && + !Arg2->getType()->isUnsignedIntegerType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << getFunctionName(Call) << S.Context.UnsignedIntTy + << Arg2->getSourceRange(); + return true; + } + + // check packet type T + if (checkOpenCLPipePacketType(S, Call, 3)) + return true; + } break; + default: + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_arg_num) + << getFunctionName(Call) << Call->getSourceRange(); + return true; + } + + return false; +} + +// \brief Performs a semantic analysis on the {work_group_/sub_group_ +// /_}reserve_{read/write}_pipe +// \param S Reference to the semantic analyzer. +// \param Call The call to the builtin function to be analyzed. +// \return True if a semantic error was found, false otherwise. +static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 2)) + return true; + + if (checkOpenCLPipeArg(S, Call)) + return true; + + // check the reserve size + if (!Call->getArg(1)->getType()->isIntegerType() && + !Call->getArg(1)->getType()->isUnsignedIntegerType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << getFunctionName(Call) << S.Context.UnsignedIntTy + << Call->getArg(1)->getSourceRange(); + return true; + } + + return false; +} + +// \brief Performs a semantic analysis on {work_group_/sub_group_ +// /_}commit_{read/write}_pipe +// \param S Reference to the semantic analyzer. +// \param Call The call to the builtin function to be analyzed. +// \return True if a semantic error was found, false otherwise. +static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 2)) + return true; + + if (checkOpenCLPipeArg(S, Call)) + return true; + + // check reserve_id_t + if (!Call->getArg(1)->getType()->isReserveIDT()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << getFunctionName(Call) << S.Context.OCLReserveIDTy + << Call->getArg(1)->getSourceRange(); + return true; + } + + return false; +} + +// \brief Performs a semantic analysis on the call to built-in Pipe +// Query Functions. +// \param S Reference to the semantic analyzer. +// \param Call The call to the builtin function to be analyzed. +// \return True if a semantic error was found, false otherwise. +static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 1)) + return true; + + if (!Call->getArg(0)->getType()->isPipeType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg) + << getFunctionName(Call) << Call->getArg(0)->getSourceRange(); + return true; + } + + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -563,6 +749,40 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.VoidPtrTy); break; + case Builtin::BIread_pipe: + case Builtin::BIwrite_pipe: + // Since those two functions are declared with var args, we need a semantic + // check for the argument. + if (SemaBuiltinRWPipe(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIreserve_read_pipe: + case Builtin::BIreserve_write_pipe: + case Builtin::BIwork_group_reserve_read_pipe: + case Builtin::BIwork_group_reserve_write_pipe: + case Builtin::BIsub_group_reserve_read_pipe: + case Builtin::BIsub_group_reserve_write_pipe: + if (SemaBuiltinReserveRWPipe(*this, TheCall)) + return ExprError(); + // Since return type of reserve_read/write_pipe built-in function is + // reserve_id_t, which is not defined in the builtin def file , we used int + // as return type and need to override the return type of these functions. + TheCall->setType(Context.OCLReserveIDTy); + break; + case Builtin::BIcommit_read_pipe: + case Builtin::BIcommit_write_pipe: + case Builtin::BIwork_group_commit_read_pipe: + case Builtin::BIwork_group_commit_write_pipe: + case Builtin::BIsub_group_commit_read_pipe: + case Builtin::BIsub_group_commit_write_pipe: + if (SemaBuiltinCommitRWPipe(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIget_pipe_num_packets: + case Builtin::BIget_pipe_max_packets: + if (SemaBuiltinPipePackets(*this, TheCall)) + return ExprError(); + break; } |