This is an archive of the discontinued LLVM Phabricator instance.

[Matrix] Implement matrix index expressions ([][]).
ClosedPublic

Authored by fhahn on Mar 25 2020, 11:27 AM.

Details

Summary

This patch implements matrix index expressions
(matrix[RowIdx][ColumnIdx]).

It does so by introducing a new MatrixSubscriptExpr(Base, RowIdx, ColumnIdx).
MatrixSubscriptExprs are built in 2 steps in ActOnMatrixSubscriptExpr. First,
if the base of a subscript is of matrix type, we create a incomplete
MatrixSubscriptExpr(base, idx, nullptr). Second, if the base is an incomplete
MatrixSubscriptExpr, we create a complete
MatrixSubscriptExpr(base->getBase(), base->getRowIdx(), idx)

Similar to vector elements, it is not possible to take the address of
a MatrixSubscriptExpr.
For CodeGen, a new MatrixElt type is added to LValue, which is very
similar to VectorElt. The only difference is that we may need to cast
the type of the base from an array to a vector type when accessing it.

Diff Detail

Event Timeline

fhahn created this revision.Mar 25 2020, 11:27 AM
fhahn updated this revision to Diff 254228.Apr 1 2020, 9:36 AM

Use placeholder type for incomplete matrix index expressions, as suggested by @rjmccall

fhahn updated this revision to Diff 262893.May 8 2020, 10:23 AM

Rebase on top of the latest version of D72281. Refactor code to re-use new address conversion helper.

fhahn updated this revision to Diff 264094.May 14 2020, 2:26 PM

Update to support non-constant-integer-expressions as indices.

Sorry for the slow review; I'm getting crushed with review requests.

clang/lib/AST/Expr.cpp
3859

You need to IgnoreParens() here.

clang/lib/AST/ExprConstant.cpp
7768

This can also occur in the other evaluators due to indexing into an r-value.

clang/lib/Sema/SemaExpr.cpp
5326

It should have the value kind of its base. get_matrix_rvalue()[0][0] is still an r-value, so you shouldn't allow it to be assigned to. Needs tests.

I'm fine with re-using OK_VectorComponent here, but you should (1) rename it to OK_VectorOrMatrixComponent and (2) take the opportunity to audit the places that use it to make sure they do something sensible. I expect you'll need to at least update some diagnostics about e.g. disallowing taking the address of the expression.

I think you should build a new expression node instead of reusing ArraySubscriptExpr, since basically none of the code that looks for an ArraySubscriptExpr will do the right thing for your operation. That will also allow you to avoid the "is this actually enabled" check, since you'll only see this node when your feature is enabled. If you're feeling generous, you could move vector subscripting to this new node as well and leave ArraySubscriptExpr exclusively for the standard (or dependent) cases.

fhahn updated this revision to Diff 265728.May 22 2020, 6:21 AM
fhahn marked 4 inline comments as done.

Sorry for the slow review; I'm getting crushed with review requests.

Thanks John! I've updated the patch and introduced a new MatrixSubscriptExpr. I think it simplifies the code in a few places and makes things clearer.

Herald added a project: Restricted Project. · View Herald TranscriptMay 22 2020, 6:21 AM
fhahn marked an inline comment as done.May 22 2020, 8:49 AM
fhahn added inline comments.
clang/lib/AST/Expr.cpp
3859

This code is now gone.

clang/lib/AST/ExprConstant.cpp
7768

This code is not required any longer.

clang/lib/Sema/SemaExpr.cpp
5326

It should have the value kind of its base. get_matrix_rvalue()[0][0] is still an r-value, so you shouldn't allow it to be assigned to. Needs tests.

added tests to Sema/matrix-type-operators.s and SemaCXX/matrix-type-operators.cpp.

I'm fine with re-using OK_VectorComponent here, but you should (1) rename it to OK_VectorOrMatrixComponent and (2) take the opportunity to audit the places that use it to make sure they do something sensible. I expect you'll need to at least update some diagnostics about e.g. disallowing taking the address of the expression.

I've introduced a new OK_MatrixElement, because I don't think there is enough information to distinguish between vectors/matrixes where it is used. Also added a reinterpret_cast test.

I think you should build a new expression node instead of reusing ArraySubscriptExpr, since basically none of the code that looks for an ArraySubscriptExpr will do the right thing for your operation. That will also allow you to avoid the "is this actually enabled" check, since you'll only see this node when your feature is enabled. If you're feeling generous, you could move vector subscripting to this new node as well and leave ArraySubscriptExpr exclusively for the standard (or dependent) cases.

I've added a new MatrixSubscriptExpr. That helps to simplify the code in a couple of places. ActOnArraySubscriptExpr calls ActOnMatrixSubscriptExpr if we can identify the base as matrix type or MatrixSubscriptExpr. I initially tried to move the ActOnMatrixSubscriptExpr call to the parse step, but that does not work in the presence of dependent base types I think. Until we instantiate the dependent types, there's no way to distinguish between ArraySubscriptExpr/MatrixSubscriptExpr I think and it is best to treat them as unanalyzed ArraySubscriptExpr until then.

fhahn updated this revision to Diff 265750.May 22 2020, 9:00 AM

Add clarifying comment to ActOnMatrixSubscriptExpr calls in ActOnArraySubscriptExpr.

rjmccall added inline comments.May 22 2020, 2:10 PM
clang/include/clang/AST/Expr.h
2653

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.

clang/include/clang/Basic/Specifiers.h
159 ↗(On Diff #265750)

redundancy

clang/include/clang/Sema/Sema.h
4907 ↗(On Diff #265750)

It'd be more conventional to call it BuildMatrixSubscriptExpr. You can do all the semantic checks here and make ActOnArraySubscriptExpr handle the syntactic checks. This is all assuming that you intend to impose the syntactic restriction discussed above.

clang/lib/AST/ItaniumMangle.cpp
4238 ↗(On Diff #265750)

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]; }
clang/lib/Sema/SemaExpr.cpp
4556

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?

fhahn updated this revision to Diff 266205.May 26 2020, 7:32 AM
fhahn marked 7 inline comments as done.

Address John's latest comments, thanks!

clang/include/clang/AST/Expr.h
2653

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.

clang/include/clang/Basic/Specifiers.h
159 ↗(On Diff #265750)

I suppose no comment is sufficient?

clang/include/clang/Sema/Sema.h
4907 ↗(On Diff #265750)

Thanks, I wasn't sure about the actual distinction. I've renamed it to BuildMatrixSubscriptExpr now.

clang/lib/AST/ItaniumMangle.cpp
4238 ↗(On Diff #265750)

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
}
clang/lib/Sema/SemaExpr.cpp
4556

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.

rjmccall added inline comments.May 27 2020, 1:45 AM
clang/include/clang/AST/Expr.h
2653

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.

clang/include/clang/Basic/Specifiers.h
159 ↗(On Diff #265750)

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.

clang/lib/AST/ItaniumMangle.cpp
4238 ↗(On Diff #265750)

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.

clang/lib/Sema/SemaExpr.cpp
4556

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].

4565

This change is no longer necessary.

4633

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.

fhahn updated this revision to Diff 266602.May 27 2020, 10:52 AM
fhahn marked 10 inline comments as done.

Addressed latest round of comments, thanks!

Changes include:

  • OK_MatrixComponent now behaves like OK_VectorComponent with respect to taking address/reference.
  • Look through non-overload placeholder expressions.
  • Move matrix related syntactic checks to new ActOnMatrixSubscriptExpr.
  • Add MatrixSubscriptExpr::isIncomplete & use it at a few places in assertions.
  • Update CreateBuiltinMatrixType to only validate indices once, on the complete expression.
  • Do not allow , in matrix subscript expressions.
fhahn added inline comments.May 27 2020, 10:59 AM
clang/include/clang/AST/Expr.h
2653

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.

clang/include/clang/Basic/Specifiers.h
159 ↗(On Diff #265750)

I've renamed it to OK_MatrixComponent and added a comment that a matrix component is a single element of a matrix.

clang/lib/AST/ItaniumMangle.cpp
4238 ↗(On Diff #265750)

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.

clang/lib/Sema/SemaExpr.cpp
4556

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].

4565

Dropped, thanks!

4633

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 :)

rjmccall added inline comments.May 27 2020, 12:29 PM
clang/lib/Sema/SemaExpr.cpp
4633

Placeholders actually need to be handled in the Build function — they can come up in template instantiation, too.

4641

Don't check for ParenExpr specifically; there are other expressions that are handled the same way, like _Generic. You need to check for !isa<MatrixSubscriptExpr>.

4651

Overload placeholder types are used for things like &foo where foo is the name of an overloaded function. The places that resolve only non-overload placeholder types are doing so in order to leave room for overload resolution to resolve the overload later, e.g. as part of non-builtin operator handling. operator[] is like operator(): non-builtin operators are only considered when the base has class type. Since you already know that the base type is a matrix type, you know that you're using your standard rules, and your standard rules have no way to resolve overloads in the index types — correctly, since indexes can't be functions or member pointers.

tl;dr: You can (and should) resolve all placeholders here, not just non-overload placeholders.

fhahn edited the summary of this revision. (Show Details)May 27 2020, 1:00 PM
fhahn updated this revision to Diff 266643.May 27 2020, 1:14 PM
fhahn marked 4 inline comments as done.

Addressed latest comments:

  • Handle placeholder types in CreateBuiltinMatrixSubscriptExpr and do not limit to non-overload types there.
  • Check !MatrixSubscriptExpr instead of ParenExpr.
  • Only handle placeholder types for Base in ActOnMatrixSubscriptExpr. Only skip isMSPropertySubscriptExpr.
clang/lib/Sema/SemaExpr.cpp
4633

Move, thanks! I think we have to retain checking placeholder expressions for base below, as noted in the response below.

4641

Done, thanks!

4651

Thanks for the clarification. I moved the code to deal with placeholders to CreateBuiltinMatrixSubscriptExpr and removed the non-overload restriction there.

I think we still need to keep dealing with placeholders in Base below, to ensure we do not miss that the base is actually a matrix type, e.g. to support. It seems it is enough to skip` isMSPropertySubscriptExpr` there (without that restriction, some non-matrix-type codegen tests start to fail. Does that make sense?

__attribute__((objc_root_class))
@interface MatrixValue
@property double4x4 value;
@end
rjmccall added inline comments.May 27 2020, 2:14 PM
clang/lib/CodeGen/CGExpr.cpp
1911

This should be handled here or else a whole lot of unusual cases are going to blow up on you — compound operators and so on.

3818

You should be able to assert that these have been coerced to the right type by Sema (probably size_t or ptrdiff_t or something).

clang/lib/Sema/SemaExpr.cpp
4553

I would prefer that the checks are inlined here, since they're very likely to not trigger.

4651

Yeah, you have to resolve some placeholders before you can check whether the base is a matrix type, and you can't resolve MS properties because the property access actually merges with the subscript in some cases.

I think you may need to resolve placeholders in base even in CreateBuiltinMatrixSubscriptExpr to handle template instantiation right. The test case would be something where the matrix expression is non-dependently-typed but loaded from an ObjC property — we might need to redundantly resolve placeholders when rebuilding expressions in the instantiation.

I also want to confirm explicitly that you've decided that the right language design is for matrix components to not be addressable. You're convinced that that's an important restriction to get the code generation you want?

fhahn updated this revision to Diff 267296.May 29 2020, 10:33 AM
fhahn marked 5 inline comments as done.

Thanks for the latest round of comments! All expect one should be addressed. For the remaining comment, I responded inline.

Also, it would be great if you could let me know if the updated check lines in D76793 are sufficient, then I'll update the tests in this patch accordingly.

I also want to confirm explicitly that you've decided that the right language design is for matrix components to not be addressable. You're convinced that that's an important restriction to get the code generation you want?

Yes at the moment I think we want to limit element wise accesses/modifications to go through the access operator only, to guarantee we can rely on the vector forms in codegen.

Additionally I think at least initially we want to avoid handing out pointers to elements, as it may be tempting to use for pointer-based accesses to subsequent elements. I am a bit worried that allowing that would muddy the waters a bit and may lead to interpreting matrix types as similar to arrays, instead of single value types with restricted element access. Does that make sense?

Yes at the moment I think we want to limit element wise accesses/modifications to go through the access operator only, to guarantee we can rely on the vector forms in codegen.

Additionally I think at least initially we want to avoid handing out pointers to elements, as it may be tempting to use for pointer-based accesses to subsequent elements. I am a bit worried that allowing that would muddy the waters a bit and may lead to interpreting matrix types as similar to arrays, instead of single value types with restricted element access. Does that make sense?

It does make sense, although it does make it very important that code generation narrows the relevant particular load/extractvalue and load/insertvalue/store sequences, or else performance and code size will be completely unacceptable for large matrices.

The test changes in the other patch look great, thanks.

fhahn added a comment.May 29 2020, 4:03 PM

Yes at the moment I think we want to limit element wise accesses/modifications to go through the access operator only, to guarantee we can rely on the vector forms in codegen.

Additionally I think at least initially we want to avoid handing out pointers to elements, as it may be tempting to use for pointer-based accesses to subsequent elements. I am a bit worried that allowing that would muddy the waters a bit and may lead to interpreting matrix types as similar to arrays, instead of single value types with restricted element access. Does that make sense?

It does make sense, although it does make it very important that code generation narrows the relevant particular load/extractvalue and load/insertvalue/store sequences, or else performance and code size will be completely unacceptable for large matrices.

Yes, dealing with large vectors is currently a weakness of LLVM unfortunately. But breaking up operations on large vectors in general is something we are planning on implementing as part of the matrix lowering. And I think even if we do not allow taking addresses, we could still just load/store a single element with the index operator, if required (maybe also based on the actual size of the matrix). And if we discover that taking addresses is really beneficial to users, it should be relatively straight forward to allow it in a backwards-compatible way I think/

The test changes in the other patch look great, thanks.

Great, I'll update them ASAP, although it takes a while. I am also submitting some inline-response that didn't got submitted when I updated the patch a few hours ago.

clang/lib/CodeGen/CGExpr.cpp
1911

Oh thanks for pointing me to those cases. Fixed and test cases added.

3818

Hm I don't think that's currently happening. Is that required? It seems a bit unfortunate if we would have to force to wider bit-widths than necessary for the given index expressions.

clang/lib/Sema/SemaExpr.cpp
4553

Done, I've removed ActOnMatrixSubscriptExpr again.

4651

Yeah, you have to resolve some placeholders before you can check whether the base is a matrix type, and you can't resolve MS properties because the property access actually merges with the subscript in some cases.

I think that should be happening in the latest version, CheckPlaceholderExpr is used on Base, RowIdx and ColumnIdx.

Yes at the moment I think we want to limit element wise accesses/modifications to go through the access operator only, to guarantee we can rely on the vector forms in codegen.

Additionally I think at least initially we want to avoid handing out pointers to elements, as it may be tempting to use for pointer-based accesses to subsequent elements. I am a bit worried that allowing that would muddy the waters a bit and may lead to interpreting matrix types as similar to arrays, instead of single value types with restricted element access. Does that make sense?

It does make sense, although it does make it very important that code generation narrows the relevant particular load/extractvalue and load/insertvalue/store sequences, or else performance and code size will be completely unacceptable for large matrices.

Yes, dealing with large vectors is currently a weakness of LLVM unfortunately. But breaking up operations on large vectors in general is something we are planning on implementing as part of the matrix lowering. And I think even if we do not allow taking addresses, we could still just load/store a single element with the index operator, if required (maybe also based on the actual size of the matrix). And if we discover that taking addresses is really beneficial to users, it should be relatively straight forward to allow it in a backwards-compatible way I think/

Yeah, if you ever decide you want that IR pattern, it should be painless to make IRGen emit it. You might even consider doing it at -O0 if the backend wouldn't otherwise be narrowing then. (That doesn't need to be in this patch, of course.)

clang/lib/CodeGen/CGExpr.cpp
3818

Can you explain what cost you're worried about? I don't understand what the benefit of using a smaller IR type for the indexes is, and usually it's better to have stronger invariants coming out of Sema.

clang/lib/Sema/SemaExpr.cpp
4651

Yes, you're right.

4663

Somewhere in here would be where you'd do the index type conversion, FWIW.

I don't know if you want to allow a class with a conversion operator to an integer type, but that function you added for +/- should do it.

fhahn updated this revision to Diff 267601.Jun 1 2020, 6:27 AM

Force index types to size_t in Sema, remove code to extend index values in Codegen. Update tests to check more targeted IR.

fhahn marked 2 inline comments as done.Jun 1 2020, 6:35 AM
fhahn added inline comments.
clang/lib/CodeGen/CGExpr.cpp
3818

I now updated the code to force the index types to size_t in Sema and remove the zext generation here. If we have signed indices, we now generate sexts, which may require additional instructions down the road., which we would not require if we perform the math on the max bit width of the operands. But looking back now, I am not really sure if that would actually be safe in all cases.

We should probably just try to narrow the index types based on the number of vector elements as an IR optimization, if it becomes a problem.

clang/lib/Sema/SemaExpr.cpp
4663

I don't know if you want to allow a class with a conversion operator to an integer type, but that function you added for +/- should do it.

Yes I updated the code here to use the same conversion function and added tests for conversion operators.

rjmccall accepted this revision.Jun 1 2020, 10:40 AM

LGTM, thanks.

clang/lib/CodeGen/CGExpr.cpp
3818

It's UB if it's actually negative, right? So the sext really shouldn't be a problem.

This revision is now accepted and ready to land.Jun 1 2020, 10:40 AM
fhahn marked an inline comment as done.Jun 1 2020, 12:08 PM

Thanks for all the feedback John!

clang/lib/CodeGen/CGExpr.cpp
3818

It's UB if it's actually negative, right? So the sext really shouldn't be a problem.

Yes exactly. At the C/C++ level, the individual row/column expressions are guaranteed to be >= 0. In the IR we emit, we compute the index in a vector and we know that the computed index must be >= 0, which is slightly weaker. It might be worth checking how to encode the fact that the extension sources must be >= 0, if it becomes a problem.

This revision was automatically updated to reflect the committed changes.
nickdesaulniers added inline comments.
clang/lib/Sema/SemaExpr.cpp
4687–4688

In a release build:

llvm-project/clang/lib/Sema/SemaExpr.cpp:4737:10: warning: unused variable 'ConversionOk' [-Wunused-variable]
    bool ConversionOk = tryConvertToTy(*this, Context.getSizeType(), &ConvExpr);
         ^
fhahn marked an inline comment as done.Jun 2 2020, 2:51 AM
fhahn added inline comments.
clang/lib/Sema/SemaExpr.cpp
4687–4688

Oh, of course, thanks for letting me know! Should be fixed in a6a42df506ca93df69725f732c396050060f026f