Hi!
I've recently encountered a peculiar behaviour regarding explicit mad() in a fragment shader. We compile shaders using DXC.
The line in question is
#define FAST_GAMMA_2_LINEAR( COLOR ) ( COLOR * (COLOR * (COLOR * 0.305306011 + 0.682171111) + 0.012522878) )
when changing the code to
#define FAST_GAMMA_2_LINEAR( COLOR ) ( COLOR * mad(COLOR, mad(COLOR, 0.305306011, 0.682171111), 0.012522878) )
all shaders that use the code become slower.
When running SPIR-V through malioc:
1. I see that
Work registers: 31 Uniform registers: 14 Stack spilling: false 16-bit arithmetic: 32% A LS V T Bound Total instruction cycles: 2.80 1.00 4.00 1.00 V Shortest path cycles: 0.67 0.00 1.25 0.50 V Longest path cycles: 2.80 1.00 4.00 1.00 V //----------------// %98 = OpFConvert %v4half %97 %99 = OpVectorShuffle %v3half %98 %98 0 1 2 %100 = OpVectorTimesScalar %v3half %99 %half_0x1_38cpn2 %101 = OpFAdd %v3half %100 %54 %102 = OpFMul %v3half %99 %101 %103 = OpFAdd %v3half %102 %56 %104 = OpFMul %v3half %99 %103
becomes
Work registers: 32 Uniform registers: 12 Stack spilling: false 16-bit arithmetic: 27% A LS V T Bound Total instruction cycles: 2.97 1.00 4.00 1.00 V Shortest path cycles: 0.71 0.00 1.25 0.50 V Longest path cycles: 2.97 1.00 4.00 1.00 V //----------------// %101 = OpFConvert %v4half %100 %102 = OpVectorShuffle %v3half %101 %101 0 1 2 %36 = OpExtInst %v3half %1 Fma %102 %59 %61 %37 = OpExtInst %v3half %1 Fma %102 %36 %63 %103 = OpFMul %v3half %102 %37
2. There are now two new decorations for related registers:
OpDecorate %36 NoContraction OpDecorate %37 NoContraction
I was under the impression that manually using mad() could be more beneficial since it would be a direct hint to the compiler/driver about our intentions. But, it looks like even the DXC compiler avoids explicit FMAs. Performance loss and ALU cost increase is observed in shader variants with either explicit half precision types or RelaxedOps.
No dedicated lerp instruction - will just end up as normal maths ops.