History

fix-mixed-struct (patch by Pip Cet)

Jsut for testing. It works for me (don't break anything) Small fixes for x86_64-gen.c in "tccpp: fix issues, add tests" are dropped in flavor of this patch. Pip Cet: Okay, here's a first patch that fixes the problem (but I've found another bug, yet unfixed, in the process), though it's not particularly pretty code (I tried hard to keep the changes to the minimum necessary). If we decide to actually get rid of VT_QLONG and VT_QFLOAT (please, can we?), there are some further simplifications in tccgen.c that might offset some of the cost of this patch. The idea is that an integer is no longer enough to describe how an argument is stored in registers. There are a number of possibilities (none, integer register, two integer registers, float register, two float registers, integer register plus float register, float register plus integer register), and instead of enumerating them I've introduced a RegArgs type that stores the offsets for each of our registers (for the other architectures, it's simply an int specifying the number of registers). If someone strongly prefers an enum, we could do that instead, but I believe this is a place where keeping things general is worth it, because this way it should be doable to add SSE or AVX support. There is one line in the patch that looks suspicious: } else { addr = (addr + align - 1) & -align; param_addr = addr; addr += size; - sse_param_index += reg_count; } break; However, this actually fixes one half of a bug we have when calling a function with eight double arguments "interrupted" by a two-double structure after the seventh double argument: f(double,double,double,double,double,double,double,struct { double x,y; },double); In this case, the last argument should be passed in %xmm7. This patch fixes the problem in gfunc_prolog, but not the corresponding problem in gfunc_call, which I'll try tackling next.

seyko committed 11 years ago

Commit 4e04f671 parent 101cc878 files · +452 −228Browse files

Unified · Split

8 files
  1. arm-gen.c +16 −6
  2. arm64-gen.c +10 −1
  3. c67-gen.c +10 −1
  4. i386-gen.c +14 −5
  5. tcc.h +5 −3
  6. tccgen.c +81 −5
  7. tests/abitest.c +4 −4
  8. x86_64-gen.c +312 −203
arm-gen.c+16−6
@@ -34,6 +34,8 @@ · 33 unmodified lines
3434 #define NB_REGS 9
3535 #endif
3636
37+typedef int RegArgs;
38+
3739 #ifndef TCC_ARM_VERSION
3840 # define TCC_ARM_VERSION 5
3941 #endif
@@ -867,9 +869,14 @@ int floats_in_core_regs(SValue *sval) · 827 unmodified lines
867869 }
868870 }
869871
872+ST_FUNC int regargs_nregs(RegArgs *args)
873+{
874+ return *args;
875+}
876+
870877 /* Return the number of registers needed to return the struct, or 0 if
871878 returning via struct pointer. */
872−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {
879+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args) {
873880 #ifdef TCC_ARM_EABI
874881 int size, align;
875882 size = type_size(vt, &align);
@@ -879,18 +886,20 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int · 3 unmodified lines
879886 *regsize = 8;
880887 ret->ref = NULL;
881888 ret->t = VT_DOUBLE;
882− return (size + 7) >> 3;
889+ *args = (size + 7) >> 3;
883890 } else if (size <= 4) {
884891 *ret_align = 4;
885892 *regsize = 4;
886893 ret->ref = NULL;
887894 ret->t = VT_INT;
888− return 1;
895+ *args = 1;
889896 } else
890− return 0;
897+ *args = 0;
891898 #else
892− return 0;
899+ *args = 0;
893900 #endif
901+
902+ return *args != 0;
894903 }
895904
896905 /* Parameters are classified according to how they are copied to their final
@@ -1260,6 +1269,7 @@ void gfunc_prolog(CType *func_type) · 363 unmodified lines
12601269 int n, nf, size, align, rs, struct_ret = 0;
12611270 int addr, pn, sn; /* pn=core, sn=stack */
12621271 CType ret_type;
1272+ RegArgs dummy;
12631273
12641274 #ifdef TCC_ARM_EABI
12651275 struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
@@ -1271,7 +1281,7 @@ void gfunc_prolog(CType *func_type) · 5 unmodified lines
12711281
12721282 n = nf = 0;
12731283 if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
1274− !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs))
1284+ !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs, &dummy))
12751285 {
12761286 n++;
12771287 struct_ret = 1;
arm64-gen.c+10−1
@@ -14,6 +14,8 @@ · 13 unmodified lines
1414 // Number of registers available to allocator:
1515 #define NB_REGS 28 // x0-x18, x30, v0-v7
1616
17+typedef int RegArgs;
18+
1719 #define TREG_R(x) (x) // x = 0..18
1820 #define TREG_R30 19
1921 #define TREG_F(x) (x + 20) // x = 0..7
@@ -1196,8 +1198,15 @@ ST_FUNC void gen_va_arg(CType *t) · 1176 unmodified lines
11961198 }
11971199 }
11981200
1199−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize)
1201+ST_FUNC int regargs_nregs(RegArgs *args)
12001202 {
1203+ return *args;
1204+}
1205+
1206+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize, RegArgs *args)
1207+{
1208+ *args = 0;
1209+
12011210 return 0;
12021211 }
12031212
c67-gen.c+10−1
@@ -25,6 +25,8 @@ · 24 unmodified lines
2525 /* number of available registers */
2626 #define NB_REGS 24
2727
28+typedef int RegArgs;
29+
2830 /* a register can belong to several classes. The classes must be
2931 sorted from more general to more precise (see gv2() code which does
3032 assumptions on it). */
@@ -1879,10 +1881,17 @@ static void gcall_or_jmp(int is_jmp) · 1848 unmodified lines
18791881 }
18801882 }
18811883
1884+ST_FUNC int regargs_nregs(RegArgs *args)
1885+{
1886+ return *args;
1887+}
1888+
18821889 /* Return the number of registers needed to return the struct, or 0 if
18831890 returning via struct pointer. */
1884−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {
1891+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args) {
18851892 *ret_align = 1; // Never have to re-align return values for x86-64
1893+ *args = 0;
1894+
18861895 return 0;
18871896 }
18881897
i386-gen.c+14−5
@@ -24,6 +24,8 @@ · 23 unmodified lines
2424 #define NB_REGS 4
2525 #define NB_ASM_REGS 8
2626
27+typedef int RegArgs;
28+
2729 /* a register can belong to several classes. The classes must be
2830 sorted from more general to more precise (see gv2() code which does
2931 assumptions on it). */
@@ -374,9 +376,14 @@ static void gcall_or_jmp(int is_jmp) · 344 unmodified lines
374376 static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
375377 static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
376378
379+ST_FUNC int regargs_nregs(RegArgs *args)
380+{
381+ return *args;
382+}
383+
377384 /* Return the number of registers needed to return the struct, or 0 if
378385 returning via struct pointer. */
379−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
386+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args)
380387 {
381388 #ifdef TCC_TARGET_PE
382389 int size, align;
@@ -385,20 +392,22 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int · 2 unmodified lines
385392 *regsize = 4;
386393 size = type_size(vt, &align);
387394 if (size > 8) {
388− return 0;
395+ *args = 0;
389396 } else if (size > 4) {
390397 ret->ref = NULL;
391398 ret->t = VT_LLONG;
392− return 1;
399+ *args = 1;
393400 } else {
394401 ret->ref = NULL;
395402 ret->t = VT_INT;
396− return 1;
403+ *args = 1;
397404 }
398405 #else
399406 *ret_align = 1; // Never have to re-align return values for x86
400− return 0;
407+ *args = 0;
401408 #endif
409+
410+ return *args != 0;
402411 }
403412
404413 /* Generate function call. The function address is pushed first, then
tcc.h+5−3
@@ -796,8 +796,8 @@ struct TCCState { · 795 unmodified lines
796796 #define VT_LLONG 12 /* 64 bit integer */
797797 #define VT_LONG 13 /* long integer (NEVER USED as type, only
798798 during parsing) */
799−#define VT_QLONG 14 /* 128-bit integer. Only used for x86-64 ABI */
800−#define VT_QFLOAT 15 /* 128-bit float. Only used for x86-64 ABI */
799+#define VT_QLONG 14 /* 128-bit integer. No longer used. */
800+#define VT_QFLOAT 15 /* 128-bit float. No longer used. */
801801 #define VT_UNSIGNED 0x0010 /* unsigned type */
802802 #define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
803803 #define VT_BITFIELD 0x0040 /* bitfield modifier */
@@ -1267,6 +1267,7 @@ ST_FUNC void save_regs(int n); · 463 unmodified lines
12671267 ST_FUNC void gaddrof(void);
12681268 ST_FUNC int gv(int rc);
12691269 ST_FUNC void gv2(int rc1, int rc2);
1270+ST_FUNC void vdup(void);
12701271 ST_FUNC void vpop(void);
12711272 ST_FUNC void gen_op(int op);
12721273 ST_FUNC int type_size(CType *type, int *a);
@@ -1355,7 +1356,8 @@ ST_FUNC void gsym_addr(int t, int a); · 82 unmodified lines
13551356 ST_FUNC void gsym(int t);
13561357 ST_FUNC void load(int r, SValue *sv);
13571358 ST_FUNC void store(int r, SValue *v);
1358−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);
1359+ST_FUNC int regargs_nregs(RegArgs *args);
1360+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize, RegArgs *args);
13591361 ST_FUNC void gfunc_call(int nb_args);
13601362 ST_FUNC void gfunc_prolog(CType *func_type);
13611363 ST_FUNC void gfunc_epilog(void);
tccgen.c+81−5
@@ -525,7 +525,7 @@ ST_FUNC void vpushv(SValue *v) · 524 unmodified lines
525525 *vtop = *v;
526526 }
527527
528−static void vdup(void)
528+ST_FUNC void vdup(void)
529529 {
530530 vpushv(vtop);
531531 }
@@ -4200,6 +4200,7 @@ ST_FUNC void unary(void) · 3668 unmodified lines
42004200 SValue ret;
42014201 Sym *sa;
42024202 int nb_args, ret_nregs, ret_align, regsize, variadic;
4203+ RegArgs args;
42034204
42044205 /* function call */
42054206 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -4224,8 +4225,10 @@ ST_FUNC void unary(void) · 18 unmodified lines
42244225 /* compute first implicit argument if a structure is returned */
42254226 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
42264227 variadic = (s->c == FUNC_ELLIPSIS);
4227− ret_nregs = gfunc_sret(&s->type, variadic, &ret.type,
4228− &ret_align, &regsize);
4228+ gfunc_sret(&s->type, variadic, &ret.type,
4229+ &ret_align, &regsize, &args);
4230+ ret_nregs = regargs_nregs(&args);
4231+
42294232 if (!ret_nregs) {
42304233 /* get some space for the returned structure */
42314234 size = type_size(&s->type, &align);
@@ -4303,6 +4306,10 @@ ST_FUNC void unary(void) · 71 unmodified lines
43034306 /* handle packed struct return */
43044307 if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {
43054308 int addr, offset;
4309+#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
4310+ int i;
4311+#endif
4312+
43064313
43074314 size = type_size(&s->type, &align);
43084315 /* We're writing whole regs often, make sure there's enough
@@ -4311,6 +4318,34 @@ ST_FUNC void unary(void) · 2 unmodified lines
43114318 align = regsize;
43124319 loc = (loc - size) & -align;
43134320 addr = loc;
4321+#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
4322+ for (i=0; i<REG_ARGS_MAX; i++) {
4323+ offset = args.ireg[i];
4324+
4325+ if (offset == -1)
4326+ break;
4327+
4328+ ret.type.t = VT_LLONG;
4329+ vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
4330+ vsetc(&ret.type, i ? REG_LRET : REG_IRET, &ret.c);
4331+ vstore();
4332+ vtop--;
4333+ vtop--;
4334+ }
4335+ for (i=0; i<REG_ARGS_MAX; i++) {
4336+ offset = args.freg[i];
4337+
4338+ if (offset == -1)
4339+ break;
4340+
4341+ ret.type.t = VT_DOUBLE;
4342+ vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
4343+ vsetc(&ret.type, i ? REG_QRET : REG_FRET, &ret.c);
4344+ vstore();
4345+ vtop--;
4346+ vtop--;
4347+ }
4348+#else
43144349 offset = 0;
43154350 for (;;) {
43164351 vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
@@ -4321,6 +4356,7 @@ ST_FUNC void unary(void) · 4 unmodified lines
43214356 break;
43224357 offset += regsize;
43234358 }
4359+#endif
43244360 vset(&s->type, VT_LOCAL | VT_LVAL, addr);
43254361 }
43264362 } else {
@@ -4891,8 +4927,11 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 564 unmodified lines
48914927 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
48924928 CType type, ret_type;
48934929 int ret_align, ret_nregs, regsize;
4894− ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type,
4895− &ret_align, &regsize);
4930+ RegArgs args;
4931+
4932+ gfunc_sret(&func_vt, func_var, &ret_type,
4933+ &ret_align, &regsize, &args);
4934+ ret_nregs = regargs_nregs(&args);
48964935 if (0 == ret_nregs) {
48974936 /* if returning structure, must copy it to implicit
48984937 first pointer arg location */
@@ -4906,6 +4945,9 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 7 unmodified lines
49064945 } else {
49074946 /* returning structure packed into registers */
49084947 int r, size, addr, align;
4948+#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
4949+ int i;
4950+#endif
49094951 size = type_size(&func_vt,&align);
49104952 if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
49114953 && (align & (ret_align-1))) {
@@ -4919,6 +4961,39 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 7 unmodified lines
49194961 vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
49204962 }
49214963 vtop->type = ret_type;
4964+#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
4965+ for (i=0; i<REG_ARGS_MAX; i++) {
4966+ int off = args.ireg[i];
4967+
4968+ if (off == -1)
4969+ break;
4970+
4971+ r = i ? RC_LRET : RC_IRET;
4972+
4973+ vdup();
4974+ vtop->c.i += off;
4975+ vtop->type.t = VT_LLONG;
4976+ gv(r);
4977+ vpop();
4978+ }
4979+ for (i=0; i<REG_ARGS_MAX; i++) {
4980+ int off = args.freg[i];
4981+
4982+ if (off == -1)
4983+ break;
4984+
4985+ /* We assume that when a structure is returned in multiple
4986+ registers, their classes are consecutive values of the
4987+ suite s(n) = 2^n */
4988+ r = rc_fret(ret_type.t) << i;
4989+
4990+ vdup();
4991+ vtop->c.i += off;
4992+ vtop->type.t = VT_DOUBLE;
4993+ gv(r);
4994+ vpop();
4995+ }
4996+#else
49224997 if (is_float(ret_type.t))
49234998 r = rc_fret(ret_type.t);
49244999 else
@@ -4935,6 +5010,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 10 unmodified lines
49355010 vtop->c.i += regsize;
49365011 vtop->r = VT_LOCAL | VT_LVAL;
49375012 }
5013+#endif
49385014 }
49395015 } else if (is_float(func_vt.t)) {
49405016 gv(rc_fret(func_vt.t));
tests/abitest.c+4−4
@@ -637,10 +637,10 @@ int main(int argc, char **argv) { · 636 unmodified lines
637637 RUN_TEST(ret_longdouble_test);
638638 RUN_TEST(ret_2float_test);
639639 RUN_TEST(ret_2double_test);
640− /* RUN_TEST(ret_8plus2double_test); currently broken on x86_64 */
641− /* RUN_TEST(ret_6plus2longlong_test); currently broken on x86_64 */
642− /* RUN_TEST(ret_mixed_test); currently broken on x86_64 */
643− /* RUN_TEST(ret_mixed2_test); currently broken on x86_64 */
640+ RUN_TEST(ret_8plus2double_test);
641+ RUN_TEST(ret_6plus2longlong_test);
642+ RUN_TEST(ret_mixed_test);
643+ RUN_TEST(ret_mixed2_test);
644644 RUN_TEST(ret_mixed3_test);
645645 RUN_TEST(reg_pack_test);
646646 RUN_TEST(reg_pack_longlong_test);
x86_64-gen.c+312−203
@@ -25,6 +25,24 @@ · 24 unmodified lines
2525 /* number of available registers */
2626 #define NB_REGS 25
2727 #define NB_ASM_REGS 8
28+#define REG_ARGS_MAX 2 /* at most 2 registers used for each argument */
29+
30+#ifdef TCC_TARGET_PE
31+typedef int RegArgs;
32+#else
33+/* This struct stores the struct offsets at which %rax, %rdx, %xmm0, and
34+ * %xmm1 are to be stored.
35+ *
36+ * struct { long long l; double x; }: ireg = { 0, -1 } freg = { 8, -1 }
37+ * struct { double x; long long l; }: ireg = { 8, -1 } freg = { 0, -1 }
38+ * struct { long long l; long long l2; }: ireg = { 0, 8 } freg = { -1, -1 }
39+ * struct { double x; double x2; }: ireg = { -1, -1 } freg = { 0, 8 }
40+ */
41+typedef struct {
42+ int ireg[REG_ARGS_MAX];
43+ int freg[REG_ARGS_MAX];
44+} RegArgs;
45+#endif
2846
2947 /* a register can belong to several classes. The classes must be
3048 sorted from more general to more precise (see gv2() code which does
@@ -745,9 +763,14 @@ void gen_offs_sp(int b, int r, int d) · 714 unmodified lines
745763 }
746764 }
747765
766+ST_FUNC int regargs_nregs(RegArgs *args)
767+{
768+ return *args;
769+}
770+
748771 /* Return the number of registers needed to return the struct, or 0 if
749772 returning via struct pointer. */
750−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
773+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args)
751774 {
752775 int size, align;
753776 *regsize = 8;
@@ -755,20 +778,22 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int · 1 unmodified line
755778 size = type_size(vt, &align);
756779 ret->ref = NULL;
757780 if (size > 8) {
758− return 0;
781+ *args = 0;
759782 } else if (size > 4) {
760783 ret->t = VT_LLONG;
761− return 1;
784+ *args = 1;
762785 } else if (size > 2) {
763786 ret->t = VT_INT;
764− return 1;
787+ *args = 1;
765788 } else if (size > 1) {
766789 ret->t = VT_SHORT;
767− return 1;
790+ *args = 1;
768791 } else {
769792 ret->t = VT_BYTE;
770− return 1;
793+ *args = 1;
771794 }
795+
796+ return *args != 0;
772797 }
773798
774799 static int is_sse_float(int t) {
@@ -1041,7 +1066,9 @@ static X86_64_Mode classify_x86_64_merge(X86_64_Mode a, X86_64_Mode b) · 266 unmodified lines
10411066 return x86_64_mode_sse;
10421067 }
10431068
1044−static X86_64_Mode classify_x86_64_inner(CType *ty)
1069+/* classify the x86 eightbytes from byte index start to byte index
1070+ * end, at offset offset from the root struct */
1071+static X86_64_Mode classify_x86_64_inner(CType *ty, int offset, int start, int end)
10451072 {
10461073 X86_64_Mode mode;
10471074 Sym *f;
@@ -1067,8 +1094,10 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) · 19 unmodified lines
10671094 f = ty->ref;
10681095
10691096 mode = x86_64_mode_none;
1070− for (f = f->next; f; f = f->next)
1071− mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type));
1097+ while ((f = f->next) != NULL) {
1098+ if (f->c + offset >= start && f->c + offset < end)
1099+ mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type, f->c + offset, start, end));
1100+ }
10721101
10731102 return mode;
10741103 }
@@ -1076,61 +1105,79 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) · 1 unmodified line
10761105 assert(0);
10771106 }
10781107
1079−static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count)
1108+static X86_64_Mode classify_x86_64_arg_eightbyte(CType *ty, int offset)
10801109 {
10811110 X86_64_Mode mode;
1111+
1112+ assert((ty->t & VT_BTYPE) == VT_STRUCT);
1113+
1114+ mode = classify_x86_64_inner(ty, 0, offset, offset + 8);
1115+
1116+ return mode;
1117+}
1118+
1119+static void regargs_init(RegArgs *args)
1120+{
1121+ int i;
1122+ for(i=0; i<REG_ARGS_MAX; i++) {
1123+ args->ireg[i] = -1;
1124+ args->freg[i] = -1;
1125+ }
1126+}
1127+
1128+static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, RegArgs *args)
1129+{
1130+ X86_64_Mode mode = x86_64_mode_none;
10821131 int size, align, ret_t = 0;
1083−
1132+ int ireg = 0, freg = 0;
1133+
1134+ if (args)
1135+ regargs_init(args);
1136+
10841137 if (ty->t & (VT_BITFIELD|VT_ARRAY)) {
10851138 *psize = 8;
10861139 *palign = 8;
1087− *reg_count = 1;
1140+ if (args)
1141+ args->ireg[ireg++] = 0;
10881142 ret_t = ty->t;
10891143 mode = x86_64_mode_integer;
10901144 } else {
10911145 size = type_size(ty, &align);
10921146 *psize = (size + 7) & ~7;
10931147 *palign = (align + 7) & ~7;
1094−
1148+
10951149 if (size > 16) {
10961150 mode = x86_64_mode_memory;
10971151 } else {
1098− mode = classify_x86_64_inner(ty);
1099− switch (mode) {
1100− case x86_64_mode_integer:
1101− if (size > 8) {
1102− *reg_count = 2;
1103− ret_t = VT_QLONG;
1152+ int start;
1153+
1154+ for(start=0; start < size; start += 8) {
1155+ if ((ty->t & VT_BTYPE) == VT_STRUCT) {
1156+ mode = classify_x86_64_arg_eightbyte(ty, start);
11041157 } else {
1105− *reg_count = 1;
1106− ret_t = (size > 4) ? VT_LLONG : VT_INT;
1158+ mode = classify_x86_64_inner(ty, 0, 0, size);
11071159 }
1108− break;
1109−
1110− case x86_64_mode_x87:
1111− *reg_count = 1;
1112− ret_t = VT_LDOUBLE;
1113− break;
11141160
1115− case x86_64_mode_sse:
1116− if (size > 8) {
1117− *reg_count = 2;
1118− ret_t = VT_QFLOAT;
1119− } else {
1120− *reg_count = 1;
1161+ if (mode == x86_64_mode_integer) {
1162+ if (args)
1163+ args->ireg[ireg++] = start;
1164+ ret_t = (size > 4) ? VT_LLONG : VT_INT;
1165+ } else if (mode == x86_64_mode_sse) {
1166+ if (args)
1167+ args->freg[freg++] = start;
11211168 ret_t = (size > 4) ? VT_DOUBLE : VT_FLOAT;
1169+ } else {
1170+ ret_t = VT_LDOUBLE;
11221171 }
1123− break;
1124− default: break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/
11251172 }
11261173 }
11271174 }
1128−
1175+
11291176 if (ret) {
11301177 ret->ref = NULL;
11311178 ret->t = ret_t;
11321179 }
1133−
1180+
11341181 return mode;
11351182 }
11361183
@@ -1140,8 +1187,8 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) · 3 unmodified lines
11401187 enum __va_arg_type {
11411188 __va_gen_reg, __va_float_reg, __va_stack
11421189 };
1143− int size, align, reg_count;
1144− X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, &reg_count);
1190+ int size, align;
1191+ X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, NULL);
11451192 switch (mode) {
11461193 default: return __va_stack;
11471194 case x86_64_mode_integer: return __va_gen_reg;
@@ -1149,14 +1196,57 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) · 1 unmodified line
11491196 }
11501197 }
11511198
1152−/* Return the number of registers needed to return the struct, or 0 if
1153− returning via struct pointer. */
1154−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
1199+static int regargs_iregs(RegArgs *args)
11551200 {
1156− int size, align, reg_count;
1201+ int i;
1202+ int ret = 0;
1203+ for(i=0; i<REG_ARGS_MAX; i++) {
1204+ if(args->ireg[i] != -1)
1205+ ret++;
1206+ }
1207+
1208+ return ret;
1209+}
1210+
1211+static int regargs_fregs(RegArgs *args)
1212+{
1213+ int i;
1214+ int ret = 0;
1215+ for(i=0; i<REG_ARGS_MAX; i++) {
1216+ if(args->freg[i] != -1)
1217+ ret++;
1218+ }
1219+
1220+ return ret;
1221+}
1222+
1223+/* Count the total number of registers used by args */
1224+ST_FUNC int regargs_nregs(RegArgs *args)
1225+{
1226+ int i;
1227+ int ret = 0;
1228+ for(i=0; i<REG_ARGS_MAX; i++) {
1229+ if(args->ireg[i] != -1)
1230+ ret++;
1231+
1232+ if(args->freg[i] != -1)
1233+ ret++;
1234+ }
1235+
1236+ return ret;
1237+}
1238+
1239+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args)
1240+{
1241+ int size, align;
1242+ X86_64_Mode mode;
11571243 *ret_align = 1; // Never have to re-align return values for x86-64
11581244 *regsize = 8;
1159− return (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) != x86_64_mode_memory);
1245+
1246+ mode = classify_x86_64_arg(vt, ret, &size, &align, args);
1247+
1248+ return mode != x86_64_mode_memory &&
1249+ mode != x86_64_mode_none;
11601250 }
11611251
11621252 #define REGN 6
@@ -1179,18 +1269,28 @@ void gfunc_call(int nb_args) · 16 unmodified lines
11791269 {
11801270 X86_64_Mode mode;
11811271 CType type;
1182− int size, align, r, args_size, stack_adjust, run_start, run_end, i, reg_count;
1272+ int size, align, r, args_size, stack_adjust, run_start, run_end, i;
11831273 int nb_reg_args = 0;
11841274 int nb_sse_args = 0;
1185− int sse_reg, gen_reg;
1275+ int sse_reg = 0, gen_reg = 0;
1276+ RegArgs *reg_args = alloca(nb_args * sizeof *reg_args);
11861277
11871278 /* calculate the number of integer/float register arguments */
1188− for(i = 0; i < nb_args; i++) {
1189− mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_count);
1190− if (mode == x86_64_mode_sse)
1191− nb_sse_args += reg_count;
1192− else if (mode == x86_64_mode_integer)
1193− nb_reg_args += reg_count;
1279+ for(i = nb_args - 1; i >= 0; i--) {
1280+ int fregs, iregs;
1281+ mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_args[i]);
1282+ fregs = regargs_fregs(&reg_args[i]);
1283+ iregs = regargs_iregs(&reg_args[i]);
1284+
1285+ nb_sse_args += fregs;
1286+ nb_reg_args += iregs;
1287+
1288+ if (sse_reg + fregs > 8 || gen_reg + iregs > REGN) {
1289+ regargs_init(&reg_args[i]);
1290+ } else {
1291+ sse_reg += fregs;
1292+ gen_reg += iregs;
1293+ }
11941294 }
11951295
11961296 /* arguments are collected in runs. Each run is a collection of 8-byte aligned arguments
@@ -1209,27 +1309,14 @@ void gfunc_call(int nb_args) · 12 unmodified lines
12091309 run_end = nb_args;
12101310 stack_adjust = 0;
12111311 for(i = run_start; (i < nb_args) && (run_end == nb_args); i++) {
1212− mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_count);
1213− switch (mode) {
1214− case x86_64_mode_memory:
1215− case x86_64_mode_x87:
1216− stack_arg:
1312+ int stack = regargs_nregs(&reg_args[i]) == 0;
1313+ classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, NULL);
1314+
1315+ if (stack) {
12171316 if (align == 16)
12181317 run_end = i;
12191318 else
12201319 stack_adjust += size;
1221− break;
1222−
1223− case x86_64_mode_sse:
1224− sse_reg -= reg_count;
1225− if (sse_reg + reg_count > 8) goto stack_arg;
1226− break;
1227−
1228− case x86_64_mode_integer:
1229− gen_reg -= reg_count;
1230− if (gen_reg + reg_count > REGN) goto stack_arg;
1231− break;
1232− default: break; /* nothing to be done for x86_64_mode_none */
12331320 }
12341321 }
12351322
@@ -1249,44 +1336,38 @@ void gfunc_call(int nb_args) · 13 unmodified lines
12491336 }
12501337
12511338 for(i = run_start; i < run_end;) {
1339+ int arg_stored = regargs_nregs(&reg_args[i]) == 0;
1340+ SValue tmp;
1341+ RegArgs args;
1342+
1343+ if (!arg_stored) {
1344+ ++i;
1345+ continue;
1346+ }
1347+
12521348 /* Swap argument to top, it will possibly be changed here,
12531349 and might use more temps. At the end of the loop we keep
12541350 in on the stack and swap it back to its original position
12551351 if it is a register. */
1256− SValue tmp = vtop[0];
1257− int arg_stored = 1;
1258−
1352+ tmp = vtop[0];
12591353 vtop[0] = vtop[-i];
12601354 vtop[-i] = tmp;
1261− mode = classify_x86_64_arg(&vtop->type, NULL, &size, &align, &reg_count);
12621355
1356+ classify_x86_64_arg(&vtop->type, NULL, &size, &align, &args);
1357+
12631358 switch (vtop->type.t & VT_BTYPE) {
12641359 case VT_STRUCT:
1265− if (mode == x86_64_mode_sse) {
1266− if (sse_reg > 8)
1267− sse_reg -= reg_count;
1268− else
1269− arg_stored = 0;
1270− } else if (mode == x86_64_mode_integer) {
1271− if (gen_reg > REGN)
1272− gen_reg -= reg_count;
1273− else
1274− arg_stored = 0;
1275− }
1276−
1277− if (arg_stored) {
1278− /* allocate the necessary size on stack */
1279− o(0x48);
1280− oad(0xec81, size); /* sub $xxx, %rsp */
1281− /* generate structure store */
1282− r = get_reg(RC_INT);
1283− orex(1, r, 0, 0x89); /* mov %rsp, r */
1284− o(0xe0 + REG_VALUE(r));
1285− vset(&vtop->type, r | VT_LVAL, 0);
1286− vswap();
1287− vstore();
1288− args_size += size;
1289− }
1360+ /* allocate the necessary size on stack */
1361+ o(0x48);
1362+ oad(0xec81, size); /* sub $xxx, %rsp */
1363+ /* generate structure store */
1364+ r = get_reg(RC_INT);
1365+ orex(1, r, 0, 0x89); /* mov %rsp, r */
1366+ o(0xe0 + REG_VALUE(r));
1367+ vset(&vtop->type, r | VT_LVAL, 0);
1368+ vswap();
1369+ vstore();
1370+ args_size += size;
12901371 break;
12911372
12921373 case VT_LDOUBLE:
@@ -1295,57 +1376,43 @@ void gfunc_call(int nb_args) · 2 unmodified lines
12951376
12961377 case VT_FLOAT:
12971378 case VT_DOUBLE:
1298− assert(mode == x86_64_mode_sse);
1299− if (sse_reg > 8) {
1300− --sse_reg;
1301− r = gv(RC_FLOAT);
1302− o(0x50); /* push $rax */
1303− /* movq %xmmN, (%rsp) */
1304− o(0xd60f66);
1305− o(0x04 + REG_VALUE(r)*8);
1306− o(0x24);
1307− args_size += size;
1308− } else {
1309− arg_stored = 0;
1310− }
1379+ r = gv(RC_FLOAT);
1380+ o(0x50); /* push $rax */
1381+ /* movq %xmmN, (%rsp) */
1382+ o(0xd60f66);
1383+ o(0x04 + REG_VALUE(r)*8);
1384+ o(0x24);
1385+ args_size += size;
13111386 break;
13121387
13131388 default:
1314− assert(mode == x86_64_mode_integer);
13151389 /* simple type */
13161390 /* XXX: implicit cast ? */
1317− if (gen_reg > REGN) {
1318− --gen_reg;
1319− r = gv(RC_INT);
1320− orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */
1321− args_size += size;
1322− } else {
1323− arg_stored = 0;
1324− }
1391+ --gen_reg;
1392+ r = gv(RC_INT);
1393+ orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */
1394+ args_size += size;
13251395 break;
13261396 }
1327−
1328− /* And swap the argument back to it's original position. */
1397+
1398+ /* And swap the argument back to its original position. */
13291399 tmp = vtop[0];
13301400 vtop[0] = vtop[-i];
13311401 vtop[-i] = tmp;
13321402
1333− if (arg_stored) {
1334− vrotb(i+1);
1335− assert((vtop->type.t == tmp.type.t) && (vtop->r == tmp.r));
1336− vpop();
1337− --nb_args;
1338− --run_end;
1339− } else {
1340− ++i;
1341− }
1403+ vrotb(i+1);
1404+ assert((vtop->type.t == tmp.type.t) && (vtop->r == tmp.r));
1405+ vpop();
1406+ memmove(reg_args + i, reg_args + i + 1, (nb_args - i - 1) * sizeof *reg_args);
1407+ --nb_args;
1408+ --run_end;
13421409 }
13431410
13441411 /* handle 16 byte aligned arguments at end of run */
13451412 run_start = i = run_end;
13461413 while (i < nb_args) {
13471414 /* Rotate argument to top since it will always be popped */
1348− mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_count);
1415+ mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, NULL);
13491416 if (align != 16)
13501417 break;
13511418
@@ -1375,13 +1442,24 @@ void gfunc_call(int nb_args) · 23 unmodified lines
13751442 }
13761443
13771444 vpop();
1445+ memmove(reg_args + i, reg_args + i + 1, (nb_args - i - 1) * sizeof *reg_args);
13781446 --nb_args;
13791447 }
13801448 }
1381−
1449+
13821450 /* XXX This should be superfluous. */
13831451 save_regs(0); /* save used temporary registers */
13841452
1453+ /* recalculate the number of register arguments there actually
1454+ * are. This is slow but more obviously correct than using the
1455+ * old counts. */
1456+ gen_reg = 0;
1457+ sse_reg = 0;
1458+ for(i = 0; i < nb_args; i++) {
1459+ gen_reg += regargs_iregs(&reg_args[i]);
1460+ sse_reg += regargs_fregs(&reg_args[i]);
1461+ }
1462+
13851463 /* then, we prepare register passing arguments.
13861464 Note that we cannot set RDX and RCX in this loop because gv()
13871465 may break these temporary registers. Let's use R10 and R11
@@ -1389,40 +1467,62 @@ void gfunc_call(int nb_args) · 1 unmodified line
13891467 assert(gen_reg <= REGN);
13901468 assert(sse_reg <= 8);
13911469 for(i = 0; i < nb_args; i++) {
1392− mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, &reg_count);
1470+ RegArgs args;
1471+
1472+ args = reg_args[i];
1473+
13931474 /* Alter stack entry type so that gv() knows how to treat it */
1394− vtop->type = type;
1395− if (mode == x86_64_mode_sse) {
1396− if (reg_count == 2) {
1397− sse_reg -= 2;
1398− gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */
1399− if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */
1400− /* movaps %xmm0, %xmmN */
1401− o(0x280f);
1402− o(0xc0 + (sse_reg << 3));
1403− /* movaps %xmm1, %xmmN */
1404− o(0x280f);
1405− o(0xc1 + ((sse_reg+1) << 3));
1406− }
1407− } else {
1408− assert(reg_count == 1);
1475+ if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
1476+ int k;
1477+
1478+ for(k=REG_ARGS_MAX-1; k>=0; k--) {
1479+ if (args.freg[k] == -1)
1480+ continue;
1481+
1482+ sse_reg--;
1483+ assert(sse_reg >= 0);
1484+
1485+ vdup();
1486+ vtop->type.t = VT_DOUBLE;
1487+ vtop->c.ull += args.freg[k];
1488+ gv(RC_XMM0 << sse_reg);
1489+ vpop();
1490+ }
1491+ for(k=REG_ARGS_MAX-1; k>=0; k--) {
1492+ int d;
1493+ if (args.ireg[k] == -1)
1494+ continue;
1495+
1496+ gen_reg--;
1497+
1498+ vdup();
1499+ vtop->type.t = VT_LLONG;
1500+ vtop->c.ull += args.ireg[k];
1501+ r = gv(RC_INT);
1502+ d = arg_prepare_reg(gen_reg);
1503+ orex(1,d,r,0x89); /* mov */
1504+ o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
1505+ vpop();
1506+ }
1507+ } else {
1508+ /* XXX is it really necessary to set vtop->type? */
1509+ classify_x86_64_arg(&vtop->type, &type, &size, &align, NULL);
1510+ vtop->type = type;
1511+ if (args.freg[0] != -1) {
14091512 --sse_reg;
14101513 /* Load directly to register */
14111514 gv(RC_XMM0 << sse_reg);
1412− }
1413− } else if (mode == x86_64_mode_integer) {
1414− /* simple type */
1415− /* XXX: implicit cast ? */
1416− int d;
1417− gen_reg -= reg_count;
1418− r = gv(RC_INT);
1419− d = arg_prepare_reg(gen_reg);
1420− orex(1,d,r,0x89); /* mov */
1421− o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
1422− if (reg_count == 2) {
1423− d = arg_prepare_reg(gen_reg+1);
1424− orex(1,d,vtop->r2,0x89); /* mov */
1425− o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d));
1515+ } else if (args.ireg[0] != -1) {
1516+ int d;
1517+ /* simple type */
1518+ /* XXX: implicit cast ? */
1519+ gen_reg--;
1520+ r = gv(RC_INT);
1521+ d = arg_prepare_reg(gen_reg);
1522+ orex(1,d,r,0x89); /* mov */
1523+ o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
1524+ } else {
1525+ assert(0);
14261526 }
14271527 }
14281528 vtop--;
@@ -1463,7 +1563,7 @@ static void push_arg_reg(int i) { · 34 unmodified lines
14631563 void gfunc_prolog(CType *func_type)
14641564 {
14651565 X86_64_Mode mode;
1466− int i, addr, align, size, reg_count;
1566+ int i, addr, align, size;
14671567 int param_addr = 0, reg_param_index, sse_param_index;
14681568 Sym *sym;
14691569 CType *type;
@@ -1483,32 +1583,38 @@ void gfunc_prolog(CType *func_type) · 13 unmodified lines
14831583 /* count the number of seen parameters */
14841584 sym = func_type->ref;
14851585 while ((sym = sym->next) != NULL) {
1586+ RegArgs args;
1587+
14861588 type = &sym->type;
1487− mode = classify_x86_64_arg(type, NULL, &size, &align, &reg_count);
1589+ mode = classify_x86_64_arg(type, NULL, &size, &align, &args);
1590+
14881591 switch (mode) {
14891592 default:
14901593 stack_arg:
14911594 seen_stack_size = ((seen_stack_size + align - 1) & -align) + size;
14921595 break;
1493−
1596+
14941597 case x86_64_mode_integer:
1495− if (seen_reg_num + reg_count <= 8) {
1496− seen_reg_num += reg_count;
1497− } else {
1598+ case x86_64_mode_sse: {
1599+ int stack = 0;
1600+
1601+ seen_sse_num += regargs_fregs(&args);
1602+ seen_reg_num += regargs_iregs(&args);
1603+
1604+ if (seen_reg_num > 8) {
14981605 seen_reg_num = 8;
1499− goto stack_arg;
1606+ stack = 1;
15001607 }
1501− break;
1502−
1503− case x86_64_mode_sse:
1504− if (seen_sse_num + reg_count <= 8) {
1505− seen_sse_num += reg_count;
1506− } else {
1608+ if (seen_sse_num > 8) {
15071609 seen_sse_num = 8;
1508− goto stack_arg;
1610+ stack = 1;
15091611 }
1612+
1613+ if (stack)
1614+ goto stack_arg;
15101615 break;
15111616 }
1617+ }
15121618 }
15131619
15141620 loc -= 16;
@@ -1544,7 +1650,7 @@ void gfunc_prolog(CType *func_type) · 29 unmodified lines
15441650 /* if the function returns a structure, then add an
15451651 implicit pointer parameter */
15461652 func_vt = sym->type;
1547− mode = classify_x86_64_arg(&func_vt, NULL, &size, &align, &reg_count);
1653+ mode = classify_x86_64_arg(&func_vt, NULL, &size, &align, NULL);
15481654 if (mode == x86_64_mode_memory) {
15491655 push_arg_reg(reg_param_index);
15501656 func_vc = loc;
@@ -1552,19 +1658,40 @@ void gfunc_prolog(CType *func_type) · 1 unmodified line
15521658 }
15531659 /* define parameters */
15541660 while ((sym = sym->next) != NULL) {
1661+ RegArgs args;
1662+ int reg_count_integer = 0;
1663+ int reg_count_sse = 0;
1664+ int arg_stored = 1;
1665+
15551666 type = &sym->type;
1556− mode = classify_x86_64_arg(type, NULL, &size, &align, &reg_count);
1667+ mode = classify_x86_64_arg(type, NULL, &size, &align, &args);
1668+ reg_count_integer = regargs_iregs(&args);
1669+ reg_count_sse = regargs_fregs(&args);
1670+
15571671 switch (mode) {
1672+ case x86_64_mode_integer:
15581673 case x86_64_mode_sse:
1559− if (sse_param_index + reg_count <= 8) {
1674+ if (reg_count_integer || reg_count_sse) {
1675+ if ((reg_count_sse == 0 || sse_param_index + reg_count_sse <= 8) &&
1676+ (reg_count_integer == 0 || reg_param_index + reg_count_integer <= REGN)) {
1677+ /* argument fits into registers */
1678+ arg_stored = 0;
1679+ }
1680+ }
1681+
1682+ if (!arg_stored) {
15601683 /* save arguments passed by register */
1561− loc -= reg_count * 8;
1684+ loc -= (reg_count_sse + reg_count_integer) * 8;
15621685 param_addr = loc;
1563− for (i = 0; i < reg_count; ++i) {
1686+ for (i = 0; i < reg_count_sse; ++i) {
15641687 o(0xd60f66); /* movq */
1565− gen_modrm(sse_param_index, VT_LOCAL, NULL, param_addr + i*8);
1688+ gen_modrm(sse_param_index, VT_LOCAL, NULL, param_addr + args.freg[i]);
15661689 ++sse_param_index;
15671690 }
1691+ for (i = 0; i < reg_count_integer; ++i) {
1692+ gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, param_addr + args.ireg[i]);
1693+ ++reg_param_index;
1694+ }
15681695 } else {
15691696 addr = (addr + align - 1) & -align;
15701697 param_addr = addr;
@@ -1578,23 +1705,6 @@ void gfunc_prolog(CType *func_type) · 7 unmodified lines
15781705 param_addr = addr;
15791706 addr += size;
15801707 break;
1581−
1582− case x86_64_mode_integer: {
1583− if (reg_param_index + reg_count <= REGN) {
1584− /* save arguments passed by register */
1585− loc -= reg_count * 8;
1586− param_addr = loc;
1587− for (i = 0; i < reg_count; ++i) {
1588− gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, param_addr + i*8);
1589− ++reg_param_index;
1590− }
1591− } else {
1592− addr = (addr + align - 1) & -align;
1593− param_addr = addr;
1594− addr += size;
1595− }
1596− break;
1597− }
15981708 default: break; /* nothing to be done for x86_64_mode_none */
15991709 }
16001710 sym_push(sym->v & ~SYM_FIELD, type,
@@ -1631,7 +1741,7 @@ void gfunc_epilog(void) · 30 unmodified lines
16311741 *bounds_ptr = 0;
16321742
16331743 /* generate bound local allocation */
1634− sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
1744+ sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
16351745 func_bound_offset, lbounds_section->data_offset);
16361746 saved_ind = ind;
16371747 ind = func_bound_ind;
@@ -2233,8 +2343,7 @@ ST_FUNC void gen_vla_alloc(CType *type, int align) { · 595 unmodified lines
22332343 gfunc_call(1);
22342344 vset(type, REG_IRET, 0);
22352345 #else
2236− int r;
2237− r = gv(RC_INT); /* allocation size */
2346+ int r = gv(RC_INT); /* allocation size */
22382347 /* sub r,%rsp */
22392348 o(0x2b48);
22402349 o(0xe0 | REG_VALUE(r));

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t