[SPIR-V] Preserve pointer address space for load/gep instructions

Differential Revision: https://reviews.llvm.org/D158761
This commit is contained in:
Michal Paszkowski 2023-09-19 01:06:43 -07:00
parent 86ddbdd3e7
commit 2616c279d5
5 changed files with 70 additions and 15 deletions

View File

@ -12,7 +12,7 @@
let TargetPrefix = "spv" in {
def int_spv_assign_type : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty]>;
def int_spv_assign_ptr_type : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty]>;
def int_spv_assign_ptr_type : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty, llvm_i32_ty], [ImmArg<ArgIndex<2>>]>;
def int_spv_assign_name : Intrinsic<[], [llvm_any_ty, llvm_vararg_ty]>;
def int_spv_track_constant : Intrinsic<[llvm_any_ty], [llvm_any_ty, llvm_metadata_ty]>;

View File

@ -58,11 +58,17 @@ class SPIRVEmitIntrinsics
void preprocessCompositeConstants();
void preprocessUndefs();
CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types,
Value *Arg, Value *Arg2) {
Value *Arg, Value *Arg2,
ArrayRef<Constant *> Imms) {
ConstantAsMetadata *CM = ValueAsMetadata::getConstant(Arg);
MDTuple *TyMD = MDNode::get(F->getContext(), CM);
MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD);
return IRB->CreateIntrinsic(IntrID, {Types}, {Arg2, VMD});
SmallVector<Value *, 4> Args;
Args.push_back(Arg2);
Args.push_back(VMD);
for (auto *Imm : Imms)
Args.push_back(Imm);
return IRB->CreateIntrinsic(IntrID, {Types}, Args);
}
void replaceMemInstrUses(Instruction *Old, Instruction *New);
void processInstrAfterVisit(Instruction *I);
@ -122,6 +128,13 @@ static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) {
B.SetInsertPoint(I);
}
static bool requireAssignPtrType(Instruction *I) {
if (isa<AllocaInst>(I) || isa<GetElementPtrInst>(I))
return true;
return false;
}
static bool requireAssignType(Instruction *I) {
IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I);
if (Intr) {
@ -389,20 +402,30 @@ void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV) {
}
void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I) {
if (I->getType()->isVoidTy() || !requireAssignType(I))
if (I->getType()->isVoidTy() || !requireAssignPtrType(I))
return;
setInsertPointSkippingPhis(*IRB, I->getNextNode());
Constant *EltTyConst;
unsigned AddressSpace = 0;
if (auto *AI = dyn_cast<AllocaInst>(I)) {
Constant *Const = Constant::getNullValue(AI->getAllocatedType());
buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {I->getType()}, Const, I);
EltTyConst = Constant::getNullValue(AI->getAllocatedType());
AddressSpace = AI->getAddressSpace();
} else if (auto *GEP = dyn_cast<GetElementPtrInst>(I)) {
EltTyConst = Constant::getNullValue(GEP->getSourceElementType());
AddressSpace = GEP->getPointerAddressSpace();
} else {
llvm_unreachable("Unexpected instruction!");
}
buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {I->getType()}, EltTyConst, I,
{IRB->getInt32(AddressSpace)});
}
void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) {
Type *Ty = I->getType();
if (!Ty->isVoidTy() && requireAssignType(I) &&
I->getOpcode() != Instruction::Alloca) {
if (!Ty->isVoidTy() && requireAssignType(I) && !requireAssignPtrType(I)) {
setInsertPointSkippingPhis(*IRB, I->getNextNode());
Type *TypeToAssign = Ty;
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
@ -414,7 +437,7 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) {
}
}
Constant *Const = Constant::getNullValue(TypeToAssign);
buildIntrWithMD(Intrinsic::spv_assign_type, {Ty}, Const, I);
buildIntrWithMD(Intrinsic::spv_assign_type, {Ty}, Const, I, {});
}
for (const auto &Op : I->operands()) {
if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) ||
@ -423,9 +446,10 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) {
setInsertPointSkippingPhis(*IRB, I);
if (isa<UndefValue>(Op) && Op->getType()->isAggregateType())
buildIntrWithMD(Intrinsic::spv_assign_type, {IRB->getInt32Ty()}, Op,
UndefValue::get(IRB->getInt32Ty()));
UndefValue::get(IRB->getInt32Ty()), {});
else
buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op);
buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op,
{});
}
}
}
@ -438,8 +462,8 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I) {
Type *Ty = IRB->getInt32Ty();
auto t = AggrConsts.find(I);
assert(t != AggrConsts.end());
auto *NewOp =
buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty}, t->second, I);
auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty},
t->second, I, {});
I->replaceAllUsesWith(NewOp);
NewOp->setArgOperand(0, I);
}
@ -454,7 +478,7 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I) {
continue;
IRB->SetInsertPoint(I);
auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,
{Op->getType(), Op->getType()}, Op, Op);
{Op->getType(), Op->getType()}, Op, Op, {});
I->setOperand(OpNo, NewOp);
}
}

View File

@ -248,7 +248,8 @@ static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
SPIRVType *BaseTy = GR->getOrCreateSPIRVType(
getMDOperandAsType(MI.getOperand(2).getMetadata(), 0), MIB);
SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
BaseTy, MI, *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo());
BaseTy, MI, *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo(),
addressSpaceToStorageClass(MI.getOperand(3).getImm()));
MachineInstr *Def = MRI.getVRegDef(Reg);
assert(Def && "Expecting an instruction that defines the register");
insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,

View File

@ -0,0 +1,14 @@
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
; CHECK: %[[#INT8:]] = OpTypeInt 8 0
; CHECK: %[[#PTR1:]] = OpTypePointer CrossWorkgroup %[[#INT8]]
; CHECK: %[[#PTR2:]] = OpTypePointer UniformConstant %[[#INT8]]
; CHECK: %[[#]] = OpInBoundsPtrAccessChain %[[#PTR1]] %[[#]] %[[#]]
; CHECK: %[[#]] = OpInBoundsPtrAccessChain %[[#PTR2]] %[[#]] %[[#]]
define spir_kernel void @foo(ptr addrspace(1) %a, ptr addrspace(2) %b) {
entry:
%c = getelementptr inbounds i8, ptr addrspace(1) %a, i32 1
%d = getelementptr inbounds i8, ptr addrspace(2) %b, i32 2
ret void
}

View File

@ -0,0 +1,16 @@
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
; CHECK: %[[#INT8:]] = OpTypeInt 8 0
; CHECK: %[[#PTR1:]] = OpTypePointer CrossWorkgroup %[[#INT8]]
; CHECK: %[[#PTR2:]] = OpTypePointer UniformConstant %[[#INT8]]
; CHECK: %[[#FNP1:]] = OpFunctionParameter %[[#PTR1]]
; CHECK: %[[#FNP2:]] = OpFunctionParameter %[[#PTR2]]
; CHECK: %[[#]] = OpLoad %[[#INT8]] %[[#FNP1]] Aligned 1
; CHECK: %[[#]] = OpLoad %[[#INT8]] %[[#FNP2]] Aligned 1
define spir_kernel void @foo(ptr addrspace(1) %a, ptr addrspace(2) %b) {
entry:
%c = load i8, ptr addrspace(1) %a
%d = load i8, ptr addrspace(2) %b
ret void
}