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 1
    if (fd.builtin == BUILTIN.unknown)
38
    {
39 1
        fd.builtin = determine_builtin(fd);
40
    }
41 1
    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 1
    if (fd.builtin == BUILTIN.unimp)
51 0
        return null;
52

53 1
    switch (fd.builtin)
54
    {
55
        foreach(e; __traits(allMembers, BUILTIN))
56
        {
57
            static if (e == "unknown")
58 0
                case BUILTIN.unknown: assert(false);
59
            else
60
                mixin("case BUILTIN."~e~": return eval_"~e~"(loc, fd, arguments);");
61
        }
62 0
        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 1
    auto fd = func.toAliasFunc();
83 1
    if (fd.isDeprecated())
84 1
        return BUILTIN.unimp;
85 1
    auto m = fd.getModule();
86 1
    if (!m || !m.md)
87 1
        return BUILTIN.unimp;
88 1
    const md = m.md;
89 1
    const id2 = md.id;
90

91
    // Look for core.math, core.bitop and std.math
92 1
    if (id2 != Id.math && id2 != Id.bitop)
93 1
        return BUILTIN.unimp;
94

95 1
    if (!md.packages)
96 0
        return BUILTIN.unimp;
97 1
    if (md.packages.length != 1)
98 0
        return BUILTIN.unimp;
99

100 1
    const id1 = (*md.packages)[0];
101 1
    if (id1 != Id.core && id1 != Id.std)
102 0
        return BUILTIN.unimp;
103 1
    const id3 = fd.ident;
104

105 1
    if (id1 == Id.core && id2 == Id.bitop)
106
    {
107 1
        if (id3 == Id.bsf)     return BUILTIN.bsf;
108 1
        if (id3 == Id.bsr)     return BUILTIN.bsr;
109 1
        if (id3 == Id.bswap)   return BUILTIN.bswap;
110 1
        if (id3 == Id._popcnt) return BUILTIN.popcnt;
111 0
        return BUILTIN.unimp;
112
    }
113

114
    // Math
115 1
    if (id3 == Id.sin)   return BUILTIN.sin;
116 1
    if (id3 == Id.cos)   return BUILTIN.cos;
117 1
    if (id3 == Id.tan)   return BUILTIN.tan;
118 1
    if (id3 == Id.atan2) return BUILTIN.unimp; // N.B unimplmeneted
119

120 1
    if (id3 == Id._sqrt) return BUILTIN.sqrt;
121 1
    if (id3 == Id.fabs)  return BUILTIN.fabs;
122

123 1
    if (id3 == Id.exp)    return BUILTIN.exp;
124 1
    if (id3 == Id.expm1)  return BUILTIN.expm1;
125 1
    if (id3 == Id.exp2)   return BUILTIN.exp2;
126 1
    if (id3 == Id.yl2x)   return CTFloat.yl2x_supported ? BUILTIN.yl2x : BUILTIN.unimp;
127 1
    if (id3 == Id.yl2xp1) return CTFloat.yl2xp1_supported ? BUILTIN.yl2xp1 : BUILTIN.unimp;
128

129 1
    if (id3 == Id.log)   return BUILTIN.log;
130 1
    if (id3 == Id.log2)  return BUILTIN.log2;
131 1
    if (id3 == Id.log10) return BUILTIN.log10;
132

133 1
    if (id3 == Id.ldexp) return BUILTIN.ldexp;
134 1
    if (id3 == Id.round) return BUILTIN.round;
135 1
    if (id3 == Id.floor) return BUILTIN.floor;
136 1
    if (id3 == Id.ceil)  return BUILTIN.ceil;
137 1
    if (id3 == Id.trunc) return BUILTIN.trunc;
138

139 1
    if (id3 == Id.fmin)     return BUILTIN.fmin;
140 1
    if (id3 == Id.fmax)     return BUILTIN.fmax;
141 1
    if (id3 == Id.fma)      return BUILTIN.fma;
142 1
    if (id3 == Id.copysign) return BUILTIN.copysign;
143

144 1
    if (id3 == Id.isnan)      return BUILTIN.isnan;
145 1
    if (id3 == Id.isInfinity) return BUILTIN.isinfinity;
146 1
    if (id3 == Id.isfinite)   return BUILTIN.isfinite;
147

148
    // Only match pow(fp,fp) where fp is a floating point type
149 1
    if (id3 == Id._pow)
150
    {
151 1
        if ((*fd.parameters)[0].type.isfloating() &&
152 1
            (*fd.parameters)[1].type.isfloating())
153 1
            return BUILTIN.pow;
154 1
        return BUILTIN.unimp;
155
    }
156

157 1
    if (id3 != Id.toPrec)
158 1
        return BUILTIN.unimp;
159 1
    const(char)* me = mangleExact(fd);
160 1
    final switch (me["_D4core4math__T6toPrecHT".length])
161
    {
162 1
        case 'd': return BUILTIN.toPrecDouble;
163 1
        case 'e': return BUILTIN.toPrecReal;
164 1
        case 'f': return BUILTIN.toPrecFloat;
165
    }
166
}
167

168
Expression eval_unimp(Loc loc, FuncDeclaration fd, Expressions* arguments)
169
{
170 0
    return null;
171
}
172

173
Expression eval_sin(Loc loc, FuncDeclaration fd, Expressions* arguments)
174
{
175 1
    Expression arg0 = (*arguments)[0];
176 1
    assert(arg0.op == TOK.float64);
177 1
    return new RealExp(loc, CTFloat.sin(arg0.toReal()), arg0.type);
178
}
179

180
Expression eval_cos(Loc loc, FuncDeclaration fd, Expressions* arguments)
181
{
182 1
    Expression arg0 = (*arguments)[0];
183 1
    assert(arg0.op == TOK.float64);
184 1
    return new RealExp(loc, CTFloat.cos(arg0.toReal()), arg0.type);
185
}
186

187
Expression eval_tan(Loc loc, FuncDeclaration fd, Expressions* arguments)
188
{
189 1
    Expression arg0 = (*arguments)[0];
190 1
    assert(arg0.op == TOK.float64);
191 1
    return new RealExp(loc, CTFloat.tan(arg0.toReal()), arg0.type);
192
}
193

194
Expression eval_sqrt(Loc loc, FuncDeclaration fd, Expressions* arguments)
195
{
196 1
    Expression arg0 = (*arguments)[0];
197 1
    assert(arg0.op == TOK.float64);
198 1
    return new RealExp(loc, CTFloat.sqrt(arg0.toReal()), arg0.type);
199
}
200

201
Expression eval_fabs(Loc loc, FuncDeclaration fd, Expressions* arguments)
202
{
203 1
    Expression arg0 = (*arguments)[0];
204 1
    assert(arg0.op == TOK.float64);
205 1
    return new RealExp(loc, CTFloat.fabs(arg0.toReal()), arg0.type);
206
}
207

208
Expression eval_ldexp(Loc loc, FuncDeclaration fd, Expressions* arguments)
209
{
210 1
    Expression arg0 = (*arguments)[0];
211 1
    assert(arg0.op == TOK.float64);
212 1
    Expression arg1 = (*arguments)[1];
213 1
    assert(arg1.op == TOK.int64);
214 1
    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 1
    Expression arg0 = (*arguments)[0];
220 1
    assert(arg0.op == TOK.float64);
221 1
    return new RealExp(loc, CTFloat.log(arg0.toReal()), arg0.type);
222
}
223

224
Expression eval_log2(Loc loc, FuncDeclaration fd, Expressions* arguments)
225
{
226 1
    Expression arg0 = (*arguments)[0];
227 1
    assert(arg0.op == TOK.float64);
228 1
    return new RealExp(loc, CTFloat.log2(arg0.toReal()), arg0.type);
229
}
230

231
Expression eval_log10(Loc loc, FuncDeclaration fd, Expressions* arguments)
232
{
233 1
    Expression arg0 = (*arguments)[0];
234 1
    assert(arg0.op == TOK.float64);
235 1
    return new RealExp(loc, CTFloat.log10(arg0.toReal()), arg0.type);
236
}
237

238
Expression eval_exp(Loc loc, FuncDeclaration fd, Expressions* arguments)
239
{
240 1
    Expression arg0 = (*arguments)[0];
241 1
    assert(arg0.op == TOK.float64);
242 1
    return new RealExp(loc, CTFloat.exp(arg0.toReal()), arg0.type);
243
}
244

245
Expression eval_expm1(Loc loc, FuncDeclaration fd, Expressions* arguments)
246
{
247 1
    Expression arg0 = (*arguments)[0];
248 1
    assert(arg0.op == TOK.float64);
249 1
    return new RealExp(loc, CTFloat.expm1(arg0.toReal()), arg0.type);
250
}
251

252
Expression eval_exp2(Loc loc, FuncDeclaration fd, Expressions* arguments)
253
{
254 1
    Expression arg0 = (*arguments)[0];
255 1
    assert(arg0.op == TOK.float64);
256 1
    return new RealExp(loc, CTFloat.exp2(arg0.toReal()), arg0.type);
257
}
258

259
Expression eval_round(Loc loc, FuncDeclaration fd, Expressions* arguments)
260
{
261 1
    Expression arg0 = (*arguments)[0];
262 1
    assert(arg0.op == TOK.float64);
263 1
    return new RealExp(loc, CTFloat.round(arg0.toReal()), arg0.type);
264
}
265

266
Expression eval_floor(Loc loc, FuncDeclaration fd, Expressions* arguments)
267
{
268 1
    Expression arg0 = (*arguments)[0];
269 1
    assert(arg0.op == TOK.float64);
270 1
    return new RealExp(loc, CTFloat.floor(arg0.toReal()), arg0.type);
271
}
272

273
Expression eval_ceil(Loc loc, FuncDeclaration fd, Expressions* arguments)
274
{
275 1
    Expression arg0 = (*arguments)[0];
276 1
    assert(arg0.op == TOK.float64);
277 1
    return new RealExp(loc, CTFloat.ceil(arg0.toReal()), arg0.type);
278
}
279

280
Expression eval_trunc(Loc loc, FuncDeclaration fd, Expressions* arguments)
281
{
282 1
    Expression arg0 = (*arguments)[0];
283 1
    assert(arg0.op == TOK.float64);
284 1
    return new RealExp(loc, CTFloat.trunc(arg0.toReal()), arg0.type);
285
}
286

287
Expression eval_copysign(Loc loc, FuncDeclaration fd, Expressions* arguments)
288
{
289 1
    Expression arg0 = (*arguments)[0];
290 1
    assert(arg0.op == TOK.float64);
291 1
    Expression arg1 = (*arguments)[1];
292 1
    assert(arg1.op == TOK.float64);
293 1
    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 1
    Expression arg0 = (*arguments)[0];
299 1
    assert(arg0.op == TOK.float64);
300 1
    Expression arg1 = (*arguments)[1];
301 1
    assert(arg1.op == TOK.float64);
302 1
    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 1
    Expression arg0 = (*arguments)[0];
308 1
    assert(arg0.op == TOK.float64);
309 1
    Expression arg1 = (*arguments)[1];
310 1
    assert(arg1.op == TOK.float64);
311 1
    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 1
    Expression arg0 = (*arguments)[0];
317 1
    assert(arg0.op == TOK.float64);
318 1
    Expression arg1 = (*arguments)[1];
319 1
    assert(arg1.op == TOK.float64);
320 1
    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 1
    Expression arg0 = (*arguments)[0];
326 1
    assert(arg0.op == TOK.float64);
327 1
    Expression arg1 = (*arguments)[1];
328 1
    assert(arg1.op == TOK.float64);
329 1
    Expression arg2 = (*arguments)[2];
330 1
    assert(arg2.op == TOK.float64);
331 1
    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 0
    Expression arg0 = (*arguments)[0];
337 0
    assert(arg0.op == TOK.float64);
338 0
    return IntegerExp.createBool(CTFloat.isNaN(arg0.toReal()));
339
}
340

341
Expression eval_isinfinity(Loc loc, FuncDeclaration fd, Expressions* arguments)
342
{
343 1
    Expression arg0 = (*arguments)[0];
344 1
    assert(arg0.op == TOK.float64);
345 1
    return IntegerExp.createBool(CTFloat.isInfinity(arg0.toReal()));
346
}
347

348
Expression eval_isfinite(Loc loc, FuncDeclaration fd, Expressions* arguments)
349
{
350 0
    Expression arg0 = (*arguments)[0];
351 0
    assert(arg0.op == TOK.float64);
352 0
    const value = !CTFloat.isNaN(arg0.toReal()) && !CTFloat.isInfinity(arg0.toReal());
353 0
    return IntegerExp.createBool(value);
354
}
355

356
Expression eval_bsf(Loc loc, FuncDeclaration fd, Expressions* arguments)
357
{
358 1
    Expression arg0 = (*arguments)[0];
359 1
    assert(arg0.op == TOK.int64);
360 1
    uinteger_t n = arg0.toInteger();
361 1
    if (n == 0)
362 0
        error(loc, "`bsf(0)` is undefined");
363 1
    return new IntegerExp(loc, core.bitop.bsf(n), Type.tint32);
364
}
365

366
Expression eval_bsr(Loc loc, FuncDeclaration fd, Expressions* arguments)
367
{
368 1
    Expression arg0 = (*arguments)[0];
369 1
    assert(arg0.op == TOK.int64);
370 1
    uinteger_t n = arg0.toInteger();
371 1
    if (n == 0)
372 0
        error(loc, "`bsr(0)` is undefined");
373 1
    return new IntegerExp(loc, core.bitop.bsr(n), Type.tint32);
374
}
375

376
Expression eval_bswap(Loc loc, FuncDeclaration fd, Expressions* arguments)
377
{
378 1
    Expression arg0 = (*arguments)[0];
379 1
    assert(arg0.op == TOK.int64);
380 1
    uinteger_t n = arg0.toInteger();
381 1
    TY ty = arg0.type.toBasetype().ty;
382 1
    if (ty == Tint64 || ty == Tuns64)
383 0
        return new IntegerExp(loc, core.bitop.bswap(cast(ulong) n), arg0.type);
384
    else
385 1
        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 1
    Expression arg0 = (*arguments)[0];
391 1
    assert(arg0.op == TOK.int64);
392 1
    uinteger_t n = arg0.toInteger();
393 1
    return new IntegerExp(loc, core.bitop.popcnt(n), Type.tint32);
394
}
395

396
Expression eval_yl2x(Loc loc, FuncDeclaration fd, Expressions* arguments)
397
{
398 0
    Expression arg0 = (*arguments)[0];
399 0
    assert(arg0.op == TOK.float64);
400 0
    Expression arg1 = (*arguments)[1];
401 0
    assert(arg1.op == TOK.float64);
402 0
    const x = arg0.toReal();
403 0
    const y = arg1.toReal();
404 0
    real_t result = CTFloat.zero;
405 0
    CTFloat.yl2x(&x, &y, &result);
406 0
    return new RealExp(loc, result, arg0.type);
407
}
408

409
Expression eval_yl2xp1(Loc loc, FuncDeclaration fd, Expressions* arguments)
410
{
411 0
    Expression arg0 = (*arguments)[0];
412 0
    assert(arg0.op == TOK.float64);
413 0
    Expression arg1 = (*arguments)[1];
414 0
    assert(arg1.op == TOK.float64);
415 0
    const x = arg0.toReal();
416 0
    const y = arg1.toReal();
417 0
    real_t result = CTFloat.zero;
418 0
    CTFloat.yl2xp1(&x, &y, &result);
419 0
    return new RealExp(loc, result, arg0.type);
420
}
421

422
Expression eval_toPrecFloat(Loc loc, FuncDeclaration fd, Expressions* arguments)
423
{
424 1
    Expression arg0 = (*arguments)[0];
425 1
    float f = cast(real)arg0.toReal();
426 1
    return new RealExp(loc, real_t(f), Type.tfloat32);
427
}
428

429
Expression eval_toPrecDouble(Loc loc, FuncDeclaration fd, Expressions* arguments)
430
{
431 1
    Expression arg0 = (*arguments)[0];
432 1
    double d = cast(real)arg0.toReal();
433 1
    return new RealExp(loc, real_t(d), Type.tfloat64);
434
}
435

436
Expression eval_toPrecReal(Loc loc, FuncDeclaration fd, Expressions* arguments)
437
{
438 1
    Expression arg0 = (*arguments)[0];
439 1
    return new RealExp(loc, arg0.toReal(), Type.tfloat80);
440
}
441

442
// These built-ins are reserved for GDC and LDC.
443
Expression eval_gcc(Loc, FuncDeclaration, Expressions*)
444
{
445 0
    assert(0);
446
}
447

448
Expression eval_llvm(Loc, FuncDeclaration, Expressions*)
449
{
450 0
    assert(0);
451
}

Read our documentation on viewing source code .

Loading