1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _builtin.d) 9 */ 10 11 module ddmd.builtin; 12 13 import core.stdc.math; 14 import core.stdc..string; 15 import ddmd.arraytypes; 16 import ddmd.dmangle; 17 import ddmd.errors; 18 import ddmd.expression; 19 import ddmd.func; 20 import ddmd.globals; 21 import ddmd.mtype; 22 import ddmd.root.ctfloat; 23 import ddmd.root.stringtable; 24 import ddmd.tokens; 25 26 private: 27 28 extern (C++) alias builtin_fp = Expression function(Loc loc, FuncDeclaration fd, Expressions* arguments); 29 30 __gshared StringTable builtins; 31 32 public extern (C++) void add_builtin(const(char)* mangle, builtin_fp fp) 33 { 34 builtins.insert(mangle, strlen(mangle), cast(void*)fp); 35 } 36 37 builtin_fp builtin_lookup(const(char)* mangle) 38 { 39 if (const sv = builtins.lookup(mangle, strlen(mangle))) 40 return cast(builtin_fp)sv.ptrvalue; 41 return null; 42 } 43 44 extern (C++) Expression eval_unimp(Loc loc, FuncDeclaration fd, Expressions* arguments) 45 { 46 return null; 47 } 48 49 extern (C++) Expression eval_sin(Loc loc, FuncDeclaration fd, Expressions* arguments) 50 { 51 Expression arg0 = (*arguments)[0]; 52 assert(arg0.op == TOKfloat64); 53 return new RealExp(loc, CTFloat.sin(arg0.toReal()), arg0.type); 54 } 55 56 extern (C++) Expression eval_cos(Loc loc, FuncDeclaration fd, Expressions* arguments) 57 { 58 Expression arg0 = (*arguments)[0]; 59 assert(arg0.op == TOKfloat64); 60 return new RealExp(loc, CTFloat.cos(arg0.toReal()), arg0.type); 61 } 62 63 extern (C++) Expression eval_tan(Loc loc, FuncDeclaration fd, Expressions* arguments) 64 { 65 Expression arg0 = (*arguments)[0]; 66 assert(arg0.op == TOKfloat64); 67 return new RealExp(loc, CTFloat.tan(arg0.toReal()), arg0.type); 68 } 69 70 extern (C++) Expression eval_sqrt(Loc loc, FuncDeclaration fd, Expressions* arguments) 71 { 72 Expression arg0 = (*arguments)[0]; 73 assert(arg0.op == TOKfloat64); 74 return new RealExp(loc, CTFloat.sqrt(arg0.toReal()), arg0.type); 75 } 76 77 extern (C++) Expression eval_fabs(Loc loc, FuncDeclaration fd, Expressions* arguments) 78 { 79 Expression arg0 = (*arguments)[0]; 80 assert(arg0.op == TOKfloat64); 81 return new RealExp(loc, CTFloat.fabs(arg0.toReal()), arg0.type); 82 } 83 84 extern (C++) Expression eval_bsf(Loc loc, FuncDeclaration fd, Expressions* arguments) 85 { 86 Expression arg0 = (*arguments)[0]; 87 assert(arg0.op == TOKint64); 88 uinteger_t n = arg0.toInteger(); 89 if (n == 0) 90 error(loc, "bsf(0) is undefined"); 91 n = (n ^ (n - 1)) >> 1; // convert trailing 0s to 1, and zero rest 92 int k = 0; 93 while (n) 94 { 95 ++k; 96 n >>= 1; 97 } 98 return new IntegerExp(loc, k, Type.tint32); 99 } 100 101 extern (C++) Expression eval_bsr(Loc loc, FuncDeclaration fd, Expressions* arguments) 102 { 103 Expression arg0 = (*arguments)[0]; 104 assert(arg0.op == TOKint64); 105 uinteger_t n = arg0.toInteger(); 106 if (n == 0) 107 error(loc, "bsr(0) is undefined"); 108 int k = 0; 109 while (n >>= 1) 110 { 111 ++k; 112 } 113 return new IntegerExp(loc, k, Type.tint32); 114 } 115 116 extern (C++) Expression eval_bswap(Loc loc, FuncDeclaration fd, Expressions* arguments) 117 { 118 Expression arg0 = (*arguments)[0]; 119 assert(arg0.op == TOKint64); 120 uinteger_t n = arg0.toInteger(); 121 enum BYTEMASK = 0x00FF00FF00FF00FFL; 122 enum SHORTMASK = 0x0000FFFF0000FFFFL; 123 enum INTMASK = 0x0000FFFF0000FFFFL; 124 // swap adjacent ubytes 125 n = ((n >> 8) & BYTEMASK) | ((n & BYTEMASK) << 8); 126 // swap adjacent ushorts 127 n = ((n >> 16) & SHORTMASK) | ((n & SHORTMASK) << 16); 128 TY ty = arg0.type.toBasetype().ty; 129 // If 64 bits, we need to swap high and low uints 130 if (ty == Tint64 || ty == Tuns64) 131 n = ((n >> 32) & INTMASK) | ((n & INTMASK) << 32); 132 return new IntegerExp(loc, n, arg0.type); 133 } 134 135 extern (C++) Expression eval_popcnt(Loc loc, FuncDeclaration fd, Expressions* arguments) 136 { 137 Expression arg0 = (*arguments)[0]; 138 assert(arg0.op == TOKint64); 139 uinteger_t n = arg0.toInteger(); 140 int cnt = 0; 141 while (n) 142 { 143 cnt += (n & 1); 144 n >>= 1; 145 } 146 return new IntegerExp(loc, cnt, arg0.type); 147 } 148 149 extern (C++) Expression eval_yl2x(Loc loc, FuncDeclaration fd, Expressions* arguments) 150 { 151 Expression arg0 = (*arguments)[0]; 152 assert(arg0.op == TOKfloat64); 153 Expression arg1 = (*arguments)[1]; 154 assert(arg1.op == TOKfloat64); 155 const x = arg0.toReal(); 156 const y = arg1.toReal(); 157 real_t result = 0; 158 CTFloat.yl2x(&x, &y, &result); 159 return new RealExp(loc, result, arg0.type); 160 } 161 162 extern (C++) Expression eval_yl2xp1(Loc loc, FuncDeclaration fd, Expressions* arguments) 163 { 164 Expression arg0 = (*arguments)[0]; 165 assert(arg0.op == TOKfloat64); 166 Expression arg1 = (*arguments)[1]; 167 assert(arg1.op == TOKfloat64); 168 const x = arg0.toReal(); 169 const y = arg1.toReal(); 170 real_t result = 0; 171 CTFloat.yl2xp1(&x, &y, &result); 172 return new RealExp(loc, result, arg0.type); 173 } 174 175 public extern (C++) void builtin_init() 176 { 177 builtins._init(47); 178 // @safe @nogc pure nothrow real function(real) 179 add_builtin("_D4core4math3sinFNaNbNiNfeZe", &eval_sin); 180 add_builtin("_D4core4math3cosFNaNbNiNfeZe", &eval_cos); 181 add_builtin("_D4core4math3tanFNaNbNiNfeZe", &eval_tan); 182 add_builtin("_D4core4math4sqrtFNaNbNiNfeZe", &eval_sqrt); 183 add_builtin("_D4core4math4fabsFNaNbNiNfeZe", &eval_fabs); 184 add_builtin("_D4core4math5expm1FNaNbNiNfeZe", &eval_unimp); 185 add_builtin("_D4core4math4exp21FNaNbNiNfeZe", &eval_unimp); 186 // @trusted @nogc pure nothrow real function(real) 187 add_builtin("_D4core4math3sinFNaNbNiNeeZe", &eval_sin); 188 add_builtin("_D4core4math3cosFNaNbNiNeeZe", &eval_cos); 189 add_builtin("_D4core4math3tanFNaNbNiNeeZe", &eval_tan); 190 add_builtin("_D4core4math4sqrtFNaNbNiNeeZe", &eval_sqrt); 191 add_builtin("_D4core4math4fabsFNaNbNiNeeZe", &eval_fabs); 192 add_builtin("_D4core4math5expm1FNaNbNiNeeZe", &eval_unimp); 193 add_builtin("_D4core4math4exp21FNaNbNiNeeZe", &eval_unimp); 194 // @safe @nogc pure nothrow double function(double) 195 add_builtin("_D4core4math4sqrtFNaNbNiNfdZd", &eval_sqrt); 196 // @safe @nogc pure nothrow float function(float) 197 add_builtin("_D4core4math4sqrtFNaNbNiNffZf", &eval_sqrt); 198 // @safe @nogc pure nothrow real function(real, real) 199 add_builtin("_D4core4math5atan2FNaNbNiNfeeZe", &eval_unimp); 200 if (CTFloat.yl2x_supported) 201 { 202 add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_yl2x); 203 } 204 else 205 { 206 add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_unimp); 207 } 208 if (CTFloat.yl2xp1_supported) 209 { 210 add_builtin("_D4core4math6yl2xp1FNaNbNiNfeeZe", &eval_yl2xp1); 211 } 212 else 213 { 214 add_builtin("_D4core4math6yl2xp1FNaNbNiNfeeZe", &eval_unimp); 215 } 216 // @safe @nogc pure nothrow long function(real) 217 add_builtin("_D4core4math6rndtolFNaNbNiNfeZl", &eval_unimp); 218 // @safe @nogc pure nothrow real function(real) 219 add_builtin("_D3std4math3sinFNaNbNiNfeZe", &eval_sin); 220 add_builtin("_D3std4math3cosFNaNbNiNfeZe", &eval_cos); 221 add_builtin("_D3std4math3tanFNaNbNiNfeZe", &eval_tan); 222 add_builtin("_D3std4math4sqrtFNaNbNiNfeZe", &eval_sqrt); 223 add_builtin("_D3std4math4fabsFNaNbNiNfeZe", &eval_fabs); 224 add_builtin("_D3std4math5expm1FNaNbNiNfeZe", &eval_unimp); 225 add_builtin("_D3std4math4exp21FNaNbNiNfeZe", &eval_unimp); 226 // @trusted @nogc pure nothrow real function(real) 227 add_builtin("_D3std4math3sinFNaNbNiNeeZe", &eval_sin); 228 add_builtin("_D3std4math3cosFNaNbNiNeeZe", &eval_cos); 229 add_builtin("_D3std4math3tanFNaNbNiNeeZe", &eval_tan); 230 add_builtin("_D3std4math4sqrtFNaNbNiNeeZe", &eval_sqrt); 231 add_builtin("_D3std4math4fabsFNaNbNiNeeZe", &eval_fabs); 232 add_builtin("_D3std4math5expm1FNaNbNiNeeZe", &eval_unimp); 233 add_builtin("_D3std4math4exp21FNaNbNiNeeZe", &eval_unimp); 234 // @safe @nogc pure nothrow double function(double) 235 add_builtin("_D3std4math4sqrtFNaNbNiNfdZd", &eval_sqrt); 236 // @safe @nogc pure nothrow float function(float) 237 add_builtin("_D3std4math4sqrtFNaNbNiNffZf", &eval_sqrt); 238 // @safe @nogc pure nothrow real function(real, real) 239 add_builtin("_D3std4math5atan2FNaNbNiNfeeZe", &eval_unimp); 240 if (CTFloat.yl2x_supported) 241 { 242 add_builtin("_D3std4math4yl2xFNaNbNiNfeeZe", &eval_yl2x); 243 } 244 else 245 { 246 add_builtin("_D3std4math4yl2xFNaNbNiNfeeZe", &eval_unimp); 247 } 248 if (CTFloat.yl2xp1_supported) 249 { 250 add_builtin("_D3std4math6yl2xp1FNaNbNiNfeeZe", &eval_yl2xp1); 251 } 252 else 253 { 254 add_builtin("_D3std4math6yl2xp1FNaNbNiNfeeZe", &eval_unimp); 255 } 256 // @safe @nogc pure nothrow long function(real) 257 add_builtin("_D3std4math6rndtolFNaNbNiNfeZl", &eval_unimp); 258 // @safe @nogc pure nothrow int function(uint) 259 add_builtin("_D4core5bitop3bsfFNaNbNiNfkZi", &eval_bsf); 260 add_builtin("_D4core5bitop3bsrFNaNbNiNfkZi", &eval_bsr); 261 // @safe @nogc pure nothrow int function(ulong) 262 add_builtin("_D4core5bitop3bsfFNaNbNiNfmZi", &eval_bsf); 263 add_builtin("_D4core5bitop3bsrFNaNbNiNfmZi", &eval_bsr); 264 // @safe @nogc pure nothrow uint function(uint) 265 add_builtin("_D4core5bitop5bswapFNaNbNiNfkZk", &eval_bswap); 266 // @safe @nogc pure nothrow int function(uint) 267 add_builtin("_D4core5bitop7_popcntFNaNbNiNfkZi", &eval_popcnt); 268 // @safe @nogc pure nothrow ushort function(ushort) 269 add_builtin("_D4core5bitop7_popcntFNaNbNiNftZt", &eval_popcnt); 270 // @safe @nogc pure nothrow int function(ulong) 271 if (global.params.is64bit) 272 add_builtin("_D4core5bitop7_popcntFNaNbNiNfmZi", &eval_popcnt); 273 } 274 275 /********************************** 276 * Determine if function is a builtin one that we can 277 * evaluate at compile time. 278 */ 279 public extern (C++) BUILTIN isBuiltin(FuncDeclaration fd) 280 { 281 if (fd.builtin == BUILTINunknown) 282 { 283 builtin_fp fp = builtin_lookup(mangleExact(fd)); 284 fd.builtin = fp ? BUILTINyes : BUILTINno; 285 } 286 return fd.builtin; 287 } 288 289 /************************************** 290 * Evaluate builtin function. 291 * Return result; NULL if cannot evaluate it. 292 */ 293 public extern (C++) Expression eval_builtin(Loc loc, FuncDeclaration fd, Expressions* arguments) 294 { 295 if (fd.builtin == BUILTINyes) 296 { 297 builtin_fp fp = builtin_lookup(mangleExact(fd)); 298 assert(fp); 299 return fp(loc, fd, arguments); 300 } 301 return null; 302 }