@@ -386,7 +386,8 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
386
386
// Traverse User instructions to deduce an element pointer type of the operand.
387
387
Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep (
388
388
Value *Op, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8) {
389
- if (!Op || !isPointerTy (Op->getType ()))
389
+ if (!Op || !isPointerTy (Op->getType ()) || isa<ConstantPointerNull>(Op) ||
390
+ isa<UndefValue>(Op))
390
391
return nullptr ;
391
392
392
393
if (auto ElemTy = getPointeeType (Op->getType ()))
@@ -483,12 +484,25 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
483
484
if (isPointerTy (Op->getType ()))
484
485
Ty = deduceElementTypeHelper (Op, Visited, UnknownElemTypeI8);
485
486
} else if (auto *Ref = dyn_cast<PHINode>(I)) {
486
- for (unsigned i = 0 ; i < Ref->getNumIncomingValues (); i++) {
487
+ Type *BestTy = nullptr ;
488
+ unsigned MaxN = 1 ;
489
+ DenseMap<Type *, unsigned > PhiTys;
490
+ for (int i = Ref->getNumIncomingValues () - 1 ; i >= 0 ; --i) {
487
491
Ty = deduceElementTypeByUsersDeep (Ref->getIncomingValue (i), Visited,
488
492
UnknownElemTypeI8);
489
- if (Ty)
490
- break ;
493
+ if (!Ty)
494
+ continue ;
495
+ auto It = PhiTys.try_emplace (Ty, 1 );
496
+ if (!It.second ) {
497
+ ++It.first ->second ;
498
+ if (It.first ->second > MaxN) {
499
+ MaxN = It.first ->second ;
500
+ BestTy = Ty;
501
+ }
502
+ }
491
503
}
504
+ if (BestTy)
505
+ Ty = BestTy;
492
506
} else if (auto *Ref = dyn_cast<SelectInst>(I)) {
493
507
for (Value *Op : {Ref->getTrueValue (), Ref->getFalseValue ()}) {
494
508
Ty = deduceElementTypeByUsersDeep (Op, Visited, UnknownElemTypeI8);
@@ -644,6 +658,62 @@ static inline Type *getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I,
644
658
return nullptr ;
645
659
}
646
660
661
+ // Try to deduce element type for a call base. Returns false if this is an
662
+ // indirect function invocation, and true otherwise.
663
+ static bool deduceOperandElementTypeCalledFunction (
664
+ SPIRVGlobalRegistry *GR, Instruction *I,
665
+ SPIRV::InstructionSet::InstructionSet InstrSet, CallInst *CI,
666
+ SmallVector<std::pair<Value *, unsigned >> &Ops, Type *&KnownElemTy) {
667
+ Function *CalledF = CI->getCalledFunction ();
668
+ if (!CalledF)
669
+ return false ;
670
+ std::string DemangledName =
671
+ getOclOrSpirvBuiltinDemangledName (CalledF->getName ());
672
+ if (DemangledName.length () > 0 &&
673
+ !StringRef (DemangledName).starts_with (" llvm." )) {
674
+ auto [Grp, Opcode, ExtNo] =
675
+ SPIRV::mapBuiltinToOpcode (DemangledName, InstrSet);
676
+ if (Opcode == SPIRV::OpGroupAsyncCopy) {
677
+ for (unsigned i = 0 , PtrCnt = 0 ; i < CI->arg_size () && PtrCnt < 2 ; ++i) {
678
+ Value *Op = CI->getArgOperand (i);
679
+ if (!isPointerTy (Op->getType ()))
680
+ continue ;
681
+ ++PtrCnt;
682
+ if (Type *ElemTy = GR->findDeducedElementType (Op))
683
+ KnownElemTy = ElemTy; // src will rewrite dest if both are defined
684
+ Ops.push_back (std::make_pair (Op, i));
685
+ }
686
+ } else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
687
+ if (CI->arg_size () < 2 )
688
+ return true ;
689
+ Value *Op = CI->getArgOperand (0 );
690
+ if (!isPointerTy (Op->getType ()))
691
+ return true ;
692
+ switch (Opcode) {
693
+ case SPIRV::OpAtomicLoad:
694
+ case SPIRV::OpAtomicCompareExchangeWeak:
695
+ case SPIRV::OpAtomicCompareExchange:
696
+ case SPIRV::OpAtomicExchange:
697
+ case SPIRV::OpAtomicIAdd:
698
+ case SPIRV::OpAtomicISub:
699
+ case SPIRV::OpAtomicOr:
700
+ case SPIRV::OpAtomicXor:
701
+ case SPIRV::OpAtomicAnd:
702
+ case SPIRV::OpAtomicUMin:
703
+ case SPIRV::OpAtomicUMax:
704
+ case SPIRV::OpAtomicSMin:
705
+ case SPIRV::OpAtomicSMax: {
706
+ KnownElemTy = getAtomicElemTy (GR, I, Op);
707
+ if (!KnownElemTy)
708
+ return true ;
709
+ Ops.push_back (std::make_pair (Op, 0 ));
710
+ } break ;
711
+ }
712
+ }
713
+ }
714
+ return true ;
715
+ }
716
+
647
717
// If the Instruction has Pointer operands with unresolved types, this function
648
718
// tries to deduce them. If the Instruction has Pointer operands with known
649
719
// types which differ from expected, this function tries to insert a bitcast to
@@ -749,53 +819,17 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(Instruction *I,
749
819
KnownElemTy = ElemTy1;
750
820
Ops.push_back (std::make_pair (Op0, 0 ));
751
821
}
752
- } else if (auto *CI = dyn_cast<CallInst>(I)) {
753
- if (Function *CalledF = CI->getCalledFunction ()) {
754
- std::string DemangledName =
755
- getOclOrSpirvBuiltinDemangledName (CalledF->getName ());
756
- if (DemangledName.length () > 0 &&
757
- !StringRef (DemangledName).starts_with (" llvm." )) {
758
- auto [Grp, Opcode, ExtNo] =
759
- SPIRV::mapBuiltinToOpcode (DemangledName, InstrSet);
760
- if (Opcode == SPIRV::OpGroupAsyncCopy) {
761
- for (unsigned i = 0 , PtrCnt = 0 ; i < CI->arg_size () && PtrCnt < 2 ;
762
- ++i) {
763
- Value *Op = CI->getArgOperand (i);
764
- if (!isPointerTy (Op->getType ()))
765
- continue ;
766
- ++PtrCnt;
767
- if (Type *ElemTy = GR->findDeducedElementType (Op))
768
- KnownElemTy = ElemTy; // src will rewrite dest if both are defined
769
- Ops.push_back (std::make_pair (Op, i));
770
- }
771
- } else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
772
- if (CI->arg_size () < 2 )
773
- return ;
774
- Value *Op = CI->getArgOperand (0 );
775
- if (!isPointerTy (Op->getType ()))
776
- return ;
777
- switch (Opcode) {
778
- case SPIRV::OpAtomicLoad:
779
- case SPIRV::OpAtomicCompareExchangeWeak:
780
- case SPIRV::OpAtomicCompareExchange:
781
- case SPIRV::OpAtomicExchange:
782
- case SPIRV::OpAtomicIAdd:
783
- case SPIRV::OpAtomicISub:
784
- case SPIRV::OpAtomicOr:
785
- case SPIRV::OpAtomicXor:
786
- case SPIRV::OpAtomicAnd:
787
- case SPIRV::OpAtomicUMin:
788
- case SPIRV::OpAtomicUMax:
789
- case SPIRV::OpAtomicSMin:
790
- case SPIRV::OpAtomicSMax: {
791
- KnownElemTy = getAtomicElemTy (GR, I, Op);
792
- if (!KnownElemTy)
793
- return ;
794
- Ops.push_back (std::make_pair (Op, 0 ));
795
- } break ;
796
- }
797
- }
798
- }
822
+ } else if (CallInst *CI = dyn_cast<CallInst>(I)) {
823
+ if (!CI->isIndirectCall ()) {
824
+ deduceOperandElementTypeCalledFunction (GR, I, InstrSet, CI, Ops,
825
+ KnownElemTy);
826
+ } else if (TM->getSubtarget <SPIRVSubtarget>(*F).canUseExtension (
827
+ SPIRV::Extension::SPV_INTEL_function_pointers)) {
828
+ Value *Op = CI->getCalledOperand ();
829
+ if (!Op || !isPointerTy (Op->getType ()))
830
+ return ;
831
+ Ops.push_back (std::make_pair (Op, std::numeric_limits<unsigned >::max ()));
832
+ KnownElemTy = CI->getFunctionType ();
799
833
}
800
834
}
801
835
@@ -846,7 +880,10 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(Instruction *I,
846
880
B.getInt32 (getPointerAddressSpace (OpTy))};
847
881
CallInst *PtrCastI =
848
882
B.CreateIntrinsic (Intrinsic::spv_ptrcast, {Types}, Args);
849
- I->setOperand (OpIt.second , PtrCastI);
883
+ if (OpIt.second == std::numeric_limits<unsigned >::max ())
884
+ dyn_cast<CallInst>(I)->setCalledOperand (PtrCastI);
885
+ else
886
+ I->setOperand (OpIt.second , PtrCastI);
850
887
buildAssignPtr (B, KnownElemTy, PtrCastI);
851
888
}
852
889
}
0 commit comments