189 changes: 152 additions & 37 deletions src/backend/cod4.c
Original file line number Diff line number Diff line change
Expand Up @@ -2375,11 +2375,14 @@ code *cdcmp(elem *e,regm_t *pretregs)
cg = gen2(cg,0x0F90 + (jop & 0x0F),modregrmx(3,0,reg)); // SETcc reg
if (I64 && reg >= 4)
code_orrex(cg,REX);
genregs(cg,0x0FB6,reg,reg); // MOVZX reg,reg
if (I64 && sz == 8)
code_orrex(cg,REX_W);
if (I64 && reg >= 4)
code_orrex(cg,REX);
if (tysize(e->Ety) > 1)
{
genregs(cg,0x0FB6,reg,reg); // MOVZX reg,reg
if (I64 && sz == 8)
code_orrex(cg,REX_W);
if (I64 && reg >= 4)
code_orrex(cg,REX);
}
*pretregs &= ~mPSW;
c = cat3(c,cg,fixresult(e,resregs,pretregs));
}
Expand Down Expand Up @@ -3481,27 +3484,40 @@ code *cdbtst(elem *e, regm_t *pretregs)

if ((retregs = (*pretregs & (ALLREGS | mBP))) != 0) // if return result in register
{
code *nop = CNIL;
regm_t save = regcon.immed.mval;
code *cg = allocreg(&retregs,&reg,TYint);
regcon.immed.mval = save;
if ((*pretregs & mPSW) == 0)
if (tysize(e->Ety) == 1)
{
cg = cat(cg,getregs(retregs));
cg = genregs(cg,0x19,reg,reg); // SBB reg,reg
cg = gen2(cg,0xF7,modregrmx(3,3,reg)); // NEG reg
assert(I64 || retregs & BYTEREGS);
code *cg = allocreg(&retregs,&reg,TYint);
cg = gen2(cg,0x0F92,modregrmx(3,0,reg)); // SETC reg
if (I64 && reg >= 4)
code_orrex(cg, REX);
*pretregs = retregs;
c2 = cat(c2,cg);
}
else
{
cg = movregconst(cg,reg,1,8); // MOV reg,1
nop = gennop(nop);
cg = genjmp(cg,JC,FLcode,(block *) nop); // Jtrue nop
// MOV reg,0
movregconst(cg,reg,0,8);
regcon.immed.mval &= ~mask[reg];
code *nop = CNIL;
regm_t save = regcon.immed.mval;
code *cg = allocreg(&retregs,&reg,TYint);
regcon.immed.mval = save;
if ((*pretregs & mPSW) == 0)
{
cg = cat(cg,getregs(retregs));
cg = genregs(cg,0x19,reg,reg); // SBB reg,reg
cg = gen2(cg,0xF7,modregrmx(3,3,reg)); // NEG reg
}
else
{
cg = movregconst(cg,reg,1,8); // MOV reg,1
nop = gennop(nop);
cg = genjmp(cg,JC,FLcode,(block *) nop); // Jtrue nop
// MOV reg,0
movregconst(cg,reg,0,8);
regcon.immed.mval &= ~mask[reg];
}
*pretregs = retregs;
c2 = cat3(c2,cg,nop);
}
*pretregs = retregs;
c2 = cat3(c2,cg,nop);
}

return cat(c,c2);
Expand All @@ -3513,6 +3529,8 @@ code *cdbtst(elem *e, regm_t *pretregs)

code *cdbt(elem *e, regm_t *pretregs)
{
//printf("cdbt(%p, %s)\n", e, regm_str(*pretregs));

elem *e1;
elem *e2;
code *c;
Expand Down Expand Up @@ -3588,27 +3606,40 @@ code *cdbt(elem *e, regm_t *pretregs)

if ((retregs = (*pretregs & (ALLREGS | mBP))) != 0) // if return result in register
{
code *nop = CNIL;
regm_t save = regcon.immed.mval;
code *cg = allocreg(&retregs,&reg,TYint);
regcon.immed.mval = save;
if ((*pretregs & mPSW) == 0)
if (tysize[e->Ety] == 1)
{
cg = cat(cg,getregs(retregs));
cg = genregs(cg,0x19,reg,reg); // SBB reg,reg
cg = gen2(cg,0xF7,modregrmx(3,3,reg)); // NEG reg
assert(I64 || retregs & BYTEREGS);
code *cg = allocreg(&retregs,&reg,TYint);
cg = gen2(cg,0x0F92,modregrmx(3,0,reg)); // SETC reg
if (I64 && reg >= 4)
code_orrex(cg, REX);
*pretregs = retregs;
c2 = cat(c2,cg);
}
else
{
cg = movregconst(cg,reg,1,8); // MOV reg,1
nop = gennop(nop);
cg = genjmp(cg,JC,FLcode,(block *) nop); // Jtrue nop
// MOV reg,0
movregconst(cg,reg,0,8);
regcon.immed.mval &= ~mask[reg];
code *nop = CNIL;
regm_t save = regcon.immed.mval;
code *cg = allocreg(&retregs,&reg,TYint);
regcon.immed.mval = save;
if ((*pretregs & mPSW) == 0)
{
cg = cat(cg,getregs(retregs));
cg = genregs(cg,0x19,reg,reg); // SBB reg,reg
cg = gen2(cg,0xF7,modregrmx(3,3,reg)); // NEG reg
}
else
{
cg = movregconst(cg,reg,1,8); // MOV reg,1
nop = gennop(nop);
cg = genjmp(cg,JC,FLcode,(block *) nop); // Jtrue nop
// MOV reg,0
movregconst(cg,reg,0,8);
regcon.immed.mval &= ~mask[reg];
}
*pretregs = retregs;
c2 = cat3(c2,cg,nop);
}
*pretregs = retregs;
c2 = cat3(c2,cg,nop);
}

return cat(c,c2);
Expand Down Expand Up @@ -3769,4 +3800,88 @@ code *cdpair(elem *e, regm_t *pretregs)
return cat4(c1,c2,cg,fixresult(e,regs1 | regs2,pretregs));
}

/*************************
* Generate code for OPcmpxchg
*/

code *cdcmpxchg(elem *e, regm_t *pretregs)
{
/* The form is:
* OPcmpxchg
* / \
* lvalue OPparam
* / \
* old new
*/
code *cr1,*cr,*cl,*c,cs;

//printf("cdmulass(e=%p, *pretregs = %s)\n",e,regm_str(*pretregs));
elem *e1 = e->E1;
elem *e2 = e->E2;
assert(e2->Eoper == OPparam);
assert(!e2->Ecount);

tym_t tyml = tybasic(e1->Ety); // type of lvalue
unsigned sz = tysize[tyml];

if (I32 && sz == 8)
{
regm_t retregs = mDX|mAX;
cr1 = codelem(e2->E1,&retregs,FALSE); // [DX,AX] = e2->E1

retregs = mCX|mBX;
cr = scodelem(e2->E2,&retregs,mDX|mAX,FALSE); // [CX,BX] = e2->E2
cl = getlvalue(&cs,e1,mCX|mBX|mAX|mDX); // get EA
cs.Iop = 0x0FC7; // CMPXCHG8B EA
cs.Iflags |= CFpsw;
code_newreg(&cs,1);
c = getregs(mDX|mAX); // CMPXCHG destroys these regs
if (e1->Ety & mTYvolatile)
c = gen1(c,LOCK); // LOCK prefix
c = gen(c,&cs);
assert(!e1->Ecount);
freenode(e1);
}
else
{
unsigned byte = (sz == 1); // 1 for byte operation
unsigned char word = (!I16 && sz == SHORTSIZE) ? CFopsize : 0;
unsigned rex = (I64 && sz == 8) ? REX_W : 0;

regm_t retregs = mAX;
cr1 = codelem(e2->E1,&retregs,FALSE); // AX = e2->E1

retregs = (ALLREGS | mBP) & ~mAX;
cr = scodelem(e2->E2,&retregs,mAX,FALSE); // load rvalue in reg
cl = getlvalue(&cs,e1,mAX | retregs); // get EA
cs.Iop = 0x0FB1 ^ byte; // CMPXCHG EA,reg
cs.Iflags |= CFpsw | word;
cs.Irex |= rex;
unsigned reg = findreg(retregs);
code_newreg(&cs,reg);
c = getregs(mAX); // CMPXCHG destroys AX
if (e1->Ety & mTYvolatile)
c = gen1(c,LOCK); // LOCK prefix
c = gen(c,&cs);
assert(!e1->Ecount);
freenode(e1);
}

regm_t retregs;
if ((retregs = (*pretregs & (ALLREGS | mBP))) != 0) // if return result in register
{
assert(tysize(e->Ety) == 1);
assert(I64 || retregs & BYTEREGS);
unsigned reg;
code *cg = allocreg(&retregs,&reg,TYint);
cg = gen2(cg,0x0F94,modregrmx(3,0,reg)); // SETZ reg
if (I64 && reg >= 4)
code_orrex(cg, REX);
*pretregs = retregs;
c = cat(c,cg);
}

return cat4(cr1,cr,cl,c);
}

#endif // !SPP
1 change: 1 addition & 0 deletions src/backend/code_x86.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ extern regm_t BYTEREGS;
#define LOOP 0xE2
#define LES 0xC4
#define LEA 0x8D
#define LOCK 0xF0

#define JO 0x70
#define JNO 0x71
Expand Down
7 changes: 7 additions & 0 deletions src/backend/dt.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,13 @@ dt_t ** dtxoff(dt_t **pdtend,symbol *s,unsigned offset,tym_t ty)
return pdtend;
}

/*********************************
*/
void dtpatchoffset(dt_t *dt, unsigned offset)
{
dt->DToffset = offset;
}

/*************************************
* Create a reference to another dt.
*/
Expand Down
1 change: 1 addition & 0 deletions src/backend/dt.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dt_t **dtdtoff(dt_t **pdtend, dt_t *dt, unsigned offset);
dt_t **dtcoff(dt_t **pdtend,unsigned offset);
dt_t ** dtcat(dt_t **pdtend,dt_t *dt);
dt_t ** dtrepeat(dt_t **pdtend, dt_t *dt, size_t count);
void dtpatchoffset(dt_t *dt, unsigned offset);
void dt_optimize(dt_t *dt);
void dtsymsize(Symbol *);
void init_common(Symbol *);
Expand Down
3 changes: 1 addition & 2 deletions src/backend/elfobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -2441,8 +2441,7 @@ unsigned Obj::bytes(int seg, targ_size_t offset, unsigned nbytes, void *p)
int save = buf->size();
//dbg_printf("Obj::bytes(seg=%d, offset=x%lx, nbytes=%d, p=x%x)\n",
//seg,offset,nbytes,p);
buf->setsize(offset);
buf->reserve(nbytes);
buf->position(offset, nbytes);
if (p)
{
buf->writen(p,nbytes);
Expand Down
2 changes: 0 additions & 2 deletions src/backend/evalu8.c
Original file line number Diff line number Diff line change
Expand Up @@ -546,10 +546,8 @@ elem *poptelem(elem *e)
if (e2->Eoper == OPconst)
{ targ_int i = e2->EV.Vint;

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
if (i && e1->EV.sp.Vsym->Sfl == FLgot)
break;
#endif
if (e->Eoper == OPmin)
i = -i;
e1->EV.sp.Voffset += i;
Expand Down
2 changes: 2 additions & 0 deletions src/backend/glocal.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ STATIC void local_exp(elem *e,int goal)
case OPandass:
case OPxorass:
case OPorass:
case OPcmpxchg:
if (ERTOL(e))
{ local_exp(e->E2,1);
case OPnegass:
Expand Down Expand Up @@ -553,6 +554,7 @@ STATIC int local_getflags(elem *e,symbol *s)
case OPandass:
case OPxorass:
case OPorass:
case OPcmpxchg:
if (e->E1->Eoper == OPvar)
{ symbol *s1;

Expand Down
4 changes: 3 additions & 1 deletion src/backend/gloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,7 @@ STATIC void markinvar(elem *n,vec_t rd)
case OPpostinc: case OPpostdec:
case OPcall:
case OPvecsto:
case OPcmpxchg:
markinvar(n->E2,rd);
case OPnegass:
n1 = n->E1;
Expand Down Expand Up @@ -1492,7 +1493,8 @@ STATIC void movelis(elem *n,block *b,loop *l,int *pdomexit)
// first block of the function. Unfortunately, the rd vector
// does not take this into account. Therefore, we assume the
// worst and reject assignments to function parameters.
if (v->Sclass == SCparameter || v->Sclass == SCregpar || v->Sclass == SCfastpar)
if (v->Sclass == SCparameter || v->Sclass == SCregpar ||
v->Sclass == SCfastpar || v->Sclass == SCshadowreg)
goto L3;

if (el_sideeffect(n->E2)) goto L3; // case 5
Expand Down
14 changes: 10 additions & 4 deletions src/backend/gother.c
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ STATIC void cpwalk(elem *n,vec_t IN)
elem *foundelem = NULL;
tym_t ty;

//dbg_printf("Checking copyprop for '%s', ty=x%x\n",v->Sident,n->Ety);
//printf("Checking copyprop for '%s', ty=x%x\n",v->Sident,n->Ety);
symbol_debug(v);
ty = n->Ety;
unsigned sz = tysize(n->Ety);
Expand All @@ -1052,13 +1052,13 @@ STATIC void cpwalk(elem *n,vec_t IN)
csz = type_size(c->ET);
assert((int)csz >= 0);

//dbg_printf("looking at: ("); WReqn(c); dbg_printf("), ty=x%x\n",c->E1->Ety);
//printf("looking at: ("); WReqn(c); dbg_printf("), ty=x%x\n",c->E1->Ety);
/* Not only must symbol numbers match, but */
/* offsets too (in case of arrays) and sizes */
/* (in case of unions). */
if (v == c->E1->EV.sp.Vsym &&
n->EV.sp.Voffset == c->E1->EV.sp.Voffset &&
sz <= csz)
n->EV.sp.Voffset >= c->E1->EV.sp.Voffset &&
n->EV.sp.Voffset + sz <= c->E1->EV.sp.Voffset + csz)
{ if (foundelem)
{ if (c->E2->EV.sp.Vsym != f)
goto noprop;
Expand All @@ -1080,9 +1080,11 @@ STATIC void cpwalk(elem *n,vec_t IN)
}
#endif
type *nt = n->ET;
targ_size_t noffset = n->EV.sp.Voffset;
el_copy(n,foundelem->E2);
n->Ety = ty; // retain original type
n->ET = nt;
n->EV.sp.Voffset += noffset - foundelem->E1->EV.sp.Voffset;

/* original => rewrite
* v = f
Expand Down Expand Up @@ -1245,6 +1247,10 @@ void elimass(elem *n)
case OPbts:
n->Eoper = OPbt;
break;
case OPcmpxchg:
n->Eoper = OPcomma;
n->E2->Eoper = OPcomma;
break;
default:
assert(0);
}
Expand Down
5 changes: 2 additions & 3 deletions src/backend/machobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -2285,8 +2285,7 @@ if (!buf) halt();
int save = buf->size();
//dbg_printf("Obj::bytes(seg=%d, offset=x%lx, nbytes=%d, p=x%x)\n",
//seg,offset,nbytes,p);
buf->setsize(offset);
buf->reserve(nbytes);
buf->position(offset, nbytes);
if (p)
{
buf->writen(p,nbytes);
Expand Down Expand Up @@ -2574,7 +2573,7 @@ int Obj::reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val,

Outbuffer *buf = SegData[seg]->SDbuf;
int save = buf->size();
buf->setsize(offset);
buf->position(offset, retsize);
//printf("offset = x%llx, val = x%llx\n", offset, val);
if (retsize == 8)
buf->write64(val);
Expand Down
4 changes: 2 additions & 2 deletions src/backend/newman.c
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ STATIC void cpp_dimension(targ_ullong u)
CHAR('0' + (char)u - 1);
else
{ char buffer[sizeof(u) * 2 + 1];
char __ss *p;
char *p;

buffer[sizeof(buffer) - 1] = 0;
for (p = &buffer[sizeof(buffer) - 1]; u; u >>= 4)
Expand All @@ -812,7 +812,7 @@ STATIC void cpp_dimension_ld(targ_ldouble ld)
CHAR('0' + (char)u - 1);
else
{ char buffer[sizeof(u) * 2 + 1];
char __ss *p;
char *p;

buffer[sizeof(buffer) - 1] = 0;
for (p = &buffer[sizeof(buffer) - 1]; u; u >>= 4)
Expand Down
1 change: 1 addition & 0 deletions src/backend/oper.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ enum OPER
OPscale, // ldexp
OPyl2x, // y * log2(x)
OPyl2xp1, // y * log2(x + 1)
OPcmpxchg, // cmpxchg
#endif
OPstrlen, /* strlen() */
OPstrcpy, /* strcpy() */
Expand Down
37 changes: 23 additions & 14 deletions src/backend/outbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#if DEBUG
static char __file__[] = __FILE__; // for tassert.h
#include "tassert.h"
#else
#include <assert.h>
#endif

Outbuffer::Outbuffer()
Expand Down Expand Up @@ -107,23 +109,25 @@ void Outbuffer::enlarge(size_t nbytes)
p = buf + used;
}

// Position buffer for output at a specified location and size.
// If data will extend buffer size, reserve space
// If data will rewrite existing data
// position for write and return previous buffer size
//
// If data will append to buffer
// position for write and return new size
size_t Outbuffer::position(size_t pos, size_t nbytes)
/*****************************************
* Position buffer for output at a specified location and size.
* Params:
* offset = specified location
* nbytes = number of bytes to be written at offset
*/
void Outbuffer::position(size_t offset, size_t nbytes)
{
size_t current_sz = size();
unsigned char *fend = buf+pos+nbytes; // future end of buffer
if (fend >= pend)
if (offset + nbytes > len)
{
reserve (fend - pend);
enlarge(offset + nbytes - (p - buf));
}
setsize(pos);
return pos+nbytes > current_sz ? pos+nbytes : current_sz;
p = buf + offset;
#if DEBUG
assert(buf <= p);
assert(p <= pend);
assert(len == pend - buf);
assert(p + nbytes <= pend);
#endif
}

// Write an array to the buffer.
Expand Down Expand Up @@ -264,6 +268,11 @@ char *Outbuffer::toString()
void Outbuffer::setsize(size_t size)
{
p = buf + size;
#if DEBUG
assert(buf <= p);
assert(p <= pend);
assert(len == pend - buf);
#endif
}

void Outbuffer::writesLEB128(int value)
Expand Down
2 changes: 1 addition & 1 deletion src/backend/outbuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct Outbuffer
void *writezeros(size_t n);

// Position buffer to accept the specified number of bytes at offset
size_t position(size_t offset, size_t nbytes);
void position(size_t offset, size_t nbytes);

// Write an array to the buffer, no reserve check
void writen(const void *b, size_t len)
Expand Down
7 changes: 1 addition & 6 deletions src/backend/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,6 @@ struct BLKLST
#endif
Srcpos BLsrcpos; /* BLfile, position in that file */
int BLsearchpath; // BLfile: remaining search path for #include_next
#if SOURCE_OFFSETS
long BLfoffset; /* BLfile, offset into file */
short BLcurcnt; /* BLfile, current count from offset */
short BLlincnt; /* BLfile, start of cur line from offset*/
#endif

void print();
};
Expand Down Expand Up @@ -533,7 +528,7 @@ type *stunspec(enum_TK tk, Symbol *s, Symbol *stempsym, param_t *template_argume
Classsym * n2_definestruct(char *struct_tag,unsigned flags,tym_t ptrtype,
symbol *stempsym,param_t *template_argument_list,int nestdecl);
void n2_classfriends(Classsym *stag);
int n2_isstruct(symbol * __ss *ps);
int n2_isstruct(symbol **ps);
void n2_addfunctoclass(Classsym *,Funcsym *,int flags);
void n2_chkexist(Classsym *stag, char *name);
void n2_addmember(Classsym *stag,symbol *smember);
Expand Down
5 changes: 4 additions & 1 deletion src/backend/type.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ type *type_dyn_array(type *tnext)
* Tcount already incremented
*/

type *type_static_array(unsigned long long dim, type *tnext)
type *type_static_array(targ_size_t dim, type *tnext)
{
type *t = type_allocn(TYarray, tnext);
t->Tdim = dim;
Expand Down Expand Up @@ -435,6 +435,8 @@ type *type_delegate(type *tnext)
* Returns:
* Tcount already incremented
*/
extern "C" // because of size_t on OSX 32
{
type *type_function(tym_t tyf, type **ptypes, size_t nparams, bool variadic, type *tret)
{
param_t *paramtypes = NULL;
Expand All @@ -450,6 +452,7 @@ type *type_function(tym_t tyf, type **ptypes, size_t nparams, bool variadic, typ
t->Tcount++;
return t;
}
}

/***************************************
* Create an enum type.
Expand Down
4 changes: 2 additions & 2 deletions src/backend/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,10 @@ int typematch(type *t1, type *t2, int relax);

type *type_pointer(type *tnext);
type *type_dyn_array(type *tnext);
type *type_static_array(unsigned long long dim, type *tnext);
extern "C" type *type_static_array(targ_size_t dim, type *tnext);
type *type_assoc_array(type *tkey, type *tvalue);
type *type_delegate(type *tnext);
type *type_function(tym_t tyf, type **ptypes, size_t nparams, bool variadic, type *tret);
extern "C" type *type_function(tym_t tyf, type **ptypes, size_t nparams, bool variadic, type *tret);
type *type_enum(const char *name, type *tbase);
type *type_struct_class(const char *name, unsigned alignsize, unsigned structsize,
type *arg1type, type *arg2type, bool isUnion, bool isClass, bool isPOD);
Expand Down
4 changes: 0 additions & 4 deletions src/backend/var.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@
#include "optab.c"
#include "tytab.c"

#if __DMC__ && _MSDOS
unsigned __cdecl _stack = 100000; // set default stack size
#endif

/* Global flags:
*/

Expand Down