Skip to content

Commit

Permalink
merge with D2
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Aug 3, 2012
1 parent e6d4b3b commit 9400bf4
Show file tree
Hide file tree
Showing 12 changed files with 1,078 additions and 955 deletions.
338 changes: 334 additions & 4 deletions src/backend/cgcod.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 1985-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// Copyright (C) 2000-2012 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
Expand Down Expand Up @@ -41,6 +41,14 @@ STATIC code * comsub(elem *,regm_t *);

bool floatreg; // !=0 if floating register is required

int hasframe; // !=0 if this function has a stack frame
targ_size_t spoff;
targ_size_t Foff; // BP offset of floating register
targ_size_t CSoff; // offset of common sub expressions
targ_size_t NDPoff; // offset of saved 8087 registers
int BPoff; // offset from BP
int EBPtoESP; // add to EBP offset to get ESP offset
int AAoff; // offset of alloca temporary
targ_size_t Aoffset; // offset of automatics and registers
targ_size_t Toffset; // offset of temporaries
targ_size_t EEoffset; // offset of SCstack variables from ESP
Expand Down Expand Up @@ -272,7 +280,7 @@ void codgen()
cstop--;

if (configv.addlinenumbers)
Obj::linnum(funcsym_p->Sfunc->Fstartline,Coffset);
objmod->linnum(funcsym_p->Sfunc->Fstartline,Coffset);

// Otherwise, jmp's to startblock will execute the prolog again
assert(!startblock->Bpred);
Expand Down Expand Up @@ -444,7 +452,7 @@ void codgen()
#endif
{ assert(!(config.flags & CFGromable));
//printf("framehandleroffset = x%x, coffset = x%x\n",framehandleroffset,coffset);
Obj::reftocodeseg(cseg,framehandleroffset,coffset);
objmod->reftocodeseg(cseg,framehandleroffset,coffset);
}
#endif

Expand Down Expand Up @@ -485,7 +493,7 @@ void codgen()
start of the last instruction
*/
/* Instead, try offset to cleanup code */
Obj::linnum(funcsym_p->Sfunc->Fendline,funcoffset + retoffset);
objmod->linnum(funcsym_p->Sfunc->Fendline,funcoffset + retoffset);

#if MARS
if (usednteh & NTEH_try)
Expand Down Expand Up @@ -548,6 +556,328 @@ void codgen()
#endif
}

/*******************************
* Generate code for a function start.
* Input:
* Coffset address of start of code
* Output:
* Coffset adjusted for size of code generated
* EBPtoESP
* hasframe
* BPoff
*/

code *prolog()
{
SYMIDX si;
bool enter;
unsigned Foffset;
unsigned xlocalsize; // amount to subtract from ESP to make room for locals
char guessneedframe;
regm_t namedargs = 0;

//printf("cod3.prolog(), needframe = %d, Aalign = %d\n", needframe, Aalign);
debugx(debugw && printf("funcstart()\n"));
regcon.immed.mval = 0; /* no values in registers yet */
EBPtoESP = -REGSIZE;
hasframe = 0;
bool pushds = false;
BPoff = 0;
code *c = CNIL;
bool pushalloc = false;
tym_t tyf = funcsym_p->ty();
tym_t tym = tybasic(tyf);
unsigned farfunc = tyfarfunc(tym);
if (config.flags & CFGalwaysframe || funcsym_p->Sfunc->Fflags3 & Ffakeeh)
needframe = 1;

Lagain:
spoff = 0;
guessneedframe = needframe;
// if (needframe && config.exe & (EX_LINUX | EX_FREEBSD | EX_SOLARIS) && !(usednteh & ~NTEHjmonitor))
// usednteh |= NTEHpassthru;

/* Compute BP offsets for variables on stack.
* The organization is:
* Poff parameters
* seg of return addr (if far function)
* IP of return addr
* BP-> caller's BP
* DS (if Windows prolog/epilog)
* exception handling context symbol
* Aoff autos and regs
* regsave.off any saved registers
* Foff floating register
* AAoff alloca temporary
* CSoff common subs
* NDPoff any 8087 saved registers
* Toff temporaries
* monitor context record
* any saved registers
*/

if (tym == TYifunc)
Poff = 26; // how is this number derived?
else
Poff = (farfunc ? 3 : 2) * REGSIZE;

Aoff = 0;
#if NTEXCEPTIONS == 2
Aoff -= nteh_contextsym_size();
#if MARS
if (funcsym_p->Sfunc->Fflags3 & Ffakeeh && nteh_contextsym_size() == 0)
Aoff -= 5 * 4;
#endif
#endif
Aoff = -align(0,-Aoff + Aoffset);

regsave.off = Aoff - align(0,regsave.top);
Foffset = floatreg ? (config.fpxmmregs ? 16 : DOUBLESIZE) : 0;
Foff = regsave.off - align(0,Foffset);
assert(usedalloca != 1);
AAoff = usedalloca ? (Foff - REGSIZE) : Foff;
CSoff = AAoff - align(0,cstop * REGSIZE);
#if TX86
NDPoff = CSoff - align(0,NDP::savetop * NDPSAVESIZE);
#else
NDPoff = CSoff;
#endif
Toff = NDPoff - align(0,Toffset);

if (Foffset > Aalign)
Aalign = Foffset;
if (Aalign > REGSIZE)
{
// Adjust Aoff so that it is Aalign byte aligned, assuming that
// before function parameters were pushed the stack was
// Aalign byte aligned
targ_size_t psize = (Poffset + (REGSIZE - 1)) & ~(REGSIZE - 1);
int sz = psize + -Aoff + Poff + (needframe ? 0 : REGSIZE);
if (sz & (Aalign - 1))
{ int adj = Aalign - (sz & (Aalign - 1));
Aoff -= adj;
regsave.off -= adj;
Foff -= adj;
AAoff -= adj;
CSoff -= adj;
NDPoff -= adj;
Toff -= adj;
}
}

localsize = -Toff;

regm_t topush = fregsaved & ~mfuncreg; // mask of registers that need saving
int npush = 0; // number of registers that need saving
for (regm_t x = topush; x; x >>= 1)
npush += x & 1;

// Keep the stack aligned by 8 for any subsequent function calls
if (!I16 && calledafunc &&
(STACKALIGN == 16 || config.flags4 & CFG4stackalign))
{
//printf("npush = %d Poff = x%x needframe = %d localsize = x%x\n",
// npush, Poff, needframe, localsize);

int sz = Poff + (needframe ? 0 : -REGSIZE) + localsize + npush * REGSIZE;
if (STACKALIGN == 16)
{
if (sz & (8|4))
localsize += STACKALIGN - (sz & (8|4));
}
else if (sz & 4)
localsize += 4;
}

//printf("Foff x%02x Aoff x%02x Toff x%02x NDPoff x%02x CSoff x%02x Poff x%02x localsize x%02x\n",
//(int)Foff,(int)Aoff,(int)Toff,(int)NDPoff,(int)CSoff,(int)Poff,(int)localsize);

xlocalsize = localsize;

if (tyf & mTYnaked) // if no prolog/epilog for function
{
hasframe = 1;
return NULL;
}

if (tym == TYifunc)
{
c = cat(c, prolog_ifunc(&tyf));
hasframe = 1;
goto Lcont;
}

/* Determine if we need BP set up */
if (config.flags & CFGalwaysframe)
needframe = 1;
else
{
if (localsize)
{
if (I16 ||
!(config.flags4 & CFG4speed) ||
config.target_cpu < TARGET_Pentium ||
farfunc ||
config.flags & CFGstack ||
xlocalsize >= 0x1000 ||
(usednteh & ~NTEHjmonitor) ||
anyiasm ||
usedalloca
)
needframe = 1;
}
if (refparam && (anyiasm || I16))
needframe = 1;
}

if (needframe)
{ assert(mfuncreg & mBP); // shouldn't have used mBP

if (!guessneedframe) // if guessed wrong
goto Lagain;
}

if (I16 && config.wflags & WFwindows && farfunc)
{
c = cat(c, prolog_16bit_windows_farfunc(&tyf, &pushds));
enter = false; /* don't use ENTER instruction */
hasframe = 1; /* we have a stack frame */
}
else if (needframe) // if variables or parameters
{
c = cat(c, prolog_frame(farfunc, &xlocalsize, &enter));
hasframe = 1;
}

if (config.flags & CFGstack) /* if stack overflow check */
goto Ladjstack;

if (needframe) /* if variables or parameters */
{
if (xlocalsize) /* if any stack offset */
{
Ladjstack:
c = cat(c, prolog_frameadj(tyf, xlocalsize, enter, &pushalloc));

if (usedalloca)
c = cat(c, prolog_setupalloca());
}
else
assert(usedalloca == 0);
}
else if (xlocalsize)
{
assert(I32);
c = cat(c, prolog_frameadj2(tyf, xlocalsize, &pushalloc));
BPoff += REGSIZE;
}
else
assert((localsize | usedalloca) == 0 || (usednteh & NTEHjmonitor));
EBPtoESP += xlocalsize;

/* The idea is to generate trace for all functions if -Nc is not thrown.
* If -Nc is thrown, generate trace only for global COMDATs, because those
* are relevant to the FUNCTIONS statement in the linker .DEF file.
* This same logic should be in epilog().
*/
if (config.flags & CFGtrace &&
(!(config.flags4 & CFG4allcomdat) ||
funcsym_p->Sclass == SCcomdat ||
funcsym_p->Sclass == SCglobal ||
(config.flags2 & CFG2comdat && SymInline(funcsym_p))
)
)
{
unsigned spalign = 0;
int sz = Poff + (needframe ? 0 : -REGSIZE) + localsize;
if (STACKALIGN == 16 && (sz & (STACKALIGN - 1)))
spalign = STACKALIGN - (sz & (STACKALIGN - 1));

if (spalign)
{ /* This could be avoided by moving the function call to after the
* registers are saved. But I don't remember why the call is here
* and not there.
*/
c = cod3_stackadj(c, spalign);
}

unsigned regsaved;
c = cat(c, prolog_trace(farfunc, &regsaved));

if (spalign)
c = cod3_stackadj(c, -spalign);
useregs((ALLREGS | mBP | mES) & ~regsaved);
}

#if MARS
if (usednteh & NTEHjmonitor)
{ Symbol *sthis;

for (si = 0; 1; si++)
{ assert(si < globsym.top);
sthis = globsym.tab[si];
if (strcmp(sthis->Sident,"this") == 0)
break;
}
c = cat(c,nteh_monitor_prolog(sthis));
EBPtoESP += 3 * 4;
}
#endif

while (topush) /* while registers to push */
{ unsigned reg = findreg(topush);
topush &= ~mask[reg];
c = genpush(c, reg);
EBPtoESP += REGSIZE;
spoff += REGSIZE;
#if ELFOBJ || MACHOBJ
if (config.fulltypes)
{ // Emit debug_frame data giving location of saved register
// relative to 0[EBP]
pinholeopt(c, NULL);
dwarf_CFA_set_loc(calcblksize(c)); // address after PUSH reg
dwarf_CFA_offset(reg, -EBPtoESP - REGSIZE);
}
#endif
}

Lcont:

c = cat(c, prolog_ifunc2(tyf, tym, pushds));

#if NTEXCEPTIONS == 2
if (usednteh & NTEH_except)
c = cat(c,nteh_setsp(0x89)); // MOV __context[EBP].esp,ESP
#endif

// Load register parameters off of the stack. Do not use
// assignaddr(), as it will replace the stack reference with
// the register!
c = cat(c, prolog_loadparams(tyf, pushalloc, &namedargs));

/* Load arguments passed in registers into the varargs save area
* so they can be accessed by va_arg().
*/
if (I64 && variadic(funcsym_p->Stype))
{
/* Look for __va_argsave
*/
symbol *sv = NULL;
for (SYMIDX si = 0; si < globsym.top; si++)
{ symbol *s = globsym.tab[si];
if (s->Sident[0] == '_' && strcmp(s->Sident, "__va_argsave") == 0)
{ sv = s;
break;
}
}

if (sv && !(sv->Sflags & SFLdead))
c = cat(c, prolog_genvarargs(sv, &namedargs));
}

return c;
}


/******************************
* Compute offsets for remaining tmp, automatic and register variables
Expand Down
Loading

0 comments on commit 9400bf4

Please sign in to comment.