diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1802,6 +1802,9 @@ STMT_SEH_FINALLY, // SEHFinallyStmt STMT_SEH_TRY, // SEHTryStmt + // Code transformation directives. + STMT_TRANSFORM_EXECUTABLE_DIRECTIVE, // TransformExecutableDirective + // OpenMP directives STMT_OMP_PARALLEL_DIRECTIVE, STMT_OMP_SIMD_DIRECTIVE, diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -261,6 +261,9 @@ /// Read an OpenMP clause, advancing Idx. OMPClause *readOMPClause(); + /// Read an transform clause, advancing Idx. + TransformClause *readTransformClause(); + /// Read a source location, advancing Idx. SourceLocation readSourceLocation() { return Reader->ReadSourceLocation(*F, Record, Idx); diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -268,6 +268,8 @@ void writeOMPClause(OMPClause *C); + void writeTransformClause(TransformClause *C); + /// Emit a string. void AddString(StringRef Str) { return Writer->AddString(Str, *Record); diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -16,6 +16,7 @@ #include "clang/AST/ASTMutationListener.h" #include "clang/AST/Decl.h" +#include "clang/AST/StmtTransform.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -774,9 +774,46 @@ } } +namespace { +class TransformClauseProfiler + : public ConstTransformClauseVisitor { + StmtProfiler *Profiler; + +public: + TransformClauseProfiler(StmtProfiler *P) : Profiler(P) {} + +#define TRANSFORM_CLAUSE(Keyword, Name) \ + void Visit##Name##Clause(const Name##Clause *); +#include "clang/AST/TransformClauseKinds.def" +}; + +void TransformClauseProfiler::VisitFullClause(const FullClause *C) { + // The full clause has no arguments. +} + +void TransformClauseProfiler::VisitPartialClause(const PartialClause *C) { + Profiler->VisitExpr(C->getFactor()); +} + +void TransformClauseProfiler::VisitWidthClause(const WidthClause *C) { + Profiler->VisitExpr(C->getWidth()); +} + +void TransformClauseProfiler::VisitFactorClause(const FactorClause *C) { + Profiler->VisitExpr(C->getFactor()); +} +} // namespace + void StmtProfiler::VisitTransformExecutableDirective( const TransformExecutableDirective *S) { VisitStmt(S); + TransformClauseProfiler P(this); + for (TransformClause *C : S->clauses()) { + if (!C) + continue; + ID.AddInteger(C->getKind()); + P.Visit(C); + } } void diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -12467,3 +12467,60 @@ Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); } + +//===----------------------------------------------------------------------===// +// TransformClauseReader implementation +//===----------------------------------------------------------------------===// +namespace { +class TransformClauseReader { + ASTRecordReader &Record; + ASTContext &Context; + +public: + TransformClauseReader(ASTRecordReader &Record) + : Record(Record), Context(Record.getContext()) {} + + TransformClause *readClause(); + +#define TRANSFORM_CLAUSE(Keyword, Name) \ + Name##Clause *read##Name##Clause(SourceRange); +#include "clang/AST/TransformClauseKinds.def" +}; +}; // namespace + +TransformClause *ASTRecordReader::readTransformClause() { + return TransformClauseReader(*this).readClause(); +} + +TransformClause *TransformClauseReader::readClause() { + uint64_t Kind = Record.readInt(); + SourceRange Range = Record.readSourceRange(); + + switch (Kind) { +#define TRANSFORM_CLAUSE(Keyword, Name) \ + case TransformClause::Kind::Name##Kind: \ + return read##Name##Clause(Range); +#include "clang/AST/TransformClauseKinds.def" + default: + llvm_unreachable("Unknown transform clause kind"); + } +} + +FullClause *TransformClauseReader::readFullClause(SourceRange Range) { + return FullClause::create(Context, Range); +} + +PartialClause *TransformClauseReader::readPartialClause(SourceRange Range) { + Expr *Factor = Record.readExpr(); + return PartialClause::create(Context, Range, Factor); +} + +WidthClause *TransformClauseReader::readWidthClause(SourceRange Range) { + Expr *Width = Record.readExpr(); + return WidthClause::create(Context, Range, Width); +} + +FactorClause *TransformClauseReader::readFactorClause(SourceRange Range) { + Expr *Factor = Record.readExpr(); + return FactorClause::create(Context, Range, Factor); +} diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2023,7 +2023,21 @@ void ASTStmtReader::VisitTransformExecutableDirective( TransformExecutableDirective *D) { - llvm_unreachable("not implemented"); + VisitStmt(D); + unsigned NumClauses = Record.readInt(); + assert(D->getNumClauses() == NumClauses); + // The binary layout up to here is also assumed by + // ASTReader::ReadStmtFromStream and must be kept in-sync. + + D->setRange(readSourceRange()); + + SmallVector Clauses; + Clauses.reserve(NumClauses); + for (unsigned i = 0; i < NumClauses; ++i) + Clauses.push_back(Record.readTransformClause()); + D->setClauses(Clauses); + + D->setAssociated(Record.readSubStmt()); } //===----------------------------------------------------------------------===// @@ -3293,6 +3307,11 @@ break; } + case STMT_TRANSFORM_EXECUTABLE_DIRECTIVE: + S = TransformExecutableDirective::createEmpty( + Context, Record[ASTStmtReader::NumStmtFields]); + break; + case EXPR_CXX_OPERATOR_CALL: S = CXXOperatorCallExpr::CreateEmpty( Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], Empty); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6545,3 +6545,52 @@ for (auto *VE : C->varlists()) Record.AddStmt(VE); } + +//===----------------------------------------------------------------------===// +// TransformClause Serialization +//===----------------------------------------------------------------------===// +namespace { +class TransformClauseWriter + : public ConstTransformClauseVisitor { + ASTRecordWriter &Record; + +public: + TransformClauseWriter(ASTRecordWriter &Record) : Record(Record) {} + + void writeClause(const TransformClause *C); + +#define TRANSFORM_CLAUSE(Keyword, Name) \ + void Visit##Name##Clause(const Name##Clause *); +#include "clang/AST/TransformClauseKinds.def" + + void VisitTransformClause(const TransformClause *C) { + llvm_unreachable("Serialization of this clause not implemented"); + } +}; +} // namespace + +void ASTRecordWriter::writeTransformClause(TransformClause *C) { + TransformClauseWriter(*this).writeClause(C); +} + +void TransformClauseWriter::writeClause(const TransformClause *C) { + Record.push_back(C->getKind()); + Record.AddSourceRange(C->getRange()); + Visit(C); +} + +void TransformClauseWriter::VisitFullClause(const FullClause *C) { + // The full clause has no arguments. +} + +void TransformClauseWriter::VisitPartialClause(const PartialClause *C) { + Record.AddStmt(C->getFactor()); +} + +void TransformClauseWriter::VisitWidthClause(const WidthClause *C) { + Record.AddStmt(C->getWidth()); +} + +void TransformClauseWriter::VisitFactorClause(const FactorClause *C) { + Record.AddStmt(C->getFactor()); +} diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1977,7 +1977,15 @@ void ASTStmtWriter::VisitTransformExecutableDirective( TransformExecutableDirective *D) { - llvm_unreachable("not implemented"); + Code = serialization::STMT_TRANSFORM_EXECUTABLE_DIRECTIVE; + VisitStmt(D); + Record.push_back(D->getNumClauses()); + + Record.AddSourceRange(D->getRange()); + for (auto C : D->clauses()) + Record.writeTransformClause(C); + + Record.AddStmt(D->getAssociated()); } //===----------------------------------------------------------------------===// diff --git a/clang/test/PCH/transform-distribute.cpp b/clang/test/PCH/transform-distribute.cpp new file mode 100644 --- /dev/null +++ b/clang/test/PCH/transform-distribute.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexperimental-transform-pragma -emit-pch -o %t.pch %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexperimental-transform-pragma -include-pch %t.pch %s -ast-dump-all -o - | FileCheck %s --dump-input=fail -vv + +#ifndef HEADER +#define HEADER + +void distribute_heuristic(int n) { +#pragma clang transform distribute + for (int i = 0; i < n; i+=1) + ; +} +// CHECK-LABEL: FunctionDecl {{.*}} imported distribute_heuristic +// CHECK: TransformExecutableDirective +// CHECK-NEXT: ForStmt + +#endif /* HEADER */ diff --git a/clang/test/PCH/transform-interleave.cpp b/clang/test/PCH/transform-interleave.cpp new file mode 100644 --- /dev/null +++ b/clang/test/PCH/transform-interleave.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexperimental-transform-pragma -emit-pch -o %t.pch %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexperimental-transform-pragma -include-pch %t.pch %s -ast-dump-all -o - | FileCheck %s + +#ifndef HEADER +#define HEADER + +void interleave_heuristic(int n) { +#pragma clang transform interleave + for (int i = 0; i < n; i+=1) + ; +} +// CHECK-LABEL: FunctionDecl {{.*}} imported interleave_heuristic +// CHECK: TransformExecutableDirective +// CHECK-NEXT: ForStmt + + +void interleave_factor(int n) { +#pragma clang transform interleave factor(4) + for (int i = 0; i < n; i+=1) + ; +} +// CHECK-LABEL: FunctionDecl {{.*}} imported interleave_factor +// CHECK: TransformExecutableDirective +// CHECK-NEXT: FactorClause +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4 +// CHECK-NEXT: ForStmt + +#endif /* HEADER */ diff --git a/clang/test/PCH/transform-unroll.cpp b/clang/test/PCH/transform-unroll.cpp new file mode 100644 --- /dev/null +++ b/clang/test/PCH/transform-unroll.cpp @@ -0,0 +1,85 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexperimental-transform-pragma -emit-pch -o %t.pch %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexperimental-transform-pragma -include-pch %t.pch %s -ast-dump-all -o - | FileCheck %s + +#ifndef HEADER +#define HEADER + +void unroll_heuristic(int n) { +#pragma clang transform unroll + for (int i = 0; i < 4; i+=1) + ; +} +// CHECK-LABEL: FunctionDecl {{.*}} imported unroll_heuristic +// CHECK: TransformExecutableDirective +// CHECK-NEXT: ForStmt + + +void unroll_full(int n) { +#pragma clang transform unroll full + for (int i = 0; i < 4; i+=1) + ; +} +// CHECK-LABEL: FunctionDecl {{.*}} imported unroll_full +// CHECK: TransformExecutableDirective +// CHECK-NEXT: FullClause +// CHECK-NEXT: ForStmt + + +void unroll_partial(int n) { +#pragma clang transform unroll partial(4) + for (int i = 0; i < n; i+=1) + ; +} +// CHECK-LABEL: FunctionDecl {{.*}} imported unroll_partial +// CHECK: TransformExecutableDirective +// CHECK-NEXT: PartialClause +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4 +// CHECK-NEXT: ForStmt + + +template +void unroll_template_function(int n) { +#pragma clang transform unroll partial(FACTOR) + for (int i = 0; i < n; i+=1) + ; +} +// CHECK-LABEL: FunctionDecl {{.*}} imported unroll_template_function +// CHECK: TransformExecutableDirective +// CHECK-NEXT: PartialClause +// CHECK-NEXT: DeclRefExpr {{.*}} 'FACTOR' 'int' +// CHECK-NEXT: ForStmt + + +template void unroll_template_function<5>(int); +// CHECK-LABEL: FunctionDecl {{.*}} imported unroll_template_function +// CHECK: TransformExecutableDirective +// CHECK-NEXT: PartialClause +// CHECK-NEXT: SubstNonTypeTemplateParmExpr +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 5 +// CHECK-NEXT: ForStmt + + +template +struct Unroll { + void unroll_template_method(int n) { +#pragma clang transform unroll partial(FACTOR) + for (int i = 0; i < n; i+=1) + ; + } +}; +// CHECK-LABEL: CXXMethodDecl {{.*}} imported unroll_template_method +// CHECK: TransformExecutableDirective +// CHECK-NEXT: PartialClause +// CHECK-NEXT: DeclRefExpr {{.*}} 'FACTOR' 'int' +// CHECK-NEXT: ForStmt + + +template struct Unroll<6>; +// CHECK-LABEL: CXXMethodDecl {{.*}} imported unroll_template_method +// CHECK: TransformExecutableDirective +// CHECK-NEXT: PartialClause +// CHECK-NEXT: SubstNonTypeTemplateParmExpr +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 6 +// CHECK-NEXT: ForStmt + +#endif /* HEADER */ diff --git a/clang/test/PCH/transform-unrollandjam.cpp b/clang/test/PCH/transform-unrollandjam.cpp new file mode 100644 --- /dev/null +++ b/clang/test/PCH/transform-unrollandjam.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexperimental-transform-pragma -emit-pch -o %t.pch %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexperimental-transform-pragma -include-pch %t.pch %s -ast-dump-all -o - | FileCheck %s + +#ifndef HEADER +#define HEADER + +void unrollandjam_heuristic(int n) { +#pragma clang transform unrollandjam + for (int i = 0; i < n; i+=1) + for (int j = 0; j < n; j+=1) + ; +} +// CHECK-LABEL: FunctionDecl {{.*}} imported unrollandjam_heuristic +// CHECK: TransformExecutableDirective +// CHECK-NEXT: ForStmt + + +void unrollandjam_partial(int n) { +#pragma clang transform unrollandjam partial(4) + for (int i = 0; i < n; i+=1) + for (int j = 0; j < n; j+=1) + ; +} +// CHECK-LABEL: FunctionDecl {{.*}} imported unrollandjam_partial +// CHECK: TransformExecutableDirective +// CHECK-NEXT: PartialClause +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4 +// CHECK-NEXT: ForStmt + +#endif /* HEADER */ diff --git a/clang/test/PCH/transform-vectorize.cpp b/clang/test/PCH/transform-vectorize.cpp new file mode 100644 --- /dev/null +++ b/clang/test/PCH/transform-vectorize.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexperimental-transform-pragma -emit-pch -o %t.pch %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexperimental-transform-pragma -include-pch %t.pch %s -ast-dump-all -o - | FileCheck %s + +#ifndef HEADER +#define HEADER + +void vectorize_heuristic(int n) { +#pragma clang transform vectorize + for (int i = 0; i < n; i+=1) + ; +} +// CHECK-LABEL: FunctionDecl {{.*}} imported vectorize_heuristic +// CHECK: TransformExecutableDirective +// CHECK-NEXT: ForStmt + + +void vectorize_width(int n) { +#pragma clang transform vectorize width(4) + for (int i = 0; i < n; i+=1) + ; +} +// CHECK-LABEL: FunctionDecl {{.*}} imported vectorize_width +// CHECK: TransformExecutableDirective +// CHECK-NEXT: WidthClause +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4 +// CHECK-NEXT: ForStmt + +#endif /* HEADER */