Skip to content

[HLSL][Matrix] Support MatrixSingleSubscript Dynamic Index Swizzle #170777

@farzonl

Description

@farzonl

The introduction of the MatrixSingleSubscriptExpr AST type meant we needed a
custom emitter in EmitMatrixSingleSubscriptExpr which meant we needed a new
MatrixRow Lvalue type because ExtVectorElt had a requirment for constant
indicies. We can still use MakeExtVectorElt but only if the row index is
constant. For now if we don't have them then EmitExtVectorElementExpr fails.
Like so:

  if (Base.isMatrixRow())
    return EmitUnsupportedLValue(E, "Matrix single index swizzle");

That means today the following cases work

export float4 getMatrix(float4x4 M, int index) {
    return M[index];
}

export void setMatrix(out float4x4 M, int index, float4 V) {
    M[index] = V;
}

export void setMatrix2(out float4x4 M, float4 V) {
    M[3].abgr = V;
}

export void setMatrix3(out float4x4 M, float4 V) {
    M[1].rgba = V;
}

That also means this doesn't work

export void setMatrix4(out float4x4 M, int index, float4 V) {
    M[index].abgr = V;
}

export float3 getMatrix2(float4x4 M, int index) {
    return M[index].rgb;
}

This failing case while visually similar to swizzling on an array of vectors is
very different. for an array-of-vectors, the “hard part” (the dynamic index) is
already solved before the swizzle ever sees it. For matrices, you’re trying to
push that dynamic index into the swizzle layer, where it fundamentally doesn’t
fit. Example

float4 v[10];
float2 x = v[i].xy;

The AST just treates the array subscript as a base:

ArraySubscriptExpr( base = v, idx = i ) --> type float4
ExtVectorElementExpr( base = ArraySubscriptExpr, "xy" )

Crucially: the dynamic index i is already baked into the pointer. The LValue
itself doesn’t need to remember i separately. MakeExtVectorElt only needs:

  1. “where is the vector?” → baseLV.getAddress()
  2. “which components (xy)?” → constant mask {0, 1}

That’s why arrays-of-vectors don’t have your problem: the dynamic part (i) is
entirely handled by the array-subscript lvalue; the swizzle only deals with
constant component selection inside a single, already-chosen vector.

With matrices, what you want conceptually is very similar:

float4x4 M;
float2 x = M[row].xy;

But the the difference is Clang’s matrix extension doesn’t model a matrix as
“array of row-vectors” or “array of col-vectors” at the IR level. Its
represented as one singular vector. For example the ir would look like

instruction <16 x float>  // for a 4x4, flattened

Plan(s)

  1. Keep flattened representation but add custom row abstraction
    • The “swizzle” logic has to special-case “base is matrix-row” and do the right gather/scatter.

Metadata

Metadata

Assignees

No one assigned

    Labels

    HLSLHLSL Language Support

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions