Pass the RelaxedPrecision decoration value to all affected instructions

GLSL.std.450 math functions and a few other instructions have lower
precision requirements when the RelaxedPrecision decoration is present:
https://www.khronos.org/registry/vulkan/specs/1.3/html/vkspec.html#spirvenv-precision-operation

This change does not alter any results. It just enables these
instructions to be optimized for relaxed precision in future changes.

The return type of the functions has been changed to an RValue<> to
prevent accidentally assigning values to them.

Bug: b/222218659
Change-Id: I43c51a597e4445e5e686b9cf3120abdf599d8dae
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/63688
Reviewed-by: Sean Risser <srisser@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/ShaderCore.cpp b/src/Pipeline/ShaderCore.cpp
index dee7a30..2c7d329 100644
--- a/src/Pipeline/ShaderCore.cpp
+++ b/src/Pipeline/ShaderCore.cpp
@@ -156,7 +156,7 @@
 }
 
 // Approximation of atan in [0..1]
-static Float4 Atan_01(Float4 x)
+static RValue<Float4> Atan_01(Float4 x)
 {
 	// From 4.4.49, page 81 of the Handbook of Mathematical Functions, by Milton Abramowitz and Irene Stegun
 	const Float4 a2(-0.3333314528f);
@@ -172,7 +172,7 @@
 }
 
 // Polynomial approximation of order 5 for sin(x * 2 * pi) in the range [-1/4, 1/4]
-static Float4 Sin5(Float4 x)
+static RValue<Float4> Sin5(Float4 x)
 {
 	// A * x^5 + B * x^3 + C * x
 	// Exact at x = 0, 1/12, 1/6, 1/4, and their negatives, which correspond to x * 2 * pi = 0, pi/6, pi/3, pi/2
@@ -185,7 +185,7 @@
 	return MulAdd(MulAdd(A, x2, B), x2, C) * x;
 }
 
-Float4 Sin(RValue<Float4> x)
+RValue<Float4> Sin(RValue<Float4> x, bool relaxedPrecision)
 {
 	const Float4 q = 0.25f;
 	const Float4 pi2 = 1 / (2 * 3.1415926535f);
@@ -197,7 +197,7 @@
 	return Sin5(z);
 }
 
-Float4 Cos(RValue<Float4> x)
+RValue<Float4> Cos(RValue<Float4> x, bool relaxedPrecision)
 {
 	const Float4 q = 0.25f;
 	const Float4 pi2 = 1 / (2 * 3.1415926535f);
@@ -209,12 +209,12 @@
 	return Sin5(z);
 }
 
-Float4 Tan(RValue<Float4> x)
+RValue<Float4> Tan(RValue<Float4> x, bool relaxedPrecision)
 {
-	return sw::Sin(x) / sw::Cos(x);
+	return sw::Sin(x, relaxedPrecision) / sw::Cos(x, relaxedPrecision);
 }
 
-static Float4 Asin_4_terms(RValue<Float4> x)
+static RValue<Float4> Asin_4_terms(RValue<Float4> x)
 {
 	// From 4.4.45, page 81 of the Handbook of Mathematical Functions, by Milton Abramowitz and Irene Stegun
 	// |e(x)| <= 5e-8
@@ -224,11 +224,11 @@
 	const Float4 a2(0.0742610f);
 	const Float4 a3(-0.0187293f);
 	Float4 absx = Abs(x);
-	return As<Float4>(As<Int4>(half_pi - Sqrt(1.0f - absx) * (a0 + absx * (a1 + absx * (a2 + absx * a3)))) ^
+	return As<Float4>(As<Int4>(half_pi - Sqrt<Highp>(1.0f - absx) * (a0 + absx * (a1 + absx * (a2 + absx * a3)))) ^
 	                  (As<Int4>(x) & Int4(0x80000000)));
 }
 
-static Float4 Asin_8_terms(RValue<Float4> x)
+static RValue<Float4> Asin_8_terms(RValue<Float4> x)
 {
 	// From 4.4.46, page 81 of the Handbook of Mathematical Functions, by Milton Abramowitz and Irene Stegun
 	// |e(x)| <= 0e-8
@@ -242,7 +242,7 @@
 	const Float4 a6(0.006700901f);
 	const Float4 a7(-0.0012624911f);
 	Float4 absx = Abs(x);
-	return As<Float4>(As<Int4>(half_pi - Sqrt(1.0f - absx) * (a0 + absx * (a1 + absx * (a2 + absx * (a3 + absx * (a4 + absx * (a5 + absx * (a6 + absx * a7)))))))) ^
+	return As<Float4>(As<Int4>(half_pi - Sqrt<Highp>(1.0f - absx) * (a0 + absx * (a1 + absx * (a2 + absx * (a3 + absx * (a4 + absx * (a5 + absx * (a6 + absx * a7)))))))) ^
 	                  (As<Int4>(x) & Int4(0x80000000)));
 }
 
@@ -265,7 +265,7 @@
 	return 1.57079632e+0f - Asin_4_terms(x);
 }
 
-Float4 Atan(RValue<Float4> x)
+RValue<Float4> Atan(RValue<Float4> x, bool relaxedPrecision)
 {
 	Float4 absx = Abs(x);
 	Int4 O = CmpNLT(absx, 1.0f);
@@ -277,7 +277,7 @@
 	                  (As<Int4>(x) & Int4(0x80000000)));
 }
 
-Float4 Atan2(RValue<Float4> y, RValue<Float4> x)
+RValue<Float4> Atan2(RValue<Float4> y, RValue<Float4> x, bool relaxedPrecision)
 {
 	const Float4 pi(3.14159265f);             // pi
 	const Float4 minus_pi(-3.14159265f);      // -pi
@@ -316,7 +316,7 @@
 }
 
 // TODO(chromium:1299047)
-Float4 Exp2_legacy(RValue<Float4> x0)
+static RValue<Float4> Exp2_legacy(RValue<Float4> x0)
 {
 	Int4 i = RoundInt(x0 - 0.5f);
 	Float4 ii = As<Float4>((i + Int4(127)) << 23);
@@ -332,7 +332,7 @@
 	return ii * ff;
 }
 
-Float4 Exp2(RValue<Float4> x)
+RValue<Float4> Exp2(RValue<Float4> x, bool relaxedPrecision)
 {
 	// This implementation is based on 2^(i + f) = 2^i * 2^f,
 	// where i is the integer part of x and f is the fraction.
@@ -367,7 +367,7 @@
 	return ii * ff;
 }
 
-Float4 Log2(RValue<Float4> x)
+RValue<Float4> Log2(RValue<Float4> x, bool relaxedPrecision)
 {
 	Float4 x0;
 	Float4 x1;
@@ -392,53 +392,53 @@
 	return As<Float4>((pos_inf_x & As<Int4>(x)) | (~pos_inf_x & As<Int4>(x1)));
 }
 
-Float4 Exp(RValue<Float4> x)
+RValue<Float4> Exp(RValue<Float4> x, bool relaxedPrecision)
 {
-	return sw::Exp2(1.44269504f * x);  // 1/ln(2)
+	return sw::Exp2(1.44269504f * x, relaxedPrecision);  // 1/ln(2)
 }
 
-Float4 Log(RValue<Float4> x)
+RValue<Float4> Log(RValue<Float4> x, bool relaxedPrecision)
 {
-	return 6.93147181e-1f * sw::Log2(x);  // ln(2)
+	return 6.93147181e-1f * sw::Log2(x, relaxedPrecision);  // ln(2)
 }
 
-Float4 Pow(RValue<Float4> x, RValue<Float4> y, bool relaxedPrecision)
+RValue<Float4> Pow(RValue<Float4> x, RValue<Float4> y, bool relaxedPrecision)
 {
-	Float4 log = sw::Log2(x);
+	Float4 log = sw::Log2(x, relaxedPrecision);
 	log *= y;
-	return sw::Exp2(log);
+	return sw::Exp2(log, relaxedPrecision);
 }
 
-Float4 Sinh(RValue<Float4> x)
+RValue<Float4> Sinh(RValue<Float4> x, bool relaxedPrecision)
 {
-	return (sw::Exp(x) - sw::Exp(-x)) * 0.5f;
+	return (sw::Exp(x, relaxedPrecision) - sw::Exp(-x, relaxedPrecision)) * 0.5f;
 }
 
-Float4 Cosh(RValue<Float4> x)
+RValue<Float4> Cosh(RValue<Float4> x, bool relaxedPrecision)
 {
-	return (sw::Exp(x) + sw::Exp(-x)) * 0.5f;
+	return (sw::Exp(x, relaxedPrecision) + sw::Exp(-x, relaxedPrecision)) * 0.5f;
 }
 
-Float4 Tanh(RValue<Float4> x)
+RValue<Float4> Tanh(RValue<Float4> x, bool relaxedPrecision)
 {
-	Float4 e_x = sw::Exp(x);
-	Float4 e_minus_x = sw::Exp(-x);
+	Float4 e_x = sw::Exp(x, relaxedPrecision);
+	Float4 e_minus_x = sw::Exp(-x, relaxedPrecision);
 	return (e_x - e_minus_x) / (e_x + e_minus_x);
 }
 
-Float4 Asinh(RValue<Float4> x)
+RValue<Float4> Asinh(RValue<Float4> x, bool relaxedPrecision)
 {
-	return sw::Log(x + Sqrt(x * x + 1.0f));
+	return sw::Log(x + Sqrt(x * x + 1.0f, relaxedPrecision), relaxedPrecision);
 }
 
-Float4 Acosh(RValue<Float4> x)
+RValue<Float4> Acosh(RValue<Float4> x, bool relaxedPrecision)
 {
-	return sw::Log(x + Sqrt(x + 1.0f) * Sqrt(x - 1.0f));
+	return sw::Log(x + Sqrt(x + 1.0f, relaxedPrecision) * Sqrt(x - 1.0f, relaxedPrecision), relaxedPrecision);
 }
 
-Float4 Atanh(RValue<Float4> x)
+RValue<Float4> Atanh(RValue<Float4> x, bool relaxedPrecision)
 {
-	return sw::Log((1.0f + x) / (1.0f - x)) * 0.5f;
+	return sw::Log((1.0f + x) / (1.0f - x), relaxedPrecision) * 0.5f;
 }
 
 RValue<Float4> Sqrt(RValue<Float4> x, bool relaxedPrecision)
@@ -446,12 +446,12 @@
 	return rr::Sqrt(x);  // TODO(b/222218659): Optimize for relaxed precision.
 }
 
-Float4 reciprocal(RValue<Float4> x, bool pp, bool exactAtPow2)
+RValue<Float4> reciprocal(RValue<Float4> x, bool pp, bool exactAtPow2)
 {
 	return Rcp(x, pp, exactAtPow2);
 }
 
-Float4 reciprocalSquareRoot(RValue<Float4> x, bool absolute, bool pp)
+RValue<Float4> reciprocalSquareRoot(RValue<Float4> x, bool absolute, bool pp)
 {
 	Float4 abs = x;
 
diff --git a/src/Pipeline/ShaderCore.hpp b/src/Pipeline/ShaderCore.hpp
index 7f7251d..7315a79 100644
--- a/src/Pipeline/ShaderCore.hpp
+++ b/src/Pipeline/ShaderCore.hpp
@@ -184,24 +184,24 @@
 }  // namespace SIMD
 
 // Vulkan 'SPIR-V Extended Instructions for GLSL' (GLSL.std.450) compliant transcendental functions
-Float4 Sin(RValue<Float4> x);
-Float4 Cos(RValue<Float4> x);
-Float4 Tan(RValue<Float4> x);
+RValue<Float4> Sin(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Cos(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Tan(RValue<Float4> x, bool relaxedPrecision);
 RValue<Float4> Asin(RValue<Float4> x, bool relaxedPrecision);
 RValue<Float4> Acos(RValue<Float4> x, bool relaxedPrecision);
-Float4 Atan(RValue<Float4> x);
-Float4 Atan2(RValue<Float4> y, RValue<Float4> x);
-Float4 Exp2(RValue<Float4> x);
-Float4 Log2(RValue<Float4> x);
-Float4 Exp(RValue<Float4> x);
-Float4 Log(RValue<Float4> x);
-Float4 Pow(RValue<Float4> x, RValue<Float4> y, bool relaxedPrecision);
-Float4 Sinh(RValue<Float4> x);
-Float4 Cosh(RValue<Float4> x);
-Float4 Tanh(RValue<Float4> x);
-Float4 Asinh(RValue<Float4> x);
-Float4 Acosh(RValue<Float4> x);
-Float4 Atanh(RValue<Float4> x);
+RValue<Float4> Atan(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Atan2(RValue<Float4> y, RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Exp2(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Log2(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Exp(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Log(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Pow(RValue<Float4> x, RValue<Float4> y, bool relaxedPrecision);
+RValue<Float4> Sinh(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Cosh(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Tanh(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Asinh(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Acosh(RValue<Float4> x, bool relaxedPrecision);
+RValue<Float4> Atanh(RValue<Float4> x, bool relaxedPrecision);
 RValue<Float4> Sqrt(RValue<Float4> x, bool relaxedPrecision);
 
 // Math functions with uses outside of shaders can be invoked using a verbose template argument instead
@@ -223,8 +223,8 @@
 template<> inline RValue<Float4> Pow<Mediump>(RValue<Float4> x, RValue<Float4> y) { return Pow(x, y, true); }
 // clang-format on
 
-Float4 reciprocal(RValue<Float4> x, bool pp = false, bool exactAtPow2 = false);
-Float4 reciprocalSquareRoot(RValue<Float4> x, bool abs, bool pp = false);
+RValue<Float4> reciprocal(RValue<Float4> x, bool pp = false, bool exactAtPow2 = false);
+RValue<Float4> reciprocalSquareRoot(RValue<Float4> x, bool abs, bool pp = false);
 
 void transpose4x4(Short4 &row0, Short4 &row1, Short4 &row2, Short4 &row3);
 void transpose4x3(Short4 &row0, Short4 &row1, Short4 &row2, Short4 &row3);
diff --git a/src/Pipeline/SpirvShaderArithmetic.cpp b/src/Pipeline/SpirvShaderArithmetic.cpp
index fee6f02..bc6bb59 100644
--- a/src/Pipeline/SpirvShaderArithmetic.cpp
+++ b/src/Pipeline/SpirvShaderArithmetic.cpp
@@ -417,13 +417,19 @@
 			dst.move(i, lhs.Float(i) * rhs.Float(i));
 			break;
 		case spv::OpFDiv:
+			// TODO(b/169760262): Optimize using reciprocal instructions (2.5 ULP).
+			// TODO(b/222218659): Optimize for RelaxedPrecision (2.5 ULP).
 			dst.move(i, lhs.Float(i) / rhs.Float(i));
 			break;
 		case spv::OpFMod:
-			// TODO(b/126873455): inaccurate for values greater than 2^24
+			// TODO(b/126873455): Inaccurate for values greater than 2^24.
+			// TODO(b/169760262): Optimize using reciprocal instructions.
+			// TODO(b/222218659): Optimize for RelaxedPrecision.
 			dst.move(i, lhs.Float(i) - rhs.Float(i) * Floor(lhs.Float(i) / rhs.Float(i)));
 			break;
 		case spv::OpFRem:
+			// TODO(b/169760262): Optimize using reciprocal instructions.
+			// TODO(b/222218659): Optimize for RelaxedPrecision.
 			dst.move(i, lhs.Float(i) % rhs.Float(i));
 			break;
 		case spv::OpFOrdEqual:
diff --git a/src/Pipeline/SpirvShaderGLSLstd450.cpp b/src/Pipeline/SpirvShaderGLSLstd450.cpp
index a58ea03..d1edb79 100644
--- a/src/Pipeline/SpirvShaderGLSLstd450.cpp
+++ b/src/Pipeline/SpirvShaderGLSLstd450.cpp
@@ -308,11 +308,12 @@
 			auto I = Operand(this, state, insn.word(5));
 			auto N = Operand(this, state, insn.word(6));
 			auto eta = Operand(this, state, insn.word(7));
+			Decorations r = GetDecorationsForId(insn.resultId());
 
 			SIMD::Float d = Dot(type.componentCount, I, N);
 			SIMD::Float k = SIMD::Float(1.0f) - eta.Float(0) * eta.Float(0) * (SIMD::Float(1.0f) - d * d);
 			SIMD::Int pos = CmpNLT(k, SIMD::Float(0.0f));
-			SIMD::Float t = (eta.Float(0) * d + Sqrt(k));
+			SIMD::Float t = (eta.Float(0) * d + Sqrt(k, r.RelaxedPrecision));
 
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
@@ -340,15 +341,18 @@
 		{
 			auto x = Operand(this, state, insn.word(5));
 			SIMD::Float d = Dot(getObjectType(insn.word(5)).componentCount, x, x);
+			Decorations r = GetDecorationsForId(insn.resultId());
 
-			dst.move(0, Sqrt(d));
+			dst.move(0, Sqrt(d, r.RelaxedPrecision));
 		}
 		break;
 	case GLSLstd450Normalize:
 		{
 			auto x = Operand(this, state, insn.word(5));
+			Decorations r = GetDecorationsForId(insn.resultId());
+
 			SIMD::Float d = Dot(getObjectType(insn.word(5)).componentCount, x, x);
-			SIMD::Float invLength = SIMD::Float(1.0f) / Sqrt(d);
+			SIMD::Float invLength = SIMD::Float(1.0f) / Sqrt(d, r.RelaxedPrecision);
 
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
@@ -360,6 +364,7 @@
 		{
 			auto p0 = Operand(this, state, insn.word(5));
 			auto p1 = Operand(this, state, insn.word(6));
+			Decorations r = GetDecorationsForId(insn.resultId());
 
 			// sqrt(dot(p0-p1, p0-p1))
 			SIMD::Float d = (p0.Float(0) - p1.Float(0)) * (p0.Float(0) - p1.Float(0));
@@ -369,7 +374,7 @@
 				d += (p0.Float(i) - p1.Float(i)) * (p0.Float(i) - p1.Float(i));
 			}
 
-			dst.move(0, Sqrt(d));
+			dst.move(0, Sqrt(d, r.RelaxedPrecision));
 		}
 		break;
 	case GLSLstd450Modf:
@@ -593,27 +598,33 @@
 	case GLSLstd450Sin:
 		{
 			auto radians = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Sin(radians.Float(i)));
+				dst.move(i, sw::Sin(radians.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Cos:
 		{
 			auto radians = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Cos(radians.Float(i)));
+				dst.move(i, sw::Cos(radians.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Tan:
 		{
 			auto radians = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Tan(radians.Float(i)));
+				dst.move(i, sw::Tan(radians.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
@@ -621,6 +632,7 @@
 		{
 			auto val = Operand(this, state, insn.word(5));
 			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
 				dst.move(i, sw::Asin(val.Float(i), d.RelaxedPrecision));
@@ -631,6 +643,7 @@
 		{
 			auto val = Operand(this, state, insn.word(5));
 			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
 				dst.move(i, sw::Acos(val.Float(i), d.RelaxedPrecision));
@@ -640,63 +653,77 @@
 	case GLSLstd450Atan:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Atan(val.Float(i)));
+				dst.move(i, sw::Atan(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Sinh:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Sinh(val.Float(i)));
+				dst.move(i, sw::Sinh(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Cosh:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Cosh(val.Float(i)));
+				dst.move(i, sw::Cosh(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Tanh:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Tanh(val.Float(i)));
+				dst.move(i, sw::Tanh(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Asinh:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Asinh(val.Float(i)));
+				dst.move(i, sw::Asinh(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Acosh:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Acosh(val.Float(i)));
+				dst.move(i, sw::Acosh(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Atanh:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Atanh(val.Float(i)));
+				dst.move(i, sw::Atanh(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
@@ -704,9 +731,11 @@
 		{
 			auto x = Operand(this, state, insn.word(5));
 			auto y = Operand(this, state, insn.word(6));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Atan2(x.Float(i), y.Float(i)));
+				dst.move(i, sw::Atan2(x.Float(i), y.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
@@ -725,45 +754,55 @@
 	case GLSLstd450Exp:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Exp(val.Float(i)));
+				dst.move(i, sw::Exp(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Log:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Log(val.Float(i)));
+				dst.move(i, sw::Log(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Exp2:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Exp2(val.Float(i)));
+				dst.move(i, sw::Exp2(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Log2:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, sw::Log2(val.Float(i)));
+				dst.move(i, sw::Log2(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
 	case GLSLstd450Sqrt:
 		{
 			auto val = Operand(this, state, insn.word(5));
+			Decorations d = GetDecorationsForId(insn.resultId());
+
 			for(auto i = 0u; i < type.componentCount; i++)
 			{
-				dst.move(i, Sqrt(val.Float(i)));
+				dst.move(i, Sqrt(val.Float(i), d.RelaxedPrecision));
 			}
 		}
 		break;
diff --git a/tests/PipelineBenchmarks/PipelineBenchmarks.cpp b/tests/PipelineBenchmarks/PipelineBenchmarks.cpp
index 2d063c4..3103fb5 100644
--- a/tests/PipelineBenchmarks/PipelineBenchmarks.cpp
+++ b/tests/PipelineBenchmarks/PipelineBenchmarks.cpp
@@ -100,11 +100,14 @@
 BENCHMARK_CAPTURE(Transcendental1, Nop, Nop)->Arg(REPS);
 
 BENCHMARK_CAPTURE(Transcendental1, rr_Sin, rr::Sin)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Sin, sw::Sin)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Sin_highp, sw::Sin, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Sin_mediump, sw::Sin, true /* relaxedPrecision */)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Cos, rr::Cos)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Cos, sw::Cos)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Cos_highp, sw::Cos, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Cos_mediump, sw::Cos, true /* relaxedPrecision */)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Tan, rr::Tan)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Tan, sw::Tan)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Tan_highp, sw::Tan, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Tan_mediump, sw::Tan, true /* relaxedPrecision */)->Arg(REPS);
 
 BENCHMARK_CAPTURE(Transcendental1, rr_Asin, rr::Asin)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, sw_Asin_highp, sw::Asin, false /* relaxedPrecision */)->Arg(REPS);
@@ -114,34 +117,46 @@
 BENCHMARK_CAPTURE(Transcendental1, sw_Acos_mediump, sw::Acos, true /* relaxedPrecision */)->Arg(REPS);
 
 BENCHMARK_CAPTURE(Transcendental1, rr_Atan, rr::Atan)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Atan, sw::Atan)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Atan_highp, sw::Atan, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Atan_mediump, sw::Atan, true /* relaxedPrecision */)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Sinh, rr::Sinh)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Sinh, sw::Sinh)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Sinh_highp, sw::Sinh, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Sinh_mediump, sw::Sinh, true /* relaxedPrecision */)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Cosh, rr::Cosh)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Cosh, sw::Cosh)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Cosh_highp, sw::Cosh, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Cosh_mediump, sw::Cosh, true /* relaxedPrecision */)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Tanh, rr::Tanh)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Tanh, sw::Tanh)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Tanh_highp, sw::Tanh, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Tanh_mediump, sw::Tanh, true /* relaxedPrecision */)->Arg(REPS);
 
 BENCHMARK_CAPTURE(Transcendental1, rr_Asinh, rr::Asinh)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Asinh, sw::Asinh)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Asinh_highp, sw::Asinh, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Asinh_mediump, sw::Asinh, true /* relaxedPrecision */)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Acosh, rr::Acosh)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Acosh, sw::Acosh)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Acosh_highp, sw::Acosh, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Acosh_mediump, sw::Acosh, true /* relaxedPrecision */)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Atanh, rr::Atanh)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Atanh, sw::Atanh)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Atanh_highp, sw::Atanh, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Atanh_mediump, sw::Atanh, true /* relaxedPrecision */)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental2, rr_Atan2, rr::Atan2)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental2, sw_Atan2, sw::Atan2)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental2, sw_Atan2_highp, sw::Atan2, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental2, sw_Atan2_mediump, sw::Atan2, true /* relaxedPrecision */)->Arg(REPS);
 
 BENCHMARK_CAPTURE(Transcendental2, rr_Pow, rr::Pow)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental2, sw_Pow_highp, sw::Pow<Highp>)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental2, sw_Pow_mediump, sw::Pow<Mediump>)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Exp, rr::Exp)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Exp, sw::Exp)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Exp_highp, sw::Exp, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Exp_mediump, sw::Exp, true /* relaxedPrecision */)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Log, rr::Log)->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Log, sw::Log)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Log_highp, sw::Log, false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Log_mediump, sw::Log, true /* relaxedPrecision */)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Exp2, LIFT(rr::Exp2))->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Exp2, LIFT(sw::Exp2))->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Exp2_highp, LIFT(sw::Exp2), false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Exp2_mediump, LIFT(sw::Exp2), true /* relaxedPrecision */)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Log2, LIFT(rr::Log2))->Arg(REPS);
-BENCHMARK_CAPTURE(Transcendental1, sw_Log2, LIFT(sw::Log2))->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Log2_highp, LIFT(sw::Log2), false /* relaxedPrecision */)->Arg(REPS);
+BENCHMARK_CAPTURE(Transcendental1, sw_Log2_mediump, LIFT(sw::Log2), true /* relaxedPrecision */)->Arg(REPS);
 
 BENCHMARK_CAPTURE(Transcendental1, rr_Rcp_pp_exactAtPow2_true, LIFT(Rcp_pp), true)->Arg(REPS);
 BENCHMARK_CAPTURE(Transcendental1, rr_Rcp_pp_exactAtPow2_false, LIFT(Rcp_pp), false)->Arg(REPS);