diff mbox

[TILE-Gx,committed] support -mcmodel=MODEL

Message ID 201208280530.q7S5UjYM009831@farm-0038.internal.tilera.com
State New
Headers show

Commit Message

Walter Lee Aug. 28, 2012, 5:30 a.m. UTC
This patch adds support for the -mcmodel=MODEL flag on TILE-Gx.  The
models supported are small and large.  In the small model (default),
distance for direct calls is limited to 500M in either direction.
PC-relative addresses are 32 bits.  Absolute addresses support the
full address range.  In the large model, there is no limiation on call
distance, pc-relative addresses, or absolute addresses.

	* doc/invoke.texi: Document -mcmodel=small, -mcmodel=large.
	* config/tilegx/tilegx.h: Include config/tilegx/tilegx-opts.h.
	(CRT_CALL_STATIC_FUNCTION): Define.
	* config/tilegx/predicates.md (const_last_symbolic_operand):
	Handle UNSPEC_HW2_LAST_PCREL, UNSPEC_HW1_LAST_PLT_PCREL, and
	UNSPEC_HW2_LAST_PLT_PCREL.
	(const_symbolic_operand): Handle UNSPEC_HW1_PCREL,
	UNSPEC_HW0_PLT_PCREL, and UNSPEC_HW1_PLT_PCREL.
	* config/tilegx/tilegx.md (UNSPEC_MOV_LARGE_PCREL_STEP4): Define,
	and renumber the constants that follow.
	(UNSPEC_HW1_PCREL): Ditto.
	(UNSPEC_HW2_LAST_PCREL): Ditto.
	(UNSPEC_HW0_PLT_PCREL): Define.
	(UNSPEC_HW1_PLT_PCREL): Define.
	(UNSPEC_HW1_LAST_PLT_PCREL): Define.
	(UNSPEC_HW2_LAST_PLT_PCREL): Define.
	(mov_large_pcrel_step1): Define.
	(mov_large_pcrel_step2): Define.
	(mov_large_pcrel_step3): Define.
	(mov_large_pcrel_step4): Define.
	(mov_plt_pcrel_step1): Define.
	(mov_plt_pcrel_step2): Define.
	(mov_plt_pcrel_step3): Define.
	(mov_plt_pcrel_step1_32bit): Define.
	(mov_plt_pcrel_step2_32bit): Define.
	(call): Handle tilegx_cmodel == CM_LARGE, CM_LARGE_PIC.
	(call_value): Ditto.
	* config/tilegx/tilegx.opt: Include config/tilegx/tilegx-opts.h.
	(mcmodel): New option.
	(enum cmodel): Define.
	(CM_SMALL): Define.
	(CM_LARGE): Define.
	* config/tilegx/tilegx-opts.h: New file.
	* config/tilegx/tilegx-protos.h (tilegx_compute_pcrel_address):
	Declare.
	(tilegx_compute_pcrel_plt_address): Declare.
	* config/tilegx/tilegx.c (tilegx_option_override): Handle
	tilegx_cmodel.
	(tilegx_function_ok_for_sibcall): Ditto.
	(compute_pcrel_address): Rename to tilegx_compute_pcrel_address,
	and don't declare static.  Handle tilegx_cmodel.
	(tilegx_compute_pcrel_plt_address): Define.
	(tilegx_legitimize_pic_address): Rename calls to
	compute_pcrel_address.
	(tilegx_delegitimize_address): Handle UNSPEC_HW1_PCREL,
	UNSPEC_HW2_LAST_PCREL, UNSPEC_HW0_PLT_PCREL, UNSPEC_HW1_PLT_PCREL,
	UNSPEC_HW1_LAST_PLT_PCREL, UNSPEC_HW2_LAST_PLT_PCREL.
	(load_pic_register): Rename call to compute_pcrel_address.
	(tilegx_print_operand): Handle UNSPEC_HW1_PCREL,
	UNSPEC_HW2_LAST_PCREL, UNSPEC_HW0_PLT_PCREL, UNSPEC_HW1_PLT_PCREL,
	UNSPEC_HW1_LAST_PLT_PCREL, UNSPEC_HW2_LAST_PLT_PCREL.

Comments

Gerald Pfeifer Sept. 1, 2012, 11:33 a.m. UTC | #1
On Tue, 28 Aug 2012, Walter Lee wrote:
> This patch adds support for the -mcmodel=MODEL flag on TILE-Gx.

At which point I cannot help asking for an update to the
release notes at http://gcc.gnu.org/gcc-4.8/changes.html. ;-)

Let me know if you need help with that.

> Index: gcc/doc/invoke.texi
> ===================================================================
>  @emph{TILE-Gx Options}
> -@gccoptlist{-mcpu=CPU -m32 -m64}
> +@gccoptlist{-mcpu=CPU -m32 -m64 -mcmodel=@var{code-model}}

Not added by this change, but should CPU be @var{CPU} here?

>  @emph{TILEPro Options}
>  @gccoptlist{-mcpu=CPU -m32}

Why are only -mcpu and -m32 listed here?

> +Generate code for the small model.  Distance for direct calls is

"The distance..."?

> +@item -mcmodel=large
> +@opindex mcmodel=large
> +Generate code for the large model.  There is no limiation on call

"limitation"

Gerald
diff mbox

Patch

Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 190736)
+++ gcc/doc/invoke.texi	(working copy)
@@ -929,7 +929,7 @@  See RS/6000 and PowerPC Options.
 @gccoptlist{-Qy  -Qn  -YP,@var{paths}  -Ym,@var{dir}}
 
 @emph{TILE-Gx Options}
-@gccoptlist{-mcpu=CPU -m32 -m64}
+@gccoptlist{-mcpu=CPU -m32 -m64 -mcmodel=@var{code-model}}
 
 @emph{TILEPro Options}
 @gccoptlist{-mcpu=CPU -m32}
@@ -18937,6 +18937,17 @@  The assembler uses this option.
 These @samp{-m} options are supported on the TILE-Gx:
 
 @table @gcctabopt
+@item -mcmodel=small
+@opindex mcmodel=small
+Generate code for the small model.  Distance for direct calls is
+limited to 500M in either direction.  PC-relative addresses are 32
+bits.  Absolute addresses support the full address range.
+
+@item -mcmodel=large
+@opindex mcmodel=large
+Generate code for the large model.  There is no limiation on call
+distance, pc-relative addresses, or absolute addresses.
+
 @item -mcpu=@var{name}
 @opindex mcpu
 Selects the type of CPU to be targeted.  Currently the only supported
Index: gcc/config/tilegx/tilegx.h
===================================================================
--- gcc/config/tilegx/tilegx.h	(revision 190736)
+++ gcc/config/tilegx/tilegx.h	(working copy)
@@ -31,6 +31,8 @@ 
     }						\
   while (0)
 
+#include "config/tilegx/tilegx-opts.h"
+
 
 /* Target CPU builtins.  */
 #define TARGET_CPU_CPP_BUILTINS() \
@@ -480,6 +482,19 @@  enum reg_class
     assemble_name ((FILE), (NAME)),			\
     fprintf ((FILE), ",%u\n", (unsigned int)(ROUNDED)))
 
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC)		\
+static void __attribute__((__used__))				\
+call_ ## FUNC (void)						\
+{								\
+  asm (SECTION_OP);						\
+  asm ("{ moveli r0, hw2_last(" #FUNC " - . - 8); lnk r1 }\n");	\
+  asm ("shl16insli r0, r0, hw1(" #FUNC " - .)\n");		\
+  asm ("shl16insli r0, r0, hw0(" #FUNC " - . + 8)\n");		\
+  asm ("add r0, r1, r0\n");					\
+  asm ("jalr r0\n");						\
+  asm (TEXT_SECTION_ASM_OP);					\
+}
+
 
 
 #define INIT_EXPANDERS tilegx_init_expanders ()
Index: gcc/config/tilegx/predicates.md
===================================================================
--- gcc/config/tilegx/predicates.md	(revision 190736)
+++ gcc/config/tilegx/predicates.md	(working copy)
@@ -80,11 +80,14 @@ 
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW1_LAST")
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW2_LAST")
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW1_LAST_PCREL")
+	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW2_LAST_PCREL")
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW0_LAST_GOT")
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW1_LAST_GOT")
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW1_LAST_TLS_GD")
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW1_LAST_TLS_IE")
-	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW1_LAST_TLS_LE"))))
+	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW1_LAST_TLS_LE")
+	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW1_LAST_PLT_PCREL")
+	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW2_LAST_PLT_PCREL"))))
 
 ;; Returns 1 if OP is an unspec wrapper for a symbol, got, or tls
 ;; reference.
@@ -96,10 +99,13 @@ 
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW2")
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW3")
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW0_PCREL")
+	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW1_PCREL")
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW0_GOT")
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW0_TLS_GD")
 	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW0_TLS_IE")
-	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW0_TLS_LE"))))
+	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW0_TLS_LE")
+	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW0_PLT_PCREL")
+	    (match_test "XINT (XEXP (op,0), 1) == UNSPEC_HW1_PLT_PCREL"))))
 
 ;; Return 1 if OP is a 8-element vector constant with identical signed
 ;; 8-bit elements or any register.
Index: gcc/config/tilegx/tilegx.md
===================================================================
--- gcc/config/tilegx/tilegx.md	(revision 190736)
+++ gcc/config/tilegx/tilegx.md	(working copy)
@@ -150,42 +150,43 @@ 
 
   ;; Insns generating difference of two labels
   (UNSPEC_MOV_PCREL_STEP3              204)
+  (UNSPEC_MOV_LARGE_PCREL_STEP4        205)
 
   ;; Latency specifying loads.
-  (UNSPEC_LATENCY_L2                   205)
-  (UNSPEC_LATENCY_MISS                 206)
+  (UNSPEC_LATENCY_L2                   206)
+  (UNSPEC_LATENCY_MISS                 207)
 
   ;; A pseudo-op that prevents network operations from being ordered.
-  (UNSPEC_NETWORK_BARRIER              207)
+  (UNSPEC_NETWORK_BARRIER              208)
 
   ;; Operations that access network registers.
-  (UNSPEC_NETWORK_RECEIVE              208)
-  (UNSPEC_NETWORK_SEND                 209)
+  (UNSPEC_NETWORK_RECEIVE              209)
+  (UNSPEC_NETWORK_SEND                 210)
 
   ;; Stack protector operations
-  (UNSPEC_SP_SET                       210)
-  (UNSPEC_SP_TEST                      211)
+  (UNSPEC_SP_SET                       211)
+  (UNSPEC_SP_TEST                      212)
 
   ;; This is used to move a value to a SPR.
-  (UNSPEC_SPR_MOVE                     212)
+  (UNSPEC_SPR_MOVE                     213)
 
   ;; A call to __tls_get_addr
-  (UNSPEC_TLS_GD_CALL                  213)
+  (UNSPEC_TLS_GD_CALL                  214)
 
   ;; An opaque TLS "add" operation for TLS general dynamic model
   ;; access.
-  (UNSPEC_TLS_GD_ADD                   214)
+  (UNSPEC_TLS_GD_ADD                   215)
 
   ;; An opaque TLS "load" operation for TLS initial exec model access.
-  (UNSPEC_TLS_IE_LOAD                  215)
+  (UNSPEC_TLS_IE_LOAD                  216)
 
   ;; An opaque TLS "add" operation for TLS access.
-  (UNSPEC_TLS_ADD                      216)
+  (UNSPEC_TLS_ADD                      217)
 
   ;; Atomics
-  (UNSPEC_ATOMIC                       217)
-  (UNSPEC_CMPXCHG                      218)
-  (UNSPEC_XCHG                         219)
+  (UNSPEC_ATOMIC                       218)
+  (UNSPEC_CMPXCHG                      219)
+  (UNSPEC_XCHG                         220)
 
   ;;
   ;; The following are operands.
@@ -199,24 +200,32 @@ 
   (UNSPEC_HW2_LAST                     306)
 
   (UNSPEC_HW0_PCREL                    307)
-  (UNSPEC_HW1_LAST_PCREL               308)
+  (UNSPEC_HW1_PCREL                    308)
+  (UNSPEC_HW1_LAST_PCREL               309)
+  (UNSPEC_HW2_LAST_PCREL               310)
 
-  (UNSPEC_HW0_GOT                      309)
-  (UNSPEC_HW0_LAST_GOT                 310)
-  (UNSPEC_HW1_LAST_GOT                 311)
+  (UNSPEC_HW0_GOT                      311)
+  (UNSPEC_HW0_LAST_GOT                 312)
+  (UNSPEC_HW1_LAST_GOT                 313)
 
-  (UNSPEC_HW0_TLS_GD                   312)
-  (UNSPEC_HW1_LAST_TLS_GD              313)
+  (UNSPEC_HW0_TLS_GD                   314)
+  (UNSPEC_HW1_LAST_TLS_GD              315)
 
-  (UNSPEC_HW0_TLS_IE                   314)
-  (UNSPEC_HW1_LAST_TLS_IE              315)
+  (UNSPEC_HW0_TLS_IE                   316)
+  (UNSPEC_HW1_LAST_TLS_IE              317)
 
-  (UNSPEC_HW0_TLS_LE                   316)
-  (UNSPEC_HW1_LAST_TLS_LE              317)
+  (UNSPEC_HW0_TLS_LE                   318)
+  (UNSPEC_HW1_LAST_TLS_LE              319)
+
+  (UNSPEC_HW0_PLT_PCREL                320)
+  (UNSPEC_HW1_PLT_PCREL                321)
+
+  (UNSPEC_HW1_LAST_PLT_PCREL           322)
+  (UNSPEC_HW2_LAST_PLT_PCREL           323)
 
   ;; This is used to wrap around the addresses of non-temporal load/store
   ;; intrinsics.
-  (UNSPEC_NON_TEMPORAL                 318)
+  (UNSPEC_NON_TEMPORAL                 324)
 ])
 
 ;; Mark the last instruction of various latencies, used to
@@ -885,15 +894,15 @@ 
 ;; Addresses
 ;;
 
-;; First step of the 3-insn sequence to materialize a symbolic
-;; address.
+;; The next three patterns are used to to materialize a position
+;; independent address by adding the difference of two labels to a base
+;; label in the text segment, assuming that the difference fits in 32
+;; signed bits.
 (define_expand "mov_address_step1"
   [(set (match_operand:DI 0 "register_operand" "")
 	(const:DI (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
 			     UNSPEC_HW2_LAST)))])
   
-;; Second step of the 3-insn sequence to materialize a symbolic
-;; address.
 (define_expand "mov_address_step2"
   [(set (match_operand:DI 0 "register_operand" "")
 	(unspec:DI
@@ -902,8 +911,6 @@ 
 			       UNSPEC_HW1))]
 	 UNSPEC_INSN_ADDR_SHL16INSLI))])
   
-;; Third step of the 3-insn sequence to materialize a symbolic
-;; address.
 (define_expand "mov_address_step3"
   [(set (match_operand:DI 0 "register_operand" "")
 	(unspec:DI
@@ -988,6 +995,106 @@ 
   "flag_pic"
   "add<x>\t%0, %r1, %r2")
 
+;; The next three patterns are used to to materialize a position
+;; independent 64-bit address by adding the difference of two labels to
+;; a base label in the text segment, without any limitation on the size
+;; of the difference.
+(define_expand "mov_large_pcrel_step1"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(const:DI (unspec:DI
+		   [(match_operand:DI 1 "symbolic_operand" "")
+		    (match_operand:DI 2 "symbolic_operand" "")]
+		   UNSPEC_HW2_LAST_PCREL)))]
+  "flag_pic")
+  
+(define_expand "mov_large_pcrel_step2"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(unspec:DI
+	 [(match_operand:DI 1 "reg_or_0_operand" "")
+	  (const:DI
+	   (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")
+		       (match_operand:DI 3 "symbolic_operand" "")]
+		      UNSPEC_HW1_PCREL))]
+	 UNSPEC_INSN_ADDR_SHL16INSLI))]
+  "flag_pic")
+
+;; Note: step 3 is same as move_pcrel_step2.
+(define_expand "mov_large_pcrel_step3"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(unspec:DI
+	 [(match_operand:DI 1 "reg_or_0_operand" "")
+	  (const:DI
+	   (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")
+		       (match_operand:DI 3 "symbolic_operand" "")]
+		      UNSPEC_HW0_PCREL))]
+	 UNSPEC_INSN_ADDR_SHL16INSLI))]
+  "flag_pic")
+
+(define_insn "mov_large_pcrel_step4"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+        (unspec:DI [(match_operand:DI 1 "reg_or_0_operand" "rO")
+		    (match_operand:DI 2 "reg_or_0_operand" "rO")
+			 (match_operand:DI 3 "symbolic_operand" "in")
+			 (match_operand:DI 4 "symbolic_operand" "in")]
+		   UNSPEC_MOV_LARGE_PCREL_STEP4))]
+  "flag_pic"
+  "add\t%0, %r1, %r2")
+
+;; The next three patterns are used to materialize a position
+;; independent 64-bit plt address by adding the difference of two
+;; labels to a base label in the text segment.
+(define_expand "mov_plt_pcrel_step1"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(const:DI (unspec:DI
+			[(match_operand:DI 1 "symbolic_operand" "")
+			 (match_operand:DI 2 "symbolic_operand" "")]
+                        UNSPEC_HW2_LAST_PLT_PCREL)))]
+  "flag_pic")
+  
+(define_expand "mov_plt_pcrel_step2"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(unspec:DI
+	 [(match_operand:DI 1 "reg_or_0_operand" "")
+	  (const:DI
+	   (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")
+			    (match_operand:DI 3 "symbolic_operand" "")]
+		      UNSPEC_HW1_PLT_PCREL))]
+	 UNSPEC_INSN_ADDR_SHL16INSLI))]
+  "flag_pic")
+
+(define_expand "mov_plt_pcrel_step3"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(unspec:DI
+	 [(match_operand:DI 1 "reg_or_0_operand" "")
+	  (const:DI
+	   (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")
+			    (match_operand:DI 3 "symbolic_operand" "")]
+		      UNSPEC_HW0_PLT_PCREL))]
+	 UNSPEC_INSN_ADDR_SHL16INSLI))]
+  "flag_pic")
+
+;; The next two patterns are used to materialize a position independent
+;; 32-bit plt address by adding the difference of two labels to a base
+;; label in the text segment.
+(define_expand "mov_plt_pcrel_step1_32bit"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(const:SI (unspec:SI
+			[(match_operand:SI 1 "symbolic_operand" "")
+			 (match_operand:SI 2 "symbolic_operand" "")]
+                        UNSPEC_HW1_LAST_PLT_PCREL)))]
+  "flag_pic")
+  
+(define_expand "mov_plt_pcrel_step2_32bit"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(unspec:SI
+	 [(match_operand:SI 1 "reg_or_0_operand" "")
+	  (const:SI
+	   (unspec:SI [(match_operand:SI 2 "symbolic_operand" "")
+			    (match_operand:SI 3 "symbolic_operand" "")]
+		      UNSPEC_HW0_PLT_PCREL))]
+	 UNSPEC_INSN_ADDR_SHL16INSLI))]
+  "flag_pic")
+
 (define_expand "add_got16<bitsuffix>"
   [(set (match_operand:I48MODE 0 "register_operand" "")
         (plus:I48MODE
@@ -2300,7 +2407,29 @@ 
               (use (reg:DI 54))
 	      (clobber (reg:DI 55))])]
   ""
-  "")
+{
+  rtx orig_addr = XEXP (operands[0], 0);
+  rtx addr;
+  if (GET_CODE (orig_addr) == SYMBOL_REF)
+    {
+      if (tilegx_cmodel == CM_LARGE)
+        {
+          addr = gen_reg_rtx (Pmode);
+          tilegx_expand_set_const64 (addr, orig_addr);
+          operands[0] = gen_rtx_MEM (DImode, addr);
+        }
+      else if (tilegx_cmodel == CM_LARGE_PIC)
+        {
+          crtl->uses_pic_offset_table = 1;
+          addr = gen_reg_rtx (Pmode);
+	  if (SYMBOL_REF_LOCAL_P (orig_addr))
+	    tilegx_compute_pcrel_address (addr, orig_addr);
+	  else
+	    tilegx_compute_pcrel_plt_address (addr, orig_addr);
+          operands[0] = gen_rtx_MEM (DImode, addr);
+        }
+    }
+})
 
 (define_insn "*call_insn"
   [(call (mem:DI (match_operand:I48MODE 0 "call_address_operand" "rO,i"))
@@ -2319,7 +2448,30 @@ 
 			 (match_operand 2 "" "")))
               (use (reg:DI 54))
 	      (clobber (reg:DI 55))])]
-  "")
+  ""
+{
+  rtx orig_addr = XEXP (operands[1], 0);
+  rtx addr;
+  if (GET_CODE (orig_addr) == SYMBOL_REF)
+    {
+      if (tilegx_cmodel == CM_LARGE)
+        {
+          addr = gen_reg_rtx (Pmode);
+          tilegx_expand_set_const64 (addr, orig_addr);
+          operands[1] = gen_rtx_MEM (DImode, addr);
+        }
+      else if (tilegx_cmodel == CM_LARGE_PIC)
+        {
+          crtl->uses_pic_offset_table = 1;
+          addr = gen_reg_rtx (Pmode);
+	  if (SYMBOL_REF_LOCAL_P (orig_addr))
+	    tilegx_compute_pcrel_address (addr, orig_addr);
+	  else
+	    tilegx_compute_pcrel_plt_address (addr, orig_addr);
+          operands[1] = gen_rtx_MEM (DImode, addr);
+        }
+      }
+})
 
 (define_insn "*call_value_insn"
   [(set (match_operand 0 "register_operand" "=r,r")
Index: gcc/config/tilegx/tilegx.opt
===================================================================
--- gcc/config/tilegx/tilegx.opt	(revision 190736)
+++ gcc/config/tilegx/tilegx.opt	(working copy)
@@ -19,6 +19,9 @@ 
 ; along with GCC; see the file COPYING3.  If not see
 ; <http://www.gnu.org/licenses/>.
 
+HeaderInclude
+config/tilegx/tilegx-opts.h
+
 mcpu=
 Target RejectNegative Joined Enum(tilegx_cpu) Var(tilegx_cpu) Init(0)
 -mcpu=CPU	Use features of and schedule code for given CPU
@@ -38,3 +41,16 @@  m64
 Target Report RejectNegative Negative(m32) InverseMask(32BIT, 64BIT)
 Compile with 64 bit longs and pointers.
 
+mcmodel=
+Target RejectNegative Joined Enum(cmodel) Var(tilegx_cmodel) Init(CM_SMALL)
+Use given TILE-Gx code model
+
+Enum
+Name(cmodel) Type(enum cmodel)
+Known code models (for use with the -mcmodel= option):
+
+EnumValue
+Enum(cmodel) String(small) Value(CM_SMALL)
+
+EnumValue
+Enum(cmodel) String(large) Value(CM_LARGE)
Index: gcc/config/tilegx/tilegx-opts.h
===================================================================
--- gcc/config/tilegx/tilegx-opts.h	(revision 0)
+++ gcc/config/tilegx/tilegx-opts.h	(revision 0)
@@ -0,0 +1,34 @@ 
+/* Definitions for option handling for TILE-Gx.
+   Copyright (C) 2012
+   Free Software Foundation, Inc.
+   Contributed by Walter Lee (walt@tilera.com)
+
+   This file is part of GCC.
+
+   GCC 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 3, or (at your
+   option) any later version.
+
+   GCC 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 GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef TILEGX_OPTS_H
+#define TILEGX_OPTS_H
+
+enum cmodel {
+  CM_SMALL,	/* Makes various assumpation about sizes of code and
+		   data fits.  */
+  CM_LARGE,	/* No assumptions.  */
+  CM_SMALL_PIC,	/* Makes various assumpation about sizes of code and
+		   data fits.  */
+  CM_LARGE_PIC	/* No assumptions.  */
+};
+
+#endif
Index: gcc/config/tilegx/tilegx-protos.h
===================================================================
--- gcc/config/tilegx/tilegx-protos.h	(revision 190736)
+++ gcc/config/tilegx/tilegx-protos.h	(working copy)
@@ -23,6 +23,8 @@ 
 #define GCC_TILEGX_PROTOS_H
 
 extern void tilegx_init_expanders (void);
+extern void tilegx_compute_pcrel_address (rtx, rtx);
+extern void tilegx_compute_pcrel_plt_address (rtx, rtx);
 extern bool tilegx_legitimate_pic_operand_p (rtx);
 extern rtx tilegx_simd_int (rtx, enum machine_mode);
 
Index: gcc/config/tilegx/tilegx.c
===================================================================
--- gcc/config/tilegx/tilegx.c	(revision 190736)
+++ gcc/config/tilegx/tilegx.c	(working copy)
@@ -67,6 +67,29 @@  static bool output_memory_autoinc_first;
 static void
 tilegx_option_override (void)
 {
+  if (global_options_set.x_tilegx_cmodel)
+    {
+      switch (tilegx_cmodel)
+	{
+	case CM_SMALL:
+	case CM_SMALL_PIC:
+	  if (flag_pic)
+	    tilegx_cmodel = CM_SMALL_PIC;
+	  break;
+
+	case CM_LARGE:
+	case CM_LARGE_PIC:
+	  if (flag_pic)
+	    tilegx_cmodel = CM_LARGE_PIC;
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+  else
+    tilegx_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
+
   /* When modulo scheduling is enabled, we still rely on regular
      scheduler for bundling.  */
   if (flag_modulo_sched)
@@ -119,7 +142,8 @@  tilegx_cannot_force_const_mem (enum mach
 static bool
 tilegx_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-  return decl != NULL;
+  return (tilegx_cmodel != CM_LARGE && tilegx_cmodel != CM_LARGE_PIC
+	  && (decl != NULL));
 }
 
 
@@ -1024,12 +1048,12 @@  tilegx_legitimize_tls_address (rtx addr)
 
 /* Returns a register that points to ADDR, a symbolic address, by
    computing its address relative to tilegx_text_label_symbol.  */
-static void
-compute_pcrel_address (rtx result, rtx addr)
+void
+tilegx_compute_pcrel_address (rtx result, rtx addr)
 {
   rtx text_label_symbol = tilegx_text_label_symbol ();
   rtx text_label_rtx = tilegx_text_label_rtx ();
-  rtx temp, temp2;
+  rtx temp, temp2, temp3;
 
   temp = create_temp_reg_if_possible (Pmode, result);
   temp2 = create_temp_reg_if_possible (Pmode, result);
@@ -1043,6 +1067,18 @@  compute_pcrel_address (rtx result, rtx a
 					    text_label_rtx,
 					    addr, text_label_symbol));
     }
+  else if (tilegx_cmodel == CM_LARGE_PIC)
+    {
+      temp3 = create_temp_reg_if_possible (Pmode, result);
+      emit_insn (gen_mov_large_pcrel_step1 (temp, addr, text_label_symbol));
+      emit_insn (gen_mov_large_pcrel_step2 (temp2, temp, addr,
+					    text_label_symbol));
+      emit_insn (gen_mov_large_pcrel_step3 (temp3, temp2, addr,
+					    text_label_symbol));
+      emit_insn (gen_mov_large_pcrel_step4 (result, temp3,
+					    text_label_rtx,
+					    addr, text_label_symbol));
+    }
   else
     {
       emit_insn (gen_mov_pcrel_step1 (temp, addr, text_label_symbol));
@@ -1054,6 +1090,41 @@  compute_pcrel_address (rtx result, rtx a
 }
 
 
+/* Returns a register that points to the plt entry of ADDR, a symbolic
+   address, by computing its address relative to
+   tilegx_text_label_symbol. */
+void
+tilegx_compute_pcrel_plt_address (rtx result, rtx addr)
+{
+  rtx text_label_symbol = tilegx_text_label_symbol ();
+  rtx text_label_rtx = tilegx_text_label_rtx ();
+  rtx temp, temp2, temp3;
+
+  temp = create_temp_reg_if_possible (Pmode, result);
+  temp2 = create_temp_reg_if_possible (Pmode, result);
+
+  if (TARGET_32BIT)
+    {
+      emit_insn (gen_mov_plt_pcrel_step1_32bit (temp, addr,
+						text_label_symbol));
+      emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2, temp, addr,
+						text_label_symbol));
+      emit_move_insn (result, gen_rtx_PLUS (Pmode, temp2, text_label_rtx));
+    }
+  else
+    {
+      temp3 = create_temp_reg_if_possible (Pmode, result);
+
+      emit_insn (gen_mov_plt_pcrel_step1 (temp, addr, text_label_symbol));
+      emit_insn (gen_mov_plt_pcrel_step2 (temp2, temp, addr,
+					  text_label_symbol));
+      emit_insn (gen_mov_plt_pcrel_step3 (temp3, temp2, addr,
+					  text_label_symbol));
+      emit_move_insn (result, gen_rtx_PLUS (Pmode, temp3, text_label_rtx));
+    }
+}
+
+
 /* Legitimize PIC addresses.  If the address is already
    position-independent, we return ORIG.  Newly generated
    position-independent addresses go into a reg.  This is REG if
@@ -1079,7 +1150,7 @@  tilegx_legitimize_pic_address (rtx orig,
 	     loading in the address, so that these instructions can be
 	     optimized properly.  */
 	  rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
-	  compute_pcrel_address (temp_reg, orig);
+	  tilegx_compute_pcrel_address (temp_reg, orig);
 
 	  /* Note: this is conservative.  We use the text_label but we
 	     don't use the pic_offset_table.  However, in some cases
@@ -1196,7 +1267,7 @@  tilegx_legitimize_pic_address (rtx orig,
          loading in the address, so that these instructions can be
          optimized properly.  */
       temp_reg = create_temp_reg_if_possible (Pmode, reg);
-      compute_pcrel_address (temp_reg, orig);
+      tilegx_compute_pcrel_address (temp_reg, orig);
 
       /* Note: this is conservative.  We use the text_label but we
          don't use the pic_offset_table.  */
@@ -1250,7 +1321,13 @@  tilegx_delegitimize_address (rtx x)
 	  case UNSPEC_HW1_LAST:
 	  case UNSPEC_HW2_LAST:
 	  case UNSPEC_HW0_PCREL:
+	  case UNSPEC_HW1_PCREL:
 	  case UNSPEC_HW1_LAST_PCREL:
+	  case UNSPEC_HW2_LAST_PCREL:
+	  case UNSPEC_HW0_PLT_PCREL:
+	  case UNSPEC_HW1_PLT_PCREL:
+	  case UNSPEC_HW1_LAST_PLT_PCREL:
+	  case UNSPEC_HW2_LAST_PLT_PCREL:
 	  case UNSPEC_HW0_GOT:
 	  case UNSPEC_HW0_LAST_GOT:
   	  case UNSPEC_HW1_LAST_GOT:
@@ -1290,7 +1367,7 @@  load_pic_register (bool delay_pic_helper
       emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol));
     }
 
-  compute_pcrel_address (tilegx_got_rtx (), got_symbol);
+  tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol);
 
   flag_pic = orig_flag_pic;
 
@@ -2577,7 +2654,7 @@  tilegx_expand_tablejump (rtx op0, rtx op
       rtx temp = gen_reg_rtx (Pmode);
       rtx temp2 = gen_reg_rtx (Pmode);
 
-      compute_pcrel_address (temp, gen_rtx_LABEL_REF (Pmode, op1));
+      tilegx_compute_pcrel_address (temp, gen_rtx_LABEL_REF (Pmode, op1));
       emit_move_insn (temp2,
 		      gen_rtx_PLUS (Pmode,
 				    convert_to_mode (Pmode, op0, false),
@@ -4961,6 +5038,7 @@  tilegx_print_operand (FILE *file, rtx x,
 	      opstr = "hw0";
 	      break;
 	    case UNSPEC_HW1:
+	    case UNSPEC_HW1_PCREL:
 	      opstr = "hw1";
 	      break;
 	    case UNSPEC_HW2:
@@ -4977,6 +5055,7 @@  tilegx_print_operand (FILE *file, rtx x,
 	      opstr = "hw1_last";
 	      break;
 	    case UNSPEC_HW2_LAST:
+	    case UNSPEC_HW2_LAST_PCREL:
 	      opstr = "hw2_last";
 	      break;
 	    case UNSPEC_HW0_GOT:
@@ -5006,6 +5085,18 @@  tilegx_print_operand (FILE *file, rtx x,
 	    case UNSPEC_HW1_LAST_TLS_LE:
 	      opstr = "hw1_last_tls_le";
 	      break;
+	    case UNSPEC_HW0_PLT_PCREL:
+	      opstr = "hw0_plt";
+	      break;
+	    case UNSPEC_HW1_PLT_PCREL:
+	      opstr = "hw1_plt";
+	      break;
+	    case UNSPEC_HW1_LAST_PLT_PCREL:
+	      opstr = "hw1_last_plt";
+	      break;
+	    case UNSPEC_HW2_LAST_PLT_PCREL:
+	      opstr = "hw2_last_plt";
+	      break;
 	    default:
 	      output_operand_lossage ("invalid %%H specifier");
 	    }
@@ -5015,7 +5106,13 @@  tilegx_print_operand (FILE *file, rtx x,
 	  output_addr_const (file, addr);
 
 	  if (unspec == UNSPEC_HW0_PCREL
-	      || unspec == UNSPEC_HW1_LAST_PCREL)
+	      || unspec == UNSPEC_HW1_PCREL
+	      || unspec == UNSPEC_HW1_LAST_PCREL
+	      || unspec == UNSPEC_HW2_LAST_PCREL
+	      || unspec == UNSPEC_HW0_PLT_PCREL
+	      || unspec == UNSPEC_HW1_PLT_PCREL
+	      || unspec == UNSPEC_HW1_LAST_PLT_PCREL
+	      || unspec == UNSPEC_HW2_LAST_PLT_PCREL)
 	    {
 	      rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
 	      fputs (" - " , file);