1 /**
2  * Implement CTFE for intrinsic (builtin) functions.
3  *
4  * Currently includes functions from `std.math`, `core.math` and `core.bitop`.
5  *
6  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d, _builtin.d)
10  * Documentation:  https://dlang.org/phobos/dmd_builtin.html
11  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/builtin.d
12  */
13 
14 module dmd.builtin;
15 
16 import core.stdc.math;
17 import core.stdc..string;
18 import dmd.arraytypes;
19 import dmd.dmangle;
20 import dmd.errors;
21 import dmd.expression;
22 import dmd.func;
23 import dmd.globals;
24 import dmd.mtype;
25 import dmd.root.ctfloat;
26 import dmd.root.stringtable;
27 import dmd.tokens;
28 import dmd.id;
29 static import core.bitop;
30 
31 /**********************************
32  * Determine if function is a builtin one that we can
33  * evaluate at compile time.
34  */
35 public extern (C++) BUILTIN isBuiltin(FuncDeclaration fd)
36 {
37     if (fd.builtin == BUILTIN.unknown)
38     {
39         fd.builtin = determine_builtin(fd);
40     }
41     return fd.builtin;
42 }
43 
44 /**************************************
45  * Evaluate builtin function.
46  * Return result; NULL if cannot evaluate it.
47  */
48 public extern (C++) Expression eval_builtin(Loc loc, FuncDeclaration fd, Expressions* arguments)
49 {
50     if (fd.builtin == BUILTIN.unimp)
51         return null;
52 
53     switch (fd.builtin)
54     {
55         foreach(e; __traits(allMembers, BUILTIN))
56         {
57             static if (e == "unknown")
58                 case BUILTIN.unknown: assert(false);
59             else
60                 mixin("case BUILTIN."~e~": return eval_"~e~"(loc, fd, arguments);");
61         }
62         default: assert(0);
63     }
64 }
65 
66 private:
67 
68 /**
69  * Handler for evaluating builtins during CTFE.
70  *
71  * Params:
72  *  loc = The call location, for error reporting.
73  *  fd = The callee declaration, e.g. to disambiguate between different overloads
74  *       in a single handler (LDC).
75  *  arguments = The function call arguments.
76  * Returns:
77  *  An Expression containing the return value of the call.
78  */
79 
80 BUILTIN determine_builtin(FuncDeclaration func)
81 {
82     auto fd = func.toAliasFunc();
83     if (fd.isDeprecated())
84         return BUILTIN.unimp;
85     auto m = fd.getModule();
86     if (!m || !m.md)
87         return BUILTIN.unimp;
88     const md = m.md;
89     const id2 = md.id;
90 
91     // Look for core.math, core.bitop and std.math
92     if (id2 != Id.math && id2 != Id.bitop)
93         return BUILTIN.unimp;
94 
95     if (!md.packages)
96         return BUILTIN.unimp;
97     if (md.packages.length != 1)
98         return BUILTIN.unimp;
99 
100     const id1 = (*md.packages)[0];
101     if (id1 != Id.core && id1 != Id.std)
102         return BUILTIN.unimp;
103     const id3 = fd.ident;
104 
105     if (id1 == Id.core && id2 == Id.bitop)
106     {
107         if (id3 == Id.bsf)     return BUILTIN.bsf;
108         if (id3 == Id.bsr)     return BUILTIN.bsr;
109         if (id3 == Id.bswap)   return BUILTIN.bswap;
110         if (id3 == Id._popcnt) return BUILTIN.popcnt;
111         return BUILTIN.unimp;
112     }
113 
114     // Math
115     if (id3 == Id.sin)   return BUILTIN.sin;
116     if (id3 == Id.cos)   return BUILTIN.cos;
117     if (id3 == Id.tan)   return BUILTIN.tan;
118     if (id3 == Id.atan2) return BUILTIN.unimp; // N.B unimplmeneted
119 
120     if (id3 == Id._sqrt) return BUILTIN.sqrt;
121     if (id3 == Id.fabs)  return BUILTIN.fabs;
122 
123     if (id3 == Id.exp)    return BUILTIN.exp;
124     if (id3 == Id.expm1)  return BUILTIN.expm1;
125     if (id3 == Id.exp2)   return BUILTIN.exp2;
126     if (id3 == Id.yl2x)   return CTFloat.yl2x_supported ? BUILTIN.yl2x : BUILTIN.unimp;
127     if (id3 == Id.yl2xp1) return CTFloat.yl2xp1_supported ? BUILTIN.yl2xp1 : BUILTIN.unimp;
128 
129     if (id3 == Id.log)   return BUILTIN.log;
130     if (id3 == Id.log2)  return BUILTIN.log2;
131     if (id3 == Id.log10) return BUILTIN.log10;
132 
133     if (id3 == Id.ldexp) return BUILTIN.ldexp;
134     if (id3 == Id.round) return BUILTIN.round;
135     if (id3 == Id.floor) return BUILTIN.floor;
136     if (id3 == Id.ceil)  return BUILTIN.ceil;
137     if (id3 == Id.trunc) return BUILTIN.trunc;
138 
139     if (id3 == Id.fmin)     return BUILTIN.fmin;
140     if (id3 == Id.fmax)     return BUILTIN.fmax;
141     if (id3 == Id.fma)      return BUILTIN.fma;
142     if (id3 == Id.copysign) return BUILTIN.copysign;
143 
144     if (id3 == Id.isnan)      return BUILTIN.isnan;
145     if (id3 == Id.isInfinity) return BUILTIN.isinfinity;
146     if (id3 == Id.isfinite)   return BUILTIN.isfinite;
147 
148     // Only match pow(fp,fp) where fp is a floating point type
149     if (id3 == Id._pow)
150     {
151         if ((*fd.parameters)[0].type.isfloating() &&
152             (*fd.parameters)[1].type.isfloating())
153             return BUILTIN.pow;
154         return BUILTIN.unimp;
155     }
156 
157     if (id3 != Id.toPrec)
158         return BUILTIN.unimp;
159     const(char)* me = mangleExact(fd);
160     final switch (me["_D4core4math__T6toPrecHT".length])
161     {
162         case 'd': return BUILTIN.toPrecDouble;
163         case 'e': return BUILTIN.toPrecReal;
164         case 'f': return BUILTIN.toPrecFloat;
165     }
166 }
167 
168 Expression eval_unimp(Loc loc, FuncDeclaration fd, Expressions* arguments)
169 {
170     return null;
171 }
172 
173 Expression eval_sin(Loc loc, FuncDeclaration fd, Expressions* arguments)
174 {
175     Expression arg0 = (*arguments)[0];
176     assert(arg0.op == TOK.float64);
177     return new RealExp(loc, CTFloat.sin(arg0.toReal()), arg0.type);
178 }
179 
180 Expression eval_cos(Loc loc, FuncDeclaration fd, Expressions* arguments)
181 {
182     Expression arg0 = (*arguments)[0];
183     assert(arg0.op == TOK.float64);
184     return new RealExp(loc, CTFloat.cos(arg0.toReal()), arg0.type);
185 }
186 
187 Expression eval_tan(Loc loc, FuncDeclaration fd, Expressions* arguments)
188 {
189     Expression arg0 = (*arguments)[0];
190     assert(arg0.op == TOK.float64);
191     return new RealExp(loc, CTFloat.tan(arg0.toReal()), arg0.type);
192 }
193 
194 Expression eval_sqrt(Loc loc, FuncDeclaration fd, Expressions* arguments)
195 {
196     Expression arg0 = (*arguments)[0];
197     assert(arg0.op == TOK.float64);
198     return new RealExp(loc, CTFloat.sqrt(arg0.toReal()), arg0.type);
199 }
200 
201 Expression eval_fabs(Loc loc, FuncDeclaration fd, Expressions* arguments)
202 {
203     Expression arg0 = (*arguments)[0];
204     assert(arg0.op == TOK.float64);
205     return new RealExp(loc, CTFloat.fabs(arg0.toReal()), arg0.type);
206 }
207 
208 Expression eval_ldexp(Loc loc, FuncDeclaration fd, Expressions* arguments)
209 {
210     Expression arg0 = (*arguments)[0];
211     assert(arg0.op == TOK.float64);
212     Expression arg1 = (*arguments)[1];
213     assert(arg1.op == TOK.int64);
214     return new RealExp(loc, CTFloat.ldexp(arg0.toReal(), cast(int) arg1.toInteger()), arg0.type);
215 }
216 
217 Expression eval_log(Loc loc, FuncDeclaration fd, Expressions* arguments)
218 {
219     Expression arg0 = (*arguments)[0];
220     assert(arg0.op == TOK.float64);
221     return new RealExp(loc, CTFloat.log(arg0.toReal()), arg0.type);
222 }
223 
224 Expression eval_log2(Loc loc, FuncDeclaration fd, Expressions* arguments)
225 {
226     Expression arg0 = (*arguments)[0];
227     assert(arg0.op == TOK.float64);
228     return new RealExp(loc, CTFloat.log2(arg0.toReal()), arg0.type);
229 }
230 
231 Expression eval_log10(Loc loc, FuncDeclaration fd, Expressions* arguments)
232 {
233     Expression arg0 = (*arguments)[0];
234     assert(arg0.op == TOK.float64);
235     return new RealExp(loc, CTFloat.log10(arg0.toReal()), arg0.type);
236 }
237 
238 Expression eval_exp(Loc loc, FuncDeclaration fd, Expressions* arguments)
239 {
240     Expression arg0 = (*arguments)[0];
241     assert(arg0.op == TOK.float64);
242     return new RealExp(loc, CTFloat.exp(arg0.toReal()), arg0.type);
243 }
244 
245 Expression eval_expm1(Loc loc, FuncDeclaration fd, Expressions* arguments)
246 {
247     Expression arg0 = (*arguments)[0];
248     assert(arg0.op == TOK.float64);
249     return new RealExp(loc, CTFloat.expm1(arg0.toReal()), arg0.type);
250 }
251 
252 Expression eval_exp2(Loc loc, FuncDeclaration fd, Expressions* arguments)
253 {
254     Expression arg0 = (*arguments)[0];
255     assert(arg0.op == TOK.float64);
256     return new RealExp(loc, CTFloat.exp2(arg0.toReal()), arg0.type);
257 }
258 
259 Expression eval_round(Loc loc, FuncDeclaration fd, Expressions* arguments)
260 {
261     Expression arg0 = (*arguments)[0];
262     assert(arg0.op == TOK.float64);
263     return new RealExp(loc, CTFloat.round(arg0.toReal()), arg0.type);
264 }
265 
266 Expression eval_floor(Loc loc, FuncDeclaration fd, Expressions* arguments)
267 {
268     Expression arg0 = (*arguments)[0];
269     assert(arg0.op == TOK.float64);
270     return new RealExp(loc, CTFloat.floor(arg0.toReal()), arg0.type);
271 }
272 
273 Expression eval_ceil(Loc loc, FuncDeclaration fd, Expressions* arguments)
274 {
275     Expression arg0 = (*arguments)[0];
276     assert(arg0.op == TOK.float64);
277     return new RealExp(loc, CTFloat.ceil(arg0.toReal()), arg0.type);
278 }
279 
280 Expression eval_trunc(Loc loc, FuncDeclaration fd, Expressions* arguments)
281 {
282     Expression arg0 = (*arguments)[0];
283     assert(arg0.op == TOK.float64);
284     return new RealExp(loc, CTFloat.trunc(arg0.toReal()), arg0.type);
285 }
286 
287 Expression eval_copysign(Loc loc, FuncDeclaration fd, Expressions* arguments)
288 {
289     Expression arg0 = (*arguments)[0];
290     assert(arg0.op == TOK.float64);
291     Expression arg1 = (*arguments)[1];
292     assert(arg1.op == TOK.float64);
293     return new RealExp(loc, CTFloat.copysign(arg0.toReal(), arg1.toReal()), arg0.type);
294 }
295 
296 Expression eval_pow(Loc loc, FuncDeclaration fd, Expressions* arguments)
297 {
298     Expression arg0 = (*arguments)[0];
299     assert(arg0.op == TOK.float64);
300     Expression arg1 = (*arguments)[1];
301     assert(arg1.op == TOK.float64);
302     return new RealExp(loc, CTFloat.pow(arg0.toReal(), arg1.toReal()), arg0.type);
303 }
304 
305 Expression eval_fmin(Loc loc, FuncDeclaration fd, Expressions* arguments)
306 {
307     Expression arg0 = (*arguments)[0];
308     assert(arg0.op == TOK.float64);
309     Expression arg1 = (*arguments)[1];
310     assert(arg1.op == TOK.float64);
311     return new RealExp(loc, CTFloat.fmin(arg0.toReal(), arg1.toReal()), arg0.type);
312 }
313 
314 Expression eval_fmax(Loc loc, FuncDeclaration fd, Expressions* arguments)
315 {
316     Expression arg0 = (*arguments)[0];
317     assert(arg0.op == TOK.float64);
318     Expression arg1 = (*arguments)[1];
319     assert(arg1.op == TOK.float64);
320     return new RealExp(loc, CTFloat.fmax(arg0.toReal(), arg1.toReal()), arg0.type);
321 }
322 
323 Expression eval_fma(Loc loc, FuncDeclaration fd, Expressions* arguments)
324 {
325     Expression arg0 = (*arguments)[0];
326     assert(arg0.op == TOK.float64);
327     Expression arg1 = (*arguments)[1];
328     assert(arg1.op == TOK.float64);
329     Expression arg2 = (*arguments)[2];
330     assert(arg2.op == TOK.float64);
331     return new RealExp(loc, CTFloat.fma(arg0.toReal(), arg1.toReal(), arg2.toReal()), arg0.type);
332 }
333 
334 Expression eval_isnan(Loc loc, FuncDeclaration fd, Expressions* arguments)
335 {
336     Expression arg0 = (*arguments)[0];
337     assert(arg0.op == TOK.float64);
338     return IntegerExp.createBool(CTFloat.isNaN(arg0.toReal()));
339 }
340 
341 Expression eval_isinfinity(Loc loc, FuncDeclaration fd, Expressions* arguments)
342 {
343     Expression arg0 = (*arguments)[0];
344     assert(arg0.op == TOK.float64);
345     return IntegerExp.createBool(CTFloat.isInfinity(arg0.toReal()));
346 }
347 
348 Expression eval_isfinite(Loc loc, FuncDeclaration fd, Expressions* arguments)
349 {
350     Expression arg0 = (*arguments)[0];
351     assert(arg0.op == TOK.float64);
352     const value = !CTFloat.isNaN(arg0.toReal()) && !CTFloat.isInfinity(arg0.toReal());
353     return IntegerExp.createBool(value);
354 }
355 
356 Expression eval_bsf(Loc loc, FuncDeclaration fd, Expressions* arguments)
357 {
358     Expression arg0 = (*arguments)[0];
359     assert(arg0.op == TOK.int64);
360     uinteger_t n = arg0.toInteger();
361     if (n == 0)
362         error(loc, "`bsf(0)` is undefined");
363     return new IntegerExp(loc, core.bitop.bsf(n), Type.tint32);
364 }
365 
366 Expression eval_bsr(Loc loc, FuncDeclaration fd, Expressions* arguments)
367 {
368     Expression arg0 = (*arguments)[0];
369     assert(arg0.op == TOK.int64);
370     uinteger_t n = arg0.toInteger();
371     if (n == 0)
372         error(loc, "`bsr(0)` is undefined");
373     return new IntegerExp(loc, core.bitop.bsr(n), Type.tint32);
374 }
375 
376 Expression eval_bswap(Loc loc, FuncDeclaration fd, Expressions* arguments)
377 {
378     Expression arg0 = (*arguments)[0];
379     assert(arg0.op == TOK.int64);
380     uinteger_t n = arg0.toInteger();
381     TY ty = arg0.type.toBasetype().ty;
382     if (ty == Tint64 || ty == Tuns64)
383         return new IntegerExp(loc, core.bitop.bswap(cast(ulong) n), arg0.type);
384     else
385         return new IntegerExp(loc, core.bitop.bswap(cast(uint) n), arg0.type);
386 }
387 
388 Expression eval_popcnt(Loc loc, FuncDeclaration fd, Expressions* arguments)
389 {
390     Expression arg0 = (*arguments)[0];
391     assert(arg0.op == TOK.int64);
392     uinteger_t n = arg0.toInteger();
393     return new IntegerExp(loc, core.bitop.popcnt(n), Type.tint32);
394 }
395 
396 Expression eval_yl2x(Loc loc, FuncDeclaration fd, Expressions* arguments)
397 {
398     Expression arg0 = (*arguments)[0];
399     assert(arg0.op == TOK.float64);
400     Expression arg1 = (*arguments)[1];
401     assert(arg1.op == TOK.float64);
402     const x = arg0.toReal();
403     const y = arg1.toReal();
404     real_t result = CTFloat.zero;
405     CTFloat.yl2x(&x, &y, &result);
406     return new RealExp(loc, result, arg0.type);
407 }
408 
409 Expression eval_yl2xp1(Loc loc, FuncDeclaration fd, Expressions* arguments)
410 {
411     Expression arg0 = (*arguments)[0];
412     assert(arg0.op == TOK.float64);
413     Expression arg1 = (*arguments)[1];
414     assert(arg1.op == TOK.float64);
415     const x = arg0.toReal();
416     const y = arg1.toReal();
417     real_t result = CTFloat.zero;
418     CTFloat.yl2xp1(&x, &y, &result);
419     return new RealExp(loc, result, arg0.type);
420 }
421 
422 Expression eval_toPrecFloat(Loc loc, FuncDeclaration fd, Expressions* arguments)
423 {
424     Expression arg0 = (*arguments)[0];
425     float f = cast(real)arg0.toReal();
426     return new RealExp(loc, real_t(f), Type.tfloat32);
427 }
428 
429 Expression eval_toPrecDouble(Loc loc, FuncDeclaration fd, Expressions* arguments)
430 {
431     Expression arg0 = (*arguments)[0];
432     double d = cast(real)arg0.toReal();
433     return new RealExp(loc, real_t(d), Type.tfloat64);
434 }
435 
436 Expression eval_toPrecReal(Loc loc, FuncDeclaration fd, Expressions* arguments)
437 {
438     Expression arg0 = (*arguments)[0];
439     return new RealExp(loc, arg0.toReal(), Type.tfloat80);
440 }