
(********************************************************************)
(*                                                                  *)
(*  int_act.s7i   Generate code for actions of the type integer.    *)
(*  Copyright (C) 1990 - 1994, 2004 - 2017  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_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, "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: 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 string: summand1_name, in integer: summand2,
    inout expr_type: c_expr) is func

  local
    var string: sum is "";
  begin
    if summand2 <> -1 and ccConf.BUILTIN_ADD_OVERFLOW <> "" then
      sum := defineTempVariable("intType", "sum_", c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= ccConf.BUILTIN_ADD_OVERFLOW;
      c_expr.expr &:= "(";
      c_expr.expr &:= summand1_name;
      c_expr.expr &:= ", ";
      c_expr.expr &:= integerLiteral(summand2);
      c_expr.expr &:= ", &";
      c_expr.expr &:= sum;
      c_expr.expr &:= "))?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= sum;
    else
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= summand1_name;
      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 &:= summand1_name;
      c_expr.expr &:= " + ";
      c_expr.expr &:= integerLiteral(summand2);
    end if;
  end func;


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

  local
    var string: difference is "";
  begin
    if subtrahend <> 1 and ccConf.BUILTIN_SUB_OVERFLOW <> "" then
      difference := defineTempVariable("intType", "diff_", c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= ccConf.BUILTIN_SUB_OVERFLOW;
      c_expr.expr &:= "(";
      c_expr.expr &:= minuend_name;
      c_expr.expr &:= ", ";
      c_expr.expr &:= integerLiteral(subtrahend);
      c_expr.expr &:= ", &";
      c_expr.expr &:= difference;
      c_expr.expr &:= "))?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= difference;
    else
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= minuend_name;
      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 &:= minuend_name;
      c_expr.expr &:= " - ";
      c_expr.expr &:= integerLiteral(subtrahend);
    end if;
  end func;


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

  local
    var string: difference is "";
  begin
    if ccConf.BUILTIN_SUB_OVERFLOW <> "" then
      difference := defineTempVariable("intType", "diff_", 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 &:= subtrahend_name;
      c_expr.expr &:= ", &";
      c_expr.expr &:= difference;
      c_expr.expr &:= "))?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= difference;
    else
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= subtrahend_name;
      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 &:= subtrahend_name;
    end if;
  end func;


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

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


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

  local
    var string: subtrahend_name is "";
    var string: difference is "";
  begin
    if ccConf.BUILTIN_SUB_OVERFLOW <> "" then
      difference := defineTempVariable("intType", "diff_", c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= ccConf.BUILTIN_SUB_OVERFLOW;
      c_expr.expr &:= "(";
      c_expr.expr &:= minuend_name;
      c_expr.expr &:= ", ";
      process_expr(subtrahend, c_expr);
      c_expr.expr &:= ", &";
      c_expr.expr &:= difference;
      c_expr.expr &:= "))?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= difference;
    else
      subtrahend_name := getParameterAsVariable("intType", "tmp_", subtrahend, c_expr);
      difference := defineTempVariable("intType", "diff_", c_expr);
      c_expr.expr &:= difference;
      c_expr.expr &:= "=(intType)((uintType)";
      c_expr.expr &:= minuend_name;
      c_expr.expr &:= "-(uintType)";
      c_expr.expr &:= subtrahend_name;
      c_expr.expr &:= "), ";
      (* Formula used: ovfChk((intType)((m^s)&(d^m))<0) *)
      c_expr.expr &:= "ovfChk((intType)((";
      c_expr.expr &:= minuend_name;
      c_expr.expr &:= "^";
      c_expr.expr &:= subtrahend_name;
      c_expr.expr &:= ")&(";
      c_expr.expr &:= difference;
      c_expr.expr &:= "^";
      c_expr.expr &:= minuend_name;
      c_expr.expr &:= "))<0)?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= difference;
    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 string: factor1_name is "";
    var string: factor2_name is "";
    var string: product_name is "";
  begin
    if FALSE and ccConf.BUILTIN_MULT_OVERFLOW <> "" then
      product_name := defineTempVariable("intType", "prod_", 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_name := getParameterAsVariable("intType", "tmp_", factor1, c_expr);
      factor2_name := getParameterAsVariable("intType", "tmp_", factor2, c_expr);
      c_expr.expr &:= factor1_name;
      c_expr.expr &:= "<0&&(";
      c_expr.expr &:= factor2_name;
      c_expr.expr &:= "<0&&";
      c_expr.expr &:= factor1_name;
      c_expr.expr &:= "<";
      c_expr.expr &:= integerLiteral(integer.last);
      c_expr.expr &:= "/";
      c_expr.expr &:= factor2_name;
      c_expr.expr &:= "||";
      c_expr.expr &:= factor2_name;
      c_expr.expr &:= ">0&&";
      c_expr.expr &:= factor1_name;
      c_expr.expr &:= "<";
      c_expr.expr &:= integerLiteral(integer.first);
      c_expr.expr &:= "/";
      c_expr.expr &:= factor2_name;
      c_expr.expr &:= ")||";
      c_expr.expr &:= factor1_name;
      c_expr.expr &:= ">0&&(";
      c_expr.expr &:= factor2_name;
      c_expr.expr &:= "<0&&";
      c_expr.expr &:= factor2_name;
      c_expr.expr &:= "<";
      c_expr.expr &:= integerLiteral(integer.first);
      c_expr.expr &:= "/";
      c_expr.expr &:= factor1_name;
      c_expr.expr &:= "||";
      c_expr.expr &:= factor2_name;
      c_expr.expr &:= ">0&&";
      c_expr.expr &:= factor2_name;
      c_expr.expr &:= ">";
      c_expr.expr &:= integerLiteral(integer.last);
      c_expr.expr &:= "/";
      c_expr.expr &:= factor1_name;
      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 reference: aParam is NIL;
    var intRange: number_range is intRange.value;
    var string: number_name is "";
  begin
    if isActionExpression(number, "INT_NEGATE") then
      # Negate a negated value. No overflow check necessary.
      aParam := getActionParameter(number, 2);
      process_expr(aParam, 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
        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", "tmp_", 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
      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 string: summand1_name is "";
  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
        c_expr.expr &:= "/*no_overflow_check_add*/(";
        process_expr(summand1, c_expr);
        c_expr.expr &:= ") + ";
        c_expr.expr &:= integerLiteral(summand2);
      else
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        summand1_name := getParameterAsVariable("intType", "tmp_", summand1, c_expr);
        const_int_add_with_overflow_check(summand1_name, summand2, c_expr);
        c_expr.expr &:= ")";
      end if;
    else
      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 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
          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", "tmp_", summand1, c_expr);
          summand2_name := getParameterAsVariable("intType", "tmp_", 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);
        c_expr.expr &:= "(";
        if summand1 = summand2 then
          incr(countOptimizations);
          summand1_name := getParameterAsVariable("intType", "tmp_", 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;
        else
          summand1_name := getParameterAsVariable("intType", "tmp_", summand1, c_expr);
          int_add_with_overflow_check(summand1_name, summand2, c_expr);
        end if;
        c_expr.expr &:= ")";
      end if;
    else
      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 string: minuend_name is "";
  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
        c_expr.expr &:= "/*no_overflow_check_sbtr*/(";
        process_expr(minuend, c_expr);
        c_expr.expr &:= ") - ";
        c_expr.expr &:= integerLiteral(subtrahend);
      else
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        minuend_name := getParameterAsVariable("intType", "tmp_", minuend, c_expr);
        const_int_sbtr_with_overflow_check(minuend_name, subtrahend, c_expr);
        c_expr.expr &:= ")";
      end if;
    else
      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 reference: evaluatedParam is NIL;
    var intRange: subtrahend_range is intRange.value;
    var string: subtrahend_name is "";
  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
        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);
        c_expr.expr &:= "(";
        subtrahend_name := getParameterAsVariable("intType", "tmp_", subtrahend, c_expr);
        const_int_sbtr_with_overflow_check(minuend, subtrahend_name, c_expr);
        c_expr.expr &:= ")";
      end if;
    else
      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 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
          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", "tmp_", minuend, c_expr);
          subtrahend_name := getParameterAsVariable("intType", "tmp_", 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);
        c_expr.expr &:= "(";
        minuend_name := getParameterAsVariable("intType", "tmp_", minuend, c_expr);
        int_sbtr_with_overflow_check(minuend_name, subtrahend, c_expr);
        c_expr.expr &:= ")";
      end if;
    else
      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 expr_type: c_expr) is func
  begin
    if summand.summand = NIL then
      if summand.doAdd then
        c_expr.expr &:= integerLiteral(summand.constSummand);
      else
        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
        process_expr(summand.summand, c_expr);
      else
        negate(summand.summand, c_expr);
      end if;
    end if;
  end func;


const proc: optimize_int_add (in addSubIntElementType: summand1,
    in addSubIntElementType: summand2, inout expr_type: c_expr) is func
  local
    var integer: summand1_value is 0;
    var integer: summand2_value is 0;
  begin
    if not summand1.doAdd then
      writeln(" ***** Problem in optimize_int_add (2)");
    elsif summand2.doAdd then
      if summand1.summand = NIL then
        if summand2.summand = NIL then
          summand1_value := summand1.constSummand;
          summand2_value := summand2.constSummand;
          if  (summand2_value > 0 and summand1_value > integer.last - summand2_value) or
              (summand2_value < 0 and summand1_value < integer.first - summand2_value) then
            warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
            c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          else
            c_expr.expr &:= integerLiteral(summand1_value + summand2_value);
          end if;
        else
          process_const_int_add(summand2.summand, summand1.constSummand, c_expr);
        end if;
      elsif summand2.summand = NIL then
        process_const_int_add(summand1.summand, summand2.constSummand, c_expr);
      else
        process_int_add(summand1.summand, summand2.summand, c_expr);
      end if;
    else
      if summand1.summand = NIL then
        if summand2.summand = NIL then
          summand1_value := summand1.constSummand;
          summand2_value := summand2.constSummand;
          if  (summand2_value < 0 and summand1_value > integer.last + summand2_value) or
              (summand2_value > 0 and summand1_value < integer.first + summand2_value) then
            warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
            c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          else
            c_expr.expr &:= integerLiteral(summand1_value - summand2_value);
          end if;
        else
          process_const_int_sbtr(summand1.constSummand, summand2.summand, c_expr);
        end if;
      elsif summand2.summand = NIL then
        process_const_int_sbtr(summand1.summand, summand2.constSummand, c_expr);
      else
        process_int_sbtr(summand1.summand, summand2.summand, c_expr);
      end if;
    end if;
  end func;


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

  local
    var reference: summand2Ref is NIL;
    var integer: summand2 is 0;
    var string: summand1_name is "";
    var string: summand2_name is "";
    var boolean: doAdd is FALSE;
    var integer: index is 1;
  begin
    if length(addSubParamList) >= 3 then
      incr(countOptimizations);
      if check_int_arithmetic_overflow then
        incr(countOverflowChecks);
        summand1_name := defineTempVariable("intType", "tmp_", c_expr);
        c_expr.expr &:= "(";
        c_expr.expr &:= summand1_name;
        c_expr.expr &:= "=";
        optimize_int_add(addSubParamList[.. pred(length(addSubParamList))], c_expr);
        c_expr.expr &:= ",";
        doAdd := addSubParamList[length(addSubParamList)].doAdd;
        summand2Ref := addSubParamList[length(addSubParamList)].summand;
        if summand2Ref = NIL then
          summand2 := addSubParamList[length(addSubParamList)].constSummand;
          if summand2 = 0 then
            # This should never happen because 0 should have been optimized out.
            writeln(" ***** Problem in optimize_int_add (1)");
            c_expr.expr &:= summand1_name;
          else
            if doAdd then
              const_int_add_with_overflow_check(summand1_name, summand2, c_expr);
            else
              const_int_sbtr_with_overflow_check(summand1_name, summand2, c_expr);
            end if;
          end if;
        else
          if doAdd then
            int_add_with_overflow_check(summand1_name, summand2Ref, c_expr);
          else
            int_sbtr_with_overflow_check(summand1_name, summand2Ref, c_expr);
          end if;
        end if;
        c_expr.expr &:= ")";
      else
        c_expr.expr &:= "(";
        optimize_int_add(addSubParamList[.. pred(length(addSubParamList))], 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) = 2 then
      incr(countOptimizations);
      optimize_int_add(addSubParamList[1], addSubParamList[2], c_expr);
    elsif length(addSubParamList) = 1 then
      incr(countOptimizations);
      optimize_int_add(addSubParamList[1], c_expr);
    else
      incr(countOptimizations);
      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;
  begin
    addSubParamList := getAddSubParamList(params, doAdd);
    evaluateConstants(addSubParamList);
    computeConstants(addSubParamList);
    optimize_int_add(addSubParamList, 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;
  begin
    addSubParamList := getAddSubParamList(summand1, summand2);
    evaluateConstants(addSubParamList);
    computeConstants(addSubParamList);
    optimize_int_add(addSubParamList, 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", "tmp_", params[1], c_expr);
          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;
          c_expr.expr &:= ")";
        else
          (* There is a signal for integer overflow. *)
          c_expr.expr &:= "(";
          number_name := getParameterAsVariable("intType", "tmp_", 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;
      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", "tmp_", 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", "tmp_", 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 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 evaluate_const_expr >= 1 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", "tmp_", variable, statement);
      statement.expr &:= "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 &:= ")?";
      statement.expr &:= intRaiseError("OVERFLOW_ERROR");
      statement.expr &:= ":(";
      statement.expr &:= variable_name;
      statement.expr &:= "+=";
      statement.expr &:= integerLiteral(delta);
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      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 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
      incr(countOverflowChecks);
      variable_name := getParameterAsReference("intType", "tmp_", params[1], statement);
      delta_name := getParameterAsVariable("intType", "tmp_", params[3], statement);
      statement.expr &:= "ovfChk(";
      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;
      statement.expr &:= ">=0&&";
      statement.expr &:= variable_name;
      statement.expr &:= ">";
      statement.expr &:= integerLiteral(integer.last);
      statement.expr &:= "-";
      statement.expr &:= delta_name;
      statement.expr &:= ")?";
      statement.expr &:= intRaiseError("OVERFLOW_ERROR");
      statement.expr &:= ":(";
      statement.expr &:= variable_name;
      statement.expr &:= "+=";
      statement.expr &:= delta_name;
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      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", "tmp_", 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", "tmp_", 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_be_2_uint (in reference: stri, in integer: length,
    inout expr_type: c_expr) is func

  local
    var string: stri_name is "";
    var integer: index is 0;
  begin
    if length = 0 then
      c_expr.expr &:= "0";
    elsif length >= 1 and length <= 8 then
      incr(countOptimizations);
      c_expr.expr &:= "(";
      stri_name := getParameterAsVariable("const_striType", "tmp_", stri, c_expr);
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->size==";
      c_expr.expr &:= integerLiteral(length);
      c_expr.expr &:= "?(";
      for index range 1 to length do
        if index <> 1 then
          c_expr.expr &:= "|";
        end if;
        if function_range_check then
          c_expr.expr &:= "(ovfChk(";
          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
          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;
      c_expr.expr &:= "):intBytesBe2UInt(";
      c_expr.expr &:= stri_name;
      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 integer: length is 0;
  begin
    if inlineFunctions and
        isActionExpression(params[1], "STR_SUBSTR") and
        category(getValue(params[1], ref_list)[6]) = INTOBJECT and
        not isVar(getValue(params[1], ref_list)[6]) then
      optimize_int_bytes_be_2_uint(params[1],
          getValue(getValue(params[1], ref_list)[6], integer), 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 reference: stri, in integer: length,
    inout expr_type: c_expr) is func

  local
    var string: stri_name is "";
    var integer: index is 0;
  begin
    if length = 0 then
      c_expr.expr &:= "0";
    elsif length >= 1 and length <= 8 then
      incr(countOptimizations);
      c_expr.expr &:= "(";
      stri_name := getParameterAsVariable("const_striType", "tmp_", stri, c_expr);
      c_expr.expr &:= stri_name;
      c_expr.expr &:= "->size==";
      c_expr.expr &:= integerLiteral(length);
      c_expr.expr &:= "?(";
      for index range 1 to length do
        if index <> 1 then
          c_expr.expr &:= "|";
        end if;
        if function_range_check then
          c_expr.expr &:= "(ovfChk(";
          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
          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;
      c_expr.expr &:= "):intBytesLe2UInt(";
      c_expr.expr &:= stri_name;
      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 integer: length is 0;
  begin
    if inlineFunctions and
        isActionExpression(params[1], "STR_SUBSTR") and
        category(getValue(params[1], ref_list)[6]) = INTOBJECT and
        not isVar(getValue(params[1], ref_list)[6]) then
      optimize_int_bytes_le_2_uint(params[1],
          getValue(getValue(params[1], ref_list)[6], integer), 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
      c_expr.expr &:= "(";
      number1_name := getParameterAsVariable("intType", "num1_", params[1], c_expr);
      number2_name := getParameterAsVariable("intType", "num2_", 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
      statement.expr &:= "--(";
      process_expr(params[1], statement);
      statement.expr &:= ");\n";
    end if;
    doLocalDeclsOfStatement(statement, c_expr);
  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 integer: dividend_value is 0;
    var string: dividend_name is "";
  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 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);
    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_div (in integer: dividend, in reference: divisor,
    inout expr_type: c_expr) is func

  local
    var string: divisor_name is "";
  begin
    if dividend = 0 then
      incr(countOptimizations);
      if integer_division_check then
        c_expr.expr &:= "(divChk((";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":0)";
      else
        c_expr.expr &:= "0";
      end if;
    elsif check_int_division_overflow and dividend = integer.first then
      # integer.first / -1 causes an integer overflow.
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "tmp_b_", divisor, c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= "==-1";
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      if check_int_div_by_zero then
        c_expr.expr &:= "divChk(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
      end if;
      c_expr.expr &:= integerLiteral(dividend);
      c_expr.expr &:= " / ";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= ")";
    elsif check_int_div_by_zero then
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "tmp_b_", 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
      c_expr.expr &:= integerLiteral(dividend);
      c_expr.expr &:= " / (";
      process_expr(divisor, c_expr);
      c_expr.expr &:= ")";
    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 "";
  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
      c_expr.expr &:= "(divChk((";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    elsif 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
        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
        c_expr.expr &:= "1";
      end if;
    elsif check_int_division_overflow then
      # integer.first / -1 causes an integer overflow.
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      dividend_name := getParameterAsVariable("intType", "tmp_b_", params[1], c_expr);
      divisor_name := getParameterAsVariable("intType", "tmp_b_", params[3], 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 &:= divisor_name;
      c_expr.expr &:= "==-1";
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      if check_int_div_by_zero then
        c_expr.expr &:= "divChk(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
      end if;
      c_expr.expr &:= dividend_name;
      c_expr.expr &:= " / ";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= ")";
    elsif check_int_div_by_zero then
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "tmp_b_", 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
      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_EQ, 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 &:= ") == (";
    process_expr(params[3], c_expr);
    c_expr.expr &:= ")";
  end func;


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

  local
    var string: number_name is "";
  begin
    c_expr.expr &:= "(";
    number_name := getParameterAsVariable("intType", "tmp_", 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 func;


const proc: process (INT_GE, 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 &:= ") >= (";
    process_expr(params[3], c_expr);
    c_expr.expr &:= ")";
  end func;


const proc: process (INT_GT, 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 &:= ") > (";
    process_expr(params[3], c_expr);
    c_expr.expr &:= ")";
  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
      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

  begin
    c_expr.expr &:= "(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ") <= (";
    process_expr(params[3], c_expr);
    c_expr.expr &:= ")";
  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
          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", "tmp_", 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", "tmp_", 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
      c_expr.expr &:= "(";
      process_expr(number, c_expr);
      c_expr.expr &:= ") << ";
      c_expr.expr &:= integerLiteral(lshift);
    end if;
  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 "";
  begin
    if check_int_shift_overflow then
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      lshift_name := getParameterAsVariable("intType", "tmp_", lshift, c_expr);
      c_expr.expr &:= "ovfChk(";
      checkRangeFromZero(lshift_name,
          integerLiteral(bitLength(integer.last) - bitLength(number) + 1), 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 &:= ")";
    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 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 "";
  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
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      number_name := getParameterAsVariable("intType", "tmp_", params[1], c_expr);
      lshift_name := getParameterAsVariable("intType", "lshift_", params[3], c_expr);
      c_expr.expr &:= "ovfChk(";
      checkRangeFromZero(lshift_name, integerLiteral(ccConf.INTTYPE_SIZE), c_expr);
      c_expr.expr &:= "||";
      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 &:= ")";
    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 func;


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

  local
    var reference: evaluatedNumber is NIL;
    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");
      c_expr.expr &:= "\n";
    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", "tmp_", variable, statement);
      statement.expr &:= "ovfChk(";
      checkIfOutsideRange(variable_name, integer.first >> lshift,
                          integer.last >> lshift, statement);
      statement.expr &:= ")?";
      statement.expr &:= intRaiseError("OVERFLOW_ERROR");
      statement.expr &:= ":(";
      statement.expr &:= variable_name;
      statement.expr &:= "<<=";
      statement.expr &:= integerLiteral(lshift);
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      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", "tmp_", params[1], statement);
      lshift_name := getParameterAsVariable("intType", "tmp_", 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
      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

  begin
    c_expr.expr &:= "(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ") < (";
    process_expr(params[3], c_expr);
    c_expr.expr &:= ")";
  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 integer: dividend_value is 0;
    var string: dividend_name is "";
  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 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", "tmp_a_", 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.
      if ccConf.TWOS_COMPLEMENT_INTTYPE then
        c_expr.expr &:= "(";
        dividend_name := getParameterAsVariable("intType", "tmp_a_", dividend, c_expr);
        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 &:= ":";
        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", "tmp_a_", 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
      c_expr.expr &:= "(";
      dividend_name := getParameterAsVariable("intType", "tmp_a_", 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:(intType)((uintType)";
        c_expr.expr &:= dividend_name;
        c_expr.expr &:= "/";
        c_expr.expr &:= integerLiteral(divisor);
        c_expr.expr &:= "))";
      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:";
        c_expr.expr &:= dividend_name;
        c_expr.expr &:= "/";
        c_expr.expr &:= integerLiteral(divisor);
        c_expr.expr &:= ")";
      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 "";
  begin
    incr(countOptimizations);
    if dividend = 0 then
      if integer_division_check then
        c_expr.expr &:= "(divChk((";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":0)";
      else
        c_expr.expr &:= "0";
      end if;
    elsif check_int_division_overflow and dividend = integer.first then
      incr(countOverflowChecks);
      (* Formula used: b==-1?OVERFLOW_ERROR:b>0?(a+1)/b-1:a/b *)
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "tmp_b_", divisor, c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= "==-1)?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      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:";
      if check_int_div_by_zero then
        c_expr.expr &:= "divChk(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
      end if;
      c_expr.expr &:= integerLiteral(dividend);
      c_expr.expr &:= "/";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "tmp_b_", divisor, c_expr);
      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:";
      if check_int_div_by_zero then
        c_expr.expr &:= "divChk(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
      end if;
      c_expr.expr &:= integerLiteral(dividend);
      c_expr.expr &:= "/";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= ")";
    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 "";
  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
      c_expr.expr &:= "(divChk((";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    elsif 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
        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
        c_expr.expr &:= "1";
      end if;
    else
      c_expr.expr &:= "(";
      dividend_name := getParameterAsVariable("intType", "tmp_a_", params[1], c_expr);
      divisor_name := getParameterAsVariable("intType", "tmp_b_", params[3], c_expr);
      (* Formula used: a>0&&b<0?(a-1)/b-1:a<0&&b>0?(a+1)/b-1:a/b *)
      c_expr.expr &:= dividend_name;
      c_expr.expr &:= ">0&&";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= "<0?(";
      c_expr.expr &:= dividend_name;
      c_expr.expr &:= "-1)/";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= "-1:";
      c_expr.expr &:= dividend_name;
      c_expr.expr &:= "<0&&";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= ">0?(";
      c_expr.expr &:= dividend_name;
      c_expr.expr &:= "+1)/";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= "-1:";
      if check_int_div_by_zero then
        c_expr.expr &:= "divChk(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
      end if;
      if check_int_division_overflow 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 &:= ":";
      end if;
      c_expr.expr &:= dividend_name;
      c_expr.expr &:= "/";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= ")";
    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 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 "";
  begin
    if getConstant(lshift, INTOBJECT, evaluatedParam) then
      lshift_value := getValue(evaluatedParam, integer);
      if lshift_value < 0 then
        warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      elsif lshift_value >= pred(ccConf.INTTYPE_SIZE) then
        c_expr.expr &:= "(uintType)0";
      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
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      lshift_name := getParameterAsVariable("intType", "tmp_", 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 &:= "))";
    else
      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;
    var integer: lshift is 0;
  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);
    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 >= pred(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))";
    elsif 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 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 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
          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
        c_expr.expr &:= "0";
      elsif reduceOverflowChecks then
        c_expr.expr &:= "/*no_overflow_check_mod*/ 0";
      else
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        dividend_name := getParameterAsVariable("intType", "tmp_", 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
            category(getValue(dividend, ref_list)[4]) = INTOBJECT and
            not isVar(getValue(dividend, ref_list)[4]) then
          optimize_mod_of_left_shifted_value(getValue(dividend, ref_list)[2],
              getValue(getValue(dividend, ref_list)[4], 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", "tmp_a_", dividend, c_expr);
      remainder_name := defineTempVariable("intType", "tmp_c_", 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 string: remainder_name is "";
  begin
    incr(countOptimizations);
    if dividend = 0 then
      if integer_division_check then
        c_expr.expr &:= "(divChk((";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":0)";
      else
        c_expr.expr &:= "0";
      end if;
    elsif dividend = 1 then
      if integer_division_check then
        c_expr.expr &:= "(";
        divisor_name := getParameterAsVariable("intType", "tmp_b_", divisor, c_expr);
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "<=0?(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):(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==1?0:1))";
      else
        c_expr.expr &:= "(";
        divisor_name := getParameterAsVariable("intType", "tmp_b_", divisor, c_expr);
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "<=0?";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "+1:(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==1?0:1))";
      end if;
    else
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "tmp_b_", divisor, c_expr);
      remainder_name := defineTempVariable("intType", "tmp_c_", c_expr);
      if check_int_division_overflow and dividend = integer.first then
        incr(countOverflowChecks);
        c_expr.expr &:= "ovfChk(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==-1";
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":";
      end if;
      if check_int_rem_by_zero then
        c_expr.expr &:= "divChk(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
      end if;
      c_expr.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 &:= ",";
      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 &:= "&&";
      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;
  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 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
      c_expr.expr &:= "(divChk((";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    elsif 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
        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
        c_expr.expr &:= "0";
      end if;
    else
      c_expr.expr &:= "(";
      dividend_name := getParameterAsVariable("intType", "tmp_a_", params[1], c_expr);
      divisor_name := getParameterAsVariable("intType", "tmp_b_", params[3], c_expr);
      remainder_name := defineTempVariable("intType", "tmp_c_", c_expr);
      if check_int_division_overflow 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 &:= ":";
      end if;
      if check_int_rem_by_zero then
        c_expr.expr &:= "divChk(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
      end if;
      c_expr.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 &:= ",";
      c_expr.expr &:= dividend_name;
      c_expr.expr &:= "<0^";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= "<0&&";
      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;
  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 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
          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", "tmp_", 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);
        c_expr.expr &:= "(";
        factor1_name := getParameterAsVariable("intType", "tmp_", 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;
    else
      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;
  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);
    elsif check_int_arithmetic_overflow 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 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", "tmp_", variable, statement);
        statement.expr &:= "ovfChk(";
        statement.expr &:= variable_name;
        statement.expr &:= "==";
        statement.expr &:= integerLiteral(integer.first);
        statement.expr &:= ")?";
        statement.expr &:= intRaiseError("OVERFLOW_ERROR");
        statement.expr &:= ":(";
        statement.expr &:= variable_name;
        statement.expr &:= "*= -1);\n";
      else
        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", "tmp_", variable, statement);
      statement.expr &:= "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 &:= ")?";
      statement.expr &:= intRaiseError("OVERFLOW_ERROR");
      statement.expr &:= ":(";
      statement.expr &:= variable_name;
      statement.expr &:= " *= ";
      statement.expr &:= integerLiteral(factor);
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      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);
      if ccConf.INTTYPE_SIZE = 64 and ccConf.INT128TYPE <> "" or
          ccConf.INTTYPE_SIZE = 32 then
        variable_name := getParameterAsReference("intType", "tmp_", params[1], statement);
        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
        variable_name := getParameterAsReference("intType", "tmp_", params[1], statement);
        factor_name := getParameterAsVariable("intType", "tmp_", 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
      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

  begin
    c_expr.expr &:= "(";
    process_expr(params[1], c_expr);
    c_expr.expr &:= ") != (";
    process_expr(params[3], c_expr);
    c_expr.expr &:= ")";
  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_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 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", "tmp_", base, c_expr);
      if check_int_arithmetic_overflow 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 &:= ":";
      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);
      incr(countOverflowChecks);
      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", "tmp_", base, c_expr);
      c_expr.expr &:= "ovfChk(";
      checkIfOutsideRange(baseName, minBase, maxBase, c_expr);
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      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 string: exponent_name is "";
    var integer: log2_of_negated_base is 0;
    var integer: max_exponent is 0;
  begin
    if base = -1 then
      incr(countOptimizations);
      if integer_power_check then
        c_expr.expr &:= "(";
        exponent_name := getParameterAsVariable("intType", "tmp_", exponent, c_expr);
        c_expr.expr &:= "numChk(";
        c_expr.expr &:= exponent_name;
        c_expr.expr &:= "<0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":1-((";
        c_expr.expr &:= exponent_name;
        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 then
        c_expr.expr &:= "(";
        exponent_name := getParameterAsVariable("intType", "tmp_", exponent, c_expr);
        c_expr.expr &:= "numChk(";
        c_expr.expr &:= exponent_name;
        c_expr.expr &:= "<0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":(";
        c_expr.expr &:= exponent_name;
        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 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);
      if integer_power_check or integer_overflow_check then
        c_expr.expr &:= "(";
        exponent_name := getParameterAsVariable("intType", "tmp_", exponent, c_expr);
        if integer_power_check then
          c_expr.expr &:= "numChk(";
          c_expr.expr &:= exponent_name;
          c_expr.expr &:= "<0)?";
          c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
          c_expr.expr &:= ":";
        end if;
        if integer_overflow_check then
          incr(countOverflowChecks);
          c_expr.expr &:= "ovfChk(";
          c_expr.expr &:= exponent_name;
          c_expr.expr &:= ">";
          c_expr.expr &:= integerLiteral(log2(integer.last) div log2(base));
          c_expr.expr &:= ")?";
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          c_expr.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 &:= exponent_name;
        c_expr.expr &:= ")";
      else
        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.
      log2_of_negated_base := ord(log2(-bigInteger(base)));
      c_expr.expr &:= "(";
      exponent_name := getParameterAsVariable("intType", "tmp_", exponent, c_expr);
      if integer_power_check then
        c_expr.expr &:= "numChk(";
        c_expr.expr &:= exponent_name;
        c_expr.expr &:= "<0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
      end if;
      if integer_overflow_check then
        incr(countOverflowChecks);
        c_expr.expr &:= "ovfChk(";
        c_expr.expr &:= exponent_name;
        c_expr.expr &:= ">";
        max_exponent := ord(log2(-bigInteger(integer.first))) div log2_of_negated_base;
        if not odd(max_exponent) then
          max_exponent := log2(integer.last) div log2_of_negated_base;
        end if;
        c_expr.expr &:= integerLiteral(max_exponent);
        c_expr.expr &:= ")?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":";
      end if;
      c_expr.expr &:= exponent_name;
      c_expr.expr &:= "&1?";
      c_expr.expr &:= integerLiteral(-1);
      c_expr.expr &:= "<<";
      if base <> -2 then
        c_expr.expr &:= integerLiteral(log2_of_negated_base);
        c_expr.expr &:= "*";
      end if;
      c_expr.expr &:= exponent_name;
      c_expr.expr &:= ":";
      c_expr.expr &:= integerLiteral(1);
      c_expr.expr &:= "<<";
      if base <> -2 then
        c_expr.expr &:= integerLiteral(log2_of_negated_base);
        c_expr.expr &:= "*";
      end if;
      c_expr.expr &:= exponent_name;
      c_expr.expr &:= ")";
    elsif integer_overflow_check then
      incr(countOptimizations);
      incr(countOverflowChecks);
      if base >= minIdx(maxExponentOfBase) and base <= maxIdx(maxExponentOfBase) then
        max_exponent := maxExponentOfBase[base];
      elsif base > 0 then
        max_exponent := 2;
        while base <= maxBaseOfExponent[max_exponent] do
          incr(max_exponent);
        end while;
        decr(max_exponent);
      else # base < 0
        max_exponent := 2;
        while base >= minBaseOfExponent[max_exponent] do
          incr(max_exponent);
        end while;
        decr(max_exponent);
      end if;
      c_expr.expr &:= "(";
      exponent_name := getParameterAsVariable("intType", "tmp_", exponent, c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= exponent_name;
      c_expr.expr &:= ">";
      c_expr.expr &:= integerLiteral(max_exponent);
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      c_expr.expr &:= "intPow(";
      c_expr.expr &:= integerLiteral(base);
      c_expr.expr &:= ", ";
      c_expr.expr &:= exponent_name;
      c_expr.expr &:= "))";
    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;
  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
      if integer_overflow_check then
        incr(countOverflowChecks);
        c_expr.expr &:= "intPowOvfChk(";
      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 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 evaluate_const_expr >= 1 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", "tmp_", 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
      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 "";
  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
          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
        c_expr.expr &:= "0";
      elsif reduceOverflowChecks then
        c_expr.expr &:= "/*no_overflow_check_rem*/ 0";
      else
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        dividend_name := getParameterAsVariable("intType", "tmp_", 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;
    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 "";
  begin
    if dividend = 0 then
      incr(countOptimizations);
      if integer_division_check then
        c_expr.expr &:= "(divChk((";
        process_expr(divisor, c_expr);
        c_expr.expr &:= ")==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":0)";
      else
        c_expr.expr &:= "0";
      end if;
    elsif check_int_division_overflow and dividend = integer.first then
      # integer.first % -1 causes an integer overflow.
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "tmp_b_", divisor, c_expr);
      c_expr.expr &:= "ovfChk(";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= "==-1";
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      if check_int_rem_by_zero then
        c_expr.expr &:= "divChk(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
      end if;
      c_expr.expr &:= integerLiteral(dividend);
      c_expr.expr &:= " % ";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= ")";
    elsif check_int_rem_by_zero then
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "tmp_b_", 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
      c_expr.expr &:= integerLiteral(dividend);
      c_expr.expr &:= " % (";
      process_expr(divisor, c_expr);
      c_expr.expr &:= ")";
    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 "";
  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
      c_expr.expr &:= "(divChk((";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    elsif 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
        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
        c_expr.expr &:= "0";
      end if;
    elsif check_int_division_overflow then
      # integer.first % -1 causes an integer overflow.
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      dividend_name := getParameterAsVariable("intType", "tmp_b_", params[1], c_expr);
      divisor_name := getParameterAsVariable("intType", "tmp_b_", params[3], 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 &:= divisor_name;
      c_expr.expr &:= "==-1";
      c_expr.expr &:= ")?";
      c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      c_expr.expr &:= ":";
      if check_int_rem_by_zero then
        c_expr.expr &:= "divChk(";
        c_expr.expr &:= divisor_name;
        c_expr.expr &:= "==0)?";
        c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
        c_expr.expr &:= ":";
      end if;
      c_expr.expr &:= dividend_name;
      c_expr.expr &:= " % ";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= ")";
    elsif check_int_rem_by_zero then
      c_expr.expr &:= "(";
      divisor_name := getParameterAsVariable("intType", "tmp_b_", 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
      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_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", "tmp_", 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 "";
  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
        incr(countOverflowChecks);
        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;
    elsif check_int_shift_overflow then
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      number_name := getParameterAsVariable("intType", "tmp_", 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", "tmp_", 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 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");
      c_expr.expr &:= "\n";
    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", "tmp_", 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", "tmp_", 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
        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", "tmp_", params[1], statement);
      rshift_name := getParameterAsVariable("intType", "tmp_", 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 &:= ":";
      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 evaluate_const_expr >= 1 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", "tmp_", variable, statement);
      statement.expr &:= "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 &:= ")?";
      statement.expr &:= intRaiseError("OVERFLOW_ERROR");
      statement.expr &:= ":(";
      statement.expr &:= variable_name;
      statement.expr &:= "-=";
      statement.expr &:= integerLiteral(delta);
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      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 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);
      variable_name := getParameterAsReference("intType", "tmp_", params[1], statement);
      delta_name := getParameterAsVariable("intType", "tmp_", params[3], statement);
      statement.expr &:= "ovfChk(";
      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;
      statement.expr &:= ">=0&&";
      statement.expr &:= variable_name;
      statement.expr &:= "<";
      statement.expr &:= integerLiteral(integer.first);
      statement.expr &:= "+";
      statement.expr &:= delta_name;
      statement.expr &:= ")?";
      statement.expr &:= intRaiseError("OVERFLOW_ERROR");
      statement.expr &:= ":(";
      statement.expr &:= variable_name;
      statement.expr &:= "-=";
      statement.expr &:= delta_name;
      statement.expr &:= ");\n";
      doLocalDeclsOfStatement(statement, c_expr);
    else
      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 evaluate_const_expr >= 1 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", "tmp_", 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
      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;
