-
Notifications
You must be signed in to change notification settings - Fork 1
[SPEC] Constexpr Specification #97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Sir-NoChill
wants to merge
5
commits into
gazprea-2026-changes
Choose a base branch
from
spec/constexpr
base: gazprea-2026-changes
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+183
−16
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
d78dd67
spec: add constant-expression (constexpr) specification
Sir-NoChill 28400b1
spec: register constexpr page in the toctree
Sir-NoChill 5407940
spec: require global initializers to be constant expressions
Sir-NoChill abc8691
docs(constexpr): clarify array sizes are constexpr, not dynamic
Sir-NoChill 256b9ad
docs(constexpr): clarify operators for constexpr
Sir-NoChill File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| .. _sec:constexpr: | ||
|
|
||
| Constant Expressions | ||
| ==================== | ||
|
|
||
| A constant expression (sometimes called a constexpr) is an expression that can | ||
| be fully evaluated by the compiler at compile time. This feature is primarily | ||
| for specifying the size of | ||
| :ref:`statically-sized arrays <ssec:array>`. | ||
|
|
||
| In *Gazprea*, a ``constexpr`` is not a keyword, but a property of a ``const`` | ||
| variable. A ``const`` variable is considered a ``constexpr`` if and only if its | ||
| initializer expression meets a strict set of criteria: | ||
|
|
||
| .. _ssec:constexpr_rules: | ||
|
|
||
| Rules for Constant Expressions | ||
| ------------------------------ | ||
|
|
||
| An expression is a valid ``constexpr`` if it is composed exclusively of: | ||
|
|
||
| 1. Literals of base types (``boolean``, ``integer``, ``real``, ``character``). | ||
| 2. The operators ``+``, ``-``, ``*``, ``/``, ``not``, ``and``, ``or``, | ||
| between two or more ``constexpr``\ s. | ||
| 3. Constructors for aggregate types, provided that the aggregate is const and | ||
| all members are ``constexpr``\ s. | ||
| 4. Index or field access on ``constexpr`` aggregate types. | ||
| 5. Other variables that are themselves valid ``constexpr``\ s. | ||
|
|
||
| An expression is **not** a ``constexpr`` if it contains: | ||
|
|
||
| 1. References to ``var`` variables. | ||
| 2. Function or procedure calls. | ||
| 3. Any I/O operations (``<-``). | ||
|
|
||
| The compiler must perform this validation recursively. When checking if a | ||
| variable is a ``constexpr``, the compiler must trace its entire dependency | ||
| chain. If the chain ever depends on a runtime value, the check fails. | ||
|
|
||
| The only expressions that *must* be ``constexpr`` are global constants. Other | ||
| constexprs arising from constants inside function scope may also be constexprs | ||
| but the implementation does not need to enforce or necessarily identify this. | ||
| Students should also note that MLIR has a constant propagation pass built in, | ||
| so doing constant folding yourself may not be necessary depending on your | ||
| implementation. | ||
|
|
||
| **Examples:** | ||
|
|
||
| **Note**: we will annotate the scope explicitly in these examples. Some | ||
| 'illegal' examples here would be legal within a non-global scope. | ||
|
|
||
| :: | ||
|
|
||
| // ---------------------------- | ||
| // in global scope | ||
| // ---------------------------- | ||
|
|
||
| // Legal Global Constant Expressions | ||
| const A = 10; | ||
| const B = A * 2; // Depends on another constexpr | ||
| const C = B + 5; // C is 25 | ||
|
|
||
| // Illegal Global Constant Expressions | ||
| var x = 10; | ||
| const Y = x + 5; // Not a constexpr: depends on a 'var' | ||
|
|
||
| function get_val() returns integer { return 100; } | ||
| const Z = get_val(); // Not a constexpr: depends on a function call | ||
|
|
||
| .. _ssec:constexpr_aggregates: | ||
|
|
||
| Constant Expressions with Aggregate Types | ||
| ----------------------------------------- | ||
|
|
||
| Arrays and tuples can also be ``constexpr``\ s if they meet specific criteria, | ||
| allowing them to be used to define other constants. | ||
|
|
||
| #. Arrays | ||
|
|
||
| A ``const`` array is a ``constexpr`` if: | ||
|
|
||
| 1. Its size is a valid ``constexpr``. | ||
| 2. All of its element initializers are valid ``constexpr``\ s. | ||
|
|
||
| A ``vector`` (the dynamically-sized type) can never be a ``constexpr`` | ||
| aggregate, since its size is determined at runtime. An inferred-size array | ||
| such as ``integer[*] X = [1, 2, 3]`` must be a ``constexpr``, meaning its | ||
| initializer is itself a ``constexpr``: ``[*]`` denotes an inferred size, not | ||
| a dynamic one. | ||
|
|
||
| :: | ||
|
|
||
| // ---------------------------- | ||
| // in global scope | ||
| // ---------------------------- | ||
|
|
||
| const WIDTH = 5; | ||
| const integer[WIDTH] LOOKUP_TABLE = [10, 20, 30, 40, 50]; // Legal constexpr array | ||
|
|
||
| const ELEMENT = LOOKUP_TABLE[3]; // Legal: ELEMENT is a constexpr with value 30 | ||
| integer[ELEMENT] my_array = 0; // Legal: static array of size 30, zero-filled | ||
|
|
||
| const integer[2] BAD_TABLE = [10, get_val()]; // Illegal: initializer is not a constexpr | ||
| // also illegal if a procedure since | ||
| // procedure calls are not allowed | ||
| // within declarations | ||
|
|
||
| A ``constexpr`` can appear anywhere a ``const`` declaration is legal, | ||
| including inside functions, procedures, and control-flow blocks. However, | ||
| **not every** ``const`` variable is a ``constexpr``. ``const`` means only | ||
| that the variable is immutable within its scope; ``constexpr`` is the | ||
| stronger property that the value is fully known at compile time. For | ||
| example: | ||
|
|
||
| :: | ||
|
|
||
| // ---------------------------------- | ||
| // in local/function/non-global scope | ||
| // ---------------------------------- | ||
| var integer x; | ||
| x <- std_input; | ||
| const integer y = x; // Legal: y is immutable, but NOT a constexpr | ||
| // because its value depends on runtime input. | ||
| integer[y] arr; // Illegal: an explicit array size must be a | ||
| // constexpr, and y is not a constexpr. | ||
| vector<integer> v; // Legal: a vector is the dynamically-sized type; | ||
| // use it when the size is only known at runtime. | ||
|
|
||
| The compiler propagates the constexpr property through local scopes | ||
| normally; there is no restriction on where in a block the declaration | ||
| appears, as long as its entire dependency chain satisfies the rules above. | ||
|
|
||
| #. Tuples | ||
|
|
||
| A ``const`` tuple is a ``constexpr`` if all of its fields are initialized | ||
| with valid constant expressions. | ||
|
|
||
| :: | ||
|
|
||
| // ---------------------------- | ||
| // in global scope | ||
| // ---------------------------- | ||
| const CONFIG = (true, 10 * 2); // Legal constexpr tuple | ||
|
|
||
| const IS_ENABLED = CONFIG.1; // Legal: IS_ENABLED is a constexpr with value 'true' | ||
| const VALUE = CONFIG.2; // Legal: VALUE is a constexpr with value 20 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,9 +26,11 @@ array instead of a ``real`` array. | |
|
|
||
| #. Explicit Size Declarations | ||
|
|
||
| When an array is declared it may be explicitly given a size. This | ||
| size can be given as any integer expression, thus the size of the | ||
| array may not be known until runtime. | ||
| When an array is declared it may be explicitly given a size. This size | ||
| must be a :ref:`constant expression <sec:constexpr>`. Every array, whether | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree with this proposal |
||
| explicitly or implicitly sized, has a size that is known at compile time; a | ||
| collection whose size is only known at runtime requires a | ||
| :ref:`vector <ssec:vector>`. | ||
|
|
||
| :: | ||
|
|
||
|
|
@@ -77,8 +79,9 @@ array instead of a ``real`` array. | |
|
|
||
|
|
||
| In this example the compiler can infer both the size and the type of | ||
| ``w`` from ``v``. The size may not always be known at compile time, so this | ||
| may need to be handled during runtime. | ||
| ``w`` from ``v``. As with any array, this inferred size is known at compile | ||
| time; a collection whose size is only known at runtime must be a | ||
| :ref:`vector <ssec:vector>`. | ||
|
|
||
| .. _sssec:array_constr: | ||
|
|
||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we agreed that literals only was too restrictive? I thought the reason we were restricting to literals only was so the teams did not have to do constant propagation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do I remember you saying that the solution is to store the constants values in the symbols, and that you were going to give them the MLIR tool to do symbolic expression evaluation?