|
@@ -74,6 +74,7 @@ unit aoptx86;
|
|
|
|
|
|
function PostPeepholeOptMov(const p : tai) : Boolean;
|
|
|
function PostPeepholeOptCmp(var p : tai) : Boolean;
|
|
|
+ function PostPeepholeOptTestOr(var p : tai) : Boolean;
|
|
|
|
|
|
procedure OptReferences;
|
|
|
end;
|
|
@@ -2683,6 +2684,99 @@ unit aoptx86;
|
|
|
end;
|
|
|
|
|
|
|
|
|
+ function TX86AsmOptimizer.PostPeepholeOptTestOr(var p : tai) : Boolean;
|
|
|
+ var
|
|
|
+ IsTestConstX : Boolean;
|
|
|
+ hp1,hp2 : tai;
|
|
|
+ begin
|
|
|
+ Result:=false;
|
|
|
+ { removes the line marked with (x) from the sequence
|
|
|
+ and/or/xor/add/sub/... $x, %y
|
|
|
+ test/or %y, %y | test $-1, %y (x)
|
|
|
+ j(n)z _Label
|
|
|
+ as the first instruction already adjusts the ZF
|
|
|
+ %y operand may also be a reference }
|
|
|
+ IsTestConstX:=(taicpu(p).opcode=A_TEST) and
|
|
|
+ MatchOperand(taicpu(p).oper[0]^,-1);
|
|
|
+ if (OpsEqual(taicpu(p).oper[0]^,taicpu(p).oper[1]^) or IsTestConstX) and
|
|
|
+ GetLastInstruction(p, hp1) and
|
|
|
+ (tai(hp1).typ = ait_instruction) and
|
|
|
+ GetNextInstruction(p,hp2) and
|
|
|
+ MatchInstruction(hp2,A_SETcc,A_Jcc,A_CMOVcc,[]) then
|
|
|
+ case taicpu(hp1).opcode Of
|
|
|
+ A_ADD, A_SUB, A_OR, A_XOR, A_AND:
|
|
|
+ begin
|
|
|
+ if OpsEqual(taicpu(hp1).oper[1]^,taicpu(p).oper[1]^) and
|
|
|
+ { does not work in case of overflow for G(E)/L(E)/C_O/C_NO }
|
|
|
+ { and in case of carry for A(E)/B(E)/C/NC }
|
|
|
+ ((taicpu(hp2).condition in [C_Z,C_NZ,C_E,C_NE]) or
|
|
|
+ ((taicpu(hp1).opcode <> A_ADD) and
|
|
|
+ (taicpu(hp1).opcode <> A_SUB))) then
|
|
|
+ begin
|
|
|
+ hp1 := tai(p.next);
|
|
|
+ asml.remove(p);
|
|
|
+ p.free;
|
|
|
+ p := tai(hp1);
|
|
|
+ Result:=true;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ A_SHL, A_SAL, A_SHR, A_SAR:
|
|
|
+ begin
|
|
|
+ if OpsEqual(taicpu(hp1).oper[1]^,taicpu(p).oper[1]^) and
|
|
|
+ { SHL/SAL/SHR/SAR with a value of 0 do not change the flags }
|
|
|
+ { therefore, it's only safe to do this optimization for }
|
|
|
+ { shifts by a (nonzero) constant }
|
|
|
+ (taicpu(hp1).oper[0]^.typ = top_const) and
|
|
|
+ (taicpu(hp1).oper[0]^.val <> 0) and
|
|
|
+ { does not work in case of overflow for G(E)/L(E)/C_O/C_NO }
|
|
|
+ { and in case of carry for A(E)/B(E)/C/NC }
|
|
|
+ (taicpu(hp2).condition in [C_Z,C_NZ,C_E,C_NE]) then
|
|
|
+ begin
|
|
|
+ hp1 := tai(p.next);
|
|
|
+ asml.remove(p);
|
|
|
+ p.free;
|
|
|
+ p := tai(hp1);
|
|
|
+ Result:=true;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ A_DEC, A_INC, A_NEG:
|
|
|
+ begin
|
|
|
+ if OpsEqual(taicpu(hp1).oper[0]^,taicpu(p).oper[1]^) and
|
|
|
+ { does not work in case of overflow for G(E)/L(E)/C_O/C_NO }
|
|
|
+ { and in case of carry for A(E)/B(E)/C/NC }
|
|
|
+ (taicpu(hp2).condition in [C_Z,C_NZ,C_E,C_NE]) then
|
|
|
+ begin
|
|
|
+ case taicpu(hp1).opcode Of
|
|
|
+ A_DEC, A_INC:
|
|
|
+ { replace inc/dec with add/sub 1, because inc/dec doesn't set the carry flag }
|
|
|
+ begin
|
|
|
+ case taicpu(hp1).opcode Of
|
|
|
+ A_DEC: taicpu(hp1).opcode := A_SUB;
|
|
|
+ A_INC: taicpu(hp1).opcode := A_ADD;
|
|
|
+ end;
|
|
|
+ taicpu(hp1).loadoper(1,taicpu(hp1).oper[0]^);
|
|
|
+ taicpu(hp1).loadConst(0,1);
|
|
|
+ taicpu(hp1).ops:=2;
|
|
|
+ end
|
|
|
+ end;
|
|
|
+ hp1 := tai(p.next);
|
|
|
+ asml.remove(p);
|
|
|
+ p.free;
|
|
|
+ p := tai(hp1);
|
|
|
+ Result:=true;
|
|
|
+ end;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ { change "test $-1,%reg" into "test %reg,%reg" }
|
|
|
+ if IsTestConstX and (taicpu(p).oper[1]^.typ=top_reg) then
|
|
|
+ taicpu(p).loadoper(0,taicpu(p).oper[1]^);
|
|
|
+ end { case }
|
|
|
+ { change "test $-1,%reg" into "test %reg,%reg" }
|
|
|
+ else if IsTestConstX and (taicpu(p).oper[1]^.typ=top_reg) then
|
|
|
+ taicpu(p).loadoper(0,taicpu(p).oper[1]^);
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
procedure TX86AsmOptimizer.OptReferences;
|
|
|
var
|
|
|
p: tai;
|