fhahn added inline comments.
================
Comment at: clang/include/clang/AST/Expr.h:2648
+/// MatrixSubscriptExpr - Matrix subscript expression for the MatrixType
+/// extension.
+class MatrixSubscriptExpr : public Expr {
----------------
rjmccall wrote:
> fhahn wrote:
> > rjmccall wrote:
> > > Oh, that's interesting. So you've changed this to flatten the component
> > > expressions? I think that might be inconsistent with our usual
> > > source-preservation goals unless you intend to restrict the intermediate
> > > base expression to be an immediate subscript. That is, this is okay if
> > > you're going to require the user to write `matrix[i][j]` and forbid
> > > `(matrix[i])[j]`, but if you intend to allow the latter, you should
> > > preserve that structure here. You can do that while still providing this
> > > API; you just have to implement `getBase()` etc. by looking through
> > > parens, and you should have an accessor which returns the syntactic base
> > > expression.
> > >
> > > What expression node do you use for the intermediate subscript
> > > expression? You should talk about this in the doc comment.
> > > Oh, that's interesting. So you've changed this to flatten the component
> > > expressions? I think that might be inconsistent with our usual
> > > source-preservation goals unless you intend to restrict the intermediate
> > > base expression to be an immediate subscript. That is, this is okay if
> > > you're going to require the user to write matrix[i][j] and forbid
> > > (matrix[i])[j], but if you intend to allow the latter, you should
> > > preserve that structure here. You can do that while still providing this
> > > API; you just have to implement getBase() etc. by looking through parens,
> > > and you should have an accessor which returns the syntactic base
> > > expression.
> >
> > My intuition was that the matrix subscript operator would be a single
> > operator with 3 arguments. Allowing things like (matrix[I])[j] has
> > potential for confusion I think, as there is no way to create an expression
> > just referencing a row/column on its own. (responded in more details at the
> > SemaExpr.cpp comment).
> >
> > > What expression node do you use for the intermediate subscript
> > > expression? You should talk about this in the doc comment.
> >
> > Intermediate subscript expressions are represented as 'incomplete'
> > MatrixSubscriptExpr (type is MatrixIncompleteIdx, ColumnIdx is nullptr).
> > I've updated the comment.
> > My intuition was that the matrix subscript operator would be a single
> > operator with 3 arguments. Allowing things like (matrix[I])[j] has
> > potential for confusion I think, as there is no way to create an expression
> > just referencing a row/column on its own. (responded in more details at the
> > SemaExpr.cpp comment).
>
> I think it's a perfectly reasonable language design to disallow parentheses
> here; it just wasn't obvious at first that that was what you were intending
> to do.
>
> > Intermediate subscript expressions are represented as 'incomplete'
> > MatrixSubscriptExpr (type is MatrixIncompleteIdx, ColumnIdx is nullptr).
> > I've updated the comment.
>
> Thanks. In that case, there should be a way to more directly query whether a
> particular expression is complete or not.
> Thanks. In that case, there should be a way to more directly query whether a
> particular expression is complete or not.
Done, I've added an isIncomplete method. I also added assertions using it in a
few places.
================
Comment at: clang/include/clang/Basic/Specifiers.h:159
+
+ /// A single matrix element of a matrix.
+ OK_MatrixElement
----------------
rjmccall wrote:
> fhahn wrote:
> > rjmccall wrote:
> > > redundancy
> > I suppose no comment is sufficient?
> A comment is a good idea; I was just pointing out that you'd written "a
> matrix element of a matrix".
>
> If you're intending to allow more complex matrix components in the future
> (e.g. row/column projections), consider going ahead and calling this
> `OK_MatrixComponent`.
I've renamed it to OK_MatrixComponent and added a comment that a matrix
component is a single element of a matrix.
================
Comment at: clang/lib/AST/ItaniumMangle.cpp:4238
+ case Expr::MatrixSubscriptExprClass:
+ llvm_unreachable("matrix subscript expressions not supported yet");
+
----------------
rjmccall wrote:
> fhahn wrote:
> > rjmccall wrote:
> > > This is simple, you should just mangle them syntactically. `'ixix' <base
> > > expression> <row expression> <column expression>`. Test case is
> > >
> > > ```
> > > using double4x4 = double __attribute__((matrix_type(4,4)));
> > >
> > > template <class R, class C>
> > > auto matrix_subscript(double4x4 m, R r, C c) -> decltype(m[r][c]) {}
> > >
> > > double test_matrix_subscript(double 4x4 m) { return m[3][2]; }
> > > ```
> > Thanks, I've updated the code as suggested and added the test. I had to
> > adjust the test slightly (adding a call to matrix_subscript).
> >
> > This test is quite interesting, because it accidentally another issue.
> > Matrix element subscripts are treated as Lvalues currently, but the code
> > currently does not support taking the address of matrix elements.
> > `decltype(m[r][c])` will be `& double` and if you add `return m[r][c];` the
> > issue is exposed.
> >
> > I am not sure how to best address this, short of computing the address of
> > the element in memory directly. Do you have any suggestions?
> >
> > I think for some vector types, we currently mis-compile here as well. For
> > example,
> >
> > ```
> > using double4 = double __attribute__((ext_vector_type(4)));
> >
> > template <class R>
> > auto matrix_subscript(const double4 m, R r) -> decltype(m[r]) { return
> > m[r]; }
> > ```
> >
> > produces the IR below. Note the ` ret double* %ref.tmp`, where `%ref.tmp`
> > is an alloca.
> >
> > ```
> > define linkonce_odr nonnull align 8 dereferenceable(8) double*
> > @_Z16matrix_subscriptIiEDTixfpK_fp0_EDv4_dT_(<4 x double>* byval(<4 x
> > double>) align 16 %0, i32 %r) #0 {
> > entry:
> > %m.addr = alloca <4 x double>, align 16
> > %r.addr = alloca i32, align 4
> > %ref.tmp = alloca double, align 8
> > %m = load <4 x double>, <4 x double>* %0, align 16
> > store <4 x double> %m, <4 x double>* %m.addr, align 16
> > store i32 %r, i32* %r.addr, align 4
> > %1 = load <4 x double>, <4 x double>* %m.addr, align 16
> > %2 = load i32, i32* %r.addr, align 4
> > %vecext = extractelement <4 x double> %1, i32 %2
> > store double %vecext, double* %ref.tmp, align 8
> > ret double* %ref.tmp
> > }
> > ```
> > Thanks, I've updated the code as suggested and added the test. I had to
> > adjust the test slightly (adding a call to matrix_subscript).
>
> Er, yes, I did mean to include one of those. :)
>
> > I am not sure how to best address this, short of computing the address of
> > the element in memory directly. Do you have any suggestions?
>
> Well, there's two levels of this.
>
> First, you *could* make matrix elements ordinary l-values — it's not like you
> have any interest in ever not storing them separately, right? Vector
> components use a special l-value kind specifically to prevent addressability,
> probably for reasons related to the swizzle projections. Although, saying
> that, I'm not sure you can assign to the swizzle projections, in which case
> I'm not really sure why vectors need a special object kind except to forbid
> taking the address for its own sake. The only problem I can see with
> allowing element l-values to be ordinary l-values is that the code coming out
> of IRGen after you assign to one isn't going to be quite so tidily
> mem2reg'able as it is with the vector-style code generation. Of course, you
> could peephole that in IRGen if it's important. And if you want e.g.
> projected column matrices to be non-addressable in the future (which I assume
> you do?), you can always add a special object kind for those when you add
> them.
>
> If you do want to restrict taking the address of an matrix component l-value,
> that should be a straightforward extra restriction in the places where we
> already forbid taking the address of a bit-field. You'll need the same
> restriction in reference-binding, of course. You could make `decltype` not
> infer a reference type for your l-values if you want, although I believe
> `decltype` does infer a reference type for bit-fields.
>
> Your example is unfortunately not a miscompile, it's just a combination of
> terrible language features. The returned reference is bound to a
> materialized temporary because vector elements aren't addressable. You
> wouldn't be able to do that if `m` weren't `const` because the return type
> would become `double &`, which can't bind to a temporary.
> If you do want to restrict taking the address of an matrix component l-value,
> that should be a straightforward extra restriction in the places where we
> already forbid taking the address of a bit-field. You'll need the same
> restriction in reference-binding, of course. You could make decltype not
> infer a reference type for your l-values if you want, although I believe
> decltype does infer a reference type for bit-fields.
Thanks for the suggestion! I think it would be best to mirror the handling of
ExtVectorElementExpr and I *think* I found all the relevant places that needed
updating. I've added tests to take references/addresses with various
valid/invalid cases.
================
Comment at: clang/lib/Sema/SemaExpr.cpp:4556
+ if (base->getType()->isMatrixType())
+ return ActOnMatrixSubscriptExpr(S, base, idx, nullptr, rbLoc);
+
----------------
rjmccall wrote:
> fhahn wrote:
> > rjmccall wrote:
> > > You're not handling the case of a parenthesized MatrixSubscriptExpr. If
> > > that should be an error, that's a reasonable language rule, but it should
> > > probably be a better error than whatever you'll get by default.
> > >
> > > And you might be specifically and problematically avoiding an error
> > > because of the special treatment of `IncompleteMatrixIdx` below. I'd
> > > just pull that up here and emit an error.
> > >
> > > Doing this before the C++2a comma-index check is intentional?
> > > You're not handling the case of a parenthesized MatrixSubscriptExpr. If
> > > that should be an error, that's a reasonable language rule, but it should
> > > probably be a better error than whatever you'll get by default.
> >
> >
> > Yes the way I think about the matrix subscript expression is in terms of a
> > single operator with 3 arguments (`base[RowIdx][ColumnIdx]`), so something
> > like `(a[i])[j]` should not be allowed, similar to things like `a([I])` not
> > being allowed.
> >
> > > And you might be specifically and problematically avoiding an error
> > > because of the special treatment of IncompleteMatrixIdx below. I'd just
> > > pull that up here and emit an error.
> >
> > I've moved the handling of IncompleteMatrixIdx here (the previous position
> > was due to the first version of the patch).
> >
> > > Doing this before the C++2a comma-index check is intentional?
> >
> > Not really. I've moved it after the check.
> >
> >
> > Not really. I've moved it after the check.
>
> Okay. However, you should consider going ahead and making it an error for
> matrix subscripts, just in case you want that syntax to mean something else
> in the future. It will also let you immediately catch people trying to use
> `m[0,0]` instead of `m[0][0]`.
Oh right! I've went back to add a ActOnMatrixSubscriptExpr, as there are a few
things that can go in there now, including rejecting `m[0,0]`.
================
Comment at: clang/lib/Sema/SemaExpr.cpp:4583
+ auto BaseTy = base->getType();
+ if (BaseTy->isNonOverloadPlaceholderType()) {
IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base);
----------------
rjmccall wrote:
> This change is no longer necessary.
Dropped, thanks!
================
Comment at: clang/lib/Sema/SemaExpr.cpp:4650
+ (Base->isTypeDependent() || RowIdx->isTypeDependent() ||
+ (ColumnIdx && ColumnIdx->isTypeDependent())))
+ return new (Context) MatrixSubscriptExpr(Base, RowIdx, ColumnIdx,
----------------
rjmccall wrote:
> Checking dependence is actually just as cheap as checking for C++, there's no
> real need to gate. But you need to check for placeholder types in the index
> operands before doing these type checks. The best test case here is an
> Objective-C property reference, something like:
>
> ```
> __attribute__((objc_root_class))
> @interface IntValue
> @property int value;
> @end
>
> double test(double4x4 m, IntValue *iv) {
> return m[iv.value][iv.value];
> }
> ```
>
> Also, I would suggest not doing any checking on incomplete matrix
> expressions; just notice that it's still incomplete, build the expression,
> and return. You can do the checking once when you have all the operands
> together.
> Checking dependence is actually just as cheap as checking for C++, there's no
> real need to gate. But you need to check for placeholder types in the index
> operands before doing these type checks. The best test case here is an
> Objective-C property reference, something like:
Done, I've added a ActOnMatrixSubscriptExpr and added code to deal with
placeholder types there.
> Also, I would suggest not doing any checking on incomplete matrix
> expressions; just notice that it's still incomplete, build the expression,
> and return. You can do the checking once when you have all the operands
> together.
Done, I initially thought it might be good to still raise an error if the row
index was invalid, but given that it's not a valid expression anyways that
probably is not too helpful anyways. Doing the checks on the complete
expression simplifies things a bit :)
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D76791/new/
https://reviews.llvm.org/D76791
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits