[cfe-dev] Matrix Support in Clang

John McCall via cfe-dev cfe-dev at lists.llvm.org
Thu Mar 26 16:02:42 PDT 2020


On 26 Mar 2020, at 18:21, Florian Hahn wrote:
> Thank you very much for your comments John! Responses inline and 
> I’ve also updated
>
> On Mar 25, 2020, at 20:39, John McCall <rjmccall at apple.com> wrote:
>> You should require the element type to be unqualified and then apply 
>> qualifiers “outside” of the matrix type. That is, you can have a 
>> const float4x4, but not a const_float4x4.
>
> Agreed, thanks! I’ve added
>
> "The element type must be unqualified and qualifiers are applied to 
> the matrix type directly.”

Sounds good.

>> Why do you want to guarantee the same alignment as the element type? 
>> Isn’t that going to be seriously performance-limiting for most 
>> matrix types?
>>
>> If your goal is to make it easy to load / store matrices from an 
>> existing buffer, I would recommend adding separate operations to do 
>> that instead of (I assume) expecting users to simply cast those 
>> buffers to a pointer-to-matrix type and dereference. That will also 
>> allow you to use non-packed representations for matrices. 
>> Furthermore, you can parameterize the operation by the 
>> row/column-major-ness of the buffer and then simply use a canonical 
>> representation for matrix types.
>
> The main reason was allowing users to cast between element type/matrix 
> pointers to load/store matrixes from buffers. But I think it would 
> indeed be better to disallow such casts and not limit ourselves to the 
> element type alignment. There already are the 
> builtin_matrix_column_load/builtin_matrix_column_store which can be 
> used instead of going through casts. In the future, similar builtins 
> could be added to load data in row-major layouts.
>
> I think initially it would be best to go with implementation defined 
> alignment. What do you think? (I’ve reworded the sentence to "A 
> matrix type is a *scalar type* and its alignment is implementation 
> defined.”)

Yeah, making the size and alignment implementation-defined is the right 
spec-ese.

>> TODO: Allow reinterpret_cast from pointer to element type. Make 
>> aliasing work.
>>
>> This seems like an anti-goal. Maybe you want a reinterpret_cast 
>> between matrix types with the same total storage size, though? Not 
>> sure if that’s a good idea.
>
> Agreed, now that we cannot cast element type pointers to matrix 
> pointer I think we should disallow it here. It should simply be enough 
> to drop the TODO, right?

Yeah, that would be fine.

>> Standard Conversions
>>
>> The standard conversions are extended as follows.
>>
>> For integral promotions, floating-point promotion, integral 
>> conversions, floating-point conversions, and floating-integral 
>> conversions: apply the rules to the underlying type of the matrix 
>> type. The resulting type is a matrix type with that underlying 
>> element type. The resulting value is as follows:
>>
>> * If the original value was of matrix type, each element is converted 
>> element by element.
>> * If the original value was not of matrix type, each element takes 
>> the value of the original value.
>>
>> This isn’t sufficient; you need to describe what happens if the 
>> element counts don’t match. I assume this is ill-formed.
>
> Yes, the dimension should match.
>
> I’ve added "If the number of rows or columns differ between the 
> original and resulting type, the program is ill-formed. Otherwise the 
> resulting value is as follows:"

Sounds good.

>> Arithmetic Conversions
>>
>> The usual arithmetic conversions are extended as follows.
>>
>> Insert at the start:
>>
>> * If either operand is of matrix type, apply the usual arithmetic 
>> conversions using its underlying element type. The resulting type is 
>> a matrix type with that underlying element type.
>>
>> This seems like a mistake, mostly because of the integer promotions. 
>> You really want short_matrix + short_matrix to yield an int_matrix, 
>> or -short_matrix to be an int_matrix? I would recommend that you 
>> specify this as working without integer promotion, so that the result 
>> of an operation two integer operations just has (1) the greater rank 
>> and (2) is unsigned if there’s a signedness mismatch and the signed 
>> type can’t express the full range of the unsigned type.
>
> The intention of choosing the rules for the underlying type was 
> consistency with the existing behavior, but maybe it would be 
> beneficial to forbid them. I think with both there might be source for 
> confusion, but it might be simpler to not allow promotion.

It’s an interesting question.  In a totally different language, I 
would say that you shouldn’t allow mis-matched binary operations or 
implicit conversions, but that explicit casts should be able to do 
arbitrary element-wise conversions.  That’s not really consistent with 
C’s normal behavior, though.  It also might be really pedantic around 
e.g. scalar multiplication by a literal: would you have to write 
`short4x4 * (short) 2`?  On the other hand, presumably you wouldn’t 
want `float4x4 * 2.0` to yield a `double4x4`.

>> You also need to specify what happens if you pass a matrix as a 
>> variadic argument.
>>
> Initially they would be passed similar to ext_vector values, but we 
> should spell the rules out correctly here. I’ll add a TODO.

Yeah, this is definitely a long-term question.

>> Matrix Type Element Access Operator
>>
>> An expression of the form `postfix-expression 
>> [expression][expression]` where the postfix-expression is of matrix 
>> type is a matrix element access expression. expression shall not be a 
>> comma expression, and shall be a prvalue of unscoped enumeration or 
>> integral type. Given the expression E1[E2][E3], the result is an 
>> lvalue of the same type as the underlying element type of the matrix 
>> that refers to the value at E2 row and E3 column in the matrix. The 
>> expression E1 is sequenced before E2 and E3. The expressions E2 and 
>> E3 are unsequenced.
>>
>> Note: We thought about providing an expression of the form 
>> `postfix-expression [expression]` to access columns of a matrix. We 
>> think that such an expression would be problematic once both column 
>> and row major matrixes are supported: depending on the memory layout, 
>> either accessing columns or rows can be done efficiently, but not 
>> both. Instead, we propose to provide builtins to extract rows and 
>> columns from a matrix. This makes the operations more explicit.
>>
>> Okay, so what happens if you do write matrix[0]?
>>
>
> That is not supported. We should probably state explicitly that single 
> index operators on matrix values are ill-defined or something like 
> that?

Yeah, you can say that incomplete subscripts can only be used as the 
base operand of another subscript.  There’s a similar rule with 
member-function accesses in C++, which can only be the function operand 
of a call.  You can enforce that rule reliably in Clang with a 
placeholder type.

John.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20200326/f9b3f237/attachment.html>


More information about the cfe-dev mailing list