Press enter to see results or esc to cancel.

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;