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 37 - PIC support


Hi,
I was finally able to test 64bit PIC compilation, so here is the code.
It is quite straighforward, as we don't need to mess up with GOT pointer.

I use (mem:DI (unspec 15 (symbol))) to represent RIP relative GOT references
and "RIP relative" entries in the PIC jumptables. Perhaps we can use them for
32bit code as well, since onlike current approach, the table may lie in
readonly section, instead of text.

Honza

So kvě  5 22:12:21 CEST 2001  Jan Hubicka  <jh@suse.cz>

	* i386.md (indirect_jump): Allow Pmode operand.
	(tablejump): LIkewise.
	(casesi): Handle 64bit cases.
	(casesi_rex64): New expander.
	* i386.c (symbolic_operand): Allow 64bit PIC references.
	(pic_symbolic_operand): Likewise.
	(ix86_find_base_term): Strip the 64bit PIC references.
	(legitimate_pic_address_disp_p): Handle 64bit PIC.
	(legitimize_pic_address): Likewise.
	(i386_simplify_dwarf_addr): Strip down the 64bit PIC references.

*** /p1/x86-64/egcs/gcc/config/i386/i386.md	Sat Apr 28 13:32:48 2001
--- i386.md	Sat May  5 21:58:43 2001
***************
*** 12986,12999 ****
    [(set_attr "type" "ibr")])
  
  (define_insn "indirect_jump"
!   [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
    ""
    "jmp\\t%A0"
    [(set_attr "type" "ibr")
     (set_attr "length_immediate" "0")])
  
  (define_insn "tablejump"
!   [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))
     (use (label_ref (match_operand 1 "" "")))]
    "! flag_pic"
    "jmp\\t%A0"
--- 12988,13001 ----
    [(set_attr "type" "ibr")])
  
  (define_insn "indirect_jump"
!   [(set (pc) (match_operand 0 "nonimmediate_operand" "rm"))]
    ""
    "jmp\\t%A0"
    [(set_attr "type" "ibr")
     (set_attr "length_immediate" "0")])
  
  (define_insn "tablejump"
!   [(set (pc) (match_operand 0 "nonimmediate_operand" "rm"))
     (use (label_ref (match_operand 1 "" "")))]
    "! flag_pic"
    "jmp\\t%A0"
***************
*** 13059,13064 ****
--- 13061,13072 ----
    "flag_pic"
    "
  {
+   if (TARGET_64BIT)
+     {
+       emit_insn (gen_casesi_rex64 (operands[0], operands[1], operands[2],
+ 				   operands[3], operands[4]));
+       DONE;
+     }
    operands[5] = gen_reg_rtx (SImode);
    operands[6] = gen_reg_rtx (SImode);
    operands[7] = gen_reg_rtx (SImode);
***************
*** 13066,13071 ****
--- 13074,13135 ----
    current_function_uses_pic_offset_table = 1;
  }")
  
+ ;; Implement switch statements when generating 64bit PIC code.
+ ;;
+ ;; Emit code here to do the range checking and make the index zero based.
+ ;;
+ ;; Each entry in the "addr_diff_vec" is relative address:
+ ;; 
+ ;; .long label-.+(.-TABLE)
+ ;; 
+ ;; Since (.-TABLE) is constant, the R_X86_64_PC32 relocation is used and
+ ;; the value is computed by linker to contain address of destination relative
+ ;; to the address of table.
+ ;;
+ ;; The pattern below emits code that looks like this:
+ ;; 
+ ;; leaq    .L11(%rip), %rdx
+ ;; mov     %eax, %eax
+ ;; movslq  (%rdx,%rax,4),%rax
+ ;; leaq    (%rax,%rdx), %rax
+ ;; jmp     *%rax
+ ;; 
+ (define_expand "casesi_rex64"
+   [(set (match_dup 5)
+ 	(match_operand:SI 0 "general_operand" ""))
+    (parallel [(set (match_dup 6)
+ 		   (minus:SI (match_dup 5)
+ 			     (match_operand:SI 1 "general_operand" "")))
+ 	      (clobber (reg:CC 17))])
+    (set (reg:CC 17)
+ 	(compare:CC (match_dup 6)
+ 		    (match_operand:SI 2 "general_operand" "")))
+    (set (pc)
+ 	(if_then_else (gtu (reg:CC 17)
+ 			   (const_int 0))
+ 		      (label_ref (match_operand 4 "" ""))
+ 		      (pc)))
+    (set (match_dup 7) (label_ref (match_operand 3 "" "")))
+    (set (match_dup 8) (zero_extend:DI (match_dup 6)))
+    (set (match_dup 9)
+ 	(sign_extend:DI (mem:SI (plus:DI (mult:DI (match_dup 8) (const_int 4))
+ 				(match_dup 7)))))
+    (parallel
+      [(set (match_dup 9)
+ 	   (plus:DI (match_dup 7) (match_dup 9)))
+       (clobber (reg:CC 17))])
+    (parallel [(set (pc) (match_dup 9))
+ 	      (use (label_ref (match_dup 3)))])]
+   "flag_pic && TARGET_64BIT"
+   "
+ {
+   operands[5] = gen_reg_rtx (SImode);
+   operands[6] = gen_reg_rtx (SImode);
+   operands[7] = gen_reg_rtx (DImode);
+   operands[8] = gen_reg_rtx (DImode);
+   operands[9] = gen_reg_rtx (DImode);
+ }")
+ 
  (define_insn "*tablejump_pic"
    [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))
     (use (label_ref (match_operand 1 "" "")))]
*** /p1/x86-64/egcs/gcc/config/i386/i386.c	Thu Apr 26 20:25:01 2001
--- i386.c	Sat May  5 21:43:39 2001
*************** symbolic_operand (op, mode)
*** 1270,1277 ****
        if (GET_CODE (op) == SYMBOL_REF
  	  || GET_CODE (op) == LABEL_REF
  	  || (GET_CODE (op) == UNSPEC
! 	      && XINT (op, 1) >= 6
! 	      && XINT (op, 1) <= 7))
  	return 1;
        if (GET_CODE (op) != PLUS
  	  || GET_CODE (XEXP (op, 1)) != CONST_INT)
--- 2267,2275 ----
        if (GET_CODE (op) == SYMBOL_REF
  	  || GET_CODE (op) == LABEL_REF
  	  || (GET_CODE (op) == UNSPEC
! 	      && (XINT (op, 1) == 6
! 		  || XINT (op, 1) == 7
! 		  || XINT (op, 1) == 15)))
  	return 1;
        if (GET_CODE (op) != PLUS
  	  || GET_CODE (XEXP (op, 1)) != CONST_INT)
*************** pic_symbolic_operand (op, mode)
*** 1304,1312 ****
       register rtx op;
       enum machine_mode mode ATTRIBUTE_UNUSED;
  {
!   if (GET_CODE (op) == CONST)
      {
-       op = XEXP (op, 0);
        if (GET_CODE (op) == UNSPEC)
  	return 1;
        if (GET_CODE (op) != PLUS
--- 2302,2317 ----
       register rtx op;
       enum machine_mode mode ATTRIBUTE_UNUSED;
  {
!   if (GET_CODE (op) != CONST)
!     return 0;
!   op = XEXP (op, 0);
!   if (TARGET_64BIT)
!     {
!       if (GET_CODE (XEXP (op, 0)) == UNSPEC)
! 	return 1;
!     }
!   else 
      {
        if (GET_CODE (op) == UNSPEC)
  	return 1;
        if (GET_CODE (op) != PLUS
*************** ix86_find_base_term (x)
*** 2938,2943 ****
--- 3955,3983 ----
  {
    rtx term;
  
+   if (TARGET_64BIT)
+     {
+       if (GET_CODE (x) != CONST)
+ 	return x;
+       term = XEXP (x, 0);
+       if (GET_CODE (term) == PLUS
+ 	  && (GET_CODE (XEXP (term, 1)) == CONST_INT
+ 	      || GET_CODE (XEXP (term, 1)) == CONST_DOUBLE))
+ 	term = XEXP (term, 0);
+       if (GET_CODE (term) != UNSPEC
+ 	  || XVECLEN (term, 0) != 1
+ 	  || XINT (term, 1) !=  15)
+ 	return x;
+ 
+       term = XVECEXP (term, 0, 0);
+ 
+       if (GET_CODE (term) != SYMBOL_REF
+ 	  && GET_CODE (term) != LABEL_REF)
+ 	return x;
+ 
+       return term;
+     }
+ 
    if (GET_CODE (x) != PLUS
        || XEXP (x, 0) != pic_offset_table_rtx
        || GET_CODE (XEXP (x, 1)) != CONST)
*************** int
*** 2969,2978 ****
--- 4009,4053 ----
  legitimate_pic_address_disp_p (disp)
       register rtx disp;
  {
+   /* In 64bit mode we can allow direct addresses of symbols and labels
+      when they are not dynamic symbols.  */
+   if (TARGET_64BIT)
+     {
+       rtx x = disp;
+       if (GET_CODE (disp) == CONST)
+ 	x = XEXP (disp, 0);
+       /* ??? Handle PIC code models */
+       if (GET_CODE (x) == PLUS
+ 	  && (GET_CODE (XEXP (x, 1)) == CONST_INT
+ 	      && ix86_cmodel == CM_SMALL_PIC
+ 	      && INTVAL (XEXP (x, 1)) < 1024*1024*1024
+ 	      && INTVAL (XEXP (x, 1)) > -1024*1024*1024))
+ 	x = XEXP (x, 0);
+       if (GET_CODE (x) == LABEL_REF
+ 	  || (GET_CODE (x) == SYMBOL_REF
+ 	      && (CONSTANT_POOL_ADDRESS_P (x)
+ 	          || SYMBOL_REF_FLAG (x))))
+ 	return 1;
+     }
    if (GET_CODE (disp) != CONST)
      return 0;
    disp = XEXP (disp, 0);
  
+   if (TARGET_64BIT)
+     {
+       /* We are unsafe to allow PLUS expressions.  This limit allowed distance
+          of GOT tables.  We should not need these anyway.  */
+       if (GET_CODE (disp) != UNSPEC
+ 	  || XVECLEN (disp, 0) != 1
+ 	  || XINT (disp, 1) != 15)
+ 	return 0;
+ 
+       if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF
+ 	  && GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF)
+ 	return 0;
+       return 1;
+     }
+ 
    if (GET_CODE (disp) == PLUS)
      {
        if (GET_CODE (XEXP (disp, 1)) != CONST_INT)
*************** legitimize_pic_address (orig, reg)
*** 3243,3279 ****
  	  && (CONSTANT_POOL_ADDRESS_P (addr)
  	      || SYMBOL_REF_FLAG (addr))))
      {
!       /* This symbol may be referenced via a displacement from the PIC
! 	 base address (@GOTOFF).  */
  
!       current_function_uses_pic_offset_table = 1;
!       new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 7);
!       new = gen_rtx_CONST (Pmode, new);
!       new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
  
!       if (reg != 0)
! 	{
! 	  emit_move_insn (reg, new);
! 	  new = reg;
  	}
      }
    else if (GET_CODE (addr) == SYMBOL_REF)
      {
!       /* This symbol must be referenced via a load from the
! 	 Global Offset Table (@GOT).  */
  
!       current_function_uses_pic_offset_table = 1;
!       new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 6);
!       new = gen_rtx_CONST (Pmode, new);
!       new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
!       new = gen_rtx_MEM (Pmode, new);
!       RTX_UNCHANGING_P (new) = 1;
!       MEM_ALIAS_SET (new) = ix86_GOT_alias_set ();
! 
!       if (reg == 0)
! 	reg = gen_reg_rtx (Pmode);
!       emit_move_insn (reg, new);
!       new = reg;
      }
    else
      {
--- 4330,4392 ----
  	  && (CONSTANT_POOL_ADDRESS_P (addr)
  	      || SYMBOL_REF_FLAG (addr))))
      {
!       /* In 64bit mode we can address such objects directly.  */
!       if (TARGET_64BIT)
! 	new = addr;
!       else
! 	{
! 	  /* This symbol may be referenced via a displacement from the PIC
! 	     base address (@GOTOFF).  */
  
! 	  current_function_uses_pic_offset_table = 1;
! 	  new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 7);
! 	  new = gen_rtx_CONST (Pmode, new);
! 	  new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
  
! 	  if (reg != 0)
! 	    {
! 	      emit_move_insn (reg, new);
! 	      new = reg;
! 	    }
  	}
      }
    else if (GET_CODE (addr) == SYMBOL_REF)
      {
!       if (TARGET_64BIT)
! 	{
! 	  current_function_uses_pic_offset_table = 1;
! 	  new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 15);
! 	  new = gen_rtx_CONST (Pmode, new);
! 	  new = gen_rtx_MEM (Pmode, new);
! 	  RTX_UNCHANGING_P (new) = 1;
! 	  MEM_ALIAS_SET (new) = ix86_GOT_alias_set ();
! 
! 	  if (reg == 0)
! 	    reg = gen_reg_rtx (Pmode);
! 	  /* Use directly gen_movsi, otherwise the address is loaded
! 	     into register for CSE.  We don't want to CSE this addresses,
! 	     instead we CSE addresses from the GOT table, so skip this.  */
! 	  emit_insn (gen_movsi (reg, new));
! 	  new = reg;
! 	}
!       else
! 	{
! 	  /* This symbol must be referenced via a load from the
! 	     Global Offset Table (@GOT).  */
! 
! 	  current_function_uses_pic_offset_table = 1;
! 	  new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 6);
! 	  new = gen_rtx_CONST (Pmode, new);
! 	  new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
! 	  new = gen_rtx_MEM (Pmode, new);
! 	  RTX_UNCHANGING_P (new) = 1;
! 	  MEM_ALIAS_SET (new) = ix86_GOT_alias_set ();
  
! 	  if (reg == 0)
! 	    reg = gen_reg_rtx (Pmode);
! 	  emit_move_insn (reg, new);
! 	  new = reg;
! 	}
      }
    else
      {
*************** legitimize_pic_address (orig, reg)
*** 3299,3314 ****
  		       || SYMBOL_REF_FLAG (op0))))
  	      && GET_CODE (op1) == CONST_INT)
  	    {
! 	      current_function_uses_pic_offset_table = 1;
! 	      new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), 7);
! 	      new = gen_rtx_PLUS (Pmode, new, op1);
! 	      new = gen_rtx_CONST (Pmode, new);
! 	      new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
  
! 	      if (reg != 0)
  		{
! 		  emit_move_insn (reg, new);
! 		  new = reg;
  		}
  	    }
  	  else
--- 4412,4434 ----
  		       || SYMBOL_REF_FLAG (op0))))
  	      && GET_CODE (op1) == CONST_INT)
  	    {
! 	      if (!TARGET_64BIT)
! 		{
! 		  current_function_uses_pic_offset_table = 1;
! 		  new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), 7);
! 		  new = gen_rtx_PLUS (Pmode, new, op1);
! 		  new = gen_rtx_CONST (Pmode, new);
! 		  new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
  
! 		  if (reg != 0)
! 		    {
! 		      emit_move_insn (reg, new);
! 		      new = reg;
! 		    }
! 		}
! 	      else
  		{
! 		  /* ??? We need to limit offsets here.  */
  		}
  	    }
  	  else
*************** output_pic_addr_const (file, x, code)
*** 3623,3628 ****
--- 4743,4751 ----
  	case 8:
  	  fputs ("@PLT", file);
  	  break;
+ 	case 15:
+ 	  fputs ("@GOTPCREL(%RIP)", file);
+ 	  break;
  	default:
  	  output_operand_lossage ("invalid UNSPEC as operand");
  	  break;
*************** i386_simplify_dwarf_addr (orig_x)
*** 3660,3665 ****
--- 4789,4803 ----
  {
    rtx x = orig_x;
  
+   if (TARGET_64BIT)
+     {
+       if (GET_CODE (x) != CONST
+ 	  || GET_CODE (XEXP (x, 0)) != UNSPEC
+ 	  || XINT (XEXP (x, 0), 1) != 15)
+ 	return orig_x;
+       return XVECEXP (XEXP (x, 0), 0, 0);
+     }
+ 
    if (GET_CODE (x) != PLUS
        || GET_CODE (XEXP (x, 0)) != REG
        || GET_CODE (XEXP (x, 1)) != CONST)


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