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-2021 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.length != 1) 96 return BUILTIN.unimp; 97 98 const id1 = md.packages[0]; 99 if (id1 != Id.core && id1 != Id.std) 100 return BUILTIN.unimp; 101 const id3 = fd.ident; 102 103 if (id1 == Id.core && id2 == Id.bitop) 104 { 105 if (id3 == Id.bsf) return BUILTIN.bsf; 106 if (id3 == Id.bsr) return BUILTIN.bsr; 107 if (id3 == Id.bswap) return BUILTIN.bswap; 108 if (id3 == Id._popcnt) return BUILTIN.popcnt; 109 return BUILTIN.unimp; 110 } 111 112 // Math 113 if (id3 == Id.sin) return BUILTIN.sin; 114 if (id3 == Id.cos) return BUILTIN.cos; 115 if (id3 == Id.tan) return BUILTIN.tan; 116 if (id3 == Id.atan2) return BUILTIN.unimp; // N.B unimplmeneted 117 118 if (id3 == Id._sqrt) return BUILTIN.sqrt; 119 if (id3 == Id.fabs) return BUILTIN.fabs; 120 121 if (id3 == Id.exp) return BUILTIN.exp; 122 if (id3 == Id.expm1) return BUILTIN.expm1; 123 if (id3 == Id.exp2) return BUILTIN.exp2; 124 if (id3 == Id.yl2x) return CTFloat.yl2x_supported ? BUILTIN.yl2x : BUILTIN.unimp; 125 if (id3 == Id.yl2xp1) return CTFloat.yl2xp1_supported ? BUILTIN.yl2xp1 : BUILTIN.unimp; 126 127 if (id3 == Id.log) return BUILTIN.log; 128 if (id3 == Id.log2) return BUILTIN.log2; 129 if (id3 == Id.log10) return BUILTIN.log10; 130 131 if (id3 == Id.ldexp) return BUILTIN.ldexp; 132 if (id3 == Id.round) return BUILTIN.round; 133 if (id3 == Id.floor) return BUILTIN.floor; 134 if (id3 == Id.ceil) return BUILTIN.ceil; 135 if (id3 == Id.trunc) return BUILTIN.trunc; 136 137 if (id3 == Id.fmin) return BUILTIN.fmin; 138 if (id3 == Id.fmax) return BUILTIN.fmax; 139 if (id3 == Id.fma) return BUILTIN.fma; 140 if (id3 == Id.copysign) return BUILTIN.copysign; 141 142 if (id3 == Id.isnan) return BUILTIN.isnan; 143 if (id3 == Id.isInfinity) return BUILTIN.isinfinity; 144 if (id3 == Id.isfinite) return BUILTIN.isfinite; 145 146 // Only match pow(fp,fp) where fp is a floating point type 147 if (id3 == Id._pow) 148 { 149 if ((*fd.parameters)[0].type.isfloating() && 150 (*fd.parameters)[1].type.isfloating()) 151 return BUILTIN.pow; 152 return BUILTIN.unimp; 153 } 154 155 if (id3 != Id.toPrec) 156 return BUILTIN.unimp; 157 const(char)* me = mangleExact(fd); 158 final switch (me["_D4core4math__T6toPrecHT".length]) 159 { 160 case 'd': return BUILTIN.toPrecDouble; 161 case 'e': return BUILTIN.toPrecReal; 162 case 'f': return BUILTIN.toPrecFloat; 163 } 164 } 165 166 Expression eval_unimp(Loc loc, FuncDeclaration fd, Expressions* arguments) 167 { 168 return null; 169 } 170 171 Expression eval_sin(Loc loc, FuncDeclaration fd, Expressions* arguments) 172 { 173 Expression arg0 = (*arguments)[0]; 174 assert(arg0.op == TOK.float64); 175 return new RealExp(loc, CTFloat.sin(arg0.toReal()), arg0.type); 176 } 177 178 Expression eval_cos(Loc loc, FuncDeclaration fd, Expressions* arguments) 179 { 180 Expression arg0 = (*arguments)[0]; 181 assert(arg0.op == TOK.float64); 182 return new RealExp(loc, CTFloat.cos(arg0.toReal()), arg0.type); 183 } 184 185 Expression eval_tan(Loc loc, FuncDeclaration fd, Expressions* arguments) 186 { 187 Expression arg0 = (*arguments)[0]; 188 assert(arg0.op == TOK.float64); 189 return new RealExp(loc, CTFloat.tan(arg0.toReal()), arg0.type); 190 } 191 192 Expression eval_sqrt(Loc loc, FuncDeclaration fd, Expressions* arguments) 193 { 194 Expression arg0 = (*arguments)[0]; 195 assert(arg0.op == TOK.float64); 196 return new RealExp(loc, CTFloat.sqrt(arg0.toReal()), arg0.type); 197 } 198 199 Expression eval_fabs(Loc loc, FuncDeclaration fd, Expressions* arguments) 200 { 201 Expression arg0 = (*arguments)[0]; 202 assert(arg0.op == TOK.float64); 203 return new RealExp(loc, CTFloat.fabs(arg0.toReal()), arg0.type); 204 } 205 206 Expression eval_ldexp(Loc loc, FuncDeclaration fd, Expressions* arguments) 207 { 208 Expression arg0 = (*arguments)[0]; 209 assert(arg0.op == TOK.float64); 210 Expression arg1 = (*arguments)[1]; 211 assert(arg1.op == TOK.int64); 212 return new RealExp(loc, CTFloat.ldexp(arg0.toReal(), cast(int) arg1.toInteger()), arg0.type); 213 } 214 215 Expression eval_log(Loc loc, FuncDeclaration fd, Expressions* arguments) 216 { 217 Expression arg0 = (*arguments)[0]; 218 assert(arg0.op == TOK.float64); 219 return new RealExp(loc, CTFloat.log(arg0.toReal()), arg0.type); 220 } 221 222 Expression eval_log2(Loc loc, FuncDeclaration fd, Expressions* arguments) 223 { 224 Expression arg0 = (*arguments)[0]; 225 assert(arg0.op == TOK.float64); 226 return new RealExp(loc, CTFloat.log2(arg0.toReal()), arg0.type); 227 } 228 229 Expression eval_log10(Loc loc, FuncDeclaration fd, Expressions* arguments) 230 { 231 Expression arg0 = (*arguments)[0]; 232 assert(arg0.op == TOK.float64); 233 return new RealExp(loc, CTFloat.log10(arg0.toReal()), arg0.type); 234 } 235 236 Expression eval_exp(Loc loc, FuncDeclaration fd, Expressions* arguments) 237 { 238 Expression arg0 = (*arguments)[0]; 239 assert(arg0.op == TOK.float64); 240 return new RealExp(loc, CTFloat.exp(arg0.toReal()), arg0.type); 241 } 242 243 Expression eval_expm1(Loc loc, FuncDeclaration fd, Expressions* arguments) 244 { 245 Expression arg0 = (*arguments)[0]; 246 assert(arg0.op == TOK.float64); 247 return new RealExp(loc, CTFloat.expm1(arg0.toReal()), arg0.type); 248 } 249 250 Expression eval_exp2(Loc loc, FuncDeclaration fd, Expressions* arguments) 251 { 252 Expression arg0 = (*arguments)[0]; 253 assert(arg0.op == TOK.float64); 254 return new RealExp(loc, CTFloat.exp2(arg0.toReal()), arg0.type); 255 } 256 257 Expression eval_round(Loc loc, FuncDeclaration fd, Expressions* arguments) 258 { 259 Expression arg0 = (*arguments)[0]; 260 assert(arg0.op == TOK.float64); 261 return new RealExp(loc, CTFloat.round(arg0.toReal()), arg0.type); 262 } 263 264 Expression eval_floor(Loc loc, FuncDeclaration fd, Expressions* arguments) 265 { 266 Expression arg0 = (*arguments)[0]; 267 assert(arg0.op == TOK.float64); 268 return new RealExp(loc, CTFloat.floor(arg0.toReal()), arg0.type); 269 } 270 271 Expression eval_ceil(Loc loc, FuncDeclaration fd, Expressions* arguments) 272 { 273 Expression arg0 = (*arguments)[0]; 274 assert(arg0.op == TOK.float64); 275 return new RealExp(loc, CTFloat.ceil(arg0.toReal()), arg0.type); 276 } 277 278 Expression eval_trunc(Loc loc, FuncDeclaration fd, Expressions* arguments) 279 { 280 Expression arg0 = (*arguments)[0]; 281 assert(arg0.op == TOK.float64); 282 return new RealExp(loc, CTFloat.trunc(arg0.toReal()), arg0.type); 283 } 284 285 Expression eval_copysign(Loc loc, FuncDeclaration fd, Expressions* arguments) 286 { 287 Expression arg0 = (*arguments)[0]; 288 assert(arg0.op == TOK.float64); 289 Expression arg1 = (*arguments)[1]; 290 assert(arg1.op == TOK.float64); 291 return new RealExp(loc, CTFloat.copysign(arg0.toReal(), arg1.toReal()), arg0.type); 292 } 293 294 Expression eval_pow(Loc loc, FuncDeclaration fd, Expressions* arguments) 295 { 296 Expression arg0 = (*arguments)[0]; 297 assert(arg0.op == TOK.float64); 298 Expression arg1 = (*arguments)[1]; 299 assert(arg1.op == TOK.float64); 300 return new RealExp(loc, CTFloat.pow(arg0.toReal(), arg1.toReal()), arg0.type); 301 } 302 303 Expression eval_fmin(Loc loc, FuncDeclaration fd, Expressions* arguments) 304 { 305 Expression arg0 = (*arguments)[0]; 306 assert(arg0.op == TOK.float64); 307 Expression arg1 = (*arguments)[1]; 308 assert(arg1.op == TOK.float64); 309 return new RealExp(loc, CTFloat.fmin(arg0.toReal(), arg1.toReal()), arg0.type); 310 } 311 312 Expression eval_fmax(Loc loc, FuncDeclaration fd, Expressions* arguments) 313 { 314 Expression arg0 = (*arguments)[0]; 315 assert(arg0.op == TOK.float64); 316 Expression arg1 = (*arguments)[1]; 317 assert(arg1.op == TOK.float64); 318 return new RealExp(loc, CTFloat.fmax(arg0.toReal(), arg1.toReal()), arg0.type); 319 } 320 321 Expression eval_fma(Loc loc, FuncDeclaration fd, Expressions* arguments) 322 { 323 Expression arg0 = (*arguments)[0]; 324 assert(arg0.op == TOK.float64); 325 Expression arg1 = (*arguments)[1]; 326 assert(arg1.op == TOK.float64); 327 Expression arg2 = (*arguments)[2]; 328 assert(arg2.op == TOK.float64); 329 return new RealExp(loc, CTFloat.fma(arg0.toReal(), arg1.toReal(), arg2.toReal()), arg0.type); 330 } 331 332 Expression eval_isnan(Loc loc, FuncDeclaration fd, Expressions* arguments) 333 { 334 Expression arg0 = (*arguments)[0]; 335 assert(arg0.op == TOK.float64); 336 return IntegerExp.createBool(CTFloat.isNaN(arg0.toReal())); 337 } 338 339 Expression eval_isinfinity(Loc loc, FuncDeclaration fd, Expressions* arguments) 340 { 341 Expression arg0 = (*arguments)[0]; 342 assert(arg0.op == TOK.float64); 343 return IntegerExp.createBool(CTFloat.isInfinity(arg0.toReal())); 344 } 345 346 Expression eval_isfinite(Loc loc, FuncDeclaration fd, Expressions* arguments) 347 { 348 Expression arg0 = (*arguments)[0]; 349 assert(arg0.op == TOK.float64); 350 const value = !CTFloat.isNaN(arg0.toReal()) && !CTFloat.isInfinity(arg0.toReal()); 351 return IntegerExp.createBool(value); 352 } 353 354 Expression eval_bsf(Loc loc, FuncDeclaration fd, Expressions* arguments) 355 { 356 Expression arg0 = (*arguments)[0]; 357 assert(arg0.op == TOK.int64); 358 uinteger_t n = arg0.toInteger(); 359 if (n == 0) 360 error(loc, "`bsf(0)` is undefined"); 361 return new IntegerExp(loc, core.bitop.bsf(n), Type.tint32); 362 } 363 364 Expression eval_bsr(Loc loc, FuncDeclaration fd, Expressions* arguments) 365 { 366 Expression arg0 = (*arguments)[0]; 367 assert(arg0.op == TOK.int64); 368 uinteger_t n = arg0.toInteger(); 369 if (n == 0) 370 error(loc, "`bsr(0)` is undefined"); 371 return new IntegerExp(loc, core.bitop.bsr(n), Type.tint32); 372 } 373 374 Expression eval_bswap(Loc loc, FuncDeclaration fd, Expressions* arguments) 375 { 376 Expression arg0 = (*arguments)[0]; 377 assert(arg0.op == TOK.int64); 378 uinteger_t n = arg0.toInteger(); 379 TY ty = arg0.type.toBasetype().ty; 380 if (ty == Tint64 || ty == Tuns64) 381 return new IntegerExp(loc, core.bitop.bswap(cast(ulong) n), arg0.type); 382 else 383 return new IntegerExp(loc, core.bitop.bswap(cast(uint) n), arg0.type); 384 } 385 386 Expression eval_popcnt(Loc loc, FuncDeclaration fd, Expressions* arguments) 387 { 388 Expression arg0 = (*arguments)[0]; 389 assert(arg0.op == TOK.int64); 390 uinteger_t n = arg0.toInteger(); 391 return new IntegerExp(loc, core.bitop.popcnt(n), Type.tint32); 392 } 393 394 Expression eval_yl2x(Loc loc, FuncDeclaration fd, Expressions* arguments) 395 { 396 Expression arg0 = (*arguments)[0]; 397 assert(arg0.op == TOK.float64); 398 Expression arg1 = (*arguments)[1]; 399 assert(arg1.op == TOK.float64); 400 const x = arg0.toReal(); 401 const y = arg1.toReal(); 402 real_t result = CTFloat.zero; 403 CTFloat.yl2x(&x, &y, &result); 404 return new RealExp(loc, result, arg0.type); 405 } 406 407 Expression eval_yl2xp1(Loc loc, FuncDeclaration fd, Expressions* arguments) 408 { 409 Expression arg0 = (*arguments)[0]; 410 assert(arg0.op == TOK.float64); 411 Expression arg1 = (*arguments)[1]; 412 assert(arg1.op == TOK.float64); 413 const x = arg0.toReal(); 414 const y = arg1.toReal(); 415 real_t result = CTFloat.zero; 416 CTFloat.yl2xp1(&x, &y, &result); 417 return new RealExp(loc, result, arg0.type); 418 } 419 420 Expression eval_toPrecFloat(Loc loc, FuncDeclaration fd, Expressions* arguments) 421 { 422 Expression arg0 = (*arguments)[0]; 423 float f = cast(real)arg0.toReal(); 424 return new RealExp(loc, real_t(f), Type.tfloat32); 425 } 426 427 Expression eval_toPrecDouble(Loc loc, FuncDeclaration fd, Expressions* arguments) 428 { 429 Expression arg0 = (*arguments)[0]; 430 double d = cast(real)arg0.toReal(); 431 return new RealExp(loc, real_t(d), Type.tfloat64); 432 } 433 434 Expression eval_toPrecReal(Loc loc, FuncDeclaration fd, Expressions* arguments) 435 { 436 Expression arg0 = (*arguments)[0]; 437 return new RealExp(loc, arg0.toReal(), Type.tfloat80); 438 } 439 440 // These built-ins are reserved for GDC and LDC. 441 Expression eval_gcc(Loc, FuncDeclaration, Expressions*) 442 { 443 assert(0); 444 } 445 446 Expression eval_llvm(Loc, FuncDeclaration, Expressions*) 447 { 448 assert(0); 449 }