Index: clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- clang/lib/CodeGen/CGExprScalar.cpp +++ clang/lib/CodeGen/CGExprScalar.cpp @@ -3782,7 +3782,8 @@ "Only fadd/fsub can be the root of an fmuladd."); // Check whether this op is marked as fusable. - if (!op.FPFeatures.allowFPContractWithinStatement()) + if (!op.FPFeatures.allowFPContractWithinStatement() && + !op.FPFeatures.allowFPContractAcrossStatement()) return nullptr; Value *LHS = op.LHS; Index: clang/test/CodeGen/ffp-contract-fast-option.cpp =================================================================== --- clang/test/CodeGen/ffp-contract-fast-option.cpp +++ clang/test/CodeGen/ffp-contract-fast-option.cpp @@ -1,29 +1,44 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py // RUN: %clang_cc1 -O3 -ffp-contract=fast -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s +// CHECK-LABEL: @_Z13fp_contract_1fff( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call contract float @llvm.fmuladd.f32(float [[A:%.*]], float [[B:%.*]], float [[C:%.*]]) +// CHECK-NEXT: ret float [[TMP0]] +// float fp_contract_1(float a, float b, float c) { - // CHECK-LABEL: fp_contract_1fff( - // CHECK: fmul contract float - // CHECK: fadd contract float return a * b + c; } +// CHECK-LABEL: @_Z13fp_contract_2fff( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[NEG:%.*]] = fneg contract float [[C:%.*]] +// CHECK-NEXT: [[TMP0:%.*]] = tail call contract float @llvm.fmuladd.f32(float [[A:%.*]], float [[B:%.*]], float [[NEG]]) +// CHECK-NEXT: ret float [[TMP0]] +// float fp_contract_2(float a, float b, float c) { - // CHECK-LABEL: fp_contract_2fff( - // CHECK: fmul contract float - // CHECK: fsub contract float return a * b - c; } +// CHECK-LABEL: @_Z13fp_contract_3Pfff( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[A:%.*]], align 4, !tbaa [[TBAA2:![0-9]+]] +// CHECK-NEXT: [[TMP1:%.*]] = tail call contract float @llvm.fmuladd.f32(float [[B:%.*]], float [[C:%.*]], float [[TMP0]]) +// CHECK-NEXT: store float [[TMP1]], ptr [[A]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: ret void +// void fp_contract_3(float *a, float b, float c) { - // CHECK-LABEL: fp_contract_3Pfff( - // CHECK: fmul contract float - // CHECK: fadd contract float a[0] += b * c; } +// CHECK-LABEL: @_Z13fp_contract_4Pfff( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[A:%.*]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[NEG:%.*]] = fneg contract float [[B:%.*]] +// CHECK-NEXT: [[TMP1:%.*]] = tail call contract float @llvm.fmuladd.f32(float [[NEG]], float [[C:%.*]], float [[TMP0]]) +// CHECK-NEXT: store float [[TMP1]], ptr [[A]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: ret void +// void fp_contract_4(float *a, float b, float c) { - // CHECK-LABEL: fp_contract_4Pfff( - // CHECK: fmul contract float - // CHECK: fsub contract float a[0] -= b * c; } Index: clang/test/CodeGen/ffp-contract-option.c =================================================================== --- clang/test/CodeGen/ffp-contract-option.c +++ clang/test/CodeGen/ffp-contract-option.c @@ -73,9 +73,8 @@ // CHECK-CONTRACTFAST: load float, ptr // CHECK-CONTRACTFAST: load float, ptr - // CHECK-CONTRACTFAST: fmul contract float // CHECK-CONTRACTFAST: load float, ptr - // CHECK-CONTRACTFAST: fadd contract float + // CHECK-CONTRACTFAST: call contract float @llvm.fmuladd.f32 // CHECK-CONTRACTOFF: load float, ptr // CHECK-CONTRACTOFF: load float, ptr @@ -90,9 +89,8 @@ // CHECK-FASTFAST: load float, ptr // CHECK-FASTFAST: load float, ptr - // CHECK-FASTFAST: fmul fast float // CHECK-FASTFAST: load float, ptr - // CHECK-FASTFAST: fadd fast float {{.*}}, {{.*}} + // CHECK-FASTFAST: call fast float @llvm.fmuladd.f32 // CHECK-NOFAST: load float, ptr // CHECK-NOFAST: load float, ptr Index: clang/test/CodeGen/ffp-model.c =================================================================== --- clang/test/CodeGen/ffp-model.c +++ clang/test/CodeGen/ffp-model.c @@ -19,9 +19,8 @@ // CHECK: define{{.*}} float @mymuladd return x * y + z; - // CHECK-FAST: fmul fast float // CHECK-FAST: load float, ptr - // CHECK-FAST: fadd fast float + // CHECK-FAST: call fast float @llvm.fmuladd.f32 // CHECK-PRECISE: load float, ptr // CHECK-PRECISE: load float, ptr @@ -36,13 +35,11 @@ // CHECK-STRICT-FAST: load float, ptr // CHECK-STRICT-FAST: load float, ptr - // CHECK-STRICT-FAST: fmul fast float {{.*}}, {{.*}} // CHECK-STRICT-FAST: load float, ptr - // CHECK-STRICT-FAST: fadd fast float {{.*}}, {{.*}} + // CHECK-STRICT-FAST: call fast float @llvm.fmuladd.f32 // CHECK-FAST1: load float, ptr // CHECK-FAST1: load float, ptr - // CHECK-FAST1: fmul fast float {{.*}}, {{.*}} // CHECK-FAST1: load float, ptr {{.*}} - // CHECK-FAST1: fadd fast float {{.*}}, {{.*}} + // CHECK-FAST1: call fast float @llvm.fmuladd.f32 } Index: clang/test/CodeGen/fp-contract-fast-pragma.cpp =================================================================== --- clang/test/CodeGen/fp-contract-fast-pragma.cpp +++ clang/test/CodeGen/fp-contract-fast-pragma.cpp @@ -1,19 +1,25 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py // RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s // Is FP_CONTRACT honored in a simple case? +// CHECK-LABEL: @_Z13fp_contract_1fff( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call contract float @llvm.fmuladd.f32(float [[A:%.*]], float [[B:%.*]], float [[C:%.*]]) +// CHECK-NEXT: ret float [[TMP0]] +// float fp_contract_1(float a, float b, float c) { -// CHECK: _Z13fp_contract_1fff -// CHECK: %[[M:.+]] = fmul contract float %a, %b -// CHECK-NEXT: fadd contract float %[[M]], %c #pragma clang fp contract(fast) return a * b + c; } // Is FP_CONTRACT state cleared on exiting compound statements? +// CHECK-LABEL: @_Z13fp_contract_2fff( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[MUL]], [[C:%.*]] +// CHECK-NEXT: ret float [[ADD]] +// float fp_contract_2(float a, float b, float c) { - // CHECK: _Z13fp_contract_2fff - // CHECK: %[[M:.+]] = fmul float %a, %b - // CHECK-NEXT: fadd float %[[M]], %c { #pragma clang fp contract(fast) } @@ -30,10 +36,12 @@ return a * b + c; } +// CHECK-LABEL: @_Z13fp_contract_3fff( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call contract float @llvm.fmuladd.f32(float [[A:%.*]], float [[B:%.*]], float [[C:%.*]]) +// CHECK-NEXT: ret float [[TMP0]] +// float fp_contract_3(float a, float b, float c) { - // CHECK: _Z13fp_contract_3fff - // CHECK: %[[M:.+]] = fmul contract float %a, %b - // CHECK-NEXT: fadd contract float %[[M]], %c return template_muladd(a, b, c); } @@ -45,25 +53,32 @@ } }; +// CHECK-LABEL: @_ZN13fp_contract_4IiE6methodEfff( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call contract float @llvm.fmuladd.f32(float [[A:%.*]], float [[B:%.*]], float [[C:%.*]]) +// CHECK-NEXT: ret float [[TMP0]] +// template class fp_contract_4; -// CHECK: _ZN13fp_contract_4IiE6methodEfff -// CHECK: %[[M:.+]] = fmul contract float %a, %b -// CHECK-NEXT: fadd contract float %[[M]], %c // Check file-scoped FP_CONTRACT #pragma clang fp contract(fast) +// CHECK-LABEL: @_Z13fp_contract_5fff( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call contract float @llvm.fmuladd.f32(float [[A:%.*]], float [[B:%.*]], float [[C:%.*]]) +// CHECK-NEXT: ret float [[TMP0]] +// float fp_contract_5(float a, float b, float c) { - // CHECK: _Z13fp_contract_5fff - // CHECK: %[[M:.+]] = fmul contract float %a, %b - // CHECK-NEXT: fadd contract float %[[M]], %c return a * b + c; } // Verify that we can handle multiple flags on the same pragma #pragma clang fp contract(fast) contract(off) +// CHECK-LABEL: @_Z13fp_contract_6fff( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[MUL]], [[C:%.*]] +// CHECK-NEXT: ret float [[ADD]] +// float fp_contract_6(float a, float b, float c) { - // CHECK: _Z13fp_contract_6fff - // CHECK: %[[M:.+]] = fmul float %a, %b - // CHECK-NEXT: fadd float %[[M]], %c return a * b + c; } Index: clang/test/CodeGen/fp-floatcontrol-stack.cpp =================================================================== --- clang/test/CodeGen/fp-floatcontrol-stack.cpp +++ clang/test/CodeGen/fp-floatcontrol-stack.cpp @@ -23,8 +23,7 @@ //CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict #endif #if FAST -//CHECK-FAST: fmul fast float -//CHECK-FAST: fadd fast float +//CHECK-FAST: call fast float @llvm.fmuladd.f32 #endif #pragma float_control(push) @@ -49,8 +48,7 @@ #endif #if FAST //Not possible to enable float_control(except) in FAST mode. -//CHECK-FAST: fmul fast float -//CHECK-FAST: fadd fast float +//CHECK-FAST: call fast float @llvm.fmuladd.f32 #endif #pragma float_control(pop) @@ -70,8 +68,7 @@ //CHECK-NOHONOR: call nnan ninf float @llvm.fmuladd{{.*}} #endif #if FAST -//CHECK-FAST: fmul fast float -//CHECK-FAST: fadd fast float +//CHECK-FAST: call fast float @llvm.fmuladd.f32 #endif #pragma float_control(except, off) @@ -87,8 +84,7 @@ //CHECK-NOHONOR: call nnan ninf float @llvm.fmuladd{{.*}} #endif #if FAST -//CHECK-FAST: fmul fast float -//CHECK-FAST: fadd fast float +//CHECK-FAST: call fast float @llvm.fmuladd.f32 #endif #pragma float_control(precise, on, push) @@ -121,8 +117,7 @@ //CHECK-NOHONOR: call nnan ninf float @llvm.fmuladd{{.*}} #endif #if FAST -//CHECK-FAST: fmul fast float -//CHECK-FAST: fadd fast float +//CHECK-FAST: call fast float @llvm.fmuladd.f32 #endif #pragma float_control(precise, off) float precise_off FUN(4) @@ -131,21 +126,17 @@ // Note: precise_off enables fp_contract=fast and the instructions // generated do not include the contract flag, although it was enabled // in IRBuilder. -//CHECK-DDEFAULT: fmul fast float -//CHECK-DDEFAULT: fadd fast float +//CHECK-DDEFAULT: call fast float @llvm.fmuladd.f32 #endif #if EBSTRICT -//CHECK-DEBSTRICT: fmul fast float -//CHECK-DEBSTRICT: fadd fast float +//CHECK-DEBSTRICT: call fast float @llvm.fmuladd.f32 #endif #if NOHONOR // fast math should be enabled, and contract should be fast -//CHECK-NOHONOR: fmul fast float -//CHECK-NOHONOR: fadd fast float +//CHECK-NOHONOR: call fast float @llvm.fmuladd.f32 #endif #if FAST -//CHECK-FAST: fmul fast float -//CHECK-FAST: fadd fast float +//CHECK-FAST: call fast float @llvm.fmuladd.f32 #endif #pragma float_control(precise, on) @@ -185,21 +176,17 @@ float precise_off2 FUN(4) //CHECK-LABEL: define {{.*}} @_Z12precise_off2f{{.*}} #if DEFAULT -//CHECK-DDEFAULT: fmul fast float -//CHECK-DDEFAULT: fadd fast float +//CHECK-DDEFAULT: call fast float @llvm.fmuladd.f32 #endif #if EBSTRICT -//CHECK-DEBSTRICT: fmul fast float -//CHECK-DEBSTRICT: fadd fast float +//CHECK-DEBSTRICT: call fast float @llvm.fmuladd.f32 #endif #if NOHONOR // fast math settings since precise is off -//CHECK-NOHONOR: fmul fast float -//CHECK-NOHONOR: fadd fast float +//CHECK-NOHONOR: call fast float @llvm.fmuladd.f32 #endif #if FAST -//CHECK-FAST: fmul fast float -//CHECK-FAST: fadd fast float +//CHECK-FAST: call fast float @llvm.fmuladd.f32 #endif #pragma float_control(pop)