@@ -70,6 +70,15 @@ static bool isIntrinsicExpansion(Function &F) {
7070 case Intrinsic::vector_reduce_add:
7171 case Intrinsic::vector_reduce_fadd:
7272 return true ;
73+ case Intrinsic::dx_resource_load_typedbuffer: // want to transform double and
74+ // double2
75+ return F.getReturnType ()
76+ ->getStructElementType (0 )
77+ ->getScalarType ()
78+ ->isDoubleTy ();
79+ case Intrinsic::dx_resource_store_typedbuffer: // want to transform double and
80+ // double2
81+ return F.getFunctionType ()->getParamType (2 )->getScalarType ()->isDoubleTy ();
7382 }
7483 return false ;
7584}
@@ -532,6 +541,80 @@ static Value *expandRadiansIntrinsic(CallInst *Orig) {
532541 return Builder.CreateFMul (X, PiOver180);
533542}
534543
544+ static void expandTypedBufferLoadIntrinsic (CallInst *Orig) {
545+ IRBuilder<> Builder (Orig);
546+
547+ unsigned ExtractNum =
548+ Orig->getType ()->getStructElementType (0 )->isVectorTy () ? 4 : 2 ;
549+ Type *Ty = VectorType::get (Builder.getInt32Ty (), ExtractNum, false );
550+
551+ Type *LoadType = StructType::get (Ty, Builder.getInt1Ty ());
552+ auto *X =
553+ Builder.CreateIntrinsic (LoadType, Intrinsic::dx_resource_load_typedbuffer,
554+ {Orig->getOperand (0 ), Orig->getOperand (1 )});
555+
556+ // create new extract value
557+ Value *Extract = Builder.CreateExtractValue (X, {0 });
558+
559+ SmallVector<Value *> ExtractElements;
560+ for (unsigned I = 0 ; I < ExtractNum; ++I)
561+ ExtractElements.push_back (
562+ Builder.CreateExtractElement (Extract, (uint64_t )I));
563+
564+ // combine into double(s)
565+ Value *Result =
566+ PoisonValue::get (VectorType::get (Builder.getDoubleTy (), 2 , false ));
567+ for (unsigned I = 0 ; I < ExtractNum; I += 2 ) {
568+ Value *Dbl =
569+ Builder.CreateIntrinsic (Builder.getDoubleTy (), Intrinsic::dx_asdouble,
570+ {ExtractElements[I], ExtractElements[I + 1 ]});
571+ if (ExtractNum == 4 )
572+ Result = Builder.CreateInsertElement (Result, Dbl, (uint64_t )I / 2 );
573+ else
574+ Result = Dbl;
575+ }
576+
577+ assert (Orig->hasOneUser () && " TypedBufferLoad is expected to have one user" );
578+ auto *U = Orig->user_back ();
579+ auto *OldExtract = dyn_cast<ExtractValueInst>(U);
580+ if (!OldExtract)
581+ llvm_unreachable (" TypedBufferLoad's only users should be ExtractValueInst" );
582+ OldExtract->replaceAllUsesWith (Result);
583+ OldExtract->eraseFromParent ();
584+ }
585+
586+ void expandTypedBufferStoreIntrinsic (CallInst *Orig) {
587+ IRBuilder<> Builder (Orig);
588+
589+ unsigned ExtractNum =
590+ Orig->getFunctionType ()->getParamType (2 )->isVectorTy () ? 4 : 2 ;
591+ Type *SplitElementTy = Builder.getInt32Ty ();
592+ SmallVector<int > Mask = {0 , 1 };
593+ if (ExtractNum == 4 ) {
594+ SplitElementTy = VectorType::get (SplitElementTy, 2 , false );
595+ Mask = {0 , 2 , 1 , 3 };
596+ }
597+
598+ // split our double(s)
599+ auto *SplitTy = llvm::StructType::get (SplitElementTy, SplitElementTy);
600+ Value *Split = Builder.CreateIntrinsic (SplitTy, Intrinsic::dx_splitdouble,
601+ Orig->getOperand (2 ));
602+ // create our vector
603+ Value *LowBits = Builder.CreateExtractValue (Split, 0 );
604+ Value *HighBits = Builder.CreateExtractValue (Split, 1 );
605+ Value *Val;
606+ if (ExtractNum == 2 ) {
607+ Val = PoisonValue::get (VectorType::get (SplitElementTy, 2 , false ));
608+ Val = Builder.CreateInsertElement (Val, LowBits, (uint64_t )0 );
609+ Val = Builder.CreateInsertElement (Val, HighBits, 1 );
610+ } else
611+ Val = Builder.CreateShuffleVector (LowBits, HighBits, {0 , 2 , 1 , 3 });
612+
613+ Builder.CreateIntrinsic (Builder.getVoidTy (),
614+ Intrinsic::dx_resource_store_typedbuffer,
615+ {Orig->getOperand (0 ), Orig->getOperand (1 ), Val});
616+ }
617+
535618static Intrinsic::ID getMaxForClamp (Intrinsic::ID ClampIntrinsic) {
536619 if (ClampIntrinsic == Intrinsic::dx_uclamp)
537620 return Intrinsic::umax;
@@ -660,6 +743,14 @@ static bool expandIntrinsic(Function &F, CallInst *Orig) {
660743 case Intrinsic::dx_radians:
661744 Result = expandRadiansIntrinsic (Orig);
662745 break ;
746+ case Intrinsic::dx_resource_load_typedbuffer:
747+ expandTypedBufferLoadIntrinsic (Orig);
748+ Orig->eraseFromParent ();
749+ return true ;
750+ case Intrinsic::dx_resource_store_typedbuffer:
751+ expandTypedBufferStoreIntrinsic (Orig);
752+ Orig->eraseFromParent ();
753+ return true ;
663754 case Intrinsic::usub_sat:
664755 Result = expandUsubSat (Orig);
665756 break ;
0 commit comments