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