23#include "llvm/IR/IntrinsicsSPIRV.h"
53class SPIRVEmitIntrinsics
55 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
59 bool TrackConstants =
true;
70 Type *deduceElementTypeHelper(
Value *
I, std::unordered_set<Value *> &Visited);
71 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
72 std::unordered_set<Value *> &Visited);
74 std::unordered_set<Value *> &Visited);
77 Type *deduceNestedTypeHelper(
User *U);
79 std::unordered_set<Value *> &Visited);
96 for (
auto *Imm : Imms)
98 return B.CreateIntrinsic(IntrID, {
Types},
Args);
107 void insertAssignTypeInstrForTargetExtTypes(
TargetExtType *AssignedType,
110 Type *ExpectedElementType,
111 unsigned OperandToReplace,
117 Type *deduceFunParamElementType(
Function *F,
unsigned OpIdx);
118 Type *deduceFunParamElementType(
Function *F,
unsigned OpIdx,
119 std::unordered_set<Function *> &FVisited);
154char SPIRVEmitIntrinsics::ID = 0;
160 return isa<IntrinsicInst>(
I) &&
161 cast<IntrinsicInst>(
I)->getIntrinsicID() == Intrinsic::spv_assign_type;
165 return isa<StoreInst>(
I) || isa<LoadInst>(
I) || isa<InsertValueInst>(
I) ||
166 isa<ExtractValueInst>(
I) || isa<AtomicCmpXchgInst>(
I);
170 return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) ||
171 (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());
176 B.SetInsertPoint(
I->getParent(),
I->getParent()->getFirstInsertionPt());
184 switch (
Intr->getIntrinsicID()) {
185 case Intrinsic::invariant_start:
186 case Intrinsic::invariant_end:
194 if (
I->getType()->isTokenTy())
196 "does not support token type",
203 buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {Arg->
getType()},
208 AssignPtrTypeInstr[Arg] = AssignPtrTyCI;
213Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
214 Type *ValueTy,
Value *Operand, std::unordered_set<Value *> &Visited) {
217 if (
auto *PtrTy = dyn_cast<PointerType>(Ty)) {
218 if (
Type *NestedTy = deduceElementTypeHelper(Operand, Visited))
221 Ty = deduceNestedTypeHelper(dyn_cast<User>(Operand), Ty, Visited);
228Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
229 Value *
Op, std::unordered_set<Value *> &Visited) {
233 if (
auto PType = dyn_cast<TypedPointerType>(
Op->getType()))
234 return PType->getElementType();
240 for (
User *OpU :
Op->users()) {
241 if (
Instruction *Inst = dyn_cast<Instruction>(OpU)) {
242 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited))
254 Function *CalledF,
unsigned OpIdx) {
255 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
258 return IntegerType::getInt8Ty(CalledF->
getContext());
264Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
Value *
I) {
265 std::unordered_set<Value *> Visited;
266 return deduceElementTypeHelper(
I, Visited);
269Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
270 Value *
I, std::unordered_set<Value *> &Visited) {
280 if (Visited.find(
I) != Visited.end())
287 if (
auto *
Ref = dyn_cast<AllocaInst>(
I)) {
288 Ty =
Ref->getAllocatedType();
289 }
else if (
auto *
Ref = dyn_cast<GetElementPtrInst>(
I)) {
290 Ty =
Ref->getResultElementType();
291 }
else if (
auto *
Ref = dyn_cast<GlobalValue>(
I)) {
292 Ty = deduceElementTypeByValueDeep(
294 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited);
295 }
else if (
auto *
Ref = dyn_cast<AddrSpaceCastInst>(
I)) {
296 Ty = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited);
297 }
else if (
auto *
Ref = dyn_cast<BitCastInst>(
I)) {
298 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
300 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited);
301 }
else if (
auto *
Ref = dyn_cast<AtomicCmpXchgInst>(
I)) {
303 Ty = deduceElementTypeByValueDeep(
Op->getType(),
Op, Visited);
304 }
else if (
auto *
Ref = dyn_cast<AtomicRMWInst>(
I)) {
306 Ty = deduceElementTypeByValueDeep(
Op->getType(),
Op, Visited);
307 }
else if (
auto *
Ref = dyn_cast<PHINode>(
I)) {
308 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
309 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited);
313 }
else if (
auto *
Ref = dyn_cast<SelectInst>(
I)) {
314 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
315 Ty = deduceElementTypeByUsersDeep(
Op, Visited);
333Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
User *U) {
334 std::unordered_set<Value *> Visited;
335 return deduceNestedTypeHelper(U,
U->getType(), Visited);
338Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
339 User *U,
Type *OrigTy, std::unordered_set<Value *> &Visited) {
348 if (Visited.find(U) != Visited.end())
352 if (dyn_cast<StructType>(OrigTy)) {
355 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
357 Type *OpTy =
Op->getType();
360 if (
auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
361 if (
Type *NestedTy = deduceElementTypeHelper(
Op, Visited))
364 Ty = deduceNestedTypeHelper(dyn_cast<User>(
Op), OpTy, Visited);
368 Change |= Ty != OpTy;
375 }
else if (
auto *ArrTy = dyn_cast<ArrayType>(OrigTy)) {
376 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
377 Type *OpTy = ArrTy->getElementType();
379 if (
auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
380 if (
Type *NestedTy = deduceElementTypeHelper(
Op, Visited))
383 Ty = deduceNestedTypeHelper(dyn_cast<User>(
Op), OpTy, Visited);
386 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
391 }
else if (
auto *VecTy = dyn_cast<VectorType>(OrigTy)) {
392 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
393 Type *OpTy = VecTy->getElementType();
395 if (
auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
396 if (
Type *NestedTy = deduceElementTypeHelper(
Op, Visited))
399 Ty = deduceNestedTypeHelper(dyn_cast<User>(
Op), OpTy, Visited);
402 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
412Type *SPIRVEmitIntrinsics::deduceElementType(
Value *
I) {
413 if (
Type *Ty = deduceElementTypeHelper(
I))
415 return IntegerType::getInt8Ty(
I->getContext());
422void SPIRVEmitIntrinsics::deduceOperandElementType(
Instruction *
I) {
424 Type *KnownElemTy =
nullptr;
426 if (
auto *
Ref = dyn_cast<PHINode>(
I)) {
430 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
435 }
else if (
auto *
Ref = dyn_cast<SelectInst>(
I)) {
439 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
444 }
else if (
auto *
Ref = dyn_cast<ReturnInst>(
I)) {
461 }
else if (
auto *
Ref = dyn_cast<ICmpInst>(
I)) {
469 KnownElemTy = ElemTy0;
471 }
else if (ElemTy1) {
472 KnownElemTy = ElemTy1;
478 if (!KnownElemTy || Ops.
size() == 0)
483 for (
auto &OpIt : Ops) {
488 if (Ty == KnownElemTy)
495 Type *OpTy =
Op->getType();
499 auto It = AssignPtrTypeInstr.
find(
Op);
500 if (It == AssignPtrTypeInstr.
end()) {
502 buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {OpTy}, OpTyVal,
Op,
504 AssignPtrTypeInstr[
Op] = CI;
518 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
519 I->setOperand(OpIt.second, PtrCastI);
524void SPIRVEmitIntrinsics::replaceMemInstrUses(
Instruction *Old,
529 if (isAssignTypeInstr(U)) {
532 B.CreateIntrinsic(Intrinsic::spv_assign_type, {
New->getType()},
Args);
533 U->eraseFromParent();
536 U->replaceUsesOfWith(Old, New);
544void SPIRVEmitIntrinsics::preprocessUndefs(
IRBuilder<> &
B) {
545 std::queue<Instruction *> Worklist;
549 while (!Worklist.empty()) {
553 for (
auto &
Op :
I->operands()) {
554 auto *AggrUndef = dyn_cast<UndefValue>(
Op);
555 if (!AggrUndef || !
Op->getType()->isAggregateType())
559 auto *IntrUndef =
B.CreateIntrinsic(Intrinsic::spv_undef, {}, {});
560 Worklist.push(IntrUndef);
561 I->replaceUsesOfWith(
Op, IntrUndef);
562 AggrConsts[IntrUndef] = AggrUndef;
563 AggrConstTypes[IntrUndef] = AggrUndef->getType();
568void SPIRVEmitIntrinsics::preprocessCompositeConstants(
IRBuilder<> &
B) {
569 std::queue<Instruction *> Worklist;
573 while (!Worklist.empty()) {
574 auto *
I = Worklist.front();
576 bool KeepInst =
false;
577 for (
const auto &
Op :
I->operands()) {
578 auto BuildCompositeIntrinsic =
581 bool &KeepInst, SPIRVEmitIntrinsics &SEI) {
584 B.CreateIntrinsic(Intrinsic::spv_const_composite, {}, {
Args});
586 I->replaceUsesOfWith(
Op, CCI);
588 SEI.AggrConsts[CCI] = AggrC;
589 SEI.AggrConstTypes[CCI] = SEI.deduceNestedTypeHelper(AggrC);
592 if (
auto *AggrC = dyn_cast<ConstantAggregate>(
Op)) {
594 BuildCompositeIntrinsic(AggrC, Args,
Op,
I,
B, Worklist, KeepInst,
596 }
else if (
auto *AggrC = dyn_cast<ConstantDataArray>(
Op)) {
598 for (
unsigned i = 0; i < AggrC->getNumElements(); ++i)
599 Args.push_back(AggrC->getElementAsConstant(i));
600 BuildCompositeIntrinsic(AggrC, Args,
Op,
I,
B, Worklist, KeepInst,
602 }
else if (isa<ConstantAggregateZero>(
Op) &&
603 !
Op->getType()->isVectorTy()) {
604 auto *AggrC = cast<ConstantAggregateZero>(
Op);
606 BuildCompositeIntrinsic(AggrC, Args,
Op,
I,
B, Worklist, KeepInst,
618 B.SetInsertPoint(&
I);
621 for (
auto &
Op :
I.operands()) {
622 if (
Op.get()->getType()->isSized()) {
624 }
else if (
BasicBlock *BB = dyn_cast<BasicBlock>(
Op.get())) {
631 CallInst *NewI =
B.CreateIntrinsic(Intrinsic::spv_switch,
635 I.replaceAllUsesWith(NewI);
639 B.SetInsertPoint(ParentBB);
650 B.SetInsertPoint(&
I);
653 Args.push_back(
B.getInt1(
I.isInBounds()));
654 for (
auto &
Op :
I.operands())
656 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
657 I.replaceAllUsesWith(NewI);
664 B.SetInsertPoint(&
I);
672 I.replaceAllUsesWith(Source);
679 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_bitcast, {
Types}, {
Args});
680 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
681 I.replaceAllUsesWith(NewI);
687void SPIRVEmitIntrinsics::insertAssignTypeInstrForTargetExtTypes(
690 if (
V->getType() == AssignedType)
696 for (
auto User :
V->users()) {
697 auto *II = dyn_cast<IntrinsicInst>(
User);
698 if (!II || II->getIntrinsicID() != Intrinsic::spv_assign_type)
703 dyn_cast<ConstantAsMetadata>(VMD->
getMetadata())->getType();
704 if (BuiltinType != AssignedType)
707 " for value " +
V->getName(),
713 buildIntrWithMD(Intrinsic::spv_assign_type, {
V->getType()},
Const,
V, {},
B);
716void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
721 while (
BitCastInst *BC = dyn_cast<BitCastInst>(Pointer))
725 Type *PointerElemTy = deduceElementTypeHelper(Pointer);
726 if (PointerElemTy == ExpectedElementType)
730 Constant *ExpectedElementTypeConst =
737 bool FirstPtrCastOrAssignPtrType =
true;
743 auto *II = dyn_cast<IntrinsicInst>(
User);
745 (II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
746 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
747 II->getOperand(0) != Pointer)
752 FirstPtrCastOrAssignPtrType =
false;
753 if (II->getOperand(1) != VMD ||
754 dyn_cast<ConstantInt>(II->getOperand(2))->getSExtValue() !=
760 if (II->getIntrinsicID() != Intrinsic::spv_ptrcast)
765 if (II->getParent() !=
I->getParent())
768 I->setOperand(OperandToReplace, II);
779 if (FirstPtrCastOrAssignPtrType &&
780 (isa<Instruction>(Pointer) || isa<Argument>(Pointer))) {
782 Intrinsic::spv_assign_ptr_type, {
Pointer->getType()},
786 AssignPtrTypeInstr[
Pointer] = CI;
793 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
794 I->setOperand(OperandToReplace, PtrCastI);
797void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(
Instruction *
I,
803 isa<Argument>(
SI->getValueOperand())) {
804 return replacePointerOperandWithPtrCast(
805 I,
SI->getValueOperand(), IntegerType::getInt8Ty(
F->getContext()), 0,
808 return replacePointerOperandWithPtrCast(
809 I,
SI->getPointerOperand(),
SI->getValueOperand()->getType(), 1,
B);
810 }
else if (
LoadInst *LI = dyn_cast<LoadInst>(
I)) {
811 return replacePointerOperandWithPtrCast(
I, LI->getPointerOperand(),
812 LI->getType(), 0,
B);
814 return replacePointerOperandWithPtrCast(
I, GEPI->getPointerOperand(),
815 GEPI->getSourceElementType(), 0,
B);
825 std::string DemangledName =
829 bool HaveTypes =
false;
830 for (
unsigned OpIdx = 0; OpIdx < CalledF->
arg_size(); ++OpIdx) {
836 CalledArgTys.
push_back(cast<TypedPointerType>(ArgType)->getElementType());
848 if (
Instruction *Inst = dyn_cast<Instruction>(U)) {
849 if ((ElemTy = deduceElementTypeHelper(Inst)) !=
nullptr)
855 HaveTypes |= ElemTy !=
nullptr;
860 if (DemangledName.empty() && !HaveTypes)
863 for (
unsigned OpIdx = 0; OpIdx < CI->
arg_size(); OpIdx++) {
865 if (!isa<PointerType>(ArgOperand->
getType()) &&
866 !isa<TypedPointerType>(ArgOperand->
getType()))
870 if (!isa<Instruction>(ArgOperand) && !isa<Argument>(ArgOperand)) {
880 OpIdx < CalledArgTys.
size() ? CalledArgTys[OpIdx] :
nullptr;
881 if (!ExpectedType && !DemangledName.empty())
883 DemangledName, OpIdx,
I->getContext());
888 insertAssignTypeInstrForTargetExtTypes(cast<TargetExtType>(ExpectedType),
891 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx,
B);
897 I.getOperand(1)->getType(),
898 I.getOperand(2)->getType()};
900 B.SetInsertPoint(&
I);
902 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
903 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
904 I.replaceAllUsesWith(NewI);
913 B.SetInsertPoint(&
I);
915 I.getIndexOperand()->getType()};
917 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {
Types}, {
Args});
918 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
919 I.replaceAllUsesWith(NewI);
927 B.SetInsertPoint(&
I);
930 for (
auto &
Op :
I.operands())
931 if (isa<UndefValue>(
Op))
935 for (
auto &
Op :
I.indices())
936 Args.push_back(
B.getInt32(
Op));
938 B.CreateIntrinsic(Intrinsic::spv_insertv, {
Types}, {
Args});
939 replaceMemInstrUses(&
I, NewI,
B);
945 B.SetInsertPoint(&
I);
947 for (
auto &
Op :
I.operands())
949 for (
auto &
Op :
I.indices())
950 Args.push_back(
B.getInt32(
Op));
952 B.CreateIntrinsic(Intrinsic::spv_extractv, {
I.getType()}, {
Args});
953 I.replaceAllUsesWith(NewI);
959 if (!
I.getType()->isAggregateType())
962 B.SetInsertPoint(&
I);
963 TrackConstants =
false;
964 const auto *TLI =
TM->getSubtargetImpl()->getTargetLowering();
966 TLI->getLoadMemOperandFlags(
I,
F->getParent()->getDataLayout());
968 B.CreateIntrinsic(Intrinsic::spv_load, {
I.getOperand(0)->
getType()},
969 {
I.getPointerOperand(),
B.getInt16(Flags),
970 B.getInt8(
I.getAlign().value())});
971 replaceMemInstrUses(&
I, NewI,
B);
979 B.SetInsertPoint(&
I);
980 TrackConstants =
false;
981 const auto *TLI =
TM->getSubtargetImpl()->getTargetLowering();
983 TLI->getStoreMemOperandFlags(
I,
F->getParent()->getDataLayout());
984 auto *PtrOp =
I.getPointerOperand();
985 auto *NewI =
B.CreateIntrinsic(
986 Intrinsic::spv_store, {
I.getValueOperand()->
getType(), PtrOp->getType()},
987 {
I.getValueOperand(), PtrOp,
B.getInt16(Flags),
988 B.getInt8(
I.getAlign().value())});
994 Value *ArraySize =
nullptr;
995 if (
I.isArrayAllocation()) {
998 SPIRV::Extension::SPV_INTEL_variable_length_array))
1000 "array allocation: this instruction requires the following "
1001 "SPIR-V extension: SPV_INTEL_variable_length_array",
1003 ArraySize =
I.getArraySize();
1006 B.SetInsertPoint(&
I);
1007 TrackConstants =
false;
1008 Type *PtrTy =
I.getType();
1010 ArraySize ?
B.CreateIntrinsic(Intrinsic::spv_alloca_array,
1011 {PtrTy, ArraySize->
getType()}, {ArraySize})
1012 :
B.CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy}, {});
1013 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
1014 I.replaceAllUsesWith(NewI);
1015 I.eraseFromParent();
1021 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
1023 B.SetInsertPoint(&
I);
1025 for (
auto &
Op :
I.operands())
1027 Args.push_back(
B.getInt32(
I.getSyncScopeID()));
1028 Args.push_back(
B.getInt32(
1030 Args.push_back(
B.getInt32(
1032 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_cmpxchg,
1034 replaceMemInstrUses(&
I, NewI,
B);
1040 B.SetInsertPoint(&
I);
1041 B.CreateIntrinsic(Intrinsic::spv_unreachable, {}, {});
1048 if (GV.
getName() ==
"llvm.global.annotations")
1054 deduceElementTypeHelper(&GV);
1058 auto *InitInst =
B.CreateIntrinsic(Intrinsic::spv_init_global,
1060 InitInst->setArgOperand(1,
Init);
1064 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
1067void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(
Instruction *
I,
1071 isa<BitCastInst>(
I))
1076 Type *ElemTy = deduceElementType(
I);
1079 CallInst *CI = buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {
I->getType()},
1082 AssignPtrTypeInstr[
I] = CI;
1085void SPIRVEmitIntrinsics::insertAssignTypeIntrs(
Instruction *
I,
1088 Type *Ty =
I->getType();
1091 Type *TypeToAssign = Ty;
1092 if (
auto *II = dyn_cast<IntrinsicInst>(
I)) {
1093 if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||
1094 II->getIntrinsicID() == Intrinsic::spv_undef) {
1095 auto It = AggrConstTypes.
find(II);
1096 if (It == AggrConstTypes.
end())
1098 TypeToAssign = It->second;
1102 buildIntrWithMD(Intrinsic::spv_assign_type, {Ty},
Const,
I, {},
B);
1104 for (
const auto &
Op :
I->operands()) {
1105 if (isa<ConstantPointerNull>(
Op) || isa<UndefValue>(
Op) ||
1107 (isa<ConstantExpr>(
Op) && isa<GEPOperator>(
Op))) {
1109 if (isa<UndefValue>(
Op) &&
Op->getType()->isAggregateType())
1110 buildIntrWithMD(Intrinsic::spv_assign_type, {
B.getInt32Ty()},
Op,
1112 else if (!isa<Instruction>(
Op))
1113 buildIntrWithMD(Intrinsic::spv_assign_type, {
Op->getType()},
Op,
Op, {},
1119void SPIRVEmitIntrinsics::processInstrAfterVisit(
Instruction *
I,
1121 auto *II = dyn_cast<IntrinsicInst>(
I);
1122 if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite &&
1124 B.SetInsertPoint(
I->getNextNode());
1125 Type *Ty =
B.getInt32Ty();
1126 auto t = AggrConsts.
find(
I);
1128 auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty},
1129 t->second,
I, {},
B);
1130 I->replaceAllUsesWith(NewOp);
1131 NewOp->setArgOperand(0,
I);
1133 for (
const auto &
Op :
I->operands()) {
1134 if ((isa<ConstantAggregateZero>(
Op) &&
Op->getType()->isVectorTy()) ||
1135 isa<PHINode>(
I) || isa<SwitchInst>(
I))
1136 TrackConstants =
false;
1137 if ((isa<ConstantData>(
Op) || isa<ConstantExpr>(
Op)) && TrackConstants) {
1138 unsigned OpNo =
Op.getOperandNo();
1139 if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
1140 (II->paramHasAttr(OpNo, Attribute::ImmArg))))
1142 B.SetInsertPoint(
I);
1144 if (
Op->getType()->isTargetExtTy())
1147 auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,
1150 I->setOperand(OpNo, NewOp);
1156 std::vector<Value *>
Args = {
I};
1158 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()},
Args);
1162Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
Function *
F,
1164 std::unordered_set<Function *> FVisited;
1165 return deduceFunParamElementType(
F, OpIdx, FVisited);
1168Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
1169 Function *
F,
unsigned OpIdx, std::unordered_set<Function *> &FVisited) {
1171 if (FVisited.find(
F) != FVisited.end())
1175 std::unordered_set<Value *> Visited;
1178 for (
User *U :
F->users()) {
1179 CallInst *CI = dyn_cast<CallInst>(U);
1180 if (!CI || OpIdx >= CI->
arg_size())
1190 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited))
1195 if (!Inst || Inst == CI)
1198 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited))
1205 if (FVisited.find(OuterF) != FVisited.end())
1207 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
1208 if (OuterF->
getArg(i) == OpArg) {
1209 Lookup.push_back(std::make_pair(OuterF, i));
1216 for (
auto &Pair :
Lookup) {
1217 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
1224void SPIRVEmitIntrinsics::processParamTypesByFunHeader(
Function *
F,
1226 B.SetInsertPointPastAllocas(
F);
1227 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
1234 buildAssignPtr(
B, ElemTy, Arg);
1239 B.SetInsertPointPastAllocas(
F);
1240 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
1245 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F, OpIdx)) !=
nullptr)
1246 buildAssignPtr(
B, ElemTy, Arg);
1250bool SPIRVEmitIntrinsics::runOnFunction(
Function &Func) {
1251 if (
Func.isDeclaration())
1255 GR =
ST.getSPIRVGlobalRegistry();
1260 AggrConstTypes.
clear();
1263 processParamTypesByFunHeader(
F,
B);
1271 Type *ElTy =
SI->getValueOperand()->getType();
1276 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
1277 for (
auto &GV :
Func.getParent()->globals())
1278 processGlobalValue(GV,
B);
1280 preprocessUndefs(
B);
1281 preprocessCompositeConstants(
B);
1286 for (
auto &
I : Worklist) {
1287 insertAssignPtrTypeIntrs(
I,
B);
1288 insertAssignTypeIntrs(
I,
B);
1289 insertPtrCastOrAssignTypeInstr(
I,
B);
1293 deduceOperandElementType(&
I);
1295 for (
auto *
I : Worklist) {
1296 TrackConstants =
true;
1297 if (!
I->getType()->isVoidTy() || isa<StoreInst>(
I))
1298 B.SetInsertPoint(
I->getNextNode());
1304 processInstrAfterVisit(
I,
B);
1310bool SPIRVEmitIntrinsics::runOnModule(
Module &M) {
1311 bool Changed =
false;
1319 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
1321 GR =
ST.getSPIRVGlobalRegistry();
1323 processParamTypes(&
F,
B);
1331 return new SPIRVEmitIntrinsics(
TM);
Expand Atomic instructions
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool runOnFunction(Function &F, bool PostInlining)
const char LLVMTargetMachineRef TM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool isMemInstrToReplace(Instruction *I)
static bool isAggrToReplace(const Value *V)
static void reportFatalOnTokenType(const Instruction *I)
static Type * getPointeeTypeByCallInst(StringRef DemangledName, Function *CalledF, unsigned OpIdx)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static bool requireAssignType(Instruction *I)
static SymbolRef::Type getType(const Symbol *Sym)
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
an instruction to allocate memory on the stack
Represent the analysis usage information of a pass.
This class represents an incoming formal argument to a Function.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
An instruction that atomically checks whether a specified value is in a memory location,...
LLVM Basic Block Representation.
const Function * getParent() const
Return the enclosing method, or null if none.
LLVMContext & getContext() const
Get the context in which this basic block lives.
This class represents a no-op cast from one type to another.
static BlockAddress * get(Function *F, BasicBlock *BB)
Return a BlockAddress for the specified function and basic block.
bool isInlineAsm() const
Check if this call is an inline asm statement.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
unsigned arg_size() const
This class represents a function call, abstracting a target machine's calling convention.
This is an important base class in LLVM.
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
This class represents an Operation in the Expression.
iterator find(const_arg_type_t< KeyT > Val)
Implements a dense probed hash-table based set.
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Argument * getArg(unsigned i) const
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
PointerType * getType() const
Global values are always pointers.
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
bool hasInitializer() const
Definitions have initializers, declarations don't.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Indirect Branch Instruction.
void addDestination(BasicBlock *Dest)
Add a destination.
This instruction inserts a single (scalar) element into a VectorType value.
This instruction inserts a struct field of array element value into an aggregate value.
Base class for instruction visitors.
RetTy visitExtractElementInst(ExtractElementInst &I)
RetTy visitInsertValueInst(InsertValueInst &I)
RetTy visitUnreachableInst(UnreachableInst &I)
RetTy visitAtomicCmpXchgInst(AtomicCmpXchgInst &I)
RetTy visitBitCastInst(BitCastInst &I)
RetTy visitSwitchInst(SwitchInst &I)
RetTy visitExtractValueInst(ExtractValueInst &I)
RetTy visitStoreInst(StoreInst &I)
RetTy visitInsertElementInst(InsertElementInst &I)
RetTy visitAllocaInst(AllocaInst &I)
RetTy visitGetElementPtrInst(GetElementPtrInst &I)
void visitInstruction(Instruction &I)
RetTy visitLoadInst(LoadInst &I)
const BasicBlock * getParent() const
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Instruction * user_back()
Specialize the methods defined in Value, as we know that an instruction can only be used by other ins...
static IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Flags
Flags values. These may be or'd together.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Type * findDeducedCompositeType(const Value *Val)
void addDeducedElementType(Value *Val, Type *Ty)
unsigned getPointerSize() const
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy)
void addDeducedCompositeType(Value *Val, Type *Ty)
Type * findDeducedElementType(const Value *Val)
bool canUseExtension(SPIRV::Extension::Extension E) const
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
StringRef - Represent a constant reference to a string, i.e.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
static StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Class to represent target extensions types, which are generally unintrospectable from target-independ...
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
StringRef getTargetExtName() const
bool isTargetExtTy() const
Return true if this is a target extension type.
bool isAggregateType() const
Return true if the type is an aggregate type.
bool isVoidTy() const
Return true if this is 'void'.
A few GPU targets, such as DXIL and SPIR-V, have typed pointers.
static TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
This function has undefined behavior.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
void setName(const Twine &Name)
Change the name of the value.
iterator_range< user_iterator > users()
unsigned getNumUses() const
This method computes the number of uses of this Value.
StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ SPIR_KERNEL
Used for SPIR kernel functions.
Type * parseBuiltinCallArgumentBaseType(const StringRef DemangledCall, unsigned ArgIdx, LLVMContext &Ctx)
Parses the provided ArgIdx argument base type in the DemangledCall skeleton.
NodeAddr< FuncNode * > Func
This is an optimization pass for GlobalISel generic memory operations.
void initializeSPIRVEmitIntrinsicsPass(PassRegistry &)
ModulePass * createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM)
unsigned getPointerAddressSpace(const Type *T)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
bool isTypedPointerTy(const Type *T)
bool isPointerTy(const Type *T)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
@ Ref
The access may reference the value stored in memory.
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
bool hasPointeeTypeAttr(Argument *Arg)
void addStringImm(const StringRef &Str, MCInst &Inst)
bool isUntypedPointerTy(const Type *T)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)