AMDGPU code size regression when using fdiv instead of rcp intrinsic
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
In this example, when using an `fdiv` which can be substituted for the `llvm.amdgcn.rcp` intrinsic, there is a small code size regression. There is an fneg here which in the rcp case is optimally placed as the source of a v_fma_f32. This is free, since fma is always a VOP3 instruction. In the regressing case, the fneg source modifier is on a v_mul_f32, which forces using a VOP3 encoding costing an extra 8 bytes. The fneg in the original IR is in the optimal placement, so the DAG combiner is moving the fneg to a worse place.
https://godbolt.org/z/4M3ncjab7
```
; RUN: llc -mcpu=gfx900 < %s
target triple = "amdgcn-amd-amdhsa"
; fneg is placed on the FMA, saves 4 bytes. Should have only 1 v_mul_f32_e64
define float @good(float %arg) #0 {
bb:
%call = tail call float @llvm.fabs.f32(float %arg)
%fcmp = fcmp uge float %call, 0x3810000000000000
%fmul = fmul float %call, 0x4170000000000000
%select = select i1 %fcmp, float %call, float %fmul
%call1 = tail call float @llvm.amdgcn.log.f32(float %select)
%fmul2 = fmul float %call1, 0x3FD5555560000000
%call3 = tail call float @llvm.amdgcn.exp2.f32(float %fmul2)
%fmul4 = fmul float %call3, %call3
%call5 = tail call float @llvm.amdgcn.rcp.f32(float %fmul4)
%fneg = fneg float %select
%call6 = tail call float @llvm.fmuladd.f32(float %call5, float %fneg, float %call3)
%call7 = tail call float @llvm.fmuladd.f32(float %call6, float 0xBFD5555560000000, float %call3)
%fmul8 = fmul float %call7, 3.906250e-03
%select9 = select i1 %fcmp, float %call7, float %fmul8
%call10 = tail call i1 @llvm.is.fpclass.f32(float %arg, i32 612)
%call11 = tail call float @llvm.copysign.f32(float %select9, float %arg)
%select12 = select i1 %call10, float %arg, float %call11
ret float %select12
}
; fneg is placed on the fmul, requiring VOP3 encoding. Uses 2 v_mul_f32_e64, when the second could be v_mul_f32_e32
define float @bad(float %arg) #0 {
bb:
%call = tail call float @llvm.fabs.f32(float %arg)
%fcmp = fcmp uge float %call, 0x3810000000000000
%fmul = fmul float %call, 0x4170000000000000
%select = select i1 %fcmp, float %call, float %fmul
%call1 = tail call float @llvm.amdgcn.log.f32(float %select)
%fmul2 = fmul float %call1, 0x3FD5555560000000
%call3 = tail call float @llvm.amdgcn.exp2.f32(float %fmul2)
%fmul4 = fmul float %call3, %call3
%fdiv = fdiv afn float 1.000000e+00, %fmul4, !fpmath !0
%fneg = fneg float %select
%call5 = tail call float @llvm.fmuladd.f32(float %fdiv, float %fneg, float %call3)
%call6 = tail call float @llvm.fmuladd.f32(float %call5, float 0xBFD5555560000000, float %call3)
%fmul7 = fmul float %call6, 3.906250e-03
%select8 = select i1 %fcmp, float %call6, float %fmul7
%call9 = tail call i1 @llvm.is.fpclass.f32(float %arg, i32 612)
%call10 = tail call float @llvm.copysign.f32(float %select8, float %arg)
%select11 = select i1 %call9, float %arg, float %call10
ret float %select11
}
declare float @llvm.amdgcn.exp2.f32(float) #1
declare float @llvm.amdgcn.log.f32(float) #1
declare float @llvm.amdgcn.rcp.f32(float) #1
declare float @llvm.copysign.f32(float, float) #1
declare float @llvm.fabs.f32(float) #1
declare float @llvm.fmuladd.f32(float, float, float) #1
declare i1 @llvm.is.fpclass.f32(float, i32 immarg) #1
attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) "amdgpu-no-cluster-id-x" "amdgpu-no-cluster-id-y" "amdgpu-no-cluster-id-z" "amdgpu-no-completion-action" "amdgpu-no-default-queue" "amdgpu-no-dispatch-id" "amdgpu-no-dispatch-ptr" "amdgpu-no-flat-scratch-init" "amdgpu-no-heap-ptr" "amdgpu-no-hostcall-ptr" "amdgpu-no-implicitarg-ptr" "amdgpu-no-lds-kernel-id" "amdgpu-no-multigrid-sync-arg" "amdgpu-no-queue-ptr" "amdgpu-no-workgroup-id-x" "amdgpu-no-workgroup-id-y" "amdgpu-no-workgroup-id-z" "amdgpu-no-workitem-id-x" "amdgpu-no-workitem-id-y" "amdgpu-no-workitem-id-z" }
attributes #1 = { nocallback nocreateundeforpoison nofree nosync nounwind speculatable willreturn memory(none) }
!0 = !{float 2.500000e+00}
```
fnegFoldsIntoOpcode and performFNegCombine probably need to handle ISD::FDIV better. hasSourceMods also reports false for fdiv, which isn't true most of the time
Contributor guide
Assessment
This issue has not been assessed yet.