Index: flang/lib/Lower/IntrinsicCall.cpp =================================================================== --- flang/lib/Lower/IntrinsicCall.cpp +++ flang/lib/Lower/IntrinsicCall.cpp @@ -33,6 +33,7 @@ #include "flang/Optimizer/Builder/Runtime/Transformational.h" #include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" +#include "flang/Optimizer/Support/FIRContext.h" #include "flang/Optimizer/Support/FatalError.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/Math/IR/Math.h" @@ -1237,8 +1238,24 @@ // a function call to a runtime function with name defined by // 'runtimeFunc'. MathGeneratorTy funcGenerator; + + // A callback that restricts this lowering only to certain triples. The + // callback is expected to return true if this lowering is supported for the + // triple that it receives as parameter. + // If the callback is set to `nullptr`, then this lowering is available on all + // platforms. + using PlatformAvailability = bool (*)(llvm::Triple); + PlatformAvailability specificTo = nullptr; + + bool isAvailableFor(llvm::Triple triple) const { + return !specificTo || specificTo(triple); + } }; +static bool MSVC(llvm::Triple triple) { return triple.isOSMSVCRT(); } + +static bool notMSVC(llvm::Triple triple) { return !MSVC(triple); } + static mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, llvm::StringRef libFuncName, mlir::FunctionType libFuncType, @@ -1384,7 +1401,8 @@ {"floor", "floor", genF64F64FuncType, genMathOp}, {"gamma", "tgammaf", genF32F32FuncType, genLibCall}, {"gamma", "tgamma", genF64F64FuncType, genLibCall}, - {"hypot", "hypotf", genF32F32F32FuncType, genLibCall}, + {"hypot", "hypotf", genF32F32F32FuncType, genLibCall, notMSVC}, + {"hypot", "_hypotf", genF32F32F32FuncType, genLibCall, MSVC}, {"hypot", "hypot", genF64F64F64FuncType, genLibCall}, {"log", "logf", genF32F32FuncType, genMathOp}, {"log", "log", genF64F64FuncType, genMathOp}, @@ -1639,8 +1657,13 @@ const MathOperation **bestNearMatch, FunctionDistance &bestMatchDistance) { auto range = mathOps.equal_range(name); + auto triple = fir::getTargetTriple(builder.getModule()); for (auto iter = range.first; iter != range.second && iter; ++iter) { const auto &impl = *iter; + + if (!impl.isAvailableFor(triple)) + continue; + auto implType = impl.typeGenerator(builder.getContext()); if (funcType == implType) return &impl; // exact match Index: flang/test/Lower/Intrinsics/hypot.f90 =================================================================== --- /dev/null +++ flang/test/Lower/Intrinsics/hypot.f90 @@ -0,0 +1,60 @@ +! RUN: %flang_fc1 -emit-fir -triple aarch64-pc-windows-msvc %s -o - | FileCheck %s -DHYPOTF=_hypotf +! RUN: %flang_fc1 -emit-fir -triple aarch64-unknown-linux-gnu %s -o - | FileCheck %s -DHYPOTF=hypotf + +! Test hypot intrinsic for different real kinds + +! CHECK-LABEL: func @_QPhypot_testh( +! CHECK-SAME: %[[AREF:.*]]: !fir.ref{{.*}}, %[[BREF:.*]]: !fir.ref{{.*}}, %[[CREF:.*]]: !fir.ref{{.*}}) { +subroutine hypot_testh(a, b, c) +! CHECK: %[[A:.*]] = fir.load %[[AREF]] : !fir.ref +! CHECK: %[[B:.*]] = fir.load %[[BREF]] : !fir.ref +! CHECK: %[[A32:.*]] = fir.convert %[[A]] : (f16) -> f32 +! CHECK: %[[B32:.*]] = fir.convert %[[B]] : (f16) -> f32 +! CHECK: %[[C32:.*]] = fir.call @[[HYPOTF]](%[[A32]], %[[B32]]) : (f32, f32) -> f32 +! CHECK: %[[C:.*]] = fir.convert %[[C32]] : (f32) -> f16 +! CHECK: fir.store %[[C]] to %[[CREF]] : !fir.ref +! CHECK: return + real(kind=2) :: a, b, c + c = hypot(a, b) +end subroutine + +! CHECK-LABEL: func @_QPhypot_testb( +! CHECK-SAME: %[[AREF:.*]]: !fir.ref{{.*}}, %[[BREF:.*]]: !fir.ref{{.*}}, %[[CREF:.*]]: !fir.ref{{.*}}) { +subroutine hypot_testb(a, b, c) +! CHECK: %[[A:.*]] = fir.load %[[AREF]] : !fir.ref +! CHECK: %[[B:.*]] = fir.load %[[BREF]] : !fir.ref +! CHECK: %[[A32:.*]] = fir.convert %[[A]] : (bf16) -> f32 +! CHECK: %[[B32:.*]] = fir.convert %[[B]] : (bf16) -> f32 +! CHECK: %[[C32:.*]] = fir.call @[[HYPOTF]](%[[A32]], %[[B32]]) : (f32, f32) -> f32 +! CHECK: %[[C:.*]] = fir.convert %[[C32]] : (f32) -> bf16 +! CHECK: fir.store %[[C]] to %[[CREF]] : !fir.ref +! CHECK: return + real(kind=3) :: a, b, c + c = hypot(a, b) +end subroutine + +! CHECK-LABEL: func @_QPhypot_testr( +! CHECK-SAME: %[[AREF:.*]]: !fir.ref{{.*}}, %[[BREF:.*]]: !fir.ref{{.*}}, %[[CREF:.*]]: !fir.ref{{.*}}) { +subroutine hypot_testr(a, b, c) +! CHECK: %[[A:.*]] = fir.load %[[AREF]] : !fir.ref +! CHECK: %[[B:.*]] = fir.load %[[BREF]] : !fir.ref +! CHECK: %[[C:.*]] = fir.call @[[HYPOTF]](%[[A]], %[[B]]) : (f32, f32) -> f32 +! CHECK: fir.store %[[C]] to %[[CREF]] : !fir.ref +! CHECK: return + real :: a, b, c + c = hypot(a, b) +end subroutine + +! CHECK-LABEL: func @_QPhypot_testd( +! CHECK-SAME: %[[AREF:.*]]: !fir.ref{{.*}}, %[[BREF:.*]]: !fir.ref{{.*}}, %[[CREF:.*]]: !fir.ref{{.*}}) { +subroutine hypot_testd(a, b, c) +! CHECK: %[[A:.*]] = fir.load %[[AREF]] : !fir.ref +! CHECK: %[[B:.*]] = fir.load %[[BREF]] : !fir.ref +! CHECK: %[[C:.*]] = fir.call @hypot(%[[A]], %[[B]]) : (f64, f64) -> f64 +! CHECK: fir.store %[[C]] to %[[CREF]] : !fir.ref +! CHECK: return + real(kind=8) :: a, b, c + c = hypot(a, b) +end subroutine + +! TODO: Test with abs(complex)