diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 49d425cde769..ab7f7dcd44e8 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1527,7 +1527,7 @@ def err_nomp_eod_expected: Error< "Expected the end of directive '%0' at line %1, column %2">; def err_nomp_identifier_expected: Error< "Expected a variable name at line %0, column %1">; -def err_nomp_function_arg_invalid: Error< +def err_nomp_invalid_function_arg: Error< "Invalid argument type at line %0, column %1: %2">; def err_nomp_pointer_type_expected: Error< "Expected a pointer in the nomp directive '%0' at line %1, column %2">; @@ -1552,6 +1552,8 @@ def err_nomp_func_decl_in_kernel: Error< "Function declaration inside kernel is not allowed at line %0 column %1">; def err_nomp_func_call_in_kernel: Error< "Function call inside kernel is not allowed at line %0 column %1">; +def err_nomp_invalid_arg_property: Error< + "Invalid argument property at line %0, column %1: %2">; // Pragma loop support. def err_pragma_loop_missing_argument : Error< diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 7e22c5a60919..d3f0f166a6b1 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3452,6 +3452,7 @@ class Parser : public CodeCompletionHandler { StmtResult ParseNompUpdate(const SourceLocation &sLoc); int ParseNompForClauses(std::vector &clauses, std::vector &reductionVariables, + std::vector &jitVariables, std::string &kernelName); StmtResult ParseNompFor(const SourceLocation &sLoc); StmtResult ParseNompSync(const SourceLocation &sLoc); diff --git a/clang/lib/Parse/ParseNomp.cpp b/clang/lib/Parse/ParseNomp.cpp index 4c86597139ee..6f2b78761504 100644 --- a/clang/lib/Parse/ParseNomp.cpp +++ b/clang/lib/Parse/ParseNomp.cpp @@ -76,6 +76,10 @@ enum ArgType { TypePointer = 16384 }; +// FIXME: Following enum ArgProperties should be based on `nomp.h` and +// shouldn't be hard-coded here. +enum ArgProperties { PropertyJit = 1 }; + //============================================================================== // Helper functions to generate C types. // @@ -245,7 +249,7 @@ void Parser::ParseNompExprListUntilRParen(llvm::SmallVector &EL, static Expr *ExprToArgc(Expr *E, ASTContext &AST) { const Type *T = E->getType().getTypePtr(); if (!T->isIntegerType() && !T->isFloatingType()) { - NompHandleError(diag::err_nomp_function_arg_invalid, E->getExprLoc(), AST, + NompHandleError(diag::err_nomp_invalid_function_arg, E->getExprLoc(), AST, "Parameter `argc` of nomp_init() must be an Integer type."); return nullptr; } @@ -274,7 +278,7 @@ static Expr *ExprToArgv(Expr *E, ASTContext &AST) { #define check_cond(cond) \ { \ if (!cond) { \ - NompHandleError(diag::err_nomp_function_arg_invalid, E->getExprLoc(), \ + NompHandleError(diag::err_nomp_invalid_function_arg, E->getExprLoc(), \ AST, \ "Parameter `argv` of nomp_init() must be an variable " \ "which reference an array of C-strings or " \ @@ -617,7 +621,8 @@ static void CreateNompJitCall(llvm::SmallVector &Stmts, ASTContext &AST, VarDecl *ID, VarDecl *VKNL, VarDecl *VCLS, std::set &EV, - const std::vector &reductionVariables) { + const std::vector &reductionVariables, + const std::vector &jitVariables) { llvm::SmallVector FuncArgs; SourceLocation SL = SourceLocation(); @@ -659,50 +664,79 @@ CreateNompJitCall(llvm::SmallVector &Stmts, ASTContext &AST, for (auto V : EV) { QualType QT = V->getType(); const Type *T = QT.getTypePtrOrNull(); - if (T) { - // Name of the variable as a string. - std::string name = V->getNameAsString(); - QualType NameStrTy = getConstantArrayType( - AST, AST.CharTy, name.size() + 1, ArrayType::Normal); - StringLiteral *SL = - StringLiteral::Create(AST, name, StringLiteral::Ordinary, false, - NameStrTy, SourceLocation()); - ImplicitCastExpr *ICE = - ImplicitCastExpr::Create(AST, StrTy, CK_ArrayToPointerDecay, SL, - nullptr, VK_PRValue, FPOptionsOverride()); - FuncArgs.push_back(ICE); - - if (T->isArrayType()) - QT = AST.getBaseElementType(dyn_cast(T)); - else if (T->isPointerType()) - QT = dyn_cast(T)->getPointeeType(); - TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(QT); - - // sizeof(variable) - FuncArgs.push_back(new (AST) UnaryExprOrTypeTraitExpr( - UETT_SizeOf, TSI, AST.getSizeType(), SourceLocation(), - SourceLocation())); - - // Check if the variable is part of a reduction since we need to pass the - // pointee type or base element type in that case. - Type *T1 = const_cast(T); - if (std::find(reductionVariables.begin(), reductionVariables.end(), - name) != reductionVariables.end()) - T1 = const_cast(QT.getTypePtrOrNull()); - - // Find the nomp type. - int type = TypeInt * T1->isSignedIntegerType() + - TypeFloat * T1->isFloatingType() + - TypeUInt * T1->isUnsignedIntegerType() + - TypePointer * (T1->isPointerType() || T1->isArrayType()); - - if (type == 0) { - NompHandleError(diag::err_nomp_function_arg_invalid, V->getLocation(), - AST); + if (!T) { + NompHandleError(diag::err_nomp_invalid_function_arg, V->getLocation(), + AST, + "Unsupported type for argument: " + V->getNameAsString()); + } + + // We first pass the name of the argument as a string: + const std::string name = V->getNameAsString(); + const QualType NameStrTy = getConstantArrayType( + AST, AST.CharTy, name.size() + 1, ArrayType::Normal); + StringLiteral *SL = StringLiteral::Create( + AST, name, StringLiteral::Ordinary, false, NameStrTy, SourceLocation()); + ImplicitCastExpr *ICE = + ImplicitCastExpr::Create(AST, StrTy, CK_ArrayToPointerDecay, SL, + nullptr, VK_PRValue, FPOptionsOverride()); + FuncArgs.push_back(ICE); + + if (T->isArrayType()) + QT = AST.getBaseElementType(dyn_cast(T)); + if (T->isPointerType()) + QT = dyn_cast(T)->getPointeeType(); + TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(QT); + + // Then: sizeof(argument) + FuncArgs.push_back( + new (AST) UnaryExprOrTypeTraitExpr(UETT_SizeOf, TSI, AST.getSizeType(), + SourceLocation(), SourceLocation())); + + // Third, we pass the nomp type of the argument. We embed various argument + // properties in the type itself. For example, if the argument is a jit + // argument, we embed the property `jit` in the type. + // + // Also, Check if the variable is part of a reduction since we need to pass + // the pointee type or base element type in that case. + Type *T1 = const_cast(T); + if (std::find(reductionVariables.begin(), reductionVariables.end(), name) != + reductionVariables.end()) + T1 = const_cast(QT.getTypePtrOrNull()); + + int type = TypeInt * T1->isSignedIntegerType() + + TypeFloat * T1->isFloatingType() + + TypeUInt * T1->isUnsignedIntegerType() + + TypePointer * (T1->isPointerType() || T1->isArrayType()); + + if (type == 0) { + NompHandleError(diag::err_nomp_invalid_function_arg, V->getLocation(), + AST, "Unsupported type for argument: " + name); + } + + if (std::find(jitVariables.begin(), jitVariables.end(), name) != + jitVariables.end()) { + if (type == TypePointer) { + NompHandleError(diag::err_nomp_invalid_arg_property, V->getLocation(), + AST, + "Argument: " + name + + " cannot have the property `jit` in nomp_jit() " + "since it is a pointer."); } + type = type | PropertyJit; + } + + FuncArgs.push_back(IntegerLiteral::Create(AST, llvm::APInt(32, type), IntTy, + SourceLocation())); - FuncArgs.push_back(IntegerLiteral::Create(AST, llvm::APInt(32, type), - IntTy, SourceLocation())); + // Fourth, If the argument has the property `jit`, we need to pass the + // pointer to the argument. + if (type & PropertyJit) { + DeclRefExpr *DRE = + DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(), + V, false, SourceLocation(), QT, VK_LValue); + FuncArgs.push_back(UnaryOperator::Create( + AST, DRE, UO_AddrOf, AST.getPointerType(QT), VK_PRValue, OK_Ordinary, + SourceLocation(), false, FPOptionsOverride())); } } @@ -713,7 +747,8 @@ CreateNompJitCall(llvm::SmallVector &Stmts, ASTContext &AST, static void CreateNompRunCall(llvm::SmallVector &Stmts, ASTContext &AST, VarDecl *ID, - std::set &EV) { + std::set &EV, + const std::vector &jitVariables) { llvm::SmallVector FuncArgs; // First argument to nomp_run() is 'id' -- input argument which passes an @@ -752,9 +787,10 @@ static void CreateNompRunCall(llvm::SmallVector &Stmts, int Parser::ParseNompForClauses(std::vector &clauses, std::vector &reductionVariables, + std::vector &jitVariables, std::string &kernelName) { - // Process auxiliary pragmas (i.e., clauses) supported after `#pragma nomp - // for`. Mainly we want to support `annotate`, `transform` and `jit` for the + // Process auxiliary clauses supported after `#pragma nomp for`. Mainly + // we want to support `annotate`, `transform` and `jit` for the // time being. All of the above should be parsed as an identifier token. bool transformDetected = 0; bool reductionDetected = 0; @@ -817,8 +853,8 @@ int Parser::ParseNompForClauses(std::vector &clauses, } // `name` and `jit` takes a single string argument. `transform`, `annotate` - // and `reduce should be followed by two arguments. In any case, we should - // get a string literal next. + // and `reduce` should be followed by two arguments. In any case, we + // should get a string literal next. // FIXME: This can be a string variable as well. Need to support that. if (Tok.isNot(tok::string_literal)) { NompHandleError(diag::err_nomp_string_literal_expected, Tok, *this); @@ -839,16 +875,21 @@ int Parser::ParseNompForClauses(std::vector &clauses, goto consume_r_paren; } - // If the clause is not `name`, store the clause, and the string literal. + // If the clause is `jit`, store the string literal in the jitVariables + // so we can easily check if a variable should be passed to the kernel or + // not later and consume the ")". + if (clause == ForClauseJit) { + jitVariables.push_back(arg0); + goto consume_r_paren; + } + + // If the clause is not `name` or `jit`, store the clause, and the + // string literal. { clauses.push_back(ForClauses[clause]); clauses.push_back(arg0); } - // We are done if the clause is `jit`. - if (clause == ForClauseJit) - goto consume_r_paren; - // If the clause is `reduce`, store the string literal in the // reductionVariables so we can easily check if a variable is part of a // reduction or not later. @@ -895,9 +936,10 @@ StmtResult Parser::ParseNompFor(const SourceLocation &SL) { Sema &S = getActions(); ASTContext &AST = S.getASTContext(); - std::vector clauses, reductionVariables; + std::vector clauses, reductionVariables, jitVariables; std::string kernelName; - if (ParseNompForClauses(clauses, reductionVariables, kernelName)) + if (ParseNompForClauses(clauses, reductionVariables, jitVariables, + kernelName)) return StmtEmpty(); // Check if the next token is tok::kw_for. If not, exit. @@ -1000,10 +1042,11 @@ StmtResult Parser::ParseNompFor(const SourceLocation &SL) { // Next we create the AST node for the function call nomp_jit(). To do that // we create the function arguments to nomp_jit(). - CreateNompJitCall(Stmts, AST, ID, VKnl, CLS, EV, reductionVariables); + CreateNompJitCall(Stmts, AST, ID, VKnl, CLS, EV, reductionVariables, + jitVariables); // Next we create AST node for nomp_run(). - CreateNompRunCall(Stmts, AST, ID, EV); + CreateNompRunCall(Stmts, AST, ID, EV, jitVariables); return CompoundStmt::Create(AST, ArrayRef(Stmts), FPOptionsOverride(), SL, SL);