Skip to content

Gazprea 2026 changes#93

Open
rcunrau wants to merge 10 commits into
masterfrom
gazprea-2026-changes
Open

Gazprea 2026 changes#93
rcunrau wants to merge 10 commits into
masterfrom
gazprea-2026-changes

Conversation

@rcunrau

@rcunrau rcunrau commented May 31, 2026

Copy link
Copy Markdown
Collaborator

Just a place to have a discussion. I already opened #92
and #91

@rcunrau

rcunrau commented May 31, 2026

Copy link
Copy Markdown
Collaborator Author

In the Declarations section we have the two lines:

<qualifier> <type> <identifier> = <expression>;
<qualifier> <type> <identifier>;

Would it be clearer to use optional notation?

[<qualifier>] <type> <identifier> [= <expression>];
[<qualifier>] [<type>] <identifier> = <expression>;

This gets into the relatively rich set of rules where you can elide either the type or the initialization, but not both.

@rcunrau

rcunrau commented May 31, 2026

Copy link
Copy Markdown
Collaborator Author

Added issue 94

@rcunrau

rcunrau commented May 31, 2026

Copy link
Copy Markdown
Collaborator Author

Historically, we have had problems with naming/categorizing errors. The problem manifests as 1000s of questions for the TAs of the form: what error should XXX generate? The root is because now that we check for errors as part of competitive testing, we check that the type of error raised is correct. This has unintended side effects because for errors that could have multiple classifications the type can depend on the order of the semantic analysis passes. A related problem is that we used to require the compiler to stop as soon as it found the first error.

I have advocated for looser checking: as long as the compiler notes that there was an error on the correct line we pass the test. This also requires that the compiler must not stop after the first error is found, so that our checkers can grep on the line number to match programs with multiple errors.

@rcunrau

rcunrau commented May 31, 2026

Copy link
Copy Markdown
Collaborator Author

Should we allow nested structs?

@rcunrau

rcunrau commented May 31, 2026

Copy link
Copy Markdown
Collaborator Author

Should we relax the restriction that structs have two fields? Rust actually uses 0 element structs effectively, and in some sense a 1 field struct is like a typedef vs typealias. I think tuples should retain the minimum of two fields, and that structs can't contain tuples.

@rcunrau

rcunrau commented May 31, 2026

Copy link
Copy Markdown
Collaborator Author

Section 7.7 of Arrays - did we decide to allow tuples and structs to be array elements? For structs, I guess the array declaration would be:

struct S(int field);
S[2] twos = [S(field: 0), S(field:1)];

Arrays of tuples might be weird looking:

(real, char)[2] twot = [(1.0, 'a'), (2.14, 'A')];

@rcunrau

rcunrau commented May 31, 2026

Copy link
Copy Markdown
Collaborator Author

7.7.1 Array Declaration - I think the declaration is missing the (optional) <qualifier>

@rcunrau

rcunrau commented May 31, 2026

Copy link
Copy Markdown
Collaborator Author

7.7.3 Operations, Concatenation b - it says types must be automatically promotable, but could we also allow casts?

Indexing - Should have a LHS example of indexing. Should we also say anything about indices being l-values?

@rcunrau

rcunrau commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator Author

7.7.4 Slices - it says slices can be strided using by, which is not true.

The example needs to be fixed - c has 10 elements but we only print 6, and 3rd example uses by.

The section only talks about slices as parameters, but they can also be used in assignments and expressions:

integer[*] a = 1..20 by 2; // a range not a slice;
integer[*] b = a[..4]; // slice being used as an r-value 
a[8..] = 0; // slice being used as an l-value

We haven't talked about the 3rd example before, but I believe it is consistent with slice semantics

@rcunrau

rcunrau commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator Author

Section 7.8 Vectors - it may be possible that vectors and arrays are interchangeable because of slices. If that is true, then we may want to say something about it in the intro.

In 7.8.1 we forgot [<qualifier>] again.

7.8.2 - we probably shouldn't lead with the erroneous slice example, especially since we haven't introduced vector methods yet. I also think the examples look suspicious, at least, to me they raise as many questions as they answer.

@rcunrau

rcunrau commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator Author

7.10 Matrices - I think we should stop talking about the builtin 2D matrices as arrays of arrays. That definitely influences people away from dense matrices, which as you know, is the only true representation. (BTW, you can ask Nelson if nested vectors can be optimized - if they can I will drop my request).

@rcunrau

rcunrau commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator Author
  1. Type Inference - strictly speaking, we do type deduction, because all we do is copy the RHS type across to the LHS. Real inference requires looking at reached uses, which we currently don't do. However, I would love to add a pass that uses the SSA in MLIR to do real inference.

@novo52

novo52 commented Jun 1, 2026

Copy link
Copy Markdown

7.7.4 Slices - it says slices can be strided using by, which is not true.

I have been thinking that operators like by and reverse ought to have the same semantics as slices, providing a view into the array. Like in this example:

integer[10] array = 1..10;
array by 2 = 0; // 0 promoted to array
print(array); // [0, 2, 0, 4, 0, 6, 0, 8, 0, 10]

I don't know if this is a good idea, but I like it. I think it may be complex and non-rewarding to implement, however.

@novo52

novo52 commented Jun 1, 2026

Copy link
Copy Markdown

In 7.8.1 we forgot [<qualifier>] again.

Fixing this, I have a question: can vectors be type inferred? e.g.

const vector<integer> v1 = 1..10;
const v2 = v1; // Is this an array or a vector?

@novo52

novo52 commented Jun 1, 2026

Copy link
Copy Markdown

Should we allow nested structs?
Should we relax the restriction that structs have two fields?
Section 7.7 of Arrays - did we decide to allow tuples and structs to be array elements?

Imo, yes to all. Ayrton says:

I think nested arrays and structs might actually make things easier especially since I now have a very clear idea of how to use memref properly to make these types of structures easily.

I have ideas of optimizations students can do with a gazprea MLIR dialect that depend on nested types.
In general, I think that arbitrary nesting of types encourages a generalized and extensible approach to gazprea implementation. Wherever possible, we should remove arbitrary restrictions (e.g. >1 struct field). However, there may be unforeseen problems that need to be explored.

FWIW, I am relatively certain that the gazprea MLIR backend I wrote in 415 was capable of arbitrary nesting of aggregate types.

@rcunrau

rcunrau commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator Author

7.7.4 Slices - it says slices can be strided using by, which is not true.

I have been thinking that operators like by and reverse ought to have the same semantics as slices, providing a view into the array. Like in this example:

integer[10] array = 1..10;
array by 2 = 0; // 0 promoted to array
print(array); // [0, 2, 0, 4, 0, 6, 0, 8, 0, 10]

I don't know if this is a good idea, but I like it. I think it may be complex and non-rewarding to implement, however.

I think you nailed it: super cool but extremely hard to implement. A simple slice can be implemented with:

template <typename T>
struct slice {
    T* start;
    usize_t len;
};

This is (almost) exactly what both an array and a vector look like. The key is their start can't change because they have to be able to free their data. Now consider your array by 2 = 0; example. I think the slice would have to look something like:

template <typename T>
class slice {
     vec<T*> window;
     
     slice(T* base, int start, int end, int stride) {
           for (size_t i=start; i<=end; i+=stride) window.push_back(&base[I]);
    }

The trick is that you have to go from sparse to dense so you can apply the operators normally. Note that all your operators would have to be rewritten to work with the extra level of indirection.

@rcunrau

rcunrau commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator Author

In 7.8.1 we forgot [] again.

Fixing this, I have a question: can vectors be type inferred? e.g.

const vector<integer> v1 = 1..10;
const v2 = v1; // Is this an array or a vector?

Great question! I think there are arguments to go either way, but I would lean towards vector, because in my head this type deduction propagates the RHS type to the LHS. Is that what you were thinking?

@rcunrau

rcunrau commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator Author

Should we allow nested structs?
Should we relax the restriction that structs have two fields?
Section 7.7 of Arrays - did we decide to allow tuples and structs to be array elements?

Imo, yes to all. Ayrton says:

I think nested arrays and structs might actually make things easier especially since I now have a very clear idea of how to use memref properly to make these types of structures easily.

I have ideas of optimizations students can do with a gazprea MLIR dialect that depend on nested types. In general, I think that arbitrary nesting of types encourages a generalized and extensible approach to gazprea implementation. Wherever possible, we should remove arbitrary restrictions (e.g. >1 struct field). However, there may be unforeseen problems that need to be explored.

FWIW, I am relatively certain that the gazprea MLIR backend I wrote in 415 was capable of arbitrary nesting of aggregate types.

Do you think we can make our reference solution handle nested aggregate types? Do you think we still have need of a reference solution?

@bloboss

bloboss commented Jun 2, 2026

Copy link
Copy Markdown

Definitely possible to make a reference solution with nested structs, but I am no longer sure that we need a reference solution personally, I think we will have a clearer idea of how we are going to evaluate the students after our meeting next week.

In terms of the by operator, I think we should drop it because of what you guys discussed above.

I think that the single allocation for matrices is important for all static arrays, and that we can make all static-sized arrays (n-d) one contiguous memory allocation. We should note this to the students when we discuss how to implement dynamic arrays.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants