summaryrefslogtreecommitdiff
path: root/closures/compiler/powerpc64/nppcadd.pas
diff options
context:
space:
mode:
Diffstat (limited to 'closures/compiler/powerpc64/nppcadd.pas')
-rw-r--r--closures/compiler/powerpc64/nppcadd.pas360
1 files changed, 360 insertions, 0 deletions
diff --git a/closures/compiler/powerpc64/nppcadd.pas b/closures/compiler/powerpc64/nppcadd.pas
new file mode 100644
index 0000000000..7d11a78a6e
--- /dev/null
+++ b/closures/compiler/powerpc64/nppcadd.pas
@@ -0,0 +1,360 @@
+{
+ Copyright (c) 2000-2002 by Florian Klaempfl and Jonas Maebe
+
+ Code generation for add nodes on the PowerPC64
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nppcadd;
+
+{$I fpcdefs.inc}
+
+interface
+
+uses
+ node, nadd, ncgadd, ngppcadd, cpubase;
+
+type
+ tppcaddnode = class(tgenppcaddnode)
+ procedure pass_generate_code override;
+ private
+ procedure emit_compare(unsigned: boolean); override;
+ end;
+
+implementation
+
+uses
+ sysutils,
+
+ globtype, systems,
+ cutils, verbose, globals,
+ symconst, symdef, paramgr,
+ aasmbase, aasmtai,aasmdata, aasmcpu, defutil, htypechk,
+ cgbase, cpuinfo, pass_1, pass_2, regvars,
+ cpupara, cgcpu, cgutils,procinfo,
+ ncon, nset,
+ ncgutil, tgobj, rgobj, rgcpu, cgobj;
+
+{*****************************************************************************
+ Helpers
+*****************************************************************************}
+
+procedure tppcaddnode.emit_compare(unsigned: boolean);
+const
+ { unsigned useconst 32bit-op }
+ cmpop_table : array[boolean, boolean, boolean] of TAsmOp = (
+ ((A_CMPD, A_CMPW), (A_CMPDI, A_CMPWI)),
+ ((A_CMPLD, A_CMPLW), (A_CMPLDI, A_CMPLWI))
+ );
+
+var
+ op: TAsmOp;
+ tmpreg: TRegister;
+ useconst: boolean;
+
+ opsize : TCgSize;
+begin
+ { get the constant on the right if there is one }
+ if (left.location.loc = LOC_CONSTANT) then
+ swapleftright;
+
+ opsize := def_cgsize(left.resultdef);
+
+ {$IFDEF EXTDEBUG}
+ current_asmdata.CurrAsmList.concat(tai_comment.create(strpnew('tppcaddnode.emit_compare ' + inttostr(ord(opsize)) + ' ' + inttostr(tcgsize2size[opsize]))));
+ {$ENDIF EXTDEBUG}
+
+ { can we use a signed comparison or not? In case of equal/unequal comparison
+ we can check whether this is possible because it does not matter. }
+ if (right.location.loc = LOC_CONSTANT) then
+ if (nodetype in [equaln,unequaln]) then
+ if (unsigned and (aword(right.location.value) > high(word))) or
+ (not unsigned and (aint(right.location.value) < low(smallint)) or
+ (aint(right.location.value) > high(smallint))) then
+ { we can then maybe use a constant in the 'othersigned' case
+ (the sign doesn't matter for equal/unequal) }
+ unsigned := not unsigned;
+
+ { calculate the size of the comparison because ppc64 only has 32 and 64
+ bit comparison opcodes; prefer 32 bits }
+ if (not (opsize in [OS_32, OS_S32, OS_64, OS_S64])) then begin
+ if (unsigned) then
+ opsize := OS_32
+ else
+ opsize := OS_S32;
+ cg.a_load_reg_reg(current_asmdata.CurrAsmList, def_cgsize(left.resultdef), opsize,
+ left.location.register, left.location.register);
+ end;
+
+ { can we use an immediate, or do we have to load the
+ constant in a register first? }
+ if (right.location.loc = LOC_CONSTANT) then begin
+ if (unsigned and
+ (aword(right.location.value) <= high(word))) or
+ (not (unsigned) and
+ (aint(right.location.value) >= low(smallint)) and (aint(right.location.value) <= high(smallint))) then
+ useconst := true
+ else begin
+ useconst := false;
+ tmpreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
+ cg.a_load_const_reg(current_asmdata.CurrAsmList, opsize, right.location.value, tmpreg);
+ end
+ end else
+ useconst := false;
+
+ location.loc := LOC_FLAGS;
+ location.resflags := getresflags;
+
+ op := cmpop_table[unsigned, useconst, opsize in [OS_S32, OS_32]];
+
+ { actually do the operation }
+ if (right.location.loc = LOC_CONSTANT) then begin
+ if useconst then
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(op, left.location.register,
+ longint(right.location.value)))
+ else
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.register, tmpreg));
+ end else
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.register,
+ right.location.register));
+end;
+
+{*****************************************************************************
+ pass_2
+*****************************************************************************}
+
+procedure tppcaddnode.pass_generate_code;
+{ is also being used for xor, and "mul", "sub, or and comparative }
+{ operators }
+var
+ cgop: topcg;
+ op: tasmop;
+ tmpreg: tregister;
+ hl: tasmlabel;
+ cmpop: boolean;
+ checkoverflow: boolean;
+
+ { true, if unsigned types are compared }
+ unsigned: boolean;
+
+begin
+ { to make it more readable, string and set (not smallset!) have their
+ own procedures }
+ case left.resultdef.typ of
+ orddef:
+ begin
+ { handling boolean expressions }
+ if is_boolean(left.resultdef) and
+ is_boolean(right.resultdef) then
+ begin
+ second_addboolean;
+ exit;
+ end;
+ end;
+ stringdef:
+ begin
+ internalerror(2002072402);
+ exit;
+ end;
+ setdef:
+ begin
+ { normalsets are already handled in pass1 }
+ if not is_smallset(left.resultdef) then
+ internalerror(200109041);
+ second_addsmallset;
+ exit;
+ end;
+ arraydef:
+ begin
+{$IFDEF SUPPORT_MMX}
+ if is_mmx_able_array(left.resultdef) then
+ begin
+ second_addmmx;
+ exit;
+ end;
+{$ENDIF SUPPORT_MMX}
+ end;
+ floatdef:
+ begin
+ second_addfloat;
+ exit;
+ end;
+ end;
+
+ { defaults }
+ cmpop := nodetype in [ltn, lten, gtn, gten, equaln, unequaln];
+ unsigned := not (is_signed(left.resultdef)) or
+ not (is_signed(right.resultdef));
+
+ pass_left_and_right;
+
+ { Convert flags to register first }
+ { can any of these things be in the flags actually?? (JM) }
+
+ if (left.location.loc = LOC_FLAGS) or
+ (right.location.loc = LOC_FLAGS) then
+ internalerror(2002072602);
+
+ { set result location }
+ if not cmpop then
+ location_reset(location, LOC_REGISTER, def_cgsize(resultdef))
+ else
+ location_reset(location, LOC_FLAGS, OS_NO);
+
+ checkoverflow:=
+ (nodetype in [addn,subn,muln]) and
+ (cs_check_overflow in current_settings.localswitches) and
+ (left.resultdef.typ<>pointerdef) and
+ (right.resultdef.typ<>pointerdef);
+
+ load_left_right(cmpop, checkoverflow);
+
+ if not (cmpop) then
+ location.register := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
+
+ if not (checkoverflow) then begin
+ case nodetype of
+ addn, muln, xorn, orn, andn:
+ begin
+ case nodetype of
+ addn:
+ cgop := OP_ADD;
+ muln:
+ if unsigned then
+ cgop := OP_MUL
+ else
+ cgop := OP_IMUL;
+ xorn:
+ cgop := OP_XOR;
+ orn:
+ cgop := OP_OR;
+ andn:
+ cgop := OP_AND;
+ end;
+ if (left.location.loc = LOC_CONSTANT) then
+ swapleftright;
+ if (right.location.loc <> LOC_CONSTANT) then
+ cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, cgop, OS_INT,
+ left.location.register, right.location.register,
+ location.register)
+ else
+ cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, cgop, OS_INT,
+ right.location.value, left.location.register,
+ location.register);
+ end;
+ subn:
+ begin
+ if (nf_swapped in flags) then
+ swapleftright;
+ if left.location.loc <> LOC_CONSTANT then
+ if right.location.loc <> LOC_CONSTANT then begin
+ cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT,
+ right.location.register, left.location.register,
+ location.register);
+ end else begin
+ cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT,
+ right.location.value, left.location.register,
+ location.register);
+ end
+ else
+ begin
+ tmpreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
+ cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT,
+ left.location.value, tmpreg);
+ cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT,
+ right.location.register, tmpreg, location.register);
+ end;
+ end;
+ ltn, lten, gtn, gten, equaln, unequaln:
+ begin
+ {$ifdef extdebug}
+ current_asmdata.CurrAsmList.concat(tai_comment.create('tppcaddnode.pass2'));
+ {$endif extdebug}
+
+ emit_compare(unsigned);
+ end;
+ end;
+ end
+ else
+ // overflow checking is on and we have an addn, subn or muln
+ begin
+ if is_signed(resultdef) then
+ begin
+ case nodetype of
+ addn:
+ op := A_ADDO;
+ subn:
+ begin
+ op := A_SUBO;
+ if (nf_swapped in flags) then
+ swapleftright;
+ end;
+ muln:
+ op := A_MULLDO;
+ else
+ internalerror(2002072601);
+ end;
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op, location.register,
+ left.location.register, right.location.register));
+ cg.g_overflowcheck(current_asmdata.CurrAsmList, location, resultdef);
+ end
+ else
+ begin
+ case nodetype of
+ addn:
+ begin
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ADD, location.register,
+ left.location.register, right.location.register));
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMPLD, location.register,
+ left.location.register));
+ cg.g_overflowcheck(current_asmdata.CurrAsmList, location, resultdef);
+ end;
+ subn:
+ begin
+ if (nf_swapped in flags) then
+ swapleftright;
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUB, location.register,
+ left.location.register, right.location.register));
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMPLD,
+ left.location.register, location.register));
+ cg.g_overflowcheck(current_asmdata.CurrAsmList, location, resultdef);
+ end;
+ muln:
+ begin
+ { calculate the upper 64 bits of the product, = 0 if no overflow }
+ cg.a_reg_alloc(current_asmdata.CurrAsmList, NR_R0);
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MULHDU_, NR_R0,
+ left.location.register, right.location.register));
+ cg.a_reg_dealloc(current_asmdata.CurrAsmList, NR_R0);
+ { calculate the real result }
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MULLD, location.register,
+ left.location.register, right.location.register));
+ { g_overflowcheck generates a OC_AE instead of OC_EQ :/ }
+ current_asmdata.getjumplabel(hl);
+ tcgppc(cg).a_jmp_cond(current_asmdata.CurrAsmList, OC_EQ, hl);
+ cg.a_call_name(current_asmdata.CurrAsmList, 'FPC_OVERFLOW',false);
+ cg.a_label(current_asmdata.CurrAsmList, hl);
+ end;
+ end;
+ end;
+ end;
+end;
+
+begin
+ caddnode := tppcaddnode;
+end.
+