blob: 1efadd86a2d757a08c9428f321508f35214008f2 [file] [log] [blame]
peter klausler42b33da2018-09-29 00:02:111// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "intrinsics.h"
16#include "type.h"
17#include "../common/enum-set.h"
18#include "../common/fortran.h"
peter klauslera70f5962018-10-04 20:43:3319#include "../common/idioms.h"
peter klausler42b33da2018-09-29 00:02:1120#include "../semantics/expression.h"
peter klauslera70f5962018-10-04 20:43:3321#include <map>
22#include <string>
23#include <utility>
peter klausler42b33da2018-09-29 00:02:1124
25namespace Fortran::evaluate {
26
27using common::TypeCategory;
28
peter klauslera70f5962018-10-04 20:43:3329// This file defines the supported intrinsic procedures and implements
30// their recognition and validation. It is largely table-driven. See
31// documentation/intrinsics.md and section 16 of the Fortran 2018 standard
32// for full details on each of the intrinsics. Be advised, they have
33// complicated details, and the design of these tables has to accommodate
34// that complexity.
35
peter klausler42b33da2018-09-29 00:02:1136// Dummy arguments to generic intrinsic procedures are each specified by
peter klauslera70f5962018-10-04 20:43:3337// their keyword name (rarely used, but always defined), allowable type
38// categories, a kind pattern, a rank pattern, and an optional special
39// note code. The kind and rank patterns are represented here with code
40// values that are significant to the matching/validation engine.
peter klausler42b33da2018-09-29 00:02:1141
peter klauslera70f5962018-10-04 20:43:3342// These are small bit-sets of type category enumerators.
43// Note that typeless (BOZ literal) values don't have a distinct type category.
44// These typeless arguments are represented in the tables as if they were
45// INTEGER with a special "typeless" kind code. Arguments of intrinsic types
46// that can also be be typeless values are encoded with a "BOZisOK" note code.
47using CategorySet = common::EnumSet<TypeCategory, 8>;
48static constexpr CategorySet Int{TypeCategory::Integer};
49static constexpr CategorySet Real{TypeCategory::Real};
50static constexpr CategorySet Complex{TypeCategory::Complex};
51static constexpr CategorySet Char{TypeCategory::Character};
52static constexpr CategorySet Logical{TypeCategory::Logical};
53static constexpr CategorySet IntOrReal{Int | Real};
54static constexpr CategorySet Floating{Real | Complex};
55static constexpr CategorySet Numeric{Int | Real | Complex};
56static constexpr CategorySet Relatable{Int | Real | Char};
57static constexpr CategorySet IntrinsicType{
58 Int | Real | Complex | Char | Logical};
59static constexpr CategorySet AnyType{
60 IntrinsicType | CategorySet{TypeCategory::Derived}};
peter klausler42b33da2018-09-29 00:02:1161
62enum class KindCode {
peter klauslerb22d4942018-10-01 18:27:4563 none,
peter klausler42b33da2018-09-29 00:02:1164 defaultIntegerKind,
peter klauslera70f5962018-10-04 20:43:3365 defaultRealKind, // is also the default COMPLEX kind
peter klausler42b33da2018-09-29 00:02:1166 doublePrecision,
peter klauslera70f5962018-10-04 20:43:3367 defaultCharKind,
peter klausler42b33da2018-09-29 00:02:1168 defaultLogicalKind,
peter klauslera70f5962018-10-04 20:43:3369 any, // matches any kind value; each instance is independent
70 typeless, // BOZ literals are INTEGER with this kind
71 teamType, // TEAM_TYPE from module ISO_FORTRAN_ENV (for coarrays)
72 kindArg, // this argument is KIND=
73 effectiveKind, // for function results: same "kindArg", possibly defaulted
74 dimArg, // this argument is DIM=
75 same, // match any kind; all "same" kinds must be equal
peter klausler42b33da2018-09-29 00:02:1176};
77
78struct TypePattern {
79 CategorySet categorySet;
peter klauslerb22d4942018-10-01 18:27:4580 KindCode kindCode{KindCode::none};
peter klausler42b33da2018-09-29 00:02:1181};
82
peter klauslera70f5962018-10-04 20:43:3383// Abbreviations for argument and result patterns in the intrinsic prototypes:
84
85// Match specific kinds of intrinsic types
86static constexpr TypePattern DftInt{Int, KindCode::defaultIntegerKind};
87static constexpr TypePattern DftReal{Real, KindCode::defaultRealKind};
88static constexpr TypePattern DftComplex{Complex, KindCode::defaultRealKind};
89static constexpr TypePattern DftChar{Char, KindCode::defaultCharKind};
90static constexpr TypePattern DftLogical{Logical, KindCode::defaultLogicalKind};
91static constexpr TypePattern BOZ{Int, KindCode::typeless};
92static constexpr TypePattern TEAM_TYPE{Int, KindCode::teamType};
93static constexpr TypePattern DoublePrecision{Real, KindCode::doublePrecision};
94
95// Match any kind of some intrinsic or derived types
96static constexpr TypePattern AnyInt{Int, KindCode::any};
97static constexpr TypePattern AnyReal{Real, KindCode::any};
98static constexpr TypePattern AnyIntOrReal{IntOrReal, KindCode::any};
99static constexpr TypePattern AnyComplex{Complex, KindCode::any};
100static constexpr TypePattern AnyNumeric{Numeric, KindCode::any};
101static constexpr TypePattern AnyChar{Char, KindCode::any};
102static constexpr TypePattern AnyLogical{Logical, KindCode::any};
103static constexpr TypePattern AnyRelatable{Relatable, KindCode::any};
104
105// Match some kind of some intrinsic type(s); all "Same" values must match,
106// even when not in the same category (e.g., SameComplex and SameReal).
107// Can be used to specify a result so long as at least one argument is
108// a "Same".
109static constexpr TypePattern SameInt{Int, KindCode::same};
110static constexpr TypePattern SameReal{Real, KindCode::same};
111static constexpr TypePattern SameIntOrReal{IntOrReal, KindCode::same};
112static constexpr TypePattern SameComplex{Complex, KindCode::same};
113static constexpr TypePattern SameFloating{Floating, KindCode::same};
114static constexpr TypePattern SameNumeric{Numeric, KindCode::same};
115static constexpr TypePattern SameChar{Char, KindCode::same};
116static constexpr TypePattern SameLogical{Logical, KindCode::same};
117static constexpr TypePattern SameRelatable{Relatable, KindCode::same};
118static constexpr TypePattern SameIntrinsic{IntrinsicType, KindCode::same};
119static constexpr TypePattern SameDerivedType{
120 CategorySet{TypeCategory::Derived}, KindCode::same};
121static constexpr TypePattern SameType{AnyType, KindCode::same};
122
123// Result types with known category and KIND=
124static constexpr TypePattern KINDInt{Int, KindCode::effectiveKind};
125static constexpr TypePattern KINDReal{Real, KindCode::effectiveKind};
126static constexpr TypePattern KINDComplex{Complex, KindCode::effectiveKind};
127static constexpr TypePattern KINDChar{Char, KindCode::effectiveKind};
128static constexpr TypePattern KINDLogical{Logical, KindCode::effectiveKind};
peter klausler42b33da2018-09-29 00:02:11129
130// The default rank pattern for dummy arguments and function results is
131// "elemental".
peter klauslera70f5962018-10-04 20:43:33132enum class Rank {
133 elemental, // scalar, or array that conforms with other array arguments
peter klausler42b33da2018-09-29 00:02:11134 scalar,
135 vector,
peter klauslera70f5962018-10-04 20:43:33136 shape, // INTEGER vector of known length and no negative element
peter klausler42b33da2018-09-29 00:02:11137 matrix,
138 array, // not scalar, rank is known and greater than zero
139 known, // rank is known and can be scalar
140 anyOrAssumedRank, // rank can be unknown
141 conformable, // scalar, or array of same rank & shape as "array" argument
142 dimReduced, // scalar if no DIM= argument, else rank(array)-1
143 dimRemoved, // scalar, or rank(array)-1
144 rankPlus1, // rank(known)+1
145 shaped, // rank is length of SHAPE vector
146};
147
148enum SpecialNote {
149 none = 0,
peter klauslera70f5962018-10-04 20:43:33150 BOZisOK, // typeless BOZ literal actual argument is also acceptable
peter klausler42b33da2018-09-29 00:02:11151 optional,
peter klauslera70f5962018-10-04 20:43:33152 defaultsToSameKind, // SameInt, &c.; OPTIONAL also implied
153 defaultsToDefaultForResult, // OPTIONAL also implied
peter klausler42b33da2018-09-29 00:02:11154};
155
156struct IntrinsicDummyArgument {
peter klauslerb22d4942018-10-01 18:27:45157 const char *keyword{nullptr};
peter klausler42b33da2018-09-29 00:02:11158 TypePattern typePattern;
peter klauslera70f5962018-10-04 20:43:33159 Rank rank{Rank::elemental};
peter klauslerb22d4942018-10-01 18:27:45160 enum SpecialNote note { none };
peter klausler42b33da2018-09-29 00:02:11161};
162
peter klauslera70f5962018-10-04 20:43:33163// constexpr abbreviations for popular arguments:
164// DefaultingKIND is a KIND= argument whose default value is the appropriate
165// KIND(0), KIND(0.0), KIND(''), &c. value for the function result.
166static constexpr IntrinsicDummyArgument DefaultingKIND{
167 "kind", {Int, KindCode::kindArg}, Rank::scalar, defaultsToDefaultForResult};
168// MatchingDefaultKIND is a KIND= argument whose default value is the
169// kind of any "Same" function argument (viz., the one whose kind pattern is
170// "same").
171static constexpr IntrinsicDummyArgument MatchingDefaultKIND{
172 "kind", {Int, KindCode::kindArg}, Rank::scalar, defaultsToSameKind};
173static constexpr IntrinsicDummyArgument OptionalDIM{
174 "dim", {Int, KindCode::dimArg}, Rank::scalar, optional};
175static constexpr IntrinsicDummyArgument OptionalMASK{
176 "mask", AnyLogical, Rank::conformable, optional};
peter klausler42b33da2018-09-29 00:02:11177
178struct IntrinsicInterface {
179 static constexpr int maxArguments{7};
peter klauslerb22d4942018-10-01 18:27:45180 const char *name{nullptr};
peter klausler42b33da2018-09-29 00:02:11181 IntrinsicDummyArgument dummy[maxArguments];
182 TypePattern result;
peter klauslera70f5962018-10-04 20:43:33183 Rank rank{Rank::elemental};
184 std::optional<SpecificIntrinsic> Match(const CallCharacteristics &,
185 const semantics::IntrinsicTypeDefaultKinds &) const;
peter klausler42b33da2018-09-29 00:02:11186};
187
peter klauslerb22d4942018-10-01 18:27:45188static const IntrinsicInterface genericIntrinsicFunction[]{
peter klauslera70f5962018-10-04 20:43:33189 {"abs", {{"a", SameIntOrReal}}, SameIntOrReal},
190 {"abs", {{"a", SameComplex}}, SameReal},
191 {"achar", {{"i", SameInt}, DefaultingKIND}, KINDChar},
192 {"acos", {{"x", SameFloating}}, SameFloating},
193 {"acosh", {{"x", SameFloating}}, SameFloating},
194 {"adjustl", {{"string", SameChar}}, SameChar},
195 {"adjustr", {{"string", SameChar}}, SameChar},
196 {"aimag", {{"x", SameComplex}}, SameReal},
197 {"aint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal},
198 {"all", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
199 Rank::dimReduced},
200 {"anint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal},
201 {"any", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
202 Rank::dimReduced},
203 {"asin", {{"x", SameFloating}}, SameFloating},
204 {"asinh", {{"x", SameFloating}}, SameFloating},
205 {"atan", {{"x", SameFloating}}, SameFloating},
206 {"atan", {{"y", SameReal}, {"x", SameReal}}, SameReal},
207 {"atan2", {{"y", SameReal}, {"x", SameReal}}, SameReal},
208 {"atanh", {{"x", SameFloating}}, SameFloating},
209 {"bessel_j0", {{"x", SameReal}}, SameReal},
210 {"bessel_j1", {{"x", SameReal}}, SameReal},
211 {"bessel_jn", {{"n", AnyInt}, {"x", SameReal}}, SameReal},
212 {"bessel_y0", {{"x", SameReal}}, SameReal},
213 {"bessel_y1", {{"x", SameReal}}, SameReal},
214 {"bessel_yn", {{"n", AnyInt}, {"x", SameReal}}, SameReal},
215 {"bge",
216 {{"i", AnyInt, Rank::elemental, BOZisOK},
217 {"j", AnyInt, Rank::elemental, BOZisOK}},
218 DftLogical},
219 {"bgt",
220 {{"i", AnyInt, Rank::elemental, BOZisOK},
221 {"j", AnyInt, Rank::elemental, BOZisOK}},
222 DftLogical},
223 {"ble",
224 {{"i", AnyInt, Rank::elemental, BOZisOK},
225 {"j", AnyInt, Rank::elemental, BOZisOK}},
226 DftLogical},
227 {"blt",
228 {{"i", AnyInt, Rank::elemental, BOZisOK},
229 {"j", AnyInt, Rank::elemental, BOZisOK}},
230 DftLogical},
231 {"btest", {{"i", AnyInt}, {"pos", AnyInt}}, DftLogical},
232 {"ceiling", {{"a", AnyReal}, DefaultingKIND}, KINDInt},
233 {"char", {{"i", AnyInt}, DefaultingKIND}, KINDChar},
234 {"cmplx", {{"x", AnyComplex}, DefaultingKIND}, KINDComplex},
peter klausler42b33da2018-09-29 00:02:11235 {"cmplx",
peter klauslera70f5962018-10-04 20:43:33236 {{"x", SameIntOrReal, Rank::elemental, BOZisOK},
237 {"y", SameIntOrReal, Rank::elemental, BOZisOK}, DefaultingKIND},
238 KINDComplex},
239 {"conjg", {{"z", SameComplex}}, SameComplex},
240 {"cos", {{"x", SameFloating}}, SameFloating},
241 {"cosh", {{"x", SameFloating}}, SameFloating},
242 {"count", {{"mask", AnyLogical, Rank::array}, OptionalDIM, DefaultingKIND},
243 KINDInt, Rank::dimReduced},
peter klausler42b33da2018-09-29 00:02:11244 {"cshift",
peter klauslera70f5962018-10-04 20:43:33245 {{"array", SameType, Rank::array}, {"shift", AnyInt, Rank::dimRemoved},
246 OptionalDIM},
247 SameType, Rank::array},
248 {"dim", {{"x", SameIntOrReal}, {"y", SameIntOrReal}}, SameIntOrReal},
249 {"dprod", {{"x", DftReal}, {"y", DftReal}}, DoublePrecision},
250 {"dshiftl",
251 {{"i", SameInt}, {"j", SameInt, Rank::elemental, BOZisOK},
252 {"shift", AnyInt}},
253 SameInt},
254 {"dshiftl", {{"i", BOZ}, {"j", SameInt}, {"shift", AnyInt}}, SameInt},
255 {"dshiftr",
256 {{"i", SameInt}, {"j", SameInt, Rank::elemental, BOZisOK},
257 {"shift", AnyInt}},
258 SameInt},
259 {"dshiftr", {{"i", BOZ}, {"j", SameInt}, {"shift", AnyInt}}, SameInt},
peter klausler42b33da2018-09-29 00:02:11260 {"eoshift",
peter klauslera70f5962018-10-04 20:43:33261 {{"array", SameIntrinsic, Rank::array},
262 {"shift", AnyInt, Rank::dimRemoved},
263 {"boundary", SameIntrinsic, Rank::dimRemoved, optional},
264 OptionalDIM},
265 SameIntrinsic, Rank::array},
peter klausler42b33da2018-09-29 00:02:11266 {"eoshift",
peter klauslera70f5962018-10-04 20:43:33267 {{"array", SameDerivedType, Rank::array},
268 {"shift", AnyInt, Rank::dimRemoved},
269 {"boundary", SameDerivedType, Rank::dimRemoved}, OptionalDIM},
270 SameDerivedType, Rank::array},
271 {"erf", {{"x", SameReal}}, SameReal},
272 {"erfc", {{"x", SameReal}}, SameReal},
273 {"erfc_scaled", {{"x", SameReal}}, SameReal},
274 {"exp", {{"x", SameFloating}}, SameFloating},
275 {"exponent", {{"x", AnyReal}}, DftInt},
peter klausler42b33da2018-09-29 00:02:11276 {"findloc",
peter klauslera70f5962018-10-04 20:43:33277 {{"array", SameNumeric, Rank::array},
278 {"value", SameNumeric, Rank::scalar}, OptionalDIM, OptionalMASK,
279 DefaultingKIND, {"back", AnyLogical, Rank::scalar, optional}},
280 KINDInt, Rank::dimReduced},
peter klausler42b33da2018-09-29 00:02:11281 {"findloc",
peter klauslera70f5962018-10-04 20:43:33282 {{"array", SameChar, Rank::array}, {"value", SameChar, Rank::scalar},
283 OptionalDIM, OptionalMASK, DefaultingKIND,
284 {"back", AnyLogical, Rank::scalar, optional}},
285 KINDInt, Rank::dimReduced},
peter klausler42b33da2018-09-29 00:02:11286 {"findloc",
peter klauslera70f5962018-10-04 20:43:33287 {{"array", AnyLogical, Rank::array},
288 {"value", AnyLogical, Rank::scalar}, OptionalDIM, OptionalMASK,
289 DefaultingKIND, {"back", AnyLogical, Rank::scalar, optional}},
290 KINDInt, Rank::dimReduced},
291 {"floor", {{"a", AnyReal}, DefaultingKIND}, KINDInt},
292 {"fraction", {{"x", SameReal}}, SameReal},
293 {"gamma", {{"x", SameReal}}, SameReal},
294 {"hypot", {{"x", SameReal}, {"y", SameReal}}, SameReal},
295 {"iachar", {{"c", AnyChar}, DefaultingKIND}, KINDInt},
296 {"iall", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
297 SameInt, Rank::dimReduced},
298 {"iany", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
299 SameInt, Rank::dimReduced},
300 {"iparity", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
301 SameInt, Rank::dimReduced},
302 {"iand", {{"i", SameInt}, {"j", SameInt, Rank::elemental, BOZisOK}},
303 SameInt},
304 {"iand", {{"i", BOZ}, {"j", SameInt}}, SameInt},
305 {"ibclr", {{"i", SameInt}, {"pos", AnyInt}}, SameInt},
306 {"ibits", {{"i", SameInt}, {"pos", AnyInt}, {"len", AnyInt}}, SameInt},
307 {"ibset", {{"i", SameInt}, {"pos", AnyInt}}, SameInt},
308 {"ichar", {{"c", AnyChar}, DefaultingKIND}, KINDInt},
309 {"ieor", {{"i", SameInt}, {"j", SameInt, Rank::elemental, BOZisOK}},
310 SameInt},
311 {"ieor", {{"i", BOZ}, {"j", SameInt}}, SameInt},
312 {"image_status",
313 {{"image", SameInt}, {"team", TEAM_TYPE, Rank::scalar, optional}},
314 DftInt},
peter klausler42b33da2018-09-29 00:02:11315 {"index",
peter klauslera70f5962018-10-04 20:43:33316 {{"string", SameChar}, {"substring", SameChar},
317 {"back", AnyLogical, Rank::scalar, optional}, DefaultingKIND},
318 KINDInt},
319 {"int", {{"a", AnyNumeric, Rank::elemental, BOZisOK}, DefaultingKIND},
320 KINDInt},
321 {"ior", {{"i", SameInt}, {"j", SameInt, Rank::elemental, BOZisOK}},
322 SameInt},
323 {"ior", {{"i", BOZ}, {"j", SameInt}}, SameInt},
324 {"ishft", {{"i", SameInt}, {"shift", AnyInt}}, SameInt},
325 {"ishftc",
326 {{"i", SameInt}, {"shift", AnyInt},
327 {"size", AnyInt, Rank::elemental, optional}},
328 SameInt},
329 {"is_iostat_end", {{"i", AnyInt}}, DftLogical},
330 {"is_iostat_eor", {{"i", AnyInt}}, DftLogical},
331 {"leadz", {{"i", AnyInt}}, DftInt},
332 {"len", {{"string", AnyChar}, DefaultingKIND}, KINDInt},
333 {"len_trim", {{"string", AnyChar}, DefaultingKIND}, KINDInt},
334 {"lge", {{"string_a", SameChar}, {"string_b", SameChar}}, DftLogical},
335 {"lgt", {{"string_a", SameChar}, {"string_b", SameChar}}, DftLogical},
336 {"lle", {{"string_a", SameChar}, {"string_b", SameChar}}, DftLogical},
337 {"llt", {{"string_a", SameChar}, {"string_b", SameChar}}, DftLogical},
338 {"log", {{"x", SameFloating}}, SameFloating},
339 {"log10", {{"x", SameReal}}, SameReal},
340 {"logical", {{"l", AnyLogical}, DefaultingKIND}, KINDLogical},
341 {"log_gamma", {{"x", SameReal}}, SameReal},
342 {"maskl", {{"i", AnyInt}, DefaultingKIND}, KINDInt},
343 {"maskr", {{"i", AnyInt}, DefaultingKIND}, KINDInt},
peter klausler42b33da2018-09-29 00:02:11344 {"maxloc",
peter klauslera70f5962018-10-04 20:43:33345 {{"array", AnyRelatable, Rank::array}, OptionalDIM, OptionalMASK,
346 DefaultingKIND, {"back", AnyLogical, Rank::scalar, optional}},
347 KINDInt, Rank::dimReduced},
peter klausler42b33da2018-09-29 00:02:11348 {"maxval",
peter klauslera70f5962018-10-04 20:43:33349 {{"array", SameRelatable, Rank::array}, OptionalDIM, OptionalMASK},
350 SameRelatable, Rank::dimReduced},
peter klausler42b33da2018-09-29 00:02:11351 {"merge_bits",
peter klauslera70f5962018-10-04 20:43:33352 {{"i", SameInt}, {"j", SameInt, Rank::elemental, BOZisOK},
353 {"mask", SameInt, Rank::elemental, BOZisOK}},
354 SameInt},
355 {"merge_bits",
356 {{"i", BOZ}, {"j", SameInt},
357 {"mask", SameInt, Rank::elemental, BOZisOK}},
358 SameInt},
peter klausler42b33da2018-09-29 00:02:11359 {"minloc",
peter klauslera70f5962018-10-04 20:43:33360 {{"array", AnyRelatable, Rank::array}, OptionalDIM, OptionalMASK,
361 DefaultingKIND, {"back", AnyLogical, Rank::scalar, optional}},
362 KINDInt, Rank::dimReduced},
peter klausler42b33da2018-09-29 00:02:11363 {"minval",
peter klauslera70f5962018-10-04 20:43:33364 {{"array", SameRelatable, Rank::array}, OptionalDIM, OptionalMASK},
365 SameRelatable, Rank::dimReduced},
366 {"mod", {{"a", SameIntOrReal}, {"p", SameIntOrReal}}, SameIntOrReal},
367 {"modulo", {{"a", SameIntOrReal}, {"p", SameIntOrReal}}, SameIntOrReal},
368 {"nearest", {{"x", SameReal}, {"s", AnyReal}}, SameReal},
369 {"nint", {{"a", AnyReal}, DefaultingKIND}, KINDInt},
370 {"norm2", {{"x", SameReal, Rank::array}, OptionalDIM}, SameReal,
371 Rank::dimReduced},
372 {"not", {{"i", SameInt}}, SameInt},
peter klausler42b33da2018-09-29 00:02:11373 {"out_of_range",
peter klauslera70f5962018-10-04 20:43:33374 {{"x", SameIntOrReal}, {"mold", AnyIntOrReal, Rank::scalar}},
375 DftLogical},
376 {"out_of_range",
377 {{"x", AnyReal}, {"mold", AnyInt, Rank::scalar},
378 {"round", AnyLogical, Rank::scalar, optional}},
379 DftLogical},
380 {"out_of_range", {{"x", AnyReal}, {"mold", AnyReal}}, DftLogical},
peter klausler42b33da2018-09-29 00:02:11381 {"pack",
peter klauslera70f5962018-10-04 20:43:33382 {{"array", SameType, Rank::array},
383 {"mask", AnyLogical, Rank::conformable},
384 {"vector", SameType, Rank::vector, optional}},
385 SameType, Rank::vector},
386 {"parity", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
387 Rank::dimReduced},
388 {"popcnt", {{"i", AnyInt}}, DftInt},
389 {"poppar", {{"i", AnyInt}}, DftInt},
peter klausler42b33da2018-09-29 00:02:11390 {"product",
peter klauslera70f5962018-10-04 20:43:33391 {{"array", SameNumeric, Rank::array}, OptionalDIM, OptionalMASK},
392 SameNumeric, Rank::dimReduced},
393 {"real", {{"a", AnyNumeric, Rank::elemental, BOZisOK}, DefaultingKIND},
394 KINDReal},
peter klausler42b33da2018-09-29 00:02:11395 {"reshape",
peter klauslera70f5962018-10-04 20:43:33396 {{"source", SameType, Rank::array}, {"shape", AnyInt, Rank::shape},
397 {"pad", SameType, Rank::array, optional},
398 {"order", AnyInt, Rank::vector, optional}},
399 SameType, Rank::shaped},
400 {"rrspacing", {{"x", SameReal}}, SameReal},
401 {"scale", {{"x", SameReal}, {"i", AnyInt}}, SameReal},
peter klausler42b33da2018-09-29 00:02:11402 {"scan",
peter klauslera70f5962018-10-04 20:43:33403 {{"string", SameChar}, {"set", SameChar},
404 {"back", AnyLogical, Rank::elemental, optional}, DefaultingKIND},
405 KINDInt},
406 {"set_exponent", {{"x", SameReal}, {"i", AnyInt}}, SameReal},
407 {"shifta", {{"i", SameInt}, {"shift", AnyInt}}, SameInt},
408 {"shiftl", {{"i", SameInt}, {"shift", AnyInt}}, SameInt},
409 {"shiftr", {{"i", SameInt}, {"shift", AnyInt}}, SameInt},
410 {"sign", {{"a", SameIntOrReal}, {"b", SameIntOrReal}}, SameIntOrReal},
411 {"sin", {{"x", SameFloating}}, SameFloating},
412 {"sinh", {{"x", SameFloating}}, SameFloating},
413 {"spacing", {{"x", SameReal}}, SameReal},
peter klausler42b33da2018-09-29 00:02:11414 {"spread",
peter klauslera70f5962018-10-04 20:43:33415 {{"source", SameType, Rank::known},
416 {"dim", {Int, KindCode::dimArg}, Rank::scalar /*not optional*/},
417 {"ncopies", AnyInt, Rank::scalar}},
418 SameType, Rank::rankPlus1},
419 {"sqrt", {{"x", SameFloating}}, SameFloating},
420 {"sum", {{"array", SameNumeric, Rank::array}, OptionalDIM, OptionalMASK},
421 SameNumeric, Rank::dimReduced},
422 {"tan", {{"x", SameFloating}}, SameFloating},
423 {"tanh", {{"x", SameFloating}}, SameFloating},
424 {"trailz", {{"i", AnyInt}}, DftInt},
425 // TODO: pmk: continue here with TRANSFER
peter klausler42b33da2018-09-29 00:02:11426 {"verify",
peter klauslera70f5962018-10-04 20:43:33427 {{"string", SameChar}, {"set", SameChar},
428 {"back", AnyLogical, Rank::elemental, optional}, DefaultingKIND},
429 KINDInt},
peter klausler42b33da2018-09-29 00:02:11430};
431
432// Not covered by the table above:
433// MAX, MIN, MERGE
434
435struct SpecificIntrinsicInterface : public IntrinsicInterface {
436 const char *generic{nullptr};
437};
438
peter klauslerb22d4942018-10-01 18:27:45439static const SpecificIntrinsicInterface specificIntrinsicFunction[]{
peter klauslera70f5962018-10-04 20:43:33440 {{"abs", {{"a", DftReal}}, DftReal}},
441 {{"acos", {{"x", DftReal}}, DftReal}},
442 {{"aimag", {{"z", DftComplex}}, DftReal}},
443 {{"aint", {{"a", DftReal}}, DftReal}},
444 {{"alog", {{"x", DftReal}}, DftReal}, "log"},
445 {{"alog10", {{"x", DftReal}}, DftReal}, "log10"},
446 {{"amod", {{"a", DftReal}, {"p", DftReal}}, DftReal}, "mod"},
447 {{"anint", {{"a", DftReal}}, DftReal}},
448 {{"asin", {{"x", DftReal}}, DftReal}},
449 {{"atan", {{"x", DftReal}}, DftReal}},
450 {{"atan2", {{"y", DftReal}, {"x", DftReal}}, DftReal}},
451 {{"cabs", {{"a", DftComplex}}, DftReal}, "abs"},
452 {{"ccos", {{"a", DftComplex}}, DftComplex}, "cos"},
453 {{"cexp", {{"a", DftComplex}}, DftComplex}, "exp"},
454 {{"clog", {{"a", DftComplex}}, DftComplex}, "log"},
455 {{"conjg", {{"a", DftComplex}}, DftComplex}},
456 {{"cos", {{"x", DftReal}}, DftReal}},
457 {{"csin", {{"a", DftComplex}}, DftComplex}, "sin"},
458 {{"csqrt", {{"a", DftComplex}}, DftComplex}, "sqrt"},
459 {{"ctan", {{"a", DftComplex}}, DftComplex}, "tan"},
460 {{"dabs", {{"a", DoublePrecision}}, DoublePrecision}, "abs"},
461 {{"dacos", {{"x", DoublePrecision}}, DoublePrecision}, "acos"},
462 {{"dasin", {{"x", DoublePrecision}}, DoublePrecision}, "asin"},
463 {{"datan", {{"x", DoublePrecision}}, DoublePrecision}, "atan"},
464 {{"datan2", {{"y", DoublePrecision}, {"x", DoublePrecision}},
465 DoublePrecision},
466 "atan2"},
467 {{"dble", {{"a", DftReal}, DefaultingKIND}, DoublePrecision}, "real"},
468 {{"dcos", {{"x", DoublePrecision}}, DoublePrecision}, "cos"},
469 {{"dcosh", {{"x", DoublePrecision}}, DoublePrecision}, "cosh"},
470 {{"ddim", {{"x", DoublePrecision}, {"y", DoublePrecision}},
471 DoublePrecision},
472 "dim"},
473 {{"dexp", {{"x", DoublePrecision}}, DoublePrecision}, "exp"},
474 {{"dim", {{"x", DftReal}, {"y", DftReal}}, DftReal}},
475 {{"dint", {{"a", DoublePrecision}}, DoublePrecision}, "aint"},
476 {{"dlog", {{"x", DoublePrecision}}, DoublePrecision}, "log"},
477 {{"dlog10", {{"x", DoublePrecision}}, DoublePrecision}, "log10"},
478 {{"dmod", {{"a", DoublePrecision}, {"p", DoublePrecision}},
479 DoublePrecision},
480 "mod"},
481 {{"dnint", {{"a", DoublePrecision}}, DoublePrecision}, "anint"},
482 {{"dprod", {{"x", DftReal}, {"y", DftReal}}, DoublePrecision}},
483 {{"dsign", {{"a", DoublePrecision}, {"b", DoublePrecision}},
484 DoublePrecision},
485 "sign"},
486 {{"dsin", {{"x", DoublePrecision}}, DoublePrecision}, "sin"},
487 {{"dsinh", {{"x", DoublePrecision}}, DoublePrecision}, "sinh"},
488 {{"dsqrt", {{"x", DoublePrecision}}, DoublePrecision}, "sqrt"},
489 {{"dtan", {{"x", DoublePrecision}}, DoublePrecision}, "tan"},
490 {{"dtanh", {{"x", DoublePrecision}}, DoublePrecision}, "tanh"},
491 {{"exp", {{"x", DftReal}}, DftReal}},
492 {{"float", {{"i", DftInt}}, DftReal}, "real"},
493 {{"iabs", {{"a", DftInt}}, DftInt}, "abs"},
494 {{"idim", {{"x", DftInt}, {"y", DftInt}}, DftInt}, "dim"},
495 {{"idint", {{"a", DoublePrecision}}, DftInt}, "int"},
496 {{"idnint", {{"a", DoublePrecision}}, DftInt}, "nint"},
497 {{"ifix", {{"a", DftReal}}, DftInt}, "int"},
498 {{"index", {{"string", DftChar}, {"substring", DftChar}}, DftInt}},
499 {{"isign", {{"a", DftInt}, {"b", DftInt}}, DftInt}, "sign"},
500 {{"len", {{"string", DftChar}}, DftInt}},
501 {{"log", {{"x", DftReal}}, DftReal}},
502 {{"log10", {{"x", DftReal}}, DftReal}},
503 {{"mod", {{"a", DftInt}, {"p", DftInt}}, DftInt}},
504 {{"nint", {{"a", DftReal}}, DftInt}},
505 {{"sign", {{"a", DftReal}, {"b", DftReal}}, DftReal}},
506 {{"sin", {{"x", DftReal}}, DftReal}},
507 {{"sinh", {{"x", DftReal}}, DftReal}},
508 {{"sngl", {{"a", DoublePrecision}}, DftReal}, "real"},
509 {{"sqrt", {{"x", DftReal}}, DftReal}},
510 {{"tan", {{"x", DftReal}}, DftReal}},
511 {{"tanh", {{"x", DftReal}}, DftReal}},
peter klausler42b33da2018-09-29 00:02:11512};
513
514// Some entries in the table above are "restricted" specifics:
515// DBLE, FLOAT, IDINT, IFIX, SNGL
516// Additional "restricted" specifics not covered by the table above:
517// AMAX0, AMAX1, AMIN0, AMIN1, DMAX1, DMIN1, MAX0, MAX1, MIN0, MIN1
518
peter klauslera70f5962018-10-04 20:43:33519// Intrinsic interface matching against the arguments of a particular
520// procedure reference.
521// TODO: return error message rather than just a std::nullopt on failure.
522std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
523 const CallCharacteristics &call,
524 const semantics::IntrinsicTypeDefaultKinds &defaults) const {
525 // Attempt to construct a 1-1 correspondence between the dummy arguments in
526 // a particular intrinsic procedure's generic interface and the actual
527 // arguments in a procedure reference.
528 const ActualArgumentCharacteristics *actualForDummy[maxArguments];
529 int dummies{0};
530 for (; dummies < maxArguments && dummy[dummies].keyword != nullptr;
531 ++dummies) {
532 actualForDummy[dummies] = nullptr;
533 }
534 for (const ActualArgumentCharacteristics &arg : call.argument) {
535 bool found{false};
536 for (int dummyArgIndex{0}; dummyArgIndex < dummies; ++dummyArgIndex) {
537 if (actualForDummy[dummyArgIndex] == nullptr) {
538 if (!arg.keyword.has_value() ||
539 *arg.keyword == dummy[dummyArgIndex].keyword) {
540 actualForDummy[dummyArgIndex] = &arg;
541 found = true;
542 break;
543 }
544 }
545 if (!found) {
546 return std::nullopt;
547 }
548 }
549 }
550
551 // Check types and kinds of the actual arguments against the intrinsic's
552 // interface. Ensure that two or more arguments that have to have the same
553 // type and kind do so. Check for missing non-optional arguments now, too.
554 const ActualArgumentCharacteristics *sameArg{nullptr};
555 const IntrinsicDummyArgument *kindDummyArg{nullptr};
556 const ActualArgumentCharacteristics *kindArg{nullptr};
557 bool hasDimArg{false};
558 for (int dummyArgIndex{0}; dummyArgIndex < dummies; ++dummyArgIndex) {
559 const IntrinsicDummyArgument &d{dummy[dummyArgIndex]};
560 if (d.typePattern.kindCode == KindCode::kindArg) {
561 CHECK(kindDummyArg == nullptr);
562 kindDummyArg = &d;
563 }
564 const ActualArgumentCharacteristics *arg{actualForDummy[dummyArgIndex]};
565 if (!arg) {
566 if (d.note >= optional) {
567 continue; // missing OPTIONAL argument is ok
568 } else {
569 return std::nullopt; // missing non-OPTIONAL argument
570 }
571 }
572 if (arg->isBOZ) {
573 if (d.typePattern.kindCode == KindCode::typeless || d.note == BOZisOK) {
574 continue;
575 }
576 return std::nullopt; // typeless argument not allowed here
577 } else if (!d.typePattern.categorySet.test(arg->type.category)) {
578 return std::nullopt; // argument has invalid type category
579 }
580 bool argOk{false};
581 switch (d.typePattern.kindCode) {
582 case KindCode::none:
583 case KindCode::typeless:
584 case KindCode::teamType: // TODO: TEAM_TYPE
585 argOk = false;
586 break;
587 case KindCode::defaultIntegerKind:
588 argOk = arg->type.kind == defaults.defaultIntegerKind;
589 break;
590 case KindCode::defaultRealKind:
591 argOk = arg->type.kind == defaults.defaultRealKind;
592 break;
593 case KindCode::doublePrecision:
594 argOk = arg->type.kind == defaults.defaultDoublePrecisionKind;
595 break;
596 case KindCode::defaultCharKind:
597 argOk = arg->type.kind == defaults.defaultCharacterKind;
598 break;
599 case KindCode::defaultLogicalKind:
600 argOk = arg->type.kind == defaults.defaultLogicalKind;
601 break;
602 case KindCode::any: argOk = true; break;
603 case KindCode::kindArg:
604 CHECK(kindArg == nullptr);
605 kindArg = arg;
606 argOk = arg->intValue.has_value();
607 break;
608 case KindCode::dimArg:
609 hasDimArg = true;
610 argOk = true;
611 break;
612 case KindCode::same:
613 if (sameArg == nullptr) {
614 sameArg = arg;
615 }
616 argOk = arg->type == sameArg->type;
617 break;
618 case KindCode::effectiveKind:
619 common::die("INTERNAL: KindCode::effectiveKind appears on argument '%s' "
620 "for intrinsic '%s'",
621 d.keyword, name);
622 break;
623 default: CRASH_NO_CASE;
624 }
625 if (!argOk) {
626 return std::nullopt;
627 }
628 }
629
630 // Check the ranks of the arguments against the intrinsic's interface.
631 const ActualArgumentCharacteristics *arrayArg{nullptr};
632 const ActualArgumentCharacteristics *knownArg{nullptr};
633 const ActualArgumentCharacteristics *shapeArg{nullptr};
634 int elementalRank{0};
635 for (int dummyArgIndex{0}; dummyArgIndex < dummies; ++dummyArgIndex) {
636 const IntrinsicDummyArgument &d{dummy[dummyArgIndex]};
637 if (const ActualArgumentCharacteristics *
638 arg{actualForDummy[dummyArgIndex]}) {
639 if (arg->isAssumedRank && d.rank != Rank::anyOrAssumedRank) {
640 return std::nullopt;
641 }
642 bool argOk{false};
643 switch (d.rank) {
644 case Rank::elemental:
645 if (elementalRank == 0) {
646 elementalRank = arg->rank;
647 }
648 argOk = arg->rank == 0 || arg->rank == elementalRank;
649 break;
650 case Rank::scalar: argOk = arg->rank == 0; break;
651 case Rank::vector: argOk = arg->rank == 1; break;
652 case Rank::shape:
653 CHECK(shapeArg == nullptr);
654 shapeArg = arg;
655 argOk = arg->rank == 1 && arg->vectorSize.has_value();
656 break;
657 case Rank::matrix: argOk = arg->rank == 2; break;
658 case Rank::array:
659 argOk = arg->rank > 0;
660 if (!arrayArg) {
661 arrayArg = arg;
662 } else {
663 argOk &= arg->rank == arrayArg->rank;
664 }
665 break;
666 case Rank::known:
667 CHECK(knownArg == nullptr);
668 knownArg = arg;
669 argOk = true;
670 break;
671 case Rank::anyOrAssumedRank: argOk = true; break;
672 case Rank::conformable:
673 CHECK(arrayArg != nullptr);
674 argOk = arg->rank == 0 || arg->rank == arrayArg->rank;
675 break;
676 case Rank::dimRemoved:
677 CHECK(arrayArg != nullptr);
678 if (hasDimArg) {
679 argOk = arg->rank + 1 == arrayArg->rank;
680 } else {
681 argOk = arg->rank == 0;
682 }
683 break;
684 case Rank::dimReduced:
685 case Rank::rankPlus1:
686 case Rank::shaped:
687 common::die("INTERNAL: result-only rank code appears on argument '%s' "
688 "for intrinsic '%s'",
689 d.keyword, name);
690 default: CRASH_NO_CASE;
691 }
692 if (!argOk) {
693 return std::nullopt;
694 }
695 }
696 }
697
698 // At this point, the call is acceptable.
699 // Calculate the characteristics of the function result, if any
700 if (result.categorySet.empty()) {
701 CHECK(result.kindCode == KindCode::none);
702 return std::make_optional<SpecificIntrinsic>(name);
703 }
704 // Determine the result type.
705 DynamicType resultType{*result.categorySet.LeastElement(), 0};
706 switch (result.kindCode) {
707 case KindCode::defaultIntegerKind:
708 CHECK(result.categorySet == Int);
709 CHECK(resultType.category == TypeCategory::Integer);
710 resultType.kind = defaults.defaultIntegerKind;
711 break;
712 case KindCode::defaultRealKind:
713 CHECK(result.categorySet == CategorySet{resultType.category});
714 CHECK(Floating.test(resultType.category));
715 resultType.kind = defaults.defaultRealKind;
716 break;
717 case KindCode::doublePrecision:
718 CHECK(result.categorySet == Real);
719 CHECK(resultType.category == TypeCategory::Real);
720 resultType.kind = defaults.defaultDoublePrecisionKind;
721 break;
722 case KindCode::defaultCharKind:
723 CHECK(result.categorySet == Char);
724 CHECK(resultType.category == TypeCategory::Character);
725 resultType.kind = defaults.defaultCharacterKind;
726 break;
727 case KindCode::defaultLogicalKind:
728 CHECK(result.categorySet == Logical);
729 CHECK(resultType.category == TypeCategory::Logical);
730 resultType.kind = defaults.defaultLogicalKind;
731 break;
732 case KindCode::same:
733 CHECK(sameArg != nullptr);
734 CHECK(result.categorySet.test(sameArg->type.category));
735 resultType = sameArg->type;
736 break;
737 case KindCode::effectiveKind:
738 CHECK(kindDummyArg != nullptr);
739 CHECK(result.categorySet == CategorySet{resultType.category});
740 if (kindArg != nullptr) {
741 CHECK(kindArg->intValue.has_value());
742 resultType.kind = *kindArg->intValue;
743 // TODO pmk: validate the kind!!
744 } else if (kindDummyArg->note == defaultsToSameKind) {
745 CHECK(sameArg != nullptr);
746 resultType = sameArg->type;
747 } else {
748 CHECK(kindDummyArg->note == defaultsToDefaultForResult);
749 resultType.kind = defaults.DefaultKind(resultType.category);
750 }
751 break;
752 case KindCode::typeless:
753 case KindCode::teamType:
754 case KindCode::any:
755 case KindCode::kindArg:
756 case KindCode::dimArg:
757 common::die(
758 "INTERNAL: bad KindCode appears on intrinsic '%s' result", name);
759 break;
760 default: CRASH_NO_CASE;
761 }
762
763 // Determine the rank of the function result.
764 int resultRank{0};
765 switch (rank) {
766 case Rank::elemental: resultRank = elementalRank; break;
767 case Rank::scalar: resultRank = 0; break;
768 case Rank::vector: resultRank = 1; break;
769 case Rank::matrix: resultRank = 2; break;
770 case Rank::dimReduced:
771 CHECK(arrayArg != nullptr);
772 resultRank = hasDimArg ? arrayArg->rank - 1 : 0;
773 break;
774 case Rank::rankPlus1:
775 CHECK(knownArg != nullptr);
776 resultRank = knownArg->rank + 1;
777 break;
778 case Rank::shaped:
779 CHECK(shapeArg != nullptr);
780 CHECK(shapeArg->vectorSize.has_value());
781 resultRank = *shapeArg->vectorSize;
782 break;
783 case Rank::shape:
784 case Rank::array:
785 case Rank::known:
786 case Rank::anyOrAssumedRank:
787 case Rank::conformable:
788 case Rank::dimRemoved:
789 common::die("INTERNAL: bad Rank code on intrinsic '%s' result", name);
790 break;
791 default: CRASH_NO_CASE;
792 }
793 CHECK(resultRank >= 0);
794
795 return std::make_optional<SpecificIntrinsic>(
796 name, elementalRank > 0, resultType, resultRank);
797}
798
peter klausler42b33da2018-09-29 00:02:11799struct IntrinsicTable::Implementation {
800 explicit Implementation(const semantics::IntrinsicTypeDefaultKinds &dfts)
peter klauslera70f5962018-10-04 20:43:33801 : defaults{dfts} {
802 for (const IntrinsicInterface &f : genericIntrinsicFunction) {
803 genericFuncs.insert(std::make_pair(std::string{f.name}, &f));
804 }
805 for (const SpecificIntrinsicInterface &f : specificIntrinsicFunction) {
806 specificFuncs.insert(std::make_pair(std::string{f.name}, &f));
807 }
808 }
peter klausler42b33da2018-09-29 00:02:11809
peter klausler75a32092018-10-05 16:57:53810 std::optional<SpecificIntrinsic> Probe(const CallCharacteristics &) const;
811
peter klausler42b33da2018-09-29 00:02:11812 semantics::IntrinsicTypeDefaultKinds defaults;
peter klauslera70f5962018-10-04 20:43:33813 std::multimap<std::string, const IntrinsicInterface *> genericFuncs;
814 std::multimap<std::string, const SpecificIntrinsicInterface *> specificFuncs;
peter klausler42b33da2018-09-29 00:02:11815};
816
peter klausler75a32092018-10-05 16:57:53817std::optional<SpecificIntrinsic> IntrinsicTable::Implementation::Probe(
818 const CallCharacteristics &call) const {
819 if (call.isSubroutineCall) {
820 return std::nullopt; // TODO
821 }
822 // Probe the specific intrinsic functions first.
823 std::string name{call.name.ToString()};
824 auto specificRange{specificFuncs.equal_range(name)};
825 for (auto iter{specificRange.first}; iter != specificRange.second; ++iter) {
826 if (auto specific{iter->second->Match(call, defaults)}) {
827 specific->name = iter->second->generic;
828 return specific;
829 }
830 }
831 auto genericRange{specificFuncs.equal_range(name)};
832 for (auto iter{genericRange.first}; iter != genericRange.second; ++iter) {
833 if (auto specific{iter->second->Match(call, defaults)}) {
834 return specific;
835 }
836 }
837 return std::nullopt;
838}
839
peter klausler42b33da2018-09-29 00:02:11840IntrinsicTable::~IntrinsicTable() {
841 delete impl_;
842 impl_ = nullptr;
843}
844
845IntrinsicTable IntrinsicTable::Configure(
846 const semantics::IntrinsicTypeDefaultKinds &defaults) {
847 IntrinsicTable result;
848 result.impl_ = new IntrinsicTable::Implementation(defaults);
849 return result;
850}
851
peter klauslera70f5962018-10-04 20:43:33852std::optional<SpecificIntrinsic> IntrinsicTable::Probe(
peter klausler75a32092018-10-05 16:57:53853 const CallCharacteristics &call) const {
peter klauslera70f5962018-10-04 20:43:33854 CHECK(impl_ != nullptr || !"IntrinsicTable: not configured");
peter klausler75a32092018-10-05 16:57:53855 return impl_->Probe(call);
peter klausler42b33da2018-09-29 00:02:11856}
857} // namespace Fortran::evaluate