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 }