Commit 20220a0b by Nicolas Capens Committed by Nicolas Capens

Reuse Store logic for Modf and Frexp output parameters

The Modf and Frexp instructions from the GLSL.std.450 extended SPIR-V instruction set take a pointer argument to write one of their results to. This makes them the only arithmetic instructions which need to know how to explicitly access memory. This change replaces the partial duplication of store logic with a call to the underlying implementation of OpStore. To support storing intermediate values not associated with SPIR-V objects, the Operand class can now also wrap an independent Intermediate instance. Bug: b/153641251 Change-Id: Iebab43640b45ed6c27a77576168481d1a27158b6 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/43728 Presubmit-Ready: Nicolas Capens <nicolascapens@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarBen Clayton <bclayton@google.com> Tested-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent 0b77aa5e
...@@ -2431,6 +2431,13 @@ SpirvShader::Operand::Operand(const EmitState *state, const Object &object) ...@@ -2431,6 +2431,13 @@ SpirvShader::Operand::Operand(const EmitState *state, const Object &object)
ASSERT(intermediate || (object.kind == SpirvShader::Object::Kind::Constant)); ASSERT(intermediate || (object.kind == SpirvShader::Object::Kind::Constant));
} }
SpirvShader::Operand::Operand(const Intermediate &value)
: constant(nullptr)
, intermediate(&value)
, componentCount(value.componentCount)
{
}
SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout) SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout)
: pipelineLayout(pipelineLayout) : pipelineLayout(pipelineLayout)
{ {
......
...@@ -992,6 +992,7 @@ private: ...@@ -992,6 +992,7 @@ private:
{ {
public: public:
Operand(const SpirvShader *shader, const EmitState *state, SpirvShader::Object::ID objectId); Operand(const SpirvShader *shader, const EmitState *state, SpirvShader::Object::ID objectId);
Operand(const Intermediate &value);
RValue<SIMD::Float> Float(uint32_t i) const RValue<SIMD::Float> Float(uint32_t i) const
{ {
......
...@@ -354,24 +354,17 @@ SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitSt ...@@ -354,24 +354,17 @@ SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitSt
{ {
auto val = Operand(this, state, insn.word(5)); auto val = Operand(this, state, insn.word(5));
auto ptrId = Object::ID(insn.word(6)); auto ptrId = Object::ID(insn.word(6));
auto ptrTy = getType(getObject(ptrId));
auto ptr = GetPointerToData(ptrId, 0, state); Intermediate whole(type.componentCount);
bool interleavedByLane = IsStorageInterleavedByLane(ptrTy.storageClass);
// TODO: GLSL modf() takes an output parameter and thus the pointer is assumed
// to be in bounds even for inactive lanes.
// - Clarify the SPIR-V spec.
// - Eliminate lane masking and assume interleaving.
auto robustness = OutOfBoundsBehavior::UndefinedBehavior;
for(auto i = 0u; i < type.componentCount; i++) for(auto i = 0u; i < type.componentCount; i++)
{ {
SIMD::Float whole, frac; auto wholeAndFrac = Modf(val.Float(i));
std::tie(whole, frac) = Modf(val.Float(i)); dst.move(i, wholeAndFrac.second);
dst.move(i, frac); whole.move(i, wholeAndFrac.first);
auto p = ptr + (i * sizeof(float));
if(interleavedByLane) { p = InterleaveByLane(p); }
p.Store(whole, robustness, state->activeLaneMask());
} }
Store(ptrId, whole, false, std::memory_order_relaxed, state);
break; break;
} }
case GLSLstd450ModfStruct: case GLSLstd450ModfStruct:
...@@ -380,10 +373,9 @@ SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitSt ...@@ -380,10 +373,9 @@ SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitSt
for(auto i = 0u; i < val.componentCount; i++) for(auto i = 0u; i < val.componentCount; i++)
{ {
SIMD::Float whole, frac; auto wholeAndFrac = Modf(val.Float(i));
std::tie(whole, frac) = Modf(val.Float(i)); dst.move(i, wholeAndFrac.second);
dst.move(i, frac); dst.move(val.componentCount + i, wholeAndFrac.first);
dst.move(i + val.componentCount, whole);
} }
break; break;
} }
...@@ -499,27 +491,17 @@ SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitSt ...@@ -499,27 +491,17 @@ SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitSt
{ {
auto val = Operand(this, state, insn.word(5)); auto val = Operand(this, state, insn.word(5));
auto ptrId = Object::ID(insn.word(6)); auto ptrId = Object::ID(insn.word(6));
auto ptrTy = getType(getObject(ptrId));
auto ptr = GetPointerToData(ptrId, 0, state); Intermediate exp(type.componentCount);
bool interleavedByLane = IsStorageInterleavedByLane(ptrTy.storageClass);
// TODO: GLSL frexp() takes an output parameter and thus the pointer is assumed
// to be in bounds even for inactive lanes.
// - Clarify the SPIR-V spec.
// - Eliminate lane masking and assume interleaving.
auto robustness = OutOfBoundsBehavior::UndefinedBehavior;
for(auto i = 0u; i < type.componentCount; i++) for(auto i = 0u; i < type.componentCount; i++)
{ {
SIMD::Float significand; auto significandAndExponent = Frexp(val.Float(i));
SIMD::Int exponent; dst.move(i, significandAndExponent.first);
std::tie(significand, exponent) = Frexp(val.Float(i)); exp.move(i, significandAndExponent.second);
dst.move(i, significand);
auto p = ptr + (i * sizeof(float));
if(interleavedByLane) { p = InterleaveByLane(p); }
p.Store(exponent, robustness, state->activeLaneMask());
} }
Store(ptrId, exp, false, std::memory_order_relaxed, state);
break; break;
} }
case GLSLstd450FrexpStruct: case GLSLstd450FrexpStruct:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment