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;