Repository navigation
FMA codegen #11260
Copy link
Copy link
Closed
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIoptimization
Milestone
Description
These two functions are doing the same thing. The only difference is the order of parameters of Fma.MultiplyAdd. However, the codegen of the second function is not as good as the first one. Maybe worth looking at this to see if the JIT can optimize it.
static unsafe void foo2(float scale, float[] src, float[] dst, int count)
{
fixed (float* psrc = &src[0])
fixed (float* pdst = &dst[0])
{
float* pSrcCurrent = psrc;
float* pDstCurrent = pdst;
float* pEnd = pdst + count;
Vector256<float> scaleVector256 = Avx.SetAllVector256(scale);
while (pDstCurrent + 8 <= pEnd)
{
Vector256<float> dstVector = Avx.LoadVector256(pDstCurrent);
dstVector = Fma.MultiplyAdd(Avx.LoadVector256(pSrcCurrent), scaleVector256, dstVector);
Avx.Store(pDstCurrent, dstVector);
pSrcCurrent += 8;
pDstCurrent += 8;
}
}
}
static unsafe void foo3(float scale, float[] src, float[] dst, int count)
{
fixed (float* psrc = &src[0])
fixed (float* pdst = &dst[0])
{
float* pSrcCurrent = psrc;
float* pDstCurrent = pdst;
float* pEnd = pdst + count;
Vector256<float> scaleVector256 = Avx.SetAllVector256(scale);
while (pDstCurrent + 8 <= pEnd)
{
Vector256<float> dstVector = Avx.LoadVector256(pDstCurrent);
dstVector = Fma.MultiplyAdd(scaleVector256, Avx.LoadVector256(pSrcCurrent), dstVector);
Avx.Store(pDstCurrent, dstVector);
pSrcCurrent += 8;
pDstCurrent += 8;
}
}
}
category:cq
theme:register-allocator
skill-level:expert
cost:medium
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIoptimization
Type
Projects
- StatusShow more project fieldsDone
Activity
helloguo commentedon Oct 18, 2018
cc\ @fiigii @tannergooding
tannergooding commentedon Oct 18, 2018
CC. @CarolEidt, it looks like there is some additional register shuffling going on.
tannergooding commentedon Oct 18, 2018
it is unnecessarily shuffling
ymm0toymm2before the call andymm2toymm1after the call.fiigii commentedon Oct 18, 2018
The first unnecessarily shuffling (ymm0 to ymm2) seems from emitter
and the second one may be from delayfree?
fiigii commentedon Oct 18, 2018
The current FMA instruction selection/RA is not optimal, but we need more scenarios to improve it.
@tannergooding As I know, you are going to use HW intrinsic for some math lib, which would be a great opportunity.
tannergooding commentedon Oct 18, 2018
@fiigii, I don't think the issue is with the emitter, but rather the register allocator deciding that the source and destination cannot be the same here. Maybe I missed something in LSRA or in the containment checks for one of the FMA cases?
tannergooding commentedon Oct 18, 2018
At least as of right now, we try to ensure at least one of the operands is contained, preferencing 3, then 2, then 1: https://github.com/dotnet/coreclr/blob/master/src/jit/lowerxarch.cpp#L3006
We then try to ensure that the correct delay free uses are setup in LSRA: https://github.com/dotnet/coreclr/blob/master/src/jit/lsraxarch.cpp#L2516
And finally just emit the appropriate encoding (based on which are is contained) in codegen: https://github.com/dotnet/coreclr/blob/master/src/jit/hwintrinsiccodegenxarch.cpp#L2410
tannergooding commentedon Oct 18, 2018
Perhaps a possible fix here is telling the register allocator which operand ends up being the RMW operand.... @CarolEidt, do we have a good way to do that (is just setting
tgtPrefthe right thing to do here?)CarolEidt commentedon Oct 12, 2020
This is really more of a register allocation (and
Lowering) issue. I've reclassified this asregister-allocatortheme, but it may be that it has been addressed already.kevinjwz commentedon Oct 21, 2020
Another example I recently encountered:
The compiled loop body:
Ideal ouput:
It seems
vfmadd231pdis hardly selected when both 3 operands are not from memory. I think this "mul and sum" pattern should be recognized.BTW, why didn't we simply add
Fma.MultiplyAdd231, etc?CarolEidt commentedon Nov 14, 2020
This should be at least be analyzed; it may have been fixed e.g. by dotnet/coreclr/pull/19429
1 remaining item
echesakov commentedon Jul 26, 2021
Moving to 7.0.0 since it's not a bug.
echesakov commentedon Mar 15, 2022
Un-assigning myself
cc @BruceForstall
tannergooding commentedon Feb 5, 2024
This has been mostly resolved and we now generate identical code in most cases. There is still a possibility of an extra
movapsin some cases, but that's a more general register allocator consideration and no longer specific to FMA