Integer Operations
Many operations in Turbo Pascal can be calculated as integer operations. This applies to pointers, Boolean values, enumerated values and Char
values. Constant integer operations are checked for possible overflow.
Procedure ConstantIntegerOperations;
Var Overflow: Boolean;
Result: LongInt;
BoolResult: LongBool absolute Result;
begin
If Operation < Calc_IsEqual then
begin
Overflow := False;
Case Operation of
Calc_Add: Result := LeftExpression.Value.Longint + RightExpression.Value.Longint;
Calc_Subtract: Result := LeftExpression.Value.Longint - RightExpression.Value.Longint;
Calc_Multiply: Result := LeftExpression.Value.Longint * RightExpression.Value.Longint;
Calc_DIV: begin
If RightExpression.Value.Longint = 0 then Error (DivisionByZero);
Result := LeftExpression.Value.Longint div RightExpression.Value.Longint;
end;
Calc_MOD: begin
If RightExpression.Value.Longint = 0 then Error (DivisionByZero);
Result := LeftExpression.Value.Longint mod RightExpression.Value.Longint;
end;
Calc_SHL: Result := LeftExpression.Value.Longint shl RightExpression.Value.Byte;
Calc_SHR: Result := LeftExpression.Value.Longint shr RightExpression.Value.Byte;
Calc_AND: Result := LeftExpression.Value.Longint and RightExpression.Value.Longint;
Calc_OR: Result := LeftExpression.Value.Longint or RightExpression.Value.Longint;
Calc_XOR: Result := LeftExpression.Value.Longint xor RightExpression.Value.Longint;
end;
Asm
JNO @1
INC Overflow
@1:
end;
If Overflow then Error (OverflowInArithmeticOperation);
LeftExpression.Value.Longint := Result;
LowestIntegerType (Result, LeftExpression.DataType);
end else begin
Case Operation of
Calc_IsEqual: BoolResult := LeftExpression.Value.Longint = RightExpression.Value.Longint;
Calc_IsNotEqual: BoolResult := LeftExpression.Value.Longint <> RightExpression.Value.Longint;
Calc_IsGreater: BoolResult := LeftExpression.Value.Longint > RightExpression.Value.Longint;
Calc_IsLower: BoolResult := LeftExpression.Value.Longint < RightExpression.Value.Longint;
Calc_IsGreaterOrEqual: BoolResult := LeftExpression.Value.Longint >= RightExpression.Value.Longint;
Calc_IsLowerOrEqual: BoolResult := LeftExpression.Value.Longint <= RightExpression.Value.Longint;
end;
SetLeftExpressionToConstantBooleanValue (BoolResult);
end;
end;
Non-constant integer expressions are prepared a little bit and the operation is performed by general routine for integer operations.
Procedure GenerateCodeForIntegerOperations;
Var CommonDataType: TIntegerTypeSet;
Label GeneralIntegerOperations;
begin
If not ((LeftExpression.Location = elPointerToMemory) and (RightExpression.Location = elConstant)) then
begin
If (LeftExpression.Location = elConstant) and (RightExpression.Location = elPointerToMemory) and
(Operation = Calc_Add) then ExchangeLeftAndRightExpression else GoTo GeneralIntegerOperations;
end;
If not (efSegment in LeftExpression.LocationData.Flags) and not (it32Bit in RightExpression.DataType) then
begin
Case Operation of
Calc_Add: Inc (LeftExpression.Value.Word, RightExpression.Value.Word);
Calc_Subtract: Dec (LeftExpression.Value.Word, RightExpression.Value.Word);
else GoTo GeneralIntegerOperations;
end;
Exit;
end;
GeneralIntegerOperations:
LeftExpression.LoadPointerToMemoryTo_DX_AX;
RightExpression.LoadPointerToMemoryTo_DX_AX;
SetLowestCommonIntegerType (LeftExpression.DataType, RightExpression.DataType, CommonDataType);
If (Operation <= Calc_SHR) and not (it16Bit in CommonDataType) then
CommonDataType := CommonDataType * [itSigned] + [it16Bit];
LeftExpression.ExtendInteger (CommonDataType);
RightExpression.ExtendInteger (CommonDataType);
IntegerOperations;
end;
This is the main routine for integer operations. It takes care for some special cases where shorter code can be generated, processes both expressions and generates code for all possible integer operations: +
, -
, *
, DIV
, MOD
, SHL
, SHR
, OR
, XOR
and AND
.
Procedure IntegerOperations;
Const IntegerOpCodes: Array [Calc_Add..Calc_XOR] of WordRec = (
(ByteL: mod_ADD_rm; ByteH: INC_AX),
(ByteL: mod_SUB_rm; ByteH: DEC_AX),
(ByteL: Unary_16Bit_Operations; ByteH: mod_MUL_rm),
(ByteL: Unary_16Bit_Operations; ByteH: mod_IDIV_rm),
(ByteL: Unary_16Bit_Operations; ByteH: mod_IDIV_rm),
(ByteL: ShiftRotateOperationsBy1_16Bit; ByteH: SHL_AX),
(ByteL: ShiftRotateOperationsBy1_16Bit; ByteH: SHR_AX),
(ByteL: mod_AND_rm),
(ByteL: mod_OR_rm),
(ByteL: mod_XOR_rm));
LongIntOpCodes: Array [Calc_Add..Calc_XOR] of WordRec = (
(ByteL: ADD_Operations; ByteH: ADC_Operations),
(ByteL: SUB_Operations; ByteH: SBB_Operations),
(Word: SysProc_LongMul),
(Word: SysProc_LongDiv),
(Word: SysProc_LongDiv),
(Word: SysProc_LongShl),
(Word: SysProc_LongShr),
(ByteL: AND_Operations; ByteH: 0),
(ByteL: OR_Operations; ByteH: 0),
(ByteL: XOR_Operations; ByteH: 0));
begin
RearrangeOperands;
If Operation >= Calc_IsEqual then
begin
If it32Bit in LeftExpression.DataType then
GenerateCodeForLongIntComparisons else GenerateCodeForIntegerComparisons;
LeftExpression.EndIntermediateCodeSubroutine;
LeftExpression.UsedRegisters := LeftExpression.UsedRegisters + RightExpression.UsedRegisters;
Exit;
end;
Case it32Bit in LeftExpression.DataType of
True: begin
LoadBothExpressionsToRegisters (LeftExpression, RightExpression, [urDX, urAX]);
Case Operation of
Calc_Add,
Calc_Subtract,
Calc_AND,
Calc_OR,
Calc_XOR: begin
RightExpression.GenerateArithmeticInstructionWith_ACC (
LongIntOpCodes [Operation].ByteL);
RightExpression.SwitchBetweenLoWordAndHiWord (2);
Case LongIntOpCodes [Operation].ByteH of
0: Case RightExpression.Location of
elConstant: begin
GenerateInstruction_TwoBytes (ArithmeticOperation_16Bit,
Operation_Register_DX or LongIntOpCodes [Operation].ByteL);
GenerateInstruction_Word (RightExpression.Value.Word);
end;
else RightExpression.GenerateInstructionWithExpressionInMemOrReg (
LongIntOpCodes [Operation].ByteL or reg__mod_rm_16Bit, regDX);
end;
else begin
RightExpression.GenerateArithmeticInstructionWith_DX (
LongIntOpCodes [Operation].ByteH);
GenerateOverflowCheckingCode (RightExpression)
end;
end;
end;
Calc_Multiply: begin
RightExpression.LoadExpressionToRegisters (urCX);
Case OverflowChecking in StatementCompilerSwitches of
True: GenerateInstruction_CALL_FAR (SysProc_LongMulOvf);
else GenerateInstruction_CALL_FAR (SysProc_LongMul);
end;
end;
Calc_DIV,
Calc_SHL,
Calc_SHR: begin
RightExpression.LoadExpressionToRegisters (urCX);
GenerateInstruction_CALL_FAR (LongIntOpCodes [Operation].Word);
end;
Calc_MOD: begin
RightExpression.LoadExpressionToRegisters (urCX);
GenerateInstruction_CALL_FAR (SysProc_LongDiv);
GenerateInstruction_TwoBytes (MOV_16Bit, MOV_AX_CX);
GenerateInstruction_TwoBytes (MOV_16Bit, MOV_DX_BX);
end;
end;
end;
else begin
If (Operation = Calc_Multiply) and (RightExpression.Location = elConstant) and
not (OverflowChecking in StatementCompilerSwitches) then
begin
LeftExpression.Calculate;
LeftExpression.IntegerMultiplicationWithConstant (rAX, RightExpression.Value.Word);
LeftExpression.EndIntermediateCodeSubroutine;
LeftExpression.UsedRegisters := LeftExpression.UsedRegisters + RightExpression.UsedRegisters;
Exit;
end;
Case Operation of
Calc_DIV,
Calc_MOD: LoadBothExpressionsToRegisters (LeftExpression, RightExpression, [urDX, urAX]);
else LoadBothExpressionsToRegisters (LeftExpression, RightExpression, [urAX]);
end;
Case Operation of
Calc_Add,
Calc_Subtract: Case OverflowChecking in StatementCompilerSwitches of
True: begin
RightExpression.GenerateArithmeticInstructionWith_ACC (
IntegerOpCodes [Operation].ByteL);
GenerateOverflowCheckingCode (RightExpression);
end;
else If RightExpression.Location = elConstant then
Case RightExpression.Value.Word of
1: GenerateInstruction_Byte (IntegerOpCodes [Operation].ByteH);
2: begin
GenerateInstruction_Byte (IntegerOpCodes [Operation].ByteH);
GenerateInstruction_Byte (IntegerOpCodes [Operation].ByteH);
end;
else RightExpression.GenerateArithmeticInstructionWith_ACC (
IntegerOpCodes [Operation].ByteL);
end else RightExpression.GenerateArithmeticInstructionWith_ACC (
IntegerOpCodes [Operation].ByteL);
end;
Calc_Multiply: Case OverflowChecking in StatementCompilerSwitches of
True: begin
If itSigned in RightExpression.DataType then
GenerateCodeForDivisionOrMultiplication (IntegerOpCodes [Operation].ByteL,
mod_IMUL_rm)
else GenerateCodeForDivisionOrMultiplication (IntegerOpCodes [Operation].ByteL,
mod_MUL_rm);
GenerateOverflowCheckingCode (RightExpression);
end;
else begin
RightExpression.GenerateInstructionWithExpressionInMemOrReg (
IntegerOpCodes [Operation].ByteL, IntegerOpCodes [Operation].ByteH);
Include (RightExpression.UsedRegisters, urDX);
end;
end;
Calc_DIV: begin
If RightExpression.Location = elConstant then
begin
If RightExpression.Value.Word = 0 then Error (DivisionByZero);
IntegerConstantDivision (RightExpression.Value.Word);
end else GeneralIntegerDivision;
end;
Calc_MOD: begin
GeneralIntegerDivision;
GenerateInstruction_Byte (XCHG_DX_AX);
end;
Calc_SHL,
Calc_SHR: If RightExpression.Location = elConstant then
begin
If RightExpression.Value.Word = 1 then
GenerateInstruction_Word (IntegerOpCodes [Operation].Word) else
Case Instructions80286 in StatementCompilerSwitches of
True: begin
GenerateInstruction_TwoBytes (ShiftRotateOperationsByValue_16Bit,
IntegerOpCodes [Operation].ByteH);
GenerateInstruction_Byte (RightExpression.Value.Byte);
end;
else begin
RightExpression.LoadExpressionToRegisters (urCX);
GenerateInstruction_TwoBytes (ShiftRotateOperationsByCL_16Bit,
IntegerOpCodes [Operation].ByteH);
end;
end;
end else begin
RightExpression.LoadExpressionToRegisters (urCX);
GenerateInstruction_TwoBytes (ShiftRotateOperationsByCL_16Bit,
IntegerOpCodes [Operation].ByteH);
end;
Calc_AND,
Calc_OR,
Calc_XOR:
RightExpression.GenerateArithmeticInstructionWith_ACC (IntegerOpCodes [Operation].ByteL);
end;
end;
end;
LeftExpression.EndIntermediateCodeSubroutine;
LeftExpression.UsedRegisters := LeftExpression.UsedRegisters + RightExpression.UsedRegisters;
end;
In some cases more efficient code can be generated if expressions are in certain registers. This procedure exchanges left and right expressions if such case is identified.
Procedure RearrangeOperands;
begin
Case Operation of
Calc_IsEqual..Calc_Divide,
Calc_Add,
Calc_Multiply,
Calc_AND,
Calc_OR,
Calc_XOR:
else Exit;
end;
If RightExpression.Location = elConstant then Exit else
If LeftExpression.Location = elConstant then ExchangeLeftAndRightExpression else
If RightExpression.UsedRegisters = [] then Exit else
If LeftExpression.UsedRegisters = [] then ExchangeLeftAndRightExpression else
If RightExpression.UsedRegisters = [urBX, urDX, urCX, urAX] then Exit else
If LeftExpression.UsedRegisters = [urBX, urDX, urCX, urAX] then ExchangeLeftAndRightExpression;
end;
This procedure exchanges left and right expressions and inverts operation if necessary.
Procedure ExchangeLeftAndRightExpression;
Var TempExpression: TExpression;
begin
TempExpression := LeftExpression;
LeftExpression := RightExpression;
RightExpression := TempExpression;
If Operation in [Calc_IsGreater, Calc_IsLower, Calc_IsGreaterOrEqual, Calc_IsLowerOrEqual] then
Operation := TCalcOperation (Ord (Operation) xor 1);
end;