mirror of
git://c9x.me/qbe.git
synced 2026-04-05 18:09:47 +00:00
thread-local storage for amd64_apple
It is quite similar to arm64_apple.
Probably, the call that needs to be
generated also provides extra
invariants on top of the regular
abi, but I have not checked that.
Clang generates code that is a bit
neater than qbe's because, on x86,
a load can be fused in a call
instruction! We do not bother with
supporting these since we expect
only sporadic use of the feature.
For reference, here is what clang
might output for a store to the
second entry of a thread-local
array of ints:
movq _x@TLVP(%rip), %rdi
callq *(%rdi)
movl %ecx, 4(%rax)
This commit is contained in:
parent
577e93fe6d
commit
8ecae92299
12
amd64/emit.c
12
amd64/emit.c
@ -167,9 +167,12 @@ emitcon(Con *con, FILE *f)
|
|||||||
case CAddr:
|
case CAddr:
|
||||||
l = str(con->label);
|
l = str(con->label);
|
||||||
p = l[0] == '"' ? "" : T.assym;
|
p = l[0] == '"' ? "" : T.assym;
|
||||||
if (con->reloc == RelThr)
|
if (con->reloc == RelThr) {
|
||||||
fprintf(f, "%%fs:%s%s@tpoff", p, l);
|
if (T.apple)
|
||||||
else
|
fprintf(f, "%s%s@TLVP", p, l);
|
||||||
|
else
|
||||||
|
fprintf(f, "%%fs:%s%s@tpoff", p, l);
|
||||||
|
} else
|
||||||
fprintf(f, "%s%s", p, l);
|
fprintf(f, "%s%s", p, l);
|
||||||
if (con->bits.i)
|
if (con->bits.i)
|
||||||
fprintf(f, "%+"PRId64, con->bits.i);
|
fprintf(f, "%+"PRId64, con->bits.i);
|
||||||
@ -340,7 +343,8 @@ Next:
|
|||||||
case RCon:
|
case RCon:
|
||||||
off = fn->con[ref.val];
|
off = fn->con[ref.val];
|
||||||
emitcon(&off, f);
|
emitcon(&off, f);
|
||||||
if (off.type == CAddr && off.reloc != RelThr)
|
if (off.type == CAddr)
|
||||||
|
if (off.reloc != RelThr || T.apple)
|
||||||
fprintf(f, "(%%rip)");
|
fprintf(f, "(%%rip)");
|
||||||
break;
|
break;
|
||||||
case RTmp:
|
case RTmp:
|
||||||
|
|||||||
25
amd64/isel.c
25
amd64/isel.c
@ -63,7 +63,8 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn)
|
|||||||
{
|
{
|
||||||
char buf[32];
|
char buf[32];
|
||||||
Addr a, *m;
|
Addr a, *m;
|
||||||
Ref r0, r1;
|
Con cc, *c;
|
||||||
|
Ref r0, r1, r2, r3;
|
||||||
int s, n, op;
|
int s, n, op;
|
||||||
|
|
||||||
r1 = r0 = *r;
|
r1 = r0 = *r;
|
||||||
@ -121,6 +122,28 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn)
|
|||||||
m->offset.type = CUndef;
|
m->offset.type = CUndef;
|
||||||
m->base = r0;
|
m->base = r0;
|
||||||
}
|
}
|
||||||
|
} else if (T.apple && rtype(r0) == RCon
|
||||||
|
&& (c = &fn->con[r0.val])->type == CAddr
|
||||||
|
&& c->reloc == RelThr) {
|
||||||
|
r1 = newtmp("isel", Kl, fn);
|
||||||
|
if (c->bits.i) {
|
||||||
|
r2 = newtmp("isel", Kl, fn);
|
||||||
|
cc = (Con){.type = CBits};
|
||||||
|
cc.bits.i = c->bits.i;
|
||||||
|
r3 = newcon(&cc, fn);
|
||||||
|
emit(Oadd, Kl, r1, r2, r3);
|
||||||
|
} else
|
||||||
|
r2 = r1;
|
||||||
|
emit(Ocopy, Kl, r2, TMP(RAX), R);
|
||||||
|
r2 = newtmp("isel", Kl, fn);
|
||||||
|
r3 = newtmp("isel", Kl, fn);
|
||||||
|
emit(Ocall, 0, R, r3, CALL(17));
|
||||||
|
emit(Ocopy, Kl, TMP(RDI), r2, R);
|
||||||
|
emit(Oload, Kl, r3, r2, R);
|
||||||
|
cc = *c;
|
||||||
|
cc.bits.i = 0;
|
||||||
|
r3 = newcon(&cc, fn);
|
||||||
|
emit(Oload, Kl, r2, r3, R);
|
||||||
}
|
}
|
||||||
*r = r1;
|
*r = r1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,9 +70,9 @@ static void
|
|||||||
fixarg(Ref *pr, int k, int phi, Fn *fn)
|
fixarg(Ref *pr, int k, int phi, Fn *fn)
|
||||||
{
|
{
|
||||||
char buf[32];
|
char buf[32];
|
||||||
|
Con *c, cc;
|
||||||
Ref r0, r1, r2, r3;
|
Ref r0, r1, r2, r3;
|
||||||
int s, n;
|
int s, n;
|
||||||
Con *c, cc;
|
|
||||||
|
|
||||||
r0 = *pr;
|
r0 = *pr;
|
||||||
switch (rtype(r0)) {
|
switch (rtype(r0)) {
|
||||||
|
|||||||
30
test/tls.ssa
Normal file
30
test/tls.ssa
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
thread data $i = align 4 {w 42}
|
||||||
|
data $fmt = align 1 {b "i%d==%d\n", b 0}
|
||||||
|
|
||||||
|
export
|
||||||
|
function w $main() {
|
||||||
|
@start
|
||||||
|
%pthr =l alloc8 8
|
||||||
|
%rval =l alloc8 8
|
||||||
|
call $pthread_create(l %pthr, l 0, l $thread, l 0)
|
||||||
|
%t =l load %pthr
|
||||||
|
call $pthread_join(l %t, l %rval)
|
||||||
|
%i0 =w loadw thread $i
|
||||||
|
call $printf(l $fmt, ..., w 0, w %i0)
|
||||||
|
%i1 =w load %rval
|
||||||
|
call $printf(l $fmt, ..., w 1, w %i1)
|
||||||
|
ret 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function l $thread(l %arg) {
|
||||||
|
@start
|
||||||
|
%i3 =l add thread $i, 3
|
||||||
|
storeb 24, %i3
|
||||||
|
%ret =l loadsw thread $i
|
||||||
|
ret %ret
|
||||||
|
}
|
||||||
|
|
||||||
|
# >>> output
|
||||||
|
# i0==42
|
||||||
|
# i1==402653226
|
||||||
|
# <<<
|
||||||
Loading…
Reference in New Issue
Block a user