mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-27 20:11:02 +02:00
* x86: Revamped OptPass2Jcc CMOV code to shrink and reuse registers as much as possible
This commit is contained in:
parent
2a83972db8
commit
6ffa258abb
@ -11696,6 +11696,9 @@ unit aoptx86;
|
|||||||
|
|
||||||
|
|
||||||
function TX86AsmOptimizer.OptPass2Jcc(var p : tai) : boolean;
|
function TX86AsmOptimizer.OptPass2Jcc(var p : tai) : boolean;
|
||||||
|
const
|
||||||
|
subreg2opsize : array[tsubregister] of topsize =
|
||||||
|
(S_NO,S_B,S_B,S_W,S_L,S_Q,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
|
||||||
var
|
var
|
||||||
hp1,hp2: tai;
|
hp1,hp2: tai;
|
||||||
carryadd_opcode : TAsmOp;
|
carryadd_opcode : TAsmOp;
|
||||||
@ -11714,6 +11717,10 @@ unit aoptx86;
|
|||||||
|
|
||||||
ConstRegs: array[0..MAX_CMOV_REGISTERS - 1] of TRegister;
|
ConstRegs: array[0..MAX_CMOV_REGISTERS - 1] of TRegister;
|
||||||
ConstVals: array[0..MAX_CMOV_REGISTERS - 1] of TCGInt;
|
ConstVals: array[0..MAX_CMOV_REGISTERS - 1] of TCGInt;
|
||||||
|
ConstSizes: array[0..MAX_CMOV_REGISTERS - 1] of TSubRegister; { May not match ConstRegs if one is shared over multiple CMOVs. }
|
||||||
|
ConstMovs: array[0..MAX_CMOV_REGISTERS - 1] of tai; { Location of initialisation instruction }
|
||||||
|
|
||||||
|
ConstWriteSizes: array[0..first_int_imreg - 1] of TSubRegister; { Largest size of register written. }
|
||||||
|
|
||||||
{ Tries to convert a mov const,%reg instruction into a CMOV by reserving a
|
{ Tries to convert a mov const,%reg instruction into a CMOV by reserving a
|
||||||
new register to store the constant }
|
new register to store the constant }
|
||||||
@ -11750,10 +11757,10 @@ unit aoptx86;
|
|||||||
{ See if the value has already been reserved for another CMOV instruction }
|
{ See if the value has already been reserved for another CMOV instruction }
|
||||||
CurrentVal := taicpu(p).oper[0]^.val;
|
CurrentVal := taicpu(p).oper[0]^.val;
|
||||||
for X := 0 to StoredCount - 1 do
|
for X := 0 to StoredCount - 1 do
|
||||||
if (ConstVals[X] = CurrentVal) and
|
if ConstVals[X] = CurrentVal then
|
||||||
(getsubreg(taicpu(p).oper[1]^.reg) <= getsubreg(ConstRegs[X])) then
|
|
||||||
begin
|
begin
|
||||||
ConstRegs[StoredCount] := newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), RegSize);
|
ConstRegs[StoredCount] := ConstRegs[X];
|
||||||
|
ConstSizes[StoredCount] := RegSize;
|
||||||
ConstVals[StoredCount] := CurrentVal;
|
ConstVals[StoredCount] := CurrentVal;
|
||||||
Result := True;
|
Result := True;
|
||||||
|
|
||||||
@ -11762,7 +11769,7 @@ unit aoptx86;
|
|||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ANewReg := GetIntRegisterBetween(RegSize, TmpUsedRegs, search_start_p, stop_search_p, True);
|
ANewReg := GetIntRegisterBetween(R_SUBWHOLE, TmpUsedRegs, search_start_p, stop_search_p, True);
|
||||||
if ANewReg = NR_NO then
|
if ANewReg = NR_NO then
|
||||||
{ No free registers }
|
{ No free registers }
|
||||||
Exit;
|
Exit;
|
||||||
@ -11772,6 +11779,7 @@ unit aoptx86;
|
|||||||
IncludeRegInUsedRegs(ANewReg, TmpUsedRegs);
|
IncludeRegInUsedRegs(ANewReg, TmpUsedRegs);
|
||||||
|
|
||||||
ConstRegs[StoredCount] := ANewReg;
|
ConstRegs[StoredCount] := ANewReg;
|
||||||
|
ConstSizes[StoredCount] := RegSize;
|
||||||
ConstVals[StoredCount] := CurrentVal;
|
ConstVals[StoredCount] := CurrentVal;
|
||||||
|
|
||||||
Inc(StoredCount);
|
Inc(StoredCount);
|
||||||
@ -12242,10 +12250,13 @@ unit aoptx86;
|
|||||||
l := 0;
|
l := 0;
|
||||||
c := 0;
|
c := 0;
|
||||||
|
|
||||||
{ Initialise RegWrites, ConstRegs and ConstVals }
|
{ Initialise RegWrites, ConstRegs, ConstVals, ConstSizes, ConstWriteSizes and ConstMovs }
|
||||||
FillChar(RegWrites[0], MAX_CMOV_INSTRUCTIONS * 2 * SizeOf(TRegister), 0);
|
FillChar(RegWrites[0], MAX_CMOV_INSTRUCTIONS * 2 * SizeOf(TRegister), 0);
|
||||||
FillChar(ConstRegs[0], MAX_CMOV_REGISTERS * SizeOf(TRegister), 0);
|
FillChar(ConstRegs[0], MAX_CMOV_REGISTERS * SizeOf(TRegister), 0);
|
||||||
FillChar(ConstVals[0], MAX_CMOV_REGISTERS * SizeOf(TCGInt), 0);
|
FillChar(ConstVals[0], MAX_CMOV_REGISTERS * SizeOf(TCGInt), 0);
|
||||||
|
FillChar(ConstSizes[0], MAX_CMOV_REGISTERS * SizeOf(TSubRegister), 0);
|
||||||
|
FillChar(ConstWriteSizes[0], first_int_imreg * SizeOf(TOpSize), 0);
|
||||||
|
FillChar(ConstMovs[0], MAX_CMOV_REGISTERS * SizeOf(taicpu), 0);
|
||||||
|
|
||||||
RefModified := False;
|
RefModified := False;
|
||||||
while assigned(hp1) and
|
while assigned(hp1) and
|
||||||
@ -12341,7 +12352,7 @@ unit aoptx86;
|
|||||||
below) }
|
below) }
|
||||||
if not TmpUsedRegs[R_INTREGISTER].IsUsed(ConstRegs[x]) then
|
if not TmpUsedRegs[R_INTREGISTER].IsUsed(ConstRegs[x]) then
|
||||||
begin
|
begin
|
||||||
hp_new := taicpu.op_const_reg(A_MOV, reg2opsize(ConstRegs[x]), taicpu(hp1).oper[0]^.val, ConstRegs[x]);
|
hp_new := taicpu.op_const_reg(A_MOV, subreg2opsize[R_SUBWHOLE], taicpu(hp1).oper[0]^.val, ConstRegs[X]);
|
||||||
taicpu(hp_new).fileinfo := taicpu(hp_prev).fileinfo;
|
taicpu(hp_new).fileinfo := taicpu(hp_prev).fileinfo;
|
||||||
|
|
||||||
asml.InsertBefore(hp_new, hp_flagalloc);
|
asml.InsertBefore(hp_new, hp_flagalloc);
|
||||||
@ -12349,14 +12360,20 @@ unit aoptx86;
|
|||||||
TrySwapMovOp(hp_prev2, hp_new);
|
TrySwapMovOp(hp_prev2, hp_new);
|
||||||
|
|
||||||
IncludeRegInUsedRegs(ConstRegs[x], TmpUsedRegs);
|
IncludeRegInUsedRegs(ConstRegs[x], TmpUsedRegs);
|
||||||
|
|
||||||
|
ConstMovs[X] := hp_new;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
{ We just need an instruction between hp_prev and hp1
|
{ We just need an instruction between hp_prev and hp1
|
||||||
where we know the register is marked as in use }
|
where we know the register is marked as in use }
|
||||||
hp_new := hpmov1;
|
hp_new := hpmov1;
|
||||||
|
|
||||||
|
{ Keep track of largest write for this register so it can be optimised later }
|
||||||
|
if (getsubreg(taicpu(hp1).oper[1]^.reg) > ConstWriteSizes[getsupreg(ConstRegs[X])]) then
|
||||||
|
ConstWriteSizes[getsupreg(ConstRegs[X])] := getsubreg(taicpu(hp1).oper[1]^.reg);
|
||||||
|
|
||||||
AllocRegBetween(ConstRegs[x], hp_new, hp1, UsedRegs);
|
AllocRegBetween(ConstRegs[x], hp_new, hp1, UsedRegs);
|
||||||
taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), getsubreg(taicpu(hp1).oper[1]^.reg)));
|
taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), ConstSizes[X]));
|
||||||
Inc(x);
|
Inc(x);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -12368,6 +12385,14 @@ unit aoptx86;
|
|||||||
GetNextInstruction(hp1, hp1);
|
GetNextInstruction(hp1, hp1);
|
||||||
until (hp1 = hp_lblxxx);
|
until (hp1 = hp_lblxxx);
|
||||||
|
|
||||||
|
{ Update initialisation MOVs to the smallest possible size }
|
||||||
|
for c := 0 to x - 1 do
|
||||||
|
if Assigned(ConstMovs[c]) then
|
||||||
|
begin
|
||||||
|
taicpu(ConstMovs[c]).opsize := subreg2opsize[ConstWriteSizes[Word(ConstRegs[c])]];
|
||||||
|
setsubreg(taicpu(ConstMovs[c]).oper[1]^.reg, ConstWriteSizes[Word(ConstRegs[c])]);
|
||||||
|
end;
|
||||||
|
|
||||||
hp2 := hp_lblxxx;
|
hp2 := hp_lblxxx;
|
||||||
repeat
|
repeat
|
||||||
if not Assigned(hp2) then
|
if not Assigned(hp2) then
|
||||||
@ -12595,7 +12620,7 @@ unit aoptx86;
|
|||||||
|
|
||||||
for x := 0 to c - 1 do
|
for x := 0 to c - 1 do
|
||||||
if (ConstVals[x] = taicpu(hp1).oper[0]^.val) and
|
if (ConstVals[x] = taicpu(hp1).oper[0]^.val) and
|
||||||
(getsubreg(taicpu(hp1).oper[1]^.reg) <= getsubreg(ConstRegs[X])) then
|
(getsubreg(taicpu(hp1).oper[1]^.reg) = ConstSizes[X]) then
|
||||||
begin
|
begin
|
||||||
RegMatch := True;
|
RegMatch := True;
|
||||||
|
|
||||||
@ -12606,20 +12631,26 @@ unit aoptx86;
|
|||||||
below) }
|
below) }
|
||||||
if not TmpUsedRegs[R_INTREGISTER].IsUsed(ConstRegs[x]) then
|
if not TmpUsedRegs[R_INTREGISTER].IsUsed(ConstRegs[x]) then
|
||||||
begin
|
begin
|
||||||
hp_new := taicpu.op_const_reg(A_MOV, reg2opsize(ConstRegs[X]), taicpu(hp1).oper[0]^.val, ConstRegs[X]);
|
hp_new := taicpu.op_const_reg(A_MOV, subreg2opsize[R_SUBWHOLE], taicpu(hp1).oper[0]^.val, ConstRegs[X]);
|
||||||
asml.InsertBefore(hp_new, hp_flagalloc);
|
asml.InsertBefore(hp_new, hp_flagalloc);
|
||||||
if Assigned(hp_prev2) then
|
if Assigned(hp_prev2) then
|
||||||
TrySwapMovOp(hp_prev2, hp_new);
|
TrySwapMovOp(hp_prev2, hp_new);
|
||||||
|
|
||||||
IncludeRegInUsedRegs(ConstRegs[x], TmpUsedRegs);
|
IncludeRegInUsedRegs(ConstRegs[x], TmpUsedRegs);
|
||||||
|
|
||||||
|
ConstMovs[X] := hp_new;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
{ We just need an instruction between hp_prev and hp1
|
{ We just need an instruction between hp_prev and hp1
|
||||||
where we know the register is marked as in use }
|
where we know the register is marked as in use }
|
||||||
hp_new := hpmov2;
|
hp_new := hpmov2;
|
||||||
|
|
||||||
|
{ Keep track of largest write for this register so it can be optimised later }
|
||||||
|
if (getsubreg(taicpu(hp1).oper[1]^.reg) > ConstWriteSizes[getsupreg(ConstRegs[X])]) then
|
||||||
|
ConstWriteSizes[getsupreg(ConstRegs[X])] := getsubreg(taicpu(hp1).oper[1]^.reg);
|
||||||
|
|
||||||
AllocRegBetween(ConstRegs[x], hp_new, hp1, UsedRegs);
|
AllocRegBetween(ConstRegs[x], hp_new, hp1, UsedRegs);
|
||||||
taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), getsubreg(taicpu(hp1).oper[1]^.reg)));
|
taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), ConstSizes[X]));
|
||||||
Break;
|
Break;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -12678,7 +12709,7 @@ unit aoptx86;
|
|||||||
|
|
||||||
for x := 0 to c - 1 do
|
for x := 0 to c - 1 do
|
||||||
if (ConstVals[x] = taicpu(hp1).oper[0]^.val) and
|
if (ConstVals[x] = taicpu(hp1).oper[0]^.val) and
|
||||||
(getsubreg(taicpu(hp1).oper[1]^.reg) <= getsubreg(ConstRegs[X])) then
|
(getsubreg(taicpu(hp1).oper[1]^.reg) = ConstSizes[X]) then
|
||||||
begin
|
begin
|
||||||
RegMatch := True;
|
RegMatch := True;
|
||||||
|
|
||||||
@ -12689,20 +12720,26 @@ unit aoptx86;
|
|||||||
below) }
|
below) }
|
||||||
if not TmpUsedRegs[R_INTREGISTER].IsUsed(ConstRegs[x]) then
|
if not TmpUsedRegs[R_INTREGISTER].IsUsed(ConstRegs[x]) then
|
||||||
begin
|
begin
|
||||||
hp_new := taicpu.op_const_reg(A_MOV, reg2opsize(ConstRegs[X]), taicpu(hp1).oper[0]^.val, ConstRegs[X]);
|
hp_new := taicpu.op_const_reg(A_MOV, subreg2opsize[R_SUBWHOLE], taicpu(hp1).oper[0]^.val, ConstRegs[X]);
|
||||||
asml.InsertBefore(hp_new, hp_flagalloc);
|
asml.InsertBefore(hp_new, hp_flagalloc);
|
||||||
if Assigned(hp_prev2) then
|
if Assigned(hp_prev2) then
|
||||||
TrySwapMovOp(hp_prev2, hp_new);
|
TrySwapMovOp(hp_prev2, hp_new);
|
||||||
|
|
||||||
IncludeRegInUsedRegs(ConstRegs[x], TmpUsedRegs);
|
IncludeRegInUsedRegs(ConstRegs[x], TmpUsedRegs);
|
||||||
|
|
||||||
|
ConstMovs[X] := hp_new;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
{ We just need an instruction between hp_prev and hp1
|
{ We just need an instruction between hp_prev and hp1
|
||||||
where we know the register is marked as in use }
|
where we know the register is marked as in use }
|
||||||
hp_new := hpmov1;
|
hp_new := hpmov1;
|
||||||
|
|
||||||
|
{ Keep track of largest write for this register so it can be optimised later }
|
||||||
|
if (getsubreg(taicpu(hp1).oper[1]^.reg) > ConstWriteSizes[getsupreg(ConstRegs[X])]) then
|
||||||
|
ConstWriteSizes[getsupreg(ConstRegs[X])] := getsubreg(taicpu(hp1).oper[1]^.reg);
|
||||||
|
|
||||||
AllocRegBetween(ConstRegs[x], hp_new, hp1, UsedRegs);
|
AllocRegBetween(ConstRegs[x], hp_new, hp1, UsedRegs);
|
||||||
taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), getsubreg(taicpu(hp1).oper[1]^.reg)));
|
taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), ConstSizes[X]));
|
||||||
Break;
|
Break;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -12717,6 +12754,14 @@ unit aoptx86;
|
|||||||
GetNextInstruction(hp1, hp1);
|
GetNextInstruction(hp1, hp1);
|
||||||
until (hp1 = hp_jump); { Stop at the jump, not lbl xxx }
|
until (hp1 = hp_jump); { Stop at the jump, not lbl xxx }
|
||||||
|
|
||||||
|
{ Update initialisation MOVs to the smallest possible size }
|
||||||
|
for x := 0 to c - 1 do
|
||||||
|
if Assigned(ConstMovs[x]) then
|
||||||
|
begin
|
||||||
|
taicpu(ConstMovs[x]).opsize := subreg2opsize[ConstWriteSizes[Word(ConstRegs[x])]];
|
||||||
|
setsubreg(taicpu(ConstMovs[x]).oper[1]^.reg, ConstWriteSizes[Word(ConstRegs[x])]);
|
||||||
|
end;
|
||||||
|
|
||||||
UpdateUsedRegs(tai(hp_jump.next));
|
UpdateUsedRegs(tai(hp_jump.next));
|
||||||
UpdateUsedRegs(tai(hp_lblyyy.next));
|
UpdateUsedRegs(tai(hp_lblyyy.next));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user