mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-16 12:49:17 +02:00
* the optimizer now keeps track of flags register usage. This fixes some
optimizer bugs with int64 calculations (because of the carry flag usage) * fixed another bug which caused wrong optimizations with complex array expressions
This commit is contained in:
parent
2990981dbc
commit
003549eba1
@ -180,104 +180,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function getPrevSequence(p: Tai; reg: tregister; currentPrev: Tai; var newPrev: Tai;
|
||||
var passedJump: boolean; var regsNotRead, regsStillValid: tregset): tregister;
|
||||
|
||||
const
|
||||
current_reg: tregister = R_NO;
|
||||
|
||||
function stillValid(p: Tai): boolean;
|
||||
begin
|
||||
stillValid :=
|
||||
(p.typ = ait_instruction) and
|
||||
(Taicpu(p).opcode <> a_jmp) and
|
||||
(pTaiprop(p.optinfo)^.regs[reg].wstate =
|
||||
pTaiprop(currentPrev.optinfo)^.regs[reg].wstate) and
|
||||
{ in case destroyreg is called with doIncState = false }
|
||||
(pTaiprop(p.optinfo)^.regs[reg].typ =
|
||||
pTaiprop(currentPrev.optinfo)^.regs[reg].typ) and
|
||||
(reg in (regsNotRead * regsStillValid));
|
||||
passedJump :=
|
||||
(p.typ = ait_instruction) and
|
||||
(Taicpu(p).is_jmp);
|
||||
end;
|
||||
|
||||
function findChangedRegister(p: Tai): tregister;
|
||||
var
|
||||
regCounter: tregister;
|
||||
begin
|
||||
for regCounter := succ(current_reg) to R_EDI do
|
||||
with pTaiprop(p.optinfo)^.regs[regCounter] do
|
||||
if ((startmod <>
|
||||
pTaiprop(currentPrev.optinfo)^.regs[regCounter].startmod) or
|
||||
(nrOfMods <>
|
||||
pTaiprop(currentPrev.optinfo)^.regs[regCounter].nrOfMods)) and
|
||||
(pTaiprop(p.optinfo)^.regs[regCounter].typ in
|
||||
[con_ref,con_noRemoveRef]) then
|
||||
begin
|
||||
findChangedRegister := regCounter;
|
||||
current_reg := regCounter;
|
||||
exit;
|
||||
end;
|
||||
current_reg := R_NO;
|
||||
findChangedRegister := R_NO;
|
||||
end;
|
||||
|
||||
var
|
||||
hp, prevFound: Tai;
|
||||
tmpResult, regCounter: tregister;
|
||||
begin
|
||||
if not(current_reg in [R_NO,R_EDI]) then
|
||||
begin
|
||||
tmpResult := findChangedRegister(currentPrev);
|
||||
if tmpResult <> R_NO then
|
||||
begin
|
||||
getPrevSequence := tmpResult;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
getPrevSequence := R_NO;
|
||||
passedJump := passedJump or
|
||||
((currentPrev.typ = ait_instruction) and
|
||||
(Taicpu(currentPrev).is_jmp));
|
||||
|
||||
if (passedJump and not(reg in (usableregs+[R_EDI]))) or
|
||||
not getLastInstruction(currentPrev,hp) then
|
||||
exit;
|
||||
|
||||
prevFound := currentPrev;
|
||||
tmpResult := R_NO;
|
||||
|
||||
while (tmpResult = R_NO) and
|
||||
stillValid(hp) and
|
||||
(pTaiprop(prevFound.optinfo)^.canBeRemoved or
|
||||
not(modifiesConflictingMemLocation(prevFound,reg,
|
||||
pTaiprop(p.optinfo)^.regs,regsStillValid))) do
|
||||
begin
|
||||
{ only update the regsread for the instructions we already passed }
|
||||
if not(pTaiprop(prevFound.optinfo)^.canBeRemoved) then
|
||||
for regCounter := R_EAX to R_EDI do
|
||||
if regReadByInstruction(regCounter,prevFound) then
|
||||
exclude(regsNotRead,regCounter);
|
||||
|
||||
{ in case getPreviousInstruction fails and sets hp to nil in the }
|
||||
{ next iteration }
|
||||
prevFound := hp;
|
||||
if not(pTaiprop(hp.optinfo)^.canBeRemoved) then
|
||||
tmpResult := findChangedRegister(hp);
|
||||
if { do not load the self pointer or a regvar before a (conditional) }
|
||||
{ jump with a new value, since if the jump is taken, the old value }
|
||||
{ is (probably) still necessary }
|
||||
(passedJump and not(reg in (usableregs+[R_EDI]))) or
|
||||
not getLastInstruction(hp,hp) then
|
||||
break;
|
||||
end;
|
||||
getPrevSequence := tmpResult;
|
||||
if tmpResult <> R_NO then
|
||||
newPrev := prevFound;
|
||||
end;
|
||||
|
||||
|
||||
function isSimpleMemLoc(const ref: treference): boolean;
|
||||
begin
|
||||
@ -297,14 +199,114 @@ end;
|
||||
Function CheckSequence(p: Tai; var prev: Tai; Reg: TRegister; Var Found: Longint;
|
||||
Var RegInfo: TRegInfo; findPrevSeqs: boolean): Boolean;
|
||||
|
||||
const
|
||||
checkingPrevSequences: boolean = false;
|
||||
var
|
||||
regsNotRead, regsStillValid: tregset;
|
||||
regsNotRead, regsStillValid : tregset;
|
||||
checkingPrevSequences,
|
||||
passedFlagsModifyingInstr,
|
||||
passedJump : boolean;
|
||||
|
||||
function getPrevSequence(p: Tai; reg: tregister; currentPrev: Tai; var newPrev: Tai): tregister;
|
||||
|
||||
const
|
||||
current_reg: tregister = R_NO;
|
||||
|
||||
function stillValid(p: Tai): boolean;
|
||||
begin
|
||||
stillValid :=
|
||||
(p.typ = ait_instruction) and
|
||||
(Taicpu(p).opcode <> a_jmp) and
|
||||
(pTaiprop(p.optinfo)^.regs[reg].wstate =
|
||||
pTaiprop(currentPrev.optinfo)^.regs[reg].wstate) and
|
||||
{ in case destroyreg is called with doIncState = false }
|
||||
(pTaiprop(p.optinfo)^.regs[reg].typ =
|
||||
pTaiprop(currentPrev.optinfo)^.regs[reg].typ) and
|
||||
(reg in (regsNotRead * regsStillValid));
|
||||
passedJump :=
|
||||
(p.typ = ait_instruction) and
|
||||
(Taicpu(p).is_jmp);
|
||||
passedFlagsModifyingInstr :=
|
||||
instrWritesFlags(currentPrev);
|
||||
end;
|
||||
|
||||
function findChangedRegister(p: Tai): tregister;
|
||||
var
|
||||
regCounter: tregister;
|
||||
begin
|
||||
for regCounter := succ(current_reg) to R_EDI do
|
||||
with pTaiprop(p.optinfo)^.regs[regCounter] do
|
||||
if ((startmod <>
|
||||
pTaiprop(currentPrev.optinfo)^.regs[regCounter].startmod) or
|
||||
(nrOfMods <>
|
||||
pTaiprop(currentPrev.optinfo)^.regs[regCounter].nrOfMods)) and
|
||||
(pTaiprop(p.optinfo)^.regs[regCounter].typ in
|
||||
[con_ref,con_noRemoveRef]) then
|
||||
begin
|
||||
findChangedRegister := regCounter;
|
||||
current_reg := regCounter;
|
||||
exit;
|
||||
end;
|
||||
current_reg := R_NO;
|
||||
findChangedRegister := R_NO;
|
||||
end;
|
||||
|
||||
var
|
||||
hp, prevFound: Tai;
|
||||
tmpResult, regCounter: tregister;
|
||||
begin
|
||||
if not(current_reg in [R_NO,R_EDI]) then
|
||||
begin
|
||||
tmpResult := findChangedRegister(currentPrev);
|
||||
if tmpResult <> R_NO then
|
||||
begin
|
||||
getPrevSequence := tmpResult;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
getPrevSequence := R_NO;
|
||||
passedJump := passedJump or
|
||||
((currentPrev.typ = ait_instruction) and
|
||||
(Taicpu(currentPrev).is_jmp));
|
||||
passedFlagsModifyingInstr := instrWritesFlags(currentPrev);
|
||||
|
||||
if (passedJump and not(reg in (usableregs+[R_EDI]))) or
|
||||
not getLastInstruction(currentPrev,hp) then
|
||||
exit;
|
||||
|
||||
prevFound := currentPrev;
|
||||
tmpResult := R_NO;
|
||||
|
||||
while (tmpResult = R_NO) and
|
||||
stillValid(hp) and
|
||||
(pTaiprop(prevFound.optinfo)^.canBeRemoved or
|
||||
not(modifiesConflictingMemLocation(prevFound,reg,
|
||||
pTaiprop(p.optinfo)^.regs,regsStillValid))) do
|
||||
begin
|
||||
{ only update the regsread for the instructions we already passed }
|
||||
if not(pTaiprop(prevFound.optinfo)^.canBeRemoved) then
|
||||
for regCounter := R_EAX to R_EDI do
|
||||
if regReadByInstruction(regCounter,prevFound) then
|
||||
exclude(regsNotRead,regCounter);
|
||||
|
||||
{ in case getPreviousInstruction fails and sets hp to nil in the }
|
||||
{ next iteration }
|
||||
prevFound := hp;
|
||||
if not(pTaiprop(hp.optinfo)^.canBeRemoved) then
|
||||
tmpResult := findChangedRegister(hp);
|
||||
if { do not load the self pointer or a regvar before a (conditional) }
|
||||
{ jump with a new value, since if the jump is taken, the old value }
|
||||
{ is (probably) still necessary }
|
||||
(passedJump and not(reg in (usableregs+[R_EDI]))) or
|
||||
not getLastInstruction(hp,hp) then
|
||||
break;
|
||||
end;
|
||||
getPrevSequence := tmpResult;
|
||||
if tmpResult <> R_NO then
|
||||
newPrev := prevFound;
|
||||
end;
|
||||
|
||||
|
||||
function getNextRegToTest(var prev: Tai; currentReg: tregister): tregister;
|
||||
const
|
||||
passedJump: boolean = false;
|
||||
begin
|
||||
if not checkingPrevSequences then
|
||||
begin
|
||||
@ -329,7 +331,7 @@ var
|
||||
if checkingPrevSequences then
|
||||
if findPrevSeqs then
|
||||
getNextRegToTest :=
|
||||
getPrevSequence(p,reg,prev,prev,passedJump,regsNotRead,RegsStillValid)
|
||||
getPrevSequence(p,reg,prev,prev)
|
||||
else
|
||||
getNextRegToTest := R_NO;
|
||||
end;
|
||||
@ -341,8 +343,7 @@ Var hp2, hp3{, EndMod},highPrev, orgPrev: Tai;
|
||||
HighFound, OrgRegFound: Byte;
|
||||
RegCounter, regCounter2, tmpreg, base, index: TRegister;
|
||||
OrgRegResult: Boolean;
|
||||
TmpResult: Boolean;
|
||||
{TmpState: Byte;}
|
||||
TmpResult, flagResultsNeeded: Boolean;
|
||||
Begin {CheckSequence}
|
||||
Reg := Reg32(Reg);
|
||||
TmpResult := False;
|
||||
@ -360,6 +361,8 @@ Begin {CheckSequence}
|
||||
end;
|
||||
|
||||
checkingPrevSequences := false;
|
||||
passedFlagsModifyingInstr := false;
|
||||
flagResultsNeeded := false;
|
||||
regsNotRead := [R_EAX,R_EBX,R_ECX,R_EDX,R_ESP,R_EBP,R_EDI,R_ESI];
|
||||
regsStillValid := regsNotRead;
|
||||
GetLastInstruction(p, prev);
|
||||
@ -417,6 +420,10 @@ Begin {CheckSequence}
|
||||
for regCounter2 := R_EAX to R_EDI do
|
||||
regModified[regCounter2] := regModified[regCounter2] or
|
||||
regModifiedByInstruction(regCounter2,hp3);
|
||||
if flagResultsNeeded then
|
||||
flagResultsNeeded := not instrReadsFlags(hp3);
|
||||
if not flagResultsNeeded then
|
||||
flagResultsNeeded := pTaiprop(hp3.optinfo)^.FlagsUsed;
|
||||
GetNextInstruction(hp2, hp2);
|
||||
GetNextInstruction(hp3, hp3);
|
||||
Inc(Found);
|
||||
@ -429,15 +436,18 @@ Begin {CheckSequence}
|
||||
include(regInfo.regsStillUsedAfterSeq,regCounter2);
|
||||
|
||||
if checkingPrevSequences then
|
||||
for regCounter2 := R_EAX to R_EDI do
|
||||
if not(regInfo.new2OldReg[regCounter2] in [R_NO,regCounter2]) and
|
||||
(not(regCounter2 in (regsNotRead * regsStillValid)) or
|
||||
not(regInfo.new2OldReg[regCounter2] in regsStillValid)) then
|
||||
begin
|
||||
begin
|
||||
for regCounter2 := R_EAX to R_EDI do
|
||||
if not(regInfo.new2OldReg[regCounter2] in [R_NO,regCounter2]) and
|
||||
(not(regCounter2 in (regsNotRead * regsStillValid)) or
|
||||
not(regInfo.new2OldReg[regCounter2] in regsStillValid)) then
|
||||
begin
|
||||
found := 0;
|
||||
break;
|
||||
end;
|
||||
if passedFlagsModifyingInstr and flagResultsNeeded then
|
||||
found := 0;
|
||||
break;
|
||||
end;
|
||||
|
||||
end;
|
||||
If (Found <> OldNrOfMods) or
|
||||
{ the following is to avoid problems with rangecheck code (see testcse2) }
|
||||
(assigned(hp3) and
|
||||
@ -1375,6 +1385,7 @@ Begin
|
||||
Cnt2 := 1;
|
||||
While Cnt2 <= Cnt Do
|
||||
Begin
|
||||
(*
|
||||
If not(regInInstruction(Taicpu(hp2).oper[1].reg, p)) and
|
||||
not(pTaiprop(p.optinfo)^.canBeRemoved) then
|
||||
begin
|
||||
@ -1409,8 +1420,9 @@ Begin
|
||||
PTaiProp(p.OptInfo)^.CanBeRemoved := True
|
||||
{$endif noremove}
|
||||
end
|
||||
*)
|
||||
{$ifndef noremove}
|
||||
else
|
||||
(* else *)
|
||||
PTaiProp(p.OptInfo)^.CanBeRemoved := True
|
||||
{$endif noremove}
|
||||
; Inc(Cnt2);
|
||||
@ -1718,7 +1730,13 @@ End.
|
||||
|
||||
{
|
||||
$Log$
|
||||
Revision 1.16 2001-08-26 13:36:55 florian
|
||||
Revision 1.17 2001-08-29 14:07:43 jonas
|
||||
* the optimizer now keeps track of flags register usage. This fixes some
|
||||
optimizer bugs with int64 calculations (because of the carry flag usage)
|
||||
* fixed another bug which caused wrong optimizations with complex
|
||||
array expressions
|
||||
|
||||
Revision 1.16 2001/08/26 13:36:55 florian
|
||||
* some cg reorganisation
|
||||
* some PPC updates
|
||||
|
||||
|
@ -130,6 +130,8 @@ type
|
||||
{$endif tempOpts}
|
||||
{ can this instruction be removed? }
|
||||
CanBeRemoved: Boolean;
|
||||
{ are the resultflags set by this instruction used? }
|
||||
FlagsUsed: Boolean;
|
||||
End;
|
||||
|
||||
PTaiProp = ^TTaiProp;
|
||||
@ -164,6 +166,8 @@ function RegReadByInstruction(reg: TRegister; hp: Tai): boolean;
|
||||
function RegModifiedByInstruction(Reg: TRegister; p1: Tai): Boolean;
|
||||
function RegInInstruction(Reg: TRegister; p1: Tai): Boolean;
|
||||
function RegInOp(Reg: TRegister; const o:toper): Boolean;
|
||||
function instrWritesFlags(p: Tai): boolean;
|
||||
function instrReadsFlags(p: Tai): boolean;
|
||||
|
||||
function writeToMemDestroysContents(regWritten: tregister; const ref: treference;
|
||||
reg: tregister; const c: tcontent): boolean;
|
||||
@ -952,6 +956,46 @@ Begin
|
||||
RegModifiedByInstruction := TmpResult
|
||||
End;
|
||||
|
||||
|
||||
function instrWritesFlags(p: Tai): boolean;
|
||||
var
|
||||
l: longint;
|
||||
begin
|
||||
instrWritesFlags := true;
|
||||
case p.typ of
|
||||
ait_instruction:
|
||||
begin
|
||||
for l := 1 to MaxCh do
|
||||
if InsProp[Taicpu(p).opcode].Ch[l] in [Ch_WFlags,Ch_RWFlags,Ch_All] then
|
||||
exit;
|
||||
end;
|
||||
ait_label:
|
||||
exit;
|
||||
else
|
||||
instrWritesFlags := false;
|
||||
end;
|
||||
end;
|
||||
|
||||
function instrReadsFlags(p: Tai): boolean;
|
||||
var
|
||||
l: longint;
|
||||
begin
|
||||
instrReadsFlags := true;
|
||||
case p.typ of
|
||||
ait_instruction:
|
||||
begin
|
||||
for l := 1 to MaxCh do
|
||||
if InsProp[Taicpu(p).opcode].Ch[l] in [Ch_RFlags,Ch_RWFlags,Ch_All] then
|
||||
exit;
|
||||
end;
|
||||
ait_label:
|
||||
exit;
|
||||
else
|
||||
instrReadsFlags := false;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{********************* GetNext and GetLastInstruction *********************}
|
||||
Function GetNextInstruction(Current: Tai; Var Next: Tai): Boolean;
|
||||
{ skips ait_regalloc, ait_regdealloc and ait_stab* objects and puts the }
|
||||
@ -1877,11 +1921,11 @@ BlockStart, BlockEnd: Tai);
|
||||
contents for the instructions starting with p. Returns the last Tai which has
|
||||
been processed}
|
||||
Var
|
||||
CurProp: PTaiProp;
|
||||
CurProp, LastFlagsChangeProp: PTaiProp;
|
||||
Cnt, InstrCnt : Longint;
|
||||
InstrProp: TInsProp;
|
||||
UsedRegs: TRegSet;
|
||||
p, hp : Tai;
|
||||
prev, p, hp : Tai;
|
||||
TmpRef: TReference;
|
||||
TmpReg: TRegister;
|
||||
{$ifdef AnalyzeLoops}
|
||||
@ -1889,6 +1933,8 @@ Var
|
||||
{$endif AnalyzeLoops}
|
||||
Begin
|
||||
p := BlockStart;
|
||||
LastFlagsChangeProp := nil;
|
||||
prev := nil;
|
||||
UsedRegs := [];
|
||||
UpdateUsedregs(UsedRegs, p);
|
||||
SkipHead(P);
|
||||
@ -1898,16 +1944,16 @@ Begin
|
||||
While (P <> BlockEnd) Do
|
||||
Begin
|
||||
CurProp := @TaiPropBlock^[InstrCnt];
|
||||
If (p <> BlockStart)
|
||||
If assigned(prev)
|
||||
Then
|
||||
Begin
|
||||
{$ifdef JumpAnal}
|
||||
If (p.Typ <> ait_label) Then
|
||||
{$endif JumpAnal}
|
||||
Begin
|
||||
GetLastInstruction(p, hp);
|
||||
CurProp^.regs := PTaiProp(hp.OptInfo)^.Regs;
|
||||
CurProp^.DirFlag := PTaiProp(hp.OptInfo)^.DirFlag;
|
||||
CurProp^.regs := PTaiProp(prev.OptInfo)^.Regs;
|
||||
CurProp^.DirFlag := PTaiProp(prev.OptInfo)^.DirFlag;
|
||||
CurProp^.FlagsUsed := false;
|
||||
End
|
||||
End
|
||||
Else
|
||||
@ -2332,7 +2378,18 @@ Begin
|
||||
tmpRef.index := R_EDI;
|
||||
DestroyRefs(p, TmpRef, R_NO)
|
||||
End;
|
||||
Ch_RFlags, Ch_WFlags, Ch_RWFlags, Ch_FPU:
|
||||
Ch_RFlags:
|
||||
if assigned(LastFlagsChangeProp) then
|
||||
LastFlagsChangeProp^.FlagsUsed := true;
|
||||
Ch_WFlags:
|
||||
LastFlagsChangeProp := CurProp;
|
||||
Ch_RWFlags:
|
||||
begin
|
||||
if assigned(LastFlagsChangeProp) then
|
||||
LastFlagsChangeProp^.FlagsUsed := true;
|
||||
LastFlagsChangeProp := CurProp;
|
||||
end;
|
||||
Ch_FPU:;
|
||||
Else
|
||||
Begin
|
||||
{$ifdef statedebug}
|
||||
@ -2341,6 +2398,7 @@ Begin
|
||||
insertllitem(asml,p, p.next,hp);
|
||||
{$endif statedebug}
|
||||
DestroyAllRegs(CurProp);
|
||||
LastFlagsChangeProp := CurProp;
|
||||
End;
|
||||
End;
|
||||
Inc(Cnt);
|
||||
@ -2360,6 +2418,7 @@ Begin
|
||||
End;
|
||||
End;
|
||||
Inc(InstrCnt);
|
||||
prev := p;
|
||||
GetNextInstruction(p, p);
|
||||
End;
|
||||
End;
|
||||
@ -2413,6 +2472,7 @@ Begin
|
||||
Begin
|
||||
InitDFAPass2 := True;
|
||||
GetMem(TaiPropBlock, NrOfTaiObjs*SizeOf(TTaiProp));
|
||||
fillchar(TaiPropBlock^,NrOfTaiObjs*SizeOf(TTaiProp),0);
|
||||
p := BlockStart;
|
||||
SkipHead(p);
|
||||
For Count := 1 To NrOfTaiObjs Do
|
||||
@ -2452,7 +2512,13 @@ End.
|
||||
|
||||
{
|
||||
$Log$
|
||||
Revision 1.19 2001-08-26 13:36:55 florian
|
||||
Revision 1.20 2001-08-29 14:07:43 jonas
|
||||
* the optimizer now keeps track of flags register usage. This fixes some
|
||||
optimizer bugs with int64 calculations (because of the carry flag usage)
|
||||
* fixed another bug which caused wrong optimizations with complex
|
||||
array expressions
|
||||
|
||||
Revision 1.19 2001/08/26 13:36:55 florian
|
||||
* some cg reorganisation
|
||||
* some PPC updates
|
||||
|
||||
|
@ -51,7 +51,8 @@ begin
|
||||
canBeFirstSwitch :=
|
||||
(p.ops >= 2) and
|
||||
(reg32(p.oper[p.ops-1].reg) = reg) and
|
||||
(p.oper[0].typ <> top_ref);
|
||||
(p.oper[0].typ <> top_ref) and
|
||||
(not pTaiprop(p.optinfo)^.FlagsUsed);
|
||||
A_INC,A_DEC,A_SUB,A_ADD:
|
||||
canBeFirstSwitch :=
|
||||
(p.oper[1].typ = top_reg) and
|
||||
@ -59,14 +60,16 @@ begin
|
||||
(reg32(p.oper[1].reg) = reg) and
|
||||
(p.oper[0].typ <> top_ref) and
|
||||
((p.opcode <> A_SUB) or
|
||||
(p.oper[0].typ = top_const));
|
||||
(p.oper[0].typ = top_const)) and
|
||||
(not pTaiprop(p.optinfo)^.FlagsUsed);
|
||||
A_SHL:
|
||||
canBeFirstSwitch :=
|
||||
(p.opsize = S_L) and
|
||||
(p.oper[1].typ = top_reg) and
|
||||
(p.oper[1].reg = reg) and
|
||||
(p.oper[0].typ = top_const) and
|
||||
(p.oper[0].val in [1,2,3]);
|
||||
(p.oper[0].val in [1,2,3]) and
|
||||
(not pTaiprop(p.optinfo)^.FlagsUsed);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -335,7 +338,13 @@ End.
|
||||
|
||||
{
|
||||
$Log$
|
||||
Revision 1.6 2001-01-06 23:35:06 jonas
|
||||
Revision 1.7 2001-08-29 14:07:43 jonas
|
||||
* the optimizer now keeps track of flags register usage. This fixes some
|
||||
optimizer bugs with int64 calculations (because of the carry flag usage)
|
||||
* fixed another bug which caused wrong optimizations with complex
|
||||
array expressions
|
||||
|
||||
Revision 1.6 2001/01/06 23:35:06 jonas
|
||||
* fixed webbug 1323
|
||||
|
||||
Revision 1.5 2000/12/25 00:07:34 peter
|
||||
|
Loading…
Reference in New Issue
Block a user