Rev 6 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* Copyright (c) 2002-2005 The TenDRA Project <http://www.tendra.org/>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of The TenDRA Project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific, prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/
/*
Crown Copyright (c) 1997
This TenDRA(r) Computer Program is subject to Copyright
owned by the United Kingdom Secretary of State for Defence
acting through the Defence Evaluation and Research Agency
(DERA). It is made available to Recipients with a
royalty-free licence for its use, reproduction, transfer
to other parties and amendment for any purpose not excluding
product development provided that any such use et cetera
shall be deemed to be acceptance of the following conditions:-
(1) Its Recipients shall ensure that this Notice is
reproduced upon any copies or amended versions of it;
(2) Any amended version of it shall be clearly marked to
show both the nature of and the organisation responsible
for the relevant amendment or amendments;
(3) Its onward transfer from a recipient to another
party shall be deemed to be that party's acceptance of
these conditions;
(4) DERA gives no warranty or assurance as to its
quality or suitability for any purpose and DERA accepts
no liability whatsoever in relation to any use to which
it may be put.
*/
/* 80x86/instr.c */
/**********************************************************************
$Author: pwe $
$Date: 1998/03/15 16:00:19 $
$Revision: 1.2 $
$Log: instr.c,v $
* Revision 1.2 1998/03/15 16:00:19 pwe
* regtrack dwarf dagnostics added
*
* Revision 1.1.1.1 1998/01/17 15:55:51 release
* First version to be checked into rolling release.
*
* Revision 1.28 1997/04/17 11:55:47 pwe
* dwarf2 improvements
*
* Revision 1.27 1997/03/24 11:15:13 pwe
* dwarf2 option/default
*
* Revision 1.26 1997/03/20 16:23:41 pwe
* dwarf2
*
* Revision 1.25 1997/02/18 11:42:52 pwe
* NEWDIAGS for debugging optimised code
*
* Revision 1.24 1996/12/13 14:39:27 pwe
* prep NEWDIAGS
*
* Revision 1.23 1996/07/09 09:43:39 pwe
* caller env_offset if callees present, and tidy
*
* Revision 1.22 1996/05/20 14:30:11 pwe
* improved 64-bit handling
*
* Revision 1.21 1996/05/13 12:51:55 pwe
* undo premature commit
*
* Revision 1.19 1996/01/17 11:24:31 pwe
* resurrect performance
*
* Revision 1.18 1995/11/01 18:41:14 pwe
* PIC tail_call and exception handling
*
* Revision 1.17 1995/10/24 17:02:43 pwe
* local calls to avoid PLT, Solaris constraint
*
* Revision 1.16 1995/10/16 14:55:19 pwe
* stack change v fpucon
*
* Revision 1.15 1995/09/26 16:46:48 pwe
* compare with zero to ignore previous overflow
*
* Revision 1.14 1995/09/15 17:39:13 pwe
* tidy and correct fistp
*
* Revision 1.13 1995/09/08 12:51:07 pwe
* exceptions improved
*
* Revision 1.12 1995/09/06 16:29:20 pwe
* exceptions now OK
*
* Revision 1.11 1995/09/05 16:24:51 pwe
* specials and exception changes
*
* Revision 1.10 1995/09/01 17:30:05 pwe
* traps and Build scripts
*
* Revision 1.9 1995/08/30 16:06:33 pwe
* prepare exception trapping
*
* Revision 1.8 1995/08/23 09:42:42 pwe
* track fpu control word for trap etc
*
* Revision 1.7 1995/08/14 13:53:36 pwe
* several corrections, tail calls and error jumps
*
* Revision 1.6 1995/08/04 08:29:23 pwe
* 4.0 general procs implemented
*
* Revision 1.5 1995/04/12 17:05:54 pwe
* name_prefix required for call_libfn
*
* Revision 1.4 1995/02/16 18:47:08 pwe
* transformed subtract inverts, sets and adds carry in case of error_jump
*
* Revision 1.3 1995/01/30 12:56:18 pwe
* Ownership -> PWE, tidy banners
*
* Revision 1.2 1994/11/08 09:55:03 jmf
* Unknown?
*
* Revision 1.1 1994/10/27 14:15:22 jmf
* Initial revision
*
* Revision 1.4 1994/08/08 15:54:29 jmf
* Dont keep_short after label
*
* Revision 1.3 1994/07/15 13:59:23 jmf
* Change fstack popping to use fstp st(0).
*
* Revision 1.2 1994/07/12 15:19:18 jmf
* No change
*
* Revision 1.1 1994/07/12 14:33:55 jmf
* Initial revision
*
**********************************************************************/
/**********************************************************************
instr.c
defines the general routines for outputting instructions and labels:
**********************************************************************/
#include "config.h"
#include "common_types.h"
#include "out.h"
#include "operand.h"
#include "instrmacs.h"
#include "expmacs.h"
#include "exp.h"
#include "instr386.h"
#include "flags.h"
#include "tags.h"
#include "shapemacs.h"
#include "flpt.h"
#include "flpttypes.h"
#include "coder.h"
#include "basicread.h"
#include "reg_record.h"
#include "installglob.h"
#include "table_fns.h"
#include "codermacs.h"
#include "install_fns.h"
#include "machine.h"
#include "localflags.h"
#include "assembler.h"
#include "messages_8.h"
#include "readglob.h"
#include "check.h"
#include "label_ops.h"
#include "externs.h"
#include "xalloc.h"
#include "instr.h"
#ifdef NEWDWARF
#include "dw2_config.h"
#include "dw2_extra.h"
#endif
/* LOCAL TYPE */
typedef union eu_u {int i; exp e;} punner;
/* MACROS */
#define fstack_base 8
/* VARIABLES */
/* All variables initialised */
int extra_stack = 0; /* init by init_all */
int max_extra_stack = 0; /* init by cproc */
int no_frame; /* init by cproc */
#ifndef NEWDIAGS
static long last_jump_pos; /* set locally */
#endif
int last_jump_label; /* cleared to -1 by outnl */
static exp cont_err_handler = nilexp;
/* IDENTITIES */
char *margin = " "; /* instruction left margin */
char *spx = " "; /* separates instruction from operands */
char *sep = ","; /* separates operands */
char *reg_name_long[8] = {
"%eax", "%edx", "%ecx", "%ebx", "%edi", "%esi", "%ebp", "%esp"
};
char *reg_name_word[7] = {
"%ax", "%dx", "%cx", "%bx", "%di", "%si", "%bp"
};
char *reg_name_byte[7] = {
"%al", "%dl", "%cl", "%bl", "%??", "%??", "%??"
};
char *fl_reg_name[8] = {
"%st", "%st(1)", "%st(2)", "%st(3)", "%st(4)", "%st(5)", "%st(6)",
"%st(7)",
};
/* PROCEDURES */
void temp_push_fl
(void)
{
++fstack_pos;
return;
}
void temp_pop_fl
(void)
{
--fstack_pos;
return;
}
/***************************************************************
outreal outputs a floating point number
****************************************************************/
void outreal
(exp e)
{
flt * f = &flptnos[no(e)];
int sw = name(sh(e)) - shrealhd;
r2l longs;
longs = real2longs_IEEE(f, sw);
switch (sw) {
case 0:
outhex(longs.i1);
outnl();
break;
case 1:
outhex(longs.i1);
outs(",");
outhex(longs.i2);
outnl();
break;
case 2:
outhex(longs.i1);
outs(",");
outhex(longs.i2);
outs(",");
outhex(longs.i3);
outnl();
break;
};
return;
}
/* output operand i (in bytes) relative to
stack pointer uses address relative to
frame pointer if it might be shorter */
void rel_sp
(int i, int b)
{
int n = i + (extra_stack / 8);
if (!must_use_bp) {
/* if we might use alloca all
displacements must be relative to frame
pointer */
if (n == 0) {
outs("(%esp");
if (b)
outs(")");
return;
};
if (n <= 127 || no_frame || stack_aligned_8byte) {
/* use stack pointer if displacement from
it is small */
outn((long)n);
outs("(%esp");
if (b)
outs(")");
return;
};
};
/* otherwise use displacement from frame pointer */
outn((long)(i + (stack_dec / 8)));
outs("-");
outs(local_prefix);
outs("disp");
outn((long)crt_proc_id);
outs("(%ebp");
if (b)
outs(")");
return;
}
/* output operand i (in bytes) relative to
stack pointer */
void rel_cp
(int i, int b)
{
int n = i + (extra_stack / 8);
if (n == 0) {
outs("(%esp");
if (b)
outs(")");
return;
};
outn((long)n);
outs("(%esp");
if (b)
outs(")");
return;
}
/* output operand relative to frame
pointer */
void rel_ap
(int i, int b)
{
if (no_frame) {
outn((long)(i + ((extra_stack - stack_dec) / 8)));
outs("+");
outs(local_prefix);
outs("disp");
outn((long)crt_proc_id);
outs("(%esp");
if (b)
outs(")");
return;
}
else {
outn((long)i + 4);
outs("(%ebp");
if (b)
outs(")");
return;
};
}
/* output operand relative to frame
pointer and push space*/
void rel_ap1
(int i, int b)
{
if (no_frame) {
outn((long)(i + ((extra_stack - stack_dec) / 8)));
outs("+");
outs(local_prefix);
outs("fcwdisp");
outn((long)crt_proc_id);
outs("(%esp");
if (b)
outs(")");
return;
}
else {
outn((long)i);
outs("-");
outs(local_prefix);
outs("fcwdisp");
outn((long)crt_proc_id);
outs("(%ebp");
if (b)
outs(")");
return;
};
}
int get_reg_no
(int regs)
{
frr fr;
/* find the registers associated with the bit pattern regs */
fr = first_reg(regs);
if (regs == 0x10000 || fr.fr_no == (fstack_pos))
return(fstack_pos);
return (fr.fr_no); /* this is the register number */
}
/* output a register address, regs is a
bit pattern, rdisp is an offset in bit
units. le tells us how to refer to the
register (eg al or ax or eax) */
void regn
(int regs, int rdisp, exp ldname, int le)
{
int z;
char **rn;
UNUSED(rdisp);
z = get_reg_no(regs);
if (name(ldname) == name_tag && islastuse(ldname))
regsinuse = regsinuse & ~regs;
if (z >= first_fl_reg) {
if (z == first_fl_reg) {
outs(fl_reg_name[0]);
return;
};
if (fstack_pos > 16) {
failer(BAD_FSTACK);
exit(EXIT_FAILURE);
};
outs(fl_reg_name[fstack_pos - z]);
/* variables held in the floating point registers have to be addressed
relative to the current stack position, because the registers are a
stack as well as a register bank */
return;
};
switch (le) {
case 8:
rn = reg_name_byte;
break;
case 16:
rn = reg_name_word;
break;
default:
rn = reg_name_long;
break;
};
outs (rn[z]); /* this outputs the register name */
return;
}
/* output a displacement from register operand */
void ind_reg
(int regs, int rdisp, int offset, exp ldname, int b)
{
if (regs == 128)
offset += extra_stack;
if (offset == 0) {
outs("(");
regn(regs, rdisp, ldname, 32);
if (b)
outs(")");
}
else {
outn((long)offset / 8);
outs("(");
regn(regs, rdisp, ldname, 32);
if (b)
outs(")");
};
return;
}
/* use indexed addressing */
void index_opnd
(where whmain, where wh, int sc)
{
exp m = whmain.where_exp;
if ((name(m) == name_tag && ptno(son(m)) == reg_pl) ||
(name(m) == cont_tag && name(son(m)) == name_tag &&
isvar(son(son(m))) && ptno(son(son(m))) == reg_pl))
outs("(");
operand(32, whmain, 0, 0);
outs(",");
operand(32, wh, 1, 0);
if (sc != 1) {
outs(",");
outn((long)sc);
};
outs(")");
return;
}
/* output an external operand */
void extn
(exp id, int off, int b)
{
dec * et;
et = brog(id);
if (PIC_code)
{
char * got;
if (et -> dec_u.dec_val.extnamed)
got = "GOT";
else
got = "GOTOFF";
outs(et -> dec_u.dec_val.dec_id);
outs("@");
outs(got);
if (off != 0)
{
outs("+");
outn((long)off / 8);
};
outs("(%ebx");
if (b)
outs(")");
return;
};
if (off == 0)
outs(et -> dec_u.dec_val.dec_id);
else {
outs(et -> dec_u.dec_val.dec_id);
outs("+");
outn((long)off / 8);
};
if (!b)
outs("(");
return;
}
/* an integer constant */
void int_operand
(int k, int l)
{
int mask;
switch (l) {
case 8:
mask = 0xff;
break;
case 16:
mask = 0xffff;
break;
default:
mask = 0xffffffff;
};
outs("$");
outn((long)k & mask);
return;
}
/* an external literal */
void const_extn
(exp ident, int noff)
{
if (!PIC_code)
outs("$");
extn(ident, noff, 1);
return;
}
/* an external literal */
void proc_extn
(exp id, int off)
{
if (PIC_code)
{
dec * et;
et = brog(id);
if (off == 0)
outs(et -> dec_u.dec_val.dec_id);
else {
outn((long)off / 8);
outs("+");
outs(et -> dec_u.dec_val.dec_id);
};
if (et -> dec_u.dec_val.extnamed)
outs("@PLT");
}
else
{
outs("$");
extn(id, off, 1);
};
return;
}
void ldisp
(void)
{
outs(local_prefix);
outs("disp");
outn((long)crt_proc_id);
}
void label_operand
(exp e)
{
punner l;
l.e = pt(e);
outs("$");
outs(local_prefix);
outs("V");
outn((long)l.i);
return;
}
void set_lv_label
(exp e)
{
punner l;
l.e = e;
min_rfree |= 0x78; /* save all callee registers */
outs(local_prefix);
outs("V");
outn((long)l.i);
outs(":");
outnl();
return;
}
void set_env_off
(int s, exp n)
{
punner l;
l.e = n;
outs(".set ");
outs(local_prefix);
outs("O");
outn((long)l.i); /* produce an identifying number */
outs(",");
if (s<4)
{
outn((long) -s/8);
outs("-");
outs(local_prefix);
outs("disp");
outn((long)crt_proc_id);
}
else
outn((long)s/8);
outnl();
}
void envoff_operand
(exp e, int off)
{
punner l;
l.e = e;
if (off != 0)
{
outn((long)off);
outs("+");
};
outs(local_prefix);
outs("O");
outn((long)l.i); /* produce an identifying number */
return;
}
void envsize_operand
(exp e)
{
dec * et = brog(e);
outs(local_prefix);
outs("ESZ");
outs(et -> dec_u.dec_val.dec_id);
return;
}
/* 80386 instruction with no operands */
void ins0
(char *i)
{
outs(margin);
outs(i);
outnl();
return;
}
/* one operand */
void ins1
(char *i, int le1, where a1)
{
outs(margin);
outs(i);
outs(spx);
operand(le1, a1, 1, 0);
outnl();
return;
}
/* one operand, which is indirect */
void ins1ind
(char *i, int le1, where a1)
{
outs(margin);
outs(i);
outs(spx);
outs("*");
operand(le1, a1, 1, 0);
outnl();
return;
}
/* one operand, which is immediate */
void ins1lit
(char *i, int le1, where a1)
{
outs(margin);
outs(i);
outs(spx);
operand(le1, a1, 1, 1);
outnl();
return;
}
/* two operands */
void ins2
(char *i, int le1, int le2, where a1, where a2)
{
outs(margin);
outs(i);
outs(spx);
operand(le1, a1, 1, 0);
outs(sep);
operand(le2, a2, 1, 0);
outnl();
return;
}
/* three operands */
void ins3
(char *i, int le1, int le2, int le3, where a1, where a2, where a3)
{
outs(margin);
outs(i);
outs(spx);
operand(le1, a1, 1, 0);
outs(sep);
operand(le2, a2, 1, 0);
outs(sep);
operand(le3, a3, 1, 0);
outnl();
return;
}
void simplest_set_lab
(int labno)
{
outs(local_prefix);
outn((long)labno);
outs(":");
outnl();
}
void simple_set_label
(int labno)
{
#ifdef CHECKIMPROVE
if (labno == last_jump_label)
failer("redundant jump");
#endif
#ifndef NEWDIAGS
int st = 0;
if (!diagnose && labno == last_jump_label) {
st = fseek(fpout, last_jump_pos, 0);
};
/* eliminate immediately previous jump to this label */
if (st == -1) {
failer(SEEK_FAILURE);
exit(EXIT_FAILURE);
};
#endif
cond1_set = 0;
cond2_set = 0;
outs(local_prefix);
outn ((long)labno); /* the label no is held in the ptr field
*/
outs(":");
outnl();
/* Removed for experiments: improves compress?
keep_short = 1;
*/
return;
}
/* set label described by the jump record jr */
void set_label
(exp jr)
{
simple_set_label(ptno(jr));
}
/* jump record: exp
pt - label;
last - forward;
son - stack_dec;
prop - floating stack position
*/
void discard_fstack
(void)
{
outs(" fstp %st(0)");
outnl();
pop_fl;
return;
}
void discard_st1
(void)
{
outs(" fstp %st(1)");
outnl();
pop_fl;
}
/* output a jump to the label described by
jump record jr */
void jump
(exp jr, int with_fl_reg)
{
int fs_dest = (int)fstack_pos_of(jr);
int good_fs = fstack_pos;
int good_sd = stack_dec;
if (fs_dest < first_fl_reg)
failer(FSTACK_UNSET);
if (with_fl_reg) { /* jumping with a floating value */
/* clear off any unwanted stack registers */
while (fstack_pos > (fs_dest + 1))
discard_st1();
fstack_pos = good_fs - 1;
}
else {
/* clear off any unwanted stack registers */
while (fstack_pos > fs_dest)
discard_fstack();
fstack_pos = good_fs;
};
if (sonno(jr) > stack_dec) {
add(slongsh, mw(zeroe,(sonno(jr) -stack_dec) / 8), sp, sp);
stack_dec = sonno(jr);
}
reset_fpucon();
stack_dec = good_sd;
#ifndef NEWDIAGS
if (flush_before_tell)
IGNORE fflush(fpout);
last_jump_pos = ftell(fpout);
#endif
outs(margin);
outs(jmp);
outs(spx);
outs(local_prefix);
outn((long)ptno(jr));
outnl();
last_jump_label = ptno(jr);
return;
}
static char* xse = "<=0"; /* no corresponding jump instruction */
static char* xnse = ">0";
/* output code for a branch instruction
determined by test_no. The test is
signed if sg is true */
static char *out_branch
(int sg, int test_no, int shnm)
{
if (shnm >= shrealhd && shnm <= doublehd) {
switch (test_no) {
case 1:
return(jne);
case 2:
return(jne);
case 3:
return(jpe);
case 4:
return(jpe);
case 5:
return(jpe);
case 6:
return(jpo);
case 7:
return(jpo);
case 8:
return(jpo);
case 9:
return(je);
case 10:
return(je);
case 11:
return(jne);
case 12:
return(je);
case 13:
return(jne);
case 14:
return(je);
default:
failer(BAD_TESTNO);
};
};
if (sg) {
switch (test_no) {
case 1:
return(sg<0 ? xse : jle);
case 2:
return(sg<0 ? js : jl);
case 3:
return(sg<0 ? jns : jge);
case 4:
return(sg<0 ? xnse : jg);
case 5:
return(jne);
case 6:
return(je);
default:
failer(BAD_TESTNO);
};
}
else {
switch (test_no) {
case 1:
return(jbe);
case 2:
return(jb);
case 3:
return(jae);
case 4:
return(ja);
case 5:
return(jne);
case 6:
return(je);
default:
failer(BAD_TESTNO);
};
};
return((char *)0);
}
void simple_branch
(char *j, int labno)
{
outs(margin);
outs(j);
outs(spx);
outs(local_prefix);
outn((long)labno);
outnl();
}
/* output conditional jump to jr. testno
specifies kind of test. sg is 1 if
signed arithmetic, 0 unsigned, -1 if
signed vs zero (ignoring overflow).
shnm name of shape */
void branch
(int test_no, exp jr, int sg, int shnm)
{
int fs_dest = (int)fstack_pos_of(jr);
int good_fs = fstack_pos;
int good_fpucon = fpucon;
if (fs_dest < first_fl_reg)
failer(FSTACK_UNSET);
if (fstack_pos > fs_dest || sonno(jr)!= stack_dec || fpucon != normal_fpucon
|| cmp_64hilab >= 0) {
/* floating point stack or call stack need attention */
int nl = next_lab();
int inv_test_no = (flpt_always_comparable ||
(shnm < shrealhd || shnm > doublehd))
?(int)int_inverse_ntest[test_no]
:(int)real_inverse_ntest[test_no];
char* cj = out_branch((cmp_64hilab >= 0 ? 0 : sg), inv_test_no, shnm);
if (*cj == 'j') {
simple_branch(cj, nl);
}
else /* compare with zero, ignoring overflow */
if (*cj == '>') {
int nl1 = next_lab();
simple_branch(js, nl1);
simple_branch(jne, nl);
simplest_set_lab(nl1);
}
else {
simple_branch(js, nl);
simple_branch(je, nl);
}
if (cmp_64hilab >= 0) {
int nl2 = ptno(jr);
if (shnm != s64hd)
failer("uncompleted 64-bit comparison");
if (fstack_pos > fs_dest || sonno(jr)!= stack_dec || fpucon != normal_fpucon) {
nl2 = next_lab();
simplest_set_lab(nl2);
}
jump(jr, 0);
simplest_set_lab(cmp_64hilab);
simple_branch(out_branch(1, test_no, shnm), nl2);
cmp_64hilab = -1;
}
else
jump(jr, 0);
fstack_pos = good_fs;
fpucon = good_fpucon;
simplest_set_lab(nl);
return;
};
{
char* cj = out_branch(sg, test_no, shnm);
if (*cj == 'j') {
simple_branch(cj, ptno(jr));
}
else /* compare with zero, ignoring overflow */
if (*cj == '>') {
int nl1 = next_lab();
simple_branch(js, nl1);
simple_branch(jne, ptno(jr));
simplest_set_lab(nl1);
}
else {
simple_branch(js, ptno(jr));
simple_branch(je, ptno(jr));
}
}
return;
}
void setcc
(int test_no, int sg, int shnm)
{
char * b;
if (cmp_64hilab >= 0) {
int chl = cmp_64hilab;
int nl = next_lab();
if (shnm != s64hd)
failer("uncompleted 64-bit comparison");
cmp_64hilab = -1;
setcc(test_no, 0, ulonghd);
simple_branch(jmp, nl);
simplest_set_lab(chl);
setcc(test_no, sg, slonghd);
simplest_set_lab(nl);
}
b = out_branch(sg, test_no, shnm);
if (*b != 'j')
failer(NO_SETCC);
outs(margin);
outs("set");
outs(&b[1]);
outs(spx);
outs(reg_name_byte[0]);
outnl();
return;
}
/* output conditional jump to jr if overflow
sg is 1 if signed arithmetic, 0 unsigned */
void jmp_overflow
(exp jr, int sg, int inv)
{
int fs_dest = (int)fstack_pos_of(jr);
int good_fs = fstack_pos;
int good_fpucon = fpucon;
if (fs_dest < first_fl_reg)
failer(FSTACK_UNSET);
if (fstack_pos > fs_dest || sonno(jr)!= stack_dec || fpucon != normal_fpucon) {
/* floating point stack or call stack need attention */
int nl = next_lab();
if (sg)
simple_branch(jno, nl);
else
simple_branch((inv ? jb : jae), nl);
jump(jr, 0);
fstack_pos = good_fs;
fpucon = good_fpucon;
simplest_set_lab(nl);
return;
};
if (sg)
simple_branch(jo, ptno(jr));
else
simple_branch((inv ? jae : jb), ptno(jr));
return;
}
/* software interrupt */
void trap_ins
(int s)
{
#ifndef AVOID_INTOV
if (s == f_overflow) {
ins0 ("int $4"); /* numeric interrupt */
return;
}
#else
#if (AVOID_INTOV == 16)
if (s == f_overflow) {
ins0 ("int $16"); /* mimic floating point interrupt */
return;
}
#endif
#endif
if (cont_err_handler == nilexp) {
cont_err_handler = make_extn("__trans386_errhandler", f_proc, 1);
if (!PIC_code)
cont_err_handler = getexp(f_proc, nilexp, 1, cont_err_handler, nilexp, 0, 0, cont_tag);
}
ins1(pushl, 32, mw(zeroe, s));
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_push();
#endif
ins2(movl, 32, 32, mw(cont_err_handler, 0), reg0);
if (PIC_code)
ins1ind(call, 32, ind_reg0);
else
ins1ind(call, 32, reg0);
return;
}
/* output software interrupt if overflow
sg is 1 if signed arithmetic, 0 unsigned */
void trap_overflow
(int sg, int inv)
{
#ifdef AVOID_INTOV
int nl = next_lab();
if (sg)
simple_branch(jno, nl);
else
simple_branch((inv ? jb : jae), nl);
trap_ins(f_overflow);
simplest_set_lab(nl);
#else
if (sg)
ins0(into);
else {
int nl = next_lab();
simple_branch((inv ? jb : jae), nl);
trap_ins(f_overflow);
simplest_set_lab(nl);
}
#endif
return;
}
/* conditional software interrupt
sg is 1 if signed arithmetic
shnm name of shape */
void test_trap
(int test_no, int sg, int shnm)
{
int nl = next_lab();
int inv_test_no = (flpt_always_comparable ||
(shnm < shrealhd || shnm > doublehd))
?(int)int_inverse_ntest[test_no]
:(int)real_inverse_ntest[test_no];
simple_branch(out_branch(sg, inv_test_no, shnm), nl);
trap_ins(f_overflow);
simplest_set_lab(nl);
return;
}
/* special output for doing multiply by
using index instructions */
void mult_op
(int inc, where rmain, where rind, int sc, where dest)
{
outs(margin);
outs("leal");
outs(spx);
if (inc != 0)
outn((long)inc);
outs("(");
if (name(rmain.where_exp)!= val_tag ||
(no(rmain.where_exp) + rmain.where_off)!= 0)
operand(32, rmain, 1, 0);
outs(",");
operand(32, rind, 1, 0);
if (sc != 1) {
outs(",");
outn((long)sc);
};
outs("),");
if (inmem(dest)) {
operand(32, reg0, 1, 0);
outnl();
invalidate_dest(reg0);
end_contop();
move(slongsh, reg0, dest);
}
else {
operand(32, dest, 1, 0);
outnl();
end_contop();
};
return;
}
/* output the case switch jump and the jump table */
void caseins
(int sz, exp arg, int min, int max, int *v, int exhaustive, int in_eax, exp case_exp)
{
int tab;
int absent;
where a;
int need_label_flag=0;
exp next= short_next_jump(case_exp);
if (next != nilexp && name(next) ==goto_tag)
{
exp lab=final_dest(pt(next));
absent=ptno(pt(son(lab)));
}
else
{
absent = (exhaustive)? -1 : next_lab();
need_label_flag=1;
}
tab = next_lab();
a = mw(arg, 0);
if (inmem(mw(arg, 0)) || sz != 32) {
if (!in_eax)
change_var(slongsh, a, reg0);
a = reg0;
}
/* the switch jump */
out_switch_jump(tab, a, min);
/* table of offsets */
out_switch_table(tab, min, max, v, absent);
if (!exhaustive && need_label_flag==1) {
/* label for default of switch; continue here */
outs(local_prefix);
outn((long)absent);
outs(":");
outnl();
#ifdef NEWDWARF
START_BB();
#endif
};
return;
}
void const_intnl
(int addr, int lab, int off)
{
if (PIC_code)
{
outs(local_prefix);
outn((long)lab);
outs("@GOTOFF");
if (off != 0) {
outs("+");
outn((long)off / 8);
};
outs("(%ebx)");
return;
}
else
{
if (addr)
outs("$");
outs(local_prefix);
outn((long)lab);
if (off != 0) {
outs("+");
outn((long)off / 8);
};
return;
};
}
void load_stack0
(void)
{
outs(" fld %st(0)");
outnl();
return;
}
void outbp
(void)
{
outs("%ebp");
}
void set_stack_from_bp
(void)
{
outs(margin);
outs(leal);
outs(spx);
outn((long)stack_dec/8);
outs("-");
outs(local_prefix);
outs("disp");
outn((long)crt_proc_id);
outs("(%ebp)");
outs(sep);
outs("%esp");
outnl();
return;
}
void testah
(int mask)
{
outs(" testb $");
outn((long)mask);
outs(",%ah");
outnl();
return;
}
exp make_extn
(char * n, shape s, int v)
{
dec * g = (dec *)(xmalloc(sizeof(dec)));
exp id = getexp(s, nilexp, 1, nilexp, nilexp, 0, 0, ident_tag);
exp nme = getexp(s, nilexp, 1, id, nilexp, 0, 0, name_tag);
setglob(id);
if (v) {
#if keep_PIC_vars
setvar(id);
#else
if (PIC_code)
sh(id) = f_pointer(f_alignment(s));
else
setvar(id);
#endif
}
brog(id) = g;
if (prefix_length != 0) {
int nl = (int)strlen(n);
int j;
char * newn = (char *)xcalloc((nl + prefix_length + 1), sizeof(char));
for (j = 0; j < prefix_length; ++j)
newn[j] = name_prefix[j];
for (j = 0; j < nl; ++j)
newn[j+prefix_length] = n[j];
newn[nl+prefix_length] = 0;
n = newn;
}
g -> dec_u.dec_val.dec_exp = id;
g -> dec_u.dec_val.dec_id = n;
g -> dec_u.dec_val.extnamed = 1;
return(nme);
}
/* shift or rotate 64 bits in reg0/reg1 */
void rotshift64
(int shft, int sig, where wshift)
{
if (name(wshift.where_exp) == val_tag) { /* no of places is constant */
int places = no(wshift.where_exp) + wshift.where_off;
if (places >= 32) {
places -= 32;
switch (shft) {
case 0:
if (places)
ins2(shll, 8, 32, mw(zeroe,places), reg0);
move(ulongsh, reg0, reg1);
move(ulongsh, zero, reg0);
return;
case 1:
move(ulongsh, reg1, reg0);
if (places)
ins2((sig ? sarl : shrl), 8, 32, mw(zeroe,places), reg0);
if (sig)
ins2(sarl, 8, 32, mw(zeroe,31), reg1);
else
move(ulongsh, zero, reg1);
return;
default: {
if (!places) {
ins2(xchg, 32, 32, reg0, reg1);
return;
}
places = 32 - places;
shft = 5 - shft; /* reverse rotate */
}
}
};
if (places == 0)
return;
switch (shft) { /* between 1 and 31 places */
case 0:
ins3(shldl, 8, 32, 32, mw(zeroe,places), reg0, reg1);
ins2(shll, 8, 32, mw(zeroe,places), reg0);
return;
case 1:
ins3(shrdl, 8, 32, 32, mw(zeroe,places), reg1, reg0);
ins2((sig ? sarl : shrl), 8, 32, mw(zeroe,places), reg1);
return;
default: {
char * dsh = (shft == 2 ? shrdl : shldl);
extra_stack += 64;
check_stack_max;
ins0(pushedx);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_push();
#endif
ins0(pusheax);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_push();
#endif
ins3(dsh, 8, 32, 32, mw(zeroe,places),
reg1, mw(ind_sp.where_exp,-32));
ins3(dsh, 8, 32, 32, mw(zeroe,places),
reg0, mw(ind_sp.where_exp,-64));
ins0(popeax);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_pop();
#endif
ins0(popedx);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_pop();
#endif
invalidate_dest(ind_sp);
extra_stack -= 64;
return;
}
}
};
{ /* number of places in reg2 */
int lablow = next_lab();
int labend = next_lab();
ins2(cmpl, 32, 32, mw(zeroe,32), reg2);
simple_branch(jl, lablow);
switch (shft) {
case 0:
ins2(subl, 32, 32, mw(zeroe,32), reg2);
ins2(shll, 8, 32, reg2, reg0);
move(ulongsh, reg0, reg1);
move(ulongsh, zero, reg0);
break;
case 1:
ins2(subl, 32, 32, mw(zeroe,32), reg2);
move(ulongsh, reg1, reg0);
ins2((sig ? sarl : shrl), 8, 32, reg2, reg0);
if (sig)
ins2(sarl, 8, 32, mw(zeroe,31), reg1);
else
move(ulongsh, zero, reg1);
break;
default: {
int labx = next_lab();
char * dsh = (shft == 2 ? shldl : shrdl); /* reversed rotate */
simple_branch(je, labx);
ins2(subl, 32, 32, mw(zeroe,64), reg2);
ins1(negl, 32, reg2);
extra_stack += 64;
check_stack_max;
ins0(pushedx);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_push();
#endif
ins0(pusheax);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_push();
#endif
ins3(dsh, 8, 32, 32, reg2, reg1, mw(ind_sp.where_exp,-32));
ins3(dsh, 8, 32, 32, reg2, reg0, mw(ind_sp.where_exp,-64));
ins0(popeax);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_pop();
#endif
ins0(popedx);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_pop();
#endif
invalidate_dest(ind_sp);
extra_stack -= 64;
simple_branch(jmp, labend);
simplest_set_lab(labx);
ins2(xchg, 32, 32, reg0, reg1);
}
}
simple_branch(jmp, labend);
simplest_set_lab(lablow);
switch (shft) { /* between 0 and 31 places */
case 0:
ins3(shldl, 8, 32, 32, reg2, reg0, reg1);
ins2(shll, 8, 32, reg2, reg0);
break;
case 1:
ins3(shrdl, 8, 32, 32, reg2, reg1, reg0);
ins2((sig ? sarl : shrl), 8, 32, reg2, reg1);
break;
default: {
char * dsh = (shft == 2 ? shrdl : shldl);
extra_stack += 64;
check_stack_max;
ins0(pushedx);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_push();
#endif
ins0(pusheax);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_push();
#endif
ins3(dsh, 8, 32, 32, reg2, reg1, mw(ind_sp.where_exp,-32));
ins3(dsh, 8, 32, 32, reg2, reg0, mw(ind_sp.where_exp,-64));
ins0(popeax);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_pop();
#endif
ins0(popedx);
#ifdef NEWDWARF
if (diagnose && dwarf2 && no_frame)
dw2_track_pop();
#endif
invalidate_dest(ind_sp);
extra_stack -= 64;
}
}
simplest_set_lab(labend);
};
return;
}