Skip to content

Commit 6034dce

Browse files
SC llvm teamSC llvm team
authored andcommitted
Merged main:a90e215dfbc9 into amd-gfx:57a10ab39b40
Local branch amd-gfx 57a10ab Merged main:2c729d29aa13 into amd-gfx:849d627d66d9 Remote branch main a90e215 [SimpleLoopUnswitch] Regenerate test checks (NFC)
2 parents 57a10ab + a90e215 commit 6034dce

32 files changed

+1985
-476
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4629,6 +4629,22 @@ The pragma can take two values: ``on`` and ``off``.
46294629
float v = t + z;
46304630
}
46314631
4632+
``#pragma clang fp reciprocal`` allows control over using reciprocal
4633+
approximations in floating point expressions. When enabled, this
4634+
pragma allows the expression ``x / y`` to be approximated as ``x *
4635+
(1.0 / y)``. This pragma can be used to disable reciprocal
4636+
approximation when it is otherwise enabled for the translation unit
4637+
with the ``-freciprocal-math`` flag or other fast-math options. The
4638+
pragma can take two values: ``on`` and ``off``.
4639+
4640+
.. code-block:: c++
4641+
4642+
float f(float x, float y)
4643+
{
4644+
// Enable floating point reciprocal approximation
4645+
#pragma clang fp reciprocal(on)
4646+
return x / y;
4647+
}
46324648
46334649
``#pragma clang fp contract`` specifies whether the compiler should
46344650
contract a multiply and an addition (or subtraction) into a fused FMA

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ Non-comprehensive list of changes in this release
228228
* ``__builtin_classify_type()`` now classifies ``_BitInt`` values as the return value ``18``
229229
and vector types as return value ``19``, to match GCC 14's behavior.
230230

231+
* Added ``#pragma clang fp reciprocal``.
232+
231233
New Compiler Flags
232234
------------------
233235

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1594,12 +1594,13 @@ def note_pragma_loop_invalid_vectorize_option : Note<
15941594
"vectorize_width(X, scalable) where X is an integer, or vectorize_width('fixed' or 'scalable')">;
15951595

15961596
def err_pragma_fp_invalid_option : Error<
1597-
"%select{invalid|missing}0 option%select{ %1|}0; expected 'contract', 'reassociate' or 'exceptions'">;
1597+
"%select{invalid|missing}0 option%select{ %1|}0; expected 'contract', 'reassociate', 'reciprocal', or 'exceptions'">;
15981598
def err_pragma_fp_invalid_argument : Error<
15991599
"unexpected argument '%0' to '#pragma clang fp %1'; expected "
16001600
"%select{"
16011601
"'fast' or 'on' or 'off'|"
16021602
"'on' or 'off'|"
1603+
"'on' or 'off'|"
16031604
"'ignore', 'maytrap' or 'strict'|"
16041605
"'source', 'double' or 'extended'}2">;
16051606

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6759,7 +6759,7 @@ def warn_floatingpoint_eq : Warning<
67596759

67606760
def err_setting_eval_method_used_in_unsafe_context : Error <
67616761
"%select{'#pragma clang fp eval_method'|option 'ffp-eval-method'}0 cannot be used with "
6762-
"%select{option 'fapprox-func'|option 'mreassociate'|option 'freciprocal'|option 'ffp-eval-method'|'#pragma clang fp reassociate'}1">;
6762+
"%select{option 'fapprox-func'|option 'mreassociate'|option 'freciprocal'|option 'ffp-eval-method'|'#pragma clang fp reassociate'|'#pragma clang fp reciprocal'}1">;
67636763

67646764
def warn_remainder_division_by_zero : Warning<
67656765
"%select{remainder|division}0 by zero is undefined">,

clang/include/clang/Basic/PragmaKinds.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ enum PragmaFloatControlKind {
3434
PFC_Push, // #pragma float_control(push)
3535
PFC_Pop // #pragma float_control(pop)
3636
};
37+
38+
enum PragmaFPKind {
39+
PFK_Contract, // #pragma clang fp contract
40+
PFK_Reassociate, // #pragma clang fp reassociate
41+
PFK_Reciprocal, // #pragma clang fp reciprocal
42+
PFK_Exceptions, // #pragma clang fp exceptions
43+
PFK_EvalMethod // #pragma clang fp eval_method
44+
};
3745
}
3846

3947
#endif

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11002,7 +11002,10 @@ class Sema final {
1100211002

1100311003
/// Called on well formed
1100411004
/// \#pragma clang fp reassociate
11005-
void ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled);
11005+
/// or
11006+
/// \#pragma clang fp reciprocal
11007+
void ActOnPragmaFPValueChangingOption(SourceLocation Loc, PragmaFPKind Kind,
11008+
bool IsEnabled);
1100611009

1100711010
/// ActOnPragmaFenvAccess - Called on well formed
1100811011
/// \#pragma STDC FENV_ACCESS

clang/lib/Parse/ParsePragma.cpp

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3233,11 +3233,11 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
32333233
namespace {
32343234
/// Used as the annotation value for tok::annot_pragma_fp.
32353235
struct TokFPAnnotValue {
3236-
enum FlagKinds { Contract, Reassociate, Exceptions, EvalMethod };
32373236
enum FlagValues { On, Off, Fast };
32383237

32393238
std::optional<LangOptions::FPModeKind> ContractValue;
32403239
std::optional<LangOptions::FPModeKind> ReassociateValue;
3240+
std::optional<LangOptions::FPModeKind> ReciprocalValue;
32413241
std::optional<LangOptions::FPExceptionModeKind> ExceptionsValue;
32423242
std::optional<LangOptions::FPEvalMethodKind> EvalMethodValue;
32433243
};
@@ -3261,12 +3261,12 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
32613261
IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
32623262

32633263
auto FlagKind =
3264-
llvm::StringSwitch<std::optional<TokFPAnnotValue::FlagKinds>>(
3265-
OptionInfo->getName())
3266-
.Case("contract", TokFPAnnotValue::Contract)
3267-
.Case("reassociate", TokFPAnnotValue::Reassociate)
3268-
.Case("exceptions", TokFPAnnotValue::Exceptions)
3269-
.Case("eval_method", TokFPAnnotValue::EvalMethod)
3264+
llvm::StringSwitch<std::optional<PragmaFPKind>>(OptionInfo->getName())
3265+
.Case("contract", PFK_Contract)
3266+
.Case("reassociate", PFK_Reassociate)
3267+
.Case("exceptions", PFK_Exceptions)
3268+
.Case("eval_method", PFK_EvalMethod)
3269+
.Case("reciprocal", PFK_Reciprocal)
32703270
.Default(std::nullopt);
32713271
if (!FlagKind) {
32723272
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
@@ -3282,7 +3282,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
32823282
}
32833283
PP.Lex(Tok);
32843284
bool isEvalMethodDouble =
3285-
Tok.is(tok::kw_double) && FlagKind == TokFPAnnotValue::EvalMethod;
3285+
Tok.is(tok::kw_double) && FlagKind == PFK_EvalMethod;
32863286

32873287
// Don't diagnose if we have an eval_metod pragma with "double" kind.
32883288
if (Tok.isNot(tok::identifier) && !isEvalMethodDouble) {
@@ -3293,7 +3293,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
32933293
}
32943294
const IdentifierInfo *II = Tok.getIdentifierInfo();
32953295

3296-
if (FlagKind == TokFPAnnotValue::Contract) {
3296+
if (FlagKind == PFK_Contract) {
32973297
AnnotValue->ContractValue =
32983298
llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>(
32993299
II->getName())
@@ -3306,19 +3306,20 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
33063306
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
33073307
return;
33083308
}
3309-
} else if (FlagKind == TokFPAnnotValue::Reassociate) {
3310-
AnnotValue->ReassociateValue =
3311-
llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>(
3312-
II->getName())
3313-
.Case("on", LangOptions::FPModeKind::FPM_On)
3314-
.Case("off", LangOptions::FPModeKind::FPM_Off)
3315-
.Default(std::nullopt);
3316-
if (!AnnotValue->ReassociateValue) {
3309+
} else if (FlagKind == PFK_Reassociate || FlagKind == PFK_Reciprocal) {
3310+
auto &Value = FlagKind == PFK_Reassociate ? AnnotValue->ReassociateValue
3311+
: AnnotValue->ReciprocalValue;
3312+
Value = llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>(
3313+
II->getName())
3314+
.Case("on", LangOptions::FPModeKind::FPM_On)
3315+
.Case("off", LangOptions::FPModeKind::FPM_Off)
3316+
.Default(std::nullopt);
3317+
if (!Value) {
33173318
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
33183319
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
33193320
return;
33203321
}
3321-
} else if (FlagKind == TokFPAnnotValue::Exceptions) {
3322+
} else if (FlagKind == PFK_Exceptions) {
33223323
AnnotValue->ExceptionsValue =
33233324
llvm::StringSwitch<std::optional<LangOptions::FPExceptionModeKind>>(
33243325
II->getName())
@@ -3331,7 +3332,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
33313332
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
33323333
return;
33333334
}
3334-
} else if (FlagKind == TokFPAnnotValue::EvalMethod) {
3335+
} else if (FlagKind == PFK_EvalMethod) {
33353336
AnnotValue->EvalMethodValue =
33363337
llvm::StringSwitch<std::optional<LangOptions::FPEvalMethodKind>>(
33373338
II->getName())
@@ -3437,9 +3438,15 @@ void Parser::HandlePragmaFP() {
34373438
reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue());
34383439

34393440
if (AnnotValue->ReassociateValue)
3440-
Actions.ActOnPragmaFPReassociate(Tok.getLocation(),
3441-
*AnnotValue->ReassociateValue ==
3442-
LangOptions::FPModeKind::FPM_On);
3441+
Actions.ActOnPragmaFPValueChangingOption(
3442+
Tok.getLocation(), PFK_Reassociate,
3443+
*AnnotValue->ReassociateValue == LangOptions::FPModeKind::FPM_On);
3444+
3445+
if (AnnotValue->ReciprocalValue)
3446+
Actions.ActOnPragmaFPValueChangingOption(
3447+
Tok.getLocation(), PFK_Reciprocal,
3448+
*AnnotValue->ReciprocalValue == LangOptions::FPModeKind::FPM_On);
3449+
34433450
if (AnnotValue->ContractValue)
34443451
Actions.ActOnPragmaFPContract(Tok.getLocation(),
34453452
*AnnotValue->ContractValue);

clang/lib/Sema/SemaAttr.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,7 +1285,8 @@ void Sema::ActOnPragmaFPContract(SourceLocation Loc,
12851285
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
12861286
}
12871287

1288-
void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) {
1288+
void Sema::ActOnPragmaFPValueChangingOption(SourceLocation Loc,
1289+
PragmaFPKind Kind, bool IsEnabled) {
12891290
if (IsEnabled) {
12901291
// For value unsafe context, combining this pragma with eval method
12911292
// setting is not recommended. See comment in function FixupInvocation#506.
@@ -1301,10 +1302,21 @@ void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) {
13011302
Reason = 0;
13021303
if (Reason != -1)
13031304
Diag(Loc, diag::err_setting_eval_method_used_in_unsafe_context)
1304-
<< Reason << 4;
1305+
<< Reason << (Kind == PFK_Reassociate ? 4 : 5);
13051306
}
1307+
13061308
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
1307-
NewFPFeatures.setAllowFPReassociateOverride(IsEnabled);
1309+
switch (Kind) {
1310+
case PFK_Reassociate:
1311+
NewFPFeatures.setAllowFPReassociateOverride(IsEnabled);
1312+
break;
1313+
case PFK_Reciprocal:
1314+
NewFPFeatures.setAllowReciprocalOverride(IsEnabled);
1315+
break;
1316+
default:
1317+
llvm_unreachable("unhandled value changing pragma fp");
1318+
}
1319+
13081320
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
13091321
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
13101322
}

clang/lib/Sema/SemaInit.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10628,7 +10628,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
1062810628

1062910629
bool AllowExplicit = !Kind.isCopyInit() || ListInit;
1063010630

10631-
// Return true is the candidate is added successfully, false otherwise.
10631+
// Return true if the candidate is added successfully, false otherwise.
1063210632
auto addDeductionCandidate = [&](FunctionTemplateDecl *TD,
1063310633
CXXDeductionGuideDecl *GD,
1063410634
DeclAccessPair FoundDecl,
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,DEFAULT %s
2+
// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -freciprocal-math -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,FLAG %s
3+
4+
float base(float a, float b, float c) {
5+
// CHECK-LABEL: _Z4basefff
6+
// FLAG: %[[A:.+]] = fdiv arcp float %b, %c
7+
// FLAG: %[[M:.+]] = fdiv arcp float %[[A]], %b
8+
// FLAG-NEXT: fadd arcp float %[[M]], %c
9+
10+
// DEFAULT: %[[A:.+]] = fdiv float %b, %c
11+
// DEFAULT: %[[M:.+]] = fdiv float %[[A]], %b
12+
// DEFAULT-NEXT: fadd float %[[M]], %c
13+
a = b / c;
14+
return a / b + c;
15+
}
16+
17+
// Simple case
18+
float fp_recip_simple(float a, float b, float c) {
19+
// CHECK-LABEL: _Z15fp_recip_simplefff
20+
// CHECK: %[[A:.+]] = fdiv arcp float %b, %c
21+
// CHECK: %[[M:.+]] = fdiv arcp float %[[A]], %b
22+
// CHECK-NEXT: fadd arcp float %[[M]], %c
23+
#pragma clang fp reciprocal(on)
24+
a = b / c;
25+
return a / b + c;
26+
}
27+
28+
// Test interaction with -freciprocal-math
29+
float fp_recip_disable(float a, float b, float c) {
30+
// CHECK-LABEL: _Z16fp_recip_disablefff
31+
// CHECK: %[[A:.+]] = fdiv float %b, %c
32+
// CHECK: %[[M:.+]] = fdiv float %[[A]], %b
33+
// CHECK-NEXT: fadd float %[[M]], %c
34+
#pragma clang fp reciprocal(off)
35+
a = b / c;
36+
return a / b + c;
37+
}
38+
39+
float fp_recip_with_reassoc_simple(float a, float b, float c) {
40+
// CHECK-LABEL: _Z28fp_recip_with_reassoc_simplefff
41+
// CHECK: %[[A:.+]] = fmul reassoc arcp float %b, %c
42+
// CHECK: %[[M:.+]] = fdiv reassoc arcp float %b, %[[A]]
43+
// CHECK-NEXT: fadd reassoc arcp float %[[M]], %c
44+
#pragma clang fp reciprocal(on) reassociate(on)
45+
a = b / c;
46+
return a / b + c;
47+
}
48+
49+
// arcp pragma should only apply to its scope
50+
float fp_recip_scoped(float a, float b, float c) {
51+
// CHECK-LABEL: _Z15fp_recip_scopedfff
52+
// DEFAULT: %[[M:.+]] = fdiv float %a, %b
53+
// DEFAULT-NEXT: fadd float %[[M]], %c
54+
// FLAG: %[[M:.+]] = fdiv arcp float %a, %b
55+
// FLAG-NEXT: fadd arcp float %[[M]], %c
56+
{
57+
#pragma clang fp reciprocal(on)
58+
}
59+
return a / b + c;
60+
}
61+
62+
// arcp pragma should apply to templates as well
63+
class Foo {};
64+
Foo operator+(Foo, Foo);
65+
template <typename T>
66+
T template_recip(T a, T b, T c) {
67+
#pragma clang fp reciprocal(on)
68+
return ((a / b) - c) + c;
69+
}
70+
71+
float fp_recip_template(float a, float b, float c) {
72+
// CHECK-LABEL: _Z17fp_recip_templatefff
73+
// CHECK: %[[A1:.+]] = fdiv arcp float %a, %b
74+
// CHECK-NEXT: %[[A2:.+]] = fsub arcp float %[[A1]], %c
75+
// CHECK-NEXT: fadd arcp float %[[A2]], %c
76+
return template_recip<float>(a, b, c);
77+
}
78+
79+
// File Scoping should work across functions
80+
#pragma clang fp reciprocal(on)
81+
float fp_file_scope_on(float a, float b, float c) {
82+
// CHECK-LABEL: _Z16fp_file_scope_onfff
83+
// CHECK: %[[M1:.+]] = fdiv arcp float %a, %c
84+
// CHECK-NEXT: %[[M2:.+]] = fdiv arcp float %b, %c
85+
// CHECK-NEXT: fadd arcp float %[[M1]], %[[M2]]
86+
return (a / c) + (b / c);
87+
}
88+
89+
// Inner pragma has precedence
90+
float fp_file_scope_stop(float a, float b, float c) {
91+
// CHECK-LABEL: _Z18fp_file_scope_stopfff
92+
// CHECK: %[[A:.+]] = fdiv arcp float %a, %a
93+
// CHECK: %[[M1:.+]] = fdiv float %[[A]], %c
94+
// CHECK-NEXT: %[[M2:.+]] = fdiv float %b, %c
95+
// CHECK-NEXT: fsub float %[[M1]], %[[M2]]
96+
a = a / a;
97+
{
98+
#pragma clang fp reciprocal(off)
99+
return (a / c) - (b / c);
100+
}
101+
}
102+
103+
#pragma clang fp reciprocal(off)
104+
float fp_recip_off(float a, float b, float c) {
105+
// CHECK-LABEL: _Z12fp_recip_offfff
106+
// CHECK: %[[D1:.+]] = fdiv float %a, %c
107+
// CHECK-NEXT: %[[D2:.+]] = fdiv float %b, %c
108+
// CHECK-NEXT: fadd float %[[D1]], %[[D2]]
109+
return (a / c) + (b / c);
110+
}
111+
112+
// Takes latest flag
113+
float fp_recip_many(float a, float b, float c) {
114+
// CHECK-LABEL: _Z13fp_recip_manyfff
115+
// CHECK: %[[D1:.+]] = fdiv arcp float %a, %c
116+
// CHECK-NEXT: %[[D2:.+]] = fdiv arcp float %b, %c
117+
// CHECK-NEXT: fadd arcp float %[[D1]], %[[D2]]
118+
#pragma clang fp reciprocal(off) reciprocal(on)
119+
return (a / c) + (b / c);
120+
}
121+
122+
// Pragma does not propagate through called functions
123+
float helper_func(float a, float b, float c) { return a + b + c; }
124+
float fp_recip_call_helper(float a, float b, float c) {
125+
// CHECK-LABEL: _Z20fp_recip_call_helperfff
126+
// CHECK: %[[S1:.+]] = fadd float %a, %b
127+
// CHECK-NEXT: fadd float %[[S1]], %c
128+
#pragma clang fp reciprocal(on)
129+
return helper_func(a, b, c);
130+
}

clang/test/Parser/pragma-fp-contract.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,18 @@ float fp_reassoc_no_fast(float a, float b) {
3838
#pragma clang fp reassociate(fast)
3939
return a - b;
4040
}
41+
42+
float fp_recip_fail(float a, float b) {
43+
// CHECK-LABEL: fp_recip_fail
44+
// expected-error@+2{{'#pragma clang fp' can only appear at file scope or at the start of a compound statement}}
45+
float c = a + b;
46+
#pragma clang fp reciprocal(off)
47+
return c - b;
48+
}
49+
50+
float fp_recip_no_fast(float a, float b) {
51+
// CHECK-LABEL: fp_recip_no_fast
52+
// expected-error@+1{{unexpected argument 'fast' to '#pragma clang fp reciprocal'; expected 'on' or 'off'}}
53+
#pragma clang fp reciprocal(fast)
54+
return a - b;
55+
}

0 commit comments

Comments
 (0)