aboutsummaryrefslogtreecommitdiff
path: root/tccgen.c
diff options
context:
space:
mode:
authorgrischka <grischka>2017-02-08 19:45:31 +0100
committergrischka <grischka>2017-02-08 19:45:31 +0100
commit68666eee2ade45ab73b07361367d0a38d350d663 (patch)
tree1cb0bdc6b04665e96ba563a137bea20bf909fdca /tccgen.c
parentf077d16c20c524d7db8cb38a9193242eeade343d (diff)
downloadtinycc-68666eee2ade45ab73b07361367d0a38d350d663.tar.gz
tinycc-68666eee2ade45ab73b07361367d0a38d350d663.tar.bz2
tccgen: factor out gfunc_return
Also: - on windows i386 and x86-64, structures of size <= 8 are NOT returned in registers if size is not one of 1,2,4,8. - cleanup: put all tv-push/pop/swap/rot into one place
Diffstat (limited to 'tccgen.c')
-rw-r--r--tccgen.c354
1 files changed, 172 insertions, 182 deletions
diff --git a/tccgen.c b/tccgen.c
index 2804539..0f08c35 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -559,14 +559,6 @@ static void apply_visibility(Sym *sym, CType *type)
/* ------------------------------------------------------------------------- */
-ST_FUNC void swap(int *p, int *q)
-{
- int t;
- t = *p;
- *p = *q;
- *q = t;
-}
-
static void vsetc(CType *type, int r, CValue *vc)
{
int v;
@@ -583,12 +575,15 @@ static void vsetc(CType *type, int r, CValue *vc)
as their value might still be used for real. All values
we push under nocode_wanted will eventually be popped
again, so that the VT_CMP/VT_JMP value will be in vtop
- when code is unsuppressed again. */
+ when code is unsuppressed again.
+
+ Same logic below in vswap(); */
if (vtop >= vstack && !nocode_wanted) {
v = vtop->r & VT_VALMASK;
if (v == VT_CMP || (v & ~1) == VT_JMP)
gv(RC_INT);
}
+
vtop++;
vtop->type = *type;
vtop->r = r;
@@ -597,6 +592,38 @@ static void vsetc(CType *type, int r, CValue *vc)
vtop->sym = NULL;
}
+ST_FUNC void vswap(void)
+{
+ SValue tmp;
+ /* cannot vswap cpu flags. See comment at vsetc() above */
+ if (vtop >= vstack && !nocode_wanted) {
+ int v = vtop->r & VT_VALMASK;
+ if (v == VT_CMP || (v & ~1) == VT_JMP)
+ gv(RC_INT);
+ }
+ tmp = vtop[0];
+ vtop[0] = vtop[-1];
+ vtop[-1] = tmp;
+}
+
+/* pop stack value */
+ST_FUNC void vpop(void)
+{
+ int v;
+ v = vtop->r & VT_VALMASK;
+#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
+ /* for x86, we need to pop the FP stack */
+ if (v == TREG_ST0) {
+ o(0xd8dd); /* fstp %st(0) */
+ } else
+#endif
+ if (v == VT_JMP || v == VT_JMPI) {
+ /* need to put correct jump if && or || without test */
+ gsym(vtop->c.i);
+ }
+ vtop--;
+}
+
/* push constant of type "type" with useless value */
ST_FUNC void vpush(CType *type)
{
@@ -637,6 +664,71 @@ static inline void vpushll(long long v)
vpush64(VT_LLONG, v);
}
+ST_FUNC void vset(CType *type, int r, long v)
+{
+ CValue cval;
+
+ cval.i = v;
+ vsetc(type, r, &cval);
+}
+
+static void vseti(int r, int v)
+{
+ CType type;
+ type.t = VT_INT;
+ type.ref = 0;
+ vset(&type, r, v);
+}
+
+ST_FUNC void vpushv(SValue *v)
+{
+ if (vtop >= vstack + (VSTACK_SIZE - 1))
+ tcc_error("memory full (vstack)");
+ vtop++;
+ *vtop = *v;
+}
+
+static void vdup(void)
+{
+ vpushv(vtop);
+}
+
+/* rotate n first stack elements to the bottom
+ I1 ... In -> I2 ... In I1 [top is right]
+*/
+ST_FUNC void vrotb(int n)
+{
+ int i;
+ SValue tmp;
+
+ tmp = vtop[-n + 1];
+ for(i=-n+1;i!=0;i++)
+ vtop[i] = vtop[i+1];
+ vtop[0] = tmp;
+}
+
+/* rotate the n elements before entry e towards the top
+ I1 ... In ... -> In I1 ... I(n-1) ... [top is right]
+ */
+ST_FUNC void vrote(SValue *e, int n)
+{
+ int i;
+ SValue tmp;
+
+ tmp = *e;
+ for(i = 0;i < n - 1; i++)
+ e[-i] = e[-i - 1];
+ e[-n + 1] = tmp;
+}
+
+/* rotate n first stack elements to the top
+ I1 ... In -> In I1 ... I(n-1) [top is right]
+ */
+ST_FUNC void vrott(int n)
+{
+ vrote(vtop, n);
+}
+
/* push a symbol value of TYPE */
static inline void vpushsym(CType *type, Sym *sym)
{
@@ -715,56 +807,6 @@ ST_FUNC void vpush_global_sym(CType *type, int v)
vpushsym(type, external_global_sym(v, type, 0));
}
-ST_FUNC void vset(CType *type, int r, long v)
-{
- CValue cval;
-
- cval.i = v;
- vsetc(type, r, &cval);
-}
-
-static void vseti(int r, int v)
-{
- CType type;
- type.t = VT_INT;
- type.ref = 0;
- vset(&type, r, v);
-}
-
-ST_FUNC void vswap(void)
-{
- SValue tmp;
- /* cannot let cpu flags if other instruction are generated. Also
- avoid leaving VT_JMP anywhere except on the top of the stack
- because it would complicate the code generator. */
- if (vtop >= vstack) {
- int v = vtop->r & VT_VALMASK;
- if (v == VT_CMP || (v & ~1) == VT_JMP)
- gv(RC_INT);
- }
- tmp = vtop[0];
- vtop[0] = vtop[-1];
- vtop[-1] = tmp;
-
-/* XXX: +2% overall speed possible with optimized memswap
- *
- * memswap(&vtop[0], &vtop[1], sizeof *vtop);
- */
-}
-
-ST_FUNC void vpushv(SValue *v)
-{
- if (vtop >= vstack + (VSTACK_SIZE - 1))
- tcc_error("memory full (vstack)");
- vtop++;
- *vtop = *v;
-}
-
-static void vdup(void)
-{
- vpushv(vtop);
-}
-
/* save registers up to (vtop - n) stack entry */
ST_FUNC void save_regs(int n)
{
@@ -1297,60 +1339,6 @@ static void lbuild(int t)
}
#endif
-/* rotate n first stack elements to the bottom
- I1 ... In -> I2 ... In I1 [top is right]
-*/
-ST_FUNC void vrotb(int n)
-{
- int i;
- SValue tmp;
-
- tmp = vtop[-n + 1];
- for(i=-n+1;i!=0;i++)
- vtop[i] = vtop[i+1];
- vtop[0] = tmp;
-}
-
-/* rotate the n elements before entry e towards the top
- I1 ... In ... -> In I1 ... I(n-1) ... [top is right]
- */
-ST_FUNC void vrote(SValue *e, int n)
-{
- int i;
- SValue tmp;
-
- tmp = *e;
- for(i = 0;i < n - 1; i++)
- e[-i] = e[-i - 1];
- e[-n + 1] = tmp;
-}
-
-/* rotate n first stack elements to the top
- I1 ... In -> In I1 ... I(n-1) [top is right]
- */
-ST_FUNC void vrott(int n)
-{
- vrote(vtop, n);
-}
-
-/* pop stack value */
-ST_FUNC void vpop(void)
-{
- int v;
- v = vtop->r & VT_VALMASK;
-#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
- /* for x86, we need to pop the FP stack */
- if (v == TREG_ST0) {
- o(0xd8dd); /* fstp %st(0) */
- } else
-#endif
- if (v == VT_JMP || v == VT_JMPI) {
- /* need to put correct jump if && or || without test */
- gsym(vtop->c.i);
- }
- vtop--;
-}
-
/* convert stack entry to register and duplicate its value in another
register */
static void gv_dup(void)
@@ -2025,7 +2013,7 @@ redo:
/* Put pointer as first operand */
if (bt2 == VT_PTR) {
vswap();
- swap(&t1, &t2);
+ t = t1, t1 = t2, t2 = t;
}
#if PTR_SIZE == 4
if ((vtop[0].type.t & VT_BTYPE) == VT_LLONG)
@@ -4668,11 +4656,11 @@ ST_FUNC void unary(void)
subtract(-0, x). */
vpush(&vtop->type);
if (t == VT_FLOAT)
- vtop->c.f = -0.0f;
+ vtop->c.f = -1.0 * 0.0;
else if (t == VT_DOUBLE)
- vtop->c.d = -0.0;
+ vtop->c.d = -1.0 * 0.0;
else
- vtop->c.ld = -0.0;
+ vtop->c.ld = -1.0 * 0.0;
} else
vpushi(0);
vswap();
@@ -5460,6 +5448,72 @@ static void label_or_decl(int l)
decl(l);
}
+#ifndef TCC_TARGET_ARM64
+static void gfunc_return(CType *func_type)
+{
+ if ((func_type->t & VT_BTYPE) == VT_STRUCT) {
+ CType type, ret_type;
+ int ret_align, ret_nregs, regsize;
+ ret_nregs = gfunc_sret(func_type, func_var, &ret_type,
+ &ret_align, &regsize);
+ if (0 == ret_nregs) {
+ /* if returning structure, must copy it to implicit
+ first pointer arg location */
+ type = *func_type;
+ mk_pointer(&type);
+ vset(&type, VT_LOCAL | VT_LVAL, func_vc);
+ indir();
+ vswap();
+ /* copy structure value to pointer */
+ vstore();
+ } else {
+ /* returning structure packed into registers */
+ int r, size, addr, align;
+ size = type_size(func_type,&align);
+ if ((vtop->r != (VT_LOCAL | VT_LVAL) ||
+ (vtop->c.i & (ret_align-1)))
+ && (align & (ret_align-1))) {
+ loc = (loc - size) & -ret_align;
+ addr = loc;
+ type = *func_type;
+ vset(&type, VT_LOCAL | VT_LVAL, addr);
+ vswap();
+ vstore();
+ vpop();
+ vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
+ }
+ vtop->type = ret_type;
+ if (is_float(ret_type.t))
+ r = rc_fret(ret_type.t);
+ else
+ r = RC_IRET;
+
+ if (ret_nregs == 1)
+ gv(r);
+ else {
+ for (;;) {
+ vdup();
+ gv(r);
+ vpop();
+ if (--ret_nregs == 0)
+ break;
+ /* We assume that when a structure is returned in multiple
+ registers, their classes are consecutive values of the
+ suite s(n) = 2^n */
+ r <<= 1;
+ vtop->c.i += regsize;
+ }
+ }
+ }
+ } else if (is_float(func_type->t)) {
+ gv(rc_fret(func_type->t));
+ } else {
+ gv(RC_IRET);
+ }
+ vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
+}
+#endif
+
static int case_cmp(const void *pa, const void *pb)
{
int64_t a = (*(struct case_t**) pa)->v1;
@@ -5655,71 +5709,7 @@ static void block(int *bsym, int *csym, int is_expr)
if (tok != ';') {
gexpr();
gen_assign_cast(&func_vt);
-#ifdef TCC_TARGET_ARM64
- // Perhaps it would be better to use this for all backends:
- greturn();
-#else
- if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
- CType type, ret_type;
- int ret_align, ret_nregs, regsize;
- ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type,
- &ret_align, &regsize);
- if (0 == ret_nregs) {
- /* if returning structure, must copy it to implicit
- first pointer arg location */
- type = func_vt;
- mk_pointer(&type);
- vset(&type, VT_LOCAL | VT_LVAL, func_vc);
- indir();
- vswap();
- /* copy structure value to pointer */
- vstore();
- } else {
- /* returning structure packed into registers */
- int r, size, addr, align;
- size = type_size(&func_vt,&align);
- if ((vtop->r != (VT_LOCAL | VT_LVAL) ||
- (vtop->c.i & (ret_align-1)))
- && (align & (ret_align-1))) {
- loc = (loc - size) & -ret_align;
- addr = loc;
- type = func_vt;
- vset(&type, VT_LOCAL | VT_LVAL, addr);
- vswap();
- vstore();
- vpop();
- vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
- }
- vtop->type = ret_type;
- if (is_float(ret_type.t))
- r = rc_fret(ret_type.t);
- else
- r = RC_IRET;
-
- if (ret_nregs == 1)
- gv(r);
- else {
- for (;;) {
- vdup();
- gv(r);
- vpop();
- if (--ret_nregs == 0)
- break;
- /* We assume that when a structure is returned in multiple
- registers, their classes are consecutive values of the
- suite s(n) = 2^n */
- r <<= 1;
- vtop->c.i += regsize;
- }
- }
- }
- } else if (is_float(func_vt.t)) {
- gv(rc_fret(func_vt.t));
- } else {
- gv(RC_IRET);
- }
-#endif
- vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
+ gfunc_return(&func_vt);
}
skip(';');
/* jump unless last stmt in top-level block */