mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
a1444219b2
some optimization opportunities (in the enclosing supper-expressions). rule 1. (-0.0 - X ) * Y => -0.0 - (X * Y) if expression "-0.0 - X" has only one reference. rule 2. (0.0 - X ) * Y => -0.0 - (X * Y) if expression "0.0 - X" has only one reference, and the instruction is marked "noSignedZero". 2. Eliminate negation (The compiler was already able to handle these opt if the 0.0s are replaced with -0.0.) rule 3: (0.0 - X) * (0.0 - Y) => X * Y rule 4: (0.0 - X) * C => X * -C if the expr is flagged "noSignedZero". 3. Rule 5: (X*Y) * X => (X*X) * Y if X!=Y and the expression is flagged with "UnsafeAlgebra". The purpose of this transformation is two-fold: a) to form a power expression (of X). b) potentially shorten the critical path: After transformation, the latency of the instruction Y is amortized by the expression of X*X, and therefore Y is in a "less critical" position compared to what it was before the transformation. 4. Remove the InstCombine code about simplifiying "X * select". The reasons are following: a) The "select" is somewhat architecture-dependent, therefore the higher level optimizers are not able to precisely predict if the simplification really yields any performance improvement or not. b) The "select" operator is bit complicate, and tends to obscure optimization opportunities. It is btter to keep it as low as possible in expr tree, and let CodeGen to tackle the optimization. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@172551 91177308-0d34-0410-b5e6-96231b3b80d8
342 lines
9.1 KiB
LLVM
342 lines
9.1 KiB
LLVM
; RUN: opt < %s -instcombine -S | FileCheck %s
|
|
|
|
; testing-case "float fold(float a) { return 1.2f * a * 2.3f; }"
|
|
; 1.2f and 2.3f is supposed to be fold.
|
|
define float @fold(float %a) {
|
|
%mul = fmul fast float %a, 0x3FF3333340000000
|
|
%mul1 = fmul fast float %mul, 0x4002666660000000
|
|
ret float %mul1
|
|
; CHECK: @fold
|
|
; CHECK: fmul float %a, 0x4006147AE0000000
|
|
}
|
|
|
|
; Same testing-case as the one used in fold() except that the operators have
|
|
; fixed FP mode.
|
|
define float @notfold(float %a) {
|
|
; CHECK: @notfold
|
|
; CHECK: %mul = fmul fast float %a, 0x3FF3333340000000
|
|
%mul = fmul fast float %a, 0x3FF3333340000000
|
|
%mul1 = fmul float %mul, 0x4002666660000000
|
|
ret float %mul1
|
|
}
|
|
|
|
define float @fold2(float %a) {
|
|
; CHECK: @fold2
|
|
; CHECK: fmul float %a, 0x4006147AE0000000
|
|
%mul = fmul float %a, 0x3FF3333340000000
|
|
%mul1 = fmul fast float %mul, 0x4002666660000000
|
|
ret float %mul1
|
|
}
|
|
|
|
; C * f1 + f1 = (C+1) * f1
|
|
define double @fold3(double %f1) {
|
|
%t1 = fmul fast double 2.000000e+00, %f1
|
|
%t2 = fadd fast double %f1, %t1
|
|
ret double %t2
|
|
; CHECK: @fold3
|
|
; CHECK: fmul fast double %f1, 3.000000e+00
|
|
}
|
|
|
|
; (C1 - X) + (C2 - Y) => (C1+C2) - (X + Y)
|
|
define float @fold4(float %f1, float %f2) {
|
|
%sub = fsub float 4.000000e+00, %f1
|
|
%sub1 = fsub float 5.000000e+00, %f2
|
|
%add = fadd fast float %sub, %sub1
|
|
ret float %add
|
|
; CHECK: @fold4
|
|
; CHECK: %1 = fadd fast float %f1, %f2
|
|
; CHECK: fsub fast float 9.000000e+00, %1
|
|
}
|
|
|
|
; (X + C1) + C2 => X + (C1 + C2)
|
|
define float @fold5(float %f1, float %f2) {
|
|
%add = fadd float %f1, 4.000000e+00
|
|
%add1 = fadd fast float %add, 5.000000e+00
|
|
ret float %add1
|
|
; CHECK: @fold5
|
|
; CHECK: fadd float %f1, 9.000000e+00
|
|
}
|
|
|
|
; (X + X) + X => 3.0 * X
|
|
define float @fold6(float %f1) {
|
|
%t1 = fadd fast float %f1, %f1
|
|
%t2 = fadd fast float %f1, %t1
|
|
ret float %t2
|
|
; CHECK: @fold6
|
|
; CHECK: fmul fast float %f1, 3.000000e+00
|
|
}
|
|
|
|
; C1 * X + (X + X) = (C1 + 2) * X
|
|
define float @fold7(float %f1) {
|
|
%t1 = fmul fast float %f1, 5.000000e+00
|
|
%t2 = fadd fast float %f1, %f1
|
|
%t3 = fadd fast float %t1, %t2
|
|
ret float %t3
|
|
; CHECK: @fold7
|
|
; CHECK: fmul fast float %f1, 7.000000e+00
|
|
}
|
|
|
|
; (X + X) + (X + X) => 4.0 * X
|
|
define float @fold8(float %f1) {
|
|
%t1 = fadd fast float %f1, %f1
|
|
%t2 = fadd fast float %f1, %f1
|
|
%t3 = fadd fast float %t1, %t2
|
|
ret float %t3
|
|
; CHECK: fold8
|
|
; CHECK: fmul fast float %f1, 4.000000e+00
|
|
}
|
|
|
|
; X - (X + Y) => 0 - Y
|
|
define float @fold9(float %f1, float %f2) {
|
|
%t1 = fadd float %f1, %f2
|
|
%t3 = fsub fast float %f1, %t1
|
|
ret float %t3
|
|
|
|
; CHECK: @fold9
|
|
; CHECK: fsub fast float 0.000000e+00, %f2
|
|
}
|
|
|
|
; Let C3 = C1 + C2. (f1 + C1) + (f2 + C2) => (f1 + f2) + C3 instead of
|
|
; "(f1 + C3) + f2" or "(f2 + C3) + f1". Placing constant-addend at the
|
|
; top of resulting simplified expression tree may potentially reveal some
|
|
; optimization opportunities in the super-expression trees.
|
|
;
|
|
define float @fold10(float %f1, float %f2) {
|
|
%t1 = fadd fast float 2.000000e+00, %f1
|
|
%t2 = fsub fast float %f2, 3.000000e+00
|
|
%t3 = fadd fast float %t1, %t2
|
|
ret float %t3
|
|
; CHECK: @fold10
|
|
; CHECK: %t3 = fadd float %t2, -1.000000e+00
|
|
; CHECK: ret float %t3
|
|
}
|
|
|
|
; once cause Crash/miscompilation
|
|
define float @fail1(float %f1, float %f2) {
|
|
%conv3 = fadd fast float %f1, -1.000000e+00
|
|
%add = fadd fast float %conv3, %conv3
|
|
%add2 = fadd fast float %add, %conv3
|
|
ret float %add2
|
|
; CHECK: @fail1
|
|
; CHECK: ret
|
|
}
|
|
|
|
define double @fail2(double %f1, double %f2) {
|
|
%t1 = fsub fast double %f1, %f2
|
|
%t2 = fadd fast double %f1, %f2
|
|
%t3 = fsub fast double %t1, %t2
|
|
ret double %t3
|
|
; CHECK: @fail2
|
|
; CHECK: ret
|
|
}
|
|
|
|
; =========================================================================
|
|
;
|
|
; Testing-cases about fmul begin
|
|
;
|
|
; =========================================================================
|
|
|
|
; ((X*C1) + C2) * C3 => (X * (C1*C3)) + (C2*C3) (i.e. distribution)
|
|
define float @fmul_distribute1(float %f1) {
|
|
%t1 = fmul float %f1, 6.0e+3
|
|
%t2 = fadd float %t1, 2.0e+3
|
|
%t3 = fmul fast float %t2, 5.0e+3
|
|
ret float %t3
|
|
; CHECK: @fmul_distribute1
|
|
; CHECK: %1 = fmul fast float %f1, 3.000000e+07
|
|
; CHECK: %t3 = fadd fast float %1, 1.000000e+07
|
|
}
|
|
|
|
; (X/C1 + C2) * C3 => X/(C1/C3) + C2*C3
|
|
define double @fmul_distribute2(double %f1, double %f2) {
|
|
%t1 = fdiv double %f1, 3.0e+0
|
|
%t2 = fadd double %t1, 5.0e+1
|
|
; 0x10000000000000 = DBL_MIN
|
|
%t3 = fmul fast double %t2, 0x10000000000000
|
|
ret double %t3
|
|
|
|
; CHECK: @fmul_distribute2
|
|
; CHECK: %1 = fdiv fast double %f1, 0x7FE8000000000000
|
|
; CHECK: fadd fast double %1, 0x69000000000000
|
|
}
|
|
|
|
; 5.0e-1 * DBL_MIN yields denormal, so "(f1*3.0 + 5.0e-1) * DBL_MIN" cannot
|
|
; be simplified into f1 * (3.0*DBL_MIN) + (5.0e-1*DBL_MIN)
|
|
define double @fmul_distribute3(double %f1) {
|
|
%t1 = fdiv double %f1, 3.0e+0
|
|
%t2 = fadd double %t1, 5.0e-1
|
|
%t3 = fmul fast double %t2, 0x10000000000000
|
|
ret double %t3
|
|
|
|
; CHECK: @fmul_distribute3
|
|
; CHECK: fmul fast double %t2, 0x10000000000000
|
|
}
|
|
|
|
; C1/X * C2 => (C1*C2) / X
|
|
define float @fmul2(float %f1) {
|
|
%t1 = fdiv float 2.0e+3, %f1
|
|
%t3 = fmul fast float %t1, 6.0e+3
|
|
ret float %t3
|
|
; CHECK: @fmul2
|
|
; CHECK: fdiv fast float 1.200000e+07, %f1
|
|
}
|
|
|
|
; X/C1 * C2 => X * (C2/C1) (if C2/C1 is normal Fp)
|
|
define float @fmul3(float %f1, float %f2) {
|
|
%t1 = fdiv float %f1, 2.0e+3
|
|
%t3 = fmul fast float %t1, 6.0e+3
|
|
ret float %t3
|
|
; CHECK: @fmul3
|
|
; CHECK: fmul fast float %f1, 3.000000e+00
|
|
}
|
|
|
|
; Rule "X/C1 * C2 => X * (C2/C1) is not applicable if C2/C1 is either a special
|
|
; value of a denormal. The 0x3810000000000000 here take value FLT_MIN
|
|
;
|
|
define float @fmul4(float %f1, float %f2) {
|
|
%t1 = fdiv float %f1, 2.0e+3
|
|
%t3 = fmul fast float %t1, 0x3810000000000000
|
|
ret float %t3
|
|
; CHECK: @fmul4
|
|
; CHECK: fmul fast float %t1, 0x3810000000000000
|
|
}
|
|
|
|
; X / C1 * C2 => X / (C2/C1) if C1/C2 is either a special value of a denormal,
|
|
; and C2/C1 is a normal value.
|
|
;
|
|
define float @fmul5(float %f1, float %f2) {
|
|
%t1 = fdiv float %f1, 3.0e+0
|
|
%t3 = fmul fast float %t1, 0x3810000000000000
|
|
ret float %t3
|
|
; CHECK: @fmul5
|
|
; CHECK: fdiv fast float %f1, 0x47E8000000000000
|
|
}
|
|
|
|
; (X*Y) * X => (X*X) * Y
|
|
define float @fmul6(float %f1, float %f2) {
|
|
%mul = fmul float %f1, %f2
|
|
%mul1 = fmul fast float %mul, %f1
|
|
ret float %mul1
|
|
; CHECK: @fmul6
|
|
; CHECK: fmul fast float %f1, %f1
|
|
}
|
|
|
|
; "(X*Y) * X => (X*X) * Y" is disabled if "X*Y" has multiple uses
|
|
define float @fmul7(float %f1, float %f2) {
|
|
%mul = fmul float %f1, %f2
|
|
%mul1 = fmul fast float %mul, %f1
|
|
%add = fadd float %mul1, %mul
|
|
ret float %add
|
|
; CHECK: @fmul7
|
|
; CHECK: fmul fast float %mul, %f1
|
|
}
|
|
|
|
; =========================================================================
|
|
;
|
|
; Testing-cases about negation
|
|
;
|
|
; =========================================================================
|
|
define float @fneg1(float %f1, float %f2) {
|
|
%sub = fsub float -0.000000e+00, %f1
|
|
%sub1 = fsub nsz float 0.000000e+00, %f2
|
|
%mul = fmul float %sub, %sub1
|
|
ret float %mul
|
|
; CHECK: @fneg1
|
|
; CHECK: fmul float %f1, %f2
|
|
}
|
|
|
|
; =========================================================================
|
|
;
|
|
; Testing-cases about div
|
|
;
|
|
; =========================================================================
|
|
|
|
; X/C1 / C2 => X * (1/(C2*C1))
|
|
define float @fdiv1(float %x) {
|
|
%div = fdiv float %x, 0x3FF3333340000000
|
|
%div1 = fdiv fast float %div, 0x4002666660000000
|
|
ret float %div1
|
|
; 0x3FF3333340000000 = 1.2f
|
|
; 0x4002666660000000 = 2.3f
|
|
; 0x3FD7303B60000000 = 0.36231884057971014492
|
|
; CHECK: @fdiv1
|
|
; CHECK: fmul fast float %x, 0x3FD7303B60000000
|
|
}
|
|
|
|
; X*C1 / C2 => X * (C1/C2)
|
|
define float @fdiv2(float %x) {
|
|
%mul = fmul float %x, 0x3FF3333340000000
|
|
%div1 = fdiv fast float %mul, 0x4002666660000000
|
|
ret float %div1
|
|
|
|
; 0x3FF3333340000000 = 1.2f
|
|
; 0x4002666660000000 = 2.3f
|
|
; 0x3FE0B21660000000 = 0.52173918485641479492
|
|
; CHECK: @fdiv2
|
|
; CHECK: fmul fast float %x, 0x3FE0B21660000000
|
|
}
|
|
|
|
; "X/C1 / C2 => X * (1/(C2*C1))" is disabled (for now) is C2/C1 is a denormal
|
|
;
|
|
define float @fdiv3(float %x) {
|
|
%div = fdiv float %x, 0x47EFFFFFE0000000
|
|
%div1 = fdiv fast float %div, 0x4002666660000000
|
|
ret float %div1
|
|
; CHECK: @fdiv3
|
|
; CHECK: fdiv float %x, 0x47EFFFFFE0000000
|
|
}
|
|
|
|
; "X*C1 / C2 => X * (C1/C2)" is disabled if C1/C2 is a denormal
|
|
define float @fdiv4(float %x) {
|
|
%mul = fmul float %x, 0x47EFFFFFE0000000
|
|
%div = fdiv float %mul, 0x3FC99999A0000000
|
|
ret float %div
|
|
; CHECK: @fdiv4
|
|
; CHECK: fmul float %x, 0x47EFFFFFE0000000
|
|
}
|
|
|
|
; (X/Y)/Z = > X/(Y*Z)
|
|
define float @fdiv5(float %f1, float %f2, float %f3) {
|
|
%t1 = fdiv float %f1, %f2
|
|
%t2 = fdiv fast float %t1, %f3
|
|
ret float %t2
|
|
; CHECK: @fdiv5
|
|
; CHECK: fmul float %f2, %f3
|
|
}
|
|
|
|
; Z/(X/Y) = > (Z*Y)/X
|
|
define float @fdiv6(float %f1, float %f2, float %f3) {
|
|
%t1 = fdiv float %f1, %f2
|
|
%t2 = fdiv fast float %f3, %t1
|
|
ret float %t2
|
|
; CHECK: @fdiv6
|
|
; CHECK: fmul float %f3, %f2
|
|
}
|
|
|
|
; C1/(X*C2) => (C1/C2) / X
|
|
define float @fdiv7(float %x) {
|
|
%t1 = fmul float %x, 3.0e0
|
|
%t2 = fdiv fast float 15.0e0, %t1
|
|
ret float %t2
|
|
; CHECK: @fdiv7
|
|
; CHECK: fdiv fast float 5.000000e+00, %x
|
|
}
|
|
|
|
; C1/(X/C2) => (C1*C2) / X
|
|
define float @fdiv8(float %x) {
|
|
%t1 = fdiv float %x, 3.0e0
|
|
%t2 = fdiv fast float 15.0e0, %t1
|
|
ret float %t2
|
|
; CHECK: @fdiv8
|
|
; CHECK: fdiv fast float 4.500000e+01, %x
|
|
}
|
|
|
|
; C1/(C2/X) => (C1/C2) * X
|
|
define float @fdiv9(float %x) {
|
|
%t1 = fdiv float 3.0e0, %x
|
|
%t2 = fdiv fast float 15.0e0, %t1
|
|
ret float %t2
|
|
; CHECK: @fdiv9
|
|
; CHECK: fmul fast float %x, 5.000000e+00
|
|
}
|