From 79792b31786d5ae8f24e1bdf31ffa4bf354e36e7 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Thu, 9 Feb 2023 14:16:41 -0500 Subject: [PATCH 01/43] Implement floating point accuracy. This is a draft patch mostly to check that the use of TargetLibraryInfo can be used from the FE. Andy let me know if that's what you were thingking about? --- clang/include/clang/Basic/FPOptions.def | 1 + clang/include/clang/Basic/LangOptions.def | 1 + clang/include/clang/Basic/LangOptions.h | 9 +++ clang/include/clang/Driver/Options.td | 5 ++ clang/lib/CodeGen/CGBuiltin.cpp | 72 +++++++++++++++++-- clang/test/CodeGen/fp-accuracy.c | 21 ++++++ .../include/llvm/Analysis/TargetLibraryInfo.h | 4 ++ llvm/include/llvm/IR/Intrinsics.td | 8 +++ llvm/lib/Analysis/TargetLibraryInfo.cpp | 15 ++++ 9 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 clang/test/CodeGen/fp-accuracy.c diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def index 0c687e3c3fa03..49a858e6afc0a 100644 --- a/clang/include/clang/Basic/FPOptions.def +++ b/clang/include/clang/Basic/FPOptions.def @@ -26,4 +26,5 @@ OPTION(AllowReciprocal, bool, 1, NoSignedZero) OPTION(AllowApproxFunc, bool, 1, AllowReciprocal) OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc) OPTION(Float16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, FPEvalMethod) +OPTION(FPAccuracy, LangOptions::FPAccuracyKind, 2, Float16ExcessPrecision) #undef OPTION diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 902f793b7e6e1..26840d3f19450 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -337,6 +337,7 @@ BENIGN_LANGOPT(RoundingMath, 1, false, "Do not assume default floating-point rou BENIGN_ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Default, "FP Exception Behavior Mode type") BENIGN_ENUM_LANGOPT(FPEvalMethod, FPEvalMethodKind, 2, FEM_UnsetOnCommandLine, "FP type used for floating point arithmetic") ENUM_LANGOPT(Float16ExcessPrecision, ExcessPrecisionKind, 2, FPP_Standard, "Intermediate truncation behavior for floating point arithmetic") +BENIGN_ENUM_LANGOPT(FPAccuracy, FPAccuracyKind, 2, FPA_Default, "Accuracy for floating point operations and library functions") LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment") LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility") LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 0b745b6f8ba20..cb031b6612066 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -303,6 +303,15 @@ class LangOptions : public LangOptionsBase { enum ExcessPrecisionKind { FPP_Standard, FPP_Fast, FPP_None }; + enum FPAccuracyKind { + FPA_Default, + FPA_High, + FPA_Medium, + FPA_Low, + FPA_Sycl, + FPA_Cuda + }; + /// Possible exception handling behavior. enum class ExceptionHandlingKind { None, SjLj, WinEH, DwarfCFI, Wasm }; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index dede416112a3b..12db006e7d2b7 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1661,6 +1661,11 @@ def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group< Values<"ignore,maytrap,strict">, NormalizedValuesScope<"LangOptions">, NormalizedValues<["FPE_Ignore", "FPE_MayTrap", "FPE_Strict"]>, MarshallingInfoEnum, "FPE_Default">; +def ffp_accuracy_EQ : Joined<["-"], "ffp-accuracy=">, Group, Flags<[CC1Option]>, + HelpText<"Specifies the required accuracy for floating-point operations and library calls.">, + Values<"default,high,medium,low">, NormalizedValuesScope<"LangOptions">, + NormalizedValues<["FPA_Default", "FPA_High", "FPA_Medium", "FPA_Low"]>, + MarshallingInfoEnum, "FPA_Default">; defm fast_math : BoolFOption<"fast-math", LangOpts<"FastMath">, DefaultFalse, PosFlaggetArg(0)); - + if (FPAccuracyIntrinsicID != Intrinsic::not_intrinsic) { + LangOptions::FPAccuracyKind FPAccuracy = CGF.getLangOpts().getFPAccuracy(); + // Enter this part of the condition only when TLI.isFPACCuracyAvailable is + // true, implying FPAccuary != LangOptions::FPA_Default. + if (FPAccuracy == LangOptions::FPA_Default) + CGF.CGM.Error(E->getExprLoc(), "FP accuracy other than defaut is expected"); + StringRef FPAccuracyVal = convertFPAccuracy(FPAccuracy); + auto *AccuracyMDS = MDString::get(CGF.Builder.getContext(), FPAccuracyVal); + auto *AccuracyMD = + MetadataAsValue::get(CGF.Builder.getContext(), AccuracyMDS); + Function *F = CGF.CGM.getIntrinsic(FPAccuracyIntrinsicID, Src0->getType()); + // TODO: For now, the IR generated for cos function for example is of this form: + // call float @llvm.experimental.fpaccuracy.cos.f32(float %0, metadata !"fpaccuracy.value") + // But the final goal is to generate this IR: + // call float @llvm.experimental.fpaccuracy.cos.f32(float %0, float ulp) + // TODO: + // TLI.getFPAccuracy should return a string of the form "float ulp" depending + // on the function (IntrinsicID) and the command line accuracy (FPAccuracyIntrinsicID) + // FPAccuracyVal = TLI.getFPAccuracy(F->getName(), FPAccuracyIntrinsicID) + // auto *AccuracyMDS = MDString::get(CGF.Builder.getContext(), FPAccuracyVal); + return CGF.Builder.CreateCall(F, {Src0, AccuracyMD}); + } if (CGF.Builder.getIsFPConstrained()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E); Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); @@ -2189,6 +2241,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // See if we can constant fold this builtin. If so, don't emit it at all. // TODO: Extend this handling to all builtin calls that we can constant-fold. Expr::EvalResult Result; + + llvm::TargetLibraryInfoImpl TLII(getTarget().getTriple()); if (E->isPRValue() && E->EvaluateAsRValue(Result, CGM.getContext()) && !Result.hasSideEffects()) { if (Result.Val.isInt()) @@ -2258,11 +2312,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosf: case Builtin::BI__builtin_cosf16: case Builtin::BI__builtin_cosl: - case Builtin::BI__builtin_cosf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::cos, - Intrinsic::experimental_constrained_cos)); - + case Builtin::BI__builtin_cosf128: { + if (TLII.isFPAccuracyAvailable()) + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::cos, Intrinsic::experimental_constrained_cos, + Intrinsic::experimental_fpaccuracy_cos)); + else + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::cos, Intrinsic::experimental_constrained_cos)); + } case Builtin::BIexp: case Builtin::BIexpf: case Builtin::BIexpl: diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c new file mode 100644 index 0000000000000..4c6add3d9a4d8 --- /dev/null +++ b/clang/test/CodeGen/fp-accuracy.c @@ -0,0 +1,21 @@ +// The next two lines are commented until the call isFPAccuracyAvailable is +// complete. +// TODO: Add next two lines to testing +// RUN %clang_cc1 -Wno-implicit-function-declaration -emit-llvm -o - %s +// RUN %clang_cc1 -ffp-accuracy=default -Wno-implicit-function-declaration -emit-llvm -o - %s + +// TODO: Add cuda and sycl lines for testing + +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=high -Wno-implicit-function-declaration -emit-llvm -o - %s | FileCheck %s -check-prefix=FPAHIGH +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=medium -Wno-implicit-function-declaration -emit-llvm -o - %s | FileCheck %s -check-prefix=FPAMED +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=low -Wno-implicit-function-declaration -emit-llvm -o - %s | FileCheck %s -check-prefix=FPALOW + +float a, b; + +void foo(void) { + // CHECK-LABEL: define {{.*}}void @foo() + a = cosf(b); + // FPAHIGH: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}, metadata !"fpaccuracy.high") + // FPAMED: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}, metadata !"fpaccuracy.medium") + // FPALOW: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}, metadata !"fpaccuracy.low") +} diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h index 3a8c72a378137..b5ab7e4b508ac 100644 --- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h +++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h @@ -15,6 +15,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/PassManager.h" #include "llvm/Pass.h" + #include namespace llvm { @@ -261,6 +262,9 @@ class TargetLibraryInfoImpl { /// conventions. static bool isCallingConvCCompatible(CallBase *CI); static bool isCallingConvCCompatible(Function *Callee); + + bool isFPAccuracyAvailable() const; + StringRef getFPAccuracy(StringRef Func, unsigned FPAccuracyID); }; /// Provides information about what library functions are available for diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 3893edb4810bc..5ab33c4e1919f 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -868,6 +868,14 @@ let IntrProperties = [IntrArgMemOnly, IntrWillReturn] in { llvm_ptr_ty, llvm_ptr_ty ]>; } +//===--------------- FPAccuracy Floating Point Intrinsics ----------------===// +// +let IntrProperties = [IntrInaccessibleMemOnly, IntrWillReturn] in { +def int_experimental_fpaccuracy_cos : DefaultAttrsIntrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + llvm_metadata_ty ]>; +// TODO: add entries for all math functions. +} //===--------------- Constrained Floating Point Intrinsics ----------------===// // diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp index 3e359c6729e51..8d800c80fe630 100644 --- a/llvm/lib/Analysis/TargetLibraryInfo.cpp +++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -1296,6 +1296,21 @@ bool TargetLibraryInfoImpl::isFunctionVectorizable(StringRef funcName) const { return I != VectorDescs.end() && StringRef(I->ScalarFnName) == funcName; } +bool TargetLibraryInfoImpl::isFPAccuracyAvailable() const { + // TODO: this must be returning true or false depending if accuracy + // for function is availble. For now, return true for testing purposes. + return true; +} + +StringRef TargetLibraryInfoImpl::getFPAccuracy(StringRef Func, + unsigned FPAccuracyID) { + // TODO: check on the Func string and return "float ulp" + // For now returning a dummy string. + StringRef ULP = "float 2.5"; + return ULP; +} + + StringRef TargetLibraryInfoImpl::getVectorizedFunction(StringRef F, const ElementCount &VF) const { From c3029ee083c7f3095e993df92cf28cef5e5dcb4f Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 13 Feb 2023 17:24:00 -0500 Subject: [PATCH 02/43] Responded to review comments and added more to the implementation. --- clang/include/clang/Basic/Attr.td | 7 +++ clang/include/clang/Driver/Options.td | 4 +- clang/lib/CodeGen/CGBuiltin.cpp | 63 +++++++++++++++------------ clang/lib/Driver/ToolChains/Clang.cpp | 12 +++++ clang/test/CodeGen/fp-accuracy.c | 23 ++++++++-- llvm/include/llvm/IR/Attributes.td | 4 ++ 6 files changed, 79 insertions(+), 34 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 39dfa9bad949e..1722aad1382ee 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2737,6 +2737,13 @@ def ReturnsTwice : InheritableAttr { let SimpleHandler = 1; } +def FPBuiltinMaxError : InheritableAttr { + let Spellings = [Clang<"fpbultin_max_error">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; + let SimpleHandler = 1; +} + def DisableTailCalls : InheritableAttr { let Spellings = [Clang<"disable_tail_calls">]; let Subjects = SubjectList<[Function, ObjCMethod]>; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 12db006e7d2b7..c22febfd53a24 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1663,8 +1663,8 @@ def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group< MarshallingInfoEnum, "FPE_Default">; def ffp_accuracy_EQ : Joined<["-"], "ffp-accuracy=">, Group, Flags<[CC1Option]>, HelpText<"Specifies the required accuracy for floating-point operations and library calls.">, - Values<"default,high,medium,low">, NormalizedValuesScope<"LangOptions">, - NormalizedValues<["FPA_Default", "FPA_High", "FPA_Medium", "FPA_Low"]>, + Values<"default,high,medium,low,sycl,cuda">, NormalizedValuesScope<"LangOptions">, + NormalizedValues<["FPA_Default", "FPA_High", "FPA_Medium", "FPA_Low", "FPA_Sycl", "FPA_Cuda"]>, MarshallingInfoEnum, "FPA_Default">; defm fast_math : BoolFOption<"fast-math", LangOpts<"FastMath">, DefaultFalse, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c803cb6df165a..dd08f74896204 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -501,36 +501,48 @@ convertFPAccuracy(LangOptions::FPAccuracyKind FPAccuracy) { return AccuracyVal; } +// TODO: This function is only a place holder. Returning for now a hard-code value +// of the ULP error. +StringRef getFPAccuracy(Function* F) { return "Float 2.5"; } + // Emit a simple mangled intrinsic that has 1 argument and a return type // matching the argument type. Depending on mode, this may be a constrained // floating-point intrinsic. static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, const CallExpr *E, unsigned IntrinsicID, - unsigned ConstrainedIntrinsicID, - unsigned FPAccuracyIntrinsicID = Intrinsic::not_intrinsic) { - llvm::TargetLibraryInfoImpl TLII(CGF.getTarget().getTriple()); + unsigned ConstrainedIntrinsicID) { llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); - if (FPAccuracyIntrinsicID != Intrinsic::not_intrinsic) { + if (CGF.getLangOpts().getFPAccuracy()) { + // TODO: Need to check here if the accuracy of the math library function + // is different than the one in the command line. LangOptions::FPAccuracyKind FPAccuracy = CGF.getLangOpts().getFPAccuracy(); - // Enter this part of the condition only when TLI.isFPACCuracyAvailable is - // true, implying FPAccuary != LangOptions::FPA_Default. - if (FPAccuracy == LangOptions::FPA_Default) - CGF.CGM.Error(E->getExprLoc(), "FP accuracy other than defaut is expected"); StringRef FPAccuracyVal = convertFPAccuracy(FPAccuracy); - auto *AccuracyMDS = MDString::get(CGF.Builder.getContext(), FPAccuracyVal); - auto *AccuracyMD = - MetadataAsValue::get(CGF.Builder.getContext(), AccuracyMDS); - Function *F = CGF.CGM.getIntrinsic(FPAccuracyIntrinsicID, Src0->getType()); - // TODO: For now, the IR generated for cos function for example is of this form: - // call float @llvm.experimental.fpaccuracy.cos.f32(float %0, metadata !"fpaccuracy.value") - // But the final goal is to generate this IR: - // call float @llvm.experimental.fpaccuracy.cos.f32(float %0, float ulp) - // TODO: - // TLI.getFPAccuracy should return a string of the form "float ulp" depending - // on the function (IntrinsicID) and the command line accuracy (FPAccuracyIntrinsicID) - // FPAccuracyVal = TLI.getFPAccuracy(F->getName(), FPAccuracyIntrinsicID) - // auto *AccuracyMDS = MDString::get(CGF.Builder.getContext(), FPAccuracyVal); - return CGF.Builder.CreateCall(F, {Src0, AccuracyMD}); + Function *F = CGF.CGM.getIntrinsic(Intrinsic::experimental_fpaccuracy_cos, + Src0->getType()); + // TODO: getFPAccuracy is a place holder for the ucooming function. This will + // have to use Target (may be?) in order to calculate the accuracy allowed + // for the function F. For now the function is retruning a hard-coded string. + StringRef AccuracyStr = getFPAccuracy(F); + auto *AccuracyMD = MDString::get(CGF.Builder.getContext(), FPAccuracyVal); + auto *Src1 = MetadataAsValue::get(CGF.Builder.getContext(), AccuracyMD); + // TODO: expecting a second argument for this intrinsic. For now keep the metada, + // but not sure what Andy wants here? + llvm::CallInst *CI = CGF.Builder.CreateCall(F, { Src0, Src1 }); + if (CGF.getLangOpts().getFPAccuracy() != + LangOptions::FPAccuracyKind::FPA_Default) { + // TODI: Do we want to mark the declaration of the new builtin + // with the attribute? See LIT test. + llvm::AttrBuilder FuncAttrs(F->getContext()); + FuncAttrs.addAttribute("fpbuiltin-max-error", AccuracyStr); + F->addFnAttrs(FuncAttrs); + // TODO: For now adding the attribute at the call site without the ULP value. + // Not sure how to do that yet. Will work on it. + llvm::AttributeList FPBuiltinMaxErrorAttr = llvm::AttributeList::get( + CGF.getLLVMContext(), llvm::AttributeList::FunctionIndex, + llvm::Attribute::FPBuiltinMaxError); + CI->setAttributes(FPBuiltinMaxErrorAttr); + } + return CI; } if (CGF.Builder.getIsFPConstrained()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E); @@ -2313,12 +2325,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosf16: case Builtin::BI__builtin_cosl: case Builtin::BI__builtin_cosf128: { - if (TLII.isFPAccuracyAvailable()) - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( - *this, E, Intrinsic::cos, Intrinsic::experimental_constrained_cos, - Intrinsic::experimental_fpaccuracy_cos)); - else - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( *this, E, Intrinsic::cos, Intrinsic::experimental_constrained_cos)); } case Builtin::BIexp: diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index ae467a22b500c..ef5951c712822 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2822,6 +2822,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, FPContract = "on"; bool StrictFPModel = false; StringRef Float16ExcessPrecision = ""; + StringRef FPAccuracy; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -3125,6 +3126,14 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, FPContract = "on"; } break; + case options::OPT_ffp_accuracy_EQ: + StringRef Val = A->getValue(); + if (!(Val.equals("high") || Val.equals("low") || Val.equals("medium") || + Val.equals("sycl") || Val.equals("cuda"))) + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + FPAccuracy = Val; + break; } if (StrictFPModel) { // If -ffp-model=strict has been specified on command line but @@ -3218,6 +3227,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back(Args.MakeArgString("-ffloat16-excess-precision=" + Float16ExcessPrecision)); + if (!FPAccuracy.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-accuracy=" + FPAccuracy)); + ParseMRecip(D, Args, CmdArgs); // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index 4c6add3d9a4d8..ec45722dd8cf9 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -6,16 +6,31 @@ // TODO: Add cuda and sycl lines for testing -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=high -Wno-implicit-function-declaration -emit-llvm -o - %s | FileCheck %s -check-prefix=FPAHIGH -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=medium -Wno-implicit-function-declaration -emit-llvm -o - %s | FileCheck %s -check-prefix=FPAMED -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=low -Wno-implicit-function-declaration -emit-llvm -o - %s | FileCheck %s -check-prefix=FPALOW +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=high \ +// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefixes=CHECK,FPAHIGH + +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=medium \ +// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefixes=CHECK,FPAMED + +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=low \ +// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefixes=CHECK,FPALOW float a, b; void foo(void) { // CHECK-LABEL: define {{.*}}void @foo() a = cosf(b); - // FPAHIGH: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}, metadata !"fpaccuracy.high") + // FPAHIGH: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}) #2 // FPAMED: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}, metadata !"fpaccuracy.medium") // FPALOW: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}, metadata !"fpaccuracy.low") } + +// CHECK: declare float @llvm.experimental.fpaccuracy.cos.f32(float, metadata) +// CHECK-SAME: #1 + +// CHECK: attributes #1 = { {{.*}} "fpbuiltin-max-error"="Float 2.5"} +// TODO: Needs to add the value of the error. +// CHECK: attributes #2 = { fpbultin_max_error } diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index 75fe534ac61ea..125b2c4bc5837 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -221,6 +221,10 @@ def ImmArg : EnumAttr<"immarg", [ParamAttr]>; /// Function can return twice. def ReturnsTwice : EnumAttr<"returns_twice", [FnAttr]>; +/// Floating point accuracy of the function defined with the ULP error of the +/// function. +def FPBuiltinMaxError : EnumAttr<"fpbultin_max_error", [FnAttr]>; + /// Safe Stack protection. def SafeStack : EnumAttr<"safestack", [FnAttr]>; From fa5180061d601d51238ce57b6078b74012f15a15 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 14 Feb 2023 16:20:21 -0500 Subject: [PATCH 03/43] Added option falt-math-library and fixed a few things with fpbuiltin-max-error attribute. --- clang/include/clang/Basic/CodeGenOptions.def | 3 +++ clang/include/clang/Basic/CodeGenOptions.h | 6 ++++++ clang/include/clang/Driver/Options.td | 6 ++++++ clang/lib/CodeGen/CGBuiltin.cpp | 20 +++++++------------- clang/test/CodeGen/fp-accuracy.c | 8 ++++---- llvm/include/llvm/IR/Intrinsics.td | 3 +-- 6 files changed, 27 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 36bc22b7b9bb3..65e4f92c6f1b8 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -419,6 +419,9 @@ VALUE_CODEGENOPT(InlineMaxStackSize, 32, UINT_MAX) // Vector functions library to use. ENUM_CODEGENOPT(VecLib, VectorLibrary, 3, NoLibrary) +// Alternate math function to use. +ENUM_CODEGENOPT(AltMathLibrary, AlternateMathLibray, 3, NoAltMathLibrary) + /// The default TLS model to use. ENUM_CODEGENOPT(DefaultTLSModel, TLSModel, 2, GeneralDynamicTLSModel) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index af0089733a5dc..cfb72977ec49c 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -63,6 +63,12 @@ class CodeGenOptions : public CodeGenOptionsBase { Darwin_libsystem_m // Use Darwin's libsytem_m vector functions. }; + enum AlternateMathLibray { + NoAltMathLibrary, // No alternate math library is used. + ImfAltMathLibrary, // IMF alternate math library is used. + TestAltMathLibrary // A fake alternate math library is used. + }; + enum ObjCDispatchMethodKind { Legacy = 0, NonLegacy = 1, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c22febfd53a24..1b46add3b1a5e 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2520,6 +2520,12 @@ def fveclib : Joined<["-"], "fveclib=">, Group, Flags<[CC1Option]>, NormalizedValues<["Accelerate", "LIBMVEC", "MASSV", "SVML", "Darwin_libsystem_m", "NoLibrary"]>, MarshallingInfoEnum, "NoLibrary">; +def falt_math_library : Joined<["-"], "falt-math-library=">, Group, Flags<[CC1Option]>, + HelpText<"Use an alternate function library">, + Values<"none,imf,test">, + NormalizedValuesScope<"CodeGenOptions">, + NormalizedValues<["NoAltMathLibrary", "ImfAltMathLibrary", "TestAltMathLibrary"]>, + MarshallingInfoEnum, "NoAltMathLibrary">; def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group, Alias, AliasArgs<["none"]>; def fno_implicit_module_maps : Flag <["-"], "fno-implicit-module-maps">, Group, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index dd08f74896204..1fd852d15210a 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -503,7 +503,7 @@ convertFPAccuracy(LangOptions::FPAccuracyKind FPAccuracy) { // TODO: This function is only a place holder. Returning for now a hard-code value // of the ULP error. -StringRef getFPAccuracy(Function* F) { return "Float 2.5"; } +StringRef getFPAccuracy(Function* F) { return "float 2.5"; } // Emit a simple mangled intrinsic that has 1 argument and a return type // matching the argument type. Depending on mode, this may be a constrained @@ -523,24 +523,18 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, // have to use Target (may be?) in order to calculate the accuracy allowed // for the function F. For now the function is retruning a hard-coded string. StringRef AccuracyStr = getFPAccuracy(F); - auto *AccuracyMD = MDString::get(CGF.Builder.getContext(), FPAccuracyVal); - auto *Src1 = MetadataAsValue::get(CGF.Builder.getContext(), AccuracyMD); - // TODO: expecting a second argument for this intrinsic. For now keep the metada, - // but not sure what Andy wants here? - llvm::CallInst *CI = CGF.Builder.CreateCall(F, { Src0, Src1 }); + auto *AccuracyMD = MDString::get(CGF.Builder.getContext(), AccuracyStr); + llvm::CallInst *CI = CGF.Builder.CreateCall(F, { Src0 }); if (CGF.getLangOpts().getFPAccuracy() != LangOptions::FPAccuracyKind::FPA_Default) { - // TODI: Do we want to mark the declaration of the new builtin - // with the attribute? See LIT test. llvm::AttrBuilder FuncAttrs(F->getContext()); FuncAttrs.addAttribute("fpbuiltin-max-error", AccuracyStr); F->addFnAttrs(FuncAttrs); - // TODO: For now adding the attribute at the call site without the ULP value. - // Not sure how to do that yet. Will work on it. - llvm::AttributeList FPBuiltinMaxErrorAttr = llvm::AttributeList::get( - CGF.getLLVMContext(), llvm::AttributeList::FunctionIndex, - llvm::Attribute::FPBuiltinMaxError); + AttributeList FPBuiltinMaxErrorAttr = F->getAttributes().get( + CGF.getLLVMContext(), AttributeList::FunctionIndex, + Attribute::FPBuiltinMaxError); CI->setAttributes(FPBuiltinMaxErrorAttr); + AttributeList A = CI->getAttributes(); } return CI; } diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index ec45722dd8cf9..06088c4256f6d 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -24,13 +24,13 @@ void foo(void) { // CHECK-LABEL: define {{.*}}void @foo() a = cosf(b); // FPAHIGH: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}) #2 - // FPAMED: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}, metadata !"fpaccuracy.medium") - // FPALOW: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}, metadata !"fpaccuracy.low") + // FPAMED: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}) #2 + // FPALOW: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}) #2 } -// CHECK: declare float @llvm.experimental.fpaccuracy.cos.f32(float, metadata) +// CHECK: declare float @llvm.experimental.fpaccuracy.cos.f32(float) // CHECK-SAME: #1 -// CHECK: attributes #1 = { {{.*}} "fpbuiltin-max-error"="Float 2.5"} +// CHECK: attributes #1 = { {{.*}} "fpbuiltin-max-error"="float 2.5" } // TODO: Needs to add the value of the error. // CHECK: attributes #2 = { fpbultin_max_error } diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 5ab33c4e1919f..177fc090ccc55 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -872,8 +872,7 @@ let IntrProperties = [IntrArgMemOnly, IntrWillReturn] in { // let IntrProperties = [IntrInaccessibleMemOnly, IntrWillReturn] in { def int_experimental_fpaccuracy_cos : DefaultAttrsIntrinsic<[ llvm_anyfloat_ty ], - [ LLVMMatchType<0>, - llvm_metadata_ty ]>; + [ LLVMMatchType<0> ]>; // TODO: add entries for all math functions. } From b584e3d09645fb82f53a6b13dd537466b87380d9 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Wed, 1 Mar 2023 16:07:30 -0500 Subject: [PATCH 04/43] Added a cc1 option triggered by the fp-accuracy option. Added a map to LangOption that will map the function in the function list of command line to its accuracy. --- clang/include/clang/Basic/Attr.td | 2 +- clang/include/clang/Basic/LangOptions.h | 8 ++++ clang/include/clang/Driver/Options.td | 2 + clang/lib/CodeGen/CGBuiltin.cpp | 27 ++++++++------ clang/lib/Driver/ToolChains/Clang.cpp | 49 +++++++++++++++++++++---- clang/test/CodeGen/fp-accuracy.c | 1 - clang/test/Driver/fp-accuracy.c | 11 ++++++ 7 files changed, 80 insertions(+), 20 deletions(-) create mode 100644 clang/test/Driver/fp-accuracy.c diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 1722aad1382ee..33132e0bab568 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2737,7 +2737,7 @@ def ReturnsTwice : InheritableAttr { let SimpleHandler = 1; } -def FPBuiltinMaxError : InheritableAttr { +def FPBuiltinMaxError : StmtAttr { let Spellings = [Clang<"fpbultin_max_error">]; let Subjects = SubjectList<[Function]>; let Documentation = [Undocumented]; diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index cb031b6612066..ac4e9804142a2 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -24,6 +24,7 @@ #include "llvm/ADT/FloatingPointMode.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/MapVector.h" #include #include #include @@ -312,6 +313,13 @@ class LangOptions : public LangOptionsBase { FPA_Cuda }; + typedef llvm::MapVector> + FPAccuracyAttrMap; + typedef llvm::MapVector> + FPAccuracyAttrFuncMap; + FPAccuracyAttrFuncMap FuncAccMap; + /// Possible exception handling behavior. enum class ExceptionHandlingKind { None, SjLj, WinEH, DwarfCFI, Wasm }; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 1b46add3b1a5e..8952dbf465a3f 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1666,6 +1666,8 @@ def ffp_accuracy_EQ : Joined<["-"], "ffp-accuracy=">, Group, Flags<[CC1 Values<"default,high,medium,low,sycl,cuda">, NormalizedValuesScope<"LangOptions">, NormalizedValues<["FPA_Default", "FPA_High", "FPA_Medium", "FPA_Low", "FPA_Sycl", "FPA_Cuda"]>, MarshallingInfoEnum, "FPA_Default">; +def fpbuiltin_max_error_EQ : Joined<["-"], "fpbuiltin-max-error=">, Group, Flags<[CC1Option]>; + defm fast_math : BoolFOption<"fast-math", LangOpts<"FastMath">, DefaultFalse, PosFlaggetContext()); - FuncAttrs.addAttribute("fpbuiltin-max-error", AccuracyStr); - F->addFnAttrs(FuncAttrs); + if (!CGF.getLangOpts().FuncAccMap.empty()) { + // TODO: Needs to go trhough the map and set the attribute + // for each function in the map. + // If this map is empty the call site should get the default + // attribute with the error corresponding to the accuracy + // given in the command line option; this should be given + // in the map. + } AttributeList FPBuiltinMaxErrorAttr = F->getAttributes().get( CGF.getLLVMContext(), AttributeList::FunctionIndex, Attribute::FPBuiltinMaxError); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index ef5951c712822..54db47ea7c069 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2822,7 +2822,14 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, FPContract = "on"; bool StrictFPModel = false; StringRef Float16ExcessPrecision = ""; - StringRef FPAccuracy; + StringRef FPAccuracy = ""; + std::string FPAccurayBis; + static constexpr size_t npos = ~size_t(0); + SmallVector ListOfMathLib; + std::string FullFPAccuracyCmdLineArgs; + LangOptions::FPAccuracyAttrMap FuncAccuracyMap; + LangOptions::FPAccuracyAttrFuncMap FuncAttrMap; + SmallVector AccuracyElement; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -3126,15 +3133,39 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, FPContract = "on"; } break; - case options::OPT_ffp_accuracy_EQ: + case options::OPT_ffp_accuracy_EQ: { StringRef Val = A->getValue(); - if (!(Val.equals("high") || Val.equals("low") || Val.equals("medium") || - Val.equals("sycl") || Val.equals("cuda"))) - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getSpelling() << Val; + FullFPAccuracyCmdLineArgs = A->getValue(); + for (StringRef Values : + Args.getAllArgValues(options::OPT_ffp_accuracy_EQ)) { + SmallVector AccuracyArr; + Values.split(AccuracyArr, ' '); + for (const auto &Accuracy : AccuracyArr) { + Accuracy.split(AccuracyElement, ':'); + FPAccuracy = AccuracyElement[0]; + if (!(FPAccuracy.equals("default") || FPAccuracy.equals("high") || + FPAccuracy.equals("low") || FPAccuracy.equals("medium") || + FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << FPAccuracy; + if (AccuracyElement.size() == 2) { + SmallVector FuncList; + AccuracyElement[1].split(FuncList, ','); + for (StringRef FuncName : FuncList) { + // TODO: For now the FuncName is given a hard-coded error. + // It will need to be computed. + FuncAccuracyMap.insert( + {"ffp-accuracy", AccuracyElement[0].str()}); + FuncAttrMap.insert({FuncName.str(), std::move(FuncAccuracyMap)}); + } + } + } + } FPAccuracy = Val; break; } + } + if (StrictFPModel) { // If -ffp-model=strict has been specified on command line but // subsequent options conflict then emit warning diagnostic. @@ -3228,7 +3259,11 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, Float16ExcessPrecision)); if (!FPAccuracy.empty()) - CmdArgs.push_back(Args.MakeArgString("-ffp-accuracy=" + FPAccuracy)); + if (!FuncAttrMap.empty()) + CmdArgs.push_back( + Args.MakeArgString("-fpbuiltin-max-error=" + FullFPAccuracyCmdLineArgs)); + else + CmdArgs.push_back(Args.MakeArgString("-ffp-accuracy=" + FPAccuracy)); ParseMRecip(D, Args, CmdArgs); diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index 06088c4256f6d..b0311ec343bfc 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -31,6 +31,5 @@ void foo(void) { // CHECK: declare float @llvm.experimental.fpaccuracy.cos.f32(float) // CHECK-SAME: #1 -// CHECK: attributes #1 = { {{.*}} "fpbuiltin-max-error"="float 2.5" } // TODO: Needs to add the value of the error. // CHECK: attributes #2 = { fpbultin_max_error } diff --git a/clang/test/Driver/fp-accuracy.c b/clang/test/Driver/fp-accuracy.c new file mode 100644 index 0000000000000..14b4f3a2fad14 --- /dev/null +++ b/clang/test/Driver/fp-accuracy.c @@ -0,0 +1,11 @@ +// TODO: add a check line for all values of fp-accuracy. + +// RUN: %clang -### -target x86_64 -ffp-accuracy=high -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK %s + +// RUN: %clang -### -target x86_64 -ffp-accuracy=low:sin,cos -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-FUNC %s + +// CHECK: "-ffp-accuracy=high" +// CHECK-FUNC: "-fpbuiltin-max-error=low:sin,cos" + From be478d8ea1b66e6f9221a2771a3c2b28f0673986 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Thu, 6 Apr 2023 12:59:23 -0400 Subject: [PATCH 05/43] Remove TargetInfoLibrary dependency. --- clang/lib/CodeGen/CGBuiltin.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 494abeb8954e5..8627854680ba0 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -34,7 +34,6 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/ValueTracking.h" -#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Intrinsics.h" @@ -65,8 +64,6 @@ using namespace clang; using namespace CodeGen; using namespace llvm; -class TargetLibraryInfoImpl; - static void initializeAlloca(CodeGenFunction &CGF, AllocaInst *AI, Value *Size, Align AlignmentInBytes) { ConstantInt *Byte; @@ -2294,7 +2291,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // TODO: Extend this handling to all builtin calls that we can constant-fold. Expr::EvalResult Result; - llvm::TargetLibraryInfoImpl TLII(getTarget().getTriple()); if (E->isPRValue() && E->EvaluateAsRValue(Result, CGM.getContext()) && !Result.hasSideEffects()) { if (Result.Val.isInt()) From 4c23010f52079d8f05d7b17191aad5f952c78d02 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Thu, 6 Apr 2023 16:49:42 -0400 Subject: [PATCH 06/43] Fix a few things. --- clang/lib/CodeGen/CGBuiltin.cpp | 13 +- .../include/llvm/Analysis/TargetLibraryInfo.h | 1265 +++++++++-------- llvm/include/llvm/IR/Intrinsics.td | 7 - 3 files changed, 640 insertions(+), 645 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 8627854680ba0..73a07f215acec 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -547,11 +547,12 @@ unsigned getFPMaxError(Function *F, LangOptions::FPAccuracyKind FPAccuracy) { // floating-point intrinsic. static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, const CallExpr *E, unsigned IntrinsicID, - unsigned ConstrainedIntrinsicID) { + unsigned ConstrainedIntrinsicID) { llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); + if (CGF.getLangOpts().getFPAccuracy()) { - // TODO: Need to check here if the accuracy of the math library function - // is different than the one in the command line. + // TODO: Need to check here if the accuracy of the math library function + // is different than the one in the command line. LangOptions::FPAccuracyKind FPAccuracy = CGF.getLangOpts().getFPAccuracy(); StringRef FPAccuracyVal = convertFPAccuracy(FPAccuracy); Function *F = CGF.CGM.getIntrinsic(Intrinsic::experimental_fpaccuracy_cos, @@ -2290,7 +2291,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // See if we can constant fold this builtin. If so, don't emit it at all. // TODO: Extend this handling to all builtin calls that we can constant-fold. Expr::EvalResult Result; - if (E->isPRValue() && E->EvaluateAsRValue(Result, CGM.getContext()) && !Result.hasSideEffects()) { if (Result.Val.isInt()) @@ -2361,8 +2361,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosf16: case Builtin::BI__builtin_cosl: case Builtin::BI__builtin_cosf128: { - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( - *this, E, Intrinsic::cos, Intrinsic::experimental_constrained_cos)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::cos, + Intrinsic::experimental_constrained_cos)); } case Builtin::BIexp: case Builtin::BIexpf: diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h index e31ab7d69290e..c7eb37ab30ecf 100644 --- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h +++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h @@ -1,632 +1,633 @@ -//===-- TargetLibraryInfo.h - Library information ---------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ANALYSIS_TARGETLIBRARYINFO_H -#define LLVM_ANALYSIS_TARGETLIBRARYINFO_H - -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/PassManager.h" -#include "llvm/Pass.h" -#include "llvm/TargetParser/Triple.h" -#include - -namespace llvm { - -template class ArrayRef; -class Function; -class Module; -class Triple; - -/// Describes a possible implementation of a floating point builtin operation. -struct AltMathDesc { - Intrinsic::ID IntrinID; - Type::TypeID BaseFPType; - ElementCount VectorizationFactor; - StringRef FnImplName; - float Accuracy; -}; - -/// Describes a possible vectorization of a function. -/// Function 'VectorFnName' is equivalent to 'ScalarFnName' vectorized -/// by a factor 'VectorizationFactor'. -struct VecDesc { - StringRef ScalarFnName; - StringRef VectorFnName; - ElementCount VectorizationFactor; -}; - - enum LibFunc : unsigned { -#define TLI_DEFINE_ENUM -#include "llvm/Analysis/TargetLibraryInfo.def" - - NumLibFuncs, - NotLibFunc - }; - -/// Implementation of the target library information. -/// -/// This class constructs tables that hold the target library information and -/// make it available. However, it is somewhat expensive to compute and only -/// depends on the triple. So users typically interact with the \c -/// TargetLibraryInfo wrapper below. -class TargetLibraryInfoImpl { - friend class TargetLibraryInfo; - - unsigned char AvailableArray[(NumLibFuncs+3)/4]; - DenseMap CustomNames; - static StringLiteral const StandardNames[NumLibFuncs]; - bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param, ShouldSignExtI32Return; - unsigned SizeOfInt; - - enum AvailabilityState { - StandardName = 3, // (memset to all ones) - CustomName = 1, - Unavailable = 0 // (memset to all zeros) - }; - void setState(LibFunc F, AvailabilityState State) { - AvailableArray[F/4] &= ~(3 << 2*(F&3)); - AvailableArray[F/4] |= State << 2*(F&3); - } - AvailabilityState getState(LibFunc F) const { - return static_cast((AvailableArray[F/4] >> 2*(F&3)) & 3); - } - - /// Alternate math library functions - sorted by intrinsic ID, then type, - /// then vector size, then accuracy - std::vector AltMathFuncDescs; - - /// Vectorization descriptors - sorted by ScalarFnName. - std::vector VectorDescs; - /// Scalarization descriptors - same content as VectorDescs but sorted based - /// on VectorFnName rather than ScalarFnName. - std::vector ScalarDescs; - - /// Return true if the function type FTy is valid for the library function - /// F, regardless of whether the function is available. - bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc F, - const Module &M) const; - -public: - /// List of known vector-functions libraries. - /// - /// The vector-functions library defines, which functions are vectorizable - /// and with which factor. The library can be specified by either frontend, - /// or a commandline option, and then used by - /// addVectorizableFunctionsFromVecLib for filling up the tables of - /// vectorizable functions. - enum VectorLibrary { - NoLibrary, // Don't use any vector library. - Accelerate, // Use Accelerate framework. - DarwinLibSystemM, // Use Darwin's libsystem_m. - LIBMVEC_X86, // GLIBC Vector Math library. - MASSV, // IBM MASS vector library. - SVML, // Intel short vector math library. - SLEEFGNUABI // SLEEF - SIMD Library for Evaluating Elementary Functions. - }; - - /// List of known alternate math libraries. - /// - /// The alternate math library provides a set of functions that can ve used - /// to replace llvm.fpbuiltin intrinsic calls when one or more constraining - /// attributes are specified. - /// The library can be specified by either frontend or a commandline option, - /// and then used by addAltMathFunctionsFromLib for populating the tables of - /// math function implementations. - enum AltMathLibrary { - NoAltMathLibrary, // Don't use any alternate math library - TestAltMathLibrary // Use a fake alternate math library for testing - }; - - TargetLibraryInfoImpl(); - explicit TargetLibraryInfoImpl(const Triple &T); - - // Provide value semantics. - TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI); - TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI); - TargetLibraryInfoImpl &operator=(const TargetLibraryInfoImpl &TLI); - TargetLibraryInfoImpl &operator=(TargetLibraryInfoImpl &&TLI); - - /// Searches for a particular function name. - /// - /// If it is one of the known library functions, return true and set F to the - /// corresponding value. - bool getLibFunc(StringRef funcName, LibFunc &F) const; - - /// Searches for a particular function name, also checking that its type is - /// valid for the library function matching that name. - /// - /// If it is one of the known library functions, return true and set F to the - /// corresponding value. - /// - /// FDecl is assumed to have a parent Module when using this function. - bool getLibFunc(const Function &FDecl, LibFunc &F) const; - - /// Forces a function to be marked as unavailable. - void setUnavailable(LibFunc F) { - setState(F, Unavailable); - } - - /// Forces a function to be marked as available. - void setAvailable(LibFunc F) { - setState(F, StandardName); - } - - /// Forces a function to be marked as available and provide an alternate name - /// that must be used. - void setAvailableWithName(LibFunc F, StringRef Name) { - if (StandardNames[F] != Name) { - setState(F, CustomName); - CustomNames[F] = std::string(Name); - assert(CustomNames.contains(F)); - } else { - setState(F, StandardName); - } - } - - /// Disables all builtins. - /// - /// This can be used for options like -fno-builtin. - void disableAllFunctions(); - - /// Add a set of alternate math library function implementations with - /// attributes that can be used to select an implementation for an - /// llvm.fpbuiltin intrinsic - void addAltMathFunctions(ArrayRef Fns); - - /// Calls addAltMathFunctions with a known preset of functions for the - /// given alternate math library. - void addAltMathFunctionsFromLib(enum AltMathLibrary AltLib); - - /// Select an alternate math library implementation that meets the criteria - /// described by an FPBuiltinIntrinsic call. - StringRef selectFPBuiltinImplementation(FPBuiltinIntrinsic *Builtin) const; - - /// Add a set of scalar -> vector mappings, queryable via - /// getVectorizedFunction and getScalarizedFunction. - void addVectorizableFunctions(ArrayRef Fns); - - /// Calls addVectorizableFunctions with a known preset of functions for the - /// given vector library. - void addVectorizableFunctionsFromVecLib(enum VectorLibrary VecLib, - const llvm::Triple &TargetTriple); - - /// Return true if the function F has a vector equivalent with vectorization - /// factor VF. - bool isFunctionVectorizable(StringRef F, const ElementCount &VF) const { - return !getVectorizedFunction(F, VF).empty(); - } - - /// Return true if the function F has a vector equivalent with any - /// vectorization factor. - bool isFunctionVectorizable(StringRef F) const; - - /// Return the name of the equivalent of F, vectorized with factor VF. If no - /// such mapping exists, return the empty string. - StringRef getVectorizedFunction(StringRef F, const ElementCount &VF) const; - - /// Set to true iff i32 parameters to library functions should have signext - /// or zeroext attributes if they correspond to C-level int or unsigned int, - /// respectively. - void setShouldExtI32Param(bool Val) { - ShouldExtI32Param = Val; - } - - /// Set to true iff i32 results from library functions should have signext - /// or zeroext attributes if they correspond to C-level int or unsigned int, - /// respectively. - void setShouldExtI32Return(bool Val) { - ShouldExtI32Return = Val; - } - - /// Set to true iff i32 parameters to library functions should have signext - /// attribute if they correspond to C-level int or unsigned int. - void setShouldSignExtI32Param(bool Val) { - ShouldSignExtI32Param = Val; - } - - /// Set to true iff i32 results from library functions should have signext - /// attribute if they correspond to C-level int or unsigned int. - void setShouldSignExtI32Return(bool Val) { - ShouldSignExtI32Return = Val; - } - - /// Returns the size of the wchar_t type in bytes or 0 if the size is unknown. - /// This queries the 'wchar_size' metadata. - unsigned getWCharSize(const Module &M) const; - - /// Returns the size of the size_t type in bits. - unsigned getSizeTSize(const Module &M) const; - - /// Get size of a C-level int or unsigned int, in bits. - unsigned getIntSize() const { - return SizeOfInt; - } - - /// Initialize the C-level size of an integer. - void setIntSize(unsigned Bits) { - SizeOfInt = Bits; - } - - /// Returns the largest vectorization factor used in the list of - /// vector functions. - void getWidestVF(StringRef ScalarF, ElementCount &FixedVF, - ElementCount &Scalable) const; - - /// Returns true if call site / callee has cdecl-compatible calling - /// conventions. - static bool isCallingConvCCompatible(CallBase *CI); - static bool isCallingConvCCompatible(Function *Callee); - - bool isFPAccuracyAvailable() const; - StringRef getFPAccuracy(StringRef Func, unsigned FPAccuracyID); -}; - -/// Provides information about what library functions are available for -/// the current target. -/// -/// This both allows optimizations to handle them specially and frontends to -/// disable such optimizations through -fno-builtin etc. -class TargetLibraryInfo { - friend class TargetLibraryAnalysis; - friend class TargetLibraryInfoWrapperPass; - - /// The global (module level) TLI info. - const TargetLibraryInfoImpl *Impl; - - /// Support for -fno-builtin* options as function attributes, overrides - /// information in global TargetLibraryInfoImpl. - BitVector OverrideAsUnavailable; - -public: - explicit TargetLibraryInfo(const TargetLibraryInfoImpl &Impl, - std::optional F = std::nullopt) - : Impl(&Impl), OverrideAsUnavailable(NumLibFuncs) { - if (!F) - return; - if ((*F)->hasFnAttribute("no-builtins")) - disableAllFunctions(); - else { - // Disable individual libc/libm calls in TargetLibraryInfo. - LibFunc LF; - AttributeSet FnAttrs = (*F)->getAttributes().getFnAttrs(); - for (const Attribute &Attr : FnAttrs) { - if (!Attr.isStringAttribute()) - continue; - auto AttrStr = Attr.getKindAsString(); - if (!AttrStr.consume_front("no-builtin-")) - continue; - if (getLibFunc(AttrStr, LF)) - setUnavailable(LF); - } - } - } - - // Provide value semantics. - TargetLibraryInfo(const TargetLibraryInfo &TLI) = default; - TargetLibraryInfo(TargetLibraryInfo &&TLI) - : Impl(TLI.Impl), OverrideAsUnavailable(TLI.OverrideAsUnavailable) {} - TargetLibraryInfo &operator=(const TargetLibraryInfo &TLI) = default; - TargetLibraryInfo &operator=(TargetLibraryInfo &&TLI) { - Impl = TLI.Impl; - OverrideAsUnavailable = TLI.OverrideAsUnavailable; - return *this; - } - - /// Determine whether a callee with the given TLI can be inlined into - /// caller with this TLI, based on 'nobuiltin' attributes. When requested, - /// allow inlining into a caller with a superset of the callee's nobuiltin - /// attributes, which is conservatively correct. - bool areInlineCompatible(const TargetLibraryInfo &CalleeTLI, - bool AllowCallerSuperset) const { - if (!AllowCallerSuperset) - return OverrideAsUnavailable == CalleeTLI.OverrideAsUnavailable; - BitVector B = OverrideAsUnavailable; - B |= CalleeTLI.OverrideAsUnavailable; - // We can inline if the union of the caller and callee's nobuiltin - // attributes is no stricter than the caller's nobuiltin attributes. - return B == OverrideAsUnavailable; - } - - /// Return true if the function type FTy is valid for the library function - /// F, regardless of whether the function is available. - bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc F, - const Module &M) const { - return Impl->isValidProtoForLibFunc(FTy, F, M); - } - - /// Searches for a particular function name. - /// - /// If it is one of the known library functions, return true and set F to the - /// corresponding value. - bool getLibFunc(StringRef funcName, LibFunc &F) const { - return Impl->getLibFunc(funcName, F); - } - - bool getLibFunc(const Function &FDecl, LibFunc &F) const { - return Impl->getLibFunc(FDecl, F); - } - - /// If a callbase does not have the 'nobuiltin' attribute, return if the - /// called function is a known library function and set F to that function. - bool getLibFunc(const CallBase &CB, LibFunc &F) const { - return !CB.isNoBuiltin() && CB.getCalledFunction() && - getLibFunc(*(CB.getCalledFunction()), F); - } - - /// Disables all builtins. - /// - /// This can be used for options like -fno-builtin. - void disableAllFunctions() LLVM_ATTRIBUTE_UNUSED { - OverrideAsUnavailable.set(); - } - - /// Forces a function to be marked as unavailable. - void setUnavailable(LibFunc F) LLVM_ATTRIBUTE_UNUSED { - OverrideAsUnavailable.set(F); - } - - TargetLibraryInfoImpl::AvailabilityState getState(LibFunc F) const { - if (OverrideAsUnavailable[F]) - return TargetLibraryInfoImpl::Unavailable; - return Impl->getState(F); - } - - /// Tests whether a library function is available. - bool has(LibFunc F) const { - return getState(F) != TargetLibraryInfoImpl::Unavailable; - } - bool isFunctionVectorizable(StringRef F, const ElementCount &VF) const { - return Impl->isFunctionVectorizable(F, VF); - } - bool isFunctionVectorizable(StringRef F) const { - return Impl->isFunctionVectorizable(F); - } - StringRef selectFPBuiltinImplementation(FPBuiltinIntrinsic *Builtin) const { - return Impl->selectFPBuiltinImplementation(Builtin); - } - StringRef getVectorizedFunction(StringRef F, const ElementCount &VF) const { - return Impl->getVectorizedFunction(F, VF); - } - - /// Tests if the function is both available and a candidate for optimized code - /// generation. - bool hasOptimizedCodeGen(LibFunc F) const { - if (getState(F) == TargetLibraryInfoImpl::Unavailable) - return false; - switch (F) { - default: break; - case LibFunc_copysign: case LibFunc_copysignf: case LibFunc_copysignl: - case LibFunc_fabs: case LibFunc_fabsf: case LibFunc_fabsl: - case LibFunc_sin: case LibFunc_sinf: case LibFunc_sinl: - case LibFunc_cos: case LibFunc_cosf: case LibFunc_cosl: - case LibFunc_sqrt: case LibFunc_sqrtf: case LibFunc_sqrtl: - case LibFunc_sqrt_finite: case LibFunc_sqrtf_finite: - case LibFunc_sqrtl_finite: - case LibFunc_fmax: case LibFunc_fmaxf: case LibFunc_fmaxl: - case LibFunc_fmin: case LibFunc_fminf: case LibFunc_fminl: - case LibFunc_floor: case LibFunc_floorf: case LibFunc_floorl: - case LibFunc_nearbyint: case LibFunc_nearbyintf: case LibFunc_nearbyintl: - case LibFunc_ceil: case LibFunc_ceilf: case LibFunc_ceill: - case LibFunc_rint: case LibFunc_rintf: case LibFunc_rintl: - case LibFunc_round: case LibFunc_roundf: case LibFunc_roundl: - case LibFunc_trunc: case LibFunc_truncf: case LibFunc_truncl: - case LibFunc_log2: case LibFunc_log2f: case LibFunc_log2l: - case LibFunc_exp2: case LibFunc_exp2f: case LibFunc_exp2l: - case LibFunc_memcpy: case LibFunc_memset: case LibFunc_memmove: - case LibFunc_memcmp: case LibFunc_bcmp: case LibFunc_strcmp: - case LibFunc_strcpy: case LibFunc_stpcpy: case LibFunc_strlen: - case LibFunc_strnlen: case LibFunc_memchr: case LibFunc_mempcpy: - return true; - } - return false; - } - - StringRef getName(LibFunc F) const { - auto State = getState(F); - if (State == TargetLibraryInfoImpl::Unavailable) - return StringRef(); - if (State == TargetLibraryInfoImpl::StandardName) - return Impl->StandardNames[F]; - assert(State == TargetLibraryInfoImpl::CustomName); - return Impl->CustomNames.find(F)->second; - } - - static void initExtensionsForTriple(bool &ShouldExtI32Param, - bool &ShouldExtI32Return, - bool &ShouldSignExtI32Param, - bool &ShouldSignExtI32Return, - const Triple &T) { - ShouldExtI32Param = ShouldExtI32Return = false; - ShouldSignExtI32Param = ShouldSignExtI32Return = false; - - // PowerPC64, Sparc64, SystemZ need signext/zeroext on i32 parameters and - // returns corresponding to C-level ints and unsigned ints. - if (T.isPPC64() || T.getArch() == Triple::sparcv9 || - T.getArch() == Triple::systemz) { - ShouldExtI32Param = true; - ShouldExtI32Return = true; - } - // Mips and riscv64, on the other hand, needs signext on i32 parameters - // corresponding to both signed and unsigned ints. - if (T.isMIPS() || T.isRISCV64()) { - ShouldSignExtI32Param = true; - } - // riscv64 needs signext on i32 returns corresponding to both signed and - // unsigned ints. - if (T.isRISCV64()) { - ShouldSignExtI32Return = true; - } - } - - /// Returns extension attribute kind to be used for i32 parameters - /// corresponding to C-level int or unsigned int. May be zeroext, signext, - /// or none. -private: - static Attribute::AttrKind getExtAttrForI32Param(bool ShouldExtI32Param_, - bool ShouldSignExtI32Param_, - bool Signed = true) { - if (ShouldExtI32Param_) - return Signed ? Attribute::SExt : Attribute::ZExt; - if (ShouldSignExtI32Param_) - return Attribute::SExt; - return Attribute::None; - } - -public: - static Attribute::AttrKind getExtAttrForI32Param(const Triple &T, - bool Signed = true) { - bool ShouldExtI32Param, ShouldExtI32Return; - bool ShouldSignExtI32Param, ShouldSignExtI32Return; - initExtensionsForTriple(ShouldExtI32Param, ShouldExtI32Return, - ShouldSignExtI32Param, ShouldSignExtI32Return, T); - return getExtAttrForI32Param(ShouldExtI32Param, ShouldSignExtI32Param, - Signed); - } - - Attribute::AttrKind getExtAttrForI32Param(bool Signed = true) const { - return getExtAttrForI32Param(Impl->ShouldExtI32Param, - Impl->ShouldSignExtI32Param, Signed); - } - - /// Returns extension attribute kind to be used for i32 return values - /// corresponding to C-level int or unsigned int. May be zeroext, signext, - /// or none. -private: - static Attribute::AttrKind getExtAttrForI32Return(bool ShouldExtI32Return_, - bool ShouldSignExtI32Return_, - bool Signed) { - if (ShouldExtI32Return_) - return Signed ? Attribute::SExt : Attribute::ZExt; - if (ShouldSignExtI32Return_) - return Attribute::SExt; - return Attribute::None; - } - -public: - static Attribute::AttrKind getExtAttrForI32Return(const Triple &T, - bool Signed = true) { - bool ShouldExtI32Param, ShouldExtI32Return; - bool ShouldSignExtI32Param, ShouldSignExtI32Return; - initExtensionsForTriple(ShouldExtI32Param, ShouldExtI32Return, - ShouldSignExtI32Param, ShouldSignExtI32Return, T); - return getExtAttrForI32Return(ShouldExtI32Return, ShouldSignExtI32Return, - Signed); - } - - Attribute::AttrKind getExtAttrForI32Return(bool Signed = true) const { - return getExtAttrForI32Return(Impl->ShouldExtI32Return, - Impl->ShouldSignExtI32Return, Signed); - } - - // Helper to create an AttributeList for args (and ret val) which all have - // the same signedness. Attributes in AL may be passed in to include them - // as well in the returned AttributeList. - AttributeList getAttrList(LLVMContext *C, ArrayRef ArgNos, - bool Signed, bool Ret = false, - AttributeList AL = AttributeList()) const { - if (auto AK = getExtAttrForI32Param(Signed)) - for (auto ArgNo : ArgNos) - AL = AL.addParamAttribute(*C, ArgNo, AK); - if (Ret) - if (auto AK = getExtAttrForI32Return(Signed)) - AL = AL.addRetAttribute(*C, AK); - return AL; - } - - /// \copydoc TargetLibraryInfoImpl::getWCharSize() - unsigned getWCharSize(const Module &M) const { - return Impl->getWCharSize(M); - } - - /// \copydoc TargetLibraryInfoImpl::getSizeTSize() - unsigned getSizeTSize(const Module &M) const { return Impl->getSizeTSize(M); } - - /// \copydoc TargetLibraryInfoImpl::getIntSize() - unsigned getIntSize() const { - return Impl->getIntSize(); - } - - /// Handle invalidation from the pass manager. - /// - /// If we try to invalidate this info, just return false. It cannot become - /// invalid even if the module or function changes. - bool invalidate(Module &, const PreservedAnalyses &, - ModuleAnalysisManager::Invalidator &) { - return false; - } - bool invalidate(Function &, const PreservedAnalyses &, - FunctionAnalysisManager::Invalidator &) { - return false; - } - /// Returns the largest vectorization factor used in the list of - /// vector functions. - void getWidestVF(StringRef ScalarF, ElementCount &FixedVF, - ElementCount &ScalableVF) const { - Impl->getWidestVF(ScalarF, FixedVF, ScalableVF); - } - - /// Check if the function "F" is listed in a library known to LLVM. - bool isKnownVectorFunctionInLibrary(StringRef F) const { - return this->isFunctionVectorizable(F); - } -}; - -/// Analysis pass providing the \c TargetLibraryInfo. -/// -/// Note that this pass's result cannot be invalidated, it is immutable for the -/// life of the module. -class TargetLibraryAnalysis : public AnalysisInfoMixin { -public: - typedef TargetLibraryInfo Result; - - /// Default construct the library analysis. - /// - /// This will use the module's triple to construct the library info for that - /// module. - TargetLibraryAnalysis() = default; - - /// Construct a library analysis with baseline Module-level info. - /// - /// This will be supplemented with Function-specific info in the Result. - TargetLibraryAnalysis(TargetLibraryInfoImpl BaselineInfoImpl) - : BaselineInfoImpl(std::move(BaselineInfoImpl)) {} - - TargetLibraryInfo run(const Function &F, FunctionAnalysisManager &); - -private: - friend AnalysisInfoMixin; - static AnalysisKey Key; - - std::optional BaselineInfoImpl; -}; - -class TargetLibraryInfoWrapperPass : public ImmutablePass { - TargetLibraryAnalysis TLA; - std::optional TLI; - - virtual void anchor(); - -public: - static char ID; - TargetLibraryInfoWrapperPass(); - explicit TargetLibraryInfoWrapperPass(const Triple &T); - explicit TargetLibraryInfoWrapperPass(const TargetLibraryInfoImpl &TLI); - - TargetLibraryInfo &getTLI(const Function &F) { - FunctionAnalysisManager DummyFAM; - TLI = TLA.run(F, DummyFAM); - return *TLI; - } -}; - -} // end namespace llvm - -#endif +//===-- TargetLibraryInfo.h - Library information ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_TARGETLIBRARYINFO_H +#define LLVM_ANALYSIS_TARGETLIBRARYINFO_H + +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" +#include "llvm/TargetParser/Triple.h" +#include + +namespace llvm { + +template class ArrayRef; +class Function; +class Module; +class Triple; + +/// Describes a possible implementation of a floating point builtin operation. +struct AltMathDesc { + Intrinsic::ID IntrinID; + Type::TypeID BaseFPType; + ElementCount VectorizationFactor; + StringRef FnImplName; + float Accuracy; +}; + +/// Describes a possible vectorization of a function. +/// Function 'VectorFnName' is equivalent to 'ScalarFnName' vectorized +/// by a factor 'VectorizationFactor'. +struct VecDesc { + StringRef ScalarFnName; + StringRef VectorFnName; + ElementCount VectorizationFactor; + bool Masked; +}; + + enum LibFunc : unsigned { +#define TLI_DEFINE_ENUM +#include "llvm/Analysis/TargetLibraryInfo.def" + + NumLibFuncs, + NotLibFunc + }; + +/// Implementation of the target library information. +/// +/// This class constructs tables that hold the target library information and +/// make it available. However, it is somewhat expensive to compute and only +/// depends on the triple. So users typically interact with the \c +/// TargetLibraryInfo wrapper below. +class TargetLibraryInfoImpl { + friend class TargetLibraryInfo; + + unsigned char AvailableArray[(NumLibFuncs+3)/4]; + DenseMap CustomNames; + static StringLiteral const StandardNames[NumLibFuncs]; + bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param, ShouldSignExtI32Return; + unsigned SizeOfInt; + + enum AvailabilityState { + StandardName = 3, // (memset to all ones) + CustomName = 1, + Unavailable = 0 // (memset to all zeros) + }; + void setState(LibFunc F, AvailabilityState State) { + AvailableArray[F/4] &= ~(3 << 2*(F&3)); + AvailableArray[F/4] |= State << 2*(F&3); + } + AvailabilityState getState(LibFunc F) const { + return static_cast((AvailableArray[F/4] >> 2*(F&3)) & 3); + } + + /// Alternate math library functions - sorted by intrinsic ID, then type, + /// then vector size, then accuracy + std::vector AltMathFuncDescs; + + /// Vectorization descriptors - sorted by ScalarFnName. + std::vector VectorDescs; + /// Scalarization descriptors - same content as VectorDescs but sorted based + /// on VectorFnName rather than ScalarFnName. + std::vector ScalarDescs; + + /// Return true if the function type FTy is valid for the library function + /// F, regardless of whether the function is available. + bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc F, + const Module &M) const; + +public: + /// List of known vector-functions libraries. + /// + /// The vector-functions library defines, which functions are vectorizable + /// and with which factor. The library can be specified by either frontend, + /// or a commandline option, and then used by + /// addVectorizableFunctionsFromVecLib for filling up the tables of + /// vectorizable functions. + enum VectorLibrary { + NoLibrary, // Don't use any vector library. + Accelerate, // Use Accelerate framework. + DarwinLibSystemM, // Use Darwin's libsystem_m. + LIBMVEC_X86, // GLIBC Vector Math library. + MASSV, // IBM MASS vector library. + SVML, // Intel short vector math library. + SLEEFGNUABI // SLEEF - SIMD Library for Evaluating Elementary Functions. + }; + + /// List of known alternate math libraries. + /// + /// The alternate math library provides a set of functions that can ve used + /// to replace llvm.fpbuiltin intrinsic calls when one or more constraining + /// attributes are specified. + /// The library can be specified by either frontend or a commandline option, + /// and then used by addAltMathFunctionsFromLib for populating the tables of + /// math function implementations. + enum AltMathLibrary { + NoAltMathLibrary, // Don't use any alternate math library + TestAltMathLibrary // Use a fake alternate math library for testing + }; + + TargetLibraryInfoImpl(); + explicit TargetLibraryInfoImpl(const Triple &T); + + // Provide value semantics. + TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI); + TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI); + TargetLibraryInfoImpl &operator=(const TargetLibraryInfoImpl &TLI); + TargetLibraryInfoImpl &operator=(TargetLibraryInfoImpl &&TLI); + + /// Searches for a particular function name. + /// + /// If it is one of the known library functions, return true and set F to the + /// corresponding value. + bool getLibFunc(StringRef funcName, LibFunc &F) const; + + /// Searches for a particular function name, also checking that its type is + /// valid for the library function matching that name. + /// + /// If it is one of the known library functions, return true and set F to the + /// corresponding value. + /// + /// FDecl is assumed to have a parent Module when using this function. + bool getLibFunc(const Function &FDecl, LibFunc &F) const; + + /// Forces a function to be marked as unavailable. + void setUnavailable(LibFunc F) { + setState(F, Unavailable); + } + + /// Forces a function to be marked as available. + void setAvailable(LibFunc F) { + setState(F, StandardName); + } + + /// Forces a function to be marked as available and provide an alternate name + /// that must be used. + void setAvailableWithName(LibFunc F, StringRef Name) { + if (StandardNames[F] != Name) { + setState(F, CustomName); + CustomNames[F] = std::string(Name); + assert(CustomNames.contains(F)); + } else { + setState(F, StandardName); + } + } + + /// Disables all builtins. + /// + /// This can be used for options like -fno-builtin. + void disableAllFunctions(); + + /// Add a set of alternate math library function implementations with + /// attributes that can be used to select an implementation for an + /// llvm.fpbuiltin intrinsic + void addAltMathFunctions(ArrayRef Fns); + + /// Calls addAltMathFunctions with a known preset of functions for the + /// given alternate math library. + void addAltMathFunctionsFromLib(enum AltMathLibrary AltLib); + + /// Select an alternate math library implementation that meets the criteria + /// described by an FPBuiltinIntrinsic call. + StringRef selectFPBuiltinImplementation(FPBuiltinIntrinsic *Builtin) const; + + /// Add a set of scalar -> vector mappings, queryable via + /// getVectorizedFunction and getScalarizedFunction. + void addVectorizableFunctions(ArrayRef Fns); + + /// Calls addVectorizableFunctions with a known preset of functions for the + /// given vector library. + void addVectorizableFunctionsFromVecLib(enum VectorLibrary VecLib, + const llvm::Triple &TargetTriple); + + /// Return true if the function F has a vector equivalent with vectorization + /// factor VF. + bool isFunctionVectorizable(StringRef F, const ElementCount &VF) const { + return !(getVectorizedFunction(F, VF, false).empty() && + getVectorizedFunction(F, VF, true).empty()); + } + + /// Return true if the function F has a vector equivalent with any + /// vectorization factor. + bool isFunctionVectorizable(StringRef F) const; + + /// Return the name of the equivalent of F, vectorized with factor VF. If no + /// such mapping exists, return the empty string. + StringRef getVectorizedFunction(StringRef F, const ElementCount &VF, + bool Masked) const; + + /// Set to true iff i32 parameters to library functions should have signext + /// or zeroext attributes if they correspond to C-level int or unsigned int, + /// respectively. + void setShouldExtI32Param(bool Val) { + ShouldExtI32Param = Val; + } + + /// Set to true iff i32 results from library functions should have signext + /// or zeroext attributes if they correspond to C-level int or unsigned int, + /// respectively. + void setShouldExtI32Return(bool Val) { + ShouldExtI32Return = Val; + } + + /// Set to true iff i32 parameters to library functions should have signext + /// attribute if they correspond to C-level int or unsigned int. + void setShouldSignExtI32Param(bool Val) { + ShouldSignExtI32Param = Val; + } + + /// Set to true iff i32 results from library functions should have signext + /// attribute if they correspond to C-level int or unsigned int. + void setShouldSignExtI32Return(bool Val) { + ShouldSignExtI32Return = Val; + } + + /// Returns the size of the wchar_t type in bytes or 0 if the size is unknown. + /// This queries the 'wchar_size' metadata. + unsigned getWCharSize(const Module &M) const; + + /// Returns the size of the size_t type in bits. + unsigned getSizeTSize(const Module &M) const; + + /// Get size of a C-level int or unsigned int, in bits. + unsigned getIntSize() const { + return SizeOfInt; + } + + /// Initialize the C-level size of an integer. + void setIntSize(unsigned Bits) { + SizeOfInt = Bits; + } + + /// Returns the largest vectorization factor used in the list of + /// vector functions. + void getWidestVF(StringRef ScalarF, ElementCount &FixedVF, + ElementCount &Scalable) const; + + /// Returns true if call site / callee has cdecl-compatible calling + /// conventions. + static bool isCallingConvCCompatible(CallBase *CI); + static bool isCallingConvCCompatible(Function *Callee); +}; + +/// Provides information about what library functions are available for +/// the current target. +/// +/// This both allows optimizations to handle them specially and frontends to +/// disable such optimizations through -fno-builtin etc. +class TargetLibraryInfo { + friend class TargetLibraryAnalysis; + friend class TargetLibraryInfoWrapperPass; + + /// The global (module level) TLI info. + const TargetLibraryInfoImpl *Impl; + + /// Support for -fno-builtin* options as function attributes, overrides + /// information in global TargetLibraryInfoImpl. + BitVector OverrideAsUnavailable; + +public: + explicit TargetLibraryInfo(const TargetLibraryInfoImpl &Impl, + std::optional F = std::nullopt) + : Impl(&Impl), OverrideAsUnavailable(NumLibFuncs) { + if (!F) + return; + if ((*F)->hasFnAttribute("no-builtins")) + disableAllFunctions(); + else { + // Disable individual libc/libm calls in TargetLibraryInfo. + LibFunc LF; + AttributeSet FnAttrs = (*F)->getAttributes().getFnAttrs(); + for (const Attribute &Attr : FnAttrs) { + if (!Attr.isStringAttribute()) + continue; + auto AttrStr = Attr.getKindAsString(); + if (!AttrStr.consume_front("no-builtin-")) + continue; + if (getLibFunc(AttrStr, LF)) + setUnavailable(LF); + } + } + } + + // Provide value semantics. + TargetLibraryInfo(const TargetLibraryInfo &TLI) = default; + TargetLibraryInfo(TargetLibraryInfo &&TLI) + : Impl(TLI.Impl), OverrideAsUnavailable(TLI.OverrideAsUnavailable) {} + TargetLibraryInfo &operator=(const TargetLibraryInfo &TLI) = default; + TargetLibraryInfo &operator=(TargetLibraryInfo &&TLI) { + Impl = TLI.Impl; + OverrideAsUnavailable = TLI.OverrideAsUnavailable; + return *this; + } + + /// Determine whether a callee with the given TLI can be inlined into + /// caller with this TLI, based on 'nobuiltin' attributes. When requested, + /// allow inlining into a caller with a superset of the callee's nobuiltin + /// attributes, which is conservatively correct. + bool areInlineCompatible(const TargetLibraryInfo &CalleeTLI, + bool AllowCallerSuperset) const { + if (!AllowCallerSuperset) + return OverrideAsUnavailable == CalleeTLI.OverrideAsUnavailable; + BitVector B = OverrideAsUnavailable; + B |= CalleeTLI.OverrideAsUnavailable; + // We can inline if the union of the caller and callee's nobuiltin + // attributes is no stricter than the caller's nobuiltin attributes. + return B == OverrideAsUnavailable; + } + + /// Return true if the function type FTy is valid for the library function + /// F, regardless of whether the function is available. + bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc F, + const Module &M) const { + return Impl->isValidProtoForLibFunc(FTy, F, M); + } + + /// Searches for a particular function name. + /// + /// If it is one of the known library functions, return true and set F to the + /// corresponding value. + bool getLibFunc(StringRef funcName, LibFunc &F) const { + return Impl->getLibFunc(funcName, F); + } + + bool getLibFunc(const Function &FDecl, LibFunc &F) const { + return Impl->getLibFunc(FDecl, F); + } + + /// If a callbase does not have the 'nobuiltin' attribute, return if the + /// called function is a known library function and set F to that function. + bool getLibFunc(const CallBase &CB, LibFunc &F) const { + return !CB.isNoBuiltin() && CB.getCalledFunction() && + getLibFunc(*(CB.getCalledFunction()), F); + } + + /// Disables all builtins. + /// + /// This can be used for options like -fno-builtin. + void disableAllFunctions() LLVM_ATTRIBUTE_UNUSED { + OverrideAsUnavailable.set(); + } + + /// Forces a function to be marked as unavailable. + void setUnavailable(LibFunc F) LLVM_ATTRIBUTE_UNUSED { + OverrideAsUnavailable.set(F); + } + + TargetLibraryInfoImpl::AvailabilityState getState(LibFunc F) const { + if (OverrideAsUnavailable[F]) + return TargetLibraryInfoImpl::Unavailable; + return Impl->getState(F); + } + + /// Tests whether a library function is available. + bool has(LibFunc F) const { + return getState(F) != TargetLibraryInfoImpl::Unavailable; + } + bool isFunctionVectorizable(StringRef F, const ElementCount &VF) const { + return Impl->isFunctionVectorizable(F, VF); + } + bool isFunctionVectorizable(StringRef F) const { + return Impl->isFunctionVectorizable(F); + } + StringRef selectFPBuiltinImplementation(FPBuiltinIntrinsic *Builtin) const { + return Impl->selectFPBuiltinImplementation(Builtin); + } + StringRef getVectorizedFunction(StringRef F, const ElementCount &VF, + bool Masked = false) const { + return Impl->getVectorizedFunction(F, VF, Masked); + } + + /// Tests if the function is both available and a candidate for optimized code + /// generation. + bool hasOptimizedCodeGen(LibFunc F) const { + if (getState(F) == TargetLibraryInfoImpl::Unavailable) + return false; + switch (F) { + default: break; + case LibFunc_copysign: case LibFunc_copysignf: case LibFunc_copysignl: + case LibFunc_fabs: case LibFunc_fabsf: case LibFunc_fabsl: + case LibFunc_sin: case LibFunc_sinf: case LibFunc_sinl: + case LibFunc_cos: case LibFunc_cosf: case LibFunc_cosl: + case LibFunc_sqrt: case LibFunc_sqrtf: case LibFunc_sqrtl: + case LibFunc_sqrt_finite: case LibFunc_sqrtf_finite: + case LibFunc_sqrtl_finite: + case LibFunc_fmax: case LibFunc_fmaxf: case LibFunc_fmaxl: + case LibFunc_fmin: case LibFunc_fminf: case LibFunc_fminl: + case LibFunc_floor: case LibFunc_floorf: case LibFunc_floorl: + case LibFunc_nearbyint: case LibFunc_nearbyintf: case LibFunc_nearbyintl: + case LibFunc_ceil: case LibFunc_ceilf: case LibFunc_ceill: + case LibFunc_rint: case LibFunc_rintf: case LibFunc_rintl: + case LibFunc_round: case LibFunc_roundf: case LibFunc_roundl: + case LibFunc_trunc: case LibFunc_truncf: case LibFunc_truncl: + case LibFunc_log2: case LibFunc_log2f: case LibFunc_log2l: + case LibFunc_exp2: case LibFunc_exp2f: case LibFunc_exp2l: + case LibFunc_memcpy: case LibFunc_memset: case LibFunc_memmove: + case LibFunc_memcmp: case LibFunc_bcmp: case LibFunc_strcmp: + case LibFunc_strcpy: case LibFunc_stpcpy: case LibFunc_strlen: + case LibFunc_strnlen: case LibFunc_memchr: case LibFunc_mempcpy: + return true; + } + return false; + } + + StringRef getName(LibFunc F) const { + auto State = getState(F); + if (State == TargetLibraryInfoImpl::Unavailable) + return StringRef(); + if (State == TargetLibraryInfoImpl::StandardName) + return Impl->StandardNames[F]; + assert(State == TargetLibraryInfoImpl::CustomName); + return Impl->CustomNames.find(F)->second; + } + + static void initExtensionsForTriple(bool &ShouldExtI32Param, + bool &ShouldExtI32Return, + bool &ShouldSignExtI32Param, + bool &ShouldSignExtI32Return, + const Triple &T) { + ShouldExtI32Param = ShouldExtI32Return = false; + ShouldSignExtI32Param = ShouldSignExtI32Return = false; + + // PowerPC64, Sparc64, SystemZ need signext/zeroext on i32 parameters and + // returns corresponding to C-level ints and unsigned ints. + if (T.isPPC64() || T.getArch() == Triple::sparcv9 || + T.getArch() == Triple::systemz) { + ShouldExtI32Param = true; + ShouldExtI32Return = true; + } + // Mips and riscv64, on the other hand, needs signext on i32 parameters + // corresponding to both signed and unsigned ints. + if (T.isMIPS() || T.isRISCV64()) { + ShouldSignExtI32Param = true; + } + // riscv64 needs signext on i32 returns corresponding to both signed and + // unsigned ints. + if (T.isRISCV64()) { + ShouldSignExtI32Return = true; + } + } + + /// Returns extension attribute kind to be used for i32 parameters + /// corresponding to C-level int or unsigned int. May be zeroext, signext, + /// or none. +private: + static Attribute::AttrKind getExtAttrForI32Param(bool ShouldExtI32Param_, + bool ShouldSignExtI32Param_, + bool Signed = true) { + if (ShouldExtI32Param_) + return Signed ? Attribute::SExt : Attribute::ZExt; + if (ShouldSignExtI32Param_) + return Attribute::SExt; + return Attribute::None; + } + +public: + static Attribute::AttrKind getExtAttrForI32Param(const Triple &T, + bool Signed = true) { + bool ShouldExtI32Param, ShouldExtI32Return; + bool ShouldSignExtI32Param, ShouldSignExtI32Return; + initExtensionsForTriple(ShouldExtI32Param, ShouldExtI32Return, + ShouldSignExtI32Param, ShouldSignExtI32Return, T); + return getExtAttrForI32Param(ShouldExtI32Param, ShouldSignExtI32Param, + Signed); + } + + Attribute::AttrKind getExtAttrForI32Param(bool Signed = true) const { + return getExtAttrForI32Param(Impl->ShouldExtI32Param, + Impl->ShouldSignExtI32Param, Signed); + } + + /// Returns extension attribute kind to be used for i32 return values + /// corresponding to C-level int or unsigned int. May be zeroext, signext, + /// or none. +private: + static Attribute::AttrKind getExtAttrForI32Return(bool ShouldExtI32Return_, + bool ShouldSignExtI32Return_, + bool Signed) { + if (ShouldExtI32Return_) + return Signed ? Attribute::SExt : Attribute::ZExt; + if (ShouldSignExtI32Return_) + return Attribute::SExt; + return Attribute::None; + } + +public: + static Attribute::AttrKind getExtAttrForI32Return(const Triple &T, + bool Signed = true) { + bool ShouldExtI32Param, ShouldExtI32Return; + bool ShouldSignExtI32Param, ShouldSignExtI32Return; + initExtensionsForTriple(ShouldExtI32Param, ShouldExtI32Return, + ShouldSignExtI32Param, ShouldSignExtI32Return, T); + return getExtAttrForI32Return(ShouldExtI32Return, ShouldSignExtI32Return, + Signed); + } + + Attribute::AttrKind getExtAttrForI32Return(bool Signed = true) const { + return getExtAttrForI32Return(Impl->ShouldExtI32Return, + Impl->ShouldSignExtI32Return, Signed); + } + + // Helper to create an AttributeList for args (and ret val) which all have + // the same signedness. Attributes in AL may be passed in to include them + // as well in the returned AttributeList. + AttributeList getAttrList(LLVMContext *C, ArrayRef ArgNos, + bool Signed, bool Ret = false, + AttributeList AL = AttributeList()) const { + if (auto AK = getExtAttrForI32Param(Signed)) + for (auto ArgNo : ArgNos) + AL = AL.addParamAttribute(*C, ArgNo, AK); + if (Ret) + if (auto AK = getExtAttrForI32Return(Signed)) + AL = AL.addRetAttribute(*C, AK); + return AL; + } + + /// \copydoc TargetLibraryInfoImpl::getWCharSize() + unsigned getWCharSize(const Module &M) const { + return Impl->getWCharSize(M); + } + + /// \copydoc TargetLibraryInfoImpl::getSizeTSize() + unsigned getSizeTSize(const Module &M) const { return Impl->getSizeTSize(M); } + + /// \copydoc TargetLibraryInfoImpl::getIntSize() + unsigned getIntSize() const { + return Impl->getIntSize(); + } + + /// Handle invalidation from the pass manager. + /// + /// If we try to invalidate this info, just return false. It cannot become + /// invalid even if the module or function changes. + bool invalidate(Module &, const PreservedAnalyses &, + ModuleAnalysisManager::Invalidator &) { + return false; + } + bool invalidate(Function &, const PreservedAnalyses &, + FunctionAnalysisManager::Invalidator &) { + return false; + } + /// Returns the largest vectorization factor used in the list of + /// vector functions. + void getWidestVF(StringRef ScalarF, ElementCount &FixedVF, + ElementCount &ScalableVF) const { + Impl->getWidestVF(ScalarF, FixedVF, ScalableVF); + } + + /// Check if the function "F" is listed in a library known to LLVM. + bool isKnownVectorFunctionInLibrary(StringRef F) const { + return this->isFunctionVectorizable(F); + } +}; + +/// Analysis pass providing the \c TargetLibraryInfo. +/// +/// Note that this pass's result cannot be invalidated, it is immutable for the +/// life of the module. +class TargetLibraryAnalysis : public AnalysisInfoMixin { +public: + typedef TargetLibraryInfo Result; + + /// Default construct the library analysis. + /// + /// This will use the module's triple to construct the library info for that + /// module. + TargetLibraryAnalysis() = default; + + /// Construct a library analysis with baseline Module-level info. + /// + /// This will be supplemented with Function-specific info in the Result. + TargetLibraryAnalysis(TargetLibraryInfoImpl BaselineInfoImpl) + : BaselineInfoImpl(std::move(BaselineInfoImpl)) {} + + TargetLibraryInfo run(const Function &F, FunctionAnalysisManager &); + +private: + friend AnalysisInfoMixin; + static AnalysisKey Key; + + std::optional BaselineInfoImpl; +}; + +class TargetLibraryInfoWrapperPass : public ImmutablePass { + TargetLibraryAnalysis TLA; + std::optional TLI; + + virtual void anchor(); + +public: + static char ID; + TargetLibraryInfoWrapperPass(); + explicit TargetLibraryInfoWrapperPass(const Triple &T); + explicit TargetLibraryInfoWrapperPass(const TargetLibraryInfoImpl &TLI); + + TargetLibraryInfo &getTLI(const Function &F) { + FunctionAnalysisManager DummyFAM; + TLI = TLA.run(F, DummyFAM); + return *TLI; + } +}; + +} // end namespace llvm + +#endif diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 9a2e4ab71c6ac..ad74ca454a0f0 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -874,13 +874,6 @@ let IntrProperties = [IntrArgMemOnly, IntrWillReturn] in { llvm_ptr_ty, llvm_ptr_ty ]>; } -//===--------------- FPAccuracy Floating Point Intrinsics ----------------===// -// -let IntrProperties = [IntrInaccessibleMemOnly, IntrWillReturn] in { -def int_experimental_fpaccuracy_cos : DefaultAttrsIntrinsic<[ llvm_anyfloat_ty ], - [ LLVMMatchType<0> ]>; -// TODO: add entries for all math functions. -} //===--------------- Constrained Floating Point Intrinsics ----------------===// // From 2bcd2a8264df90c9d4d80508e08cba92cd30f4a7 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Thu, 6 Apr 2023 16:52:51 -0400 Subject: [PATCH 07/43] Fix a few things. --- clang/lib/CodeGen/CGBuiltin.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 0f8292572b393..118681874c391 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2360,11 +2360,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosf: case Builtin::BI__builtin_cosf16: case Builtin::BI__builtin_cosl: - case Builtin::BI__builtin_cosf128: { + case Builtin::BI__builtin_cosf128: return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, Intrinsic::cos, Intrinsic::experimental_constrained_cos)); - } case Builtin::BIexp: case Builtin::BIexpf: case Builtin::BIexpl: From bdf5dbe8c3120ff796384e7b2d842cb3ffde298e Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 18 Apr 2023 07:41:15 -0400 Subject: [PATCH 08/43] Adding code to support the option. --- .../clang/Basic/DiagnosticDriverKinds.td | 5 +- clang/include/clang/Basic/LangOptions.h | 14 +- clang/include/clang/Driver/Options.td | 7 +- .../clang/Frontend/CompilerInvocation.h | 3 + clang/lib/CodeGen/CGBuiltin.cpp | 123 +++++------------- clang/lib/CodeGen/CGCall.cpp | 18 ++- clang/lib/CodeGen/CodeGenFunction.h | 22 ++++ clang/lib/CodeGen/CodeGenModule.cpp | 9 ++ clang/lib/CodeGen/CodeGenModule.h | 2 + clang/lib/Driver/ToolChains/Clang.cpp | 67 +++------- clang/lib/Frontend/CompilerInvocation.cpp | 77 +++++++++++ clang/test/CodeGen/fp-accuracy.c | 47 +++---- clang/test/Driver/fp-accuracy.c | 21 ++- 13 files changed, 235 insertions(+), 180 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index fcdfeefa75582..f5ff2e014922e 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -60,7 +60,10 @@ def err_drv_no_cuda_libdevice : Error< "cannot find libdevice for %0; provide path to different CUDA installation " "via '--cuda-path', or pass '-nocudalib' to build without linking with " "libdevice">; - +def warn_function_fp_accuray_already_set : Warning <"FP accuracy value of '%0' has already " + "been assigned to function '%1'">; +def warn_all_fp_accuray_already_set : Warning <"FP accuracy value of '%0' has already " + "been assigned to all functions in the program">; def err_drv_no_rocm_device_lib : Error< "cannot find ROCm device library%select{| for %1|for ABI version %1}0; provide its path via " "'--rocm-path' or '--rocm-device-lib-path', or pass '-nogpulib' to build " diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index cbeb0e9dbc15f..5657ad2dfb7a7 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -313,13 +313,6 @@ class LangOptions : public LangOptionsBase { FPA_Cuda }; - typedef llvm::MapVector> - FPAccuracyAttrMap; - typedef llvm::MapVector> - FPAccuracyAttrFuncMap; - FPAccuracyAttrFuncMap FuncAccMap; - /// Possible exception handling behavior. enum class ExceptionHandlingKind { None, SjLj, WinEH, DwarfCFI, Wasm }; @@ -403,6 +396,13 @@ class LangOptions : public LangOptionsBase { IncompleteOnly = 3, }; + using FPAccuracyMapTy = + llvm::MapVector>; + FPAccuracyMapTy FPAccuracyMap; + using FPAccuracyFuncMapTy = + llvm::MapVector>; + FPAccuracyFuncMapTy FPAccuracyFuncMap; + public: /// The used language standard. LangStandard::Kind LangStd; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index d6357c9fef192..e524683c50722 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1705,7 +1705,7 @@ def ffp_accuracy_EQ : Joined<["-"], "ffp-accuracy=">, Group, Flags<[CC1 Values<"default,high,medium,low,sycl,cuda">, NormalizedValuesScope<"LangOptions">, NormalizedValues<["FPA_Default", "FPA_High", "FPA_Medium", "FPA_Low", "FPA_Sycl", "FPA_Cuda"]>, MarshallingInfoEnum, "FPA_Default">; -def fpbuiltin_max_error_EQ : Joined<["-"], "fpbuiltin-max-error=">, Group, Flags<[CC1Option]>; +def ffp_accuracy_attr_EQ : Joined<["-"], "ffp-accuracy-attr=">, Group, Flags<[CC1Option]>; defm fast_math : BoolFOption<"fast-math", LangOpts<"FastMath">, DefaultFalse, @@ -6959,6 +6959,11 @@ class CLRemainingArgsJoined : Option<["/", "-"], name, // (We don't put any of these in cl_compile_Group as the options they alias are // already in the right group.) +def _SLASH_Qfp_accuracy_EQ : CLJoined<"Qfp-accuracy=">, + Alias; +def _SLASH_Qfp_accuracy_COL : CLJoined<"Qfp-accuracy:">, + Alias,HelpText<"Defines the accuracy for math library " + "functions.">; def _SLASH_Brepro : CLFlag<"Brepro">, HelpText<"Do not write current time into COFF output (breaks link.exe /incremental)">, Alias; diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 1dbd1eda62b3f..ee147022e5c62 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -276,6 +276,9 @@ class CompilerInvocation : public CompilerInvocationRefBase, std::vector &Includes, DiagnosticsEngine &Diags); + static void ParseFpAccuracyArgs(LangOptions &Opts, llvm::opt::ArgList &Args, + DiagnosticsEngine &Diags); + /// Generate command line options from LangOptions. static void GenerateLangArgs(const LangOptions &Opts, SmallVectorImpl &Args, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 118681874c391..6a077fb43be14 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -489,103 +489,41 @@ static Value *EmitISOVolatileStore(CodeGenFunction &CGF, const CallExpr *E) { return Store; } -static StringRef -convertFPAccuracy(LangOptions::FPAccuracyKind FPAccuracy) { - StringRef AccuracyVal; - switch (FPAccuracy) { - case LangOptions::FPA_Default: - AccuracyVal = "default"; - break; - case LangOptions::FPA_High: - AccuracyVal = "high"; - break; - case LangOptions::FPA_Medium: - AccuracyVal = "medium"; - break; - case LangOptions::FPA_Low: - AccuracyVal = "low"; - break; - case LangOptions::FPA_Sycl: - AccuracyVal = "sycl"; - break; - case LangOptions::FPA_Cuda: - AccuracyVal = "cuda"; - break; - } - return AccuracyVal; -} - -// TODO: This function is only a place holder. Returning for now a hard-code value -// of the ULP error. -unsigned getFPMaxError(Function *F, LangOptions::FPAccuracyKind FPAccuracy) { - unsigned MaxError; - switch (FPAccuracy) { - case LangOptions::FPA_Default: - MaxError = 0; - break; - case LangOptions::FPA_High: - MaxError = 1; - break; - case LangOptions::FPA_Medium: - MaxError = 4; - break; - case LangOptions::FPA_Low: - MaxError = 11; - break; - case LangOptions::FPA_Sycl: - MaxError = 10; - break; - case LangOptions::FPA_Cuda: - MaxError = 2; - break; - } - return MaxError; +static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, + llvm::Function *F, + ArrayRef Args) { + llvm::CallInst *CI = CGF.Builder.CreateCall(F, Args); + unsigned BuiltinID = CGF.getCurrentBuiltinID(); + StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); + llvm::AttributeList AttrList; + CGF.CGM.getFPAccuracyFuncAttributes(Name, AttrList); + // TODO: Needs some processing here to call fp::getAccuracyForFPBuiltin + // before setting the attribute for the call. + CI->setAttributes(AttrList); + return CI; } // Emit a simple mangled intrinsic that has 1 argument and a return type // matching the argument type. Depending on mode, this may be a constrained // floating-point intrinsic. -static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, - const CallExpr *E, unsigned IntrinsicID, - unsigned ConstrainedIntrinsicID) { +static Value * +emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, const CallExpr *E, + unsigned IntrinsicID, + unsigned ConstrainedIntrinsicID) { llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); - - if (CGF.getLangOpts().getFPAccuracy()) { - // TODO: Need to check here if the accuracy of the math library function - // is different than the one in the command line. - LangOptions::FPAccuracyKind FPAccuracy = CGF.getLangOpts().getFPAccuracy(); - StringRef FPAccuracyVal = convertFPAccuracy(FPAccuracy); - Function *F = CGF.CGM.getIntrinsic(Intrinsic::experimental_fpaccuracy_cos, - Src0->getType()); - // TODO: getFPAccuracy is a place holder for the ucooming function. This will - // have to use Target (may be?) in order to calculate the accuracy allowed - // for the function F. For now the function is retruning a hard-coded string. - unsigned MaxError = getFPMaxError(F, FPAccuracy); - StringRef AccuracyStr = "fpbuiltin-max-error"; - auto *AccuracyMD = MDString::get(CGF.Builder.getContext(), AccuracyStr); - llvm::CallInst *CI = CGF.Builder.CreateCall(F, { Src0 }); - if (CGF.getLangOpts().getFPAccuracy() != - LangOptions::FPAccuracyKind::FPA_Default) { - if (!CGF.getLangOpts().FuncAccMap.empty()) { - // TODO: Needs to go trhough the map and set the attribute - // for each function in the map. - // If this map is empty the call site should get the default - // attribute with the error corresponding to the accuracy - // given in the command line option; this should be given - // in the map. - } - AttributeList FPBuiltinMaxErrorAttr = F->getAttributes().get( - CGF.getLLVMContext(), AttributeList::FunctionIndex, - Attribute::FPBuiltinMaxError); - CI->setAttributes(FPBuiltinMaxErrorAttr); - AttributeList A = CI->getAttributes(); - } - return CI; + if (!CGF.getLangOpts().FPAccuracyMap.empty()) { + Function *Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + return CreateBuiltinCallWithAttr(CGF, Func, {Src0}); + } + if (!CGF.getLangOpts().FPAccuracyFuncMap.empty()) { + Function *Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + return CreateBuiltinCallWithAttr(CGF, Func, {Src0}); } + if (CGF.Builder.getIsFPConstrained()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E); Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); - return CGF.Builder.CreateConstrainedFPCall(F, { Src0 }); + return CGF.Builder.CreateConstrainedFPCall(F, {Src0}); } else { Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); return CGF.Builder.CreateCall(F, Src0); @@ -2301,6 +2239,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Result.Val.getFloat())); } + CurrentBuiltinIDRAII CB(*this, BuiltinID); + // If current long-double semantics is IEEE 128-bit, replace math builtins // of long-double with f128 equivalent. // TODO: This mutation should also be applied to other targets other than PPC, @@ -2361,9 +2301,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosf16: case Builtin::BI__builtin_cosl: case Builtin::BI__builtin_cosf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::cos, - Intrinsic::experimental_constrained_cos)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::cos, Intrinsic::fpbuiltin_cos)); + case Builtin::BIexp: case Builtin::BIexpf: case Builtin::BIexpl: @@ -2566,8 +2506,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_sinl: case Builtin::BI__builtin_sinf128: return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::sin, - Intrinsic::experimental_constrained_sin)); + Intrinsic::sin, Intrinsic::fpbuiltin_cos)); case Builtin::BIsqrt: case Builtin::BIsqrtf: diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 3b97081177d42..48ea10c1c9d17 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1839,7 +1839,23 @@ static bool HasStrictReturn(const CodeGenModule &Module, QualType RetTy, void CodeGenModule::getDefaultFunctionAttributes(StringRef Name, bool HasOptnone, bool AttrOnCallSite, - llvm::AttrBuilder &FuncAttrs) { + llvm::AttrBuilder &FuncAttrs) { + for (const auto &M : getLangOpts().FPAccuracyMap) { + llvm::StringSet<> FuncOwnAttrs; + FuncAttrs.addAttribute("fpaccuracy=", M.second); + FuncOwnAttrs.insert(M.first); + } + if (!getLangOpts().FPAccuracyFuncMap.empty()) { + llvm::StringSet<> FuncOwnAttrs; + auto FuncMapIt = getLangOpts().FPAccuracyFuncMap.find(Name.str()); + if (FuncMapIt != getLangOpts().FPAccuracyFuncMap.end()) { + for (const std::pair &AttrPair : + FuncMapIt->second) { + FuncAttrs.addAttribute("fpaccuracy=", AttrPair.second); + FuncOwnAttrs.insert(AttrPair.first); + } + } + } // OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed. if (!HasOptnone) { if (CodeGenOpts.OptimizeSize) diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 0957b7fd474c5..10c6e154702e3 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1597,6 +1597,28 @@ class CodeGenFunction : public CodeGenTypeCache { SourceLocation LastStopPoint; public: + /// Class to manage the BuiltinID for the current builtin expression during + /// processing in EmitBuiltinExpr. + class CurrentBuiltinIDRAII { + CodeGenFunction &CGF; + unsigned SavedBuiltinID; + + public: + CurrentBuiltinIDRAII(CodeGenFunction &CGF, unsigned BuiltinID) + : CGF(CGF), SavedBuiltinID(CGF.CurrentBuiltinID) { + CGF.CurrentBuiltinID = BuiltinID; + } + ~CurrentBuiltinIDRAII() { CGF.CurrentBuiltinID = SavedBuiltinID; } + }; + +private: + unsigned CurrentBuiltinID = /*NotBuiltin*/ 0; + +public: + unsigned getCurrentBuiltinID() { + assert(CurrentBuiltinID != /*NotBuiltin*/ 0); + return CurrentBuiltinID; + } /// Source location information about the default argument or member /// initializer expression we're evaluating, if any. CurrentSourceLocExprScope CurSourceLocExprScope; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index a038c099c8f48..a964ca6c4b573 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -7852,3 +7852,12 @@ void CodeGenModule::moveLazyEmissionStates(CodeGenModule *NewBuilder) { NewBuilder->ABI->MangleCtx = std::move(ABI->MangleCtx); } + +void CodeGenModule::getFPAccuracyFuncAttributes(StringRef Name, + llvm::AttributeList &AttrList) { + llvm::AttrBuilder FuncAttrs(getLLVMContext()); + getDefaultFunctionAttributes(Name, /*HasOptNone*/ false, + /*AttrOnCallSite*/ true, FuncAttrs); + AttrList = llvm::AttributeList::get( + getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs); +} \ No newline at end of file diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 6283aab6b0d7c..a76e9e117d686 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1591,6 +1591,8 @@ class CodeGenModule : public CodeGenTypeCache { /// because we'll lose all important information after each repl. void moveLazyEmissionStates(CodeGenModule *NewBuilder); + void getFPAccuracyFuncAttributes(StringRef Name, llvm::AttributeList &AttrList); + private: llvm::Constant *GetOrCreateLLVMFunction( StringRef MangledName, llvm::Type *Ty, GlobalDecl D, bool ForVTable, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index a3531a6e26ca7..33ff354da1533 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2830,14 +2830,6 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, FPContract = "on"; bool StrictFPModel = false; StringRef Float16ExcessPrecision = ""; - StringRef FPAccuracy = ""; - std::string FPAccurayBis; - static constexpr size_t npos = ~size_t(0); - SmallVector ListOfMathLib; - std::string FullFPAccuracyCmdLineArgs; - LangOptions::FPAccuracyAttrMap FuncAccuracyMap; - LangOptions::FPAccuracyAttrFuncMap FuncAttrMap; - SmallVector AccuracyElement; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -3141,37 +3133,6 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, FPContract = "on"; } break; - case options::OPT_ffp_accuracy_EQ: { - StringRef Val = A->getValue(); - FullFPAccuracyCmdLineArgs = A->getValue(); - for (StringRef Values : - Args.getAllArgValues(options::OPT_ffp_accuracy_EQ)) { - SmallVector AccuracyArr; - Values.split(AccuracyArr, ' '); - for (const auto &Accuracy : AccuracyArr) { - Accuracy.split(AccuracyElement, ':'); - FPAccuracy = AccuracyElement[0]; - if (!(FPAccuracy.equals("default") || FPAccuracy.equals("high") || - FPAccuracy.equals("low") || FPAccuracy.equals("medium") || - FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getSpelling() << FPAccuracy; - if (AccuracyElement.size() == 2) { - SmallVector FuncList; - AccuracyElement[1].split(FuncList, ','); - for (StringRef FuncName : FuncList) { - // TODO: For now the FuncName is given a hard-coded error. - // It will need to be computed. - FuncAccuracyMap.insert( - {"ffp-accuracy", AccuracyElement[0].str()}); - FuncAttrMap.insert({FuncName.str(), std::move(FuncAccuracyMap)}); - } - } - } - } - FPAccuracy = Val; - break; - } } if (StrictFPModel) { @@ -3266,13 +3227,6 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back(Args.MakeArgString("-ffloat16-excess-precision=" + Float16ExcessPrecision)); - if (!FPAccuracy.empty()) - if (!FuncAttrMap.empty()) - CmdArgs.push_back( - Args.MakeArgString("-fpbuiltin-max-error=" + FullFPAccuracyCmdLineArgs)); - else - CmdArgs.push_back(Args.MakeArgString("-ffp-accuracy=" + FPAccuracy)); - ParseMRecip(D, Args, CmdArgs); // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the @@ -6028,6 +5982,27 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, << A->getAsString(Args) << TripleStr; } + std::string FpAccuracyAttr; + auto RenderFPAccuracyOptions = [&FpAccuracyAttr](const Twine &optStr) { + optStr.isSingleStringRef(); + if (FpAccuracyAttr.empty()) + FpAccuracyAttr = std::move(std::string("-ffp-accuracy-attr=")); + else + FpAccuracyAttr += " "; + FpAccuracyAttr += optStr.str(); + }; + for (const Arg *A : Args) { + unsigned OptionID = A->getOption().getID(); + switch (OptionID) { + case options::OPT_ffp_accuracy_EQ: + RenderFPAccuracyOptions(A->getValue()); + A->claim(); + break; + } + } + if (!FpAccuracyAttr.empty()) + CmdArgs.push_back(Args.MakeArgString(FpAccuracyAttr)); + // Decide whether to use verbose asm. Verbose assembly is the default on // toolchains which have the integrated assembler on by default. bool IsIntegratedAssemblerDefault = TC.IsIntegratedAssemblerDefault(); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 1d5caa5b75e15..7f3a157d3817f 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3323,6 +3323,21 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, #include "clang/Driver/Options.inc" #undef LANG_OPTION_WITH_MARSHALLING + for (const auto &M : Opts.FPAccuracyMap) { + SmallString<128> S; + S += M.second; + GenerateArg(Args, OPT_ffp_accuracy_attr_EQ, S, SA); + } + for (const auto &F : Opts.FPAccuracyFuncMap) { + for (const auto &C : F.second) { + SmallString<128> S; + S += C.second; + S += ':'; + S += F.first; + GenerateArg(Args, OPT_ffp_accuracy_attr_EQ, S, SA); + } + } + // The '-fcf-protection=' option is generated by CodeGenOpts generator. if (Opts.ObjC) { @@ -3565,6 +3580,66 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, GenerateArg(Args, OPT_fno_gpu_rdc, SA); } +void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, + DiagnosticsEngine &Diags) { + for (StringRef Values : Args.getAllArgValues(OPT_ffp_accuracy_attr_EQ)) { + SmallVector ValuesArr; + Values.split(ValuesArr, ' '); + for (const auto &Val : ValuesArr) { + SmallVector ValElement; + Val.split(ValElement, ':'); + // The option is of the form -ffp-accuracy=value. + if (ValElement.size() == 1) { + StringRef FPAccuracy = ValElement[0]; + if (!(FPAccuracy.equals("default") || FPAccuracy.equals("high") || + FPAccuracy.equals("low") || FPAccuracy.equals("medium") || + FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) + Diags.Report(diag::err_drv_unsupported_option_argument) + << "ffp-accuracy" << FPAccuracy; + std::pair Result = + Opts.FPAccuracyMap.insert({"fp-accuracy", FPAccuracy.str()}); + if (!Result.second) { + Diags.Report(diag::warn_all_fp_accuray_already_set) + << Result.first->second; + } + } + // The option is of the form -ffp-accuracy=value:[f1, ... fn]. + if (ValElement.size() == 2) { + SmallVector FuncList; + ValElement[1].split(FuncList, ','); + for (StringRef FuncName : FuncList) { + if (FuncName.front() == '[') + FuncName = FuncName.drop_front(1); + if (FuncName.back() == ']') + FuncName = FuncName.drop_back(1); + auto FuncMapIt = Opts.FPAccuracyFuncMap.find(FuncName.str()); + if (FuncMapIt != Opts.FPAccuracyFuncMap.end()) { + // The math function has already been assigned an fp accuracy. + std::pair Result = + FuncMapIt->second.insert( + {"fp-accuracy", ValElement[0].str()}); + if (!Result.second) { + Diags.Report(diag::warn_function_fp_accuray_already_set) + << Result.first->second << FuncName.str(); + } + } else { + LangOptions::FPAccuracyMapTy FPAccMap; + StringRef FPAccuracy = ValElement[0]; + if (!(FPAccuracy.equals("default") || FPAccuracy.equals("high") || + FPAccuracy.equals("low") || FPAccuracy.equals("medium") || + FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) + Diags.Report(diag::err_drv_unsupported_option_argument) + << "ffp-accuracy" << FPAccuracy; + FPAccMap.insert({"fp-accuracy", FPAccuracy.str()}); + Opts.FPAccuracyFuncMap.insert( + {FuncName.str(), std::move(FPAccMap)}); + } + } + } + } + } +} + bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, const llvm::Triple &T, std::vector &Includes, @@ -3721,6 +3796,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, #include "clang/Driver/Options.inc" #undef LANG_OPTION_WITH_MARSHALLING + ParseFpAccuracyArgs(Opts, Args, Diags); + if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { StringRef Name = A->getValue(); if (Name == "full" || Name == "branch") { diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index b0311ec343bfc..0feb29a758cb6 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -1,35 +1,30 @@ -// The next two lines are commented until the call isFPAccuracyAvailable is -// complete. -// TODO: Add next two lines to testing -// RUN %clang_cc1 -Wno-implicit-function-declaration -emit-llvm -o - %s -// RUN %clang_cc1 -ffp-accuracy=default -Wno-implicit-function-declaration -emit-llvm -o - %s - -// TODO: Add cuda and sycl lines for testing - -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=high \ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy-attr=high \ // RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ -// RUN: | FileCheck %s -check-prefixes=CHECK,FPAHIGH +// RUN: | FileCheck %s -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=medium \ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown \ +// RUN: "-ffp-accuracy-attr=high:[sin,cosf] low:[tan]" \ // RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ -// RUN: | FileCheck %s -check-prefixes=CHECK,FPAMED +// RUN: | FileCheck --check-prefix=CHECK-FUNC %s -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy=low \ -// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ -// RUN: | FileCheck %s -check-prefixes=CHECK,FPALOW - -float a, b; +float a, b, c, d, e; void foo(void) { - // CHECK-LABEL: define {{.*}}void @foo() + // CHECK-LABEL: define {{.*}}void @foo() a = cosf(b); - // FPAHIGH: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}) #2 - // FPAMED: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}) #2 - // FPALOW: call float @llvm.experimental.fpaccuracy.cos.f32(float %{{.*}}) #2 + c = sin(a); + d = tan(c); + e = cos(d); + // CHECK: call float @llvm.cos.f32(float {{.*}}) [[ATTR3:#[0-9]+]] + // CHECK: call double @llvm.sin.f64(double {{.*}}) [[ATTR3:#[0-9]+]] + // CHECK: call double @tan(double noundef {{.*}}) [[ATTR3:#[0-9]+]] + // CHECK: call double @llvm.cos.f64(double {{.*}}) [[ATTR3:#[0-9]+]] + + // CHECK-FUNC: call float @llvm.cos.f32(float {{.*}}) [[ATTR3:#[0-9]+]] + // CHECK-FUNC: call double @llvm.sin.f64(double {{.*}}) [[ATTR3:#[0-9]+]] + // CHECK-FUNC: call double @tan(double noundef {{.*}}) [[ATTR4:#[0-9]+]] + // CHECK-FUNC: call double @llvm.cos.f64(double {{.*}}) } -// CHECK: declare float @llvm.experimental.fpaccuracy.cos.f32(float) -// CHECK-SAME: #1 - -// TODO: Needs to add the value of the error. -// CHECK: attributes #2 = { fpbultin_max_error } +// CHECK-FUNC: attributes [[ATTR3]] = {{{.*}}"fpaccuracy="="high" +// CHECK-FUNC: attributes [[ATTR4]] = {{{.*}} "fpaccuracy="="low" diff --git a/clang/test/Driver/fp-accuracy.c b/clang/test/Driver/fp-accuracy.c index 14b4f3a2fad14..693293b96de69 100644 --- a/clang/test/Driver/fp-accuracy.c +++ b/clang/test/Driver/fp-accuracy.c @@ -1,11 +1,20 @@ -// TODO: add a check line for all values of fp-accuracy. - // RUN: %clang -### -target x86_64 -ffp-accuracy=high -c %s 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK %s +// RUN: | FileCheck --check-prefix=CHECK-H %s + +// RUN: %clang -### -target x86_64 -ffp-accuracy=low -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-L %s + +// RUN: %clang -### -target x86_64 -ffp-accuracy=medium -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-M %s // RUN: %clang -### -target x86_64 -ffp-accuracy=low:sin,cos -c %s 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-FUNC %s +// RUN: | FileCheck --check-prefix=CHECK-FUNC-1 %s -// CHECK: "-ffp-accuracy=high" -// CHECK-FUNC: "-fpbuiltin-max-error=low:sin,cos" +// RUN: %clang -### -target x86_64 -ffp-accuracy=low:sin,cos -ffp-accuracy=high:tan -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-FUNC-2 %s +// CHECK-H: "-ffp-accuracy-attr=high" +// CHECK-L: "-ffp-accuracy-attr=low" +// CHECK-M: "-ffp-accuracy-attr=medium" +// CHECK-FUNC-1: "-ffp-accuracy-attr=low:sin,cos" +// CHECK-FUNC-2: "-ffp-accuracy-attr=low:sin,cos high:tan" From d796b5f1f792f5f2d646b1198a49611fb1f3c024 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 18 Apr 2023 08:10:33 -0400 Subject: [PATCH 09/43] Fix formatting issues and remove unused code. --- clang/include/clang/Basic/CodeGenOptions.def | 3 --- clang/include/clang/Basic/CodeGenOptions.h | 6 ------ .../clang/Basic/DiagnosticDriverKinds.td | 1 + clang/include/clang/Driver/Options.td | 6 ------ clang/lib/CodeGen/CGBuiltin.cpp | 17 +++++++++-------- clang/lib/CodeGen/CGCall.cpp | 2 +- clang/lib/CodeGen/CodeGenModule.cpp | 2 +- clang/lib/Driver/ToolChains/Clang.cpp | 1 - llvm/include/llvm/IR/Attributes.td | 4 ---- 9 files changed, 12 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 8a8a57c7d8c78..80cb432cc106b 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -421,9 +421,6 @@ VALUE_CODEGENOPT(InlineMaxStackSize, 32, UINT_MAX) // Vector functions library to use. ENUM_CODEGENOPT(VecLib, VectorLibrary, 3, NoLibrary) -// Alternate math function to use. -ENUM_CODEGENOPT(AltMathLibrary, AlternateMathLibray, 3, NoAltMathLibrary) - /// The default TLS model to use. ENUM_CODEGENOPT(DefaultTLSModel, TLSModel, 2, GeneralDynamicTLSModel) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index fc02a6e234769..44e96fa7d68ea 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -64,12 +64,6 @@ class CodeGenOptions : public CodeGenOptionsBase { Darwin_libsystem_m // Use Darwin's libsytem_m vector functions. }; - enum AlternateMathLibray { - NoAltMathLibrary, // No alternate math library is used. - ImfAltMathLibrary, // IMF alternate math library is used. - TestAltMathLibrary // A fake alternate math library is used. - }; - enum ObjCDispatchMethodKind { Legacy = 0, NonLegacy = 1, diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index f5ff2e014922e..448e1f60fd428 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -60,6 +60,7 @@ def err_drv_no_cuda_libdevice : Error< "cannot find libdevice for %0; provide path to different CUDA installation " "via '--cuda-path', or pass '-nocudalib' to build without linking with " "libdevice">; + def warn_function_fp_accuray_already_set : Warning <"FP accuracy value of '%0' has already " "been assigned to function '%1'">; def warn_all_fp_accuray_already_set : Warning <"FP accuracy value of '%0' has already " diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index e524683c50722..f977650fb5752 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2563,12 +2563,6 @@ def fveclib : Joined<["-"], "fveclib=">, Group, Flags<[CC1Option]>, NormalizedValues<["Accelerate", "LIBMVEC", "MASSV", "SVML", "SLEEF", "Darwin_libsystem_m", "NoLibrary"]>, MarshallingInfoEnum, "NoLibrary">; -def falt_math_library : Joined<["-"], "falt-math-library=">, Group, Flags<[CC1Option]>, - HelpText<"Use an alternate function library">, - Values<"none,imf,test">, - NormalizedValuesScope<"CodeGenOptions">, - NormalizedValues<["NoAltMathLibrary", "ImfAltMathLibrary", "TestAltMathLibrary"]>, - MarshallingInfoEnum, "NoAltMathLibrary">; def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group, Alias, AliasArgs<["none"]>; def fno_implicit_module_maps : Flag <["-"], "fno-implicit-module-maps">, Group, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 6a077fb43be14..f64bc55f3a15a 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -506,10 +506,9 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, // Emit a simple mangled intrinsic that has 1 argument and a return type // matching the argument type. Depending on mode, this may be a constrained // floating-point intrinsic. -static Value * -emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, const CallExpr *E, - unsigned IntrinsicID, - unsigned ConstrainedIntrinsicID) { +static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, + const CallExpr *E, unsigned IntrinsicID, + unsigned ConstrainedIntrinsicID) { llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); if (!CGF.getLangOpts().FPAccuracyMap.empty()) { Function *Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); @@ -523,7 +522,7 @@ emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, const CallExpr *E, if (CGF.Builder.getIsFPConstrained()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E); Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); - return CGF.Builder.CreateConstrainedFPCall(F, {Src0}); + return CGF.Builder.CreateConstrainedFPCall(F, { Src0 }); } else { Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); return CGF.Builder.CreateCall(F, Src0); @@ -2301,8 +2300,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosf16: case Builtin::BI__builtin_cosl: case Builtin::BI__builtin_cosf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( - *this, E, Intrinsic::cos, Intrinsic::fpbuiltin_cos)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::cos, + Intrinsic::fpbuiltin_cos)); case Builtin::BIexp: case Builtin::BIexpf: @@ -2506,7 +2506,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_sinl: case Builtin::BI__builtin_sinf128: return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::sin, Intrinsic::fpbuiltin_cos)); + Intrinsic::sin, + Intrinsic::fpbuiltin_cos)); case Builtin::BIsqrt: case Builtin::BIsqrtf: diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 48ea10c1c9d17..0d88aabad348f 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1839,7 +1839,7 @@ static bool HasStrictReturn(const CodeGenModule &Module, QualType RetTy, void CodeGenModule::getDefaultFunctionAttributes(StringRef Name, bool HasOptnone, bool AttrOnCallSite, - llvm::AttrBuilder &FuncAttrs) { + llvm::AttrBuilder &FuncAttrs) { for (const auto &M : getLangOpts().FPAccuracyMap) { llvm::StringSet<> FuncOwnAttrs; FuncAttrs.addAttribute("fpaccuracy=", M.second); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index a964ca6c4b573..f5c17da50526e 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -7860,4 +7860,4 @@ void CodeGenModule::getFPAccuracyFuncAttributes(StringRef Name, /*AttrOnCallSite*/ true, FuncAttrs); AttrList = llvm::AttributeList::get( getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs); -} \ No newline at end of file +} diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 33ff354da1533..d2cccf8d04f39 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3134,7 +3134,6 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, } break; } - if (StrictFPModel) { // If -ffp-model=strict has been specified on command line but // subsequent options conflict then emit warning diagnostic. diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index dac1674cd696b..e72054cfd475e 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -224,10 +224,6 @@ def ImmArg : EnumAttr<"immarg", [ParamAttr]>; /// Function can return twice. def ReturnsTwice : EnumAttr<"returns_twice", [FnAttr]>; -/// Floating point accuracy of the function defined with the ULP error of the -/// function. -def FPBuiltinMaxError : EnumAttr<"fpbultin_max_error", [FnAttr]>; - /// Safe Stack protection. def SafeStack : EnumAttr<"safestack", [FnAttr]>; From 6c005d8d5885fa838f6e54f99a19084856702997 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 18 Apr 2023 09:30:47 -0400 Subject: [PATCH 10/43] Fix format issues. --- clang/include/clang/Basic/LangOptions.h | 2 +- clang/lib/CodeGen/CGBuiltin.cpp | 10 ++++------ clang/lib/CodeGen/CodeGenModule.h | 3 ++- clang/lib/Frontend/CompilerInvocation.cpp | 3 +-- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 5657ad2dfb7a7..7448a6f42e268 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -22,8 +22,8 @@ #include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/Visibility.h" #include "llvm/ADT/FloatingPointMode.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/TargetParser/Triple.h" #include #include diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index f64bc55f3a15a..0b9879e3e6cf1 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2300,9 +2300,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosf16: case Builtin::BI__builtin_cosl: case Builtin::BI__builtin_cosf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::cos, - Intrinsic::fpbuiltin_cos)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::cos, Intrinsic::fpbuiltin_cos)); case Builtin::BIexp: case Builtin::BIexpf: @@ -2505,9 +2504,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_sinf16: case Builtin::BI__builtin_sinl: case Builtin::BI__builtin_sinf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::sin, - Intrinsic::fpbuiltin_cos)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::sin, Intrinsic::fpbuiltin_cos)); case Builtin::BIsqrt: case Builtin::BIsqrtf: diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index a76e9e117d686..39d979a627301 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1591,7 +1591,8 @@ class CodeGenModule : public CodeGenTypeCache { /// because we'll lose all important information after each repl. void moveLazyEmissionStates(CodeGenModule *NewBuilder); - void getFPAccuracyFuncAttributes(StringRef Name, llvm::AttributeList &AttrList); + void getFPAccuracyFuncAttributes(StringRef Name, + llvm::AttributeList &AttrList); private: llvm::Constant *GetOrCreateLLVMFunction( diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 7f3a157d3817f..52cbe0031e01e 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3616,8 +3616,7 @@ void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, if (FuncMapIt != Opts.FPAccuracyFuncMap.end()) { // The math function has already been assigned an fp accuracy. std::pair Result = - FuncMapIt->second.insert( - {"fp-accuracy", ValElement[0].str()}); + FuncMapIt->second.insert({"fp-accuracy", ValElement[0].str()}); if (!Result.second) { Diags.Report(diag::warn_function_fp_accuray_already_set) << Result.first->second << FuncName.str(); From b93d9ecac17ebd5740895b2575dca0ba6d0b1796 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 18 Apr 2023 12:04:07 -0400 Subject: [PATCH 11/43] Respond to review. --- clang/include/clang/Basic/Attr.td | 7 ------- clang/lib/CodeGen/CGBuiltin.cpp | 10 ++++++---- clang/lib/Driver/ToolChains/Clang.cpp | 12 ++---------- 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index a555355b8022b..f9ba455884059 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2741,13 +2741,6 @@ def ReturnsTwice : InheritableAttr { let SimpleHandler = 1; } -def FPBuiltinMaxError : StmtAttr { - let Spellings = [Clang<"fpbultin_max_error">]; - let Subjects = SubjectList<[Function]>; - let Documentation = [Undocumented]; - let SimpleHandler = 1; -} - def DisableTailCalls : InheritableAttr { let Spellings = [Clang<"disable_tail_calls">]; let Subjects = SubjectList<[Function, ObjCMethod]>; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 0b9879e3e6cf1..e647e74cec9b9 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2300,8 +2300,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosf16: case Builtin::BI__builtin_cosl: case Builtin::BI__builtin_cosf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( - *this, E, Intrinsic::cos, Intrinsic::fpbuiltin_cos)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::cos, + Intrinsic::experimental_constrained_cos)); case Builtin::BIexp: case Builtin::BIexpf: @@ -2504,8 +2505,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_sinf16: case Builtin::BI__builtin_sinl: case Builtin::BI__builtin_sinf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( - *this, E, Intrinsic::sin, Intrinsic::fpbuiltin_cos)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::sin, + Intrinsic::experimental_constrained_sin)); case Builtin::BIsqrt: case Builtin::BIsqrtf: diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index d2cccf8d04f39..003cc5dee15f3 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5983,22 +5983,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, std::string FpAccuracyAttr; auto RenderFPAccuracyOptions = [&FpAccuracyAttr](const Twine &optStr) { - optStr.isSingleStringRef(); if (FpAccuracyAttr.empty()) FpAccuracyAttr = std::move(std::string("-ffp-accuracy-attr=")); else FpAccuracyAttr += " "; FpAccuracyAttr += optStr.str(); }; - for (const Arg *A : Args) { - unsigned OptionID = A->getOption().getID(); - switch (OptionID) { - case options::OPT_ffp_accuracy_EQ: - RenderFPAccuracyOptions(A->getValue()); - A->claim(); - break; - } - } + for (StringRef A : Args.getAllArgValues(options::OPT_ffp_accuracy_EQ)) + RenderFPAccuracyOptions(A); if (!FpAccuracyAttr.empty()) CmdArgs.push_back(Args.MakeArgString(FpAccuracyAttr)); From 17eb30f8d709030d704a7481c4b3e8812d5c3dea Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 18 Apr 2023 14:05:17 -0400 Subject: [PATCH 12/43] Fix typo. --- clang/include/clang/Basic/DiagnosticDriverKinds.td | 2 +- clang/lib/Frontend/CompilerInvocation.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 448e1f60fd428..321f9b15dc33e 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -61,7 +61,7 @@ def err_drv_no_cuda_libdevice : Error< "via '--cuda-path', or pass '-nocudalib' to build without linking with " "libdevice">; -def warn_function_fp_accuray_already_set : Warning <"FP accuracy value of '%0' has already " +def warn_function_fp_accuracy_already_set : Warning <"FP accuracy value of '%0' has already " "been assigned to function '%1'">; def warn_all_fp_accuray_already_set : Warning <"FP accuracy value of '%0' has already " "been assigned to all functions in the program">; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 52cbe0031e01e..7ad59580f4409 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3618,7 +3618,7 @@ void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, std::pair Result = FuncMapIt->second.insert({"fp-accuracy", ValElement[0].str()}); if (!Result.second) { - Diags.Report(diag::warn_function_fp_accuray_already_set) + Diags.Report(diag::warn_function_fp_accuracy_already_set) << Result.first->second << FuncName.str(); } } else { From 4ffd86f5173d290d8c4e796f8589dc7ae9e1e2de Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 18 Apr 2023 14:50:33 -0400 Subject: [PATCH 13/43] Add a group to the diag and fixed typo. --- clang/include/clang/Basic/DiagnosticDriverKinds.td | 8 +++++--- clang/include/clang/Basic/DiagnosticGroups.td | 3 +++ clang/lib/Frontend/CompilerInvocation.cpp | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 321f9b15dc33e..1430c67991a0d 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -62,9 +62,11 @@ def err_drv_no_cuda_libdevice : Error< "libdevice">; def warn_function_fp_accuracy_already_set : Warning <"FP accuracy value of '%0' has already " - "been assigned to function '%1'">; -def warn_all_fp_accuray_already_set : Warning <"FP accuracy value of '%0' has already " - "been assigned to all functions in the program">; + "been assigned to function '%1'">, + InGroup; +def warn_all_fp_accuracy_already_set : Warning <"FP accuracy value of '%0' has already " + "been assigned to all functions in the program">, + InGroup; def err_drv_no_rocm_device_lib : Error< "cannot find ROCm device library%select{| for %1|for ABI version %1}0; provide its path via " "'--rocm-path' or '--rocm-device-lib-path', or pass '-nogpulib' to build " diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index fc014de17ce06..ccfed0903ac14 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1445,3 +1445,6 @@ def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">; // Warnings and fixes to support the "safe buffers" programming model. def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage">; + +// Warnings for fp accuracy already set. +def FPAccuracyAlreadySet : DiagGroup; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 7ad59580f4409..ca7c911d8e66f 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3599,7 +3599,7 @@ void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, std::pair Result = Opts.FPAccuracyMap.insert({"fp-accuracy", FPAccuracy.str()}); if (!Result.second) { - Diags.Report(diag::warn_all_fp_accuray_already_set) + Diags.Report(diag::warn_all_fp_accuracy_already_set) << Result.first->second; } } From bd458b9d7784cb0ed3d290ddb95e55e42a2d6c33 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 18 Apr 2023 17:29:11 -0400 Subject: [PATCH 14/43] Fixed typo. --- clang/include/clang/Basic/DiagnosticGroups.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index ccfed0903ac14..b5ac8888ef96b 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1447,4 +1447,4 @@ def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">; def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage">; // Warnings for fp accuracy already set. -def FPAccuracyAlreadySet : DiagGroup; +def FPAccuracyAlreadySet : DiagGroup<"fp-accuracy-value">; From 80c131a8ddd21b36aed2eca4aeab21da28e744e1 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 24 Apr 2023 15:32:27 -0400 Subject: [PATCH 15/43] Hooking BE code with FE. --- clang/include/clang/Basic/CodeGenOptions.def | 2 + clang/lib/CodeGen/CGBuiltin.cpp | 32 +++-- clang/lib/CodeGen/CGCall.cpp | 46 +++++-- clang/lib/CodeGen/CodeGenModule.cpp | 8 +- clang/lib/CodeGen/CodeGenModule.h | 7 +- clang/lib/Frontend/CompilerInvocation.cpp | 3 + clang/test/CodeGen/fp-accuracy.c | 40 ++++-- llvm/include/llvm/IR/FPAccuracy.def | 66 +++++++++ llvm/include/llvm/IR/FPAccuracy.h | 60 ++++++++ llvm/lib/IR/CMakeLists.txt | 1 + llvm/lib/IR/FPAccuracy.cpp | 137 +++++++++++++++++++ 11 files changed, 363 insertions(+), 39 deletions(-) create mode 100644 llvm/include/llvm/IR/FPAccuracy.def create mode 100644 llvm/include/llvm/IR/FPAccuracy.h create mode 100644 llvm/lib/IR/FPAccuracy.cpp diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 80cb432cc106b..2322cc0cd5ca3 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -374,6 +374,8 @@ CODEGENOPT(VirtualFunctionElimination, 1, 0) ///< Whether to apply the dead /// virtual function elimination /// optimization. +CODEGENOPT(FPAccuracy, 1, 0) + /// Whether to use public LTO visibility for entities in std and stdext /// namespaces. This is enabled by clang-cl's /MT and /MTd flags. CODEGENOPT(LTOVisibilityPublicStd, 1, 0) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e647e74cec9b9..b94c4d7b4441e 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -53,6 +53,7 @@ #include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/MatrixBuilder.h" +#include "llvm/IR/FPAccuracy.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/TargetParser/AArch64TargetParser.h" @@ -490,15 +491,15 @@ static Value *EmitISOVolatileStore(CodeGenFunction &CGF, const CallExpr *E) { } static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, - llvm::Function *F, - ArrayRef Args) { - llvm::CallInst *CI = CGF.Builder.CreateCall(F, Args); + llvm::Function *FPBuiltinF, + ArrayRef Args, + unsigned ID) { + llvm::CallInst *CI = CGF.Builder.CreateCall(FPBuiltinF, Args); unsigned BuiltinID = CGF.getCurrentBuiltinID(); StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); llvm::AttributeList AttrList; - CGF.CGM.getFPAccuracyFuncAttributes(Name, AttrList); - // TODO: Needs some processing here to call fp::getAccuracyForFPBuiltin - // before setting the attribute for the call. + CGF.CGM.getFPAccuracyFuncAttributes(Name, AttrList, ID, + FPBuiltinF->getReturnType()); CI->setAttributes(AttrList); return CI; } @@ -510,13 +511,11 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, const CallExpr *E, unsigned IntrinsicID, unsigned ConstrainedIntrinsicID) { llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); - if (!CGF.getLangOpts().FPAccuracyMap.empty()) { - Function *Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); - return CreateBuiltinCallWithAttr(CGF, Func, {Src0}); - } - if (!CGF.getLangOpts().FPAccuracyFuncMap.empty()) { - Function *Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); - return CreateBuiltinCallWithAttr(CGF, Func, {Src0}); + if (CGF.CGM.getCodeGenOpts().FPAccuracy) { + Function *Func = + CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); + return CreateBuiltinCallWithAttr(CGF, Func, {Src0}, + ConstrainedIntrinsicID); } if (CGF.Builder.getIsFPConstrained()) { @@ -2270,6 +2269,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, ((ConstWithoutErrnoAndExceptions || ConstWithoutExceptions) && (!ConstWithoutErrnoAndExceptions || (!getLangOpts().MathErrno)))) { switch (BuiltinIDIfNoAsmLabel) { + case Builtin::BItan: + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::fpbuiltin_tan, Intrinsic::fpbuiltin_tan)); case Builtin::BIceil: case Builtin::BIceilf: case Builtin::BIceill: @@ -2302,7 +2304,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosf128: return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, Intrinsic::cos, - Intrinsic::experimental_constrained_cos)); + Intrinsic::fpbuiltin_cos)); case Builtin::BIexp: case Builtin::BIexpf: @@ -2507,7 +2509,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_sinf128: return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, Intrinsic::sin, - Intrinsic::experimental_constrained_sin)); + Intrinsic::fpbuiltin_sin)); case Builtin::BIsqrt: case Builtin::BIsqrtf: diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 0d88aabad348f..bbb703fa5ab9d 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -38,6 +38,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Type.h" +#include "llvm/IR/FPAccuracy.h" #include "llvm/Transforms/Utils/Local.h" #include using namespace clang; @@ -1836,14 +1837,30 @@ static bool HasStrictReturn(const CodeGenModule &Module, QualType RetTy, Module.getLangOpts().Sanitize.has(SanitizerKind::Return); } -void CodeGenModule::getDefaultFunctionAttributes(StringRef Name, - bool HasOptnone, - bool AttrOnCallSite, - llvm::AttrBuilder &FuncAttrs) { +llvm::fp::FPAccuracy convertFPAccuracy(StringRef FPAccuracy) { + StringRef AccuracyVal; + if (FPAccuracy == "high") + return llvm::fp::FPAccuracy::High; + else if (FPAccuracy == "medium") + return llvm::fp::FPAccuracy::Medium; + else if (FPAccuracy == "low") + return llvm::fp::FPAccuracy::Low; + else if (FPAccuracy == "sycl") + return llvm::fp::FPAccuracy::SYCL; + else if (FPAccuracy == "cuda") + return llvm::fp::FPAccuracy::CUDA; + else + llvm_unreachable("Unexpected type for FPAccuracy"); +} + +void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( + StringRef Name, llvm::AttrBuilder &FuncAttrs, unsigned ID, + const llvm::Type *FuncType) { for (const auto &M : getLangOpts().FPAccuracyMap) { llvm::StringSet<> FuncOwnAttrs; - FuncAttrs.addAttribute("fpaccuracy=", M.second); - FuncOwnAttrs.insert(M.first); + StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( + ID, FuncType, convertFPAccuracy(M.second)); + FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); } if (!getLangOpts().FPAccuracyFuncMap.empty()) { llvm::StringSet<> FuncOwnAttrs; @@ -1851,11 +1868,18 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name, if (FuncMapIt != getLangOpts().FPAccuracyFuncMap.end()) { for (const std::pair &AttrPair : FuncMapIt->second) { - FuncAttrs.addAttribute("fpaccuracy=", AttrPair.second); - FuncOwnAttrs.insert(AttrPair.first); + StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( + ID, FuncType, convertFPAccuracy(AttrPair.second)); + FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); } } } +} + +void CodeGenModule::getDefaultFunctionAttributes(StringRef Name, + bool HasOptnone, + bool AttrOnCallSite, + llvm::AttrBuilder &FuncAttrs) { // OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed. if (!HasOptnone) { if (CodeGenOpts.OptimizeSize) @@ -5411,6 +5435,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, /*AttrOnCallSite=*/true, /*IsThunk=*/false); + if (CGM.getCodeGenOpts().FPAccuracy && CalleePtr->getName() == "sincos") { + CGM.getFPAccuracyFuncAttributes( + CalleePtr->getName(), Attrs, llvm::Intrinsic::fpbuiltin_sincos, + CGM.getTypes().ConvertType(CallArgs[0].getType())); + } + if (const FunctionDecl *FD = dyn_cast_or_null(CurFuncDecl)) if (FD->hasAttr()) // All calls within a strictfp function are marked strictfp diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index f5c17da50526e..326a3ec0b4cfb 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -7854,10 +7854,12 @@ void CodeGenModule::moveLazyEmissionStates(CodeGenModule *NewBuilder) { } void CodeGenModule::getFPAccuracyFuncAttributes(StringRef Name, - llvm::AttributeList &AttrList) { + llvm::AttributeList &AttrList, + unsigned ID, + const llvm::Type *FuncType) { llvm::AttrBuilder FuncAttrs(getLLVMContext()); - getDefaultFunctionAttributes(Name, /*HasOptNone*/ false, - /*AttrOnCallSite*/ true, FuncAttrs); + getDefaultFunctionFPAccuracyAttributes(Name, FuncAttrs, ID, + FuncType); AttrList = llvm::AttributeList::get( getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs); } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 39d979a627301..e7a4fff8757ba 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1592,7 +1592,8 @@ class CodeGenModule : public CodeGenTypeCache { void moveLazyEmissionStates(CodeGenModule *NewBuilder); void getFPAccuracyFuncAttributes(StringRef Name, - llvm::AttributeList &AttrList); + llvm::AttributeList &AttrList, unsigned ID, + const llvm::Type *FuncType); private: llvm::Constant *GetOrCreateLLVMFunction( @@ -1782,6 +1783,10 @@ class CodeGenModule : public CodeGenTypeCache { bool AttrOnCallSite, llvm::AttrBuilder &FuncAttrs); + void getDefaultFunctionFPAccuracyAttributes(StringRef Name, + llvm::AttrBuilder &FuncAttrs, + unsigned ID, const llvm::Type *FuncType); + llvm::Metadata *CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map, StringRef Suffix); }; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index ca7c911d8e66f..682e65bba8d34 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2029,6 +2029,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, } } + if (Arg *A = Args.getLastArg(options::OPT_ffp_accuracy_attr_EQ)) + Opts.FPAccuracy = 1; + if (auto *arg = Args.getLastArg(options::OPT_fdiagnostics_misexpect_tolerance_EQ)) { auto ResultOrErr = parseToleranceOption(arg->getValue()); diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index 0feb29a758cb6..e6d9f1240d906 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -3,11 +3,16 @@ // RUN: | FileCheck %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ -// RUN: "-ffp-accuracy-attr=high:[sin,cosf] low:[tan]" \ +// RUN: "-ffp-accuracy-attr=high:[sin,cosf] low:[tan] medium:[sincos]" \ // RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CHECK-FUNC %s -float a, b, c, d, e; +// RUN: %clang_cc1 -triple spir64-unknown-unknown \ +// RUN: -D SPIR -ffp-accuracy-attr=sycl \ +// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefix=CHECK-SPIR %s + +float a, b, c, d, e, f; void foo(void) { // CHECK-LABEL: define {{.*}}void @foo() @@ -15,16 +20,27 @@ void foo(void) { c = sin(a); d = tan(c); e = cos(d); - // CHECK: call float @llvm.cos.f32(float {{.*}}) [[ATTR3:#[0-9]+]] - // CHECK: call double @llvm.sin.f64(double {{.*}}) [[ATTR3:#[0-9]+]] - // CHECK: call double @tan(double noundef {{.*}}) [[ATTR3:#[0-9]+]] - // CHECK: call double @llvm.cos.f64(double {{.*}}) [[ATTR3:#[0-9]+]] +#ifndef SPIR + d = sincos(e); +#endif + // CHECK: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR3:#[0-9]+]] + // CHECK: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR3:#[0-9]+]] + // CHECK: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR3:#[0-9]+]] + // CHECK: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) [[ATTR3:#[0-9]+]] + + // CHECK-FUNC: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR3:#[0-9]+]] + // CHECK-FUNC: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR3:#[0-9]+]] + // CHECK-FUNC: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR4:#[0-9]+]] + // CHECK-FUNC: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) + // CHECK-FUNC: call i32 (double, ...) @sincos(double {{.*}}) [[ATTR5:#[0-9]+]] - // CHECK-FUNC: call float @llvm.cos.f32(float {{.*}}) [[ATTR3:#[0-9]+]] - // CHECK-FUNC: call double @llvm.sin.f64(double {{.*}}) [[ATTR3:#[0-9]+]] - // CHECK-FUNC: call double @tan(double noundef {{.*}}) [[ATTR4:#[0-9]+]] - // CHECK-FUNC: call double @llvm.cos.f64(double {{.*}}) + // CHECK-SPIR: call float @llvm.fpbuiltin.cos.f32(float {{.*}} [[ATTR5:#[0-9]+]] + // CHECK-SPIR: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR5:#[0-9]+]] + // CHECK-SPIR: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR6:#[0-9]+]] + // CHECK-SPIR: call double @llvm.fpbuiltin.cos.f64(double {{.*}} [[ATTR5:#[0-9]+]] } -// CHECK-FUNC: attributes [[ATTR3]] = {{{.*}}"fpaccuracy="="high" -// CHECK-FUNC: attributes [[ATTR4]] = {{{.*}} "fpaccuracy="="low" +// CHECK-FUNC: attributes [[ATTR3]] = {{{.*}}"fpbuiltin-max-error="="1.0f" +// CHECK-FUNC: attributes [[ATTR4]] = {{{.*}}"fpbuiltin-max-error="="67108864.0f" +// CHECK-FUNC: attributes [[ATTR5]] = {{{.*}}"fpbuiltin-max-error="="4.0f" +// CHECK-SPIR: attributes [[ATTR6]] = {{{.*}}"fpbuiltin-max-error="="5.0f" diff --git a/llvm/include/llvm/IR/FPAccuracy.def b/llvm/include/llvm/IR/FPAccuracy.def new file mode 100644 index 0000000000000..f4e8d009929d5 --- /dev/null +++ b/llvm/include/llvm/IR/FPAccuracy.def @@ -0,0 +1,66 @@ +//===--- llvm/IR/FPAccuracy.def - Mappings for fp accuracy -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines properties of floating point builtin intrinsics. +// +//===----------------------------------------------------------------------===// + +// This customization is only in xmain for review purposes. +// When approved, it will go into the intel/llvm repository. + +#ifndef FP_ACCURACY +#define FP_ACCURACY(IID,SF,SD,CF,CD +#endif + +// Each entry below maps an fpbuiltin intrinsic ID to the required accuracy +// for that operation for single- and double-precision for SYCL and CUDA +// +// All accuracies are returned as single-precision floating-point values. +// +// Note: for single-precision fdiv and sqrt, the value returned here assumes +// that the "-cl-fp32-correctly-rounded-divide-sqrt" option is not used. +// If the option is used, these operations require special handling elsewhere +// +// FP_ACCURACY(, , , , ) +// +FP_ACCURACY(fpbuiltin_fadd, "0.0f", "0.0f", "0.0f", "0.0f") +FP_ACCURACY(fpbuiltin_fsub, "0.0f", "0.0f", "0.0f", "0.0f") +FP_ACCURACY(fpbuiltin_fmul, "0.0f", "0.0f", "0.0f", "0.0f") +FP_ACCURACY(fpbuiltin_fdiv, "2.5f", "0.0f", "2.0f", "0.0f") +FP_ACCURACY(fpbuiltin_frem, "0.0f", "0.0f", "0.0f", "0.0f") +FP_ACCURACY(fpbuiltin_sin, "4.0f", "4.0f", "2.0f", "2.0f") +FP_ACCURACY(fpbuiltin_cos, "4.0f", "4.0f", "2.0f", "2.0f") +FP_ACCURACY(fpbuiltin_tan, "5.0f", "5.0f", "4.0f", "2.0f") +FP_ACCURACY(fpbuiltin_sinh, "4.0f", "4.0f", "3.0f", "2.0f") +FP_ACCURACY(fpbuiltin_cosh, "4.0f", "4.0f", "3.0f", "2.0f") +FP_ACCURACY(fpbuiltin_tanh, "5.0f", "5.0f", "2.0f", "2.0f") +FP_ACCURACY(fpbuiltin_asin, "4.0f", "4.0f", "4.0f", "2.0f") +FP_ACCURACY(fpbuiltin_acos, "4.0f", "4.0f", "3.0f", "2.0f") +FP_ACCURACY(fpbuiltin_atan, "5.0f", "5.0f", "2.0f", "2.0f") +FP_ACCURACY(fpbuiltin_atan2, "6.0f", "6.0f", "3.0f", "2.0f") +FP_ACCURACY(fpbuiltin_asinh, "4.0f", "4.0f", "3.0f", "2.0f") +FP_ACCURACY(fpbuiltin_acosh, "4.0f", "4.0f", "4.0f", "2.0f") +FP_ACCURACY(fpbuiltin_atanh, "5.0f", "5.0f", "3.0f", "2.0f") +FP_ACCURACY(fpbuiltin_exp, "3.0f", "3.0f", "2.0f", "1.0f") +FP_ACCURACY(fpbuiltin_exp2, "3.0f", "3.0f", "2.0f", "1.0f") +FP_ACCURACY(fpbuiltin_exp10, "3.0f", "3.0f", "2.0f", "1.0f") +FP_ACCURACY(fpbuiltin_expm1, "3.0f", "3.0f", "1.0f", "1.0f") +FP_ACCURACY(fpbuiltin_log, "3.0f", "3.0f", "1.0f", "1.0f") +FP_ACCURACY(fpbuiltin_log2, "3.0f", "3.0f", "1.0f", "1.0f") +FP_ACCURACY(fpbuiltin_log10, "3.0f", "3.0f", "2.0f", "1.0f") +FP_ACCURACY(fpbuiltin_log1p, "2.0f", "2.0f", "1.0f", "1.0f") +FP_ACCURACY(fpbuiltin_hypot, "4.0f", "4.0f", "3.0f", "2.0f") +FP_ACCURACY(fpbuiltin_pow, "16.0f", "16.0f", "8.0f", "2.0f") +FP_ACCURACY(fpbuiltin_ldexp, "0.0f", "0.0f", "0.0f", "0.0f") +FP_ACCURACY(fpbuiltin_sqrt, "2.5f", "0.0f", "2.0f", "0.0f") +FP_ACCURACY(fpbuiltin_rsqrt, "2.0f", "2.0f", "2.0f", "1.0f") +FP_ACCURACY(fpbuiltin_erf, "16.0f", "16.0f", "2.0f", "2.0f") +FP_ACCURACY(fpbuiltin_erfc, "16.0f", "16.0f", "4.0f", "5.0f") +FP_ACCURACY(fpbuiltin_sincos, "4.0f", "4.0f", "2.0f", "2.0f") + +#undef FP_ACCURACY diff --git a/llvm/include/llvm/IR/FPAccuracy.h b/llvm/include/llvm/IR/FPAccuracy.h new file mode 100644 index 0000000000000..9121379459ae8 --- /dev/null +++ b/llvm/include/llvm/IR/FPAccuracy.h @@ -0,0 +1,60 @@ +//===- llvm/IR/FPAccuracy.h -------------------------------------*- C++ -*-===/ +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Interfaces related to floating-point accuracy control. +/// mode controls. +/// +//===----------------------------------------------------------------------===/ + +#ifndef LLVM_IR_FPACCURACY_H +#define LLVM_IR_FPACCURACY_H + +// This customization is only in xmain for review purposes. +// When approved, it will go into the intel/llvm repository. + +#include + +namespace llvm { + +class StringRef; +class Type; + +namespace Intrinsic { +typedef unsigned ID; +} + +namespace fp { + +/// FP accuracy +/// +/// Enumerates supported accuracy modes for fpbuiltin intrinisics. These +/// modes are used to lookup required accuracy in terms of ULP for known +/// math operations that are represented by the fpbuiltin intrinsics. +/// +/// These values can also be used to set the default accuracy for an IRBuilder +/// object and the IRBuilder will automatically attach the corresponding +/// "fpbuiltin-max-error" attribute to any fpbuiltin intrinsics that are +/// created using the IRBuilder object. +/// +enum class FPAccuracy { High, Medium, Low, SYCL, CUDA }; + +// Returns the required accuracy, in terms of ulp, for an fpbuiltin intrinsic +// given the intrinsic ID, the base type for the operation, and the required +// accuracy level (as an enumerated identifier). +// +// If the supplied intrinsic ID and type do not identify an operation for +// which required accuracy is available, this function will not return a value. +StringRef getAccuracyForFPBuiltin(Intrinsic::ID, const Type *, + FPAccuracy); + +} // namespace fp + +} // namespace llvm + +#endif // LLVM_IR_FPACCURACY_H diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt index 88c493860c8d4..d4e14d9394cea 100644 --- a/llvm/lib/IR/CMakeLists.txt +++ b/llvm/lib/IR/CMakeLists.txt @@ -22,6 +22,7 @@ add_llvm_component_library(LLVMCore Dominators.cpp EHPersonalities.cpp FPEnv.cpp + FPAccuracy.cpp Function.cpp GCStrategy.cpp GVMaterializer.cpp diff --git a/llvm/lib/IR/FPAccuracy.cpp b/llvm/lib/IR/FPAccuracy.cpp new file mode 100644 index 0000000000000..632450cd42868 --- /dev/null +++ b/llvm/lib/IR/FPAccuracy.cpp @@ -0,0 +1,137 @@ +//===-- FPAccuracy.cpp ---- FP Accuracy Support ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// @file +/// This file contains the implementations of functions that map standard +/// accuracy levels to required accuracy expressed in terms of ulps. +// +//===----------------------------------------------------------------------===// + +// This customization is only in xmain for review purposes. +// When approved, it will go into the intel/llvm repository. + +#include "llvm/IR/FPAccuracy.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include + +namespace llvm { + +static bool isFPBuiltinIntrinsic(Intrinsic::ID IID) { + switch (IID) { +#define OPERATION(NAME, INTRINSIC) case Intrinsic::INTRINSIC: +#include "llvm/IR/FPBuiltinOps.def" + return true; + default: + return false; + } +} + +static StringRef LookupSyclFloatAccuracy(Intrinsic::ID IID) { + switch (IID) { +#define FP_ACCURACY(INTRINSIC, SYCL_FLOAT_ACCURACY, SDA, CFA, CDA) \ + case Intrinsic::INTRINSIC: \ + return SYCL_FLOAT_ACCURACY; +#include "llvm/IR/FPAccuracy.def" + default: + return StringRef(); + } +} + +static StringRef LookupSyclDoubleAccuracy(Intrinsic::ID IID) { + switch (IID) { +#define FP_ACCURACY(INTRINSIC, SFA, SYCL_DOUBLE_ACCURACY, CFA, CDA) \ + case Intrinsic::INTRINSIC: \ + return SYCL_DOUBLE_ACCURACY; +#include "llvm/IR/FPAccuracy.def" + default: + return StringRef(); + } +} + +static StringRef LookupCudaFloatAccuracy(Intrinsic::ID IID) { + switch (IID) { +#define FP_ACCURACY(INTRINSIC, SFA, SDA, CUDA_FLOAT_ACCURACY, CDA) \ + case Intrinsic::INTRINSIC: \ + return CUDA_FLOAT_ACCURACY; +#include "llvm/IR/FPAccuracy.def" + default: + return StringRef(); + } +} + +static StringRef LookupCudaDoubleAccuracy(Intrinsic::ID IID) { + switch (IID) { +#define FP_ACCURACY(INTRINSIC, SFA, SDA, CFA, CUDA_DOUBLE_ACCURACY) \ + case Intrinsic::INTRINSIC: \ + return CUDA_DOUBLE_ACCURACY; +#include "llvm/IR/FPAccuracy.def" + default: + return StringRef(); + } +} + +StringRef fp::getAccuracyForFPBuiltin(Intrinsic::ID IID, + const Type *Ty, + fp::FPAccuracy AccuracyLevel) { + assert(isFPBuiltinIntrinsic(IID) && "Invalid intrinsic ID for FPAccuracy"); + + assert(Ty->isFPOrFPVectorTy() && "Invalid type for FPAccuracy"); + + // Vector fpbuiltins have the same accuracy requirements as the corresponding + // scalar operation. + if (const auto *VecTy = dyn_cast(Ty)) + Ty = VecTy->getElementType(); + + // This will probably change at some point. + assert((Ty->isFloatTy() || Ty->isDoubleTy()) && + "Invalid type for FPAccuracy"); + + // High and medium accuracy have the same requirement for all functions + if (AccuracyLevel == fp::FPAccuracy::High) + return "1.0f"; + if (AccuracyLevel == fp::FPAccuracy::Medium) + return "4.0f"; + + // Low accuracy is computed in terms of accurate bits, so it depends on the + // type + if (AccuracyLevel == fp::FPAccuracy::Low) { + if (Ty->isFloatTy()) + return "8192.0f"; + if (Ty->isDoubleTy()) + return "67108864.0f"; // 2^(53-26-1) == 26-bits of accuracy + + // Other types are not supported + llvm_unreachable("Unexpected type for FPAccuracy"); + } + + assert((AccuracyLevel == fp::FPAccuracy::SYCL || + AccuracyLevel == fp::FPAccuracy::CUDA) && + "Unexpected FPAccuracy level"); +#if 1 + if (Ty->isFloatTy()) { + if (AccuracyLevel == fp::FPAccuracy::SYCL) + return LookupSyclFloatAccuracy(IID); + if (AccuracyLevel == fp::FPAccuracy::CUDA) + return LookupCudaFloatAccuracy(IID); + llvm_unreachable("Unexpected FPAccuracy level"); + } else if (Ty->isDoubleTy()) { + if (AccuracyLevel == fp::FPAccuracy::SYCL) + return LookupSyclDoubleAccuracy(IID); + if (AccuracyLevel == fp::FPAccuracy::CUDA) + return LookupCudaDoubleAccuracy(IID); + llvm_unreachable("Unexpected FPAccuracy level"); + } else { + // This is here for error detection if the logic above is changed. + llvm_unreachable("Unexpected type for FPAccuracy"); + } + #endif +} + +} // namespace llvm From faae1a0adc9afbc84a4fff008f505fcaacfe07bd Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 25 Apr 2023 12:48:58 -0400 Subject: [PATCH 16/43] Responded to review. --- clang/include/clang/Driver/Options.td | 7 ++- clang/lib/CodeGen/CGBuiltin.cpp | 43 ++++++++----- clang/lib/CodeGen/CGCall.cpp | 10 +-- clang/lib/CodeGen/CodeGenModule.cpp | 3 +- clang/lib/CodeGen/CodeGenModule.h | 3 +- clang/lib/Driver/ToolChains/Clang.cpp | 2 +- clang/lib/Frontend/CompilerInvocation.cpp | 8 +-- clang/test/CodeGen/fp-accuracy.c | 75 +++++++++++++++-------- clang/test/Driver/fp-accuracy.c | 10 +-- llvm/include/llvm/IR/FPAccuracy.h | 3 +- llvm/lib/IR/FPAccuracy.cpp | 8 +-- 11 files changed, 102 insertions(+), 70 deletions(-) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index f977650fb5752..ff25a35fc883f 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1705,7 +1705,7 @@ def ffp_accuracy_EQ : Joined<["-"], "ffp-accuracy=">, Group, Flags<[CC1 Values<"default,high,medium,low,sycl,cuda">, NormalizedValuesScope<"LangOptions">, NormalizedValues<["FPA_Default", "FPA_High", "FPA_Medium", "FPA_Low", "FPA_Sycl", "FPA_Cuda"]>, MarshallingInfoEnum, "FPA_Default">; -def ffp_accuracy_attr_EQ : Joined<["-"], "ffp-accuracy-attr=">, Group, Flags<[CC1Option]>; +def ffp_builtin_accuracy_EQ : Joined<["-"], "ffp-builtin-accuracy=">, Group, Flags<[CC1Option]>; defm fast_math : BoolFOption<"fast-math", LangOpts<"FastMath">, DefaultFalse, @@ -6956,8 +6956,9 @@ class CLRemainingArgsJoined : Option<["/", "-"], name, def _SLASH_Qfp_accuracy_EQ : CLJoined<"Qfp-accuracy=">, Alias; def _SLASH_Qfp_accuracy_COL : CLJoined<"Qfp-accuracy:">, - Alias,HelpText<"Defines the accuracy for math library " - "functions.">; + Alias,HelpText<"Specifies the required accuracy for " + "floating-point operations and library calls.">; + def _SLASH_Brepro : CLFlag<"Brepro">, HelpText<"Do not write current time into COFF output (breaks link.exe /incremental)">, Alias; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index b94c4d7b4441e..fbfab1b11510e 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -35,6 +35,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/FPAccuracy.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicsAArch64.h" @@ -53,7 +54,6 @@ #include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/MatrixBuilder.h" -#include "llvm/IR/FPAccuracy.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/TargetParser/AArch64TargetParser.h" @@ -491,12 +491,11 @@ static Value *EmitISOVolatileStore(CodeGenFunction &CGF, const CallExpr *E) { } static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, + StringRef Name, llvm::Function *FPBuiltinF, ArrayRef Args, unsigned ID) { llvm::CallInst *CI = CGF.Builder.CreateCall(FPBuiltinF, Args); - unsigned BuiltinID = CGF.getCurrentBuiltinID(); - StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); llvm::AttributeList AttrList; CGF.CGM.getFPAccuracyFuncAttributes(Name, AttrList, ID, FPBuiltinF->getReturnType()); @@ -506,18 +505,34 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, // Emit a simple mangled intrinsic that has 1 argument and a return type // matching the argument type. Depending on mode, this may be a constrained -// floating-point intrinsic. +// or an fpbuiltin floating-point intrinsic. static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, const CallExpr *E, unsigned IntrinsicID, unsigned ConstrainedIntrinsicID) { llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); - if (CGF.CGM.getCodeGenOpts().FPAccuracy) { - Function *Func = - CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); - return CreateBuiltinCallWithAttr(CGF, Func, {Src0}, + if (CGF.CGM.getCodeGenOpts().FPAccuracy) { + unsigned BuiltinID = CGF.getCurrentBuiltinID(); + StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); + Function *Func; + // Use fpbuiltin intrinsic only when needed. + bool IsBuiltin = false; + if (!CGF.getLangOpts().FPAccuracyMap.empty()) + IsBuiltin = true; + for (auto F : CGF.getLangOpts().FPAccuracyFuncMap) { + auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); + if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) + if (FuncMapIt->first == Name) { + IsBuiltin = true; + break; + } + } + if (IsBuiltin) + Func = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); + else + Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0}, ConstrainedIntrinsicID); } - if (CGF.Builder.getIsFPConstrained()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E); Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); @@ -2302,9 +2317,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosf16: case Builtin::BI__builtin_cosl: case Builtin::BI__builtin_cosf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::cos, - Intrinsic::fpbuiltin_cos)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::cos, Intrinsic::fpbuiltin_cos)); case Builtin::BIexp: case Builtin::BIexpf: @@ -2507,9 +2521,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_sinf16: case Builtin::BI__builtin_sinl: case Builtin::BI__builtin_sinf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::sin, - Intrinsic::fpbuiltin_sin)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::sin, Intrinsic::fpbuiltin_sin)); case Builtin::BIsqrt: case Builtin::BIsqrtf: diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index bbb703fa5ab9d..7ae370a926985 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -34,11 +34,11 @@ #include "llvm/IR/Attributes.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/FPAccuracy.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Type.h" -#include "llvm/IR/FPAccuracy.h" #include "llvm/Transforms/Utils/Local.h" #include using namespace clang; @@ -1857,20 +1857,20 @@ void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( StringRef Name, llvm::AttrBuilder &FuncAttrs, unsigned ID, const llvm::Type *FuncType) { for (const auto &M : getLangOpts().FPAccuracyMap) { - llvm::StringSet<> FuncOwnAttrs; StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( ID, FuncType, convertFPAccuracy(M.second)); - FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); + if (!FPAccuracyVal.empty()) + FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); } if (!getLangOpts().FPAccuracyFuncMap.empty()) { - llvm::StringSet<> FuncOwnAttrs; auto FuncMapIt = getLangOpts().FPAccuracyFuncMap.find(Name.str()); if (FuncMapIt != getLangOpts().FPAccuracyFuncMap.end()) { for (const std::pair &AttrPair : FuncMapIt->second) { StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( ID, FuncType, convertFPAccuracy(AttrPair.second)); - FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); + if (!FPAccuracyVal.empty()) + FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); } } } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 326a3ec0b4cfb..3b560b347e0fd 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -7858,8 +7858,7 @@ void CodeGenModule::getFPAccuracyFuncAttributes(StringRef Name, unsigned ID, const llvm::Type *FuncType) { llvm::AttrBuilder FuncAttrs(getLLVMContext()); - getDefaultFunctionFPAccuracyAttributes(Name, FuncAttrs, ID, - FuncType); + getDefaultFunctionFPAccuracyAttributes(Name, FuncAttrs, ID, FuncType); AttrList = llvm::AttributeList::get( getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs); } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index e7a4fff8757ba..6a0e1c7d3e218 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1785,7 +1785,8 @@ class CodeGenModule : public CodeGenTypeCache { void getDefaultFunctionFPAccuracyAttributes(StringRef Name, llvm::AttrBuilder &FuncAttrs, - unsigned ID, const llvm::Type *FuncType); + unsigned ID, + const llvm::Type *FuncType); llvm::Metadata *CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map, StringRef Suffix); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 003cc5dee15f3..e3fbec9e23b13 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5984,7 +5984,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, std::string FpAccuracyAttr; auto RenderFPAccuracyOptions = [&FpAccuracyAttr](const Twine &optStr) { if (FpAccuracyAttr.empty()) - FpAccuracyAttr = std::move(std::string("-ffp-accuracy-attr=")); + FpAccuracyAttr = std::move(std::string("-ffp-builtin-accuracy=")); else FpAccuracyAttr += " "; FpAccuracyAttr += optStr.str(); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 682e65bba8d34..bd0a2cd0fdc2a 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2029,7 +2029,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, } } - if (Arg *A = Args.getLastArg(options::OPT_ffp_accuracy_attr_EQ)) + if (Arg *A = Args.getLastArg(options::OPT_ffp_builtin_accuracy_EQ)) Opts.FPAccuracy = 1; if (auto *arg = @@ -3329,7 +3329,7 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, for (const auto &M : Opts.FPAccuracyMap) { SmallString<128> S; S += M.second; - GenerateArg(Args, OPT_ffp_accuracy_attr_EQ, S, SA); + GenerateArg(Args, OPT_ffp_builtin_accuracy_EQ, S, SA); } for (const auto &F : Opts.FPAccuracyFuncMap) { for (const auto &C : F.second) { @@ -3337,7 +3337,7 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, S += C.second; S += ':'; S += F.first; - GenerateArg(Args, OPT_ffp_accuracy_attr_EQ, S, SA); + GenerateArg(Args, OPT_ffp_builtin_accuracy_EQ, S, SA); } } @@ -3585,7 +3585,7 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { - for (StringRef Values : Args.getAllArgValues(OPT_ffp_accuracy_attr_EQ)) { + for (StringRef Values : Args.getAllArgValues(OPT_ffp_builtin_accuracy_EQ)) { SmallVector ValuesArr; Values.split(ValuesArr, ' '); for (const auto &Val : ValuesArr) { diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index e6d9f1240d906..2c3a0ca86560c 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -1,18 +1,25 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-accuracy-attr=high \ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-builtin-accuracy=high \ // RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ -// RUN: "-ffp-accuracy-attr=high:[sin,cosf] low:[tan] medium:[sincos]" \ +// RUN: "-ffp-builtin-accuracy=high:[sin,cosf] low:[tan] medium:[sincos]" \ // RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ -// RUN: | FileCheck --check-prefix=CHECK-FUNC %s +// RUN: | FileCheck --check-prefix=CHECK-FUNC-1 %s -// RUN: %clang_cc1 -triple spir64-unknown-unknown \ -// RUN: -D SPIR -ffp-accuracy-attr=sycl \ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown \ +// RUN: "-ffp-builtin-accuracy=medium high:[tan] cuda:[cos]" \ +// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefix=CHECK-FUNC-2 %s + +// RUN: %clang_cc1 -triple spir64-unknown-unknown -ffp-builtin-accuracy=sycl \ // RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CHECK-SPIR %s -float a, b, c, d, e, f; +float a, b, c, d, f; +double e; + +extern double sincos (double __x) __attribute__ ((__nothrow__ )); void foo(void) { // CHECK-LABEL: define {{.*}}void @foo() @@ -20,27 +27,41 @@ void foo(void) { c = sin(a); d = tan(c); e = cos(d); -#ifndef SPIR d = sincos(e); -#endif - // CHECK: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR3:#[0-9]+]] - // CHECK: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR3:#[0-9]+]] - // CHECK: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR3:#[0-9]+]] - // CHECK: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) [[ATTR3:#[0-9]+]] - - // CHECK-FUNC: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR3:#[0-9]+]] - // CHECK-FUNC: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR3:#[0-9]+]] - // CHECK-FUNC: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR4:#[0-9]+]] - // CHECK-FUNC: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) - // CHECK-FUNC: call i32 (double, ...) @sincos(double {{.*}}) [[ATTR5:#[0-9]+]] - - // CHECK-SPIR: call float @llvm.fpbuiltin.cos.f32(float {{.*}} [[ATTR5:#[0-9]+]] - // CHECK-SPIR: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR5:#[0-9]+]] - // CHECK-SPIR: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR6:#[0-9]+]] - // CHECK-SPIR: call double @llvm.fpbuiltin.cos.f64(double {{.*}} [[ATTR5:#[0-9]+]] + + // CHECK: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_HIGH:#[0-9]+]] + // CHECK: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR_HIGH]] + // CHECK: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_HIGH]] + // CHECK: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) [[ATTR_HIGH]] + + // CHECK-FUNC-1: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_HIGH:#[0-9]+]] + // CHECK-FUNC-1: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR_HIGH]] + // CHECK-FUNC-1: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_LOW:#[0-9]+]] + // CHECK-FUNC-1: call double @llvm.cos.f64(double {{.*}}) + // CHECK-FUNC-1: call double @sincos(double {{.*}}) [[ATTR_MEDIUM:#[0-9]+]] + + // CHECK-FUNC-2: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_MEDIUM:#[0-9]+]] + // CHECK-FUNC-2: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR_MEDIUM]] + // CHECK-FUNC-2: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_HIGH:#[0-9]+]] + // CHECK-FUNC-2: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) [[ATTR_CUDA:#[0-9]+]] + // CHECK-FUNC-2: call double @sincos(double {{.*}}) [[ATTR_MEDIUM]] + + // CHECK-SPIR: call float @llvm.fpbuiltin.cos.f32(float %0) [[ATTR_MEDIUM:#[0-9]+]] + // CHECK-SPIR: call double @llvm.fpbuiltin.sin.f64(double %conv) [[ATTR_MEDIUM]] + // CHECK-SPIR: call double @llvm.fpbuiltin.tan.f64(double %conv2) [[ATTR_SYCL:#[0-9]+]] + // CHECK-SPIR: call double @llvm.fpbuiltin.cos.f64(double %conv4) [[ATTR_MEDIUM]] + // CHECK-SPIR: call spir_func double @sincos(double %8) [[ATTR_MEDIUM]] } -// CHECK-FUNC: attributes [[ATTR3]] = {{{.*}}"fpbuiltin-max-error="="1.0f" -// CHECK-FUNC: attributes [[ATTR4]] = {{{.*}}"fpbuiltin-max-error="="67108864.0f" -// CHECK-FUNC: attributes [[ATTR5]] = {{{.*}}"fpbuiltin-max-error="="4.0f" -// CHECK-SPIR: attributes [[ATTR6]] = {{{.*}}"fpbuiltin-max-error="="5.0f" +// CHECK: attributes [[ATTR_HIGH]] = {{{.*}}"fpbuiltin-max-error="="1.0f" + +// CHECK-FUNC-1: attributes [[ATTR_HIGH]] = {{{.*}}"fpbuiltin-max-error="="1.0f" +// CHECK-FUNC-1: attributes [[ATTR_LOW]] = {{{.*}}"fpbuiltin-max-error="="67108864.0f" +// CHECK-FUNC-1: attributes [[ATTR_MEDIUM]] = {{{.*}}"fpbuiltin-max-error="="4.0f" + +// CHECK-FUNC-2: attributes [[ATTR_MEDIUM]] = {{{.*}}"fpbuiltin-max-error="="4.0f" +// CHECK-FUNC-2: attributes [[ATTR_HIGH]] = {{{.*}}"fpbuiltin-max-error="="1.0f" +// CHECK-FUNC-2: attributes [[ATTR_CUDA]] = {{{.*}}"fpbuiltin-max-error="="2.0f" + +// CHECK-SPIR: attributes [[ATTR_MEDIUM]] = {{{.*}}"fpbuiltin-max-error="="4.0f" +// CHECK-SPIR: attributes [[ATTR_SYCL]] = {{{.*}}"fpbuiltin-max-error="="5.0f" diff --git a/clang/test/Driver/fp-accuracy.c b/clang/test/Driver/fp-accuracy.c index 693293b96de69..836b621025cf8 100644 --- a/clang/test/Driver/fp-accuracy.c +++ b/clang/test/Driver/fp-accuracy.c @@ -13,8 +13,8 @@ // RUN: %clang -### -target x86_64 -ffp-accuracy=low:sin,cos -ffp-accuracy=high:tan -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-FUNC-2 %s -// CHECK-H: "-ffp-accuracy-attr=high" -// CHECK-L: "-ffp-accuracy-attr=low" -// CHECK-M: "-ffp-accuracy-attr=medium" -// CHECK-FUNC-1: "-ffp-accuracy-attr=low:sin,cos" -// CHECK-FUNC-2: "-ffp-accuracy-attr=low:sin,cos high:tan" +// CHECK-H: "-ffp-builtin-accuracy=high" +// CHECK-L: "-ffp-builtin-accuracy=low" +// CHECK-M: "-ffp-builtin-accuracy=medium" +// CHECK-FUNC-1: "-ffp-builtin-accuracy=low:sin,cos" +// CHECK-FUNC-2: "-ffp-builtin-accuracy=low:sin,cos high:tan" diff --git a/llvm/include/llvm/IR/FPAccuracy.h b/llvm/include/llvm/IR/FPAccuracy.h index 9121379459ae8..290517a15b29f 100644 --- a/llvm/include/llvm/IR/FPAccuracy.h +++ b/llvm/include/llvm/IR/FPAccuracy.h @@ -50,8 +50,7 @@ enum class FPAccuracy { High, Medium, Low, SYCL, CUDA }; // // If the supplied intrinsic ID and type do not identify an operation for // which required accuracy is available, this function will not return a value. -StringRef getAccuracyForFPBuiltin(Intrinsic::ID, const Type *, - FPAccuracy); +StringRef getAccuracyForFPBuiltin(Intrinsic::ID, const Type *, FPAccuracy); } // namespace fp diff --git a/llvm/lib/IR/FPAccuracy.cpp b/llvm/lib/IR/FPAccuracy.cpp index 632450cd42868..2c8cdb0691cae 100644 --- a/llvm/lib/IR/FPAccuracy.cpp +++ b/llvm/lib/IR/FPAccuracy.cpp @@ -77,9 +77,8 @@ static StringRef LookupCudaDoubleAccuracy(Intrinsic::ID IID) { } } -StringRef fp::getAccuracyForFPBuiltin(Intrinsic::ID IID, - const Type *Ty, - fp::FPAccuracy AccuracyLevel) { +StringRef fp::getAccuracyForFPBuiltin(Intrinsic::ID IID, const Type *Ty, + fp::FPAccuracy AccuracyLevel) { assert(isFPBuiltinIntrinsic(IID) && "Invalid intrinsic ID for FPAccuracy"); assert(Ty->isFPOrFPVectorTy() && "Invalid type for FPAccuracy"); @@ -114,7 +113,7 @@ StringRef fp::getAccuracyForFPBuiltin(Intrinsic::ID IID, assert((AccuracyLevel == fp::FPAccuracy::SYCL || AccuracyLevel == fp::FPAccuracy::CUDA) && "Unexpected FPAccuracy level"); -#if 1 + if (Ty->isFloatTy()) { if (AccuracyLevel == fp::FPAccuracy::SYCL) return LookupSyclFloatAccuracy(IID); @@ -131,7 +130,6 @@ StringRef fp::getAccuracyForFPBuiltin(Intrinsic::ID IID, // This is here for error detection if the logic above is changed. llvm_unreachable("Unexpected type for FPAccuracy"); } - #endif } } // namespace llvm From bbabbb59d8b730bc178fdc7754c1ba7dec4ee69c Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 25 Apr 2023 13:59:00 -0400 Subject: [PATCH 17/43] Fix format. --- clang/lib/CodeGen/CGBuiltin.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index fbfab1b11510e..6180b1f160c3f 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -490,8 +490,7 @@ static Value *EmitISOVolatileStore(CodeGenFunction &CGF, const CallExpr *E) { return Store; } -static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, - StringRef Name, +static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, StringRef Name, llvm::Function *FPBuiltinF, ArrayRef Args, unsigned ID) { From 8aabc411a520c5f82a4c6b7771f98db2f7250031 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 25 Apr 2023 17:40:35 -0400 Subject: [PATCH 18/43] Responded to review comments. --- clang/lib/CodeGen/CGBuiltin.cpp | 8 ++++---- clang/lib/CodeGen/CGCall.cpp | 4 ++++ clang/test/Driver/fp-accuracy.c | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c6cab89080521..a4560bcbbb67b 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -514,18 +514,18 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); Function *Func; // Use fpbuiltin intrinsic only when needed. - bool IsBuiltin = false; + bool HasAccuracyRequirement = false; if (!CGF.getLangOpts().FPAccuracyMap.empty()) - IsBuiltin = true; + HasAccuracyRequirement = true; for (auto F : CGF.getLangOpts().FPAccuracyFuncMap) { auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) if (FuncMapIt->first == Name) { - IsBuiltin = true; + HasAccuracyRequirement = true; break; } } - if (IsBuiltin) + if (HasAccuracyRequirement) Func = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); else Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 7ae370a926985..7d485d9d47176 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1861,6 +1861,8 @@ void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( ID, FuncType, convertFPAccuracy(M.second)); if (!FPAccuracyVal.empty()) FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); + else + assert("A valid accuracy value is expected"); } if (!getLangOpts().FPAccuracyFuncMap.empty()) { auto FuncMapIt = getLangOpts().FPAccuracyFuncMap.find(Name.str()); @@ -1871,6 +1873,8 @@ void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( ID, FuncType, convertFPAccuracy(AttrPair.second)); if (!FPAccuracyVal.empty()) FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); + else + assert("A valid accuracy value is expected"); } } } diff --git a/clang/test/Driver/fp-accuracy.c b/clang/test/Driver/fp-accuracy.c index 836b621025cf8..6fe4c929002fe 100644 --- a/clang/test/Driver/fp-accuracy.c +++ b/clang/test/Driver/fp-accuracy.c @@ -13,8 +13,23 @@ // RUN: %clang -### -target x86_64 -ffp-accuracy=low:sin,cos -ffp-accuracy=high:tan -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-FUNC-2 %s +// RUN: not %clang -Xclang -verify -ffp-accuracy=foo %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ERR + +// RUN: not %clang -Xclang -verify -ffp-accuracy=foo:[sin,cos] %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ERR + +// RUN: not %clang -Xclang -verify -ffp-accuracy=foo:[sin,cos] \ +// RUN: -ffp-accuracy=goo %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ERR + +// RUN: not %clang -Xclang -verify -ffp-accuracy=foo:[sin,cos] \ +// RUN: -ffp-accuracy=goo:[tan] %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ERR + // CHECK-H: "-ffp-builtin-accuracy=high" // CHECK-L: "-ffp-builtin-accuracy=low" // CHECK-M: "-ffp-builtin-accuracy=medium" // CHECK-FUNC-1: "-ffp-builtin-accuracy=low:sin,cos" // CHECK-FUNC-2: "-ffp-builtin-accuracy=low:sin,cos high:tan" +// CHECK-ERR: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' From 6681fc2a48d1fe09dfb81a8b84c517aa49a06a92 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Wed, 26 Apr 2023 11:12:00 -0400 Subject: [PATCH 19/43] Fixed Lit test failures. --- clang/lib/CodeGen/CGBuiltin.cpp | 29 ++++++++++++++++++++--------- clang/lib/CodeGen/CGCall.cpp | 12 ++++-------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index a4560bcbbb67b..16378366b9d2f 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -505,9 +505,10 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, StringRef Name, // Emit a simple mangled intrinsic that has 1 argument and a return type // matching the argument type. Depending on mode, this may be a constrained // or an fpbuiltin floating-point intrinsic. -static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, - const CallExpr *E, unsigned IntrinsicID, - unsigned ConstrainedIntrinsicID) { +static Value *emitUnaryMaybeConstrainedFPBuiltin( + CodeGenFunction &CGF, const CallExpr *E, unsigned IntrinsicID, + unsigned ConstrainedIntrinsicID, + unsigned FPAccuracyIntrinsicID = Intrinsic::not_intrinsic) { llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); if (CGF.CGM.getCodeGenOpts().FPAccuracy) { unsigned BuiltinID = CGF.getCurrentBuiltinID(); @@ -526,11 +527,11 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, } } if (HasAccuracyRequirement) - Func = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); + Func = CGF.CGM.getIntrinsic(FPAccuracyIntrinsicID, Src0->getType()); else Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0}, - ConstrainedIntrinsicID); + FPAccuracyIntrinsicID); } if (CGF.Builder.getIsFPConstrained()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E); @@ -2284,8 +2285,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, (!ConstWithoutErrnoAndExceptions || (!getLangOpts().MathErrno)))) { switch (BuiltinIDIfNoAsmLabel) { case Builtin::BItan: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( - *this, E, Intrinsic::fpbuiltin_tan, Intrinsic::fpbuiltin_tan)); + case Builtin::BItanf: + case Builtin::BItanh: + case Builtin::BItanhf: + case Builtin::BItanhl: + case Builtin::BItanl: + if (CGM.getCodeGenOpts().FPAccuracy) + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::fpbuiltin_tan, Intrinsic::fpbuiltin_tan, + Intrinsic::fpbuiltin_tan)); + break; case Builtin::BIceil: case Builtin::BIceilf: case Builtin::BIceill: @@ -2317,7 +2326,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosl: case Builtin::BI__builtin_cosf128: return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( - *this, E, Intrinsic::cos, Intrinsic::fpbuiltin_cos)); + *this, E, Intrinsic::cos, Intrinsic::experimental_constrained_cos, + Intrinsic::fpbuiltin_cos)); case Builtin::BIexp: case Builtin::BIexpf: @@ -2521,7 +2531,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_sinl: case Builtin::BI__builtin_sinf128: return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( - *this, E, Intrinsic::sin, Intrinsic::fpbuiltin_sin)); + *this, E, Intrinsic::sin, Intrinsic::experimental_constrained_sin, + Intrinsic::fpbuiltin_sin)); case Builtin::BIsqrt: case Builtin::BIsqrtf: diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 7d485d9d47176..460e66f120c36 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1859,10 +1859,8 @@ void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( for (const auto &M : getLangOpts().FPAccuracyMap) { StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( ID, FuncType, convertFPAccuracy(M.second)); - if (!FPAccuracyVal.empty()) - FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); - else - assert("A valid accuracy value is expected"); + assert(!FPAccuracyVal.empty() && "A valid accuracy value is expected"); + FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); } if (!getLangOpts().FPAccuracyFuncMap.empty()) { auto FuncMapIt = getLangOpts().FPAccuracyFuncMap.find(Name.str()); @@ -1871,10 +1869,8 @@ void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( FuncMapIt->second) { StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( ID, FuncType, convertFPAccuracy(AttrPair.second)); - if (!FPAccuracyVal.empty()) - FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); - else - assert("A valid accuracy value is expected"); + assert(!FPAccuracyVal.empty() && "A valid accuracy value is expected"); + FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); } } } From 20fd09b01cd98702b5ec747e2e0d8db5c0afa5f9 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Wed, 26 Apr 2023 17:06:15 -0400 Subject: [PATCH 20/43] Fixed sincos issue and did some code refactoring. --- clang/lib/CodeGen/CGBuiltin.cpp | 51 ++++++++++++++++------ clang/lib/CodeGen/CGCall.cpp | 8 +--- clang/lib/CodeGen/CodeGenFunction.h | 3 ++ clang/test/CodeGen/fp-accuracy.c | 68 +++++++++++++++-------------- 4 files changed, 78 insertions(+), 52 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 16378366b9d2f..101e1c6fc04c4 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -496,8 +496,11 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, StringRef Name, unsigned ID) { llvm::CallInst *CI = CGF.Builder.CreateCall(FPBuiltinF, Args); llvm::AttributeList AttrList; - CGF.CGM.getFPAccuracyFuncAttributes(Name, AttrList, ID, - FPBuiltinF->getReturnType()); + if (Name == "sincos") + CGF.CGM.getFPAccuracyFuncAttributes(Name, AttrList, ID, Args[0]->getType()); + else + CGF.CGM.getFPAccuracyFuncAttributes(Name, AttrList, ID, + FPBuiltinF->getReturnType()); CI->setAttributes(AttrList); return CI; } @@ -2284,17 +2287,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, ((ConstWithoutErrnoAndExceptions || ConstWithoutExceptions) && (!ConstWithoutErrnoAndExceptions || (!getLangOpts().MathErrno)))) { switch (BuiltinIDIfNoAsmLabel) { - case Builtin::BItan: - case Builtin::BItanf: - case Builtin::BItanh: - case Builtin::BItanhf: - case Builtin::BItanhl: - case Builtin::BItanl: - if (CGM.getCodeGenOpts().FPAccuracy) - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( - *this, E, Intrinsic::fpbuiltin_tan, Intrinsic::fpbuiltin_tan, - Intrinsic::fpbuiltin_tan)); - break; case Builtin::BIceil: case Builtin::BIceilf: case Builtin::BIceill: @@ -21874,6 +21866,39 @@ RValue CodeGenFunction::EmitIntelFPGAMemBuiltin(const CallExpr *E) { return RValue::get(Ann); } +RValue CodeGenFunction::EmitFPBuiltinIndirectCall( + llvm::FunctionType *IRFuncTy, const SmallVectorImpl &IRArgs, + llvm::Value *FnPtr) { + llvm::Function *Func; + unsigned FPAccuracyIntrinsicID = 0; + llvm::CallInst *CI; + if (FnPtr->getName() == "sincos") { + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; + Func = CGM.getIntrinsic(FPAccuracyIntrinsicID, IRArgs[0]->getType()); + CI = CreateBuiltinCallWithAttr(*this, FnPtr->getName(), Func, + {IRArgs[0], IRArgs[1], IRArgs[2]}, + FPAccuracyIntrinsicID); + } else { + unsigned BuiltinID = getCurrentBuiltinID(); + StringRef Name = CGM.getContext().BuiltinInfo.getName(BuiltinID); + unsigned FPAccuracyIntrinsicID = 0; + switch (BuiltinID) { + case Builtin::BItan: + case Builtin::BItanf: + case Builtin::BItanh: + case Builtin::BItanhf: + case Builtin::BItanhl: + case Builtin::BItanl: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_tan; + break; + } + Func = CGM.getIntrinsic(FPAccuracyIntrinsicID, IRArgs[0]->getType()); + CI = CreateBuiltinCallWithAttr(*this, Name, Func, {IRArgs[0]}, + FPAccuracyIntrinsicID); + } + return RValue::get(CI); +} + Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 460e66f120c36..3132c37e91d27 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -5435,12 +5435,6 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, /*AttrOnCallSite=*/true, /*IsThunk=*/false); - if (CGM.getCodeGenOpts().FPAccuracy && CalleePtr->getName() == "sincos") { - CGM.getFPAccuracyFuncAttributes( - CalleePtr->getName(), Attrs, llvm::Intrinsic::fpbuiltin_sincos, - CGM.getTypes().ConvertType(CallArgs[0].getType())); - } - if (const FunctionDecl *FD = dyn_cast_or_null(CurFuncDecl)) if (FD->hasAttr()) // All calls within a strictfp function are marked strictfp @@ -5527,6 +5521,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // Emit the actual call/invoke instruction. llvm::CallBase *CI; if (!InvokeDest) { + if (CGM.getCodeGenOpts().FPAccuracy) + return EmitFPBuiltinIndirectCall(IRFuncTy, IRCallArgs, CalleePtr); CI = Builder.CreateCall(IRFuncTy, CalleePtr, IRCallArgs, BundleList); } else { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index a256fbab78d52..b97e96b1e7e44 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4306,6 +4306,9 @@ class CodeGenFunction : public CodeGenTypeCache { ReturnValueSlot ReturnValue); RValue EmitIntelFPGAMemBuiltin(const CallExpr *E); + RValue EmitFPBuiltinIndirectCall(llvm::FunctionType *IRFuncTy, + const SmallVectorImpl &IRArgs, + llvm::Value *FnPtr); enum class MSVCIntrin; llvm::Value *EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID, const CallExpr *E); diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index 2c3a0ca86560c..63b86daa4f7a6 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -13,44 +13,47 @@ // RUN: | FileCheck --check-prefix=CHECK-FUNC-2 %s // RUN: %clang_cc1 -triple spir64-unknown-unknown -ffp-builtin-accuracy=sycl \ -// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: -D SPIR -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CHECK-SPIR %s -float a, b, c, d, f; -double e; +#ifdef SPIR +void sincos(float, float *, float *); +#endif -extern double sincos (double __x) __attribute__ ((__nothrow__ )); +void foo(float f1, float f2) { + // CHECK-LABEL: define {{.*}}void @foo(float noundef {{.*}}, float noundef {{.*}}) + float sin = 0.f, cos = 0.f; -void foo(void) { - // CHECK-LABEL: define {{.*}}void @foo() - a = cosf(b); - c = sin(a); - d = tan(c); - e = cos(d); - d = sincos(e); + f2 = cosf(f1); + f2 = sinf(f1); + f2 = tan(f1); + f2 = tanf(f1); + sincos(f1, &sin, &cos); - // CHECK: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_HIGH:#[0-9]+]] - // CHECK: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR_HIGH]] - // CHECK: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_HIGH]] - // CHECK: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) [[ATTR_HIGH]] + // CHECK: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_HIGH:#[0-9]+]] + // CHECK: call float @llvm.fpbuiltin.sin.f32(float {{.*}}) [[ATTR_HIGH]] + // CHECK: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_HIGH]] + // CHECK: call float @llvm.fpbuiltin.tan.f32(float {{.*}}) [[ATTR_HIGH]] + // CHECK: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) [[ATTR_HIGH]] // CHECK-FUNC-1: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_HIGH:#[0-9]+]] - // CHECK-FUNC-1: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR_HIGH]] + // CHECK-FUNC-1: call float @llvm.sin.f32(float {{.*}}) // CHECK-FUNC-1: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_LOW:#[0-9]+]] - // CHECK-FUNC-1: call double @llvm.cos.f64(double {{.*}}) - // CHECK-FUNC-1: call double @sincos(double {{.*}}) [[ATTR_MEDIUM:#[0-9]+]] + // CHECK-FUNC-1: call float @llvm.fpbuiltin.tan.f32(float {{.*}}) + // CHECK-FUNC-1: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) [[ATTR_MEDIUM:#[0-9]+]] + + // CHECK-FUNC-2: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_MEDIUM:#[0-9]+]] + // CHECK-FUNC-2: call float @llvm.fpbuiltin.sin.f32(float {{.*}}) [[ATTR_MEDIUM]] + // CHECK-FUNC-2: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_HIGH:#[0-9]+]] + // CHECK-FUNC-2: call float @llvm.fpbuiltin.tan.f32(float {{.*}}) [[ATTR_MEDIUM]] + // CHECK-FUNC-2: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) [[ATTR_MEDIUM]] - // CHECK-FUNC-2: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_MEDIUM:#[0-9]+]] - // CHECK-FUNC-2: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) [[ATTR_MEDIUM]] - // CHECK-FUNC-2: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_HIGH:#[0-9]+]] - // CHECK-FUNC-2: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) [[ATTR_CUDA:#[0-9]+]] - // CHECK-FUNC-2: call double @sincos(double {{.*}}) [[ATTR_MEDIUM]] + // CHECK-SPIR: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_SYCL1:#[0-9]+]] + // CHECK-SPIR: call float @llvm.fpbuiltin.sin.f32(float {{.*}}) [[ATTR_SYCL1]] + // CHECK-SPIR: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_SYCL2:#[0-9]+]] + // CHECK-SPIR: call float @llvm.fpbuiltin.tan.f32(float {{.*}}) [[ATTR_SYCL2]] + // CHECK-SPIR: call void @llvm.fpbuiltin.sincos.f32(float {{.*}}, ptr {{.*}}, ptr {{.*}}) [[ATTR_SYCL1]] - // CHECK-SPIR: call float @llvm.fpbuiltin.cos.f32(float %0) [[ATTR_MEDIUM:#[0-9]+]] - // CHECK-SPIR: call double @llvm.fpbuiltin.sin.f64(double %conv) [[ATTR_MEDIUM]] - // CHECK-SPIR: call double @llvm.fpbuiltin.tan.f64(double %conv2) [[ATTR_SYCL:#[0-9]+]] - // CHECK-SPIR: call double @llvm.fpbuiltin.cos.f64(double %conv4) [[ATTR_MEDIUM]] - // CHECK-SPIR: call spir_func double @sincos(double %8) [[ATTR_MEDIUM]] } // CHECK: attributes [[ATTR_HIGH]] = {{{.*}}"fpbuiltin-max-error="="1.0f" @@ -59,9 +62,8 @@ void foo(void) { // CHECK-FUNC-1: attributes [[ATTR_LOW]] = {{{.*}}"fpbuiltin-max-error="="67108864.0f" // CHECK-FUNC-1: attributes [[ATTR_MEDIUM]] = {{{.*}}"fpbuiltin-max-error="="4.0f" -// CHECK-FUNC-2: attributes [[ATTR_MEDIUM]] = {{{.*}}"fpbuiltin-max-error="="4.0f" -// CHECK-FUNC-2: attributes [[ATTR_HIGH]] = {{{.*}}"fpbuiltin-max-error="="1.0f" -// CHECK-FUNC-2: attributes [[ATTR_CUDA]] = {{{.*}}"fpbuiltin-max-error="="2.0f" +// CHECK-FUNC-2: attributes #5 = { "fpbuiltin-max-error="="4.0f" } +// CHECK-FUNC-2: attributes #6 = { "fpbuiltin-max-error="="1.0f" } -// CHECK-SPIR: attributes [[ATTR_MEDIUM]] = {{{.*}}"fpbuiltin-max-error="="4.0f" -// CHECK-SPIR: attributes [[ATTR_SYCL]] = {{{.*}}"fpbuiltin-max-error="="5.0f" +// CHECK-SPIR: attributes [[ATTR_SYCL1]] = {{{.*}}"fpbuiltin-max-error="="4.0f" +// CHECK-SPIR: attributes [[ATTR_SYCL2]] = {{{.*}}"fpbuiltin-max-error="="5.0f" From 300d2fedd95e4b740e5816bce1899328e60494ca Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Thu, 27 Apr 2023 16:14:05 -0400 Subject: [PATCH 21/43] Remove FPAccuracyMap. --- clang/include/clang/Basic/LangOptions.h | 11 +++--- clang/lib/CodeGen/CGBuiltin.cpp | 4 +-- clang/lib/CodeGen/CGCall.cpp | 15 ++++----- clang/lib/Frontend/CompilerInvocation.cpp | 41 ++++++++--------------- 4 files changed, 26 insertions(+), 45 deletions(-) diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 7448a6f42e268..a3e4eb84c339b 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -396,13 +396,6 @@ class LangOptions : public LangOptionsBase { IncompleteOnly = 3, }; - using FPAccuracyMapTy = - llvm::MapVector>; - FPAccuracyMapTy FPAccuracyMap; - using FPAccuracyFuncMapTy = - llvm::MapVector>; - FPAccuracyFuncMapTy FPAccuracyFuncMap; - public: /// The used language standard. LangStandard::Kind LangStd; @@ -526,6 +519,10 @@ class LangOptions : public LangOptionsBase { /// records. std::string OptRecordFile; + std::string FPAccuracyVal; + using FPAccuracyFuncMapTy = std::map; + FPAccuracyFuncMapTy FPAccuracyFuncMap; + LangOptions(); /// Set language defaults for the given input language and diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 101e1c6fc04c4..5826bf339f280 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -519,7 +519,7 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin( Function *Func; // Use fpbuiltin intrinsic only when needed. bool HasAccuracyRequirement = false; - if (!CGF.getLangOpts().FPAccuracyMap.empty()) + if (!CGF.getLangOpts().FPAccuracyVal.empty()) HasAccuracyRequirement = true; for (auto F : CGF.getLangOpts().FPAccuracyFuncMap) { auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); @@ -539,7 +539,7 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin( if (CGF.Builder.getIsFPConstrained()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E); Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); - return CGF.Builder.CreateConstrainedFPCall(F, { Src0 }); + return CGF.Builder.CreateConstrainedFPCall(F, {Src0}); } else { Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); return CGF.Builder.CreateCall(F, Src0); diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 3132c37e91d27..d3612906c6385 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1856,22 +1856,19 @@ llvm::fp::FPAccuracy convertFPAccuracy(StringRef FPAccuracy) { void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( StringRef Name, llvm::AttrBuilder &FuncAttrs, unsigned ID, const llvm::Type *FuncType) { - for (const auto &M : getLangOpts().FPAccuracyMap) { + if (!getLangOpts().FPAccuracyVal.empty()) { StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( - ID, FuncType, convertFPAccuracy(M.second)); + ID, FuncType, convertFPAccuracy(getLangOpts().FPAccuracyVal)); assert(!FPAccuracyVal.empty() && "A valid accuracy value is expected"); FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); } if (!getLangOpts().FPAccuracyFuncMap.empty()) { auto FuncMapIt = getLangOpts().FPAccuracyFuncMap.find(Name.str()); if (FuncMapIt != getLangOpts().FPAccuracyFuncMap.end()) { - for (const std::pair &AttrPair : - FuncMapIt->second) { - StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( - ID, FuncType, convertFPAccuracy(AttrPair.second)); - assert(!FPAccuracyVal.empty() && "A valid accuracy value is expected"); - FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); - } + StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( + ID, FuncType, convertFPAccuracy(FuncMapIt->second)); + assert(!FPAccuracyVal.empty() && "A valid accuracy value is expected"); + FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); } } } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index bd0a2cd0fdc2a..9803077b0c3b3 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3326,19 +3326,17 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, #include "clang/Driver/Options.inc" #undef LANG_OPTION_WITH_MARSHALLING - for (const auto &M : Opts.FPAccuracyMap) { - SmallString<128> S; - S += M.second; + if (!Opts.FPAccuracyVal.empty()) { + StringRef S = Opts.FPAccuracyVal; GenerateArg(Args, OPT_ffp_builtin_accuracy_EQ, S, SA); } + for (const auto &F : Opts.FPAccuracyFuncMap) { - for (const auto &C : F.second) { - SmallString<128> S; - S += C.second; - S += ':'; - S += F.first; - GenerateArg(Args, OPT_ffp_builtin_accuracy_EQ, S, SA); - } + SmallString<128> S; + S += F.second; + S += ':'; + S += F.first; + GenerateArg(Args, OPT_ffp_builtin_accuracy_EQ, S, SA); } // The '-fcf-protection=' option is generated by CodeGenOpts generator. @@ -3599,12 +3597,7 @@ void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) Diags.Report(diag::err_drv_unsupported_option_argument) << "ffp-accuracy" << FPAccuracy; - std::pair Result = - Opts.FPAccuracyMap.insert({"fp-accuracy", FPAccuracy.str()}); - if (!Result.second) { - Diags.Report(diag::warn_all_fp_accuracy_already_set) - << Result.first->second; - } + Opts.FPAccuracyVal = ValElement[0].str(); } // The option is of the form -ffp-accuracy=value:[f1, ... fn]. if (ValElement.size() == 2) { @@ -3615,26 +3608,20 @@ void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, FuncName = FuncName.drop_front(1); if (FuncName.back() == ']') FuncName = FuncName.drop_back(1); - auto FuncMapIt = Opts.FPAccuracyFuncMap.find(FuncName.str()); - if (FuncMapIt != Opts.FPAccuracyFuncMap.end()) { - // The math function has already been assigned an fp accuracy. - std::pair Result = - FuncMapIt->second.insert({"fp-accuracy", ValElement[0].str()}); - if (!Result.second) { + auto FuncMap = Opts.FPAccuracyFuncMap.find(FuncName.str()); + if (FuncMap != Opts.FPAccuracyFuncMap.end()) { + if (!FuncMap->second.empty()) { Diags.Report(diag::warn_function_fp_accuracy_already_set) - << Result.first->second << FuncName.str(); + << FuncMap->second << FuncName.str(); } } else { - LangOptions::FPAccuracyMapTy FPAccMap; StringRef FPAccuracy = ValElement[0]; if (!(FPAccuracy.equals("default") || FPAccuracy.equals("high") || FPAccuracy.equals("low") || FPAccuracy.equals("medium") || FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) Diags.Report(diag::err_drv_unsupported_option_argument) << "ffp-accuracy" << FPAccuracy; - FPAccMap.insert({"fp-accuracy", FPAccuracy.str()}); - Opts.FPAccuracyFuncMap.insert( - {FuncName.str(), std::move(FPAccMap)}); + Opts.FPAccuracyFuncMap.insert({FuncName.str(), FPAccuracy.str()}); } } } From 1e148b3399757dfa6476a4e1ab3fcbb6e71f5fb3 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 1 May 2023 14:16:02 -0400 Subject: [PATCH 22/43] Added testing for the all the fpbuiltin. --- clang/lib/CodeGen/CGBuiltin.cpp | 222 ++++++++++++++++----- clang/lib/CodeGen/CGCall.cpp | 9 +- clang/lib/CodeGen/CodeGenFunction.h | 5 +- clang/test/CodeGen/fp-accuracy.c | 292 ++++++++++++++++++++++++---- clang/test/Driver/fp-accuracy.c | 9 +- 5 files changed, 439 insertions(+), 98 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 5826bf339f280..82d37192d506b 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -548,12 +548,35 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin( // Emit an intrinsic that has 2 operands of the same type as its result. // Depending on mode, this may be a constrained floating-point intrinsic. -static Value *emitBinaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, - const CallExpr *E, unsigned IntrinsicID, - unsigned ConstrainedIntrinsicID) { +static Value *emitBinaryMaybeConstrainedFPBuiltin( + CodeGenFunction &CGF, const CallExpr *E, unsigned IntrinsicID, + unsigned ConstrainedIntrinsicID, + unsigned FPAccuracyIntrinsicID = Intrinsic::not_intrinsic) { llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1)); - + if (CGF.CGM.getCodeGenOpts().FPAccuracy) { + unsigned BuiltinID = CGF.getCurrentBuiltinID(); + StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); + Function *Func; + // Use fpbuiltin intrinsic only when needed. + bool HasAccuracyRequirement = false; + if (!CGF.getLangOpts().FPAccuracyVal.empty()) + HasAccuracyRequirement = true; + for (auto F : CGF.getLangOpts().FPAccuracyFuncMap) { + auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); + if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) + if (FuncMapIt->first == Name) { + HasAccuracyRequirement = true; + break; + } + } + if (HasAccuracyRequirement) + Func = CGF.CGM.getIntrinsic(FPAccuracyIntrinsicID, Src0->getType()); + else + Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0, Src1}, + FPAccuracyIntrinsicID); + } if (CGF.Builder.getIsFPConstrained()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E); Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); @@ -2329,9 +2352,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_expf16: case Builtin::BI__builtin_expl: case Builtin::BI__builtin_expf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::exp, - Intrinsic::experimental_constrained_exp)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::exp, Intrinsic::experimental_constrained_exp, + Intrinsic::fpbuiltin_exp)); case Builtin::BIexp2: case Builtin::BIexp2f: @@ -2341,9 +2364,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_exp2f16: case Builtin::BI__builtin_exp2l: case Builtin::BI__builtin_exp2f128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::exp2, - Intrinsic::experimental_constrained_exp2)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::exp2, Intrinsic::experimental_constrained_exp2, + Intrinsic::fpbuiltin_exp2)); case Builtin::BIfabs: case Builtin::BIfabsf: @@ -2427,9 +2450,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_logf16: case Builtin::BI__builtin_logl: case Builtin::BI__builtin_logf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::log, - Intrinsic::experimental_constrained_log)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::log, Intrinsic::experimental_constrained_log, + Intrinsic::fpbuiltin_log)); case Builtin::BIlog10: case Builtin::BIlog10f: @@ -2439,9 +2462,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_log10f16: case Builtin::BI__builtin_log10l: case Builtin::BI__builtin_log10f128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::log10, - Intrinsic::experimental_constrained_log10)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::log10, Intrinsic::experimental_constrained_log10, + Intrinsic::fpbuiltin_log10)); case Builtin::BIlog2: case Builtin::BIlog2f: @@ -2451,9 +2474,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_log2f16: case Builtin::BI__builtin_log2l: case Builtin::BI__builtin_log2f128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::log2, - Intrinsic::experimental_constrained_log2)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::log2, Intrinsic::experimental_constrained_log2, + Intrinsic::fpbuiltin_log2)); case Builtin::BInearbyint: case Builtin::BInearbyintf: @@ -2474,9 +2497,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_powf16: case Builtin::BI__builtin_powl: case Builtin::BI__builtin_powf128: - return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::pow, - Intrinsic::experimental_constrained_pow)); + return RValue::get(emitBinaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::pow, Intrinsic::experimental_constrained_pow, + Intrinsic::fpbuiltin_pow)); case Builtin::BIrint: case Builtin::BIrintf: @@ -2534,9 +2557,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_sqrtf16: case Builtin::BI__builtin_sqrtl: case Builtin::BI__builtin_sqrtf128: - return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, - Intrinsic::sqrt, - Intrinsic::experimental_constrained_sqrt)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::sqrt, Intrinsic::experimental_constrained_sqrt, + Intrinsic::fpbuiltin_sqrt)); case Builtin::BItrunc: case Builtin::BItruncf: @@ -21866,39 +21889,136 @@ RValue CodeGenFunction::EmitIntelFPGAMemBuiltin(const CallExpr *E) { return RValue::get(Ann); } -RValue CodeGenFunction::EmitFPBuiltinIndirectCall( +llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( llvm::FunctionType *IRFuncTy, const SmallVectorImpl &IRArgs, - llvm::Value *FnPtr) { + llvm::Value *FnPtr, const Decl *TargetDecl) { llvm::Function *Func; unsigned FPAccuracyIntrinsicID = 0; - llvm::CallInst *CI; - if (FnPtr->getName() == "sincos") { - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; - Func = CGM.getIntrinsic(FPAccuracyIntrinsicID, IRArgs[0]->getType()); - CI = CreateBuiltinCallWithAttr(*this, FnPtr->getName(), Func, - {IRArgs[0], IRArgs[1], IRArgs[2]}, - FPAccuracyIntrinsicID); - } else { - unsigned BuiltinID = getCurrentBuiltinID(); - StringRef Name = CGM.getContext().BuiltinInfo.getName(BuiltinID); - unsigned FPAccuracyIntrinsicID = 0; - switch (BuiltinID) { - case Builtin::BItan: - case Builtin::BItanf: - case Builtin::BItanh: - case Builtin::BItanhf: - case Builtin::BItanhl: - case Builtin::BItanl: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_tan; - break; + llvm::CallInst *CI = nullptr; + StringRef Name; + if (CurrentBuiltinID == 0) { + // Even if the current function doesn't have a clang builtin, create + // an 'fpbuiltin-max-error' attribute for it; unless it's marked with + // an NoBuiltin attribute. + if (const FunctionDecl *FD = dyn_cast_or_null(TargetDecl)) { + if (!FD->hasAttr()) { + Name = FD->getName(); + if (Name == "fadd") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fadd; + else if (Name == "fdiv") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fdiv; + else if (Name == "fmul") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fmul; + else if (Name == "fsub") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fsub; + else if (Name == "frem") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_frem; + else if (Name == "sincos") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; + else if (Name == "exp10") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_exp10; + else if (Name == "rsqrt") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_rsqrt; + else + llvm_unreachable("unexpected fpbuiltin ID"); + } + } + } else { + // The function has a clang builtin. Create an attribute for it + // only if it has an fpbuiltin intrinsic. + unsigned BuiltinID = getCurrentBuiltinID(); + Name = CGM.getContext().BuiltinInfo.getName(BuiltinID); + switch (BuiltinID) { + default: + break; + case Builtin::BItan: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_tan; + break; + case Builtin::BItanh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_tanh; + break; + case Builtin::BIlog2: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_log2; + break; + case Builtin::BIlog1p: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_log1p; + break; + case Builtin::BIcosh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_cosh; + break; + case Builtin::BIacos: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_acos; + break; + case Builtin::BIacosh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_acosh; + break; + case Builtin::BIsinh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_sinh; + break; + case Builtin::BIasin: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_asin; + break; + case Builtin::BIasinh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_asinh; + break; + case Builtin::BIatan: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_atan; + break; + case Builtin::BIatanh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_atanh; + break; + case Builtin::BIatan2: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_atan2; + break; + case Builtin::BIerf: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_erf; + break; + case Builtin::BIerfc: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_erfc; + break; + case Builtin::BIexp: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_exp; + break; + case Builtin::BIexp2: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_exp2; + break; + case Builtin::BIexpm1: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_expm1; + break; + case Builtin::BIhypot: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_hypot; + break; + case Builtin::BIldexp: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_ldexp; + break; + } } + if (FPAccuracyIntrinsicID == 0) + // If the function has a clang builtin but doesn't have an + // fpbuiltin, it will be generated with no 'fpbuiltin-max-error' + // attribute. + return nullptr; Func = CGM.getIntrinsic(FPAccuracyIntrinsicID, IRArgs[0]->getType()); - CI = CreateBuiltinCallWithAttr(*this, Name, Func, {IRArgs[0]}, - FPAccuracyIntrinsicID); - } - return RValue::get(CI); + if (IRArgs.size() == 1) + CI = CreateBuiltinCallWithAttr(*this, Name, Func, {IRArgs[0]}, + FPAccuracyIntrinsicID); + else if (IRArgs.size() == 2) + CI = CreateBuiltinCallWithAttr(*this, FnPtr->getName(), Func, + {IRArgs[0], IRArgs[1]}, + FPAccuracyIntrinsicID); + + else if (IRArgs.size() == 3) + CI = CreateBuiltinCallWithAttr(*this, FnPtr->getName(), Func, + {IRArgs[0], IRArgs[1], IRArgs[2]}, + FPAccuracyIntrinsicID); + else + llvm_unreachable( + "Not expecting an fpbuiltin intrinsic with more than 3 arguments"); + + return CI; } + Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index d3612906c6385..8e696090f22b4 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -5518,8 +5518,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // Emit the actual call/invoke instruction. llvm::CallBase *CI; if (!InvokeDest) { - if (CGM.getCodeGenOpts().FPAccuracy) - return EmitFPBuiltinIndirectCall(IRFuncTy, IRCallArgs, CalleePtr); + if (CGM.getCodeGenOpts().FPAccuracy) { + if (const FunctionDecl *FD = dyn_cast_or_null(TargetDecl)) + CI = EmitFPBuiltinIndirectCall(IRFuncTy, IRCallArgs, CalleePtr, + TargetDecl); + if (CI) + return RValue::get(CI); + } CI = Builder.CreateCall(IRFuncTy, CalleePtr, IRCallArgs, BundleList); } else { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index b97e96b1e7e44..ae091a4c5453b 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4306,9 +4306,10 @@ class CodeGenFunction : public CodeGenTypeCache { ReturnValueSlot ReturnValue); RValue EmitIntelFPGAMemBuiltin(const CallExpr *E); - RValue EmitFPBuiltinIndirectCall(llvm::FunctionType *IRFuncTy, + llvm::CallInst *EmitFPBuiltinIndirectCall( + llvm::FunctionType *IRFuncTy, const SmallVectorImpl &IRArgs, - llvm::Value *FnPtr); + llvm::Value *FnPtr, const Decl *TargetDecl); enum class MSVCIntrin; llvm::Value *EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID, const CallExpr *E); diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index 63b86daa4f7a6..ba7ee316a1271 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -1,69 +1,277 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-builtin-accuracy=high \ // RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ -// RUN: | FileCheck %s +// RUN: | FileCheck --check-prefixes=CHECK %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ -// RUN: "-ffp-builtin-accuracy=high:[sin,cosf] low:[tan] medium:[sincos]" \ +// RUN: "-ffp-builtin-accuracy=high:[cosf] low:[tan] medium:[sincos,log10]" \ // RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ -// RUN: | FileCheck --check-prefix=CHECK-FUNC-1 %s +// RUN: | FileCheck --check-prefix=CHECK-F1 %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ // RUN: "-ffp-builtin-accuracy=medium high:[tan] cuda:[cos]" \ // RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ -// RUN: | FileCheck --check-prefix=CHECK-FUNC-2 %s +// RUN: | FileCheck --check-prefix=CHECK-F2 %s // RUN: %clang_cc1 -triple spir64-unknown-unknown -ffp-builtin-accuracy=sycl \ // RUN: -D SPIR -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CHECK-SPIR %s #ifdef SPIR +// This is a declaration when compiling with -fsycl to avoid +// the compilation error "function with no prototype cannot use +// the spir_function calling convention". void sincos(float, float *, float *); +double exp10(double); +double fadd(double, double); +float fdiv(float, float); +float fmul(float, float); +float frem(float, float); +float fsub(float, float); +double rsqrt(double); #endif -void foo(float f1, float f2) { - // CHECK-LABEL: define {{.*}}void @foo(float noundef {{.*}}, float noundef {{.*}}) - float sin = 0.f, cos = 0.f; - - f2 = cosf(f1); - f2 = sinf(f1); - f2 = tan(f1); - f2 = tanf(f1); - sincos(f1, &sin, &cos); - // CHECK: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_HIGH:#[0-9]+]] - // CHECK: call float @llvm.fpbuiltin.sin.f32(float {{.*}}) [[ATTR_HIGH]] - // CHECK: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_HIGH]] - // CHECK: call float @llvm.fpbuiltin.tan.f32(float {{.*}}) [[ATTR_HIGH]] - // CHECK: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) [[ATTR_HIGH]] +// CHECK-LABEL: define dso_local void @f1 +// CHECK: call double @llvm.fpbuiltin.acos.f64(double {{.*}}) #[[ATTR_HIGH:[0-9]+]] +// CHECK: call double @llvm.fpbuiltin.acosh.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.asin.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.asinh.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.atan.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.atan2.f64(double {{.*}}, double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.atanh.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.cosh.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.erf.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.erfc.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.exp.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.exp10.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.exp2.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.expm1.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.fadd.f64(double {{.*}}, double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.fdiv.f64(double {{.*}}, double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.fmul.f64(double {{.*}}, double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.frem.f64(double {{.*}}, double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.fsub.f64(double {{.*}}, double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.hypot.f64(double {{.*}}, double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.ldexp.f64(double {{.*}}, i32 {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.log.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.log10.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.log1p.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.log2.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.pow.f64(double {{.*}}, double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.rsqrt.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.sinh.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.sqrt.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.tanh.f64(double {{.*}}) #[[ATTR_HIGH]] - // CHECK-FUNC-1: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_HIGH:#[0-9]+]] - // CHECK-FUNC-1: call float @llvm.sin.f32(float {{.*}}) - // CHECK-FUNC-1: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_LOW:#[0-9]+]] - // CHECK-FUNC-1: call float @llvm.fpbuiltin.tan.f32(float {{.*}}) - // CHECK-FUNC-1: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) [[ATTR_MEDIUM:#[0-9]+]] +// CHECK-F1-LABEL: define dso_local void @f1 +// CHECK-F1: call double @llvm.fpbuiltin.acos.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.acosh.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.asin.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.asinh.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.atan.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.atan2.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.atanh.f64(double {{.*}}) +// CHECK-F1: call double @llvm.cos.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.cosh.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.erf.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.erfc.f64(double {{.*}}) +// CHECK-F1: call double @llvm.exp.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.exp10.f64(double {{.*}}) +// CHECK-F1: call double @llvm.exp2.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.expm1.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.fadd.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.fdiv.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.fmul.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.frem.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.fsub.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.hypot.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.ldexp.f64(double {{.*}}, i32 {{.*}}) +// CHECK-F1: call double @llvm.log.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.log10.f64(double {{.*}}) #[[ATTR_F1_MEDIUM:[0-9]+]] +// CHECK-F1: call double @llvm.fpbuiltin.log1p.f64(double {{.*}}) +// CHECK-F1: call double @llvm.log2.f64(double {{.*}}) +// CHECK-F1: call double @llvm.pow.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.rsqrt.f64(double {{.*}}) +// CHECK-F1: call double @llvm.sin.f64(double {{.*}}) +// CHECK-F1: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_F1_MEDIUM]] +// CHECK-F1: call double @llvm.fpbuiltin.sinh.f64(double {{.*}}) +// CHECK-F1: call double @llvm.sqrt.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_F1_LOW:[0-9]+]] +// CHECK-F1: call double @llvm.fpbuiltin.tanh.f64(double {{.*}}) +// +// CHECK-F2-LABEL: define dso_local void @f1 +// CHECK-F2: call double @llvm.fpbuiltin.acos.f64(double {{.*}}) #[[ATTR_F2_MEDIUM:[0-9]+]] +// CHECK-F2: call double @llvm.fpbuiltin.acosh.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.asin.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.asinh.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.atan.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.atan2.f64(double {{.*}}, double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.atanh.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) #[[ATTR_F2_CUDA:[0-9]+]] +// CHECK-F2: call double @llvm.fpbuiltin.cosh.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.erf.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.erfc.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.exp.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.exp10.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.exp2.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.expm1.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.fadd.f64(double {{.*}}, double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.fdiv.f64(double {{.*}}, double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.fmul.f64(double {{.*}}, double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.frem.f64(double {{.*}}, double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.fsub.f64(double {{.*}}, double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.hypot.f64(double {{.*}}, double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.ldexp.f64(double {{.*}}, i32 {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.log.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.log10.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.log1p.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.log2.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.pow.f64(double {{.*}}, double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.rsqrt.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.sinh.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.sqrt.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_F2_HIGH:[0-9]+]] +// CHECK-F2: call double @llvm.fpbuiltin.tanh.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// +// CHECK-SPIR-LABEL: define dso_local spir_func void @f1 +// CHECK-SPIR: call double @llvm.fpbuiltin.acos.f64(double {{.*}}) #[[ATTR_SYCL1:[0-9]+]] +// CHECK-SPIR: call double @llvm.fpbuiltin.acosh.f64(double {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call double @llvm.fpbuiltin.asin.f64(double {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call double @llvm.fpbuiltin.asinh.f64(double {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call double @llvm.fpbuiltin.atan.f64(double {{.*}}) #[[ATTR_SYCL2:[0-9]+]] +// CHECK-SPIR: call double @llvm.fpbuiltin.atan2.f64(double {{.*}}, double {{.*}}) #[[ATTR_SYCL3:[0-9]+]] +// CHECK-SPIR: call double @llvm.fpbuiltin.atanh.f64(double {{.*}}) #[[ATTR_SYCL2]] +// CHECK-SPIR: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call double @llvm.fpbuiltin.cosh.f64(double {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call double @llvm.fpbuiltin.erf.f64(double {{.*}}) #[[ATTR_SYCL4:[0-9]+]] +// CHECK-SPIR: call double @llvm.fpbuiltin.erfc.f64(double {{.*}}) #[[ATTR_SYCL4]] +// CHECK-SPIR: call double @llvm.fpbuiltin.exp.f64(double {{.*}}) #[[ATTR_SYCL5:[0-9]+]] +// CHECK-SPIR: call double @llvm.fpbuiltin.exp10.f64(double {{.*}}) #[[ATTR_SYCL5]] +// CHECK-SPIR: call double @llvm.fpbuiltin.exp2.f64(double {{.*}}) #[[ATTR_SYCL5]] +// CHECK-SPIR: call double @llvm.fpbuiltin.expm1.f64(double {{.*}}) #[[ATTR_SYCL5]] +// CHECK-SPIR: call double @llvm.fpbuiltin.fadd.f64(double {{.*}}, double {{.*}}) #[[ATTR_SYCL6:[0-9]+]] +// CHECK-SPIR: call float @llvm.fpbuiltin.fdiv.f32(float {{.*}}, float {{.*}}) #[[ATTR_SYCL7:[0-9]+]] +// CHECK-SPIR: call float @llvm.fpbuiltin.fmul.f32(float {{.*}}, float {{.*}}) #[[ATTR_SYCL6]] +// CHECK-SPIR: call float @llvm.fpbuiltin.frem.f32(float {{.*}}, float {{.*}}) #[[ATTR_SYCL6]] +// CHECK-SPIR: call float @llvm.fpbuiltin.fsub.f32(float {{.*}}, float {{.*}}) #[[ATTR_SYCL6]] +// CHECK-SPIR: call double @llvm.fpbuiltin.hypot.f64(double {{.*}}, double {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call double @llvm.fpbuiltin.ldexp.f64(double {{.*}}, i32 {{.*}}) #[[ATTR_SYCL6]] +// CHECK-SPIR: call double @llvm.fpbuiltin.log.f64(double {{.*}}) #[[ATTR_SYCL5]] +// CHECK-SPIR: call double @llvm.fpbuiltin.log10.f64(double {{.*}}) #[[ATTR_SYCL5]] +// CHECK-SPIR: call double @llvm.fpbuiltin.log1p.f64(double {{.*}}) #[[ATTR_SYCL8:[0-9]+]] +// CHECK-SPIR: call double @llvm.fpbuiltin.log2.f64(double {{.*}}) #[[ATTR_SYCL5]] +// CHECK-SPIR: call double @llvm.fpbuiltin.pow.f64(double {{.*}}, double {{.*}}) #[[ATTR_SYCL4]] +// CHECK-SPIR: call double @llvm.fpbuiltin.rsqrt.f64(double {{.*}}) #[[ATTR_SYCL8]] +// CHECK-SPIR: call double @llvm.fpbuiltin.sin.f64(double {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call void @llvm.fpbuiltin.sincos.f32(float {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call double @llvm.fpbuiltin.sinh.f64(double {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call double @llvm.fpbuiltin.sqrt.f64(double {{.*}}) #[[ATTR_SYCL6]] +// CHECK-SPIR: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_SYCL2]] +// CHECK-SPIR: call double @llvm.fpbuiltin.tanh.f64(double {{.*}}) #[[ATTR_SYCL2]] +// +void f1(float a, float b) { + float p1 = 0.f, p2 = 0.f; - // CHECK-FUNC-2: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_MEDIUM:#[0-9]+]] - // CHECK-FUNC-2: call float @llvm.fpbuiltin.sin.f32(float {{.*}}) [[ATTR_MEDIUM]] - // CHECK-FUNC-2: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_HIGH:#[0-9]+]] - // CHECK-FUNC-2: call float @llvm.fpbuiltin.tan.f32(float {{.*}}) [[ATTR_MEDIUM]] - // CHECK-FUNC-2: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) [[ATTR_MEDIUM]] + b = acos(b); + b = acosh(b); + b = asin(b); + b = asinh(b); + b = atan(b); + b = atan2(b,b); + b = atanh(b); + b = cos(b); + b = cosh(b); + b = erf(b); + b = erfc(b); + b = exp(b); + b = exp10(b); + b = exp2(b); + b = expm1(b); + b = fadd(b,b); + b = fdiv(b,b); + b = fmul(b,b); + b = frem(b,b); + b = fsub(b,b); + b = hypot(b,b); + b = ldexp(b,b); + b = log(b); + b = log10(b); + b = log1p(b); + b = log2(b); + b = pow(b,b); + b = rsqrt(b); + b = sin(b); + sincos(b,&p1,&p2); + b = sinh(b); + b = sqrt(b); + b =tan(b); + b = tanh(b); +} +// CHECK-LABEL: define dso_local void @f2 +// CHECK: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) #[[ATTR_HIGH]] +// CHECK: call float @llvm.fpbuiltin.sin.f32(float {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call double @llvm.fpbuiltin.log10.f64(double {{.*}}) #[[ATTR_HIGH]] +// CHECK: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_HIGH]] +// CHECK: call float @tanf(float noundef {{.*}}) +// +// CHECK-F1-LABEL: define dso_local void @f2 +// CHECK-F1: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) #[[ATTR_F1_HIGH:[0-9]+]] +// CHECK-F1: call float @llvm.sin.f32(float {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_F1_LOW]] +// CHECK-F1: call double @llvm.fpbuiltin.log10.f64(double {{.*}}) #[[ATTR_F1_MEDIUM]] +// CHECK-F1: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_F1_MEDIUM]] +// CHECK-F1: call float @tanf(float noundef {{.*}}) +// +// CHECK-F2-LABEL: define dso_local void @f2 +// CHECK-F2: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call float @llvm.fpbuiltin.sin.f32(float {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_F2_HIGH]] +// CHECK-F2: call double @llvm.fpbuiltin.log10.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_F2_MEDIUM]] +// CHECK-F2: call float @tanf(float noundef {{.*}}) +// +// CHECK-SPIR-LABEL: define dso_local spir_func void @f2 +// CHECK-SPIR: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call float @llvm.fpbuiltin.sin.f32(float {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_SYCL2]] +// CHECK-SPIR: call double @llvm.fpbuiltin.log10.f64(double {{.*}}) #[[ATTR_SYCL5]] +// CHECK-SPIR: call void @llvm.fpbuiltin.sincos.f32(float {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_SYCL1]] +// CHECK-SPIR: call spir_func float @tanf(float noundef {{.*}}) - // CHECK-SPIR: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) [[ATTR_SYCL1:#[0-9]+]] - // CHECK-SPIR: call float @llvm.fpbuiltin.sin.f32(float {{.*}}) [[ATTR_SYCL1]] - // CHECK-SPIR: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) [[ATTR_SYCL2:#[0-9]+]] - // CHECK-SPIR: call float @llvm.fpbuiltin.tan.f32(float {{.*}}) [[ATTR_SYCL2]] - // CHECK-SPIR: call void @llvm.fpbuiltin.sincos.f32(float {{.*}}, ptr {{.*}}, ptr {{.*}}) [[ATTR_SYCL1]] +// Zahira +// CHECK: attributes #[[ATTR_HIGH]] = {{.*}}"fpbuiltin-max-error="="1.0f" -} +// CHECK-F1: attributes #[[ATTR_F1_MEDIUM]] = {{.*}}"fpbuiltin-max-error="="4.0f" +// CHECK-F1: attributes #[[ATTR_F1_LOW]] = {{.*}}"fpbuiltin-max-error="="67108864.0f" +// CHECK-F1: attributes #[[ATTR_F1_HIGH]] = {{.*}}"fpbuiltin-max-error="="1.0f" -// CHECK: attributes [[ATTR_HIGH]] = {{{.*}}"fpbuiltin-max-error="="1.0f" +// CHECK-F2: attributes #[[ATTR_F2_MEDIUM]] = {{.*}}"fpbuiltin-max-error="="4.0f" +// CHECK-F2: attributes #[[ATTR_F2_CUDA]] = {{.*}}"fpbuiltin-max-error="="2.0f" +// CHECK-F2: attributes #[[ATTR_F2_HIGH]] = {{.*}}"fpbuiltin-max-error="="1.0f" -// CHECK-FUNC-1: attributes [[ATTR_HIGH]] = {{{.*}}"fpbuiltin-max-error="="1.0f" -// CHECK-FUNC-1: attributes [[ATTR_LOW]] = {{{.*}}"fpbuiltin-max-error="="67108864.0f" -// CHECK-FUNC-1: attributes [[ATTR_MEDIUM]] = {{{.*}}"fpbuiltin-max-error="="4.0f" +// CHECK-SPIR: attributes #[[ATTR_SYCL1]] = {{.*}}"fpbuiltin-max-error="="4.0f" +// CHECK-SPIR: attributes #[[ATTR_SYCL2]] = {{.*}}"fpbuiltin-max-error="="5.0f" +// CHECK-SPIR: attributes #[[ATTR_SYCL3]] = {{.*}}"fpbuiltin-max-error="="6.0f" +// CHECK-SPIR: attributes #[[ATTR_SYCL4]] = {{.*}}"fpbuiltin-max-error="="16.0f" +// CHECK-SPIR: attributes #[[ATTR_SYCL5]] = {{.*}}"fpbuiltin-max-error="="3.0f" +// CHECK-SPIR: attributes #[[ATTR_SYCL6]] = {{.*}}"fpbuiltin-max-error="="0.0f" +// CHECK-SPIR: attributes #[[ATTR_SYCL7]] = {{.*}}"fpbuiltin-max-error="="2.5f" +// CHECK-SPIR: attributes #[[ATTR_SYCL8]] = {{.*}}"fpbuiltin-max-error="="2.0f" -// CHECK-FUNC-2: attributes #5 = { "fpbuiltin-max-error="="4.0f" } -// CHECK-FUNC-2: attributes #6 = { "fpbuiltin-max-error="="1.0f" } +void f2(float a, float b) { + float sin = 0.f, cos = 0.f; -// CHECK-SPIR: attributes [[ATTR_SYCL1]] = {{{.*}}"fpbuiltin-max-error="="4.0f" -// CHECK-SPIR: attributes [[ATTR_SYCL2]] = {{{.*}}"fpbuiltin-max-error="="5.0f" + b = cosf(b); + b = sinf(b); + b = tan(b); + b = log10(b); + sincos(b, &sin, &cos); + b = tanf(b); +} diff --git a/clang/test/Driver/fp-accuracy.c b/clang/test/Driver/fp-accuracy.c index 6fe4c929002fe..6474351a3e425 100644 --- a/clang/test/Driver/fp-accuracy.c +++ b/clang/test/Driver/fp-accuracy.c @@ -25,7 +25,10 @@ // RUN: not %clang -Xclang -verify -ffp-accuracy=foo:[sin,cos] \ // RUN: -ffp-accuracy=goo:[tan] %s 2>&1 \ -// RUN: | FileCheck %s --check-prefixes=CHECK-ERR +// RUN: | FileCheck %s --check-prefixes=CHECK-ERR-1 + +// RUN: not %clang -Xclang -verify -ffp-accuracy=high=[sin] %s 2>& 1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ERR-2 // CHECK-H: "-ffp-builtin-accuracy=high" // CHECK-L: "-ffp-builtin-accuracy=low" @@ -33,3 +36,7 @@ // CHECK-FUNC-1: "-ffp-builtin-accuracy=low:sin,cos" // CHECK-FUNC-2: "-ffp-builtin-accuracy=low:sin,cos high:tan" // CHECK-ERR: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' +// CHECK-ERR-1: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' +// CHECK-ERR-1: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' +// CHECK-ERR-1: (frontend): unsupported argument 'goo' to option 'ffp-accuracy' +// CHECK-ERR-2: (frontend): unsupported argument 'high=[sin]' to option 'ffp-accuracy' From 4f6089aa25e5e3b3c0baa81b77ac24a80fe7a714 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 1 May 2023 15:28:08 -0400 Subject: [PATCH 23/43] Fix format. --- clang/lib/CodeGen/CGBuiltin.cpp | 232 ++++++++++++++-------------- clang/lib/CodeGen/CodeGenFunction.h | 9 +- 2 files changed, 120 insertions(+), 121 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 82d37192d506b..96ebb4249bdee 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -571,7 +571,7 @@ static Value *emitBinaryMaybeConstrainedFPBuiltin( } } if (HasAccuracyRequirement) - Func = CGF.CGM.getIntrinsic(FPAccuracyIntrinsicID, Src0->getType()); + Func = CGF.CGM.getIntrinsic(FPAccuracyIntrinsicID, Src0->getType()); else Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0, Src1}, @@ -21897,128 +21897,126 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( llvm::CallInst *CI = nullptr; StringRef Name; if (CurrentBuiltinID == 0) { - // Even if the current function doesn't have a clang builtin, create - // an 'fpbuiltin-max-error' attribute for it; unless it's marked with - // an NoBuiltin attribute. - if (const FunctionDecl *FD = dyn_cast_or_null(TargetDecl)) { - if (!FD->hasAttr()) { - Name = FD->getName(); - if (Name == "fadd") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fadd; - else if (Name == "fdiv") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fdiv; - else if (Name == "fmul") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fmul; - else if (Name == "fsub") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fsub; - else if (Name == "frem") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_frem; - else if (Name == "sincos") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; - else if (Name == "exp10") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_exp10; - else if (Name == "rsqrt") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_rsqrt; - else - llvm_unreachable("unexpected fpbuiltin ID"); - } - } - } else { - // The function has a clang builtin. Create an attribute for it - // only if it has an fpbuiltin intrinsic. - unsigned BuiltinID = getCurrentBuiltinID(); - Name = CGM.getContext().BuiltinInfo.getName(BuiltinID); - switch (BuiltinID) { - default: - break; - case Builtin::BItan: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_tan; - break; - case Builtin::BItanh: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_tanh; - break; - case Builtin::BIlog2: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_log2; - break; - case Builtin::BIlog1p: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_log1p; - break; - case Builtin::BIcosh: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_cosh; - break; - case Builtin::BIacos: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_acos; - break; - case Builtin::BIacosh: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_acosh; - break; - case Builtin::BIsinh: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_sinh; - break; - case Builtin::BIasin: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_asin; - break; - case Builtin::BIasinh: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_asinh; - break; - case Builtin::BIatan: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_atan; - break; - case Builtin::BIatanh: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_atanh; - break; - case Builtin::BIatan2: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_atan2; - break; - case Builtin::BIerf: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_erf; - break; - case Builtin::BIerfc: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_erfc; - break; - case Builtin::BIexp: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_exp; - break; - case Builtin::BIexp2: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_exp2; - break; - case Builtin::BIexpm1: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_expm1; - break; - case Builtin::BIhypot: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_hypot; - break; - case Builtin::BIldexp: - FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_ldexp; - break; + // Even if the current function doesn't have a clang builtin, create + // an 'fpbuiltin-max-error' attribute for it; unless it's marked with + // an NoBuiltin attribute. + if (const FunctionDecl *FD = dyn_cast_or_null(TargetDecl)) { + if (!FD->hasAttr()) { + Name = FD->getName(); + if (Name == "fadd") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fadd; + else if (Name == "fdiv") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fdiv; + else if (Name == "fmul") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fmul; + else if (Name == "fsub") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fsub; + else if (Name == "frem") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_frem; + else if (Name == "sincos") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; + else if (Name == "exp10") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_exp10; + else if (Name == "rsqrt") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_rsqrt; + else + llvm_unreachable("unexpected fpbuiltin ID"); } } - if (FPAccuracyIntrinsicID == 0) - // If the function has a clang builtin but doesn't have an - // fpbuiltin, it will be generated with no 'fpbuiltin-max-error' - // attribute. - return nullptr; - Func = CGM.getIntrinsic(FPAccuracyIntrinsicID, IRArgs[0]->getType()); - if (IRArgs.size() == 1) - CI = CreateBuiltinCallWithAttr(*this, Name, Func, {IRArgs[0]}, - FPAccuracyIntrinsicID); - else if (IRArgs.size() == 2) - CI = CreateBuiltinCallWithAttr(*this, FnPtr->getName(), Func, - {IRArgs[0], IRArgs[1]}, - FPAccuracyIntrinsicID); - - else if (IRArgs.size() == 3) - CI = CreateBuiltinCallWithAttr(*this, FnPtr->getName(), Func, - {IRArgs[0], IRArgs[1], IRArgs[2]}, - FPAccuracyIntrinsicID); - else - llvm_unreachable( - "Not expecting an fpbuiltin intrinsic with more than 3 arguments"); + } else { + // The function has a clang builtin. Create an attribute for it + // only if it has an fpbuiltin intrinsic. + unsigned BuiltinID = getCurrentBuiltinID(); + Name = CGM.getContext().BuiltinInfo.getName(BuiltinID); + switch (BuiltinID) { + default: + break; + case Builtin::BItan: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_tan; + break; + case Builtin::BItanh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_tanh; + break; + case Builtin::BIlog2: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_log2; + break; + case Builtin::BIlog1p: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_log1p; + break; + case Builtin::BIcosh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_cosh; + break; + case Builtin::BIacos: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_acos; + break; + case Builtin::BIacosh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_acosh; + break; + case Builtin::BIsinh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_sinh; + break; + case Builtin::BIasin: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_asin; + break; + case Builtin::BIasinh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_asinh; + break; + case Builtin::BIatan: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_atan; + break; + case Builtin::BIatanh: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_atanh; + break; + case Builtin::BIatan2: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_atan2; + break; + case Builtin::BIerf: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_erf; + break; + case Builtin::BIerfc: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_erfc; + break; + case Builtin::BIexp: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_exp; + break; + case Builtin::BIexp2: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_exp2; + break; + case Builtin::BIexpm1: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_expm1; + break; + case Builtin::BIhypot: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_hypot; + break; + case Builtin::BIldexp: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_ldexp; + break; + } + } + if (FPAccuracyIntrinsicID == 0) + // If the function has a clang builtin but doesn't have an + // fpbuiltin, it will be generated with no 'fpbuiltin-max-error' + // attribute. + return nullptr; + Func = CGM.getIntrinsic(FPAccuracyIntrinsicID, IRArgs[0]->getType()); + if (IRArgs.size() == 1) + CI = CreateBuiltinCallWithAttr(*this, Name, Func, {IRArgs[0]}, + FPAccuracyIntrinsicID); + else if (IRArgs.size() == 2) + CI = CreateBuiltinCallWithAttr(*this, FnPtr->getName(), Func, + {IRArgs[0], IRArgs[1]}, + FPAccuracyIntrinsicID); + else if (IRArgs.size() == 3) + CI = CreateBuiltinCallWithAttr(*this, FnPtr->getName(), Func, + {IRArgs[0], IRArgs[1], IRArgs[2]}, + FPAccuracyIntrinsicID); + else + llvm_unreachable( + "Not expecting an fpbuiltin intrinsic with more than 3 arguments"); return CI; } - Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index ae091a4c5453b..6d5c6e965ab9c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4306,10 +4306,11 @@ class CodeGenFunction : public CodeGenTypeCache { ReturnValueSlot ReturnValue); RValue EmitIntelFPGAMemBuiltin(const CallExpr *E); - llvm::CallInst *EmitFPBuiltinIndirectCall( - llvm::FunctionType *IRFuncTy, - const SmallVectorImpl &IRArgs, - llvm::Value *FnPtr, const Decl *TargetDecl); + llvm::CallInst * + EmitFPBuiltinIndirectCall(llvm::FunctionType *IRFuncTy, + const SmallVectorImpl &IRArgs, + llvm::Value *FnPtr, const Decl *TargetDecl); + enum class MSVCIntrin; llvm::Value *EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID, const CallExpr *E); From 5a61b28cdbbdf1bf146ab575d75e13129d3840c5 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 1 May 2023 15:36:36 -0400 Subject: [PATCH 24/43] Fix format. --- clang/lib/CodeGen/CGBuiltin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 96ebb4249bdee..69a4eaa9c9dc6 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -22014,7 +22014,7 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( llvm_unreachable( "Not expecting an fpbuiltin intrinsic with more than 3 arguments"); - return CI; + return CI; } Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, From f02d393ee980eb14dc672e041fc3d374e8479ae5 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 1 May 2023 15:42:07 -0400 Subject: [PATCH 25/43] Fix format. --- clang/lib/CodeGen/CGBuiltin.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 69a4eaa9c9dc6..ac6f962601d0f 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -21904,23 +21904,23 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( if (!FD->hasAttr()) { Name = FD->getName(); if (Name == "fadd") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fadd; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fadd; else if (Name == "fdiv") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fdiv; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fdiv; else if (Name == "fmul") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fmul; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fmul; else if (Name == "fsub") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fsub; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fsub; else if (Name == "frem") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_frem; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_frem; else if (Name == "sincos") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; else if (Name == "exp10") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_exp10; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_exp10; else if (Name == "rsqrt") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_rsqrt; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_rsqrt; else - llvm_unreachable("unexpected fpbuiltin ID"); + llvm_unreachable("unexpected fpbuiltin ID"); } } } else { From edb89ce8c787988e3ba295a13082719282eafed2 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Fri, 5 May 2023 09:42:19 -0400 Subject: [PATCH 26/43] Added default mode. --- clang/lib/CodeGen/CGBuiltin.cpp | 92 +++++++++--------- clang/lib/CodeGen/CGCall.cpp | 16 ++- clang/lib/CodeGen/CodeGenFunction.h | 2 +- clang/lib/Driver/ToolChains/Clang.cpp | 14 ++- clang/lib/Frontend/CompilerInvocation.cpp | 8 +- clang/test/CodeGen/fp-accuracy.c | 113 ++++++++++++++++------ 6 files changed, 160 insertions(+), 85 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index ac6f962601d0f..b12478c821f1c 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -513,28 +513,30 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin( unsigned ConstrainedIntrinsicID, unsigned FPAccuracyIntrinsicID = Intrinsic::not_intrinsic) { llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); - if (CGF.CGM.getCodeGenOpts().FPAccuracy) { - unsigned BuiltinID = CGF.getCurrentBuiltinID(); - StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); - Function *Func; - // Use fpbuiltin intrinsic only when needed. - bool HasAccuracyRequirement = false; - if (!CGF.getLangOpts().FPAccuracyVal.empty()) - HasAccuracyRequirement = true; - for (auto F : CGF.getLangOpts().FPAccuracyFuncMap) { - auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); - if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) - if (FuncMapIt->first == Name) { - HasAccuracyRequirement = true; - break; - } + if (FPAccuracyIntrinsicID != Intrinsic::not_intrinsic) { + if (CGF.CGM.getCodeGenOpts().FPAccuracy) { + unsigned BuiltinID = CGF.getCurrentBuiltinID(); + StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); + Function *Func; + // Use fpbuiltin intrinsic only when needed. + bool HasAccuracyRequirement = false; + if (!CGF.getLangOpts().FPAccuracyVal.empty()) + HasAccuracyRequirement = true; + for (auto F : CGF.getLangOpts().FPAccuracyFuncMap) { + auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); + if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) + if (FuncMapIt->first == Name) { + HasAccuracyRequirement = true; + break; + } + } + if (HasAccuracyRequirement) + Func = CGF.CGM.getIntrinsic(FPAccuracyIntrinsicID, Src0->getType()); + else + Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0}, + FPAccuracyIntrinsicID); } - if (HasAccuracyRequirement) - Func = CGF.CGM.getIntrinsic(FPAccuracyIntrinsicID, Src0->getType()); - else - Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); - return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0}, - FPAccuracyIntrinsicID); } if (CGF.Builder.getIsFPConstrained()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E); @@ -2306,6 +2308,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, getContext().BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID); bool ConstWithoutExceptions = getContext().BuiltinInfo.isConstWithoutExceptions(BuiltinID); + unsigned MathErrno = getLangOpts().MathErrno; if (FD->hasAttr() || ((ConstWithoutErrnoAndExceptions || ConstWithoutExceptions) && (!ConstWithoutErrnoAndExceptions || (!getLangOpts().MathErrno)))) { @@ -21891,7 +21894,7 @@ RValue CodeGenFunction::EmitIntelFPGAMemBuiltin(const CallExpr *E) { llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( llvm::FunctionType *IRFuncTy, const SmallVectorImpl &IRArgs, - llvm::Value *FnPtr, const Decl *TargetDecl) { + llvm::Value *FnPtr, const FunctionDecl *FD) { llvm::Function *Func; unsigned FPAccuracyIntrinsicID = 0; llvm::CallInst *CI = nullptr; @@ -21900,28 +21903,26 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( // Even if the current function doesn't have a clang builtin, create // an 'fpbuiltin-max-error' attribute for it; unless it's marked with // an NoBuiltin attribute. - if (const FunctionDecl *FD = dyn_cast_or_null(TargetDecl)) { - if (!FD->hasAttr()) { - Name = FD->getName(); - if (Name == "fadd") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fadd; - else if (Name == "fdiv") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fdiv; - else if (Name == "fmul") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fmul; - else if (Name == "fsub") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fsub; - else if (Name == "frem") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_frem; - else if (Name == "sincos") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; - else if (Name == "exp10") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_exp10; - else if (Name == "rsqrt") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_rsqrt; - else - llvm_unreachable("unexpected fpbuiltin ID"); - } + if (!FD->hasAttr()) { + Name = FD->getName(); + if (Name == "fadd") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fadd; + else if (Name == "fdiv") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fdiv; + else if (Name == "fmul") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fmul; + else if (Name == "fsub") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fsub; + else if (Name == "frem") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_frem; + else if (Name == "sincos") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; + else if (Name == "exp10") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_exp10; + else if (Name == "rsqrt") + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_rsqrt; + else + llvm_unreachable("unexpected fpbuiltin ID"); } } else { // The function has a clang builtin. Create an attribute for it @@ -21943,6 +21944,9 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( case Builtin::BIlog1p: FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_log1p; break; + case Builtin::BIcos: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_cos; + break; case Builtin::BIcosh: FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_cosh; break; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 8e696090f22b4..189e876038f62 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -5516,12 +5516,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Attrs = AllocAlignAttrEmitter.TryEmitAsCallSiteAttribute(Attrs); // Emit the actual call/invoke instruction. - llvm::CallBase *CI; + llvm::CallBase *CI = nullptr; if (!InvokeDest) { if (CGM.getCodeGenOpts().FPAccuracy) { - if (const FunctionDecl *FD = dyn_cast_or_null(TargetDecl)) - CI = EmitFPBuiltinIndirectCall(IRFuncTy, IRCallArgs, CalleePtr, - TargetDecl); + const FunctionDecl *FD = dyn_cast_or_null(TargetDecl); + assert(FD && "expecting a function"); + if (!getLangOpts().FPAccuracyVal.empty()) + CI = EmitFPBuiltinIndirectCall(IRFuncTy, IRCallArgs, CalleePtr, FD); + if (!getLangOpts().FPAccuracyFuncMap.empty()) { + auto FuncMapIt = + getLangOpts().FPAccuracyFuncMap.find(FD->getName().str()); + if (FuncMapIt != getLangOpts().FPAccuracyFuncMap.end()) { + CI = EmitFPBuiltinIndirectCall(IRFuncTy, IRCallArgs, CalleePtr, FD); + } + } if (CI) return RValue::get(CI); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 6d5c6e965ab9c..b998b1784d450 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4309,7 +4309,7 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::CallInst * EmitFPBuiltinIndirectCall(llvm::FunctionType *IRFuncTy, const SmallVectorImpl &IRArgs, - llvm::Value *FnPtr, const Decl *TargetDecl); + llvm::Value *FnPtr, const FunctionDecl *FD); enum class MSVCIntrin; llvm::Value *EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID, const CallExpr *E); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index fc32ed61b703b..b350db4386fd0 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6007,11 +6007,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, std::string FpAccuracyAttr; auto RenderFPAccuracyOptions = [&FpAccuracyAttr](const Twine &optStr) { - if (FpAccuracyAttr.empty()) - FpAccuracyAttr = std::move(std::string("-ffp-builtin-accuracy=")); - else - FpAccuracyAttr += " "; - FpAccuracyAttr += optStr.str(); + // In case the value is 'default' don't add the -ffp-builtin-accuracy + // attribute. + if (optStr.str() != "default") { + if (FpAccuracyAttr.empty()) + FpAccuracyAttr = std::move(std::string("-ffp-builtin-accuracy=")); + else + FpAccuracyAttr += " "; + FpAccuracyAttr += optStr.str(); + } }; for (StringRef A : Args.getAllArgValues(options::OPT_ffp_accuracy_EQ)) RenderFPAccuracyOptions(A); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 9803077b0c3b3..b1078dfd2cabf 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3621,7 +3621,13 @@ void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) Diags.Report(diag::err_drv_unsupported_option_argument) << "ffp-accuracy" << FPAccuracy; - Opts.FPAccuracyFuncMap.insert({FuncName.str(), FPAccuracy.str()}); + if (!Opts.FPAccuracyVal.empty()) + Diags.Report(diag::warn_function_fp_accuracy_already_set) + << Opts.FPAccuracyVal << FuncName.str(); + // No need to fill the map if the FPaccuracy is 'default'. + // The default builtin will be generated. + if (!FPAccuracy.equals("default")) + Opts.FPAccuracyFuncMap.insert({FuncName.str(), FPAccuracy.str()}); } } } diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index ba7ee316a1271..197b365348cf7 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -3,7 +3,7 @@ // RUN: | FileCheck --check-prefixes=CHECK %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ -// RUN: "-ffp-builtin-accuracy=high:[cosf] low:[tan] medium:[sincos,log10]" \ +// RUN: "-ffp-builtin-accuracy=high:[acosf,cos,pow] low:[tan] medium:[sincos,log10]" \ // RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CHECK-F1 %s @@ -16,6 +16,15 @@ // RUN: -D SPIR -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CHECK-SPIR %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown \ +// RUN: "-ffp-builtin-accuracy=default:[acosf,cos,pow]" \ +// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes=CHECK-DEFAULT %s + +// RUN: %clang_cc1 -triple x86_64-unknown-unknown \ +// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes=CHECK-DEFAULT %s + #ifdef SPIR // This is a declaration when compiling with -fsycl to avoid // the compilation error "function with no prototype cannot use @@ -68,40 +77,41 @@ double rsqrt(double); // CHECK: call double @llvm.fpbuiltin.tanh.f64(double {{.*}}) #[[ATTR_HIGH]] // CHECK-F1-LABEL: define dso_local void @f1 -// CHECK-F1: call double @llvm.fpbuiltin.acos.f64(double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.acosh.f64(double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.asin.f64(double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.asinh.f64(double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.atan.f64(double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.atan2.f64(double {{.*}}, double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.atanh.f64(double {{.*}}) -// CHECK-F1: call double @llvm.cos.f64(double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.cosh.f64(double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.erf.f64(double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.erfc.f64(double {{.*}}) +// CHECK-F1: call double @acos(double noundef {{.*}}) +// CHECK-F1: call double @acosh(double noundef {{.*}}) +// CHECK-F1: call double @asin(double noundef {{.*}}) +// CHECK-F1: call double @asinh(double noundef {{.*}}) +// CHECK-F1: call double @atan(double noundef {{.*}}) +// CHECK-F1: call double @atan2(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-F1: call double @atanh(double noundef {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) #[[ATTR_F1_HIGH:[0-9]+]] +// CHECK-F1: call double @cosh(double noundef {{.*}}) +// CHECK-F1: call double @erf(double noundef {{.*}}) +// CHECK-F1: call double @erfc(double noundef {{.*}}) // CHECK-F1: call double @llvm.exp.f64(double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.exp10.f64(double {{.*}}) +// CHECK-F1: call i32 (double, ...) @exp10(double noundef {{.*}}) // CHECK-F1: call double @llvm.exp2.f64(double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.expm1.f64(double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.fadd.f64(double {{.*}}, double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.fdiv.f64(double {{.*}}, double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.fmul.f64(double {{.*}}, double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.frem.f64(double {{.*}}, double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.fsub.f64(double {{.*}}, double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.hypot.f64(double {{.*}}, double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.ldexp.f64(double {{.*}}, i32 {{.*}}) +// CHECK-F1: call double @expm1(double noundef {{.*}}) +// CHECK-F1: call i32 (double, double, ...) @fadd(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-F1: call i32 (double, double, ...) @fdiv(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-F1: call i32 (double, double, ...) @fmul(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-F1: call i32 (double, double, ...) @frem(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-F1: call i32 (double, double, ...) @fsub(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-F1: call double @hypot(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-F1: call double @ldexp(double noundef {{.*}}, i32 noundef {{.*}}) // CHECK-F1: call double @llvm.log.f64(double {{.*}}) // CHECK-F1: call double @llvm.fpbuiltin.log10.f64(double {{.*}}) #[[ATTR_F1_MEDIUM:[0-9]+]] -// CHECK-F1: call double @llvm.fpbuiltin.log1p.f64(double {{.*}}) +// CHECK-F1: call double @log1p(double noundef {{.*}}) // CHECK-F1: call double @llvm.log2.f64(double {{.*}}) -// CHECK-F1: call double @llvm.pow.f64(double {{.*}}, double {{.*}}) -// CHECK-F1: call double @llvm.fpbuiltin.rsqrt.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.pow.f64(double {{.*}}, double {{.*}}) #[[ATTR_F1_HIGH]] +// CHECK-F1: call i32 (double, ...) @rsqrt(double noundef {{.*}}) // CHECK-F1: call double @llvm.sin.f64(double {{.*}}) -// CHECK-F1: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_F1_MEDIUM]] -// CHECK-F1: call double @llvm.fpbuiltin.sinh.f64(double {{.*}}) + +// CHECK-F1: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_F1_MEDIUM]] +// CHECK-F1: call double @sinh(double noundef {{.*}}) // CHECK-F1: call double @llvm.sqrt.f64(double {{.*}}) // CHECK-F1: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_F1_LOW:[0-9]+]] -// CHECK-F1: call double @llvm.fpbuiltin.tanh.f64(double {{.*}}) +// CHECK-F1: call double @tanh(double noundef {{.*}}) // // CHECK-F2-LABEL: define dso_local void @f1 // CHECK-F2: call double @llvm.fpbuiltin.acos.f64(double {{.*}}) #[[ATTR_F2_MEDIUM:[0-9]+]] @@ -222,7 +232,7 @@ void f1(float a, float b) { // CHECK: call float @tanf(float noundef {{.*}}) // // CHECK-F1-LABEL: define dso_local void @f2 -// CHECK-F1: call float @llvm.fpbuiltin.cos.f32(float {{.*}}) #[[ATTR_F1_HIGH:[0-9]+]] +// CHECK-F1: call float @llvm.cos.f32(float {{.*}}) // CHECK-F1: call float @llvm.sin.f32(float {{.*}}) // CHECK-F1: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_F1_LOW]] // CHECK-F1: call double @llvm.fpbuiltin.log10.f64(double {{.*}}) #[[ATTR_F1_MEDIUM]] @@ -245,12 +255,11 @@ void f1(float a, float b) { // CHECK-SPIR: call void @llvm.fpbuiltin.sincos.f32(float {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_SYCL1]] // CHECK-SPIR: call spir_func float @tanf(float noundef {{.*}}) -// Zahira // CHECK: attributes #[[ATTR_HIGH]] = {{.*}}"fpbuiltin-max-error="="1.0f" +// CHECK-F1: attributes #[[ATTR_F1_HIGH]] = {{.*}}"fpbuiltin-max-error="="1.0f" // CHECK-F1: attributes #[[ATTR_F1_MEDIUM]] = {{.*}}"fpbuiltin-max-error="="4.0f" // CHECK-F1: attributes #[[ATTR_F1_LOW]] = {{.*}}"fpbuiltin-max-error="="67108864.0f" -// CHECK-F1: attributes #[[ATTR_F1_HIGH]] = {{.*}}"fpbuiltin-max-error="="1.0f" // CHECK-F2: attributes #[[ATTR_F2_MEDIUM]] = {{.*}}"fpbuiltin-max-error="="4.0f" // CHECK-F2: attributes #[[ATTR_F2_CUDA]] = {{.*}}"fpbuiltin-max-error="="2.0f" @@ -265,6 +274,50 @@ void f1(float a, float b) { // CHECK-SPIR: attributes #[[ATTR_SYCL7]] = {{.*}}"fpbuiltin-max-error="="2.5f" // CHECK-SPIR: attributes #[[ATTR_SYCL8]] = {{.*}}"fpbuiltin-max-error="="2.0f" +// CHECK-DEFAULT-LABEL: define dso_local void @f1 +// CHECK-DEFAULT: call double @acos(double noundef {{.*}}) +// CHECK-DEFAULT: call double @acosh(double noundef {{.*}}) +// CHECK-DEFAULT: call double @asin(double noundef {{.*}}) +// CHECK-DEFAULT: call double @asinh(double noundef {{.*}}) +// CHECK-DEFAULT: call double @atan(double noundef {{.*}}) +// CHECK-DEFAULT: call double @atan2(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-DEFAULT: call double @atanh(double noundef {{.*}}) +// CHECK-DEFAULT: call double @llvm.cos.f64(double {{.*}}) +// CHECK-DEFAULT: call double @cosh(double noundef {{.*}}) +// CHECK-DEFAULT: call double @erf(double noundef {{.*}}) +// CHECK-DEFAULT: call double @erfc(double noundef {{.*}}) +// CHECK-DEFAULT: call double @llvm.exp.f64(double {{.*}}) +// CHECK-DEFAULT: call i32 (double, ...) @exp10(double noundef {{.*}}) +// CHECK-DEFAULT: call double @llvm.exp2.f64(double {{.*}}) +// CHECK-DEFAULT: call double @expm1(double noundef {{.*}}) +// CHECK-DEFAULT: call i32 (double, double, ...) @fadd(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-DEFAULT: call i32 (double, double, ...) @fdiv(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-DEFAULT: call i32 (double, double, ...) @fmul(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-DEFAULT: call i32 (double, double, ...) @frem(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-DEFAULT: call i32 (double, double, ...) @fsub(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-DEFAULT: call double @hypot(double noundef {{.*}}, double noundef {{.*}}) +// CHECK-DEFAULT: call double @ldexp(double noundef {{.*}}, i32 noundef {{.*}}) +// CHECK-DEFAULT: call double @llvm.log.f64(double {{.*}}) +// CHECK-DEFAULT: call double @llvm.log10.f64(double {{.*}}) +// CHECK-DEFAULT: call double @log1p(double noundef {{.*}}) +// CHECK-DEFAULT: call double @llvm.log2.f64(double {{.*}}) +// CHECK-DEFAULT: call double @llvm.pow.f64(double {{.*}}, double {{.*}}) +// CHECK-DEFAULT: call i32 (double, ...) @rsqrt(double noundef {{.*}}) +// CHECK-DEFAULT: call double @llvm.sin.f64(double {{.*}}) +// CHECK-DEFAULT: call i32 (double, ptr, ptr, ...) @sincos(double noundef {{.*}}, ptr noundef {{.*}}, ptr noundef {{.*}}) +// CHECK-DEFAULT: call double @sinh(double noundef {{.*}}) +// CHECK-DEFAULT: call double @llvm.sqrt.f64(double {{.*}}) +// CHECK-DEFAULT: call double @tan(double noundef {{.*}}) +// CHECK-DEFAULT: call double @tanh(double noundef {{.*}}) +// +// CHECK-DEFAULT-LABEL: define dso_local void @f2 +// CHECK-DEFAULT: call float @llvm.cos.f32(float {{.*}}) +// CHECK-DEFAULT: call float @llvm.sin.f32(float {{.*}}) +// CHECK-DEFAULT: call double @tan(double noundef {{.*}}) +// CHECK-DEFAULT: call double @llvm.log10.f64(double {{.*}}) +// CHECK-DEFAULT: call i32 (double, ptr, ptr, ...) @sincos(double noundef {{.*}}, ptr noundef {{.*}}, ptr noundef {{.*}}) +// CHECK-DEFAULT: call float @tanf(float noundef {{.*}}) + void f2(float a, float b) { float sin = 0.f, cos = 0.f; From ec3be135d12f4c2ba035538c5300f64bb5ef2c7e Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Fri, 5 May 2023 16:53:45 -0400 Subject: [PATCH 27/43] Responded to reviews. --- clang/lib/CodeGen/CGBuiltin.cpp | 18 ++++++++--- clang/lib/CodeGen/CGCall.cpp | 30 +++++++++--------- clang/test/CodeGen/fp-accuracy.c | 47 ++++++++++++++--------------- clang/test/Driver/fp-accuracy.c | 6 ++++ llvm/include/llvm/IR/FPAccuracy.def | 5 +-- llvm/include/llvm/IR/FPAccuracy.h | 5 --- llvm/lib/IR/FPAccuracy.cpp | 16 +++++----- 7 files changed, 66 insertions(+), 61 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index b12478c821f1c..39f8f3a4be150 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -505,6 +505,14 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, StringRef Name, return CI; } +Function *getIntrinsic(CodeGenFunction &CGF, llvm::Value *Src0, + unsigned FPIntrinsicID, unsigned IntrinsicID, + bool HasAccuracyRequirement) { + return HasAccuracyRequirement + ? CGF.CGM.getIntrinsic(FPIntrinsicID, Src0->getType()) + : CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); +} + // Emit a simple mangled intrinsic that has 1 argument and a return type // matching the argument type. Depending on mode, this may be a constrained // or an fpbuiltin floating-point intrinsic. @@ -530,10 +538,8 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin( break; } } - if (HasAccuracyRequirement) - Func = CGF.CGM.getIntrinsic(FPAccuracyIntrinsicID, Src0->getType()); - else - Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + Func = getIntrinsic(CGF, Src0, FPAccuracyIntrinsicID, IntrinsicID, + HasAccuracyRequirement); return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0}, FPAccuracyIntrinsicID); } @@ -2308,7 +2314,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, getContext().BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID); bool ConstWithoutExceptions = getContext().BuiltinInfo.isConstWithoutExceptions(BuiltinID); - unsigned MathErrno = getLangOpts().MathErrno; if (FD->hasAttr() || ((ConstWithoutErrnoAndExceptions || ConstWithoutExceptions) && (!ConstWithoutErrnoAndExceptions || (!getLangOpts().MathErrno)))) { @@ -21956,6 +21961,9 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( case Builtin::BIacosh: FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_acosh; break; + case Builtin::BIsin: + FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_sin; + break; case Builtin::BIsinh: FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_sinh; break; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 189e876038f62..d87cafd3a6bc1 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1856,12 +1856,8 @@ llvm::fp::FPAccuracy convertFPAccuracy(StringRef FPAccuracy) { void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( StringRef Name, llvm::AttrBuilder &FuncAttrs, unsigned ID, const llvm::Type *FuncType) { - if (!getLangOpts().FPAccuracyVal.empty()) { - StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( - ID, FuncType, convertFPAccuracy(getLangOpts().FPAccuracyVal)); - assert(!FPAccuracyVal.empty() && "A valid accuracy value is expected"); - FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); - } + // First check that a specific accuracy hasn't been requested for this + // function. if (!getLangOpts().FPAccuracyFuncMap.empty()) { auto FuncMapIt = getLangOpts().FPAccuracyFuncMap.find(Name.str()); if (FuncMapIt != getLangOpts().FPAccuracyFuncMap.end()) { @@ -1871,6 +1867,18 @@ void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); } } + if (!getLangOpts().FPAccuracyVal.empty()) { + StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( + ID, FuncType, convertFPAccuracy(getLangOpts().FPAccuracyVal)); + assert(!FPAccuracyVal.empty() && "A valid accuracy value is expected"); + if (FuncAttrs.attrs().size() == 0) + // No specific accuracy has been requested for this function. + // Add the general accuracy value to the attribute list. + FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); + else + assert(FuncAttrs.attrs().size() == 1 && + "Expected an attribute has already been mapped to the function"); + } } void CodeGenModule::getDefaultFunctionAttributes(StringRef Name, @@ -5521,15 +5529,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (CGM.getCodeGenOpts().FPAccuracy) { const FunctionDecl *FD = dyn_cast_or_null(TargetDecl); assert(FD && "expecting a function"); - if (!getLangOpts().FPAccuracyVal.empty()) - CI = EmitFPBuiltinIndirectCall(IRFuncTy, IRCallArgs, CalleePtr, FD); - if (!getLangOpts().FPAccuracyFuncMap.empty()) { - auto FuncMapIt = - getLangOpts().FPAccuracyFuncMap.find(FD->getName().str()); - if (FuncMapIt != getLangOpts().FPAccuracyFuncMap.end()) { - CI = EmitFPBuiltinIndirectCall(IRFuncTy, IRCallArgs, CalleePtr, FD); - } - } + CI = EmitFPBuiltinIndirectCall(IRFuncTy, IRCallArgs, CalleePtr, FD); if (CI) return RValue::get(CI); } diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index 197b365348cf7..8aeb1c9e3b801 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -77,41 +77,40 @@ double rsqrt(double); // CHECK: call double @llvm.fpbuiltin.tanh.f64(double {{.*}}) #[[ATTR_HIGH]] // CHECK-F1-LABEL: define dso_local void @f1 -// CHECK-F1: call double @acos(double noundef {{.*}}) -// CHECK-F1: call double @acosh(double noundef {{.*}}) -// CHECK-F1: call double @asin(double noundef {{.*}}) -// CHECK-F1: call double @asinh(double noundef {{.*}}) -// CHECK-F1: call double @atan(double noundef {{.*}}) -// CHECK-F1: call double @atan2(double noundef {{.*}}, double noundef {{.*}}) -// CHECK-F1: call double @atanh(double noundef {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.acos.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.acosh.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.asin.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.asinh.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.atan.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.atan2.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.atanh.f64(double {{.*}}) // CHECK-F1: call double @llvm.fpbuiltin.cos.f64(double {{.*}}) #[[ATTR_F1_HIGH:[0-9]+]] -// CHECK-F1: call double @cosh(double noundef {{.*}}) -// CHECK-F1: call double @erf(double noundef {{.*}}) -// CHECK-F1: call double @erfc(double noundef {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.cosh.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.erf.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.erfc.f64(double {{.*}}) // CHECK-F1: call double @llvm.exp.f64(double {{.*}}) -// CHECK-F1: call i32 (double, ...) @exp10(double noundef {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.exp10.f64(double {{.*}}) // CHECK-F1: call double @llvm.exp2.f64(double {{.*}}) -// CHECK-F1: call double @expm1(double noundef {{.*}}) -// CHECK-F1: call i32 (double, double, ...) @fadd(double noundef {{.*}}, double noundef {{.*}}) -// CHECK-F1: call i32 (double, double, ...) @fdiv(double noundef {{.*}}, double noundef {{.*}}) -// CHECK-F1: call i32 (double, double, ...) @fmul(double noundef {{.*}}, double noundef {{.*}}) -// CHECK-F1: call i32 (double, double, ...) @frem(double noundef {{.*}}, double noundef {{.*}}) -// CHECK-F1: call i32 (double, double, ...) @fsub(double noundef {{.*}}, double noundef {{.*}}) -// CHECK-F1: call double @hypot(double noundef {{.*}}, double noundef {{.*}}) -// CHECK-F1: call double @ldexp(double noundef {{.*}}, i32 noundef {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.expm1.f64(double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.fadd.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.fdiv.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.fmul.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.frem.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.fsub.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.hypot.f64(double {{.*}}, double {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.ldexp.f64(double {{.*}}, i32 {{.*}}) // CHECK-F1: call double @llvm.log.f64(double {{.*}}) // CHECK-F1: call double @llvm.fpbuiltin.log10.f64(double {{.*}}) #[[ATTR_F1_MEDIUM:[0-9]+]] -// CHECK-F1: call double @log1p(double noundef {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.log1p.f64(double {{.*}}) // CHECK-F1: call double @llvm.log2.f64(double {{.*}}) // CHECK-F1: call double @llvm.fpbuiltin.pow.f64(double {{.*}}, double {{.*}}) #[[ATTR_F1_HIGH]] -// CHECK-F1: call i32 (double, ...) @rsqrt(double noundef {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.rsqrt.f64(double {{.*}}) // CHECK-F1: call double @llvm.sin.f64(double {{.*}}) - // CHECK-F1: call void @llvm.fpbuiltin.sincos.f64(double {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_F1_MEDIUM]] -// CHECK-F1: call double @sinh(double noundef {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.sinh.f64(double {{.*}}) // CHECK-F1: call double @llvm.sqrt.f64(double {{.*}}) // CHECK-F1: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_F1_LOW:[0-9]+]] -// CHECK-F1: call double @tanh(double noundef {{.*}}) +// CHECK-F1: call double @llvm.fpbuiltin.tanh.f64(double {{.*}}) // // CHECK-F2-LABEL: define dso_local void @f1 // CHECK-F2: call double @llvm.fpbuiltin.acos.f64(double {{.*}}) #[[ATTR_F2_MEDIUM:[0-9]+]] diff --git a/clang/test/Driver/fp-accuracy.c b/clang/test/Driver/fp-accuracy.c index 6474351a3e425..96b425c2d2350 100644 --- a/clang/test/Driver/fp-accuracy.c +++ b/clang/test/Driver/fp-accuracy.c @@ -30,6 +30,10 @@ // RUN: not %clang -Xclang -verify -ffp-accuracy=high=[sin] %s 2>& 1 \ // RUN: | FileCheck %s --check-prefixes=CHECK-ERR-2 +// RUN: not %clang -Xclang -verify -ffp-accuracy=low:[sin,cos] \ +// RUN: -ffp-accuracy=high %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=WARN + // CHECK-H: "-ffp-builtin-accuracy=high" // CHECK-L: "-ffp-builtin-accuracy=low" // CHECK-M: "-ffp-builtin-accuracy=medium" @@ -40,3 +44,5 @@ // CHECK-ERR-1: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' // CHECK-ERR-1: (frontend): unsupported argument 'goo' to option 'ffp-accuracy' // CHECK-ERR-2: (frontend): unsupported argument 'high=[sin]' to option 'ffp-accuracy' +// WARN: (frontend): FP accuracy value of 'high' has already been assigned to function 'cos' +// WARN: (frontend): FP accuracy value of 'high' has already been assigned to function 'sin' diff --git a/llvm/include/llvm/IR/FPAccuracy.def b/llvm/include/llvm/IR/FPAccuracy.def index f4e8d009929d5..d2f69b12a2aec 100644 --- a/llvm/include/llvm/IR/FPAccuracy.def +++ b/llvm/include/llvm/IR/FPAccuracy.def @@ -10,11 +10,8 @@ // //===----------------------------------------------------------------------===// -// This customization is only in xmain for review purposes. -// When approved, it will go into the intel/llvm repository. - #ifndef FP_ACCURACY -#define FP_ACCURACY(IID,SF,SD,CF,CD +#define FP_ACCURACY(IID,SF,SD,CF,CD) #endif // Each entry below maps an fpbuiltin intrinsic ID to the required accuracy diff --git a/llvm/include/llvm/IR/FPAccuracy.h b/llvm/include/llvm/IR/FPAccuracy.h index 290517a15b29f..a722b0604de4b 100644 --- a/llvm/include/llvm/IR/FPAccuracy.h +++ b/llvm/include/llvm/IR/FPAccuracy.h @@ -15,11 +15,6 @@ #ifndef LLVM_IR_FPACCURACY_H #define LLVM_IR_FPACCURACY_H -// This customization is only in xmain for review purposes. -// When approved, it will go into the intel/llvm repository. - -#include - namespace llvm { class StringRef; diff --git a/llvm/lib/IR/FPAccuracy.cpp b/llvm/lib/IR/FPAccuracy.cpp index 2c8cdb0691cae..69376f92f8f4c 100644 --- a/llvm/lib/IR/FPAccuracy.cpp +++ b/llvm/lib/IR/FPAccuracy.cpp @@ -33,7 +33,7 @@ static bool isFPBuiltinIntrinsic(Intrinsic::ID IID) { } } -static StringRef LookupSyclFloatAccuracy(Intrinsic::ID IID) { +static StringRef lookupSyclFloatAccuracy(Intrinsic::ID IID) { switch (IID) { #define FP_ACCURACY(INTRINSIC, SYCL_FLOAT_ACCURACY, SDA, CFA, CDA) \ case Intrinsic::INTRINSIC: \ @@ -44,7 +44,7 @@ static StringRef LookupSyclFloatAccuracy(Intrinsic::ID IID) { } } -static StringRef LookupSyclDoubleAccuracy(Intrinsic::ID IID) { +static StringRef lookupSyclDoubleAccuracy(Intrinsic::ID IID) { switch (IID) { #define FP_ACCURACY(INTRINSIC, SFA, SYCL_DOUBLE_ACCURACY, CFA, CDA) \ case Intrinsic::INTRINSIC: \ @@ -55,7 +55,7 @@ static StringRef LookupSyclDoubleAccuracy(Intrinsic::ID IID) { } } -static StringRef LookupCudaFloatAccuracy(Intrinsic::ID IID) { +static StringRef lookupCudaFloatAccuracy(Intrinsic::ID IID) { switch (IID) { #define FP_ACCURACY(INTRINSIC, SFA, SDA, CUDA_FLOAT_ACCURACY, CDA) \ case Intrinsic::INTRINSIC: \ @@ -66,7 +66,7 @@ static StringRef LookupCudaFloatAccuracy(Intrinsic::ID IID) { } } -static StringRef LookupCudaDoubleAccuracy(Intrinsic::ID IID) { +static StringRef lookupCudaDoubleAccuracy(Intrinsic::ID IID) { switch (IID) { #define FP_ACCURACY(INTRINSIC, SFA, SDA, CFA, CUDA_DOUBLE_ACCURACY) \ case Intrinsic::INTRINSIC: \ @@ -116,15 +116,15 @@ StringRef fp::getAccuracyForFPBuiltin(Intrinsic::ID IID, const Type *Ty, if (Ty->isFloatTy()) { if (AccuracyLevel == fp::FPAccuracy::SYCL) - return LookupSyclFloatAccuracy(IID); + return lookupSyclFloatAccuracy(IID); if (AccuracyLevel == fp::FPAccuracy::CUDA) - return LookupCudaFloatAccuracy(IID); + return lookupCudaFloatAccuracy(IID); llvm_unreachable("Unexpected FPAccuracy level"); } else if (Ty->isDoubleTy()) { if (AccuracyLevel == fp::FPAccuracy::SYCL) - return LookupSyclDoubleAccuracy(IID); + return lookupSyclDoubleAccuracy(IID); if (AccuracyLevel == fp::FPAccuracy::CUDA) - return LookupCudaDoubleAccuracy(IID); + return lookupCudaDoubleAccuracy(IID); llvm_unreachable("Unexpected FPAccuracy level"); } else { // This is here for error detection if the logic above is changed. From 9cce8b78187876b7d788f64ef98d7c6433a8649c Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Fri, 5 May 2023 17:06:42 -0400 Subject: [PATCH 28/43] Fix format. --- clang/lib/CodeGen/CGBuiltin.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 39f8f3a4be150..621262e4bbc06 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -21911,23 +21911,23 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( if (!FD->hasAttr()) { Name = FD->getName(); if (Name == "fadd") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fadd; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fadd; else if (Name == "fdiv") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fdiv; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fdiv; else if (Name == "fmul") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fmul; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fmul; else if (Name == "fsub") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fsub; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fsub; else if (Name == "frem") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_frem; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_frem; else if (Name == "sincos") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; else if (Name == "exp10") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_exp10; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_exp10; else if (Name == "rsqrt") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_rsqrt; + FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_rsqrt; else - llvm_unreachable("unexpected fpbuiltin ID"); + llvm_unreachable("unexpected fpbuiltin ID"); } } else { // The function has a clang builtin. Create an attribute for it From 2ea8d5a4653cb88d97a40be3e063cd6b62a4d538 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 8 May 2023 11:57:52 -0400 Subject: [PATCH 29/43] Added support for math-errno. --- .../clang/Basic/DiagnosticFrontendKinds.td | 3 + clang/lib/CodeGen/CGBuiltin.cpp | 42 +++++---- clang/lib/Driver/ToolChains/Clang.cpp | 17 +++- clang/lib/Frontend/CompilerInvocation.cpp | 92 ++++++++++--------- clang/test/Driver/fp-accuracy.c | 60 ++++++------ llvm/lib/IR/FPAccuracy.cpp | 1 - 6 files changed, 123 insertions(+), 92 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index fbdbe3d6f9928..28b204c4d2fcf 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -60,6 +60,9 @@ def err_incompatible_fp_eval_method_options : Error< "option 'ffp-eval-method' cannot be used with option " "%select{'fapprox-func'|'mreassociate'|'freciprocal'}0">; +def err_incompatible_fp_accuracy_options : Error< + "option 'ffp-accuracy' cannot be used with option 'fmath-errno'">; + def remark_fe_backend_optimization_remark : Remark<"%0">, BackendInfo, InGroup; def remark_fe_backend_optimization_remark_missed : Remark<"%0">, BackendInfo, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 621262e4bbc06..19fc2cadcf42c 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -523,25 +523,31 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin( llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); if (FPAccuracyIntrinsicID != Intrinsic::not_intrinsic) { if (CGF.CGM.getCodeGenOpts().FPAccuracy) { - unsigned BuiltinID = CGF.getCurrentBuiltinID(); - StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); - Function *Func; - // Use fpbuiltin intrinsic only when needed. - bool HasAccuracyRequirement = false; - if (!CGF.getLangOpts().FPAccuracyVal.empty()) - HasAccuracyRequirement = true; - for (auto F : CGF.getLangOpts().FPAccuracyFuncMap) { - auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); - if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) - if (FuncMapIt->first == Name) { - HasAccuracyRequirement = true; - break; - } + if (CGF.getLangOpts().MathErrno) { + DiagnosticsEngine &Diags = CGF.CGM.getDiags(); + Diags.Report(E->getBeginLoc(), + diag::err_incompatible_fp_accuracy_options); + } else { + unsigned BuiltinID = CGF.getCurrentBuiltinID(); + StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); + Function *Func; + // Use fpbuiltin intrinsic only when needed. + bool HasAccuracyRequirement = false; + if (!CGF.getLangOpts().FPAccuracyVal.empty()) + HasAccuracyRequirement = true; + for (auto F : CGF.getLangOpts().FPAccuracyFuncMap) { + auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); + if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) + if (FuncMapIt->first == Name) { + HasAccuracyRequirement = true; + break; + } + } + Func = getIntrinsic(CGF, Src0, FPAccuracyIntrinsicID, IntrinsicID, + HasAccuracyRequirement); + return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0}, + FPAccuracyIntrinsicID); } - Func = getIntrinsic(CGF, Src0, FPAccuracyIntrinsicID, IntrinsicID, - HasAccuracyRequirement); - return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0}, - FPAccuracyIntrinsicID); } } if (CGF.Builder.getIsFPConstrained()) { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index b350db4386fd0..50e59bb954410 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2849,6 +2849,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, FPContract = "on"; bool StrictFPModel = false; StringRef Float16ExcessPrecision = ""; + StringRef FPAccuracy = ""; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2861,13 +2862,20 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, switch (optID) { default: break; + case options::OPT_ffp_accuracy_EQ: { + StringRef Val = A->getValue(); + FPAccuracy = Val; + break; + } case options::OPT_ffp_model_EQ: { // If -ffp-model= is seen, reset to fno-fast-math HonorINFs = true; HonorNaNs = true; ApproxFunc = false; - // Turning *off* -ffast-math restores the toolchain default. - MathErrno = TC.IsMathErrnoDefault(); + // Turning *off* -ffast-math restores the toolchain default, + // unless the -fp-accuracy is used. + if (FPAccuracy.empty()) + MathErrno = TC.IsMathErrnoDefault(); AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; @@ -3135,8 +3143,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, HonorNaNs = true; // Turning on -ffast-math (with either flag) removes the need for // MathErrno. However, turning *off* -ffast-math merely restores the - // toolchain default (which may be false). - MathErrno = TC.IsMathErrnoDefault(); + // toolchain default (which may be false). Unless -fp-accuracy is used. + if (FPAccuracy.empty()) + MathErrno = TC.IsMathErrnoDefault(); AssociativeMath = false; ReciprocalMath = false; ApproxFunc = false; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b1078dfd2cabf..be5ef798a29ea 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3584,50 +3584,56 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { for (StringRef Values : Args.getAllArgValues(OPT_ffp_builtin_accuracy_EQ)) { - SmallVector ValuesArr; - Values.split(ValuesArr, ' '); - for (const auto &Val : ValuesArr) { - SmallVector ValElement; - Val.split(ValElement, ':'); - // The option is of the form -ffp-accuracy=value. - if (ValElement.size() == 1) { - StringRef FPAccuracy = ValElement[0]; - if (!(FPAccuracy.equals("default") || FPAccuracy.equals("high") || - FPAccuracy.equals("low") || FPAccuracy.equals("medium") || - FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) - Diags.Report(diag::err_drv_unsupported_option_argument) - << "ffp-accuracy" << FPAccuracy; - Opts.FPAccuracyVal = ValElement[0].str(); - } - // The option is of the form -ffp-accuracy=value:[f1, ... fn]. - if (ValElement.size() == 2) { - SmallVector FuncList; - ValElement[1].split(FuncList, ','); - for (StringRef FuncName : FuncList) { - if (FuncName.front() == '[') - FuncName = FuncName.drop_front(1); - if (FuncName.back() == ']') - FuncName = FuncName.drop_back(1); - auto FuncMap = Opts.FPAccuracyFuncMap.find(FuncName.str()); - if (FuncMap != Opts.FPAccuracyFuncMap.end()) { - if (!FuncMap->second.empty()) { - Diags.Report(diag::warn_function_fp_accuracy_already_set) - << FuncMap->second << FuncName.str(); + if (Opts.MathErrno) { + Diags.Report(diag::err_drv_incompatible_options) << "ffp-accuracy" + << "-fmath-errno"; + } else { + SmallVector ValuesArr; + Values.split(ValuesArr, ' '); + for (const auto &Val : ValuesArr) { + SmallVector ValElement; + Val.split(ValElement, ':'); + // The option is of the form -ffp-accuracy=value. + if (ValElement.size() == 1) { + StringRef FPAccuracy = ValElement[0]; + if (!(FPAccuracy.equals("default") || FPAccuracy.equals("high") || + FPAccuracy.equals("low") || FPAccuracy.equals("medium") || + FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) + Diags.Report(diag::err_drv_unsupported_option_argument) + << "ffp-accuracy" << FPAccuracy; + Opts.FPAccuracyVal = ValElement[0].str(); + } + // The option is of the form -ffp-accuracy=value:[f1, ... fn]. + if (ValElement.size() == 2) { + SmallVector FuncList; + ValElement[1].split(FuncList, ','); + for (StringRef FuncName : FuncList) { + if (FuncName.front() == '[') + FuncName = FuncName.drop_front(1); + if (FuncName.back() == ']') + FuncName = FuncName.drop_back(1); + auto FuncMap = Opts.FPAccuracyFuncMap.find(FuncName.str()); + if (FuncMap != Opts.FPAccuracyFuncMap.end()) { + if (!FuncMap->second.empty()) { + Diags.Report(diag::warn_function_fp_accuracy_already_set) + << FuncMap->second << FuncName.str(); + } + } else { + StringRef FPAccuracy = ValElement[0]; + if (!(FPAccuracy.equals("default") || FPAccuracy.equals("high") || + FPAccuracy.equals("low") || FPAccuracy.equals("medium") || + FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) + Diags.Report(diag::err_drv_unsupported_option_argument) + << "ffp-accuracy" << FPAccuracy; + if (!Opts.FPAccuracyVal.empty()) + Diags.Report(diag::warn_function_fp_accuracy_already_set) + << Opts.FPAccuracyVal << FuncName.str(); + // No need to fill the map if the FPaccuracy is 'default'. + // The default builtin will be generated. + if (!FPAccuracy.equals("default")) + Opts.FPAccuracyFuncMap.insert( + {FuncName.str(), FPAccuracy.str()}); } - } else { - StringRef FPAccuracy = ValElement[0]; - if (!(FPAccuracy.equals("default") || FPAccuracy.equals("high") || - FPAccuracy.equals("low") || FPAccuracy.equals("medium") || - FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) - Diags.Report(diag::err_drv_unsupported_option_argument) - << "ffp-accuracy" << FPAccuracy; - if (!Opts.FPAccuracyVal.empty()) - Diags.Report(diag::warn_function_fp_accuracy_already_set) - << Opts.FPAccuracyVal << FuncName.str(); - // No need to fill the map if the FPaccuracy is 'default'. - // The default builtin will be generated. - if (!FPAccuracy.equals("default")) - Opts.FPAccuracyFuncMap.insert({FuncName.str(), FPAccuracy.str()}); } } } diff --git a/clang/test/Driver/fp-accuracy.c b/clang/test/Driver/fp-accuracy.c index 96b425c2d2350..0f0d2d8122877 100644 --- a/clang/test/Driver/fp-accuracy.c +++ b/clang/test/Driver/fp-accuracy.c @@ -1,48 +1,56 @@ // RUN: %clang -### -target x86_64 -ffp-accuracy=high -c %s 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-H %s +// RUN: | FileCheck --check-prefix=HIGH %s // RUN: %clang -### -target x86_64 -ffp-accuracy=low -c %s 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-L %s +// RUN: | FileCheck --check-prefix=LOW %s // RUN: %clang -### -target x86_64 -ffp-accuracy=medium -c %s 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-M %s +// RUN: | FileCheck --check-prefix=MEDIUM %s // RUN: %clang -### -target x86_64 -ffp-accuracy=low:sin,cos -c %s 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-FUNC-1 %s +// RUN: | FileCheck --check-prefix=FUNC-1 %s // RUN: %clang -### -target x86_64 -ffp-accuracy=low:sin,cos -ffp-accuracy=high:tan -c %s 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-FUNC-2 %s +// RUN: | FileCheck --check-prefix=FUNC-2 %s -// RUN: not %clang -Xclang -verify -ffp-accuracy=foo %s 2>&1 \ -// RUN: | FileCheck %s --check-prefixes=CHECK-ERR +// RUN: not %clang -Xclang -verify -fno-math-errno -ffp-accuracy=foo %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=ERR -// RUN: not %clang -Xclang -verify -ffp-accuracy=foo:[sin,cos] %s 2>&1 \ -// RUN: | FileCheck %s --check-prefixes=CHECK-ERR +// RUN: not %clang -Xclang -verify -fno-math-errno -ffp-accuracy=foo:[sin,cos] %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=ERR -// RUN: not %clang -Xclang -verify -ffp-accuracy=foo:[sin,cos] \ +// RUN: not %clang -Xclang -verify -fno-math-errno -ffp-accuracy=foo:[sin,cos] \ // RUN: -ffp-accuracy=goo %s 2>&1 \ -// RUN: | FileCheck %s --check-prefixes=CHECK-ERR +// RUN: | FileCheck %s --check-prefixes=ERR -// RUN: not %clang -Xclang -verify -ffp-accuracy=foo:[sin,cos] \ +// RUN: not %clang -Xclang -verify -fno-math-errno -ffp-accuracy=foo:[sin,cos] \ // RUN: -ffp-accuracy=goo:[tan] %s 2>&1 \ -// RUN: | FileCheck %s --check-prefixes=CHECK-ERR-1 +// RUN: | FileCheck %s --check-prefixes=ERR-1 -// RUN: not %clang -Xclang -verify -ffp-accuracy=high=[sin] %s 2>& 1 \ -// RUN: | FileCheck %s --check-prefixes=CHECK-ERR-2 +// RUN: not %clang -Xclang -verify -fno-math-errno -ffp-accuracy=high=[sin] %s 2>& 1 \ +// RUN: | FileCheck %s --check-prefixes=ERR-2 -// RUN: not %clang -Xclang -verify -ffp-accuracy=low:[sin,cos] \ +// RUN: not %clang -Xclang -verify -fno-math-errno -ffp-accuracy=low:[sin,cos] \ // RUN: -ffp-accuracy=high %s 2>&1 \ // RUN: | FileCheck %s --check-prefix=WARN -// CHECK-H: "-ffp-builtin-accuracy=high" -// CHECK-L: "-ffp-builtin-accuracy=low" -// CHECK-M: "-ffp-builtin-accuracy=medium" -// CHECK-FUNC-1: "-ffp-builtin-accuracy=low:sin,cos" -// CHECK-FUNC-2: "-ffp-builtin-accuracy=low:sin,cos high:tan" -// CHECK-ERR: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' -// CHECK-ERR-1: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' -// CHECK-ERR-1: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' -// CHECK-ERR-1: (frontend): unsupported argument 'goo' to option 'ffp-accuracy' -// CHECK-ERR-2: (frontend): unsupported argument 'high=[sin]' to option 'ffp-accuracy' +// RUN: not %clang -Xclang -verify -ffp-accuracy=low:[sin,cos] \ +// RUN: -ffp-accuracy=high -fmath-errno %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=ERR-3 + +// RUN: not %clang -Xclang -verify -ffp-accuracy=high \ +// RUN: -fmath-errno %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=ERR-3 + + +// HIGH: "-ffp-builtin-accuracy=high" +// LOW: "-ffp-builtin-accuracy=low" +// MEDIUM: "-ffp-builtin-accuracy=medium" +// FUNC-1: "-ffp-builtin-accuracy=low:sin,cos" +// FUNC-2: "-ffp-builtin-accuracy=low:sin,cos high:tan" +// ERR: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' +// ERR-1: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' +// ERR-2: (frontend): unsupported argument 'high=[sin]' to option 'ffp-accuracy' // WARN: (frontend): FP accuracy value of 'high' has already been assigned to function 'cos' // WARN: (frontend): FP accuracy value of 'high' has already been assigned to function 'sin' +// ERR-3: (frontend): The combination of 'ffp-accuracy' and '-fmath-errno' is incompatible diff --git a/llvm/lib/IR/FPAccuracy.cpp b/llvm/lib/IR/FPAccuracy.cpp index 69376f92f8f4c..af29554b910b4 100644 --- a/llvm/lib/IR/FPAccuracy.cpp +++ b/llvm/lib/IR/FPAccuracy.cpp @@ -19,7 +19,6 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" -#include namespace llvm { From 7abea950751b583768b9df57151ba3ad84f3c184 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 8 May 2023 12:12:07 -0400 Subject: [PATCH 30/43] Fixed diag comment. --- clang/include/clang/Basic/DiagnosticDriverKinds.td | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 26418bc96cbfb..cdd713766b758 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -145,7 +145,8 @@ def err_drv_invalid_unwindlib_name : Error< def err_drv_incompatible_unwindlib : Error< "--rtlib=libgcc requires --unwindlib=libgcc">; def err_drv_incompatible_options : Error< - "The combination of '%0' and '%1' is incompatible">; + "fp-accuracy requirements cannot be guaranteed when math-errno is enabled. " + "Use -fno-math-errno to enable fp-accuracy control.">; def err_drv_invalid_stdlib_name : Error< "invalid library name in argument '%0'">; def err_drv_invalid_output_with_multiple_archs : Error< From 773f1ed112835fca9c2738d9e08a6a6271212cc2 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 8 May 2023 14:34:38 -0400 Subject: [PATCH 31/43] Fix lit test. --- clang/test/Driver/fp-accuracy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Driver/fp-accuracy.c b/clang/test/Driver/fp-accuracy.c index 0f0d2d8122877..020cb377b3c02 100644 --- a/clang/test/Driver/fp-accuracy.c +++ b/clang/test/Driver/fp-accuracy.c @@ -53,4 +53,4 @@ // ERR-2: (frontend): unsupported argument 'high=[sin]' to option 'ffp-accuracy' // WARN: (frontend): FP accuracy value of 'high' has already been assigned to function 'cos' // WARN: (frontend): FP accuracy value of 'high' has already been assigned to function 'sin' -// ERR-3: (frontend): The combination of 'ffp-accuracy' and '-fmath-errno' is incompatible +// ERR-3: (frontend): fp-accuracy requirements cannot be guaranteed when math-errno is enabled. Use -fno-math-errno to enable fp-accuracy control. From 68c9a702913adaf9f44ade03e30ae3e3c642028b Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 9 May 2023 09:12:09 -0400 Subject: [PATCH 32/43] Fixed Diag. --- clang/include/clang/Basic/DiagnosticDriverKinds.td | 2 ++ clang/lib/Frontend/CompilerInvocation.cpp | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index cdd713766b758..81f0f63b3d6de 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -145,6 +145,8 @@ def err_drv_invalid_unwindlib_name : Error< def err_drv_incompatible_unwindlib : Error< "--rtlib=libgcc requires --unwindlib=libgcc">; def err_drv_incompatible_options : Error< + "The combination of '%0' and '%1' is incompatible">; +def err_drv_incompatible_fp_accuracy_options : Error< "fp-accuracy requirements cannot be guaranteed when math-errno is enabled. " "Use -fno-math-errno to enable fp-accuracy control.">; def err_drv_invalid_stdlib_name : Error< diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index be5ef798a29ea..fe1fc9fdbe773 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3585,8 +3585,7 @@ void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { for (StringRef Values : Args.getAllArgValues(OPT_ffp_builtin_accuracy_EQ)) { if (Opts.MathErrno) { - Diags.Report(diag::err_drv_incompatible_options) << "ffp-accuracy" - << "-fmath-errno"; + Diags.Report(diag::err_drv_incompatible_fp_accuracy_options); } else { SmallVector ValuesArr; Values.split(ValuesArr, ' '); From bffc1fd18b9385881f52a68ef93672ee85e775b0 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 9 May 2023 15:28:51 -0400 Subject: [PATCH 33/43] Responded to review comments. --- clang/lib/CodeGen/CGBuiltin.cpp | 42 +++++++++++++-------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 602ed008c8210..38c4884039f49 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -512,6 +512,18 @@ Function *getIntrinsic(CodeGenFunction &CGF, llvm::Value *Src0, : CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); } +bool hasAccuracyRequirement(CodeGenFunction &CGF, StringRef Name) { + bool HasRequirement = false; + if (!CGF.getLangOpts().FPAccuracyVal.empty()) + HasRequirement = true; + if (!CGF.getLangOpts().FPAccuracyFuncMap.empty()) { + auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); + if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) + HasRequirement = true; + } + return HasRequirement; +} + // Emit a simple mangled intrinsic that has 1 argument and a return type // matching the argument type. Depending on mode, this may be a constrained // or an fpbuiltin floating-point intrinsic. @@ -531,17 +543,7 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin( StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); Function *Func; // Use fpbuiltin intrinsic only when needed. - bool HasAccuracyRequirement = false; - if (!CGF.getLangOpts().FPAccuracyVal.empty()) - HasAccuracyRequirement = true; - for (auto F : CGF.getLangOpts().FPAccuracyFuncMap) { - auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); - if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) - if (FuncMapIt->first == Name) { - HasAccuracyRequirement = true; - break; - } - } + bool HasAccuracyRequirement = hasAccuracyRequirement(CGF, Name); Func = getIntrinsic(CGF, Src0, FPAccuracyIntrinsicID, IntrinsicID, HasAccuracyRequirement); return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0}, @@ -572,21 +574,9 @@ static Value *emitBinaryMaybeConstrainedFPBuiltin( StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); Function *Func; // Use fpbuiltin intrinsic only when needed. - bool HasAccuracyRequirement = false; - if (!CGF.getLangOpts().FPAccuracyVal.empty()) - HasAccuracyRequirement = true; - for (auto F : CGF.getLangOpts().FPAccuracyFuncMap) { - auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); - if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) - if (FuncMapIt->first == Name) { - HasAccuracyRequirement = true; - break; - } - } - if (HasAccuracyRequirement) - Func = CGF.CGM.getIntrinsic(FPAccuracyIntrinsicID, Src0->getType()); - else - Func = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + bool HasAccuracyRequirement = hasAccuracyRequirement(CGF, Name); + Func = getIntrinsic(CGF, Src0, FPAccuracyIntrinsicID, IntrinsicID, + HasAccuracyRequirement); return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0, Src1}, FPAccuracyIntrinsicID); } From 7900b877d8dd27d3969ffe3836cda6df4801d296 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Thu, 18 May 2023 09:44:53 -0400 Subject: [PATCH 34/43] Responded to review comments. --- clang/lib/CodeGen/CGBuiltin.cpp | 38 ++++++++++++++------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 38c4884039f49..219cf779d6e08 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -513,15 +513,14 @@ Function *getIntrinsic(CodeGenFunction &CGF, llvm::Value *Src0, } bool hasAccuracyRequirement(CodeGenFunction &CGF, StringRef Name) { - bool HasRequirement = false; if (!CGF.getLangOpts().FPAccuracyVal.empty()) - HasRequirement = true; + return true; if (!CGF.getLangOpts().FPAccuracyFuncMap.empty()) { auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) - HasRequirement = true; + return true; } - return HasRequirement; + return false; } // Emit a simple mangled intrinsic that has 1 argument and a return type @@ -539,13 +538,12 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin( Diags.Report(E->getBeginLoc(), diag::err_incompatible_fp_accuracy_options); } else { - unsigned BuiltinID = CGF.getCurrentBuiltinID(); - StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); - Function *Func; + StringRef Name = + CGF.CGM.getContext().BuiltinInfo.getName(CGF.getCurrentBuiltinID()); // Use fpbuiltin intrinsic only when needed. - bool HasAccuracyRequirement = hasAccuracyRequirement(CGF, Name); - Func = getIntrinsic(CGF, Src0, FPAccuracyIntrinsicID, IntrinsicID, - HasAccuracyRequirement); + Function *Func = + getIntrinsic(CGF, Src0, FPAccuracyIntrinsicID, IntrinsicID, + hasAccuracyRequirement(CGF, Name)); return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0}, FPAccuracyIntrinsicID); } @@ -570,13 +568,11 @@ static Value *emitBinaryMaybeConstrainedFPBuiltin( llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1)); if (CGF.CGM.getCodeGenOpts().FPAccuracy) { - unsigned BuiltinID = CGF.getCurrentBuiltinID(); - StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(BuiltinID); - Function *Func; + StringRef Name = + CGF.CGM.getContext().BuiltinInfo.getName(CGF.getCurrentBuiltinID()); // Use fpbuiltin intrinsic only when needed. - bool HasAccuracyRequirement = hasAccuracyRequirement(CGF, Name); - Func = getIntrinsic(CGF, Src0, FPAccuracyIntrinsicID, IntrinsicID, - HasAccuracyRequirement); + Function *Func = getIntrinsic(CGF, Src0, FPAccuracyIntrinsicID, IntrinsicID, + hasAccuracyRequirement(CGF, Name)); return CreateBuiltinCallWithAttr(CGF, Name, Func, {Src0, Src1}, FPAccuracyIntrinsicID); } @@ -21930,7 +21926,10 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( Name = CGM.getContext().BuiltinInfo.getName(BuiltinID); switch (BuiltinID) { default: - break; + // If the function has a clang builtin but doesn't have an + // fpbuiltin, it will be generated with no 'fpbuiltin-max-error' + // attribute. + return nullptr; case Builtin::BItan: FPAccuracyIntrinsicID = Intrinsic::fpbuiltin_tan; break; @@ -21999,11 +21998,6 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( break; } } - if (FPAccuracyIntrinsicID == 0) - // If the function has a clang builtin but doesn't have an - // fpbuiltin, it will be generated with no 'fpbuiltin-max-error' - // attribute. - return nullptr; Func = CGM.getIntrinsic(FPAccuracyIntrinsicID, IRArgs[0]->getType()); if (IRArgs.size() == 1) CI = CreateBuiltinCallWithAttr(*this, Name, Func, {IRArgs[0]}, From a71e5f2113a9635aaf1f14b2eac0ccd8c5d305cd Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Fri, 19 May 2023 15:06:36 -0400 Subject: [PATCH 35/43] Responded to review comments. --- clang/include/clang/Basic/CodeGenOptions.def | 2 ++ .../clang/Basic/DiagnosticCommonKinds.td | 3 +++ .../clang/Basic/DiagnosticDriverKinds.td | 14 ++++------- clang/include/clang/Driver/Options.td | 2 ++ clang/lib/CodeGen/CGBuiltin.cpp | 13 +++++++--- clang/lib/CodeGen/CGCall.cpp | 4 +-- clang/test/CodeGen/fp-accuracy.c | 25 +++++++++++++++---- clang/test/Driver/fp-accuracy.c | 6 ++--- 8 files changed, 46 insertions(+), 23 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 2322cc0cd5ca3..809f431337830 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -374,6 +374,8 @@ CODEGENOPT(VirtualFunctionElimination, 1, 0) ///< Whether to apply the dead /// virtual function elimination /// optimization. +/// Whether accuracy levels for math library functions are requested by the +/// user. These accuracy levels will then be expressed in terms of ULPs. CODEGENOPT(FPAccuracy, 1, 0) /// Whether to use public LTO visibility for entities in std and stdext diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index da4e2b42dc2ea..0e40f7eca03f7 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -299,6 +299,9 @@ def warn_stack_clash_protection_inline_asm : Warning< def warn_slh_does_not_support_asm_goto : Warning< "speculative load hardening does not protect functions with asm goto">, InGroup>; + +def err_drv_incompatible_options : Error< + "The combination of '%0' and '%1' is incompatible">; } // Sema && Serialization diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index a265f15dd5b01..eddc2b45ffd70 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -63,11 +63,9 @@ def err_drv_no_cuda_libdevice : Error< "via '--cuda-path', or pass '-nocudalib' to build without linking with " "libdevice">; -def warn_function_fp_accuracy_already_set : Warning <"FP accuracy value of '%0' has already " - "been assigned to function '%1'">, - InGroup; -def warn_all_fp_accuracy_already_set : Warning <"FP accuracy value of '%0' has already " - "been assigned to all functions in the program">, +def warn_function_fp_accuracy_already_set : Warning < + "floating point accuracy value of '%0' has already been assigned to " + "function '%1'">, InGroup; def err_drv_no_rocm_device_lib : Error< "cannot find ROCm device library%select{| for %1|for ABI version %1}0; provide its path via " @@ -144,11 +142,9 @@ def err_drv_invalid_unwindlib_name : Error< "invalid unwind library name in argument '%0'">; def err_drv_incompatible_unwindlib : Error< "--rtlib=libgcc requires --unwindlib=libgcc">; -def err_drv_incompatible_options : Error< - "The combination of '%0' and '%1' is incompatible">; def err_drv_incompatible_fp_accuracy_options : Error< - "fp-accuracy requirements cannot be guaranteed when math-errno is enabled. " - "Use -fno-math-errno to enable fp-accuracy control.">; + "floating point accuracy requirements cannot be guaranteed when '-fmath-errno' " + "is enabled; use '-fno-math-errno' to enable floating point accuracy control">; def err_drv_invalid_stdlib_name : Error< "invalid library name in argument '%0'">; def err_drv_invalid_output_with_multiple_archs : Error< diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index b2e1c6bac4a9f..a544ce1bf8e0e 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -6985,11 +6985,13 @@ class CLRemainingArgsJoined : Option<["/", "-"], name, // (We don't put any of these in cl_compile_Group as the options they alias are // already in the right group.) +// INTEL_CUSTOMIZATION def _SLASH_Qfp_accuracy_EQ : CLJoined<"Qfp-accuracy=">, Alias; def _SLASH_Qfp_accuracy_COL : CLJoined<"Qfp-accuracy:">, Alias,HelpText<"Specifies the required accuracy for " "floating-point operations and library calls.">; +// END INTEL_CUSTOMIZATION def _SLASH_Brepro : CLFlag<"Brepro">, HelpText<"Do not write current time into COFF output (breaks link.exe /incremental)">, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 219cf779d6e08..d8186b8a4d218 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -495,6 +495,8 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, StringRef Name, unsigned ID) { llvm::CallInst *CI = CGF.Builder.CreateCall(FPBuiltinF, Args); llvm::AttributeList AttrList; + // sincos() doesn 't return a value, but it still has a type associated with + // it that corresponds the operand type. if (Name == "sincos") CGF.CGM.getFPAccuracyFuncAttributes(Name, AttrList, ID, Args[0]->getType()); else @@ -504,7 +506,7 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, StringRef Name, return CI; } -Function *getIntrinsic(CodeGenFunction &CGF, llvm::Value *Src0, +static Function *getIntrinsic(CodeGenFunction &CGF, llvm::Value *Src0, unsigned FPIntrinsicID, unsigned IntrinsicID, bool HasAccuracyRequirement) { return HasAccuracyRequirement @@ -512,7 +514,7 @@ Function *getIntrinsic(CodeGenFunction &CGF, llvm::Value *Src0, : CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); } -bool hasAccuracyRequirement(CodeGenFunction &CGF, StringRef Name) { +static bool hasAccuracyRequirement(CodeGenFunction &CGF, StringRef Name) { if (!CGF.getLangOpts().FPAccuracyVal.empty()) return true; if (!CGF.getLangOpts().FPAccuracyFuncMap.empty()) { @@ -535,8 +537,9 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin( if (CGF.CGM.getCodeGenOpts().FPAccuracy) { if (CGF.getLangOpts().MathErrno) { DiagnosticsEngine &Diags = CGF.CGM.getDiags(); - Diags.Report(E->getBeginLoc(), - diag::err_incompatible_fp_accuracy_options); + Diags.Report(E->getBeginLoc(), diag::err_drv_incompatible_options) + << "ffp-accuracy" + << "fmath-errno"; } else { StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(CGF.getCurrentBuiltinID()); @@ -21918,6 +21921,8 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_rsqrt; else llvm_unreachable("unexpected fpbuiltin ID"); + } else { + return CI; } } else { // The function has a clang builtin. Create an attribute for it diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 854bb5805868c..d078df5c74a72 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1837,7 +1837,7 @@ static bool HasStrictReturn(const CodeGenModule &Module, QualType RetTy, Module.getLangOpts().Sanitize.has(SanitizerKind::Return); } -llvm::fp::FPAccuracy convertFPAccuracy(StringRef FPAccuracy) { +static llvm::fp::FPAccuracy convertFPAccuracy(StringRef FPAccuracy) { StringRef AccuracyVal; if (FPAccuracy == "high") return llvm::fp::FPAccuracy::High; @@ -5605,7 +5605,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::CallBase *CI = nullptr; if (!InvokeDest) { if (CGM.getCodeGenOpts().FPAccuracy) { - const FunctionDecl *FD = dyn_cast_or_null(TargetDecl); + const auto *FD = dyn_cast_or_null(TargetDecl); assert(FD && "expecting a function"); CI = EmitFPBuiltinIndirectCall(IRFuncTy, IRCallArgs, CalleePtr, FD); if (CI) diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index 8aeb1c9e3b801..d05a7d50e8390 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -1,15 +1,15 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-builtin-accuracy=high \ -// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: -Wno-return-type -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefixes=CHECK %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ // RUN: "-ffp-builtin-accuracy=high:[acosf,cos,pow] low:[tan] medium:[sincos,log10]" \ -// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: -Wno-return-type -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CHECK-F1 %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ // RUN: "-ffp-builtin-accuracy=medium high:[tan] cuda:[cos]" \ -// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: -Wno-return-type -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CHECK-F2 %s // RUN: %clang_cc1 -triple spir64-unknown-unknown -ffp-builtin-accuracy=sycl \ @@ -18,11 +18,11 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ // RUN: "-ffp-builtin-accuracy=default:[acosf,cos,pow]" \ -// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: -Wno-return-type -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefixes=CHECK-DEFAULT %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ -// RUN: -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: -Wno-return-type -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefixes=CHECK-DEFAULT %s #ifdef SPIR @@ -254,6 +254,13 @@ void f1(float a, float b) { // CHECK-SPIR: call void @llvm.fpbuiltin.sincos.f32(float {{.*}}, ptr {{.*}}, ptr {{.*}}) #[[ATTR_SYCL1]] // CHECK-SPIR: call spir_func float @tanf(float noundef {{.*}}) +// CHECK-LABEL: define dso_local void @f3 +// CHECK: call float @fake_exp10(float {{.*}}) +// CHECK-F1: call float @fake_exp10(float {{.*}}) +// CHECK-F2: call float @fake_exp10(float {{.*}}) +// CHECK-SPIR-LABEL: define dso_local spir_func void @f3 +// CHECK-SPIR: call spir_func float @fake_exp10(float {{.*}}) + // CHECK: attributes #[[ATTR_HIGH]] = {{.*}}"fpbuiltin-max-error="="1.0f" // CHECK-F1: attributes #[[ATTR_F1_HIGH]] = {{.*}}"fpbuiltin-max-error="="1.0f" @@ -317,6 +324,9 @@ void f1(float a, float b) { // CHECK-DEFAULT: call i32 (double, ptr, ptr, ...) @sincos(double noundef {{.*}}, ptr noundef {{.*}}, ptr noundef {{.*}}) // CHECK-DEFAULT: call float @tanf(float noundef {{.*}}) +// CHECK-DEFAULT-LABEL: define dso_local void @f3 +// CHECK-DEFAULT: call float @fake_exp10(float {{.*}}) + void f2(float a, float b) { float sin = 0.f, cos = 0.f; @@ -327,3 +337,8 @@ void f2(float a, float b) { sincos(b, &sin, &cos); b = tanf(b); } + +float fake_exp10(float a) __attribute__((no_builtin)){} +void f3(float a, float b) { + a = fake_exp10(b); +} diff --git a/clang/test/Driver/fp-accuracy.c b/clang/test/Driver/fp-accuracy.c index 020cb377b3c02..5f054604ae48a 100644 --- a/clang/test/Driver/fp-accuracy.c +++ b/clang/test/Driver/fp-accuracy.c @@ -51,6 +51,6 @@ // ERR: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' // ERR-1: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' // ERR-2: (frontend): unsupported argument 'high=[sin]' to option 'ffp-accuracy' -// WARN: (frontend): FP accuracy value of 'high' has already been assigned to function 'cos' -// WARN: (frontend): FP accuracy value of 'high' has already been assigned to function 'sin' -// ERR-3: (frontend): fp-accuracy requirements cannot be guaranteed when math-errno is enabled. Use -fno-math-errno to enable fp-accuracy control. +// WARN: (frontend): floating point accuracy value of 'high' has already been assigned to function 'cos' +// WARN: (frontend): floating point accuracy value of 'high' has already been assigned to function 'sin' +// ERR-3: (frontend): floating point accuracy requirements cannot be guaranteed when '-fmath-errno' is enabled; use '-fno-math-errno' to enable floating point accuracy control From a05458fcb4a6fc61df005d4cede9a88de8cf85b9 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Thu, 25 May 2023 17:31:44 -0400 Subject: [PATCH 36/43] Responded to review comments. --- .../clang/Basic/DiagnosticCommonKinds.td | 2 +- .../clang/Basic/DiagnosticDriverKinds.td | 2 +- .../clang/Basic/DiagnosticFrontendKinds.td | 3 -- clang/include/clang/Basic/DiagnosticGroups.td | 3 -- clang/include/clang/Basic/FPOptions.def | 2 +- clang/include/clang/Basic/LangOptions.def | 2 +- clang/include/clang/Basic/LangOptions.h | 2 +- clang/lib/CodeGen/CGBuiltin.cpp | 47 ++++++------------- clang/lib/CodeGen/CGCall.cpp | 21 +++------ clang/lib/CodeGen/CodeGenFunction.h | 2 +- clang/lib/Frontend/CompilerInvocation.cpp | 32 ++++++++----- clang/test/Driver/fp-accuracy.c | 8 ++++ 12 files changed, 54 insertions(+), 72 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index 0e40f7eca03f7..26681945fd595 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -301,7 +301,7 @@ def warn_slh_does_not_support_asm_goto : Warning< InGroup>; def err_drv_incompatible_options : Error< - "The combination of '%0' and '%1' is incompatible">; + "the combination of '%0' and '%1' is incompatible">; } // Sema && Serialization diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index eddc2b45ffd70..85c1968510588 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -66,7 +66,7 @@ def err_drv_no_cuda_libdevice : Error< def warn_function_fp_accuracy_already_set : Warning < "floating point accuracy value of '%0' has already been assigned to " "function '%1'">, - InGroup; + InGroup>; def err_drv_no_rocm_device_lib : Error< "cannot find ROCm device library%select{| for %1|for ABI version %1}0; provide its path via " "'--rocm-path' or '--rocm-device-lib-path', or pass '-nogpulib' to build " diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 28b204c4d2fcf..fbdbe3d6f9928 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -60,9 +60,6 @@ def err_incompatible_fp_eval_method_options : Error< "option 'ffp-eval-method' cannot be used with option " "%select{'fapprox-func'|'mreassociate'|'freciprocal'}0">; -def err_incompatible_fp_accuracy_options : Error< - "option 'ffp-accuracy' cannot be used with option 'fmath-errno'">; - def remark_fe_backend_optimization_remark : Remark<"%0">, BackendInfo, InGroup; def remark_fe_backend_optimization_remark_missed : Remark<"%0">, BackendInfo, diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 9a4e36391d147..b4b1a5002ccd3 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1445,6 +1445,3 @@ def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">; // Warnings and fixes to support the "safe buffers" programming model. def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage">; - -// Warnings for fp accuracy already set. -def FPAccuracyAlreadySet : DiagGroup<"fp-accuracy-value">; diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def index 49a858e6afc0a..fb043645cd978 100644 --- a/clang/include/clang/Basic/FPOptions.def +++ b/clang/include/clang/Basic/FPOptions.def @@ -26,5 +26,5 @@ OPTION(AllowReciprocal, bool, 1, NoSignedZero) OPTION(AllowApproxFunc, bool, 1, AllowReciprocal) OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc) OPTION(Float16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, FPEvalMethod) -OPTION(FPAccuracy, LangOptions::FPAccuracyKind, 2, Float16ExcessPrecision) +OPTION(FPAccuracy, LangOptions::FPAccuracyKind, 3, Float16ExcessPrecision) #undef OPTION diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 5fbb34971259b..951b00696020e 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -336,7 +336,7 @@ BENIGN_LANGOPT(RoundingMath, 1, false, "Do not assume default floating-point rou BENIGN_ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Default, "FP Exception Behavior Mode type") BENIGN_ENUM_LANGOPT(FPEvalMethod, FPEvalMethodKind, 2, FEM_UnsetOnCommandLine, "FP type used for floating point arithmetic") ENUM_LANGOPT(Float16ExcessPrecision, ExcessPrecisionKind, 2, FPP_Standard, "Intermediate truncation behavior for floating point arithmetic") -BENIGN_ENUM_LANGOPT(FPAccuracy, FPAccuracyKind, 2, FPA_Default, "Accuracy for floating point operations and library functions") +BENIGN_ENUM_LANGOPT(FPAccuracy, FPAccuracyKind, 3, FPA_Default, "Accuracy for floating point operations and library functions") LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment") LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility") LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 58e7a421565f4..f8c8bd8d303d6 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -310,7 +310,7 @@ class LangOptions : public LangOptionsBase { FPA_Medium, FPA_Low, FPA_Sycl, - FPA_Cuda + FPA_Cuda, }; /// Possible exception handling behavior. diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index d8186b8a4d218..294976334b2cf 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -21903,24 +21903,18 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( // an NoBuiltin attribute. if (!FD->hasAttr()) { Name = FD->getName(); - if (Name == "fadd") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fadd; - else if (Name == "fdiv") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fdiv; - else if (Name == "fmul") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fmul; - else if (Name == "fsub") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_fsub; - else if (Name == "frem") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_frem; - else if (Name == "sincos") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_sincos; - else if (Name == "exp10") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_exp10; - else if (Name == "rsqrt") - FPAccuracyIntrinsicID = llvm::Intrinsic::fpbuiltin_rsqrt; - else - llvm_unreachable("unexpected fpbuiltin ID"); + FPAccuracyIntrinsicID = + llvm::StringSwitch(Name) + .Case("fadd", llvm::Intrinsic::fpbuiltin_fadd) + .Case("fdiv", llvm::Intrinsic::fpbuiltin_fdiv) + .Case("fmul", llvm::Intrinsic::fpbuiltin_fmul) + .Case("fsub", llvm::Intrinsic::fpbuiltin_fsub) + .Case("frem", llvm::Intrinsic::fpbuiltin_frem) + .Case("sincos", llvm::Intrinsic::fpbuiltin_sincos) + .Case("exp10", llvm::Intrinsic::fpbuiltin_exp10) + .Case("rsqrt", llvm::Intrinsic::fpbuiltin_rsqrt) + .Default(-1); + assert(FPAccuracyIntrinsicID != -1 && "unexpected fpbuiltin ID"); } else { return CI; } @@ -22004,21 +21998,8 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( } } Func = CGM.getIntrinsic(FPAccuracyIntrinsicID, IRArgs[0]->getType()); - if (IRArgs.size() == 1) - CI = CreateBuiltinCallWithAttr(*this, Name, Func, {IRArgs[0]}, - FPAccuracyIntrinsicID); - else if (IRArgs.size() == 2) - CI = CreateBuiltinCallWithAttr(*this, FnPtr->getName(), Func, - {IRArgs[0], IRArgs[1]}, - FPAccuracyIntrinsicID); - else if (IRArgs.size() == 3) - CI = CreateBuiltinCallWithAttr(*this, FnPtr->getName(), Func, - {IRArgs[0], IRArgs[1], IRArgs[2]}, - FPAccuracyIntrinsicID); - else - llvm_unreachable( - "Not expecting an fpbuiltin intrinsic with more than 3 arguments"); - + CI = CreateBuiltinCallWithAttr(*this, Name, Func, ArrayRef(IRArgs), + FPAccuracyIntrinsicID); return CI; } diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index d078df5c74a72..bea03d51d071b 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1837,20 +1837,13 @@ static bool HasStrictReturn(const CodeGenModule &Module, QualType RetTy, Module.getLangOpts().Sanitize.has(SanitizerKind::Return); } -static llvm::fp::FPAccuracy convertFPAccuracy(StringRef FPAccuracy) { - StringRef AccuracyVal; - if (FPAccuracy == "high") - return llvm::fp::FPAccuracy::High; - else if (FPAccuracy == "medium") - return llvm::fp::FPAccuracy::Medium; - else if (FPAccuracy == "low") - return llvm::fp::FPAccuracy::Low; - else if (FPAccuracy == "sycl") - return llvm::fp::FPAccuracy::SYCL; - else if (FPAccuracy == "cuda") - return llvm::fp::FPAccuracy::CUDA; - else - llvm_unreachable("Unexpected type for FPAccuracy"); +static llvm::fp::FPAccuracy convertFPAccuracy(StringRef FPAccuracyStr) { + return llvm::StringSwitch(FPAccuracyStr) + .Case("high", llvm::fp::FPAccuracy::High) + .Case("medium", llvm::fp::FPAccuracy::Medium) + .Case("low", llvm::fp::FPAccuracy::Low) + .Case("sycl", llvm::fp::FPAccuracy::SYCL) + .Case("cuda", llvm::fp::FPAccuracy::CUDA); } void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index b998b1784d450..2b626e1417fd0 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1615,7 +1615,7 @@ class CodeGenFunction : public CodeGenTypeCache { unsigned CurrentBuiltinID = /*NotBuiltin*/ 0; public: - unsigned getCurrentBuiltinID() { + unsigned getCurrentBuiltinID() const { assert(CurrentBuiltinID != /*NotBuiltin*/ 0); return CurrentBuiltinID; } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 19ddc14e8b7e4..19e1167c273fb 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3310,16 +3310,12 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, #undef LANG_OPTION_WITH_MARSHALLING if (!Opts.FPAccuracyVal.empty()) { - StringRef S = Opts.FPAccuracyVal; - GenerateArg(Args, OPT_ffp_builtin_accuracy_EQ, S, SA); + GenerateArg(Args, OPT_ffp_builtin_accuracy_EQ, Opts.FPAccuracyVal, SA); } for (const auto &F : Opts.FPAccuracyFuncMap) { - SmallString<128> S; - S += F.second; - S += ':'; - S += F.first; - GenerateArg(Args, OPT_ffp_builtin_accuracy_EQ, S, SA); + GenerateArg(Args, OPT_ffp_builtin_accuracy_EQ, (F.second + ":" + F.first), + SA); } // The '-fcf-protection=' option is generated by CodeGenOpts generator. @@ -3578,9 +3574,14 @@ void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, // The option is of the form -ffp-accuracy=value. if (ValElement.size() == 1) { StringRef FPAccuracy = ValElement[0]; - if (!(FPAccuracy.equals("default") || FPAccuracy.equals("high") || - FPAccuracy.equals("low") || FPAccuracy.equals("medium") || - FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) + if (!llvm::StringSwitch(FPAccuracy) + .Case("default", true) + .Case("high", true) + .Case("low", true) + .Case("medium", true) + .Case("sycl", true) + .Case("cuda", true) + .Default(false)) Diags.Report(diag::err_drv_unsupported_option_argument) << "ffp-accuracy" << FPAccuracy; Opts.FPAccuracyVal = ValElement[0].str(); @@ -3602,9 +3603,14 @@ void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, } } else { StringRef FPAccuracy = ValElement[0]; - if (!(FPAccuracy.equals("default") || FPAccuracy.equals("high") || - FPAccuracy.equals("low") || FPAccuracy.equals("medium") || - FPAccuracy.equals("sycl") || FPAccuracy.equals("cuda"))) + if (!llvm::StringSwitch(FPAccuracy) + .Case("default", true) + .Case("high", true) + .Case("low", true) + .Case("medium", true) + .Case("sycl", true) + .Case("cuda", true) + .Default(false)) Diags.Report(diag::err_drv_unsupported_option_argument) << "ffp-accuracy" << FPAccuracy; if (!Opts.FPAccuracyVal.empty()) diff --git a/clang/test/Driver/fp-accuracy.c b/clang/test/Driver/fp-accuracy.c index 5f054604ae48a..43db9670b5880 100644 --- a/clang/test/Driver/fp-accuracy.c +++ b/clang/test/Driver/fp-accuracy.c @@ -7,6 +7,12 @@ // RUN: %clang -### -target x86_64 -ffp-accuracy=medium -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=MEDIUM %s +// RUN: %clang -### -target x86_64 -ffp-accuracy=sycl -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=SYCL %s + +// RUN: %clang -### -target x86_64 -ffp-accuracy=cuda -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CUDA %s + // RUN: %clang -### -target x86_64 -ffp-accuracy=low:sin,cos -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=FUNC-1 %s @@ -46,6 +52,8 @@ // HIGH: "-ffp-builtin-accuracy=high" // LOW: "-ffp-builtin-accuracy=low" // MEDIUM: "-ffp-builtin-accuracy=medium" +// SYCL: "-ffp-builtin-accuracy=sycl" +// CUDA: "-ffp-builtin-accuracy=cuda" // FUNC-1: "-ffp-builtin-accuracy=low:sin,cos" // FUNC-2: "-ffp-builtin-accuracy=low:sin,cos high:tan" // ERR: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' From 02831e81357d3c5bbf5127a943f7b068fd93facf Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Fri, 26 May 2023 09:49:10 -0400 Subject: [PATCH 37/43] Responded to review comments. --- clang/lib/CodeGen/CGBuiltin.cpp | 10 ++++------ clang/lib/CodeGen/CGCall.cpp | 12 +++++++++--- clang/lib/Driver/ToolChains/Clang.cpp | 4 ++-- clang/lib/Frontend/CompilerInvocation.cpp | 8 +++----- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 294976334b2cf..2fb320eaf82f9 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -496,7 +496,7 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, StringRef Name, llvm::CallInst *CI = CGF.Builder.CreateCall(FPBuiltinF, Args); llvm::AttributeList AttrList; // sincos() doesn 't return a value, but it still has a type associated with - // it that corresponds the operand type. + // it that corresponds to the operand type. if (Name == "sincos") CGF.CGM.getFPAccuracyFuncAttributes(Name, AttrList, ID, Args[0]->getType()); else @@ -21895,7 +21895,6 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( llvm::Value *FnPtr, const FunctionDecl *FD) { llvm::Function *Func; unsigned FPAccuracyIntrinsicID = 0; - llvm::CallInst *CI = nullptr; StringRef Name; if (CurrentBuiltinID == 0) { // Even if the current function doesn't have a clang builtin, create @@ -21916,7 +21915,7 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( .Default(-1); assert(FPAccuracyIntrinsicID != -1 && "unexpected fpbuiltin ID"); } else { - return CI; + return nullptr; } } else { // The function has a clang builtin. Create an attribute for it @@ -21998,9 +21997,8 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( } } Func = CGM.getIntrinsic(FPAccuracyIntrinsicID, IRArgs[0]->getType()); - CI = CreateBuiltinCallWithAttr(*this, Name, Func, ArrayRef(IRArgs), - FPAccuracyIntrinsicID); - return CI; + return CreateBuiltinCallWithAttr(*this, Name, Func, ArrayRef(IRArgs), + FPAccuracyIntrinsicID); } Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index bea03d51d071b..06234c832fa07 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1849,8 +1849,14 @@ static llvm::fp::FPAccuracy convertFPAccuracy(StringRef FPAccuracyStr) { void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( StringRef Name, llvm::AttrBuilder &FuncAttrs, unsigned ID, const llvm::Type *FuncType) { - // First check that a specific accuracy hasn't been requested for this - // function. + // Priority is given to to the accuracy specific to the function. + // So, for example if the command line is something like this: + // 'clang -fp-accuracy = high -fp-accuracy = low:[sin]'. + // This means, all library functions will have the accuracy 'high' + // except 'sin', which should have an accuracy value of 'low'. To + // ensure that, first check that a specific accuracy hasn't been + // requested for this function, by visiting the 'FPAccuracyFuncMap', then + // set the accuracy for all other functions than 'sin'. if (!getLangOpts().FPAccuracyFuncMap.empty()) { auto FuncMapIt = getLangOpts().FPAccuracyFuncMap.find(Name.str()); if (FuncMapIt != getLangOpts().FPAccuracyFuncMap.end()) { @@ -5595,7 +5601,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Attrs = AllocAlignAttrEmitter.TryEmitAsCallSiteAttribute(Attrs); // Emit the actual call/invoke instruction. - llvm::CallBase *CI = nullptr; + llvm::CallBase *CI; if (!InvokeDest) { if (CGM.getCodeGenOpts().FPAccuracy) { const auto *FD = dyn_cast_or_null(TargetDecl); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index f474672041895..a069476e34989 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2897,7 +2897,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, HonorNaNs = true; ApproxFunc = false; // Turning *off* -ffast-math restores the toolchain default, - // unless the -fp-accuracy is used. + // unless -fp-accuracy is used. if (FPAccuracy.empty()) MathErrno = TC.IsMathErrnoDefault(); AssociativeMath = false; @@ -3167,7 +3167,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, HonorNaNs = true; // Turning on -ffast-math (with either flag) removes the need for // MathErrno. However, turning *off* -ffast-math merely restores the - // toolchain default (which may be false). Unless -fp-accuracy is used. + // toolchain default (which may be false), unless -fp-accuracy is used. if (FPAccuracy.empty()) MathErrno = TC.IsMathErrnoDefault(); AssociativeMath = false; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 19e1167c273fb..8fc73c458d312 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2012,7 +2012,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, } } - if (Arg *A = Args.getLastArg(options::OPT_ffp_builtin_accuracy_EQ)) + if (Args.getLastArg(options::OPT_ffp_builtin_accuracy_EQ)) Opts.FPAccuracy = 1; if (auto *arg = @@ -3309,14 +3309,12 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, #include "clang/Driver/Options.inc" #undef LANG_OPTION_WITH_MARSHALLING - if (!Opts.FPAccuracyVal.empty()) { + if (!Opts.FPAccuracyVal.empty()) GenerateArg(Args, OPT_ffp_builtin_accuracy_EQ, Opts.FPAccuracyVal, SA); - } - for (const auto &F : Opts.FPAccuracyFuncMap) { + for (const auto &F : Opts.FPAccuracyFuncMap) GenerateArg(Args, OPT_ffp_builtin_accuracy_EQ, (F.second + ":" + F.first), SA); - } // The '-fcf-protection=' option is generated by CodeGenOpts generator. From c3f2ca2882fc9bdbdc5c4295c385b2226f4fc0bd Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 30 May 2023 10:54:41 -0400 Subject: [PATCH 38/43] Fix format. --- clang/lib/CodeGen/CGBuiltin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 30cd7e2365824..c1b56dfa6d3ac 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -523,8 +523,8 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, StringRef Name, } static Function *getIntrinsic(CodeGenFunction &CGF, llvm::Value *Src0, - unsigned FPIntrinsicID, unsigned IntrinsicID, - bool HasAccuracyRequirement) { + unsigned FPIntrinsicID, unsigned IntrinsicID, + bool HasAccuracyRequirement) { return HasAccuracyRequirement ? CGF.CGM.getIntrinsic(FPIntrinsicID, Src0->getType()) : CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); From a3803dba6b19afd4cc1e9456fbe98decc3fa4162 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Wed, 31 May 2023 17:20:08 -0400 Subject: [PATCH 39/43] Re-wrote the condition to make it more readable. Edited the comment and added a new run line to support the change for this condition. --- clang/lib/CodeGen/CGCall.cpp | 27 ++++++++----------- clang/test/CodeGen/fp-accuracy.c | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 0aebf7ef576fe..2a7521d2d03b3 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1850,13 +1850,13 @@ void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( StringRef Name, llvm::AttrBuilder &FuncAttrs, unsigned ID, const llvm::Type *FuncType) { // Priority is given to to the accuracy specific to the function. - // So, for example if the command line is something like this: + // So, if the command line is something like this: // 'clang -fp-accuracy = high -fp-accuracy = low:[sin]'. // This means, all library functions will have the accuracy 'high' - // except 'sin', which should have an accuracy value of 'low'. To - // ensure that, first check that a specific accuracy hasn't been - // requested for this function, by visiting the 'FPAccuracyFuncMap', then - // set the accuracy for all other functions than 'sin'. + // except 'sin', which should have an accuracy value of 'low'. + // To ensure that, first check if Name has a required accuracy by visiting + // the 'FPAccuracyFuncMap'; if no accuracy is mapped to Name (FuncAttrs + // is empty), then set its accuracy from the TU's accuracy value. if (!getLangOpts().FPAccuracyFuncMap.empty()) { auto FuncMapIt = getLangOpts().FPAccuracyFuncMap.find(Name.str()); if (FuncMapIt != getLangOpts().FPAccuracyFuncMap.end()) { @@ -1866,18 +1866,13 @@ void CodeGenModule::getDefaultFunctionFPAccuracyAttributes( FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); } } - if (!getLangOpts().FPAccuracyVal.empty()) { - StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( - ID, FuncType, convertFPAccuracy(getLangOpts().FPAccuracyVal)); - assert(!FPAccuracyVal.empty() && "A valid accuracy value is expected"); - if (FuncAttrs.attrs().size() == 0) - // No specific accuracy has been requested for this function. - // Add the general accuracy value to the attribute list. + if (FuncAttrs.attrs().size() == 0) + if (!getLangOpts().FPAccuracyVal.empty()) { + StringRef FPAccuracyVal = llvm::fp::getAccuracyForFPBuiltin( + ID, FuncType, convertFPAccuracy(getLangOpts().FPAccuracyVal)); + assert(!FPAccuracyVal.empty() && "A valid accuracy value is expected"); FuncAttrs.addAttribute("fpbuiltin-max-error=", FPAccuracyVal); - else - assert(FuncAttrs.attrs().size() == 1 && - "Expected an attribute has already been mapped to the function"); - } + } } /// Add denormal-fp-math and denormal-fp-math-f32 as appropriate for the diff --git a/clang/test/CodeGen/fp-accuracy.c b/clang/test/CodeGen/fp-accuracy.c index d05a7d50e8390..7cc5296089adc 100644 --- a/clang/test/CodeGen/fp-accuracy.c +++ b/clang/test/CodeGen/fp-accuracy.c @@ -12,6 +12,11 @@ // RUN: -Wno-return-type -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CHECK-F2 %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown \ +// RUN: "-ffp-builtin-accuracy=high low:[tan] medium:[sincos,log10]" \ +// RUN: -Wno-return-type -Wno-implicit-function-declaration -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefix=CHECK-F3 %s + // RUN: %clang_cc1 -triple spir64-unknown-unknown -ffp-builtin-accuracy=sycl \ // RUN: -D SPIR -Wno-implicit-function-declaration -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CHECK-SPIR %s @@ -148,6 +153,46 @@ double rsqrt(double); // CHECK-F2: call double @llvm.fpbuiltin.tan.f64(double {{.*}}) #[[ATTR_F2_HIGH:[0-9]+]] // CHECK-F2: call double @llvm.fpbuiltin.tanh.f64(double {{.*}}) #[[ATTR_F2_MEDIUM]] // +// CHECK-F3-LABEL: define dso_local void @f1 +// CHECK-F3: call double @llvm.fpbuiltin.acos.f64(double %conv) #[[ATTR_F3_HIGH:[0-9]+]] +// CHECK-F3: call double @llvm.fpbuiltin.acosh.f64(double %conv2) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.asin.f64(double %conv4) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.asinh.f64(double %conv6) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.atan.f64(double %conv8) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.atan2.f64(double %conv10, double %conv11) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.atanh.f64(double %conv13) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.cos.f64(double %conv15) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.cosh.f64(double %conv17) #[[ATTR_F3_HIGH]] +// CHECk-F3: call double @llvm.fpbuiltin.erf.f64(double %conv19) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.erfc.f64(double %conv21) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.exp.f64(double %conv23) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.exp10.f64(double %conv25) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.exp2.f64(double %conv27) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.expm1.f64(double %conv29) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.fadd.f64(double %conv31, double %conv32) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.fdiv.f64(double %conv34, double %conv35) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.fmul.f64(double %conv37, double %conv38) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.frem.f64(double %conv40, double %conv41) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.fsub.f64(double %conv43, double %conv44) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.hypot.f64(double %conv46, double %conv47) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.ldexp.f64(double %conv49, i32 %conv50) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.log.f64(double %conv52) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.log10.f64(double %conv54) #[[ATTR_F3_MEDIUM:[0-9]+]] +// CHECK-F3: call double @llvm.fpbuiltin.log1p.f64(double %conv56) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.log2.f64(double %conv58) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.pow.f64(double %conv60, double %conv61) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.rsqrt.f64(double %conv63) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.sin.f64(double %conv65) #[[ATTR_F3_HIGH]] +// CHECK-F3: call void @llvm.fpbuiltin.sincos.f64(double %conv67, ptr %p1, ptr %p2) #[[ATTR_F3_MEDIUM]] +// CHECK-F3: call double @llvm.fpbuiltin.sinh.f64(double %conv68) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.sqrt.f64(double %conv70) #[[ATTR_F3_HIGH]] +// CHECK-F3: call double @llvm.fpbuiltin.tan.f64(double %conv72) #[[ATTR_F3_LOW:[0-9]+]] +// CHECK-F3: call double @llvm.fpbuiltin.tanh.f64(double %conv74) #[[ATTR_F3_HIGH]] + +// CHECK-F3: attributes #[[ATTR_F3_HIGH]] = {{.*}}"fpbuiltin-max-error="="1.0f" +// CHECK-F3: attributes #[[ATTR_F3_MEDIUM]] = {{.*}}"fpbuiltin-max-error="="4.0f" +// CHECK-F3: attributes #[[ATTR_F3_LOW]] = {{.*}}"fpbuiltin-max-error="="67108864.0f" +// // CHECK-SPIR-LABEL: define dso_local spir_func void @f1 // CHECK-SPIR: call double @llvm.fpbuiltin.acos.f64(double {{.*}}) #[[ATTR_SYCL1:[0-9]+]] // CHECK-SPIR: call double @llvm.fpbuiltin.acosh.f64(double {{.*}}) #[[ATTR_SYCL1]] From 98ed36d62618d5103d0da3bc5049a17825be7b32 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Tue, 6 Jun 2023 11:05:42 -0400 Subject: [PATCH 40/43] Responded to review comments. --- clang/include/clang/Basic/LangOptions.h | 1 - clang/lib/CodeGen/CGBuiltin.cpp | 26 +++++--------- clang/lib/CodeGen/CGCall.cpp | 2 +- clang/lib/Driver/ToolChains/Clang.cpp | 8 ++--- clang/lib/Frontend/CompilerInvocation.cpp | 42 ++++++++++------------- clang/test/Driver/fp-accuracy.c | 6 ++-- 6 files changed, 35 insertions(+), 50 deletions(-) diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index f8c8bd8d303d6..04ec54cc43973 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -22,7 +22,6 @@ #include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/Visibility.h" #include "llvm/ADT/FloatingPointMode.h" -#include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/TargetParser/Triple.h" #include diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c1b56dfa6d3ac..70dc0c5476a96 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -511,13 +511,11 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, StringRef Name, unsigned ID) { llvm::CallInst *CI = CGF.Builder.CreateCall(FPBuiltinF, Args); llvm::AttributeList AttrList; - // sincos() doesn 't return a value, but it still has a type associated with + // sincos() doesn't return a value, but it still has a type associated with // it that corresponds to the operand type. - if (Name == "sincos") - CGF.CGM.getFPAccuracyFuncAttributes(Name, AttrList, ID, Args[0]->getType()); - else - CGF.CGM.getFPAccuracyFuncAttributes(Name, AttrList, ID, - FPBuiltinF->getReturnType()); + CGF.CGM.getFPAccuracyFuncAttributes( + Name, AttrList, ID, + Name == "sincos" ? Args[0]->getType() : FPBuiltinF->getReturnType()); CI->setAttributes(AttrList); return CI; } @@ -533,12 +531,8 @@ static Function *getIntrinsic(CodeGenFunction &CGF, llvm::Value *Src0, static bool hasAccuracyRequirement(CodeGenFunction &CGF, StringRef Name) { if (!CGF.getLangOpts().FPAccuracyVal.empty()) return true; - if (!CGF.getLangOpts().FPAccuracyFuncMap.empty()) { - auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); - if (FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end()) - return true; - } - return false; + auto FuncMapIt = CGF.getLangOpts().FPAccuracyFuncMap.find(Name.str()); + return FuncMapIt != CGF.getLangOpts().FPAccuracyFuncMap.end(); } // Emit a simple mangled intrinsic that has 1 argument and a return type @@ -554,8 +548,8 @@ static Value *emitUnaryMaybeConstrainedFPBuiltin( if (CGF.getLangOpts().MathErrno) { DiagnosticsEngine &Diags = CGF.CGM.getDiags(); Diags.Report(E->getBeginLoc(), diag::err_drv_incompatible_options) - << "ffp-accuracy" - << "fmath-errno"; + << "-ffp-accuracy" + << "-fmath-errno"; } else { StringRef Name = CGF.CGM.getContext().BuiltinInfo.getName(CGF.getCurrentBuiltinID()); @@ -21954,9 +21948,7 @@ llvm::CallInst *CodeGenFunction::EmitFPBuiltinIndirectCall( .Case("frem", llvm::Intrinsic::fpbuiltin_frem) .Case("sincos", llvm::Intrinsic::fpbuiltin_sincos) .Case("exp10", llvm::Intrinsic::fpbuiltin_exp10) - .Case("rsqrt", llvm::Intrinsic::fpbuiltin_rsqrt) - .Default(-1); - assert(FPAccuracyIntrinsicID != -1 && "unexpected fpbuiltin ID"); + .Case("rsqrt", llvm::Intrinsic::fpbuiltin_rsqrt); } else { return nullptr; } diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 2a7521d2d03b3..2ae6269299f5b 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -5621,7 +5621,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::CallBase *CI; if (!InvokeDest) { if (CGM.getCodeGenOpts().FPAccuracy) { - const auto *FD = dyn_cast_or_null(TargetDecl); + const auto *FD = dyn_cast_if_present(TargetDecl); assert(FD && "expecting a function"); CI = EmitFPBuiltinIndirectCall(IRFuncTy, IRCallArgs, CalleePtr, FD); if (CI) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 35055f08b82c7..badc0fdd3258f 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6062,15 +6062,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } std::string FpAccuracyAttr; - auto RenderFPAccuracyOptions = [&FpAccuracyAttr](const Twine &optStr) { + auto RenderFPAccuracyOptions = [&FpAccuracyAttr](const Twine &OptStr) { // In case the value is 'default' don't add the -ffp-builtin-accuracy // attribute. - if (optStr.str() != "default") { + if (OptStr.str() != "default") { if (FpAccuracyAttr.empty()) - FpAccuracyAttr = std::move(std::string("-ffp-builtin-accuracy=")); + FpAccuracyAttr = "-ffp-builtin-accuracy="; else FpAccuracyAttr += " "; - FpAccuracyAttr += optStr.str(); + FpAccuracyAttr += OptStr.str(); } }; for (StringRef A : Args.getAllArgValues(options::OPT_ffp_accuracy_EQ)) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 75fc94f6e4dc9..2c9daa13ab568 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3580,6 +3580,20 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, GenerateArg(Args, OPT_fno_gpu_rdc, SA); } +static void checkFPAccuracyIsValid(StringRef ValElement, + DiagnosticsEngine &Diags) { + if (!llvm::StringSwitch(ValElement) + .Case("default", true) + .Case("high", true) + .Case("low", true) + .Case("medium", true) + .Case("sycl", true) + .Case("cuda", true) + .Default(false)) + Diags.Report(diag::err_drv_unsupported_option_argument) + << "-ffp-accuracy" << ValElement; +} + void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { for (StringRef Values : Args.getAllArgValues(OPT_ffp_builtin_accuracy_EQ)) { @@ -3593,17 +3607,7 @@ void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, Val.split(ValElement, ':'); // The option is of the form -ffp-accuracy=value. if (ValElement.size() == 1) { - StringRef FPAccuracy = ValElement[0]; - if (!llvm::StringSwitch(FPAccuracy) - .Case("default", true) - .Case("high", true) - .Case("low", true) - .Case("medium", true) - .Case("sycl", true) - .Case("cuda", true) - .Default(false)) - Diags.Report(diag::err_drv_unsupported_option_argument) - << "ffp-accuracy" << FPAccuracy; + checkFPAccuracyIsValid(ValElement[0], Diags); Opts.FPAccuracyVal = ValElement[0].str(); } // The option is of the form -ffp-accuracy=value:[f1, ... fn]. @@ -3622,25 +3626,15 @@ void CompilerInvocation::ParseFpAccuracyArgs(LangOptions &Opts, ArgList &Args, << FuncMap->second << FuncName.str(); } } else { - StringRef FPAccuracy = ValElement[0]; - if (!llvm::StringSwitch(FPAccuracy) - .Case("default", true) - .Case("high", true) - .Case("low", true) - .Case("medium", true) - .Case("sycl", true) - .Case("cuda", true) - .Default(false)) - Diags.Report(diag::err_drv_unsupported_option_argument) - << "ffp-accuracy" << FPAccuracy; + checkFPAccuracyIsValid(ValElement[0], Diags); if (!Opts.FPAccuracyVal.empty()) Diags.Report(diag::warn_function_fp_accuracy_already_set) << Opts.FPAccuracyVal << FuncName.str(); // No need to fill the map if the FPaccuracy is 'default'. // The default builtin will be generated. - if (!FPAccuracy.equals("default")) + if (!ValElement[0].equals("default")) Opts.FPAccuracyFuncMap.insert( - {FuncName.str(), FPAccuracy.str()}); + {FuncName.str(), ValElement[0].str()}); } } } diff --git a/clang/test/Driver/fp-accuracy.c b/clang/test/Driver/fp-accuracy.c index 43db9670b5880..e13c2dfc657f1 100644 --- a/clang/test/Driver/fp-accuracy.c +++ b/clang/test/Driver/fp-accuracy.c @@ -56,9 +56,9 @@ // CUDA: "-ffp-builtin-accuracy=cuda" // FUNC-1: "-ffp-builtin-accuracy=low:sin,cos" // FUNC-2: "-ffp-builtin-accuracy=low:sin,cos high:tan" -// ERR: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' -// ERR-1: (frontend): unsupported argument 'foo' to option 'ffp-accuracy' -// ERR-2: (frontend): unsupported argument 'high=[sin]' to option 'ffp-accuracy' +// ERR: (frontend): unsupported argument 'foo' to option '-ffp-accuracy' +// ERR-1: (frontend): unsupported argument 'foo' to option '-ffp-accuracy' +// ERR-2: (frontend): unsupported argument 'high=[sin]' to option '-ffp-accuracy' // WARN: (frontend): floating point accuracy value of 'high' has already been assigned to function 'cos' // WARN: (frontend): floating point accuracy value of 'high' has already been assigned to function 'sin' // ERR-3: (frontend): floating point accuracy requirements cannot be guaranteed when '-fmath-errno' is enabled; use '-fno-math-errno' to enable floating point accuracy control From d3d470e2494d105ef309a0b20883e1d41ed61257 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 12 Jun 2023 12:27:50 -0400 Subject: [PATCH 41/43] Responded to review for CmakeLists.txt. --- llvm/lib/IR/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt index 6793252ae0507..b19620b36acc5 100644 --- a/llvm/lib/IR/CMakeLists.txt +++ b/llvm/lib/IR/CMakeLists.txt @@ -23,7 +23,6 @@ add_llvm_component_library(LLVMCore EHPersonalities.cpp FPAccuracy.cpp FPEnv.cpp - FPAccuracy.cpp Function.cpp GCStrategy.cpp GVMaterializer.cpp From e08362e8942d7a4d2aea9d332669de5e355e4f03 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 12 Jun 2023 14:26:34 -0400 Subject: [PATCH 42/43] Responded to review about the AttrList. --- clang/lib/CodeGen/CGBuiltin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 2bd7bcabac06c..c74c6f30a7dbc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -510,6 +510,8 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, StringRef Name, ArrayRef Args, unsigned ID) { llvm::CallInst *CI = CGF.Builder.CreateCall(FPBuiltinF, Args); + // TODO: Replace AttrList a single attribute. The call can only have a + // single FPAccuracy attribute. llvm::AttributeList AttrList; // sincos() doesn't return a value, but it still has a type associated with // it that corresponds to the operand type. From 6d5890db7826f1ee0129c40bfc507983466148d8 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 12 Jun 2023 14:49:01 -0400 Subject: [PATCH 43/43] Fixed typo. --- clang/lib/CodeGen/CGBuiltin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c74c6f30a7dbc..6913860314308 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -510,7 +510,7 @@ static CallInst *CreateBuiltinCallWithAttr(CodeGenFunction &CGF, StringRef Name, ArrayRef Args, unsigned ID) { llvm::CallInst *CI = CGF.Builder.CreateCall(FPBuiltinF, Args); - // TODO: Replace AttrList a single attribute. The call can only have a + // TODO: Replace AttrList with a single attribute. The call can only have a // single FPAccuracy attribute. llvm::AttributeList AttrList; // sincos() doesn't return a value, but it still has a type associated with