From: jfc@athena.mit.edu (John F Carr)
Subject: Re: Exponentiation operator proposal
Organization: Massachusetts Institute of Technology
Date: Wed, 16 Sep 1992 00:57:48 GMT


I have implemented the exponentiation proposal for gcc and g++.  Here are
the changes.  This was a very quick implementation, and is intended only for
people to gain experience using the feature.  I am certain there are bugs
and missing features.

Your line numbers may vary as the patches here are for the gcc development
sources, not the 2.2.2 release.

This requires one additional library routine: double __ipow(double, int)
which is like pow() except for the argument types.



add to expr.c:expand_expr()


    case EXPON_EXPR:
      if (target == 0)
	target = gen_reg_rtx (tmode != VOIDmode
			      ? tmode : TYPE_MODE (TREE_TYPE (exp)));
      return expand_pow (exp, target);


add to expr.c:


static rtx expand_pow (exp, target)
register tree exp;
rtx target;
{
  enum machine_mode tmode;
  register rtx op0, op1;
  tree arg0, arg1;

  arg0 = TREE_OPERAND (exp, 0);
  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);

  arg1 = TREE_OPERAND (exp, 1);
  op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);

  tmode = GET_MODE (target);

  /* Special case: -1 *^ j */
  if (op0 == constm1_rtx
      && (GET_CODE (op1) == CONST_INT
	  || GET_MODE_CLASS (GET_MODE (op1)) == MODE_INT))
    {
      enum machine_mode op1mode = (GET_CODE (op1) == CONST_INT
				? tmode : (enum machine_mode)GET_MODE (op1));
#if BITS_BIG_ENDIAN
      return extract_bit_field (op1, 1, GET_MODE_BITSIZE (op1mode), 0,
				target, op1mode, tmode,
				GET_MODE_BITSIZE (op1mode),
				GET_MODE_BITSIZE (op1mode));
#else
      return extract_bit_field (op1, 1, 0, 0, target, op1mode, tmode,
				GET_MODE_BITSIZE (op1mode),
				GET_MODE_BITSIZE (op1mode));
#endif
    }

  /* Optimize small integer exponents.  */
  if (GET_CODE (op1) == CONST_INT)
    {
      rtx tmp = op0;
      switch (INTVAL (op1))
	{
	case 0:
	  return const_tiny_rtx[1][tmode];

	case 1:
	  return op0;

	case 3:
	  tmp = expand_mult (tmode, op0, op0, NULL_RTX, 0);
	  /* fall through */
	case 2:
	  return expand_mult (tmode, op0, tmp, target, 0);

	case -1:
	  if (GET_MODE_CLASS (tmode) == MODE_FLOAT)
	    return expand_binop (tmode, flodiv_optab, const_tiny_rtx[1][tmode],
				 op0, target, 0, OPTAB_LIB_WIDEN);
	}
    }

  /* For now, always pass a floating point first argument to the
     library function.  */
  if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE)
    {
      rtx tmp = gen_reg_rtx (DFmode);
      expand_float (tmp, op0, 0);
      op0 = tmp;
    }

  if (GET_CODE (op1) == CONST_INT
      || GET_MODE_CLASS (GET_MODE (op1)) == MODE_INT)
    emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__ipow"), 1,
		       DFmode, 2, op0, DFmode, op1, SImode);
  else
    emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "pow"), 1,
		       DFmode, 2, op0, DFmode,
		       convert_to_mode (DFmode, op1, 0),
		       DFmode);

  if (GET_MODE_CLASS (GET_MODE (target)) == MODE_INT)
    expand_fix (target, hard_libcall_value (DFmode), 0);
  else
    convert_move (target, hard_libcall_value (DFmode));

  return target;
}


add to c-typeck.c:build_binary_op and cp-typeck.c:build_binary_op_nodefault()

    case EXPON_EXPR:
      /* Rules for exponent: type of result is always converted type of LHS.
	 If RHS is integer, no conversions.
	 If RHS is real and LHS is integer, convert LHS to RHS.  */

      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
	  && code1 == INTEGER_TYPE)
	{
	  result_type = type0;
	  converted = 1;
	}
      else if (code0 == REAL_TYPE && code1 == REAL_TYPE)
	{
	  result_type = type0;
	  converted = 1;
	}
      else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
	{
	  op0 = convert (type1, op0);
	  result_type = type1;
	  converted = 1;
	}
      break;


*** cp-parse.y.orig	Thu Sep  3 22:27:15 1992
--- cp-parse.y	Sat Sep 12 13:11:06 1992
***************
*** 190,195 ****
--- 190,196 ----
  %left <code> '+' '-'
  %left <code> '*' '/' '%'
  %right <code> UNARY PLUSPLUS MINUSMINUS
+ %right <code> EXPON
  %left HYPERUNARY
  %left <ttype> PAREN_STAR_PAREN LEFT_RIGHT
  %left <code> POINTSAT POINTSAT_STAR '.' DOT_STAR '(' '['
***************
*** 1209,1214 ****
--- 1210,1217 ----
  		{ $$ = build_x_binary_op ($2, $$, $3); }
  	| expr_no_commas '*' expr_no_commas
  		{ $$ = build_x_binary_op ($2, $$, $3); }
+ 	| expr_no_commas EXPON expr_no_commas
+ 		{ $$ = build_x_binary_op ($2, $$, $3); }
  	| expr_no_commas '/' expr_no_commas
  		{ $$ = build_x_binary_op ($2, $$, $3); }
  	| expr_no_commas '%' expr_no_commas
***************
*** 3736,3741 ****
--- 3739,3746 ----
  operator_name:
  	  OPERATOR '*'
  		{ $$ = ansi_opname[MULT_EXPR]; }
+ 	| OPERATOR EXPON
+ 		{ $$ = ansi_opname[EXPON_EXPR]; }
  	| OPERATOR '/'
  		{ $$ = ansi_opname[TRUNC_DIV_EXPR]; }
  	| OPERATOR '%'

*** c-parse.y	Wed Aug 26 20:42:25 1992
--- c-parse.y	Sun Sep 13 12:30:22 1992
***************
*** 130,135 ****
--- 130,136 ----
  %left <code> '+' '-'
  %left <code> '*' '/' '%'
  %right <code> UNARY PLUSPLUS MINUSMINUS
+ %right <code> EXPON
  %left HYPERUNARY
  %left <code> POINTSAT '.' '(' '['
  
***************
*** 402,407 ****
--- 403,410 ----
  		{ $$ = parser_build_binary_op ($2, $1, $3); }
  	| expr_no_commas '*' expr_no_commas
  		{ $$ = parser_build_binary_op ($2, $1, $3); }
+ 	| expr_no_commas EXPON expr_no_commas
+ 		{ $$ = parser_build_binary_op ($2, $$, $3); }
  	| expr_no_commas '/' expr_no_commas
  		{ $$ = parser_build_binary_op ($2, $1, $3); }
  	| expr_no_commas '%' expr_no_commas

*** c-lex.c	Tue Sep  1 20:23:56 1992
--- c-lex.c	Sun Sep 13 12:34:45 1992
***************
*** 1889,1894 ****
--- 1889,1910 ----
  	    }
  	else if ((c == '-') && (c1 == '>'))
  	  { value = POINTSAT; goto done; }
+ 	else if (c == '*' && c1 == '^')
+ 	  {
+ 	    yylval.code = EXPON_EXPR;
+ 	    token_buffer[2] = c1 = getc (finput);
+ 	    if (c1 == '=')
+ 	      {
+ 		value = ASSIGN;
+ 		goto done;
+ 	      }
+ 	    ungetc (c1, finput);
+ 	    token_buffer[2] = 0;
+ 	    value = EXPON;
+ 	    goto done;
+ 	  }
+ 
+ 
  	ungetc (c1, finput);
  	token_buffer[1] = 0;
  
*** cp-lex.c.orig	Thu Sep  3 22:27:06 1992
--- cp-lex.c	Sat Sep 12 13:30:12 1992
***************
*** 480,485 ****
--- 485,492 ----
    ansi_assopname[(int) CEIL_DIV_EXPR] = ansi_assopname[(int) EXACT_DIV_EXPR];
    ansi_assopname[(int) FLOOR_DIV_EXPR] = ansi_assopname[(int) EXACT_DIV_EXPR];
    ansi_assopname[(int) ROUND_DIV_EXPR] = ansi_assopname[(int) EXACT_DIV_EXPR];
+   ansi_opname[(int) EXPON_EXPR] = get_identifier ("__exp");
+   IDENTIFIER_OPNAME_P (ansi_opname[(int) EXPON_EXPR]) = 1;
    ansi_opname[(int) PLUS_EXPR] = get_identifier ("__pl");
    IDENTIFIER_OPNAME_P (ansi_opname[(int) PLUS_EXPR]) = 1;
    ansi_assopname[(int) PLUS_EXPR] = get_identifier ("__apl");
***************
*** 658,663 ****
--- 665,671 ----
    opname_tab[(int) PLUS_EXPR] = "+";
    opname_tab[(int) MINUS_EXPR] = "-";
    opname_tab[(int) MULT_EXPR] = "*";
+   opname_tab[(int) EXPON_EXPR] = "*^";
    opname_tab[(int) TRUNC_DIV_EXPR] = "/";
    opname_tab[(int) CEIL_DIV_EXPR] = "(ceiling /)";
    opname_tab[(int) FLOOR_DIV_EXPR] = "(floor /)";
***************
*** 707,712 ****
--- 715,721 ----
    assignop_tab[(int) MINUS_EXPR] = "-=";
    assignop_tab[(int) NEGATE_EXPR] = "-=";
    assignop_tab[(int) MULT_EXPR] = "*=";
+   assignop_tab[(int) MULT_EXPR] = "*^=";
    assignop_tab[(int) INDIRECT_REF] = "*=";
    assignop_tab[(int) TRUNC_DIV_EXPR] = "/=";
    assignop_tab[(int) EXACT_DIV_EXPR] = "(exact /=)";
***************
*** 3592,3597 ****
--- 3605,3626 ----
  		     token_buffer);
  	    goto done;
  	  }
+ 	else if (c == '*' && c1 == '^')
+ 	  {
+ 	    c1 = getch ();
+ 	    yylval.code = EXPON_EXPR;
+ 	    if (c1 == '=')
+ 	      {
+ 		value = ASSIGN;
+ 		nextchar = -1;
+ 	      }
+ 	    else
+ 	      {
+ 		value = EXPON;
+ 		nextchar = c1;
+ 	      }
+ 	    goto done;
+ 	  }
  
  	nextchar = c1;
  	token_buffer[1] = 0;
*** c-common.c.orig	Tue Jul 28 23:46:51 1992
--- c-common.c	Sat Sep 12 13:45:45 1992
***************
*** 476,481 ****
--- 476,483 ----
      case LROTATE_EXPR:
      case RROTATE_EXPR:
        opname = "rotate"; break;
+     case EXPON_EXPR:
+       opname = "exponentiation"; break;
      }
    error ("invalid operands to binary %s", opname);
  }

--
    John Carr (jfc@athena.mit.edu)