[clang] Add serialization for loop hint annotation tokens

When late parsed templates are used with PCH tokens are serialized. The
existing code does not handle annotation tokens which can occur due to
various pragmas.

This patch implements the serialization for annot_pragma_loop_hint.

This also enables use of OpenMP pragmas and #pragma unused which do not
need special serialization of the PtrData field.

Fixes https://github.com/llvm/llvm-project/issues/39504

Differential Revision: https://reviews.llvm.org/D138453
This commit is contained in:
Mike Rice 2022-11-21 10:56:05 -08:00
parent 65df5bf2d1
commit 530eb263c0
7 changed files with 105 additions and 17 deletions

View File

@ -450,6 +450,10 @@ Non-comprehensive list of changes in this release
It can be used to writing conditionally constexpr code that uses builtins.
- The time profiler (using ``-ftime-trace`` option) now traces various constant
evaluation events.
- Clang can now generate a PCH when using ``-fdelayed-template-parsing`` for
code with templates containing loop hint pragmas, OpenMP pragmas, and
``#pragma unused``.
New Compiler Flags
------------------

View File

@ -15,6 +15,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TokenKinds.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include <cassert>
@ -330,6 +331,12 @@ struct PPConditionalInfo {
bool FoundElse;
};
// Extra information needed for annonation tokens.
struct PragmaLoopHintInfo {
Token PragmaName;
Token Option;
ArrayRef<Token> Toks;
};
} // end namespace clang
#endif // LLVM_CLANG_LEX_TOKEN_H

View File

@ -41,7 +41,7 @@ namespace serialization {
/// Version 4 of AST files also requires that the version control branch and
/// revision match exactly, since there is no backward compatibility of
/// AST files at this time.
const unsigned VERSION_MAJOR = 23;
const unsigned VERSION_MAJOR = 24;
/// AST file minor version number supported by this version of
/// Clang.

View File

@ -1293,14 +1293,6 @@ bool Parser::HandlePragmaMSAllocText(StringRef PragmaName,
return true;
}
namespace {
struct PragmaLoopHintInfo {
Token PragmaName;
Token Option;
ArrayRef<Token> Toks;
};
} // end anonymous namespace
static std::string PragmaLoopHintString(Token PragmaName, Token Option) {
StringRef Str = PragmaName.getIdentifierInfo()->getName();
std::string ClangLoopStr("clang loop ");

View File

@ -1669,11 +1669,38 @@ Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record,
Token Tok;
Tok.startToken();
Tok.setLocation(ReadSourceLocation(F, Record, Idx));
Tok.setLength(Record[Idx++]);
if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++]))
Tok.setIdentifierInfo(II);
Tok.setKind((tok::TokenKind)Record[Idx++]);
Tok.setFlag((Token::TokenFlags)Record[Idx++]);
if (Tok.isAnnotation()) {
Tok.setAnnotationEndLoc(ReadSourceLocation(F, Record, Idx));
switch (Tok.getKind()) {
case tok::annot_pragma_loop_hint: {
auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
Info->PragmaName = ReadToken(F, Record, Idx);
Info->Option = ReadToken(F, Record, Idx);
unsigned NumTokens = Record[Idx++];
SmallVector<Token, 4> Toks;
Toks.reserve(NumTokens);
for (unsigned I = 0; I < NumTokens; ++I)
Toks.push_back(ReadToken(F, Record, Idx));
Info->Toks = llvm::makeArrayRef(Toks).copy(PP.getPreprocessorAllocator());
Tok.setAnnotationValue(static_cast<void *>(Info));
break;
}
// Some annotation tokens do not use the PtrData field.
case tok::annot_pragma_openmp:
case tok::annot_pragma_openmp_end:
case tok::annot_pragma_unused:
break;
default:
llvm_unreachable("missing deserialization code for annotation token");
}
} else {
Tok.setLength(Record[Idx++]);
if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++]))
Tok.setIdentifierInfo(II);
}
return Tok;
}

View File

@ -4372,15 +4372,37 @@ void ASTRecordWriter::AddAttributes(ArrayRef<const Attr *> Attrs) {
void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {
AddSourceLocation(Tok.getLocation(), Record);
Record.push_back(Tok.getLength());
// FIXME: When reading literal tokens, reconstruct the literal pointer
// if it is needed.
AddIdentifierRef(Tok.getIdentifierInfo(), Record);
// FIXME: Should translate token kind to a stable encoding.
Record.push_back(Tok.getKind());
// FIXME: Should translate token flags to a stable encoding.
Record.push_back(Tok.getFlags());
if (Tok.isAnnotation()) {
AddSourceLocation(Tok.getAnnotationEndLoc(), Record);
switch (Tok.getKind()) {
case tok::annot_pragma_loop_hint: {
auto *Info = static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
AddToken(Info->PragmaName, Record);
AddToken(Info->Option, Record);
Record.push_back(Info->Toks.size());
for (const auto &T : Info->Toks)
AddToken(T, Record);
break;
}
// Some annotation tokens do not use the PtrData field.
case tok::annot_pragma_openmp:
case tok::annot_pragma_openmp_end:
case tok::annot_pragma_unused:
break;
default:
llvm_unreachable("missing serialization code for annotation token");
}
} else {
Record.push_back(Tok.getLength());
// FIXME: When reading literal tokens, reconstruct the literal pointer if it
// is needed.
AddIdentifierRef(Tok.getIdentifierInfo(), Record);
}
}
void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) {

View File

@ -0,0 +1,36 @@
// RUN: %clang_cc1 -fopenmp -emit-pch -o %t.pch %s
// RUN: %clang_cc1 -fopenmp -fdelayed-template-parsing -emit-pch -o %t.delayed.pch %s
// RUN: %clang_cc1 -DMAIN_FILE -fopenmp -include-pch %t.pch \
// RUN: -emit-llvm -o - %s -fopenmp | FileCheck %s
// RUN: %clang_cc1 -DMAIN_FILE -fopenmp -fdelayed-template-parsing -verify \
// RUN: -Wunused-variable -include-pch %t.delayed.pch \
// RUN: -emit-llvm -o - %s | FileCheck %s
#ifndef MAIN_FILE
template <typename T>
void a(T t) {
#pragma clang loop unroll_count(4)
for(int i=0;i<8;++i) {}
#pragma omp simd
for(int i=0;i<8;++i) {}
{
int x, y, z, zz;
#pragma unused(x)
#pragma unused(y, z)
}
}
#else
// CHECK: !llvm.loop !3
// CHECK: !llvm.loop !7
// CHECK: !3 = distinct !{!3, !4, !5}
// CHECK: !4 = !{!"llvm.loop.mustprogress"}
// CHECK: !5 = !{!"llvm.loop.unroll.count", i32 4}
// CHECK: !7 = distinct !{!7, !8, !9}
// CHECK: !8 = !{!"llvm.loop.parallel_accesses", !6}
// CHECK: !9 = !{!"llvm.loop.vectorize.enable", i1 true}
// expected-warning@17 {{unused variable 'zz'}}
void foo()
{
a(1);
}
#endif