From 02c263294c8edc4da643241aad629ca926628254 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Fri, 13 Sep 2024 03:03:21 -0700 Subject: [PATCH] Move the constants in the precedence table into the header. (#4308) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Getting the basic constants is actually quite hot in the parser, and is spending all of its time in memory stalls due to touching the call stack just to return a constant when these are out-of-line. This alone is worth another 8% improvement in parsing, and 2% in syntax checking: ``` name old cpu/op new cpu/op delta BM_CompileAPIFileDenseDecls/256 37.7µs ± 1% 37.5µs ± 2% -0.58% (p=0.019 n=19+18) BM_CompileAPIFileDenseDecls/1024 181µs ± 1% 179µs ± 2% -0.95% (p=0.001 n=20+20) BM_CompileAPIFileDenseDecls/4096 743µs ± 1% 736µs ± 2% -0.85% (p=0.001 n=20+19) BM_CompileAPIFileDenseDecls/16384 3.30ms ± 1% 3.25ms ± 2% -1.48% (p=0.000 n=17+19) BM_CompileAPIFileDenseDecls/65536 14.2ms ± 1% 13.9ms ± 2% -1.95% (p=0.000 n=17+19) BM_CompileAPIFileDenseDecls/262144 64.7ms ± 2% 63.8ms ± 2% -1.30% (p=0.000 n=18+18) BM_CompileAPIFileDenseDecls/256 71.0µs ± 1% 65.2µs ± 2% -8.20% (p=0.000 n=19+20) BM_CompileAPIFileDenseDecls/1024 351µs ± 1% 320µs ± 1% -9.02% (p=0.000 n=19+20) BM_CompileAPIFileDenseDecls/4096 1.43ms ± 2% 1.31ms ± 2% -8.41% (p=0.000 n=19+20) BM_CompileAPIFileDenseDecls/16384 6.08ms ± 2% 5.57ms ± 1% -8.49% (p=0.000 n=19+19) BM_CompileAPIFileDenseDecls/65536 25.2ms ± 1% 23.2ms ± 1% -8.08% (p=0.000 n=19+19) BM_CompileAPIFileDenseDecls/262144 109ms ± 1% 101ms ± 1% -6.93% (p=0.000 n=19+19) BM_CompileAPIFileDenseDecls/256 752µs ± 1% 744µs ± 1% -1.07% (p=0.000 n=19+20) BM_CompileAPIFileDenseDecls/1024 1.62ms ± 1% 1.59ms ± 1% -1.88% (p=0.000 n=19+20) BM_CompileAPIFileDenseDecls/4096 4.97ms ± 2% 4.85ms ± 1% -2.43% (p=0.000 n=20+20) BM_CompileAPIFileDenseDecls/16384 19.0ms ± 2% 18.5ms ± 2% -2.32% (p=0.000 n=19+20) BM_CompileAPIFileDenseDecls/65536 78.8ms ± 2% 76.9ms ± 2% -2.50% (p=0.000 n=20+20) BM_CompileAPIFileDenseDecls/262144 334ms ± 1% 327ms ± 2% -2.29% (p=0.000 n=20+20) ``` --- toolchain/parse/precedence.cpp | 64 +----------------------------- toolchain/parse/precedence.h | 72 ++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 62 deletions(-) diff --git a/toolchain/parse/precedence.cpp b/toolchain/parse/precedence.cpp index bc68a3500c8c..f62c118d40a8 100644 --- a/toolchain/parse/precedence.cpp +++ b/toolchain/parse/precedence.cpp @@ -8,48 +8,11 @@ namespace Carbon::Parse { -namespace { -enum PrecedenceLevel : int8_t { - // Sentinel representing the absence of any operator. - Highest, - // Terms. - TermPrefix, - // Numeric. - IncrementDecrement, - NumericPrefix, - Modulo, - Multiplicative, - Additive, - // Bitwise. - BitwisePrefix, - BitwiseAnd, - BitwiseOr, - BitwiseXor, - BitShift, - // Type formation. - TypePrefix, - TypePostfix, - // `where` keyword. - Where, - // Casts. - As, - // Logical. - LogicalPrefix, - Relational, - LogicalAnd, - LogicalOr, - // Conditional. - If, - // Assignment. - Assignment, - // Sentinel representing a context in which any operator can appear. - Lowest, -}; -constexpr int8_t NumPrecedenceLevels = Lowest + 1; +constexpr int8_t PrecedenceGroup::NumPrecedenceLevels = Lowest + 1; // A precomputed lookup table determining the relative precedence of two // precedence groups. -struct OperatorPriorityTable { +struct PrecedenceGroup::OperatorPriorityTable { constexpr OperatorPriorityTable() : table() { // Start with a list of , // relationships. @@ -176,29 +139,6 @@ struct OperatorPriorityTable { OperatorPriority table[NumPrecedenceLevels][NumPrecedenceLevels]; }; -} // namespace - -auto PrecedenceGroup::ForPostfixExpr() -> PrecedenceGroup { - return PrecedenceGroup(Highest); -} - -auto PrecedenceGroup::ForTopLevelExpr() -> PrecedenceGroup { - return PrecedenceGroup(If); -} - -auto PrecedenceGroup::ForExprStatement() -> PrecedenceGroup { - return PrecedenceGroup(Lowest); -} - -auto PrecedenceGroup::ForType() -> PrecedenceGroup { return ForTopLevelExpr(); } - -auto PrecedenceGroup::ForImplAs() -> PrecedenceGroup { - return PrecedenceGroup(As); -} - -auto PrecedenceGroup::ForRequirements() -> PrecedenceGroup { - return PrecedenceGroup(Where); -} auto PrecedenceGroup::ForLeading(Lex::TokenKind kind) -> std::optional { diff --git a/toolchain/parse/precedence.h b/toolchain/parse/precedence.h index d418a0fad898..5cd290efb9ab 100644 --- a/toolchain/parse/precedence.h +++ b/toolchain/parse/precedence.h @@ -88,6 +88,11 @@ class PrecedenceGroup { } private: + enum PrecedenceLevel : int8_t; + struct OperatorPriorityTable; + + static const int8_t NumPrecedenceLevels; + // We rely on implicit conversions via `int8_t` for enumerators defined in the // implementation. // NOLINTNEXTLINE(google-explicit-constructor) @@ -106,6 +111,73 @@ struct PrecedenceGroup::Trailing { bool is_binary; }; +//////////////////////////////////////////////////////////////////////////////// +// +// Only implementation details below this point. +// +//////////////////////////////////////////////////////////////////////////////// + +enum PrecedenceGroup::PrecedenceLevel : int8_t { + // Sentinel representing the absence of any operator. + Highest, + // Terms. + TermPrefix, + // Numeric. + IncrementDecrement, + NumericPrefix, + Modulo, + Multiplicative, + Additive, + // Bitwise. + BitwisePrefix, + BitwiseAnd, + BitwiseOr, + BitwiseXor, + BitShift, + // Type formation. + TypePrefix, + TypePostfix, + // `where` keyword. + Where, + // Casts. + As, + // Logical. + LogicalPrefix, + Relational, + LogicalAnd, + LogicalOr, + // Conditional. + If, + // Assignment. + Assignment, + // Sentinel representing a context in which any operator can appear. + Lowest, +}; + +inline auto PrecedenceGroup::ForPostfixExpr() -> PrecedenceGroup { + return PrecedenceGroup(Highest); +} + +inline auto PrecedenceGroup::ForTopLevelExpr() -> PrecedenceGroup { + return PrecedenceGroup(If); +} + +inline auto PrecedenceGroup::ForExprStatement() -> PrecedenceGroup { + return PrecedenceGroup(Lowest); +} + +inline auto PrecedenceGroup::ForType() -> PrecedenceGroup { + return ForTopLevelExpr(); +} + +inline auto PrecedenceGroup::ForImplAs() -> PrecedenceGroup { + return PrecedenceGroup(As); +} + +inline auto PrecedenceGroup::ForRequirements() -> PrecedenceGroup { + return PrecedenceGroup(Where); +} + } // namespace Carbon::Parse #endif // CARBON_TOOLCHAIN_PARSE_PRECEDENCE_H_