Changeset 64 for trunk/UTarget.pas


Ignore:
Timestamp:
Dec 4, 2014, 2:59:28 PM (10 years ago)
Author:
chronos
Message:
  • Modified: Now commands cmInc, cmDec, cmPointerInc, cmPointerDec and cmSet use numeric parameter to merge multiple small steps to one unary operation with numeric parameter. Optimization is done on TTarget side and not on each specific targets.
  • Added: Optimization to eliminate redundant source code.
  • Added: Optimization level option in Options dialog.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/UTarget.pas

    r63 r64  
    6666  end;
    6767
    68   TBrainFuckCommand = (cmNoOperation, cmInc, cmDec, cmPointerInc, cmPointerDec,
    69     cmOutput, cmInput, cmLoopStart, cmLoopEnd, cmDebug);
     68  TMachineCommand = (cmNoOperation, cmInc, cmDec, cmPointerInc, cmPointerDec,
     69    cmOutput, cmInput, cmLoopStart, cmLoopEnd, cmDebug, cmSet);
     70
     71  TMachineOperation = record
     72    Command: TMachineCommand;
     73    Parameter: Integer;
     74  end;
    7075
    7176  TLogEvent = procedure (Lines: TStrings) of object;
     
    8085    function SourceReadNext: Char;
    8186    function CheckClear: Boolean;
    82     function CheckOccurence(C: TBrainFuckCommand): Integer;
     87    function CheckOccurenceSumParam(C: TMachineCommand): Integer;
     88    function CheckOccurence(C: TMachineCommand): Integer;
     89    procedure OptimizeAddSub;
     90    procedure OptimizeMerge;
     91    procedure OptimizeZeroInitMemory;
    8392  protected
    8493    FSourceCode: string;
    85     FProgram: array of TBrainFuckCommand;
     94    FProgram: array of TMachineOperation;
    8695    FProgramIndex: Integer;
    8796    FTargetCode: string;
     
    101110    ProgramName: string;
    102111    ImageIndex: Integer;
    103     Optimization: TCompilerOptimization;
     112    OptimizationLevel: TCompilerOptimization;
    104113    CompilerPath: string;
    105114    ExecutorPath: string;
     
    367376begin
    368377  inherited;
    369   Optimization := coNormal;
     378  OptimizationLevel := coNormal;
    370379  BreakPoints := TBreakPointList.Create;
    371380  DebugSteps := TDebugStepList.Create;
     
    387396
    388397procedure TTarget.OptimizeSource;
    389 begin
    390   // Remove redundand code
    391 
     398var
     399  OldLength: Integer;
     400begin
     401  OptimizeAddSub;
     402  repeat
     403    OldLength := Length(FProgram);
     404    OptimizeMerge;
     405  until Length(FProgram) = OldLength;
     406  OptimizeZeroInitMemory;
    392407end;
    393408
     
    395410begin
    396411  LoadProgram;
     412  if OptimizationLevel = coNormal then OptimizeSource;
    397413  Compiled := True;
    398414end;
     
    528544end;
    529545
    530 function TTarget.CheckOccurence(C: TBrainFuckCommand): Integer;
     546function TTarget.CheckOccurence(C: TMachineCommand): Integer;
    531547begin
    532548  Result := 1;
    533   if Optimization = coNormal then
    534   while ((FProgramIndex + 1) < Length(FProgram)) and (FProgram[FProgramIndex + 1] = C) do begin
     549  while ((FProgramIndex + 1) < Length(FProgram)) and (FProgram[FProgramIndex + 1].Command = C) do begin
    535550    Inc(Result);
    536551    Inc(FProgramIndex);
    537552  end;
     553end;
     554
     555function TTarget.CheckOccurenceSumParam(C: TMachineCommand): Integer;
     556begin
     557  Result := FProgram[FProgramIndex].Parameter;
     558  while ((FProgramIndex + 1) < Length(FProgram)) and (FProgram[FProgramIndex + 1].Command = C) do begin
     559    Inc(Result, FProgram[FProgramIndex + 1].Parameter);
     560    Inc(FProgramIndex);
     561  end;
     562end;
     563
     564procedure TTarget.OptimizeAddSub;
     565var
     566  NewProgram: array of TMachineOperation;
     567  NewProgramIndex: Integer;
     568begin
     569  NewProgramIndex := 0;
     570  SetLength(NewProgram, Length(FProgram));
     571
     572  FProgramIndex := 0;
     573  while (FProgramIndex < Length(FProgram)) do begin
     574    case FProgram[FProgramIndex].Command of
     575      cmPointerInc: begin
     576        NewProgram[NewProgramIndex].Command := cmPointerInc;
     577        NewProgram[NewProgramIndex].Parameter := CheckOccurenceSumParam(cmPointerInc);
     578      end;
     579      cmPointerDec: begin
     580        NewProgram[NewProgramIndex].Command := cmPointerDec;
     581        NewProgram[NewProgramIndex].Parameter := CheckOccurenceSumParam(cmPointerDec);
     582      end;
     583      cmInc: begin
     584        NewProgram[NewProgramIndex].Command := cmInc;
     585        NewProgram[NewProgramIndex].Parameter := CheckOccurenceSumParam(cmInc);
     586      end;
     587      cmDec: begin
     588        NewProgram[NewProgramIndex].Command := cmDec;
     589        NewProgram[NewProgramIndex].Parameter := CheckOccurenceSumParam(cmDec);
     590      end;
     591      else begin
     592        NewProgram[NewProgramIndex].Command := FProgram[FProgramIndex].Command;
     593        NewProgram[NewProgramIndex].Parameter := FProgram[FProgramIndex].Parameter;
     594      end;
     595    end;
     596    Inc(FProgramIndex);
     597    Inc(NewProgramIndex);
     598  end;
     599  SetLength(NewProgram, NewProgramIndex);
     600
     601  // Replace old program by new program
     602  SetLength(FProgram, Length(NewProgram));
     603  Move(NewProgram[0], FProgram[0], SizeOf(TMachineOperation) * Length(NewProgram));
     604end;
     605
     606procedure TTarget.OptimizeMerge;
     607var
     608  NewProgram: array of TMachineOperation;
     609  NewProgramIndex: Integer;
     610  PreviousCommand: TMachineCommand;
     611begin
     612  // Merge together cmInc, cmDec, cmSet
     613  // Merge together cmPointerInc, cmPointerDec
     614  PreviousCommand := cmNoOperation;
     615  NewProgramIndex := 0;
     616  SetLength(NewProgram, Length(FProgram));
     617
     618  FProgramIndex := 0;
     619  while (FProgramIndex < Length(FProgram)) do begin
     620    case FProgram[FProgramIndex].Command of
     621      cmPointerInc: begin
     622        if PreviousCommand in [cmPointerInc, cmPointerDec] then begin
     623          if NewProgram[NewProgramIndex - 1].Command = cmPointerInc then
     624            NewProgram[NewProgramIndex - 1].Parameter := NewProgram[NewProgramIndex - 1].Parameter +
     625              FProgram[FProgramIndex].Parameter
     626          else if NewProgram[NewProgramIndex - 1].Command = cmPointerDec then
     627            NewProgram[NewProgramIndex - 1].Parameter := NewProgram[NewProgramIndex - 1].Parameter -
     628              FProgram[FProgramIndex].Parameter;
     629          // If value negative then change command
     630          if NewProgram[NewProgramIndex - 1].Parameter < 0 then begin
     631            NewProgram[NewProgramIndex - 1].Parameter := -NewProgram[NewProgramIndex - 1].Parameter;
     632            if NewProgram[NewProgramIndex - 1].Command = cmPointerInc then
     633              NewProgram[NewProgramIndex - 1].Command := cmPointerDec
     634              else NewProgram[NewProgramIndex - 1].Command := cmPointerInc;
     635          end;
     636          if NewProgram[NewProgramIndex - 1].Parameter = 0 then Dec(NewProgramIndex);
     637          Dec(NewProgramIndex);
     638        end else begin
     639          NewProgram[NewProgramIndex].Command := cmPointerInc;
     640          NewProgram[NewProgramIndex].Parameter := FProgram[FProgramIndex].Parameter;
     641        end;
     642      end;
     643      cmPointerDec: begin
     644        if PreviousCommand in [cmPointerInc, cmPointerDec] then begin
     645          if NewProgram[NewProgramIndex - 1].Command = cmPointerDec then
     646            NewProgram[NewProgramIndex - 1].Parameter := NewProgram[NewProgramIndex - 1].Parameter +
     647              FProgram[FProgramIndex].Parameter
     648          else if NewProgram[NewProgramIndex - 1].Command = cmPointerInc then
     649            NewProgram[NewProgramIndex - 1].Parameter := NewProgram[NewProgramIndex - 1].Parameter -
     650              FProgram[FProgramIndex].Parameter;
     651          // If value negative then change command
     652          if NewProgram[NewProgramIndex - 1].Parameter < 0 then begin
     653            NewProgram[NewProgramIndex - 1].Parameter := -NewProgram[NewProgramIndex - 1].Parameter;
     654            if NewProgram[NewProgramIndex - 1].Command = cmPointerInc then
     655              NewProgram[NewProgramIndex - 1].Command := cmPointerDec
     656              else NewProgram[NewProgramIndex - 1].Command := cmPointerInc;
     657          end;
     658          if NewProgram[NewProgramIndex - 1].Parameter = 0 then Dec(NewProgramIndex);
     659          Dec(NewProgramIndex);
     660        end else begin
     661          NewProgram[NewProgramIndex].Command := cmPointerDec;
     662          NewProgram[NewProgramIndex].Parameter := FProgram[FProgramIndex].Parameter;
     663        end;
     664      end;
     665      cmInc: begin
     666        if PreviousCommand in [cmInc, cmDec, cmSet] then begin
     667          if NewProgram[NewProgramIndex - 1].Command in [cmInc, cmSet] then
     668            NewProgram[NewProgramIndex - 1].Parameter := NewProgram[NewProgramIndex - 1].Parameter +
     669              FProgram[FProgramIndex].Parameter
     670          else if NewProgram[NewProgramIndex - 1].Command = cmDec then
     671            NewProgram[NewProgramIndex - 1].Parameter := NewProgram[NewProgramIndex - 1].Parameter -
     672              FProgram[FProgramIndex].Parameter;
     673          // If value negative then change command
     674          if (NewProgram[NewProgramIndex - 1].Parameter < 0) and (NewProgram[NewProgramIndex - 1].Command <> cmSet) then begin
     675            NewProgram[NewProgramIndex - 1].Parameter := -NewProgram[NewProgramIndex - 1].Parameter;
     676            if NewProgram[NewProgramIndex - 1].Command = cmInc then
     677              NewProgram[NewProgramIndex - 1].Command := cmDec
     678              else NewProgram[NewProgramIndex - 1].Command := cmInc;
     679          end;
     680          if NewProgram[NewProgramIndex - 1].Parameter = 0 then Dec(NewProgramIndex);
     681          Dec(NewProgramIndex);
     682        end else begin
     683          NewProgram[NewProgramIndex].Command := cmInc;
     684          NewProgram[NewProgramIndex].Parameter := FProgram[FProgramIndex].Parameter;
     685        end;
     686      end;
     687      cmDec: begin
     688        if PreviousCommand in [cmInc, cmDec, cmSet] then begin
     689          if NewProgram[NewProgramIndex - 1].Command = cmDec then
     690            NewProgram[NewProgramIndex - 1].Parameter := NewProgram[NewProgramIndex - 1].Parameter +
     691              FProgram[FProgramIndex].Parameter
     692          else if NewProgram[NewProgramIndex - 1].Command in [cmInc, cmSet] then
     693            NewProgram[NewProgramIndex - 1].Parameter := NewProgram[NewProgramIndex - 1].Parameter -
     694              FProgram[FProgramIndex].Parameter;
     695          // If value negative then change command
     696          if (NewProgram[NewProgramIndex - 1].Parameter < 0) and (NewProgram[NewProgramIndex - 1].Command <> cmSet) then begin
     697            NewProgram[NewProgramIndex - 1].Parameter := -NewProgram[NewProgramIndex - 1].Parameter;
     698            if NewProgram[NewProgramIndex - 1].Command = cmInc then
     699              NewProgram[NewProgramIndex - 1].Command := cmDec
     700              else NewProgram[NewProgramIndex - 1].Command := cmInc;
     701          end;
     702          if NewProgram[NewProgramIndex - 1].Parameter = 0 then Dec(NewProgramIndex);
     703          Dec(NewProgramIndex);
     704        end else begin
     705          NewProgram[NewProgramIndex].Command := cmDec;
     706          NewProgram[NewProgramIndex].Parameter := FProgram[FProgramIndex].Parameter;
     707        end;
     708      end;
     709      cmSet: begin
     710        if PreviousCommand in [cmInc, cmDec, cmSet] then begin
     711          // Set overrides value of previous commands
     712          Dec(NewProgramIndex);
     713          NewProgram[NewProgramIndex].Command := cmSet;
     714          NewProgram[NewProgramIndex].Parameter := FProgram[FProgramIndex].Parameter;
     715        end else begin
     716          NewProgram[NewProgramIndex].Command := cmSet;
     717          NewProgram[NewProgramIndex].Parameter := FProgram[FProgramIndex].Parameter;
     718        end;
     719      end;
     720      cmLoopStart: begin
     721        if CheckClear then begin
     722          NewProgram[NewProgramIndex].Command := cmSet;
     723          NewProgram[NewProgramIndex].Parameter := 0;
     724          Inc(FProgramIndex, 2);
     725        end else begin
     726          NewProgram[NewProgramIndex].Command := FProgram[FProgramIndex].Command;
     727          NewProgram[NewProgramIndex].Parameter := FProgram[FProgramIndex].Parameter;
     728        end;
     729      end;
     730      else begin
     731        NewProgram[NewProgramIndex].Command := FProgram[FProgramIndex].Command;
     732        NewProgram[NewProgramIndex].Parameter := FProgram[FProgramIndex].Parameter;
     733      end;
     734    end;
     735    PreviousCommand := FProgram[FProgramIndex].Command;
     736    Inc(FProgramIndex);
     737    Inc(NewProgramIndex);
     738  end;
     739  SetLength(NewProgram, NewProgramIndex);
     740
     741  // Replace old program by new program
     742  SetLength(FProgram, Length(NewProgram));
     743  Move(NewProgram[0], FProgram[0], SizeOf(TMachineOperation) * Length(NewProgram));
     744end;
     745
     746procedure TTarget.OptimizeZeroInitMemory;
     747begin
     748  // Here optimization related to assumption that initial memory is filled with zeroes
     749  // Then code for constants preparation can be translated to cmSet commands
     750  // To eliminate also loops for building constants code need to be somehow interpretted partialy
    538751end;
    539752
     
    549762    case FSourceCode[I] of
    550763      '+': begin
    551         FProgram[FProgramIndex] := cmInc;
     764        FProgram[FProgramIndex].Command := cmInc;
     765        FProgram[FProgramIndex].Parameter := 1;
    552766        DebugSteps.AddStep(I - 1, FProgramIndex, soNormal);
    553767      end;
    554768      '-': begin
    555         FProgram[FProgramIndex] := cmDec;
     769        FProgram[FProgramIndex].Command := cmDec;
     770        FProgram[FProgramIndex].Parameter := 1;
    556771        DebugSteps.AddStep(I - 1, FProgramIndex, soNormal);
    557772      end;
    558773      '>': begin
    559         FProgram[FProgramIndex] := cmPointerInc;
     774        FProgram[FProgramIndex].Command := cmPointerInc;
     775        FProgram[FProgramIndex].Parameter := 1;
    560776        DebugSteps.AddStep(I - 1, FProgramIndex, soNormal);
    561777      end;
    562778      '<': begin
    563         FProgram[FProgramIndex] := cmPointerDec;
     779        FProgram[FProgramIndex].Command := cmPointerDec;
     780        FProgram[FProgramIndex].Parameter := 1;
    564781        DebugSteps.AddStep(I - 1, FProgramIndex, soNormal);
    565782      end;
    566783      ',': begin
    567         FProgram[FProgramIndex] := cmInput;
     784        FProgram[FProgramIndex].Command := cmInput;
     785        FProgram[FProgramIndex].Parameter := 0;
    568786        DebugSteps.AddStep(I - 1, FProgramIndex, soNormal);
    569787      end;
    570788      '.': begin
    571         FProgram[FProgramIndex] := cmOutput;
     789        FProgram[FProgramIndex].Command := cmOutput;
     790        FProgram[FProgramIndex].Parameter := 0;
    572791        DebugSteps.AddStep(I - 1, FProgramIndex, soNormal);
    573792      end;
    574793      '[': begin
    575         FProgram[FProgramIndex] := cmLoopStart;
     794        FProgram[FProgramIndex].Command := cmLoopStart;
     795        FProgram[FProgramIndex].Parameter := 0;
    576796        DebugSteps.AddStep(I - 1, FProgramIndex, soStepIn);
    577797      end;
    578798      ']': begin
    579         FProgram[FProgramIndex] := cmLoopEnd;
     799        FProgram[FProgramIndex].Command := cmLoopEnd;
     800        FProgram[FProgramIndex].Parameter := 0;
    580801        DebugSteps.AddStep(I - 1, FProgramIndex, soStepOut);
    581802      end
     
    594815function TTarget.CheckClear: Boolean;
    595816begin
    596   Result := (FProgram[FProgramIndex] = cmLoopStart) and (Length(FProgram) >= FProgramIndex + 2) and
    597     (FProgram[FProgramIndex + 1] = cmDec) and (FProgram[FProgramIndex + 2] = cmLoopEnd);
     817  Result := (FProgram[FProgramIndex].Command = cmLoopStart) and (Length(FProgram) >= FProgramIndex + 2) and
     818    (((FProgram[FProgramIndex + 1].Command = cmDec) and (FProgram[FProgramIndex + 1].Parameter = 1)) or
     819    ((FProgram[FProgramIndex + 1].Command = cmInc) and (FProgram[FProgramIndex + 1].Parameter = -1)))
     820    and (FProgram[FProgramIndex + 2].Command = cmLoopEnd);
    598821end;
    599822
Note: See TracChangeset for help on using the changeset viewer.