* MIPS: rewrote 32-bit code generation methods, reducing code duplication.

+ Implemented overflow checking for unsigned 32-bit addition and subtraction.
* Use optimize_op_const instead of custom optimizations.
* Change AND/OR/XOR into ANDI/ORI/XORI if they use immediate operands, and use correct range for these immediate operands, must be 0..65535 unlike -32768..32767 for arithmetic operations.
* Don't treat AND/OR/XOR as macros, no longer necessary.
* Don't treat BEQ/BNE as macros either.

git-svn-id: trunk@24445 -
This commit is contained in:
sergei 2013-05-05 05:55:03 +00:00
parent da35b3c601
commit 7cfc737866
2 changed files with 115 additions and 182 deletions

View File

@ -44,6 +44,7 @@ type
procedure make_simple_ref(list: tasmlist; var ref: treference);
procedure handle_reg_const_reg(list: tasmlist; op: Tasmop; src: tregister; a: tcgint; dst: tregister);
procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
procedure overflowcheck_internal(list: TAsmList; arg1, arg2: TRegister);
{ parameter }
procedure a_loadfpu_reg_cgpara(list: tasmlist; size: tcgsize; const r: tregister; const paraloc: TCGPara); override;
@ -857,58 +858,44 @@ begin
a_load_reg_reg(list,OS_32,size,dst,dst);
end;
procedure TCGMIPS.a_op_const_reg(list: tasmlist; Op: TOpCG; size: tcgsize; a: tcgint; reg: TRegister);
procedure TCGMIPS.overflowcheck_internal(list: tasmlist; arg1, arg2: tregister);
var
power: longint;
tmpreg1: tregister;
carry, hreg: tregister;
begin
if ((op = OP_MUL) or (op = OP_IMUL)) then
begin
if ispowerof2(a, power) then
begin
{ can be done with a shift }
if power < 32 then
begin
list.concat(taicpu.op_reg_reg_const(A_SLL, reg, reg, power));
exit;
end;
end;
end;
if ((op = OP_SUB) or (op = OP_ADD)) then
begin
if (a = 0) then
exit;
end;
carry:=GetIntRegister(list,OS_INT);
hreg:=GetIntRegister(list,OS_INT);
list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,arg1,arg2));
{ if carry<>0, this will cause hardware overflow interrupt }
a_load_const_reg(list,OS_INT,$80000000,hreg);
list.concat(taicpu.op_reg_reg_reg(A_SUB,hreg,hreg,carry));
end;
if Op in [OP_NEG, OP_NOT] then
internalerror(200306011);
if (a = 0) then
begin
if (Op = OP_IMUL) or (Op = OP_MUL) then
list.concat(taicpu.op_reg_reg(A_MOVE, reg, NR_R0))
else
list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), reg, reg, NR_R0))
end
const
ops_mul_ovf: array[boolean] of TAsmOp = (A_MULOU, A_MULO);
ops_mul: array[boolean] of TAsmOp = (A_MULTU,A_MULT);
ops_add: array[boolean] of TAsmOp = (A_ADDU, A_ADD);
ops_sub: array[boolean] of TAsmOp = (A_SUBU, A_SUB);
ops_and: array[boolean] of TAsmOp = (A_AND, A_ANDI);
ops_or: array[boolean] of TAsmOp = (A_OR, A_ORI);
ops_xor: array[boolean] of TasmOp = (A_XOR, A_XORI);
procedure TCGMIPS.a_op_const_reg(list: tasmlist; Op: TOpCG; size: tcgsize; a: tcgint; reg: TRegister);
begin
optimize_op_const(op,a);
case op of
OP_NONE:
exit;
OP_MOVE:
a_load_const_reg(list,size,a,reg);
OP_NEG,OP_NOT:
internalerror(200306011);
else
begin
if op = OP_IMUL then
begin
tmpreg1 := GetIntRegister(list, OS_INT);
a_load_const_reg(list, OS_INT, a, tmpreg1);
list.concat(taicpu.op_reg_reg(A_MULT, reg, tmpreg1));
list.concat(taicpu.op_reg(A_MFLO, reg));
end
else if op = OP_MUL then
begin
tmpreg1 := GetIntRegister(list, OS_INT);
a_load_const_reg(list, OS_INT, a, tmpreg1);
list.concat(taicpu.op_reg_reg(A_MULTU, reg, tmpreg1));
list.concat(taicpu.op_reg(A_MFLO, reg));
end
else
handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), reg, a, reg);
a_op_const_reg_reg(list,op,size,a,reg,reg);
end;
maybeadjustresult(list,op,size,reg);
end;
@ -916,29 +903,18 @@ procedure TCGMIPS.a_op_reg_reg(list: tasmlist; Op: TOpCG; size: TCGSize; src, ds
begin
case Op of
OP_NEG:
{ discard overflow checking }
list.concat(taicpu.op_reg_reg(A_NEGU{A_NEG}, dst, src));
list.concat(taicpu.op_reg_reg_reg(A_SUBU, dst, NR_R0, src));
OP_NOT:
begin
list.concat(taicpu.op_reg_reg(A_NOT, dst, src));
end;
else
begin
if op = OP_IMUL then
list.concat(taicpu.op_reg_reg_reg(A_NOR, dst, NR_R0, src));
OP_IMUL,OP_MUL:
begin
list.concat(taicpu.op_reg_reg(A_MULT, dst, src));
list.concat(taicpu.op_reg_reg(ops_mul[op=OP_IMUL], dst, src));
list.concat(taicpu.op_reg(A_MFLO, dst));
end
else if op = OP_MUL then
begin
list.concat(taicpu.op_reg_reg(A_MULTU, dst, src));
list.concat(taicpu.op_reg(A_MFLO, dst));
end
else
begin
list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, dst, src));
end;
end;
else
list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, dst, src));
end;
maybeadjustresult(list,op,size,dst);
end;
@ -946,50 +922,9 @@ end;
procedure TCGMIPS.a_op_const_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
var
power: longint;
tmpreg1: tregister;
l: TLocation;
begin
case op of
OP_MUL,
OP_IMUL:
begin
if ispowerof2(a, power) then
begin
{ can be done with a shift }
if power < 32 then
list.concat(taicpu.op_reg_reg_const(A_SLL, dst, src, power))
else
inherited a_op_const_reg_reg(list, op, size, a, src, dst);
exit;
end;
end;
OP_SUB,
OP_ADD:
begin
if (a = 0) then
begin
a_load_reg_reg(list, size, size, src, dst);
exit;
end;
end;
end;
if op = OP_IMUL then
begin
tmpreg1 := GetIntRegister(list, OS_INT);
a_load_const_reg(list, OS_INT, a, tmpreg1);
list.concat(taicpu.op_reg_reg(A_MULT, src, tmpreg1));
list.concat(taicpu.op_reg(A_MFLO, dst));
end
else if op = OP_MUL then
begin
tmpreg1 := GetIntRegister(list, OS_INT);
a_load_const_reg(list, OS_INT, a, tmpreg1);
list.concat(taicpu.op_reg_reg(A_MULTU, src, tmpreg1));
list.concat(taicpu.op_reg(A_MFLO, dst));
end
else
handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), src, a, dst);
maybeadjustresult(list,op,size,dst);
a_op_const_reg_reg_checkoverflow(list, op, size, a, src, dst, false, l);
end;
@ -1003,110 +938,105 @@ end;
procedure TCGMIPS.a_op_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
var
tmpreg1: tregister;
signed,immed: boolean;
hreg: TRegister;
asmop: TAsmOp;
begin
ovloc.loc := LOC_VOID;
optimize_op_const(op,a);
signed:=(size in [OS_S8,OS_S16,OS_S32]);
case op of
OP_SUB,
OP_ADD:
begin
if (a = 0) then
begin
a_load_reg_reg(list, size, size, src, dst);
exit;
end;
end;
end;{case}
OP_NONE:
a_load_reg_reg(list,size,size,src,dst);
OP_MOVE:
a_load_const_reg(list,size,a,dst);
case op of
OP_ADD:
begin
if setflags then
handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst)
else
handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), src, a, dst);
handle_reg_const_reg(list,ops_add[setflags and signed],src,a,dst);
if setflags and (not signed) then
overflowcheck_internal(list,dst,src);
end;
OP_SUB:
begin
if setflags then
handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst)
else
handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), src, a, dst);
handle_reg_const_reg(list,ops_sub[setflags and signed],src,a,dst);
if setflags and (not signed) then
overflowcheck_internal(list,src,dst);
end;
OP_MUL:
OP_MUL,OP_IMUL:
begin
if setflags then
handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst)
hreg:=GetIntRegister(list,OS_INT);
a_load_const_reg(list,OS_INT,a,hreg);
a_op_reg_reg_reg_checkoverflow(list,op,size,src,hreg,dst,setflags,ovloc);
exit;
end;
OP_AND,OP_OR,OP_XOR:
begin
{ logical operations zero-extend, not sign-extend, the immediate }
immed:=(a>=0) and (a<=65535);
case op of
OP_AND: asmop:=ops_and[immed];
OP_OR: asmop:=ops_or[immed];
OP_XOR: asmop:=ops_xor[immed];
else
begin
tmpreg1 := GetIntRegister(list, OS_INT);
a_load_const_reg(list, OS_INT, a, tmpreg1);
list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size),src, tmpreg1));
list.concat(taicpu.op_reg(A_MFLO, dst));
InternalError(2013050401);
end;
end;
OP_IMUL:
begin
if setflags then
handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst)
if immed then
list.concat(taicpu.op_reg_reg_const(asmop,dst,src,a))
else
begin
tmpreg1 := GetIntRegister(list, OS_INT);
a_load_const_reg(list, OS_INT, a, tmpreg1);
list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size),src, tmpreg1));
list.concat(taicpu.op_reg(A_MFLO, dst));
end;
begin
hreg:=GetIntRegister(list,OS_INT);
a_load_const_reg(list,OS_INT,a,hreg);
list.concat(taicpu.op_reg_reg_reg(asmop,dst,src,hreg));
end;
end;
OP_XOR, OP_OR, OP_AND:
begin
handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst);
end;
else
internalerror(2007012601);
OP_SHL,OP_SHR,OP_SAR:
list.concat(taicpu.op_reg_reg_const(f_TOpCG2AsmOp_ovf(op,size),dst,src,a));
else
internalerror(2007012601);
end;
maybeadjustresult(list,op,size,dst);
end;
procedure TCGMIPS.a_op_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
var
signed: boolean;
begin
ovloc.loc := LOC_VOID;
signed:=(size in [OS_S8,OS_S16,OS_S32]);
case op of
OP_ADD:
begin
if setflags then
list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1))
else
list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, src2, src1));
list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], dst, src2, src1));
if setflags and (not signed) then
overflowcheck_internal(list, dst, src2);
end;
OP_SUB:
begin
if setflags then
list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1))
else
list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, src2, src1));
list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], dst, src2, src1));
if setflags and (not signed) then
overflowcheck_internal(list, src2, dst);
end;
OP_MUL:
OP_MUL,OP_IMUL:
begin
if setflags then
list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1))
{ TODO: still uses a macro }
list.concat(taicpu.op_reg_reg_reg(ops_mul_ovf[op=OP_IMUL], dst, src2, src1))
else
begin
list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size), src2, src1));
list.concat(taicpu.op_reg_reg(ops_mul[op=OP_IMUL], src2, src1));
list.concat(taicpu.op_reg(A_MFLO, dst));
end;
end;
OP_IMUL:
begin
if setflags then
list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1))
else
begin
list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size), src2, src1));
list.concat(taicpu.op_reg(A_MFLO, dst));
end;
end;
OP_XOR, OP_OR, OP_AND:
OP_AND,OP_OR,OP_XOR:
begin
list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1));
end;

View File

@ -222,18 +222,21 @@ unit cpugas;
end;
}
function is_macro_instruction(op : TAsmOp) : boolean;
function is_macro_instruction(ai : taicpu) : boolean;
var
op: tasmop;
begin
op:=ai.opcode;
is_macro_instruction :=
{ 'seq', 'sge', 'sgeu', 'sgt', 'sgtu', 'sle', 'sleu', 'sne', }
(op=A_SEQ) or (op = A_SGE) or (op=A_SGEU) or (op=A_SGT) or
(op=A_SGTU) or (op=A_SLE) or (op=A_SLEU) or (op=A_SNE)
{ JAL is not here! See comments in TCGMIPS.a_call_name. }
or (op=A_LA) or (op=A_BC) {or (op=A_JAL)}
or (op=A_LA) or ((op=A_BC) and not (ai.condition in [C_EQ,C_NE])) {or (op=A_JAL)}
or (op=A_REM) or (op=A_REMU)
or (op=A_DIV) or (op=A_DIVU)
or (op=A_DIV) or (op=A_DIVU)
{ A_LI is only a macro if the immediate is not in thez 16-bit range }
or (op=A_LI) or (op=A_AND) or (op=A_XOR);
or (op=A_LI);
end;
procedure TMIPSInstrWriter.WriteInstruction(hp: Tai);
@ -346,7 +349,7 @@ unit cpugas;
end;
else
begin
if is_macro_instruction(op) and TMIPSGNUAssembler(owner).nomacro then
if is_macro_instruction(taicpu(hp)) and TMIPSGNUAssembler(owner).nomacro then
owner.AsmWriteln(#9'.set'#9'macro');
s := #9 + gas_op2str[op] + cond2str[taicpu(hp).condition];
if taicpu(hp).delayslot_annulled then
@ -358,7 +361,7 @@ unit cpugas;
s := s + ',' + getopstr(taicpu(hp).oper[i]^);
end;
owner.AsmWriteLn(s);
if is_macro_instruction(op) and TMIPSGNUAssembler(owner).nomacro then
if is_macro_instruction(taicpu(hp)) and TMIPSGNUAssembler(owner).nomacro then
owner.AsmWriteln(#9'.set'#9'nomacro');
end;
end;