Press enter to see results or esc to cancel.

Generating Code

This procedure generates target (x86) code from intermediate code instructions. This is the last phase in program block compilation. If debug info is enabled, source line code offsets will be saved into dedicated table, redundant loadings of addresses to ES:DI register pair will be removed and near jumps will be converted to short jumps where possible. The latest optimization of jump instructions will be performed in a loop since each optimization reduces code size and provides opportunity for further jump optimizations. After the optimizations are finished the code size and instruction offsets are already calculated.

Procedure GenerateCode;
Var Block9Record: PStatementCodeSizesBlockRecord;
    ProcedureIdentifierData: PProcedureIdentifierData;
    LocalDebugProcedureIdentifier: Word;
    StatementCodeSize: Word;
    N, Dif: Integer;
    CodePointer: Pointer;
    CodePointerRec: PtrRec absolute CodePointer;
    IntermediateCodePointer: PIntermediateCodeRecord;
    IntermediateCodePointerRec: PtrRec absolute IntermediateCodePointer;
    LabelIdentifier: PIdentifier;
    LabelIdentifierData: PLabelIdentifierData absolute LabelIdentifier;
    LabelIdentifierDataRec: PtrRec absolute LabelIdentifierData;
    ErrorString: PString;
begin
  If DebugInformation in ModuleCompilerSwitches then
    With PIntermediateCodeRecord (IncreaseSymbolTable (stIntermediateCode, 3))^ do
      begin
        RecordType := icSourceLineNumber;
        StatementLineNumber := LastProgramBlockSourceLineNumber + 1;
      end;
  With PIntermediateCodeRecord (IncreaseSymbolTable (stIntermediateCode, 1))^ do RecordType := icEnd;
  RemoveRedundant_ES_DI_AddressLoading;
  Repeat
    CalculateCodeSizeAndOffsets;
  until not ConvertNearJumpsToShort;
  If DebugInformation in ModuleCompilerSwitches then
    begin
      ProcedureIdentifierData := Ptr (SymbolTable [stMain].Segment, ProcedureIdentifierDataOffset);
      Block9Record := IncreaseSymbolTable (stSourceLineCodeOffsets,
                        2 * (LastProgramBlockSourceLineNumber - FirstProgramBlocktSourceLineNumber) + 14);
      If (LocalDebugSymbols in ModuleCompilerSwitches) then
        begin
          If not (pfAssembler in ProcedureIdentifierData^.Flags ) or
            (PushedParametersSize or ProgramBlockMaxStackFrameOffset <> 0) then
              LocalDebugProcedureIdentifier := CurrentProcedureIdentifier else LocalDebugProcedureIdentifier := 0;
        end else LocalDebugProcedureIdentifier := 0;
      With Block9Record^ do
        begin
          ProcedureIdentifier := LocalDebugProcedureIdentifier;
          SourceFileRecordOffset := CurrentSourceFile^.FileRecordOffset;
          ProcedureStartLine := ProcedureStartLineNumber;
          StatementStartCodeOffset := SymbolTable [stCode].UsedSize;
          SizeOfConstantsInCode := SymbolTable [stCode].UsedSize - LastProgramBlockCodeSize;
          FirstSourceLineNumber := FirstProgramBlocktSourceLineNumber;
          NumberOfSourceLines := LastProgramBlockSourceLineNumber - FirstProgramBlocktSourceLineNumber + 1;
          SymbolTable [stSourceLineCodeOffsets].UsedSize := Ofs (StatementsCodeSizeData);
        end;
      StatementFirstSourceLineNumber := FirstProgramBlocktSourceLineNumber;
    end;
  SymbolTable [stCodeReferences].UsedSize := Ofs (IncreaseSymbolTable (stCodeReferences, SizeOfCodeReferenceRecords)^);
  CodePointer := IncreaseSymbolTable (stCode, SizeOfGeneratedCode);
  IntermediateCodePointer := Ptr (SymbolTable [stIntermediateCode].Segment, LastIntermediateCodeSubroutine);
  Repeat
    Case IntermediateCodePointer^.RecordType of
      icGoSub: begin
                 Asm
                   MOV    AX, WORD PTR IntermediateCodePointer
                   ADD    AX, 3
                   PUSH   AX
                 end;
                 IntermediateCodePointerRec.Ofs := IntermediateCodePointer^.NewOffset;
               end;
      icReturn: Asm
                  POP    WORD PTR IntermediateCodePointer
                end;
      icByte: begin
              Byte (CodePointer^) := IntermediateCodePointer^.ByteCode;
              Inc (CodePointerRec.Ofs);
              Inc (IntermediateCodePointerRec.Ofs, 2);
            end;
      icWord: begin
              Word (CodePointer^) := IntermediateCodePointer^.WordCode.Word;
              Inc (CodePointerRec.Ofs, 2);
              Inc (IntermediateCodePointerRec.Ofs, 3);
            end;
      icJumpNear: With IntermediateCodePointer^ do
                    begin
                      If JumpOpCode <> JMP_ShortDirect then
                        begin
                          If JumpOpCode >= JMP_ConditionalShortLimit then Error (CodeGenerationError);
                          Byte (CodePointer^) := JumpOpCode xor $01;          { Invert condition }
                          Inc (CodePointerRec.Ofs);
                          Byte (CodePointer^) := 3;                           { Size of next near jump }
                          Inc (CodePointerRec.Ofs);
                        end;
                      Byte (CodePointer^) := JMP_NearDirect;
                      Inc (CodePointerRec.Ofs);
                      Word (CodePointer^) :=
                        PIntermediateCodeRecord (Ptr (SymbolTable [stIntermediateCode].Segment, LabelRecordOffset - 1))^
                        .LabelAddress - CodePointerRec.Ofs - 2;
                      Inc (CodePointerRec.Ofs, 2);
                      Inc (IntermediateCodePointerRec.Ofs, 8);
                    end;
      icJumpShort: With IntermediateCodePointer^ do
                     begin
                       Byte (CodePointer^) := JumpOpCode;
                       Inc (CodePointerRec.Ofs);
                       Byte (CodePointer^) :=
                         PIntermediateCodeRecord (Ptr (SymbolTable [stIntermediateCode].Segment, LabelRecordOffset - 1))^.
                           LabelAddress - CodePointerRec.Ofs - 1;
                       Inc (CodePointerRec.Ofs);
                       Inc (IntermediateCodePointerRec.Ofs, 8);
                     end;
      icLabel,
      icSkippedGoSubSaveAddress: Inc (IntermediateCodePointerRec.Ofs, 3);
      icReference: With IntermediateCodePointer^ do
                     begin
                       With PReferencesBlockRecord (SymbolTable [stCodeReferences].Ptr)^ do
                         begin
                           ReferencedUnitRecord :=        ReferencedUnitRecordOfs;
                           ReferencedBlockRecordOffset := ReferencedBlockRecordOfs;
                           ReferencedOffset :=            ReferencedOfs;
                           PositionOfReference :=         CodePointerRec.Ofs - LastProgramBlockCodeSize;
                         end;
                       Inc (SymbolTable [stCodeReferences].UsedSize, SizeOf (TReferencesBlockRecord));
                       Word (CodePointer^) := 0;
                       Inc (CodePointerRec.Ofs, 2);
                       If Flags * [rfSegment, rfOffset] = [rfSegment, rfOffset] then
                         begin
                           Word (CodePointer^) := 0;
                           Inc (CodePointerRec.Ofs, 2);
                         end;
                       Inc (IntermediateCodePointerRec.Ofs, 7);
                     end;
      icReferenceAsmBlock: With IntermediateCodePointer^ do
                             begin
                               LabelIdentifier := Ptr (SymbolTable [stMain].Segment, LabelIdentifierOfs);
                               LabelIdentifierDataRec.Seg := SymbolTable [stMain].Segment;
                               ErrorString := @LabelIdentifier^.Name.Str;
                               Inc (LabelIdentifierDataRec.Ofs, LabelIdentifier^.Name.Len + 4);
                               If LabelIdentifierData^.LabelRecordOffset = 0 then
                                 IdentifierError (ErrorString^, UndefinedLabelInPrecedingStatementPart);
                               With PReferencesBlockRecord (SymbolTable [stCodeReferences].Ptr)^ do
                                 begin
                                   ReferencedUnitRecord := ReferencedUnitRecordOfs;
                                   ReferencedBlockRecordOffset := SymbolTable [stCodeBlocks].NextRecordOffset;
                                   ReferencedOffset :=
                                     W5_10 + PIntermediateCodeRecord (Ptr (SymbolTable [stIntermediateCode].Segment,
                                     LabelIdentifierData^.LabelRecordOffset - 1))^.LabelAddress -
                                       LastProgramBlockCodeSize;
                                   PositionOfReference := CodePointerRec.Ofs - LastProgramBlockCodeSize;
                                 end;
                               Inc (SymbolTable [stCodeReferences].UsedSize, SizeOf (TReferencesBlockRecord));
                               Word (CodePointer^) := 0;
                               Inc (CodePointerRec.Ofs, 2);
                               If Flags * [rfSegment, rfOffset] = [rfSegment, rfOffset] then
                                 begin
                                   Word (CodePointer^) := 0;
                                   Inc (CodePointerRec.Ofs, 2);
                                 end;
                               Inc (IntermediateCodePointerRec.Ofs, 7);
                             end;
      ic12,
      icSourceLineNumber: With IntermediateCodePointer^ do
                            begin
                              Dif := StatementLineNumber - StatementFirstSourceLineNumber;
                              If Dif > 0 then
                                begin
                                  StatementFirstSourceLineNumber := StatementLineNumber;          { Next statement }
                                  StatementCodeSize := CodePointerRec.Ofs - StatementStartCodeOffset;
                                  StatementStartCodeOffset := CodePointerRec.Ofs;
                                  If StatementCodeSize >= 128 then
                                    begin
                                      Byte (SymbolTable [stSourceLineCodeOffsets].Ptr^) := Hi (StatementCodeSize) or $80;
                                      Inc (SymbolTable [stSourceLineCodeOffsets].UsedSize);
                                    end;
                                  Byte (SymbolTable [stSourceLineCodeOffsets].Ptr^) := Lo (StatementCodeSize);
                                  Inc (SymbolTable [stSourceLineCodeOffsets].UsedSize);
                                  For N := 1 to Dif - 1 do
                                    begin
                                      Byte (SymbolTable [stSourceLineCodeOffsets].Ptr^) := 0;
                                      Inc (SymbolTable [stSourceLineCodeOffsets].UsedSize);
                                    end;
                                end;
                              Inc (IntermediateCodePointerRec.Ofs, 3);
                            end;
      icLoad_ES_DI: begin
                       With IntermediateCodePointer^ do
                         GenerateCode_LES_DI_WithVariableAddress (Displacement, DestinationProcedure);
                       Inc (IntermediateCodePointerRec.Ofs, 7);
                     end;
      ic_ES_DI_Loaded: Inc (IntermediateCodePointerRec.Ofs, 7);
      ic_ES_DI_Destroyed: Inc (IntermediateCodePointerRec.Ofs);
      icEnd: Break;
      {$IFDEF DEBUG}
      else begin
             Writeln;
             Writeln ('Error: ic Error');
             Halt ($FF);
           end;
      {$ENDIF}
    end;
  until False;
end;