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