-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[HLSL] Make memory representation of boolean vectors in HLSL, vectors of i32. Add support for boolean swizzling. #123977
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
50f8b16
b231f4e
dd7e459
6734eed
d9a4777
e0638d1
2e534a5
793541d
1fe0951
505b17b
0e6da2b
fbaf536
3d22ed0
7a0ccdd
d3904c4
e947d2c
5b364cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -410,6 +410,12 @@ VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements, | |
VectorTypeBits.NumElements = nElements; | ||
} | ||
|
||
bool Type::isPackedVectorBoolType(const ASTContext &ctx) const { | ||
if (ctx.getLangOpts().HLSL) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be a dumb suggestion, but is the a way to just check if the mem reprsentation is i32 or i1? HLSL is probably the only language mode that needs this distinction but it feel like this shouldn't have a lang opt toggle based on the function name. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code to state that a bool vector should be a vector of i32s isn't accessible here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would make for slightly better abstraction to add a |
||
return false; | ||
return isExtVectorBoolType(); | ||
} | ||
|
||
BitIntType::BitIntType(bool IsUnsigned, unsigned NumBits) | ||
: Type(BitInt, QualType{}, TypeDependence::None), IsUnsigned(IsUnsigned), | ||
NumBits(NumBits) {} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1985,7 +1985,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, | |
|
||
if (const auto *ClangVecTy = Ty->getAs<VectorType>()) { | ||
// Boolean vectors use `iN` as storage type. | ||
if (ClangVecTy->isExtVectorBoolType()) { | ||
if (ClangVecTy->isPackedVectorBoolType(getContext())) { | ||
llvm::Type *ValTy = ConvertType(Ty); | ||
unsigned ValNumElems = | ||
cast<llvm::FixedVectorType>(ValTy)->getNumElements(); | ||
|
@@ -2064,6 +2064,10 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) { | |
|
||
if (Ty->isExtVectorBoolType()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you replaced a bunch of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My intention was to replace calls to 'isExtVectorBoolType' with 'isPackedVectorBoolType' anywhere we want an hlsl boolean vector to follow the normal handling path for vectors; Hopefully reviews will verify I got this right. |
||
llvm::Type *StoreTy = convertTypeForLoadStore(Ty, Value->getType()); | ||
if (StoreTy->isVectorTy() && StoreTy->getScalarSizeInBits() > | ||
Value->getType()->getScalarSizeInBits()) | ||
return Builder.CreateZExt(Value, StoreTy); | ||
|
||
// Expand to the memory bit width. | ||
unsigned MemNumElems = StoreTy->getPrimitiveSizeInBits(); | ||
// <N x i1> --> <P x i1>. | ||
|
@@ -2079,8 +2083,9 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) { | |
/// by convertTypeForLoadStore) to its primary IR type (as returned | ||
/// by ConvertType). | ||
llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) { | ||
if (Ty->isExtVectorBoolType()) { | ||
if (Ty->isPackedVectorBoolType(getContext())) { | ||
const auto *RawIntTy = Value->getType(); | ||
|
||
// Bitcast iP --> <P x i1>. | ||
auto *PaddedVecTy = llvm::FixedVectorType::get( | ||
Builder.getInt1Ty(), RawIntTy->getPrimitiveSizeInBits()); | ||
|
@@ -2091,10 +2096,10 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) { | |
return emitBoolVecConversion(V, ValNumElems, "extractvec"); | ||
} | ||
|
||
if (hasBooleanRepresentation(Ty) || Ty->isBitIntType()) { | ||
llvm::Type *ResTy = ConvertType(Ty); | ||
llvm::Type *ResTy = ConvertType(Ty); | ||
if (hasBooleanRepresentation(Ty) || Ty->isBitIntType() || | ||
Ty->isExtVectorBoolType()) | ||
return Builder.CreateTrunc(Value, ResTy, "loadedv"); | ||
} | ||
|
||
return Value; | ||
} | ||
|
@@ -2152,7 +2157,8 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr, | |
if (auto *VecTy = dyn_cast<llvm::FixedVectorType>(SrcTy)) { | ||
auto *NewVecTy = | ||
CGM.getABIInfo().getOptimalVectorMemoryType(VecTy, getLangOpts()); | ||
if (!ClangVecTy->isExtVectorBoolType() && VecTy != NewVecTy) { | ||
if (!ClangVecTy->isPackedVectorBoolType(getContext()) && | ||
VecTy != NewVecTy) { | ||
SmallVector<int, 16> Mask(NewVecTy->getNumElements(), -1); | ||
std::iota(Mask.begin(), Mask.begin() + VecTy->getNumElements(), 0); | ||
Value = Builder.CreateShuffleVector(Value, Mask, "extractVec"); | ||
|
@@ -2343,7 +2349,15 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) { | |
if (!ExprVT) { | ||
unsigned InIdx = getAccessedFieldNo(0, Elts); | ||
llvm::Value *Elt = llvm::ConstantInt::get(SizeTy, InIdx); | ||
return RValue::get(Builder.CreateExtractElement(Vec, Elt)); | ||
|
||
llvm::Value *Element = Builder.CreateExtractElement(Vec, Elt); | ||
|
||
llvm::Type *LVTy = ConvertType(LV.getType()); | ||
if (Element->getType()->getPrimitiveSizeInBits() > | ||
LVTy->getPrimitiveSizeInBits()) | ||
Element = Builder.CreateTrunc(Element, LVTy); | ||
|
||
return RValue::get(Element); | ||
} | ||
|
||
// Always use shuffle vector to try to retain the original program structure | ||
|
@@ -2354,6 +2368,10 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) { | |
Mask.push_back(getAccessedFieldNo(i, Elts)); | ||
|
||
Vec = Builder.CreateShuffleVector(Vec, Mask); | ||
|
||
if (LV.getType()->isExtVectorBoolType()) | ||
Vec = Builder.CreateTrunc(Vec, ConvertType(LV.getType()), "truncv"); | ||
Comment on lines
+2372
to
+2373
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this have a check for bitsize to avoid a no-op trunc, like we do elsewhere in this patch? |
||
|
||
return RValue::get(Vec); | ||
} | ||
|
||
|
@@ -2407,26 +2425,35 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, | |
// Read/modify/write the vector, inserting the new element. | ||
llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddress(), | ||
Dst.isVolatileQualified()); | ||
llvm::Type *VecTy = Vec->getType(); | ||
llvm::Value *SrcVal = Src.getScalarVal(); | ||
|
||
if (SrcVal->getType()->getPrimitiveSizeInBits() < | ||
VecTy->getScalarSizeInBits()) | ||
SrcVal = Builder.CreateZExt(SrcVal, VecTy->getScalarType()); | ||
|
||
auto *IRStoreTy = dyn_cast<llvm::IntegerType>(Vec->getType()); | ||
if (IRStoreTy) { | ||
auto *IRVecTy = llvm::FixedVectorType::get( | ||
Builder.getInt1Ty(), IRStoreTy->getPrimitiveSizeInBits()); | ||
Vec = Builder.CreateBitCast(Vec, IRVecTy); | ||
// iN --> <N x i1>. | ||
} | ||
llvm::Value *SrcVal = Src.getScalarVal(); | ||
|
||
// Allow inserting `<1 x T>` into an `<N x T>`. It can happen with scalar | ||
// types which are mapped to vector LLVM IR types (e.g. for implementing | ||
// an ABI). | ||
if (auto *EltTy = dyn_cast<llvm::FixedVectorType>(SrcVal->getType()); | ||
EltTy && EltTy->getNumElements() == 1) | ||
SrcVal = Builder.CreateBitCast(SrcVal, EltTy->getElementType()); | ||
|
||
Vec = Builder.CreateInsertElement(Vec, SrcVal, Dst.getVectorIdx(), | ||
"vecins"); | ||
if (IRStoreTy) { | ||
// <N x i1> --> <iN>. | ||
Vec = Builder.CreateBitCast(Vec, IRStoreTy); | ||
} | ||
|
||
Builder.CreateStore(Vec, Dst.getVectorAddress(), | ||
Dst.isVolatileQualified()); | ||
return; | ||
|
@@ -2623,14 +2650,12 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, | |
// This access turns into a read/modify/write of the vector. Load the input | ||
// value now. | ||
llvm::Value *Vec = Builder.CreateLoad(DstAddr, Dst.isVolatileQualified()); | ||
llvm::Type *VecTy = Vec->getType(); | ||
const llvm::Constant *Elts = Dst.getExtVectorElts(); | ||
|
||
llvm::Value *SrcVal = Src.getScalarVal(); | ||
|
||
if (const VectorType *VTy = Dst.getType()->getAs<VectorType>()) { | ||
unsigned NumSrcElts = VTy->getNumElements(); | ||
unsigned NumDstElts = | ||
cast<llvm::FixedVectorType>(Vec->getType())->getNumElements(); | ||
unsigned NumDstElts = cast<llvm::FixedVectorType>(VecTy)->getNumElements(); | ||
if (NumDstElts == NumSrcElts) { | ||
// Use shuffle vector is the src and destination are the same number of | ||
// elements and restore the vector mask since it is on the side it will be | ||
|
@@ -2639,6 +2664,11 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, | |
for (unsigned i = 0; i != NumSrcElts; ++i) | ||
Mask[getAccessedFieldNo(i, Elts)] = i; | ||
|
||
llvm::Value *SrcVal = Src.getScalarVal(); | ||
if (VecTy->getScalarSizeInBits() > | ||
SrcVal->getType()->getScalarSizeInBits()) | ||
SrcVal = Builder.CreateZExt(SrcVal, VecTy); | ||
|
||
Vec = Builder.CreateShuffleVector(SrcVal, Mask); | ||
} else if (NumDstElts > NumSrcElts) { | ||
// Extended the source vector to the same length and then shuffle it | ||
|
@@ -2649,7 +2679,8 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, | |
for (unsigned i = 0; i != NumSrcElts; ++i) | ||
ExtMask.push_back(i); | ||
ExtMask.resize(NumDstElts, -1); | ||
llvm::Value *ExtSrcVal = Builder.CreateShuffleVector(SrcVal, ExtMask); | ||
llvm::Value *ExtSrcVal = | ||
Builder.CreateShuffleVector(Src.getScalarVal(), ExtMask); | ||
// build identity | ||
SmallVector<int, 4> Mask; | ||
for (unsigned i = 0; i != NumDstElts; ++i) | ||
|
@@ -2674,6 +2705,11 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, | |
// be updating one element. | ||
unsigned InIdx = getAccessedFieldNo(0, Elts); | ||
llvm::Value *Elt = llvm::ConstantInt::get(SizeTy, InIdx); | ||
|
||
llvm::Value *SrcVal = Src.getScalarVal(); | ||
if (VecTy->getScalarSizeInBits() > SrcVal->getType()->getScalarSizeInBits()) | ||
SrcVal = Builder.CreateZExt(SrcVal, VecTy->getScalarType()); | ||
|
||
Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt); | ||
} | ||
|
||
|
@@ -4701,9 +4737,13 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { | |
|
||
// Store the vector to memory (because LValue wants an address). | ||
Address VecMem = CreateMemTemp(E->getBase()->getType()); | ||
// need to zero extend an hlsl boolean vector to store it back to memory | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably better to phrase this comment in terms of packed/non-packed boolean vectors given the abstraction in LangOpts |
||
QualType Ty = E->getBase()->getType(); | ||
llvm::Type *LTy = convertTypeForLoadStore(Ty, Vec->getType()); | ||
if (LTy->getScalarSizeInBits() > Vec->getType()->getScalarSizeInBits()) | ||
Vec = Builder.CreateZExt(Vec, LTy); | ||
Builder.CreateStore(Vec, VecMem); | ||
Base = MakeAddrLValue(VecMem, E->getBase()->getType(), | ||
AlignmentSource::Decl); | ||
Base = MakeAddrLValue(VecMem, Ty, AlignmentSource::Decl); | ||
} | ||
|
||
QualType type = | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1978,7 +1978,10 @@ llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM, | |
} | ||
|
||
// Zero-extend bool. | ||
if (C->getType()->isIntegerTy(1) && !destType->isBitIntType()) { | ||
// In HLSL bool vectors are stored in memory as a vector of i32 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here |
||
if ((C->getType()->isIntegerTy(1) && !destType->isBitIntType()) || | ||
(destType->isExtVectorBoolType() && | ||
!destType->isPackedVectorBoolType(CGM.getContext()))) { | ||
llvm::Type *boolTy = CGM.getTypes().ConvertTypeForMem(destType); | ||
llvm::Constant *Res = llvm::ConstantFoldCastOperand( | ||
llvm::Instruction::ZExt, C, boolTy, CGM.getDataLayout()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -112,6 +112,12 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) { | |
// Check for the boolean vector case. | ||
if (T->isExtVectorBoolType()) { | ||
auto *FixedVT = cast<llvm::FixedVectorType>(R); | ||
|
||
if (Context.getLangOpts().HLSL) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could use the |
||
llvm::Type *IRElemTy = ConvertTypeForMem(Context.BoolTy); | ||
return llvm::FixedVectorType::get(IRElemTy, FixedVT->getNumElements()); | ||
} | ||
|
||
// Pad to at least one byte. | ||
uint64_t BytePadded = std::max<uint64_t>(FixedVT->getNumElements(), 8); | ||
return llvm::IntegerType::get(FixedVT->getContext(), BytePadded); | ||
|
@@ -654,7 +660,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { | |
case Type::Vector: { | ||
const auto *VT = cast<VectorType>(Ty); | ||
// An ext_vector_type of Bool is really a vector of bits. | ||
llvm::Type *IRElemTy = VT->isExtVectorBoolType() | ||
llvm::Type *IRElemTy = VT->isPackedVectorBoolType(Context) | ||
? llvm::Type::getInt1Ty(getLLVMContext()) | ||
: VT->getElementType()->isMFloat8Type() | ||
? llvm::Type::getInt8Ty(getLLVMContext()) | ||
|
Uh oh!
There was an error while loading. Please reload this page.