
(********************************************************************)
(*                                                                  *)
(*  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_PARSE             is action "INT_PARSE";
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);");
    declareExtern(c_prog, "uintType    uintRand (void);");
    declareExtern(c_prog, "uintType    uintRandLimited (uintType);");
    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 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: 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: negate (in reference: number, inout expr_type: c_expr) is func

  local
    var reference: aParam is NIL;
    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
      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 &:= ")";
    else
      c_expr.expr &:= "-(";
      process_expr(number, c_expr);
      c_expr.expr &:= ")";
    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

  begin
    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 func;


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

  begin
    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 func;


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

  begin
    c_expr.expr &:= "ovfChk(";
    c_expr.expr &:= summand2_name;
    c_expr.expr &:= "<0&&";
    c_expr.expr &:= summand1_name;
    c_expr.expr &:= "<";
    c_expr.expr &:= integerLiteral(integer.first);
    c_expr.expr &:= "-";
    c_expr.expr &:= summand2_name;
    c_expr.expr &:= " || ";
    c_expr.expr &:= summand2_name;
    c_expr.expr &:= ">=0&&";
    c_expr.expr &:= summand1_name;
    c_expr.expr &:= ">";
    c_expr.expr &:= integerLiteral(integer.last);
    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;
  end func;


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

  begin
    c_expr.expr &:= "ovfChk(";
    c_expr.expr &:= subtrahend_name;
    c_expr.expr &:= "<0&&";
    c_expr.expr &:= minuend_name;
    c_expr.expr &:= ">";
    c_expr.expr &:= integerLiteral(integer.last);
    c_expr.expr &:= "+";
    c_expr.expr &:= subtrahend_name;
    c_expr.expr &:= " || ";
    c_expr.expr &:= subtrahend_name;
    c_expr.expr &:= ">=0&&";
    c_expr.expr &:= minuend_name;
    c_expr.expr &:= "<";
    c_expr.expr &:= integerLiteral(integer.first);
    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;
  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 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;
    elsif check_int_abs_overflow 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
        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 func;


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

  local
    var reference: evaluatedParam is NIL;
    var string: summand1_name is "";
  begin
    if getConstant(summand1, INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      block
        c_expr.expr &:= integerLiteral(getValue(evaluatedParam, integer) + summand2);
      exception
        catch OVERFLOW_ERROR:
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end block;
    elsif summand2 = 0 then
      incr(countOptimizations);
      process_expr(summand1, c_expr);
    elsif check_int_arithmetic_overflow then
      incr(countOptimizations);
      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 &:= ")";
    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 string: summand1_name is "";
    var string: summand2_name is "";
  begin
    if check_int_arithmetic_overflow 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);
        summand2_name := getParameterAsVariable("intType", "tmp_", summand2, c_expr);
        int_add_with_overflow_check(summand1_name, summand2_name, c_expr);
      end if;
      c_expr.expr &:= ")";
    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 forward;
const proc: process_const_int_sbtr (in integer: minuend, in reference: subtrahend,
    inout expr_type: c_expr) is forward;
const proc: process_int_sbtr (in reference: minuend, in reference: subtrahend,
    inout expr_type: c_expr) is forward;


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
          summand2_name := getParameterAsVariable("intType", "tmp_", summand2Ref, c_expr);
          if doAdd then
            int_add_with_overflow_check(summand1_name, summand2_name, c_expr);
          else
            int_sbtr_with_overflow_check(summand1_name, summand2_name, 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
      if not addSubParamList[1].doAdd then
        writeln(" ***** Problem in optimize_int_add (2)");
      elsif addSubParamList[2].doAdd then
        if addSubParamList[1].summand = NIL then
          if addSubParamList[2].summand = NIL then
            block
              c_expr.expr &:= integerLiteral(addSubParamList[1].constSummand +
                                             addSubParamList[2].constSummand);
            exception
              catch OVERFLOW_ERROR:
                warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
                c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
            end block;
          else
            process_const_int_add(addSubParamList[2].summand,
                addSubParamList[1].constSummand, c_expr);
          end if;
        elsif addSubParamList[2].summand = NIL then
          process_const_int_add(addSubParamList[1].summand,
              addSubParamList[2].constSummand, c_expr);
        else
          process_int_add(addSubParamList[1].summand, addSubParamList[2].summand, c_expr);
        end if;
      else
        if addSubParamList[1].summand = NIL then
          if addSubParamList[2].summand = NIL then
            block
              c_expr.expr &:= integerLiteral(addSubParamList[1].constSummand -
                                             addSubParamList[2].constSummand);
            exception
              catch OVERFLOW_ERROR:
                warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
                c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
            end block;
          else
            process_const_int_sbtr(addSubParamList[1].constSummand,
                addSubParamList[2].summand, c_expr);
          end if;
        elsif addSubParamList[2].summand = NIL then
          process_const_int_sbtr(addSubParamList[1].summand,
              addSubParamList[2].constSummand, c_expr);
        else
          process_int_sbtr(addSubParamList[1].summand, addSubParamList[2].summand, c_expr);
        end if;
      end if;
    elsif length(addSubParamList) = 1 then
      incr(countOptimizations);
      if addSubParamList[1].summand = NIL then
        if addSubParamList[1].doAdd then
          c_expr.expr &:= integerLiteral(addSubParamList[1].constSummand);
        else
          block
            c_expr.expr &:= integerLiteral(-addSubParamList[1].constSummand);
          exception
            catch OVERFLOW_ERROR:
              warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
              c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
          end block;
        end if;
      else
        if addSubParamList[1].doAdd then
          process_expr(addSubParamList[1].summand, c_expr);
        else
          negate(addSubParamList[1].summand, c_expr);
        end if;
      end if;
    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 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: process (INT_BYTES_BE_2_UINT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intBytesBe2UInt(";
    getAnyParamToExpr(params[1], c_expr);
    c_expr.expr &:= ")";
  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: process (INT_BYTES_LE_2_UINT, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intBytesLe2UInt(";
    getAnyParamToExpr(params[1], c_expr);
    c_expr.expr &:= ")";
  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 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);
      block
        c_expr.expr &:= integerLiteral(getValue(evaluatedDividend, integer) div divisor);
      exception
        catch OVERFLOW_ERROR:
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end block;
    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);
      c_expr.expr &:= "(divChk((";
      process_expr(divisor, c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    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 ccConf.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 ccConf.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 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 ccConf.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 ccConf.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

  begin
    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 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 string: number_name is "";
  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);
      block
        c_expr.expr &:= integerLiteral(getValue(evaluatedNumber, integer) << lshift);
      exception
        catch OVERFLOW_ERROR:
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end block;
    elsif lshift = 0 then
      incr(countOptimizations);
      process_expr(number, c_expr);
    elsif check_int_shift_overflow then
      incr(countOptimizations);
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      number_name := getParameterAsVariable("intType", "tmp_", number, c_expr);
      c_expr.expr &:= "ovfChk(";
      checkIfOutsideRange(number_name, integer.first >> lshift,
                          integer.last >> lshift, 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 &:= ")";
    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 &:= ":";
      c_expr.expr &:= integerLiteral(number);
      c_expr.expr &:= " << ";
      c_expr.expr &:= lshift_name;
      c_expr.expr &:= ")";
    else
      c_expr.expr &:= integerLiteral(number);
      c_expr.expr &:= " << (";
      process_expr(lshift, c_expr);
      c_expr.expr &:= ")";
    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 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
      block
        c_expr.expr &:= integerLiteral(getValue(evaluatedDividend, integer) mdiv divisor);
      exception
        catch OVERFLOW_ERROR:
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end block;
    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
      c_expr.expr &:= "(divChk((";
      process_expr(divisor, c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    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 ccConf.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 ccConf.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);
    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 ccConf.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: process_const_int_mod (in reference: dividend, in integer: divisor,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedDividend is NIL;
    var string: dividend_name is "";
    var string: quotient_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
      block
        c_expr.expr &:= integerLiteral(getValue(evaluatedDividend, integer) mod divisor);
      exception
        catch OVERFLOW_ERROR:
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end block;
    elsif divisor = -1 then
      if check_int_division_overflow then
        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)";
      else
        c_expr.expr &:= "0";
      end if;
    elsif divisor > 0 and 2 ** log2(divisor) = divisor then
      # Divisor is a power of two.
      c_expr.expr &:= "(";
      process_expr(dividend, c_expr);
      c_expr.expr &:= ")&";
      c_expr.expr &:= integerLiteral(pred(divisor));
    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 when 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);
      quotient_name := defineTempVariable("intType", "tmp_c_", c_expr);
      (* Formula used: c=a%b,a<0^b<0&&c!=0?c+b:c *)
      c_expr.expr &:= quotient_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 &:= quotient_name;
      c_expr.expr &:= "!=0?";
      c_expr.expr &:= quotient_name;
      c_expr.expr &:= "+";
      c_expr.expr &:= integerLiteral(divisor);
      c_expr.expr &:= ":";
      c_expr.expr &:= quotient_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: quotient_name is "";
  begin
    incr(countOptimizations);
    if dividend = 0 then
      c_expr.expr &:= "(divChk((";
      process_expr(divisor, c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    elsif dividend = 1 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);
      quotient_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 ccConf.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 &:= quotient_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 &:= quotient_name;
      c_expr.expr &:= "!=0?";
      c_expr.expr &:= quotient_name;
      c_expr.expr &:= "+";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= ":";
      c_expr.expr &:= quotient_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: quotient_name is "";
  begin
    if 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 ccConf.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 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
      incr(countOptimizations);
      c_expr.expr &:= "/* mask lower bits */ (";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ")&((1<<(";
      process_expr(getValue(params[3], ref_list)[4], c_expr);
      c_expr.expr &:= "))-1)";
*)
    else
      c_expr.expr &:= "(";
      dividend_name := getParameterAsVariable("intType", "tmp_a_", params[1], c_expr);
      divisor_name := getParameterAsVariable("intType", "tmp_b_", params[3], c_expr);
      quotient_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 ccConf.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 &:= quotient_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 &:= quotient_name;
      c_expr.expr &:= "!=0?";
      c_expr.expr &:= quotient_name;
      c_expr.expr &:= "+";
      c_expr.expr &:= divisor_name;
      c_expr.expr &:= ":";
      c_expr.expr &:= quotient_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 reference: evaluatedParam is NIL;
    var string: factor1_name is "";
  begin
    if getConstant(factor1, INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      block
        c_expr.expr &:= integerLiteral(getValue(evaluatedParam, integer) * factor2);
      exception
        catch OVERFLOW_ERROR:
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end block;
    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
      incr(countOptimizations);
      negate(factor1, c_expr);
    elsif check_int_arithmetic_overflow then
      incr(countOptimizations);
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      factor1_name := getParameterAsVariable("intType", "tmp_", factor1, c_expr);
      c_expr.expr &:= "ovfChk(";
      if factor2 < 0 then
        checkIfOutsideRange(factor1_name, integer.last div factor2,
                            integer.first div factor2, c_expr);
      else
        checkIfOutsideRange(factor1_name, integer.first div factor2,
                            integer.last div factor2, c_expr);
      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
      c_expr.expr &:= "(";
      process_expr(factor1, c_expr);
      c_expr.expr &:= ") * ";
      c_expr.expr &:= integerLiteral(factor2);
    end if;
  end func;


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

  local
    var reference: evaluatedParam is NIL;
    var string: factor1_name is "";
    var string: factor2_name is "";
    var string: product_name is "";
  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 &:= "(";
      if 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(params[1], c_expr);
        c_expr.expr &:= ") * (doubleIntType)(";
        process_expr(params[3], 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;
        c_expr.expr &:= ")";
      else
        factor1_name := getParameterAsVariable("intType", "tmp_", params[1], c_expr);
        factor2_name := getParameterAsVariable("intType", "tmp_", params[3], 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 &:= intRaiseError("OVERFLOW_ERROR");
        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.first);
        c_expr.expr &:= "/";
        c_expr.expr &:= factor2_name;
        c_expr.expr &:= "?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":0):0):";
        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 &:= intRaiseError("OVERFLOW_ERROR");
        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.last);
        c_expr.expr &:= "/";
        c_expr.expr &:= factor1_name;
        c_expr.expr &:= "?";
        c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
        c_expr.expr &:= ":0):0):0,";
        c_expr.expr &:= factor1_name;
        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 &:= 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;
        c_expr.expr &:= ")";

      end if;
    else
      c_expr.expr &:= "(";
      process_expr(params[1], c_expr);
      c_expr.expr &:= ") * (";
      process_expr(params[3], c_expr);
      c_expr.expr &:= ")";
    end if;
  end 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 := getParameterAsVariable("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_PARSE, in reference: function,
    in ref_list: params, inout expr_type: c_expr) is func

  begin
    c_expr.expr &:= "intParse(";
    getAnyParamToExpr(params[3], 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 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 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);
      block
        c_expr.expr &:= integerLiteral(getValue(evaluatedBase, integer) ** exponent);
      exception
        catch OVERFLOW_ERROR:
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end block;
    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);
      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))";
    elsif base = 0 then
      incr(countOptimizations);
      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 &:= "))";
    elsif base = 1 then
      incr(countOptimizations);
      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 &:= ")";
    elsif base > 0 and 2 ** log2(base) = base then
      # Base is a power of two.
      incr(countOptimizations);
      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 &:= ":";
      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 &:= ")";
    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);
      c_expr.expr &:= "numChk(";
      c_expr.expr &:= exponent_name;
      c_expr.expr &:= "<0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":";
      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_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_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 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);
      block
        c_expr.expr &:= integerLiteral(getValue(evaluatedDividend, integer) rem divisor);
      exception
        catch OVERFLOW_ERROR:
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end block;
    elsif divisor = -1 then
      if check_int_division_overflow then
        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)";
      else
        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);
      c_expr.expr &:= "(divChk((";
      process_expr(divisor, c_expr);
      c_expr.expr &:= ")==0)?";
      c_expr.expr &:= intRaiseError("NUMERIC_ERROR");
      c_expr.expr &:= ":0)";
    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 ccConf.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 ccConf.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 ccConf.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 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 ccConf.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 ccConf.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);
      block
        c_expr.expr &:= integerLiteral(getValue(evaluatedNumber, integer) >> rshift);
      exception
        catch OVERFLOW_ERROR:
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end block;
    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_const_int_sbtr (in reference: minuend, in integer: subtrahend,
    inout expr_type: c_expr) is func

  local
    var reference: evaluatedParam is NIL;
    var string: minuend_name is "";
  begin
    if getConstant(minuend, INTOBJECT, evaluatedParam) then
      incr(countOptimizations);
      block
        c_expr.expr &:= integerLiteral(getValue(evaluatedParam, integer) - subtrahend);
      exception
        catch OVERFLOW_ERROR:
          warning(DOES_RAISE, "OVERFLOW_ERROR", c_expr);
          c_expr.expr &:= intRaiseError("OVERFLOW_ERROR");
      end block;
    elsif subtrahend = 0 then
      incr(countOptimizations);
      process_expr(minuend, c_expr);
    elsif check_int_arithmetic_overflow then
      incr(countOptimizations);
      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 &:= ")";
    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 reference: evaluatedParam is NIL;
    var string: subtrahend_name is "";
  begin
    if minuend = 0 then
      negate(subtrahend, c_expr);
    elsif check_int_arithmetic_overflow then
      incr(countOptimizations);
      incr(countOverflowChecks);
      c_expr.expr &:= "(";
      subtrahend_name := getParameterAsVariable("intType", "tmp_", subtrahend, c_expr);
      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;
      c_expr.expr &:= ")";
    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 string: minuend_name is "";
    var string: subtrahend_name is "";
  begin
    if check_int_arithmetic_overflow then
      if minuend = subtrahend then
        incr(countOptimizations);
        c_expr.expr &:= "0";
      else
        incr(countOverflowChecks);
        c_expr.expr &:= "(";
        minuend_name := getParameterAsVariable("intType", "tmp_", minuend, c_expr);
        subtrahend_name := getParameterAsVariable("intType", "tmp_", subtrahend, c_expr);
        int_sbtr_with_overflow_check(minuend_name, subtrahend_name, 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: 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;
