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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to