Skip to content

[SPIR-V] Add validation to the test case with get_image_array_size/get_image_dim calls #94467

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 36 additions & 11 deletions llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1451,11 +1451,22 @@ static bool generateImageSizeQueryInst(const SPIRV::IncomingCall *Call,
Component == 3 ? NumActualRetComponents - 1 : Component;
assert(ExtractedComposite < NumActualRetComponents &&
"Invalid composite index!");
Register TypeReg = GR->getSPIRVTypeID(Call->ReturnType);
SPIRVType *NewType = nullptr;
if (QueryResultType->getOpcode() == SPIRV::OpTypeVector) {
Register NewTypeReg = QueryResultType->getOperand(1).getReg();
if (TypeReg != NewTypeReg &&
(NewType = GR->getSPIRVTypeForVReg(NewTypeReg)) != nullptr)
TypeReg = NewTypeReg;
}
MIRBuilder.buildInstr(SPIRV::OpCompositeExtract)
.addDef(Call->ReturnRegister)
.addUse(GR->getSPIRVTypeID(Call->ReturnType))
.addUse(TypeReg)
.addUse(QueryResult)
.addImm(ExtractedComposite);
if (NewType != nullptr)
insertAssignInstr(Call->ReturnRegister, nullptr, NewType, GR, MIRBuilder,
MIRBuilder.getMF().getRegInfo());
} else {
// More than 1 component is expected, fill a new vector.
auto MIB = MIRBuilder.buildInstr(SPIRV::OpVectorShuffle)
Expand Down Expand Up @@ -2055,16 +2066,30 @@ static bool generateAsyncCopy(const SPIRV::IncomingCall *Call,
auto Scope = buildConstantIntReg(SPIRV::Scope::Workgroup, MIRBuilder, GR);

switch (Opcode) {
case SPIRV::OpGroupAsyncCopy:
return MIRBuilder.buildInstr(Opcode)
.addDef(Call->ReturnRegister)
.addUse(GR->getSPIRVTypeID(Call->ReturnType))
.addUse(Scope)
.addUse(Call->Arguments[0])
.addUse(Call->Arguments[1])
.addUse(Call->Arguments[2])
.addUse(buildConstantIntReg(1, MIRBuilder, GR))
.addUse(Call->Arguments[3]);
case SPIRV::OpGroupAsyncCopy: {
SPIRVType *NewType =
Call->ReturnType->getOpcode() == SPIRV::OpTypeEvent
? nullptr
: GR->getOrCreateSPIRVTypeByName("spirv.Event", MIRBuilder);
Register TypeReg = GR->getSPIRVTypeID(NewType ? NewType : Call->ReturnType);
unsigned NumArgs = Call->Arguments.size();
Register EventReg = Call->Arguments[NumArgs - 1];
bool Res = MIRBuilder.buildInstr(Opcode)
.addDef(Call->ReturnRegister)
.addUse(TypeReg)
.addUse(Scope)
.addUse(Call->Arguments[0])
.addUse(Call->Arguments[1])
.addUse(Call->Arguments[2])
.addUse(Call->Arguments.size() > 4
? Call->Arguments[3]
: buildConstantIntReg(1, MIRBuilder, GR))
.addUse(EventReg);
if (NewType != nullptr)
insertAssignInstr(Call->ReturnRegister, nullptr, NewType, GR, MIRBuilder,
MIRBuilder.getMF().getRegInfo());
return Res;
}
case SPIRV::OpGroupWaitEvents:
return MIRBuilder.buildInstr(Opcode)
.addUse(Scope)
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/SPIRV/SPIRVBuiltins.td
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@ defm : DemangledNativeBuiltin<"__spirv_SpecConstantComposite", OpenCL_std, SpecC

// Async Copy and Prefetch builtin records:
defm : DemangledNativeBuiltin<"async_work_group_copy", OpenCL_std, AsyncCopy, 4, 4, OpGroupAsyncCopy>;
defm : DemangledNativeBuiltin<"async_work_group_strided_copy", OpenCL_std, AsyncCopy, 5, 5, OpGroupAsyncCopy>;
defm : DemangledNativeBuiltin<"__spirv_GroupAsyncCopy", OpenCL_std, AsyncCopy, 6, 6, OpGroupAsyncCopy>;
defm : DemangledNativeBuiltin<"wait_group_events", OpenCL_std, AsyncCopy, 2, 2, OpGroupWaitEvents>;
defm : DemangledNativeBuiltin<"__spirv_GroupWaitEvents", OpenCL_std, AsyncCopy, 3, 3, OpGroupWaitEvents>;
Expand Down
149 changes: 93 additions & 56 deletions llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@ class SPIRVEmitIntrinsics
DenseMap<Instruction *, Type *> AggrConstTypes;
DenseSet<Instruction *> AggrStores;

// a registry of created Intrinsic::spv_assign_ptr_type instructions
DenseMap<Value *, CallInst *> AssignPtrTypeInstr;

// deduce element type of untyped pointers
Type *deduceElementType(Value *I);
Type *deduceElementTypeHelper(Value *I);
Expand Down Expand Up @@ -98,14 +95,16 @@ class SPIRVEmitIntrinsics
return B.CreateIntrinsic(IntrID, {Types}, Args);
}

void buildAssignType(IRBuilder<> &B, Type *ElemTy, Value *Arg);
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg);
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType);

void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);
void processInstrAfterVisit(Instruction *I, IRBuilder<> &B);
void insertAssignPtrTypeIntrs(Instruction *I, IRBuilder<> &B);
void insertAssignTypeIntrs(Instruction *I, IRBuilder<> &B);
void insertAssignTypeInstrForTargetExtTypes(TargetExtType *AssignedType,
Value *V, IRBuilder<> &B);
void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType, Value *V,
IRBuilder<> &B);
void replacePointerOperandWithPtrCast(Instruction *I, Value *Pointer,
Type *ExpectedElementType,
unsigned OperandToReplace,
Expand Down Expand Up @@ -218,15 +217,39 @@ static inline void reportFatalOnTokenType(const Instruction *I) {
false);
}

void SPIRVEmitIntrinsics::buildAssignType(IRBuilder<> &B, Type *Ty,
Value *Arg) {
Value *OfType = PoisonValue::get(Ty);
CallInst *AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type,
{Arg->getType()}, OfType, Arg, {}, B);
GR->addAssignPtrTypeInstr(Arg, AssignCI);
}

void SPIRVEmitIntrinsics::buildAssignPtr(IRBuilder<> &B, Type *ElemTy,
Value *Arg) {
CallInst *AssignPtrTyCI =
buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {Arg->getType()},
Constant::getNullValue(ElemTy), Arg,
{B.getInt32(getPointerAddressSpace(Arg->getType()))}, B);
Value *OfType = PoisonValue::get(ElemTy);
CallInst *AssignPtrTyCI = buildIntrWithMD(
Intrinsic::spv_assign_ptr_type, {Arg->getType()}, OfType, Arg,
{B.getInt32(getPointerAddressSpace(Arg->getType()))}, B);
GR->addDeducedElementType(AssignPtrTyCI, ElemTy);
GR->addDeducedElementType(Arg, ElemTy);
AssignPtrTypeInstr[Arg] = AssignPtrTyCI;
GR->addAssignPtrTypeInstr(Arg, AssignPtrTyCI);
}

void SPIRVEmitIntrinsics::updateAssignType(CallInst *AssignCI, Value *Arg,
Value *OfType) {
LLVMContext &Ctx = Arg->getContext();
AssignCI->setArgOperand(
1, MetadataAsValue::get(
Ctx, MDNode::get(Ctx, ValueAsMetadata::getConstant(OfType))));
if (cast<IntrinsicInst>(AssignCI)->getIntrinsicID() !=
Intrinsic::spv_assign_ptr_type)
return;

// update association with the pointee type
Type *ElemTy = OfType->getType();
GR->addDeducedElementType(AssignCI, ElemTy);
GR->addDeducedElementType(Arg, ElemTy);
}

// Set element pointer type to the given value of ValueTy and tries to
Expand Down Expand Up @@ -513,19 +536,16 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(Instruction *I) {
if (!Ty) {
GR->addDeducedElementType(Op, KnownElemTy);
// check if there is existing Intrinsic::spv_assign_ptr_type instruction
auto It = AssignPtrTypeInstr.find(Op);
if (It == AssignPtrTypeInstr.end()) {
CallInst *AssignCI = GR->findAssignPtrTypeInstr(Op);
if (AssignCI == nullptr) {
Instruction *User = dyn_cast<Instruction>(Op->use_begin()->get());
setInsertPointSkippingPhis(B, User ? User->getNextNode() : I);
CallInst *CI =
buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {OpTy}, OpTyVal, Op,
{B.getInt32(getPointerAddressSpace(OpTy))}, B);
AssignPtrTypeInstr[Op] = CI;
GR->addAssignPtrTypeInstr(Op, CI);
} else {
It->second->setArgOperand(
1,
MetadataAsValue::get(
Ctx, MDNode::get(Ctx, ValueAsMetadata::getConstant(OpTyVal))));
updateAssignType(AssignCI, Op, OpTyVal);
}
} else {
if (auto *OpI = dyn_cast<Instruction>(Op)) {
Expand Down Expand Up @@ -559,7 +579,9 @@ void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
if (isAssignTypeInstr(U)) {
B.SetInsertPoint(U);
SmallVector<Value *, 2> Args = {New, U->getOperand(1)};
B.CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args);
CallInst *AssignCI =
B.CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args);
GR->addAssignPtrTypeInstr(New, AssignCI);
U->eraseFromParent();
} else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) ||
isa<CallInst>(U)) {
Expand Down Expand Up @@ -751,33 +773,39 @@ Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
return NewI;
}

void SPIRVEmitIntrinsics::insertAssignTypeInstrForTargetExtTypes(
void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
TargetExtType *AssignedType, Value *V, IRBuilder<> &B) {
// Do not emit spv_assign_type if the V is of the AssignedType already.
if (V->getType() == AssignedType)
return;
Type *VTy = V->getType();

// Do not emit spv_assign_type if there is one already targetting V. If the
// found spv_assign_type assigns a type different than AssignedType, report an
// error. Builtin types cannot be redeclared or casted.
for (auto User : V->users()) {
auto *II = dyn_cast<IntrinsicInst>(User);
if (!II || II->getIntrinsicID() != Intrinsic::spv_assign_type)
continue;
// A couple of sanity checks.
assert(isPointerTy(VTy) && "Expect a pointer type!");
if (auto PType = dyn_cast<TypedPointerType>(VTy))
if (PType->getElementType() != AssignedType)
report_fatal_error("Unexpected pointer element type!");

MetadataAsValue *VMD = cast<MetadataAsValue>(II->getOperand(1));
Type *BuiltinType =
dyn_cast<ConstantAsMetadata>(VMD->getMetadata())->getType();
if (BuiltinType != AssignedType)
report_fatal_error("Type mismatch " + BuiltinType->getTargetExtName() +
"/" + AssignedType->getTargetExtName() +
" for value " + V->getName(),
false);
CallInst *AssignCI = GR->findAssignPtrTypeInstr(V);
if (!AssignCI) {
buildAssignType(B, AssignedType, V);
return;
}

Constant *Const = UndefValue::get(AssignedType);
buildIntrWithMD(Intrinsic::spv_assign_type, {V->getType()}, Const, V, {}, B);
Type *CurrentType =
dyn_cast<ConstantAsMetadata>(
cast<MetadataAsValue>(AssignCI->getOperand(1))->getMetadata())
->getType();
if (CurrentType == AssignedType)
return;

// Builtin types cannot be redeclared or casted.
if (CurrentType->isTargetExtTy())
report_fatal_error("Type mismatch " + CurrentType->getTargetExtName() +
"/" + AssignedType->getTargetExtName() +
" for value " + V->getName(),
false);

// Our previous guess about the type seems to be wrong, let's update
// inferred type according to a new, more precise type information.
updateAssignType(AssignCI, V, PoisonValue::get(AssignedType));
}

void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
Expand Down Expand Up @@ -850,7 +878,7 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
ExpectedElementTypeConst, Pointer, {B.getInt32(AddressSpace)}, B);
GR->addDeducedElementType(CI, ExpectedElementType);
GR->addDeducedElementType(Pointer, ExpectedElementType);
AssignPtrTypeInstr[Pointer] = CI;
GR->addAssignPtrTypeInstr(Pointer, CI);
return;
}

Expand Down Expand Up @@ -929,8 +957,7 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,

for (unsigned OpIdx = 0; OpIdx < CI->arg_size(); OpIdx++) {
Value *ArgOperand = CI->getArgOperand(OpIdx);
if (!isa<PointerType>(ArgOperand->getType()) &&
!isa<TypedPointerType>(ArgOperand->getType()))
if (!isPointerTy(ArgOperand->getType()))
continue;

// Constants (nulls/undefs) are handled in insertAssignPtrTypeIntrs()
Expand All @@ -952,8 +979,8 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
continue;

if (ExpectedType->isTargetExtTy())
insertAssignTypeInstrForTargetExtTypes(cast<TargetExtType>(ExpectedType),
ArgOperand, B);
insertAssignPtrTypeTargetExt(cast<TargetExtType>(ExpectedType),
ArgOperand, B);
else
replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx, B);
}
Expand Down Expand Up @@ -1145,7 +1172,7 @@ void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
CallInst *CI = buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {I->getType()},
EltTyConst, I, {B.getInt32(AddressSpace)}, B);
GR->addDeducedElementType(CI, ElemTy);
AssignPtrTypeInstr[I] = CI;
GR->addAssignPtrTypeInstr(I, CI);
}

void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
Expand All @@ -1164,20 +1191,32 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
TypeToAssign = It->second;
}
}
Constant *Const = UndefValue::get(TypeToAssign);
buildIntrWithMD(Intrinsic::spv_assign_type, {Ty}, Const, I, {}, B);
buildAssignType(B, TypeToAssign, I);
}
for (const auto &Op : I->operands()) {
if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) ||
// Check GetElementPtrConstantExpr case.
(isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) {
setInsertPointSkippingPhis(B, I);
if (isa<UndefValue>(Op) && Op->getType()->isAggregateType())
buildIntrWithMD(Intrinsic::spv_assign_type, {B.getInt32Ty()}, Op,
UndefValue::get(B.getInt32Ty()), {}, B);
else if (!isa<Instruction>(Op))
buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op, {},
B);
Type *OpTy = Op->getType();
if (isa<UndefValue>(Op) && OpTy->isAggregateType()) {
CallInst *AssignCI =
buildIntrWithMD(Intrinsic::spv_assign_type, {B.getInt32Ty()}, Op,
UndefValue::get(B.getInt32Ty()), {}, B);
GR->addAssignPtrTypeInstr(Op, AssignCI);
} else if (!isa<Instruction>(Op)) {
Type *OpTy = Op->getType();
if (auto PType = dyn_cast<TypedPointerType>(OpTy)) {
buildAssignPtr(B, PType->getElementType(), Op);
} else if (isPointerTy(OpTy)) {
Type *ElemTy = GR->findDeducedElementType(Op);
buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op), Op);
} else {
CallInst *AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type,
{OpTy}, Op, Op, {}, B);
GR->addAssignPtrTypeInstr(Op, AssignCI);
}
}
}
}
}
Expand Down Expand Up @@ -1368,14 +1407,12 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
continue;

insertAssignPtrTypeIntrs(I, B);
deduceOperandElementType(I);
insertAssignTypeIntrs(I, B);
insertPtrCastOrAssignTypeInstr(I, B);
insertSpirvDecorations(I, B);
}

for (auto &I : instructions(Func))
deduceOperandElementType(&I);

for (auto *I : Worklist) {
TrackConstants = true;
if (!I->getType()->isVoidTy() || isa<StoreInst>(I))
Expand Down
16 changes: 15 additions & 1 deletion llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@ class SPIRVGlobalRegistry {
// untyped pointers.
DenseMap<Value *, Type *> DeducedElTys;
// Maps composite values to deduced types where untyped pointers are replaced
// with typed ones
// with typed ones.
DenseMap<Value *, Type *> DeducedNestedTys;
// Maps values to "assign type" calls, thus being a registry of created
// Intrinsic::spv_assign_ptr_type instructions.
DenseMap<Value *, CallInst *> AssignPtrTypeInstr;

// Add a new OpTypeXXX instruction without checking for duplicates.
SPIRVType *createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder,
Expand Down Expand Up @@ -148,6 +151,17 @@ class SPIRVGlobalRegistry {
return It == FunResPointerTypes.end() ? nullptr : It->second;
}

// A registry of "assign type" records:
// - Add a record.
void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI) {
AssignPtrTypeInstr[Val] = AssignPtrTyCI;
}
// - Find a record.
CallInst *findAssignPtrTypeInstr(const Value *Val) {
auto It = AssignPtrTypeInstr.find(Val);
return It == AssignPtrTypeInstr.end() ? nullptr : It->second;
}

// Deduced element types of untyped pointers and composites:
// - Add a record to the map of deduced element types.
void addDeducedElementType(Value *Val, Type *Ty) { DeducedElTys[Val] = Ty; }
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,8 @@ generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
MachineInstr *Def = MRI.getVRegDef(Reg);
assert(Def && "Expecting an instruction that defines the register");
// G_GLOBAL_VALUE already has type info.
if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE &&
Def->getOpcode() != SPIRV::ASSIGN_TYPE)
insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,
MF.getRegInfo());
ToErase.push_back(&MI);
Expand All @@ -427,7 +428,8 @@ generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
MachineInstr *Def = MRI.getVRegDef(Reg);
assert(Def && "Expecting an instruction that defines the register");
// G_GLOBAL_VALUE already has type info.
if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE &&
Def->getOpcode() != SPIRV::ASSIGN_TYPE)
insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
ToErase.push_back(&MI);
} else if (MIOp == TargetOpcode::G_CONSTANT ||
Expand Down
Loading
Loading