blob: 6d9ad8d3ad4364ef6575f02a3ad60d9a3b97f996 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt < %s -passes=nvptx-ir-peephole -S | FileCheck %s
target triple = "nvptx64-nvidia-cuda"
; fsub(fmul(a, b), c) => fma(a, b, fneg(c))
define float @test_fsub_fmul_c(float %a, float %b, float %c) {
; CHECK-LABEL: define float @test_fsub_fmul_c(
; CHECK-SAME: float [[A:%.*]], float [[B:%.*]], float [[C:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[C]]
; CHECK-NEXT: [[TMP2:%.*]] = call contract float @llvm.fma.f32(float [[A]], float [[B]], float [[TMP1]])
; CHECK-NEXT: ret float [[TMP2]]
;
%mul = fmul contract float %a, %b
%sub = fsub contract float %mul, %c
ret float %sub
}
; fsub(c, fmul(a, b)) => fma(-a, b, c)
define float @test_fsub_c_fmul(float %a, float %b, float %c) {
; CHECK-LABEL: define float @test_fsub_c_fmul(
; CHECK-SAME: float [[A:%.*]], float [[B:%.*]], float [[C:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[A]]
; CHECK-NEXT: [[TMP2:%.*]] = call contract float @llvm.fma.f32(float [[TMP1]], float [[B]], float [[C]])
; CHECK-NEXT: ret float [[TMP2]]
;
%mul = fmul contract float %a, %b
%sub = fsub contract float %c, %mul
ret float %sub
}
; fsub(fmul(a, b), fmul(c, d)) => fma(a, b, fneg(fmul(c, d)))
define float @test_fsub_fmul_fmul(float %a, float %b, float %c, float %d) {
; CHECK-LABEL: define float @test_fsub_fmul_fmul(
; CHECK-SAME: float [[A:%.*]], float [[B:%.*]], float [[C:%.*]], float [[D:%.*]]) {
; CHECK-NEXT: [[MUL2:%.*]] = fmul contract float [[C]], [[D]]
; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[MUL2]]
; CHECK-NEXT: [[TMP2:%.*]] = call contract float @llvm.fma.f32(float [[A]], float [[B]], float [[TMP1]])
; CHECK-NEXT: ret float [[TMP2]]
;
%mul1 = fmul contract float %a, %b
%mul2 = fmul contract float %c, %d
%sub = fsub contract float %mul1, %mul2
ret float %sub
}
; fsub(fmul(a, b), fmul(c, d)) => fma(fneg(c), d, fmul(a, b)))
; fmul(a, b) has multiple uses.
define float @test_fsub_fmul_fmul_multiple_use(float %a, float %b, float %c, float %d) {
; CHECK-LABEL: define float @test_fsub_fmul_fmul_multiple_use(
; CHECK-SAME: float [[A:%.*]], float [[B:%.*]], float [[C:%.*]], float [[D:%.*]]) {
; CHECK-NEXT: [[MUL1:%.*]] = fmul contract float [[A]], [[B]]
; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[C]]
; CHECK-NEXT: [[TMP2:%.*]] = call contract float @llvm.fma.f32(float [[TMP1]], float [[D]], float [[MUL1]])
; CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP2]], [[MUL1]]
; CHECK-NEXT: ret float [[ADD]]
;
%mul1 = fmul contract float %a, %b
%mul2 = fmul contract float %c, %d
%sub = fsub contract float %mul1, %mul2
%add = fadd float %sub, %mul1
ret float %add
}
; fsub(fmul(a, b), c) => fma(a, b, fneg(c)) where fsub and fmul are in different BBs
define float @test_fsub_fmul_different_BB(float %a, float %b, float %c, i32 %n) {
; CHECK-LABEL: define float @test_fsub_fmul_different_BB(
; CHECK-SAME: float [[A:%.*]], float [[B:%.*]], float [[C:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[INIT:.*]]:
; CHECK-NEXT: [[CMP_ITER:%.*]] = icmp sgt i32 [[N]], 10
; CHECK-NEXT: br i1 [[CMP_ITER]], label %[[ITERATION:.*]], label %[[EXIT:.*]]
; CHECK: [[ITERATION]]:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, %[[INIT]] ], [ [[I_NEXT:%.*]], %[[ITERATION]] ]
; CHECK-NEXT: [[ACC:%.*]] = phi float [ [[C]], %[[INIT]] ], [ [[ACC_NEXT:%.*]], %[[ITERATION]] ]
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
; CHECK-NEXT: [[ACC_NEXT]] = fadd contract float [[ACC]], 1.000000e+00
; CHECK-NEXT: [[CMP_LOOP:%.*]] = icmp slt i32 [[I_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[CMP_LOOP]], label %[[ITERATION]], label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[C_PHI:%.*]] = phi float [ [[C]], %[[INIT]] ], [ [[ACC_NEXT]], %[[ITERATION]] ]
; CHECK-NEXT: [[TMP0:%.*]] = fneg contract float [[C_PHI]]
; CHECK-NEXT: [[TMP1:%.*]] = call contract float @llvm.fma.f32(float [[A]], float [[B]], float [[TMP0]])
; CHECK-NEXT: ret float [[TMP1]]
;
init:
%mul = fmul contract float %a, %b
%cmp_iter = icmp sgt i32 %n, 10
br i1 %cmp_iter, label %iteration, label %exit
iteration:
%i = phi i32 [ 0, %init ], [ %i_next, %iteration ]
%acc = phi float [ %c, %init ], [ %acc_next, %iteration ]
%i_next = add i32 %i, 1
%acc_next = fadd contract float %acc, 1.0
%cmp_loop = icmp slt i32 %i_next, %n
br i1 %cmp_loop, label %iteration, label %exit
exit:
%c_phi = phi float [ %c, %init ], [ %acc_next, %iteration ]
%sub = fsub contract float %mul, %c_phi
ret float %sub
}
; fadd(fmul(a, b), c) => fma(a, b, c)
define float @test_fadd_fmul_c(float %a, float %b, float %c) {
; CHECK-LABEL: define float @test_fadd_fmul_c(
; CHECK-SAME: float [[A:%.*]], float [[B:%.*]], float [[C:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call contract float @llvm.fma.f32(float [[A]], float [[B]], float [[C]])
; CHECK-NEXT: ret float [[TMP1]]
;
%mul = fmul contract float %a, %b
%add = fadd contract float %mul, %c
ret float %add
}
; fadd(c, fmul(a, b)) => fma(a, b, c)
define float @test_fadd_c_fmul(float %a, float %b, float %c) {
; CHECK-LABEL: define float @test_fadd_c_fmul(
; CHECK-SAME: float [[A:%.*]], float [[B:%.*]], float [[C:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call contract float @llvm.fma.f32(float [[A]], float [[B]], float [[C]])
; CHECK-NEXT: ret float [[TMP1]]
;
%mul = fmul contract float %a, %b
%add = fadd contract float %c, %mul
ret float %add
}
; fadd(fmul(a, b), fmul(c, d)) => fma(a, b, fmul(c, d))
define float @test_fadd_fmul_fmul(float %a, float %b, float %c, float %d) {
; CHECK-LABEL: define float @test_fadd_fmul_fmul(
; CHECK-SAME: float [[A:%.*]], float [[B:%.*]], float [[C:%.*]], float [[D:%.*]]) {
; CHECK-NEXT: [[MUL2:%.*]] = fmul contract float [[C]], [[D]]
; CHECK-NEXT: [[TMP1:%.*]] = call contract float @llvm.fma.f32(float [[A]], float [[B]], float [[MUL2]])
; CHECK-NEXT: ret float [[TMP1]]
;
%mul1 = fmul contract float %a, %b
%mul2 = fmul contract float %c, %d
%add = fadd contract float %mul1, %mul2
ret float %add
}
; fadd(fmul(a, b), c) => fma(a, b, c) where fadd and fmul are in different BBs
define float @test_fadd_fmul_different_BB(float %a, float %b, float %c, i32 %n) {
; CHECK-LABEL: define float @test_fadd_fmul_different_BB(
; CHECK-SAME: float [[A:%.*]], float [[B:%.*]], float [[C:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[INIT:.*]]:
; CHECK-NEXT: [[CMP_ITER:%.*]] = icmp sgt i32 [[N]], 10
; CHECK-NEXT: br i1 [[CMP_ITER]], label %[[ITERATION:.*]], label %[[EXIT:.*]]
; CHECK: [[ITERATION]]:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, %[[INIT]] ], [ [[I_NEXT:%.*]], %[[ITERATION]] ]
; CHECK-NEXT: [[ACC:%.*]] = phi float [ [[C]], %[[INIT]] ], [ [[ACC_NEXT:%.*]], %[[ITERATION]] ]
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
; CHECK-NEXT: [[ACC_NEXT]] = fadd contract float [[ACC]], 1.000000e+00
; CHECK-NEXT: [[CMP_LOOP:%.*]] = icmp slt i32 [[I_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[CMP_LOOP]], label %[[ITERATION]], label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[C_PHI:%.*]] = phi float [ [[C]], %[[INIT]] ], [ [[ACC_NEXT]], %[[ITERATION]] ]
; CHECK-NEXT: [[TMP0:%.*]] = call contract float @llvm.fma.f32(float [[A]], float [[B]], float [[C_PHI]])
; CHECK-NEXT: ret float [[TMP0]]
;
init:
%mul = fmul contract float %a, %b
%cmp_iter = icmp sgt i32 %n, 10
br i1 %cmp_iter, label %iteration, label %exit
iteration:
%i = phi i32 [ 0, %init ], [ %i_next, %iteration ]
%acc = phi float [ %c, %init ], [ %acc_next, %iteration ]
%i_next = add i32 %i, 1
%acc_next = fadd contract float %acc, 1.0
%cmp_loop = icmp slt i32 %i_next, %n
br i1 %cmp_loop, label %iteration, label %exit
exit:
%c_phi = phi float [ %c, %init ], [ %acc_next, %iteration ]
%add = fadd contract float %mul, %c_phi
ret float %add
}
; These scenarios shouldn't work.
; fadd(fpext(fmul(a, b)), c) => fma(fpext(a), fpext(b), c)
define double @test_fadd_fpext_fmul_c(float %a, float %b, double %c) {
; CHECK-LABEL: define double @test_fadd_fpext_fmul_c(
; CHECK-SAME: float [[A:%.*]], float [[B:%.*]], double [[C:%.*]]) {
; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[A]], [[B]]
; CHECK-NEXT: [[EXT:%.*]] = fpext float [[MUL]] to double
; CHECK-NEXT: [[ADD:%.*]] = fadd contract double [[EXT]], [[C]]
; CHECK-NEXT: ret double [[ADD]]
;
%mul = fmul contract float %a, %b
%ext = fpext float %mul to double
%add = fadd contract double %ext, %c
ret double %add
}
; fadd(c, fpext(fmul(a, b))) => fma(fpext(a), fpext(b), c)
define double @test_fadd_c_fpext_fmul(float %a, float %b, double %c) {
; CHECK-LABEL: define double @test_fadd_c_fpext_fmul(
; CHECK-SAME: float [[A:%.*]], float [[B:%.*]], double [[C:%.*]]) {
; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[A]], [[B]]
; CHECK-NEXT: [[EXT:%.*]] = fpext float [[MUL]] to double
; CHECK-NEXT: [[ADD:%.*]] = fadd contract double [[C]], [[EXT]]
; CHECK-NEXT: ret double [[ADD]]
;
%mul = fmul contract float %a, %b
%ext = fpext float %mul to double
%add = fadd contract double %c, %ext
ret double %add
}
; Double precision tests
; fsub(fmul(a, b), c) => fma(a, b, fneg(c))
define double @test_fsub_fmul_c_double(double %a, double %b, double %c) {
; CHECK-LABEL: define double @test_fsub_fmul_c_double(
; CHECK-SAME: double [[A:%.*]], double [[B:%.*]], double [[C:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg contract double [[C]]
; CHECK-NEXT: [[TMP2:%.*]] = call contract double @llvm.fma.f64(double [[A]], double [[B]], double [[TMP1]])
; CHECK-NEXT: ret double [[TMP2]]
;
%mul = fmul contract double %a, %b
%sub = fsub contract double %mul, %c
ret double %sub
}
; fadd(fmul(a, b), c) => fma(a, b, c)
define double @test_fadd_fmul_c_double(double %a, double %b, double %c) {
; CHECK-LABEL: define double @test_fadd_fmul_c_double(
; CHECK-SAME: double [[A:%.*]], double [[B:%.*]], double [[C:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call contract double @llvm.fma.f64(double [[A]], double [[B]], double [[C]])
; CHECK-NEXT: ret double [[TMP1]]
;
%mul = fmul contract double %a, %b
%add = fadd contract double %mul, %c
ret double %add
}