@@ -226,17 +226,9 @@ SpirvInstruction *SpirvBuilder::createLoad(QualType resultType,
226226 if (!bitfieldInfo.hasValue ())
227227 return instruction;
228228
229- auto *offset = getConstantInt (
230- astContext.UnsignedIntTy ,
231- llvm::APInt (32 , static_cast <uint64_t >(bitfieldInfo->offsetInBits ),
232- /* isSigned= */ false ));
233- auto *count = getConstantInt (
234- astContext.UnsignedIntTy ,
235- llvm::APInt (32 , static_cast <uint64_t >(bitfieldInfo->sizeInBits ),
236- /* isSigned= */ false ));
237- return createBitFieldExtract (
238- resultType, instruction, offset, count,
239- pointer->getAstResultType ()->isSignedIntegerOrEnumerationType (), loc);
229+ return createBitFieldExtract (resultType, instruction,
230+ bitfieldInfo->offsetInBits ,
231+ bitfieldInfo->sizeInBits , loc, range);
240232}
241233
242234SpirvCopyObject *SpirvBuilder::createCopyObject (QualType resultType,
@@ -980,12 +972,71 @@ SpirvBuilder::createBitFieldInsert(QualType resultType, SpirvInstruction *base,
980972 return inst;
981973}
982974
983- SpirvBitFieldExtract *SpirvBuilder::createBitFieldExtract (
984- QualType resultType, SpirvInstruction *base, SpirvInstruction *offset,
985- SpirvInstruction *count, bool isSigned, SourceLocation loc) {
975+ SpirvInstruction *SpirvBuilder::createEmulatedBitFieldExtract (
976+ QualType resultType, uint32_t baseTypeBitwidth, SpirvInstruction *base,
977+ unsigned bitOffset, unsigned bitCount, SourceLocation loc,
978+ SourceRange range) {
979+ assert (bitCount <= 64 &&
980+ " Bitfield extraction emulation can only extract at most 64 bits." );
981+
982+ // The base is a raw struct field, which can contain several bitfields:
983+ // raw field: AAAABBBBCCCCCCCCDDDD
984+ // Extracting B means shifting it right until B's LSB is the basetype LSB.
985+ // But first, we need to left shift until B's MSB becomes the basetype MSB:
986+ // - is B is signed, its sign bits won't necessarily extend up to the
987+ // basetype MSB.
988+ // - meaning a right-shift could fail to sign-extend.
989+ // - shifting left first, then right makes sure the sign extension happens.
990+
991+ // input: AAAABBBBCCCCCCCCDDDD
992+ // output: BBBBCCCCCCCCDDDD0000
993+ auto *leftShiftOffset =
994+ getConstantInt (astContext.UnsignedIntTy ,
995+ llvm::APInt (32 , baseTypeBitwidth - bitOffset - bitCount));
996+ auto *leftShift = createBinaryOp (spv::Op::OpShiftLeftLogical, resultType,
997+ base, leftShiftOffset, loc, range);
998+
999+ // input: BBBBCCCCCCCCDDDD0000
1000+ // output: SSSSSSSSSSSSSSSSBBBB
1001+ auto *rightShiftOffset = getConstantInt (
1002+ astContext.UnsignedIntTy , llvm::APInt (32 , baseTypeBitwidth - bitCount));
1003+ auto *rightShift = createBinaryOp (spv::Op::OpShiftRightArithmetic, resultType,
1004+ leftShift, rightShiftOffset, loc, range);
1005+
1006+ if (resultType == QualType ({})) {
1007+ auto baseType = dyn_cast<IntegerType>(base->getResultType ());
1008+ leftShift->setResultType (baseType);
1009+ rightShift->setResultType (baseType);
1010+ }
1011+
1012+ return rightShift;
1013+ }
1014+
1015+ SpirvInstruction *
1016+ SpirvBuilder::createBitFieldExtract (QualType resultType, SpirvInstruction *base,
1017+ unsigned bitOffset, unsigned bitCount,
1018+ SourceLocation loc, SourceRange range) {
9861019 assert (insertPoint && " null insert point" );
987- auto *inst = new (context)
988- SpirvBitFieldExtract (resultType, loc, base, offset, count, isSigned);
1020+
1021+ uint32_t bitWidth = 0 ;
1022+ if (resultType == QualType ({})) {
1023+ assert (base->hasResultType () && " No type information for bitfield." );
1024+ bitWidth = dyn_cast<IntegerType>(base->getResultType ())->getBitwidth ();
1025+ } else {
1026+ bitWidth = getElementSpirvBitwidth (astContext, resultType,
1027+ spirvOptions.enable16BitTypes );
1028+ }
1029+
1030+ if (bitWidth != 32 )
1031+ return createEmulatedBitFieldExtract (resultType, bitWidth, base, bitOffset,
1032+ bitCount, loc, range);
1033+
1034+ auto *offset =
1035+ getConstantInt (astContext.UnsignedIntTy , llvm::APInt (32 , bitOffset));
1036+ auto *count =
1037+ getConstantInt (astContext.UnsignedIntTy , llvm::APInt (32 , bitCount));
1038+ auto *inst =
1039+ new (context) SpirvBitFieldExtract (resultType, loc, base, offset, count);
9891040 insertPoint->addInstruction (inst);
9901041 inst->setRValue (true );
9911042 return inst;
0 commit comments