OpenCores
URL https://opencores.org/ocsvn/thor/thor/trunk

Subversion Repositories thor

[/] [thor/] [trunk/] [FT64v5/] [software/] [CC64/] [source/] [ENODE.cpp] - Rev 55

Go to most recent revision | Compare with Previous | Blame | View Log

// ============================================================================
//        __
//   \\__/ o\    (C) 2017-2018  Robert Finch, Waterloo
//    \  __ /    All rights reserved.
//     \/_//     robfinch<remove>@finitron.ca
//       ||
//
// CC64 - 'C' derived language compiler
//  - 64 bit CPU
//
// This source file is free software: you can redistribute it and/or modify 
// it under the terms of the GNU Lesser General Public License as published 
// by the Free Software Foundation, either version 3 of the License, or     
// (at your option) any later version.                                      
//                                                                          
// This source file is distributed in the hope that it will be useful,      
// but WITHOUT ANY WARRANTY; without even the implied warranty of           
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            
// GNU General Public License for more details.                             
//                                                                          
// You should have received a copy of the GNU General Public License        
// along with this program.  If not, see <http://www.gnu.org/licenses/>.    
//                                                                          
// ============================================================================
//
#include "stdafx.h"
 
void swap_nodes(ENODE *node)
{
	ENODE *temp;
	temp = node->p[0];
	node->p[0] = node->p[1];
	node->p[1] = temp;
}
 
bool ENODE::IsEqualOperand(Operand *a, Operand *b)
{
	return (Operand::IsEqual(a, b));
};
 
char ENODE::fsize()
{
	switch (etype) {
	case bt_float:	return ('d');
	case bt_double:	return ('d');
	case bt_triple:	return ('t');
	case bt_quad:	return ('q');
	default:	return ('d');
	}
}
 
long ENODE::GetReferenceSize()
{
	switch (nodetype)        /* get load size */
	{
	case en_b_ref:
	case en_ub_ref:
	case en_bfieldref:
	case en_ubfieldref:
		return (1);
	case en_c_ref:
	case en_uc_ref:
	case en_cfieldref:
	case en_ucfieldref:
		return (2);
	case en_ref32:
	case en_ref32u:
		return (4);
	case en_h_ref:
	case en_uh_ref:
	case en_hfieldref:
	case en_uhfieldref:
		return (sizeOfWord / 2);
	case en_w_ref:
	case en_uw_ref:
	case en_wfieldref:
	case en_uwfieldref:
		return (sizeOfWord);
	case en_fpregvar:
		if (tp)
			return(tp->size);
		else
			return (sizeOfFPD);
	case en_tempref:
	case en_regvar:
		return (sizeOfWord);
	case en_dbl_ref:
		return (sizeOfFPD);
	case en_quad_ref:
		return (sizeOfFPQ);
	case en_flt_ref:
		return (sizeOfFPD);
	case en_triple_ref:
		return (sizeOfFPT);
	case en_hp_ref:
		return (sizeOfPtr >> 1);
	case en_wp_ref:
		return (sizeOfPtr);
	case en_vector_ref:
		return (512);
		//			return node->esize;
	}
	return (8);
}
 
bool ENODE::IsBitfield()
{
	return (nodetype == en_wfieldref
		|| nodetype == en_bfieldref
		|| nodetype == en_cfieldref
		|| nodetype == en_hfieldref
		|| nodetype == en_ubfieldref
		|| nodetype == en_ucfieldref
		|| nodetype == en_uhfieldref
		|| nodetype == en_uwfieldref
		);
}
 
//
// equalnode will return 1 if the expressions pointed to by
// node1 and node2 are equivalent.
//
bool ENODE::IsEqual(ENODE *node1, ENODE *node2)
{
	if (node1 == nullptr || node2 == nullptr) {
		return (false);
	}
	if (node1->nodetype != node2->nodetype) {
		return (false);
	}
	switch (node1->nodetype) {
	case en_fcon:
		return (Float128::IsEqual(&node1->f128, &node2->f128));
		//			return (node1->f == node2->f);
	case en_regvar:
	case en_fpregvar:
	case en_tempref:
	case en_icon:
	case en_labcon:
	case en_classcon:	// Check type ?
	case en_autocon:
	case en_autovcon:
	case en_autofcon:
	{
		return (node1->i == node2->i);
	}
	case en_nacon: {
		return (node1->sp->compare(*node2->sp) == 0);
	}
	case en_cnacon:
		return (node1->sp->compare(*node2->sp) == 0);
	default:
		if (IsLValue(node1) && IsEqual(node1->p[0], node2->p[0])) {
			//	        if( equalnode(node1->p[0], node2->p[0])  )
			return (true);
		}
	}
	return (false);
}
 
 
ENODE *ENODE::Clone()
{
	ENODE *temp;
 
	if (this == nullptr)
		return (ENODE *)nullptr;
	temp = allocEnode();
	memcpy(temp, this, sizeof(ENODE));	// copy all the fields
	return (temp);
}
 
 
 
//	repexpr will replace all allocated references within an expression
//	with tempref nodes.
 
void ENODE::repexpr()
{
	CSE *csp;
	if (this == nullptr)
		return;
	switch (nodetype) {
	case en_fcon:
	case en_autofcon:
	case en_tempfpref:
		if ((csp = currentFn->csetbl->Search(this)) != nullptr) {
			csp->isfp = TRUE; //**** a kludge
			if (csp->reg > 0) {
				nodetype = en_fpregvar;
				i = csp->reg;
			}
		}
		break;
		/*
		if( (csp = SearchCSEList(node)) != NULL ) {
		if( csp->reg > 0 ) {
		node->nodetype = en_fpregvar;
		node->i = csp->reg;
		}
		}
		break;
		*/
	case en_icon:
	case en_nacon:
	case en_labcon:
	case en_autovcon:
	case en_autocon:
	case en_classcon:
	case en_cnacon:
	case en_clabcon:
	case en_tempref:
		if ((csp = currentFn->csetbl->Search(this)) != NULL) {
			if (csp->reg > 0) {
				nodetype = en_regvar;
				i = csp->reg;
			}
		}
		break;
	case en_ref32: case en_ref32u:
	case en_b_ref:
	case en_c_ref:
	case en_h_ref:
	case en_w_ref:
	case en_ub_ref:
	case en_uc_ref:
	case en_uh_ref:
	case en_uw_ref:
	case en_wp_ref:
	case en_hp_ref:
	case en_bfieldref:
	case en_ubfieldref:
	case en_cfieldref:
	case en_ucfieldref:
	case en_hfieldref:
	case en_uhfieldref:
	case en_wfieldref:
	case en_uwfieldref:
	case en_vector_ref:
		if ((csp = currentFn->csetbl->Search(this)) != NULL) {
			if (csp->reg > 0) {
				nodetype = en_regvar;
				i = csp->reg;
			}
			else
				p[0]->repexpr();
		}
		else
			p[0]->repexpr();
		break;
	case en_dbl_ref:
	case en_flt_ref:
	case en_quad_ref:
		if ((csp = currentFn->csetbl->Search(this)) != NULL) {
			if (csp->reg > 0) {
				nodetype = en_fpregvar;
				i = csp->reg;
			}
			else
				p[0]->repexpr();
		}
		else
			p[0]->repexpr();
		break;
	case en_cbc: case en_cubw:
	case en_cbh: case en_cucw:
	case en_cbw: case en_cuhw:
	case en_cbu: case en_ccu: case en_chu:
	case en_cubu: case en_cucu: case en_cuhu:
	case en_ccwp: case en_cucwp:
	case en_cch:
	case en_ccw:
	case en_chw:
	case en_uminus:
	case en_abs:
	case en_sxb: case en_sxh: case en_sxc:
	case en_not:    case en_compl:
	case en_chk:
		p[0]->repexpr();
		break;
	case en_i2d:
		p[0]->repexpr();
		break;
	case en_i2q:
	case en_d2i:
	case en_q2i:
	case en_s2q:
	case en_d2q:
	case en_t2q:
		p[0]->repexpr();
		break;
	case en_add:    case en_sub:
	case en_mul:    case en_mulu:   case en_div:	case en_udiv:
	case en_mod:    case en_umod:
	case en_shl:	case en_asl:
	case en_shlu:	case en_shru:	case en_asr:
	case en_shr:
	case en_and:
	case en_or:     case en_xor:
	case en_land:   case en_lor:
	case en_eq:     case en_ne:
	case en_lt:     case en_le:
	case en_gt:     case en_ge:
	case en_ult:	case en_ule:
	case en_ugt:	case en_uge:
 
	case en_feq:    case en_fne:
	case en_flt:    case en_fle:
	case en_fgt:    case en_fge:
	case en_fdmul:  case en_fddiv:
	case en_fdadd:  case en_fdsub:
	case en_fadd: case en_fsub:
	case en_fmul: case en_fdiv:
 
	case en_veq:    case en_vne:
	case en_vlt:    case en_vle:
	case en_vgt:    case en_vge:
	case en_vadd: case en_vsub:
	case en_vmul: case en_vdiv:
	case en_vadds: case en_vsubs:
	case en_vmuls: case en_vdivs:
 
	case en_cond:   case en_void:
	case en_asadd:  case en_assub:
	case en_asmul:  case en_asmulu:
	case en_asdiv:  case en_asdivu:
	case en_asor:   case en_asand:    case en_asxor:
	case en_asmod:  case en_aslsh:
	case en_asrsh:  case en_fcall:
	case en_list: case en_aggregate:
	case en_assign:
		p[0]->repexpr();
		p[1]->repexpr();
		break;
	case en_regvar:
	case en_fpregvar:
		break;
	case en_bchk:
		p[0]->repexpr();
		p[1]->repexpr();
		p[2]->repexpr();
		break;
	default:
		dfs.printf("Uncoded node in repexr():%d\r\n", nodetype);
	}
}
 
 
/*
*      scanexpr will scan the expression pointed to by node for optimizable
*      subexpressions. when an optimizable expression is found it is entered
*      into the tree. if a reference to an autocon node is scanned the
*      corresponding auto dereferenced node will be voided. duse should be
*      set if the expression will be dereferenced.
*/
void ENODE::scanexpr(int duse)
{
	CSE *csp, *csp1;
	int first;
	int nn;
 
	if (this == nullptr)
		return;
 
	switch (nodetype) {
	case en_fpregvar:
	case en_regvar:
		break;
	case en_cnacon:
	case en_clabcon:
	case en_fcon:
	case en_icon:
	case en_labcon:
	case en_nacon:
		currentFn->csetbl->InsertNode(this, duse);
		break;
	case en_autofcon:
	case en_tempfpref:
		csp1 = currentFn->csetbl->InsertNode(this, duse);
		csp1->isfp = TRUE;
		if ((nn = currentFn->csetbl->voidauto2(this)) > 0) {
			csp1->duses += loop_active;
			csp1->uses = csp1->duses + nn - loop_active;
		}
		break;
	case en_autovcon:
	case en_autocon:
	case en_classcon:
	case en_tempref:
		csp1 = currentFn->csetbl->InsertNode(this, duse);
		if ((nn = currentFn->csetbl->voidauto2(this)) > 0) {
			csp1->duses += loop_active;
			csp1->uses = csp1->duses + nn - loop_active;
		}
		break;
	case en_ref32: case en_ref32u:
	case en_b_ref:
	case en_c_ref:
	case en_h_ref:
	case en_w_ref:
	case en_ub_ref:
	case en_uc_ref:
	case en_uh_ref:
	case en_uw_ref:
	case en_flt_ref:
	case en_dbl_ref:
	case en_quad_ref:
	case en_bfieldref:
	case en_ubfieldref:
	case en_cfieldref:
	case en_ucfieldref:
	case en_hfieldref:
	case en_uhfieldref:
	case en_wfieldref:
	case en_uwfieldref:
	case en_wp_ref:
	case en_hp_ref:
	case en_vector_ref:
		// There is something wrong with the following code that causes
		// it to remove zero extension conversion from a byte to a word.
		if (p[0]->nodetype == en_autocon || p[0]->nodetype == en_autofcon
			|| p[0]->nodetype == en_classcon || p[0]->nodetype == en_autovcon) {
			first = (currentFn->csetbl->Search(this) == nullptr);	// Detect if this is the first insert
			csp = currentFn->csetbl->InsertNode(this, duse);
			if (csp->voidf)
				p[0]->scanexpr(1);
			// take care: the non-derereferenced use of the autocon node may
			// already be in the list. In this case, set voidf to 1
			if (currentFn->csetbl->Search(p[0]) != NULL) {
				csp->voidf = 1;
				p[0]->scanexpr(1);
			}
			else {
				//                        if( csp->voidf )
				//                             scanexpr(node->p[0],1);
				if (first) {
					///* look for register nodes */
					//int i = 0;
					//long j = node->p[0]->i;
					//if ((node->p[0]->nodetype== en_regvar || node->p[0]->nodetype==en_bregvar) &&
					//	(j >= 11 && j < 18))
					//{
					//	csp->voidf--;	/* this is not in auto_lst */
					//	//csp->uses += 90 * (100 - i);
					//	//csp->duses += 30 * (100 - i);
					//	break;
					//}
					///* set voidf if the node is not in autolst */
					//csp->voidf++;
					//i = 0;
					//while (i < autoptr) {
					//	if (autolst[i] == j) {
					//		csp->voidf--;
					//		break;
					//	}
					//	++i;
					//}
					/*
					* even if that item must not be put in a register,
					* it is legal to put its address therein
					*/
					//if (csp->voidf)
					//	scanexpr(node->p[0], 1);
					//}
 
					//if( csp->voidf )
					//    scanexpr(node->p[0],1);
				}
			}
		}
		else
			p[0]->scanexpr(1);
		break;
	case en_cbc: case en_cubw:
	case en_cbh: case en_cucw:
	case en_cbw: case en_cuhw:
	case en_cbu: case en_ccu: case en_chu:
	case en_cubu: case en_cucu: case en_cuhu:
	case en_ccwp: case en_cucwp:
	case en_cch:
	case en_ccw:
	case en_chw:
	case en_uminus:
	case en_abs:
	case en_sxb: case en_sxc: case en_sxh:
	case en_zxb: case en_zxc: case en_zxh:
	case en_compl:
	case en_not:
	case en_chk:
		p[0]->scanexpr(duse);
		break;
	case en_i2d:
		p[0]->scanexpr(duse);
		break;
	case en_i2q:
	case en_d2i:
	case en_q2i:
	case en_s2q:
	case en_d2q:
	case en_t2q:
		p[0]->scanexpr(duse);
		break;
	case en_asadd:  case en_assub:
	case en_add:    case en_sub:
		p[0]->scanexpr(duse);
		p[1]->scanexpr(duse);
		break;
	case en_mul:    case en_mulu:   case en_div:	case en_udiv:
	case en_shl:    case en_asl:	case en_shlu:	case en_shr:	case en_shru:	case en_asr:
	case en_mod:    case en_umod:   case en_and:
	case en_or:     case en_xor:
	case en_lor:    case en_land:
	case en_eq:     case en_ne:
	case en_gt:     case en_ge:
	case en_lt:     case en_le:
	case en_ugt:    case en_uge:
	case en_ult:    case en_ule:
	case en_feq:    case en_fne:
	case en_flt:    case en_fle:
	case en_fgt:    case en_fge:
	case en_fdmul:  case en_fddiv:
	case en_fdadd:  case en_fdsub:
	case en_fadd: case en_fsub:
	case en_fmul: case en_fdiv:
 
	case en_veq:    case en_vne:
	case en_vlt:    case en_vle:
	case en_vgt:    case en_vge:
	case en_vadd: case en_vsub:
	case en_vmul: case en_vdiv:
	case en_vadds: case en_vsubs:
	case en_vmuls: case en_vdivs:
 
	case en_asmul:  case en_asmulu:
	case en_asdiv:	case en_asdivu:
	case en_asmod:  case en_aslsh:
	case en_asrsh:
	case en_asand:	case en_asxor: case en_asor:
	case en_cond:
	case en_void:
	case en_list:
	case en_aggregate:
		p[0]->scanexpr(0);
		p[1]->scanexpr(0);
		break;
	case en_assign:
		p[0]->scanexpr(0);
		p[1]->scanexpr(0);
		break;
	case en_fcall:
		p[0]->scanexpr(1);
		p[1]->scanexpr(0);
		break;
	case en_bchk:
		p[0]->scanexpr(0);
		p[1]->scanexpr(0);
		p[2]->scanexpr(0);
		break;
	default: dfs.printf("Uncoded node in ENODE::scanexpr():%d\r\n", nodetype);
	}
}
 
 
// ----------------------------------------------------------------------------
// Generate code to evaluate an index node (^+) and return the addressing mode
// of the result. This routine takes no flags since it always returns either
// am_ind or am_indx.
//
// No reason to ReleaseTempReg() because the registers used are transported
// forward.
// ----------------------------------------------------------------------------
Operand *ENODE::GenIndex()
{
	Operand *ap1, *ap2;
 
	if ((p[0]->nodetype == en_tempref || p[0]->nodetype == en_regvar)
		&& (p[1]->nodetype == en_tempref || p[1]->nodetype == en_regvar))
	{       /* both nodes are registers */
			// Don't need to free ap2 here. It is included in ap1.
		GenerateHint(8);
		ap1 = GenerateExpression(p[0], F_REG, 8);
		ap2 = GenerateExpression(p[1], F_REG, 8);
		GenerateHint(9);
		ap1->mode = am_indx2;
		ap1->sreg = ap2->preg;
		ap1->deep2 = ap2->deep2;
		ap1->offset = makeinode(en_icon, 0);
		ap1->scale = scale;
		return (ap1);
	}
	GenerateHint(8);
	ap1 = GenerateExpression(p[0], F_REG | F_IMMED, 8);
	if (ap1->mode == am_imm)
	{
		ap2 = GenerateExpression(p[1], F_REG | F_IMM0, 8);
		if (ap2->mode == am_imm) {	// value is zero
			ap1->mode = am_direct;
			return (ap1);
		}
		GenerateHint(9);
		ap2->mode = am_indx;
		ap2->offset = ap1->offset;
		ap2->isUnsigned = ap1->isUnsigned;
		return (ap2);
	}
	ap2 = GenerateExpression(p[1], F_ALL, 8);   /* get right op */
	GenerateHint(9);
	if (ap2->mode == am_imm && ap1->mode == am_reg) /* make am_indx */
	{
		ap2->mode = am_indx;
		ap2->preg = ap1->preg;
		ap2->deep = ap1->deep;
		return ap2;
	}
	if (ap2->mode == am_ind && ap1->mode == am_reg) {
		ap2->mode = am_indx2;
		ap2->sreg = ap1->preg;
		ap2->deep2 = ap1->deep;
		return ap2;
	}
	if (ap2->mode == am_direct && ap1->mode == am_reg) {
		ap2->mode = am_indx;
		ap2->preg = ap1->preg;
		ap2->deep = ap1->deep;
		return ap2;
	}
	// ap1->mode must be F_REG
	ap2->MakeLegal( F_REG, 8);
	ap1->mode = am_indx2;            /* make indexed */
	ap1->sreg = ap2->preg;
	ap1->deep2 = ap2->deep;
	ap1->offset = makeinode(en_icon, 0);
	ap1->scale = scale;
	return ap1;                     /* return indexed */
}
 
 
//
// Generate code to evaluate a condition operator node (?:)
//
Operand *ENODE::GenHook(int flags, int size)
{
	Operand *ap1, *ap2, *ap3, *ap4;
	int false_label, end_label;
	OCODE *ip1;
	int n1;
	ENODE *node;
 
	false_label = nextlabel++;
	end_label = nextlabel++;
	flags = (flags & F_REG) | F_VOL;
	/*
	if (p[0]->constflag && p[1]->constflag) {
	GeneratePredicateMonadic(hook_predreg,op_op_ldi,make_immed(p[0]->i));
	GeneratePredicateMonadic(hook_predreg,op_ldi,make_immed(p[0]->i));
	}
	*/
	ip1 = peep_tail;
	if (!opt_nocgo) {
		ap4 = GetTempRegister();
		ap1 = GenerateExpression(p[0], flags, size);
		ap2 = GenerateExpression(p[1]->p[0], flags, size);
		ap3 = GenerateExpression(p[1]->p[1], (flags & ~F_VOL) | F_IMMED, size);
		n1 = PeepCount(ip1);
		if (n1 < 20) {
			Generate4adic(op_cmovenz, 0, ap4, ap1, ap2, ap3);
			ReleaseTempReg(ap3);
			ReleaseTempReg(ap2);
			ReleaseTempReg(ap1);
			return (ap4);
		}
		ReleaseTempReg(ap3);
		ReleaseTempReg(ap2);
		ReleaseTempReg(ap1);
		ReleaseTempReg(ap4);
		peep_tail = ip1;
		peep_tail->fwd = nullptr;
	}
	ap2 = GenerateExpression(p[1]->p[1], flags, size);
	n1 = PeepCount(ip1);
	if (opt_nocgo)
		n1 = 9999;
	if (n1 > 4) {
		peep_tail = ip1;
		peep_tail->fwd = nullptr;
	}
	GenerateFalseJump(p[0], false_label, 0);
	node = p[1];
	ap1 = GenerateExpression(node->p[0], flags, size);
	if (n1 > 4)
		GenerateDiadic(op_bra, 0, make_clabel(end_label), 0);
	else {
		if (!IsEqualOperand(ap1, ap2))
		{
			GenerateMonadic(op_hint, 0, make_immed(2));
			GenerateDiadic(op_mov, 0, ap2, ap1);
		}
	}
	GenerateLabel(false_label);
	if (n1 > 4) {
		ap2 = GenerateExpression(node->p[1], flags, size);
		if (!IsEqualOperand(ap1, ap2))
		{
			GenerateMonadic(op_hint, 0, make_immed(2));
			GenerateDiadic(op_mov, 0, ap1, ap2);
		}
	}
	if (n1 > 4) {
		ReleaseTempReg(ap2);
		GenerateLabel(end_label);
		return (ap1);
	}
	else {
		ReleaseTempReg(ap1);
		GenerateLabel(end_label);
		return (ap2);
	}
}
 
Operand *ENODE::GenShift(int flags, int size, int op)
{
	Operand *ap1, *ap2, *ap3;
 
	ap3 = GetTempRegister();
	ap1 = GenerateExpression(p[0], F_REG, size);
	ap2 = GenerateExpression(p[1], F_REG | F_IMM6, 8);
	GenerateTriadic(op, size, ap3, ap1, ap2);
	// Rotates automatically sign extend
	if ((op == op_rol || op == op_ror) && ap2->isUnsigned)
		switch (size) {
		case 1:	GenerateDiadic(op_zxb, 0, ap3, ap3); break;
		case 2:	GenerateDiadic(op_zxc, 0, ap3, ap3); break;
		case 4:	GenerateDiadic(op_zxh, 0, ap3, ap3); break;
		default:;
		}
	ReleaseTempRegister(ap2);
	ReleaseTempRegister(ap1);
	ap3->MakeLegal(flags, size);
	return (ap3);
}
 
 
Operand *ENODE::GenAssignShift(int flags, int size, int op)
{
	Operand    *ap1, *ap2, *ap3;
 
	//size = GetNaturalSize(node->p[0]);
	ap3 = GenerateExpression(p[0], F_ALL & ~F_IMMED, size);
	ap2 = GenerateExpression(p[1], F_REG | F_IMM6, size);
	if (ap3->mode == am_reg) {
		GenerateTriadic(op, size, ap3, ap3, ap2);
		ReleaseTempRegister(ap2);
		ap3->MakeLegal(flags, size);
		return (ap3);
	}
	ap1 = GetTempRegister();
	GenLoad(ap1, ap3, size, size);
	GenerateTriadic(op, size, ap1, ap1, ap2);
	GenStore(ap1, ap3, size);
	ReleaseTempRegister(ap1);
	ReleaseTempRegister(ap2);
	ap3->MakeLegal(flags, size);
	return (ap3);
}
 
 
//
//      generate code to evaluate a mod operator or a divide
//      operator.
//
Operand *ENODE::GenDivMod(int flags, int size, int op)
{
	Operand *ap1, *ap2, *ap3;
 
	//if( node->p[0]->nodetype == en_icon ) //???
	//	swap_nodes(node);
	if (op == op_fdiv) {
		ap3 = GetTempFPRegister();
		ap1 = GenerateExpression(p[0], F_FPREG, 8);
		ap2 = GenerateExpression(p[1], F_FPREG, 8);
	}
	else {
		ap3 = GetTempRegister();
		ap1 = GenerateExpression(p[0], F_REG, 8);
		ap2 = GenerateExpression(p[1], F_REG | F_IMMED, 8);
	}
	if (op == op_fdiv) {
		// Generate a convert operation ?
		if (ap1->fpsize() != ap2->fpsize()) {
			if (ap2->fpsize() == 's')
				GenerateDiadic(op_fcvtsq, 0, ap2, ap2);
		}
		GenerateTriadic(op, ap1->fpsize(), ap3, ap1, ap2);
	}
	else
		GenerateTriadic(op, 0, ap3, ap1, ap2);
	//    GenerateDiadic(op_ext,0,ap3,0);
	ap3->MakeLegal( flags, 2);
	ReleaseTempReg(ap2);
	ReleaseTempReg(ap1);
	return (ap3);
}
 
 
//
// Generate code to evaluate a unary minus or complement.
//
Operand *ENODE::GenUnary(int flags, int size, int op)
{
	Operand *ap, *ap2;
 
	if (IsFloatType()) {
		ap2 = GetTempFPRegister();
		ap = GenerateExpression(p[0], F_FPREG, size);
		if (op == op_neg)
			op = op_fneg;
		GenerateDiadic(op, fsize(), ap2, ap);
	}
	else if (etype == bt_vector) {
		ap2 = GetTempVectorRegister();
		ap = GenerateExpression(p[0], F_VREG, size);
		GenerateDiadic(op, 0, ap2, ap);
	}
	else {
		ap2 = GetTempRegister();
		ap = GenerateExpression(p[0], F_REG, size);
		GenerateHint(3);
		GenerateDiadic(op, 0, ap2, ap);
	}
	ReleaseTempReg(ap);
	ap2->MakeLegal( flags, size);
	return (ap2);
}
 
// Generate code for a binary expression
 
Operand *ENODE::GenBinary(int flags, int size, int op)
{
	Operand *ap1, *ap2, *ap3, *ap4;
 
	if (IsFloatType())
	{
		ap3 = GetTempFPRegister();
		ap1 = GenerateExpression(p[0], F_FPREG, size);
		ap2 = GenerateExpression(p[1], F_FPREG, size);
		// Generate a convert operation ?
		if (ap1->fpsize() != ap2->fpsize()) {
			if (ap2->fpsize() == 's')
				GenerateDiadic(op_fcvtsq, 0, ap2, ap2);
		}
		GenerateTriadic(op, ap1->fpsize(), ap3, ap1, ap2);
		ap3->type = ap1->type;
	}
	else if (op == op_vadd || op == op_vsub || op == op_vmul || op == op_vdiv
		|| op == op_vadds || op == op_vsubs || op == op_vmuls || op == op_vdivs
		|| op == op_veins) {
		ap3 = GetTempVectorRegister();
		if (ENODE::IsEqual(p[0], p[1]) && !opt_nocgo) {
			ap1 = GenerateExpression(p[0], F_VREG, size);
			ap2 = GenerateExpression(vmask, F_VMREG, size);
			Generate4adic(op, 0, ap3, ap1, ap1, ap2);
			ReleaseTempReg(ap2);
			ap2 = nullptr;
		}
		else {
			ap1 = GenerateExpression(p[0], F_VREG, size);
			ap2 = GenerateExpression(p[1], F_VREG, size);
			ap4 = GenerateExpression(vmask, F_VMREG, size);
			Generate4adic(op, 0, ap3, ap1, ap2, ap4);
			ReleaseTempReg(ap4);
		}
		// Generate a convert operation ?
		//if (fpsize(ap1) != fpsize(ap2)) {
		//	if (fpsize(ap2)=='s')
		//		GenerateDiadic(op_fcvtsq, 0, ap2, ap2);
		//}
	}
	else if (op == op_vex) {
		ap3 = GetTempRegister();
		ap1 = GenerateExpression(p[0], F_REG, size);
		ap2 = GenerateExpression(p[1], F_REG, size);
		GenerateTriadic(op, 0, ap3, ap1, ap2);
	}
	else {
		ap3 = GetTempRegister();
		if (ENODE::IsEqual(p[0], p[1]) && !opt_nocgo) {
			ap1 = GenerateExpression(p[0], F_REG, size);
			ap2 = nullptr;
			GenerateTriadic(op, 0, ap3, ap1, ap1);
		}
		else {
			ap1 = GenerateExpression(p[0], F_REG, size);
			ap2 = GenerateExpression(p[1], F_REG | F_IMMED, size);
			if (ap2->mode == am_imm) {
				switch (op) {
				case op_and:
					GenerateTriadic(op, 0, ap3, ap1, make_immed(ap2->offset->i));
					/*
					if (ap2->offset->i & 0xFFFF0000LL)
					GenerateDiadic(op_andq1,0,ap3,make_immed((ap2->offset->i >> 16) & 0xFFFFLL));
					if (ap2->offset->i & 0xFFFF00000000LL)
					GenerateDiadic(op_andq2,0,ap3,make_immed((ap2->offset->i >> 32) & 0xFFFFLL));
					if (ap2->offset->i & 0xFFFF000000000000LL)
					GenerateDiadic(op_andq3,0,ap3,make_immed((ap2->offset->i >> 48) & 0xFFFFLL));
					*/
					break;
				case op_or:
					GenerateTriadic(op, 0, ap3, ap1, make_immed(ap2->offset->i));
					/*
					if (ap2->offset->i & 0xFFFF0000LL)
					GenerateDiadic(op_orq1,0,ap3,make_immed((ap2->offset->i >> 16) & 0xFFFFLL));
					if (ap2->offset->i & 0xFFFF00000000LL)
					GenerateDiadic(op_orq2,0,ap3,make_immed((ap2->offset->i >> 32) & 0xFFFFLL));
					if (ap2->offset->i & 0xFFFF000000000000LL)
					GenerateDiadic(op_orq3,0,ap3,make_immed((ap2->offset->i >> 48) & 0xFFFFLL));
					*/
					break;
					// Most ops handle a max 16 bit immediate operand. If the operand is over 16 bits
					// it has to be loaded into a register.
				default:
					if (ap2->offset->i < -32768LL || ap2->offset->i > 32767LL) {
						ap4 = GetTempRegister();
						GenerateTriadic(op_or, 0, ap4, makereg(regZero), make_immed(ap2->offset->i));
						/*
						if (ap2->offset->i & 0xFFFF0000LL)
						GenerateDiadic(op_orq1,0,ap4,make_immed((ap2->offset->i >> 16) & 0xFFFFLL));
						if (ap2->offset->i & 0xFFFF00000000LL)
						GenerateDiadic(op_orq2,0,ap4,make_immed((ap2->offset->i >> 32) & 0xFFFFLL));
						if (ap2->offset->i & 0xFFFF000000000000LL)
						GenerateDiadic(op_orq3,0,ap4,make_immed((ap2->offset->i >> 48) & 0xFFFFLL));
						*/
						GenerateTriadic(op, 0, ap3, ap1, ap4);
						ReleaseTempReg(ap4);
					}
					else
						GenerateTriadic(op, 0, ap3, ap1, ap2);
				}
			}
			else
				GenerateTriadic(op, 0, ap3, ap1, ap2);
		}
	}
	if (ap2)
		ReleaseTempReg(ap2);
	ReleaseTempReg(ap1);
	ap3->MakeLegal( flags, size);
	return (ap3);
}
 
 
Operand *ENODE::GenAssignAdd(int flags, int size, int op)
{
	Operand *ap1, *ap2, *ap3;
	int ssize;
	bool negf = false;
 
	ssize = GetNaturalSize(p[0]);
	if (ssize > size)
		size = ssize;
	if (p[0]->IsBitfield()) {
		ap3 = GetTempRegister();
		ap1 = GenerateBitfieldDereference(p[0], F_REG | F_MEM, size);
		GenerateDiadic(op_mov, 0, ap3, ap1);
		ap2 = GenerateExpression(p[1], F_REG | F_IMMED, size);
		GenerateTriadic(op, 0, ap1, ap1, ap2);
		GenerateBitfieldInsert(ap3, ap1, ap1->offset->bit_offset, ap1->offset->bit_width);
		GenStore(ap3, ap1->next, ssize);
		ReleaseTempReg(ap2);
		ReleaseTempReg(ap1->next);
		ReleaseTempReg(ap1);
		ap3->MakeLegal( flags, size);
		return (ap3);
	}
	if (IsFloatType()) {
		ap1 = GenerateExpression(p[0], F_FPREG | F_MEM, ssize);
		ap2 = GenerateExpression(p[1], F_FPREG, size);
		if (op == op_add)
			op = op_fadd;
		else if (op == op_sub)
			op = op_fsub;
	}
	else if (etype == bt_vector) {
		ap1 = GenerateExpression(p[0], F_REG | F_MEM, ssize);
		ap2 = GenerateExpression(p[1], F_REG, size);
		if (op == op_add)
			op = op_vadd;
		else if (op == op_sub)
			op = op_vsub;
	}
	else {
		ap1 = GenerateExpression(p[0], F_ALL, ssize);
		ap2 = GenerateExpression(p[1], F_REG | F_IMMED, size);
	}
	if (ap1->mode == am_reg) {
		GenerateTriadic(op, 0, ap1, ap1, ap2);
	}
	else if (ap1->mode == am_fpreg) {
		GenerateTriadic(op, ap1->fpsize(), ap1, ap1, ap2);
		ReleaseTempReg(ap2);
		ap1->MakeLegal( flags, size);
		return (ap1);
	}
	else {
		GenMemop(op, ap1, ap2, ssize);
	}
	ReleaseTempReg(ap2);
	if (ap1->type != stddouble.GetIndex() && !ap1->isUnsigned)
		ap1->GenSignExtend(ssize, size, flags);
	ap1->MakeLegal( flags, size);
	return (ap1);
}
 
Operand *ENODE::GenAssignLogic(int flags, int size, int op)
{
	Operand *ap1, *ap2, *ap3;
	int ssize;
 
	ssize = GetNaturalSize(p[0]);
	if (ssize > size)
		size = ssize;
	if (p[0]->IsBitfield()) {
		ap3 = GetTempRegister();
		ap1 = GenerateBitfieldDereference(p[0], F_REG | F_MEM, size);
		GenerateDiadic(op_mov, 0, ap3, ap1);
		ap2 = GenerateExpression(p[1], F_REG | F_IMMED, size);
		GenerateTriadic(op, 0, ap1, ap1, ap2);
		GenerateBitfieldInsert(ap3, ap1, ap1->offset->bit_offset, ap1->offset->bit_width);
		GenStore(ap3, ap1->next, ssize);
		ReleaseTempReg(ap2);
		ReleaseTempReg(ap1->next);
		ReleaseTempReg(ap1);
		ap3->MakeLegal( flags, size);
		return (ap3);
	}
	ap1 = GenerateExpression(p[0], F_ALL & ~F_FPREG, ssize);
	ap2 = GenerateExpression(p[1], F_REG | F_IMMED, size);
	if (ap1->mode == am_reg) {
		GenerateTriadic(op, 0, ap1, ap1, ap2);
	}
	else {
		GenMemop(op, ap1, ap2, ssize);
	}
	ReleaseTempRegister(ap2);
	if (!ap1->isUnsigned && !(flags & F_NOVALUE)) {
		if (size > ssize) {
			if (ap1->mode != am_reg) {
				ap1->MakeLegal( F_REG, ssize);
			}
			switch (ssize) {
			case 1:	GenerateDiadic(op_sxb, 0, ap1, ap1); break;
			case 2:	GenerateDiadic(op_sxc, 0, ap1, ap1); break;
			case 4:	GenerateDiadic(op_sxh, 0, ap1, ap1); break;
			}
			ap1->MakeLegal( flags, size);
			return (ap1);
		}
		ap1->GenSignExtend(ssize, size, flags);
	}
	ap1->MakeLegal( flags, size);
	return (ap1);
}
 
Operand *ENODE::GenLand(int flags, int op)
{
	Operand *ap1, *ap2, *ap3, *ap4, *ap5;
 
	ap3 = GetTempRegister();
	ap1 = GenerateExpression(p[0], flags, 8);
	ap4 = GetTempRegister();
	GenerateDiadic(op_redor, 0, ap4, ap1);
	ap2 = GenerateExpression(p[1], flags, 8);
	ap5 = GetTempRegister();
	GenerateDiadic(op_redor, 0, ap5, ap2);
	GenerateTriadic(op, 0, ap3, ap4, ap5);
	ReleaseTempReg(ap5);
	ReleaseTempReg(ap2);
	ReleaseTempReg(ap4);
	ReleaseTempReg(ap1);
	ap3->MakeLegal( flags, 8);
	return (ap3);
}
 
void ENODE::PutConstant(txtoStream& ofs, unsigned int lowhigh, unsigned int rshift)
{
	// ASM statment text (up to 3500 chars) may be placed in the following buffer.
	static char buf[4000];
 
	switch (nodetype)
	{
	case en_autofcon:
		sprintf_s(buf, sizeof(buf), "%lld", i);
		ofs.write(buf);
		break;
	case en_fcon:
		goto j1;
		// The following spits out a warning, but is okay.
		sprintf_s(buf, sizeof(buf), "0x%llx", f);
		ofs.write(buf);
		break;
	case en_autovcon:
	case en_autocon:
	case en_icon:
		if (lowhigh == 2) {
			sprintf_s(buf, sizeof(buf), "%lld", i & 0xffff);
			ofs.write(buf);
		}
		else if (lowhigh == 3) {
			sprintf_s(buf, sizeof(buf), "%lld", (i >> 16) & 0xffff);
			ofs.write(buf);
		}
		else {
			sprintf_s(buf, sizeof(buf), "%lld", i);
			ofs.write(buf);
		}
		if (rshift > 0) {
			sprintf_s(buf, sizeof(buf), ">>%d", rshift);
			ofs.write(buf);
		}
		break;
	case en_labcon:
	j1:
		sprintf_s(buf, sizeof(buf), "%s_%lld", GetNamespace(), i);
		ofs.write(buf);
		if (rshift > 0) {
			sprintf_s(buf, sizeof(buf), ">>%d", rshift);
			ofs.write(buf);
		}
		break;
	case en_clabcon:
		sprintf_s(buf, sizeof(buf), "%s_%lld", GetNamespace(), i);
		ofs.write(buf);
		if (rshift > 0) {
			sprintf_s(buf, sizeof(buf), ">>%d", rshift);
			ofs.write(buf);
		}
		break;
	case en_nacon:
		sprintf_s(buf, sizeof(buf), "%s", (char *)sp->c_str());
		ofs.write(buf);
		if (lowhigh == 3) {
			sprintf_s(buf, sizeof(buf), ">>16");
			ofs.write(buf);
		}
		if (rshift > 0) {
			sprintf_s(buf, sizeof(buf), ">>%d", rshift);
			ofs.write(buf);
		}
		break;
	case en_cnacon:
		sprintf_s(buf, sizeof(buf), "%s", (char *)msp->c_str());
		ofs.write(buf);
		if (rshift > 0) {
			sprintf_s(buf, sizeof(buf), ">>%d", rshift);
			ofs.write(buf);
		}
		break;
	case en_add:
		p[0]->PutConstant(ofs, 0, 0);
		ofs.write("+");
		p[1]->PutConstant(ofs, 0, 0);
		break;
	case en_sub:
		p[0]->PutConstant(ofs, 0, 0);
		ofs.write("-");
		p[1]->PutConstant(ofs, 0, 0);
		break;
	case en_uminus:
		ofs.write("-");
		p[0]->PutConstant(ofs, 0, 0);
		break;
	default:
		printf("DIAG - illegal constant node.\n");
		break;
	}
}
 
ENODE *ENODE::GetConstantHex(std::ifstream& ifs)
{
	static char buf[4000];
	ENODE *ep;
 
	ep = allocEnode();
	ifs.read(buf, 2);
	buf[2] = '\0';
	ep->nodetype = (e_node)strtol(buf, nullptr, 16);
	switch (ep->nodetype) {
	case en_autofcon:
		ifs.read(buf, 8);
		buf[8] = '\0';
		ep->i = strtol(buf, nullptr, 16);
		break;
	case en_fcon:
		goto j1;
	case en_autovcon:
	case en_autocon:
	case en_icon:
		ifs.read(buf, 8);
		buf[8] = '\0';
		ep->i = strtol(buf, nullptr, 16);
		break;
	case en_labcon:
j1:		;
	}
}
 
void ENODE::PutConstantHex(txtoStream& ofs, unsigned int lowhigh, unsigned int rshift)
{
	// ASM statment text (up to 3500 chars) may be placed in the following buffer.
	static char buf[4000];
 
	ofs.printf("N%02X", nodetype);
	switch (nodetype)
	{
	case en_autofcon:
		sprintf_s(buf, sizeof(buf), "%08LLX", i);
		ofs.write(buf);
		break;
	case en_fcon:
		goto j1;
	case en_autovcon:
	case en_autocon:
	case en_icon:
		sprintf_s(buf, sizeof(buf), "%08llX", i);
		ofs.write(buf);
		break;
	case en_labcon:
	j1:
		sprintf_s(buf, sizeof(buf), "%s_%lld:", GetNamespace(), i);
		ofs.write(buf);
		break;
	case en_clabcon:
		sprintf_s(buf, sizeof(buf), "%s_%lld:", GetNamespace(), i);
		ofs.write(buf);
		break;
	case en_nacon:
		sprintf_s(buf, sizeof(buf), "%s:", (char *)sp->c_str());
		ofs.write(buf);
		break;
	case en_cnacon:
		sprintf_s(buf, sizeof(buf), "%s:", (char *)msp->c_str());
		ofs.write(buf);
		break;
	case en_add:
		p[0]->PutConstantHex(ofs, 0, 0);
		ofs.write("+");
		p[1]->PutConstantHex(ofs, 0, 0);
		break;
	case en_sub:
		p[0]->PutConstantHex(ofs, 0, 0);
		ofs.write("-");
		p[1]->PutConstantHex(ofs, 0, 0);
		break;
	case en_uminus:
		ofs.write("-");
		p[0]->PutConstantHex(ofs, 0, 0);
		break;
	default:
		printf("DIAG - illegal constant node.\n");
		break;
	}
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.