⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ccout.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
		outtab ();
		outtab ();
		outnum (p->Pdouble2);
		outc (']');
		}
	    if (!delete)			/* If keeping asm file around, */
		fprintf (out,"\t; %.20g",p->Pdouble); /* add comment for humans */
	    break;

	default:
	    int_error ("outinstr: bad adrmode %d", (p->Ptype & PTF_ADRMODE));
	}
    outnl ();			/* Done with instruction, finish off! */

    if (vrbfun)
	_word_cnt++;
}

/* ONEINSTR (p) - See if an instruction is safe to skip over.
**
** Takes an instruction as argument and returns true if that
** instruction will expand to one machine code word.
** This routine is in CCOUT because it must accurately reflect what
** CCOUT will actually do for a given pseudo-instruction.
*/
int
oneinstr (PCODE *p)
{
    switch (p->Pop & POF_OPCODE)
	{

    /* Simulated ops always expand out. */
	case P_PTRCNV:
	case P_SMOVE:
	case P_UIDIV:
	case P_UFLTR:
	case P_SUBBP:
	case P_DFIX:
	case P_DSNGL:
	    return 0;

    /* These instructions may or may not expand out, depending on the
    ** target machine.  If unsupported, they are actually macros defined
    ** by the assembler header.
    ** None of them have an "immediate" form, so PTV_IINDEXED can never happen.
    */
	case P_DMOVE:
	case P_DMOVN:
	case P_DMOVEM:
	    return 1;			/* TRUE if machine has DMOVx */
	case P_ADJBP:
	    return 1;			/* TRUE if machine has ADJBP */
	case P_DFAD:
	case P_DFSB:
	case P_DFMP:
	case P_DFDV:
	    return 1;			/* TRUE if machine has hardware dbls */
	case P_FLTR:
	    return 1;			/* TRUE if machine has hardware FLTR */

	case P_TRN:
	case P_TRO:
	case P_TRC:
	case P_TRZ:	/* RH tests */
	case P_TLN:
	case P_TLO:
	case P_TLC:
	case P_TLZ:	/* LH tests */
	case P_CAI:
	case P_LSH:
	case P_ASH:
	    return (p->Ptype != PTA_MINDEXED);	/* PTV_IINDEXED for implicit immed op */

    /* All other (standard) instructions.
    */
	default:			/* OPI R,addr  expands to */
	    return (p->Ptype != PTV_IINDEXED);	/* MOVEI 16,addr ? OP r,16 */

    /* Special case of above, which always wins */
	case P_MOVE:
	case P_MOVEI:
	    return 1;			/* OK even for PTV_IINDEXED */
	}
}

static int
directop (int op)
{
    switch (op & POF_OPCODE)
	{
	case P_CAI:
	    return op ^ (P_CAI ^ P_CAM);
	case P_TRN:
	    return op ^ (P_TRN ^ P_TDN);
	case P_TRO:
	    return op ^ (P_TRO ^ P_TDO);
	case P_TRC:
	    return op ^ (P_TRC ^ P_TDC);
	case P_TRZ:
	    return op ^ (P_TRZ ^ P_TDZ);
	default:
	    return 0;
	}
}

/* SIMUFLTR - Output expansion of P_UFLTR unsigned float "instruction".
**	UFLTR R,M
**		R = register to leave single-precision float in.
**		M = any memory reference to single-word integer operand
**
** Note that for machines without the FLTR instruction, we don't even
** bother to get things right since the usual substitute (FSC R,233) won't
** work.  Need a fancy KA-10 float routine.
**
** Expands into:
**	if R == M	if R != M
**	SKIPGE 16,M	SKIPGE R,M	; Fetch or copy the float
**	 LSH R,-1	 LSH R,-1	; If sign bit set, shift down
**	FLTR R,R	FLTR R,R	; Float the positive integer!
**	CAIGE 16,	SKIPGE M	; If number was shifted,
**	 FSC R,1	 FSC R,1	; adjust exponent accordingly.
*/
static void
simufltr (PCODE *p)
{
    int r = p->Preg;
    int mr = ((p->Ptype&PTF_ADRMODE) == PTA_REGIS) ? p->Pr2 : 0;

    p->Pop = P_SKIP+POF_ISSKIP+POS_SKPGE;
    if (r == mr)
	p->Preg = R_SCRREG;	/* 16 */
    outinstr (p);			/* SKIPGE R,M or SKIPGE 16,R */
    fprintf (out,"\t LSH\t%o,-1\n", r);		/* LSH R,-1 */
    fprintf (out,"\tFLTR\t%o,%o\n", r, r);	/* FLTR R,R */

    if (r == mr)
	fprintf (out,"\tCAIGE\t%o,\n", R_SCRREG);	/* CAIGE 16, */
    else					/* or */
	{
	if (mr)
	    fprintf (out,"\tCAIGE\t%o,\n", R_SCRREG);	/* CAIGE R, */
	else
	    {
	    outstr ("\tSKIPGE ");			/* SKIPGE M */
	    outaddress (p);
	    outnl ();
	    }
	}
    fprintf (out,"\t FSC\t%o,1\n", r);		/* FSC R,1 */
}

/* SIMDFIX - Output expansion of P_DFIX double-to-integer conversion "instr"
**	P_DFIX reg,M
**		reg = register pair, integer will be left in 1st reg.
**		M = any memory ref to double-word float operand.
**
** Note that reg+1 is clobbered!
** Expands into:
**	DMOVE	R,M
**	HLRE	16,R		;This mattered when shifts were bit-at-a-time
**	ASH	16,-11		;Get just exponent (9 bits)
**	JUMPGE	16,.+3		;Positive?
**	  DMOVN	R,R		;No, negate, orig sign still in 1B0[A]
**				; For KA-10 format this is DFN R,R+1.
**	  TRC	16,777777	;Watch for diff between twos and ones comp
**	TLZ	R,777000	;Bash exponent and sign ... now positive
**				; For KA-10 format, LSH R+1,10 goes here.
**	ASHC	R,-233 (16)	;Make an integer (may overflow)
**	CAIGE	16,		;Original negative?  Check its sign.
**	 MOVN	R,R		;Yup, negate result.
*/
static void
simdfix (PCODE *p)
{
    int r = p->Preg;

    /* Check for DFIX R,R and skip the DMOVE if that's what we have */
    if ((p->Ptype&PTF_ADRMODE) != PTA_REGIS || r != p->Pr2)
	{
	p->Pop = P_DMOVE;		/* Make DMOVE R,M to get double */
	outinstr (p);
	}
    fprintf (out, "\tHLRE\t16,%o\n\tASH\t16,-11\n\tJUMPGE\t16,.+3\n", r);
    fprintf (out, "\tDMOVN\t%o,%o\n", r, r);
    outstr ("\tTRC\t16,-1\n");

    fprintf (out, "\tTLZ\t%o,777000\n", r);
    fprintf (out, "\tASHC\t%o,-233 (16)\n", r);
    outstr ("\tCAIGE\t16,\n");		/* Check sign bit of original # */
    fprintf (out, "\t MOVNS\t%o\n", r);	/* Negate result */
}

/* SIMDSNGL - Output expansion of P_DSNGL double-to-float conversion "instr"
**	P_DSNGL reg,M
**		reg = register pair, float will be left in 1st reg.
**		M = any memory ref to double-word float operand.
**
** Note that reg+1 is clobbered!
** Expands into:
**	DMOVE R,M		; Get double value
**	SKIPGE 16,R		; Check sign, save indicator
**	 DMOVN R,R		; Negative, make positive temporarily.
**	TLNE R+1,200000		; If low word >= .5
**	 TRON R,1		; then must round high wd, try fast hack
**	  JRST .+4		; Won!
**	   MOVE R+1,R		; Ugh, have to do it hard way.  Copy high wd
**	   AND R+1,[777000000001]	; Zap all but exp and low-order bit
**	   FADR R,R+1		; Add low bit to effect rounding
**	CAIGE 16,		; Now if original was negative,
**	 MOVN R,R		; make it negative again.
*/
static void
simdsngl (PCODE *p)
{
    int r = p->Preg;
    /* Check for DSNGL R,R and skip the DMOVE if that's what we have */
    if ((p->Ptype&PTF_ADRMODE) != PTA_REGIS || r != p->Pr2)
	{
	p->Pop = P_DMOVE;		/* Make DMOVE R,M to get double */
	outinstr (p);
	}
    fprintf (out, "\tSKIPGE\t16,%o\n", r);
    fprintf (out, "\t DMOVN\t%o,%o\n", r, r);
    fprintf (out, "\tTLNE\t%o,200000\n", r+1);
    fprintf (out, "\t TRON\t%o,1\n\t  JRST\t.+4\n", r);
    fprintf (out, "\tMOVE\t%o,%o\n\tAND\t%o,[777000,,1]\n\tFADR\t%o,%o\n",
		r+1, r,
		r+1,
		r, r+1);

    outstr ("\tCAIGE\t16,\n");		/* Check sign bit of original # */
    fprintf (out, "\t MOVNS\t%o\n", r);	/* Negate result */
}

/* SIMSUBBP - Output expansion of P_SUBBP byte-pointer subtraction "instr".
**	P_SUBBP reg,M		[plus Pbsize set to bytesize if known]
**		reg = register pair, 1st reg contains minuend BP
**		M = any memory ref to subtrahend BP
**		Pbsize = bytesize of pointers (> 0 if known)
**			This is currently only used if M operand is P_CONST.
**	Leaves resulting # in 2nd reg!
**
**	This makes use of 2 special symbols from CPU.C and
** some tables in CRT.C, and expands into:
**	Known size		Unknown size
**				LDB 16,[$$BPSZ,,R]	; get PS from R
**	SUB R,M			SUB R,M
**	MULI R,$$BMPn		MUL R,$BPMUL (16)
**	ASH R+1,$$BSHF		ASH R+1,$$BSHF
**				ADD R,$BPADT (16)
**	ADD R+1,$BPADn (A)	ADD R+1, (A)
*/
static void
simsubbp (PCODE *p)
{
    int siz, typ, tbidx;

    if ((typ = (p->Ptype&PTF_ADRMODE)) == PTA_PCONST)
	siz = (int) p->Pbsize;		/* Aha, size is known! */
    else
	siz = 0;

    switch (siz)
	{
	case 6:
	    tbidx = 0;
	    break;
	case 7:
	    tbidx = 1;
	    break;
	case 8:
	    tbidx = 2;
	    break;
	case 9:
	    tbidx = 3;
	    break;
	case 18:
	    tbidx = 4;
	    break;
	default:
	    int_error ("simsubbp: bad Pbsize: %ld", (INT) siz);
	    siz = 0;
	case 0:
	    fprintf (out, "\tLDB\t16,[%s,,%o]\n", crtsnam[CRT_BPSZ], p->Preg);
	    crtref[CRT_BPSZ]++;
	}

    /* Simple check to verify addressing mode is OK */
    switch (typ)
	{
	case PTA_PCONST:
	case PTA_REGIS:
	case PTA_MINDEXED:
	    break;
	default:
	    int_error ("simsubbp: bad adrmode: %ld", (INT) typ);
	}
    p->Pop = P_SUB;			/* Make SUB R,M */
    outinstr (p);

    if (siz)
	{
	fprintf (out, "\tMULI\t%o,%s\n", p->Preg, crtsnam[CRT_BMP6+tbidx]);
	crtref[CRT_BMP6+tbidx]++;
	}
    else
	{
	fprintf (out, "\tMUL\t%o,%s (16)\n", p->Preg, crtsnam[CRT_BPMUL]);
	crtref[CRT_BPMUL]++;
	}
    fprintf (out, "\tASH\t%o,-%s\n", p->Preg+1, crtsnam[CRT_BSHF]);
    crtref[CRT_BSHF]++;
    if (!siz)
	{
	fprintf (out, "\tADD\t%o,%s (16)\n", p->Preg, crtsnam[CRT_BPADT]);
	crtref[CRT_BPADT]++;
	fprintf (out, "\tADD\t%o, (%o)\n", p->Preg+1, p->Preg);
	}
    else
	{
	fprintf (out, "\tADD\t%o,%s (%o)\n",
		p->Preg+1, crtsnam[CRT_BPAD6+tbidx], p->Preg);
	crtref[CRT_BPAD6+tbidx]++;
	}
}

/*
** NOTE:
** Byte pointer comparison used to be simulated too but now is done
** with explicit instructions by CCGEN2.
*/
/* NOTE:
** Some PDP-10 architecture machines have no ADJBP instruction.
** We used to expand a sequence for P_ADJBP similar to that for
** P_SUBBP, but now we always just output P_ADJBP
** as ADJBP R,X and it is up to the C-HDR preamble file to redefine
** ADJBP as a macro (in a form similar to the above) if the machine
** does not support ADJBP.  This allows machine-language library routines
** to use ADJBP in their code.
*/

/* SIMPTRCNV - Output expansion of P_PTRCNV pointer conversion "instruction".
**	P_PTRCNV reg,offset	[plus Pbsize set to desired bytesize]
**		reg = register containing pointer to convert
**		offset = bytesize of old pointer
**		Pbsize = desired bytesize of new pointer
**
**	Currently this only supports 9<->18 bit conversions, and the
** code generator shouldn't give us anything else.
** The interaction between the special instruction symbols defined in the
** library $$$CPU module and the code here has been carefully arranged.
** In particular the instructions must take up the same amount of space
** whether being loaded for zero-section or multi-section operation, and
** they must NOT change the value of a NULL (zero) pointer.
**
** The conversions to and from word pointers are done by the code
** generator (with TDZ/TLZ or SKIPE+IOR/TLO) because it may be possible
** for the peephole optimizer to do something with those instructions.
*/
static void
simptrcnv (PCODE *p)
{
    int *ip;
#ifdef	MULTI_SECTION /* FW 2A (51) */
    static INT cvH_9[] = {CRT_PH90, CRT_PH91, 0};
    static INT cv9_H[] = {CRT_P9H0, CRT_P9H1, CRT_P9H2, 0};
#endif


    /* Switch depending on original size plus desired size */
    switch ((int) (TGSIZ_WORD* p->Poffset + p->Pbsize))
	{
	case TGSIZ_WORD* 9 + 18:	/* 9-bit to 18-bit */
		fprintf (out, "\tTLZE\t%o,117700\n", p->Preg);
		fprintf (out, "\t TLO\t%o,002200\n", p->Preg);
		return;

	case TGSIZ_WORD* 18 + 9:	/* 18-bit to 9-bit */
		fprintf (out, "\tTLZE\t%o,007700\n", p->Preg);
		fprintf (out, "\t TLO\t%o,111100\n", p->Preg);
		return;

	default:
	    int_error ("simptrcnv: bad bsize: %ld", (INT) p->Pbsize);
	    return;
	}

    /* Wrap up with special instructions the value of which depends
    ** on whether the code is being loaded for a zero-section or
    ** multi-section program.  The specified register is added into
    ** the symbols in such a way that it fits into the AC field.
    */
    for (; *ip; ++ip)
	{
	fprintf (out,"\t%s+<%lo>\n", crtsnam[*ip], (INT) p->Preg<<23);
	++crtref[*ip];
	}
}

/* SIMSMOVE - Output expansion of P_SMOVE structure copy "instruction".
**	P_SMOVE reg,addr+offset (idx)  [plus Pbsize set to # words]
**		reg = register containing destination word address
**		addr+offset (idx) = source address
**		Pbsize = # words to copy
*/
static void
simsmove (PCODE *p)
{
    INT size;

    if ((p->Ptype&PTF_ADRMODE) != PTA_MINDEXED)
	{
	int_error ("simsmove: bad adrmode:\t%o", p->Ptype);
	return;
	}
    switch ((int) (size = p->Pbsize))
	{
	case 1:
	case 2:
	    fprintf (out,"\tMOVEI\t16,-1 (%o)\n", p->Preg); /* dest <addr-1> */
	    while (--size >= 0)
		{
		outstr ("\tPUSH\t16,");
		outaddress (p);
		outnl ();
		++ (p->Poffset);
		}
	    return;

	default:

	    if (size <= 0)
		{
		int_error ("simsmove: bad size %ld", (INT) size);
		return;
		}

	    fprintf (out,"\tMOVEI\t16, (%o)\n\tHRLI\t16,",p->Preg);
	    outaddress (p);		/* for HRLI\t16,<source-addr> */
	    fprintf (out,"\n\tBLT\t16,%lo (%o)\n", (INT) size-1, p->Preg);
	    return;
	}
    }

/* SIMUIDIV - Output expansion of P_UIDIV unsigned division "instruction".
**	P_UIDIV reg,<addr>
**		reg = register containing dividend (two-word register)
**		addr = divisor

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -