-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[HLSL] Add support for elementwise and aggregate splat casting struct types with bitfields #161263
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 1 commit
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 |
---|---|---|
|
@@ -6784,74 +6784,104 @@ LValue CodeGenFunction::EmitPseudoObjectLValue(const PseudoObjectExpr *E) { | |
return emitPseudoObjectExpr(*this, E, true, AggValueSlot::ignored()).LV; | ||
} | ||
|
||
void CodeGenFunction::FlattenAccessAndType( | ||
Address Addr, QualType AddrType, | ||
SmallVectorImpl<std::pair<Address, llvm::Value *>> &AccessList, | ||
SmallVectorImpl<QualType> &FlatTypes) { | ||
// WorkList is list of type we are processing + the Index List to access | ||
// the field of that type in Addr for use in a GEP | ||
llvm::SmallVector<std::pair<QualType, llvm::SmallVector<llvm::Value *, 4>>, | ||
16> | ||
void CodeGenFunction::FlattenAccessAndTypeLValue( | ||
LValue Val, SmallVectorImpl<LValue> &AccessList) { | ||
|
||
llvm::SmallVector< | ||
std::tuple<LValue, QualType, llvm::SmallVector<llvm::Value *, 4>>, 16> | ||
WorkList; | ||
llvm::IntegerType *IdxTy = llvm::IntegerType::get(getLLVMContext(), 32); | ||
// Addr should be a pointer so we need to 'dereference' it | ||
WorkList.push_back({AddrType, {llvm::ConstantInt::get(IdxTy, 0)}}); | ||
WorkList.push_back({Val, Val.getType(), {llvm::ConstantInt::get(IdxTy, 0)}}); | ||
|
||
while (!WorkList.empty()) { | ||
auto [T, IdxList] = WorkList.pop_back_val(); | ||
auto [LVal, T, IdxList] = WorkList.pop_back_val(); | ||
T = T.getCanonicalType().getUnqualifiedType(); | ||
assert(!isa<MatrixType>(T) && "Matrix types not yet supported in HLSL"); | ||
|
||
if (const auto *CAT = dyn_cast<ConstantArrayType>(T)) { | ||
uint64_t Size = CAT->getZExtSize(); | ||
for (int64_t I = Size - 1; I > -1; I--) { | ||
llvm::SmallVector<llvm::Value *, 4> IdxListCopy = IdxList; | ||
IdxListCopy.push_back(llvm::ConstantInt::get(IdxTy, I)); | ||
WorkList.emplace_back(CAT->getElementType(), IdxListCopy); | ||
WorkList.push_back({LVal, CAT->getElementType(), IdxListCopy}); | ||
} | ||
} else if (const auto *RT = dyn_cast<RecordType>(T)) { | ||
const RecordDecl *Record = RT->getOriginalDecl()->getDefinitionOrSelf(); | ||
assert(!Record->isUnion() && "Union types not supported in flat cast."); | ||
|
||
const CXXRecordDecl *CXXD = dyn_cast<CXXRecordDecl>(Record); | ||
|
||
llvm::SmallVector<QualType, 16> FieldTypes; | ||
llvm::SmallVector< | ||
std::tuple<LValue, QualType, llvm::SmallVector<llvm::Value *, 4>>, 16> | ||
ReverseList; | ||
if (CXXD && CXXD->isStandardLayout()) | ||
Record = CXXD->getStandardLayoutBaseWithFields(); | ||
|
||
// deal with potential base classes | ||
if (CXXD && !CXXD->isStandardLayout()) { | ||
for (auto &Base : CXXD->bases()) | ||
FieldTypes.push_back(Base.getType()); | ||
if (CXXD->getNumBases() > 0) { | ||
assert(CXXD->getNumBases() == 1 && | ||
"HLSL doesn't support multiple inheritance."); | ||
auto Base = CXXD->bases_begin(); | ||
llvm::SmallVector<llvm::Value *, 4> IdxListCopy = IdxList; | ||
IdxListCopy.push_back(llvm::ConstantInt::get( | ||
IdxTy, 0)); // base struct should be at index zero | ||
ReverseList.insert(ReverseList.end(), | ||
{LVal, Base->getType(), IdxListCopy}); | ||
} | ||
} | ||
|
||
for (auto *FD : Record->fields()) | ||
FieldTypes.push_back(FD->getType()); | ||
const CGRecordLayout &Layout = CGM.getTypes().getCGRecordLayout(Record); | ||
|
||
for (int64_t I = FieldTypes.size() - 1; I > -1; I--) { | ||
llvm::SmallVector<llvm::Value *, 4> IdxListCopy = IdxList; | ||
IdxListCopy.push_back(llvm::ConstantInt::get(IdxTy, I)); | ||
WorkList.insert(WorkList.end(), {FieldTypes[I], IdxListCopy}); | ||
llvm::Type *LLVMT = ConvertTypeForMem(T); | ||
CharUnits Align = getContext().getTypeAlignInChars(T); | ||
LValue RLValue; | ||
bool createdGEP = false; | ||
for (auto *FD : Record->fields()) { | ||
if (FD->isBitField()) { | ||
if (FD->isUnnamedBitField()) | ||
continue; | ||
if (!createdGEP) { | ||
createdGEP = true; | ||
Address GEP = Builder.CreateInBoundsGEP(LVal.getAddress(), IdxList, | ||
LLVMT, Align, "gep"); | ||
Comment on lines
+6843
to
+6846
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 would like to see (in a test) how it looks like when there are multiple fields with bitfield annotation, when does the GEP get skipped. And what if the set of bitfields span multiple 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. Also, what if you have a set of bitfields, a regular field, and then set of bitfields? Should the 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. no it should only create a gep once, since its for the struct itself. I'll add a test 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 gep should be skipped if it is a regular field and not a bitfield. EmitLValueForField should only be used if it is a bitfield and we need to construct a special LValue for it; this requires the GEP for the struct itself. Otherwise we wait as long as possible to generate the gep to access a 'scalar' field, because we want to generate as few geps as possible. 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. @hekota I added a test to try and address your questions. Let me know if it looks sufficient to you. |
||
RLValue = MakeAddrLValue(GEP, T); | ||
} | ||
LValue FieldLVal = EmitLValueForField(RLValue, FD, true); | ||
ReverseList.insert(ReverseList.end(), {FieldLVal, FD->getType(), {}}); | ||
} else { | ||
llvm::SmallVector<llvm::Value *, 4> IdxListCopy = IdxList; | ||
IdxListCopy.push_back( | ||
llvm::ConstantInt::get(IdxTy, Layout.getLLVMFieldNo(FD))); | ||
ReverseList.insert(ReverseList.end(), | ||
{LVal, FD->getType(), IdxListCopy}); | ||
} | ||
} | ||
|
||
std::reverse(ReverseList.begin(), ReverseList.end()); | ||
llvm::append_range(WorkList, ReverseList); | ||
} else if (const auto *VT = dyn_cast<VectorType>(T)) { | ||
llvm::Type *LLVMT = ConvertTypeForMem(T); | ||
CharUnits Align = getContext().getTypeAlignInChars(T); | ||
Address GEP = | ||
Builder.CreateInBoundsGEP(Addr, IdxList, LLVMT, Align, "vector.gep"); | ||
Address GEP = Builder.CreateInBoundsGEP(LVal.getAddress(), IdxList, LLVMT, | ||
Align, "vector.gep"); | ||
LValue Base = MakeAddrLValue(GEP, T); | ||
for (unsigned I = 0, E = VT->getNumElements(); I < E; I++) { | ||
llvm::Value *Idx = llvm::ConstantInt::get(IdxTy, I); | ||
// gep on vector fields is not recommended so combine gep with | ||
// extract/insert | ||
AccessList.emplace_back(GEP, Idx); | ||
FlatTypes.push_back(VT->getElementType()); | ||
llvm::Constant *Idx = llvm::ConstantInt::get(IdxTy, I); | ||
LValue LV = | ||
LValue::MakeVectorElt(Base.getAddress(), Idx, VT->getElementType(), | ||
Base.getBaseInfo(), TBAAAccessInfo()); | ||
AccessList.emplace_back(LV); | ||
} | ||
} else { | ||
// a scalar/builtin type | ||
llvm::Type *LLVMT = ConvertTypeForMem(T); | ||
CharUnits Align = getContext().getTypeAlignInChars(T); | ||
Address GEP = | ||
Builder.CreateInBoundsGEP(Addr, IdxList, LLVMT, Align, "gep"); | ||
AccessList.emplace_back(GEP, nullptr); | ||
FlatTypes.push_back(T); | ||
} else { // a scalar/builtin type | ||
if (!IdxList.empty()) { | ||
llvm::Type *LLVMT = ConvertTypeForMem(T); | ||
CharUnits Align = getContext().getTypeAlignInChars(T); | ||
Address GEP = Builder.CreateInBoundsGEP(LVal.getAddress(), IdxList, | ||
LLVMT, Align, "gep"); | ||
AccessList.emplace_back(MakeAddrLValue(GEP, T)); | ||
} else // must be a bitfield we already created an lvalue for | ||
AccessList.emplace_back(LVal); | ||
} | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.