Skip to content

Commit 15b6edb

Browse files
committed
[clang] Macro for constant rounding mode
The forthcoming C standard defines pragma FENV_ROUND to support constant rounding mode. It also requires some functions to be evaluated with such mode, N3096 7.6.2p4 states: Within the scope of an FENV_ROUND pragma establishing a mode other than FE_DYNAMIC ... invocations of functions indicated in the table below, for which macro replacement has not been suppressed (7.1.4), shall be evaluated according to the specified constant rounding mode ... . Invocations of functions for which macro replacement has been suppressed and invocations of functions other than those indicated in the table below shall not be affected by constant rounding modes – they are affected by (and affect) only the dynamic mode. The way this requirement is formulated indicates that it could be implemented using preprocessor facility. Such implementation would require a builtin macro that is set in the region where pragma FENV_ROUND is in effect and reflects constant rounding mode. This change introduces macro __ROUNDING_MODE__, which is a string dependent on the constant rounding mode: FE_TOWARDZERO "_rtz" FE_TONEAREST "_rte" FE_DOWNWARD "_rtp" FE_UPWARD "_rtn" FE_TONEARESTFROMZERO "_rta" FE_DYNAMIC empty string All these values except "_rta" are OpenCL rounding mode modifiers. Default value, when no pragma FENV_ROUND is specified, is empty string. Concatenation of a function name with the builtin macro can be used to obtain name of the function variant for particular rounding mode, like "sin_rtz", or "__builtin_cos_rtd". The test "macro_rounding_mode.c" added in this change provides an example of possible use. The macro is implemented in the same way as FLT_EVAL_METHOD, which also depends on the results of semantic analysis.
1 parent 643f361 commit 15b6edb

File tree

5 files changed

+94
-0
lines changed

5 files changed

+94
-0
lines changed

clang/include/clang/Lex/Preprocessor.h

+12
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ class Preprocessor {
181181
IdentifierInfo *Ident__is_target_variant_os;
182182
IdentifierInfo *Ident__is_target_variant_environment;
183183
IdentifierInfo *Ident__FLT_EVAL_METHOD__; // __FLT_EVAL_METHOD
184+
IdentifierInfo *Ident__ROUNDING_MODE__; // __ROUNDING_MODE__
184185

185186
// Weak, only valid (and set) while InMacroArgs is true.
186187
Token* ArgMacro;
@@ -201,6 +202,9 @@ class Preprocessor {
201202
LangOptions::FPEvalMethodKind TUFPEvalMethod =
202203
LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine;
203204

205+
LangOptions::RoundingMode CurrentRoundingMode =
206+
LangOptions::RoundingMode::Dynamic;
207+
204208
// Next __COUNTER__ value, starts at 0.
205209
unsigned CounterValue = 0;
206210

@@ -2356,6 +2360,14 @@ class Preprocessor {
23562360
TUFPEvalMethod = Val;
23572361
}
23582362

2363+
LangOptions::RoundingMode getCurrentRoundingMode() const {
2364+
return CurrentRoundingMode;
2365+
}
2366+
2367+
void setCurrentRoundingMode(LangOptions::RoundingMode RM) {
2368+
CurrentRoundingMode = RM;
2369+
}
2370+
23592371
/// Retrieves the module that we're currently building, if any.
23602372
Module *getCurrentModule();
23612373

clang/lib/Lex/PPMacroExpansion.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ void Preprocessor::RegisterBuiltinMacros() {
344344
Ident__COUNTER__ = RegisterBuiltinMacro(*this, "__COUNTER__");
345345
Ident_Pragma = RegisterBuiltinMacro(*this, "_Pragma");
346346
Ident__FLT_EVAL_METHOD__ = RegisterBuiltinMacro(*this, "__FLT_EVAL_METHOD__");
347+
Ident__ROUNDING_MODE__ = RegisterBuiltinMacro(*this, "__ROUNDING_MODE__");
347348

348349
// C++ Standing Document Extensions.
349350
if (getLangOpts().CPlusPlus)
@@ -1654,6 +1655,30 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
16541655
Diag(Tok, diag::err_illegal_use_of_flt_eval_macro);
16551656
Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here);
16561657
}
1658+
} else if (II == Ident__ROUNDING_MODE__) {
1659+
switch (getCurrentRoundingMode()) {
1660+
case LangOptions::RoundingMode::TowardZero:
1661+
OS << "_rtz";
1662+
break;
1663+
case LangOptions::RoundingMode::NearestTiesToEven:
1664+
OS << "_rte";
1665+
break;
1666+
case LangOptions::RoundingMode::TowardPositive:
1667+
OS << "_rtp";
1668+
break;
1669+
case LangOptions::RoundingMode::TowardNegative:
1670+
OS << "_rtn";
1671+
break;
1672+
case LangOptions::RoundingMode::NearestTiesToAway:
1673+
OS << "_rta";
1674+
break;
1675+
case LangOptions::RoundingMode::Dynamic:
1676+
OS << "";
1677+
break;
1678+
default:
1679+
llvm_unreachable("unknown rounding mode");
1680+
}
1681+
Tok.setKind(tok::string_literal);
16571682
} else if (II == Ident__COUNTER__) {
16581683
// __COUNTER__ expands to a simple numeric value.
16591684
OS << CounterValue++;

clang/lib/Sema/Sema.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -2725,6 +2725,7 @@ Sema::FPFeaturesStateRAII::~FPFeaturesStateRAII() {
27252725
S.CurFPFeatures = OldFPFeaturesState;
27262726
S.FpPragmaStack.CurrentValue = OldOverrides;
27272727
S.PP.setCurrentFPEvalMethod(OldFPPragmaLocation, OldEvalMethod);
2728+
S.PP.setCurrentRoundingMode(S.CurFPFeatures.getConstRoundingMode());
27282729
}
27292730

27302731
bool Sema::isDeclaratorFunctionLike(Declarator &D) {

clang/lib/Sema/SemaAttr.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,7 @@ void Sema::ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode FPR) {
13221322
NewFPFeatures.setConstRoundingModeOverride(FPR);
13231323
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
13241324
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
1325+
PP.setCurrentRoundingMode(FPR);
13251326
}
13261327

13271328
void Sema::setExceptionMode(SourceLocation Loc,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %clang_cc1 -emit-llvm -triple i386-linux -Wno-unknown-pragmas %s -o - | FileCheck %s
2+
3+
double sin(double);
4+
double sin_rte(double);
5+
double sin_rtz(double);
6+
double sin_rtp(double);
7+
double sin_rtn(double);
8+
double sin_rta(double);
9+
10+
#define CONCAT(a, b) CONCAT_(a, b)
11+
#define CONCAT_(a, b) a##b
12+
#define ADD_ROUNDING_MODE_SUFFIX(func) CONCAT(func, __ROUNDING_MODE__)
13+
14+
#define sin(x) ADD_ROUNDING_MODE_SUFFIX(sin)(x)
15+
16+
double call_dyn(double x) {
17+
return sin(x);
18+
}
19+
// CHECK-LABEL: define {{.*}} double @call_dyn(
20+
// CHECK: call double @sin(
21+
22+
#pragma STDC FENV_ROUND FE_TOWARDZERO
23+
double call_tz(double x) {
24+
return sin(x);
25+
}
26+
// CHECK-LABEL: define {{.*}} double @call_tz(
27+
// CHECK: call double @sin_rtz(
28+
29+
#pragma STDC FENV_ROUND FE_TONEAREST
30+
double call_te(double x) {
31+
return sin(x);
32+
}
33+
// CHECK-LABEL: define {{.*}} double @call_te(
34+
// CHECK: call double @sin_rte(
35+
36+
#pragma STDC FENV_ROUND FE_DOWNWARD
37+
double call_tn(double x) {
38+
return sin(x);
39+
}
40+
// CHECK-LABEL: define {{.*}} double @call_tn(
41+
// CHECK: call double @sin_rtn(
42+
43+
#pragma STDC FENV_ROUND FE_UPWARD
44+
double call_tp(double x) {
45+
return sin(x);
46+
}
47+
// CHECK-LABEL: define {{.*}} double @call_tp(
48+
// CHECK: call double @sin_rtp(
49+
50+
#pragma STDC FENV_ROUND FE_TONEARESTFROMZERO
51+
double call_tea(double x) {
52+
return sin(x);
53+
}
54+
// CHECK-LABEL: define {{.*}} double @call_tea(
55+
// CHECK: call double @sin_rta(

0 commit comments

Comments
 (0)