| ; 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 |
| } |