def int_spv_cmpxchg : Intrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_vararg_ty]>;
def int_spv_unreachable : Intrinsic<[], []>;
def int_spv_alloca : Intrinsic<[llvm_any_ty], []>;
+ def int_spv_undef : Intrinsic<[llvm_i32_ty], []>;
}
DenseMap<Instruction *, Constant *> AggrConsts;
DenseSet<Instruction *> AggrStores;
void preprocessCompositeConstants();
+ void preprocessUndefs();
CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types,
Value *Arg, Value *Arg2) {
ConstantAsMetadata *CM = ValueAsMetadata::getConstant(Arg);
Old->eraseFromParent();
}
+void SPIRVEmitIntrinsics::preprocessUndefs() {
+ std::queue<Instruction *> Worklist;
+ for (auto &I : instructions(F))
+ Worklist.push(&I);
+
+ while (!Worklist.empty()) {
+ Instruction *I = Worklist.front();
+ Worklist.pop();
+
+ for (auto &Op : I->operands()) {
+ auto *AggrUndef = dyn_cast<UndefValue>(Op);
+ if (!AggrUndef || !Op->getType()->isAggregateType())
+ continue;
+
+ IRB->SetInsertPoint(I);
+ auto *IntrUndef = IRB->CreateIntrinsic(Intrinsic::spv_undef, {}, {});
+ Worklist.push(IntrUndef);
+ I->replaceUsesOfWith(Op, IntrUndef);
+ AggrConsts[IntrUndef] = AggrUndef;
+ }
+ }
+}
+
void SPIRVEmitIntrinsics::preprocessCompositeConstants() {
std::queue<Instruction *> Worklist;
for (auto &I : instructions(F))
setInsertPointSkippingPhis(*IRB, I->getNextNode());
Type *TypeToAssign = Ty;
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
- if (II->getIntrinsicID() == Intrinsic::spv_const_composite) {
+ if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||
+ II->getIntrinsicID() == Intrinsic::spv_undef) {
auto t = AggrConsts.find(II);
assert(t != AggrConsts.end());
TypeToAssign = t->second->getType();
for (auto &GV : Func.getParent()->globals())
processGlobalValue(GV);
+ preprocessUndefs();
preprocessCompositeConstants();
SmallVector<Instruction *> Worklist;
for (auto &I : instructions(Func))
switch (I.getIntrinsicID()) {
case Intrinsic::spv_load:
return selectLoad(ResVReg, ResType, I);
- break;
case Intrinsic::spv_store:
return selectStore(I);
- break;
case Intrinsic::spv_extractv:
return selectExtractVal(ResVReg, ResType, I);
- break;
case Intrinsic::spv_insertv:
return selectInsertVal(ResVReg, ResType, I);
- break;
case Intrinsic::spv_extractelt:
return selectExtractElt(ResVReg, ResType, I);
- break;
case Intrinsic::spv_insertelt:
return selectInsertElt(ResVReg, ResType, I);
- break;
case Intrinsic::spv_gep:
return selectGEP(ResVReg, ResType, I);
- break;
case Intrinsic::spv_unref_global:
case Intrinsic::spv_init_global: {
MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg());
: nullptr;
assert(MI);
return selectGlobalValue(MI->getOperand(0).getReg(), *MI, Init);
- } break;
+ }
+ case Intrinsic::spv_undef: {
+ auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType));
+ return MIB.constrainAllUses(TII, TRI, RBI);
+ }
case Intrinsic::spv_const_composite: {
// If no values are attached, the composite is null constant.
bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands();
}
}
return MIB.constrainAllUses(TII, TRI, RBI);
- } break;
+ }
case Intrinsic::spv_assign_name: {
auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpName));
MIB.addUse(I.getOperand(I.getNumExplicitDefs() + 1).getReg());
MIB.addImm(I.getOperand(i).getImm());
}
return MIB.constrainAllUses(TII, TRI, RBI);
- } break;
+ }
case Intrinsic::spv_switch: {
auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSwitch));
for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
llvm_unreachable("Unexpected OpSwitch operand");
}
return MIB.constrainAllUses(TII, TRI, RBI);
- } break;
+ }
case Intrinsic::spv_cmpxchg:
return selectAtomicCmpXchg(ResVReg, ResType, I);
- break;
case Intrinsic::spv_unreachable:
BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUnreachable));
break;
case Intrinsic::spv_alloca:
return selectFrameIndex(ResVReg, ResType, I);
- break;
default:
llvm_unreachable("Intrinsic selection not implemented");
}
--- /dev/null
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+
+; CHECK-DAG: %[[#I32:]] = OpTypeInt 32
+; CHECK-DAG: %[[#I16:]] = OpTypeInt 16
+; CHECK-DAG: %[[#STRUCT:]] = OpTypeStruct %[[#I32]] %[[#I16]]
+; CHECK-DAG: %[[#NESTED_STRUCT:]] = OpTypeStruct %[[#STRUCT]] %[[#I16]]
+; CHECK-DAG: %[[#UNDEF:]] = OpUndef %[[#NESTED_STRUCT]]
+
+; CHECK: %[[#]] = OpFunction %[[#]] None %[[#]]
+; CHECK-NEXT: %[[#PTR:]] = OpFunctionParameter %[[#]]
+; CHECK-NEXT: %[[#]] = OpLabel
+; CHECK-NEXT: OpStore %[[#PTR]] %[[#UNDEF]] Aligned 4
+; CHECK-NEXT: OpReturn
+; CHECK-NEXT: OpFunctionEnd
+
+%struct = type {
+ i32,
+ i16
+}
+
+%nested_struct = type {
+ %struct,
+ i16
+}
+
+define void @foo(ptr %ptr) {
+ store %nested_struct undef, ptr %ptr
+ ret void
+}
--- /dev/null
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+
+; CHECK-DAG: %[[#I32:]] = OpTypeInt 32
+; CHECK-DAG: %[[#I16:]] = OpTypeInt 16
+; CHECK-DAG: %[[#STRUCT:]] = OpTypeStruct %[[#I32]] %[[#I16]]
+; CHECK-DAG: %[[#UNDEF:]] = OpUndef %[[#STRUCT]]
+
+; CHECK: %[[#]] = OpFunction %[[#]] None %[[#]]
+; CHECK-NEXT: %[[#PTR:]] = OpFunctionParameter %[[#]]
+; CHECK-NEXT: %[[#]] = OpLabel
+; CHECK-NEXT: OpStore %[[#PTR]] %[[#UNDEF]] Aligned 4
+; CHECK-NEXT: OpReturn
+; CHECK-NEXT: OpFunctionEnd
+
+define void @foo(ptr %ptr) {
+ store { i32, i16 } undef, ptr %ptr
+ ret void
+}