Skip to content

Commit

Permalink
add prolog_genva_start() (#20909)
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright authored Feb 25, 2025
1 parent ee82f26 commit 152815e
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 17 deletions.
163 changes: 148 additions & 15 deletions compiler/src/dmd/backend/arm/cod3.d
Original file line number Diff line number Diff line change
Expand Up @@ -329,26 +329,159 @@ void prolog_genvarargs(ref CGstate cg, ref CodeBuilder cdb, Symbol* sv)
cdb.gen1(INSTR.str_imm_fpsimd(0,2,offset,29,q));
}
}
}

/********************************
* Generate elems for va_start()
* Params:
* sv = symbol for __va_argsave
* parmn = last named parameter
*/
@trusted
elem* prolog_genva_start(Symbol* sv, Symbol* parmn)
{
printf("prolog_genva_start()\n");

/* the stack variable __va_argsave points to an instance of:
* struct __va_argsave_t {
* size_t[Vregnum] regs;
* real[8] fpregs;
* struct __va_list_tag {
* uint offset_regs;
* uint offset_fpregs;
* void* stack_args;
* void* reg_args;
* }
* // AArch64 Procedure Call Standard 12.2
* struct __va_list_tag {
* void* stack; // next stack param
* void* gr_top; // end of GP arg reg save area
* void* vr_top; // end of FP/SIMD arg reg save area
* int gr_offs; // offset from gr_top to next GP register arg
* int vr_offs; // offset from vr_top to next FP/SIMD register arg
* }
* void* stack_args_save;
* }
*/

enum OFF // offsets into __va_argsave_t
{
Offset_stack,
Offset_gr_top,
Offset_vr_top,
Offset_gr_offs,
Offset_vr_offs,

Offset_regs = 8*8 + 8*16,
Offset_fpregs = Offset_regs + 4,
Stack_args = Offset_fpregs + 4,
Reg_args = Stack_args + 8,
Stack_args_save = Reg_args + 8,
}

regm_t namedargs = prolog_namedArgs();

// AArch64 Procedure Call Standard 12.3
uint named_gr; // number of general registers known to hold named incoming arguments
foreach (reg_t x; 0 .. 8)
{
if (!namedargs)
break;
regm_t m = mask(x);
if (m & namedargs)
{
++named_gr;
namedargs &= ~m;
}
}

uint named_vr; // number of FP/SIMD registers known to hold named incoming arguments
foreach (reg_t q; 32 + 0 .. 32 + 8)
{
if (!namedargs)
break;
regm_t m = mask(q);
if (m & namedargs)
{
++named_vr;
namedargs &= ~m;
}
}

// set stack to address following the last named incoming argument on the stack
// rounded upwards to a multiple of 8 bytes, or if there are no named arguments on the stack, then
// the value of the stack pointer when the function was entered.
elem* e1 = null; // TODO

// set gr_top to address following the general register save area
elem* e2 = el_bin(OPeq, TYptr, el_var(sv), el_ptr(sv));
e2.E1.Voffset = OFF.Offset_vr_offs;

static if (0) // TODO
// set vr_top to address following the FP/SIMD register save area
elem* ex3 = el_bin(OPadd, TYptr, el_ptr(sv), el_long(TYlong, 8 * 8));
elem* e3 = el_bin(OPeq,TYptr,el_var(sv),ex3);
e3.E1.Ety = TYptr;
e3.E1.Voffset = OFF.Offset_vr_offs;

// set gr_offs
elem* e4 = el_bin(OPeq, TYint, el_var(sv), el_long(TYint, 0 - ((8 - named_gr) * 8)));
e4.E1.Ety = TYint;
e4.E1.Voffset = OFF.Offset_gr_offs;

// set vr_offs
elem* e5 = el_bin(OPeq, TYint, el_var(sv), el_long(TYint, 0 - ((8 - named_vr) * 16)));
e5.E1.Ety = TYint;
e5.E1.Voffset = OFF.Offset_vr_offs;

static if (0)
{
// LEA R11, Para.size+Para.offset[RBP]
uint ea2 = modregxrm(2,R11,BPRM);
if (!cg.hasframe)
ea2 = (modregrm(0,4,SP) << 8) | modregrm(2,DX,4);
cg.Para.offset = (cg.Para.offset + (REGSIZE - 1)) & ~(REGSIZE - 1);
cdb.genc1(LEA,(REX_W << 16) | ea2,FL.const_,cg.Para.size + cg.Para.offset);

// MOV 9+16[RAX],R11
cdb.genc1(0x89,(REX_W << 16) | modregxrm(2,R11,AX),FL.const_,9 + 16); // into stack_args_save

pinholeopt(cdb.peek(), null);
useregs(mAX|mR11);
// set offset_regs
elem* e1 = el_bin(OPeq, TYint, el_var(sv), el_long(TYint, offset_regs));
e1.E1.Ety = TYint;
e1.E1.Voffset = OFF.Offset_regs;

// set offset_fpregs
elem* e2 = el_bin(OPeq, TYint, el_var(sv), el_long(TYint, offset_fpregs));
e2.E1.Ety = TYint;
e2.E1.Voffset = OFF.Offset_fpregs;

// set reg_args
elem* e4 = el_bin(OPeq, TYnptr, el_var(sv), el_ptr(sv));
e4.E1.Ety = TYnptr;
e4.E1.Voffset = OFF.Reg_args;

// set stack_args
/* which is a pointer to the first variadic argument on the stack.
* Normally, we could set it by taking the address of the last named parameter
* (parmn) and then skipping past it. The trouble, though, is it fails
* when all the named parameters get passed in a register.
* elem* e3 = el_bin(OPeq, TYnptr, el_var(sv), el_ptr(parmn));
* e3.E1.Ety = TYnptr;
* e3.E1.Voffset = OFF.Stack_args;
* auto sz = type_size(parmn.Stype);
* sz = (sz + (REGSIZE - 1)) & ~(REGSIZE - 1);
* e3.E2.Voffset += sz;
* The next possibility is to do it the way prolog_genvarargs() does:
* LEA R11, Para.size+Para.offset[RBP]
* The trouble there is Para.size and Para.offset is not available when
* this function is called. It might be possible to compute this earlier.(1)
* Another possibility is creating a special operand type that gets filled
* in after the prolog_genvarargs() is called.
* Or do it this simpler way - compute the needed value in prolog_genvarargs(),
* and save it in a slot just after va_argsave, called `stack_args_save`.
* Then, just copy from `stack_args_save` to `stack_args`.
* Although, doing (1) might be optimal.
*/
elem* e3 = el_bin(OPeq, TYnptr, el_var(sv), el_var(sv));
e3.E1.Ety = TYnptr;
e3.E1.Voffset = OFF.Stack_args;
e3.E2.Ety = TYnptr;
e3.E2.Voffset = OFF.Stack_args_save;
}
elem* e = el_combine(e1, el_combine(e2, el_combine(e3, el_combine(e4, e5))));
return e;
}

// prolog_genvarargs
// prolog_genva_start
// prolog_gen_win64_varargs
// prolog_namedArgs
// prolog_loadparams
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dmd/backend/backconfig.d
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ void out_config_init(
cfg.fulltypes = CVNONE;
cfg.fpxmmregs = false;
if (!arm)
cfg.inline8087 = 1;
cfg.inline8087 = 1;
cfg.memmodel = 0;
cfg.flags |= CFGuchar; // make sure TYchar is unsigned
cfg.exe = exefmt;
Expand Down
6 changes: 5 additions & 1 deletion compiler/src/dmd/backend/cgelem.d
Original file line number Diff line number Diff line change
Expand Up @@ -5513,6 +5513,7 @@ private elem* elclassinit(elem* e, Goal goal)
}

/********************************************
* Handle OPva_start
*/

@trusted
Expand Down Expand Up @@ -5616,7 +5617,10 @@ if (config.exe & EX_posix)
if (va_argsave)
{
e.E2 = el_ptr(va_argsave);
e.E2.Voffset = 6 * 8 + 8 * 16; // offset to struct __va_list_tag defined in sysv_x64.d
if (cgstate.AArch64)
e.E2.Voffset = 8 * 8 + 8 * 16; // offset to struct __va_list_tag
else
e.E2.Voffset = 6 * 8 + 8 * 16; // offset to struct __va_list_tag defined in sysv_x64.d
return el_combine(prolog_genva_start(va_argsave, parmn.Vsym), e);
}
else
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dmd/backend/x86/cod3.d
Original file line number Diff line number Diff line change
Expand Up @@ -4078,6 +4078,9 @@ void prolog_genvarargs(ref CGstate cg, ref CodeBuilder cdb, Symbol* sv)
@trusted
elem* prolog_genva_start(Symbol* sv, Symbol* parmn)
{
if (cgstate.AArch64)
return dmd.backend.arm.cod3.prolog_genva_start(sv, parmn);

enum Vregnum = 6;

/* the stack variable __va_argsave points to an instance of:
Expand Down

0 comments on commit 152815e

Please sign in to comment.