ORCA-C/Gen.pas

7922 lines
256 KiB
ObjectPascal

{$optimize 7}
{---------------------------------------------------------------}
{ }
{ Gen }
{ }
{ Generates native code from intermediate code instructions. }
{ }
{---------------------------------------------------------------}
unit Gen;
interface
{$segment 'gen'}
{$LibPrefix '0/obj/'}
uses CCommon, CGI, CGC, ObjOut, Native;
{---------------------------------------------------------------}
function LabelToDisp (lab: integer): integer;
{ convert a local label number to a stack frame displacement }
{ }
{ parameters: }
{ lab - label number }
procedure Gen (blk: blockPtr);
{ Generates native code for a list of blocks }
{ }
{ parameters: }
{ blk - first of the list of blocks }
{---------------------------------------------------------------}
implementation
const
{longword/quadword locations}
A_X = 1; {longword only}
onStack = 2;
inPointer = 4;
localAddress = 8;
globalLabel = 16;
constant = 32;
nowhere = 64;
inStackLoc = 128;
{stack frame locations}
{---------------------}
returnSize = 3; {size of return address}
type
{possible locations for 4 byte values}
longType = record {description of current four byte value}
preference: integer; {where you want the value (bitmask)}
where: integer; {where the value is at}
fixedDisp: boolean; {is the displacement a fixed value?}
isLong: boolean; {is long addr required for named labs?}
disp: integer; {fixed displacement/local addr}
lval: longint; {value}
lab: stringPtr; {global label name}
end;
{possible locations for 8 byte values}
{note: these always have fixed disp}
quadType = record {description of current 8 byte value}
preference: integer; {where you want the value (single value)}
where: integer; {where the value is at}
disp: integer; {fixed displacement/local addr}
lval: longlong; {value}
lab: stringPtr; {global label name}
end;
var
gLong: longType; {info about last long value}
gQuad: quadType; {info about last quad value}
namePushed: boolean; {has a name been pushed in this proc?}
skipLoad: boolean; {skip load for a pc_lli, etc?}
stackSaveDepth: integer; {nesting depth of saved stack positions}
argsSize: integer; {total size of argument to a function}
isQuadFunction: boolean; {is the return type cg(U)Quad?}
{stack frame locations}
{---------------------}
bankLoc: integer; {disp in dp where bank reg is stored}
dworkLoc: integer; {disp in dp of 4 byte work spage for cg}
funLoc: integer; {loc of fn ret value in stack frame}
localSize: integer; {local space for current proc}
parameterSize: integer; {# bytes of parameters for current proc}
stackLoc: integer; {disp in dp where stack reg is stored}
{---------------------------------------------------------------}
procedure GenTree (op: icptr); forward;
procedure OperA (mop: integer; op: icptr);
{ Do an operation on op that has addr modes equivalent to STA }
{ }
{ parameters: }
{ op - node to generate the leaf for }
{ mop - operation }
var
loc: integer; {stack frame position}
opcode: pcodes; {temp storage}
begin {OperA}
opcode := op^.opcode;
case opcode of
pc_ldo,pc_gil,pc_gli,pc_gdl,pc_gld: begin
case mop of
m_cmp_imm: mop := m_cmp_abs;
m_adc_imm: mop := m_adc_abs;
m_and_imm: mop := m_and_abs;
m_ora_imm: mop := m_ora_abs;
m_sbc_imm: mop := m_sbc_abs;
m_eor_imm: mop := m_eor_abs;
otherwise: Error(cge1);
end; {case}
if opcode = pc_gil then
GenNative(m_inc_abs, absolute, op^.q, op^.lab, 0)
else if opcode = pc_gdl then
GenNative(m_dec_abs, absolute, op^.q, op^.lab, 0);
if smallMemoryModel then
GenNative(mop, absolute, op^.q, op^.lab, 0)
else
GenNative(mop+2, longAbs, op^.q, op^.lab, 0);
if opcode in [pc_gli,pc_gld] then begin
if mop in [m_sbc_dir,m_cmp_dir] then
GenImplied(m_php);
if opcode = pc_gli then
GenNative(m_inc_abs, absolute, op^.q, op^.lab, 0)
else {if opcode = pc_gld then}
GenNative(m_dec_abs, absolute, op^.q, op^.lab, 0);
if mop in [m_sbc_dir,m_cmp_dir] then
GenImplied(m_plp);
end; {else}
end; {case pc_ldo,pc_gil,pc_gli,pc_gdl,pc_gld}
pc_lod,pc_lli,pc_lil,pc_lld,pc_ldl: begin
case mop of
m_cmp_imm: mop := m_cmp_dir;
m_adc_imm: mop := m_adc_dir;
m_and_imm: mop := m_and_dir;
m_ora_imm: mop := m_ora_dir;
m_sbc_imm: mop := m_sbc_dir;
m_eor_imm: mop := m_eor_dir;
otherwise: Error(cge1);
end; {case}
loc := LabelToDisp(op^.r);
if opcode = pc_lod then
loc := loc + op^.q;
if opcode = pc_lil then
GenNative(m_inc_dir, direct, loc, nil, 0)
else if opcode = pc_ldl then
GenNative(m_dec_dir, direct, loc, nil, 0);
GenNative(mop, direct, loc, nil, 0);
if opcode in [pc_lli,pc_lld] then begin
if mop in [m_sbc_dir,m_cmp_dir] then
GenImplied(m_php);
if opcode = pc_lli then
GenNative(m_inc_dir, direct, loc, nil, 0)
else {if opc = pc_lld then}
GenNative(m_dec_dir, direct, loc, nil, 0);
if mop in [m_sbc_dir,m_cmp_dir] then
GenImplied(m_plp);
end; {else}
end; {case pc_lod,pc_lli,pc_lil,pc_lld,pc_ldl}
pc_ldc:
GenNative(mop, immediate, op^.q, nil, 0);
otherwise:
Error(cge1);
end; {case}
end; {OperA}
function Complex (op: icptr): boolean;
{ determine if loading the intermediate code involves anything }
{ but one reg }
{ }
{ parameters: }
{ code - intermediate code to check }
{ }
{ NOTE: for one and two byte values only!!! }
begin {Complex}
Complex := true;
if op^.opcode in [pc_ldo,pc_ldc] then
Complex := false
else if op^.opcode in [pc_gil,pc_gli,pc_gdl,pc_gld] then
Complex := smallMemoryModel
else if op^.opcode = pc_lod then
if LabelToDisp(op^.r) + op^.q < 256 then
Complex := false
else if op^.opcode in [pc_lli,pc_lil,pc_ldl,pc_lld] then
if LabelToDisp(op^.r) < 256 then
Complex := false;
if op^.optype in [cgByte,cgUByte] then
Complex := true;
end; {Complex}
procedure DoOp(op_imm, op_abs, op_dir: integer; icode: icptr; disp: integer);
{ Do an operation. }
{ }
{ Parameters: }
{ op_imm,op_abs,op_dir - op codes for the various }
{ addressing modes }
{ icode - intermediate code record }
{ disp - disp past the location (1 or 2) }
var
val: integer; {value for immediate operations}
lval: longint; {long value for immediate operations}
begin {DoOp}
if icode^.opcode = pc_ldc then begin
lval := icode^.lval;
if disp = 0 then
val := long(lval).lsw
else
val := long(lval).msw;
GenNative(op_imm, immediate, val, nil, 0);
end {if}
else if icode^.opcode in [pc_lod,pc_str] then
GenNative(op_dir, direct, LabelToDisp(icode^.r) + icode^.q + disp, nil, 0)
else {if icode^.opcode in [pc_ldo, pc_sro] then}
GenNative(op_abs, absolute, icode^.q + disp, icode^.lab, 0);
end; {DoOp}
procedure OpOnWordOfQuad (mop: integer; op: icptr; offset: integer);
{ Do an operation that has addr modes equivalent to LDA on the }
{ subword at specified offset of the location specified by op. }
{ }
{ The generated code may modify X, and may set Y to offset. }
{ }
{ parameters: }
{ mop - machine opcode }
{ op - node to generate the leaf for }
{ offset - offset of the word to access (0, 2, 4, or 6) }
var
loc: integer; {stack frame position}
val: integer; {immediate value}
begin {OpOnWordOfQuad}
case op^.opcode of
pc_ldo: begin
case mop of
m_lda_imm: mop := m_lda_abs;
m_cmp_imm: mop := m_cmp_abs;
m_adc_imm: mop := m_adc_abs;
m_and_imm: mop := m_and_abs;
m_ora_imm: mop := m_ora_abs;
m_sbc_imm: mop := m_sbc_abs;
m_eor_imm: mop := m_eor_abs;
otherwise: Error(cge1);
end; {case}
if smallMemoryModel then
GenNative(mop, absolute, op^.q+offset, op^.lab, 0)
else
GenNative(mop+2, longAbs, op^.q+offset, op^.lab, 0);
end; {case pc_ldo}
pc_lod: begin
case mop of
m_lda_imm: mop := m_lda_dir;
m_cmp_imm: mop := m_cmp_dir;
m_adc_imm: mop := m_adc_dir;
m_and_imm: mop := m_and_dir;
m_ora_imm: mop := m_ora_dir;
m_sbc_imm: mop := m_sbc_dir;
m_eor_imm: mop := m_eor_dir;
otherwise: Error(cge1);
end; {case}
loc := LabelToDisp(op^.r) + op^.q + offset;
if loc < 256 then
GenNative(mop, direct, loc, nil, 0)
else begin
GenNative(m_ldx_imm, immediate, loc, nil, 0);
GenNative(mop+$10, direct, 0, nil, 0);
end; {else}
end; {case pc_lod}
pc_ldc: begin
case offset of
0: val := long(op^.qval.lo).lsw;
2: val := long(op^.qval.lo).msw;
4: val := long(op^.qval.hi).lsw;
6: val := long(op^.qval.hi).msw;
otherwise: Error(cge1);
end; {case}
GenNative(mop, immediate, val, nil, 0);
end; {case pc_ldc}
pc_ind: begin
case mop of
m_lda_imm: mop := m_lda_indl;
m_cmp_imm: mop := m_cmp_indl;
m_adc_imm: mop := m_adc_indl;
m_and_imm: mop := m_and_indl;
m_ora_imm: mop := m_ora_indl;
m_sbc_imm: mop := m_sbc_indl;
m_eor_imm: mop := m_eor_indl;
otherwise: Error(cge1);
end; {case}
if op^.left^.opcode = pc_lod then
loc := LabelToDisp(op^.left^.r) + op^.left^.q;
if (op^.left^.opcode <> pc_lod) or (loc > 255) then
Error(cge1);
offset := offset + op^.q;
if offset = 0 then
GenNative(mop, direct, loc, nil, 0)
else begin
GenNative(m_ldy_imm, immediate, offset, nil, 0);
GenNative(mop+$10, direct, loc, nil, 0);
end; {else}
end; {case pc_ind}
otherwise:
Error(cge1);
end; {case}
end; {OpOnWordOfQuad}
function SimpleQuadLoad(op: icptr): boolean;
{ Is op a simple load operation on a cg(U)Quad, which can be }
{ broken up into word operations handled by OpOnWordOfQuad? }
{ }
{ parameters: }
{ op - node to check }
begin {SimpleQuadLoad}
case op^.opcode of
pc_ldo,pc_lod,pc_ldc:
SimpleQuadLoad := true;
pc_ind:
SimpleQuadLoad :=
(op^.left^.opcode = pc_lod)
and (LabelToDisp(op^.left^.r) + op^.left^.q < 256);
otherwise:
SimpleQuadLoad := false;
end; {case}
end; {SimpleQuadLoad}
function SimplestQuadLoad(op: icptr): boolean;
{ Is op a simple load operation on a cg(U)Quad, which can be }
{ broken up into word operations handled by OpOnWordOfQuad }
{ and for which those operations will not modify X or Y. }
{ }
{ parameters: }
{ op - node to check }
begin {SimplestQuadLoad}
case op^.opcode of
pc_ldo,pc_ldc:
SimplestQuadLoad := true;
pc_lod:
SimplestQuadLoad := LabelToDisp(op^.r) + op^.q < 250;
pc_ind,otherwise:
SimplestQuadLoad := false;
end; {case}
end; {SimplestQuadLoad}
procedure StoreWordOfQuad(offset: integer);
{ Store one word of a quad value to the location specified by }
{ gQuad.preference. The word value to store must be in A. }
{ }
{ The generated code may modify X, and may set Y to offset. }
{ It does not modify A or the carry flag. }
{ }
{ parameters: }
{ offset - offset of the word to store (0, 2, 4, or 6) }
{ }
{ Note: If gQuad.preference is onStack, this just generates a }
{ PHA. That is suitable if storing a value starting from }
{ the most significant word, but not in other cases. For }
{ other gQuad.preference values, any order is okay. }
begin {StoreWordOfQuad}
case gQuad.preference of
localAddress: begin
if gQuad.disp+offset <= 255 then
GenNative(m_sta_dir, direct, gQuad.disp+offset, nil, 0)
else begin
GenNative(m_ldx_imm, immediate, gQuad.disp+offset, nil, 0);
GenNative(m_sta_dirX, direct, 0, nil, 0);
end; {else}
end;
globalLabel: begin
if smallMemoryModel then
GenNative(m_sta_abs, absolute, gQuad.disp+offset, gQuad.lab, 0)
else
GenNative(m_sta_long, longabsolute, gQuad.disp+offset, gQuad.lab, 0);
end;
inPointer: begin
if (gQuad.disp > 255) or (gQuad.disp < 0) then
Error(cge1);
if offset = 0 then
GenNative(m_sta_indl, direct, gQuad.disp, nil, 0)
else begin
GenNative(m_ldy_imm, immediate, offset, nil, 0);
GenNative(m_sta_indly, direct, gQuad.disp, nil, 0);
end; {else}
end;
inStackLoc:
GenNative(m_sta_s, direct, gQuad.disp+offset, nil, 0);
onStack:
GenImplied(m_pha);
nowhere: ; {discard the value}
otherwise: Error(cge1);
end; {case}
end; {StoreWordOfQuad}
procedure GetPointer (op: icptr);
{ convert a tree into a usable pointer for indirect }
{ loads/stores }
{ }
{ parameters: }
{ op - pointer tree }
begin {GetPointer}
gLong.preference := A_X+inPointer+localAddress+globalLabel;
GenTree(op);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
gLong.where := A_X;
end; {if}
if gLong.where = A_X then begin
GenNative(m_sta_dir, direct, dworkLoc, nil, 0);
GenNative(m_stx_dir, direct, dworkLoc+2, nil, 0);
gLong.where := inPointer;
gLong.fixedDisp := true;
gLong.disp := dworkLoc;
end; {else if}
end; {GetPointer}
procedure IncAddr (size: integer);
{ add a two byte constant to a four byte value - generally an }
{ address }
{ }
{ parameters: }
{ size - integer to add }
var
lab1: integer; {branch point}
begin {IncAddr}
if size <> 0 then
case gLong.where of
onStack: begin
lab1 := GenLabel;
GenImplied(m_pla);
if size = 1 then begin
GenImplied(m_ina);
GenNative(m_bne, relative, lab1, nil, 0);
end {if}
else begin
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, size, nil, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
end; {else}
GenImplied(m_plx);
GenImplied(m_inx);
GenImplied(m_phx);
GenLab(lab1);
GenImplied(m_pha);
end;
A_X: begin
lab1 := GenLabel;
if size = 1 then begin
GenImplied(m_ina);
GenNative(m_bne, relative, lab1, nil, 0);
end {if}
else begin
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, size, nil, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
end; {else}
GenImplied(m_inx);
GenLab(lab1);
end;
inPointer:
if gLong.fixedDisp then begin
gLong.fixedDisp := false;
GenNative(m_ldy_imm, immediate, size, nil, 0);
end {if}
else if size <= 4 then begin
while size <> 0 do begin
GenImplied(m_iny);
size := size - 1;
end; {while}
end {else if}
else begin
GenImplied(m_tya);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, size, nil, 0);
GenImplied(m_tay);
end; {else}
localAddress,globalLabel:
gLong.disp := gLong.disp+size;
otherwise:
Error(cge1);
end; {case}
end; {IncAddr}
procedure LoadX (op: icptr);
{ Load X with a two byte value }
{ }
{ parameters: }
{ op - value to load }
var
q, r: integer;
lab: stringPtr;
begin {LoadX}
q := op^.q;
r := op^.r;
lab := op^.lab;
case op^.opcode of
pc_lao,pc_lda:
Error(cge1);
pc_ldc:
GenNative(m_ldx_imm, immediate, q, nil, 0);
pc_ldo:
GenNative(m_ldx_abs, absolute, q, lab, 0);
pc_gli: begin
GenNative(m_ldx_abs, absolute, q, lab, 0);
GenNative(m_inc_abs, absolute, q, lab, 0);
end; {if}
pc_gil: begin
GenNative(m_inc_abs, absolute, q, lab, 0);
GenNative(m_ldx_abs, absolute, q, lab, 0);
end; {if}
pc_gld: begin
GenNative(m_ldx_abs, absolute, q, lab, 0);
GenNative(m_dec_abs, absolute, q, lab, 0);
end; {if}
pc_gdl: begin
GenNative(m_dec_abs, absolute, q, lab, 0);
GenNative(m_ldx_abs, absolute, q, lab, 0);
end; {if}
pc_lod:
GenNative(m_ldx_dir, direct, LabelToDisp(r) + q, nil, 0);
pc_lli: begin
GenNative(m_ldx_dir, direct, LabelToDisp(r), nil, 0);
GenNative(m_inc_dir, direct, LabelToDisp(r), nil, 0);
end; {if}
pc_lil: begin
GenNative(m_inc_dir, direct, LabelToDisp(r), nil, 0);
GenNative(m_ldx_dir, direct, LabelToDisp(r), nil, 0);
end; {if}
pc_lld: begin
GenNative(m_ldx_dir, direct, LabelToDisp(r), nil, 0);
GenNative(m_dec_dir, direct, LabelToDisp(r), nil, 0);
end; {if}
pc_ldl: begin
GenNative(m_dec_dir, direct, LabelToDisp(r), nil, 0);
GenNative(m_ldx_dir, direct, LabelToDisp(r), nil, 0);
end; {if}
otherwise:
Error(cge1);
end; {case}
end; {LoadX}
function NeedsCondition (opcode: pcodes): boolean;
{ See if the operation is one that doesn't set the condition }
{ code reliably }
{ }
{ Parameters: }
{ opcodes - operation to check }
{ }
{ Returns: True if the condition code is not set properly for }
{ an operand type of cgByte,cgUByte,cgWord,cgUWord, else }
{ false }
begin {NeedsCondition}
NeedsCondition := opcode in
[pc_and,pc_ior,pc_cui,pc_cup,pc_ldl,pc_lil,pc_lld,
pc_lli,pc_gil,pc_gli,pc_gdl,pc_gld,pc_iil,pc_ili,pc_idl,pc_ild,
pc_cop,pc_cpo,pc_cpi,pc_dvi,pc_mpi,pc_adi,pc_sbi,pc_mod,pc_bno,
pc_udi,pc_uim,pc_umi,pc_cnv,pc_rbo,pc_shl,pc_shr,pc_usr,pc_lbf,
pc_lbu,pc_cbf,pc_tri];
end; {NeedsCondition}
function SameLoc (load, save: icptr): boolean;
{ See if load and save represent the same location (which must }
{ be a direct page value or a global label). }
{ }
{ parameters: }
{ load - load operation }
{ save - save operation }
{ }
{ Returns: True the the same location is used, else false }
begin {SameLoc}
SameLoc := false;
if save <> nil then begin
if load^.opcode = pc_lod then begin
if LabelToDisp(load^.r) + load^.q < 254 then
if save^.opcode = pc_str then
if save^.q = load^.q then
if save^.r = load^.r then
SameLoc := true;
end {if}
else if smallMemoryModel then
if load^.opcode = pc_ldo then
if save^.opcode = pc_sro then
if load^.lab^ = save^.lab^ then
if load^.q = save^.q then
SameLoc := true;
end; {if}
end; {SameLoc}
procedure SaveRetValue (optype: baseTypeEnum);
{ save a value returned by a function }
{ }
{ parameters: }
{ optype - function type }
begin {SaveRetValue}
if optype in [cgLong,cgULong] then begin
if (A_X & gLong.preference) = 0 then begin
gLong.where := onStack;
GenImplied(m_phx);
GenImplied(m_pha);
end
else
gLong.where := A_X;
end {if}
else if optype in [cgReal,cgDouble,cgExtended,cgComp] then
GenCall(8);
end; {SaveRetValue}
procedure GenAdlSbl (op, save: icptr);
{ generate code for pc_adl, pc_sbl }
{ }
{ parameters: }
{ op - pc_adl or pc_sbl operation }
{ save - save location (pc_str or pc_sro) or nil }
var
bcc,clc,adc_imm,inc_dir,adc_abs, {for op-code insensitive code}
adc_dir,inc_abs,adc_s: integer;
disp: integer; {direct page location}
lab1: integer; {label number}
nd: icptr; {for swapping left/right children}
opcode: pcodes; {temp storage; for efficiency}
simpleStore: boolean; {is the store absolute or direct?}
val: longint; {long constant value}
function Simple (icode: icptr): boolean;
{ See if the intermediate code is simple; i.e., can be }
{ reached by direct page or absolute addressing. }
begin {Simple}
Simple := false;
if icode^.opcode = pc_ldc then
Simple := true
else if icode^.opcode in [pc_lod,pc_str] then begin
if LabelToDisp(icode^.r) + icode^.q < 254 then
Simple := true;
end {else if}
else if icode^.opcode in [pc_ldo,pc_sro] then
Simple := smallMemoryModel;
end; {Simple}
begin {GenAdlSbl}
{determine where the result goes}
if save <> nil then
gLong.preference :=
A_X+onStack+inPointer+localAddress+globalLabel+constant;
{set up the master instructions}
opcode := op^.opcode;
if opcode = pc_adl then begin
clc := m_clc;
bcc := m_bcc;
adc_imm := m_adc_imm;
adc_abs := m_adc_abs;
adc_dir := m_adc_dir;
adc_s := m_adc_s;
inc_dir := m_inc_dir;
inc_abs := m_inc_abs;
end {if}
else begin
clc := m_sec;
bcc := m_bcs;
adc_imm := m_sbc_imm;
adc_abs := m_sbc_abs;
adc_dir := m_sbc_dir;
adc_s := m_sbc_s;
inc_dir := m_dec_dir;
inc_abs := m_dec_abs;
end; {else}
{if the lhs is a constant, swap the nodes}
if ((op^.left^.opcode = pc_ldc) and (opcode = pc_adl)) then begin
nd := op^.left;
op^.left := op^.right;
op^.right := nd;
end; {if}
{handle a constant rhs}
if op^.right^.opcode = pc_ldc then
val := op^.right^.lval
else
val := -1;
if SameLoc(op^.left, save) and (long(val).msw = 0) then begin
lab1 := GenLabel;
if val = 1 then begin
if opcode = pc_adl then begin
DoOp(0, m_inc_abs, m_inc_dir, op^.left, 0);
GenNative(m_bne, relative, lab1, nil, 0);
DoOp(0, m_inc_abs, m_inc_dir, op^.left, 2);
GenLab(lab1);
end {if}
else {if opcode = pc_sbl then} begin
DoOp(m_lda_imm, m_lda_abs, m_lda_dir, op^.left, 0);
GenNative(m_beq, relative, lab1, nil, 0);
DoOp(0, m_dec_abs, m_dec_dir, op^.left, 0);
GenLab(lab1);
DoOp(0, m_dec_abs, m_dec_dir, op^.left, 2);
end; {else}
end {if}
else begin {rhs in [2..65535]}
GenImplied(clc);
DoOp(m_lda_imm, m_lda_abs, m_lda_dir, op^.left, 0);
GenNative(adc_imm, immediate, long(val).lsw, nil, 0);
DoOp(0, m_sta_abs, m_sta_dir, op^.left, 0);
GenNative(bcc, relative, lab1, nil, 0);
if opcode = pc_adl then
DoOp(0, m_inc_abs, m_inc_dir, op^.left, 2)
else
DoOp(0, m_dec_abs, m_dec_dir, op^.left, 2);
GenLab(lab1);
end; {else}
end {if constant rhs}
else begin
simpleStore := false;
if save <> nil then
simpleStore := Simple(save);
if (opcode = pc_adl) and Simple(op^.left) then begin
nd := op^.left;
op^.left := op^.right;
op^.right := nd;
end; {if}
if simpleStore and Simple(op^.right) then begin
if Simple(op^.left) then begin
GenImplied(clc);
DoOp(m_lda_imm, m_lda_abs, m_lda_dir, op^.left, 0);
DoOp(adc_imm, adc_abs, adc_dir, op^.right, 0);
DoOp(0, m_sta_abs, m_sta_dir, save, 0);
DoOp(m_lda_imm, m_lda_abs, m_lda_dir, op^.left, 2);
DoOp(adc_imm, adc_abs, adc_dir, op^.right, 2);
DoOp(0, m_sta_abs, m_sta_dir, save, 2);
end {if}
else begin
gLong.preference := A_X;
GenTree(op^.left);
GenImplied(clc);
if gLong.where = onStack then
GenImplied(m_pla);
DoOp(adc_imm, adc_abs, adc_dir, op^.right, 0);
DoOp(0, m_sta_abs, m_sta_dir, save, 0);
if gLong.where = onStack then
GenImplied(m_pla)
else
GenImplied(m_txa);
DoOp(adc_imm, adc_abs, adc_dir, op^.right, 2);
DoOp(0, m_sta_abs, m_sta_dir, save, 2);
end; {else}
end {if}
else if (save = nil) and Simple(op^.right) then begin
gLong.preference := gLong.preference & A_X;
GenTree(op^.left);
GenImplied(clc);
if gLong.where = onStack then begin
GenImplied(m_pla);
DoOp(adc_imm, adc_abs, adc_dir, op^.right, 0);
GenImplied(m_pha);
GenNative(m_lda_s, direct, 3, nil, 0);
DoOp(adc_imm, adc_abs, adc_dir, op^.right, 2);
GenNative(m_sta_s, direct, 3, nil, 0);
end {if}
else begin
DoOp(adc_imm, adc_abs, adc_dir, op^.right, 0);
GenImplied(m_tay);
GenImplied(m_txa);
DoOp(adc_imm, adc_abs, adc_dir, op^.right, 2);
GenImplied(m_tax);
GenImplied(m_tya);
end; {else}
end {else if}
else begin {doing it the hard way}
gLong.preference := onStack;
GenTree(op^.right);
gLong.preference := onStack;
GenTree(op^.left);
GenImplied(clc);
GenImplied(m_pla);
GenNative(adc_s, direct, 3, nil, 0);
GenNative(m_sta_s, direct, 3, nil, 0);
GenImplied(m_pla);
GenNative(adc_s, direct, 3, nil, 0);
GenNative(m_sta_s, direct, 3, nil, 0);
if save = nil then
gLong.where := onStack
else if save^.opcode = pc_str then begin
disp := LabelToDisp(save^.r) + save^.q;
if disp < 254 then begin
GenImplied(m_pla);
GenNative(m_sta_dir, direct, disp, nil, 0);
GenImplied(m_pla);
GenNative(m_sta_dir, direct, disp+2, nil, 0);
end {else if}
else begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
GenImplied(m_pla);
GenNative(m_sta_dirX, direct, 0, nil, 0);
GenImplied(m_pla);
GenNative(m_sta_dirX, direct, 2, nil, 0);
end; {else}
end {else if}
else {if save^.opcode = pc_sro then} begin
GenImplied(m_pla);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, save^.q, save^.lab, 0)
else
GenNative(m_sta_long, longabsolute, save^.q, save^.lab, 0);
GenImplied(m_pla);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, save^.q+2, save^.lab, 0)
else
GenNative(m_sta_long, longabsolute, save^.q+2, save^.lab, 0);
end; {else}
end; {else}
end; {else}
end; {GenAdlSbl}
procedure GenAdqSbq (op: icptr);
{ generate code for pc_adq, pc_sbq }
{ }
{ parameters: }
{ op - pc_adq or pc_sbq operation }
begin {GenAdqSbq}
if op^.opcode = pc_adq then begin
if SimpleQuadLoad(op^.left) and SimpleQuadLoad(op^.right) then begin
gQuad.where := gQuad.preference;
if gQuad.preference = onStack then begin
GenImplied(m_tsc);
GenImplied(m_sec);
GenNative(m_sbc_imm, immediate, 8, nil, 0);
GenImplied(m_tcs);
gQuad.preference := inStackLoc;
gQuad.disp := 1;
end; {if}
GenImplied(m_clc);
OpOnWordOfQuad(m_lda_imm, op^.left, 0);
OpOnWordOfQuad(m_adc_imm, op^.right, 0);
StoreWordOfQuad(0);
OpOnWordOfQuad(m_lda_imm, op^.left, 2);
OpOnWordOfQuad(m_adc_imm, op^.right, 2);
StoreWordOfQuad(2);
OpOnWordOfQuad(m_lda_imm, op^.left, 4);
OpOnWordOfQuad(m_adc_imm, op^.right, 4);
StoreWordOfQuad(4);
OpOnWordOfQuad(m_lda_imm, op^.left, 6);
OpOnWordOfQuad(m_adc_imm, op^.right, 6);
StoreWordOfQuad(6);
end {if}
else begin
gQuad.preference := onStack;
GenTree(op^.right);
gQuad.preference := onStack;
GenTree(op^.left);
GenImplied(m_clc);
GenImplied(m_pla);
GenNative(m_adc_s, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_adc_s, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_adc_s, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_adc_s, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
gQuad.where := onStack;
end; {else}
end {if}
else {if op^.opcode = pc_sbq then} begin
if SimpleQuadLoad(op^.left) and SimpleQuadLoad(op^.right) then begin
gQuad.where := gQuad.preference;
if gQuad.preference = onStack then begin
GenImplied(m_tsc);
GenImplied(m_sec);
GenNative(m_sbc_imm, immediate, 8, nil, 0);
GenImplied(m_tcs);
gQuad.preference := inStackLoc;
gQuad.disp := 1;
end; {if}
GenImplied(m_sec);
OpOnWordOfQuad(m_lda_imm, op^.left, 0);
OpOnWordOfQuad(m_sbc_imm, op^.right, 0);
StoreWordOfQuad(0);
OpOnWordOfQuad(m_lda_imm, op^.left, 2);
OpOnWordOfQuad(m_sbc_imm, op^.right, 2);
StoreWordOfQuad(2);
OpOnWordOfQuad(m_lda_imm, op^.left, 4);
OpOnWordOfQuad(m_sbc_imm, op^.right, 4);
StoreWordOfQuad(4);
OpOnWordOfQuad(m_lda_imm, op^.left, 6);
OpOnWordOfQuad(m_sbc_imm, op^.right, 6);
StoreWordOfQuad(6);
end {if}
else begin
gQuad.preference := onStack;
GenTree(op^.right);
gQuad.preference := onStack;
GenTree(op^.left);
GenImplied(m_sec);
GenImplied(m_pla);
GenNative(m_sbc_s, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_sbc_s, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_sbc_s, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_sbc_s, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
gQuad.where := onStack;
end; {else}
end; {else}
end; {GenAdqSbq}
procedure GenCkp (op: icptr);
{ generate code for pc_ckp }
{ }
{ parameters: }
{ op - pc_ckp operation }
begin {GenCkp}
if op^.left^.opcode in [pc_lda,pc_lad,pc_lca,pc_lao] then
GenTree(op^.left)
else begin
gLong.preference := onStack;
GenTree(op^.left);
GenCall(98);
end; {else}
end; {GenCkp}
procedure GenCmp (op: icptr; rOpcode: pcodes; lb: integer);
{ generate code for pc_les, pc_leq, pc_grt or pc_geq }
{ }
{ parameters: }
{ op - operation }
{ rOpcode - Opcode that will use the result of the }
{ compare. If the result is used by a tjp or fjp, }
{ this procedure generated special code and does the }
{ branch internally. }
{ lb - For fjp, tjp, this is the label to branch to if }
{ the condition is satisfied. }
var
i: integer; {loop variable}
lab1,lab2,lab3,lab4: integer; {label numbers}
num: integer; {constant to compare to}
simple: boolean; {is this a simple case?}
alwaysFalse: boolean; {is the comparison always false?}
procedure Switch;
{ switch the operands }
var
nd: icptr; {used to switch nodes}
begin {Switch}
nd := op^.left;
op^.left := op^.right;
op^.right := nd;
end; {Switch}
procedure ReverseConditional;
{ Change tjp to an equivalent fjp, or vice versa. }
{ }
{ Note: assumes opcode is pc_geq or pc_grt. }
begin {ReverseConditional}
if rOpcode in [pc_tjp,pc_fjp] then begin
if op^.opcode = pc_geq then
op^.opcode := pc_grt
else
op^.opcode := pc_geq;
if rOpcode = pc_tjp then
rOpcode := pc_fjp
else
rOpcode := pc_tjp;
Switch;
end; {if}
end; {ReverseConditional}
function SimpleLongOp(op: icptr): boolean;
{ Is op an operation on cg(U)Long that can be done using the }
{ addressing modes of CPX? }
begin {SimpleLongOp}
SimpleLongOp :=
(op^.opcode = pc_ldc)
or (op^.opcode = pc_lao)
or ((op^.opcode = pc_lod) and (LabelToDisp(op^.r) + op^.q <= 253))
or ((op^.opcode = pc_ldo) and smallMemoryModel);
end; {SimpleLongOp}
begin {GenCmp}
{To reduce the number of possibilities that must be handled, pc_les }
{and pc_leq compares are reduced to their equivalent pc_grt and }
{pc_geq instructions. }
if op^.opcode = pc_les then begin
Switch;
op^.opcode := pc_grt;
end {if}
else if op^.opcode = pc_leq then begin
Switch;
op^.opcode := pc_geq;
end; {else if}
{To take advantage of shortcuts, switch operands if generating }
{for a tjp or fjp with a constant left operand. }
if op^.optype in [cgByte,cgUByte,cgWord,cgUWord] then
if op^.left^.opcode = pc_ldc then
ReverseConditional;
{Short cuts are available for single-word operands where the }
{right operand is a constant. }
if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
(op^.right^.opcode = pc_ldc) then begin
GenTree(op^.left);
num := op^.right^.q;
{Convert x > N comparisons to x >= N+1, unless N is max value }
{(in which case x > N is always false). }
alwaysFalse := false;
if op^.opcode = pc_grt then begin
if ((op^.optype in [cgByte,cgWord]) and (num = 32767))
or ((op^.optype in [cgUByte,cgUWord]) and (num = -1)) then
alwaysFalse := true
else begin
op^.opcode := pc_geq;
num := num+1;
end; {else}
end; {if}
lab1 := GenLabel;
if rOpcode = pc_fjp then begin
if alwaysFalse then
GenNative(m_brl, longrelative, lb, nil, 0)
else if op^.optype in [cgByte,cgWord] then begin
if NeedsCondition(op^.left^.opcode) then
GenImpliedForFlags(m_tax);
if (num >= 0) and (num < 3) then begin
if num = 0 then
GenNative(m_bpl, relative, lab1, nil, 0)
else begin
lab2 := GenLabel;
GenNative(m_bmi, relative, lab2, nil, 0);
if num = 2 then
GenImplied(m_lsr_a);
GenNative(m_bne, relative, lab1, nil, 0);
GenLabUsedOnce(lab2);
end; {else}
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if (num >= 0) and (num < 3)}
else begin
lab2 := GenLabel;
if num > 0 then
GenNative(m_bmi, relative, lab1, nil, 0)
else
GenNative(m_bpl, relative, lab1, nil, 0);
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcs, relative, lab2, nil, 0);
if num > 0 then begin
GenLabUsedOnce(lab1);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {if}
else begin
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
GenLab(lab1);
end; {else}
end; {else if}
end {if}
else {if optype in [cgUByte,cgUWord] then} begin
if num <> 0 then begin
if num in [1,2] then begin
if num = 1 then
GenImpliedForFlags(m_tax)
else
GenImplied(m_lsr_a);
GenNative(m_bne, relative, lab1, nil, 0);
end {if}
else begin
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
end; {else}
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end; {if}
end; {else}
end {if rOpcode = pc_fjp}
else if rOpcode = pc_tjp then begin
if alwaysFalse then
{nothing to generate}
else if op^.optype in [cgByte,cgWord] then begin
if NeedsCondition(op^.left^.opcode) then
GenImpliedForFlags(m_tax);
if (num >= 0) and (num < 3) then begin
GenNative(m_bmi, relative, lab1, nil, 0);
if num > 0 then begin
if num = 2 then
GenImplied(m_lsr_a);
GenNative(m_beq, relative, lab1, nil, 0);
end; {if}
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if (num >= 0) and (num < 3)}
else begin
lab2 := GenLabel;
if num > 0 then
GenNative(m_bmi, relative, lab1, nil, 0)
else
GenNative(m_bpl, relative, lab1, nil, 0);
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcc, relative, lab2, nil, 0);
if num > 0 then begin
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
GenLab(lab1);
end {if}
else begin
GenLabUsedOnce(lab1);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end; {else}
end; {else}
end {if}
else {if optype in [cgUByte,cgUWord] then} begin
if num <> 0 then begin
if num in [1,2] then begin
if num = 1 then
GenImpliedForFlags(m_tax)
else
GenImplied(m_lsr_a);
GenNative(m_beq, relative, lab1, nil, 0);
end {if}
else begin
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
end; {else}
end; {if}
GenNative(m_brl, longrelative, lb, nil, 0);
if num <> 0 then
GenLab(lab1);
end; {else}
end {if rOpcode = pc_tjp}
else if alwaysFalse then
GenNative(m_lda_imm, immediate, 0, nil, 0)
else if op^.optype in [cgByte,cgWord] then begin
lab2 := GenLabel;
GenNative(m_ldx_imm, immediate, 1, nil, 0);
GenImplied(m_sec);
GenNative(m_sbc_imm, immediate, num, nil, 0);
GenNative(m_bvc, relative, lab1, nil, 0);
GenImplied(m_ror_a);
GenLab(lab1);
GenNative(m_bpl, relative, lab2, nil, 0);
GenImplied(m_dex);
GenLab(lab2);
GenImplied(m_txa);
end {else if}
else begin
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenImplied(m_rol_a);
end; {else if}
end {if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
(op^.right^.opcode = pc_ldc)}
{This section of code handles the cases where the above short }
{cuts cannot be used. }
else
case op^.optype of
cgByte,cgUByte,cgWord,cgUWord: begin
if ((op^.opcode = pc_grt) and (Complex(op^.left) <= Complex(op^.right)))
or (Complex(op^.right) and not Complex(op^.left)) then
ReverseConditional;
if Complex(op^.right) then begin
GenTree(op^.right);
if Complex(op^.left) then begin
GenImplied(m_pha);
GenTree(op^.left);
GenImplied(m_ply);
GenNative(m_sty_dir, direct, dworkLoc, nil, 0);
end {if}
else begin
GenNative(m_sta_dir, direct, dworkLoc, nil, 0);
GenTree(op^.left);
end; {else}
if not (rOpcode in [pc_fjp,pc_tjp]) then
GenNative(m_ldx_imm, immediate, 1, nil, 0);
if op^.optype in [cgByte,cgWord] then begin
GenImplied(m_sec);
GenNative(m_sbc_dir, direct, dworkLoc, nil, 0);
end {if}
else
GenNative(m_cmp_dir, direct, dworkLoc, nil, 0);
end {if}
else begin
GenTree(op^.left);
if not (rOpcode in [pc_fjp,pc_tjp]) then
GenNative(m_ldx_imm, immediate, 1, nil, 0);
if op^.optype in [cgByte,cgWord] then begin
GenImplied(m_sec);
OperA(m_sbc_imm, op^.right);
if op^.right^.opcode in [pc_lld,pc_lli,pc_gli,pc_gld] then
GenImplied(m_tay);
end {if}
else
OperA(m_cmp_imm, op^.right);
end; {else}
if rOpcode = pc_fjp then begin
lab2 := GenLabel;
if op^.opcode = pc_grt then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
end; {if}
if op^.optype in [cgByte,cgWord] then begin
lab1 := GenLabel;
GenNative(m_bvc, relative, lab1, nil, 0);
GenImplied(m_ror_a);
GenLab(lab1);
GenNative(m_bpl, relative, lab2, nil, 0);
end {if}
else
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLabUsedOnce(lab3);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {if}
else if rOpcode = pc_tjp then begin
lab2 := GenLabel;
if op^.opcode = pc_grt then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
end; {if}
if op^.optype in [cgByte,cgWord] then begin
lab1 := GenLabel;
GenNative(m_bvc, relative, lab1, nil, 0);
GenImplied(m_ror_a);
GenLab(lab1);
GenNative(m_bmi, relative, lab2, nil, 0);
end {if}
else
GenNative(m_bcc, relative, lab2, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
if op^.opcode = pc_grt then
GenLab(lab3);
end {else if}
else begin
lab2 := GenLabel;
if op^.opcode = pc_grt then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
end; {if}
if op^.optype in [cgByte,cgWord] then begin
lab1 := GenLabel;
GenNative(m_bvc, relative, lab1, nil, 0);
GenImplied(m_ror_a);
GenLab(lab1);
GenNative(m_bpl, relative, lab2, nil, 0);
end {if}
else
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLab(lab3);
GenImplied(m_dex);
GenLab(lab2);
GenImplied(m_txa);
end; {else}
end; {case optype of cgByte,cgUByte,cgWord,cgUWord}
cgULong: begin
lab1 := GenLabel;
lab2 := GenLabel;
simple := false;
if SimpleLongOp(op^.right) then
simple := true
else if rOpcode in [pc_fjp,pc_tjp] then
if SimpleLongOp(op^.left) then begin
ReverseConditional;
simple := true;
end; {if}
if simple then begin
if op^.opcode = pc_grt then begin
if SimpleLongOp(op^.left) then
ReverseConditional;
if op^.opcode = pc_grt then
if op^.right^.opcode = pc_ldc then
if op^.right^.lval <> $ffffffff then begin
op^.right^.lval := op^.right^.lval + 1;
op^.opcode := pc_geq;
end; {if}
end; {if}
gLong.preference := A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {if}
if op^.opcode = pc_grt then
if not (rOpcode in [pc_fjp,pc_tjp]) then
GenNative(m_ldy_imm, immediate, 0, nil, 0);
with op^.right^ do
case opcode of
pc_ldc:
GenNative(m_cpx_imm, immediate, long(lval).msw, nil, 0);
pc_lao:
GenNative(m_cpx_imm, immediate, q, lab, shift16);
pc_lod:
GenNative(m_cpx_dir, direct, LabelToDisp(r)+q+2, nil, 0);
pc_ldo:
GenNative(m_cpx_abs, absolute, q+2, lab, 0);
end; {case}
GenNative(m_bne, relative, lab1, nil, 0);
with op^.right^ do
case opcode of
pc_ldc:
GenNative(m_cmp_imm, immediate, long(lval).lsw, nil, 0);
pc_lao:
GenNative(m_cmp_imm, immediate, q, lab, 0);
pc_lod:
GenNative(m_cmp_dir, direct, LabelToDisp(r)+q, nil, 0);
pc_ldo:
GenNative(m_cmp_abs, absolute, q, lab, 0);
end; {case}
GenLab(lab1);
if rOpcode = pc_fjp then begin
if op^.opcode = pc_grt then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
end; {if}
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLabUsedOnce(lab3);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {if}
else if rOpcode = pc_tjp then begin
if op^.opcode = pc_grt then
GenNative(m_beq, relative, lab2, nil, 0);
GenNative(m_bcc, relative, lab2, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {else if}
else if op^.opcode = pc_geq then begin
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenImplied(m_rol_a);
end {else if}
else {if op^.opcode = pc_grt then} begin
GenNative(m_beq, relative, lab2, nil, 0);
GenNative(m_bcc, relative, lab2, nil, 0);
GenImplied(m_iny);
GenLab(lab2);
GenImplied(m_tya);
end; {else}
end {if}
else begin
gLong.preference := onStack;
GenTree(op^.right);
gLong.preference := A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_ply);
GenImplied(m_pla);
end {if}
else begin
GenImplied(m_tay);
GenImplied(m_txa);
end; {else}
GenNative(m_ldx_imm, immediate, 1, nil, 0);
GenNative(m_cmp_s, direct, 3, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_tya);
GenNative(m_cmp_s, direct, 1, nil, 0);
GenLab(lab1);
if op^.opcode = pc_grt then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
end; {if}
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLab(lab3);
GenImplied(m_dex);
GenLab(lab2);
GenImplied(m_pla);
GenImplied(m_pla);
GenImplied(m_txa);
if rOpcode = pc_fjp then begin
lab4 := GenLabel;
GenNative(m_bne, relative, lab4, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab4);
end {if}
else if rOpcode = pc_tjp then begin
lab4 := GenLabel;
GenNative(m_beq, relative, lab4, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab4);
end; {else if}
end; {else}
end;
cgReal,cgDouble,cgComp,cgExtended: begin
GenTree(op^.left);
GenTree(op^.right);
num := 31;
if op^.opcode = pc_geq then
GenCall(32)
else
GenCall(31);
if (rOpcode = pc_fjp) or (rOpcode = pc_tjp) then begin
lab1 := GenLabel;
if rOpcode = pc_fjp then
GenNative(m_bne, relative, lab1, nil, 0)
else
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_brl,longrelative,lb,nil,0);
GenLab(lab1);
end; {if}
end; {case optype of cgReal..cgExtended}
cgLong: begin
gLong.preference := onStack;
GenTree(op^.left);
if op^.opcode = pc_geq then begin
gLong.preference := A_X;
GenTree(op^.right);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {if}
num := 30;
end {if}
else begin
gLong.preference := onStack;
GenTree(op^.right);
num := 29;
end; {else}
GenCall(num);
if (rOpcode = pc_fjp) or (rOpcode = pc_tjp) then begin
lab1 := GenLabel;
if rOpcode = pc_fjp then
GenNative(m_bne, relative, lab1, nil, 0)
else
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end; {if}
end; {case optype of cgLong}
cgQuad: begin
if op^.opcode = pc_geq then begin
gQuad.preference := onStack;
GenTree(op^.left);
gQuad.preference := onStack;
GenTree(op^.right);
end {if}
else {if op^.opcode = pc_grt then} begin
gQuad.preference := onStack;
GenTree(op^.right);
gQuad.preference := onStack;
GenTree(op^.left);
end; {else}
GenCall(88);
if (rOpcode = pc_fjp) or (rOpcode = pc_tjp) then begin
lab1 := GenLabel;
if (rOpcode = pc_fjp) <> (op^.opcode = pc_grt) then
GenNative(m_bcs, relative, lab1, nil, 0)
else
GenNative(m_bcc, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if}
else begin
if op^.opcode = pc_geq then begin
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenImplied(m_rol_a);
end {if}
else {if op^.opcode = pc_grt then} begin
lab1 := GenLabel;
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
GenImplied(m_dea);
GenLab(lab1);
end; {else}
end; {else}
end; {case optype of cgQuad}
cgUQuad: begin
simple :=
SimplestQuadLoad(op^.left) and SimplestQuadLoad(op^.right)
and not volatile;
if not simple then begin
gQuad.preference := onStack;
GenTree(op^.left);
gQuad.preference := onStack;
GenTree(op^.right);
end; {if}
if op^.opcode = pc_geq then
GenNative(m_ldx_imm, immediate, 1, nil, 0)
else {if op^.opcode = pc_grt then}
GenNative(m_ldx_imm, immediate, 0, nil, 0);
lab1 := GenLabel;
lab2 := GenLabel;
if simple then begin
OpOnWordOfQuad(m_lda_imm, op^.left, 6);
OpOnWordOfQuad(m_cmp_imm, op^.right, 6);
GenNative(m_bne, relative, lab1, nil, 0);
OpOnWordOfQuad(m_lda_imm, op^.left, 4);
OpOnWordOfQuad(m_cmp_imm, op^.right, 4);
GenNative(m_bne, relative, lab1, nil, 0);
OpOnWordOfQuad(m_lda_imm, op^.left, 2);
OpOnWordOfQuad(m_cmp_imm, op^.right, 2);
GenNative(m_bne, relative, lab1, nil, 0);
OpOnWordOfQuad(m_lda_imm, op^.left, 0);
OpOnWordOfQuad(m_cmp_imm, op^.right, 0);
end {if}
else begin
GenNative(m_lda_s, direct, 15, nil, 0);
GenNative(m_cmp_s, direct, 7, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenNative(m_lda_s, direct, 13, nil, 0);
GenNative(m_cmp_s, direct, 5, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenNative(m_lda_s, direct, 11, nil, 0);
GenNative(m_cmp_s, direct, 3, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenNative(m_lda_s, direct, 9, nil, 0);
GenNative(m_cmp_s, direct, 1, nil, 0);
end; {else}
GenLab(lab1);
if op^.opcode = pc_geq then begin
GenNative(m_bcs, relative, lab2, nil, 0);
GenImplied(m_dex);
end {if}
else begin {if op^.opcode = pc_grt then}
GenNative(m_bcc, relative, lab2, nil, 0);
GenNative(m_beq, relative, lab2, nil, 0);
GenImplied(m_inx);
end; {else}
GenLab(lab2);
if not simple then begin
GenImplied(m_tsc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, 16, nil, 0);
GenImplied(m_tcs);
end; {if}
GenImplied(m_txa);
if rOpcode = pc_fjp then begin
lab3 := GenLabel;
GenNative(m_bne, relative, lab3, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab3);
end {if}
else if rOpcode = pc_tjp then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab3);
end; {else if}
end; {case optype of cgUQuad}
otherwise:
Error(cge1);
end; {case}
end; {GenCmp}
procedure GenCnv (op: icptr);
{ generate a pc_cnv instruction }
const {note: these constants list all legal }
{ conversions; others are ignored}
cReal = $06;
cDouble = $07;
cComp = $08;
cExtended = $09;
cVoid = $0B;
cLong = $04;
cULong = $05;
byteToWord = $02;
byteToUword = $03;
byteToLong = $04;
byteToUlong = $05;
byteToQuad = $0C;
byteToUQuad = $0D;
byteToReal = $06;
byteToDouble = $07;
ubyteToLong = $14;
ubyteToUlong = $15;
ubyteToQuad = $1C;
ubyteToUQuad = $1D;
ubyteToReal = $16;
ubyteToDouble = $17;
wordToByte = $20;
wordToUByte = $21;
wordToLong = $24;
wordToUlong = $25;
wordToQuad = $2C;
wordToUQuad = $2D;
wordToReal = $26;
wordToDouble = $27;
uwordToByte = $30;
uwordToUByte = $31;
uwordToLong = $34;
uwordToUlong = $35;
uwordToQuad = $3C;
uwordToUQuad = $3D;
uwordToReal = $36;
uwordToDouble = $37;
longTobyte = $40;
longToUbyte = $41;
longToWord = $42;
longToUword = $43;
longToQuad = $4C;
longToUQuad = $4D;
longToReal = $46;
longToDouble = $47;
longToVoid = $4B;
ulongTobyte = $50;
ulongToUbyte = $51;
ulongToWord = $52;
ulongToUword = $53;
ulongToQuad = $5C;
ulongToUQuad = $5D;
ulongToReal = $56;
ulongToDouble = $57;
ulongToVoid = $5B;
realTobyte = $60;
realToUbyte = $61;
realToWord = $62;
realToUword = $63;
realToLong = $64;
realToUlong = $65;
realToQuad = $6C;
realToUQuad = $6D;
realToVoid = $6B;
doubleTobyte = $70;
doubleToUbyte = $71;
doubleToWord = $72;
doubleToUword = $73;
doubleToLong = $74;
doubleToUlong = $75;
doubleToQuad = $7C;
doubleToUQuad = $7D;
quadToByte = $C0;
quadToUByte = $C1;
quadToWord = $C2;
quadToUword = $C3;
quadToLong = $C4;
quadToULong = $C5;
quadToReal = $C6;
quadToDouble = $C7;
quadToVoid = $CB;
uquadToByte = $D0;
uquadToUByte = $D1;
uquadToWord = $D2;
uquadToUword = $D3;
uquadToLong = $D4;
uquadToULong = $D5;
uquadToReal = $D6;
uquadToDouble = $D7;
uquadToVoid = $DB;
var
toRealType: baseTypeEnum; {real type converted to}
lab1: integer; {used for branches}
lLong: longType; {used to reserve gLong}
begin {GenCnv}
lLong := gLong;
gLong.preference := onStack+A_X+constant;
gLong.where := onStack;
if op^.q in [quadToVoid,uQuadToVoid] then
gQuad.preference := nowhere
else
gQuad.preference := onStack;
if ((op^.q & $00F0) >> 4) in [cDouble,cExtended,cComp] then begin
op^.q := (op^.q & $000F) | (cReal * 16);
end; {if}
if (op^.q & $000F) in [cDouble,cExtended,cComp,cReal] then begin
toRealType := baseTypeEnum(op^.q & $000F);
op^.q := (op^.q & $00F0) | cReal;
end {if}
else
toRealType := cgVoid;
GenTree(op^.left);
if op^.q in [wordToLong,wordToUlong] then begin
lab1 := GenLabel;
GenNative(m_ldx_imm, immediate, 0, nil, 0);
GenImpliedForFlags(m_tay);
GenNative(m_bpl, relative, lab1, nil, 0);
GenImplied(m_dex);
GenLab(lab1);
if (lLong.preference & A_X) <> 0 then
gLong.where := A_X
else begin
gLong.where := onStack;
GenImplied(m_phx);
GenImplied(m_pha);
end; {else}
end {if}
else if op^.q in [byteToLong,byteToUlong] then begin
lab1 := GenLabel;
GenNative(m_ldx_imm, immediate, 0, nil, 0);
GenNative(m_bit_imm, immediate, $0080, nil, 0);
GenNative(m_beq, relative, lab1, nil, 0);
GenImplied(m_dex);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
if (lLong.preference & A_X) <> 0 then
gLong.where := A_X
else begin
gLong.where := onStack;
GenImplied(m_phx);
GenImplied(m_pha);
end; {else}
end {else if}
else if op^.q in [byteToWord,byteToUword] then begin
lab1 := GenLabel;
GenNative(m_bit_imm, immediate, $0080, nil, 0);
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
end {else if}
else if op^.q in [ubyteToLong,ubyteToUlong,uwordToLong,uwordToUlong] then
begin
if (lLong.preference & A_X) <> 0 then begin
gLong.where := A_X;
GenNative(m_ldx_imm, immediate, 0, nil, 0);
end {if}
else begin
gLong.where := onStack;
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_pha);
end; {else}
end {else if}
else if op^.q in [wordToUbyte,uwordToUbyte] then
GenNative(m_and_imm, immediate, $00FF, nil, 0)
else if op^.q in [wordToByte,uwordToByte] then begin
lab1 := GenLabel;
GenNative(m_and_imm, immediate, $00FF, nil, 0);
GenNative(m_bit_imm, immediate, $0080, nil, 0);
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
end {else if}
else if op^.q in [byteToReal,uByteToReal,wordToReal] then begin
GenCall(11);
toRealType := cgExtended;
end {else if}
else if op^.q = uwordToReal then begin
GenNative(m_ldx_imm, immediate, 0, nil, 0);
GenCall(12);
toRealType := cgExtended;
end {else if}
else if op^.q in [longToUbyte,ulongToUbyte] then begin
if gLong.where = A_X then
GenNative(m_and_imm, immediate, $00FF, nil, 0)
else if gLong.where = constant then
GenNative(m_lda_imm, immediate, long(gLong.lval).lsw & $00FF, nil, 0)
else {if gLong.where = onStack then} begin
GenImplied(m_pla);
GenImplied(m_plx);
GenNative(m_and_imm, immediate, $00FF, nil, 0);
end; {else if}
end {else if}
else if op^.q in [longToByte,ulongToByte] then begin
if gLong.where = A_X then
GenNative(m_and_imm, immediate, $00FF, nil, 0)
else if gLong.where = constant then
GenNative(m_lda_imm, immediate, long(gLong.lval).lsw & $00FF, nil, 0)
else {if gLong.where = onStack then} begin
GenImplied(m_pla);
GenImplied(m_plx);
GenNative(m_and_imm, immediate, $00FF, nil, 0);
end; {else if}
lab1 := GenLabel;
GenNative(m_bit_imm, immediate, $0080, nil, 0);
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
end {else if}
else if op^.q in [longToWord,longToUword,ulongToWord,ulongToUword] then begin
{Note: if the result is in A_X, no further action is needed}
if gLong.where = constant then
GenNative(m_lda_imm, immediate, long(gLong.lval).lsw, nil, 0)
else if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {else if}
end {else if}
else if op^.q in [longToReal,uLongToReal] then begin
if gLong.where = constant then begin
GenNative(m_lda_imm, immediate, long(gLong.lval).lsw, nil, 0);
GenNative(m_ldx_imm, immediate, long(gLong.lval).msw, nil, 0);
end {if}
else if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {else if}
if op^.q = longToReal then
GenCall(12)
else
GenCall(13);
if toRealType <> cgReal then
toRealType := cgExtended;
end {else if}
else if op^.q = realToWord then
GenCall(14)
else if op^.q = realToUbyte then begin
GenCall(14);
GenNative(m_and_imm, immediate, $00FF, nil, 0);
end {else if}
else if op^.q = realToByte then begin
lab1 := GenLabel;
GenCall(14);
GenNative(m_and_imm, immediate, $00FF, nil, 0);
GenNative(m_bit_imm, immediate, $0080, nil, 0);
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
end {else if}
else if op^.q = realToUword then
GenCall(15)
else if op^.q in [realToLong,realToUlong] then begin
if op^.q & $00FF = 5 then
GenCall(17)
else
GenCall(16);
if (lLong.preference & A_X) <> 0 then
gLong.where := A_X
else begin
gLong.where := onStack;
GenImplied(m_phx);
GenImplied(m_pha);
end; {else}
end {else if}
else if op^.q = realToVoid then begin
GenImplied(m_tsc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, 10, nil, 0);
GenImplied(m_tcs);
end {else if}
else if op^.q in [longToVoid,ulongToVoid] then begin
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
gLong.where := A_X;
end; {if}
end {else if}
else if op^.q in [ubyteToQuad,ubyteToUQuad,uwordToQuad,uwordToUQuad] then begin
GenNative(m_ldy_imm, immediate, 0, nil, 0);
GenImplied(m_phy);
GenImplied(m_phy);
GenImplied(m_phy);
GenImplied(m_pha);
gQuad.where := onStack;
end {else if}
else if op^.q in [byteToQuad,byteToUQuad] then begin
lab1 := GenLabel;
GenNative(m_ldx_imm, immediate, 0, nil, 0);
GenNative(m_bit_imm, immediate, $0080, nil, 0);
GenNative(m_beq, relative, lab1, nil, 0);
GenImplied(m_dex);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
GenImplied(m_phx);
GenImplied(m_phx);
GenImplied(m_phx);
GenImplied(m_pha);
gQuad.where := onStack;
end {else if}
else if op^.q in [wordToQuad,wordToUQuad] then begin
lab1 := GenLabel;
GenNative(m_ldx_imm, immediate, 0, nil, 0);
GenImpliedForFlags(m_tay);
GenNative(m_bpl, relative, lab1, nil, 0);
GenImplied(m_dex);
GenLab(lab1);
GenImplied(m_phx);
GenImplied(m_phx);
GenImplied(m_phx);
GenImplied(m_pha);
gQuad.where := onStack;
end {else if}
else if op^.q in [ulongToQuad,ulongToUQuad] then begin
if gLong.where = A_X then begin
GenNative(m_pea, immediate, 0, nil, 0);
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_phx);
GenImplied(m_pha);
end {if}
else if gLong.where = constant then begin
GenNative(m_pea, immediate, 0, nil, 0);
GenNative(m_pea, immediate, 0, nil, 0);
GenNative(m_pea, immediate, long(gLong.lval).msw, nil, 0);
GenNative(m_pea, immediate, long(gLong.lval).lsw, nil, 0);
end {else if}
else {if gLong.where = onStack then} begin
GenImplied(m_pla);
GenImplied(m_plx);
GenNative(m_pea, immediate, 0, nil, 0);
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_phx);
GenImplied(m_pha);
end; {else}
gQuad.where := onStack;
end {else if}
else if op^.q in [longToQuad,longToUQuad] then begin
if gLong.where = constant then begin
if glong.lval < 0 then begin
GenNative(m_pea, immediate, -1, nil, 0);
GenNative(m_pea, immediate, -1, nil, 0);
GenNative(m_pea, immediate, long(gLong.lval).msw, nil, 0);
GenNative(m_pea, immediate, long(gLong.lval).lsw, nil, 0);
end {if}
else begin
GenNative(m_pea, immediate, 0, nil, 0);
GenNative(m_pea, immediate, 0, nil, 0);
GenNative(m_pea, immediate, long(gLong.lval).msw, nil, 0);
GenNative(m_pea, immediate, long(gLong.lval).lsw, nil, 0);
end; {else}
end {if}
else begin
GenNative(m_ldy_imm, immediate, 0, nil, 0);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end {if}
else {if gLong.where = A_X then}
GenNative(m_cpx_imm, immediate, 0, nil, 0);
lab1 := GenLabel;
GenNative(m_bpl, relative, lab1, nil, 0);
GenImplied(m_dey);
GenLab(lab1);
GenImplied(m_phy);
GenImplied(m_phy);
GenImplied(m_phx);
GenImplied(m_pha);
end; {else}
gQuad.where := onStack;
end {else if}
else if op^.q = realToQuad then begin
GenCall(89);
gQuad.where := onStack;
end {else if}
else if op^.q = realToUQuad then begin
GenCall(90);
gQuad.where := onStack;
end {else if}
else if op^.q in [quadToWord,uquadToWord,quadToUWord,uquadToUWord] then begin
GenImplied(m_pla);
GenImplied(m_plx);
GenImplied(m_plx);
GenImplied(m_plx);
end {else if}
else if op^.q in [quadToUByte,uquadToUByte] then begin
GenImplied(m_pla);
GenImplied(m_plx);
GenImplied(m_plx);
GenImplied(m_plx);
GenNative(m_and_imm, immediate, $00FF, nil, 0);
end {else if}
else if op^.q in [quadToByte,uquadToByte] then begin
GenImplied(m_pla);
GenImplied(m_plx);
GenImplied(m_ply);
GenImplied(m_ply);
GenNative(m_and_imm, immediate, $00FF, nil, 0);
lab1 := GenLabel;
GenNative(m_bit_imm, immediate, $0080, nil, 0);
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
end {else if}
else if op^.q in [quadToLong,uquadToLong,quadToULong,uquadToULong] then begin
GenImplied(m_pla);
GenImplied(m_plx);
GenImplied(m_ply);
GenImplied(m_ply);
if (lLong.preference & A_X) <> 0 then
gLong.where := A_X
else begin
gLong.where := onStack;
GenImplied(m_phx);
GenImplied(m_pha);
end; {else}
end {else if}
else if op^.q in [quadToVoid,uquadToVoid] then begin
if gQuad.where = onStack then begin
GenImplied(m_tsc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, 8, nil, 0);
GenImplied(m_tcs);
end; {if}
end {else if}
else if op^.q = quadToReal then
GenCall(83)
else if op^.q = uquadToReal then
GenCall(84)
else if (op^.q & $000F) = cVoid then
{do nothing}
else if (op^.q & $000F) in [cLong,cULong] then
if (lLong.preference & gLong.where) = 0 then begin
if gLong.where = constant then begin
GenNative(m_pea, immediate, long(gLong.lval).msw, nil, 0);
GenNative(m_pea, immediate, long(gLong.lval).lsw, nil, 0);
end {if}
else if gLong.where = A_X then begin
GenImplied(m_phx);
GenImplied(m_pha);
end; {else if}
gLong.where := onStack;
end; {if}
if toRealType <> cgVoid then
case toRealType of
cgReal: GenCall(91);
cgDouble: GenCall(92);
cgComp: GenCall(93);
cgExtended: ;
end; {case}
end; {GenCnv}
procedure GenEquNeq (op: icptr; opcode: pcodes; lb: integer);
{ generate a pc_equ or pc_neq instruction }
{ }
{ parameters: }
{ op - node to generate the compare for }
{ opcode - Opcode that will use the result of the compare. }
{ If the result is used by a tjp or fjp, this procedure }
{ generates special code and does the branch internally. }
{ lb - For fjp, tjp, this is the label to branch to if }
{ the condition is satisfied. }
var
nd: icptr; {work node}
num: integer; {constant to compare to}
lab1,lab2,lab3: integer; {label numbers}
bne: integer; {instruction for a pc_equ bne branch}
beq: integer; {instruction for a pc_equ beq branch}
leftOp,rightOp: pcodes; {opcode codes to left, right}
procedure DoOr (op: icptr);
{ or the two halves of a four byte value }
{ }
{ parameters: }
{ operand to or }
var
disp: integer; {disp of value on stack frame}
begin {DoOr}
with op^ do begin
if opcode = pc_ldo then begin
if smallMemoryModel then begin
GenNative(m_lda_abs, absolute, q, lab, 0);
GenNative(m_ora_abs, absolute, q+2, lab, 0);
end {if}
else begin
GenNative(m_lda_long, longabsolute, q, lab, 0);
GenNative(m_ora_long, longabsolute, q+2, lab, 0);
end; {else}
end {if}
else begin
disp := LabelToDisp(r) + q;
if disp < 254 then begin
GenNative(m_lda_dir, direct, disp, nil, 0);
GenNative(m_ora_dir, direct, disp+2, nil, 0);
end {if}
else begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
GenNative(m_lda_dirX, direct, 0, nil, 0);
GenNative(m_ora_dirX, direct, 2, nil, 0);
end; {else}
end; {else}
end; {with}
end; {DoOr}
procedure DoCmp (op: icPtr);
{ compare a long value in A_X to a local or global scalar }
{ }
{ parameters: }
{ op - value to compare to }
var
disp: integer; {disp of value on stack frame}
lab1: integer; {label numbers}
begin {DoCmp}
lab1 := GenLabel;
with op^ do begin
if opcode = pc_ldo then begin
if smallMemoryModel then begin
GenNative(m_cmp_abs, absolute, q, lab, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenNative(m_cpx_abs, absolute, q+2, lab, 0);
end {if}
else begin
GenNative(m_cmp_long, longabsolute, q, lab, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_txa);
GenNative(m_cmp_long, longabsolute, q+2, lab, 0);
end; {else}
end {if}
else begin
disp := LabelToDisp(r) + q;
if disp < 254 then begin
GenNative(m_cmp_dir, direct, disp, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenNative(m_cpx_dir, direct, disp+2, nil, 0);
end {if}
else begin
GenImplied(m_txy);
GenNative(m_ldx_imm, immediate, disp, nil, 0);
GenNative(m_cmp_dirX, direct, 0, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_tya);
GenNative(m_cmp_dirX, direct, 2, nil, 0);
end; {else}
end; {else}
GenLab(lab1);
end; {with}
end; {DoCmp}
begin {GenEquNeq}
if op^.opcode = pc_equ then begin
bne := m_bne;
beq := m_beq;
end {if}
else begin
bne := m_beq;
beq := m_bne;
end; {else}
if op^.left^.opcode in [pc_lod,pc_ldo] then begin
nd := op^.left;
op^.left := op^.right;
op^.right := nd;
end; {if}
if op^.left^.opcode = pc_ldc then begin
nd := op^.left;
op^.left := op^.right;
op^.right := nd;
end; {if}
leftOp := op^.left^.opcode; {set op codes for fast access}
rightOp := op^.right^.opcode;
if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
(rightOp = pc_ldc) then begin
GenTree(op^.left);
num := op^.right^.q;
lab1 := GenLabel;
if opcode in [pc_fjp,pc_tjp] then begin
if num = 0 then begin
if NeedsCondition(leftOp) then
GenImpliedForFlags(m_tay);
end {if}
else if num = 1 then
GenImplied(m_dea)
else if num = -1 then
GenImplied(m_ina)
else
GenNative(m_cmp_imm, immediate, num, nil, 0);
if opcode = pc_fjp then
GenNative(beq, relative, lab1, nil, 0)
else
GenNative(bne, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if}
else begin
if num <> 0 then
GenNative(m_eor_imm, immediate, num, nil, 0)
else if NeedsCondition(leftOp) then
GenImpliedForFlags(m_tax);
GenNative(m_beq, relative, lab1, nil, 0);
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end; {else}
end; {else}
end {if}
else if (op^.optype in [cgLong,cgULong]) and (leftOp in [pc_ldo,pc_lod])
and (rightOp = pc_ldc) and (op^.right^.lval = 0) then begin
if opcode in [pc_fjp,pc_tjp] then begin
DoOr(op^.left);
lab1 := GenLabel;
if opcode = pc_fjp then
GenNative(beq, relative, lab1, nil, 0)
else
GenNative(bne, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if}
else begin
lab1 := GenLabel;
DoOr(op^.left);
GenNative(m_beq, relative, lab1, nil, 0);
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end; {else}
end; {else}
end {else if}
else if (op^.optype in [cgLong,cgULong]) and (rightOp in [pc_ldo,pc_lod]) then begin
gLong.preference := A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {if}
if opcode in [pc_fjp,pc_tjp] then begin
DoCmp(op^.right);
lab1 := GenLabel;
if opcode = pc_fjp then
GenNative(beq, relative, lab1, nil, 0)
else
GenNative(bne, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if}
else begin
lab1 := GenLabel;
lab2 := GenLabel;
DoCmp(op^.right);
GenNative(bne, relative, lab1, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenNative(m_bra, relative, lab2, nil, 0);
GenLab(lab1);
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenLab(lab2);
end; {else}
end {else if}
else
case op^.optype of
cgByte,cgUByte,cgWord,cgUWord: begin
if not Complex(op^.left) then
if Complex(op^.right) then begin
nd := op^.left;
op^.left := op^.right;
op^.right := nd;
end; {if}
GenTree(op^.left);
if Complex(op^.right) or (not (opcode in [pc_fjp,pc_tjp])) then begin
GenImplied(m_pha);
GenTree(op^.right);
GenNative(m_eor_s, direct, 1, nil, 0);
GenImplied(m_plx);
GenImplied(m_tax);
if opcode in [pc_fjp,pc_tjp] then begin
lab1 := GenLabel;
if opcode = pc_fjp then
GenNative(beq, relative, lab1, nil, 0)
else
GenNative(bne, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if}
else begin
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end; {else}
end; {else}
end {if}
else begin
OperA(m_cmp_imm, op^.right);
lab1 := GenLabel;
if opcode = pc_fjp then
GenNative(beq, relative, lab1, nil, 0)
else
GenNative(bne, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end; {else}
end; {case optype of cgByte,cgUByte,cgWord,cgUWord}
cgLong,cgULong: begin
gLong.preference := onStack;
GenTree(op^.left);
gLong.preference := A_X;
GenTree(op^.right);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {if}
GenNative(m_ldy_imm, immediate, 1, nil, 0);
GenNative(m_cmp_s, direct, 1, nil, 0);
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenImplied(m_dey);
GenLab(lab1);
GenImplied(m_txa);
GenNative(m_cmp_s, direct, 3, nil, 0);
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ldy_imm, immediate, 0, nil, 0);
GenLab(lab1);
GenImplied(m_pla);
GenImplied(m_pla);
GenImplied(m_tya);
if opcode in [pc_fjp,pc_tjp] then begin
lab1 := GenLabel;
if opcode = pc_fjp then
GenNative(bne, relative, lab1, nil, 0)
else
GenNative(beq, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if}
else if op^.opcode = pc_neq then
GenNative(m_eor_imm, immediate, 1, nil, 0);
end; {case optype of cgLong,cgULong}
cgReal,cgDouble,cgComp,cgExtended: begin
GenTree(op^.left);
GenTree(op^.right);
GenCall(36);
if opcode in [pc_fjp,pc_tjp] then begin
lab1 := GenLabel;
if opcode = pc_fjp then
GenNative(bne, relative, lab1, nil, 0)
else
GenNative(beq, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if}
else if op^.opcode = pc_neq then
GenNative(m_eor_imm, immediate, 1, nil, 0);
end; {case optype of cgReal..cgExtended}
cgQuad,cgUQuad: begin
if SimpleQuadLoad(op^.left) and (op^.right^.opcode = pc_ldc)
and (op^.right^.qval.hi = 0) and (op^.right^.qval.lo = 0) then begin
lab1 := GenLabel;
OpOnWordOfQuad(m_lda_imm, op^.left, 0);
if not volatile then
GenNative(m_bne, relative, lab1, nil, 0);
OpOnWordOfQuad(m_ora_imm, op^.left, 2);
OpOnWordOfQuad(m_ora_imm, op^.left, 4);
OpOnWordOfQuad(m_ora_imm, op^.left, 6);
GenLab(lab1);
end {if}
else if SimpleQuadLoad(op^.left) and SimpleQuadLoad(op^.right)
and not volatile then begin
lab1 := GenLabel;
OpOnWordOfQuad(m_lda_imm, op^.left, 0);
OpOnWordOfQuad(m_eor_imm, op^.right, 0);
GenNative(m_bne, relative, lab1, nil, 0);
OpOnWordOfQuad(m_lda_imm, op^.left, 2);
OpOnWordOfQuad(m_eor_imm, op^.right, 2);
GenNative(m_bne, relative, lab1, nil, 0);
OpOnWordOfQuad(m_lda_imm, op^.left, 4);
OpOnWordOfQuad(m_eor_imm, op^.right, 4);
GenNative(m_bne, relative, lab1, nil, 0);
OpOnWordOfQuad(m_lda_imm, op^.left, 6);
OpOnWordOfQuad(m_eor_imm, op^.right, 6);
GenLab(lab1);
end {if}
else begin
gQuad.preference := onStack;
GenTree(op^.left);
gQuad.preference := onStack;
GenTree(op^.right);
lab1 := GenLabel;
lab2 := GenLabel;
GenImplied(m_pla);
GenImplied(m_plx);
GenImplied(m_ply);
GenNative(m_eor_s, direct, 3, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_txa);
GenNative(m_eor_s, direct, 5, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_tya);
GenNative(m_eor_s, direct, 7, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_pla);
GenNative(m_eor_s, direct, 7, nil, 0);
GenNative(m_bra, relative, lab2, nil, 0);
GenLab(lab1);
GenImplied(m_plx);
GenLab(lab2);
GenImplied(m_tax);
GenImplied(m_tsc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, 8, nil, 0);
GenImplied(m_tcs);
GenImplied(m_txa);
end; {else}
if opcode in [pc_fjp,pc_tjp] then begin
lab3 := GenLabel;
if opcode = pc_fjp then
GenNative(beq, relative, lab3, nil, 0)
else
GenNative(bne, relative, lab3, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab3);
end {if}
else begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab3);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab3);
end; {else}
end; {else}
end; {case optype of cgQuad,cgUQuad}
otherwise:
Error(cge1);
end; {case}
end; {GenEquNeq}
procedure GenGilGliGdlGld (op: icptr);
{ Generate code for a pc_gil, pc_gli, pc_gdl or pc_gld }
var
lab1: integer; {branch point}
lab: stringPtr; {op^.lab}
opcode: pcodes; {op^.opcode}
q: integer; {op^.q}
procedure DoGIncDec (opcode: pcodes; lab: stringPtr; p, q: integer);
{ Do a decrement or increment on a global four byte value }
{ }
{ parameters }
{ opcode - operation code }
{ lab - label }
{ q - disp to value }
{ p - number to ind/dec by }
var
lab1: integer; {branch point}
begin {DoGIncDec}
if smallMemoryModel then begin
if opcode in [pc_gil,pc_gli] then begin
lab1 := GenLabel;
if p = 1 then begin
GenNative(m_inc_abs, absolute, q, lab, 0);
GenNative(m_bne, relative, lab1, nil, 0);
end {if}
else begin
GenImplied(m_clc);
GenNative(m_lda_abs, absolute, q, lab, 0);
GenNative(m_adc_imm, immediate, p, nil, 0);
GenNative(m_sta_abs, absolute, q, lab, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
end; {else}
GenNative(m_inc_abs, absolute, q+2, lab, 0);
GenLab(lab1);
end {if}
else {if opcode in [pc_gdl,pc_gld] then} begin
lab1 := GenLabel;
if p = 1 then begin
GenNative(m_lda_abs, absolute, q, lab, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenNative(m_dec_abs, absolute, q+2, lab, 0);
GenLab(lab1);
GenNative(m_dec_abs, absolute, q, lab, 0);
end {if}
else begin
GenImplied(m_sec);
GenNative(m_lda_abs, absolute, q, lab, 0);
GenNative(m_sbc_imm, immediate, p, nil, 0);
GenNative(m_sta_abs, absolute, q, lab, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
GenNative(m_dec_abs, absolute, q+2, lab, 0);
GenLab(lab1);
end; {else}
end {else}
end {of smallMemoryModel}
else begin
if opcode in [pc_gil,pc_gli] then begin
lab1 := GenLabel;
GenImplied(m_clc);
GenNative(m_lda_long, longabsolute, q, lab, 0);
GenNative(m_adc_imm, immediate, p, nil, 0);
GenNative(m_sta_long, longabsolute, q, lab, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
GenNative(m_lda_long, longabsolute, q+2, lab, 0);
GenImplied(m_ina);
GenNative(m_sta_long, longabsolute, q+2, lab, 0);
GenLab(lab1);
end {if}
else {if opcode in [pc_gdl,pc_gld] then} begin
lab1 := GenLabel;
GenImplied(m_sec);
GenNative(m_lda_long, longabsolute, q, lab, 0);
GenNative(m_sbc_imm, immediate, p, nil, 0);
GenNative(m_sta_long, longabsolute, q, lab, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
GenNative(m_lda_long, longabsolute, q+2, lab, 0);
GenImplied(m_dea);
GenNative(m_sta_long, longabsolute, q+2, lab, 0);
GenLab(lab1);
end; {else if}
end; {else}
end; {DoGIncDec}
begin {GenGilGliGdlGld}
opcode := op^.opcode;
q := op^.q;
lab := op^.lab;
case op^.optype of
cgWord, cgUWord: begin
if opcode = pc_gil then
GenNative(m_inc_abs, absolute, q, lab, 0)
else if opcode = pc_gdl then
GenNative(m_dec_abs, absolute, q, lab, 0);
if not skipLoad then
GenNative(m_lda_abs, absolute, q, lab, 0);
if opcode = pc_gli then
GenNative(m_inc_abs, absolute, q, lab, 0)
else if opcode = pc_gld then
GenNative(m_dec_abs, absolute, q, lab, 0);
end;
cgByte, cgUByte: begin
GenNative(m_sep, immediate, 32, nil, 0);
if opcode = pc_gil then
GenNative(m_inc_abs, absolute, q, lab, 0)
else if opcode = pc_gdl then
GenNative(m_dec_abs, absolute, q, lab, 0);
if not skipLoad then
GenNative(m_lda_abs, absolute, q, lab, 0);
if opcode = pc_gli then
GenNative(m_inc_abs, absolute, q, lab, 0)
else if opcode = pc_gld then
GenNative(m_dec_abs, absolute, q, lab, 0);
GenNative(m_rep, immediate, 32, nil, 0);
if not skipLoad then begin
GenNative(m_and_imm, immediate, 255, nil, 0);
if op^.optype = cgByte then begin
GenNative(m_bit_imm, immediate, $0080, nil, 0);
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
GenNative(m_cmp_imm, immediate, $0000, nil, 0);
end; {if}
end; {if}
end;
cgLong, cgULong: begin
if (A_X & gLong.preference) <> 0 then
gLong.where := A_X
else
gLong.where := onStack;
if opcode in [pc_gil,pc_gdl] then
DoGIncDec(opcode, lab, op^.r, q);
if not skipLoad then
if smallMemoryModel then begin
GenNative(m_ldx_abs, absolute, q+2, lab, 0);
GenNative(m_lda_abs, absolute, q, lab, 0);
if (opcode in [pc_gli,pc_gld]) and (op^.r <> 1) then
gLong.where := onStack;
if gLong.where = onStack then begin
GenImplied(m_phx);
GenImplied(m_pha);
end; {if}
end {if}
else begin
if opcode in [pc_gli,pc_gld] then
gLong.where := onStack;
GenNative(m_lda_long, longabsolute, q+2, lab, 0);
if gLong.where = onStack then
GenImplied(m_pha)
else
GenImplied(m_tax);
GenNative(m_lda_long, longabsolute, q, lab, 0);
if gLong.where = onStack then
GenImplied(m_pha);
end; {else}
if opcode in [pc_gli,pc_gld] then
DoGIncDec(opcode, lab, op^.r, q);
end; {case cgLong,cgULong}
otherwise:
Error(cge1);
end; {case}
end; {GenGilGliGdlGld}
procedure GenIilIliIdlIld (op: icptr);
{ Generate code for a pc_iil, pc_ili, pc_idl or pc_ild }
var
lab1: integer; {label}
lSkipLoad: boolean; {copy of skipLoad}
opcode: pcodes; {op^.opcode}
short: boolean; {doing a one byte operand?}
begin {GenIilIliIdlIld}
opcode := op^.opcode;
case op^.optype of
cgByte,cgUByte,cgWord,cgUWord: begin
short := op^.optype in [cgByte,cgUByte];
lSkipLoad := skipLoad;
skipLoad := false;
GetPointer(op^.left);
skipLoad := lSkipLoad;
if gLong.where = inPointer then begin
if short then
GenNative(m_sep, immediate, 32, nil, 0);
if gLong.fixedDisp then
GenNative(m_lda_indl, direct, gLong.disp, nil, 0)
else
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if opcode in [pc_ili,pc_iil] then
GenImplied(m_ina)
else
GenImplied(m_dea);
if gLong.fixedDisp then
GenNative(m_sta_indl, direct, gLong.disp, nil, 0)
else
GenNative(m_sta_indly, direct, gLong.disp, nil, 0);
if not skipLoad then
if opcode = pc_ili then
GenImplied(m_dea)
else if opcode = pc_ild then
GenImplied(m_ina);
if short then
GenNative(m_rep, immediate, 32, nil, 0);
end {if}
else if gLong.where = localAddress then begin
gLong.disp := gLong.disp+op^.q;
if gLong.fixedDisp then begin
if short then
GenNative(m_sep, immediate, 32, nil, 0);
if (gLong.disp < 256) and (gLong.disp >= 0) then begin
if (not skipLoad) and (opcode in [pc_ili,pc_ild]) then
GenNative(m_lda_dir, direct, gLong.disp, nil, 0);
if opcode in [pc_ili,pc_iil] then
GenNative(m_inc_dir, direct, gLong.disp, nil, 0)
else
GenNative(m_dec_dir, direct, gLong.disp, nil, 0);
if (not skipLoad) and (opcode in [pc_iil,pc_idl]) then
GenNative(m_lda_dir, direct, gLong.disp, nil, 0);
end {if}
else begin
GenNative(m_ldx_imm, immediate, gLong.disp, nil, 0);
if (not skipLoad) and (opcode in [pc_ili,pc_ild]) then
GenNative(m_lda_dirX, direct, 0, nil, 0);
if opcode in [pc_ili,pc_iil] then
GenNative(m_inc_dirX, direct, 0, nil, 0)
else
GenNative(m_dec_dirX, direct, 0, nil, 0);
if (not skipLoad) and (opcode in [pc_iil,pc_idl]) then
GenNative(m_lda_dirX, direct, 0, nil, 0);
end; {else}
if short then
GenNative(m_rep, immediate, 32, nil, 0);
end
else begin
if (gLong.disp > 255) or (gLong.disp < 0) then begin
GenImplied(m_txa);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
GenImplied(m_tax);
gLong.disp := 0;
end; {if}
if short then
GenNative(m_sep, immediate, 32, nil, 0);
if (not skipLoad) and (opcode in [pc_ili,pc_ild]) then
GenNative(m_lda_dirX, direct, gLong.disp, nil, 0);
if opcode in [pc_ili,pc_iil] then
GenNative(m_inc_dirX, direct, gLong.disp, nil, 0)
else
GenNative(m_dec_dirX, direct, gLong.disp, nil, 0);
if (not skipLoad) and (opcode in [pc_iil,pc_idl]) then
GenNative(m_lda_dirX, direct, gLong.disp, nil, 0);
if short then
GenNative(m_rep, immediate, 32, nil, 0);
end; {else}
end {else if}
else {if gLong.where = globalLabel then} begin
gLong.disp := gLong.disp+op^.q;
if short then
GenNative(m_sep, immediate, 32, nil, 0);
if gLong.fixedDisp then
if smallMemoryModel then begin
if (not skipLoad) and (opcode in [pc_ili,pc_ild]) then
GenNative(m_lda_abs, absolute, gLong.disp, gLong.lab, 0);
if opcode in [pc_ili,pc_iil] then
GenNative(m_inc_abs, absolute, gLong.disp, gLong.lab, 0)
else
GenNative(m_dec_abs, absolute, gLong.disp, gLong.lab, 0);
if (not skipLoad) and (opcode in [pc_iil,pc_idl]) then
GenNative(m_lda_abs, absolute, gLong.disp, gLong.lab, 0);
end {if}
else begin
GenNative(m_lda_long, longAbs, gLong.disp, gLong.lab, 0);
if opcode in [pc_ili,pc_iil] then
GenImplied(m_ina)
else
GenImplied(m_dea);
GenNative(m_sta_long, longAbs, gLong.disp, gLong.lab, 0);
if not skipLoad then
if opcode = pc_ili then
GenImplied(m_dea)
else if opcode = pc_ild then
GenImplied(m_ina);
end {else}
else
if smallMemoryModel then begin
if (not skipLoad) and (opcode in [pc_ili,pc_ild]) then
GenNative(m_lda_absX, absolute, gLong.disp, gLong.lab, 0);
if opcode in [pc_ili,pc_iil] then
GenNative(m_inc_absX, absolute, gLong.disp, gLong.lab, 0)
else
GenNative(m_dec_absX, absolute, gLong.disp, gLong.lab, 0);
if (not skipLoad) and (opcode in [pc_iil,pc_idl]) then
GenNative(m_lda_absX, absolute, gLong.disp, gLong.lab, 0);
end {if}
else begin
GenNative(m_lda_longX, longAbs, gLong.disp, gLong.lab, 0);
if opcode in [pc_ili,pc_iil] then
GenImplied(m_ina)
else
GenImplied(m_dea);
GenNative(m_sta_longX, longAbs, gLong.disp, gLong.lab, 0);
if not skipLoad then
if opcode = pc_ili then
GenImplied(m_dea)
else if opcode = pc_ild then
GenImplied(m_ina);
end; {else}
if short then
GenNative(m_rep, immediate, 32, nil, 0);
end; {else}
if not skipLoad then
if short then begin
GenNative(m_and_imm, immediate, $00FF, nil, 0);
if op^.optype = cgByte then begin
GenNative(m_bit_imm, immediate, $0080, nil, 0);
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
end; {if}
end; {if}
end; {case cgByte,cgUByte,cgWord,cgUWord}
otherwise:
Error(cge1);
end; {case}
end; {GenIilIliIdlIld}
procedure GenIncDec (op, save: icptr);
{ generate code for pc_inc, pc_dec }
{ }
{ parameters: }
{ op - pc_inc or pc_dec operation }
{ save - save location (pc_str or pc_sro) or nil }
var
disp: integer; {disp in stack frame}
lab1: integer; {branch point}
opcode: pcodes; {temp storage for op code}
size: integer; {number to increment by}
clc,ina,adc: integer; {instructions to generate}
begin {GenIncDec}
{set up local variables}
opcode := op^.opcode;
size := op^.q;
if op^.optype in [cgByte,cgUByte,cgWord,cgUWord] then begin
GenTree(op^.left);
if opcode = pc_inc then begin
clc := m_clc;
ina := m_ina;
adc := m_adc_imm;
end {if}
else begin
clc := m_sec;
ina := m_dea;
adc := m_sbc_imm;
end; {else}
if size = 1 then
GenImplied(ina)
else if size = 2 then begin
GenImplied(ina);
GenImplied(ina);
end {else if}
else if size <> 0 then begin
GenImplied(clc);
GenNative(adc, immediate, size, nil, 0);
end; {else if}
end {if}
else if op^.optype in [cgLong,cgULong] then begin
if SameLoc(op^.left, save) then begin
lab1 := GenLabel;
if size = 1 then begin
if opcode = pc_inc then begin
DoOp(0, m_inc_abs, m_inc_dir, op^.left, 0);
GenNative(m_bne, relative, lab1, nil, 0);
DoOp(0, m_inc_abs, m_inc_dir, op^.left, 2);
GenLab(lab1);
end {if}
else {if opcode = pc_dec then} begin
DoOp(m_lda_imm, m_lda_abs, m_lda_dir, op^.left, 0);
GenNative(m_bne, relative, lab1, nil, 0);
DoOp(0, m_dec_abs, m_dec_dir, op^.left, 2);
GenLab(lab1);
DoOp(0, m_dec_abs, m_dec_dir, op^.left, 0);
end; {else}
end {if}
else if opcode = pc_inc then begin
GenImplied(m_clc);
DoOp(m_lda_imm, m_lda_abs, m_lda_dir, op^.left, 0);
GenNative(m_adc_imm, immediate, size, nil, 0);
DoOp(0, m_sta_abs, m_sta_dir, op^.left, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
DoOp(0, m_inc_abs, m_inc_dir, op^.left, 2);
GenLab(lab1);
end {else if}
else begin
GenImplied(m_sec);
DoOp(m_lda_imm, m_lda_abs, m_lda_dir, op^.left, 0);
GenNative(m_sbc_imm, immediate, size, nil, 0);
DoOp(0, m_sta_abs, m_sta_dir, op^.left, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
DoOp(0, m_dec_abs, m_dec_dir, op^.left, 2);
GenLab(lab1);
end; {else}
end {if}
else begin
if save <> nil then
gLong.preference := A_X
else
gLong.preference := gLong.preference & (A_X | inpointer);
if opcode = pc_dec then
gLong.preference := gLong.preference & A_X;
GenTree(op^.left);
if opcode = pc_inc then
IncAddr(size)
else begin
lab1 := GenLabel;
if gLong.where = A_X then begin
GenImplied(m_sec);
GenNative(m_sbc_imm, immediate, size, nil, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
GenImplied(m_dex);
end {if}
else begin
GenImplied(m_sec);
GenNative(m_lda_s, direct, 1, nil, 0);
GenNative(m_sbc_imm, immediate, size, nil, 0);
GenNative(m_sta_s, direct, 1, nil, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
GenNative(m_lda_s, direct, 3, nil, 0);
GenImplied(m_dea);
GenNative(m_sta_s, direct, 3, nil, 0);
end; {else}
GenLab(lab1);
end; {else}
if save <> nil then
if save^.opcode = pc_str then begin
disp := LabelToDisp(save^.r) + save^.q;
if disp < 254 then begin
if gLong.where = onStack then
GenImplied(m_pla);
GenNative(m_sta_dir, direct, disp, nil, 0);
if gLong.where = onStack then
GenImplied(m_plx);
GenNative(m_stx_dir, direct, disp+2, nil, 0);
end {else if}
else begin
if gLong.where = A_X then
GenImplied(m_txy);
GenNative(m_ldx_imm, immediate, disp, nil, 0);
if gLong.where = onStack then
GenImplied(m_pla);
GenNative(m_sta_dirX, direct, 0, nil, 0);
if gLong.where = onStack then
GenImplied(m_pla)
else
GenImplied(m_tya);
GenNative(m_sta_dirX, direct, 2, nil, 0);
end; {else}
end {else if}
else {if save^.opcode = pc_sro then} begin
if gLong.where = onStack then
GenImplied(m_pla);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, save^.q, save^.lab, 0)
else
GenNative(m_sta_long, longabsolute, save^.q, save^.lab, 0);
if smallMemoryModel then begin
if gLong.where = onStack then
GenImplied(m_plx);
GenNative(m_stx_abs, absolute, save^.q+2, save^.lab, 0)
end {if}
else begin
if gLong.where = onStack then
GenImplied(m_pla)
else
GenImplied(m_txa);
GenNative(m_sta_long, longabsolute, save^.q+2, save^.lab, 0);
end; {else}
end; {else}
end; {else}
end {else if}
else
Error(cge1);
end; {GenIncDec}
procedure GenInd (op: icptr);
{ Generate code for a pc_ind }
var
lab1: integer; {label}
lLong: longType; {requested address type}
lQuad: quadType; {requested quad address type}
optype: baseTypeEnum; {op^.optype}
q: integer; {op^.q}
volatileByte: boolean; {is this a volatile byte access?}
begin {GenInd}
optype := op^.optype;
q := op^.q;
case optype of
cgReal,cgDouble,cgComp,cgExtended: begin
gLong.preference := onStack;
GenTree(op^.left);
if q <> 0 then
IncAddr(q);
if optype = cgReal then
GenCall(21)
else if optype = cgDouble then
GenCall(22)
else if optype = cgComp then
GenCall(70)
else if optype = cgExtended then
GenCall(71);
end; {case cgReal,cgDouble,cgComp,cgExtended}
cgLong,cgULong: begin
lLong := gLong;
GetPointer(op^.left);
if gLong.where = inPointer then begin
if q = 0 then begin
if gLong.fixedDisp then begin
GenNative(m_ldy_imm, immediate, 2, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if (A_X & lLong.preference) <> 0 then
GenImplied(m_tax)
else
GenImplied(m_pha);
GenNative(m_lda_indl, direct, gLong.disp, nil, 0);
end {if}
else begin
GenImplied(m_iny);
GenImplied(m_iny);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if (A_X & lLong.preference) <> 0 then
GenImplied(m_tax)
else
GenImplied(m_pha);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
end; {else}
if (A_X & lLong.preference) = 0 then
GenImplied(m_pha);
end {if q = 0}
else begin
if gLong.fixedDisp then begin
GenNative(m_ldy_imm, immediate, q+2, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if (A_X & lLong.preference) <> 0 then
GenImplied(m_tax)
else
GenImplied(m_pha);
GenNative(m_ldy_imm, immediate, q, nil, 0);
end {if}
else begin
GenImplied(m_tya);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, q+2, nil, 0);
GenImplied(m_tay);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if (A_X & lLong.preference) <> 0 then
GenImplied(m_tax)
else
GenImplied(m_pha);
GenImplied(m_dey);
GenImplied(m_dey);
end; {else}
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if (A_X & lLong.preference) = 0 then
GenImplied(m_pha);
end; {else}
end {if glong.where = inPointer}
else if gLong.where = localAddress then begin
gLong.disp := gLong.disp+q;
if gLong.fixedDisp then
if (gLong.disp < 254) and (gLong.disp >= 0) then begin
GenNative(m_lda_dir, direct, gLong.disp, nil, 0);
GenNative(m_ldx_dir, direct, gLong.disp+2, nil, 0);
end {if}
else begin
GenNative(m_ldx_imm, immediate, gLong.disp, nil, 0);
GenNative(m_lda_dirX, direct, 0, nil, 0);
GenNative(m_ldy_dirX, direct, 2, nil, 0);
GenImplied(m_tyx);
end {else}
else begin
if (gLong.disp >= 254) or (gLong.disp < 0) then begin
GenImplied(m_txa);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
GenImplied(m_tax);
gLong.disp := 0;
end; {if}
GenNative(m_ldy_dirX, direct, gLong.disp+2, nil, 0);
GenNative(m_lda_dirX, direct, gLong.disp, nil, 0);
GenImplied(m_tyx);
end; {else}
if (A_X & lLong.preference) = 0 then begin
GenImplied(m_phx);
GenImplied(m_pha);
end; {if}
end {else if gLong.where = localAddress}
else {if gLong.where = globalLabel then} begin
gLong.disp := gLong.disp+q;
if gLong.fixedDisp then
if smallMemoryModel then begin
GenNative(m_lda_abs, absolute, gLong.disp, gLong.lab, 0);
GenNative(m_ldx_abs, absolute, gLong.disp+2, gLong.lab, 0);
end {if}
else begin
GenNative(m_lda_long, longAbs, gLong.disp+2, gLong.lab, 0);
GenImplied(m_tax);
GenNative(m_lda_long, longAbs, gLong.disp, gLong.lab, 0);
end {else}
else
if smallMemoryModel then begin
GenNative(m_ldy_absX, absolute, gLong.disp+2, gLong.lab, 0);
GenNative(m_lda_absX, absolute, gLong.disp, gLong.lab, 0);
GenImplied(m_tyx);
end {if}
else begin
GenNative(m_lda_longX, longAbs, gLong.disp+2, gLong.lab, 0);
GenImplied(m_tay);
GenNative(m_lda_longX, longAbs, gLong.disp, gLong.lab, 0);
GenImplied(m_tyx);
end; {else}
if (A_X & lLong.preference) = 0 then begin
GenImplied(m_phx);
GenImplied(m_pha);
end; {if}
end; {else}
if (A_X & lLong.preference) <> 0 then
gLong.where := A_X
else
gLong.where := onStack;
end; {cgLong,cgULong}
cgByte,cgUByte,cgWord,cgUWord: begin
GetPointer(op^.left);
if gLong.where = inPointer then begin
volatileByte := (op^.r <> 0) and (optype in [cgByte,cgUByte]);
if q = 0 then begin
if volatileByte then
GenNative(m_sep, immediate, 32, nil, 0);
if gLong.fixedDisp then
GenNative(m_lda_indl, direct, gLong.disp, nil, 0)
else
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if volatileByte then
GenNative(m_rep, immediate, 32, nil, 0);
end {if}
else
if gLong.fixedDisp then begin
if volatileByte then
GenNative(m_sep, immediate, 32, nil, 0);
GenNative(m_ldy_imm, immediate, q, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if volatileByte then
GenNative(m_rep, immediate, 32, nil, 0);
end {if}
else begin
GenImplied(m_tya);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, q, nil, 0);
GenImplied(m_tay);
if volatileByte then
GenNative(m_sep, immediate, 32, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if volatileByte then
GenNative(m_rep, immediate, 32, nil, 0);
end; {else}
end {if}
else if gLong.where = localAddress then begin
gLong.disp := gLong.disp+q;
if gLong.fixedDisp then
if (gLong.disp & $FF00) = 0 then
GenNative(m_lda_dir, direct, gLong.disp, nil, 0)
else begin
GenNative(m_ldx_imm, immediate, gLong.disp, nil, 0);
GenNative(m_lda_dirX, direct, 0, nil, 0);
end {else}
else
if (gLong.disp & $FF00) = 0 then
GenNative(m_lda_dirX, direct, gLong.disp, nil, 0)
else begin
GenImplied(m_txa);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
GenImplied(m_tax);
GenNative(m_lda_dirX, direct, 0, nil, 0);
end {else}
end {else if}
else {if gLong.where = globalLabel then} begin
gLong.disp := gLong.disp+q;
if gLong.fixedDisp then
if smallMemoryModel then
GenNative(m_lda_abs, absolute, gLong.disp, gLong.lab, 0)
else
GenNative(m_lda_long, longAbs, gLong.disp, gLong.lab, 0)
else
if smallMemoryModel then
GenNative(m_lda_absX, absolute, gLong.disp, gLong.lab, 0)
else
GenNative(m_lda_longX, longAbs, gLong.disp, gLong.lab, 0)
end; {else}
if optype in [cgByte,cgUByte] then begin
GenNative(m_and_imm, immediate, 255, nil, 0);
if optype = cgByte then begin
GenNative(m_cmp_imm, immediate, 128, nil, 0);
lab1 := GenLabel;
GenNative(m_bcc, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
end; {if}
end; {if}
end; {case cgByte,cgUByte,cgWord,cgUWord}
cgQuad,cgUQuad: begin
lQuad := gQuad;
GetPointer(op^.left);
gQuad := lQuad;
gQuad.where := gQuad.preference; {unless overridden later}
if gLong.where = inPointer then begin
if gLong.fixedDisp then begin
GenNative(m_ldy_imm, immediate, q+6, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(6);
GenNative(m_ldy_imm, immediate, q+4, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(4);
GenNative(m_ldy_imm, immediate, q+2, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(2);
if q = 0 then
GenNative(m_lda_indl, direct, gLong.disp, nil, 0)
else begin
GenNative(m_ldy_imm, immediate, q, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
end; {else}
StoreWordOfQuad(0);
end {if}
else begin
gQuad.where := onStack;
GenImplied(m_tya);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, q+6, nil, 0);
GenImplied(m_tay);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
GenImplied(m_pha);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
GenImplied(m_pha);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
GenImplied(m_pha);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
GenImplied(m_pha);
end; {else}
end {if glong.where = inPointer}
else if gLong.where = localAddress then begin
gLong.disp := gLong.disp+q;
if gLong.fixedDisp then
if (gLong.disp < 250) and (gLong.disp >= 0) then begin
if gQuad.preference = onStack then begin
GenNative(m_pei_dir, direct, gLong.disp+6, nil, 0);
GenNative(m_pei_dir, direct, gLong.disp+4, nil, 0);
GenNative(m_pei_dir, direct, gLong.disp+2, nil, 0);
GenNative(m_pei_dir, direct, gLong.disp, nil, 0);
end {if}
else begin
GenNative(m_lda_dir, direct, gLong.disp+6, nil, 0);
StoreWordOfQuad(6);
GenNative(m_lda_dir, direct, gLong.disp+4, nil, 0);
StoreWordOfQuad(4);
GenNative(m_lda_dir, direct, gLong.disp+2, nil, 0);
StoreWordOfQuad(2);
GenNative(m_lda_dir, direct, gLong.disp, nil, 0);
StoreWordOfQuad(0);
end; {else}
end {if}
else begin
gQuad.where := onStack;
GenNative(m_ldx_imm, immediate, gLong.disp, nil, 0);
GenNative(m_lda_dirX, direct, 6, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_dirX, direct, 4, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_dirX, direct, 2, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_dirX, direct, 0, nil, 0);
GenImplied(m_pha);
end {else}
else begin
gQuad.where := onStack;
if (gLong.disp >= 250) or (gLong.disp < 0) then begin
GenImplied(m_txa);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
GenImplied(m_tax);
gLong.disp := 0;
end; {if}
GenNative(m_lda_dirX, direct, gLong.disp+6, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_dirX, direct, gLong.disp+4, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_dirX, direct, gLong.disp+2, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_dirX, direct, gLong.disp, nil, 0);
GenImplied(m_pha);
end; {else}
end {else if gLong.where = localAddress}
else {if gLong.where = globalLabel then} begin
gLong.disp := gLong.disp+q;
if gLong.fixedDisp then
if smallMemoryModel then begin
GenNative(m_lda_abs, absolute, gLong.disp+6, gLong.lab, 0);
StoreWordOfQuad(6);
GenNative(m_lda_abs, absolute, gLong.disp+4, gLong.lab, 0);
StoreWordOfQuad(4);
GenNative(m_lda_abs, absolute, gLong.disp+2, gLong.lab, 0);
StoreWordOfQuad(2);
GenNative(m_lda_abs, absolute, gLong.disp, gLong.lab, 0);
StoreWordOfQuad(0);
end {if}
else begin
GenNative(m_lda_long, longAbs, gLong.disp+6, gLong.lab, 0);
StoreWordOfQuad(6);
GenNative(m_lda_long, longAbs, gLong.disp+4, gLong.lab, 0);
StoreWordOfQuad(4);
GenNative(m_lda_long, longAbs, gLong.disp+2, gLong.lab, 0);
StoreWordOfQuad(2);
GenNative(m_lda_long, longAbs, gLong.disp, gLong.lab, 0);
StoreWordOfQuad(6);
end {else}
else
if smallMemoryModel then begin
gQuad.where := onStack;
GenNative(m_lda_absX, absolute, gLong.disp+6, gLong.lab, 0);
GenImplied(m_pha);
GenNative(m_lda_absX, absolute, gLong.disp+4, gLong.lab, 0);
GenImplied(m_pha);
GenNative(m_lda_absX, absolute, gLong.disp+2, gLong.lab, 0);
GenImplied(m_pha);
GenNative(m_lda_absX, absolute, gLong.disp, gLong.lab, 0);
GenImplied(m_pha);
end {if}
else begin
gQuad.where := onStack;
GenNative(m_lda_longX, longAbs, gLong.disp+6, gLong.lab, 0);
GenImplied(m_pha);
GenNative(m_lda_longX, longAbs, gLong.disp+4, gLong.lab, 0);
GenImplied(m_pha);
GenNative(m_lda_longX, longAbs, gLong.disp+2, gLong.lab, 0);
GenImplied(m_pha);
GenNative(m_lda_longX, longAbs, gLong.disp, gLong.lab, 0);
GenImplied(m_pha);
end; {else}
end; {else}
end; {case cgQuad,cgUQuad}
otherwise: Error(cge1);
end; {case}
end; {GenInd}
procedure GenIxa (op: icptr);
{ Generate code for a pc_ixa }
var
lab1,lab2: integer; {branch labels}
lLong: longType; {type of address}
signed: boolean; {doing signed addition?}
zero: boolean; {is the index 0?}
procedure Index;
{ Get the index size }
var
lLong: longType; {temp for preserving left node info}
begin {Index}
zero := false;
with op^.right^ do begin
if opcode = pc_ldc then begin
if q = 0 then
zero := true
else
GenNative(m_lda_imm, immediate, q, nil, 0);
end {if}
else begin
lLong := gLong;
GenTree(op^.right);
gLong := lLong;
end; {else}
end; {with}
end; {Index}
function IndexCanBeNegative: boolean;
{ Check if the index value (right argument) of a pc_ixa }
{ can validly be negative. Returns false if this is }
{ precluded by the type of the operation or other available }
{ information, or if any use of a negative index would be }
{ undefined behavior. Otherwise, returns true. }
{ }
{ parameters: }
{ op - pc_ixa operation }
begin {IndexCanBeNegative}
IndexCanBeNegative := true;
if op^.optype in [cgUByte,cgUWord] then
IndexCanBeNegative := false
else if (op^.right^.opcode = pc_ldc) and (op^.right^.q >= 0) then
IndexCanBeNegative := false
else if (op^.left^.opcode in [pc_lao,pc_lda]) and (op^.left^.q = 0) then
{Can't index before start of array, so using a negative index would be UB}
IndexCanBeNegative := false;
end; {IndexCanBeNegative}
begin {GenIxa}
lLong := gLong;
if smallMemoryModel or (op^.left^.opcode = pc_lda) then begin
gLong.preference := inPointer+localAddress+globalLabel;
GenTree(op^.left);
case gLong.where of
onStack: begin
Index;
if not zero then begin
GenImplied(m_clc);
GenNative(m_adc_s, direct, 1, nil, 0);
GenNative(m_sta_s, direct, 1, nil, 0);
lab1 := GenLabel;
GenNative(m_bcc, relative, lab1, nil, 0);
GenNative(m_lda_s, direct, 3, nil, 0);
GenImplied(m_ina);
GenNative(m_sta_s, direct, 3, nil, 0);
GenLab(lab1);
end; {if}
end; {case onStack}
inPointer: begin
if not gLong.fixedDisp then begin
if Complex(op^.right) then begin
GenImplied(m_phy);
Index;
if not zero then begin
GenImplied(m_clc);
GenNative(m_adc_s, direct, 1, nil, 0);
GenNative(m_sta_s, direct, 1, nil, 0);
end; {if}
GenImplied(m_ply);
end {if}
else begin
GenImplied(m_tya);
GenImplied(m_clc);
OperA(m_adc_imm, op^.right);
GenImplied(m_tay);
end; {else}
end {if}
else begin
Index;
if not zero then begin
GenImplied(m_tay);
gLong.fixedDisp := false;
end; {if}
end; {else}
if (inPointer & lLong.preference) = 0 then begin
if not gLong.fixedDisp then begin
GenImplied(m_tya);
GenImplied(m_clc);
GenNative(m_adc_dir, direct, gLong.disp, nil, 0);
GenNative(m_ldx_dir, direct, gLong.disp+2, nil, 0);
lab1 := GenLabel;
GenNative(m_bcc, relative, lab1, nil, 0);
GenImplied(m_inx);
GenLab(lab1);
end {if}
else begin
GenNative(m_ldx_dir, direct, gLong.disp+2, nil, 0);
GenNative(m_lda_dir, direct, gLong.disp, nil, 0);
end; {else}
GenImplied(m_phx);
GenImplied(m_pha);
gLong.where := onStack;
end; {if}
end; {case inPointer}
localAddress,globalLabel: begin
if not gLong.fixedDisp then begin
if Complex(op^.right) then begin
GenImplied(m_phx);
Index;
if not zero then begin
GenImplied(m_clc);
GenNative(m_adc_s, direct, 1, nil, 0);
GenNative(m_sta_s, direct, 1, nil, 0);
end; {if}
GenImplied(m_plx);
end {if}
else begin
GenImplied(m_txa);
GenImplied(m_clc);
OperA(m_adc_imm, op^.right);
GenImplied(m_tax);
end; {else}
end {if}
else if Complex(op^.right) then begin
Index;
if not zero then begin
GenImplied(m_tax);
gLong.fixedDisp := false;
end; {if}
end {else if}
else begin
LoadX(op^.right);
gLong.fixedDisp := false;
end; {else}
if gLong.where = globalLabel then
if IndexCanBeNegative then begin
if (gLong.disp >= 0) and (gLong.disp <= 2) then begin
while gLong.disp > 0 do begin
GenImplied(m_inx);
gLong.disp := gLong.disp - 1;
end; {while}
end {if}
else begin
GenImplied(m_txa);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
GenImplied(m_tax);
gLong.disp := 0;
end; {else}
end; {if}
if (lLong.preference & gLong.where) = 0 then begin
if (lLong.preference & inPointer) <> 0 then begin
if gLong.where = localAddress then begin
if not gLong.fixedDisp then begin
GenNative(m_stz_dir, direct, dworkLoc+2, nil, 0);
GenImplied(m_phx);
GenImplied(m_tdc);
GenImplied(m_clc);
if gLong.disp <> 0 then
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
GenNative(m_adc_s, direct, 1, nil, 0);
GenNative(m_sta_dir, direct, dworkLoc, nil, 0);
GenImplied(m_plx);
end {if}
else begin
GenNative(m_stz_dir, direct, dworkLoc+2, nil, 0);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
GenNative(m_sta_dir, direct, dworkLoc, nil, 0);
end; {else}
end {if}
else begin
if not gLong.fixedDisp then begin
GenImplied(m_txa);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, gLong.lab, 0);
GenNative(m_sta_dir, direct, dworkLoc, nil, 0);
GenNative(m_ldx_imm, immediate, gLong.disp, gLong.lab, shift16);
lab1 := GenLabel;
GenNative(m_bcc, relative, lab1, nil, 0);
GenImplied(m_inx);
GenLab(lab1);
GenNative(m_stx_dir, direct, dworkLoc+2, nil, 0);
end {if}
else begin
GenNative(m_lda_imm, immediate, gLong.disp, gLong.lab, shift16);
GenNative(m_sta_dir, direct, dworkLoc+2, nil, 0);
GenNative(m_lda_imm, immediate, gLong.disp, gLong.lab, 0);
GenNative(m_sta_dir, direct, dworkLoc, nil, 0);
end; {else}
end; {else}
gLong.where := inPointer;
gLong.fixedDisp := true;
gLong.disp := dworkLoc;
end {if}
else begin
if gLong.where = localAddress then begin
if not gLong.fixedDisp then begin
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_phx);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_s, direct, 1, nil, 0);
if gLong.disp <> 0 then
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
GenNative(m_sta_s, direct, 1, nil, 0);
end {if}
else begin
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
GenImplied(m_pha);
end; {else}
end {if}
else begin
if not gLong.fixedDisp then begin
GenImplied(m_txa);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, gLong.lab, 0);
GenNative(m_ldx_imm, immediate, gLong.disp, gLong.lab, shift16);
lab1 := GenLabel;
GenNative(m_bcc, relative, lab1, nil, 0);
GenImplied(m_inx);
GenLab(lab1);
GenImplied(m_phx);
GenImplied(m_pha);
end {if}
else begin
GenNative(m_pea, immediate, gLong.disp, gLong.lab, shift16);
GenNative(m_pea, immediate, gLong.disp, gLong.lab, 0);
end; {else}
end; {else}
gLong.where := onStack;
end; {else}
end; {if}
end; {case localAddress,globalLabel}
otherwise:
Error(cge1);
end; {case}
end {if smallMemoryModel or (op^.left^.opcode = pc_lda)}
else begin
signed := IndexCanBeNegative;
if (not signed)
and ((globalLabel & lLong.preference) <> 0)
and (op^.left^.opcode = pc_lao)
then begin
if Complex(op^.right) then begin
GenTree(op^.right);
GenImplied(m_tax);
end {if}
else
LoadX(op^.right);
gLong.where := globalLabel;
gLong.fixedDisp := false;
gLong.disp := op^.left^.q;
gLong.lab := op^.left^.lab;
end {if}
else begin
if op^.left^.opcode = pc_lao then begin
GenTree(op^.right);
GenNative(m_ldx_imm, immediate, op^.left^.q, op^.left^.lab, shift16);
if signed then begin
GenImpliedForFlags(m_tay);
lab2 := GenLabel;
GenNative(m_bpl, relative, lab2, nil, 0);
GenImplied(m_dex);
GenLab(lab2);
signed := false;
end; {if}
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, op^.left^.q, op^.left^.lab, 0);
end {if}
else begin
gLong.preference := onStack;
GenTree(op^.left);
GenTree(op^.right);
if signed then
GenImplied(m_tay);
GenImplied(m_clc);
GenNative(m_adc_s, direct, 1, nil, 0);
GenImplied(m_plx);
GenImplied(m_plx);
end; {else}
lab1 := GenLabel;
GenNative(m_bcc, relative, lab1, nil, 0);
GenImplied(m_inx);
GenLab(lab1);
if signed then begin
GenNative(m_cpy_imm, immediate, $0000, nil, 0);
lab2 := GenLabel;
GenNative(m_bpl, relative, lab2, nil, 0);
GenImplied(m_dex);
GenLab(lab2);
end; {if}
if (A_X & lLong.preference) <> 0 then
gLong.where := A_X
else begin
GenImplied(m_phx);
GenImplied(m_pha);
gLong.where := onStack;
end; {else}
end; {else}
end; {else}
end; {GenIxa}
procedure GenLilLliLdlLld (op: icptr);
{ Generate code for a pc_lil, pc_lli, pc_ldl or pc_lld }
var
disp: integer; {load location}
lab1: integer; {branch point}
opcode: pcodes; {op^.opcode}
procedure DoXIncDec (op: pcodes; p: integer);
{ Do a decrement or increment on a local four byte value X }
{ bytes into the stack frame }
{ }
{ parameters }
{ op - operation code }
{ p - number to ind/dec by }
var
lab1: integer; {branch point}
begin {DoXIncDec}
if op in [pc_lil,pc_lli] then begin
lab1 := GenLabel;
if p = 1 then begin
GenNative(m_inc_dirx, direct, 0, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
end {if}
else begin
GenImplied(m_clc);
GenNative(m_lda_dirx, direct, 0, nil, 0);
GenNative(m_adc_imm, immediate, p, nil, 0);
GenNative(m_sta_dirx, direct, 0, nil, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
end; {else}
GenNative(m_inc_dirx, direct, 2, nil, 0);
GenLab(lab1);
end {if}
else {if op in [pc_ldl,pc_lld] then} begin
lab1 := GenLabel;
if p = 1 then begin
GenNative(m_lda_dirx, direct, 0, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenNative(m_dec_dirx, direct, 2, nil, 0);
GenLab(lab1);
GenNative(m_dec_dirx, direct, 0, nil, 0);
end {if}
else begin
GenImplied(m_sec);
GenNative(m_lda_dirx, direct, 0, nil, 0);
GenNative(m_sbc_imm, immediate, p, nil, 0);
GenNative(m_sta_dirx, direct, 0, nil, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
GenNative(m_dec_dirx, direct, 2, nil, 0);
GenLab(lab1);
end; {else}
end; {else}
end; {DoXIncDec}
procedure DoLIncDec (op: pcodes; disp, p: integer);
{ Do a decrement or increment on a local four byte value }
{ }
{ parameters }
{ op - operation code }
{ disp - disp in stack frame to value }
{ p - number to ind/dec by }
var
lab1: integer; {branch point}
begin {DoLIncDec}
if op in [pc_lil,pc_lli] then begin
lab1 := GenLabel;
if p = 1 then begin
GenNative(m_inc_dir, direct, disp, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
end {if}
else begin
GenImplied(m_clc);
GenNative(m_lda_dir, direct, disp, nil, 0);
GenNative(m_adc_imm, immediate, p, nil, 0);
GenNative(m_sta_dir, direct, disp, nil, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
end; {else}
GenNative(m_inc_dir, direct, disp+2, nil, 0);
GenLab(lab1);
end {if}
else {if op in [pc_ldl,pc_lld] then} begin
lab1 := GenLabel;
if p = 1 then begin
GenNative(m_lda_dir, direct, disp, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenNative(m_dec_dir, direct, disp+2, nil, 0);
GenLab(lab1);
GenNative(m_dec_dir, direct, disp, nil, 0);
end {if}
else begin
GenImplied(m_sec);
GenNative(m_lda_dir, direct, disp, nil, 0);
GenNative(m_sbc_imm, immediate, p, nil, 0);
GenNative(m_sta_dir, direct, disp, nil, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
GenNative(m_dec_dir, direct, disp+2, nil, 0);
GenLab(lab1);
end; {else}
end; {else}
end; {DoLIncDec}
begin {GenLilLliLdlLld}
disp := LabelToDisp(op^.r);
opcode := op^.opcode;
case op^.optype of
cgLong, cgULong: begin
gLong.where := onStack;
if disp >= 254 then begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
if opcode in [pc_lil,pc_ldl] then
DoXIncDec(opcode, op^.q);
if not skipLoad then begin
GenNative(m_lda_dirx, direct, 2, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_dirx, direct, 0, nil, 0);
GenImplied(m_pha);
end {if}
else
gLong.where := A_X;
if opcode in [pc_lli,pc_lld] then
DoXIncDec(opcode, op^.q);
end {if}
else begin
if opcode in [pc_lil,pc_ldl] then
DoLIncDec(opcode, disp, op^.q);
if not skipLoad then begin
GenNative(m_pei_dir, direct, disp+2, nil, 0);
GenNative(m_pei_dir, direct, disp, nil, 0);
end {if}
else
gLong.where := A_X;
if opcode in [pc_lli,pc_lld] then
DoLIncDec(opcode, disp, op^.q);
end; {else}
end;
cgByte, cgUByte, cgWord, cgUWord: begin
if op^.optype in [cgByte,cgUByte] then
GenNative(m_sep, immediate, 32, nil, 0);
if disp >= 256 then begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
if opcode = pc_lil then
GenNative(m_inc_dirx, direct, 0, nil, 0)
else if opcode = pc_ldl then
GenNative(m_dec_dirx, direct, 0, nil, 0);
if not skipLoad then
GenNative(m_lda_dirx, direct, 0, nil, 0);
if opcode = pc_lli then
GenNative(m_inc_dirx, direct, 0, nil, 0)
else if opcode = pc_lld then
GenNative(m_dec_dirx, direct, 0, nil, 0);
end
else begin
if opcode = pc_lil then
GenNative(m_inc_dir, direct, disp, nil, 0)
else if opcode = pc_ldl then
GenNative(m_dec_dir, direct, disp, nil, 0);
if not skipLoad then
GenNative(m_lda_dir, direct, disp, nil, 0);
if opcode = pc_lli then
GenNative(m_inc_dir, direct, disp, nil, 0)
else if opcode = pc_lld then
GenNative(m_dec_dir, direct, disp, nil, 0);
end; {else}
if op^.optype in [cgByte,cgUByte] then begin
GenNative(m_rep, immediate, 32, nil, 0);
if not skipLoad then begin
GenNative(m_and_imm, immediate, $00FF, nil, 0);
if op^.optype = cgByte then begin
GenNative(m_bit_imm, immediate, $0080, nil, 0);
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
GenNative(m_cmp_imm, immediate, $0000, nil, 0);
end; {if}
end; {if}
end; {if}
end;
otherwise:
Error(cge1);
end; {case}
end; {GenLilLliLdlLld}
procedure GenLogic (op: icptr);
{ generate a pc_and, pc_ior, pc_bnd, pc_bor or pc_bxr }
var
lab1,lab2,lab3: integer; {label}
nd: icptr; {temp node pointer}
opcode: pcodes; {operation code}
begin {GenLogic}
opcode := op^.opcode;
if opcode in [pc_and,pc_ior] then begin
lab1 := GenLabel;
GenTree(op^.left);
GenImpliedForFlags(m_tax);
lab2 := GenLabel;
if opcode = pc_and then begin
GenNative(m_bne, relative, lab2, nil, 0);
GenNative(m_brl, longrelative, lab1, nil, 0);
end {if}
else begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab2, nil, 0);
GenNative(m_brl, longrelative, lab3, nil, 0);
end; {else}
GenLab(lab2);
GenTree(op^.right);
GenImpliedForFlags(m_tax);
GenNative(m_beq, relative, lab1, nil, 0);
if opcode = pc_ior then
GenLab(lab3);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end {if}
else begin
if not Complex(op^.left) then
if Complex(op^.right) then begin
nd := op^.left;
op^.left := op^.right;
op^.right := nd;
end; {if}
GenTree(op^.left);
if Complex(op^.right) then begin
GenImplied(m_pha);
GenTree(op^.right);
case opcode of
pc_bnd: GenNative(m_and_s, direct, 1, nil, 0);
pc_bor: GenNative(m_ora_s, direct, 1, nil, 0);
pc_bxr: GenNative(m_eor_s, direct, 1, nil, 0);
otherwise:
Error(cge1);
end; {case}
GenImplied(m_plx);
GenImplied(m_tax);
end {if}
else
case opcode of
pc_bnd: OperA(m_and_imm, op^.right);
pc_bor: OperA(m_ora_imm, op^.right);
pc_bxr: OperA(m_eor_imm, op^.right);
otherwise:
Error(cge1);
end; {case}
end; {else}
end; {GenLogic}
procedure GenSroCpo (op: icptr);
{ Generate code for a pc_sro or pc_cpo }
var
lab: stringPtr; {op^.lab}
lab1: integer; {branch point}
lval: longint; {op^.left^.lval}
opcode: pcodes; {op^.opcode}
optype: baseTypeEnum; {op^.optype}
q: integer; {op^.q}
begin {GenSroCpo}
opcode := op^.opcode;
optype := op^.optype;
q := op^.q;
lab := op^.lab;
case optype of
cgByte, cgUByte: begin
if smallMemoryModel and (op^.left^.opcode = pc_ldc)
and (op^.left^.q = 0) and (opcode = pc_sro) then begin
GenNative(m_sep, immediate, 32, nil, 0);
GenNative(m_stz_abs, absolute, q, lab, 0);
end {if}
else begin
if op^.opcode = pc_sro then
if op^.left^.opcode = pc_cnv then
if (op^.left^.q >> 4) in [ord(cgWord),ord(cgUWord)] then
op^.left := op^.left^.left;
if op^.left^.opcode in [pc_ldc,pc_ldc,pc_lod] then begin
GenNative(m_sep, immediate, 32, nil, 0);
GenTree(op^.left);
end {if}
else begin
GenTree(op^.left);
GenNative(m_sep, immediate, 32, nil, 0);
end; {else}
if smallMemoryModel then
GenNative(m_sta_abs, absolute, q, lab, 0)
else
GenNative(m_sta_long, longabsolute, q, lab, 0);
end; {else}
GenNative(m_rep, immediate, 32, nil, 0);
end;
cgWord, cgUWord:
if smallMemoryModel and (op^.left^.opcode = pc_ldc)
and (op^.left^.q = 0) and (opcode = pc_sro) then
GenNative(m_stz_abs, absolute, q, lab, 0)
else begin
GenTree(op^.left);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, q, lab, 0)
else
GenNative(m_sta_long, longabsolute, q, lab, 0);
end; {else}
cgReal, cgDouble, cgComp, cgExtended: begin
GenTree(op^.left);
GenNative(m_pea, immediate, q, lab, shift16);
GenNative(m_pea, immediate, q, lab, 0);
if opcode = pc_sro then begin
if optype = cgReal then
GenCall(9)
else if optype = cgDouble then
GenCall(10)
else if optype = cgComp then
GenCall(66)
else {if optype = cgExtended then}
GenCall(67);
end {if}
else {if opcode = pc_cpo then} begin
if optype = cgReal then begin
GenCall(9);
GenNative(m_pea, immediate, q, lab, shift16);
GenNative(m_pea, immediate, q, lab, 0);
GenCall(21);
end {if}
else if optype = cgDouble then begin
GenCall(10);
GenNative(m_pea, immediate, q, lab, shift16);
GenNative(m_pea, immediate, q, lab, 0);
GenCall(22);
end {else if}
else if optype = cgComp then begin
GenCall(66);
GenNative(m_pea, immediate, q, lab, shift16);
GenNative(m_pea, immediate, q, lab, 0);
GenCall(70);
end {else if}
else {if optype = cgExtended then}
GenCall(69);
end; {else}
end;
cgLong, cgULong: begin
if (opcode = pc_sro) and (op^.left^.opcode in [pc_adl,pc_sbl]) then
GenAdlSbl(op^.left, op)
else if (opcode = pc_sro) and (op^.left^.opcode in [pc_inc,pc_dec]) then
GenIncDec(op^.left, op)
else if smallMemoryModel and (op^.left^.opcode = pc_ldc) then begin
lval := op^.left^.lval;
if long(lval).lsw = 0 then
GenNative(m_stz_abs, absolute, q, lab, 0)
else begin
GenNative(m_lda_imm, immediate, long(lval).lsw, nil, 0);
GenNative(m_sta_abs, absolute, q, lab, 0)
end; {else}
if long(lval).msw = 0 then
GenNative(m_stz_abs, absolute, q+2, lab, 0)
else begin
GenNative(m_ldx_imm, immediate, long(lval).msw, nil, 0);
GenNative(m_stx_abs, absolute, q+2, lab, 0)
end; {else}
if op^.opcode = pc_cpo then
GenTree(op^.left);
end {if}
else begin
if op^.opcode = pc_sro then
gLong.preference := A_X | inPointer | localAddress | globalLabel | constant
else
gLong.preference := gLong.preference &
(A_X | inPointer | localAddress | globalLabel | constant);
GenTree(op^.left);
case gLong.where of
A_X: begin
if smallMemoryModel then begin
GenNative(m_stx_abs, absolute, q+2, lab, 0);
GenNative(m_sta_abs, absolute, q, lab, 0);
end {if}
else begin
GenNative(m_sta_long, longabsolute, q, lab, 0);
if opcode = pc_cpo then
GenImplied(m_pha);
GenImplied(m_txa);
GenNative(m_sta_long, longabsolute, q+2, lab, 0);
if opcode = pc_cpo then
GenImplied(m_pla);
end; {else}
end;
onStack: begin
if opcode = pc_sro then
GenImplied(m_pla)
else {if opcode = pc_cpo then}
GenNative(m_lda_s, direct, 1, nil, 0);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, q, lab, 0)
else
GenNative(m_sta_long, longabsolute, q, lab, 0);
if opcode = pc_sro then
GenImplied(m_pla)
else {if opcode = pc_cpo then}
GenNative(m_lda_s, direct, 3, nil, 0);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, q+2, lab, 0)
else
GenNative(m_sta_long, longabsolute, q+2, lab, 0);
end;
inPointer: begin
GenNative(m_ldx_dir, direct, gLong.disp+2, nil, 0);
if gLong.fixedDisp then
GenNative(m_lda_dir, direct, gLong.disp, nil, 0)
else begin
GenImplied(m_tya);
GenImplied(m_clc);
GenNative(m_adc_dir, direct, gLong.disp, nil, 0);
if not smallMemoryModel then begin
lab1 := GenLabel;
GenNative(m_bcc, relative, lab1, nil, 0);
GenImplied(m_inx);
GenLab(lab1);
end; {if}
end; {else}
if smallMemoryModel then begin
GenNative(m_stx_abs, absolute, q+2, lab, 0);
GenNative(m_sta_abs, absolute, q, lab, 0);
end {if}
else begin
GenNative(m_sta_long, longabsolute, q, lab, 0);
if opcode = pc_cpo then
GenImplied(m_pha);
GenImplied(m_txa);
GenNative(m_sta_long, longabsolute, q+2, lab, 0);
if opcode = pc_cpo then
GenImplied(m_pla);
end; {else}
gLong.where := A_X;
end;
localAddress: begin
if smallMemoryModel then
GenNative(m_stz_abs, absolute, q+2, lab, 0)
else begin
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenNative(m_sta_long, longabsolute, q+2, lab, 0);
end; {else}
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
if not gLong.fixedDisp then begin
GenImplied(m_phx);
GenNative(m_adc_s, direct, 1, nil, 0);
GenImplied(m_plx);
end; {if}
if smallMemoryModel then
GenNative(m_sta_abs, absolute, q, lab, 0)
else
GenNative(m_sta_long, longabsolute, q, lab, 0);
end;
globalLabel:
if gLong.fixedDisp then begin
if smallMemoryModel then begin
GenNative(m_lda_imm, immediate, gLong.disp, gLong.lab, 0);
GenNative(m_ldx_imm, immediate, gLong.disp, gLong.lab, shift16);
GenNative(m_stx_abs, absolute, q+2, lab, 0);
GenNative(m_sta_abs, absolute, q, lab, 0);
end {if}
else begin
GenNative(m_lda_imm, immediate, gLong.disp, gLong.lab, shift16);
GenNative(m_sta_long, longabsolute, q+2, lab, 0);
if opcode = pc_cpo then
GenImplied(m_tax);
GenNative(m_lda_imm, immediate, gLong.disp, gLong.lab, 0);
GenNative(m_sta_long, longabsolute, q, lab, 0);
end; {else}
gLong.where := A_X;
end {if}
else begin
GenImplied(m_txa);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, gLong.lab, 0);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, q, lab, 0)
else
GenNative(m_sta_long, longabsolute, q, lab, 0);
GenNative(m_lda_imm, immediate, gLong.disp, gLong.lab, shift16);
GenNative(m_adc_imm, immediate, 0, nil, 0);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, q+2, lab, 0)
else
GenNative(m_sta_long, longabsolute, q+2, lab, 0);
end; {else}
constant: begin
if gLong.lval = 0 then begin
if smallMemoryModel then begin
GenNative(m_stz_abs, absolute, q+2, lab, 0);
GenNative(m_stz_abs, absolute, q, lab, 0);
end {if}
else begin
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenNative(m_sta_long, longabsolute, q+2, lab, 0);
GenNative(m_sta_long, longabsolute, q, lab, 0);
end; {else}
end {if}
else if not smallMemoryModel then begin
GenNative(m_lda_imm, immediate, long(gLong.lval).msw, nil, 0);
GenNative(m_sta_long, longabsolute, q+2, lab, 0);
GenNative(m_lda_imm, immediate, long(gLong.lval).lsw, nil, 0);
GenNative(m_sta_long, longabsolute, q, lab, 0);
end {else if}
else begin
if long(gLong.lval).msw = 0 then
GenNative(m_stz_abs, absolute, q+2, lab, 0)
else begin
GenNative(m_ldx_imm, immediate, long(gLong.lval).msw, nil, 0);
GenNative(m_stx_abs, absolute, q+2, lab, 0);
end; {else}
if long(gLong.lval).lsw = 0 then
GenNative(m_stz_abs, absolute, q, lab, 0)
else begin
GenNative(m_lda_imm, immediate, long(gLong.lval).lsw, nil, 0);
GenNative(m_sta_abs, absolute, q, lab, 0);
end; {else}
if (long(gLong.lval).lsw <> 0) and (long(gLong.lval).msw <> 0) then
gLong.where := A_X;
end; {else}
end; {case constant}
otherwise:
Error(cge1);
end; {case}
end; {else}
end; {case CGLong, cgULong}
cgQuad, cgUQuad: begin
if opcode = pc_sro then begin
gQuad.preference := globalLabel;
gQuad.lab := lab;
gQuad.disp := q;
end {if}
else {if opcode = pc_cpo then}
gQuad.preference := onStack;
GenTree(op^.left);
if gQuad.where = onStack then begin
if opcode = pc_sro then
GenImplied(m_pla)
else {if opcode = pc_cpo then}
GenNative(m_lda_s, direct, 1, nil, 0);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, q, lab, 0)
else
GenNative(m_sta_long, longabsolute, q, lab, 0);
if opcode = pc_sro then
GenImplied(m_pla)
else {if opcode = pc_cpo then}
GenNative(m_lda_s, direct, 3, nil, 0);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, q+2, lab, 0)
else
GenNative(m_sta_long, longabsolute, q+2, lab, 0);
if opcode = pc_sro then
GenImplied(m_pla)
else {if opcode = pc_cpo then}
GenNative(m_lda_s, direct, 5, nil, 0);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, q+4, lab, 0)
else
GenNative(m_sta_long, longabsolute, q+4, lab, 0);
if opcode = pc_sro then
GenImplied(m_pla)
else {if opcode = pc_cpo then}
GenNative(m_lda_s, direct, 7, nil, 0);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, q+6, lab, 0)
else
GenNative(m_sta_long, longabsolute, q+6, lab, 0);
end; {if}
end; {case cgQuad, cgUQuad}
end; {case}
end; {GenSroCpo}
procedure GenStoCpi (op: icptr);
{ Generate code for a pc_sto or pc_cpi }
var
disp: integer; {disp in stack frame}
opcode: pcodes; {temp storage for op code}
optype: baseTypeEnum; {operand type}
short: boolean; {use short registers?}
simple: boolean; {is the load a simple load?}
lLong: longType; {address record for left node}
zero: boolean; {is the operand a constant zero?}
lab1: integer; {label}
procedure LoadLSW;
{ load the least significant word of a four byte value }
begin {LoadLSW}
if lLong.where = onStack then
if opcode = pc_sto then
GenImplied(m_pla)
else
GenNative(m_lda_s, direct, 1, nil, 0)
else {if lLong.where = constant then}
GenNative(m_lda_imm, immediate, long(lLong.lval).lsw, nil, 0);
end; {LoadLSW}
procedure LoadMSW;
{ load the most significant word of a four byte value }
{ }
{ Note: LoadLSW MUST be called first! }
begin {LoadMSW}
if lLong.where = onStack then
if opcode = pc_sto then
GenImplied(m_pla)
else
GenNative(m_lda_s, direct, 3, nil, 0)
else {if lLong.where = constant then}
GenNative(m_lda_imm, immediate, long(lLong.lval).msw, nil, 0);
end; {LoadMSW}
procedure LoadWord;
{ Get the operand for a cgByte, cgUByte, cgWord or cgUWord }
{ into the accumulator }
begin {LoadWord}
if simple then begin
with op^.right^ do
if opcode = pc_ldc then
GenNative(m_lda_imm, immediate, q, nil, 0)
else if opcode = pc_lod then
GenNative(m_lda_dir, direct, LabelToDisp(r) + q, nil, 0)
else {if opcode = pc_ldo then}
if smallMemoryModel then
GenNative(m_lda_abs, absolute, q, lab, 0)
else
GenNative(m_lda_long, longabsolute, q, lab, 0);
if not short then
if op^.right^.optype in [cgByte,cgUByte] then
if op^.right^.opcode <> pc_ldc then begin
GenNative(m_and_imm, immediate, $00FF, nil, 0);
if optype = cgByte then begin
GenNative(m_bit_imm, immediate, $0080, nil, 0);
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
end; {if}
end; {if}
end {if}
else begin
GenImplied(m_pla);
if short then
GenNative(m_sep, immediate, 32, nil, 0);
end {else}
end; {LoadWord}
begin {GenStoCpi}
opcode := op^.opcode;
optype := op^.optype;
case optype of
cgReal,cgDouble,cgComp,cgExtended: begin
if opcode = pc_sto then begin
GenTree(op^.right);
gLong.preference := onStack;
GenTree(op^.left);
if optype = cgReal then
GenCall(9)
else if optype = cgDouble then
GenCall(10)
else if optype = cgComp then
GenCall(66)
else {if optype = cgExtended then}
GenCall(67);
end {if}
else {if opcode = pc_cpi then} begin
if optype = cgExtended then begin
GenTree(op^.right);
gLong.preference := onStack;
GenTree(op^.left);
GenCall(69);
end {if}
else begin
gLong.preference := onStack;
GenTree(op^.left);
GenTree(op^.right);
GenNative(m_lda_s, direct, 13, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_s, direct, 13, nil, 0);
GenImplied(m_pha);
if optype = cgReal then begin
GenCall(9);
GenCall(21);
end {if}
else if optype = cgDouble then begin
GenCall(10);
GenCall(22);
end {else if}
else {if optype = cgComp then} begin
GenCall(66);
GenCall(70);
end; {else}
end; {else}
end; {else}
end; {case cgReal,cgDouble,cgComp,cgExtended}
cgQuad,cgUQuad: begin
gQuad.preference := onStack;
if opcode = pc_sto then
if op^.left^.opcode = pc_lod then begin
disp := LabelToDisp(op^.left^.r) + op^.left^.q;
if disp <= 255 then begin
gQuad.preference := inPointer;
gQuad.disp := disp;
end; {if}
end; {if}
GenTree(op^.right);
if gQuad.where = onStack then begin
gLong.preference := A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {if}
GenNative(m_sta_dir, direct, dworkLoc, nil, 0);
GenNative(m_stx_dir, direct, dworkLoc+2, nil, 0);
if opcode = pc_sto then
GenImplied(m_pla)
else {if op^.opcode = pc_cpi then}
GenNative(m_lda_s, direct, 1, nil, 0);
GenNative(m_sta_indl, direct, dworkLoc, nil, 0);
GenNative(m_ldy_imm, immediate, 2, nil, 0);
if opcode = pc_sto then
GenImplied(m_pla)
else {if op^.opcode = pc_cpi then}
GenNative(m_lda_s, direct, 3, nil, 0);
GenNative(m_sta_indly, direct, dworkLoc, nil, 0);
GenImplied(m_iny);
GenImplied(m_iny);
if opcode = pc_sto then
GenImplied(m_pla)
else {if op^.opcode = pc_cpi then}
GenNative(m_lda_s, direct, 5, nil, 0);
GenNative(m_sta_indly, direct, dworkLoc, nil, 0);
GenImplied(m_iny);
GenImplied(m_iny);
if opcode = pc_sto then
GenImplied(m_pla)
else {if op^.opcode = pc_cpi then}
GenNative(m_lda_s, direct, 7, nil, 0);
GenNative(m_sta_indly, direct, dworkLoc, nil, 0);
if op^.opcode = pc_cpi then
gQuad.where := onStack;
end; {if}
end; {case cgQuad,cgUQuad}
cgLong,cgULong: begin
if opcode = pc_sto then
gLong.preference := onStack+constant
else
gLong.preference := (onStack+constant) & gLong.preference;
GenTree(op^.right);
lLong := gLong;
gLong.preference := localAddress+inPointer+globalLabel+A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenNative(m_sta_dir, direct, dworkLoc, nil, 0);
GenImplied(m_pla);
GenNative(m_sta_dir, direct, dworkLoc+2, nil, 0);
LoadLSW;
GenNative(m_sta_indl, direct, dworkLoc, nil, 0);
GenNative(m_ldy_imm, immediate, 2, nil, 0);
LoadMSW;
GenNative(m_sta_indly, direct, dworkLoc, nil, 0);
end {if}
else if gLong.where = A_X then begin
GenNative(m_sta_dir, direct, dworkLoc, nil, 0);
GenNative(m_stx_dir, direct, dworkLoc+2, nil, 0);
LoadLSW;
GenNative(m_sta_indl, direct, dworkLoc, nil, 0);
GenNative(m_ldy_imm, immediate, 2, nil, 0);
LoadMSW;
GenNative(m_sta_indly, direct, dworkLoc, nil, 0);
end {if}
else if gLong.where = localAddress then begin
LoadLSW;
if gLong.fixedDisp then
if (gLong.disp & $FF00) = 0 then
GenNative(m_sta_dir, direct, gLong.disp, nil, 0)
else begin
GenNative(m_ldx_imm, immediate, gLong.disp, nil, 0);
GenNative(m_sta_dirX, direct, 0, nil, 0);
end {else}
else begin
if (gLong.disp >= 254) or (gLong.disp < 0) then begin
GenImplied(m_tay);
GenImplied(m_txa);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
GenImplied(m_tax);
GenImplied(m_tya);
gLong.disp := 0;
end; {if}
GenNative(m_sta_dirX, direct, gLong.disp, nil, 0);
end; {else}
LoadMSW;
if gLong.fixedDisp then
if ((gLong.disp+2) & $FF00) = 0 then
GenNative(m_sta_dir, direct, gLong.disp+2, nil, 0)
else begin
GenNative(m_ldx_imm, immediate, gLong.disp+2, nil, 0);
GenNative(m_sta_dirX, direct, 0, nil, 0);
end {else}
else begin
if (gLong.disp >= 254) or (gLong.disp < 0) then begin
GenImplied(m_tay);
GenImplied(m_txa);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
GenImplied(m_tax);
GenImplied(m_tya);
gLong.disp := 0;
end; {if}
GenNative(m_sta_dirX, direct, gLong.disp+2, nil, 0);
end; {else}
end {else if}
else if gLong.where = globalLabel then begin
LoadLSW;
if gLong.fixedDisp then
if smallMemoryModel then
GenNative(m_sta_abs, absolute, gLong.disp, gLong.lab, 0)
else
GenNative(m_sta_long, longAbs, gLong.disp, gLong.lab, 0)
else
if smallMemoryModel then
GenNative(m_sta_absX, absolute, gLong.disp, gLong.lab, 0)
else
GenNative(m_sta_longX, longAbs, gLong.disp, gLong.lab, 0);
LoadMSW;
if gLong.fixedDisp then
if smallMemoryModel then
GenNative(m_sta_abs, absolute, gLong.disp+2, gLong.lab, 0)
else
GenNative(m_sta_long, longAbs, gLong.disp+2, gLong.lab, 0)
else
if smallMemoryModel then
GenNative(m_sta_absX, absolute, gLong.disp+2, gLong.lab, 0)
else
GenNative(m_sta_longX, longAbs, gLong.disp+2, gLong.lab, 0);
end {else if}
else begin
LoadLSW;
if gLong.fixedDisp = true then begin
GenNative(m_sta_indl, direct, gLong.disp, nil, 0);
GenNative(m_ldy_imm, immediate, 2, nil, 0);
end {if}
else begin
GenNative(m_sta_indlY, direct, gLong.disp, nil, 0);
GenImplied(m_iny);
GenImplied(m_iny);
end; {else}
LoadMSW;
GenNative(m_sta_indly, direct, gLong.Disp, nil, 0);
end; {else}
gLong := lLong;
end; {case cgLong,cgULong}
cgByte,cgUByte,cgWord,cgUWord: begin
short := optype in [cgByte,cgUByte];
simple := false;
zero := false;
if op^.opcode = pc_sto then begin
if short then
if op^.right^.opcode = pc_cnv then
if (op^.right^.q >> 4) in [ord(cgWord),ord(cgUWord)] then
op^.right := op^.right^.left;
with op^.right^ do begin
if opcode = pc_ldo then
simple := true
else if opcode = pc_lod then
simple := LabelToDisp(r) + q < 256
else if opcode = pc_ldc then begin
simple := true;
zero := q = 0;
end; {else if}
end; {with}
end; {if}
if not (zero or simple) then begin
GenTree(op^.right);
GenImplied(m_pha);
end; {if}
GetPointer(op^.left);
if gLong.where = inPointer then begin
if short and simple then
GenNative(m_sep, immediate, 32, nil, 0);
if zero then
GenNative(m_lda_imm, immediate, 0, nil, 0)
else
LoadWord;
if gLong.fixedDisp then
GenNative(m_sta_indl, direct, gLong.disp, nil, 0)
else
GenNative(m_sta_indlY, direct, gLong.disp, nil, 0);
end {if}
else if gLong.where = localAddress then begin
if gLong.fixedDisp then begin
if short and simple then
GenNative(m_sep, immediate, 32, nil, 0);
if (gLong.disp & $FF00) = 0 then
if zero then
GenNative(m_stz_dir, direct, gLong.disp, nil, 0)
else begin
LoadWord;
GenNative(m_sta_dir, direct, gLong.disp, nil, 0);
end {else}
else begin
if zero then begin
GenNative(m_ldx_imm, immediate, gLong.disp, nil, 0);
GenNative(m_stz_dirX, direct, 0, nil, 0);
end {if}
else begin
LoadWord;
GenNative(m_ldx_imm, immediate, gLong.disp, nil, 0);
GenNative(m_sta_dirX, direct, 0, nil, 0);
end; {else}
end {else}
end {if}
else begin
if (gLong.disp & $FF00) <> 0 then begin
GenImplied(m_txa);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, glong.disp, nil, 0);
GenImplied(m_tax);
gLong.disp := 0;
end; {if}
if short and simple then
GenNative(m_sep, immediate, 32, nil, 0);
if zero then
GenNative(m_stz_dirX, direct, gLong.disp, nil, 0)
else begin
LoadWord;
GenNative(m_sta_dirX, direct, gLong.disp, nil, 0);
end; {else}
end; {else}
end {else if}
else {if gLong.where = globalLabel then} begin
if short and simple then
GenNative(m_sep, immediate, 32, nil, 0);
if zero then begin
if not smallMemoryModel then
GenNative(m_lda_imm, immediate, 0, nil, 0);
end {if}
else
LoadWord;
if gLong.fixedDisp then
if smallMemoryModel then
if zero then
GenNative(m_stz_abs, absolute, gLong.disp, gLong.lab, 0)
else
GenNative(m_sta_abs, absolute, gLong.disp, gLong.lab, 0)
else
GenNative(m_sta_long, longAbs, gLong.disp, gLong.lab, 0)
else
if smallMemoryModel then
if zero then
GenNative(m_stz_absX, absolute, gLong.disp, gLong.lab, 0)
else
GenNative(m_sta_absX, absolute, gLong.disp, gLong.lab, 0)
else
GenNative(m_sta_longX, longAbs, gLong.disp, gLong.lab, 0);
end; {else}
if short then begin
GenNative(m_rep, immediate, 32, nil, 0);
if opcode = pc_cpi then begin
GenNative(m_and_imm, immediate, $00FF, nil, 0);
if optype = cgByte then begin
GenNative(m_bit_imm, immediate, $0080, nil, 0);
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
end; {if}
end; {if}
end; {if}
end; {case cgByte,cgUByte,cgWord,cgUWord}
otherwise:
Error(cge1);
end; {case}
end; {GenStoCpi}
procedure GenStrCop (op: icptr);
{ Generate code for a pc_str or pc_cop }
var
disp: integer; {store location}
optype: baseTypeEnum; {op^.optype}
zero: boolean; {is the operand a constant zero?}
begin {GenStrCop}
disp := LabelToDisp(op^.r) + op^.q;
optype := op^.optype;
case optype of
cgByte, cgUByte, cgWord, cgUWord: begin
zero := false;
if op^.left^.opcode = pc_ldc then
if op^.opcode = pc_str then
if op^.left^.q = 0 then
zero := true;
if not zero then begin
if optype in [cgByte,cgUByte] then begin
if op^.opcode = pc_str then
if op^.left^.opcode = pc_cnv then
if (op^.left^.q >> 4) in [ord(cgWord),ord(cgUWord)] then
op^.left := op^.left^.left;
if (op^.left^.opcode in [pc_ldc,pc_ldc,pc_lod])
and (op^.opcode = pc_str) then begin
GenNative(m_sep, immediate, 32, nil, 0);
GenTree(op^.left);
end {if}
else begin
GenTree(op^.left);
GenNative(m_sep, immediate, 32, nil, 0);
end; {else}
end {if}
else
GenTree(op^.left);
end {if}
else
if optype in [cgByte,cgUByte] then
GenNative(m_sep, immediate, 32, nil, 0);
if disp > 255 then begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
if zero then
GenNative(m_stz_dirx, direct, 0, nil, 0)
else
GenNative(m_sta_dirx, direct, 0, nil, 0);
end {if}
else
if zero then
GenNative(m_stz_dir, direct, disp, nil, 0)
else
GenNative(m_sta_dir, direct, disp, nil, 0);
if optype in [cgByte,cgUByte] then
GenNative(m_rep, immediate, 32, nil, 0);
end;
cgReal, cgDouble, cgComp, cgExtended: begin
GenTree(op^.left);
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, disp, nil, 0);
GenImplied(m_pha);
if op^.opcode = pc_str then begin
if optype = cgReal then
GenCall(9)
else if optype = cgDouble then
GenCall(10)
else if optype = cgComp then
GenCall(66)
else {if optype = cgExtended then}
GenCall(67);
end {if}
else begin
if optype = cgReal then begin
GenCall(9);
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, disp, nil, 0);
GenImplied(m_pha);
GenCall(21);
end {if}
else if optype = cgDouble then begin
GenCall(10);
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, disp, nil, 0);
GenImplied(m_pha);
GenCall(22);
end {else if}
else if optype = cgComp then begin
GenCall(66);
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, disp, nil, 0);
GenImplied(m_pha);
GenCall(70);
end {else if}
else {if optype = cgExtended then}
GenCall(69);
end; {else}
end;
cgLong, cgULong: begin
if (op^.opcode = pc_str) and (op^.left^.opcode in [pc_adl,pc_sbl]) then
GenAdlSbl(op^.left, op)
else if (op^.opcode = pc_str) and (op^.left^.opcode in [pc_inc,pc_dec]) then
GenIncDec(op^.left, op)
else begin
if op^.opcode = pc_str then
gLong.preference :=
A_X+onStack+inPointer+localAddress+globalLabel+constant
else
gLong.preference := onStack;
GenTree(op^.left);
case gLong.where of
A_X:
if disp < 254 then begin
GenNative(m_stx_dir, direct, disp+2, nil, 0);
GenNative(m_sta_dir, direct, disp, nil, 0);
end {else if}
else begin
GenImplied(m_txy);
GenNative(m_ldx_imm, immediate, disp, nil, 0);
GenNative(m_sta_dirX, direct, 0, nil, 0);
GenNative(m_sty_dirX, direct, 2, nil, 0);
if op^.opcode = pc_cop then
GenImplied(m_tyx);
end; {else}
onStack:
if disp < 254 then begin
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 1, nil, 0);
GenNative(m_sta_dir, direct, disp, nil, 0);
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 3, nil, 0);
GenNative(m_sta_dir, direct, disp+2, nil, 0);
end {else if}
else begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 1, nil, 0);
GenNative(m_sta_dirX, direct, 0, nil, 0);
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 3, nil, 0);
GenNative(m_sta_dirX, direct, 2, nil, 0);
end; {else}
inPointer: begin
if (disp < 254) and (gLong.disp < 254) and gLong.fixedDisp
and (disp >= 0) and (gLong.disp >= 0) then begin
GenNative(m_lda_dir, direct, gLong.disp, nil, 0);
GenNative(m_ldx_dir, direct, gLong.disp+2, nil, 0);
GenNative(m_sta_dir, direct, disp, nil, 0);
GenNative(m_stx_dir, direct, disp+2, nil, 0);
end {if}
else if (disp < 254) and (gLong.disp < 254)
and (disp >= 0) and (gLong.disp >= 0)
and (op^.opcode = pc_str) then begin
GenImplied(m_tya);
GenImplied(m_clc);
GenNative(m_adc_dir, direct, gLong.disp, nil, 0);
GenNative(m_sta_dir, direct, disp, nil, 0);
GenNative(m_lda_dir, direct, gLong.disp+2, nil, 0);
GenNative(m_adc_imm, immediate, 0, nil, 0);
GenNative(m_sta_dir, direct, disp+2, nil, 0);
end {else if}
else begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
if not gLong.fixedDisp then begin
GenImplied(m_tya);
GenImplied(m_clc);
GenNative(m_adc_dir, direct, gLong.disp, nil, 0);
end {if}
else
GenNative(m_lda_dir, direct, gLong.disp, nil, 0);
GenNative(m_sta_dirX, direct, 0, nil, 0);
GenNative(m_lda_dir, direct, gLong.disp+2, nil, 0);
if not gLong.fixedDisp then
GenNative(m_adc_imm, immediate, 0, nil, 0);
GenNative(m_sta_dirX, direct, 2, nil, 0);
end; {else}
end;
localAddress:
if disp < 254 then begin
GenNative(m_stz_dir, direct, disp+2, nil, 0);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
if not gLong.fixedDisp then begin
GenImplied(m_phx);
GenNative(m_adc_s, direct, 1, nil, 0);
GenImplied(m_plx);
end; {if}
GenNative(m_sta_dir, direct, disp, nil, 0);
end {else if disp < 254}
else begin
if not gLong.fixedDisp then
GenImplied(m_phx);
GenNative(m_ldx_imm, immediate, disp, nil, 0);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, nil, 0);
if not gLong.fixedDisp then
GenNative(m_adc_s, direct, 1, nil, 0);
GenNative(m_sta_dirX, direct, 0, nil, 0);
GenNative(m_stz_dirX, direct, 2, nil, 0);
if not gLong.fixedDisp then
GenImplied(m_plx);
end; {else}
globalLabel: begin
if not gLong.fixedDisp then
GenImplied(m_txa);
if disp > 253 then begin
if op^.opcode = pc_cop then
if not gLong.fixedDisp then
GenImplied(m_tay)
else
GenImplied(m_txy);
GenNative(m_ldx_imm, immediate, disp, nil, 0);
end; {if}
if gLong.fixedDisp then
GenNative(m_lda_imm, immediate, gLong.disp, gLong.lab, 0)
else begin
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gLong.disp, gLong.lab, 0);
end; {else}
if disp < 254 then
GenNative(m_sta_dir, direct, disp, nil, 0)
else
GenNative(m_sta_dirX, direct, 0, nil, 0);
GenNative(m_lda_imm, immediate, gLong.disp, gLong.lab, shift16);
if not gLong.fixedDisp then
GenNative(m_adc_imm, immediate, 0, nil, 0);
if disp < 254 then
GenNative(m_sta_dir, direct, disp+2, nil, 0)
else begin
GenNative(m_sta_dirX, direct, 2, nil, 0);
if op^.opcode = pc_cop then
GenImplied(m_tyx);
end; {else}
end;
constant:
if disp < 254 then begin
GenNative(m_lda_imm, immediate, long(gLong.lval).lsw, nil, 0);
GenNative(m_sta_dir, direct, disp, nil, 0);
GenNative(m_lda_imm, immediate, long(gLong.lval).msw, nil, 0);
GenNative(m_sta_dir, direct, disp+2, nil, 0);
end {else}
else begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
GenNative(m_lda_imm, immediate, long(gLong.lval).lsw, nil, 0);
GenNative(m_sta_dirX, direct, 0, nil, 0);
GenNative(m_lda_imm, immediate, long(gLong.lval).msw, nil, 0);
GenNative(m_sta_dirX, direct, 2, nil, 0);
end; {else}
otherwise:
Error(cge1);
end; {case}
end; {else}
end;
cgQuad, cgUQuad: begin
if op^.opcode = pc_str then begin
gQuad.preference := localAddress;
gQuad.disp := disp;
end {if}
else {if op^.opcode = pc_cop then}
gQuad.preference := onStack;
GenTree(op^.left);
if gQuad.where = onStack then begin
if disp < 250 then begin
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 1, nil, 0);
GenNative(m_sta_dir, direct, disp, nil, 0);
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 3, nil, 0);
GenNative(m_sta_dir, direct, disp+2, nil, 0);
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 5, nil, 0);
GenNative(m_sta_dir, direct, disp+4, nil, 0);
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 7, nil, 0);
GenNative(m_sta_dir, direct, disp+6, nil, 0);
end {else if}
else begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 1, nil, 0);
GenNative(m_sta_dirX, direct, 0, nil, 0);
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 3, nil, 0);
GenNative(m_sta_dirX, direct, 2, nil, 0);
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 5, nil, 0);
GenNative(m_sta_dirX, direct, 4, nil, 0);
if op^.opcode = pc_str then
GenImplied(m_pla)
else {if op^.opcode = pc_cop then}
GenNative(m_lda_s, direct, 7, nil, 0);
GenNative(m_sta_dirX, direct, 6, nil, 0);
end; {else}
end; {if}
end;
otherwise: Error(cge1);
end; {case}
end; {GenStrCop}
procedure GenUnaryLong (op: icptr);
{ generate a pc_bnl or pc_ngl }
begin {GenUnaryLong}
gLong.preference := onStack; {get the operand}
GenTree(op^.left);
case op^.opcode of {do the operation}
pc_bnl: begin
GenNative(m_lda_s, direct, 1, nil, 0);
GenNative(m_eor_imm, immediate, $FFFF, nil, 0);
GenNative(m_sta_s, direct, 1, nil, 0);
GenNative(m_lda_s, direct, 3, nil, 0);
GenNative(m_eor_imm, immediate, $FFFF, nil, 0);
GenNative(m_sta_s, direct, 3, nil, 0);
end; {case pc_bnl}
pc_ngl: begin
GenImplied(m_sec);
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenNative(m_sbc_s, direct, 1, nil, 0);
GenNative(m_sta_s, direct, 1, nil, 0);
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenNative(m_sbc_s, direct, 3, nil, 0);
GenNative(m_sta_s, direct, 3, nil, 0);
end; {case pc_ngl}
end; {case}
gLong.where := onStack; {the result is on the stack}
end; {GenUnaryLong}
procedure GenUnaryQuad (op: icptr);
{ generate a pc_bnq or pc_ngq }
begin {GenUnaryQuad}
case op^.opcode of {do the operation}
pc_bnq: begin
if SimpleQuadLoad(op^.left) then begin
OpOnWordOfQuad(m_lda_imm, op^.left, 6);
GenNative(m_eor_imm, immediate, $FFFF, nil, 0);
StoreWordOfQuad(6);
OpOnWordOfQuad(m_lda_imm, op^.left, 4);
GenNative(m_eor_imm, immediate, $FFFF, nil, 0);
StoreWordOfQuad(4);
OpOnWordOfQuad(m_lda_imm, op^.left, 2);
GenNative(m_eor_imm, immediate, $FFFF, nil, 0);
StoreWordOfQuad(2);
OpOnWordOfQuad(m_lda_imm, op^.left, 0);
GenNative(m_eor_imm, immediate, $FFFF, nil, 0);
StoreWordOfQuad(0);
gQuad.where := gQuad.preference;
end {if}
else begin
gQuad.preference := onStack;
GenTree(op^.left);
GenNative(m_lda_s, direct, 1, nil, 0);
GenNative(m_eor_imm, immediate, $FFFF, nil, 0);
GenNative(m_sta_s, direct, 1, nil, 0);
GenNative(m_lda_s, direct, 3, nil, 0);
GenNative(m_eor_imm, immediate, $FFFF, nil, 0);
GenNative(m_sta_s, direct, 3, nil, 0);
GenNative(m_lda_s, direct, 5, nil, 0);
GenNative(m_eor_imm, immediate, $FFFF, nil, 0);
GenNative(m_sta_s, direct, 5, nil, 0);
GenNative(m_lda_s, direct, 7, nil, 0);
GenNative(m_eor_imm, immediate, $FFFF, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
gQuad.where := onStack;
end; {else}
end; {case pc_bnq}
pc_ngq: begin
if SimpleQuadLoad(op^.left) then begin
gQuad.where := gQuad.preference;
if gQuad.preference = onStack then begin
GenImplied(m_tsc);
GenImplied(m_sec);
GenNative(m_sbc_imm, immediate, 8, nil, 0);
GenImplied(m_tcs);
gQuad.preference := inStackLoc;
gQuad.disp := 1;
end; {if}
GenImplied(m_sec);
GenNative(m_lda_imm, immediate, 0, nil, 0);
OpOnWordOfQuad(m_sbc_imm, op^.left, 0);
StoreWordOfQuad(0);
GenNative(m_lda_imm, immediate, 0, nil, 0);
OpOnWordOfQuad(m_sbc_imm, op^.left, 2);
StoreWordOfQuad(2);
GenNative(m_lda_imm, immediate, 0, nil, 0);
OpOnWordOfQuad(m_sbc_imm, op^.left, 4);
StoreWordOfQuad(4);
GenNative(m_lda_imm, immediate, 0, nil, 0);
OpOnWordOfQuad(m_sbc_imm, op^.left, 6);
StoreWordOfQuad(6);
end {if}
else begin
gQuad.preference := onStack;
GenTree(op^.left);
GenImplied(m_sec);
GenNative(m_ldy_imm, immediate, 0, nil, 0);
GenImplied(m_tya);
GenNative(m_sbc_s, direct, 1, nil, 0);
GenNative(m_sta_s, direct, 1, nil, 0);
GenImplied(m_tya);
GenNative(m_sbc_s, direct, 3, nil, 0);
GenNative(m_sta_s, direct, 3, nil, 0);
GenImplied(m_tya);
GenNative(m_sbc_s, direct, 5, nil, 0);
GenNative(m_sta_s, direct, 5, nil, 0);
GenImplied(m_tya);
GenNative(m_sbc_s, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
gQuad.where := onStack;
end; {else}
end; {case pc_ngq}
end; {case}
end; {GenUnaryQuad}
{$segment 'gen2'}
procedure GenDebugSourceFile (debugFile: gsosOutStringPtr);
{ generate debug code indicating the specified source file name }
var
i: integer; {loop/index variable}
len: integer; {length of the file name}
begin {GenDebugSourceFile}
GenNative(m_cop, immediate, 6, nil, 0);
GenNative(d_add, genaddress, stringSize, nil, stringReference);
GenNative(d_add, genaddress, stringSize, nil, stringReference+shift16);
len := debugFile^.theString.size;
if len > 255 then
len := 255;
if maxString-stringSize >= len+1 then begin
stringSpace^[stringSize+1] := chr(len);
for i := 1 to len do
stringSpace^[i+stringSize+1] :=
debugFile^.theString.theString[i];
stringSize := stringSize + len + 1;
end {if}
else
Error(cge3);
end; {GenDebugSourceFile}
procedure GenTree {op: icptr};
{ generate code for op and its children }
{ }
{ parameters: }
{ op - opcode for which to generate code }
procedure GenAdi (op: icptr);
{ generate a pc_adi }
var
nd: icptr;
begin {GenAdi}
if not Complex(op^.left) then
if Complex(op^.right) then begin
nd := op^.left;
op^.left := op^.right;
op^.right := nd;
end; {if}
GenTree(op^.left);
if Complex(op^.right) then begin
GenImplied(m_pha);
GenTree(op^.right);
GenImplied(m_clc);
GenNative(m_adc_s, direct, 1, nil, 0);
GenImplied(m_plx);
end {if}
else begin
GenImplied(m_clc);
OperA(m_adc_imm, op^.right);
end; {else}
end; {GenAdi}
procedure GenBinLong (op: icptr);
{ generate one of: pc_blr, pc_blx, pc_bal, pc_dvl, pc_mdl, }
{ pc_mpl, pc_sll, pc_slr, pc_udl, pc_ulm, pc_uml, pc_vsr }
var
nd: icptr; {for swapping left/right children}
lab1,lab2: integer; {label numbers}
procedure GenOp (ops, opi: integer);
{ generate a binary operation }
{ }
{ parameters: }
{ ops - stack version of operation }
{ opi - immediate version of operation }
begin {GenOp}
if gLong.where = A_X then
GenImplied(m_phx)
else
GenImplied(m_pla);
if gLong.where = constant then begin
GenNative(opi, immediate, long(gLong.lval).lsw, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_s, direct, 3, nil, 0);
GenNative(opi, immediate, long(gLong.lval).msw, nil, 0);
GenNative(m_sta_s, direct, 3, nil, 0);
end {if}
else begin
GenNative(ops, direct, 3, nil, 0);
GenNative(m_sta_s, direct, 3, nil, 0);
GenImplied(m_pla);
GenNative(ops, direct, 3, nil, 0);
GenNative(m_sta_s, direct, 3, nil, 0);
end; {else}
end; {GenOp}
begin {GenBinLong}
if (op^.left^.opcode = pc_ldc) and
(op^.opcode in [pc_blr,pc_blx,pc_bal]) then begin
nd := op^.left;
op^.left := op^.right;
op^.right := nd;
end; {if}
if op^.opcode = pc_mdl then
GenImplied(m_phd); {reserve stack space}
gLong.preference := onStack;
GenTree(op^.left);
if op^.opcode in [pc_blr,pc_blx,pc_bal] then begin
gLong.preference := constant;
GenTree(op^.right);
end {if}
else if op^.opcode in [pc_uml,pc_udl,pc_ulm] then begin
gLong.preference := A_X;
GenTree(op^.right);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {if}
end {else if}
else begin
gLong.preference := onStack;
GenTree(op^.right);
end; {else}
case op^.opcode of
pc_blr: GenOp(m_ora_s, m_ora_imm);
pc_blx: GenOp(m_eor_s, m_eor_imm);
pc_bal: GenOp(m_and_s, m_and_imm);
pc_dvl: GenCall(43);
pc_mdl: begin
lab1 := GenLabel;
lab2 := GenLabel;
{stash high word of dividend (for sign)}
GenNative(m_lda_s, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 9, nil, 0);
GenCall(78); {call ~DIV4}
GenImplied(m_ply); {ignore quotient}
GenImplied(m_ply);
GenImplied(m_pla); {get remainder (always positive or 0)}
GenImplied(m_plx);
GenImplied(m_ply); {if dividend was negative...}
GenNative(m_bpl, relative, lab1, nil, 0);
GenImplied(m_clc); { negate remainder}
GenNative(m_eor_imm, immediate, -1, nil, 0);
GenNative(m_adc_imm, immediate, 1, nil, 0);
GenImplied(m_tay);
GenImplied(m_txa);
GenNative(m_eor_imm, immediate, -1, nil, 0);
GenNative(m_adc_imm, immediate, 0, nil, 0);
GenImplied(m_pha);
GenImplied(m_phy);
GenNative(m_bra, relative, lab2, nil, 0);
GenLab(lab1);
GenImplied(m_phx);
GenImplied(m_pha);
GenLab(lab2);
end;
pc_mpl: GenCall(42);
pc_sll: GenCall(45);
pc_slr: GenCall(47);
pc_udl: GenCall(49);
pc_ulm: GenCall(50);
pc_uml: GenCall(48);
pc_vsr: GenCall(46);
otherwise: Error(cge1);
end; {case}
gLong.where := onStack;
end; {GenBinLong}
procedure GenBinQuad (op: icptr);
{ generate one of: pc_bqr, pc_bqx, pc_baq, pc_mpq, pc_umq, }
{ pc_dvq, pc_udq, pc_mdq, pc_uqm }
procedure GenBitwiseOp;
{ generate a 64-bit binary bitwise operation }
{ }
{ parameters: }
{ ops - stack version of operation }
var
mop: integer; {machine opcode}
begin {GenBitwiseOp}
if SimpleQuadLoad(op^.left) and SimpleQuadLoad(op^.right) then begin
case op^.opcode of
pc_bqr: mop := m_ora_imm;
pc_bqx: mop := m_eor_imm;
pc_baq: mop := m_and_imm;
end; {case}
OpOnWordOfQuad(m_lda_imm, op^.left, 6);
OpOnWordOfQuad(mop, op^.right, 6);
StoreWordOfQuad(6);
OpOnWordOfQuad(m_lda_imm, op^.left, 4);
OpOnWordOfQuad(mop, op^.right, 4);
StoreWordOfQuad(4);
OpOnWordOfQuad(m_lda_imm, op^.left, 2);
OpOnWordOfQuad(mop, op^.right, 2);
StoreWordOfQuad(2);
OpOnWordOfQuad(m_lda_imm, op^.left, 0);
OpOnWordOfQuad(mop, op^.right, 0);
StoreWordOfQuad(0);
gQuad.where := gQuad.preference;
end {if}
else begin
case op^.opcode of
pc_bqr: mop := m_ora_s;
pc_bqx: mop := m_eor_s;
pc_baq: mop := m_and_s;
end; {case}
gQuad.preference := onStack;
GenTree(op^.left);
gQuad.preference := onStack;
GenTree(op^.right);
GenImplied(m_pla);
GenNative(mop, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(mop, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(mop, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(mop, direct, 7, nil, 0);
GenNative(m_sta_s, direct, 7, nil, 0);
gQuad.where := onStack;
end; {else}
end; {GenBitwiseOp}
begin {GenBinQuad}
if op^.opcode in [pc_bqr,pc_bqx,pc_baq] then
GenBitwiseOp
else begin
gQuad.preference := onStack;
GenTree(op^.left);
gQuad.preference := onStack;
GenTree(op^.right);
case op^.opcode of
pc_mpq: GenCall(79);
pc_umq: GenCall(80);
pc_dvq: begin
GenCall(81); {do division}
GenImplied(m_pla); {get quotient, discarding remainder}
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_sta_s, direct, 7, nil, 0);
end;
pc_udq: begin
GenCall(82); {do division}
GenImplied(m_pla); {get quotient, discarding remainder}
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_sta_s, direct, 7, nil, 0);
GenImplied(m_pla);
GenNative(m_sta_s, direct, 7, nil, 0);
end;
pc_mdq: begin
GenCall(81); {do division}
GenImplied(m_tsc); {discard quotient, leaving remainder}
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, 8, nil, 0);
GenImplied(m_tcs);
end;
pc_uqm: begin
GenCall(82); {do division}
GenImplied(m_tsc); {discard quotient, leaving remainder}
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, 8, nil, 0);
GenImplied(m_tcs);
end;
pc_slq: GenCall(85);
pc_sqr: GenCall(86);
pc_wsr: GenCall(87);
otherwise: Error(cge1);
end; {case}
gQuad.where := onStack;
end; {else}
end; {GenBinQuad}
procedure GenBno (op: icptr);
{ Generate code for a pc_bno }
var
lLong: longType; {requested address type}
lQuad: quadType;
begin {GenBno}
lLong := gLong;
lQuad := gQuad;
GenTree(op^.left);
gLong := lLong;
gQuad := lQuad;
GenTree(op^.right);
end; {GenBno}
procedure GenBntNgiNot (op: icptr);
{ Generate code for a pc_bnt, pc_ngi or pc_not }
var
lab1: integer;
operandIsBoolean: boolean;
begin {GenBntNgiNot}
if op^.opcode = pc_not then
operandIsBoolean := op^.left^.opcode in
[pc_and,pc_ior,pc_lnd,pc_lor,pc_not,pc_neq,pc_equ,pc_geq,pc_leq,
pc_les,pc_grt];
GenTree(op^.left);
case op^.opcode of
pc_bnt:
GenNative(m_eor_imm, immediate, -1, nil, 0);
pc_ngi: begin
GenNative(m_eor_imm, immediate, -1, nil, 0);
GenImplied(m_ina);
end; {case pc_ngi}
pc_not:
if not operandIsBoolean then begin
lab1 := GenLabel;
GenImpliedForFlags(m_tax);
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
GenImplied(m_ina);
end {if}
else
GenNative(m_eor_imm, immediate, 1, nil, 0);
end; {case}
end; {GenBntNgiNot}
procedure GenCui (op: icptr);
{ Generate code for a pc_cui }
var
lab1: integer; {return point}
lLong: longType; {used to reserve gLong}
lQuad: quadType; {saved copy of gQuad}
lArgsSize: integer; {saved copy of argsSize}
extraStackSize: integer; {size of extra stuff pushed on stack}
begin {GenCui}
lArgsSize := argsSize;
argsSize := 0;
extraStackSize := 0;
{For functions returning cg(U)Quad, make space for result}
if op^.optype in [cgQuad,cgUQuad] then
if gQuad.preference <> localAddress then begin
GenImplied(m_tsc);
GenImplied(m_sec);
GenNative(m_sbc_imm, immediate, 8, nil, 0);
GenImplied(m_tcs);
end; {if}
{save the stack register}
if ((saveStack or checkStack) and (op^.q >= 0)) or (op^.q > 0) then begin
if stackSaveDepth <> 0 then begin
GenNative(m_pei_dir, direct, stackLoc, nil, 0);
extraStackSize := 2;
end; {if}
GenImplied(m_tsx);
GenNative(m_stx_dir, direct, stackLoc, nil, 0);
stackSaveDepth := stackSaveDepth + 1;
end; {if}
{generate parameters}
{place the operands on the stack}
lQuad := gQuad;
lLong := gLong;
GenTree(op^.left);
{get the address to call}
gLong.preference := A_X;
GenTree(op^.right);
{create a return label}
lab1 := GenLabel;
{place the call/return addrs on stack}
if gLong.where = A_X then begin
GenImplied(m_tay);
GenImplied(m_txa);
end {if}
else {if gLong.where = onStack then} begin
GenImplied(m_ply);
GenImplied(m_pla);
end; {else}
GenNative(m_and_imm, immediate, $00ff, nil, 0);
GenNative(m_ora_imm, genAddress, lab1, nil, subtract1+shiftLeft8);
GenNative(m_pea, genAddress, lab1, nil, subtract1+shift8);
GenImplied(m_pha);
GenImplied(m_dey);
GenImplied(m_phy);
{For functions returning cg(U)Quad, x = address to store result in}
if op^.optype in [cgQuad,cgUQuad] then
if lQuad.preference = localAddress then begin
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, lQuad.disp, nil, 0);
GenImplied(m_tax);
end {if}
else begin
GenImplied(m_tsc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, argsSize+extraStackSize+6+1, nil, 0);
GenImplied(m_tax);
end; {else}
{indirect call}
GenImplied(m_rtl);
GenLab(lab1);
if checkStack and (op^.q >= 0) then begin
{check the stack for errors}
stackSaveDepth := stackSaveDepth - 1;
GenNative(m_ldy_dir, direct, stackLoc, nil, 0);
GenCall(76);
if stackSaveDepth <> 0 then begin
GenImplied(m_ply);
GenNative(m_sty_dir, direct, stackLoc, nil, 0);
end; {if}
end {if}
else if (saveStack and (op^.q >= 0)) or (op^.q > 0) then begin
stackSaveDepth := stackSaveDepth - 1;
if not (op^.optype in [cgVoid,cgByte,cgUByte,cgWord,cgUWord,cgQuad,cgUQuad])
then
GenImplied(m_txy);
GenNative(m_ldx_dir, direct, stackLoc, nil, 0);
GenImplied(m_txs);
if not (op^.optype in [cgVoid,cgByte,cgUByte,cgWord,cgUWord,cgQuad,cgUQuad])
then
GenImplied(m_tyx);
if stackSaveDepth <> 0 then begin
GenImplied(m_ply);
GenNative(m_sty_dir, direct, stackLoc, nil, 0);
end; {if}
end; {else}
{save the returned value}
gLong := lLong;
gQuad := lQuad;
gLong.where := A_X;
if gQuad.preference = localAddress then
gQuad.where := localAddress
else
gQuad.where := onStack;
SaveRetValue(op^.optype);
argsSize := lArgsSize;
end; {GenCui}
procedure GenCup (op: icptr);
{ Generate code for a pc_cup }
var
lLong: longType; {used to reserve gLong}
lQuad: quadType; {saved copy of gQuad}
lArgsSize: integer; {saved copy of argsSize}
extraStackSize: integer; {size of extra stuff pushed on stack}
begin {GenCup}
lArgsSize := argsSize;
argsSize := 0;
extraStackSize := 0;
{For functions returning cg(U)Quad, make space for result}
if op^.optype in [cgQuad,cgUQuad] then
if gQuad.preference <> localAddress then begin
GenImplied(m_tsc);
GenImplied(m_sec);
GenNative(m_sbc_imm, immediate, 8, nil, 0);
GenImplied(m_tcs);
end; {if}
{save the stack register}
if ((saveStack or checkStack) and (op^.q >= 0)) or (op^.q > 0) then begin
if stackSaveDepth <> 0 then begin
GenNative(m_pei_dir, direct, stackLoc, nil, 0);
extraStackSize := 2;
end; {if}
GenImplied(m_tsx);
GenNative(m_stx_dir, direct, stackLoc, nil, 0);
stackSaveDepth := stackSaveDepth + 1;
end; {if}
{generate parameters}
lQuad := gQuad;
lLong := gLong;
GenTree(op^.left);
gLong := lLong;
gQuad := lQuad;
{For functions returning cg(U)Quad, x = address to store result in}
if op^.optype in [cgQuad,cgUQuad] then
if gQuad.preference = localAddress then begin
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, gQuad.disp, nil, 0);
GenImplied(m_tax);
end {if}
else if argsSize + extraStackSize in [0,1,2] then begin
GenImplied(m_tsx);
GenImplied(m_inx);
if argsSize + extraStackSize in [1,2] then begin
GenImplied(m_inx);
if argsSize + extraStackSize = 2 then
GenImplied(m_inx);
end; {if}
end {if}
else begin
GenImplied(m_tsc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, argsSize+extraStackSize+1, nil, 0);
GenImplied(m_tax);
end; {else}
{generate the jsl}
GenNative(m_jsl, longAbs, 0, op^.lab, 0);
{check the stack for errors}
if checkStack and (op^.q >= 0) then begin
stackSaveDepth := stackSaveDepth - 1;
GenNative(m_ldy_dir, direct, stackLoc, nil, 0);
GenCall(76);
if stackSaveDepth <> 0 then begin
GenImplied(m_ply);
GenNative(m_sty_dir, direct, stackLoc, nil, 0);
end; {if}
end {if}
else if (saveStack and (op^.q >= 0)) or (op^.q > 0) then begin
stackSaveDepth := stackSaveDepth - 1;
if not (op^.optype in [cgVoid,cgByte,cgUByte,cgWord,cgUWord,cgQuad,cgUQuad])
then
GenImplied(m_txy);
GenNative(m_ldx_dir, direct, stackLoc, nil, 0);
GenImplied(m_txs);
if not (op^.optype in [cgVoid,cgByte,cgUByte,cgWord,cgUWord,cgQuad,cgUQuad])
then
GenImplied(m_tyx);
if stackSaveDepth <> 0 then begin
GenImplied(m_ply);
GenNative(m_sty_dir, direct, stackLoc, nil, 0);
end; {if}
end; {else}
{save the returned value}
gLong.where := A_X;
if gQuad.preference = localAddress then
gQuad.where := localAddress
else
gQuad.where := onStack;
SaveRetValue(op^.optype);
argsSize := lArgsSize;
end; {GenCup}
procedure GenDviMod (op: icptr);
{ Generate code for a pc_dvi, pc_mod, pc_udi or pc_uim }
var
opcode: pcodes; {temp storage}
lab1,lab2,lab3: integer; {label numbers}
val: integer;
power: integer;
begin {GenDviMod}
opcode := op^.opcode;
if (op^.right^.opcode = pc_ldc) and not rangeCheck then begin
val := op^.right^.q;
if opcode = pc_udi then begin
case val of
1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384: begin
GenTree(op^.left);
if val >= 256 then begin
GenNative(m_and_imm, immediate, $FF00, nil, 0);
GenImplied(m_xba);
val := val >> 8;
end; {if}
while not odd(val) do begin
GenImplied(m_lsr_a);
val := val >> 1;
end; {while}
opcode := pc_nop;
end;
otherwise:
if (val >= 1000) or (val < 0) then begin {1000..65535}
GenTree(op^.left);
lab1 := GenLabel;
GenNative(m_ldy_imm, immediate, -1, nil, 0);
GenImplied(m_sec);
GenLab(lab1);
GenImplied(m_iny);
GenNative(m_sbc_imm, immediate, val, nil, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
GenImplied(m_tya);
opcode := pc_nop;
end; {if}
end; {case}
end {if}
else if opcode = pc_uim then begin
case val of
1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384: begin
GenTree(op^.left);
GenNative(m_and_imm, immediate, val-1, nil, 0);
opcode := pc_nop;
end;
otherwise:
if (val >= 750) or (val < 0) then begin {750..65535}
GenTree(op^.left);
lab1 := GenLabel;
GenImplied(m_sec);
GenLab(lab1);
GenNative(m_sbc_imm, immediate, val, nil, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
GenNative(m_adc_imm, immediate, val, nil, 0);
opcode := pc_nop;
end; {if}
end; {case}
end {else if}
else if opcode = pc_dvi then begin
case val of
-1: begin
GenTree(op^.left);
GenNative(m_eor_imm, immediate, -1, nil, 0);
GenImplied(m_ina);
opcode := pc_nop;
end;
1: begin
GenTree(op^.left);
opcode := pc_nop;
end;
2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384: begin
GenTree(op^.left);
power := 0;
while not odd(val) do begin
power := power + 1;
val := val >> 1;
end; {while}
if power <> 1 then begin
GenNative(m_ldy_imm, immediate, power, nil, 0);
lab1 := GenLabel;
GenLab(lab1);
end; {if}
lab2 := GenLabel;
lab3 := GenLabel;
GenImpliedForFlags(m_tax);
GenImplied(m_clc);
GenNative(m_bpl, relative, lab2, nil, 0);
GenImplied(m_ina);
GenNative(m_beq, relative, lab3, nil, 0);
GenImplied(m_sec);
GenLab(lab2);
GenImplied(m_ror_a);
if power <> 1 then begin
GenImplied(m_dey);
GenNative(m_bne, relative, lab1, nil, 0);
end; {if}
GenLab(lab3);
opcode := pc_nop;
end;
otherwise: ;
end; {case}
end {else if}
else {if opcode = pc_mod then} begin
case val of
-1,1: begin
GenTree(op^.left);
GenNative(m_lda_imm, immediate, 0, nil, 0);
opcode := pc_nop;
end;
2: begin
GenTree(op^.left);
lab1 := GenLabel;
lab2 := GenLabel;
GenImplied(m_asl_a);
GenNative(m_and_imm, immediate, 2, nil, 0);
GenNative(m_beq, relative, lab2, nil, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
GenImplied(m_dea);
GenImplied(m_dea);
GenLab(lab1);
GenImplied(m_dea);
GenLab(lab2);
opcode := pc_nop;
end;
otherwise: ;
end; {case}
end; {else}
end; {if}
if opcode = pc_nop then
{nothing to do - optimized above}
else if Complex(op^.right) then begin
GenTree(op^.right);
if Complex(op^.left) then begin
GenImplied(m_pha);
GenTree(op^.left);
GenImplied(m_plx);
end {if}
else begin
GenImplied(m_tax);
GenTree(op^.left);
end; {else}
end {else if}
else begin
GenTree(op^.left);
LoadX(op^.right);
end; {else}
if opcode = pc_mod then begin
lab1 := GenLabel;
GenImplied(m_pha); {stash away dividend (for sign)}
GenCall(26); {call ~DIV2}
GenImplied(m_txa); {get remainder (always positive or 0)}
GenImplied(m_ply); {if dividend was negative...}
GenNative(m_bpl, relative, lab1, nil, 0);
GenNative(m_eor_imm, immediate, -1, nil, 0); {...negate remainder}
GenImplied(m_ina);
GenLab(lab1);
end {if}
else if opcode = pc_dvi then
GenCall(26)
else if opcode in [pc_udi,pc_uim] then begin
GenCall(40);
if opcode = pc_uim then
GenImplied(m_txa);
end; {else}
if rangeCheck then
GenCall(25);
end; {GenDviMod}
procedure GenEnt(op: icptr);
{ Generate code for a pc_ent }
var
i: integer;
len: integer;
begin {GenEnt}
if debugStrFlag then begin {gsbug/niftylist debug string}
len := length(op^.lab^);
CnOut(m_brl);
CnOut2(len + 3);
CnOut2($7771);
CnOut(len);
for i := 1 to len do
CnOut(ord(op^.lab^[i]));
end;
if rangeCheck then begin {if range checking is on, check for a stack overflow}
GenNative(m_pea, immediate, localSize - returnSize - 1, nil, 0);
GenCall(1);
end; {if}
if localSize = 0 then begin {create the stack frame}
if parameterSize <> 0 then begin
GenImplied(m_tsc);
GenImplied(m_phd);
GenImplied(m_tcd);
end; {if}
end {if}
else if localSize = 2 then begin
GenImplied(m_pha);
GenImplied(m_tsc);
GenImplied(m_phd);
GenImplied(m_tcd);
end {else if}
else begin
GenImplied(m_tsc);
GenImplied(m_sec);
GenNative(m_sbc_imm, immediate, localSize, nil, 0);
GenImplied(m_tcs);
GenImplied(m_phd);
GenImplied(m_tcd);
end; {if}
if isQuadFunction then begin {save return location for cg(U)Quad}
GenNative(m_stx_dir, direct, funloc, nil, 0);
GenNative(m_stz_dir, direct, funloc+2, nil, 0);
end; {if}
if dataBank then begin {preserve and set data bank}
GenImplied(m_phb);
GenImplied(m_phb);
GenImplied(m_pla);
GenNative(m_sta_dir, direct, bankLoc, nil, 0);
GenNative(m_pea, immediate, 0, @'~GLOBALS', shift8);
GenImplied(m_plb);
GenImplied(m_plb);
end; {if}
{no pc_nam (yet)}
namePushed := false;
end; {GenEnt}
procedure GenFix (op: icptr);
{ Generate code for a pc_fix }
begin {GenFix}
GenNative(m_pea, immediate, localLabel[op^.q], nil, 0);
if op^.optype = cgReal then
GenCall(95)
else if op^.optype = cgDouble then
GenCall(96)
else if op^.optype = cgComp then
GenCall(97);
end; {GenFix}
procedure GenFjpTjp (op: icptr);
{ Generate code for a pc_fjp or pc_tjp }
var
lab1: integer; {branch point}
opcode: pcodes; {op^.left^.opcode}
begin {GenFjpTjp}
if op^.left^.opcode in [pc_equ,pc_geq,pc_grt,pc_les,pc_leq,pc_neq] then
if op^.left^.opcode in [pc_equ,pc_neq] then
GenEquNeq(op^.left, op^.opcode, op^.q)
else
GenCmp(op^.left, op^.opcode, op^.q)
else begin
lab1 := GenLabel;
GenTree(op^.left);
opcode := op^.left^.opcode;
if NeedsCondition(opcode) then
GenImpliedForFlags(m_tax)
else if opcode = pc_ind then
if op^.left^.optype in [cgByte,cgUByte] then
GenImpliedForFlags(m_tax);
if op^.opcode = pc_fjp then
GenNative(m_bne, relative, lab1, nil, 0)
else {if op^.opcode = pc_tjp then}
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, op^.q, nil, 0);
GenLab(lab1);
end; {else}
end; {GenFjpTjp}
procedure GenLaoLad (op: icptr);
{ Generate code for a pc_lao, pc_lad }
var
q: integer; {displacement}
begin {GenLaoLad}
if op^.opcode = pc_lad then
q := 0
else
q := op^.q;
if (globalLabel & gLong.preference) <> 0 then begin
gLong.fixedDisp := true;
gLong.where := globalLabel;
gLong.disp := q;
gLong.lab := op^.lab;
end {if}
else if (A_X & gLong.preference) <> 0 then begin
gLong.where := A_X;
GenNative(m_ldx_imm, immediate, q, op^.lab, shift16);
GenNative(m_lda_imm, immediate, q, op^.lab, 0);
end {else if}
else begin
gLong.where := onStack;
GenNative(m_pea, immediate, q, op^.lab, shift16);
GenNative(m_pea, immediate, q, op^.lab, 0);
end; {else}
end; {GenLaoLad}
procedure GenLbfLbu (op: icptr);
{ Generate code for a pc_lbf or pc_lbu }
var
lLong: longType; {requested address type}
begin {GenLbfLbu}
lLong := gLong;
gLong.preference := onStack;
GenTree(op^.left);
GenNative(m_pea, immediate, op^.r, nil, 0);
GenNative(m_pea, immediate, op^.q, nil, 0);
if op^.opcode = pc_lbf then
GenCall(73)
else
GenCall(72);
if op^.optype in [cgLong,cgULong] then begin
if (A_X & lLong.preference) <> 0 then
gLong.where := A_X
else begin
gLong.where := onStack;
GenImplied(m_phx);
GenImplied(m_pha);
end; {else}
end; {if}
end; {GenLbfLbu}
procedure GenLca (op: icptr);
{ Generate code for a pc_lca }
var
i: integer; {loop/index variable}
begin {GenLca}
gLong.where := onStack;
GenNative(m_pea, immediate, stringSize, nil, stringReference+shift16);
GenNative(m_pea, immediate, stringSize, nil, stringReference);
if maxString-stringSize >= op^.q then begin
for i := 1 to op^.q do
stringSpace^[i+stringSize] := op^.str^.str[i];
stringSize := stringSize+op^.q;
end
else
Error(cge3);
op^.optype := cgULong;
end; {GenLca}
procedure GenLda (op: icptr);
{ Generate code for a pc_lda }
begin {GenLda}
if (localAddress & gLong.preference) <> 0 then begin
gLong.fixedDisp := true;
gLong.where := localAddress;
gLong.disp := LabelToDisp(op^.r) + op^.q;
end {if}
else if (A_X & gLong.preference) <> 0 then begin
gLong.where := A_X;
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, LabelToDisp(op^.r) + op^.q, nil, 0);
GenNative(m_ldx_imm, immediate, 0, nil, 0);
end {else if}
else begin
gLong.where := onStack;
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, LabelToDisp(op^.r) + op^.q, nil, 0);
GenImplied(m_pha);
end; {else}
end; {GenLda}
procedure GenLdc (op: icptr);
{ Generate code for a pc_ldc }
type
kind = (vreal, vlonglong, vwords); {kinds of equivalenced data}
switchRec = packed record
case kind of
vreal: (theReal: extended);
vlonglong: (theLonglong: longlong);
vwords: (words: packed array[1..5] of integer);
end;
var
switch: switchRec; {used for type conversion}
procedure PushWords (switch: switchRec; count: integer);
{ Generate code to push words from the switch record }
{ }
{ parameters }
{ switch - the switch record }
{ count - number of words to push }
var
val: integer; {word value to push}
begin {PushWords}
repeat
val := switch.words[count];
if (count >= 3)
and (switch.words[count-1] = val)
and (switch.words[count-2] = val)
then begin
GenNative(m_lda_imm, immediate, val, nil, 0);
repeat
GenImplied(m_pha);
count := count - 1;
until (count = 0) or (switch.words[count] <> val);
end {if}
else begin
GenNative(m_pea, immediate, val, nil, 0);
count := count - 1;
end; {else}
until count = 0;
end; {PushWords}
begin {GenLdc}
case op^.optype of
cgByte: begin
if op^.q > 127 then
op^.q := op^.q | $FF00;
GenNative(m_lda_imm, immediate, op^.q, nil, 0);
end;
cgUByte, cgWord, cgUWord:
GenNative(m_lda_imm, immediate, op^.q, nil, 0);
cgReal, cgDouble, cgComp, cgExtended: begin
switch.theReal := op^.rval;
PushWords(switch, 5);
end;
cgLong, cgULong:
if (constant & gLong.preference) <> 0 then begin
gLong.where := constant;
gLong.lval := op^.lval;
end
else if (A_X & gLong.preference) <> 0 then begin
gLong.where := A_X;
GenNative(m_lda_imm, immediate, long(op^.lval).lsw, nil, 0);
GenNative(m_ldx_imm, immediate, long(op^.lval).msw, nil, 0);
end
else begin
gLong.where := onStack;
GenNative(m_pea, immediate, long(op^.lval).msw, nil, 0);
GenNative(m_pea, immediate, long(op^.lval).lsw, nil, 0);
end;
cgQuad,cgUQuad: begin
if gQuad.preference = onStack then begin
switch.theLonglong := op^.qval;
PushWords(switch, 4);
end {if}
else begin
GenNative(m_lda_imm, immediate, long(op^.qval.hi).msw, nil, 0);
StoreWordOfQuad(6);
GenNative(m_lda_imm, immediate, long(op^.qval.hi).lsw, nil, 0);
StoreWordOfQuad(4);
GenNative(m_lda_imm, immediate, long(op^.qval.lo).msw, nil, 0);
StoreWordOfQuad(2);
GenNative(m_lda_imm, immediate, long(op^.qval.lo).lsw, nil, 0);
StoreWordOfQuad(0);
end; {else}
gQuad.where := gQuad.preference;
end;
otherwise:
Error(cge1);
end; {case}
end; {GenLdc}
procedure GenLdo (op: icptr);
{ Generate code for a pc_ldo }
var
lab1: integer; {branch point}
begin {GenLdo}
case op^.optype of
cgWord, cgUWord:
if smallMemoryModel then
GenNative(m_lda_abs, absolute, op^.q, op^.lab, 0)
else
GenNative(m_lda_long, longAbs, op^.q, op^.lab, 0);
cgByte, cgUByte: begin
if smallMemoryModel then
GenNative(m_lda_abs, absolute, op^.q, op^.lab, 0)
else
GenNative(m_lda_long, longAbs, op^.q, op^.lab, 0);
GenNative(m_and_imm, immediate, 255, nil, 0);
if op^.optype = cgByte then begin
GenNative(m_bit_imm, immediate, $0080, nil, 0);
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
GenNative(m_cmp_imm, immediate, $0000, nil, 0);
end; {if}
end;
cgReal, cgDouble, cgComp, cgExtended: begin
GenNative(m_pea, immediate, op^.q, op^.lab, shift16);
GenNative(m_pea, immediate, op^.q, op^.lab, 0);
if op^.optype = cgReal then
GenCall(21)
else if op^.optype = cgDouble then
GenCall(22)
else if op^.optype = cgComp then
GenCall(70)
else {if op^.optype = cgExtended then}
GenCall(71);
end;
cgLong, cgULong: begin
if (A_X & gLong.preference) <> 0 then
gLong.where := A_X
else
gLong.where := onStack;
if smallMemoryModel then begin
GenNative(m_ldx_abs, absolute, op^.q+2, op^.lab, 0);
GenNative(m_lda_abs, absolute, op^.q, op^.lab, 0);
if gLong.where = onStack then begin
GenImplied(m_phx);
GenImplied(m_pha);
end; {if}
end {if}
else begin
GenNative(m_lda_long, longabsolute, op^.q+2, op^.lab, 0);
if gLong.where = onStack then
GenImplied(m_pha)
else
GenImplied(m_tax);
GenNative(m_lda_long, longabsolute, op^.q, op^.lab, 0);
if gLong.where = onStack then
GenImplied(m_pha);
end; {else}
end; {case cgLong,cgULong}
cgQuad, cgUQuad: begin
if smallMemoryModel then begin
GenNative(m_lda_abs, absolute, op^.q+6, op^.lab, 0);
StoreWordOfQuad(6);
GenNative(m_lda_abs, absolute, op^.q+4, op^.lab, 0);
StoreWordOfQuad(4);
GenNative(m_lda_abs, absolute, op^.q+2, op^.lab, 0);
StoreWordOfQuad(2);
GenNative(m_lda_abs, absolute, op^.q, op^.lab, 0);
StoreWordOfQuad(0);
end {if}
else begin
GenNative(m_lda_long, longabsolute, op^.q+6, op^.lab, 0);
StoreWordOfQuad(6);
GenNative(m_lda_long, longabsolute, op^.q+4, op^.lab, 0);
StoreWordOfQuad(4);
GenNative(m_lda_long, longabsolute, op^.q+2, op^.lab, 0);
StoreWordOfQuad(2);
GenNative(m_lda_long, longabsolute, op^.q, op^.lab, 0);
StoreWordOfQuad(0);
end; {else}
gQuad.where := gQuad.preference;
end; {case cgQuad,cgUQuad}
otherwise:
Error(cge1);
end; {case}
end; {GenLdo}
procedure GenLnm (op: icptr);
{ Generate code for a pc_lnm }
begin {GenLnm}
if op^.left <> nil then
GenTree(op^.left);
if traceBack then begin
GenNative(m_pea, immediate, op^.r, nil, 0);
GenCall(6);
end; {if}
if debugFlag then begin
if op^.lab <> nil then
GenDebugSourceFile(op^.lab);
GenNative(m_cop, immediate, op^.q, nil, 0);
GenNative(d_wrd, special, op^.r, nil, 0);
end; {if}
end; {GenLnm}
procedure GenLod (op: icptr);
{ Generate code for a pc_lod }
var
disp: integer; {load location}
lab1: integer; {branch point}
optype: baseTypeEnum; {op^.optype}
begin {GenLod}
disp := LabelToDisp(op^.r) + op^.q;
optype := op^.optype;
case optype of
cgReal, cgDouble, cgComp, cgExtended: begin
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, disp, nil, 0);
GenImplied(m_pha);
if optype = cgReal then
GenCall(21)
else if optype = cgDouble then
GenCall(22)
else if optype = cgComp then
GenCall(70)
else {if optype = cgExtended then}
GenCall(71);
end;
cgQuad, cgUQuad: begin
if disp >= 250 then begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
GenNative(m_lda_dirx, direct, 6, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_dirx, direct, 4, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_dirx, direct, 2, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_dirx, direct, 0, nil, 0);
GenImplied(m_pha);
gQuad.where := onStack;
end {if}
else begin
if gQuad.preference = onStack then begin
GenNative(m_pei_dir, direct, disp+6, nil, 0);
GenNative(m_pei_dir, direct, disp+4, nil, 0);
GenNative(m_pei_dir, direct, disp+2, nil, 0);
GenNative(m_pei_dir, direct, disp, nil, 0);
end {if}
else begin
GenNative(m_lda_dir, direct, disp+6, nil, 0);
StoreWordOfQuad(6);
GenNative(m_lda_dir, direct, disp+4, nil, 0);
StoreWordOfQuad(4);
GenNative(m_lda_dir, direct, disp+2, nil, 0);
StoreWordOfQuad(2);
GenNative(m_lda_dir, direct, disp, nil, 0);
StoreWordOfQuad(0);
end; {else}
gQuad.where := gQuad.preference;
end; {else}
end;
cgLong, cgULong: begin
if ((inPointer & gLong.preference) <> 0) and (disp < 254) then
begin
gLong.where := inPointer;
gLong.fixedDisp := true;
gLong.disp := disp;
end {if}
else if ((A_X & gLong.preference) <> 0) and (disp < 254) then begin
gLong.where := A_X;
GenNative(m_ldx_dir, direct, disp+2, nil, 0);
GenNative(m_lda_dir, direct, disp, nil, 0);
end {else if}
else begin
gLong.where := onStack;
if disp >= 254 then begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
GenNative(m_lda_dirx, direct, 2, nil, 0);
GenImplied(m_pha);
GenNative(m_lda_dirx, direct, 0, nil, 0);
GenImplied(m_pha);
end {if}
else begin
GenNative(m_pei_dir, direct, disp+2, nil, 0);
GenNative(m_pei_dir, direct, disp, nil, 0);
end; {else}
end; {else}
end;
cgByte, cgUByte, cgWord, cgUWord: begin
if disp >= 256 then begin
GenNative(m_ldx_imm, immediate, disp, nil, 0);
GenNative(m_lda_dirx, direct, 0, nil, 0);
end
else
GenNative(m_lda_dir, direct, disp, nil, 0);
if optype in [cgByte,cgUByte] then begin
GenNative(m_and_imm, immediate, $00FF, nil, 0);
if optype = cgByte then begin
GenNative(m_bit_imm, immediate, $0080, nil, 0);
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
GenNative(m_cmp_imm, immediate, $0000, nil, 0);
end; {if}
end;
end;
otherwise:
Error(cge1);
end; {case}
end; {GenLod}
procedure GenLorLnd (op: icptr);
{ Generate code for a pc_lor or pc_lnd }
var
lab1,lab2,lab3,lab4: integer; {labels}
begin {GenLorLnd}
lab1 := GenLabel;
lab3 := GenLabel;
lab4 := GenLabel;
gLong.preference := A_X;
GenTree(op^.left);
if glong.where = A_X then
GenImpliedForFlags(m_tay)
else begin
GenImplied(m_plx);
GenImplied(m_pla);
end; {else}
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_txa);
if op^.opcode = pc_lor then begin
lab2 := GenLabel;
GenNative(m_beq, relative, lab2, nil, 0);
GenLabUsedOnce(lab1);
GenNative(m_brl, longrelative, lab3, nil, 0);
GenLab(lab2);
end {if}
else begin
GenNative(m_bne, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lab4, nil, 0);
GenLab(lab1);
end; {if}
gLong.preference := A_X;
GenTree(op^.right);
if glong.where = A_X then
GenImpliedForFlags(m_tay)
else begin
GenImplied(m_plx);
GenImplied(m_pla);
end; {else}
GenNative(m_bne, relative, lab3, nil, 0);
GenImplied(m_txa);
GenNative(m_beq, relative, lab4, nil, 0);
GenLab(lab3);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab4);
end; {GenLorLnd}
procedure GenMov (op: icptr; duplicate: boolean);
{ Generate code for a pc_mov }
{ }
{ parameters: }
{ op - pc_mov instruction }
{ duplicate - should the dest address be left on the }
{ stack? }
var
banks: integer; {number of banks to move}
procedure Load (opcode: integer; op: icptr);
{ generate a load immediate based on instruction type }
{ }
{ parameters: }
{ opcode - native code load operation }
{ op - node to load }
var
i: integer;
begin {Load}
if op^.opcode = pc_lao then
GenNative(opcode, immediate, op^.q, op^.lab, 0)
else if op^.opcode = pc_lca then begin
GenNative(opcode, immediate, stringsize, nil, StringReference);
if maxstring-stringsize >= op^.q then begin
for i := 1 to op^.q do
stringspace^[i+stringsize] := op^.str^.str[i];
stringsize := stringsize + op^.q;
end {if}
else
Error(cge3);
end {else if}
else {if op^.opcode = pc_lda then} begin
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, LabelToDisp(op^.r) + op^.q, nil, 0);
if opcode = m_ldy_imm then
GenImplied(m_tay)
else
GenImplied(m_tax);
end; {else}
end; {Load}
begin {GenMov}
banks := op^.r;
{determine if the destination address must be left on the stack}
if (banks = 0)
and (op^.q <> 0)
and (not duplicate)
and ((op^.left^.opcode in [pc_lca,pc_lda])
or ((op^.left^.opcode = pc_lao) and smallMemoryModel))
and ((op^.right^.opcode in [pc_lca,pc_lda])
or ((op^.right^.opcode = pc_lao) and smallMemoryModel)) then begin
{take advantage of any available short cuts}
Load(m_ldy_imm, op^.left);
Load(m_ldx_imm, op^.right);
GenNative(m_lda_imm, immediate, op^.q-1, nil, 0);
GenImplied(m_phb);
GenImplied(m_mvn);
with op^.left^ do
if opcode = pc_lao then
GenNative(d_bmov, immediate, q, lab, shift16)
else if opcode = pc_lca then
GenNative(d_bmov, immediate, 0, nil, stringReference+shift16)
else {if opcode = pc_lda then}
GenNative(d_bmov, immediate, 0, nil, 0);
with op^.right^ do
if opcode = pc_lao then
GenNative(d_bmov, immediate, q, lab, shift16)
else if opcode = pc_lca then
GenNative(d_bmov, immediate, 0, nil, stringReference+shift16)
else {if opcode = pc_lda then}
GenNative(d_bmov, immediate, 0, nil, 0);
GenImplied(m_plb);
end {if}
else begin
{no short cuts are available - do it the hard way}
gLong.preference := onStack;
GenTree(op^.left);
gLong.preference := onStack;
GenTree(op^.right);
if banks <> 0 then
GenNative(m_pea, immediate, banks, nil, 0);
GenNative(m_pea, immediate, op^.q, nil, 0);
if banks = 0 then begin
if duplicate then
GenCall(55)
else
GenCall(54);
end {if}
else
if duplicate then
GenCall(63)
else
GenCall(62);
end; {else}
end; {GenMov}
procedure GenMpi (op: icptr);
{ Generate code for a pc_mpi or pc_umi }
var
nd: icptr;
val: integer;
begin {GenMpi}
if ((op^.left^.opcode = pc_ldc) or (op^.right^.opcode = pc_ldc))
and ((op^.opcode = pc_umi) or (not rangeCheck)) then begin
if op^.left^.opcode = pc_ldc then begin
val := op^.left^.q;
nd := op^.right;
end {if}
else begin
val := op^.right^.q;
nd := op^.left;
end; {else}
if nd^.opcode = pc_ldc then
GenNative(m_lda_imm, immediate, ord(ord4(val) * ord4(nd^.q)), nil, 0)
else begin
GenTree(nd);
case val of
0: GenNative(m_lda_imm, immediate, 0, nil, 0);
1,2,4,8,16,32,64,128:
while not odd(val) do begin
GenImplied(m_asl_a);
val := val >> 1;
end; {while}
256,512,1024,2048,4096,8192,16384: begin
GenNative(m_and_imm, immediate, $00FF, nil, 0);
GenImplied(m_xba);
val := val >> 8;
while not odd(val) do begin
GenImplied(m_asl_a);
val := val >> 1;
end; {while}
end;
3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96: begin
if odd(val) then {prevent lda+pha -> pei optimization}
GenLab(GenLabel);
while not odd(val) do begin
GenImplied(m_asl_a);
val := val >> 1;
end; {while}
GenImplied(m_pha);
val := val - 1;
while not odd(val) do begin
GenImplied(m_asl_a);
val := val >> 1;
end; {while}
GenImplied(m_clc);
GenNative(m_adc_s, direct, 1, nil, 0);
GenImplied(m_plx);
end;
-1,-2,-4,-8,-16,-32,-64,-128: begin
GenNative(m_eor_imm, immediate, -1, nil, 0);
GenImplied(m_ina);
val := -val;
while not odd(val) do begin
GenImplied(m_asl_a);
val := val >> 1;
end; {while}
end;
-256: begin
GenNative(m_eor_imm, immediate, -1, nil, 0);
GenImplied(m_ina);
GenNative(m_and_imm, immediate, $00FF, nil, 0);
GenImplied(m_xba);
end;
otherwise: begin
if val = $8000 then begin
GenImplied(m_lsr_a);
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenImplied(m_ror_a);
end {if}
else begin
GenNative(m_ldx_imm, immediate, val, nil, 0);
if op^.opcode = pc_mpi then
GenCall(28)
else {pc_umi}
GenCall(94);
end; {else}
end;
end; {case}
end; {else}
end {if}
else begin
if not Complex(op^.left) then
if Complex(op^.right) then begin
nd := op^.left;
op^.left := op^.right;
op^.right := nd;
end; {if}
GenTree(op^.left);
if Complex(op^.right) then begin
GenImplied(m_pha);
GenTree(op^.right);
GenImplied(m_plx);
end {if}
else
LoadX(op^.right);
if op^.opcode = pc_mpi then begin
GenCall(28);
if rangeCheck then
GenCall(25);
end {if}
else {pc_umi}
GenCall(94);
end; {else}
end; {GenMpi}
procedure GenNam (op: icptr);
{ Generate code for a pc_nam }
var
i: integer; {loop/index variable}
begin {GenNam}
{generate a call to install the name in the traceback facility}
if traceBack then begin
GenNative(m_pea, immediate, stringSize, nil, stringReference+shift16);
GenNative(m_pea, immediate, stringSize, nil, stringReference);
GenCall(5);
namePushed := true;
end; {if}
{send the name to the profiler}
if profileFlag then begin
GenNative(m_cop, immediate, 3, nil, 0);
GenNative(d_add, genaddress, stringSize, nil, stringReference);
GenNative(d_add, genaddress, stringSize, nil, stringReference+shift16);
end; {if}
{place the name in the string buffer}
if maxString-stringSize >= op^.q+1 then begin
stringSpace^[stringSize+1] := chr(op^.q);
for i := 1 to op^.q do
stringSpace^[i+stringSize+1] := op^.str^.str[i];
stringSize := stringSize + op^.q + 1;
end {if}
else
Error(cge3);
{send the file name to the debugger}
if debugFlag then
GenDebugSourceFile(@debugSourceFileGS);
end; {GenNam}
procedure GenNat (op: icptr);
{ Generate code for a pc_nat }
var
flags: integer; {work var for flags}
mode: addressingmode; {work var for addressing mode}
pval: longint; {temp pointer}
val: longint; {constant operand}
opcode: integer; {opcode}
begin {GenNat}
val := op^.opnd;
flags := op^.q;
pval := op^.llab;
mode := addressingMode(op^.r);
opcode := op^.s;
if opcode < 256 then
opcode := opcode | asmFlag;
if op^.slab <> 0 then begin
val := val+LabelToDisp(op^.slab);
if mode = direct then
if (val > 255) or (val < 0) then
Error(cge4);
end; {if}
if mode in [relative,longrelative] then
GenNative(opcode, mode, op^.llab, op^.lab, op^.q)
else if (mode = longabsolute) and (op^.llab <> 0) then
GenNative(opcode, mode, long(val).lsw, pointer(pval),
flags | localLab)
else if (mode = longabsolute) and (op^.llab = 0)
and (op^.lab = nil) then
GenNative(opcode, mode, 0, pointer(val), flags | constantOpnd)
else begin
if (mode = absolute) and (op^.llab = 0) then
flags := flags | constantOpnd;
if op^.llab <> 0 then
GenNative(opcode, mode, long(val).lsw, pointer(pval),
flags | localLab)
else
GenNative(opcode, mode, long(val).lsw, op^.lab, flags);
end; {else}
end; {GenNat}
procedure GenNgr (op: icptr);
{ Generate code for a pc_ngr }
begin {GenNgr}
GenTree(op^.left);
GenNative(m_lda_s, direct, 9, nil, 0);
GenNative(m_eor_imm, immediate, -32767-1, nil, 0);
GenNative(m_sta_s, direct, 9, nil, 0);
end; {GenNgr}
procedure GenPop (op: icptr);
{ Generate code for a pc_pop }
var
isIncLoad: boolean; {is the operand one of the inc/dec & load commands?}
begin {GenPop}
glong.preference := A_X; {generate the operand}
gQuad.preference := nowhere;
isIncLoad := op^.left^.opcode in
[pc_lil,pc_lli,pc_ldl,pc_lld,pc_gil,pc_gli,pc_gdl,pc_gld,
pc_iil,pc_ili,pc_idl,pc_ild];
if isIncLoad then
skipLoad := true;
if op^.left^.opcode = pc_mov then
GenMov(op^.left, false)
else if op^.left^.opcode in [pc_cop,pc_cpo,pc_cpi,pc_cbf] then begin
if op^.left^.opcode = pc_cop then
op^.left^.opcode := pc_str
else if op^.left^.opcode = pc_cpo then
op^.left^.opcode := pc_sro
else if op^.left^.opcode = pc_cpi then
op^.left^.opcode := pc_sto
else {if op^.left^.opcode = pc_cbf then}
op^.left^.opcode := pc_sbf;
GenTree(op^.left);
end {else if}
else begin
GenTree(op^.left);
if isIncLoad then
skipLoad := false;
case op^.optype of {do the pop}
otherwise: Error(cge1);
cgByte, cgUByte, cgWord, cgUWord, cgVoid: ;
cgLong, cgULong:
if not isIncLoad then
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_pla);
end; {if}
{else do nothing}
cgQuad, cgUQuad: begin
if gQuad.where = onStack then begin
GenImplied(m_tsc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, 8, nil, 0);
GenImplied(m_tcs);
end; {if}
end;
cgReal, cgDouble, cgComp, cgExtended: begin
GenImplied(m_tsc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, 10, nil, 0);
GenImplied(m_tcs);
end;
end; {case}
end; {else}
end; {GenPop}
procedure GenPsh (op: icptr);
{ Generate code for a pc_psh }
begin {GenPsh}
gLong.preference := onStack;
GenTree(op^.left);
GenTree(op^.right);
GenImplied(m_pha);
GenCall(77);
end; {GenPsh}
procedure GenRbo (op: icptr);
{ Generate code for a pc_rbo }
begin {GenRbo}
GenTree(op^.left);
GenImplied(m_xba);
end; {GenRbo}
procedure GenRealBinOp (op: icptr);
{ Generate code for a pc_adr, pc_dvr, pc_mpr or pc_sbr }
var
nd: icptr; {temp pointer}
snum: integer; {library subroutine numbers}
ss,sd,sc,se: integer; {sane call numbers}
begin {GenRealBinOp}
case op^.opcode of
pc_adr: begin
snum := 56;
ss := $0200;
sd := $0100;
sc := $0500;
se := $0000;
end;
pc_dvr: begin
snum := 57;
ss := $0206;
sd := $0106;
sc := $0506;
se := $0006;
end;
pc_mpr: begin
snum := 58;
ss := $0204;
sd := $0104;
sc := $0504;
se := $0004;
end;
pc_sbr: begin
snum := 59;
ss := $0202;
sd := $0102;
sc := $0502;
se := $0002;
end;
end; {case}
if op^.opcode in [pc_mpr,pc_adr] then
if op^.left^.opcode in [pc_lod,pc_ldo] then begin
nd := op^.left;
op^.left := op^.right;
op^.right := nd;
end; {if}
GenTree(op^.left);
if (op^.right^.opcode in [pc_lod,pc_ldo]) and (floatCard = 0) then
with op^.right^ do begin
if opcode = pc_lod then begin
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_tdc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, LabelToDisp(r) + q, nil, 0);
GenImplied(m_pha);
end {if}
else begin
GenNative(m_pea, immediate, q, lab, shift16);
GenNative(m_pea, immediate, q, lab, 0);
end; {else}
GenNative(m_pea, immediate, 0, nil, 0);
GenImplied(m_tsc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, 7, nil, 0);
GenImplied(m_pha);
if optype = cgReal then
sd := ss
else if optype = cgExtended then
sd := se
else if optype = cgComp then
sd := sc;
GenNative(m_pea, immediate, sd, nil, 0);
GenNative(m_ldx_imm, immediate, $090A, nil, 0);
GenNative(m_jsl, longAbs, 0, nil, toolCall);
end {with}
else begin
GenTree(op^.right);
GenCall(snum);
end; {else}
end; {GenRealBinOp}
procedure GenRetRev (op: icptr);
{ Generate code for a pc_ret or pc_rev }
var
size: integer; {localSize + parameterSize}
lab1: integer; {label}
valuePushed: boolean; {return value pushed on stack?}
evaluateAtEnd: boolean; {evaluate return val right before rtl?}
begin {GenRetRev}
size := localSize + parameterSize;
evaluateAtEnd := false;
{calculate return value, if necessary}
if op^.opcode = pc_rev then begin
if op^.left^.opcode in [pc_ldc,pc_lca,pc_lao,pc_lad] then begin
evaluateAtEnd := true;
valuePushed := false;
end {if}
else begin
valuePushed := namePushed or debugFlag or profileFlag
or ((parameterSize <> 0) and (size > 253));
if valuePushed then
gLong.preference := onStack
else
gLong.preference := A_X;
GenTree(op^.left);
if op^.optype in [cgByte,cgUByte,cgWord,cgUWord] then begin
if valuePushed then
GenImplied(m_pha)
else
GenImplied(m_tay);
end {if}
else {if op^.optype in [cgLong,cgULong] then} begin
valuePushed := gLong.where = onStack;
if not valuePushed then
GenImplied(m_tay);
end; {else}
end; {else}
end;
{pop the name record}
if namePushed then
GenCall(2);
{generate an exit code for the debugger/profiler's benefit}
if debugFlag or profileFlag then
GenNative(m_cop, immediate, 4, nil, 0);
{if anything needs to be removed from the stack, move the return address}
if parameterSize <> 0 then begin
if localSize > 253 then begin
GenNative(m_ldx_imm, immediate, localSize+1, nil, 0);
GenNative(m_lda_dirx, direct, 0, nil, 0);
GenNative(m_ldy_dirx, direct, 1, nil, 0);
GenNative(m_ldx_imm, immediate,
localSize+parameterSize+1, nil, 0);
GenNative(m_sta_dirx, direct, 0, nil, 0);
GenNative(m_sty_dirx, direct, 1, nil, 0);
end {if}
else begin
GenNative(m_lda_dir, direct, localSize+2, nil, 0);
if localSize+parameterSize > 253 then begin
GenNative(m_ldx_imm, immediate,
localSize+parameterSize+1, nil, 0);
GenNative(m_sta_dirx, direct, 1, nil, 0);
GenNative(m_lda_dir, direct, localSize+1, nil, 0);
GenNative(m_sta_dirx, direct, 0, nil, 0);
end {if}
else begin
GenNative(m_sta_dir, direct,
localSize+parameterSize+2, nil, 0);
GenNative(m_lda_dir, direct, localSize+1, nil, 0);
GenNative(m_sta_dir, direct,
localSize+parameterSize+1, nil, 0);
end; {else}
end; {else}
end; {if}
if op^.opcode = pc_rev then begin
if valuePushed then begin
if size = 2 then
GenImplied(m_pla)
else
GenImplied(m_ply);
if op^.optype in [cgLong,cgULong] then
GenImplied(m_plx);
end {if}
else if not evaluateAtEnd then
if size = 2 then
GenImplied(m_tya);
end {if}
else
case op^.optype of {load the value to return}
cgVoid: ;
cgByte,cgUByte: begin
GenNative(m_lda_dir, direct, funLoc, nil, 0);
GenNative(m_and_imm, immediate, $00FF, nil, 0);
if op^.optype = cgByte then begin
GenNative(m_bit_imm, immediate, $0080, nil, 0);
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_ora_imm, immediate, $FF00, nil, 0);
GenLab(lab1);
end; {if}
if size <> 2 then
GenImplied(m_tay);
end;
cgWord,cgUWord:
if size = 2 then
GenNative(m_lda_dir, direct, funLoc, nil, 0)
else
GenNative(m_ldy_dir, direct, funLoc, nil, 0);
cgReal:
GenCall(3);
cgDouble:
GenCall(4);
cgComp:
GenCall(64);
cgExtended:
GenCall(65);
cgLong,cgULong: begin
GenNative(m_ldx_dir, direct, funLoc+2, nil, 0);
GenNative(m_ldy_dir, direct, funLoc, nil, 0);
end;
cgQuad,cgUQuad: ; {return value was already written}
otherwise:
Error(cge1);
end; {case}
{restore data bank reg}
if dataBank then begin
GenNative(m_pei_dir, direct, bankLoc, nil, 0);
GenImplied(m_plb);
GenImplied(m_plb);
end; {if}
{get rid of the stack frame space}
if size <> 0 then
GenImplied(m_pld);
if size = 2 then
GenImplied(m_ply)
else if size <> 0 then begin
GenImplied(m_tsc);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, size, nil, 0);
GenImplied(m_tcs);
end; {if}
{put return value in correct place}
case op^.optype of
cgByte,cgUByte,cgWord,cgUWord: begin
if evaluateAtEnd then
GenTree(op^.left)
else if size <> 2 then
GenImplied(m_tya);
if toolParms then {save value on stack for tools}
GenNative(m_sta_s, direct, returnSize+1, nil, 0);
end;
cgLong,cgULong,cgReal,cgDouble,cgComp,cgExtended: begin
if evaluateAtEnd then begin
gLong.preference := A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {if}
end {if}
else if size <> 2 then
GenImplied(m_tya);
if toolParms then begin {save value on stack for tools}
GenNative(m_sta_s, direct, returnSize+1, nil, 0);
GenImplied(m_txa);
GenNative(m_sta_s, direct, returnSize+3, nil, 0);
end; {if}
end;
cgVoid,cgQuad,cgUQuad: ;
otherwise:
Error(cge1);
end; {case}
{return to the caller}
GenImplied(m_rtl);
end; {GenRetRev}
procedure GenSbfCbf (op: icptr);
{ Generate code for a pc_sbf or pc_cbf }
begin {GenSbfCbf}
gLong.preference := onStack;
GenTree(op^.left);
GenNative(m_pea, immediate, op^.r, nil, 0);
GenNative(m_pea, immediate, op^.q, nil, 0);
if op^.optype in [cgLong,cgULong] then begin
gLong.preference := onStack;
GenTree(op^.right);
end {if}
else begin
GenNative(m_pea, immediate, 0, nil, 0);
GenTree(op^.right);
GenImplied(m_pha);
end; {else}
if op^.opcode = pc_sbf then
GenCall(74)
else begin
GenCall(75);
if not (op^.optype in [cgLong,cgULong]) then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {if}
end; {else}
end; {GenSbfCbf}
procedure GenSbi (op: icptr);
{ Generate code for a pc_sbi }
begin {GenSbi}
if Complex(op^.right) then begin
GenTree(op^.right);
if Complex(op^.left) then begin
GenImplied(m_pha);
GenTree(op^.left);
GenImplied(m_sec);
GenNative(m_sbc_s, direct, 1, nil, 0);
GenImplied(m_plx);
end {if}
else begin
GenNative(m_eor_imm, immediate, $FFFF, nil, 0);
GenImplied(m_sec);
OperA(m_adc_imm, op^.left);
end; {else}
end {if}
else begin
GenTree(op^.left);
GenImplied(m_sec);
OperA(m_sbc_imm, op^.right);
end; {else}
end; {GenSbi}
procedure GenStk (op: icptr);
{ Generate code for a pc_stk }
begin {GenStk}
if op^.left^.opcode = pc_psh then begin
if (op^.left^.right^.opcode = pc_ldc) and
(op^.left^.right^.optype in [cgWord,cgUWord]) then
argsSize := argsSize + op^.left^.right^.q
else
Error(cge1);
end {if}
else
case op^.optype of
cgByte,cgUByte,cgWord,cgUWord:
argsSize := argsSize + cgWordSize;
cgReal,cgDouble,cgComp,cgExtended:
argsSize := argsSize + cgExtendedSize;
cgLong,cgULong:
argsSize := argsSize + cgLongSize;
cgQuad,cgUQuad:
argsSize := argsSize + cgQuadSize;
otherwise: Error(cge1);
end; {case}
glong.preference := onStack; {generate the operand}
gQuad.preference := onStack;
GenTree(op^.left);
if op^.optype in {do the stk}
[cgByte, cgUByte, cgWord, cgUWord] then
GenImplied(m_pha);
end; {GenStk}
procedure GenShlShrUsr (op: icptr);
{ Generate code for a pc_shl, pc_shr or pc_usr }
var
i,op1,op2,op3,num: integer; {temp variables}
begin {GenShlShrUsr}
{get the standard native operations}
if op^.opcode = pc_shl then begin
op1 := m_asl_a;
op2 := m_lsr_a;
op3 := m_ror_a;
end {if}
else begin
op1 := m_lsr_a;
op2 := m_asl_a;
op3 := m_rol_a;
end; {else}
{take short cuts if they are legal}
if (op^.right^.opcode = pc_ldc) and (op^.opcode <> pc_shr) then begin
num := op^.right^.q;
if (num > 16) or (num < -16) then
GenNative(m_lda_imm, immediate, 0, nil, 0)
else if num > 0 then begin
GenTree(op^.left);
if num in [13..15] then begin
for i := 1 to 17-num do
GenImplied(op3);
if op^.opcode = pc_shl then
i := $ffff << num
else
i := $7fff >> (num-1);
GenNative(m_and_imm, immediate, i, nil, 0);
end {if}
else begin
if num >= 8 then begin
GenImplied(m_xba);
if op1 = m_lsr_a then
i := $00FF
else
i := $FF00;
GenNative(m_and_imm, immediate, i, nil, 0);
num := num-8;
end; {if}
for i := 1 to num do
GenImplied(op1);
end; {else}
end {else if}
else if num < 0 then begin
GenTree(op^.left);
if num <= -8 then begin
GenImplied(m_xba);
if op2 = m_lsr_a then
i := $00FF
else
i := $FF00;
GenNative(m_and_imm, immediate, i, nil, 0);
num := num+8;
end; {if}
for i := 1 to -num do
GenImplied(op2);
end {else if}
else
GenTree(op^.left);
end {if}
else begin
GenTree(op^.left);
if Complex(op^.right) then begin
GenImplied(m_pha);
GenTree(op^.right);
GenImplied(m_tax);
GenImplied(m_pla);
end {if}
else
LoadX(op^.right);
if op^.opcode = pc_shl then
GenCall(23)
else if op^.opcode = pc_shr then
GenCall(24)
else {if op^.opcode = pc_usr then}
GenCall(41);
end; {else}
end; {GenShlShrUsr}
procedure GenTl1 (op: icptr);
{ Generate code for a pc_tl1 }
var
lLong: longType; {used to reserve gLong}
begin {GenTl1}
if op^.r in [2,4] then begin
GenImplied(m_pha);
if op^.r = 4 then
GenImplied(m_pha);
end; {if}
lLong := gLong;
GenTree(op^.left);
gLong := lLong;
GenNative(m_ldx_imm, immediate, op^.q, nil, 0);
GenNative(m_jsl, longAbs, 0, pointer(op^.lval), toolCall);
if smallMemoryModel then
GenNative(m_sta_abs, absolute, 0, @'~TOOLERROR', 0)
else
GenNative(m_sta_long, longAbs, 0, @'~TOOLERROR', 0);
if op^.r in [2,4] then begin
if op^.r = 2 then
GenImplied(m_pla)
else
gLong.where := onStack;
end; {if}
end; {GenTl1}
procedure GenTri (op: icptr);
{ Generate code for a pc_tri }
var
lab1,lab2,lab3: integer; {label for branches}
begin {GenTri}
lab1 := GenLabel;
lab2 := GenLabel;
lab3 := GenLabel;
GenTree(op^.left);
if NeedsCondition(op^.left^.opcode) then
GenImpliedForFlags(m_tax);
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lab2, nil, 0);
GenLab(lab1);
gLong.preference := onStack;
GenTree(op^.right^.right);
GenNative(m_brl, longrelative, lab3, nil, 0);
GenLab(lab2);
gLong.preference := onStack;
GenTree(op^.right^.left);
GenLab(lab3);
gLong.where := onStack;
end; {GenTri}
procedure GenXjp (op: icptr);
{ Generate code for a pc_xjp }
var
lab1: integer;
q: integer;
begin {GenXjp}
q := op^.q;
GenTree(op^.left);
GenNative(m_cmp_imm, immediate, q, nil, 0);
lab1 := GenLabel;
GenNative(m_bcc, relative, lab1, nil, 0);
GenNative(m_lda_imm, immediate, q, nil, 0);
GenLab(lab1);
GenImplied(m_asl_a);
GenImplied(m_tax);
lab1 := GenLabel;
GenNative(m_jmp_indX, absolute, lab1, nil, 0);
GenLab(lab1);
end; {GenXjp}
procedure DirEnp;
{ Generate code for a dc_enp }
begin {DirEnp}
GenImplied(d_end);
EndSeg;
InitLabels;
end; {DirEnp}
procedure DirStr (op: icptr);
{ Generate code for a dc_str }
begin {DirStr}
skipLoad := false;
InitNative;
Header(op^.lab, op^.r, op^.q);
end; {DirStr}
procedure DirSym (op: icptr);
{ Generate code for a dc_sym }
begin {DirSym}
if debugFlag then
GenNative(d_sym, special, op^.q, pointer(op^.lab), 0);
end; {DirSym}
begin {GenTree}
{write('GEN: '); WriteCode(op); {debug}
Spin;
case op^.opcode of
dc_cns: GenNative(d_cns, gnrConstant, op^.q, pointer(op), 0);
dc_dst: GenNative(d_lab, gnrSpace, op^.q, nil, 0);
dc_enp: DirEnp;
dc_lab: GenLab(op^.q);
dc_loc,dc_prm: ;
dc_glb: GenNative(d_lab, gnrLabel, op^.r, op^.lab, isPrivate*op^.q);
dc_pin: GenNative(d_pin, special, 0, nil, 0);
dc_str: DirStr(op);
dc_sym: DirSym(op);
pc_add: GenNative(d_add, genaddress, op^.q, nil, 0);
pc_adi: GenAdi(op);
pc_adl,pc_sbl: GenAdlSbl(op, nil);
pc_adq,pc_sbq: GenAdqSbq(op);
pc_adr,pc_dvr,pc_mpr,pc_sbr: GenRealBinOp(op);
pc_and,pc_bnd,pc_bor,pc_bxr,pc_ior: GenLogic(op);
pc_blr,pc_blx,pc_bal,pc_dvl,pc_mdl,pc_mpl,pc_sll,pc_slr,pc_udl,pc_ulm,
pc_uml,pc_vsr: GenBinLong(op);
pc_bqr,pc_bqx,pc_baq,pc_mpq,pc_umq,pc_dvq,pc_udq,pc_mdq,pc_uqm,pc_slq,
pc_sqr,pc_wsr: GenBinQuad(op);
pc_bnl,pc_ngl: GenUnaryLong(op);
pc_bnq,pc_ngq: GenUnaryQuad(op);
pc_bno: GenBno(op);
pc_bnt,pc_ngi,pc_not: GenBntNgiNot(op);
pc_ckp: GenCkp(op);
pc_cnv: GenCnv(op);
pc_cui: GenCui(op);
pc_cup: GenCup(op);
pc_dec,pc_inc: GenIncDec(op, nil);
pc_dvi,pc_mod,pc_udi,pc_uim: GenDviMod(op);
pc_ent: GenEnt(op);
pc_equ,pc_neq: GenEquNeq(op, op^.opcode, 0);
pc_fix: GenFix(op);
pc_fjp,pc_tjp: GenFjpTjp(op);
pc_geq,pc_grt,pc_leq,pc_les: GenCmp(op, op^.opcode, 0);
pc_gil,pc_gli,pc_gdl,pc_gld: GenGilGliGdlGld(op);
pc_iil,pc_ili,pc_idl,pc_ild: GenIilIliIdlIld(op);
pc_ind: GenInd(op);
pc_ixa: GenIxa(op);
pc_lao,pc_lad: GenLaoLad(op);
pc_lbf,pc_lbu: GenLbfLbu(op);
pc_lca: GenLca(op);
pc_lda: GenLda(op);
pc_ldc: GenLdc(op);
pc_ldo: GenLdo(op);
pc_lil,pc_lli,pc_ldl,pc_lld: GenLilLliLdlLld(op);
pc_lnm: GenLnm(op);
pc_lod: GenLod(op);
pc_lor,pc_lnd: GenLorLnd(op);
pc_mov: GenMov(op, true);
pc_mpi,pc_umi: GenMpi(op);
pc_nam: GenNam(op);
pc_nat: GenNat(op);
pc_ngr: GenNgr(op);
pc_nop: ;
pc_pop: GenPop(op);
pc_psh: GenPsh(op);
pc_rbo: GenRbo(op);
pc_ret,pc_rev: GenRetRev(op);
pc_sbf,pc_cbf: GenSbfCbf(op);
pc_sbi: GenSbi(op);
pc_shl,pc_shr,pc_usr: GenShlShrUsr(op);
pc_stk: GenStk(op);
pc_sro,pc_cpo: GenSroCpo(op);
pc_sto,pc_cpi: GenStoCpi(op);
pc_str,pc_cop: GenStrCop(op);
pc_tl1: GenTl1(op);
pc_tri: GenTri(op);
pc_ujp: GenNative(m_brl, longrelative, op^.q, nil, 0);
pc_xjp: GenXjp(op);
otherwise: Error(cge1);
end; {case}
end; {GenTree}
{---------------------------------------------------------------}
procedure Gen {blk: blockPtr};
{ Generates native code for a list of blocks }
{ }
{ parameters: }
{ blk - first of the list of blocks }
const
locSize = 4; {variables <= this size allocated first}
var
bk: blockPtr; {used to trace block lists}
minSize: integer; {location for the next local label}
op: icptr; {used to trace code lists}
procedure DirLoc1 (op: icptr);
{ allocates stack frame locations for small dc_loc }
begin {DirLoc1}
if op^.q <= locSize then begin
if op^.r < maxLocalLabel then begin
localLabel[op^.r] := minSize;
minSize := minSize + op^.q;
end {if}
else
Error(cge2);
end; {if}
end; {DirLoc1}
procedure DirLoc2 (op: icptr);
{ allocates stack frame locations for large dc_loc }
begin {DirLoc2}
if op^.q > locSize then begin
if op^.r < maxLocalLabel then begin
localLabel[op^.r] := minSize;
minSize := minSize + op^.q;
end {if}
else
Error(cge2);
end; {if}
end; {DirLoc2}
procedure DirPrm (op: icptr);
{ allocates stack frame locations for parameters }
begin {DirPrm}
if op^.s < maxLocalLabel then
localLabel[op^.s] := localSize + returnSize + 1 + op^.r
else
Error(cge2);
end; {DirPrm}
procedure Scan (op: icptr);
{ scans the code stream for instructions that effect the }
{ size of the stack frame }
{ }
{ parameters: }
{ op - scan this opcode and its children }
var
opcode: pcodes; {op^.opcode}
size: integer; {function return value size}
begin {Scan}
if op^.left <> nil then
Scan(op^.left);
if op^.right <> nil then
Scan(op^.right);
opcode := op^.opcode;
if opcode = dc_loc then
localSize := localSize + op^.q
else if opcode = dc_prm then
parameterSize := parameterSize + op^.q
else if opcode = pc_ret then begin
case op^.optype of
otherwise: size := 0;
cgByte,cgUByte,cgWord,cgUWord: size := cgWordSize;
cgReal: size := cgRealSize;
cgDouble: size := cgDoubleSize;
cgComp: size := cgCompSize;
cgExtended: size := cgExtendedSize;
cgLong,cgULong: size := cgLongSize;
cgQuad,cgUQuad: begin
size := cgLongSize; {pointer}
isQuadFunction := true;
end;
end; {case}
funLoc := 1;
if dworkLoc <> 0 then
dworkLoc := dworkLoc + size;
minSize := minSize + size;
localSize := localSize + size;
end {else if}
else if opcode in
[pc_les,pc_leq,pc_grt,pc_geq,pc_sto,pc_cpi,pc_ind,
pc_ili,pc_iil,pc_idl,pc_ild,pc_ixa]
then begin
if dworkLoc = 0 then begin
dworkLoc := minSize;
minSize := minSize + 4;
localSize := localSize + 4;
end; {if}
end; {else if}
end; {Scan}
begin {Gen}
bk := blk; {determine the size of the stack frame}
localSize := 0;
parameterSize := 0;
funLoc := 0;
dworkLoc := 0;
minSize := 1;
stackSaveDepth := 0;
isQuadFunction := false;
while bk <> nil do begin
op := bk^.code;
while op <> nil do begin
Scan(op);
op := op^.next;
end; {while}
bk := bk^.next;
end; {while}
if saveStack or checkStack or (strictVararg and hasVarargsCall) then begin
stackLoc := minSize;
minSize := minSize + 2;
localSize := localSize + 2;
end; {if}
if dataBank then begin
bankLoc := minSize;
minSize := minSize + 2;
localSize := localSize + 2;
end; {if}
bk := blk; {allocate locations for the values}
while bk <> nil do begin
op := bk^.code;
while op <> nil do begin
if op^.opcode = dc_loc then
DirLoc1(op)
else if op^.opcode = dc_prm then
DirPrm(op);
op := op^.next;
end; {while}
bk := bk^.next;
end; {while}
bk := blk;
while bk <> nil do begin
op := bk^.code;
while op <> nil do begin
if op^.opcode = dc_loc then
DirLoc2(op);
op := op^.next;
end; {while}
bk := bk^.next;
end; {while}
while blk <> nil do begin {generate code for the block}
op := blk^.code;
while op <> nil do begin
GenTree(op);
op := op^.next;
end; {while}
blk := blk^.next;
end; {while}
end; {Gen}
function LabelToDisp {lab: integer): integer};
{ convert a local label number to a stack frame displacement }
{ }
{ parameters: }
{ lab - label number }
begin {LabelToDisp}
if lab = 0 then
LabelToDisp := funLoc
else
LabelToDisp := localLabel[lab];
end; {LabelToDisp}
end.