@@ -42,6 +42,15 @@ class DXILIntrinsicExpansionLegacy : public ModulePass {
42
42
static char ID; // Pass identification.
43
43
};
44
44
45
+ static bool resourceAccessNeeds64BitExpansion (Module *M, Type *OverloadTy,
46
+ bool IsRaw) {
47
+ if (IsRaw && M->getTargetTriple ().getDXILVersion () > VersionTuple (1 , 2 ))
48
+ return false ;
49
+
50
+ Type *ScalarTy = OverloadTy->getScalarType ();
51
+ return ScalarTy->isDoubleTy () || ScalarTy->isIntegerTy (64 );
52
+ }
53
+
45
54
static bool isIntrinsicExpansion (Function &F) {
46
55
switch (F.getIntrinsicID ()) {
47
56
case Intrinsic::abs:
@@ -72,27 +81,19 @@ static bool isIntrinsicExpansion(Function &F) {
72
81
case Intrinsic::vector_reduce_fadd:
73
82
return true ;
74
83
case Intrinsic::dx_resource_load_rawbuffer:
75
- if (F.getParent ()->getTargetTriple ().getDXILVersion () > VersionTuple (1 , 2 ))
76
- return false ;
77
- // fallthrough to check if double or i64
78
- LLVM_FALLTHROUGH;
79
- case Intrinsic::dx_resource_load_typedbuffer: {
80
- // We need to handle i64, doubles, and vectors of them.
81
- Type *ScalarTy =
82
- F.getReturnType ()->getStructElementType (0 )->getScalarType ();
83
- return ScalarTy->isDoubleTy () || ScalarTy->isIntegerTy (64 );
84
- }
85
- case Intrinsic::dx_resource_store_rawbuffer: {
86
- if (F.getParent ()->getTargetTriple ().getDXILVersion () > VersionTuple (1 , 2 ))
87
- return false ;
88
- Type *ScalarTy = F.getFunctionType ()->getParamType (3 )->getScalarType ();
89
- return ScalarTy->isDoubleTy () || ScalarTy->isIntegerTy (64 );
90
- }
91
- case Intrinsic::dx_resource_store_typedbuffer: {
92
- // We need to handle i64 and doubles and vectors of i64 and doubles.
93
- Type *ScalarTy = F.getFunctionType ()->getParamType (2 )->getScalarType ();
94
- return ScalarTy->isDoubleTy () || ScalarTy->isIntegerTy (64 );
95
- }
84
+ return resourceAccessNeeds64BitExpansion (
85
+ F.getParent (), F.getReturnType ()->getStructElementType (0 ),
86
+ /* IsRaw*/ true );
87
+ case Intrinsic::dx_resource_load_typedbuffer:
88
+ return resourceAccessNeeds64BitExpansion (
89
+ F.getParent (), F.getReturnType ()->getStructElementType (0 ),
90
+ /* IsRaw*/ false );
91
+ case Intrinsic::dx_resource_store_rawbuffer:
92
+ return resourceAccessNeeds64BitExpansion (
93
+ F.getParent (), F.getFunctionType ()->getParamType (3 ), /* IsRaw*/ true );
94
+ case Intrinsic::dx_resource_store_typedbuffer:
95
+ return resourceAccessNeeds64BitExpansion (
96
+ F.getParent (), F.getFunctionType ()->getParamType (2 ), /* IsRaw*/ false );
96
97
}
97
98
return false ;
98
99
}
@@ -563,19 +564,20 @@ static bool expandBufferLoadIntrinsic(CallInst *Orig, bool IsRaw) {
563
564
bool IsDouble = ScalarTy->isDoubleTy ();
564
565
assert (IsDouble || ScalarTy->isIntegerTy (64 ) &&
565
566
" Only expand double or int64 scalars or vectors" );
566
- bool IsVector = isa<FixedVectorType>(BufferTy);
567
-
567
+ bool IsVector = false ;
568
568
unsigned ExtractNum = 2 ;
569
569
if (auto *VT = dyn_cast<FixedVectorType>(BufferTy)) {
570
- if (!IsRaw)
571
- assert (VT->getNumElements () == 2 &&
572
- " TypedBufferLoad vector must be size 2" );
573
570
ExtractNum = 2 * VT->getNumElements ();
571
+ IsVector = true ;
572
+ assert (IsRaw || ExtractNum == 4 && " TypedBufferLoad vector must be size 2" );
574
573
}
575
574
576
575
SmallVector<Value *, 2 > Loads;
577
576
Value *Result = PoisonValue::get (BufferTy);
578
577
unsigned Base = 0 ;
578
+ // If we need to extract more than 4 i32; we need to break it up into
579
+ // more than one load. LoadNum tells us how many i32s we are loading in
580
+ // each load
579
581
while (ExtractNum > 0 ) {
580
582
unsigned LoadNum = std::min (ExtractNum, 4u );
581
583
Type *Ty = VectorType::get (Builder.getInt32Ty (), LoadNum, false );
@@ -649,6 +651,8 @@ static bool expandBufferLoadIntrinsic(CallInst *Orig, bool IsRaw) {
649
651
} else {
650
652
// Use of the check bit
651
653
assert (Indices[0 ] == 1 && " Unexpected type for typedbufferload" );
654
+ // Note: This does not always match the historical behaviour of DXC.
655
+ // See https://github.com/microsoft/DirectXShaderCompiler/issues/7622
652
656
if (!CheckBit) {
653
657
SmallVector<Value *, 2 > CheckBits;
654
658
for (Value *L : Loads)
@@ -666,22 +670,22 @@ static bool expandBufferLoadIntrinsic(CallInst *Orig, bool IsRaw) {
666
670
static bool expandBufferStoreIntrinsic (CallInst *Orig, bool IsRaw) {
667
671
IRBuilder<> Builder (Orig);
668
672
669
- Type *BufferTy = Orig->getFunctionType ()->getParamType (IsRaw ? 3 : 2 );
673
+ unsigned ValIndex = IsRaw ? 3 : 2 ;
674
+ Type *BufferTy = Orig->getFunctionType ()->getParamType (ValIndex);
670
675
Type *ScalarTy = BufferTy->getScalarType ();
671
676
bool IsDouble = ScalarTy->isDoubleTy ();
672
677
assert ((IsDouble || ScalarTy->isIntegerTy (64 )) &&
673
678
" Only expand double or int64 scalars or vectors" );
674
679
675
680
// Determine if we're dealing with a vector or scalar
676
- bool IsVector = isa<FixedVectorType>(BufferTy) ;
681
+ bool IsVector = false ;
677
682
unsigned ExtractNum = 2 ;
678
683
unsigned VecLen = 0 ;
679
684
if (auto *VT = dyn_cast<FixedVectorType>(BufferTy)) {
680
- if (!IsRaw)
681
- assert (VT->getNumElements () == 2 &&
682
- " TypedBufferStore vector must be size 2" );
683
685
VecLen = VT->getNumElements ();
686
+ assert (IsRaw || VecLen == 2 && " TypedBufferStore vector must be size 2" );
684
687
ExtractNum = VecLen * 2 ;
688
+ IsVector = true ;
685
689
}
686
690
687
691
// Create the appropriate vector type for the result
@@ -699,12 +703,12 @@ static bool expandBufferStoreIntrinsic(CallInst *Orig, bool IsRaw) {
699
703
if (IsDouble) {
700
704
auto *SplitTy = llvm::StructType::get (SplitElementTy, SplitElementTy);
701
705
Value *Split = Builder.CreateIntrinsic (SplitTy, Intrinsic::dx_splitdouble,
702
- {Orig->getOperand (IsRaw ? 3 : 2 )});
706
+ {Orig->getOperand (ValIndex )});
703
707
LowBits = Builder.CreateExtractValue (Split, 0 );
704
708
HighBits = Builder.CreateExtractValue (Split, 1 );
705
709
} else {
706
710
// Handle int64 type(s)
707
- Value *InputVal = Orig->getOperand (IsRaw ? 3 : 2 );
711
+ Value *InputVal = Orig->getOperand (ValIndex );
708
712
Constant *ShiftAmt = Builder.getInt64 (32 );
709
713
if (IsVector)
710
714
ShiftAmt =
@@ -728,6 +732,9 @@ static bool expandBufferStoreIntrinsic(CallInst *Orig, bool IsRaw) {
728
732
Val = Builder.CreateInsertElement (Val, HighBits, Builder.getInt32 (1 ));
729
733
}
730
734
735
+ // If we need to extract more than 4 i32; we need to break it up into
736
+ // more than one store. StoreNum tells us how many i32s we are storing in
737
+ // each store
731
738
unsigned Base = 0 ;
732
739
while (ExtractNum > 0 ) {
733
740
unsigned StoreNum = std::min (ExtractNum, 4u );
@@ -744,7 +751,10 @@ static bool expandBufferStoreIntrinsic(CallInst *Orig, bool IsRaw) {
744
751
for (unsigned I = 0 ; I < StoreNum; ++I) {
745
752
Mask.push_back (Base + I);
746
753
}
747
- Value *SubVal = Builder.CreateShuffleVector (Val, Mask);
754
+
755
+ Value *SubVal = Val;
756
+ if (VecLen > 2 )
757
+ SubVal = Builder.CreateShuffleVector (Val, Mask);
748
758
749
759
Args.push_back (SubVal);
750
760
// Create the final intrinsic call
0 commit comments