Skip to content

Commit

Permalink
✨ Speedy #embed implementation
Browse files Browse the repository at this point in the history
⚡ [Lex] Better reservations for improved performance/memory usage.

🛠 [Lex, Frontend] Remove comma hardcoding since we are servicing a full file

apply suggestions from git-clang-format
  • Loading branch information
ThePhD authored and h-vetinari committed Oct 14, 2023
1 parent 0b4b6a6 commit a6f134d
Show file tree
Hide file tree
Showing 45 changed files with 1,347 additions and 176 deletions.
51 changes: 51 additions & 0 deletions clang/include/clang/AST/Expr.h
Expand Up @@ -4805,6 +4805,57 @@ class SourceLocExpr final : public Expr {
friend class ASTStmtReader;
};

/// Represents a function call to __builtin_pp_embed().
class PPEmbedExpr final : public Expr {
SourceLocation BuiltinLoc, RParenLoc;
DeclContext *ParentContext;
StringLiteral *Filename;
StringLiteral *BinaryData;

public:
enum Action {
NotFound,
FoundOne,
Expanded,
};

PPEmbedExpr(const ASTContext &Ctx, QualType ResultTy, StringLiteral *Filename,
StringLiteral *BinaryData, SourceLocation BLoc,
SourceLocation RParenLoc, DeclContext *Context);

/// Build an empty call expression.
explicit PPEmbedExpr(EmptyShell Empty) : Expr(SourceLocExprClass, Empty) {}

/// If the PPEmbedExpr has been resolved return the subexpression
/// representing the resolved value. Otherwise return null.
const DeclContext *getParentContext() const { return ParentContext; }
DeclContext *getParentContext() { return ParentContext; }

SourceLocation getLocation() const { return BuiltinLoc; }
SourceLocation getBeginLoc() const { return BuiltinLoc; }
SourceLocation getEndLoc() const { return RParenLoc; }

StringLiteral *getFilenameStringLiteral() const { return Filename; }
StringLiteral *getDataStringLiteral() const { return BinaryData; }

size_t getDataElementCount(ASTContext &Context) const;

child_range children() {
return child_range(child_iterator(), child_iterator());
}

const_child_range children() const {
return const_child_range(child_iterator(), child_iterator());
}

static bool classof(const Stmt *T) {
return T->getStmtClass() == PPEmbedExprClass;
}

private:
friend class ASTStmtReader;
};

/// Describes an C or C++ initializer list.
///
/// InitListExpr describes an initializer list, which can be used to
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Expand Up @@ -2809,6 +2809,7 @@ DEF_TRAVERSE_STMT(ShuffleVectorExpr, {})
DEF_TRAVERSE_STMT(ConvertVectorExpr, {})
DEF_TRAVERSE_STMT(StmtExpr, {})
DEF_TRAVERSE_STMT(SourceLocExpr, {})
DEF_TRAVERSE_STMT(PPEmbedExpr, {})

DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Expand Up @@ -59,6 +59,9 @@ def err_expected_string_literal : Error<"expected string literal "
"'external_source_symbol' attribute|"
"as argument of '%1' attribute}0">;

def err_builtin_pp_embed_invalid_argument : Error<
"invalid argument to '__builtin_pp_embed': %0">;

def err_invalid_string_udl : Error<
"string literal with user-defined suffix cannot be used here">;
def err_invalid_character_udl : Error<
Expand All @@ -80,6 +83,9 @@ def err_expected : Error<"expected %0">;
def err_expected_either : Error<"expected %0 or %1">;
def err_expected_after : Error<"expected %1 after %0">;

def err_builtin_pp_embed_invalid_location : Error<
"'__builtin_pp_embed' in invalid location: %0%select{|%2}1">;

def err_param_redefinition : Error<"redefinition of parameter %0">;
def warn_method_param_redefinition : Warning<"redefinition of method parameter %0">;
def warn_method_param_declaration : Warning<"redeclaration of method parameter %0">,
Expand Down
5 changes: 3 additions & 2 deletions clang/include/clang/Basic/FileManager.h
Expand Up @@ -282,8 +282,9 @@ class FileManager : public RefCountedBase<FileManager> {
getBufferForFile(StringRef Filename, bool isVolatile = false,
bool RequiresNullTerminator = true,
std::optional<int64_t> MaybeLimit = std::nullopt) {
return getBufferForFileImpl(Filename, /*FileSize=*/(MaybeLimit ? *MaybeLimit : -1), isVolatile,
RequiresNullTerminator);
return getBufferForFileImpl(Filename,
/*FileSize=*/(MaybeLimit ? *MaybeLimit : -1),
isVolatile, RequiresNullTerminator);
}

private:
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/StmtNodes.td
Expand Up @@ -203,6 +203,7 @@ def OpaqueValueExpr : StmtNode<Expr>;
def TypoExpr : StmtNode<Expr>;
def RecoveryExpr : StmtNode<Expr>;
def BuiltinBitCastExpr : StmtNode<ExplicitCastExpr>;
def PPEmbedExpr : StmtNode<Expr>;

// Microsoft Extensions.
def MSPropertyRefExpr : StmtNode<Expr>;
Expand Down
6 changes: 2 additions & 4 deletions clang/include/clang/Basic/TokenKinds.def
Expand Up @@ -154,10 +154,6 @@ TOK(eod) // End of preprocessing directive (end of line inside a
// directive).
TOK(code_completion) // Code completion marker

// #embed speed support
TOK(builtin_embed)


// C99 6.4.9: Comments.
TOK(comment) // Comment (only in -E -C[C] mode)

Expand Down Expand Up @@ -758,6 +754,7 @@ ALIAS("__char32_t" , char32_t , KEYCXX)
KEYWORD(__builtin_bit_cast , KEYALL)
KEYWORD(__builtin_available , KEYALL)
KEYWORD(__builtin_sycl_unique_stable_name, KEYSYCL)
KEYWORD(__builtin_pp_embed , KEYALL)

// Keywords defined by Attr.td.
#ifndef KEYWORD_ATTRIBUTE
Expand Down Expand Up @@ -993,6 +990,7 @@ ANNOTATION(repl_input_end)
#undef CXX11_KEYWORD
#undef KEYWORD
#undef PUNCTUATOR
#undef BUILTINOK
#undef TOK
#undef C99_KEYWORD
#undef C23_KEYWORD
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Frontend/PreprocessorOutputOptions.h
Expand Up @@ -22,7 +22,8 @@ class PreprocessorOutputOptions {
unsigned ShowMacroComments : 1; ///< Show comments, even in macros.
unsigned ShowMacros : 1; ///< Print macro definitions.
unsigned ShowIncludeDirectives : 1; ///< Print includes, imports etc. within preprocessed output.
unsigned ShowEmbedDirectives : 1; ///< Print embeds, etc. within preprocessed output.
unsigned ShowEmbedDirectives : 1; ///< Print embeds, etc. within preprocessed
///< output.
unsigned RewriteIncludes : 1; ///< Preprocess include directives only.
unsigned RewriteImports : 1; ///< Include contents of transitively-imported modules.
unsigned MinimizeWhitespace : 1; ///< Ignore whitespace from input.
Expand Down
32 changes: 32 additions & 0 deletions clang/include/clang/Lex/PPDirectiveParameter.h
@@ -0,0 +1,32 @@
//===--- MacroArgs.h - Formal argument info for Macros ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the MacroArgs interface.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_LEX_PPDIRECTIVEPARAMETER_H
#define LLVM_CLANG_LEX_PPDIRECTIVEPARAMETER_H

#include "clang/Basic/SourceLocation.h"

namespace clang {

/// Captures basic information about a preprocessor directive parameter.
class PPDirectiveParameter {
public:
SourceLocation Start;
SourceLocation End;

PPDirectiveParameter(SourceLocation Start, SourceLocation End)
: Start(Start), End(End) {}
};

} // end namespace clang

#endif
78 changes: 78 additions & 0 deletions clang/include/clang/Lex/PPEmbedParameters.h
@@ -0,0 +1,78 @@
//===--- MacroArgs.h - Formal argument info for Macros ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the MacroArgs interface.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_LEX_PPEMBEDPARAMETERS_H
#define LLVM_CLANG_LEX_PPEMBEDPARAMETERS_H

#include "clang/Lex/PPDirectiveParameter.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/SmallVector.h"

namespace clang {

/// Preprocessor extension embed parameter "clang::offset"
/// `clang::offset( constant-expression )`
class PPEmbedParameterOffset : public PPDirectiveParameter {
public:
size_t Offset;

PPEmbedParameterOffset(size_t Offset, SourceLocation Start,
SourceLocation End)
: Offset(Offset), PPDirectiveParameter(Start, End) {}
};

/// Preprocessor standard embed parameter "limit"
/// `limit( constant-expression )`
class PPEmbedParameterLimit : public PPDirectiveParameter {
public:
size_t Limit;

PPEmbedParameterLimit(size_t Limit, SourceLocation Start, SourceLocation End)
: Limit(Limit), PPDirectiveParameter(Start, End) {}
};

/// Preprocessor standard embed parameter "prefix"
/// `prefix( balanced-token-seq )`
class PPEmbedParameterPrefix : public PPDirectiveParameter {
public:
SmallVector<Token, 2> Tokens;

PPEmbedParameterPrefix(SmallVector<Token, 2> Tokens, SourceLocation Start,
SourceLocation End)
: Tokens(std::move(Tokens)), PPDirectiveParameter(Start, End) {}
};

/// Preprocessor standard embed parameter "suffix"
/// `suffix( balanced-token-seq )`
class PPEmbedParameterSuffix : public PPDirectiveParameter {
public:
SmallVector<Token, 2> Tokens;

PPEmbedParameterSuffix(SmallVector<Token, 2> Tokens, SourceLocation Start,
SourceLocation End)
: Tokens(std::move(Tokens)), PPDirectiveParameter(Start, End) {}
};

/// Preprocessor standard embed parameter "if_empty"
/// `if_empty( balanced-token-seq )`
class PPEmbedParameterIfEmpty : public PPDirectiveParameter {
public:
SmallVector<Token, 2> Tokens;

PPEmbedParameterIfEmpty(SmallVector<Token, 2> Tokens, SourceLocation Start,
SourceLocation End)
: Tokens(std::move(Tokens)), PPDirectiveParameter(Start, End) {}
};

} // end namespace clang

#endif
39 changes: 25 additions & 14 deletions clang/include/clang/Lex/Preprocessor.h
Expand Up @@ -29,6 +29,7 @@
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/ModuleMap.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/PPEmbedParameters.h"
#include "clang/Lex/Token.h"
#include "clang/Lex/TokenLexer.h"
#include "llvm/ADT/APSInt.h"
Expand Down Expand Up @@ -1165,6 +1166,9 @@ class Preprocessor {

void updateOutOfDateIdentifier(IdentifierInfo &II) const;

/// Buffers for used #embed directives
std::vector<std::string> EmbedBuffers;

public:
Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
DiagnosticsEngine &diags, const LangOptions &LangOpts,
Expand Down Expand Up @@ -1735,15 +1739,15 @@ class Preprocessor {
bool LexHeaderName(Token &Result, bool AllowMacroExpansion = true);

struct LexEmbedParametersResult {
bool Successful;
std::optional<size_t> MaybeLimitParam;
std::optional<size_t> MaybeOffsetParam;
std::optional<SmallVector<Token, 2>> MaybeIfEmptyParam;
std::optional<SmallVector<Token, 2>> MaybePrefixParam;
std::optional<SmallVector<Token, 2>> MaybeSuffixParam;
int UnrecognizedParams;
std::optional<PPEmbedParameterLimit> MaybeLimitParam;
std::optional<PPEmbedParameterOffset> MaybeOffsetParam;
std::optional<PPEmbedParameterIfEmpty> MaybeIfEmptyParam;
std::optional<PPEmbedParameterPrefix> MaybePrefixParam;
std::optional<PPEmbedParameterSuffix> MaybeSuffixParam;
SourceLocation StartLoc;
SourceLocation EndLoc;
int UnrecognizedParams;
bool Successful;
};

LexEmbedParametersResult LexEmbedParameters(Token &Current,
Expand Down Expand Up @@ -1812,7 +1816,8 @@ class Preprocessor {
/// Parses a simple integer literal to get its numeric value. Floating
/// point literals and user defined literals are rejected. Used primarily to
/// handle pragmas that accept integer arguments.
bool parseSimpleIntegerLiteral(Token &Tok, uint64_t &Value);
bool parseSimpleIntegerLiteral(Token &Tok, uint64_t &Value,
bool WithLex = true);

/// Disables macro expansion everywhere except for preprocessor directives.
void SetMacroExpansionOnlyInDirectives() {
Expand Down Expand Up @@ -2735,12 +2740,18 @@ class Preprocessor {
// Binary data inclusion
void HandleEmbedDirective(SourceLocation HashLoc, Token &Tok,
const FileEntry *LookupFromFile = nullptr);
void HandleEmbedDirectiveNaive(
SourceLocation FilenameTok, LexEmbedParametersResult &Params,
StringRef BinaryContents, const size_t TargetCharWidth);
void HandleEmbedDirectiveBuiltin(
SourceLocation FilenameTok, LexEmbedParametersResult &Params,
StringRef BinaryContents, const size_t TargetCharWidth);
void HandleEmbedDirectiveNaive(SourceLocation HashLoc,
SourceLocation FilenameTok,
const LexEmbedParametersResult &Params,
StringRef BinaryContents,
const size_t TargetCharWidth);
void HandleEmbedDirectiveBuiltin(SourceLocation HashLoc,
const Token &FilenameTok,
StringRef ResolvedFilename,
StringRef SearchPath, StringRef RelativePath,
const LexEmbedParametersResult &Params,
StringRef BinaryContents,
const size_t TargetCharWidth);

// File inclusion.
void HandleIncludeDirective(SourceLocation HashLoc, Token &Tok,
Expand Down
37 changes: 37 additions & 0 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -5983,6 +5983,10 @@ class Sema final {
ArrayRef<Expr *> Arg, SourceLocation RParenLoc,
Expr *Config = nullptr, bool IsExecConfig = false,
ADLCallKind UsesADL = ADLCallKind::NotADL);
/// `Fn` may be a null pointer.
void ModifyCallExprArguments(Expr *Fn, SourceLocation LParenLoc,
SmallVectorImpl<Expr *> &ArgExprs,
SourceLocation RParenLoc);

ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
MultiExprArg ExecConfig,
Expand Down Expand Up @@ -6100,6 +6104,35 @@ class Sema final {
SourceLocation BuiltinLoc,
SourceLocation RPLoc);

// __builtin_pp_embed()
ExprResult ActOnPPEmbedExpr(SourceLocation BuiltinLoc,
SourceLocation Base64DataLocation,
SourceLocation RPLoc, StringLiteral *Filename,
QualType DataTy, std::vector<char> BinaryData);

IntegerLiteral *ExpandSinglePPEmbedExpr(PPEmbedExpr *PPEmbed);

PPEmbedExpr::Action
CheckExprListForPPEmbedExpr(ArrayRef<Expr *> ExprList,
std::optional<QualType> MaybeInitType);
PPEmbedExpr::Action
ExpandPPEmbedExprInExprList(ArrayRef<Expr *> ExprList,
SmallVectorImpl<Expr *> &OutputExprList,
bool ClearOutputFirst = true);
PPEmbedExpr::Action
ExpandPPEmbedExprInExprList(SmallVectorImpl<Expr *> &OutputList);

enum PPEmbedExprContext {
PPEEC__StaticAssert,
PPEEC_StaticAssert,
};

StringRef GetLocationName(PPEmbedExprContext Context) const;

bool DiagnosePPEmbedExpr(Expr *&E, SourceLocation ContextLocation,
PPEmbedExprContext Context,
bool SingleAllowed = true);

// Build a potentially resolved SourceLocExpr.
ExprResult BuildSourceLocExpr(SourceLocExpr::IdentKind Kind,
QualType ResultTy, SourceLocation BuiltinLoc,
Expand Down Expand Up @@ -8292,6 +8325,10 @@ class Sema final {
SourceLocation EqualLoc,
ParsedTemplateArgument DefaultArg);

void ModifyTemplateArguments(
const TemplateTy &Template,
SmallVectorImpl<ParsedTemplateArgument> &TemplateArgs);

TemplateParameterList *
ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Serialization/ASTBitCodes.h
Expand Up @@ -1715,6 +1715,9 @@ enum StmtCode {
/// A SourceLocExpr record.
EXPR_SOURCE_LOC,

/// A PPEmbedExpr record.
EXPR_BUILTIN_PP_EMBED,

/// A ShuffleVectorExpr record.
EXPR_SHUFFLE_VECTOR,

Expand Down

0 comments on commit a6f134d

Please sign in to comment.