add ability to call helper functions (#21275)

This commit is contained in:
Walter Bright 2025-04-19 20:23:18 -07:00 committed by GitHub
parent 6208d4da8d
commit 4c2d438f75
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 150 additions and 3 deletions

View file

@ -1314,6 +1314,146 @@ void fixresult(ref CodeBuilder cdb, elem* e, regm_t retregs, ref regm_t outretre
}
}
/*******************************
* Extra information about each CLIB_A runtime library function.
*/
private
enum CLIB_A
{
realToDouble,
doubleToReal,
}
private
struct ClibInfo
{
regm_t retregs; // registers that 32 bit result is returned in
}
__gshared int clib_inited = false; // true if initialized
@trusted private
Symbol* symboly(string name, regm_t desregs)
{
Symbol* s = symbol_calloc(name);
s.Stype = tsclib;
s.Sclass = SC.extern_;
s.Sfl = FL.func;
s.Ssymnum = 0;
s.Sregsaved = fregsaved; // assume C conventions
return s;
}
private
void initClibInfo(ref Symbol*[CLIB_A.max + 1] clibsyms, ref ClibInfo[CLIB_A.max + 1] clibinfo)
{
foreach (s; clibsyms[])
{
if (s)
{
s.Sxtrnnum = 0;
s.Stypidx = 0;
}
}
}
private
void getClibFunction(uint clib, ref Symbol* s, ref ClibInfo* cinfo, objfmt_t objfmt, exefmt_t exe)
{
switch (clib)
{
case CLIB_A.realToDouble:
{
string name = "__trunctfdf2";
s = symboly(name, mask(32));
cinfo.retregs = mask(32);
break;
}
case CLIB_A.doubleToReal:
{
string name = "__extenddftf2";
s = symboly(name, mask(32));
cinfo.retregs = mask(32);
break;
}
default:
assert(0);
}
}
@trusted private
void getClibInfo(uint clib, Symbol** ps, ClibInfo** pinfo, objfmt_t objfmt, exefmt_t exe)
{
static Symbol*[CLIB_A.max + 1] clibsyms;
static ClibInfo[CLIB_A.max + 1] clibinfo;
if (!clib_inited)
{
initClibInfo(clibsyms, clibinfo);
clib_inited = true;
}
ClibInfo* cinfo = &clibinfo[clib];
Symbol* s = clibsyms[clib];
if (!s)
{
getClibFunction(clib, s, cinfo, objfmt, exe);
clibsyms[clib] = s;
}
*ps = s;
*pinfo = cinfo;
}
/********************************
* Generate code sequence to call C runtime library support routine.
* clib = CLIB_A.xxxx
* keepmask = mask of registers not to destroy. Currently can
* handle only 1. Should use a temporary rather than
* push/pop for speed.
*/
@trusted
void callclib(ref CodeBuilder cdb, elem* e, uint clib, ref regm_t pretregs, regm_t keepmask)
{
//printf("callclib(e = %p, clib = %d, pretregs = %s, keepmask = %s\n", e, clib, regm_str(pretregs), regm_str(keepmask));
//elem_print(e);
Symbol* s;
ClibInfo* cinfo;
getClibInfo(clib, &s, &cinfo, config.objfmt, config.exe);
getregs(cdb,(~s.Sregsaved & (cgstate.allregs | INSTR.FLOATREGS | mask(cgstate.BP)) & ~keepmask)); // mask of regs destroyed
keepmask &= ~s.Sregsaved;
int npushed = popcnt(keepmask);
CodeBuilder cdbpop;
cdbpop.ctor();
gensaverestore(keepmask, cdb, cdbpop);
makeitextern(s);
int nalign = 0;
if (STACKALIGN >= 16)
{ // Align the stack (assume no args on stack)
int npush = npushed * REGSIZE + cgstate.stackpush;
if (npush & (STACKALIGN - 1))
{ nalign = STACKALIGN - (npush & (STACKALIGN - 1));
cod3_stackadj(cdb, nalign);
}
}
cdb.gencs1(INSTR.branch_imm(1,0),0,FL.func,s); // CALL s
if (nalign)
cod3_stackadj(cdb, -nalign);
cgstate.calledafunc = 1;
cdb.append(cdbpop);
fixresult(cdb, e, cinfo.retregs, pretregs);
}
/*******************************
* Generate code sequence for function call.
*/

View file

@ -68,7 +68,7 @@ nothrow:
@trusted
void REGSAVE_save(ref REGSAVE regsave, ref CodeBuilder cdb, reg_t reg, out uint idx)
{
// TODO AArch64 floating point registers
assert(reg < 32); // TODO AArch64 floating point registers
if (!regsave.alignment)
regsave.alignment = REGSIZE;
idx = regsave.idx;
@ -96,7 +96,7 @@ void REGSAVE_save(ref REGSAVE regsave, ref CodeBuilder cdb, reg_t reg, out uint
@trusted
void REGSAVE_restore(const ref REGSAVE regsave, ref CodeBuilder cdb, reg_t reg, uint idx)
{
// TODO AArch64 floating point registers
assert(reg < 32); // TODO AArch64 floating point registers
// LDR reg,[BP, #idx]
code cs;
cs.reg = reg;

View file

@ -37,6 +37,7 @@ import dmd.backend.ty;
import dmd.backend.type;
import dmd.backend.x86.xmm;
import dmd.backend.arm.cod1;
import dmd.backend.arm.instr : INSTR;
import dmd.backend.cg : segfl, stackfl;
@ -349,7 +350,7 @@ uint gensaverestore(regm_t regm,ref CodeBuilder cdbsave,ref CodeBuilder cdbresto
if (cgstate.AArch64)
{
regm &= cgstate.allregs | mask(cgstate.BP);
regm &= cgstate.allregs | mask(cgstate.BP) | INSTR.FLOATREGS;
if (!regm)
return 0;
@ -2092,6 +2093,7 @@ void fixresult(ref CodeBuilder cdb, elem* e, regm_t retregs, ref regm_t outretre
* Extra information about each CLIB runtime library function.
*/
private
enum
{
INF32 = 1, /// if 32 bit only
@ -2102,6 +2104,7 @@ enum
INFpusheabcdx = 0x20, /// pass EAX/EBX/ECX/EDX on stack, callee does ret 16
}
private
struct ClibInfo
{
regm_t retregs16; /* registers that 16 bit result is returned in */
@ -2114,6 +2117,7 @@ struct ClibInfo
int clib_inited = false; // true if initialized
private
Symbol* symboly(string name, regm_t desregs)
{
Symbol* s = symbol_calloc(name);
@ -2125,6 +2129,7 @@ Symbol* symboly(string name, regm_t desregs)
return s;
}
private
void initClibInfo(ref Symbol*[CLIB.MAX] clibsyms, ref ClibInfo[CLIB.MAX] clibinfo)
{
for (size_t i = 0; i < CLIB.MAX; ++i)
@ -2139,6 +2144,7 @@ void initClibInfo(ref Symbol*[CLIB.MAX] clibsyms, ref ClibInfo[CLIB.MAX] clibinf
}
}
private
void getClibFunction(uint clib, ref Symbol* s, ref ClibInfo* cinfo, objfmt_t objfmt, exefmt_t exe)
{
const uint ex_unix = (EX_LINUX | EX_LINUX64 |
@ -2805,6 +2811,7 @@ void getClibFunction(uint clib, ref Symbol* s, ref ClibInfo* cinfo, objfmt_t obj
}
}
private
void getClibInfo(uint clib, Symbol** ps, ClibInfo** pinfo, objfmt_t objfmt, exefmt_t exe)
{
static Symbol*[CLIB.MAX] clibsyms;