Skip to content

SPIRVEmitIntrinsics assertion failure when assigning a vec3 to an array of vec4s #156775

@bob80905

Description

@bob80905

Given this line of HLSL:
Out3[tid.x].xyz = vec3s[tid.x];
Where
RWStructuredBuffer<half4> Out3 : register(u3); // test half3
and
half3 vec3s [4] = { v3_1, v3_2, v3_3, v3_4 };, where the initializer list is composed of half3's, and tid.x is

[numthreads(4,1,1)]
void main(uint3 tid : SV_GroupThreadID)

constrained to [0,3],
SPIRVEmitIntrinsics.cpp hits an assertion failure.
The context of the assertion is below:

bool SPIRVEmitIntrinsics::walkLogicalAccessChain(
    GetElementPtrInst &GEP,
    const std::function<void(Type *, uint64_t)> &OnLiteralIndexing,
    const std::function<void(Type *, Value *)> &OnDynamicIndexing) {
  // We only rewrite i8* GEP. Other should be left as-is.
  // Valid i8* GEP must always have a single index.
  assert(GEP.getSourceElementType() ==
         IntegerType::getInt8Ty(CurrF->getContext()));
  assert(GEP.getNumIndices() == 1);

  auto &DL = CurrF->getDataLayout();
  Value *Src = getPointerRoot(GEP.getPointerOperand());
  Type *CurType = deduceElementType(Src, true);

  Value *Operand = *GEP.idx_begin();
  ConstantInt *CI = dyn_cast<ConstantInt>(Operand);
  if (!CI) {
    ArrayType *AT = dyn_cast<ArrayType>(CurType);
    // Operand is not constant. Either we have an array and accept it, or we
    // give up.
    if (AT)
      OnDynamicIndexing(AT->getElementType(), Operand);
    return AT == nullptr;
  }

  assert(CI);
  uint64_t Offset = CI->getZExtValue();

  do {
    if (ArrayType *AT = dyn_cast<ArrayType>(CurType)) {
      uint32_t EltTypeSize = DL.getTypeSizeInBits(AT->getElementType()) / 8;
      assert(Offset < AT->getNumElements() * EltTypeSize);
      uint64_t Index = Offset / EltTypeSize;
      Offset = Offset - (Index * EltTypeSize);
      CurType = AT->getElementType();
      OnLiteralIndexing(CurType, Index);
    } else if (StructType *ST = dyn_cast<StructType>(CurType)) {
      uint32_t StructSize = DL.getTypeSizeInBits(ST) / 8;
      assert(Offset < StructSize);
      (void)StructSize;
      const auto &STL = DL.getStructLayout(ST);
      unsigned Element = STL->getElementContainingOffset(Offset);
      Offset -= STL->getElementOffset(Element);
      CurType = ST->getElementType(Element);
      OnLiteralIndexing(CurType, Element);
    } else {
      // Vector type indexing should not use GEP.
      // So if we have an index left, something is wrong. Giving up.
      return true;
    }
  } while (Offset > 0);

  return false;
}

When assigning the half3's, we actually enter the else case, where the comment states that something has gone wrong.
I believe it's possible this logic doesn't account for the padding that's added when storing half3's, since Offset goes from 8 to 16 to 24, as if 4 halves were stored, when really it should probably be going from 6 to 12 to 18. When this function runs 3 times while pertaining to Out3, which is being stored to in the hlsl, the assertion fails, but behavior is consistent with the half and half2 cases.

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