This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

x86_64 merger part 15 - new extra constraints



Hi,
We are getting closer for the patterns :)
The x86_64 does keep immediates 32bit wide even for 64bit instructions.
The immediates are sign extended, but result of 32bit instructions is
zero extended.
This allows to do both extensions in most of operations. Also the move
instructions have special form with full 64bit immediate.

To handle these beasts in gcc I define new extra constraint 'e' and 'Z'.
One for sign Excented and second for Zero extended values.  Since most
applications fits in 2GB address space the 32bit immediates can handle
w/o problems, we define multiple coding models with various constraints
on place and size of the code.

These may change slightly in future and I expect only small/kernel/medium
model to be useable.

Honza

Tue Mar 13 22:52:07 CET 2001  Jan Hubicka  <jh@suse.cz>
	* i386.c (ix86_cmodel_string, ix86_cmodel): Define.
	(override_options): Parse cmodel string.
	(x86_64_sign_extended_value, x86_64_zero_extended_value): New.
	* i386.h (TARGET_OPTIONS): Add "cmodel".
	(EXTRA_CONSTRAINT): Recognize 'e' and 'Z'.
	(enum cmodel): New.
	(ix86_cmodel_string, ix86_cmodel): Declare.

Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.c,v
retrieving revision 1.234
diff -c -3 -p -r1.234 i386.c
*** i386.c	2001/03/12 15:31:51	1.234
--- i386.c	2001/03/13 21:48:50
*************** struct ix86_frame
*** 487,492 ****
--- 487,497 ----
    HOST_WIDE_INT stack_pointer_offset;
  };
  
+ /* Code model option as passed by user.  */
+ const char *ix86_cmodel_string;
+ /* Parsed value.  */
+ enum cmodel ix86_cmodel;
+ 
  /* which cpu are we scheduling for */
  enum processor_type ix86_cpu;
  
*************** override_options ()
*** 659,664 ****
--- 664,698 ----
    ix86_arch = PROCESSOR_I386;
    ix86_cpu = (enum processor_type) TARGET_CPU_DEFAULT;
  
+   if (ix86_cmodel_string != 0)
+     {
+       if (!strcmp (ix86_cmodel_string, "small"))
+ 	ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
+       else if (flag_pic)
+ 	error ("Code model %s not supported in PIC mode", ix86_cmodel_string);
+       else if (!strcmp (ix86_cmodel_string, "32"))
+ 	ix86_cmodel = CM_32;
+       else if (!strcmp (ix86_cmodel_string, "kernel") && !flag_pic)
+ 	ix86_cmodel = CM_KERNEL;
+       else if (!strcmp (ix86_cmodel_string, "medium") && !flag_pic)
+ 	ix86_cmodel = CM_MEDIUM;
+       else if (!strcmp (ix86_cmodel_string, "large") && !flag_pic)
+ 	ix86_cmodel = CM_LARGE;
+       else
+ 	error ("bad value (%s) for -mcmodel= switch", ix86_cmodel_string);
+     }
+   else
+     {
+       ix86_cmodel = CM_32;
+       if (TARGET_64BIT)
+ 	ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
+     }
+   if ((TARGET_64BIT == 0) != (ix86_cmodel == CM_32))
+     error ("Code model `%s' not supported in the %s bit mode.",
+ 	   ix86_cmodel_string, TARGET_64BIT ? "64" : "32");
+   if (ix86_cmodel == CM_LARGE)
+     error ("Code model `large' not supported yet.");
+ 
    if (ix86_arch_string != 0)
      {
        for (i = 0; i < pta_size; i++)
*************** ix86_can_use_return_insn_p ()
*** 1792,1797 ****
--- 1826,1999 ----
  
    ix86_compute_frame_layout (&frame);
    return frame.to_allocate == 0 && frame.nregs == 0;
+ }
+ 
+ /* Return 1 if VALUE can be stored in the sign extended immediate field.  */
+ int
+ x86_64_sign_extended_value (value)
+      rtx value;
+ {
+   switch (GET_CODE (value))
+     {
+       /* CONST_DOUBLES never match, since HOST_BITS_PER_WIDE_INT is known
+          to be at least 32 and this all acceptable constants are
+ 	 represented as CONST_INT.  */
+       case CONST_INT:
+ #if HOST_BITS_PER_WIDE_INT == 32
+ 	return 1;
+ #else
+ 	{
+ 	  HOST_WIDE_INT val = trunc_int_for_mode (INTVAL (value), DImode);
+ 	  return (HOST_WIDE_INT)(int)val == val;
+ 	}
+ #endif
+ 	break;
+ 
+       /* For certain code models, the symbolic references are known to fit.  */
+       case SYMBOL_REF:
+ 	return ix86_cmodel == CM_SMALL || ix86_cmodel == CM_KERNEL;
+ 
+       /* For certain code models, the code is near as well.  */
+       case LABEL_REF:
+ 	return ix86_cmodel != CM_LARGE && ix86_cmodel != CM_SMALL_PIC;
+ 
+       /* We also may accept the offsetted memory references in certain special
+          cases.  */
+       case CONST:
+ 	if (GET_CODE (XEXP (value, 0)) == UNSPEC
+ 	    && XVECLEN (XEXP (value, 0), 0) == 1
+ 	    && XINT (XEXP (value, 0), 1) ==  15)
+ 	  return 1;
+ 	else if (GET_CODE (XEXP (value, 0)) == PLUS)
+ 	  {
+ 	    rtx op1 = XEXP (XEXP (value, 0), 0);
+ 	    rtx op2 = XEXP (XEXP (value, 0), 1);
+ 	    HOST_WIDE_INT offset;
+ 
+ 	    if (ix86_cmodel == CM_LARGE)
+ 	      return 0;
+ 	    if (GET_CODE (op2) != CONST_INT)
+ 	      return 0;
+ 	    offset = trunc_int_for_mode (INTVAL (op2), DImode);
+ 	    switch (GET_CODE (op1))
+ 	      {
+ 		case SYMBOL_REF:
+ 		  /* For CM_SMALL assume that latest object is 1MB before
+ 		     end of 31bits boundary.  We may also accept pretty
+ 		     large negative constants knowing that all objects are
+ 		     in the positive half of address space.  */
+ 		  if (ix86_cmodel == CM_SMALL
+ 		      && offset < 1024*1024*1024
+ 		      && trunc_int_for_mode (offset, SImode) == offset)
+ 		    return 1;
+ 		  /* For CM_KERNEL we know that all object resist in the
+ 		     negative half of 32bits address space.  We may not
+ 		     accept negative offsets, since they may be just off
+ 		     and we may accept pretty large possitive ones.  */
+ 		  if (ix86_cmodel == CM_KERNEL
+ 		      && offset > 0
+ 		      && trunc_int_for_mode (offset, SImode) == offset)
+ 		    return 1;
+ 		  break;
+ 		case LABEL_REF:
+ 		  /* These conditions are similar to SYMBOL_REF ones, just the
+ 		     constraints for code models differ.  */
+ 		  if ((ix86_cmodel == CM_SMALL || ix86_cmodel == CM_MEDIUM)
+ 		      && offset < 1024*1024*1024
+ 		      && trunc_int_for_mode (offset, SImode) == offset)
+ 		    return 1;
+ 		  if (ix86_cmodel == CM_KERNEL
+ 		      && offset > 0
+ 		      && trunc_int_for_mode (offset, SImode) == offset)
+ 		    return 1;
+ 		  break;
+ 		default:
+ 		  return 0;
+ 	      }
+ 	  }
+ 	return 0;
+       default:
+ 	return 0;
+     }
+ }
+ 
+ /* Return 1 if VALUE can be stored in the zero extended immediate field.  */
+ int
+ x86_64_zero_extended_value (value)
+      rtx value;
+ {
+   switch (GET_CODE (value))
+     {
+       case CONST_DOUBLE:
+ #if HOST_BITS_PER_WIDE_INT == 32
+ 	return  (GET_MODE (value) == VOIDmode
+ 		 && !CONST_DOUBLE_HIGH (value));
+ #else
+ 	return 0;
+ #endif
+       case CONST_INT:
+ #if HOST_BITS_PER_WIDE_INT == 32
+ 	return INTVAL (value) >= 0;
+ #else
+ 	return !(INTVAL (value) & ~(HOST_WIDE_INT)0xffffffff);
+ #endif
+ 	break;
+ 
+       /* For certain code models, the symbolic references are known to fit.  */
+       case SYMBOL_REF:
+ 	return ix86_cmodel == CM_SMALL;
+ 
+       /* For certain code models, the code is near as well.  */
+       case LABEL_REF:
+ 	return ix86_cmodel == CM_SMALL || ix86_cmodel == CM_MEDIUM;
+ 
+       /* We also may accept the offsetted memory references in certain special
+          cases.  */
+       case CONST:
+ 	if (GET_CODE (XEXP (value, 0)) == PLUS)
+ 	  {
+ 	    rtx op1 = XEXP (XEXP (value, 0), 0);
+ 	    rtx op2 = XEXP (XEXP (value, 0), 1);
+ 
+ 	    if (ix86_cmodel == CM_LARGE)
+ 	      return 0;
+ 	    switch (GET_CODE (op1))
+ 	      {
+ 		case SYMBOL_REF:
+ 		    return 0;
+ 		  /* For small code model we may accept pretty large possitive
+ 		     offsets, since one bit is available for free.  Negative
+ 		     offsets are limited by the size of NULL pointer area
+ 		     specified by the ABI.  */
+ 		  if (ix86_cmodel == CM_SMALL
+ 		      && GET_CODE (op2) == CONST_INT
+ 		      && trunc_int_for_mode (INTVAL (op2), DImode) > -0x10000
+ 		      && (trunc_int_for_mode (INTVAL (op2), SImode)
+ 			  == INTVAL (op2)))
+ 		    return 1;
+ 	          /* ??? For the kernel, we may accept adjustment of
+ 		     -0x10000000, since we know that it will just convert
+ 		     negative address space to possitive, but perhaps this
+ 		     is not worthwhile.  */
+ 		  break;
+ 		case LABEL_REF:
+ 		  /* These conditions are similar to SYMBOL_REF ones, just the
+ 		     constraints for code models differ.  */
+ 		  if ((ix86_cmodel == CM_SMALL || ix86_cmodel == CM_MEDIUM)
+ 		      && GET_CODE (op2) == CONST_INT
+ 		      && trunc_int_for_mode (INTVAL (op2), DImode) > -0x10000
+ 		      && (trunc_int_for_mode (INTVAL (op2), SImode)
+ 			  == INTVAL (op2)))
+ 		    return 1;
+ 		  break;
+ 		default:
+ 		  return 0;
+ 	      }
+ 	  }
+ 	return 0;
+       default:
+ 	return 0;
+     }
  }
  
  /* Value should be nonzero if functions must have frame pointers.
Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.h,v
retrieving revision 1.166
diff -c -3 -p -r1.166 i386.h
*** i386.h	2001/03/12 14:18:57	1.166
--- i386.h	2001/03/13 21:48:56
*************** extern int ix86_arch;
*** 393,398 ****
--- 393,400 ----
      N_("Attempt to keep stack aligned to this power of 2") },	\
    { "branch-cost=",	&ix86_branch_cost_string,		\
      N_("Branches are this expensive (1-5, arbitrary units)") },	\
+   { "cmodel=", &ix86_cmodel_string,				\
+     N_("Use given x86-64 code model") },			\
    SUBTARGET_OPTIONS						\
  }
  
*************** enum reg_class
*** 1247,1252 ****
--- 1249,1271 ----
    ((C) == 'G' ? standard_80387_constant_p (VALUE) \
     : ((C) == 'H' ? standard_sse_constant_p (VALUE) : 0))
  
+ /* A C expression that defines the optional machine-dependent
+    constraint letters that can be used to segregate specific types of
+    operands, usually memory references, for the target machine.  Any
+    letter that is not elsewhere defined and not matched by
+    `REG_CLASS_FROM_LETTER' may be used.  Normally this macro will not
+    be defined.
+ 
+    If it is required for a particular target machine, it should
+    return 1 if VALUE corresponds to the operand type represented by
+    the constraint letter C.  If C is not defined as an extra
+    constraint, the value returned should be 0 regardless of VALUE.  */
+ 
+ #define EXTRA_CONSTRAINT(VALUE, C)				\
+   ((C) == 'e' ? x86_64_sign_extended_value (VALUE)		\
+    : (C) == 'Z' ? x86_64_zero_extended_value (VALUE)		\
+    : 0)
+ 
  /* Place additional restrictions on the register class to use when it
     is necessary to be able to hold a value of mode MODE in a reload
     register for which class CLASS would ordinarily be used. */
*************** do { long l;						\
*** 3050,3055 ****
--- 3069,3099 ----
  
  #define SPECIAL_MODE_PREDICATES \
    "ext_register_operand",
+ 
+ /* CM_32 is used by 32bit ABI
+    CM_SMALL is small model assuming that all code and data fits in the first
+    31bits of address space.
+    CM_KERNEL is model assuming that all code and data fits in the negative
+    31bits of address space.
+    CM_MEDIUM is model assuming that code fits in the first 31bits of address
+    space.  Size of data is unlimited.
+    CM_LARGE is model making no assumptions about size of particular sections.
+   
+    CM_SMALL_PIC is model for PIC libraries assuming that code+data+got/plt
+    tables first in 31bits of address space.
+  */
+ enum cmodel {
+   CM_32,
+   CM_SMALL,
+   CM_KERNEL,
+   CM_MEDIUM,
+   CM_LARGE,
+   CM_SMALL_PIC
+ };
+ 
+ /* Valud of -mcmodel specified by user.  */
+ extern const char *ix86_cmodel_string;
+ extern enum cmodel ix86_cmodel;
  
  /* Variables in i386.c */
  extern const char *ix86_cpu_string;		/* for -mcpu=<xxx> */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]