mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-27 05:40:06 +00:00
Fixed --eliminate-common-uniform so that it does not eliminate loads of volatile variables.
This commit is contained in:
parent
98072b749f
commit
97990dc907
@ -15,9 +15,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "common_uniform_elim_pass.h"
|
||||
|
||||
#include "cfa.h"
|
||||
#include "iterator.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
@ -130,6 +128,68 @@ ir::Instruction* CommonUniformElimPass::GetPtr(
|
||||
return ptrInst;
|
||||
}
|
||||
|
||||
bool CommonUniformElimPass::IsVolatileStruct(uint32_t type_id) {
|
||||
assert(def_use_mgr_->GetDef(type_id)->opcode() == SpvOpTypeStruct);
|
||||
bool has_volatile_deco = false;
|
||||
dec_mgr_->ForEachDecoration(type_id, SpvDecorationVolatile,
|
||||
[&has_volatile_deco](const ir::Instruction&){ has_volatile_deco = true;});
|
||||
return has_volatile_deco;
|
||||
}
|
||||
|
||||
bool CommonUniformElimPass::IsAccessChainToVolatileStructType(const ir::Instruction &AccessChainInst) {
|
||||
assert(AccessChainInst.opcode() == SpvOpAccessChain);
|
||||
|
||||
uint32_t ptr_id = AccessChainInst.GetSingleWordInOperand(0);
|
||||
const ir::Instruction* ptr_inst = def_use_mgr_->GetDef(ptr_id);
|
||||
uint32_t pointee_type_id = GetPointeeTypeId(ptr_inst);
|
||||
const uint32_t num_operands = AccessChainInst.NumOperands();
|
||||
|
||||
// walk the type tree:
|
||||
for (uint32_t idx = 3; idx < num_operands; ++idx) {
|
||||
ir::Instruction* pointee_type = def_use_mgr_->GetDef(pointee_type_id);
|
||||
|
||||
switch (pointee_type->opcode()) {
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeVector:
|
||||
case SpvOpTypeArray:
|
||||
case SpvOpTypeRuntimeArray:
|
||||
pointee_type_id = pointee_type->GetSingleWordOperand(1);
|
||||
break;
|
||||
case SpvOpTypeStruct:
|
||||
// check for volatile decorations:
|
||||
if (IsVolatileStruct(pointee_type_id)) return true;
|
||||
|
||||
if (idx < num_operands - 1) {
|
||||
const uint32_t index_id = AccessChainInst.GetSingleWordOperand(idx);
|
||||
const ir::Instruction* index_inst = def_use_mgr_->GetDef(index_id);
|
||||
uint32_t index_value = index_inst->GetSingleWordOperand(2); // TODO: replace with GetUintValueFromConstant()
|
||||
pointee_type_id = pointee_type->GetSingleWordInOperand(index_value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false && "Unhandled pointee type.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CommonUniformElimPass::IsVolatileLoad(const ir::Instruction& loadInst) {
|
||||
assert(loadInst.opcode() == SpvOpLoad);
|
||||
// Check if this Load instruction has Volatile Memory Access flag
|
||||
if (loadInst.NumOperands() == 4) {
|
||||
uint32_t memory_access_mask = loadInst.GetSingleWordOperand(3);
|
||||
if (memory_access_mask & SpvMemoryAccessVolatileMask)
|
||||
return true;
|
||||
}
|
||||
// If we load a struct directly (result type is struct),
|
||||
// check if the struct is decorated volatile
|
||||
uint32_t type_id = loadInst.type_id();
|
||||
if (def_use_mgr_->GetDef(type_id)->opcode() == SpvOpTypeStruct)
|
||||
return IsVolatileStruct(type_id);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CommonUniformElimPass::IsUniformVar(uint32_t varId) {
|
||||
const ir::Instruction* varInst =
|
||||
def_use_mgr_->id_to_defs().find(varId)->second;
|
||||
@ -301,6 +361,10 @@ bool CommonUniformElimPass::UniformAccessChainConvert(ir::Function* func) {
|
||||
continue;
|
||||
if (HasUnsupportedDecorates(ptrInst->result_id()))
|
||||
continue;
|
||||
if (IsVolatileLoad(*ii))
|
||||
continue;
|
||||
if (IsAccessChainToVolatileStructType(*ptrInst))
|
||||
continue;
|
||||
std::vector<std::unique_ptr<ir::Instruction>> newInsts;
|
||||
uint32_t replId;
|
||||
GenACLoadRepl(ptrInst, &newInsts, &replId);
|
||||
@ -386,6 +450,8 @@ bool CommonUniformElimPass::CommonUniformLoadElimination(ir::Function* func) {
|
||||
continue;
|
||||
if (HasUnsupportedDecorates(ii->result_id()))
|
||||
continue;
|
||||
if (IsVolatileLoad(*ii))
|
||||
continue;
|
||||
uint32_t replId;
|
||||
const auto uItr = uniform2load_id_.find(varId);
|
||||
if (uItr != uniform2load_id_.end()) {
|
||||
@ -438,6 +504,8 @@ bool CommonUniformElimPass::CommonUniformLoadElimBlock(ir::Function* func) {
|
||||
continue;
|
||||
if (HasUnsupportedDecorates(ii->result_id()))
|
||||
continue;
|
||||
if (IsVolatileLoad(*ii))
|
||||
continue;
|
||||
uint32_t replId;
|
||||
const auto uItr = uniform2load_id_.find(varId);
|
||||
if (uItr != uniform2load_id_.end()) {
|
||||
@ -527,6 +595,7 @@ void CommonUniformElimPass::Initialize(ir::Module* module) {
|
||||
|
||||
// TODO(greg-lunarg): Use def/use from previous pass
|
||||
def_use_mgr_.reset(new analysis::DefUseManager(consumer(), module_));
|
||||
dec_mgr_.reset(new analysis::DecorationManager(module_));
|
||||
|
||||
// Initialize next unused Id.
|
||||
next_id_ = module->id_bound();
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "def_use_manager.h"
|
||||
#include "decoration_manager.h"
|
||||
#include "module.h"
|
||||
#include "basic_block.h"
|
||||
#include "pass.h"
|
||||
@ -66,6 +67,20 @@ class CommonUniformElimPass : public Pass {
|
||||
// Return true if variable is uniform
|
||||
bool IsUniformVar(uint32_t varId);
|
||||
|
||||
// Given the type id for a struct type, checks if the struct type
|
||||
// or any struct member is volatile decorated
|
||||
bool IsVolatileStruct(uint32_t type_id);
|
||||
|
||||
// Given an OpAccessChain instruction, return true
|
||||
// if the accessed variable belongs to a volatile
|
||||
// decorated object or member of a struct type
|
||||
bool IsAccessChainToVolatileStructType(const ir::Instruction &AccessChainInst);
|
||||
|
||||
// Given an OpLoad instruction, return true if
|
||||
// OpLoad has a Volatile Memory Access flag or if
|
||||
// the resulting type is a volatile decorated struct
|
||||
bool IsVolatileLoad(const ir::Instruction& loadInst);
|
||||
|
||||
// Return true if any uses of |id| are decorate ops.
|
||||
bool HasUnsupportedDecorates(uint32_t id) const;
|
||||
|
||||
@ -179,6 +194,9 @@ class CommonUniformElimPass : public Pass {
|
||||
// Def-Uses for the module we are processing
|
||||
std::unique_ptr<analysis::DefUseManager> def_use_mgr_;
|
||||
|
||||
// Decorations for the module we are processing
|
||||
std::unique_ptr<analysis::DecorationManager> dec_mgr_;
|
||||
|
||||
// Map from block's label id to block.
|
||||
std::unordered_map<uint32_t, ir::BasicBlock*> id2block_;
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "pass_fixture.h"
|
||||
#include "pass_utils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -664,6 +663,380 @@ OpFunctionEnd
|
||||
predefs + before, predefs + after, true, true);
|
||||
}
|
||||
|
||||
TEST_F(CommonUniformElimTest, Volatile1) {
|
||||
// Note: This test exemplifies the following:
|
||||
// - Same test as Basic1 with the exception that
|
||||
// the Load of g_F in else-branch is volatile
|
||||
// - Common uniform (%_) load floated to nearest non-controlled block
|
||||
//
|
||||
// #version 140
|
||||
// in vec4 BaseColor;
|
||||
// in float fi;
|
||||
//
|
||||
// layout(std140) uniform U_t
|
||||
// {
|
||||
// float g_F;
|
||||
// float g_F2;
|
||||
// } ;
|
||||
//
|
||||
// void main()
|
||||
// {
|
||||
// vec4 v = BaseColor;
|
||||
// if (fi > 0) {
|
||||
// v = v * g_F;
|
||||
// }
|
||||
// else {
|
||||
// float f2 = g_F2 - g_F;
|
||||
// v = v * f2;
|
||||
// }
|
||||
// gl_FragColor = v;
|
||||
// }
|
||||
|
||||
const std::string predefs =
|
||||
R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragColor
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 140
|
||||
OpName %main "main"
|
||||
OpName %v "v"
|
||||
OpName %BaseColor "BaseColor"
|
||||
OpName %fi "fi"
|
||||
OpName %U_t "U_t"
|
||||
OpMemberName %U_t 0 "g_F"
|
||||
OpMemberName %U_t 1 "g_F2"
|
||||
OpName %_ ""
|
||||
OpName %f2 "f2"
|
||||
OpName %gl_FragColor "gl_FragColor"
|
||||
OpMemberDecorate %U_t 0 Offset 0
|
||||
OpMemberDecorate %U_t 1 Offset 4
|
||||
OpDecorate %U_t Block
|
||||
OpDecorate %_ DescriptorSet 0
|
||||
%void = OpTypeVoid
|
||||
%11 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%fi = OpVariable %_ptr_Input_float Input
|
||||
%float_0 = OpConstant %float 0
|
||||
%bool = OpTypeBool
|
||||
%U_t = OpTypeStruct %float %float
|
||||
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
|
||||
%_ = OpVariable %_ptr_Uniform_U_t Uniform
|
||||
%int = OpTypeInt 32 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%int_1 = OpConstant %int 1
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
||||
)";
|
||||
|
||||
const std::string before =
|
||||
R"(%main = OpFunction %void None %11
|
||||
%26 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4float Function
|
||||
%f2 = OpVariable %_ptr_Function_float Function
|
||||
%27 = OpLoad %v4float %BaseColor
|
||||
OpStore %v %27
|
||||
%28 = OpLoad %float %fi
|
||||
%29 = OpFOrdGreaterThan %bool %28 %float_0
|
||||
OpSelectionMerge %30 None
|
||||
OpBranchConditional %29 %31 %32
|
||||
%31 = OpLabel
|
||||
%33 = OpLoad %v4float %v
|
||||
%34 = OpAccessChain %_ptr_Uniform_float %_ %int_0
|
||||
%35 = OpLoad %float %34
|
||||
%36 = OpVectorTimesScalar %v4float %33 %35
|
||||
OpStore %v %36
|
||||
OpBranch %30
|
||||
%32 = OpLabel
|
||||
%37 = OpAccessChain %_ptr_Uniform_float %_ %int_1
|
||||
%38 = OpLoad %float %37
|
||||
%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0
|
||||
%40 = OpLoad %float %39 Volatile
|
||||
%41 = OpFSub %float %38 %40
|
||||
OpStore %f2 %41
|
||||
%42 = OpLoad %v4float %v
|
||||
%43 = OpLoad %float %f2
|
||||
%44 = OpVectorTimesScalar %v4float %42 %43
|
||||
OpStore %v %44
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
%45 = OpLoad %v4float %v
|
||||
OpStore %gl_FragColor %45
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after =
|
||||
R"(%main = OpFunction %void None %11
|
||||
%26 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4float Function
|
||||
%f2 = OpVariable %_ptr_Function_float Function
|
||||
%50 = OpLoad %U_t %_
|
||||
%27 = OpLoad %v4float %BaseColor
|
||||
OpStore %v %27
|
||||
%28 = OpLoad %float %fi
|
||||
%29 = OpFOrdGreaterThan %bool %28 %float_0
|
||||
OpSelectionMerge %30 None
|
||||
OpBranchConditional %29 %31 %32
|
||||
%31 = OpLabel
|
||||
%33 = OpLoad %v4float %v
|
||||
%47 = OpCompositeExtract %float %50 0
|
||||
%36 = OpVectorTimesScalar %v4float %33 %47
|
||||
OpStore %v %36
|
||||
OpBranch %30
|
||||
%32 = OpLabel
|
||||
%49 = OpCompositeExtract %float %50 1
|
||||
%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0
|
||||
%40 = OpLoad %float %39 Volatile
|
||||
%41 = OpFSub %float %49 %40
|
||||
OpStore %f2 %41
|
||||
%42 = OpLoad %v4float %v
|
||||
%43 = OpLoad %float %f2
|
||||
%44 = OpVectorTimesScalar %v4float %42 %43
|
||||
OpStore %v %44
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
%45 = OpLoad %v4float %v
|
||||
OpStore %gl_FragColor %45
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<opt::CommonUniformElimPass>(
|
||||
predefs + before, predefs + after, true, true);
|
||||
}
|
||||
|
||||
TEST_F(CommonUniformElimTest, Volatile2) {
|
||||
// Note: This test exemplifies the following:
|
||||
// - Same test as Basic1 with the exception that
|
||||
// U_t is Volatile.
|
||||
// - No optimizations are applied
|
||||
//
|
||||
// #version 430
|
||||
// in vec4 BaseColor;
|
||||
// in float fi;
|
||||
//
|
||||
// layout(std430) volatile buffer U_t
|
||||
// {
|
||||
// float g_F;
|
||||
// float g_F2;
|
||||
// };
|
||||
//
|
||||
//
|
||||
// void main(void)
|
||||
// {
|
||||
// vec4 v = BaseColor;
|
||||
// if (fi > 0) {
|
||||
// v = v * g_F;
|
||||
// } else {
|
||||
// float f2 = g_F2 - g_F;
|
||||
// v = v * f2;
|
||||
// }
|
||||
// }
|
||||
|
||||
const std::string text =
|
||||
R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %BaseColor %fi
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 430
|
||||
OpName %main "main"
|
||||
OpName %v "v"
|
||||
OpName %BaseColor "BaseColor"
|
||||
OpName %fi "fi"
|
||||
OpName %U_t "U_t"
|
||||
OpMemberName %U_t 0 "g_F"
|
||||
OpMemberName %U_t 1 "g_F2"
|
||||
OpName %_ ""
|
||||
OpName %f2 "f2"
|
||||
OpDecorate %BaseColor Location 0
|
||||
OpDecorate %fi Location 0
|
||||
OpMemberDecorate %U_t 0 Volatile
|
||||
OpMemberDecorate %U_t 0 Offset 0
|
||||
OpMemberDecorate %U_t 1 Volatile
|
||||
OpMemberDecorate %U_t 1 Offset 4
|
||||
OpDecorate %U_t BufferBlock
|
||||
OpDecorate %_ DescriptorSet 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%fi = OpVariable %_ptr_Input_float Input
|
||||
%float_0 = OpConstant %float 0
|
||||
%bool = OpTypeBool
|
||||
%U_t = OpTypeStruct %float %float
|
||||
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
|
||||
%_ = OpVariable %_ptr_Uniform_U_t Uniform
|
||||
%int = OpTypeInt 32 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4float Function
|
||||
%f2 = OpVariable %_ptr_Function_float Function
|
||||
%12 = OpLoad %v4float %BaseColor
|
||||
OpStore %v %12
|
||||
%15 = OpLoad %float %fi
|
||||
%18 = OpFOrdGreaterThan %bool %15 %float_0
|
||||
OpSelectionMerge %20 None
|
||||
OpBranchConditional %18 %19 %31
|
||||
%19 = OpLabel
|
||||
%21 = OpLoad %v4float %v
|
||||
%28 = OpAccessChain %_ptr_Uniform_float %_ %int_0
|
||||
%29 = OpLoad %float %28
|
||||
%30 = OpVectorTimesScalar %v4float %21 %29
|
||||
OpStore %v %30
|
||||
OpBranch %20
|
||||
%31 = OpLabel
|
||||
%35 = OpAccessChain %_ptr_Uniform_float %_ %int_1
|
||||
%36 = OpLoad %float %35
|
||||
%37 = OpAccessChain %_ptr_Uniform_float %_ %int_0
|
||||
%38 = OpLoad %float %37
|
||||
%39 = OpFSub %float %36 %38
|
||||
OpStore %f2 %39
|
||||
%40 = OpLoad %v4float %v
|
||||
%41 = OpLoad %float %f2
|
||||
%42 = OpVectorTimesScalar %v4float %40 %41
|
||||
OpStore %v %42
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
opt::Pass::Status res = std::get<1>(SinglePassRunAndDisassemble<opt::CommonUniformElimPass>(text, true));
|
||||
EXPECT_EQ(res, opt::Pass::Status::SuccessWithoutChange);
|
||||
}
|
||||
|
||||
TEST_F(CommonUniformElimTest, Volatile3) {
|
||||
// Note: This test exemplifies the following:
|
||||
// - Same test as Volatile2 with the exception that
|
||||
// the nested struct S is volatile
|
||||
// - No optimizations are applied
|
||||
//
|
||||
// #version 430
|
||||
// in vec4 BaseColor;
|
||||
// in float fi;
|
||||
//
|
||||
// struct S {
|
||||
// volatile float a;
|
||||
// };
|
||||
//
|
||||
// layout(std430) buffer U_t
|
||||
// {
|
||||
// S g_F;
|
||||
// S g_F2;
|
||||
// };
|
||||
//
|
||||
//
|
||||
// void main(void)
|
||||
// {
|
||||
// vec4 v = BaseColor;
|
||||
// if (fi > 0) {
|
||||
// v = v * g_F.a;
|
||||
// } else {
|
||||
// float f2 = g_F2.a - g_F.a;
|
||||
// v = v * f2;
|
||||
// }
|
||||
// }
|
||||
|
||||
const std::string text =
|
||||
R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %BaseColor %fi
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 430
|
||||
OpName %main "main"
|
||||
OpName %v "v"
|
||||
OpName %BaseColor "BaseColor"
|
||||
OpName %fi "fi"
|
||||
OpName %S "S"
|
||||
OpMemberName %S 0 "a"
|
||||
OpName %U_t "U_t"
|
||||
OpMemberName %U_t 0 "g_F"
|
||||
OpMemberName %U_t 1 "g_F2"
|
||||
OpName %_ ""
|
||||
OpName %f2 "f2"
|
||||
OpDecorate %BaseColor Location 0
|
||||
OpDecorate %fi Location 0
|
||||
OpMemberDecorate %S 0 Offset 0
|
||||
OpMemberDecorate %S 0 Volatile
|
||||
OpMemberDecorate %U_t 0 Offset 0
|
||||
OpMemberDecorate %U_t 1 Offset 4
|
||||
OpDecorate %U_t BufferBlock
|
||||
OpDecorate %_ DescriptorSet 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%fi = OpVariable %_ptr_Input_float Input
|
||||
%float_0 = OpConstant %float 0
|
||||
%bool = OpTypeBool
|
||||
%S = OpTypeStruct %float
|
||||
%U_t = OpTypeStruct %S %S
|
||||
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
|
||||
%_ = OpVariable %_ptr_Uniform_U_t Uniform
|
||||
%int = OpTypeInt 32 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4float Function
|
||||
%f2 = OpVariable %_ptr_Function_float Function
|
||||
%12 = OpLoad %v4float %BaseColor
|
||||
OpStore %v %12
|
||||
%15 = OpLoad %float %fi
|
||||
%18 = OpFOrdGreaterThan %bool %15 %float_0
|
||||
OpSelectionMerge %20 None
|
||||
OpBranchConditional %18 %19 %32
|
||||
%19 = OpLabel
|
||||
%21 = OpLoad %v4float %v
|
||||
%29 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_0
|
||||
%30 = OpLoad %float %29
|
||||
%31 = OpVectorTimesScalar %v4float %21 %30
|
||||
OpStore %v %31
|
||||
OpBranch %20
|
||||
%32 = OpLabel
|
||||
%36 = OpAccessChain %_ptr_Uniform_float %_ %int_1 %int_0
|
||||
%37 = OpLoad %float %36
|
||||
%38 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_0
|
||||
%39 = OpLoad %float %38
|
||||
%40 = OpFSub %float %37 %39
|
||||
OpStore %f2 %40
|
||||
%41 = OpLoad %v4float %v
|
||||
%42 = OpLoad %float %f2
|
||||
%43 = OpVectorTimesScalar %v4float %41 %42
|
||||
OpStore %v %43
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
opt::Pass::Status res = std::get<1>(SinglePassRunAndDisassemble<opt::CommonUniformElimPass>(text, true));
|
||||
EXPECT_EQ(res, opt::Pass::Status::SuccessWithoutChange);
|
||||
}
|
||||
// TODO(greg-lunarg): Add tests to verify handling of these cases:
|
||||
//
|
||||
// Disqualifying cases: extensions, decorations, non-logical addressing,
|
||||
|
Loading…
Reference in New Issue
Block a user