(********************************************************************)
(*                                                                  *)
(*  int_act.s7i   Generate code for actions of the type integer.    *)
(*  Copyright (C) 1990 - 1994, 2004 - 2022  Thomas Mertes           *)
(*                                                                  *)
(*  This file is part of the Seed7 compiler.                        *)
(*                                                                  *)
(*  This program is free software; you can redistribute it and/or   *)
(*  modify it under the terms of the GNU General Public License as  *)
(*  published by the Free Software Foundation; either version 2 of  *)
(*  the License, or (at your option) any later version.             *)
(*                                                                  *)
(*  This program is distributed in the hope that it will be useful, *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of  *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *)
(*  GNU General Public License for more details.                    *)
(*                                                                  *)
(*  You should have received a copy of the GNU General Public       *)
(*  License along with this program; if not, write to the           *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


const ACTION: INT_ABS                 is action "INT_ABS";
const ACTION: INT_ADD                 is action "INT_ADD";
const ACTION: INT_ADD_ASSIGN          is action "INT_ADD_ASSIGN";
const ACTION: INT_BINOM               is action "INT_BINOM";
const ACTION: INT_BIT_LENGTH          is action "INT_BIT_LENGTH";
const ACTION: INT_BYTES_BE_2_INT      is action "INT_BYTES_BE_2_INT";
const ACTION: INT_BYTES_BE_2_UINT     is action "INT_BYTES_BE_2_UINT";
const ACTION: INT_BYTES_BE_SIGNED     is action "INT_BYTES_BE_SIGNED";
const ACTION: INT_BYTES_BE_UNSIGNED   is action "INT_BYTES_BE_UNSIGNED";
const ACTION: INT_BYTES_LE_2_INT      is action "INT_BYTES_LE_2_INT";
const ACTION: INT_BYTES_LE_2_UINT     is action "INT_BYTES_LE_2_UINT";
const ACTION: INT_BYTES_LE_SIGNED     is action "INT_BYTES_LE_SIGNED";
const ACTION: INT_BYTES_LE_UNSIGNED   is action "INT_BYTES_LE_UNSIGNED";
const ACTION: INT_CMP                 is action "INT_CMP";
const ACTION: INT_CPY                 is action "INT_CPY";
const ACTION: INT_DECR                is action "INT_DECR";
const ACTION: INT_DIV                 is action "INT_DIV";
const ACTION: INT_EQ                  is action "INT_EQ";
const ACTION: INT_FACT                is action "INT_FACT";
const ACTION: INT_GE                  is action "INT_GE";
const ACTION: INT_GT                  is action "INT_GT";
const ACTION: INT_HASHCODE            is action "INT_HASHCODE";
const ACTION: INT_ICONV1              is action "INT_ICONV1";
const ACTION: INT_ICONV3              is action "INT_ICONV3";
const ACTION: INT_INCR                is action "INT_INCR";
const ACTION: INT_LE                  is action "INT_LE";
const ACTION: INT_LOG10               is action "INT_LOG10";
const ACTION: INT_LOG2                is action "INT_LOG2";
const ACTION: INT_LOWEST_SET_BIT      is action "INT_LOWEST_SET_BIT";
const ACTION: INT_LPAD0               is action "INT_LPAD0";
const ACTION: INT_LSHIFT              is action "INT_LSHIFT";
const ACTION: INT_LSHIFT_ASSIGN       is action "INT_LSHIFT_ASSIGN";
const ACTION: INT_LT                  is action "INT_LT";
const ACTION: INT_MDIV                is action "INT_MDIV";
const ACTION: INT_MOD                 is action "INT_MOD";
const ACTION: INT_MULT                is action "INT_MULT";
const ACTION: INT_MULT_ASSIGN         is action "INT_MULT_ASSIGN";
const ACTION: INT_NE                  is action "INT_NE";
const ACTION: INT_NEGATE              is action "INT_NEGATE";
const ACTION: INT_N_BYTES_BE_SIGNED   is action "INT_N_BYTES_BE_SIGNED";
const ACTION: INT_N_BYTES_BE_UNSIGNED is action "INT_N_BYTES_BE_UNSIGNED";
const ACTION: INT_N_BYTES_LE_SIGNED   is action "INT_N_BYTES_LE_SIGNED";
const ACTION: INT_N_BYTES_LE_UNSIGNED is action "INT_N_BYTES_LE_UNSIGNED";
const ACTION: INT_ODD                 is action "INT_ODD";
const ACTION: INT_PARSE1              is action "INT_PARSE1";
const ACTION: INT_PLUS                is action "INT_PLUS";
const ACTION: INT_POW                 is action "INT_POW";
const ACTION: INT_PRED                is action "INT_PRED";
const ACTION: INT_radix               is action "INT_radix";
const ACTION: INT_RADIX               is action "INT_RADIX";
const ACTION: INT_RAND                is action "INT_RAND";
const ACTION: INT_REM                 is action "INT_REM";
const ACTION: INT_RSHIFT              is action "INT_RSHIFT";
const ACTION: INT_RSHIFT_ASSIGN       is action "INT_RSHIFT_ASSIGN";
const ACTION: INT_SBTR                is action "INT_SBTR";
const ACTION: INT_SBTR_ASSIGN         is action "INT_SBTR_ASSIGN";
const ACTION: INT_SQRT                is action "INT_SQRT";
const ACTION: INT_STR                 is action "INT_STR";
const ACTION: INT_SUCC                is action "INT_SUCC";
const ACTION: INT_VALUE               is action "INT_VALUE";


const proc: int_prototypes (inout file: c_prog) is func

  begin
    declareExtern(c_prog, "void        setupRand (void);");
    if inlineFunctions and
        (ccConf.INTTYPE_SIZE = 32 and ccConf.UINT64TYPE <> "") or
        (ccConf.INTTYPE_SIZE = 64 and ccConf.UINT128TYPE <> "") then
      if ccConf.INTTYPE_SIZE = 32 then
        declareExtern(c_prog, ccConf.UINT64TYPE <& " seed;");
      elsif ccConf.INTTYPE_SIZE = 64 then
        declareExtern(c_prog, ccConf.UINT128TYPE <& " seed;");
      end if;
      writeln(c_prog, "#define            RAND_MULTIPLIER " <& ccConf.RAND_MULTIPLIER);
      writeln(c_prog, "#define            RAND_INCREMENT " <& ccConf.RAND_INCREMENT);
      writeln(c_prog, "#define            uintRand() \
                      \(seed = seed * RAND_MULTIPLIER + RAND_INCREMENT, \
                      \(uintType) (seed >> " <&
                      ccConf.INTTYPE_SIZE <& "))");
      writeln(c_prog, "#define            uintRandMantissa() \
                      \(seed = seed * RAND_MULTIPLIER + RAND_INCREMENT, \
                      \(uintType) (seed >> " <&
                      2 * ccConf.INTTYPE_SIZE - ccConf.FLOATTYPE_MANTISSA_BITS <& "))");
      if ccConf.STMT_BLOCK_IN_PARENTHESES_OK then
        writeln(c_prog, "#define            uintRandLimited(rand_max) \
                        \({uintType rand_val; \
                        \do {rand_val = uintRand();} while (rand_val > (rand_max)); \
                        \rand_val;})");
      else
        declareExtern(c_prog, "uintType    uintRandLimited (uintType);");
      end if;
    else
      declareExtern(c_prog, "uintType    uintRand (void);");
      declareExtern(c_prog, "uintType    uintRandMantissa (void);");
      declareExtern(c_prog, "uintType    uintRandLimited (uintType);");
    end if;
    declareExtern(c_prog, "intType     intBinom (intType, intType);");
    declareExtern(c_prog, "uintType    uintBinomNoChk (uintType, intType);");
    declareExtern(c_prog, "intType     intBitLength (intType);");
    declareExtern(c_prog, "striType    intBytesBe (intType, boolType);");
    declareExtern(c_prog, "intType     intBytesBe2Int (const const_striType);");
    declareExtern(c_prog, "intType     intBytesBe2UInt (const const_striType);");
    declareExtern(c_prog, "striType    intBytesLe (intType, boolType);");
    declareExtern(c_prog, "intType     intBytesLe2Int (const const_striType);");
    declareExtern(c_prog, "intType     intBytesLe2UInt (const const_striType);");
    declareExtern(c_prog, "intType     intCmp (intType, intType);");
    declareExtern(c_prog, "intType     intCmpGeneric (const genericType, const genericType);");
    declareExtern(c_prog, "intType     intLog10 (intType);");
    declareExtern(c_prog, "intType     intLog2 (intType);");
    declareExtern(c_prog, "intType     intLowestSetBit (intType);");
    declareExtern(c_prog, "striType    intLpad0 (intType, const intType);");
    declareExtern(c_prog, "striType    intNBytesBeSigned (intType, intType);");
    declareExtern(c_prog, "striType    intNBytesBeUnsigned (intType, intType);");
    declareExtern(c_prog, "striType    intNBytesLeSigned (intType, intType);");
    declareExtern(c_prog, "striType    intNBytesLeUnsigned (intType, intType);");
    declareExtern(c_prog, "intType     intParse (const const_striType);");
    declareExtern(c_prog, "intType     intPow (intType, intType);");
    declareExtern(c_prog, "intType     intPowOvfChk (intType, intType);");
    declareExtern(c_prog, "striType    intRadix (intType, intType, boolType);");
    declareExtern(c_prog, "striType    intRadixPow2 (intType, int, int, boolType);");
    declareExtern(c_prog, "intType     intRand (intType, intType);");
    declareExtern(c_prog, "intType     intSqrt (intType);");
    declareExtern(c_prog, "striType    intStr (intType);");
    declareExtern(c_prog, "striType    intStrToBuffer (intType, striType);");
    declareExtern(c_prog, "intType     intValue (const const_objRefType);");
  end func;


const array integer: maxExponentOfBase is [-8] (
    21, 22, 24, 27, 31, 39, 63,
    integer.last, integer.last, integer.last,
    62, 39, 31, 27, 24, 22, 20);
const array integer: minBaseOfExponent is [2] (
    -3037000499, -2097152, -55108, -6208, -1448, -512, -234, -128,
    -78, -52, -38, -28, -22, -18, -15, -13, -11, -9, -8, -8, -7);
const array integer: maxBaseOfExponent is [2] (
    3037000499, 2097151, 55108, 6208, 1448, 511, 234, 127,
    78, 52, 38, 28, 22, 18, 15, 13, 11, 9, 8, 7, 7);
const type: addSubIntElementType is new struct
    var boolean: doAdd is TRUE;
    var reference: summand is NIL;
    var integer: constSummand is 0;
  end struct;
const type: addSubIntListType is array addSubIntElementType;


const proc: generateAddSubParamList (inout addSubIntListType: addSubParamList,
    in var reference: leftParam) is func

  local
    var boolean: actionFound is FALSE;
    var ref_list: subExprParams is ref_list.EMPTY;
    var addSubIntElementType: addSubElement is addSubIntElementType.value;
  begin
    repeat
      actionFound := FALSE;
      if category(leftParam) = CALLOBJECT then
        subExprParams := getValue(leftParam, ref_list);
        if category(subExprParams[1]) = ACTOBJECT then
          if str(getValue(subExprParams[1], ACTION)) = "INT_ADD" then
            leftParam := subExprParams[2];
            addSubElement.doAdd := TRUE;
            addSubElement.summand := subExprParams[4];
            addSubParamList := [] (addSubElement) & addSubParamList;
            actionFound := TRUE;
          elsif str(getValue(subExprParams[1], ACTION)) = "INT_SBTR" then
            leftParam := subExprParams[2];
            addSubElement.doAdd := FALSE;
            addSubElement.summand := subExprParams[4];
            addSubParamList := [] (addSubElement) & addSubParamList;
            actionFound := TRUE;
          end if;
        end if;
      end if;
    until not actionFound;
    if category(leftParam) = CALLOBJECT then
      subExprParams := getValue(leftParam, ref_list);
      if category(subExprParams[1]) = ACTOBJECT then
        if str(getValue(subExprParams[1], ACTION)) = "INT_SUCC" then
          addSubElement.doAdd := TRUE;
          addSubElement.summand := NIL;
          addSubElement.constSummand := 1;
          addSubParamList := [] (addSubElement) & addSubParamList;
          generateAddSubParamList(addSubParamList, subExprParams[2]);
          actionFound := TRUE;
        elsif str(getValue(subExprParams[1], ACTION)) = "INT_PRED" then
          addSubElement.doAdd := FALSE;
          addSubElement.summand := NIL;
          addSubElement.constSummand := 1;
          addSubParamList := [] (addSubElement) & addSubParamList;
          generateAddSubParamList(addSubParamList, subExprParams[2]);
          actionFound := TRUE;
        end if;
      end if;
    end if;
    if not actionFound then
      addSubElement.doAdd := TRUE;
      addSubElement.summand := leftParam;
      addSubParamList := [] (addSubElement) & addSubParamList;
    end if;
  end func;


const func addSubIntListType: getAddSubParamList (in ref_list: params,
    in boolean: doAdd) is func

  result
    var addSubIntListType: addSubParamList is 0 times addSubIntElementType.value;
  local
    var addSubIntElementType: addSubElement is addSubIntElementType.value;
  begin
    addSubElement.doAdd := doAdd;
    addSubElement.summand := params[3];
    addSubParamList := [] (addSubElement);
    generateAddSubParamList(addSubParamList, params[1]);
  end func;


const func addSubIntListType: getAddSubParamList (in reference: summand1,
    in integer: summand2) is func

  result
    var addSubIntListType: addSubParamList is 0 times addSubIntElementType.value;
  local
    var addSubIntElementType: addSubElement is addSubIntElementType.value;
  begin
    addSubElement.constSummand := summand2;
    addSubParamList := [] (addSubElement);
    generateAddSubParamList(addSubParamList, summand1);
  end func;


const proc: processNegations (inout addSubIntListType: addSubParamList,
    inout expr_type: c_expr) is func

  local
    var integer: index is 1;
    var boolean: doAdd is TRUE;
    var reference: summand is NIL;
  begin
    for key index range addSubParamList do
      if index > 1 and addSubParamList[index].summand <> NIL then
        doAdd := addSubParamList[index].doAdd;
        summand := addSubParamList[index].summand;
        while isActionExpression(summand, "INT_NEGATE") or
              isActionExpression(summand, "INT_PLUS") do
          if isActionExpression(summand, "INT_NEGATE") then
            # Negate a negated value. No overflow check necessary.
            countOverflowOptimizations(c_expr);
            doAdd := not doAdd;
          end if;
          summand := getActionParameter(summand, 2);
        end while;
        addSubParamList[index].doAdd := doAdd;
        addSubParamList[index].summand := summand;
      end if;
    end for;
  end func;


const proc: summarizeConstants (inout addSubIntListType: addSubParamList) is func

  local
    var integer: index is 1;
    var integer: paramValue is 0;
    var bigInteger: bigSum is 0_;
  begin
    while index <= length(addSubParamList) do
      if addSubParamList[index].summand = NIL then
        paramValue := addSubParamList[index].constSummand;
        if index < length(addSubParamList) and
            addSubParamList[succ(index)].summand = NIL then
          # Two consecutive constant integers are added or subtracted at compile time.
          if addSubParamList[index].doAdd then
            bigSum := bigInteger(paramValue);
          else
            bigSum := -bigInteger(paramValue);
          end if;
          if addSubParamList[succ(index)].doAdd then
            bigSum +:= bigInteger(addSubParamList[succ(index)].constSummand);
          else
            bigSum -:= bigInteger(addSubParamList[succ(index)].constSummand);
          end if;
          if bigSum > bigInteger(integer.first) and bigSum < 0_ then
            incr(countOptimizations);
            if index > 1 then
              addSubParamList[index].doAdd := FALSE;
              addSubParamList[index].constSummand := -ord(bigSum);
            else
              addSubParamList[index].doAdd := TRUE;
              addSubParamList[index].constSummand := ord(bigSum);
            end if;
            ignore(remove(addSubParamList, succ(index)));
          elsif bigSum > 0_ and bigSum <= bigInteger(integer.last) then
            incr(countOptimizations);
            addSubParamList[index].doAdd := TRUE;
            addSubParamList[index].constSummand := ord(bigSum);
            ignore(remove(addSubParamList, succ(index)));
          elsif bigSum = 0_ then
            incr(countOptimizations);
            if index > 1 or length(addSubParamList) = 2 or
                addSubParamList[3].doAdd then
              ignore(remove(addSubParamList, index));
              ignore(remove(addSubParamList, index));
            else
              addSubParamList[index].doAdd := TRUE;
              addSubParamList[index].constSummand := 0;
              ignore(remove(addSubParamList, succ(index)));
            end if;
          elsif bigSum = bigInteger(integer.first) then
            incr(countOptimizations);
            addSubParamList[index].doAdd := TRUE;
            addSubParamList[index].constSummand := integer.first;
            ignore(remove(addSubParamList, succ(index)));
          elsif bigSum = -bigInteger(integer.first) then
            incr(countOptimizations);
            if index > 1 then
              addSubParamList[index].doAdd := FALSE;
              addSubParamList[index].constSummand := integer.first;
              ignore(remove(addSubParamList, succ(index)));
            else
              incr(index);
            end if;
          else
            incr(index);
          end if;
        elsif paramValue = 0 then
          if index > 1 or index = length(addSubParamList) or
              addSubParamList[succ(index)].doAdd then
            # Zero elements are removed.
            incr(countOptimizations);
            ignore(remove(addSubParamList, index));
          else
            incr(index);
          end if;
        else
          incr(index);
        end if;
      else
        incr(index);
      end if;
    end while;
  end func;


const proc: evaluateConstants (inout addSubIntListType: addSubParamList) is func

  local
    var integer: index is 1;
    var reference: evaluatedParam is NIL;
    var integer: paramValue is 0;
  begin
    for key index range addSubParamList do
      if addSubParamList[index].summand <> NIL then
        if getConstant(addSubParamList[index].summand, INTOBJECT, evaluatedParam) then
          paramValue := getValue(evaluatedParam, integer);
          addSubParamList[index].summand := NIL;
        end if;
      else
        paramValue := addSubParamList[index].constSummand;
      end if;
      if addSubParamList[index].summand = NIL then
        if index > 1 and paramValue > integer.first and paramValue < 0 then
          addSubParamList[index].doAdd := not addSubParamList[index].doAdd;
          addSubParamList[index].constSummand := -paramValue;
        else
          addSubParamList[index].constSummand := paramValue;
        end if;
      end if;
    end for;
  end func;


const proc: computeConstants (inout addSubIntListType: addSubParamList) is func

  begin
    summarizeConstants(addSubParamList);
    if length(addSubParamList) >= 2 and
        addSubParamList[1].doAdd and addSubParamList[1].summand = NIL and
        addSubParamList[2].doAdd and addSubParamList[2].summand <> NIL then
      # Exchange the first and the second summand.
      # This way constants before and after the first expression can be combined.
      # Other summands cannot be exchanged without changing overflow behavior.
      addSubParamList[1].summand := addSubParamList[2].summand;
      addSubParamList[2].summand := NIL;
      addSubParamList[2].constSummand := addSubParamList[1].constSummand;
      summarizeConstants(addSubParamList);
    end if;
  end func;


const proc: checkIfOutsideRange (in string: number_name, in integer: lowerBound,
    in integer: upperBound, inout expr_type: c_expr) is func

  begin
    if ccConf.TWOS_COMPLEMENT_INTTYPE then
      (* Formula used: (uintType)x-l>(uintType)u-l *)
      c_expr.expr &:= "(uintType)";
      c_expr.expr &:= number_name;
      if lowerBound < 0 then
        c_expr.expr &:= "+(uintType)";
        c_expr.expr &:= integerLiteral(-lowerBound);
      elsif lowerBound > 0 then
        c_expr.expr &:= "-(uintType)";
        c_expr.expr &:= integerLiteral(lowerBound);
      end if;
      c_expr.expr &:= ">(uintType)";
      c_expr.expr &:= integerLiteral(upperBound - lowerBound);
    else
      (* Formula used: x<l||x>u *)
      c_expr.expr &:= number_name;
      c_expr.expr &:= "<";
      c_expr.expr &:= integerLiteral(lowerBound);
      c_expr.expr &:= "||";
      c_expr.expr &:= number_name;
      c_expr.expr &:= ">";
      c_expr.expr &:= integerLiteral(upperBound);
    end if;
  end func;


const proc: const_int_add_with_overflow_check (in expr_type: summand1Expr, in integer: summand2,
    inout expr_type: c_expr) is func

  local
    var string: sumName is "";
    var string: summand1Name is "";
  begin
    if summand2 <> -1 and ccConf.BUILTIN_ADD_OVERFLOW <> "" then
      sumName := defineTempVariable("intType", "sum_", c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= ccConf.BUILTIN_ADD_OVERFLOW;
      c_expr.expr &:= "(";
      c_expr.expr &:= summand1Expr.expr;
      c_expr.expr &:= ", ";
      c_expr.expr &:= integerLiteral(summand2);
      c_expr.expr &:= ", &";
      c_expr.expr &:= sumName;
      c_expr.expr &:= "))?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= sumName;
    else
      c_expr.expr &:= "(";
      summand1Name := defineTempVariable("intType", "summand1_", summand1Expr, c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= summand1Name;
      if summand2 = -1 then
        c_expr.expr &:= "==";
        c_expr.expr &:= integerLiteral(integer.first);
      elsif summand2 = 1 then
        c_expr.expr &:= "==";
        c_expr.expr &:= integerLiteral(integer.last);
      elsif summand2 < 0 then
        c_expr.expr &:= "<";
        c_expr.expr &:= integerLiteral(integer.first - summand2);
      else
        c_expr.expr &:= ">";
        c_expr.expr &:= integerLiteral(integer.last - summand2);
      end if;
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= summand1Name;
      c_expr.expr &:= " + ";
      c_expr.expr &:= integerLiteral(summand2);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: const_int_sbtr_with_overflow_check (in expr_type: minuendExpr, in integer: subtrahend,
    inout expr_type: c_expr) is func

  local
    var string: differenceName is "";
    var string: minuendName is "";
  begin
    if subtrahend <> 1 and ccConf.BUILTIN_SUB_OVERFLOW <> "" then
      differenceName := defineTempVariable("intType", "difference_", c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= ccConf.BUILTIN_SUB_OVERFLOW;
      c_expr.expr &:= "(";
      c_expr.expr &:= minuendExpr.expr;
      c_expr.expr &:= ", ";
      c_expr.expr &:= integerLiteral(subtrahend);
      c_expr.expr &:= ", &";
      c_expr.expr &:= differenceName;
      c_expr.expr &:= "))?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= differenceName;
    else
      c_expr.expr &:= "(";
      minuendName := defineTempVariable("intType", "minuend_", minuendExpr, c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= minuendName;
      if subtrahend = -1 then
        c_expr.expr &:= "==";
        c_expr.expr &:= integerLiteral(integer.last);
      elsif subtrahend = 1 then
        c_expr.expr &:= "==";
        c_expr.expr &:= integerLiteral(integer.first);
      elsif subtrahend < 0 then
        c_expr.expr &:= ">";
        c_expr.expr &:= integerLiteral(integer.last + subtrahend);
      else
        c_expr.expr &:= "<";
        c_expr.expr &:= integerLiteral(integer.first + subtrahend);
      end if;
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= minuendName;
      c_expr.expr &:= " - ";
      c_expr.expr &:= integerLiteral(subtrahend);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: const_int_sbtr_with_overflow_check (in integer: minuend, in expr_type: subtrahendExpr,
    inout expr_type: c_expr) is func

  local
    var string: differenceName is "";
    var string: subtrahendName is "";
  begin
    if ccConf.BUILTIN_SUB_OVERFLOW <> "" then
      differenceName := defineTempVariable("intType", "difference_", c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= ccConf.BUILTIN_SUB_OVERFLOW;
      c_expr.expr &:= "(";
      c_expr.expr &:= integerLiteral(minuend);
      c_expr.expr &:= ", ";
      c_expr.expr &:= subtrahendExpr.expr;
      c_expr.expr &:= ", &";
      c_expr.expr &:= differenceName;
      c_expr.expr &:= "))?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= differenceName;
    else
      c_expr.expr &:= "(";
      subtrahendName := defineTempVariable("intType", "subtrahend_", subtrahendExpr, c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= subtrahendName;
      if minuend < 0 then
        c_expr.expr &:= ">";
        c_expr.expr &:= integerLiteral(-(integer.first - minuend));
      elsif minuend = 0 then
        c_expr.expr &:= "==";
        c_expr.expr &:= integerLiteral(integer.first);
      else
        c_expr.expr &:= "<";
        c_expr.expr &:= integerLiteral(-(integer.last - minuend));
      end if;
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      if minuend <> 0 then
        c_expr.expr &:= integerLiteral(minuend);
      end if;
      c_expr.expr &:= " - ";
      c_expr.expr &:= subtrahendName;
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: int_add_with_overflow_check (in expr_type: summand1Expr, in reference: summand2,
    inout expr_type: c_expr) is func

  local
    var string: sumName is "";
    var string: summand1Name is "";
    var string: summand2Name is "";
  begin
    if ccConf.BUILTIN_ADD_OVERFLOW <> "" then
      sumName := defineTempVariable("intType", "sum_", c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= ccConf.BUILTIN_ADD_OVERFLOW;
      c_expr.expr &:= "(";
      c_expr.expr &:= summand1Expr.expr;
      c_expr.expr &:= ", ";
      process_expr(summand2, c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= sumName;
      c_expr.expr &:= "))?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= sumName;
    else
      c_expr.expr &:= "(";
      summand1Name := defineTempVariable("intType", "summand1_", summand1Expr, c_expr);
      summand2Name := getParameterAsVariable("intType", "summand2_", summand2, c_expr);
      sumName := defineTempVariable("intType", "sum_", c_expr);
      c_expr.expr &:= sumName;
      c_expr.expr &:= "=(intType)((uintType)";
      c_expr.expr &:= summand1Name;
      c_expr.expr &:= "+(uintType)";
      c_expr.expr &:= summand2Name;
      c_expr.expr &:= "), ";
      (* Formula used: ovfChk((intType)(~(s1^s2)&(sum^s1))<0) *)
      c_expr.expr &:= "ovfChk((intType)(~(";
      c_expr.expr &:= summand1Name;
      c_expr.expr &:= "^";
      c_expr.expr &:= summand2Name;
      c_expr.expr &:= ")&(";
      c_expr.expr &:= sumName;
      c_expr.expr &:= "^";
      c_expr.expr &:= summand1Name;
      c_expr.expr &:= "))<0)?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= sumName;
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: int_sbtr_with_overflow_check (in expr_type: minuendExpr, in reference: subtrahend,
    inout expr_type: c_expr) is func

  local
    var string: differenceName is "";
    var string: minuendName is "";
    var string: subtrahendName is "";
  begin
    if ccConf.BUILTIN_SUB_OVERFLOW <> "" then
      differenceName := defineTempVariable("intType", "difference_", c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= ccConf.BUILTIN_SUB_OVERFLOW;
      c_expr.expr &:= "(";
      c_expr.expr &:= minuendExpr.expr;
      c_expr.expr &:= ", ";
      process_expr(subtrahend, c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= differenceName;
      c_expr.expr &:= "))?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= differenceName;
    else
      c_expr.expr &:= "(";
      minuendName := defineTempVariable("intType", "minuend_", minuendExpr, c_expr);
      subtrahendName := getParameterAsVariable("intType", "subtrahend_", subtrahend, c_expr);
      differenceName := defineTempVariable("intType", "difference_", c_expr);
      c_expr.expr &:= differenceName;
      c_expr.expr &:= "=(intType)((uintType)";
      c_expr.expr &:= minuendName;
      c_expr.expr &:= "-(uintType)";
      c_expr.expr &:= subtrahendName;
      c_expr.expr &:= "), ";
      (* Formula used: ovfChk((intType)((m^s)&(d^m))<0) *)
      c_expr.expr &:= "ovfChk((intType)((";
      c_expr.expr &:= minuendName;
      c_expr.expr &:= "^";
      c_expr.expr &:= subtrahendName;
      c_expr.expr &:= ")&(";
      c_expr.expr &:= differenceName;
      c_expr.expr &:= "^";
      c_expr.expr &:= minuendName;
      c_expr.expr &:= "))<0)?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= differenceName;
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: int_mult_with_overflow_check (in reference: factor1, in reference: factor2,
    inout expr_type: c_expr) is func

  local
    var intRange: factor1_range is intRange.value;
    var intRange: factor2_range is intRange.value;
    var string: factor1_name is "";
    var string: factor2_name is "";
    var string: product_name is "";
  begin
    if ccConf.BUILTIN_MULT_OVERFLOW <> "" then
      product_name := defineTempVariable("intType", "product_", c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= ccConf.BUILTIN_MULT_OVERFLOW;
      c_expr.expr &:= "(";
      process_expr(factor1, c_expr);
      c_expr.expr &:= ", ";
      process_expr(factor2, c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= product_name;
      c_expr.expr &:= "))?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= product_name;
    elsif ccConf.INTTYPE_SIZE = 64 and ccConf.INT128TYPE <> "" or
          ccConf.INTTYPE_SIZE = 32 then
      product_name := defineTempVariable("doubleIntType", "product_", c_expr);
      c_expr.expr &:= product_name;
      c_expr.expr &:= "=(doubleIntType)(";
      process_expr(factor1, c_expr);
      c_expr.expr &:= ") * (doubleIntType)(";
      process_expr(factor2, c_expr);
      c_expr.expr &:= "),ovfChk(!inIntTypeRange(";
      c_expr.expr &:= product_name;
      c_expr.expr &:= "))?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":(intType)";
      c_expr.expr &:= product_name;
    else
      factor1_range := getIntRange(factor1);
      factor2_range := getIntRange(factor2);
      factor1_name := getParameterAsVariable("intType", "factor1_", factor1, c_expr);
      factor2_name := getParameterAsVariable("intType", "factor2_", factor2, c_expr);
      c_expr.expr &:= "ovfChk(";
      if factor1_range.minValue < 0 then
        c_expr.expr &:= factor1_name;
        c_expr.expr &:= "<0?";
        if factor2_range.maxValue < 0 then
          c_expr.expr &:= factor1_name;
          c_expr.expr &:= "<";
          c_expr.expr &:= integerLiteral(integer.last);
          c_expr.expr &:= "/";
          c_expr.expr &:= factor2_name;
        elsif factor2_range.minValue < 0 then
          c_expr.expr &:= factor2_name;
          c_expr.expr &:= "<0";
          if factor2_range.minValue < 0 and factor2_range.maxValue > 0 then
            c_expr.expr &:= "?";
          else
            c_expr.expr &:= "&&";
          end if;
          c_expr.expr &:= factor1_name;
          c_expr.expr &:= "<";
          c_expr.expr &:= integerLiteral(integer.last);
          c_expr.expr &:= "/";
          c_expr.expr &:= factor2_name;
        end if;
        if factor2_range.minValue < 0 and factor2_range.maxValue > 0 then
          c_expr.expr &:= ":(";
        end if;
        if factor2_range.minValue > 0 then
          c_expr.expr &:= factor1_name;
          c_expr.expr &:= "<";
          c_expr.expr &:= integerLiteral(integer.first);
          c_expr.expr &:= "/";
          c_expr.expr &:= factor2_name;
        elsif factor2_range.maxValue > 0 then
          c_expr.expr &:= factor2_name;
          c_expr.expr &:= ">0";
          c_expr.expr &:= "&&";
          c_expr.expr &:= factor1_name;
          c_expr.expr &:= "<";
          c_expr.expr &:= integerLiteral(integer.first);
          c_expr.expr &:= "/";
          c_expr.expr &:= factor2_name;
        end if;
        if factor2_range.minValue < 0 and factor2_range.maxValue > 0 then
          c_expr.expr &:= ")";
        end if;
        if factor1_range.maxValue <= 0 then
          c_expr.expr &:= ":0";
        end if;
      end if;
      if factor1_range.minValue < 0 and factor1_range.maxValue > 0 then
        c_expr.expr &:= ":(";
      end if;
      if factor1_range.maxValue > 0 then
        c_expr.expr &:= factor1_name;
        c_expr.expr &:= ">0?";
        if factor2_range.maxValue < 0 then
          c_expr.expr &:= factor2_name;
          c_expr.expr &:= "<";
          c_expr.expr &:= integerLiteral(integer.first);
          c_expr.expr &:= "/";
          c_expr.expr &:= factor1_name;
        elsif factor2_range.minValue < 0 then
          c_expr.expr &:= factor2_name;
          c_expr.expr &:= "<0";
          if factor2_range.minValue < 0 and factor2_range.maxValue > 0 then
            c_expr.expr &:= "?";
          else
            c_expr.expr &:= "&&";
          end if;
          c_expr.expr &:= factor2_name;
          c_expr.expr &:= "<";
          c_expr.expr &:= integerLiteral(integer.first);
          c_expr.expr &:= "/";
          c_expr.expr &:= factor1_name;
        end if;
        if factor2_range.minValue < 0 and factor2_range.maxValue > 0 then
          c_expr.expr &:= ":(";
        end if;
        if factor2_range.minValue > 0 then
          c_expr.expr &:= factor2_name;
          c_expr.expr &:= ">";
          c_expr.expr &:= integerLiteral(integer.last);
          c_expr.expr &:= "/";
          c_expr.expr &:= factor1_name;
        elsif factor2_range.maxValue > 0 then
          c_expr.expr &:= factor2_name;
          c_expr.expr &:= ">0";
          c_expr.expr &:= "&&";
          c_expr.expr &:= factor2_name;
          c_expr.expr &:= ">";
          c_expr.expr &:= integerLiteral(integer.last);
          c_expr.expr &:= "/";
          c_expr.expr &:= factor1_name;
        end if;
        if factor2_range.minValue < 0 and factor2_range.maxValue > 0 then
          c_expr.expr &:= ")";
        end if;
        if factor1_range.minValue >= 0 then
          c_expr.expr &:= ":0";
        end if;
      end if;
      if factor1_range.minValue < 0 and factor1_range.maxValue > 0 then
        c_expr.expr &:= ":0)";
      end if;
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= factor1_name;
      c_expr.expr &:= " * ";
      c_expr.expr &:= factor2_name;
    end if;
  end func;


const proc: negate (in reference: number, inout expr_type: c_expr) is func

  local
    var intRange: number_range is intRange.value;
    var string: number_name is "";
  begin
    if reduceOverflowChecks and
        isActionExpression(number, "INT_NEGATE") then
      # Negate a negated value. No overflow check necessary.
      countOverflowOptimizations(c_expr);
      c_expr.expr &:= "/*no_overflow_check_negate_of_negate*/";
      process_expr(getActionParameter(number, 2), c_expr);
    elsif check_int_arithmetic_overflow and ccConf.TWOS_COMPLEMENT_INTTYPE then
      number_range := getIntRange(number);
      if number_range.minValue >= -integer.last then
        # This negation cannot overflow
        countOverflowOptimizations(c_expr);
        c_expr.expr &:= "/*no_overflow_check_negate*/-(";
        process_expr(number, c_expr);
        c_expr.expr &:= ")";
      else
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        number_name := getParameterAsVariable("intType", "number_", number, c_expr);
        c_expr.expr &:= "ovfChk(";
        c_expr.expr &:= number_name;
        c_expr.expr &:= "==";
        c_expr.expr &:= integerLiteral(integer.first);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ": -";
        c_expr.expr &:= number_name;
        c_expr.expr &:= ")";
      end if;
    else
      if ccConf.TWOS_COMPLEMENT_INTTYPE then
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      end if;
      c_expr.expr &:= "-(";
      process_expr(number, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_int_add (in reference: summand1, in integer: summand2,
    inout expr_type: c_expr) is func

  local
    var integer: minAllowedSummand1 is 0;
    var integer: maxAllowedSummand1 is 0;
    var reference: evaluatedParam is NIL;
    var integer: summand1_value is 0;
    var intRange: summand1_range is intRange.value;
    var expr_type: summand1Expr is expr_type.value;
  begin
    if summand2 < 0 then
      minAllowedSummand1 := integer.first - summand2;
      maxAllowedSummand1 := integer.last;
    else
      minAllowedSummand1 := integer.first;
      maxAllowedSummand1 := integer.last - summand2;
    end if;
    if getConstant(summand1, INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      summand1_value := getValue(evaluatedParam, integer);
      if  summand1_value < minAllowedSummand1 or
          summand1_value > maxAllowedSummand1 then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= integerLiteral(summand1_value + summand2);
      end if;
    elsif summand2 = 0 then
      incr(countOptimizations);
      process_expr(summand1, c_expr);
    elsif check_int_arithmetic_overflow then
      incr(countOptimizations);
      summand1_range := getIntRange(summand1);
      if summand1_range <> intRange.value and
          summand1_range.minValue >= minAllowedSummand1 and
          summand1_range.maxValue <= maxAllowedSummand1 then
        # This addition cannot overflow
        countOverflowOptimizations(c_expr);
        c_expr.expr &:= "/*no_overflow_check_add*/(";
        process_expr(summand1, c_expr);
        c_expr.expr &:= ") + ";
        c_expr.expr &:= integerLiteral(summand2);
      else
        incr(countOverflowChecks);
        summand1Expr.temp_num := c_expr.temp_num;
        process_expr(summand1, summand1Expr);
        c_expr.temp_num := summand1Expr.temp_num;
        c_expr.temp_decls &:= summand1Expr.temp_decls;
        c_expr.temp_assigns &:= summand1Expr.temp_assigns;
        c_expr.temp_frees &:= summand1Expr.temp_frees;
        c_expr.temp_to_null &:= summand1Expr.temp_to_null;
        const_int_add_with_overflow_check(summand1Expr, summand2, c_expr);
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "(";
      process_expr(summand1, c_expr);
      c_expr.expr &:= ") + ";
      c_expr.expr &:= integerLiteral(summand2);
    end if;
  end func;


const proc: process_int_add (in reference: summand1, in reference: summand2,
    inout expr_type: c_expr) is func

  local
    var intRange: summand1_range is intRange.value;
    var intRange: summand2_range is intRange.value;
    var integer: minAllowedSummand2 is 0;
    var integer: maxAllowedSummand2 is 0;
    var boolean: fullOverflowCheck is FALSE;
    var expr_type: summand1Expr is expr_type.value;
    var string: summand1_name is "";
    var string: summand2_name is "";
  begin
    if check_int_arithmetic_overflow then
      summand1_range := getIntRange(summand1);
      summand2_range := getIntRange(summand2);
      if summand1_range <> intRange.value and summand2_range <> intRange.value then
        if summand1_range.minValue < 0 then
          minAllowedSummand2 := integer.first - summand1_range.minValue;
        else
          minAllowedSummand2 := integer.first;
        end if;
        if summand1_range.maxValue > 0 then
          maxAllowedSummand2 := integer.last - summand1_range.maxValue;
        else
          maxAllowedSummand2 := integer.last;
        end if;
        if  summand2_range.minValue >= minAllowedSummand2 and
            summand2_range.maxValue <= maxAllowedSummand2 then
          # This addition cannot overflow
          countOverflowOptimizations(c_expr);
          c_expr.expr &:= "/*no_overflow_check_add*/(";
          process_expr(summand1, c_expr);
          c_expr.expr &:= ") + (";
          process_expr(summand2, c_expr);
          c_expr.expr &:= ")";
        elsif summand2_range.minValue >= minAllowedSummand2 or
              summand2_range.maxValue <= maxAllowedSummand2 then
          incr(countOverflowChecks);
          c_expr.expr &:= "/*simplified_overflow_check_add*/(";
          summand1_name := getParameterAsVariable("intType", "summand1_", summand1, c_expr);
          summand2_name := getParameterAsVariable("intType", "summand2_", summand2, c_expr);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= summand2_name;
          if summand2_range.maxValue <= maxAllowedSummand2 then
            c_expr.expr &:= "<0&&";
            c_expr.expr &:= summand1_name;
            c_expr.expr &:= "<";
            c_expr.expr &:= integerLiteral(integer.first);
          else
            c_expr.expr &:= ">=0&&";
            c_expr.expr &:= summand1_name;
            c_expr.expr &:= ">";
            c_expr.expr &:= integerLiteral(integer.last);
          end if;
          c_expr.expr &:= "-";
          c_expr.expr &:= summand2_name;
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
          c_expr.expr &:= summand1_name;
          c_expr.expr &:= " + ";
          c_expr.expr &:= summand2_name;
          c_expr.expr &:= ")";
        else
          fullOverflowCheck := TRUE;
        end if;
      else
        fullOverflowCheck := TRUE;
      end if;
      if fullOverflowCheck then
        incr(countOverflowChecks);
        if summand1 = summand2 then
          incr(countOptimizations);
          c_expr.expr &:= "(";
          summand1_name := getParameterAsVariable("intType", "summand1_", summand1, c_expr);
          c_expr.expr &:= "ovfChk(";
          checkIfOutsideRange(summand1_name, integer.first div 2,
                              integer.last div 2, c_expr);
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
          c_expr.expr &:= summand1_name;
          c_expr.expr &:= " + ";
          c_expr.expr &:= summand1_name;
          c_expr.expr &:= ")";
        else
          summand1Expr.temp_num := c_expr.temp_num;
          process_expr(summand1, summand1Expr);
          c_expr.temp_num := summand1Expr.temp_num;
          c_expr.temp_decls &:= summand1Expr.temp_decls;
          c_expr.temp_assigns &:= summand1Expr.temp_assigns;
          c_expr.temp_frees &:= summand1Expr.temp_frees;
          c_expr.temp_to_null &:= summand1Expr.temp_to_null;
          int_add_with_overflow_check(summand1Expr, summand2, c_expr);
        end if;
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "(";
      process_expr(summand1, c_expr);
      c_expr.expr &:= ") + (";
      process_expr(summand2, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_int_sbtr (in reference: minuend, in integer: subtrahend,
    inout expr_type: c_expr) is func

  local
    var integer: minAllowedMinuend is 0;
    var integer: maxAllowedMinuend is 0;
    var reference: evaluatedParam is NIL;
    var integer: minuend_value is 0;
    var intRange: minuend_range is intRange.value;
    var expr_type: minuendExpr is expr_type.value;
  begin
    if subtrahend < 0 then
      minAllowedMinuend := integer.first;
      maxAllowedMinuend := integer.last + subtrahend;
    else
      minAllowedMinuend := integer.first + subtrahend;
      maxAllowedMinuend := integer.last;
    end if;
    if getConstant(minuend, INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      minuend_value := getValue(evaluatedParam, integer);
      if  minuend_value < minAllowedMinuend or
          minuend_value > maxAllowedMinuend then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= integerLiteral(minuend_value - subtrahend);
      end if;
    elsif subtrahend = 0 then
      incr(countOptimizations);
      process_expr(minuend, c_expr);
    elsif check_int_arithmetic_overflow then
      incr(countOptimizations);
      minuend_range := getIntRange(minuend);
      if minuend_range <> intRange.value and
          minuend_range.minValue >= minAllowedMinuend and
          minuend_range.maxValue <= maxAllowedMinuend then
        # This subtraction cannot overflow
        countOverflowOptimizations(c_expr);
        c_expr.expr &:= "/*no_overflow_check_sbtr*/(";
        process_expr(minuend, c_expr);
        c_expr.expr &:= ") - ";
        c_expr.expr &:= integerLiteral(subtrahend);
      else
        incr(countOverflowChecks);
        minuendExpr.temp_num := c_expr.temp_num;
        process_expr(minuend, minuendExpr);
        c_expr.temp_num := minuendExpr.temp_num;
        c_expr.temp_decls &:= minuendExpr.temp_decls;
        c_expr.temp_assigns &:= minuendExpr.temp_assigns;
        c_expr.temp_frees &:= minuendExpr.temp_frees;
        c_expr.temp_to_null &:= minuendExpr.temp_to_null;
        const_int_sbtr_with_overflow_check(minuendExpr, subtrahend, c_expr);
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "(";
      process_expr(minuend, c_expr);
      c_expr.expr &:= ") - ";
      c_expr.expr &:= integerLiteral(subtrahend);
    end if;
  end func;


const proc: process_const_int_sbtr (in integer: minuend, in reference: subtrahend,
    inout expr_type: c_expr) is func

  local
    var integer: minAllowedSubtrahend is 0;
    var integer: maxAllowedSubtrahend is 0;
    var intRange: subtrahend_range is intRange.value;
    var expr_type: subtrahendExpr is expr_type.value;
  begin
    if minuend < 0 then
      minAllowedSubtrahend := integer.first;
      maxAllowedSubtrahend := minuend - integer.first;
    else
      minAllowedSubtrahend := minuend - integer.last;
      maxAllowedSubtrahend := integer.last;
    end if;
    if minuend = 0 then
      negate(subtrahend, c_expr);
    elsif check_int_arithmetic_overflow then
      incr(countOptimizations);
      subtrahend_range := getIntRange(subtrahend);
      if subtrahend_range <> intRange.value and
          subtrahend_range.minValue >= minAllowedSubtrahend and
          subtrahend_range.maxValue <= maxAllowedSubtrahend then
        # This subtraction cannot overflow
        countOverflowOptimizations(c_expr);
        c_expr.expr &:= "/*no_overflow_check_sbtr*/ ";
        c_expr.expr &:= integerLiteral(minuend);
        c_expr.expr &:= " - (";
        process_expr(subtrahend, c_expr);
        c_expr.expr &:= ")";
      else
        incr(countOverflowChecks);
        subtrahendExpr.temp_num := c_expr.temp_num;
        process_expr(subtrahend, subtrahendExpr);
        c_expr.temp_num := subtrahendExpr.temp_num;
        c_expr.temp_decls &:= subtrahendExpr.temp_decls;
        c_expr.temp_assigns &:= subtrahendExpr.temp_assigns;
        c_expr.temp_frees &:= subtrahendExpr.temp_frees;
        c_expr.temp_to_null &:= subtrahendExpr.temp_to_null;
        const_int_sbtr_with_overflow_check(minuend, subtrahendExpr, c_expr);
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= integerLiteral(minuend);
      c_expr.expr &:= " - (";
      process_expr(subtrahend, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_int_sbtr (in reference: minuend, in reference: subtrahend,
    inout expr_type: c_expr) is func

  local
    var intRange: minuend_range is intRange.value;
    var intRange: subtrahend_range is intRange.value;
    var integer: minAllowedSubtrahend is 0;
    var integer: maxAllowedSubtrahend is 0;
    var boolean: fullOverflowCheck is FALSE;
    var expr_type: minuendExpr is expr_type.value;
    var string: minuend_name is "";
    var string: subtrahend_name is "";
  begin
    if minuend = subtrahend then
      incr(countOptimizations);
      c_expr.expr &:= "0";
    elsif check_int_arithmetic_overflow then
      minuend_range := getIntRange(minuend);
      subtrahend_range := getIntRange(subtrahend);
      if minuend_range <> intRange.value and subtrahend_range <> intRange.value then
        if minuend_range.maxValue > 0 then
          minAllowedSubtrahend := minuend_range.maxValue - integer.last;
        else
          minAllowedSubtrahend := -integer.last;
        end if;
        if minuend_range.minValue < 0 then
          maxAllowedSubtrahend := minuend_range.minValue - integer.first;
        else
          maxAllowedSubtrahend := integer.last;
        end if;
        if  subtrahend_range.minValue >= minAllowedSubtrahend and
            subtrahend_range.maxValue <= maxAllowedSubtrahend then
          # This subtraction cannot overflow
          countOverflowOptimizations(c_expr);
          c_expr.expr &:= "/*no_overflow_check_sbtr*/(";
          process_expr(minuend, c_expr);
          c_expr.expr &:= ") - (";
          process_expr(subtrahend, c_expr);
          c_expr.expr &:= ")";
        elsif subtrahend_range.minValue >= minAllowedSubtrahend or
              subtrahend_range.maxValue <= maxAllowedSubtrahend then
          incr(countOverflowChecks);
          c_expr.expr &:= "/*simplified_overflow_check_sbtr*/(";
          minuend_name := getParameterAsVariable("intType", "minuend_", minuend, c_expr);
          subtrahend_name := getParameterAsVariable("intType", "subtrahend_", subtrahend, c_expr);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= subtrahend_name;
          if subtrahend_range.minValue >= minAllowedSubtrahend then
            c_expr.expr &:= "<0&&";
            c_expr.expr &:= minuend_name;
            c_expr.expr &:= ">";
            c_expr.expr &:= integerLiteral(integer.last);
          else
            c_expr.expr &:= ">=0&&";
            c_expr.expr &:= minuend_name;
            c_expr.expr &:= "<";
            c_expr.expr &:= integerLiteral(integer.first);
          end if;
          c_expr.expr &:= "+";
          c_expr.expr &:= subtrahend_name;
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
          c_expr.expr &:= minuend_name;
          c_expr.expr &:= " - ";
          c_expr.expr &:= subtrahend_name;
          c_expr.expr &:= ")";
        else
          fullOverflowCheck := TRUE;
        end if;
      else
        fullOverflowCheck := TRUE;
      end if;
      if fullOverflowCheck then
        incr(countOverflowChecks);
        minuendExpr.temp_num := c_expr.temp_num;
        process_expr(minuend, minuendExpr);
        c_expr.temp_num := minuendExpr.temp_num;
        c_expr.temp_decls &:= minuendExpr.temp_decls;
        c_expr.temp_assigns &:= minuendExpr.temp_assigns;
        c_expr.temp_frees &:= minuendExpr.temp_frees;
        c_expr.temp_to_null &:= minuendExpr.temp_to_null;
        int_sbtr_with_overflow_check(minuendExpr, subtrahend, c_expr);
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "(";
      process_expr(minuend, c_expr);
      c_expr.expr &:= ") - (";
      process_expr(subtrahend, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: optimize_int_add (in addSubIntElementType: summand,
    inout intRange: sumRange, inout expr_type: c_expr) is func
  begin
    if summand.summand = NIL then
      if summand.doAdd then
        sumRange := getIntRange(summand.constSummand);
        c_expr.expr &:= integerLiteral(summand.constSummand);
      else
        sumRange := getIntNegateRange(getIntRange(summand.constSummand));
        if summand.constSummand < -integer.last then
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        else
          c_expr.expr &:= integerLiteral(-summand.constSummand);
        end if;
      end if;
    else
      if summand.doAdd then
        sumRange := getIntRange(summand.summand);
        process_expr(summand.summand, c_expr);
      else
        sumRange := getIntNegateRange(getIntRange(summand.summand));
        negate(summand.summand, c_expr);
      end if;
    end if;
  end func;


const proc: optimize_int_add (in addSubIntListType: addSubParamList,
    inout intRange: sumRange, inout expr_type: c_expr) is func

  local
    var intRange: summand1Range is intRange.value;
    var intRange: summand2Range is intRange.value;
    var expr_type: summand1Expr is expr_type.value;
    var reference: summand2Ref is NIL;
    var integer: summand2Value is 0;
    var boolean: doAdd is FALSE;
  begin
    if length(addSubParamList) >= 2 then
      incr(countOptimizations);
      if check_int_arithmetic_overflow then
        summand1Expr.temp_num := c_expr.temp_num;
        optimize_int_add(addSubParamList[.. pred(length(addSubParamList))], summand1Range, summand1Expr);
        c_expr.temp_num := summand1Expr.temp_num;
        c_expr.temp_decls &:= summand1Expr.temp_decls;
        c_expr.temp_assigns &:= summand1Expr.temp_assigns;
        c_expr.temp_frees &:= summand1Expr.temp_frees;
        c_expr.temp_to_null &:= summand1Expr.temp_to_null;
        doAdd := addSubParamList[length(addSubParamList)].doAdd;
        summand2Ref := addSubParamList[length(addSubParamList)].summand;
        if summand2Ref = NIL then
          summand2Value := addSubParamList[length(addSubParamList)].constSummand;
          if summand2Value = 0 then
            # This should never happen because 0 should have been optimized out.
            writeln(" ***** Problem in optimize_int_add (1)");
            sumRange := summand1Range;
            c_expr.expr &:= summand1Expr.expr;
          else
            summand2Range := getIntRange(summand2Value);
            if doAdd then
              sumRange := getIntAddRange(summand1Range, summand2Range);
            else
              sumRange := getIntSbtrRange(summand1Range, summand2Range);
            end if;
            if not sumRange.mayOverflow then
              countOverflowOptimizations(c_expr);
              if doAdd then
                c_expr.expr &:= "/*no_overflow_check_add*/(";
                c_expr.expr &:= summand1Expr.expr;
                c_expr.expr &:= ") + ";
              else
                c_expr.expr &:= "/*no_overflow_check_sbtr*/(";
                c_expr.expr &:= summand1Expr.expr;
                c_expr.expr &:= ") - ";
              end if;
              c_expr.expr &:= integerLiteral(summand2Value);
            elsif sumRange.minValue = 0 and sumRange.maxValue = -1 and sumRange.mayOverflow then
              warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
              c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
            else
              incr(countOverflowChecks);
              if doAdd then
                const_int_add_with_overflow_check(summand1Expr, summand2Value, c_expr);
              else
                const_int_sbtr_with_overflow_check(summand1Expr, summand2Value, c_expr);
              end if;
            end if;
          end if;
        else
          summand2Range := getIntRange(summand2Ref);
          if doAdd then
            sumRange := getIntAddRange(summand1Range, summand2Range);
          else
            sumRange := getIntSbtrRange(summand1Range, summand2Range);
          end if;
          if not sumRange.mayOverflow then
            countOverflowOptimizations(c_expr);
            if doAdd then
              c_expr.expr &:= "/*no_overflow_check_add*/(";
              c_expr.expr &:= summand1Expr.expr;
              c_expr.expr &:= ") + (";
            else
              c_expr.expr &:= "/*no_overflow_check_sbtr*/(";
              c_expr.expr &:= summand1Expr.expr;
              c_expr.expr &:= ") - (";
            end if;
            process_expr(summand2Ref, c_expr);
            c_expr.expr &:= ")";
          elsif sumRange.minValue = 0 and sumRange.maxValue = -1 then
            warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
            c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          else
            incr(countOverflowChecks);
            if doAdd then
              int_add_with_overflow_check(summand1Expr, summand2Ref, c_expr);
            else
              int_sbtr_with_overflow_check(summand1Expr, summand2Ref, c_expr);
            end if;
          end if;
        end if;
      else
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
        c_expr.expr &:= "(";
        optimize_int_add(addSubParamList[.. pred(length(addSubParamList))], summand1Range, c_expr);
        if addSubParamList[length(addSubParamList)].doAdd then
          c_expr.expr &:= ") + ";
        else
          c_expr.expr &:= ") - ";
        end if;
        if addSubParamList[length(addSubParamList)].summand = NIL then
          c_expr.expr &:= integerLiteral(addSubParamList[length(addSubParamList)].constSummand);
        else
          c_expr.expr &:= "(";
          process_expr(addSubParamList[length(addSubParamList)].summand, c_expr);
          c_expr.expr &:= ")";
        end if;
      end if;
    elsif length(addSubParamList) = 1 then
      incr(countOptimizations);
      optimize_int_add(addSubParamList[1], sumRange, c_expr);
    else
      incr(countOptimizations);
      sumRange := getIntRange(0);
      c_expr.expr &:= integerLiteral(0);
    end if;
  end func;


const proc: optimize_int_add (in ref_list: params, in boolean: doAdd,
    inout expr_type: c_expr) is func

  local
    var addSubIntListType: addSubParamList is 0 times addSubIntElementType.value;
    var intRange: sumRange is intRange.value;
  begin
    addSubParamList := getAddSubParamList(params, doAdd);
    processNegations(addSubParamList, c_expr);
    evaluateConstants(addSubParamList);
    computeConstants(addSubParamList);
    optimize_int_add(addSubParamList, sumRange, c_expr);
  end func;


const proc: optimize_int_add (in reference: summand1, in integer: summand2,
    inout expr_type: c_expr) is func

  local
    var addSubIntListType: addSubParamList is 0 times addSubIntElementType.value;
    var intRange: sumRange is intRange.value;
  begin
    addSubParamList := getAddSubParamList(summand1, summand2);
    processNegations(addSubParamList, c_expr);
    evaluateConstants(addSubParamList);
    computeConstants(addSubParamList);
    optimize_int_add(addSubParamList, sumRange, c_expr);
  end func;


const func boolean: constValueIsEqual (in reference: anExpr, in integer: number) is func

  result
    var boolean: isEqual is FALSE;
  local
    var reference: aParam is NIL;
  begin
    if category(anExpr) = INTOBJECT and
        not isVar(anExpr) and
        getValue(anExpr, integer) = number then
      isEqual := TRUE;
    elsif number < 0 then
      if isActionExpression(anExpr, "INT_NEGATE") then
        aParam := getActionParameter(anExpr, 2);
        if category(aParam) = INTOBJECT and
            not isVar(aParam) and
            getValue(aParam, integer) = -number then
          isEqual := TRUE;
        end if;
      end if;
    end if;
  end func;


const proc: process_int_str (in reference: param1, inout expr_type: c_expr) is func

  local
    var string: buffer_name is "";
  begin
    if ccConf.ALLOW_STRITYPE_SLICES and c_expr.demand < ASSIGN_RESULT then
      incr(c_expr.temp_num);
      buffer_name := "buffer_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "union {\n";
      c_expr.temp_decls &:= "  struct striStruct striBuf;\n";
      c_expr.temp_decls &:= "  char charBuf[SIZ_STRI(INTTYPE_DECIMAL_SIZE)];\n";
      c_expr.temp_decls &:= "} ";
      c_expr.temp_decls &:= buffer_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "intStrToBuffer(";
      process_expr(param1, c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf)";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "intStr(";
      getStdParamToResultExpr(param1, c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process (INT_ABS, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var intRange: number_range is intRange.value;
    var string: number_name is "";
    var string: sign_name is "";
    var integer: number is 0;
  begin
    if getConstant(params[1], INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      number := getValue(evaluatedParam, integer);
      if number = integer.first and ccConf.TWOS_COMPLEMENT_INTTYPE then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= integerLiteral(abs(number));
      end if;
    else
      number_range := getIntRange(params[1]);
      if check_int_abs_overflow and number_range.minValue = integer.first then
        if check_int_arithmetic_overflow then
          incr(countOverflowChecks);
          c_expr.expr &:= "(";
          number_name := getParameterAsVariable("intType", "number_", params[1], c_expr);
          if number_range.maxValue <= 0 then
            incr(countOptimizations);
            c_expr.expr &:= "ovfChk(";
            c_expr.expr &:= number_name;
            c_expr.expr &:= "==";
            c_expr.expr &:= integerLiteral(integer.first);
            c_expr.expr &:= ")?";
            c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
            c_expr.expr &:= ": /*abs_of_nonpositive_number*/-";
            c_expr.expr &:= number_name;
          else
            c_expr.expr &:= number_name;
            c_expr.expr &:= "<0?";
            c_expr.expr &:= "(ovfChk(";
            c_expr.expr &:= number_name;
            c_expr.expr &:= "==";
            c_expr.expr &:= integerLiteral(integer.first);
            c_expr.expr &:= ")?";
            c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
            c_expr.expr &:= ": -";
            c_expr.expr &:= number_name;
            c_expr.expr &:= "):";
            c_expr.expr &:= number_name;
          end if;
          c_expr.expr &:= ")";
        else
          (* There is a signal for integer overflow. *)
          if number_range.maxValue <= 0 then
            incr(countOptimizations);
            c_expr.expr &:= "/*abs_of_nonpositive_number*/-(";
            process_expr(params[1], c_expr);
            c_expr.expr &:= ")";
          else
            c_expr.expr &:= "(";
            number_name := getParameterAsVariable("intType", "number_", params[1], c_expr);
            c_expr.expr &:= number_name;
            c_expr.expr &:= "<0?";
            c_expr.expr &:= " -";
            c_expr.expr &:= number_name;
            c_expr.expr &:= ":";
            c_expr.expr &:= number_name;
            c_expr.expr &:= ")";
          end if;
        end if;
      else
        if check_int_abs_overflow and check_int_arithmetic_overflow then
          countOverflowOptimizations(c_expr);
        end if;
        if number_range.minValue >= 0 then
          incr(countOptimizations);
          c_expr.expr &:= "/*abs_of_nonnegative_number*/";
          process_expr(params[1], c_expr);
        elsif number_range.maxValue <= 0 then
          incr(countOptimizations);
          c_expr.expr &:= "/*abs_of_nonpositive_number*/-(";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ")";
        elsif ccConf.INT_SIZE = ccConf.INTTYPE_SIZE then
          c_expr.expr &:= "abs(";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ")";
        elsif ccConf.LONG_SIZE = ccConf.INTTYPE_SIZE then
          c_expr.expr &:= "labs(";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ")";
        elsif ccConf.TWOS_COMPLEMENT_INTTYPE and ccConf.RSHIFT_DOES_SIGN_EXTEND then
          c_expr.expr &:= "(";
          number_name := getParameterAsVariable("intType", "number_", params[1], c_expr);
          sign_name := defineTempVariable("intType", "sign_", c_expr);
          c_expr.expr &:= sign_name;
          c_expr.expr &:= " = ";
          c_expr.expr &:= number_name;
          c_expr.expr &:= " >> ";
          c_expr.expr &:= str(pred(ccConf.INTTYPE_SIZE));
          c_expr.expr &:= ", (";
          c_expr.expr &:= number_name;
          c_expr.expr &:= " + ";
          c_expr.expr &:= sign_name;
          c_expr.expr &:= ") ^ ";
          c_expr.expr &:= sign_name;
          c_expr.expr &:= ")";
        else
          c_expr.expr &:= "(";
          number_name := getParameterAsVariable("intType", "number_", params[1], c_expr);
          c_expr.expr &:= number_name;
          c_expr.expr &:= "<0? (intType)(-(uintType)";
          c_expr.expr &:= number_name;
          c_expr.expr &:= "):";
          c_expr.expr &:= number_name;
          c_expr.expr &:= ")";
        end if;
      end if;
    end if;
  end func;


const proc: process (INT_ADD, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
  begin
    if callOptimizeIntAdd then
      optimize_int_add(params, TRUE, c_expr);
    elsif getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_add(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
      process_const_int_add(params[3], getValue(evaluatedParam, integer), c_expr);
    elsif evaluate_const_expr = 0 and
          category(params[3]) = INTOBJECT and not isVar(params[3]) and
          getValue(params[3], integer) = integer.first then
      # Special case to avoid a compiler error of icc.
      process_const_int_add(params[1], integer.first, c_expr);
    elsif evaluate_const_expr = 0 and
          category(params[1]) = INTOBJECT and not isVar(params[1]) and
          getValue(params[1], integer) = integer.first then
      # Special case to avoid a compiler error of icc.
      process_const_int_add(params[3], integer.first, c_expr);
    else
      process_int_add(params[1], params[3], c_expr);
    end if;
  end func;


const proc: process_const_int_add_assign (in reference: variable, in integer: delta,
    inout expr_type: c_expr) is func

  local
    var string: variable_name is "";
    var expr_type: statement is expr_type.value;
  begin
    if delta = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "/* ignore integer +:= 0; */\n";
    elsif check_int_arithmetic_overflow then
      incr(countOptimizations);
      incr(countOverflowChecks);
      variable_name := getParameterAsReference("intType", "variable_", variable, statement);
      statement.expr &:= "if (ovfChk(";
      statement.expr &:= variable_name;
      if delta = -1 then
        statement.expr &:= "==";
        statement.expr &:= integerLiteral(integer.first);
      elsif delta = 1 then
        statement.expr &:= "==";
        statement.expr &:= integerLiteral(integer.last);
      elsif delta < 0 then
        statement.expr &:= "<";
        statement.expr &:= integerLiteral(integer.first - delta);
      else
        statement.expr &:= ">";
        statement.expr &:= integerLiteral(integer.last - delta);
      end if;
      statement.expr &:= ")) {\n";
      statement.expr &:= raiseError("OVERFLOW_ERROR");
      statement.expr &:= "} else {\n";
      statement.expr &:= variable_name;
      statement.expr &:= "+=";
      statement.expr &:= integerLiteral(delta);
      statement.expr &:= ";\n";
      statement.expr &:= "}\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      process_expr(variable, statement);
      statement.expr &:= "+=";
      statement.expr &:= integerLiteral(delta);
      statement.expr &:= ";\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (INT_ADD_ASSIGN, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: variable_name is "";
    var string: delta_name is "";
    var intRange: deltaRange is intRange.value;
    var expr_type: statement is expr_type.value;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_add_assign(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif check_int_arithmetic_overflow then
      deltaRange := getIntRange(params[3]);
      if deltaRange.minValue = 0 and deltaRange.maxValue = 0 then
        c_expr.expr &:= "/* ignore integer +:= 0; */\n";
      else
        incr(countOverflowChecks);
        variable_name := getParameterAsReference("intType", "variable_", params[1], statement);
        if ccConf.BUILTIN_ADD_OVERFLOW <> "" then
          statement.expr &:= "ovfChk(";
          statement.expr &:= ccConf.BUILTIN_ADD_OVERFLOW;
          statement.expr &:= "(";
          statement.expr &:= variable_name;
          statement.expr &:= ", ";
          process_expr(params[3], statement);
          statement.expr &:= ", &(";
          statement.expr &:= variable_name;
          statement.expr &:= ")))?";
          statement.expr &:= intRaiseError("OVERFLOW_ERROR");
          statement.expr &:= ":0;\n";
        else
          delta_name := getParameterAsVariable("intType", "delta_", params[3], statement);
          if deltaRange.minValue < 0 or deltaRange.maxValue > 0 then
            statement.expr &:= "ovfChk(";
            if deltaRange.minValue < 0 and deltaRange.maxValue > 0 then
              statement.expr &:= delta_name;
              statement.expr &:= "<0&&";
              statement.expr &:= variable_name;
              statement.expr &:= "<";
              statement.expr &:= integerLiteral(integer.first);
              statement.expr &:= "-";
              statement.expr &:= delta_name;
              statement.expr &:= " || ";
              statement.expr &:= delta_name;
              # The comparison >= 0 supports optimizations by the C compiler.
              statement.expr &:= ">=0&&";
              statement.expr &:= variable_name;
              statement.expr &:= ">";
              statement.expr &:= integerLiteral(integer.last);
              statement.expr &:= "-";
              statement.expr &:= delta_name;
            elsif deltaRange.minValue < 0 then
              statement.expr &:= variable_name;
              statement.expr &:= "<";
              statement.expr &:= integerLiteral(integer.first);
              statement.expr &:= "-";
              statement.expr &:= delta_name;
            else # deltaRange.maxValue > 0
              statement.expr &:= variable_name;
              statement.expr &:= ">";
              statement.expr &:= integerLiteral(integer.last);
              statement.expr &:= "-";
              statement.expr &:= delta_name;
            end if;
            statement.expr &:= ")?";
            statement.expr &:= intRaiseError("OVERFLOW_ERROR");
            statement.expr &:= ":";
          end if;
          statement.expr &:= "(";
          statement.expr &:= variable_name;
          statement.expr &:= "+=";
          statement.expr &:= delta_name;
          statement.expr &:= ");\n";
        end if;
        doLocalDeclsOfStatement(statement, c_expr);
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      process_expr(params[1], statement);
      statement.expr &:= "+=";
      process_expr(params[3], statement);
      statement.expr &:= ";\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process_const_int_binom (in integer: n_number, in reference: k_number,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: k_name is "";
  begin
    if getConstant(k_number, INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      block
        c_expr.expr &:= integerLiteral(n_number ! getValue(evaluatedParam, integer));
      exception
        catch OVERFLOW_ERROR:
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end block;
    elsif n_number = -1 then
      c_expr.expr &:= "(";
      k_name := getParameterAsVariable("intType", "k_number_", k_number, c_expr);
      c_expr.expr &:= k_name;
      c_expr.expr &:= "<0?0:(";
      c_expr.expr &:= k_name;
      c_expr.expr &:= "&1?-1:1))";
    elsif n_number = 0 then
      c_expr.expr &:= "(";
      process_expr(k_number, c_expr);
      c_expr.expr &:= ")==0?1:0";
    elsif n_number = 1 then
      c_expr.expr &:= "(";
      k_name := getParameterAsVariable("intType", "k_number_", k_number, c_expr);
      c_expr.expr &:= k_name;
      c_expr.expr &:= "==0||";
      c_expr.expr &:= k_name;
      c_expr.expr &:= "==1?1:0)";
    else
      if n_number >= 0 and
          ((ccConf.INTTYPE_SIZE = 32 and n_number <= 30) or
           (ccConf.INTTYPE_SIZE = 64 and n_number <= 62)) then
        c_expr.expr &:= "(intType) uintBinomNoChk((uintType) ";
      else
        c_expr.expr &:= "intBinom(";
      end if;
      c_expr.expr &:= integerLiteral(n_number);
      c_expr.expr &:= ", ";
      process_expr(k_number, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_int_binom (in reference: n_number, in integer: k_number,
    inout expr_type: c_expr) is func

  begin
    if k_number <= 1 then
      if k_number < 0 then
        c_expr.expr &:= "/* binom(n, negative k) */ ";
        c_expr.expr &:= integerLiteral(0);
      elsif k_number = 0 then
        c_expr.expr &:= "/* binom(n, 0) */ ";
        c_expr.expr &:= integerLiteral(1);
      else
        c_expr.expr &:= "/* binom(n, 1) */ ";
        process_expr(n_number, c_expr);
      end if;
    else
      c_expr.expr &:= "intBinom(";
      process_expr(n_number, c_expr);
      c_expr.expr &:= ", ";
      c_expr.expr &:= integerLiteral(k_number);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_BINOM, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
  begin
    if getConstant(params[1], INTOBJECT, evaluatedParam) then
      process_const_int_binom(getValue(evaluatedParam, integer), params[3], c_expr);
    elsif getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_binom(params[1], getValue(evaluatedParam, integer), c_expr);
    else
      c_expr.expr &:= "intBinom(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_BIT_LENGTH, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intBitLength(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: process (INT_BYTES_BE_2_INT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intBytesBe2Int(";
    getAnyParamToExpr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: optimize_int_bytes_2_uint_length_0 (in reference: stri,
    in reference: start, in boolean: fixedLengthSubstring,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var boolean: stri_is_variable is TRUE;
    var string: stri_name is "";
    var integer: stri_length is 0;
    var string: stri_size is "";
    var intRange: start_range is intRange.value;
    var string: start_name is "";
    var boolean: raisesException is FALSE;
    var string: logicalOr is "";
  begin
    incr(countOptimizations);
    incr(countInlinedFunctions);
    start_range := getIntRange(start);
    c_expr.expr &:= "(";
    if start_range.maxValue < 1 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
      raisesException := TRUE;
    elsif getConstant(stri, STRIOBJECT, evaluatedParam) then
      stri_is_variable := FALSE;
      stri_length := length(getValue(evaluatedParam, string));
      stri_size := memSizeLiteral(stri_length);
      if start_range.minValue > stri_length then
        if fixedLengthSubstring then
          warning(DOES_RAISE, "INDEX_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
        else
          warning(DOES_RAISE, "RANGE_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("RANGE_ERROR");
        end if;
        raisesException := TRUE;
      end if;
    else
      stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
      stri_size := stri_name & "->size";
    end if;
    if not raisesException then
      if getConstant(start, INTOBJECT, evaluatedParam) then
        start_name := integerLiteral(getValue(evaluatedParam, integer));
      else
        start_name := getTempVariable("intType", "start_", start, c_expr);
      end if;
      if string_index_check then
        if start_range.minValue < 1 or (fixedLengthSubstring and
            (stri_is_variable or start_range.maxValue > stri_length)) then
          incr(countIndexChecks);
          c_expr.expr &:= "idxChk(";
          if start_range.minValue < 1 then
            c_expr.expr &:= start_name;
            c_expr.expr &:= "<1";
            logicalOr := "||";
          end if;
          if fixedLengthSubstring and
              (stri_is_variable or start_range.maxValue > stri_length) then
            c_expr.expr &:= logicalOr;
            c_expr.expr &:= start_name;
            c_expr.expr &:= ">";
            c_expr.expr &:= stri_size;
          end if;
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":";
        else
          countIndexOptimizations(c_expr);
        end if;
      else
        incr(countSuppressedIndexChecks);
      end if;
      c_expr.expr &:= intRaiseError("RANGE_ERROR");
    end if;
    c_expr.expr &:= ")";
  end func;


const proc: optimize_int_bytes_2_uint_length_1 (in reference: stri,
    in reference: start, in boolean: fixedLengthSubstring,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var boolean: stri_is_variable is TRUE;
    var string: stri_name is "";
    var string: stri_value is "";
    var integer: stri_length is 0;
    var string: stri_size is "";
    var string: start_name is "";
    var integer: start_value is 0;
    var intRange: start_range is intRange.value;
    var boolean: raisesException is FALSE;
    var string: logicalOr is "";
  begin
    incr(countOptimizations);
    incr(countInlinedFunctions);
    c_expr.expr &:= "(";
    if getConstant(stri, STRIOBJECT, evaluatedParam) then
      stri_is_variable := FALSE;
      stri_value := getValue(evaluatedParam, string);
      stri_name := "(" & stringLiteral(stri_value) & ")";
      stri_length := length(stri_value);
      stri_size := memSizeLiteral(stri_length);
    else
      stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
      stri_size := stri_name & "->size";
    end if;
    start_range := getIntRange(start);
    if start_range.maxValue < 1 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
      raisesException := TRUE;
    elsif not stri_is_variable and start_range.minValue > stri_length then
      if fixedLengthSubstring then
        warning(DOES_RAISE, "INDEX_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("INDEX_ERROR");
      else
        warning(DOES_RAISE, "RANGE_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("RANGE_ERROR");
      end if;
      raisesException := TRUE;
    elsif getConstant(start, INTOBJECT, evaluatedParam) then
      start_value := getValue(evaluatedParam, integer);
      start_name := integerLiteral(start_value);
    else
      start_name := getTempVariable("intType", "start_", start, c_expr);
    end if;
    if not raisesException then
      if string_index_check then
        if start_range.minValue < 1 or (fixedLengthSubstring and
            (stri_is_variable or start_range.maxValue > stri_length)) then
          incr(countIndexChecks);
          c_expr.expr &:= "idxChk(";
          if start_range.minValue < 1 then
            c_expr.expr &:= start_name;
            c_expr.expr &:= "<1";
            logicalOr := "||";
          end if;
          if fixedLengthSubstring and
              (stri_is_variable or start_range.maxValue > stri_length) then
            c_expr.expr &:= logicalOr;
            c_expr.expr &:= start_name;
            c_expr.expr &:= ">";
            c_expr.expr &:= stri_size;
          end if;
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("INDEX_ERROR");
          c_expr.expr &:= ":";
        else
          countIndexOptimizations(c_expr);
        end if;
      else
        incr(countSuppressedIndexChecks);
      end if;
      c_expr.expr &:= "(";
      if function_range_check then
        incr(countRangeChecks);
        c_expr.expr &:= "rngChk(";
        if not fixedLengthSubstring then
          c_expr.expr &:= start_name;
          c_expr.expr &:= ">";
          c_expr.expr &:= stri_size;
          c_expr.expr &:= "||";
        end if;
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[";
        c_expr.expr &:= start_name;
        c_expr.expr &:= "-1]>255)?";
        c_expr.expr &:= intRaiseError("RANGE_ERROR");
        c_expr.expr &:= ":";
      else
        incr(countNoRangeChecks);
      end if;
      c_expr.expr &:= "(intType)";
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->mem[";
      c_expr.expr &:= start_name;
      c_expr.expr &:= "-1])";
    end if;
    c_expr.expr &:= ")";
  end func;


const proc: optimize_int_bytes_be_2_uint (in string: stri_name, in integer: length,
    inout expr_type: c_expr) is func

  local
    var integer: index is 0;
  begin
    for index range 1 to length do
      if index <> 1 then
        c_expr.expr &:= "|";
      end if;
      if function_range_check then
        incr(countRangeChecks);
        c_expr.expr &:= "(rngChk(";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[";
        c_expr.expr &:= integerLiteral(pred(index));
        c_expr.expr &:= "]>";
        if length = 8 and index = 1 then
          c_expr.expr &:= "127";
        else
          c_expr.expr &:= "255";
        end if;
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("RANGE_ERROR");
        c_expr.expr &:= ":(intType)";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[";
        c_expr.expr &:= integerLiteral(pred(index));
        c_expr.expr &:= "])";
      else
        incr(countNoRangeChecks);
        c_expr.expr &:= "(intType)";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[";
        c_expr.expr &:= integerLiteral(pred(index));
        c_expr.expr &:= "]";
      end if;
      if index < length then
        c_expr.expr &:= "<<";
        c_expr.expr &:= integerLiteral((length - index) * 8);
      end if;
    end for;
  end func;


const proc: optimize_int_bytes_be_2_uint (in reference: stri, in integer: length,
    in boolean: fixedLengthSubstring, inout expr_type: c_expr) is func

  local
    var string: stri_name is "";
  begin
    if length < 0 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
    elsif length = 0 then
      optimize_int_bytes_2_uint_length_0(getValue(stri, ref_list)[2],
          getValue(stri, ref_list)[4], fixedLengthSubstring, c_expr);
    elsif length = 1 then
      optimize_int_bytes_2_uint_length_1(getValue(stri, ref_list)[2],
          getValue(stri, ref_list)[4], fixedLengthSubstring, c_expr);
    elsif length >= 2 and length <= 8 then
      incr(countOptimizations);
      incr(countInlinedFunctions);
      c_expr.expr &:= "(";
      stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
      if fixedLengthSubstring then
        optimize_int_bytes_be_2_uint(stri_name, length, c_expr);
      else
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->size==";
        c_expr.expr &:= integerLiteral(length);
        c_expr.expr &:= "?(";
        optimize_int_bytes_be_2_uint(stri_name, length, c_expr);
        c_expr.expr &:= "):intBytesBe2UInt(";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "intBytesBe2UInt(";
      getAnyParamToExpr(stri, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_BYTES_BE_2_UINT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
  begin
    if inlineFunctions and
        isActionExpression(params[1], "STR_SUBSTR") and
        getConstant(getActionParameter(params[1], 5), INTOBJECT, evaluatedParam) then
      optimize_int_bytes_be_2_uint(params[1],
          getValue(evaluatedParam, integer), FALSE, c_expr);
    elsif inlineFunctions and
        isActionExpression(params[1], "STR_SUBSTR_FIXLEN") and
        getConstant(getActionParameter(params[1], 5), INTOBJECT, evaluatedParam) then
      optimize_int_bytes_be_2_uint(params[1],
          getValue(evaluatedParam, integer), TRUE, c_expr);
    else
      c_expr.expr &:= "intBytesBe2UInt(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_BYTES_BE_SIGNED, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    prepare_stri_result(c_expr);
    c_expr.result_expr := "intBytesBe(";
    getStdParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", 1)";
  end func;


const proc: process (INT_BYTES_BE_UNSIGNED, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    prepare_stri_result(c_expr);
    c_expr.result_expr := "intBytesBe(";
    getStdParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", 0)";
  end func;


const proc: process (INT_BYTES_LE_2_INT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intBytesLe2Int(";
    getAnyParamToExpr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: optimize_int_bytes_le_2_uint (in string: stri_name, in integer: length,
    inout expr_type: c_expr) is func

  local
    var integer: index is 0;
  begin
    for index range 1 to length do
      if index <> 1 then
        c_expr.expr &:= "|";
      end if;
      if function_range_check then
        incr(countRangeChecks);
        c_expr.expr &:= "(rngChk(";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[";
        c_expr.expr &:= integerLiteral(pred(index));
        c_expr.expr &:= "]>";
        if length = 8 and index = 8 then
          c_expr.expr &:= "127";
        else
          c_expr.expr &:= "255";
        end if;
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("RANGE_ERROR");
        c_expr.expr &:= ":(intType)";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[";
        c_expr.expr &:= integerLiteral(pred(index));
        c_expr.expr &:= "])";
      else
        incr(countNoRangeChecks);
        c_expr.expr &:= "(intType)";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->mem[";
        c_expr.expr &:= integerLiteral(pred(index));
        c_expr.expr &:= "]";
      end if;
      if index <> 1 then
        c_expr.expr &:= "<<";
        c_expr.expr &:= integerLiteral(pred(index) * 8);
      end if;
    end for;
  end func;


const proc: optimize_int_bytes_le_2_uint (in reference: stri, in integer: length,
    in boolean: fixedLengthSubstring, inout expr_type: c_expr) is func

  local
    var string: stri_name is "";
  begin
    if length < 0 then
      warning(DOES_RAISE, "INDEX_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("INDEX_ERROR");
    elsif length = 0 then
      optimize_int_bytes_2_uint_length_0(getValue(stri, ref_list)[2],
          getValue(stri, ref_list)[4], fixedLengthSubstring, c_expr);
    elsif length = 1 then
      optimize_int_bytes_2_uint_length_1(getValue(stri, ref_list)[2],
          getValue(stri, ref_list)[4], fixedLengthSubstring, c_expr);
    elsif length >= 2 and length <= 8 then
      incr(countOptimizations);
      incr(countInlinedFunctions);
      c_expr.expr &:= "(";
      stri_name := getParameterAsVariable("const_striType", "stri_", stri, c_expr);
      if fixedLengthSubstring then
        optimize_int_bytes_le_2_uint(stri_name, length, c_expr);
      else
        c_expr.expr &:= stri_name;
        c_expr.expr &:= "->size==";
        c_expr.expr &:= integerLiteral(length);
        c_expr.expr &:= "?(";
        optimize_int_bytes_le_2_uint(stri_name, length, c_expr);
        c_expr.expr &:= "):intBytesLe2UInt(";
        c_expr.expr &:= stri_name;
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "intBytesLe2UInt(";
      getAnyParamToExpr(stri, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_BYTES_LE_2_UINT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
  begin
    if inlineFunctions and
        isActionExpression(params[1], "STR_SUBSTR") and
        getConstant(getActionParameter(params[1], 5), INTOBJECT, evaluatedParam) then
      optimize_int_bytes_le_2_uint(params[1],
          getValue(evaluatedParam, integer), FALSE, c_expr);
    elsif inlineFunctions and
        isActionExpression(params[1], "STR_SUBSTR_FIXLEN") and
        getConstant(getActionParameter(params[1], 5), INTOBJECT, evaluatedParam) then
      optimize_int_bytes_le_2_uint(params[1],
          getValue(evaluatedParam, integer), TRUE, c_expr);
    else
      c_expr.expr &:= "intBytesLe2UInt(";
      getAnyParamToExpr(params[1], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_BYTES_LE_SIGNED, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    prepare_stri_result(c_expr);
    c_expr.result_expr := "intBytesLe(";
    getStdParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", 1)";
  end func;


const proc: process (INT_BYTES_LE_UNSIGNED, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    prepare_stri_result(c_expr);
    c_expr.result_expr := "intBytesLe(";
    getStdParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", 0)";
  end func;


const proc: process (INT_CMP, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var string: number1_name is "";
    var string: number2_name is "";
  begin
    if inlineFunctions then
      incr(countOptimizations);
      incr(countInlinedFunctions);
      c_expr.expr &:= "(";
      number1_name := getParameterAsVariable("intType", "number1_", params[1], c_expr);
      number2_name := getParameterAsVariable("intType", "number2_", params[2], c_expr);
      c_expr.expr &:= number1_name;
      c_expr.expr &:= "<";
      c_expr.expr &:= number2_name;
      c_expr.expr &:= "? -1 : ";
      c_expr.expr &:= number1_name;
      c_expr.expr &:= ">";
      c_expr.expr &:= number2_name;
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "intCmp(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[2], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_CPY, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var expr_type: statement is expr_type.value;
  begin
    statement.temp_num := c_expr.temp_num;
    process_expr(params[1], statement);
    statement.expr &:= "=";
    process_expr(params[3], statement);
    statement.expr &:= ";\n";
    doLocalDeclsOfStatement(statement, c_expr);
    c_expr.temp_num := statement.temp_num;
  end func;


const proc: process (INT_DECR, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var expr_type: c_param1 is expr_type.value;
    var string: variable_name is "";
    var expr_type: statement is expr_type.value;
  begin
    if check_int_arithmetic_overflow then
      incr(countOverflowChecks);
      if isNormalVariable(params[1]) then
        process_expr(params[1], c_param1);
        statement.expr &:= "if (ovfChk(";
        statement.expr &:= c_param1.expr;
        statement.expr &:= "==";
        statement.expr &:= integerLiteral(integer.first);
        statement.expr &:= ")) {";
        statement.expr &:= raiseError("OVERFLOW_ERROR");
        statement.expr &:= "} else --(";
        statement.expr &:= c_param1.expr;
        statement.expr &:= ");\n";
      else
        incr(statement.temp_num);
        variable_name := "var_" & str(statement.temp_num);
        statement.temp_decls &:= "intType *";
        statement.temp_decls &:= variable_name;
        statement.temp_decls &:= ";\n";
        statement.expr &:= variable_name;
        statement.expr &:= "=&(";
        process_expr(params[1], statement);
        statement.expr &:= ");\n";
        statement.expr &:= "if (ovfChk(*";
        statement.expr &:= variable_name;
        statement.expr &:= "==";
        statement.expr &:= integerLiteral(integer.first);
        statement.expr &:= ")) {";
        statement.expr &:= raiseError("OVERFLOW_ERROR");
        statement.expr &:= "} else --(*";
        statement.expr &:= variable_name;
        statement.expr &:= ");\n";
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      statement.expr &:= "--(";
      process_expr(params[1], statement);
      statement.expr &:= ");\n";
    end if;
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


const proc: process_const_int_mult (in reference: factor1, in integer: factor2,
    inout expr_type: c_expr) is forward;


const proc: process_const_int_div (in reference: dividend, in integer: divisor,
    inout expr_type: c_expr) is forward;


const func boolean: optimize_div_of_product (in reference: number, in integer: factor,
    in integer: divisor, inout expr_type: c_expr) is func

  result
    var boolean: done is TRUE;
  begin
    if factor = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "0";
    elsif factor = divisor then
      incr(countOptimizations);
      countOverflowOptimizations(c_expr);
      process_expr(number, c_expr);
    elsif factor rem divisor = 0 then
      incr(countOptimizations);
      process_const_int_mult(number, factor div divisor, c_expr);
    elsif divisor rem factor = 0 then
      incr(countOptimizations);
      countOverflowOptimizations(c_expr);
      process_const_int_div(number, divisor div factor, c_expr);
    else
      done := FALSE;
    end if;
  end func;


const proc: process_const_int_div (in reference: dividend, in integer: divisor,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedDividend is NIL;
    var reference: evaluatedFactor is NIL;
    var integer: dividend_value is 0;
    var string: dividend_name is "";
    var intRange: dividend_range is intRange.value;
    var boolean: done is TRUE;
  begin
    if divisor = 0 then
      incr(countOptimizations);
      warning(DOES_RAISE, "NUMERIC_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
    elsif getConstant(dividend, INTOBJECT, evaluatedDividend) then
      incr(countOptimizations);
      dividend_value := getValue(evaluatedDividend, integer);
      if divisor = -1 and dividend_value < -integer.last then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= integerLiteral(dividend_value div divisor);
      end if;
    elsif divisor = 1 then
      incr(countOptimizations);
      c_expr.expr &:= "(";
      process_expr(dividend, c_expr);
      c_expr.expr &:= ")";
    elsif isActionExpression(dividend, "INT_MULT") and
        getConstant(getActionParameter(dividend, 3), INTOBJECT, evaluatedFactor) then
      done := optimize_div_of_product(getActionParameter(dividend, 1),
            getValue(evaluatedFactor, integer), divisor, c_expr);
    elsif isActionExpression(dividend, "INT_MULT") and
        getConstant(getActionParameter(dividend, 1), INTOBJECT, evaluatedFactor) then
      done := optimize_div_of_product(getActionParameter(dividend, 3),
            getValue(evaluatedFactor, integer), divisor, c_expr);
    else
      done := FALSE;
    end if;
    if not done then
      if divisor = -1 then
        # Dividing by -1 is equal to changing the sign.
        # integer.first / -1 causes an integer overflow.
        incr(countOptimizations);
        negate(dividend, c_expr);
      elsif divisor > 0 and 2 ** log2(divisor) = divisor then
        # Divisor is a power of two.
        dividend_range := getIntRange(dividend);
        if dividend_range.minValue >= 0 then
          incr(countOptimizations);
          if ccConf.RSHIFT_DOES_SIGN_EXTEND then
            c_expr.expr &:= "(";
            process_expr(dividend, c_expr);
            c_expr.expr &:= ") >> ";
            c_expr.expr &:= integerLiteral(log2(divisor));
          else
            c_expr.expr &:= "(";
            dividend_name := getParameterAsVariable("intType", "dividend_", dividend, c_expr);
            doRshift(dividend_name, integerLiteral(log2(divisor)), c_expr);
            c_expr.expr &:= ")";
          end if;
        else
          c_expr.expr &:= "(";
          process_expr(dividend, c_expr);
          c_expr.expr &:= ") / ";
          c_expr.expr &:= integerLiteral(divisor);
        end if;
      elsif divisor < 0 and bitLength(divisor) = lowestSetBit(divisor) then
        # Divisor is a negative power of two.
        # The check above is (almost) equivalent to:
        #   divisor < 0 and 2 ** log2(-divisor) = -divisor
        # The check with bitLength is used to avoid negating the divisor.
        # Negating the divisor would fail for the most negative integer.
        dividend_range := getIntRange(dividend);
        if dividend_range.maxValue <= 0 then
          incr(countOptimizations);
          c_expr.expr &:= "(intType)(-(uintType)(";
          process_expr(dividend, c_expr);
          c_expr.expr &:= ") >> ";
          c_expr.expr &:= integerLiteral(bitLength(divisor));
          c_expr.expr &:= ")";
        else
          c_expr.expr &:= "(";
          process_expr(dividend, c_expr);
          c_expr.expr &:= ") / ";
          c_expr.expr &:= integerLiteral(divisor);
        end if;
      else
        c_expr.expr &:= "(";
        process_expr(dividend, c_expr);
        c_expr.expr &:= ") / ";
        c_expr.expr &:= integerLiteral(divisor);
      end if;
    end if;
  end func;


const proc: process_const_int_div (in integer: dividend, in reference: divisor,
    inout expr_type: c_expr) is func

  local
    var string: divisor_name is "";
    var intRange: divisor_range is intRange.value;
  begin
    divisor_range := getIntRange(divisor);
    if dividend = 0 then
      incr(countOptimizations);
      if integer_division_check then
        if (divisor_range.minValue <= 0 and divisor_range.maxValue >= 0) or
            divisor_range.mayRaiseException then
          incr(countDivisionChecks);
          c_expr.expr &:= "(divChk((";
          process_expr(divisor, c_expr);
          c_expr.expr &:= ")==0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":0)";
        else
          countDivisionOptimizations(c_expr);
          c_expr.expr &:= "0";
        end if;
      else
        c_expr.expr &:= "0";
      end if;
    elsif check_int_division_overflow and dividend = integer.first then
      # integer.first / -1 causes an integer overflow.
      if divisor_range.maxValue < -1 or divisor_range.minValue > 0 then
        # No checks for integer overflow and division by zero necessary.
        countOverflowOptimizations(c_expr);
        if check_int_div_by_zero then
          countDivisionOptimizations(c_expr);
        end if;
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= " / (";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")";
      else
        c_expr.expr &:= "(";
        divisor_name := getParameterAsVariable("intType", "divisor_", divisor, c_expr);
        if divisor_range.minValue <= -1 and divisor_range.maxValue >= -1 then
          incr(countOverflowChecks);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "==-1)?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
        else
          countOverflowOptimizations(c_expr);
        end if;
        if check_int_div_by_zero then
          if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
            incr(countDivisionChecks);
            c_expr.expr &:= "divChk(";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= "==0)?";
            c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
            c_expr.expr &:= ":";
          else
            countDivisionOptimizations(c_expr);
          end if;
        end if;
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= " / ";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= ")";
      end if;
    else
      if dividend = integer.first then
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      end if;
      if check_int_div_by_zero then
        if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
          incr(countDivisionChecks);
          c_expr.expr &:= "(";
          divisor_name := getParameterAsVariable("intType", "divisor_", divisor, c_expr);
          c_expr.expr &:= "divChk(";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "==0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":";
          c_expr.expr &:= integerLiteral(dividend);
          c_expr.expr &:= " / ";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= ")";
        else
          countDivisionOptimizations(c_expr);
          c_expr.expr &:= integerLiteral(dividend);
          c_expr.expr &:= " / (";
          process_expr(divisor, c_expr);
          c_expr.expr &:= ")";
        end if;
      else
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= " / (";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")";
      end if;
    end if;
  end func;


const proc: process (INT_DIV, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: dividend_name is "";
    var string: divisor_name is "";
    var intRange: dividend_range is intRange.value;
    var intRange: divisor_range is intRange.value;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_div(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
      process_const_int_div(getValue(evaluatedParam, integer), params[3], c_expr);
    elsif evaluate_const_expr = 0 and
          category(params[3]) = INTOBJECT and not isVar(params[3]) and
          getValue(params[3], integer) = 0 then
      warning(DOES_RAISE, "NUMERIC_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
    elsif evaluate_const_expr = 0 and check_int_div_zero_by_zero and
          category(params[1]) = INTOBJECT and not isVar(params[1]) and
          getValue(params[1], integer) = 0 then
      incr(countDivisionChecks);
      c_expr.expr &:= "(divChk((";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    else
      divisor_range := getIntRange(params[3]);
      if params[1] = params[3] then
        # C compilers are allowed to optimize variable/variable to 1.
        # A C compiler can assume, that an "undefined behavior", like a
        # division by zero will never happen. So we need to handle this case.
        if integer_division_check then
          if (divisor_range.minValue <= 0 and divisor_range.maxValue >= 0) or
              divisor_range.mayRaiseException then
            incr(countDivisionChecks);
            c_expr.expr &:= "(divChk((";
            process_expr(params[1], c_expr);
            c_expr.expr &:= ")==0)?";
            c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
            c_expr.expr &:= ":1)";
          else
            countDivisionOptimizations(c_expr);
            c_expr.expr &:= "1";
          end if;
        else
          c_expr.expr &:= "1";
        end if;
      elsif check_int_division_overflow then
        # integer.first / -1 causes an integer overflow.
        dividend_range := getIntRange(params[1]);
        if (dividend_range.minValue > integer.first or
            divisor_range.maxValue < -1 or divisor_range.minValue > -1) and
            (not check_int_div_by_zero or
            divisor_range.maxValue < 0 or divisor_range.minValue > 0) then
          # No checks for integer overflow and division by zero necessary.
          countOverflowOptimizations(c_expr);
          if check_int_div_by_zero then
            countDivisionOptimizations(c_expr);
          end if;
          c_expr.expr &:= "(";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ") / (";
          process_expr(params[3], c_expr);
          c_expr.expr &:= ")";
        else
          c_expr.expr &:= "(";
          dividend_name := getParameterAsVariable("intType", "dividend_", params[1], c_expr);
          divisor_name := getParameterAsVariable("intType", "divisor_", params[3], c_expr);
          if dividend_range.minValue = integer.first and
              divisor_range.minValue <= -1 and divisor_range.maxValue >= -1 then
            incr(countOverflowChecks);
            c_expr.expr &:= "ovfChk(";
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= "==";
            c_expr.expr &:= integerLiteral(integer.first);
            c_expr.expr &:= "&&";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= "==-1";
            c_expr.expr &:= ")?";
            c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
            c_expr.expr &:= ":";
          else
            countOverflowOptimizations(c_expr);
          end if;
          if check_int_div_by_zero then
            if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
              incr(countDivisionChecks);
              c_expr.expr &:= "divChk(";
              c_expr.expr &:= divisor_name;
              c_expr.expr &:= "==0)?";
              c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
              c_expr.expr &:= ":";
            else
              countDivisionOptimizations(c_expr);
            end if;
          end if;
          c_expr.expr &:= dividend_name;
          c_expr.expr &:= " / ";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= ")";
        end if;
      else
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
        if check_int_div_by_zero then
          if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
            incr(countDivisionChecks);
            c_expr.expr &:= "(";
            divisor_name := getParameterAsVariable("intType", "divisor_", params[3], c_expr);
            c_expr.expr &:= "divChk(";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= "==0)?";
            c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
            c_expr.expr &:= ":(";
            process_expr(params[1], c_expr);
            c_expr.expr &:= ") / ";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= ")";
          else
            countDivisionOptimizations(c_expr);
            c_expr.expr &:= "(";
            process_expr(params[1], c_expr);
            c_expr.expr &:= ") / (";
            process_expr(params[3], c_expr);
            c_expr.expr &:= ")";
          end if;
        else
          c_expr.expr &:= "(";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ") / (";
          process_expr(params[3], c_expr);
          c_expr.expr &:= ")";
        end if;
      end if;
    end if;
  end func;


const proc: process (INT_EQ, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var intRange: number1Range is intRange.value;
    var intRange: number2Range is intRange.value;
    var boolean: doCompare is TRUE;
  begin
    if optimizeComparisons then
      number1Range := getIntRange(params[1]);
      number2Range := getIntRange(params[3]);
      if not number1Range.mayRaiseException and not number2Range.mayRaiseException then
        if number1Range.minValue = number1Range.maxValue and
            number2Range.minValue = number2Range.maxValue and
            number1Range.minValue = number2Range.minValue then
          warning(COMPARISON_RESULT_CONSTANT, "=", TRUE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "1";
          doCompare := FALSE;
        elsif number1Range.maxValue < number2Range.minValue or
            number1Range.minValue > number2Range.maxValue then
          warning(COMPARISON_RESULT_CONSTANT, "=", FALSE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "0";
          doCompare := FALSE;
        end if;
      end if;
    end if;
    if doCompare then
      c_expr.expr &:= "(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ") == (";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_FACT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var integer: number is 0;
    var integer: limit is 0;
    var string: number_name is "";
  begin
    if getConstant(params[2], INTOBJECT, evaluatedParam) then
      number := getValue(evaluatedParam, integer);
      if ccConf.INTTYPE_SIZE = 64 then
        limit := 20;
      else
        limit := 12;
      end if;
      if number < 0 or number > limit then
        warning(DOES_RAISE, "NUMERIC_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      else
        c_expr.expr &:= integerLiteral(!number);
      end if;
    else
      c_expr.expr &:= "(";
      number_name := getParameterAsVariable("intType", "number_", params[2], c_expr);
      c_expr.expr &:= "numChk(";
      checkRangeFromZero(number_name, "sizeof(fact)/sizeof(intType)", c_expr);
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":fact[";
      c_expr.expr &:= number_name;
      c_expr.expr &:= "])";
    end if;
  end func;


const proc: process (INT_GE, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var intRange: number1Range is intRange.value;
    var intRange: number2Range is intRange.value;
    var boolean: doCompare is TRUE;
  begin
    if optimizeComparisons then
      number1Range := getIntRange(params[1]);
      number2Range := getIntRange(params[3]);
      if not number1Range.mayRaiseException and not number2Range.mayRaiseException then
        if number1Range.minValue >= number2Range.maxValue then
          warning(COMPARISON_RESULT_CONSTANT, ">=", TRUE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "1";
          doCompare := FALSE;
        elsif number1Range.maxValue < number2Range.minValue then
          warning(COMPARISON_RESULT_CONSTANT, ">=", FALSE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "0";
          doCompare := FALSE;
        end if;
      end if;
    end if;
    if doCompare then
      c_expr.expr &:= "(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ") >= (";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_GT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var intRange: number1Range is intRange.value;
    var intRange: number2Range is intRange.value;
    var boolean: doCompare is TRUE;
  begin
    if optimizeComparisons then
      number1Range := getIntRange(params[1]);
      number2Range := getIntRange(params[3]);
      if not number1Range.mayRaiseException and not number2Range.mayRaiseException then
        if number1Range.minValue > number2Range.maxValue then
          warning(COMPARISON_RESULT_CONSTANT, ">", TRUE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "1";
          doCompare := FALSE;
        elsif number1Range.maxValue <= number2Range.minValue then
          warning(COMPARISON_RESULT_CONSTANT, ">", FALSE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "0";
          doCompare := FALSE;
        end if;
      end if;
    end if;
    if doCompare then
      c_expr.expr &:= "(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ") > (";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_HASHCODE, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: process (INT_ICONV1, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: process (INT_ICONV3, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "(";
    process_expr(params[3], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: process (INT_INCR, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var expr_type: c_param1 is expr_type.value;
    var string: variable_name is "";
    var expr_type: statement is expr_type.value;
  begin
    if check_int_arithmetic_overflow then
      incr(countOverflowChecks);
      if isNormalVariable(params[1]) then
        process_expr(params[1], c_param1);
        statement.expr &:= "if (ovfChk(";
        statement.expr &:= c_param1.expr;
        statement.expr &:= "==";
        statement.expr &:= integerLiteral(integer.last);
        statement.expr &:= ")) {";
        statement.expr &:= raiseError("OVERFLOW_ERROR");
        statement.expr &:= "} else ++(";
        statement.expr &:= c_param1.expr;
        statement.expr &:= ");\n";
      else
        incr(statement.temp_num);
        variable_name := "var_" & str(statement.temp_num);
        statement.temp_decls &:= "intType *";
        statement.temp_decls &:= variable_name;
        statement.temp_decls &:= ";\n";
        statement.expr &:= variable_name;
        statement.expr &:= "=&(";
        process_expr(params[1], statement);
        statement.expr &:= ");\n";
        statement.expr &:= "if (ovfChk(*";
        statement.expr &:= variable_name;
        statement.expr &:= "==";
        statement.expr &:= integerLiteral(integer.last);
        statement.expr &:= ")) {";
        statement.expr &:= raiseError("OVERFLOW_ERROR");
        statement.expr &:= "} else ++(*";
        statement.expr &:= variable_name;
        statement.expr &:= ");\n";
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      statement.expr &:= "++(";
      process_expr(params[1], statement);
      statement.expr &:= ");\n";
    end if;
    doLocalDeclsOfStatement(statement, c_expr);
  end func;


const proc: process (INT_LE, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var intRange: number1Range is intRange.value;
    var intRange: number2Range is intRange.value;
    var boolean: doCompare is TRUE;
  begin
    if optimizeComparisons then
      number1Range := getIntRange(params[1]);
      number2Range := getIntRange(params[3]);
      if not number1Range.mayRaiseException and not number2Range.mayRaiseException then
        if number1Range.maxValue <= number2Range.minValue then
          warning(COMPARISON_RESULT_CONSTANT, "<=", TRUE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "1";
          doCompare := FALSE;
        elsif number1Range.minValue > number2Range.maxValue then
          warning(COMPARISON_RESULT_CONSTANT, "<=", FALSE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "0";
          doCompare := FALSE;
        end if;
      end if;
    end if;
    if doCompare then
      c_expr.expr &:= "(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ") <= (";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_LOG10, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intLog10(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: process (INT_LOG2, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intLog2(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: process (INT_LOWEST_SET_BIT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intLowestSetBit(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: process (INT_LPAD0, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) and
        getValue(evaluatedParam, integer) <= 1 then
      incr(countOptimizations);
      process_int_str(params[1], c_expr);
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "intLpad0(";
      getStdParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= ",";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process_const_int_lshift (in reference: number, in integer: lshift,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedNumber is NIL;
    var integer: number_value is 0;
    var intRange: number_range is intRange.value;
    var string: number_name is "";
    var integer: minAllowedNumber is 0;
    var integer: maxAllowedNumber is 0;
    var boolean: fullOverflowCheck is FALSE;
  begin
    if lshift < 0 or lshift >= ccConf.INTTYPE_SIZE then
      incr(countOptimizations);
      warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
    elsif getConstant(number, INTOBJECT, evaluatedNumber) then
      incr(countOptimizations);
      number_value := getValue(evaluatedNumber, integer);
      if number_value < integer.first >> lshift or
          number_value > integer.last >> lshift then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= integerLiteral(number_value << lshift);
      end if;
    elsif lshift = 0 then
      incr(countOptimizations);
      process_expr(number, c_expr);
    elsif check_int_shift_overflow then
      incr(countOptimizations);
      minAllowedNumber := integer.first >> lshift;
      maxAllowedNumber := integer.last >> lshift;
      number_range := getIntRange(number);
      if number_range <> intRange.value then
        if  number_range.minValue >= minAllowedNumber and
            number_range.maxValue <= maxAllowedNumber then
          # This lshift cannot overflow
          countOverflowOptimizations(c_expr);
          c_expr.expr &:= "/*no_overflow_check_lshift*/(";
          process_expr(number, c_expr);
          c_expr.expr &:= ") << ";
          c_expr.expr &:= integerLiteral(lshift);
        elsif number_range.minValue >= minAllowedNumber or
              number_range.maxValue <= maxAllowedNumber then
          incr(countOverflowChecks);
          c_expr.expr &:= "/*simplified_overflow_check_lshift*/(";
          number_name := getParameterAsVariable("intType", "number_", number, c_expr);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= number_name;
          if number_range.minValue >= minAllowedNumber then
            c_expr.expr &:= ">";
            c_expr.expr &:= integerLiteral(maxAllowedNumber);
          else
            c_expr.expr &:= "<";
            c_expr.expr &:= integerLiteral(minAllowedNumber);
          end if;
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
          c_expr.expr &:= number_name;
          c_expr.expr &:= " << ";
          c_expr.expr &:= integerLiteral(lshift);
          c_expr.expr &:= ")";
        else
          fullOverflowCheck := TRUE;
        end if;
      else
        fullOverflowCheck := TRUE;
      end if;
      if fullOverflowCheck then
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        number_name := getParameterAsVariable("intType", "number_", number, c_expr);
        c_expr.expr &:= "ovfChk(";
        checkIfOutsideRange(number_name, minAllowedNumber,
                            maxAllowedNumber, c_expr);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":";
        c_expr.expr &:= number_name;
        c_expr.expr &:= " << ";
        c_expr.expr &:= integerLiteral(lshift);
        c_expr.expr &:= ")";
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "(";
      process_expr(number, c_expr);
      c_expr.expr &:= ") << ";
      c_expr.expr &:= integerLiteral(lshift);
    end if;
  end func;


const proc: optimize_int_lshift_by_sum (in integer: number, in reference: lshift,
    in integer: deltaLshift, inout expr_type: c_expr) is func

  local
    var string: lshift_name is "";
  begin
# (ovfChk((uintType)(o_4995_bitWidth)-(uintType)1L>(uintType)63L)?intRaiseError(OVERFLOW_ERROR):1L << ((o_4995_bitWidth) - 1L))
    writeln(c_expr.currentFile <& "(" <& c_expr.currentLine <& ")");
    c_expr.expr &:= "(";
    lshift_name := defineTempVariable("uintType", "lshift_", c_expr);
    c_expr.expr &:= lshift_name;
    c_expr.expr &:= "=(uintType)(";
    process_expr(lshift, c_expr);
    c_expr.expr &:= ")";
    if deltaLshift > 0 or deltaLshift = integer.first then
      c_expr.expr &:= "+(uintType)";
      c_expr.expr &:= integerLiteral(deltaLshift);
    elsif deltaLshift < 0 then
      c_expr.expr &:= "-(uintType)";
      c_expr.expr &:= integerLiteral(-deltaLshift);
    end if;
    c_expr.expr &:= ",";
    c_expr.expr &:= "ovfChk(";
    checkRangeFromZero(lshift_name,
        integerLiteral(ccConf.INTTYPE_SIZE - bitLength(number)), c_expr);
    c_expr.expr &:= ")?";
    c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
    c_expr.expr &:= ":";
    if number = 0 then
      c_expr.expr &:= integerLiteral(0);
    else
      c_expr.expr &:= integerLiteral(number);
      c_expr.expr &:= " << ";
      c_expr.expr &:= lshift_name;
    end if;
    c_expr.expr &:= ")";
  end func;


const proc: process_const_int_lshift (in integer: number, in reference: lshift,
    inout expr_type: c_expr) is func

  local
    var string: lshift_name is "";
    var intRange: lshift_range is intRange.value;
    var boolean: raisesException is FALSE;
    var boolean: doOverflowCheck is FALSE;
    var reference: evaluatedDelta is NIL;
  begin
    if check_int_shift_overflow then
      lshift_range := getIntRange(lshift);
      if lshift_range.maxValue < 0 or
          lshift_range.minValue >= ccConf.INTTYPE_SIZE - bitLength(number) then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        raisesException := TRUE;
      elsif lshift_range.minValue >= 0 and
          lshift_range.maxValue < ccConf.INTTYPE_SIZE - bitLength(number) then
        # This lshift cannot overflow
        countOverflowOptimizations(c_expr);
        c_expr.expr &:= "/*no_overflow_check_lshift*/";
      else
        incr(countOverflowChecks);
        doOverflowCheck := TRUE;
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
    end if;
    if not raisesException then
      if doOverflowCheck then
(*
        if isActionExpression(lshift, "INT_ADD") and
            getConstant(getActionParameter(lshift, 1), INTOBJECT, evaluatedDelta) then
          optimize_int_lshift_by_sum(number, getActionParameter(lshift, 3),
                                     getValue(evaluatedDelta, integer), c_expr);
        elsif isActionExpression(lshift, "INT_ADD") and
            getConstant(getActionParameter(lshift, 3), INTOBJECT, evaluatedDelta) then
          optimize_int_lshift_by_sum(number, getActionParameter(lshift, 1),
                                     getValue(evaluatedDelta, integer), c_expr);
        elsif isActionExpression(lshift, "INT_SBTR") and
            getConstant(getActionParameter(lshift, 3), INTOBJECT, evaluatedDelta) and
            getValue(evaluatedDelta, integer) <> integer.first then
          optimize_int_lshift_by_sum(number, getActionParameter(lshift, 1),
                                     -getValue(evaluatedDelta, integer), c_expr);
        elsif isActionExpression(lshift, "INT_SUCC") then
          optimize_int_lshift_by_sum(number, getActionParameter(lshift, 1),
                                     1, c_expr);
        elsif isActionExpression(lshift, "INT_PRED") then
          optimize_int_lshift_by_sum(number, getActionParameter(lshift, 1),
                                    -1, c_expr);
        else
*)
          c_expr.expr &:= "(";
          lshift_name := getParameterAsVariable("intType", "lshift_", lshift, c_expr);
          c_expr.expr &:= "ovfChk(";
          checkRangeFromZero(lshift_name,
              integerLiteral(ccConf.INTTYPE_SIZE - bitLength(number)), c_expr);
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
          if number = 0 then
            c_expr.expr &:= integerLiteral(0);
          else
            c_expr.expr &:= integerLiteral(number);
            c_expr.expr &:= " << ";
            c_expr.expr &:= lshift_name;
          end if;
          c_expr.expr &:= ")";
#        end if;
      else
        if number = 0 then
          c_expr.expr &:= integerLiteral(0);
        else
          c_expr.expr &:= integerLiteral(number);
          c_expr.expr &:= " << (";
          process_expr(lshift, c_expr);
          c_expr.expr &:= ")";
        end if;
      end if;
    end if;
  end func;


const proc: process (INT_LSHIFT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: number_name is "";
    var string: lshift_name is "";
    var intRange: number_range is intRange.value;
    var intRange: lshift_range is intRange.value;
    var boolean: fullOverflowCheck is FALSE;
    var reference: evaluatedDelta is NIL;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_lshift(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
      process_const_int_lshift(getValue(evaluatedParam, integer), params[3], c_expr);
    elsif check_int_shift_overflow then
        if isActionExpression(params[3], "INT_ADD") and
            getConstant(getActionParameter(params[3], 1), INTOBJECT, evaluatedDelta) then
          writeln(c_expr.currentFile <& "(" <& c_expr.currentLine <& ")");
        elsif isActionExpression(params[3], "INT_ADD") and
            getConstant(getActionParameter(params[3], 3), INTOBJECT, evaluatedDelta) then
          writeln(c_expr.currentFile <& "(" <& c_expr.currentLine <& ")");
        elsif isActionExpression(params[3], "INT_SBTR") and
            getConstant(getActionParameter(params[3], 1), INTOBJECT, evaluatedDelta) and
            getValue(evaluatedDelta, integer) <> integer.first then
          writeln(c_expr.currentFile <& "(" <& c_expr.currentLine <& ")");
        elsif isActionExpression(params[3], "INT_SBTR") and
            getConstant(getActionParameter(params[3], 3), INTOBJECT, evaluatedDelta) and
            getValue(evaluatedDelta, integer) <> integer.first then
          writeln(c_expr.currentFile <& "(" <& c_expr.currentLine <& ")");
        elsif isActionExpression(params[3], "INT_SUCC") then
          writeln(c_expr.currentFile <& "(" <& c_expr.currentLine <& ")");
        elsif isActionExpression(params[3], "INT_PRED") then
          writeln(c_expr.currentFile <& "(" <& c_expr.currentLine <& ")");
        end if;
      number_range := getIntRange(params[1]);
      lshift_range := getIntRange(params[3]);
      if lshift_range.maxValue < 0 or
          lshift_range.minValue >= ccConf.INTTYPE_SIZE or
          (lshift_range.minValue >= 0 and
           lshift_range.minValue < ccConf.INTTYPE_SIZE and
           (integer.first >> lshift_range.minValue > number_range.maxValue or
            integer.last >> lshift_range.minValue < number_range.minValue)) then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      elsif lshift_range.maxValue >= 0 and
          lshift_range.maxValue < ccConf.INTTYPE_SIZE and
          integer.first >> lshift_range.maxValue <= number_range.minValue and
          integer.last >> lshift_range.maxValue >= number_range.maxValue then
        if lshift_range.minValue >= 0 then
          countOverflowOptimizations(c_expr);
          c_expr.expr &:= "/*no_overflow_check_lshift*/(";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ") << (";
          process_expr(params[3], c_expr);
          c_expr.expr &:= ")";
        else
          incr(countOverflowChecks);
          c_expr.expr &:= "(";
          lshift_name := getParameterAsVariable("intType", "lshift_", params[3], c_expr);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= lshift_name;
          c_expr.expr &:= "<0)?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":(";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ") << ";
          c_expr.expr &:= lshift_name;
          c_expr.expr &:= ")";
        end if;
      else
        fullOverflowCheck := TRUE;
      end if;
      if fullOverflowCheck then
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        number_name := getParameterAsVariable("intType", "number_", params[1], c_expr);
        lshift_name := getParameterAsVariable("intType", "lshift_", params[3], c_expr);
        c_expr.expr &:= "ovfChk(";
        if lshift_range.minValue < 0 or
            lshift_range.maxValue >= ccConf.INTTYPE_SIZE then
          checkRangeFromZero(lshift_name, integerLiteral(ccConf.INTTYPE_SIZE), c_expr);
          c_expr.expr &:= "||";
        else
          countOverflowOptimizations(c_expr);
        end if;
        c_expr.expr &:= number_name;
        c_expr.expr &:= "<";
        if ccConf.RSHIFT_DOES_SIGN_EXTEND then
          c_expr.expr &:= integerLiteral(integer.first);
          c_expr.expr &:= ">>";
          c_expr.expr &:= lshift_name;
        else
          c_expr.expr &:= "~(~";
          c_expr.expr &:= integerLiteral(integer.first);
          c_expr.expr &:= ">>";
          c_expr.expr &:= lshift_name;
          c_expr.expr &:= ")";
        end if;
        c_expr.expr &:= "||";
        c_expr.expr &:= number_name;
        c_expr.expr &:= ">";
        c_expr.expr &:= integerLiteral(integer.last);
        c_expr.expr &:= ">>";
        c_expr.expr &:= lshift_name;
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":";
        c_expr.expr &:= number_name;
        c_expr.expr &:= " << ";
        c_expr.expr &:= lshift_name;
        c_expr.expr &:= ")";
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ") << (";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_int_lshift_assign (in reference: variable, in integer: lshift,
    inout expr_type: c_expr) is func

  local
    var string: variable_name is "";
    var expr_type: statement is expr_type.value;
  begin
    if lshift < 0 or lshift >= ccConf.INTTYPE_SIZE then
      incr(countOptimizations);
      setDiagnosticLine(c_expr);
      warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
      c_expr.expr &:= raiseError("OVERFLOW_ERROR");
    elsif lshift = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "/* ignore integer <<:= 0; */\n";
    elsif check_int_shift_overflow then
      incr(countOptimizations);
      incr(countOverflowChecks);
      variable_name := getParameterAsReference("intType", "variable_", variable, statement);
      statement.expr &:= "if (ovfChk(";
      checkIfOutsideRange(variable_name, integer.first >> lshift,
                          integer.last >> lshift, statement);
      statement.expr &:= ")) {\n";
      statement.expr &:= raiseError("OVERFLOW_ERROR");
      statement.expr &:= "} else {\n";
      statement.expr &:= variable_name;
      statement.expr &:= "<<=";
      statement.expr &:= integerLiteral(lshift);
      statement.expr &:= ";\n";
      statement.expr &:= "}\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      process_expr(variable, statement);
      statement.expr &:= "<<=";
      statement.expr &:= integerLiteral(lshift);
      statement.expr &:= ";\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (INT_LSHIFT_ASSIGN, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: variable_name is "";
    var string: lshift_name is "";
    var expr_type: statement is expr_type.value;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_lshift_assign(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif check_int_shift_overflow then
      incr(countOverflowChecks);
      variable_name := getParameterAsReference("intType", "variable_", params[1], statement);
      lshift_name := getParameterAsVariable("intType", "lshift_", params[3], statement);
      statement.expr &:= "ovfChk(";
      checkRangeFromZero(lshift_name, integerLiteral(ccConf.INTTYPE_SIZE), statement);
      statement.expr &:= "||";
      statement.expr &:= variable_name;
      statement.expr &:= "<";
      if ccConf.RSHIFT_DOES_SIGN_EXTEND then
        statement.expr &:= integerLiteral(integer.first);
        statement.expr &:= ">>";
        statement.expr &:= lshift_name;
      else
        statement.expr &:= "~(~";
        statement.expr &:= integerLiteral(integer.first);
        statement.expr &:= ">>";
        statement.expr &:= lshift_name;
        statement.expr &:= ")";
      end if;
      statement.expr &:= "||";
      statement.expr &:= variable_name;
      statement.expr &:= ">";
      statement.expr &:= integerLiteral(integer.last);
      statement.expr &:= ">>";
      statement.expr &:= lshift_name;
      statement.expr &:= ")?";
      statement.expr &:= intRaiseError("OVERFLOW_ERROR");
      statement.expr &:= ":(";
      statement.expr &:= variable_name;
      statement.expr &:= "<<=";
      statement.expr &:= lshift_name;
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      process_expr(params[1], statement);
      statement.expr &:= "<<=";
      process_expr(params[3], statement);
      statement.expr &:= ";\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (INT_LT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var intRange: number1Range is intRange.value;
    var intRange: number2Range is intRange.value;
    var boolean: doCompare is TRUE;
  begin
    if optimizeComparisons then
      number1Range := getIntRange(params[1]);
      number2Range := getIntRange(params[3]);
      if not number1Range.mayRaiseException and not number2Range.mayRaiseException then
        if number1Range.maxValue < number2Range.minValue then
          warning(COMPARISON_RESULT_CONSTANT, "<", TRUE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "1";
          doCompare := FALSE;
        elsif number1Range.minValue >= number2Range.maxValue then
          warning(COMPARISON_RESULT_CONSTANT, "<", FALSE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "0";
          doCompare := FALSE;
        end if;
      end if;
    end if;
    if doCompare then
      c_expr.expr &:= "(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ") < (";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_int_mdiv (in reference: dividend, in integer: divisor,
    inout expr_type: c_expr) is forward;


const func boolean: optimize_mdiv_of_product (in reference: number, in integer: factor,
    in integer: divisor, inout expr_type: c_expr) is func

  result
    var boolean: done is TRUE;
  begin
    if factor = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "0";
    elsif factor = divisor then
      incr(countOptimizations);
      countOverflowOptimizations(c_expr);
      process_expr(number, c_expr);
    elsif factor mod divisor = 0 then
      incr(countOptimizations);
      process_const_int_mult(number, factor mdiv divisor, c_expr);
    elsif divisor mod factor = 0 then
      incr(countOptimizations);
      countOverflowOptimizations(c_expr);
      process_const_int_mdiv(number, divisor mdiv factor, c_expr);
    else
      done := FALSE;
    end if;
  end func;


const proc: process_const_int_mdiv (in reference: dividend, in integer: divisor,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedDividend is NIL;
    var reference: evaluatedFactor is NIL;
    var integer: dividend_value is 0;
    var string: dividend_name is "";
    var intRange: dividend_range is intRange.value;
    var boolean: done is TRUE;
  begin
    incr(countOptimizations);
    if divisor = 0 then
      warning(DOES_RAISE, "NUMERIC_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
    elsif getConstant(dividend, INTOBJECT, evaluatedDividend) then
      dividend_value := getValue(evaluatedDividend, integer);
      if divisor = -1 and dividend_value < -integer.last then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= integerLiteral(dividend_value mdiv divisor);
      end if;
    elsif divisor = 1 then
      c_expr.expr &:= "(";
      process_expr(dividend, c_expr);
      c_expr.expr &:= ")";
    elsif isActionExpression(dividend, "INT_MULT") and
        getConstant(getActionParameter(dividend, 3), INTOBJECT, evaluatedFactor) then
      done := optimize_mdiv_of_product(getActionParameter(dividend, 1),
            getValue(evaluatedFactor, integer), divisor, c_expr);
    elsif isActionExpression(dividend, "INT_MULT") and
        getConstant(getActionParameter(dividend, 1), INTOBJECT, evaluatedFactor) then
      done := optimize_mdiv_of_product(getActionParameter(dividend, 3),
            getValue(evaluatedFactor, integer), divisor, c_expr);
    else
      done := FALSE;
    end if;
    if not done then
      if divisor = -1 then
        # Dividing by -1 is equal to changing the sign.
        # integer.first / -1 causes an integer overflow.
        negate(dividend, c_expr);
      elsif divisor > 0 and 2 ** log2(divisor) = divisor then
        # Divisor is a power of two.
        if ccConf.RSHIFT_DOES_SIGN_EXTEND then
          c_expr.expr &:= "(";
          process_expr(dividend, c_expr);
          c_expr.expr &:= ") >> ";
          c_expr.expr &:= integerLiteral(log2(divisor));
        else
          c_expr.expr &:= "(";
          dividend_name := getParameterAsVariable("intType", "dividend_", dividend, c_expr);
          doRshift(dividend_name, integerLiteral(log2(divisor)), c_expr);
          c_expr.expr &:= ")";
        end if;
      elsif divisor < 0 and bitLength(divisor) = lowestSetBit(divisor) then
        # Divisor is a negative power of two.
        # The check above is (almost) equivalent to:
        #   divisor < 0 and 2 ** log2(-divisor) = -divisor
        # The check with bitLength is used to avoid negating the divisor.
        # Negating the divisor would fail for the most negative integer.
        dividend_range := getIntRange(dividend);
        if ccConf.TWOS_COMPLEMENT_INTTYPE then
          c_expr.expr &:= "(";
          dividend_name := getParameterAsVariable("intType", "dividend_", dividend, c_expr);
          if dividend_range.minValue = integer.first then
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= "==";
            c_expr.expr &:= integerLiteral(integer.first);
            c_expr.expr &:= "?";
            c_expr.expr &:= integerLiteral(-(integer.first >> 1) >> pred(bitLength(divisor)));
            c_expr.expr &:= ":";
          end if;
          if ccConf.RSHIFT_DOES_SIGN_EXTEND then
            c_expr.expr &:= "-";
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= " >> ";
            c_expr.expr &:= integerLiteral(bitLength(divisor));
          else
            c_expr.expr &:= "(";
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= "=-";
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= ",";
            doRshift(dividend_name, integerLiteral(bitLength(divisor)), c_expr);
            c_expr.expr &:= ")";
          end if;
          c_expr.expr &:= ")";
        else
          if ccConf.RSHIFT_DOES_SIGN_EXTEND then
            c_expr.expr &:= "-(";
            process_expr(dividend, c_expr);
            c_expr.expr &:= ") >> ";
            c_expr.expr &:= integerLiteral(bitLength(divisor));
          else
            dividend_name := defineTempVariable("intType", "dividend_", c_expr);
            c_expr.expr &:= "(";
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= "=-(";
            process_expr(dividend, c_expr);
            c_expr.expr &:= "),";
            doRshift(dividend_name, integerLiteral(bitLength(divisor)), c_expr);
            c_expr.expr &:= ")";
          end if;
        end if;
      else
        dividend_range := getIntRange(dividend);
        if divisor > 0 and dividend_range.minValue >= 0 or
            divisor < 0 and dividend_range.maxValue <= 0 then
          # Dividend and divisor have the same sign.
          # Formula used: a/b
          c_expr.expr &:= "(";
          process_expr(dividend, c_expr);
          c_expr.expr &:= ")/";
          c_expr.expr &:= integerLiteral(divisor);
        elsif divisor > 0 and dividend_range.maxValue < 0 then
          # Formula used: (a+1)/b-1
          c_expr.expr &:= "((";
          process_expr(dividend, c_expr);
          c_expr.expr &:= ")+1)/";
          c_expr.expr &:= integerLiteral(divisor);
          c_expr.expr &:= "-1";
        elsif divisor < 0 and dividend_range.minValue > 0 then
          # Formula used: (a-1)/b-1
          c_expr.expr &:= "((";
          process_expr(dividend, c_expr);
          c_expr.expr &:= ")-1)/";
          c_expr.expr &:= integerLiteral(divisor);
          c_expr.expr &:= "-1";
        else
          c_expr.expr &:= "(";
          dividend_name := getParameterAsVariable("intType", "dividend_", dividend, c_expr);
          c_expr.expr &:= dividend_name;
          if divisor > 0 then
            # Formula used: a<0?(a+1)/b-1:a/b
            c_expr.expr &:= "<0?(";
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= "+1)/";
            c_expr.expr &:= integerLiteral(divisor);
            c_expr.expr &:= "-1:";
          else # divisor < 0
            # Formula used: a>0?(a-1)/b-1:a/b
            c_expr.expr &:= ">0?(";
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= "-1)/";
            c_expr.expr &:= integerLiteral(divisor);
            c_expr.expr &:= "-1:";
          end if;
          c_expr.expr &:= dividend_name;
          c_expr.expr &:= "/";
          c_expr.expr &:= integerLiteral(divisor);
          c_expr.expr &:= ")";
        end if;
      end if;
    end if;
  end func;


const proc: process_const_int_mdiv (in integer: dividend, in reference: divisor,
    inout expr_type: c_expr) is func

  local
    var string: divisor_name is "";
    var intRange: divisor_range is intRange.value;
  begin
    incr(countOptimizations);
    divisor_range := getIntRange(divisor);
    if dividend = 0 then
      if integer_division_check then
        if (divisor_range.minValue <= 0 and divisor_range.maxValue >= 0) or
            divisor_range.mayRaiseException then
          incr(countDivisionChecks);
          c_expr.expr &:= "(divChk((";
          process_expr(divisor, c_expr);
          c_expr.expr &:= ")==0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":0)";
        else
          countDivisionOptimizations(c_expr);
          c_expr.expr &:= "0";
        end if;
      else
        c_expr.expr &:= "0";
      end if;
    elsif check_int_division_overflow and dividend = integer.first then
      if divisor_range.maxValue < -1 then
        # Dividend and divisor have the same sign.
        # No checks for integer overflow and division by zero necessary.
        # Formula used: a/b
        countOverflowOptimizations(c_expr);
        if check_int_div_by_zero then
          countDivisionOptimizations(c_expr);
        end if;
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= "/(";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")";
      elsif divisor_range.minValue > 0 then
        # No checks for integer overflow and division by zero necessary.
        # Formula used: (a+1)/b-1
        countOverflowOptimizations(c_expr);
        if check_int_div_by_zero then
          countDivisionOptimizations(c_expr);
        end if;
        c_expr.expr &:= integerLiteral(succ(dividend));
        c_expr.expr &:= "/(";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")-1";
      else
        # Formula used: b==-1?OVERFLOW_ERROR:b>0?(a+1)/b-1:a/b
        c_expr.expr &:= "(";
        divisor_name := getParameterAsVariable("intType", "divisor_", divisor, c_expr);
        if divisor_range.minValue <= -1 and divisor_range.maxValue >= -1 then
          incr(countOverflowChecks);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "==-1)?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
        else
          countOverflowOptimizations(c_expr);
        end if;
        if divisor_range.maxValue > 0 then
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= ">0?";
          c_expr.expr &:= integerLiteral(succ(dividend));
          c_expr.expr &:= "/";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "-1:";
        end if;
        if check_int_div_by_zero then
          if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
            incr(countDivisionChecks);
            c_expr.expr &:= "divChk(";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= "==0)?";
            c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
            c_expr.expr &:= ":";
          else
            countDivisionOptimizations(c_expr);
          end if;
        end if;
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= "/";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= ")";
      end if;
    else
      if dividend = integer.first then
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      end if;
      if (dividend <= 0 and
          ((dividend > integer.first and divisor_range.maxValue < 0) or
          divisor_range.maxValue < -1)) or
          (dividend >= 0 and divisor_range.minValue > 0) then
        # Dividend and divisor have the same sign.
        # No checks for integer overflow and division by zero necessary.
        # Formula used: a/b
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= "/(";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")";
      elsif dividend > 0 and divisor_range.maxValue < 0 then
        # No checks for integer overflow and division by zero necessary.
        # Formula used: (a-1)/b-1
        c_expr.expr &:= integerLiteral(pred(dividend));
        c_expr.expr &:= "/(";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")-1";
      elsif dividend < 0 and divisor_range.minValue > 0 then
        # No checks for integer overflow and division by zero necessary.
        # Formula used: (a+1)/b-1
        c_expr.expr &:= integerLiteral(succ(dividend));
        c_expr.expr &:= "/(";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")-1";
      else
        c_expr.expr &:= "(";
        divisor_name := getParameterAsVariable("intType", "divisor_", divisor, c_expr);
        if (dividend < 0 or divisor_range.minValue < 0) and
            (dividend > 0 or divisor_range.maxValue > 0) then
          c_expr.expr &:= divisor_name;
          if dividend > 0 then
            # Formula used: b<0?(a-1)/b-1:a/b
            c_expr.expr &:= "<0?";
            c_expr.expr &:= integerLiteral(pred(dividend));
          else # dividend < 0
            # Formula used: b>0?(a+1)/b-1:a/b
            c_expr.expr &:= ">0?";
            c_expr.expr &:= integerLiteral(succ(dividend));
          end if;
          c_expr.expr &:= "/";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "-1:";
        end if;
        if check_int_div_by_zero then
          if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
            incr(countDivisionChecks);
            c_expr.expr &:= "divChk(";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= "==0)?";
            c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
            c_expr.expr &:= ":";
          else
            countDivisionOptimizations(c_expr);
          end if;
        end if;
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= "/";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= ")";
      end if;
    end if;
  end func;


const proc: process (INT_MDIV, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: dividend_name is "";
    var string: divisor_name is "";
    var intRange: dividend_range is intRange.value;
    var intRange: divisor_range is intRange.value;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_mdiv(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
      process_const_int_mdiv(getValue(evaluatedParam, integer), params[3], c_expr);
    elsif evaluate_const_expr = 0 and check_int_div_zero_by_zero and
          category(params[1]) = INTOBJECT and not isVar(params[1]) and
          getValue(params[1], integer) = 0 then
      incr(countDivisionChecks);
      c_expr.expr &:= "(divChk((";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    else
      divisor_range := getIntRange(params[3]);
      if params[1] = params[3] then
        # C compilers are allowed to optimize variable/variable to 1.
        # A C compiler can assume, that an "undefined behavior", like a
        # division by zero will never happen. So we need to handle this case.
        if integer_division_check then
          if (divisor_range.minValue <= 0 and divisor_range.maxValue >= 0) or
              divisor_range.mayRaiseException then
            incr(countDivisionChecks);
            c_expr.expr &:= "(divChk((";
            process_expr(params[1], c_expr);
            c_expr.expr &:= ")==0)?";
            c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
            c_expr.expr &:= ":1)";
          else
            countDivisionOptimizations(c_expr);
            c_expr.expr &:= "1";
          end if;
        else
          c_expr.expr &:= "1";
        end if;
      else
        # Formula used: a>0&&b<0?(a-1)/b-1:a<0&&b>0?(a+1)/b-1:a/b
        dividend_range := getIntRange(params[1]);
        if (dividend_range.maxValue <= 0 and
            ((dividend_range.minValue > integer.first and divisor_range.maxValue < 0) or
            divisor_range.maxValue < -1)) or
            (dividend_range.minValue >= 0 and divisor_range.minValue > 0) then
          # Dividend and divisor have the same sign.
          # No checks for integer overflow and division by zero necessary.
          # Formula used: a/b
          c_expr.expr &:= "(";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ")/(";
          process_expr(params[3], c_expr);
          c_expr.expr &:= ")";
        elsif dividend_range.minValue > 0 and divisor_range.maxValue < 0 then
          # No checks for integer overflow and division by zero necessary.
          # Formula used: (a-1)/b-1
          if check_int_division_overflow then
            countOverflowOptimizations(c_expr);
          else
            countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
          end if;
          if check_int_div_by_zero then
            countDivisionOptimizations(c_expr);
          end if;
          c_expr.expr &:= "((";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ")-1)/(";
          process_expr(params[3], c_expr);
          c_expr.expr &:= ")-1";
        elsif dividend_range.maxValue < 0 and divisor_range.minValue > 0 then
          # No checks for integer overflow and division by zero necessary.
          # Formula used: (a+1)/b-1
          if check_int_division_overflow then
            countOverflowOptimizations(c_expr);
          else
            countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
          end if;
          if check_int_div_by_zero then
            countDivisionOptimizations(c_expr);
          end if;
          c_expr.expr &:= "((";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ")+1)/(";
          process_expr(params[3], c_expr);
          c_expr.expr &:= ")-1";
        else
          c_expr.expr &:= "(";
          dividend_name := getParameterAsVariable("intType", "dividend_", params[1], c_expr);
          divisor_name := getParameterAsVariable("intType", "divisor_", params[3], c_expr);
          if dividend_range.maxValue > 0 and divisor_range.minValue < 0 then
            if dividend_range.minValue <= 0 then
              c_expr.expr &:= dividend_name;
              c_expr.expr &:= ">0";
              if divisor_range.maxValue >= 0 then
                c_expr.expr &:= "&&";
              end if;
            end if;
            if divisor_range.maxValue >= 0 then
              c_expr.expr &:= divisor_name;
              c_expr.expr &:= "<0";
            end if;
            c_expr.expr &:= "?(";
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= "-1)/";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= "-1:";
          end if;
          if dividend_range.minValue < 0 and divisor_range.maxValue > 0 then
            if dividend_range.maxValue >= 0 then
              c_expr.expr &:= dividend_name;
              c_expr.expr &:= "<0";
              if divisor_range.minValue <= 0 then
                c_expr.expr &:= "&&";
              end if;
            end if;
            if divisor_range.minValue <= 0 then
              c_expr.expr &:= divisor_name;
              c_expr.expr &:= ">0";
            end if;
            c_expr.expr &:= "?(";
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= "+1)/";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= "-1:";
          end if;
          if check_int_div_by_zero then
            if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
              incr(countDivisionChecks);
              c_expr.expr &:= "divChk(";
              c_expr.expr &:= divisor_name;
              c_expr.expr &:= "==0)?";
              c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
              c_expr.expr &:= ":";
            else
              countDivisionOptimizations(c_expr);
            end if;
          end if;
          if check_int_division_overflow then
            if dividend_range.minValue = integer.first and
                divisor_range.minValue <= -1 and divisor_range.maxValue >= -1 then
              incr(countOverflowChecks);
              c_expr.expr &:= "ovfChk(";
              c_expr.expr &:= dividend_name;
              c_expr.expr &:= "==";
              c_expr.expr &:= integerLiteral(integer.first);
              c_expr.expr &:= "&&";
              c_expr.expr &:= divisor_name;
              c_expr.expr &:= "==-1";
              c_expr.expr &:= ")?";
              c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
              c_expr.expr &:= ":";
            else
              countOverflowOptimizations(c_expr);
            end if;
          else
            countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
          end if;
          c_expr.expr &:= dividend_name;
          c_expr.expr &:= "/";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= ")";
        end if;
      end if;
    end if;
  end func;


const proc: optimize_mod_of_left_shifted_value (in reference: argument,
    in integer: lshift, in integer: bitsToMask, inout expr_type: c_expr) is func

  begin
    if lshift < 0 or lshift >= ccConf.INTTYPE_SIZE then
      warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
    elsif lshift >= bitsToMask then
      c_expr.expr &:= "0";
    else
      c_expr.expr &:= "/*mod_of_lshift*/ ((";
      process_expr(argument, c_expr);
      c_expr.expr &:= ")&";
      c_expr.expr &:= integerLiteral(pred(2 ** (bitsToMask - lshift)));
      c_expr.expr &:= ")<<";
      c_expr.expr &:= integerLiteral(lshift);
    end if;
  end func;


const proc: optimize_mod_of_left_shifted_value (in reference: argument,
    in reference: lshift, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var integer: lshift_value is 0;
    var string: lshift_name is "";
    var intRange: lshift_range is intRange.value;
  begin
    if getConstant(lshift, INTOBJECT, evaluatedParam) then
      lshift_value := getValue(evaluatedParam, integer);
      if lshift_value < 0 or lshift_value >= ccConf.INTTYPE_SIZE then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= "((uintType)(";
        process_expr(argument, c_expr);
        c_expr.expr &:= ") << ";
        c_expr.expr &:= integerLiteral(lshift_value);
        c_expr.expr &:= ")";
      end if;
    elsif check_int_shift_overflow then
      lshift_range := getIntRange(lshift);
      if lshift_range.maxValue < 0 or
          lshift_range.minValue >= ccConf.INTTYPE_SIZE then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      elsif lshift_range.minValue >= 0 and
          lshift_range.maxValue < ccConf.INTTYPE_SIZE then
        # This lshift cannot overflow
        countOverflowOptimizations(c_expr);
        c_expr.expr &:= "/*no_overflow_check_lshift*/";
        c_expr.expr &:= "((uintType)(";
        process_expr(argument, c_expr);
        c_expr.expr &:= ") << (";
        process_expr(lshift, c_expr);
        c_expr.expr &:= "))";
      else
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        lshift_name := getParameterAsVariable("intType", "lshift_", lshift, c_expr);
        c_expr.expr &:= "ovfChk(";
        checkRangeFromZero(lshift_name,
            integerLiteral(ccConf.INTTYPE_SIZE), c_expr);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":";
        c_expr.expr &:= "((uintType)(";
        process_expr(argument, c_expr);
        c_expr.expr &:= ") << ";
        c_expr.expr &:= lshift_name;
        c_expr.expr &:= "))";
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "((uintType)(";
      process_expr(argument, c_expr);
      c_expr.expr &:= ") << (";
      process_expr(lshift, c_expr);
      c_expr.expr &:= "))";
    end if;
  end func;


const proc: optimize_mod_of_product (in reference: factor1,
    in reference: factor2, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "(uintType)(";
    process_expr(factor1, c_expr);
    c_expr.expr &:= ")*(uintType)(";
    process_expr(factor2, c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: optimize_mod_of_sum (in addSubIntListType: addSubParamList,
    inout expr_type: c_expr) is func

  local
    var integer: index is 1;
    var bigInteger: constSummand is 0_;
    var reference: summand is NIL;
  begin
    for key index range addSubParamList do
      if addSubParamList[index].summand = NIL then
        if addSubParamList[index].doAdd then
          constSummand +:= bigInteger(addSubParamList[index].constSummand);
        else
          constSummand -:= bigInteger(addSubParamList[index].constSummand);
        end if;
      end if;
    end for;
    c_expr.expr &:= "/*mod_of_sum*/ ((intType) (";
    for key index range addSubParamList do
      if addSubParamList[index].summand <> NIL then
        if addSubParamList[index].doAdd then
          c_expr.expr &:= "+";
        else
          c_expr.expr &:= "-";
        end if;
        summand := addSubParamList[index].summand;
        if isActionExpression(summand, "INT_MULT") then
          optimize_mod_of_product(getValue(summand, ref_list)[2],
              getValue(summand, ref_list)[4], c_expr);
        elsif isActionExpression(summand, "INT_LSHIFT") then
          optimize_mod_of_left_shifted_value(getValue(summand, ref_list)[2],
              getValue(summand, ref_list)[4], c_expr);
        else
          c_expr.expr &:= "(uintType)(";
          process_expr(summand, c_expr);
          c_expr.expr &:= ")";
        end if;
      end if;
    end for;
    if constSummand >= 0_ then
      constSummand := constSummand mod (2_ ** 63);
      if constSummand <> 0_ then
        c_expr.expr &:= "+(uintType)(";
        c_expr.expr &:= integerLiteral(ord(constSummand));
        c_expr.expr &:= ")";
      end if;
    else
      constSummand := -constSummand mod (2_ ** 63);
      if constSummand <> 0_ then
        c_expr.expr &:= "-(uintType)(";
        c_expr.expr &:= integerLiteral(ord(constSummand));
        c_expr.expr &:= ")";
      end if;
    end if;
    c_expr.expr &:= "))";
  end func;


const proc: optimize_mod_of_sum (in ref_list: params, in boolean: doAdd,
    inout expr_type: c_expr) is func

  local
    var addSubIntListType: addSubParamList is 0 times addSubIntElementType.value;
  begin
    addSubParamList := getAddSubParamList(params, doAdd);
    evaluateConstants(addSubParamList);
    optimize_mod_of_sum(addSubParamList, c_expr);
  end func;


const proc: optimize_mod_of_sum (in reference: summand1, in integer: summand2,
    inout expr_type: c_expr) is func

  local
    var addSubIntListType: addSubParamList is 0 times addSubIntElementType.value;
  begin
    addSubParamList := getAddSubParamList(summand1, summand2);
    evaluateConstants(addSubParamList);
    optimize_mod_of_sum(addSubParamList, c_expr);
  end func;


const proc: optimize_mod_dividend (in reference: dividend, inout expr_type: c_expr) is func

  begin
    if isActionExpression(dividend, "INT_MULT") then
      c_expr.expr &:= "/*mod_of_product*/ ((intType) (";
      optimize_mod_of_product(getValue(dividend, ref_list)[2],
          getValue(dividend, ref_list)[4], c_expr);
      c_expr.expr &:= "))";
    elsif isActionExpression(dividend, "INT_LSHIFT") then
      c_expr.expr &:= "/*mod_of_lshift*/ ((intType) (";
      optimize_mod_of_left_shifted_value(getValue(dividend, ref_list)[2],
          getValue(dividend, ref_list)[4], c_expr);
      c_expr.expr &:= "))";
    elsif isActionExpression(dividend, "INT_ADD") then
      optimize_mod_of_sum(getValue(dividend, ref_list)[2 ..], TRUE, c_expr)
    elsif isActionExpression(dividend, "INT_SBTR") then
      optimize_mod_of_sum(getValue(dividend, ref_list)[2 ..], FALSE, c_expr)
    elsif isActionExpression(dividend, "INT_SUCC") then
      optimize_mod_of_sum(getValue(dividend, ref_list)[2], 1, c_expr);
    elsif isActionExpression(dividend, "INT_PRED") then
      optimize_mod_of_sum(getValue(dividend, ref_list)[2], -1, c_expr);
    elsif isActionExpression(dividend, "INT_ICONV1") then
      optimize_mod_dividend(getActionParameter(dividend, 1), c_expr);
    elsif isActionExpression(dividend, "INT_ICONV3") then
      optimize_mod_dividend(getActionParameter(dividend, 3), c_expr);
    else
      c_expr.expr &:= "(";
      process_expr(dividend, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: optimize_mod_by_power_of_two (in reference: dividend, in reference: lshift,
    in boolean: powerOperator, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var integer: lshift_value is 0;
    var string: lshift_name is "";
  begin
    incr(countOptimizations);
    c_expr.expr &:= "/*mod_by_power_of_two*/ ";
    if getConstant(lshift, INTOBJECT, evaluatedParam) then
      lshift_value := getValue(evaluatedParam, integer);
      if lshift_value < 0 then
        if powerOperator then
          warning(DOES_RAISE, "NUMERIC_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        else
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        end if;
      elsif lshift_value >= ccConf.INTTYPE_SIZE then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      elsif lshift_value = 0 then
        c_expr.expr &:= "0";
      else
        optimize_mod_dividend(dividend, c_expr);
        c_expr.expr &:= "&";
        c_expr.expr &:= integerLiteral(pred(1 << lshift_value));
      end if;
    elsif check_int_shift_overflow then
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      lshift_name := getParameterAsVariable("intType", "lshift_", lshift, c_expr);
      if powerOperator then
        c_expr.expr &:= "numChk(";
        c_expr.expr &:= lshift_name;
        c_expr.expr &:= "<0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":ovfChk(";
        c_expr.expr &:= lshift_name;
        c_expr.expr &:= ">=";
        c_expr.expr &:= integerLiteral(pred(ccConf.INTTYPE_SIZE));
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= "ovfChk(";
        checkRangeFromZero(lshift_name, integerLiteral(pred(ccConf.INTTYPE_SIZE)), c_expr);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end if;
      c_expr.expr &:= ":";
      optimize_mod_dividend(dividend, c_expr);
      c_expr.expr &:= "&((";
      c_expr.expr &:= integerLiteral(1);
      c_expr.expr &:= "<<(";
      c_expr.expr &:= lshift_name;
      c_expr.expr &:= "))-1))";
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      if powerOperator then
        c_expr.expr &:= "(";
        lshift_name := getParameterAsVariable("intType", "lshift_", lshift, c_expr);
        c_expr.expr &:= "numChk(";
        c_expr.expr &:= lshift_name;
        c_expr.expr &:= "<0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
        optimize_mod_dividend(dividend, c_expr);
        c_expr.expr &:= "&((";
        c_expr.expr &:= integerLiteral(1);
        c_expr.expr &:= "<<(";
        c_expr.expr &:= lshift_name;
        c_expr.expr &:= "))-1))";
      else
        optimize_mod_dividend(dividend, c_expr);
        c_expr.expr &:= "&((";
        c_expr.expr &:= integerLiteral(1);
        c_expr.expr &:= "<<(";
        process_expr(lshift, c_expr);
        c_expr.expr &:= "))-1)";
      end if;
    end if;
  end func;


const proc: process_const_int_mod (in reference: dividend, in integer: divisor,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedDividend is NIL;
    var reference: evaluatedLshift is NIL;
    var integer: dividend_value is 0;
    var string: dividend_name is "";
    var string: remainder_name is "";
  begin
    incr(countOptimizations);
    if divisor = 0 then
      warning(DOES_RAISE, "NUMERIC_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
    elsif divisor = 1 then
      c_expr.expr &:= "0";
    elsif getConstant(dividend, INTOBJECT, evaluatedDividend) then
      dividend_value := getValue(evaluatedDividend, integer);
      if divisor = -1 and dividend_value < -integer.last then
        # Normally this raises OVERFLOW_ERROR, but it is not guaranteed to do so.
        # According to the optimization rules for overflow it is okay
        # to deliver the correct result instead of raising OVERFLOW_ERROR.
        # In case of a modulo by -1 the correct result is always 0.
        if reduceOverflowChecks then
          countOverflowOptimizations(c_expr);
          c_expr.expr &:= "/*no_overflow_check_mod*/ 0";
        else
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        end if;
      else
        c_expr.expr &:= integerLiteral(dividend_value mod divisor);
      end if;
    elsif divisor = -1 then
      if not check_int_division_overflow then
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
        c_expr.expr &:= "0";
      elsif reduceOverflowChecks then
        countOverflowOptimizations(c_expr);
        c_expr.expr &:= "/*no_overflow_check_mod*/ 0";
      else
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        dividend_name := getParameterAsVariable("intType", "dividend_", dividend, c_expr);
        c_expr.expr &:= "ovfChk(";
        c_expr.expr &:= dividend_name;
        c_expr.expr &:= "==";
        c_expr.expr &:= integerLiteral(integer.first);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":0)";
      end if;
    elsif divisor > 0 and 2 ** log2(divisor) = divisor then
      # Divisor is a power of two.
      incr(countOptimizations);
      if modDividendOptimization then
        if isActionExpression(dividend, "INT_LSHIFT") and
            getConstant(getActionParameter(dividend, 3), INTOBJECT, evaluatedLshift) then
          optimize_mod_of_left_shifted_value(getActionParameter(dividend, 1),
              getValue(evaluatedLshift, integer), log2(divisor), c_expr);
        else
          optimize_mod_dividend(dividend, c_expr);
          c_expr.expr &:= "&";
          c_expr.expr &:= integerLiteral(pred(divisor));
        end if;
      else
        c_expr.expr &:= "(";
        process_expr(dividend, c_expr);
        c_expr.expr &:= ")";
        c_expr.expr &:= "&";
        c_expr.expr &:= integerLiteral(pred(divisor));
      end if;
    elsif divisor < 0 and bitLength(divisor) = lowestSetBit(divisor) then
      # Divisor is a negative power of two.
      # The check above is (almost) equivalent to:
      #   divisor < 0 and 2 ** log2(-divisor) = -divisor
      # The check with bitLength is used to avoid negating the divisor.
      # Negating the divisor would fail for the most negative integer.
      # Below the unsigned value is negated to avoid a signed integer
      # overflow if the smallest signed integer is negated.
      c_expr.expr &:= "(intType)-(-(uintType)(";
      process_expr(dividend, c_expr);
      c_expr.expr &:= ")&";
      c_expr.expr &:= integerLiteral(-succ(divisor));
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "(";
      dividend_name := getParameterAsVariable("intType", "dividend_", dividend, c_expr);
      remainder_name := defineTempVariable("intType", "remainder_", c_expr);
      # Formula used: c=a%b,a<0^b<0&&c!=0?c+b:c
      c_expr.expr &:= remainder_name;
      c_expr.expr &:= "=";
      c_expr.expr &:= dividend_name;
      c_expr.expr &:= "%";
      c_expr.expr &:= integerLiteral(divisor);
      c_expr.expr &:= ",";
      c_expr.expr &:= dividend_name;
      if divisor > 0 then
        # Formula used: c=a%b,a<0&&c!=0?c+b:c
        c_expr.expr &:= "<0";
      else # divisor < 0
        # Formula used: c=a%b,a>0&&c!=0?c+b:c
        c_expr.expr &:= ">0";
      end if;
      c_expr.expr &:= "&&";
      c_expr.expr &:= remainder_name;
      c_expr.expr &:= "!=0?";
      c_expr.expr &:= remainder_name;
      c_expr.expr &:= "+";
      c_expr.expr &:= integerLiteral(divisor);
      c_expr.expr &:= ":";
      c_expr.expr &:= remainder_name;
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_int_mod (in integer: dividend, in reference: divisor,
    inout expr_type: c_expr) is func

  local
    var string: divisor_name is "";
    var intRange: divisor_range is intRange.value;
    var string: remainder_name is "";
  begin
    incr(countOptimizations);
    divisor_range := getIntRange(divisor);
    if dividend = 0 then
      if integer_division_check then
        if (divisor_range.minValue <= 0 and divisor_range.maxValue >= 0) or
            divisor_range.mayRaiseException then
          incr(countDivisionChecks);
          c_expr.expr &:= "(divChk((";
          process_expr(divisor, c_expr);
          c_expr.expr &:= ")==0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":0)";
        else
          countDivisionOptimizations(c_expr);
          c_expr.expr &:= "0";
        end if;
      else
        c_expr.expr &:= "0";
      end if;
    elsif dividend = 1 then
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "divisor_", divisor, c_expr);
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= "<=0?";
      if integer_division_check then
        if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
          incr(countDivisionChecks);
          c_expr.expr &:= "(divChk(";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "==0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "+1)";
        else
          countDivisionOptimizations(c_expr);
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "+1";
        end if;
      else
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "+1";
      end if;
      c_expr.expr &:= ":(";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= "==1?0:1))";
    elsif check_int_division_overflow and dividend = integer.first then
      # integer.first % -1 causes an integer overflow.
      if divisor_range.maxValue < -1 then
        # No checks for integer overflow and division by zero necessary.
        countOverflowOptimizations(c_expr);
        if check_int_rem_by_zero then
          countDivisionOptimizations(c_expr);
        end if;
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= " % (";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")";
      else
        c_expr.expr &:= "(";
        divisor_name := getParameterAsVariable("intType", "divisor_", divisor, c_expr);
        remainder_name := defineTempVariable("intType", "remainder_", c_expr);
        if divisor_range.minValue <= -1 and divisor_range.maxValue >= -1 then
          incr(countOverflowChecks);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "==-1)?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
        else
          countOverflowOptimizations(c_expr);
        end if;
        if check_int_rem_by_zero then
          if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
            incr(countDivisionChecks);
            c_expr.expr &:= "divChk(";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= "==0)?";
            c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
            c_expr.expr &:= ":";
          else
            countDivisionOptimizations(c_expr);
          end if;
        end if;
        c_expr.expr &:= "(";
        # Formula used: c=a%b,b>0&&c!=0?c+b:c
        c_expr.expr &:= remainder_name;
        c_expr.expr &:= "=";
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= "%";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= ",";
        if divisor_range.maxValue <= 0 then
          c_expr.expr &:= remainder_name;
        else
          if divisor_range.minValue <= 0 then
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= ">0";
            c_expr.expr &:= "&&";
          end if;
          c_expr.expr &:= remainder_name;
          c_expr.expr &:= "!=0?";
          c_expr.expr &:= remainder_name;
          c_expr.expr &:= "+";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= ":";
          c_expr.expr &:= remainder_name;
        end if;
        c_expr.expr &:= "))";
      end if;
    else
      if dividend = integer.first then
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      end if;
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "divisor_", divisor, c_expr);
      if check_int_rem_by_zero then
        if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
          incr(countDivisionChecks);
          c_expr.expr &:= "divChk(";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "==0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":";
        else
          countDivisionOptimizations(c_expr);
        end if;
      end if;
      if (dividend >= 0 and divisor_range.minValue >= 0) or
          (dividend <= 0 and divisor_range.maxValue <= 0) then
        # Formula used: a%b
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= "%";
        c_expr.expr &:= divisor_name;
      else
        c_expr.expr &:= "(";
        remainder_name := defineTempVariable("intType", "remainder_", c_expr);
        # Formula used: c=a%b,a<0^b<0&&c!=0?c+b:c
        c_expr.expr &:= remainder_name;
        c_expr.expr &:= "=";
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= "%";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= ",";
        if (dividend < 0 or divisor_range.maxValue >= 0) and
            (dividend > 0 or divisor_range.minValue <= 0) then
          c_expr.expr &:= divisor_name;
          if dividend > 0 then
            # Formula used: c=a%b,b<0&&c!=0?c+b:c
            c_expr.expr &:= "<0";
          else # dividend < 0 then
            # Formula used: c=a%b,b>0&&c!=0?c+b:c
            c_expr.expr &:= ">0";
          end if;
          c_expr.expr &:= "&&";
        end if;
        c_expr.expr &:= remainder_name;
        c_expr.expr &:= "!=0?";
        c_expr.expr &:= remainder_name;
        c_expr.expr &:= "+";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= ":";
        c_expr.expr &:= remainder_name;
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_MOD, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: dividend_name is "";
    var string: divisor_name is "";
    var intRange: dividend_range is intRange.value;
    var intRange: divisor_range is intRange.value;
    var string: remainder_name is "";
  begin
    if modDividendOptimization and
        isActionExpression(params[3], "INT_LSHIFT") and
        category(getValue(params[3], ref_list)[2]) = INTOBJECT and
        not isVar(getValue(params[3], ref_list)[2]) and
        getValue(getValue(params[3], ref_list)[2], integer) = 1 then
      optimize_mod_by_power_of_two(params[1], getValue(params[3], ref_list)[4],
          FALSE, c_expr);
    elsif modDividendOptimization and
        isActionExpression(params[3], "INT_POW") and
        category(getValue(params[3], ref_list)[2]) = INTOBJECT and
        not isVar(getValue(params[3], ref_list)[2]) and
        getValue(getValue(params[3], ref_list)[2], integer) = 2 then
      optimize_mod_by_power_of_two(params[1], getValue(params[3], ref_list)[4],
          TRUE, c_expr);
    elsif getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_mod(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
      process_const_int_mod(getValue(evaluatedParam, integer), params[3], c_expr);
    elsif evaluate_const_expr = 0 and check_int_rem_zero_by_zero and
          category(params[1]) = INTOBJECT and not isVar(params[1]) and
          getValue(params[1], integer) = 0 then
      incr(countDivisionChecks);
      c_expr.expr &:= "(divChk((";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    else
      divisor_range := getIntRange(params[3]);
      if params[1] = params[3] then
        # C compilers are allowed to optimize variable%variable to 0.
        # A C compiler can assume, that an "undefined behavior", like a
        # division by zero will never happen. So we need to handle this case.
        if integer_division_check then
          if (divisor_range.minValue <= 0 and divisor_range.maxValue >= 0) or
              divisor_range.mayRaiseException then
            incr(countDivisionChecks);
            c_expr.expr &:= "(divChk((";
            process_expr(params[1], c_expr);
            c_expr.expr &:= ")==0)?";
            c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
            c_expr.expr &:= ":0)";
          else
            countDivisionOptimizations(c_expr);
            c_expr.expr &:= "0";
          end if;
        else
          c_expr.expr &:= "0";
        end if;
      else
        dividend_range := getIntRange(params[1]);
        if (dividend_range.maxValue <= 0 and
            ((dividend_range.minValue > integer.first and divisor_range.maxValue < 0) or
            divisor_range.maxValue < -1)) or
            (dividend_range.minValue >= 0 and divisor_range.minValue > 0) then
          # Dividend and divisor have the same sign.
          # No checks for integer overflow and division by zero necessary.
          # Formula used: a%b
          countOverflowOptimizations(c_expr);
          if check_int_rem_by_zero then
            countDivisionOptimizations(c_expr);
          end if;
          c_expr.expr &:= "(";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ") % (";
          process_expr(params[3], c_expr);
          c_expr.expr &:= ")";
        else
          c_expr.expr &:= "(";
          dividend_name := getParameterAsVariable("intType", "dividend_", params[1], c_expr);
          divisor_name := getParameterAsVariable("intType", "divisor_", params[3], c_expr);
          if check_int_division_overflow then
            if dividend_range.minValue = integer.first and
                divisor_range.minValue <= -1 and divisor_range.maxValue >= -1 then
              incr(countOverflowChecks);
              c_expr.expr &:= "ovfChk(";
              c_expr.expr &:= dividend_name;
              c_expr.expr &:= "==";
              c_expr.expr &:= integerLiteral(integer.first);
              c_expr.expr &:= "&&";
              c_expr.expr &:= divisor_name;
              c_expr.expr &:= "==-1";
              c_expr.expr &:= ")?";
              c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
              c_expr.expr &:= ":";
            else
              countOverflowOptimizations(c_expr);
            end if;
          else
            countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
          end if;
          if check_int_rem_by_zero then
            if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
              incr(countDivisionChecks);
              c_expr.expr &:= "divChk(";
              c_expr.expr &:= divisor_name;
              c_expr.expr &:= "==0)?";
              c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
              c_expr.expr &:= ":";
            else
              countDivisionOptimizations(c_expr);
            end if;
          end if;
          if (dividend_range.minValue >= 0 and divisor_range.minValue >= 0) or
              (dividend_range.maxValue <= 0 and divisor_range.maxValue <= 0) then
            # Formula used: a%b
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= "%";
            c_expr.expr &:= divisor_name;
          else
            c_expr.expr &:= "(";
            remainder_name := defineTempVariable("intType", "remainder_", c_expr);
            # Formula used: c=a%b,a<0^b<0&&c!=0?c+b:c
            c_expr.expr &:= remainder_name;
            c_expr.expr &:= "=";
            c_expr.expr &:= dividend_name;
            c_expr.expr &:= "%";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= ",";
            if (dividend_range.maxValue >= 0 or divisor_range.minValue < 0) and
                (dividend_range.minValue < 0 or divisor_range.maxValue >= 0) then
              if dividend_range.maxValue < 0 then
                # Formula used: c=a%b,b>0&&c!=0?c+b:c
                c_expr.expr &:= divisor_name;
                c_expr.expr &:= ">0";
              elsif dividend_range.minValue >= 0 then
                # Formula used: c=a%b,b<0&&c!=0?c+b:c
                c_expr.expr &:= divisor_name;
                c_expr.expr &:= "<0";
              elsif divisor_range.minValue >= 0 then
                # Formula used: c=a%b,a<0&&c!=0?c+b:c
                c_expr.expr &:= dividend_name;
                c_expr.expr &:= "<0";
              elsif divisor_range.maxValue < 0 then
                # Formula used: c=a%b,a>0&&c!=0?c+b:c
                c_expr.expr &:= dividend_name;
                c_expr.expr &:= ">0";
              else
                # Formula used: c=a%b,a<0^b<0&&c!=0?c+b:c
                c_expr.expr &:= dividend_name;
                c_expr.expr &:= "<0^";
                c_expr.expr &:= divisor_name;
                c_expr.expr &:= "<0";
              end if;
              c_expr.expr &:= "&&";
            end if;
            c_expr.expr &:= remainder_name;
            c_expr.expr &:= "!=0?";
            c_expr.expr &:= remainder_name;
            c_expr.expr &:= "+";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= ":";
            c_expr.expr &:= remainder_name;
            c_expr.expr &:= ")";
          end if;
          c_expr.expr &:= ")";
        end if;
      end if;
    end if;
  end func;


const proc: process_const_int_mult (in reference: factor1, in integer: factor2,
    inout expr_type: c_expr) is func

  local
    var integer: minAllowedFactor1 is 0;
    var integer: maxAllowedFactor1 is 0;
    var reference: evaluatedParam is NIL;
    var integer: factor1_value is 0;
    var intRange: factor1_range is intRange.value;
    var string: factor1_name is "";
    var string: product_name is "";
    var boolean: fullOverflowCheck is FALSE;
  begin
    if factor2 < -1 then
      minAllowedFactor1 := integer.last div factor2;
      maxAllowedFactor1 := integer.first div factor2;
    elsif factor2 = -1 then
      minAllowedFactor1 := -integer.last;
      maxAllowedFactor1 := integer.last;
    elsif factor2 = 0 then
      minAllowedFactor1 := integer.first;
      maxAllowedFactor1 := integer.last;
    elsif factor2 >= 1 then
      minAllowedFactor1 := integer.first div factor2;
      maxAllowedFactor1 := integer.last div factor2;
    end if;
    if getConstant(factor1, INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      factor1_value := getValue(evaluatedParam, integer);
      if  factor1_value < minAllowedFactor1 or
          factor1_value > maxAllowedFactor1 then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= integerLiteral(factor1_value * factor2);
      end if;
    elsif factor2 = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "0";
    elsif factor2 = 1 then
      incr(countOptimizations);
      process_expr(factor1, c_expr);
    elsif factor2 = -1 then
      # Multiplying with -1 is equal to changing the sign.
      # integer.first * -1 causes an integer overflow.
      incr(countOptimizations);
      negate(factor1, c_expr);
    elsif check_int_arithmetic_overflow then
      incr(countOptimizations);
      factor1_range := getIntRange(factor1);
      if factor1_range <> intRange.value then
        if  factor1_range.minValue >= minAllowedFactor1 and
            factor1_range.maxValue <= maxAllowedFactor1 then
          # This multiplication cannot overflow
          countOverflowOptimizations(c_expr);
          c_expr.expr &:= "/*no_overflow_check_mult*/(";
          process_expr(factor1, c_expr);
          c_expr.expr &:= ") * ";
          c_expr.expr &:= integerLiteral(factor2);
        elsif factor1_range.minValue >= minAllowedFactor1 or
              factor1_range.maxValue <= maxAllowedFactor1 then
          incr(countOverflowChecks);
          c_expr.expr &:= "/*simplified_overflow_check_mult*/(";
          factor1_name := getParameterAsVariable("intType", "factor1_", factor1, c_expr);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= factor1_name;
          if factor1_range.minValue >= minAllowedFactor1 then
            c_expr.expr &:= ">";
            c_expr.expr &:= integerLiteral(maxAllowedFactor1);
          else
            c_expr.expr &:= "<";
            c_expr.expr &:= integerLiteral(minAllowedFactor1);
          end if;
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
          c_expr.expr &:= factor1_name;
          c_expr.expr &:= " * ";
          c_expr.expr &:= integerLiteral(factor2);
          c_expr.expr &:= ")";
        else
          fullOverflowCheck := TRUE;
        end if;
      else
        fullOverflowCheck := TRUE;
      end if;
      if fullOverflowCheck then
        incr(countOverflowChecks);
        if ccConf.BUILTIN_MULT_OVERFLOW <> "" then
          product_name := defineTempVariable("intType", "product_", c_expr);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= ccConf.BUILTIN_MULT_OVERFLOW;
          c_expr.expr &:= "(";
          process_expr(factor1, c_expr);
          c_expr.expr &:= ", ";
          c_expr.expr &:= integerLiteral(factor2);
          c_expr.expr &:= ", &";
          c_expr.expr &:= product_name;
          c_expr.expr &:= "))?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
          c_expr.expr &:= product_name;
        else
          c_expr.expr &:= "(";
          factor1_name := getParameterAsVariable("intType", "factor1_", factor1, c_expr);
          c_expr.expr &:= "ovfChk(";
          checkIfOutsideRange(factor1_name, minAllowedFactor1,
                              maxAllowedFactor1, c_expr);
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
          c_expr.expr &:= factor1_name;
          c_expr.expr &:= " * ";
          c_expr.expr &:= integerLiteral(factor2);
          c_expr.expr &:= ")";
        end if;
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "(";
      process_expr(factor1, c_expr);
      c_expr.expr &:= ") * ";
      c_expr.expr &:= integerLiteral(factor2);
    end if;
  end func;


const proc: process (INT_MULT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var intRange: productRange is intRange.value;
    var boolean: doOverflowCheck is FALSE;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_mult(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
      process_const_int_mult(params[3], getValue(evaluatedParam, integer), c_expr);
    else
      if check_int_arithmetic_overflow then
        if reduceOverflowChecks then
          productRange := getIntMultRange(getIntRange(params[1]),
                                          getIntRange(params[3]));
          if productRange.mayOverflow then
            doOverflowCheck := TRUE;
          else
            countOverflowOptimizations(c_expr);
            c_expr.expr &:= "/*no_overflow_check_mult*/";
          end if;
        else
          doOverflowCheck := TRUE;
        end if;
      else
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      end if;
      if doOverflowCheck then
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        int_mult_with_overflow_check(params[1], params[3], c_expr);
        c_expr.expr &:= ")";
      else
        c_expr.expr &:= "(";
        process_expr(params[1], c_expr);
        c_expr.expr &:= ") * (";
        process_expr(params[3], c_expr);
        c_expr.expr &:= ")";
      end if;
    end if;
  end func;


const proc: process_const_int_mult_assign (in reference: variable, in integer: factor,
    inout expr_type: c_expr) is func

  local
    var string: variable_name is "";
    var expr_type: statement is expr_type.value;
  begin
    if factor = 0 then
      incr(countOptimizations);
      process_expr(variable, statement);
      statement.expr &:= "=";
      statement.expr &:= integerLiteral(0);
      statement.expr &:= ";\n";
      doLocalDeclsOfStatement(statement, c_expr);
    elsif factor = 1 then
      incr(countOptimizations);
      c_expr.expr &:= "/* ignore integer *:= 1; */\n";
    elsif factor = -1 then
      if check_int_arithmetic_overflow and ccConf.TWOS_COMPLEMENT_INTTYPE then
        incr(countOverflowChecks);
        variable_name := getParameterAsReference("intType", "variable_", variable, statement);
        statement.expr &:= "if (ovfChk(";
        statement.expr &:= variable_name;
        statement.expr &:= "==";
        statement.expr &:= integerLiteral(integer.first);
        statement.expr &:= ")) {\n";
        statement.expr &:= raiseError("OVERFLOW_ERROR");
        statement.expr &:= "} else {\n";
        statement.expr &:= variable_name;
        statement.expr &:= "*= -1;\n";
        statement.expr &:= "}\n";
      else
        if ccConf.TWOS_COMPLEMENT_INTTYPE then
          countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
        end if;
        process_expr(variable, statement);
        statement.expr &:= "*= -1;\n";
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    elsif check_int_arithmetic_overflow then
      incr(countOptimizations);
      incr(countOverflowChecks);
      variable_name := getParameterAsReference("intType", "variable_", variable, statement);
      statement.expr &:= "if (ovfChk(";
      if factor < 0 then
        checkIfOutsideRange(variable_name, integer.last div factor,
                            integer.first div factor, statement);
      else
        checkIfOutsideRange(variable_name, integer.first div factor,
                            integer.last div factor, statement);
      end if;
      statement.expr &:= ")) {\n";
      statement.expr &:= raiseError("OVERFLOW_ERROR");
      statement.expr &:= "} else {\n";
      statement.expr &:= variable_name;
      statement.expr &:= " *= ";
      statement.expr &:= integerLiteral(factor);
      statement.expr &:= ";\n";
      statement.expr &:= "}\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      process_expr(variable, statement);
      statement.expr &:= "*=";
      statement.expr &:= integerLiteral(factor);
      statement.expr &:= ";\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (INT_MULT_ASSIGN, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: variable_name is "";
    var string: factor_name is "";
    var string: product_name is "";
    var expr_type: statement is expr_type.value;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_mult_assign(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif check_int_arithmetic_overflow then
      incr(countOverflowChecks);
      variable_name := getParameterAsReference("intType", "variable_", params[1], statement);
      if ccConf.BUILTIN_MULT_OVERFLOW <> "" then
        statement.expr &:= "ovfChk(";
        statement.expr &:= ccConf.BUILTIN_MULT_OVERFLOW;
        statement.expr &:= "(";
        statement.expr &:= variable_name;
        statement.expr &:= ", ";
        process_expr(params[3], statement);
        statement.expr &:= ", &(";
        statement.expr &:= variable_name;
        statement.expr &:= ")))?";
        statement.expr &:= intRaiseError("OVERFLOW_ERROR");
        statement.expr &:= ":0;";
      elsif ccConf.INTTYPE_SIZE = 64 and ccConf.INT128TYPE <> "" or
          ccConf.INTTYPE_SIZE = 32 then
        product_name := defineTempVariable("doubleIntType", "product_", statement);
        statement.expr &:= product_name;
        statement.expr &:= "=(doubleIntType)(";
        statement.expr &:= variable_name;
        statement.expr &:= ") * (doubleIntType)(";
        process_expr(params[3], statement);
        statement.expr &:= "),ovfChk(!inIntTypeRange(";
        statement.expr &:= product_name;
        statement.expr &:= "))?";
        statement.expr &:= intRaiseError("OVERFLOW_ERROR");
        statement.expr &:= ":(";
        statement.expr &:= variable_name;
        statement.expr &:= "=(intType)";
        statement.expr &:= product_name;
        statement.expr &:= ");\n";
      else
        factor_name := getParameterAsVariable("intType", "factor_", params[3], statement);
        statement.expr &:= variable_name;
        statement.expr &:= "<0&&(";
        statement.expr &:= factor_name;
        statement.expr &:= "<0&&";
        statement.expr &:= variable_name;
        statement.expr &:= "<";
        statement.expr &:= integerLiteral(integer.last);
        statement.expr &:= "/";
        statement.expr &:= factor_name;
        statement.expr &:= "||";
        statement.expr &:= factor_name;
        statement.expr &:= ">0&&";
        statement.expr &:= variable_name;
        statement.expr &:= "<";
        statement.expr &:= integerLiteral(integer.first);
        statement.expr &:= "/";
        statement.expr &:= factor_name;
        statement.expr &:= ")||";
        statement.expr &:= variable_name;
        statement.expr &:= ">0&&(";
        statement.expr &:= factor_name;
        statement.expr &:= "<0&&";
        statement.expr &:= factor_name;
        statement.expr &:= "<";
        statement.expr &:= integerLiteral(integer.first);
        statement.expr &:= "/";
        statement.expr &:= variable_name;
        statement.expr &:= "||";
        statement.expr &:= factor_name;
        statement.expr &:= ">0&&";
        statement.expr &:= factor_name;
        statement.expr &:= ">";
        statement.expr &:= integerLiteral(integer.last);
        statement.expr &:= "/";
        statement.expr &:= variable_name;
        statement.expr &:= ")?";
        statement.expr &:= intRaiseError("OVERFLOW_ERROR");
        statement.expr &:= ":(";
        statement.expr &:= variable_name;
        statement.expr &:= " *= ";
        statement.expr &:= factor_name;
        statement.expr &:= ");\n";
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      process_expr(params[1], statement);
      statement.expr &:= "*=";
      process_expr(params[3], statement);
      statement.expr &:= ";\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (INT_NE, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var intRange: number1Range is intRange.value;
    var intRange: number2Range is intRange.value;
    var boolean: doCompare is TRUE;
  begin
    if optimizeComparisons then
      number1Range := getIntRange(params[1]);
      number2Range := getIntRange(params[3]);
      if not number1Range.mayRaiseException and not number2Range.mayRaiseException then
        if number1Range.maxValue < number2Range.minValue or
            number1Range.minValue > number2Range.maxValue then
          warning(COMPARISON_RESULT_CONSTANT, "<>", TRUE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "1";
          doCompare := FALSE;
        elsif number1Range.minValue = number1Range.maxValue and
            number2Range.minValue = number2Range.maxValue and
            number1Range.minValue = number2Range.minValue then
          warning(COMPARISON_RESULT_CONSTANT, "<>", FALSE, c_expr);
          incr(countOptimizations);
          c_expr.expr &:= "0";
          doCompare := FALSE;
        end if;
      end if;
    end if;
    if doCompare then
      c_expr.expr &:= "(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ") != (";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_NEGATE, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: number_name is "";
    var integer: number is 0;
  begin
    if getConstant(params[2], INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      number := getValue(evaluatedParam, integer);
      if number = integer.first and ccConf.TWOS_COMPLEMENT_INTTYPE then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= integerLiteral(-number);
      end if;
    else
      negate(params[2], c_expr);
    end if;
  end func;


const proc: process (INT_N_BYTES_BE_SIGNED, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    prepare_stri_result(c_expr);
    c_expr.result_expr := "intNBytesBeSigned(";
    getStdParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", ";
    getStdParamToResultExpr(params[4], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process_const_int_n_bytes_be_unsigned (in reference: number,
    in integer: length, inout expr_type: c_expr) is func

  local
    var reference: evaluatedNumber is NIL;
    var integer: numberValue is 0;
    var intRange: numberRange is intRange.value;
    var boolean: rangeCheckDone is FALSE;
    var string: buffer_name is "";
    var string: number_name is "";
    var integer: index is 0;
  begin
    if length <= 0 then
      incr(countOptimizations);
      warning(DOES_RAISE, "RANGE_ERROR", c_expr);
      c_expr.expr &:= strRaiseError("RANGE_ERROR");
    elsif getConstant(number, INTOBJECT, evaluatedNumber) then
      incr(countOptimizations);
      numberValue := getValue(evaluatedNumber, integer);
      if numberValue < 0 or (length < 8 and numberValue >= 2 ** (8 * length)) then
        warning(DOES_RAISE, "RANGE_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("RANGE_ERROR");
      else
        c_expr.expr &:= stringLiteral(bytes(numberValue, UNSIGNED, BE, length));
      end if;
    elsif ccConf.ALLOW_STRITYPE_SLICES and length <= 8 then
      incr(countOptimizations);
      incr(countInlinedFunctions);
      incr(c_expr.temp_num);
      buffer_name := "buffer_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "union {\n";
      c_expr.temp_decls &:= "  struct striStruct striBuf;\n";
      c_expr.temp_decls &:= "  char charBuf[SIZ_STRI(";
      c_expr.temp_decls &:= str(length);
      c_expr.temp_decls &:= ")];\n";
      c_expr.temp_decls &:= "} ";
      c_expr.temp_decls &:= buffer_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "(";
      number_name := getParameterAsVariable("intType", "number_", number, c_expr);
      if function_range_check then
        numberRange := getIntRange(number);
        if numberRange.minValue >= 0 and
            (length >= 8 or numberRange.maxValue < 2 ** (8 * length)) then
          # This function cannot trigger a range error.
          countRangeOptimizations(c_expr);
        else
          incr(countRangeChecks);
          c_expr.expr &:= "rngChk(";
          if length >= 8 or numberRange.maxValue < 2 ** (8 * length) then
            c_expr.expr &:= number_name;
            c_expr.expr &:= "<0";
          else
            checkIfOutsideRange(number_name, 0, pred(2 ** (8 * length)), c_expr);
          end if;
          c_expr.expr &:= ")?";
          c_expr.expr &:= strRaiseError("RANGE_ERROR");
          c_expr.expr &:= ":(";
          rangeCheckDone := TRUE;
        end if;
      else
        incr(countNoRangeChecks);
      end if;
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.size=";
      c_expr.expr &:= str(length);
      c_expr.expr &:= ",";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.mem=";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.mem1,";
      for index range 1 to length do
        c_expr.expr &:= buffer_name;
        c_expr.expr &:= ".striBuf.mem1[";
        c_expr.expr &:= str(pred(index));
        c_expr.expr &:= "]=(strElemType)(";
        if index <> length then
          c_expr.expr &:= "(";
          c_expr.expr &:= number_name;
          c_expr.expr &:= ">>";
          c_expr.expr &:= str(8 * (length - index));
          c_expr.expr &:= ")";
        else
          c_expr.expr &:= number_name;
        end if;
        if index <> 1 then
          c_expr.expr &:= "&255";
        end if;
        c_expr.expr &:= "),";
      end for;
      c_expr.expr &:= "&";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf";
      if rangeCheckDone then
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "intNBytesBeUnsigned(";
      getStdParamToResultExpr(number, c_expr);
      c_expr.result_expr &:= ", ";
      c_expr.result_expr &:= integerLiteral(length);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process (INT_N_BYTES_BE_UNSIGNED, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedLength is NIL;
  begin
    if inlineFunctions and
        getConstant(params[4], INTOBJECT, evaluatedLength) then
      process_const_int_n_bytes_be_unsigned(params[1],
          getValue(evaluatedLength, integer), c_expr);
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "intNBytesBeUnsigned(";
      getStdParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[4], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process (INT_N_BYTES_LE_SIGNED, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    prepare_stri_result(c_expr);
    c_expr.result_expr := "intNBytesLeSigned(";
    getStdParamToResultExpr(params[1], c_expr);
    c_expr.result_expr &:= ", ";
    getStdParamToResultExpr(params[4], c_expr);
    c_expr.result_expr &:= ")";
  end func;


const proc: process_const_int_n_bytes_le_unsigned (in reference: number,
    in integer: length, inout expr_type: c_expr) is func

  local
    var reference: evaluatedNumber is NIL;
    var integer: numberValue is 0;
    var intRange: numberRange is intRange.value;
    var boolean: rangeCheckDone is FALSE;
    var string: buffer_name is "";
    var string: number_name is "";
    var integer: index is 0;
  begin
    if length <= 0 then
      incr(countOptimizations);
      warning(DOES_RAISE, "RANGE_ERROR", c_expr);
      c_expr.expr &:= strRaiseError("RANGE_ERROR");
    elsif getConstant(number, INTOBJECT, evaluatedNumber) then
      incr(countOptimizations);
      numberValue := getValue(evaluatedNumber, integer);
      if numberValue < 0 or (length < 8 and numberValue >= 2 ** (8 * length)) then
        warning(DOES_RAISE, "RANGE_ERROR", c_expr);
        c_expr.expr &:= strRaiseError("RANGE_ERROR");
      else
        c_expr.expr &:= stringLiteral(bytes(numberValue, UNSIGNED, LE, length));
      end if;
    elsif ccConf.ALLOW_STRITYPE_SLICES and length <= 8 then
      incr(countOptimizations);
      incr(countInlinedFunctions);
      incr(c_expr.temp_num);
      buffer_name := "buffer_" & str(c_expr.temp_num);
      c_expr.temp_decls &:= "union {\n";
      c_expr.temp_decls &:= "  struct striStruct striBuf;\n";
      c_expr.temp_decls &:= "  char charBuf[SIZ_STRI(";
      c_expr.temp_decls &:= str(length);
      c_expr.temp_decls &:= ")];\n";
      c_expr.temp_decls &:= "} ";
      c_expr.temp_decls &:= buffer_name;
      c_expr.temp_decls &:= ";\n";
      c_expr.expr &:= "(";
      number_name := getParameterAsVariable("intType", "number_", number, c_expr);
      if function_range_check then
        numberRange := getIntRange(number);
        if numberRange.minValue >= 0 and
            (length >= 8 or numberRange.maxValue < 2 ** (8 * length)) then
          # This function cannot trigger a range error.
          countRangeOptimizations(c_expr);
        else
          incr(countRangeChecks);
          c_expr.expr &:= "rngChk(";
          if length >= 8 or numberRange.maxValue < 2 ** (8 * length) then
            c_expr.expr &:= number_name;
            c_expr.expr &:= "<0";
          else
            checkIfOutsideRange(number_name, 0, pred(2 ** (8 * length)), c_expr);
          end if;
          c_expr.expr &:= ")?";
          c_expr.expr &:= strRaiseError("RANGE_ERROR");
          c_expr.expr &:= ":(";
          rangeCheckDone := TRUE;
        end if;
      else
        incr(countNoRangeChecks);
      end if;
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.size=";
      c_expr.expr &:= str(length);
      c_expr.expr &:= ",";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.mem=";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf.mem1,";
      for index range 1 to length do
        c_expr.expr &:= buffer_name;
        c_expr.expr &:= ".striBuf.mem1[";
        c_expr.expr &:= str(pred(index));
        c_expr.expr &:= "]=(strElemType)(";
        if index <> 1 then
          c_expr.expr &:= "(";
          c_expr.expr &:= number_name;
          c_expr.expr &:= ">>";
          c_expr.expr &:= str(8 * pred(index));
          c_expr.expr &:= ")";
        else
          c_expr.expr &:= number_name;
        end if;
        if index <> length then
          c_expr.expr &:= "&255";
        end if;
        c_expr.expr &:= "),";
      end for;
      c_expr.expr &:= "&";
      c_expr.expr &:= buffer_name;
      c_expr.expr &:= ".striBuf";
      if rangeCheckDone then
        c_expr.expr &:= ")";
      end if;
      c_expr.expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "intNBytesLeUnsigned(";
      getStdParamToResultExpr(number, c_expr);
      c_expr.result_expr &:= ", ";
      c_expr.result_expr &:= integerLiteral(length);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process (INT_N_BYTES_LE_UNSIGNED, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedLength is NIL;
  begin
    if inlineFunctions and
        getConstant(params[4], INTOBJECT, evaluatedLength) then
      process_const_int_n_bytes_le_unsigned(params[1],
          getValue(evaluatedLength, integer), c_expr);
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "intNBytesLeUnsigned(";
      getStdParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[4], c_expr);
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process (INT_ODD, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ")&1";
  end func;


const proc: process (INT_PARSE1, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intParse(";
    getAnyParamToExpr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: process (INT_PLUS, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    process_expr(params[2], c_expr);
  end func;


const func boolean: powerOverflows (in integer: base, in integer: exponent) is func

  result
    var boolean: powerOverflows is FALSE;
  begin
    if exponent < 0 then
      # A negative exponent raises NUMERIC_ERROR instead of OVERFLOW_ERROR.
      # The function powerOverflows() is never called with a negative exponent.
      powerOverflows := FALSE;
    elsif exponent >= minIdx(minBaseOfExponent) then
      if exponent <= maxIdx(minBaseOfExponent) then
        if  base < minBaseOfExponent[exponent] or
            base > maxBaseOfExponent[exponent] then
          powerOverflows := TRUE;
        end if;
      elsif base < minIdx(maxExponentOfBase) or
            base > maxIdx(maxExponentOfBase) or
            exponent > maxExponentOfBase[base] then
        powerOverflows := TRUE;
      end if;
    end if;
  end func;


const proc: process_const_int_pow (in reference: base, in integer: exponent,
    inout expr_type: c_expr) is func

  local
    const array string: power is [2] (
        (*  2 *) "x*x", "x*x*x", "(a=x*x,a*a)", "(a=x*x,a*a*x)", "(a=x*x*x,a*a)",
        (*  7 *) "(a=x*x,a*a*a*x)", "(b=(a=x*x,a*a),b*b)", "(b=(a=x*x,a*a),b*b*x)",
        (* 10 *) "(b=(a=x*x,a*a*x),b*b)", "(b=(a=x*x,a*a*x),b*b*x)",
        (* 12 *) "(b=(a=x*x*x,a*a),b*b)", "(b=(a=x*x,a*a),b*b*b*x)",
        (* 14 *) "(b=(a=x*x,a*a*a*x),b*b)", "(b=(a=x*x*x,a*a),b*b*a)",
        (* 16 *) "(c=(b=(a=x*x,a*a),b*b),c*c)", "(c=(b=(a=x*x,a*a),b*b),c*c*x)",
        (* 18 *) "(c=(b=(a=x*x,a*a),b*b),c*c*a)", "(c=(b=(a=x*x,a*a*x),b*a),c*c*b)",
        (* 20 *) "(c=(b=(a=x*x,a*a*x),b*b),c*c)", "(c=(b=(a=x*x,a*a*x),b*b),c*c*x)",
        (* 22 *) "(c=(b=(a=x*x,a*a*x),b*b*x),c*c)");
    const string: variables is "abc";
    var reference: evaluatedBase is NIL;
    var integer: baseValue is 0;
    var string: powerTemplate is "";
    var intRange: baseRange is intRange.value;
    var string: baseName is "";
    var string: variableName is "";
    var char: ch is ' ';
    var integer: minBase is 0;
    var integer: maxBase is 0;
  begin
    if exponent < 0 then
      incr(countOptimizations);
      warning(DOES_RAISE, "NUMERIC_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
    elsif getConstant(base, INTOBJECT, evaluatedBase) then
      incr(countOptimizations);
      baseValue := getValue(evaluatedBase, integer);
      if powerOverflows(baseValue, exponent) then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= integerLiteral(baseValue ** exponent);
      end if;
    elsif exponent = 0 then
      incr(countOptimizations);
      c_expr.expr &:= integerLiteral(1);
    elsif exponent = 1 then
      incr(countOptimizations);
      process_expr(base, c_expr);
    elsif exponent in {2 .. maxIdx(power)} then
      incr(countOptimizations);
      powerTemplate := power[exponent];
      c_expr.expr &:= "(";
      baseName := getParameterAsVariable("intType", "base_", base, c_expr);
      if check_int_arithmetic_overflow then
        baseRange := getIntRange(base);
        if baseRange.minValue < minBaseOfExponent[exponent] or
            baseRange.maxValue > maxBaseOfExponent[exponent] then
          incr(countOverflowChecks);
          c_expr.expr &:= "ovfChk(";
          checkIfOutsideRange(baseName, minBaseOfExponent[exponent],
                              maxBaseOfExponent[exponent], c_expr);
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
        else
          countOverflowOptimizations(c_expr);
        end if;
      else
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      end if;
      for ch range variables do
        if pos(powerTemplate, ch) <> 0 then
          variableName := defineTempVariable("intType", str(ch) & "_", c_expr);
          powerTemplate := replace(powerTemplate, str(ch), variableName);
        end if;
      end for;
      c_expr.expr &:= replace(powerTemplate, "x", baseName);
      c_expr.expr &:= ")";
    elsif integer_overflow_check then
      incr(countOptimizations);
      baseRange := getIntRange(base);
      minBase := minIdx(maxExponentOfBase);
      while exponent > maxExponentOfBase[minBase] do
        incr(minBase);
      end while;
      maxBase := maxIdx(maxExponentOfBase);
      while exponent > maxExponentOfBase[maxBase] do
        decr(maxBase);
      end while;
      c_expr.expr &:= "(";
      baseName := getParameterAsVariable("intType", "base_", base, c_expr);
      if baseRange.minValue < minBase or
          baseRange.maxValue > maxBase then
        incr(countOverflowChecks);
        c_expr.expr &:= "ovfChk(";
        checkIfOutsideRange(baseName, minBase, maxBase, c_expr);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":";
      else
        countOverflowOptimizations(c_expr);
      end if;
      c_expr.expr &:= "intPow(";
      c_expr.expr &:= baseName;
      c_expr.expr &:= ", ";
      c_expr.expr &:= integerLiteral(exponent);
      c_expr.expr &:= "))";
    else
      c_expr.expr &:= "intPow(";
      process_expr(base, c_expr);
      c_expr.expr &:= ", ";
      c_expr.expr &:= integerLiteral(exponent);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_int_pow (in integer: base, in reference: exponent,
    inout expr_type: c_expr) is func

  local
    var intRange: exponentRange is intRange.value;
    var string: exponentName is "";
    var integer: log2ofNegatedBase is 0;
    var integer: maxExponent is 0;
  begin
    exponentRange := getIntRange(exponent);
    if exponentRange.maxValue < 0 then
      warning(DOES_RAISE, "NUMERIC_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
    elsif base = -1 then
      incr(countOptimizations);
      if integer_power_check and exponentRange.minValue < 0 then
        c_expr.expr &:= "(";
        exponentName := getParameterAsVariable("intType", "exponent_", exponent, c_expr);
        c_expr.expr &:= "numChk(";
        c_expr.expr &:= exponentName;
        c_expr.expr &:= "<0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":1-((";
        c_expr.expr &:= exponentName;
        c_expr.expr &:= "&1)<<1))";
      else
        c_expr.expr &:= "1-(((";
        process_expr(exponent, c_expr);
        c_expr.expr &:= ")&1)<<1)";
      end if;
    elsif base = 0 then
      incr(countOptimizations);
      if integer_power_check and exponentRange.minValue < 0 then
        c_expr.expr &:= "(";
        exponentName := getParameterAsVariable("intType", "exponent_", exponent, c_expr);
        c_expr.expr &:= "numChk(";
        c_expr.expr &:= exponentName;
        c_expr.expr &:= "<0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
        c_expr.expr &:= exponentName;
        c_expr.expr &:= "==0?";
        c_expr.expr &:= integerLiteral(1);
        c_expr.expr &:= ":";
        c_expr.expr &:= integerLiteral(0);
        c_expr.expr &:= ")";
      else
        c_expr.expr &:= "(";
        process_expr(exponent, c_expr);
        c_expr.expr &:= ")==0?";
        c_expr.expr &:= integerLiteral(1);
        c_expr.expr &:= ":";
        c_expr.expr &:= integerLiteral(0);
      end if;
    elsif base = 1 then
      incr(countOptimizations);
      if integer_power_check and exponentRange.minValue < 0 then
        c_expr.expr &:= "(numChk((";
        process_expr(exponent, c_expr);
        c_expr.expr &:= ")<0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
        c_expr.expr &:= integerLiteral(1);
        c_expr.expr &:= ")";
      else
        c_expr.expr &:= integerLiteral(1);
      end if;
    elsif base > 0 and 2 ** log2(base) = base then
      # Base is a power of two.
      incr(countOptimizations);
      maxExponent := log2(integer.last) div log2(base);
      if exponentRange.minValue > maxExponent then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      elsif integer_power_check and exponentRange.minValue < 0 or
          integer_overflow_check and exponentRange.maxValue > maxExponent then
        c_expr.expr &:= "(";
        exponentName := getParameterAsVariable("intType", "exponent_", exponent, c_expr);
        if integer_power_check and exponentRange.minValue < 0 then
          c_expr.expr &:= "numChk(";
          c_expr.expr &:= exponentName;
          c_expr.expr &:= "<0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":";
        end if;
        if integer_overflow_check then
          if exponentRange.maxValue > maxExponent then
            incr(countOverflowChecks);
            c_expr.expr &:= "ovfChk(";
            c_expr.expr &:= exponentName;
            c_expr.expr &:= ">";
            c_expr.expr &:= integerLiteral(maxExponent);
            c_expr.expr &:= ")?";
            c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
            c_expr.expr &:= ":";
          else
            countOverflowOptimizations(c_expr);
          end if;
        end if;
        c_expr.expr &:= integerLiteral(1);
        c_expr.expr &:= "<<";
        if base <> 2 then
          c_expr.expr &:= integerLiteral(log2(base));
          c_expr.expr &:= "*";
        end if;
        c_expr.expr &:= exponentName;
        c_expr.expr &:= ")";
      else
        if integer_overflow_check then
          countOverflowOptimizations(c_expr);
        end if;
        c_expr.expr &:= integerLiteral(1);
        c_expr.expr &:= "<<";
        if base <> 2 then
          c_expr.expr &:= integerLiteral(log2(base));
          c_expr.expr &:= "*";
        end if;
        c_expr.expr &:= "(";
        process_expr(exponent, c_expr);
        c_expr.expr &:= ")";
      end if;
    elsif base < 0 and bitLength(base) = lowestSetBit(base) then
      # Base is a negative power of two.
      # The check above is (almost) equivalent to:
      #   base < 0 and 2 ** log2(-base) = -base
      # The check with bitLength is used to avoid negating the base.
      # Negating the base would fail for the most negative integer.
      incr(countOptimizations);
      # The following computation is done with bigInteger,
      # because base could be integer.first.
      log2ofNegatedBase := ord(log2(-bigInteger(base)));
      maxExponent := ord(log2(-bigInteger(integer.first))) div log2ofNegatedBase;
      if not odd(maxExponent) then
        maxExponent := log2(integer.last) div log2ofNegatedBase;
      end if;
      if exponentRange.minValue > maxExponent then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= "(";
        exponentName := getParameterAsVariable("intType", "exponent_", exponent, c_expr);
        if integer_power_check and exponentRange.minValue < 0 then
          c_expr.expr &:= "numChk(";
          c_expr.expr &:= exponentName;
          c_expr.expr &:= "<0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":";
        end if;
        if integer_overflow_check then
          if exponentRange.maxValue > maxExponent then
            incr(countOverflowChecks);
            c_expr.expr &:= "ovfChk(";
            c_expr.expr &:= exponentName;
            c_expr.expr &:= ">";
            c_expr.expr &:= integerLiteral(maxExponent);
            c_expr.expr &:= ")?";
            c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
            c_expr.expr &:= ":";
          else
            countOverflowOptimizations(c_expr);
          end if;
        end if;
        c_expr.expr &:= exponentName;
        c_expr.expr &:= "&1?";
        c_expr.expr &:= integerLiteral(-1);
        c_expr.expr &:= "<<";
        if base <> -2 then
          c_expr.expr &:= integerLiteral(log2ofNegatedBase);
          c_expr.expr &:= "*";
        end if;
        c_expr.expr &:= exponentName;
        c_expr.expr &:= ":";
        c_expr.expr &:= integerLiteral(1);
        c_expr.expr &:= "<<";
        if base <> -2 then
          c_expr.expr &:= integerLiteral(log2ofNegatedBase);
          c_expr.expr &:= "*";
        end if;
        c_expr.expr &:= exponentName;
        c_expr.expr &:= ")";
      end if;
    elsif integer_overflow_check then
      incr(countOptimizations);
      if base >= minIdx(maxExponentOfBase) and base <= maxIdx(maxExponentOfBase) then
        maxExponent := maxExponentOfBase[base];
      elsif base > 0 then
        maxExponent := 2;
        while base <= maxBaseOfExponent[maxExponent] do
          incr(maxExponent);
        end while;
        decr(maxExponent);
      else # base < 0
        maxExponent := 2;
        while base >= minBaseOfExponent[maxExponent] do
          incr(maxExponent);
        end while;
        decr(maxExponent);
      end if;
      if exponentRange.minValue > maxExponent then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= "(";
        exponentName := getParameterAsVariable("intType", "exponent_", exponent, c_expr);
        if exponentRange.maxValue > maxExponent then
          incr(countOverflowChecks);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= exponentName;
          c_expr.expr &:= ">";
          c_expr.expr &:= integerLiteral(maxExponent);
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
        else
          countOverflowOptimizations(c_expr);
        end if;
        c_expr.expr &:= "intPow(";
        c_expr.expr &:= integerLiteral(base);
        c_expr.expr &:= ", ";
        c_expr.expr &:= exponentName;
        c_expr.expr &:= "))";
      end if;
    else
      c_expr.expr &:= "intPow(";
      c_expr.expr &:= integerLiteral(base);
      c_expr.expr &:= ", ";
      process_expr(exponent, c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process (INT_POW, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var intRange: baseRange is intRange.value;
    var intRange: exponentRange is intRange.value;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_pow(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
      process_const_int_pow(getValue(evaluatedParam, integer), params[3], c_expr);
    else
      baseRange := getIntRange(params[1]);
      exponentRange := getIntRange(params[3]);
      if exponentRange.maxValue < 0 then
        warning(DOES_RAISE, "NUMERIC_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      else
        if integer_overflow_check then
          if exponentRange.maxValue < minIdx(minBaseOfExponent) or
              exponentRange.maxValue > maxIdx(minBaseOfExponent) or
              baseRange.minValue < minBaseOfExponent[exponentRange.maxValue] or
              baseRange.maxValue > maxBaseOfExponent[exponentRange.maxValue] then
            incr(countOverflowChecks);
            c_expr.expr &:= "intPowOvfChk(";
          else
            countOverflowOptimizations(c_expr);
            c_expr.expr &:= "intPow(";
          end if;
        else
          c_expr.expr &:= "intPow(";
        end if;
        process_expr(params[1], c_expr);
        c_expr.expr &:= ", ";
        process_expr(params[3], c_expr);
        c_expr.expr &:= ")";
      end if;
    end if;
  end func;


const proc: process (INT_PRED, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: number_name is "";
    var integer: number is 0;
  begin
    if callOptimizeIntAdd then
      optimize_int_add(params[1], -1, c_expr);
    elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      number := getValue(evaluatedParam, integer);
      if number = integer.first then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= integerLiteral(pred(number));
      end if;
    elsif check_int_arithmetic_overflow then
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      number_name := getParameterAsVariable("intType", "number_", params[1], c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= number_name;
      c_expr.expr &:= "==";
      c_expr.expr &:= integerLiteral(integer.first);
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= number_name;
      c_expr.expr &:= "-1)";
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ")-1";
    end if;
  end func;


const proc: process_const_int_radix (in reference: param1, in integer: base,
    in boolean: upperCase, inout expr_type: c_expr) is func

  begin
    if base < 2 or base > 36 then
      incr(countOptimizations);
      warning(DOES_RAISE, "RANGE_ERROR", c_expr);
      c_expr.expr &:= strRaiseError("RANGE_ERROR");
    elsif base = 10 then
      incr(countOptimizations);
      process_int_str(param1, c_expr);
    elsif 2 ** log2(base) = base then
      incr(countOptimizations);
      prepare_stri_result(c_expr);
      c_expr.result_expr := "intRadixPow2(";
      getStdParamToResultExpr(param1, c_expr);
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= integerLiteral(log2(base));
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= integerLiteral(pred(base));
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= str(ord(upperCase));
      c_expr.result_expr &:= ")";
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "intRadix(";
      getStdParamToResultExpr(param1, c_expr);
      c_expr.result_expr &:= ", ";
      c_expr.result_expr &:= integerLiteral(base);
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= str(ord(upperCase));
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process_int_radix (in ref_list: params, in boolean: upperCase,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_radix(params[1], getValue(evaluatedParam, integer),
          upperCase, c_expr);
    else
      prepare_stri_result(c_expr);
      c_expr.result_expr := "intRadix(";
      getStdParamToResultExpr(params[1], c_expr);
      c_expr.result_expr &:= ", ";
      getStdParamToResultExpr(params[3], c_expr);
      c_expr.result_expr &:= ",";
      c_expr.result_expr &:= str(ord(upperCase));
      c_expr.result_expr &:= ")";
    end if;
  end func;


const proc: process (INT_radix, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    process_int_radix(params, FALSE, c_expr);
  end func;


const proc: process (INT_RADIX, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    process_int_radix(params, TRUE, c_expr);
  end func;


const proc: process_const_int_rand (in integer: lowerBound, in integer: upperBound,
    inout expr_type: c_expr) is func

  local
    const bigInteger: UINTTYPE_MAX is 18446744073709551615_;
    var bigInteger: beyond is 0_;
    var bigInteger: rand_max is 0_;
  begin
    incr(countOptimizations);
    if lowerBound >= upperBound then
      if lowerBound = upperBound then
        c_expr.expr &:= integerLiteral(lowerBound);
      else
        warning(DOES_RAISE, "RANGE_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("RANGE_ERROR");
      end if;
    else
      beyond := bigInteger(upperBound) - bigInteger(lowerBound) + 1_;
      if beyond = succ(UINTTYPE_MAX) then
        # lowerBound must be integer.first and upperBound must be integer.last.
        c_expr.expr &:= "(intType) uintRand()";
      elsif 2_ ** ord(log2(beyond)) = beyond then
        # beyond is a power of two.
        c_expr.expr &:= "(intType) (";
        if lowerBound <> 0 then
          c_expr.expr &:= "(uintType) ";
          c_expr.expr &:= integerLiteral(lowerBound);
          c_expr.expr &:= " + (";
        end if;
        c_expr.expr &:= "uintRand() & ";
        c_expr.expr &:= str(pred(beyond));
        c_expr.expr &:= "U";
        c_expr.expr &:= ccConf.INTTYPE_LITERAL_SUFFIX;
        if lowerBound <> 0 then
          c_expr.expr &:= ")";
        end if;
        c_expr.expr &:= ")";
      else
        c_expr.expr &:= "(intType) (";
        if lowerBound <> 0 then
          c_expr.expr &:= "(uintType) ";
          c_expr.expr &:= integerLiteral(lowerBound);
          c_expr.expr &:= " + ";
        end if;
        rand_max := UINTTYPE_MAX - (succ(UINTTYPE_MAX) rem beyond);
        # succ(UINTTYPE_MAX) is a power of two.
        # Therefore rand_max will always be below UINTTYPE_MAX.
        c_expr.expr &:= "uintRandLimited(";
        c_expr.expr &:= str(rand_max);
        c_expr.expr &:= "U";
        c_expr.expr &:= ccConf.INTTYPE_LITERAL_SUFFIX;
        c_expr.expr &:= ") % ";
        c_expr.expr &:= str(beyond);
        c_expr.expr &:= "U";
        c_expr.expr &:= ccConf.INTTYPE_LITERAL_SUFFIX;
        c_expr.expr &:= ")";
      end if;
    end if;
  end func;


const proc: process (INT_RAND, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedLowerBound is NIL;
    var reference: evaluatedUpperBound is NIL;
  begin
    if getConstant(params[1], INTOBJECT, evaluatedLowerBound) and
        getConstant(params[2], INTOBJECT, evaluatedUpperBound) then
      process_const_int_rand(getValue(evaluatedLowerBound, integer),
                             getValue(evaluatedUpperBound, integer), c_expr);
    else
      c_expr.expr &:= "intRand(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ", ";
      process_expr(params[2], c_expr);
      c_expr.expr &:= ")";
    end if;
  end func;


const proc: process_const_int_rem (in reference: dividend, in integer: divisor,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedDividend is NIL;
    var integer: dividend_value is 0;
    var string: dividend_name is "";
    var intRange: dividend_range is intRange.value;
  begin
    if divisor = 0 then
      incr(countOptimizations);
      warning(DOES_RAISE, "NUMERIC_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
    elsif divisor = 1 then
      incr(countOptimizations);
      c_expr.expr &:= "0";
    elsif getConstant(dividend, INTOBJECT, evaluatedDividend) then
      incr(countOptimizations);
      dividend_value := getValue(evaluatedDividend, integer);
      if divisor = -1 and dividend_value < -integer.last then
        # Normally this raises OVERFLOW_ERROR, but it is not guaranteed to do so.
        # According to the optimization rules for overflow it is okay
        # to deliver the correct result instead of raising OVERFLOW_ERROR.
        # In case of a remainder by -1 the correct result is always 0.
        if reduceOverflowChecks then
          countOverflowOptimizations(c_expr);
          c_expr.expr &:= "/*no_overflow_check_rem*/ 0";
        else
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        end if;
      else
        c_expr.expr &:= integerLiteral(dividend_value rem divisor);
      end if;
    elsif divisor = -1 then
      incr(countOptimizations);
      if not check_int_division_overflow then
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
        c_expr.expr &:= "0";
      elsif reduceOverflowChecks then
        countOverflowOptimizations(c_expr);
        c_expr.expr &:= "/*no_overflow_check_rem*/ 0";
      else
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        dividend_name := getParameterAsVariable("intType", "dividend_", dividend, c_expr);
        c_expr.expr &:= "ovfChk(";
        c_expr.expr &:= dividend_name;
        c_expr.expr &:= "==";
        c_expr.expr &:= integerLiteral(integer.first);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":0)";
      end if;
    elsif divisor > 0 and 2 ** log2(divisor) = divisor then
      # Divisor is a power of two.
      dividend_range := getIntRange(dividend);
      if dividend_range.minValue >= 0 then
        incr(countOptimizations);
        c_expr.expr &:= "(";
        process_expr(dividend, c_expr);
        c_expr.expr &:= ")";
        c_expr.expr &:= "&";
        c_expr.expr &:= integerLiteral(pred(divisor));
      else
        c_expr.expr &:= "(";
        process_expr(dividend, c_expr);
        c_expr.expr &:= ") % ";
        c_expr.expr &:= integerLiteral(divisor);
      end if;
    else
      c_expr.expr &:= "(";
      process_expr(dividend, c_expr);
      c_expr.expr &:= ") % ";
      c_expr.expr &:= integerLiteral(divisor);
    end if;
  end func;


const proc: process_const_int_rem (in integer: dividend, in reference: divisor,
    inout expr_type: c_expr) is func

  local
    var string: divisor_name is "";
    var intRange: divisor_range is intRange.value;
  begin
    divisor_range := getIntRange(divisor);
    if dividend = 0 then
      incr(countOptimizations);
      if integer_division_check then
        if (divisor_range.minValue <= 0 and divisor_range.maxValue >= 0) or
            divisor_range.mayRaiseException then
          incr(countDivisionChecks);
          c_expr.expr &:= "(divChk((";
          process_expr(divisor, c_expr);
          c_expr.expr &:= ")==0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":0)";
        else
          countDivisionOptimizations(c_expr);
          c_expr.expr &:= "0";
        end if;
      else
        c_expr.expr &:= "0";
      end if;
    elsif check_int_division_overflow and dividend = integer.first then
      # integer.first % -1 causes an integer overflow.
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "divisor_", divisor, c_expr);
      if divisor_range.minValue <= -1 and divisor_range.maxValue >= -1 then
        incr(countOverflowChecks);
        c_expr.expr &:= "ovfChk(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==-1)?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":";
      else
        countOverflowOptimizations(c_expr);
      end if;
      if check_int_rem_by_zero then
        if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
          incr(countDivisionChecks);
          c_expr.expr &:= "divChk(";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "==0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":";
        else
          countDivisionOptimizations(c_expr);
        end if;
      end if;
      c_expr.expr &:= integerLiteral(dividend);
      c_expr.expr &:= " % ";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= ")";
    else
      if dividend = integer.first then
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      end if;
      if check_int_rem_by_zero then
        if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
          incr(countDivisionChecks);
          c_expr.expr &:= "(";
          divisor_name := getParameterAsVariable("intType", "divisor_", divisor, c_expr);
          c_expr.expr &:= "divChk(";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "==0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":";
          c_expr.expr &:= integerLiteral(dividend);
          c_expr.expr &:= " % ";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= ")";
        else
          countDivisionOptimizations(c_expr);
          c_expr.expr &:= integerLiteral(dividend);
          c_expr.expr &:= " % (";
          process_expr(divisor, c_expr);
          c_expr.expr &:= ")";
        end if;
      else
        c_expr.expr &:= integerLiteral(dividend);
        c_expr.expr &:= " % (";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")";
      end if;
    end if;
  end func;


const proc: process (INT_REM, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: dividend_name is "";
    var string: divisor_name is "";
    var intRange: dividend_range is intRange.value;
    var intRange: divisor_range is intRange.value;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_rem(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif constValueIsEqual(params[3], -1) then
      process_const_int_rem(params[1], -1, c_expr);
    elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
      process_const_int_rem(getValue(evaluatedParam, integer), params[3], c_expr);
    elsif evaluate_const_expr = 0 and check_int_rem_zero_by_zero and
          category(params[1]) = INTOBJECT and not isVar(params[1]) and
          getValue(params[1], integer) = 0 then
      incr(countDivisionChecks);
      c_expr.expr &:= "(divChk((";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    else
      divisor_range := getIntRange(params[3]);
      if params[1] = params[3] then
        # C compilers are allowed to optimize variable%variable to 0.
        # A C compiler can assume, that an "undefined behavior", like a
        # division by zero will never happen. So we need to handle this case.
        if integer_division_check then
          if (divisor_range.minValue <= 0 and divisor_range.maxValue >= 0) or
              divisor_range.mayRaiseException then
            incr(countDivisionChecks);
            c_expr.expr &:= "(divChk((";
            process_expr(params[1], c_expr);
            c_expr.expr &:= ")==0)?";
            c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
            c_expr.expr &:= ":0)";
          else
            countDivisionOptimizations(c_expr);
            c_expr.expr &:= "0";
          end if;
        else
          c_expr.expr &:= "0";
        end if;
      elsif check_int_division_overflow then
        # integer.first % -1 causes an integer overflow.
        dividend_range := getIntRange(params[1]);
        c_expr.expr &:= "(";
        dividend_name := getParameterAsVariable("intType", "dividend_", params[1], c_expr);
        divisor_name := getParameterAsVariable("intType", "divisor_", params[3], c_expr);
        if dividend_range.minValue = integer.first and
            divisor_range.minValue <= -1 and divisor_range.maxValue >= -1 then
          incr(countOverflowChecks);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= dividend_name;
          c_expr.expr &:= "==";
          c_expr.expr &:= integerLiteral(integer.first);
          c_expr.expr &:= "&&";
          c_expr.expr &:= divisor_name;
          c_expr.expr &:= "==-1";
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.expr &:= ":";
        else
          countOverflowOptimizations(c_expr);
        end if;
        if check_int_rem_by_zero then
          if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
            incr(countDivisionChecks);
            c_expr.expr &:= "divChk(";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= "==0)?";
            c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
            c_expr.expr &:= ":";
          else
            countDivisionOptimizations(c_expr);
          end if;
        end if;
        c_expr.expr &:= dividend_name;
        c_expr.expr &:= " % ";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= ")";
      else
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
        if check_int_rem_by_zero then
          if divisor_range.minValue <= 0 and divisor_range.maxValue >= 0 then
            incr(countDivisionChecks);
            c_expr.expr &:= "(";
            divisor_name := getParameterAsVariable("intType", "divisor_", params[3], c_expr);
            c_expr.expr &:= "divChk(";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= "==0)?";
            c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
            c_expr.expr &:= ":(";
            process_expr(params[1], c_expr);
            c_expr.expr &:= ") % ";
            c_expr.expr &:= divisor_name;
            c_expr.expr &:= ")";
          else
            countDivisionOptimizations(c_expr);
            c_expr.expr &:= "(";
            process_expr(params[1], c_expr);
            c_expr.expr &:= ") % (";
            process_expr(params[3], c_expr);
            c_expr.expr &:= ")";
          end if;
        else
          c_expr.expr &:= "(";
          process_expr(params[1], c_expr);
          c_expr.expr &:= ") % (";
          process_expr(params[3], c_expr);
          c_expr.expr &:= ")";
        end if;
      end if;
    end if;
  end func;


const proc: process_const_int_rshift (in reference: number, in integer: rshift,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedNumber is NIL;
    var string: number_name is "";
  begin
    if rshift < 0 or rshift >= ccConf.INTTYPE_SIZE then
      incr(countOptimizations);
      warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
    elsif getConstant(number, INTOBJECT, evaluatedNumber) then
      incr(countOptimizations);
      # Right shift does never trigger OVERFLOW_ERROR.
      c_expr.expr &:= integerLiteral(getValue(evaluatedNumber, integer) >> rshift);
    elsif rshift = 0 then
      incr(countOptimizations);
      process_expr(number, c_expr);
    else
      if ccConf.RSHIFT_DOES_SIGN_EXTEND then
        c_expr.expr &:= "(";
        process_expr(number, c_expr);
        c_expr.expr &:= ") >> ";
        c_expr.expr &:= integerLiteral(rshift);
      else
        c_expr.expr &:= "(";
        number_name := getParameterAsVariable("intType", "number_", number, c_expr);
        doRshift(number_name, integerLiteral(rshift), c_expr);
        c_expr.expr &:= ")";
      end if;
    end if;
  end func;


const proc: process (INT_RSHIFT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: number_name is "";
    var string: rshift_name is "";
    var intRange: rshift_range is intRange.value;
    var boolean: doOverflowCheck is FALSE;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_rshift(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif ccConf.RSHIFT_DOES_SIGN_EXTEND then
      if check_int_shift_overflow then
        rshift_range := getIntRange(params[3]);
        if rshift_range.minValue < 0 or
            rshift_range.maxValue >= ccConf.INTTYPE_SIZE then
          incr(countOverflowChecks);
          doOverflowCheck := TRUE;
        else
          countOverflowOptimizations(c_expr);
          c_expr.expr &:= "/*no_overflow_check_rshift*/";
        end if;
      else
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      end if;
      if doOverflowCheck then
        c_expr.expr &:= "(";
        rshift_name := getParameterAsVariable("intType", "rshift_", params[3], c_expr);
        c_expr.expr &:= "ovfChk(";
        checkRangeFromZero(rshift_name, integerLiteral(ccConf.INTTYPE_SIZE), c_expr);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":(";
        process_expr(params[1], c_expr);
        c_expr.expr &:= ") >> ";
        c_expr.expr &:= rshift_name;
        c_expr.expr &:= ")";
      else
        c_expr.expr &:= "(";
        process_expr(params[1], c_expr);
        c_expr.expr &:= ") >> (";
        process_expr(params[3], c_expr);
        c_expr.expr &:= ")";
      end if;
    else
      if check_int_shift_overflow then
        rshift_range := getIntRange(params[3]);
        if rshift_range.minValue < 0 or
            rshift_range.maxValue >= ccConf.INTTYPE_SIZE then
          incr(countOverflowChecks);
          doOverflowCheck := TRUE;
        else
          countOverflowOptimizations(c_expr);
          c_expr.expr &:= "/*no_overflow_check_rshift*/";
        end if;
      else
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      end if;
      if doOverflowCheck then
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        number_name := getParameterAsVariable("intType", "number_", params[1], c_expr);
        rshift_name := getParameterAsVariable("intType", "rshift_", params[3], c_expr);
        c_expr.expr &:= "ovfChk(";
        checkRangeFromZero(rshift_name, integerLiteral(ccConf.INTTYPE_SIZE), c_expr);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":";
        doRshift(number_name, rshift_name, c_expr);
        c_expr.expr &:= ")";
      else
        c_expr.expr &:= "(";
        number_name := getParameterAsVariable("intType", "number_", params[1], c_expr);
        (* Formula used: a<0?~(~a>>b):a>>b *)
        c_expr.expr &:= number_name;
        c_expr.expr &:= "<0?~(~";
        c_expr.expr &:= number_name;
        c_expr.expr &:= " >> (";
        process_expr(params[3], c_expr);
        c_expr.expr &:= ")):";
        c_expr.expr &:= number_name;
        c_expr.expr &:= " >> (";
        process_expr(params[3], c_expr);
        c_expr.expr &:= "))";
      end if;
    end if;
  end func;


const proc: process_const_int_rshift_assign (in reference: variable, in integer: rshift,
    inout expr_type: c_expr) is func

  local
    var string: variable_name is "";
    var expr_type: statement is expr_type.value;
  begin
    if rshift < 0 or rshift >= ccConf.INTTYPE_SIZE then
      incr(countOptimizations);
      setDiagnosticLine(c_expr);
      warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
      c_expr.expr &:= raiseError("OVERFLOW_ERROR");
    elsif rshift = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "/* ignore integer >>:= 0; */\n";
    elsif ccConf.RSHIFT_DOES_SIGN_EXTEND then
      process_expr(variable, statement);
      statement.expr &:= ">>=";
      statement.expr &:= integerLiteral(rshift);
      statement.expr &:= ";\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      variable_name := getParameterAsReference("intType", "variable_", variable, statement);
      (* Formula used: a<0?a=~(~a>>b):a>>=b; *)
      statement.expr &:= variable_name;
      statement.expr &:= "<0?";
      statement.expr &:= variable_name;
      statement.expr &:= "= ~(~";
      statement.expr &:= variable_name;
      statement.expr &:= " >> ";
      statement.expr &:= integerLiteral(rshift);
      statement.expr &:= "):(";
      statement.expr &:= variable_name;
      statement.expr &:= " >>= ";
      statement.expr &:= integerLiteral(rshift);
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (INT_RSHIFT_ASSIGN, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var expr_type: statement is expr_type.value;
    var string: variable_name is "";
    var string: rshift_name is "";
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_rshift_assign(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif ccConf.RSHIFT_DOES_SIGN_EXTEND then
      if check_int_shift_overflow then
        incr(countOverflowChecks);
        rshift_name := getParameterAsVariable("intType", "rshift_", params[3], statement);
        statement.expr &:= "ovfChk(";
        checkRangeFromZero(rshift_name, integerLiteral(ccConf.INTTYPE_SIZE), statement);
        statement.expr &:= ")?";
        statement.expr &:= intRaiseError("OVERFLOW_ERROR");
        statement.expr &:= ":(";
        process_expr(params[1], statement);
        statement.expr &:= ">>=";
        statement.expr &:= rshift_name;
        statement.expr &:= ");\n";
      else
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
        process_expr(params[1], statement);
        statement.expr &:= ">>=";
        process_expr(params[3], statement);
        statement.expr &:= ";\n";
      end if;
      doLocalDeclsOfStatement(statement, c_expr);
    else
      variable_name := getParameterAsReference("intType", "variable_", params[1], statement);
      rshift_name := getParameterAsVariable("intType", "rshift_", params[3], statement);
      if check_int_shift_overflow then
        incr(countOverflowChecks);
        statement.expr &:= "ovfChk(";
        checkRangeFromZero(rshift_name, integerLiteral(ccConf.INTTYPE_SIZE), statement);
        statement.expr &:= ")?";
        statement.expr &:= intRaiseError("OVERFLOW_ERROR");
        statement.expr &:= ":";
      else
        countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      end if;
      (* Formula used: a<0?a=~(~a>>b):a>>=b; *)
      statement.expr &:= variable_name;
      statement.expr &:= "<0? ";
      statement.expr &:= variable_name;
      statement.expr &:= "= ~(~";
      statement.expr &:= variable_name;
      statement.expr &:= " >> ";
      statement.expr &:= rshift_name;
      statement.expr &:= "):(";
      statement.expr &:= variable_name;
      statement.expr &:= " >>= ";
      statement.expr &:= rshift_name;
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (INT_SBTR, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: minuend_name is "";
    var string: subtrahend_name is "";
  begin
    if callOptimizeIntAdd then
      optimize_int_add(params, FALSE, c_expr);
    elsif getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_sbtr(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
      process_const_int_sbtr(getValue(evaluatedParam, integer), params[3], c_expr);
    else
      process_int_sbtr(params[1], params[3], c_expr);
    end if;
  end func;


const proc: process_const_int_sbtr_assign (in reference: variable, in integer: delta,
    inout expr_type: c_expr) is func

  local
    var string: variable_name is "";
    var expr_type: statement is expr_type.value;
  begin
    if delta = 0 then
      incr(countOptimizations);
      c_expr.expr &:= "/* ignore integer -:= 0; */\n";
    elsif check_int_arithmetic_overflow then
      incr(countOptimizations);
      incr(countOverflowChecks);
      variable_name := getParameterAsReference("intType", "variable_", variable, statement);
      statement.expr &:= "if (ovfChk(";
      statement.expr &:= variable_name;
      if delta = -1 then
        statement.expr &:= "==";
        statement.expr &:= integerLiteral(integer.last);
      elsif delta = 1 then
        statement.expr &:= "==";
        statement.expr &:= integerLiteral(integer.first);
      elsif delta < 0 then
        statement.expr &:= ">";
        statement.expr &:= integerLiteral(integer.last + delta);
      else
        statement.expr &:= "<";
        statement.expr &:= integerLiteral(integer.first + delta);
      end if;
      statement.expr &:= ")) {\n";
      statement.expr &:= raiseError("OVERFLOW_ERROR");
      statement.expr &:= "} else {\n";
      statement.expr &:= variable_name;
      statement.expr &:= "-=";
      statement.expr &:= integerLiteral(delta);
      statement.expr &:= ";\n";
      statement.expr &:= "}\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      process_expr(variable, statement);
      statement.expr &:= "-=";
      statement.expr &:= integerLiteral(delta);
      statement.expr &:= ";\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (INT_SBTR_ASSIGN, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: variable_name is "";
    var string: delta_name is "";
    var intRange: deltaRange is intRange.value;
    var expr_type: statement is expr_type.value;
  begin
    if getConstant(params[3], INTOBJECT, evaluatedParam) then
      process_const_int_sbtr_assign(params[1], getValue(evaluatedParam, integer), c_expr);
    elsif check_int_arithmetic_overflow then
      incr(countOverflowChecks);
      deltaRange := getIntRange(params[3]);
      if deltaRange.minValue = 0 and deltaRange.maxValue = 0 then
        c_expr.expr &:= "/* ignore integer -:= 0; */\n";
      else
        variable_name := getParameterAsReference("intType", "variable_", params[1], statement);
        if ccConf.BUILTIN_SUB_OVERFLOW <> "" then
          statement.expr &:= "ovfChk(";
          statement.expr &:= ccConf.BUILTIN_SUB_OVERFLOW;
          statement.expr &:= "(";
          statement.expr &:= variable_name;
          statement.expr &:= ", ";
          process_expr(params[3], statement);
          statement.expr &:= ", &(";
          statement.expr &:= variable_name;
          statement.expr &:= ")))?";
          statement.expr &:= intRaiseError("OVERFLOW_ERROR");
          statement.expr &:= ":0;\n";
        else
          delta_name := getParameterAsVariable("intType", "delta_", params[3], statement);
          if deltaRange.minValue < 0 or deltaRange.maxValue > 0 then
            statement.expr &:= "ovfChk(";
            if deltaRange.minValue < 0 and deltaRange.maxValue > 0 then
              statement.expr &:= delta_name;
              statement.expr &:= "<0&&";
              statement.expr &:= variable_name;
              statement.expr &:= ">";
              statement.expr &:= integerLiteral(integer.last);
              statement.expr &:= "+";
              statement.expr &:= delta_name;
              statement.expr &:= " || ";
              statement.expr &:= delta_name;
              # The comparison >= 0 supports optimizations by the C compiler.
              statement.expr &:= ">=0&&";
              statement.expr &:= variable_name;
              statement.expr &:= "<";
              statement.expr &:= integerLiteral(integer.first);
              statement.expr &:= "+";
              statement.expr &:= delta_name;
            elsif deltaRange.minValue < 0 then
              statement.expr &:= variable_name;
              statement.expr &:= ">";
              statement.expr &:= integerLiteral(integer.last);
              statement.expr &:= "+";
              statement.expr &:= delta_name;
            else # deltaRange.maxValue > 0
              statement.expr &:= variable_name;
              statement.expr &:= "<";
              statement.expr &:= integerLiteral(integer.first);
              statement.expr &:= "+";
              statement.expr &:= delta_name;
            end if;
            statement.expr &:= ")?";
            statement.expr &:= intRaiseError("OVERFLOW_ERROR");
            statement.expr &:= ":";
          end if;
          statement.expr &:= "(";
          statement.expr &:= variable_name;
          statement.expr &:= "-=";
          statement.expr &:= delta_name;
          statement.expr &:= ");\n";
        end if;
        doLocalDeclsOfStatement(statement, c_expr);
      end if;
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      process_expr(params[1], statement);
      statement.expr &:= "-=";
      process_expr(params[3], statement);
      statement.expr &:= ";\n";
      doLocalDeclsOfStatement(statement, c_expr);
    end if;
  end func;


const proc: process (INT_SQRT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intSqrt(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: process (INT_STR, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    process_int_str(params[1], c_expr);
  end func;


const proc: process (INT_SUCC, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: number_name is "";
    var integer: number is 0;
  begin
    if callOptimizeIntAdd then
      optimize_int_add(params[1], 1, c_expr);
    elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      number := getValue(evaluatedParam, integer);
      if number = integer.last then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      else
        c_expr.expr &:= integerLiteral(succ(number));
      end if;
    elsif check_int_arithmetic_overflow then
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      number_name := getParameterAsVariable("intType", "number_", params[1], c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= number_name;
      c_expr.expr &:= "==";
      c_expr.expr &:= integerLiteral(integer.last);
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= number_name;
      c_expr.expr &:= "+1)";
    else
      countSuppressedOverflowChecks +:= ord(not integer_overflow_check);
      c_expr.expr &:= "(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ")+1";
    end if;
  end func;


const proc: process (INT_VALUE, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intValue(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ")";
  end func;