Index: llvm/include/llvm/IR/IntrinsicsSPIRV.td =================================================================== --- llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -31,4 +31,5 @@ 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], []>; } Index: llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp =================================================================== --- llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +++ llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp @@ -56,6 +56,7 @@ DenseMap AggrConsts; DenseSet AggrStores; void preprocessCompositeConstants(); + void preprocessUndefs(); CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef Types, Value *Arg, Value *Arg2) { ConstantAsMetadata *CM = ValueAsMetadata::getConstant(Arg); @@ -151,6 +152,28 @@ Old->eraseFromParent(); } +void SPIRVEmitIntrinsics::preprocessUndefs() { + std::queue Worklist; + for (auto &I : instructions(F)) + Worklist.push(&I); + + while (!Worklist.empty()) { + Instruction *I = Worklist.front(); + Worklist.pop(); + + for (auto &Op : I->operands()) { + if (isa(Op) && Op->getType()->isAggregateType()) { + auto *AggrUndef = dyn_cast(Op); + 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 Worklist; for (auto &I : instructions(F)) @@ -369,7 +392,7 @@ setInsertPointSkippingPhis(*IRB, I->getNextNode()); Type *TypeToAssign = Ty; if (auto *II = dyn_cast(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(); @@ -453,6 +476,7 @@ for (auto &GV : Func.getParent()->globals()) processGlobalValue(GV); + preprocessUndefs(); preprocessCompositeConstants(); SmallVector Worklist; for (auto &I : instructions(Func)) Index: llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp =================================================================== --- llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -1344,6 +1344,12 @@ 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); + } break; case Intrinsic::spv_const_composite: { // If no values are attached, the composite is null constant. bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands(); Index: llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll @@ -0,0 +1,29 @@ +; 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 +} Index: llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll @@ -0,0 +1,18 @@ +; 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 +}