Skip to content

Commit d3f9ef1

Browse files
spirv-val: Add OpLifetimeStart/Stop (#6514)
1 parent 7ad2d7b commit d3f9ef1

File tree

2 files changed

+183
-1
lines changed

2 files changed

+183
-1
lines changed

source/val/validate_cfg.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,34 @@ spv_result_t ValidateLoopMerge(ValidationState_t& _, const Instruction* inst) {
352352
return SPV_SUCCESS;
353353
}
354354

355+
spv_result_t ValidateLifetime(ValidationState_t& _, const Instruction* inst) {
356+
const uint32_t pointer_id = _.GetOperandTypeId(inst, 0);
357+
const Instruction* pointer_inst = _.FindDef(pointer_id);
358+
if (pointer_inst->opcode() != spv::Op::OpTypePointer) {
359+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
360+
<< "Op" << spvOpcodeString(inst->opcode())
361+
<< " pointer operand type must be a OpTypePointer.";
362+
} else if (pointer_inst->GetOperandAs<spv::StorageClass>(1) !=
363+
spv::StorageClass::Function) {
364+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
365+
<< "Op" << spvOpcodeString(inst->opcode())
366+
<< " pointer operand must be in the Function storage class.";
367+
}
368+
369+
const uint32_t size = inst->GetOperandAs<uint32_t>(1);
370+
if (size != 0) {
371+
if (!_.HasCapability(spv::Capability::Addresses)) {
372+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
373+
<< "Op" << spvOpcodeString(inst->opcode())
374+
<< " size is non-zero, but the Addresses Capability is not "
375+
"declared.";
376+
}
377+
// TODO - "Size must be 0 if Pointer is a pointer to a non-void type"
378+
}
379+
380+
return SPV_SUCCESS;
381+
}
382+
355383
} // namespace
356384

357385
void printDominatorList(const BasicBlock& b) {
@@ -1268,6 +1296,10 @@ spv_result_t ControlFlowPass(ValidationState_t& _, const Instruction* inst) {
12681296
case spv::Op::OpLoopMerge:
12691297
if (auto error = ValidateLoopMerge(_, inst)) return error;
12701298
break;
1299+
case spv::Op::OpLifetimeStart:
1300+
case spv::Op::OpLifetimeStop:
1301+
if (auto error = ValidateLifetime(_, inst)) return error;
1302+
break;
12711303
default:
12721304
break;
12731305
}

test/val/val_cfg_test.cpp

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4316,7 +4316,7 @@ TEST_F(ValidateCFG, StructuredSelections_RegisterBothTrueAndFalse) {
43164316
OpMemoryModel Logical Simple
43174317
OpEntryPoint Fragment %main "main"
43184318
OpExecutionMode %main OriginUpperLeft
4319-
4319+
43204320
%void = OpTypeVoid
43214321
%void_fn = OpTypeFunction %void
43224322
@@ -5241,6 +5241,156 @@ OpFunctionEnd
52415241
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
52425242
}
52435243

5244+
TEST_F(ValidateCFG, LifetimeGood) {
5245+
const std::string text = R"(
5246+
OpCapability Kernel
5247+
OpCapability Addresses
5248+
OpCapability Int64
5249+
OpCapability Int8
5250+
OpMemoryModel Physical64 OpenCL
5251+
OpEntryPoint Kernel %func "main"
5252+
OpExecutionMode %func ContractionOff
5253+
OpDecorate %24 Alignment 4
5254+
%uint = OpTypeInt 32 0
5255+
%void = OpTypeVoid
5256+
%5 = OpTypeFunction %void
5257+
%ulong = OpTypeInt 64 0
5258+
%uint_4 = OpConstant %uint 4
5259+
%_arr_uint_4 = OpTypeArray %uint %uint_4
5260+
%_ptr_arr_uint_4 = OpTypePointer Function %_arr_uint_4
5261+
%uchar = OpTypeInt 8 0
5262+
%_ptr_uchar = OpTypePointer Function %uchar
5263+
%14 = OpTypeFunction %void %_ptr_uchar
5264+
%_ptr_uint = OpTypePointer Function %uint
5265+
%bool = OpTypeBool
5266+
%uint_n = OpConstantNull %uint
5267+
%uint_1 = OpConstant %uint 1
5268+
%func = OpFunction %void None %5
5269+
%52 = OpLabel
5270+
%24 = OpVariable %_ptr_arr_uint_4 Function
5271+
%28 = OpSGreaterThan %bool %uint_1 %uint_n
5272+
OpBranchConditional %28 %53 %54
5273+
%53 = OpLabel
5274+
%29 = OpBitcast %_ptr_uchar %24
5275+
5276+
OpLifetimeStart %29 16
5277+
%30 = OpBitcast %_ptr_uint %24
5278+
OpStore %30 %uint_1 Aligned 4
5279+
%36 = OpBitcast %_ptr_uchar %24
5280+
OpLifetimeStop %36 16
5281+
5282+
OpBranch %54
5283+
%54 = OpLabel
5284+
OpReturn
5285+
OpFunctionEnd
5286+
)";
5287+
5288+
CompileSuccessfully(text);
5289+
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5290+
}
5291+
5292+
TEST_F(ValidateCFG, LifetimeStorageClass) {
5293+
const std::string text = R"(
5294+
OpCapability Kernel
5295+
OpCapability Addresses
5296+
OpCapability Int64
5297+
OpCapability Int8
5298+
OpMemoryModel Physical64 OpenCL
5299+
OpEntryPoint Kernel %func "main"
5300+
OpExecutionMode %func ContractionOff
5301+
OpDecorate %24 Alignment 4
5302+
%uint = OpTypeInt 32 0
5303+
%void = OpTypeVoid
5304+
%5 = OpTypeFunction %void
5305+
%ulong = OpTypeInt 64 0
5306+
%uint_4 = OpConstant %uint 4
5307+
%_arr_uint_4 = OpTypeArray %uint %uint_4
5308+
%_ptr_arr_uint_4 = OpTypePointer Function %_arr_uint_4
5309+
%uchar = OpTypeInt 8 0
5310+
%_ptr_uchar = OpTypePointer CrossWorkgroup %uchar
5311+
%14 = OpTypeFunction %void %_ptr_uchar
5312+
%_ptr_uint = OpTypePointer Function %uint
5313+
%bool = OpTypeBool
5314+
%uint_n = OpConstantNull %uint
5315+
%uint_1 = OpConstant %uint 1
5316+
%func = OpFunction %void None %5
5317+
%52 = OpLabel
5318+
%24 = OpVariable %_ptr_arr_uint_4 Function
5319+
%28 = OpSGreaterThan %bool %uint_1 %uint_n
5320+
OpBranchConditional %28 %53 %54
5321+
%53 = OpLabel
5322+
%29 = OpBitcast %_ptr_uchar %24
5323+
5324+
OpLifetimeStart %29 16
5325+
%30 = OpBitcast %_ptr_uint %24
5326+
OpStore %30 %uint_1 Aligned 4
5327+
%36 = OpBitcast %_ptr_uchar %24
5328+
OpLifetimeStop %36 16
5329+
5330+
OpBranch %54
5331+
%54 = OpLabel
5332+
OpReturn
5333+
OpFunctionEnd
5334+
)";
5335+
5336+
CompileSuccessfully(text);
5337+
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
5338+
EXPECT_THAT(getDiagnosticString(),
5339+
HasSubstr("OpLifetimeStart pointer operand must be in the "
5340+
"Function storage class"));
5341+
}
5342+
5343+
TEST_F(ValidateCFG, LifetimeNonPointer) {
5344+
const std::string text = R"(
5345+
OpCapability Kernel
5346+
OpCapability Addresses
5347+
OpCapability Int64
5348+
OpCapability Int8
5349+
OpMemoryModel Physical64 OpenCL
5350+
OpEntryPoint Kernel %func "main"
5351+
OpExecutionMode %func ContractionOff
5352+
OpDecorate %24 Alignment 4
5353+
%uint = OpTypeInt 32 0
5354+
%void = OpTypeVoid
5355+
%5 = OpTypeFunction %void
5356+
%ulong = OpTypeInt 64 0
5357+
%uint_4 = OpConstant %uint 4
5358+
%_arr_uint_4 = OpTypeArray %uint %uint_4
5359+
%_ptr_arr_uint_4 = OpTypePointer Function %_arr_uint_4
5360+
%uchar = OpTypeInt 8 0
5361+
%_ptr_uchar = OpTypePointer Function %uchar
5362+
%14 = OpTypeFunction %void %_ptr_uchar
5363+
%_ptr_uint = OpTypePointer Function %uint
5364+
%bool = OpTypeBool
5365+
%uint_n = OpConstantNull %uint
5366+
%uint_1 = OpConstant %uint 1
5367+
%func = OpFunction %void None %5
5368+
%52 = OpLabel
5369+
%24 = OpVariable %_ptr_arr_uint_4 Function
5370+
%28 = OpSGreaterThan %bool %uint_1 %uint_n
5371+
OpBranchConditional %28 %53 %54
5372+
%53 = OpLabel
5373+
5374+
OpLifetimeStart %28 16
5375+
%30 = OpBitcast %_ptr_uint %24
5376+
OpStore %30 %uint_1 Aligned 4
5377+
%36 = OpBitcast %_ptr_uchar %24
5378+
OpLifetimeStop %36 16
5379+
5380+
OpBranch %54
5381+
%54 = OpLabel
5382+
OpReturn
5383+
OpFunctionEnd
5384+
)";
5385+
5386+
CompileSuccessfully(text);
5387+
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
5388+
EXPECT_THAT(
5389+
getDiagnosticString(),
5390+
HasSubstr(
5391+
"OpLifetimeStart pointer operand type must be a OpTypePointer"));
5392+
}
5393+
52445394
} // namespace
52455395
} // namespace val
52465396
} // namespace spvtools

0 commit comments

Comments
 (0)