Skip to content

Commit b30a1ba

Browse files
committed
introduce ldc_simd to workaround linking bugs
1 parent 85e7c51 commit b30a1ba

3 files changed

Lines changed: 314 additions & 6 deletions

File tree

source/mir/internal/ldc_simd.d

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
// module ldc.simd;
2+
// compilers has permanent issues with .di files
3+
module mir.internal.ldc_simd;
4+
5+
version(LDC):
6+
7+
import core.simd;
8+
import ldc.llvmasm;
9+
10+
pure:
11+
nothrow:
12+
@nogc:
13+
@trusted:
14+
15+
private template isFloatingPoint(T)
16+
{
17+
enum isFloatingPoint =
18+
is(T == float) ||
19+
is(T == double) ||
20+
is(T == real);
21+
}
22+
23+
private template isIntegral(T)
24+
{
25+
enum isIntegral =
26+
is(T == byte) ||
27+
is(T == ubyte) ||
28+
is(T == short) ||
29+
is(T == ushort) ||
30+
is(T == int) ||
31+
is(T == uint) ||
32+
is(T == long) ||
33+
is(T == ulong);
34+
}
35+
36+
private template isSigned(T)
37+
{
38+
enum isSigned =
39+
is(T == byte) ||
40+
is(T == short) ||
41+
is(T == int) ||
42+
is(T == long);
43+
}
44+
45+
private template IntOf(T)
46+
if(isIntegral!T || isFloatingPoint!T)
47+
{
48+
enum n = T.sizeof;
49+
static if(n == 1)
50+
alias byte IntOf;
51+
else static if(n == 2)
52+
alias short IntOf;
53+
else static if(n == 4)
54+
alias int IntOf;
55+
else static if(n == 8)
56+
alias long IntOf;
57+
else
58+
static assert(0, "Type not supported");
59+
}
60+
61+
private template BaseType(V)
62+
{
63+
alias typeof(V.array[0]) BaseType;
64+
}
65+
66+
private template numElements(V)
67+
{
68+
enum numElements = V.sizeof / BaseType!(V).sizeof;
69+
}
70+
71+
private template llvmType(T)
72+
{
73+
static if(is(T == float))
74+
enum llvmType = "float";
75+
else static if(is(T == double))
76+
enum llvmType = "double";
77+
else static if(is(T == byte) || is(T == ubyte) || is(T == void))
78+
enum llvmType = "i8";
79+
else static if(is(T == short) || is(T == ushort))
80+
enum llvmType = "i16";
81+
else static if(is(T == int) || is(T == uint))
82+
enum llvmType = "i32";
83+
else static if(is(T == long) || is(T == ulong))
84+
enum llvmType = "i64";
85+
else
86+
static assert(0,
87+
"Can't determine llvm type for D type " ~ T.stringof);
88+
}
89+
90+
private template llvmVecType(V)
91+
{
92+
static if(is(V == void16))
93+
enum llvmVecType = "<16 x i8>";
94+
else static if(is(V == void32))
95+
enum llvmVecType = "<32 x i8>";
96+
else
97+
{
98+
alias BaseType!V T;
99+
enum int n = numElements!V;
100+
enum llvmT = llvmType!T;
101+
enum llvmVecType = "<"~n.stringof~" x "~llvmT~">";
102+
}
103+
}
104+
105+
/**
106+
This template provides access to
107+
$(LINK2 http://llvm.org/docs/LangRef.html#i_shufflevector,
108+
LLVM's shufflevector instruction).
109+
110+
Example:
111+
---
112+
int4 a = [0, 10, 20, 30];
113+
int4 b = [40, 50, 60, 70];
114+
int4 c = shufflevector!(int4, 0, 2, 4, 6)(a, b);
115+
assert(c.array == [0, 20, 40, 60]);
116+
---
117+
*/
118+
119+
template shufflevector(V, mask...)
120+
if(is(typeof(llvmVecType!V)) && mask.length == numElements!V)
121+
{
122+
enum int n = mask.length;
123+
enum llvmV = llvmVecType!V;
124+
125+
template genMaskIr(string ir, m...)
126+
{
127+
static if(m.length == 0)
128+
enum genMaskIr = ir;
129+
else
130+
{
131+
enum int mfront = m[0];
132+
133+
enum genMaskIr =
134+
genMaskIr!(ir ~ ", i32 " ~ mfront.stringof, m[1 .. $]);
135+
}
136+
}
137+
enum maskIr = genMaskIr!("", mask)[2 .. $];
138+
enum ir = `
139+
%r = shufflevector `~llvmV~` %0, `~llvmV~` %1, <`~n.stringof~` x i32> <`~maskIr~`>
140+
ret `~llvmV~` %r`;
141+
142+
alias __ir_pure!(ir, V, V, V) shufflevector;
143+
}
144+
145+
/**
146+
This template provides access to
147+
$(LINK2 http://llvm.org/docs/LangRef.html#i_extractelement,
148+
LLVM's extractelement instruction).
149+
150+
Example:
151+
---
152+
int4 a = [0, 10, 20, 30];
153+
int k = extractelement!(int4, 2)(a);
154+
assert(k == 20);
155+
---
156+
*/
157+
158+
template extractelement(V, int i)
159+
if(is(typeof(llvmVecType!V)) && i < numElements!V)
160+
{
161+
enum llvmT = llvmType!(BaseType!V);
162+
enum llvmV = llvmVecType!V;
163+
enum ir = `
164+
%r = extractelement `~llvmV~` %0, i32 `~i.stringof~`
165+
ret `~llvmT~` %r`;
166+
167+
alias __ir_pure!(ir, BaseType!V, V) extractelement;
168+
}
169+
170+
/**
171+
This template provides access to
172+
$(LINK2 http://llvm.org/docs/LangRef.html#i_insertelement,
173+
LLVM's insertelement instruction).
174+
175+
Example:
176+
---
177+
int4 a = [0, 10, 20, 30];
178+
int b = insertelement!(int4, 2)(a, 50);
179+
assert(b.array == [0, 10, 50, 30]);
180+
---
181+
*/
182+
183+
template insertelement(V, int i)
184+
if(is(typeof(llvmVecType!V)) && i < numElements!V)
185+
{
186+
enum llvmT = llvmType!(BaseType!V);
187+
enum llvmV = llvmVecType!V;
188+
enum ir = `
189+
%r = insertelement `~llvmV~` %0, `~llvmT~` %1, i32 `~i.stringof~`
190+
ret `~llvmV~` %r`;
191+
192+
alias __ir_pure!(ir, V, V, BaseType!V) insertelement;
193+
}
194+
195+
/**
196+
loadUnaligned: Loads a vector from an unaligned pointer.
197+
Example:
198+
---
199+
int[4] a = [0, 10, 20, 30];
200+
int4 v = loadUnaligned!int4(a.ptr);
201+
assert(v.array == a);
202+
---
203+
*/
204+
template loadUnaligned(V)
205+
if(is(typeof(llvmVecType!V)))
206+
{
207+
enum llvmElementType = llvmType!(BaseType!V);
208+
enum llvmV = llvmVecType!V;
209+
enum ir = `
210+
%p = bitcast `~llvmElementType~`* %0 to `~llvmV~`*
211+
%r = load `~llvmV~`, `~llvmV~`* %p, align 1
212+
ret `~llvmV~` %r`;
213+
private alias impl = __ir_pure!(ir, V, const(BaseType!V)*);
214+
215+
pragma(inline, true):
216+
217+
V loadUnaligned(const(BaseType!V)* p)
218+
{
219+
return impl(p);
220+
}
221+
}
222+
223+
/**
224+
storeUnaligned: Stores a vector to an unaligned pointer.
225+
Example:
226+
---
227+
int[4] a;
228+
int4 v = [0, 10, 20, 30];
229+
storeUnaligned!int4(v, a.ptr);
230+
assert(v.array == a);
231+
---
232+
*/
233+
template storeUnaligned(V)
234+
if(is(typeof(llvmVecType!V)))
235+
{
236+
enum llvmElementType = llvmType!(BaseType!V);
237+
enum llvmV = llvmVecType!V;
238+
enum ir = `
239+
%p = bitcast `~llvmElementType~`* %1 to `~llvmV~`*
240+
store `~llvmV~` %0, `~llvmV~`* %p, align 1`;
241+
private alias impl = __ir_pure!(ir, void, V, BaseType!V*);
242+
243+
pragma(inline, true):
244+
245+
void storeUnaligned(V value, BaseType!V* p)
246+
{
247+
impl(value, p);
248+
}
249+
}
250+
251+
private enum Cond{ eq, ne, gt, ge }
252+
253+
private template cmpMask(Cond cond)
254+
{
255+
template cmpMask(V)
256+
if(is(IntOf!(BaseType!V)))
257+
{
258+
alias BaseType!V T;
259+
enum llvmT = llvmType!T;
260+
261+
alias IntOf!T Relem;
262+
263+
enum int n = numElements!V;
264+
alias __vector(Relem[n]) R;
265+
266+
enum llvmV = llvmVecType!V;
267+
enum llvmR = llvmVecType!R;
268+
enum sign =
269+
(cond == Cond.eq || cond == Cond.ne) ? "" :
270+
isSigned!T ? "s" : "u";
271+
enum condStr =
272+
cond == Cond.eq ? "eq" :
273+
cond == Cond.ne ? "ne" :
274+
cond == Cond.ge ? "ge" : "gt";
275+
enum op =
276+
isFloatingPoint!T ? "fcmp o"~condStr : "icmp "~sign~condStr;
277+
278+
enum ir = `
279+
%cmp = `~op~` `~llvmV~` %0, %1
280+
%r = sext <`~n.stringof~` x i1> %cmp to `~llvmR~`
281+
ret `~llvmR~` %r`;
282+
283+
alias __ir_pure!(ir, R, V, V) cmpMask;
284+
}
285+
}
286+
287+
/**
288+
equalMask, notEqualMask, greaterMask and greaterOrEqualMask perform an
289+
element-wise comparison between two vectors and return a vector with
290+
signed integral elements. The number of elements in the returned vector
291+
and their size is the same as in parameter vectors. If the condition in
292+
the name of the function holds for elements of the parameter vectors at
293+
a given index, all bits of the element of the result at that index are
294+
set to 1, otherwise the element of the result is zero.
295+
296+
Example:
297+
---
298+
float4 a = [1, 3, 5, 7];
299+
float4 b = [2, 3, 4, 5];
300+
int4 c = greaterMask!float4(a, b);
301+
writeln(c.array);
302+
assert(c.array == [0, 0, 0xffff_ffff, 0xffff_ffff]);
303+
---
304+
*/
305+
alias cmpMask!(Cond.eq) equalMask;
306+
alias cmpMask!(Cond.ne) notEqualMask; /// Ditto
307+
alias cmpMask!(Cond.gt) greaterMask; /// Ditto
308+
alias cmpMask!(Cond.ge) greaterOrEqualMask; /// Ditto

source/mir/interpolate/package.d

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ void shuffle3(size_t P, F, size_t N)(ref F[N] a, ref F[N] b, ref F[N] c, ref F[N
307307
{
308308
enum masks = generateShuffles3!(N, P);
309309
import std.meta: aliasSeqOf;
310-
import ldc.simd: shufflevector;
310+
import mir.internal.ldc_simd: shufflevector;
311311
alias V = __vector(F[N]); // @FUTURE@ vector support
312312
auto as = shufflevector!(V, aliasSeqOf!(masks[0]))(*cast(V*)a.ptr, *cast(V*)b.ptr);
313313
auto bs = shufflevector!(V, aliasSeqOf!(masks[1]))(*cast(V*)a.ptr, *cast(V*)b.ptr);
@@ -347,7 +347,7 @@ void shuffle2(size_t P, F, size_t N)(ref F[N] a, ref F[N] b, ref F[N] c, ref F[N
347347
{
348348
enum masks = generateShuffles2!(N, P);
349349
import std.meta: aliasSeqOf;
350-
import ldc.simd: shufflevector;
350+
import mir.internal.ldc_simd: shufflevector;
351351
alias V = __vector(F[N]); // @FUTURE@ vector support
352352
auto as = shufflevector!(V, aliasSeqOf!(masks[0]))(*cast(V*)a.ptr, *cast(V*)b.ptr);
353353
auto bs = shufflevector!(V, aliasSeqOf!(masks[1]))(*cast(V*)a.ptr, *cast(V*)b.ptr);
@@ -388,7 +388,7 @@ void shuffle1(size_t P, F, size_t N)(ref F[N] a, ref F[N] b, ref F[N] c, ref F[N
388388
{
389389
enum masks = generateShuffles1!(N, P);
390390
import std.meta: aliasSeqOf;
391-
import ldc.simd: shufflevector;
391+
import mir.internal.ldc_simd: shufflevector;
392392
alias V = __vector(F[N]); // @FUTURE@ vector support
393393
auto as = shufflevector!(V, aliasSeqOf!(masks[0]))(*cast(V*)a.ptr, *cast(V*)b.ptr);
394394
auto bs = shufflevector!(V, aliasSeqOf!(masks[1]))(*cast(V*)a.ptr, *cast(V*)b.ptr);

source/mir/string.d

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ bool containsAny(C, size_t L)
5151
{
5252
auto a = cast(V) *cast(const U[N]*) str.ptr;
5353

54-
import ldc.simd: mask = equalMask;
54+
import mir.internal.ldc_simd: mask = equalMask;
5555

5656
V[L] masked;
5757
static foreach (i; 0 .. L)
@@ -143,7 +143,7 @@ template scanLeftAny(string op = "==")
143143
{
144144
auto a = cast(V) *cast(const U[N]*) str.ptr;
145145

146-
import ldc.simd: mask = equalMask;
146+
import mir.internal.ldc_simd: mask = equalMask;
147147

148148
V[L] masked;
149149
static foreach (i; 0 .. L)
@@ -277,7 +277,7 @@ template scanRightAny(string op = "==")
277277
{
278278
auto a = cast(V) *cast(const U[N]*) (str.ptr + str.length - N);
279279

280-
import ldc.simd: mask = equalMask;
280+
import mir.internal.ldc_simd: mask = equalMask;
281281

282282
V[L] masked;
283283
static foreach (i; 0 .. L)

0 commit comments

Comments
 (0)