Skip to content

Commit 702d116

Browse files
committed
Fix for issue ldc-developers#648.
Uses the llvmInternal member and the intrinsic name to identify an intrinsic. Implements llvm.bswap, llvm.ctpop, llvm.ctlz and llvm.cttz intrinsics as builtins and remove the core.bitop counterparts. The implementation is complicated by the fact that the overloaded intrinsic name is resolved during code generation.
1 parent b73e5fb commit 702d116

File tree

1 file changed

+202
-0
lines changed

1 file changed

+202
-0
lines changed

dmd2/builtin.c

+202
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
#include "identifier.h"
2424
#include "id.h"
2525
#include "module.h"
26+
#if IN_LLVM
27+
#include "template.h"
28+
#include "gen/pragma.h"
29+
#endif
2630

2731
StringTable builtins;
2832

@@ -78,6 +82,154 @@ Expression *eval_fabs(Loc loc, FuncDeclaration *fd, Expressions *arguments)
7882
return new RealExp(loc, fabsl(arg0->toReal()), arg0->type);
7983
}
8084

85+
#if IN_LLVM
86+
87+
static inline Type *getTypeOfOverloadedIntrinsic(FuncDeclaration *fd)
88+
{
89+
// Depending on the state of the code generation we have to look at
90+
// the template instance or the function declaration.
91+
assert(fd->parent && "function declaration requires parent");
92+
TemplateInstance* tinst = fd->parent->isTemplateInstance();
93+
if (tinst)
94+
{
95+
// See DtoOverloadedIntrinsicName
96+
assert(tinst->tdtypes.dim == 1);
97+
return static_cast<Type*>(tinst->tdtypes.data[0]);
98+
}
99+
else
100+
{
101+
assert(fd->type->ty == Tfunction);
102+
TypeFunction *tf = static_cast<TypeFunction *>(fd->type);
103+
assert(tf->parameters->dim >= 1);
104+
return tf->parameters->data[0]->type;
105+
}
106+
}
107+
108+
static inline int getBitsizeOfType(Loc loc, Type *type)
109+
{
110+
switch (type->toBasetype()->ty)
111+
{
112+
case Tint64:
113+
case Tuns64: return 64;
114+
case Tint32:
115+
case Tuns32: return 32;
116+
case Tint16:
117+
case Tuns16: return 16;
118+
case Tint128:
119+
case Tuns128:
120+
error(loc, "cent/ucent not supported");
121+
break;
122+
default:
123+
error(loc, "unsupported type");
124+
break;
125+
}
126+
return 32; // in case of error
127+
}
128+
129+
Expression *eval_cttz(Loc loc, FuncDeclaration *fd, Expressions *arguments)
130+
{
131+
Type* type = getTypeOfOverloadedIntrinsic(fd);
132+
133+
Expression *arg0 = (*arguments)[0];
134+
assert(arg0->op == TOKint64);
135+
uinteger_t x = arg0->toInteger();
136+
137+
int n = getBitsizeOfType(loc, type);
138+
139+
if (x == 0)
140+
{
141+
if ((*arguments)[1]->toInteger())
142+
error(loc, "llvm.cttz.i#(0) is undefined");
143+
}
144+
else
145+
{
146+
int c = n >> 1;
147+
n -= 1;
148+
const uinteger_t mask = (static_cast<uinteger_t>(1L) << n)
149+
| (static_cast<uinteger_t>(1L) << n)-1;
150+
do {
151+
uinteger_t y = (x << c) & mask; if (y != 0) { n -= c; x = y; }
152+
c = c >> 1;
153+
} while (c != 0);
154+
}
155+
156+
return new IntegerExp(loc, n, type);
157+
}
158+
159+
Expression *eval_ctlz(Loc loc, FuncDeclaration *fd, Expressions *arguments)
160+
{
161+
Type* type = getTypeOfOverloadedIntrinsic(fd);
162+
163+
Expression *arg0 = (*arguments)[0];
164+
assert(arg0->op == TOKint64);
165+
uinteger_t x = arg0->toInteger();
166+
if (x == 0 && (*arguments)[1]->toInteger())
167+
error(loc, "llvm.ctlz.i#(0) is undefined");
168+
169+
int n = getBitsizeOfType(loc, type);
170+
int c = n >> 1;
171+
do {
172+
uinteger_t y = x >> c; if (y != 0) { n -= c; x = y; }
173+
c = c >> 1;
174+
} while (c != 0);
175+
176+
return new IntegerExp(loc, n - x, type);
177+
}
178+
179+
Expression *eval_bswap(Loc loc, FuncDeclaration *fd, Expressions *arguments)
180+
{
181+
Type* type = getTypeOfOverloadedIntrinsic(fd);
182+
183+
Expression *arg0 = (*arguments)[0];
184+
assert(arg0->op == TOKint64);
185+
uinteger_t n = arg0->toInteger();
186+
#define BYTEMASK 0x00FF00FF00FF00FFLL
187+
#define SHORTMASK 0x0000FFFF0000FFFFLL
188+
#define INTMASK 0x0000FFFF0000FFFFLL
189+
switch (type->toBasetype()->ty)
190+
{
191+
case Tint64:
192+
case Tuns64:
193+
// swap high and low uints
194+
n = ((n >> 32) & INTMASK) | ((n & INTMASK) << 32);
195+
case Tint32:
196+
case Tuns32:
197+
// swap adjacent ushorts
198+
n = ((n >> 16) & SHORTMASK) | ((n & SHORTMASK) << 16);
199+
case Tint16:
200+
case Tuns16:
201+
// swap adjacent ubytes
202+
n = ((n >> 8 ) & BYTEMASK) | ((n & BYTEMASK) << 8 );
203+
break;
204+
case Tint128:
205+
case Tuns128:
206+
error(loc, "cent/ucent not supported");
207+
break;
208+
default:
209+
error(loc, "unsupported type");
210+
break;
211+
}
212+
return new IntegerExp(loc, n, type);
213+
}
214+
215+
Expression *eval_ctpop(Loc loc, FuncDeclaration *fd, Expressions *arguments)
216+
{
217+
// FIXME Does not work for cent/ucent
218+
Type* type = getTypeOfOverloadedIntrinsic(fd);
219+
220+
Expression *arg0 = (*arguments)[0];
221+
assert(arg0->op == TOKint64);
222+
uinteger_t n = arg0->toInteger();
223+
n = n - ((n >> 1) & 0x5555555555555555);
224+
n = (n & 0x3333333333333333) + ((n >> 2) & 0x3333333333333333);
225+
n = n + ((n >> 4) & 0x0F0F0F0F0F0F0F0F);
226+
n = n + (n >> 8);
227+
n = n + (n >> 16);
228+
n = n + (n >> 32);
229+
return new IntegerExp(loc, n, type);
230+
}
231+
#else
232+
81233
Expression *eval_bsf(Loc loc, FuncDeclaration *fd, Expressions *arguments)
82234
{
83235
Expression *arg0 = (*arguments)[0];
@@ -127,10 +279,15 @@ Expression *eval_bswap(Loc loc, FuncDeclaration *fd, Expressions *arguments)
127279
n = ((n >> 32) & INTMASK) | ((n & INTMASK) << 32);
128280
return new IntegerExp(loc, n, arg0->type);
129281
}
282+
#endif
130283

131284
void builtin_init()
132285
{
286+
#if IN_LLVM
287+
builtins._init(67); // Prime number like default value
288+
#else
133289
builtins._init(45);
290+
#endif
134291

135292
// @safe pure nothrow real function(real)
136293
add_builtin("_D4core4math3sinFNaNbNfeZe", &eval_sin);
@@ -194,6 +351,38 @@ void builtin_init()
194351
// @safe pure nothrow long function(real)
195352
add_builtin("_D3std4math6rndtolFNaNbNfeZl", &eval_unimp);
196353

354+
#if IN_LLVM
355+
// intrinsic llvm.bswap.i16/i32/i64/i128
356+
add_builtin("llvm.bswap.i#", &eval_bswap);
357+
add_builtin("llvm.bswap.i16", &eval_bswap);
358+
add_builtin("llvm.bswap.i32", &eval_bswap);
359+
add_builtin("llvm.bswap.i64", &eval_bswap);
360+
add_builtin("llvm.bswap.i128", &eval_bswap);
361+
362+
// intrinsic llvm.cttz.i8/i16/i32/i64/i128
363+
add_builtin("llvm.cttz.i#", &eval_cttz);
364+
add_builtin("llvm.cttz.i8", &eval_cttz);
365+
add_builtin("llvm.cttz.i16", &eval_cttz);
366+
add_builtin("llvm.cttz.i32", &eval_cttz);
367+
add_builtin("llvm.cttz.i64", &eval_cttz);
368+
add_builtin("llvm.cttz.i128", &eval_cttz);
369+
370+
// intrinsic llvm.ctlz.i8/i16/i32/i64/i128
371+
add_builtin("llvm.ctlz.i#", &eval_ctlz);
372+
add_builtin("llvm.ctlz.i8", &eval_ctlz);
373+
add_builtin("llvm.ctlz.i16", &eval_ctlz);
374+
add_builtin("llvm.ctlz.i32", &eval_ctlz);
375+
add_builtin("llvm.ctlz.i64", &eval_ctlz);
376+
add_builtin("llvm.ctlz.i128", &eval_ctlz);
377+
378+
// intrinsic llvm.ctpop.i8/i16/i32/i64/i128
379+
add_builtin("llvm.ctpop.i#", &eval_ctpop);
380+
add_builtin("llvm.ctpop.i8", &eval_ctpop);
381+
add_builtin("llvm.ctpop.i16", &eval_ctpop);
382+
add_builtin("llvm.ctpop.i32", &eval_ctpop);
383+
add_builtin("llvm.ctpop.i64", &eval_ctpop);
384+
add_builtin("llvm.ctpop.i128", &eval_ctpop);
385+
#else
197386
// @safe pure nothrow int function(uint)
198387
add_builtin("_D4core5bitop3bsfFNaNbNfkZi", &eval_bsf);
199388
add_builtin("_D4core5bitop3bsrFNaNbNfkZi", &eval_bsr);
@@ -204,6 +393,7 @@ void builtin_init()
204393

205394
// @safe pure nothrow uint function(uint)
206395
add_builtin("_D4core5bitop5bswapFNaNbNfkZk", &eval_bswap);
396+
#endif
207397
}
208398

209399
/**********************************
@@ -214,7 +404,13 @@ BUILTIN FuncDeclaration::isBuiltin()
214404
{
215405
if (builtin == BUILTINunknown)
216406
{
407+
#if IN_LLVM
408+
const char *name = llvmInternal == LLVMintrinsic ? intrinsicName.c_str()
409+
: mangleExact();
410+
builtin_fp fp = builtin_lookup(name);
411+
#else
217412
builtin_fp fp = builtin_lookup(mangleExact());
413+
#endif
218414
builtin = fp ? BUILTINyes : BUILTINno;
219415
}
220416
return builtin;
@@ -229,7 +425,13 @@ Expression *eval_builtin(Loc loc, FuncDeclaration *fd, Expressions *arguments)
229425
{
230426
if (fd->builtin == BUILTINyes)
231427
{
428+
#if IN_LLVM
429+
const char *name = fd->llvmInternal == LLVMintrinsic ? fd->intrinsicName.c_str()
430+
: fd->mangleExact();
431+
builtin_fp fp = builtin_lookup(name);
432+
#else
232433
builtin_fp fp = builtin_lookup(fd->mangleExact());
434+
#endif
233435
assert(fp);
234436
return fp(loc, fd, arguments);
235437
}

0 commit comments

Comments
 (0)