diff mbox

[i386,MPX,1/X] Support of Intel MPX ISA. 2/2 New registers and instructions

Message ID 20131024100605.GB30896@msticlxl57.ims.intel.com
State New
Headers show

Commit Message

Ilya Enkovich Oct. 24, 2013, 10:06 a.m. UTC
On 01 Oct 20:00, Uros Bizjak wrote:
> 
> This is OK for mainline, on the condition that target independent part
> is approved and committed first.
> 
> Thanks,
> Uros.

Thanks for review!

Attached is a version to be committed.  The only difference from the previous one is BOUND_MODE renamed to POINTER_BOUNDS_MODE due to changes in target independent part.  ChangeLog was not modified.

Ilya

Comments

Uros Bizjak Oct. 24, 2013, 11:17 a.m. UTC | #1
On Thu, Oct 24, 2013 at 12:06 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
> On 01 Oct 20:00, Uros Bizjak wrote:
>>
>> This is OK for mainline, on the condition that target independent part
>> is approved and committed first.
>>
>> Thanks,
>> Uros.
>
> Thanks for review!
>
> Attached is a version to be committed.  The only difference from the previous one is BOUND_MODE renamed to POINTER_BOUNDS_MODE due to changes in target independent part.  ChangeLog was not modified.

I think you missed a couple of length -> length_nobnd updates:

@@ -11635,7 +11680,12 @@
   [(simple_return)
    (unspec [(const_int 0)] UNSPEC_REP)]
   "reload_completed"
-  "rep%; ret"
+{
+  if (ix86_bnd_prefixed_insn_p (insn))
+    return "%!ret";
+
+  return "rep%; ret";
+}
   [(set_attr "length" "2")
    (set_attr "atom_unit" "jeu")
    (set_attr "length_immediate" "0")

and possibly here:

@@ -11186,7 +11231,7 @@
 (define_insn "*indirect_jump"
   [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))]
   ""
-  "jmp\t%A0"
+  "%!jmp\t%A0"
   [(set_attr "type" "ibr")
    (set_attr "length_immediate" "0")])

@@ -11235,7 +11280,7 @@
   [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))
    (use (label_ref (match_operand 1)))]
   ""
-  "jmp\t%A0"
+  "%!jmp\t%A0"
   [(set_attr "type" "ibr")
    (set_attr "length_immediate" "0")])

Uros.
Ilya Enkovich Oct. 24, 2013, 11:29 a.m. UTC | #2
2013/10/24 Uros Bizjak <ubizjak@gmail.com>:
> On Thu, Oct 24, 2013 at 12:06 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
>> On 01 Oct 20:00, Uros Bizjak wrote:
>>>
>>> This is OK for mainline, on the condition that target independent part
>>> is approved and committed first.
>>>
>>> Thanks,
>>> Uros.
>>
>> Thanks for review!
>>
>> Attached is a version to be committed.  The only difference from the previous one is BOUND_MODE renamed to POINTER_BOUNDS_MODE due to changes in target independent part.  ChangeLog was not modified.
>
> I think you missed a couple of length -> length_nobnd updates:
>
> @@ -11635,7 +11680,12 @@
>    [(simple_return)
>     (unspec [(const_int 0)] UNSPEC_REP)]
>    "reload_completed"
> -  "rep%; ret"
> +{
> +  if (ix86_bnd_prefixed_insn_p (insn))
> +    return "%!ret";
> +
> +  return "rep%; ret";
> +}
>    [(set_attr "length" "2")
>     (set_attr "atom_unit" "jeu")
>     (set_attr "length_immediate" "0")
>

There is no reason for length_nobnd because instruction length is
always 2. Difference is in prefix used for MPX and non-MPX code.

> and possibly here:
>
> @@ -11186,7 +11231,7 @@
>  (define_insn "*indirect_jump"
>    [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))]
>    ""
> -  "jmp\t%A0"
> +  "%!jmp\t%A0"
>    [(set_attr "type" "ibr")
>     (set_attr "length_immediate" "0")])
>
> @@ -11235,7 +11280,7 @@
>    [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))
>     (use (label_ref (match_operand 1)))]
>    ""
> -  "jmp\t%A0"
> +  "%!jmp\t%A0"
>    [(set_attr "type" "ibr")
>     (set_attr "length_immediate" "0")])

For these cases 'prefix_rep' attribute makes the work due to 'ibr'
type. Generic length should work fine.

Thanks,
Ilya

>
> Uros.
Uros Bizjak Oct. 24, 2013, 11:34 a.m. UTC | #3
On Thu, Oct 24, 2013 at 1:29 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:

>>>> This is OK for mainline, on the condition that target independent part
>>>> is approved and committed first.
>>>>
>>>> Thanks,
>>>> Uros.
>>>
>>> Thanks for review!
>>>
>>> Attached is a version to be committed.  The only difference from the previous one is BOUND_MODE renamed to POINTER_BOUNDS_MODE due to changes in target independent part.  ChangeLog was not modified.
>>
>> I think you missed a couple of length -> length_nobnd updates:
>>
>> @@ -11635,7 +11680,12 @@
>>    [(simple_return)
>>     (unspec [(const_int 0)] UNSPEC_REP)]
>>    "reload_completed"
>> -  "rep%; ret"
>> +{
>> +  if (ix86_bnd_prefixed_insn_p (insn))
>> +    return "%!ret";
>> +
>> +  return "rep%; ret";
>> +}
>>    [(set_attr "length" "2")
>>     (set_attr "atom_unit" "jeu")
>>     (set_attr "length_immediate" "0")
>>
>
> There is no reason for length_nobnd because instruction length is
> always 2. Difference is in prefix used for MPX and non-MPX code.
>
>> and possibly here:
>>
>> @@ -11186,7 +11231,7 @@
>>  (define_insn "*indirect_jump"
>>    [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))]
>>    ""
>> -  "jmp\t%A0"
>> +  "%!jmp\t%A0"
>>    [(set_attr "type" "ibr")
>>     (set_attr "length_immediate" "0")])
>>
>> @@ -11235,7 +11280,7 @@
>>    [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))
>>     (use (label_ref (match_operand 1)))]
>>    ""
>> -  "jmp\t%A0"
>> +  "%!jmp\t%A0"
>>    [(set_attr "type" "ibr")
>>     (set_attr "length_immediate" "0")])
>
> For these cases 'prefix_rep' attribute makes the work due to 'ibr'
> type. Generic length should work fine.

Indeed. Thanks for explanation!

Uros.
diff mbox

Patch

diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
index 92e0c05..ddfd402 100644
--- a/gcc/config/i386/constraints.md
+++ b/gcc/config/i386/constraints.md
@@ -18,7 +18,7 @@ 
 ;; <http://www.gnu.org/licenses/>.
 
 ;;; Unused letters:
-;;;     B     H           T
+;;;           H
 ;;;           h j
 
 ;; Integer register constraints.
@@ -91,6 +91,9 @@ 
 (define_register_constraint "x" "TARGET_SSE ? SSE_REGS : NO_REGS"
  "Any SSE register.")
 
+(define_register_constraint "B" "TARGET_MPX ? BND_REGS : NO_REGS"
+ "@internal Any bound register.")
+
 ;; We use the Y prefix to denote any number of conditional register sets:
 ;;  z	First SSE register.
 ;;  i	SSE2 inter-unit moves to SSE register enabled
@@ -232,3 +235,15 @@ 
    to fit that range (for immediate operands in zero-extending x86-64
    instructions)."
   (match_operand 0 "x86_64_zext_immediate_operand"))
+
+;; T prefix is used for different address constraints
+;;   i - address with no index and no rip
+;;   b - address with no base and no rip
+
+(define_address_constraint "Ti"
+  "MPX address operand without index"
+  (match_operand 0 "address_mpx_no_index_operand"))
+
+(define_address_constraint "Tb"
+  "MPX address operand without base"
+  (match_operand 0 "address_mpx_no_base_operand"))
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 2e764e7..da16240 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -358,6 +358,8 @@  ix86_target_macros_internal (HOST_WIDE_INT isa_flag,
     def_or_undef (parse_in, "__SSE_MATH__");
   if ((fpmath & FPMATH_SSE) && (isa_flag & OPTION_MASK_ISA_SSE2))
     def_or_undef (parse_in, "__SSE2_MATH__");
+  if (isa_flag & OPTION_MASK_ISA_MPX)
+    def_or_undef (parse_in, "__MPX__");
 }
 
 
diff --git a/gcc/config/i386/i386-modes.def b/gcc/config/i386/i386-modes.def
index e0b8fc8..a73730e 100644
--- a/gcc/config/i386/i386-modes.def
+++ b/gcc/config/i386/i386-modes.def
@@ -87,6 +87,9 @@  VECTOR_MODE (INT, DI, 1);     /*                   V1DI */
 VECTOR_MODE (INT, SI, 1);     /*                   V1SI */
 VECTOR_MODE (INT, QI, 2);     /*                   V2QI */
 
+POINTER_BOUNDS_MODE (BND32, 8);
+POINTER_BOUNDS_MODE (BND64, 16);
+
 INT_MODE (OI, 32);
 INT_MODE (XI, 64);
 
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 3ab2f3a..fdd98fc 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -239,6 +239,8 @@  extern void ix86_expand_mul_widen_hilo (rtx, rtx, rtx, bool, bool);
 extern void ix86_expand_sse2_mulv4si3 (rtx, rtx, rtx);
 extern void ix86_expand_sse2_mulvxdi3 (rtx, rtx, rtx);
 
+extern bool ix86_bnd_prefixed_insn_p (rtx);
+
 /* In i386-c.c  */
 extern void ix86_target_macros (void);
 extern void ix86_register_pragmas (void);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 21fc531..f973f84 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -1956,6 +1956,8 @@  enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER] =
   /* Mask registers.  */
   MASK_REGS, MASK_EVEX_REGS, MASK_EVEX_REGS, MASK_EVEX_REGS,
   MASK_EVEX_REGS, MASK_EVEX_REGS, MASK_EVEX_REGS, MASK_EVEX_REGS,
+  /* MPX bound registers */
+  BND_REGS, BND_REGS, BND_REGS, BND_REGS,
 };
 
 /* The "default" register map used in 32bit mode.  */
@@ -1972,6 +1974,7 @@  int const dbx_register_map[FIRST_PSEUDO_REGISTER] =
   -1, -1, -1, -1, -1, -1, -1, -1,       /* AVX-512 registers 16-23*/
   -1, -1, -1, -1, -1, -1, -1, -1,       /* AVX-512 registers 24-31*/
   93, 94, 95, 96, 97, 98, 99, 100,      /* Mask registers */
+  101, 102, 103, 104,			/* bound registers */
 };
 
 /* The "default" register map used in 64bit mode.  */
@@ -1988,6 +1991,7 @@  int const dbx64_register_map[FIRST_PSEUDO_REGISTER] =
   67, 68, 69, 70, 71, 72, 73, 74,       /* AVX-512 registers 16-23 */
   75, 76, 77, 78, 79, 80, 81, 82,       /* AVX-512 registers 24-31 */
   118, 119, 120, 121, 122, 123, 124, 125, /* Mask registers */
+  126, 127, 128, 129,			/* bound registers */
 };
 
 /* Define the register numbers to be used in Dwarf debugging information.
@@ -2056,6 +2060,7 @@  int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER] =
   -1, -1, -1, -1, -1, -1, -1, -1,       /* AVX-512 registers 16-23*/
   -1, -1, -1, -1, -1, -1, -1, -1,       /* AVX-512 registers 24-31*/
   93, 94, 95, 96, 97, 98, 99, 100,      /* Mask registers */
+  -1, -1, -1, -1,                       /* bound registers */
 };
 
 /* Define parameter passing and return registers.  */
@@ -2478,6 +2483,7 @@  ix86_target_string (HOST_WIDE_INT isa, int flags, const char *arch,
     { "-mrtm",		OPTION_MASK_ISA_RTM },
     { "-mxsave",	OPTION_MASK_ISA_XSAVE },
     { "-mxsaveopt",	OPTION_MASK_ISA_XSAVEOPT },
+    { "-mmpx",          OPTION_MASK_ISA_MPX },
   };
 
   /* Flag options.  */
@@ -2970,6 +2976,7 @@  ix86_option_override_internal (bool main_args_p)
 #define PTA_AVX512ER		(HOST_WIDE_INT_1 << 41)
 #define PTA_AVX512PF		(HOST_WIDE_INT_1 << 42)
 #define PTA_AVX512CD		(HOST_WIDE_INT_1 << 43)
+#define PTA_MPX			(HOST_WIDE_INT_1 << 44)
 
 /* if this reaches 64, need to widen struct pta flags below */
 
@@ -3500,12 +3507,18 @@  ix86_option_override_internal (bool main_args_p)
 	if (processor_alias_table[i].flags & PTA_AVX512CD
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX512CD))
 	  ix86_isa_flags |= OPTION_MASK_ISA_AVX512CD;
+        if (processor_alias_table[i].flags & PTA_MPX
+            && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_MPX))
+          ix86_isa_flags |= OPTION_MASK_ISA_MPX;
 	if (processor_alias_table[i].flags & (PTA_PREFETCH_SSE | PTA_SSE))
 	  x86_prefetch_sse = true;
 
 	break;
       }
 
+  if (TARGET_X32 && (ix86_isa_flags & OPTION_MASK_ISA_MPX))
+    error ("Intel MPX does not support x32");
+
   if (!strcmp (ix86_arch_string, "generic"))
     error ("generic CPU can be used only for %stune=%s %s",
 	   prefix, suffix, sw);
@@ -4134,6 +4147,11 @@  ix86_conditional_register_usage (void)
       for (i = FIRST_MASK_REG; i <= LAST_MASK_REG; i++)
 	fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
     }
+
+  /* If MPX is disabled, squash the registers.  */
+  if (! TARGET_MPX)
+    for (i = FIRST_BND_REG; i <= LAST_BND_REG; i++)
+      fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
 }
 
 
@@ -8835,7 +8853,7 @@  ix86_code_end (void)
       xops[0] = gen_rtx_REG (Pmode, regno);
       xops[1] = gen_rtx_MEM (Pmode, stack_pointer_rtx);
       output_asm_insn ("mov%z0\t{%1, %0|%0, %1}", xops);
-      fputs ("\tret\n", asm_out_file);
+      output_asm_insn ("%!ret", NULL);
       final_end_function ();
       init_insn_lengths ();
       free_after_compilation (cfun);
@@ -8893,7 +8911,7 @@  output_set_got (rtx dest, rtx label)
 
       xops[2] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
       xops[2] = gen_rtx_MEM (QImode, xops[2]);
-      output_asm_insn ("call\t%X2", xops);
+      output_asm_insn ("%!call\t%X2", xops);
 
 #if TARGET_MACHO
       /* Output the Mach-O "canonical" pic base label name ("Lxx$pb") here.
@@ -14244,7 +14262,7 @@  print_reg (rtx x, int code, FILE *file)
     case 8:
     case 4:
     case 12:
-      if (! ANY_FP_REG_P (x))
+      if (! ANY_FP_REG_P (x) &&  ! ANY_BND_REG_P (x))
 	putc (code == 8 && TARGET_64BIT ? 'r' : 'e', file);
       /* FALLTHRU */
     case 16:
@@ -14367,6 +14385,7 @@  get_some_local_dynamic_name (void)
    ~ -- print "i" if TARGET_AVX2, "f" otherwise.
    @ -- print a segment register of thread base pointer load
    ^ -- print addr32 prefix if TARGET_64BIT and Pmode != word_mode
+   ! -- print MPX prefix for jxx/call/ret instructions if required.
  */
 
 void
@@ -14861,6 +14880,11 @@  ix86_print_operand (FILE *file, rtx x, int code)
 	    fputs ("addr32 ", file);
 	  return;
 
+	case '!':
+	  if (ix86_bnd_prefixed_insn_p (NULL_RTX))
+	    fputs ("bnd ", file);
+	  return;
+
 	default:
 	    output_operand_lossage ("invalid operand code '%c'", code);
 	}
@@ -15003,7 +15027,7 @@  static bool
 ix86_print_operand_punct_valid_p (unsigned char code)
 {
   return (code == '@' || code == '*' || code == '+' || code == '&'
-	  || code == ';' || code == '~' || code == '^');
+	  || code == ';' || code == '~' || code == '^' || code == '!');
 }
 
 /* Print a memory operand whose address is ADDR.  */
@@ -15033,6 +15057,25 @@  ix86_print_operand_address (FILE *file, rtx addr)
       ok = ix86_decompose_address (XVECEXP (addr, 0, 0), &parts);
       code = 'q';
     }
+  else if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_BNDMK_ADDR)
+    {
+      ok = ix86_decompose_address (XVECEXP (addr, 0, 1), &parts);
+      gcc_assert (parts.base == NULL_RTX || parts.index == NULL_RTX);
+      if (parts.base != NULL_RTX)
+	{
+	  parts.index = parts.base;
+	  parts.scale = 1;
+	}
+      parts.base = XVECEXP (addr, 0, 0);
+      addr = XVECEXP (addr, 0, 0);
+    }
+  else if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_BNDLDX_ADDR)
+    {
+      ok = ix86_decompose_address (XVECEXP (addr, 0, 0), &parts);
+      gcc_assert (parts.index == NULL_RTX);
+      parts.index = XVECEXP (addr, 0, 1);
+      addr = XVECEXP (addr, 0, 0);
+    }
   else
     ok = ix86_decompose_address (addr, &parts);
 
@@ -24056,13 +24099,13 @@  ix86_output_call_insn (rtx insn, rtx call_op)
   if (SIBLING_CALL_P (insn))
     {
       if (direct_p)
-	xasm = "jmp\t%P0";
+	xasm = "%!jmp\t%P0";
       /* SEH epilogue detection requires the indirect branch case
 	 to include REX.W.  */
       else if (TARGET_SEH)
-	xasm = "rex.W jmp %A0";
+	xasm = "%!rex.W jmp %A0";
       else
-	xasm = "jmp\t%A0";
+	xasm = "%!jmp\t%A0";
 
       output_asm_insn (xasm, &call_op);
       return "";
@@ -24099,9 +24142,9 @@  ix86_output_call_insn (rtx insn, rtx call_op)
     }
 
   if (direct_p)
-    xasm = "call\t%P0";
+    xasm = "%!call\t%P0";
   else
-    xasm = "call\t%A0";
+    xasm = "%!call\t%A0";
 
   output_asm_insn (xasm, &call_op);
 
@@ -34061,6 +34104,7 @@  ix86_class_likely_spilled_p (reg_class_t rclass)
       case SSE_FIRST_REG:
       case FP_TOP_REG:
       case FP_SECOND_REG:
+      case BND_REGS:
 	return true;
 
       default:
@@ -34409,6 +34453,8 @@  ix86_hard_regno_mode_ok (int regno, enum machine_mode mode)
     return VALID_FP_MODE_P (mode);
   if (MASK_REGNO_P (regno))
     return VALID_MASK_REG_MODE (mode);
+  if (BND_REGNO_P (regno))
+    return VALID_BND_REG_MODE (mode);
   if (SSE_REGNO_P (regno))
     {
       /* We implement the move patterns for all vector modes into and
@@ -35222,6 +35268,10 @@  x86_order_regs_for_local_alloc (void)
    for (i = FIRST_MASK_REG; i <= LAST_MASK_REG; i++)
      reg_alloc_order [pos++] = i;
 
+   /* MPX bound registers.  */
+   for (i = FIRST_BND_REG; i <= LAST_BND_REG; i++)
+     reg_alloc_order [pos++] = i;
+
    /* x87 registers.  */
    if (TARGET_SSE_MATH)
      for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
@@ -41654,6 +41704,18 @@  ix86_expand_sse2_mulvxdi3 (rtx op0, rtx op1, rtx op2)
 		       gen_rtx_MULT (mode, op1, op2));
 }
 
+/* Return 1 if control tansfer instruction INSN
+   should be encoded with bnd prefix.
+   If insn is NULL then return 1 when control
+   transfer instructions should be prefixed with
+   bnd by default for current function.  */
+
+bool
+ix86_bnd_prefixed_insn_p (rtx insn ATTRIBUTE_UNUSED)
+{
+  return false;
+}
+
 /* Expand an insert into a vector register through pinsr insn.
    Return true if successful.  */
 
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 440844e..87a703d 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -84,6 +84,7 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define TARGET_FXSR	TARGET_ISA_FXSR
 #define TARGET_XSAVE	TARGET_ISA_XSAVE
 #define TARGET_XSAVEOPT	TARGET_ISA_XSAVEOPT
+#define TARGET_MPX      TARGET_ISA_MPX
 
 #define TARGET_LP64	TARGET_ABI_64
 #define TARGET_X32	TARGET_ABI_X32
@@ -891,7 +892,7 @@  enum target_cpu_default
    eliminated during reloading in favor of either the stack or frame
    pointer.  */
 
-#define FIRST_PSEUDO_REGISTER 77
+#define FIRST_PSEUDO_REGISTER 81
 
 /* Number of hardware registers that go into the DWARF-2 unwind info.
    If not defined, equals FIRST_PSEUDO_REGISTER.  */
@@ -923,7 +924,9 @@  enum target_cpu_default
 /*xmm24,xmm25,xmm26,xmm27,xmm28,xmm29,xmm30,xmm31*/		\
      0,   0,    0,    0,    0,    0,    0,    0,		\
 /*  k0,  k1, k2, k3, k4, k5, k6, k7*/				\
-     0,  0,   0,  0,  0,  0,  0,  0 }
+     0,  0,   0,  0,  0,  0,  0,  0,				\
+/*   b0, b1, b2, b3*/						\
+     0,  0,  0,  0 }
 
 /* 1 for registers not available across function calls.
    These must include the FIXED_REGISTERS and also any
@@ -957,7 +960,9 @@  enum target_cpu_default
 /*xmm24,xmm25,xmm26,xmm27,xmm28,xmm29,xmm30,xmm31*/		\
      6,    6,     6,    6,    6,    6,    6,    6,		\
  /* k0,  k1,  k2,  k3,  k4,  k5,  k6,  k7*/			\
-     1,   1,   1,   1,   1,   1,   1,   1 }
+     1,   1,   1,   1,   1,   1,   1,   1,			\
+/*   b0, b1, b2, b3*/						\
+     1,  1,  1,  1 }
 
 /* Order in which to allocate registers.  Each register must be
    listed once, even those in FIXED_REGISTERS.  List frame pointer
@@ -973,7 +978,8 @@  enum target_cpu_default
    18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,	\
    33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,  \
    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,	\
-   63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76 }
+   63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,  \
+   78, 79, 80 }
 
 /* ADJUST_REG_ALLOC_ORDER is a macro which permits reg_alloc_order
    to be rearranged based on a particular function.  When using sse math,
@@ -995,6 +1001,7 @@  enum target_cpu_default
 
 #define HARD_REGNO_NREGS(REGNO, MODE)					\
   (STACK_REGNO_P (REGNO) || SSE_REGNO_P (REGNO) || MMX_REGNO_P (REGNO)	\
+   || BND_REGNO_P (REGNO)						\
    ? (COMPLEX_MODE_P (MODE) ? 2 : 1)					\
    : ((MODE) == XFmode							\
       ? (TARGET_64BIT ? 2 : 3)						\
@@ -1044,6 +1051,9 @@  enum target_cpu_default
    || (MODE) == V2SImode || (MODE) == SImode				\
    || (MODE) == V4HImode || (MODE) == V8QImode)
 
+#define VALID_BND_REG_MODE(MODE) \
+  (TARGET_64BIT ? (MODE) == BND64mode : (MODE) == BND32mode)
+
 #define VALID_DFP_MODE_P(MODE) \
   ((MODE) == SDmode || (MODE) == DDmode || (MODE) == TDmode)
 
@@ -1150,6 +1160,9 @@  enum target_cpu_default
 #define FIRST_MASK_REG  (LAST_EXT_REX_SSE_REG + 1) /*69*/
 #define LAST_MASK_REG   (FIRST_MASK_REG + 7) /*76*/
 
+#define FIRST_BND_REG  (LAST_MASK_REG + 1) /*77*/
+#define LAST_BND_REG   (FIRST_BND_REG + 3) /*80*/
+
 /* Override this in other tm.h files to cope with various OS lossage
    requiring a frame pointer.  */
 #ifndef SUBTARGET_FRAME_POINTER_REQUIRED
@@ -1230,6 +1243,7 @@  enum reg_class
   SSE_FIRST_REG,
   SSE_REGS,
   EVEX_SSE_REGS,
+  BND_REGS,
   ALL_SSE_REGS,
   MMX_REGS,
   FP_TOP_SSE_REGS,
@@ -1287,6 +1301,7 @@  enum reg_class
    "SSE_FIRST_REG",			\
    "SSE_REGS",				\
    "EVEX_SSE_REGS",			\
+   "BND_REGS",				\
    "ALL_SSE_REGS",			\
    "MMX_REGS",				\
    "FP_TOP_SSE_REGS",			\
@@ -1306,37 +1321,38 @@  enum reg_class
    TARGET_CONDITIONAL_REGISTER_USAGE.  */
 
 #define REG_CLASS_CONTENTS                                              \
-{     { 0x00,       0x0,   0x0 },                                       \
-      { 0x01,       0x0,   0x0 },       /* AREG */                      \
-      { 0x02,       0x0,   0x0 },       /* DREG */                      \
-      { 0x04,       0x0,   0x0 },       /* CREG */                      \
-      { 0x08,       0x0,   0x0 },       /* BREG */                      \
-      { 0x10,       0x0,   0x0 },       /* SIREG */                     \
-      { 0x20,       0x0,   0x0 },       /* DIREG */                     \
-      { 0x03,       0x0,   0x0 },       /* AD_REGS */                   \
-      { 0x0f,       0x0,   0x0 },       /* Q_REGS */                    \
-  { 0x1100f0,    0x1fe0,   0x0 },       /* NON_Q_REGS */                \
-      { 0x7f,    0x1fe0,   0x0 },       /* INDEX_REGS */                \
-  { 0x1100ff,       0x0,   0x0 },       /* LEGACY_REGS */               \
-      { 0x07,       0x0,   0x0 },       /* CLOBBERED_REGS */            \
-  { 0x1100ff,    0x1fe0,   0x0 },       /* GENERAL_REGS */              \
-     { 0x100,       0x0,   0x0 },       /* FP_TOP_REG */                \
-    { 0x0200,       0x0,   0x0 },       /* FP_SECOND_REG */             \
-    { 0xff00,       0x0,   0x0 },       /* FLOAT_REGS */                \
-  { 0x200000,       0x0,   0x0 },       /* SSE_FIRST_REG */             \
-{ 0x1fe00000,  0x1fe000,   0x0 },       /* SSE_REGS */                  \
-       { 0x0,0xffe00000,  0x1f },       /* EVEX_SSE_REGS */             \
-{ 0x1fe00000,0xffffe000,  0x1f },       /* ALL_SSE_REGS */              \
-{ 0xe0000000,      0x1f,   0x0 },       /* MMX_REGS */                  \
-{ 0x1fe00100,0xffffe000,  0x1f },       /* FP_TOP_SSE_REG */            \
-{ 0x1fe00200,0xffffe000,  0x1f },       /* FP_SECOND_SSE_REG */         \
-{ 0x1fe0ff00,0xffffe000,  0x1f },       /* FLOAT_SSE_REGS */            \
-{   0x11ffff,    0x1fe0,   0x0 },       /* FLOAT_INT_REGS */            \
-{ 0x1ff100ff,0xffffffe0,  0x1f },       /* INT_SSE_REGS */              \
-{ 0x1ff1ffff,0xffffffe0,  0x1f },       /* FLOAT_INT_SSE_REGS */        \
-       { 0x0,       0x0,0x1fc0 },       /* MASK_EVEX_REGS */           \
-       { 0x0,       0x0,0x1fe0 },       /* MASK_REGS */                 \
-{ 0xffffffff,0xffffffff,0x1fff }                                        \
+{     { 0x00,       0x0,    0x0 },                                       \
+      { 0x01,       0x0,    0x0 },       /* AREG */                      \
+      { 0x02,       0x0,    0x0 },       /* DREG */                      \
+      { 0x04,       0x0,    0x0 },       /* CREG */                      \
+      { 0x08,       0x0,    0x0 },       /* BREG */                      \
+      { 0x10,       0x0,    0x0 },       /* SIREG */                     \
+      { 0x20,       0x0,    0x0 },       /* DIREG */                     \
+      { 0x03,       0x0,    0x0 },       /* AD_REGS */                   \
+      { 0x0f,       0x0,    0x0 },       /* Q_REGS */                    \
+  { 0x1100f0,    0x1fe0,    0x0 },       /* NON_Q_REGS */                \
+      { 0x7f,    0x1fe0,    0x0 },       /* INDEX_REGS */                \
+  { 0x1100ff,       0x0,    0x0 },       /* LEGACY_REGS */               \
+      { 0x07,       0x0,    0x0 },       /* CLOBBERED_REGS */            \
+  { 0x1100ff,    0x1fe0,    0x0 },       /* GENERAL_REGS */              \
+     { 0x100,       0x0,    0x0 },       /* FP_TOP_REG */                \
+    { 0x0200,       0x0,    0x0 },       /* FP_SECOND_REG */             \
+    { 0xff00,       0x0,    0x0 },       /* FLOAT_REGS */                \
+  { 0x200000,       0x0,    0x0 },       /* SSE_FIRST_REG */             \
+{ 0x1fe00000,  0x1fe000,    0x0 },       /* SSE_REGS */                  \
+       { 0x0,0xffe00000,   0x1f },       /* EVEX_SSE_REGS */             \
+       { 0x0,       0x0,0x1e000 },       /* BND_REGS */			 \
+{ 0x1fe00000,0xffffe000,   0x1f },       /* ALL_SSE_REGS */              \
+{ 0xe0000000,      0x1f,    0x0 },       /* MMX_REGS */                  \
+{ 0x1fe00100,0xffffe000,   0x1f },       /* FP_TOP_SSE_REG */            \
+{ 0x1fe00200,0xffffe000,   0x1f },       /* FP_SECOND_SSE_REG */         \
+{ 0x1fe0ff00,0xffffe000,   0x1f },       /* FLOAT_SSE_REGS */            \
+{   0x11ffff,    0x1fe0,    0x0 },       /* FLOAT_INT_REGS */            \
+{ 0x1ff100ff,0xffffffe0,   0x1f },       /* INT_SSE_REGS */              \
+{ 0x1ff1ffff,0xffffffe0,   0x1f },       /* FLOAT_INT_SSE_REGS */        \
+       { 0x0,       0x0, 0x1fc0 },       /* MASK_EVEX_REGS */           \
+       { 0x0,       0x0, 0x1fe0 },       /* MASK_REGS */                 \
+{ 0xffffffff,0xffffffff, 0x1fff }                                        \
 }
 
 /* The same information, inverted:
@@ -1412,6 +1428,9 @@  enum reg_class
 #define CC_REG_P(X) (REG_P (X) && CC_REGNO_P (REGNO (X)))
 #define CC_REGNO_P(X) ((X) == FLAGS_REG || (X) == FPSR_REG)
 
+#define BND_REGNO_P(N) IN_RANGE ((N), FIRST_BND_REG, LAST_BND_REG)
+#define ANY_BND_REG_P(X) (REG_P (X) && BND_REGNO_P (REGNO (X)))
+
 /* The class value for index registers, and the one for base regs.  */
 
 #define INDEX_REG_CLASS INDEX_REGS
@@ -1843,6 +1862,9 @@  do {							\
    between pointers and any other objects of this machine mode.  */
 #define Pmode (ix86_pmode == PMODE_DI ? DImode : SImode)
 
+/* Specify the machine mode that bounds have.  */
+#define BNDmode (ix86_pmode == PMODE_DI ? BND64mode : BND32mode)
+
 /* A C expression whose value is zero if pointers that need to be extended
    from being `POINTER_SIZE' bits wide to `Pmode' are sign-extended and
    greater then zero if they are zero-extended and less then zero if the
@@ -1953,7 +1975,8 @@  do {							\
  "xmm20", "xmm21", "xmm22", "xmm23",					\
  "xmm24", "xmm25", "xmm26", "xmm27",					\
  "xmm28", "xmm29", "xmm30", "xmm31",					\
- "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7" }
+ "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7",			\
+ "bnd0", "bnd1", "bnd2", "bnd3" }
 
 #define REGISTER_NAMES HI_REGISTER_NAMES
 
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 03b3842..a83a2b6 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -63,6 +63,7 @@ 
 ;; ~ -- print "i" if TARGET_AVX2, "f" otherwise.
 ;; @ -- print a segment register of thread base pointer load
 ;; ^ -- print addr32 prefix if TARGET_64BIT and Pmode != word_mode
+;; ! -- print MPX prefix for jxx/call/ret instructions if required.
 
 (define_c_enum "unspec" [
   ;; Relocation specifiers
@@ -178,6 +179,16 @@ 
   ;; For BMI2 support
   UNSPEC_PDEP
   UNSPEC_PEXT
+
+  UNSPEC_BNDMK
+  UNSPEC_BNDMK_ADDR
+  UNSPEC_BNDSTX
+  UNSPEC_BNDLDX
+  UNSPEC_BNDLDX_ADDR
+  UNSPEC_BNDCL
+  UNSPEC_BNDCU
+  UNSPEC_BNDCN
+  UNSPEC_MPX_FENCE
 ])
 
 (define_c_enum "unspecv" [
@@ -336,6 +347,8 @@ 
    (MASK5_REG			74)
    (MASK6_REG			75)
    (MASK7_REG			76)
+   (BND0_REG			77)
+   (BND1_REG			78)
   ])
 
 ;; Insns whose names begin with "x86_" are emitted by gen_FOO calls
@@ -369,7 +382,8 @@ 
    ssecvt,ssecvt1,sseicvt,sseins,
    sseshuf,sseshuf1,ssemuladd,sse4arg,
    lwp,mskmov,msklog,
-   mmx,mmxmov,mmxadd,mmxmul,mmxcmp,mmxcvt,mmxshft"
+   mmx,mmxmov,mmxadd,mmxmul,mmxcmp,mmxcvt,mmxshft,
+   mpxmov,mpxmk,mpxchk,mpxld,mpxst"
   (const_string "other"))
 
 ;; Main data type used by the insn
@@ -398,7 +412,8 @@ 
 ;; The (bounding maximum) length of an instruction immediate.
 (define_attr "length_immediate" ""
   (cond [(eq_attr "type" "incdec,setcc,icmov,str,lea,other,multi,idiv,leave,
-			  bitmanip,imulx,msklog,mskmov")
+			  bitmanip,imulx,msklog,mskmov,mpxmk,mpxmov,mpxchk,
+			  mpxld,mpxst")
 	   (const_int 0)
 	 (eq_attr "unit" "i387,sse,mmx")
 	   (const_int 0)
@@ -453,13 +468,17 @@ 
 	   (const_int 0)
 	 (and (eq_attr "unit" "sse") (eq_attr "mode" "SF,DF"))
 	   (const_int 1)
+	 (and (eq_attr "type" "ibr,call,callv")
+	      (match_test "ix86_bnd_prefixed_insn_p (insn)"))
+	   (const_int 1)
 	]
 	(const_int 0)))
 
 ;; Set when 0f opcode prefix is used.
 (define_attr "prefix_0f" ""
   (if_then_else
-    (ior (eq_attr "type" "imovx,setcc,icmov,bitmanip,msklog,mskmov")
+    (ior (eq_attr "type" "imovx,setcc,icmov,bitmanip,msklog,mskmov,
+			  mpxmk,mpxmov,mpxchk,mpxld,mpxst")
 	 (eq_attr "unit" "sse,mmx"))
     (const_int 1)
     (const_int 0)))
@@ -562,12 +581,19 @@ 
 	 ]
 	 (const_int 1)))
 
+;; When this attribute is set, calculate total insn length from
+;; length_nobnd attribute, prefixed with eventual bnd prefix byte
+(define_attr "length_nobnd" "" (const_int 0))
+
 ;; The (bounding maximum) length of an instruction in bytes.
 ;; ??? fistp and frndint are in fact fldcw/{fistp,frndint}/fldcw sequences.
 ;; Later we may want to split them and compute proper length as for
 ;; other insns.
 (define_attr "length" ""
-  (cond [(eq_attr "type" "other,multi,fistp,frndint")
+  (cond [(eq_attr "length_nobnd" "!0")
+	   (plus (symbol_ref ("ix86_bnd_prefixed_insn_p (insn)"))
+		 (attr "length_nobnd"))
+	 (eq_attr "type" "other,multi,fistp,frndint")
 	   (const_int 16)
 	 (eq_attr "type" "fcmp")
 	   (const_int 4)
@@ -608,12 +634,16 @@ 
 (define_attr "memory" "none,load,store,both,unknown"
   (cond [(eq_attr "type" "other,multi,str,lwp")
 	   (const_string "unknown")
-	 (eq_attr "type" "lea,fcmov,fpspc")
+	 (eq_attr "type" "lea,fcmov,fpspc,mpxmk,mpxchk")
 	   (const_string "none")
 	 (eq_attr "type" "fistp,leave")
 	   (const_string "both")
 	 (eq_attr "type" "frndint")
 	   (const_string "load")
+	 (eq_attr "type" "mpxld")
+	   (const_string "load")
+	 (eq_attr "type" "mpxst")
+	   (const_string "store")
 	 (eq_attr "type" "push")
 	   (if_then_else (match_operand 1 "memory_operand")
 	     (const_string "both")
@@ -659,7 +689,7 @@ 
 		   fmov,fcmp,fsgn,
 		   sse,ssemov,ssecmp,ssecomi,ssecvt,ssecvt1,sseicvt,
 		   sselog1,sseshuf1,sseadd1,sseiadd1,sseishft1,
-		   mmx,mmxmov,mmxcmp,mmxcvt,mskmov,msklog")
+		   mmx,mmxmov,mmxcmp,mmxcvt,mskmov,msklog,mpxmov")
 	      (match_operand 2 "memory_operand"))
 	   (const_string "load")
 	 (and (eq_attr "type" "icmov,ssemuladd,sse4arg")
@@ -885,6 +915,21 @@ 
 (define_mode_iterator DWIH [(SI "!TARGET_64BIT")
 			    (DI "TARGET_64BIT")])
 
+;; Bound modes.
+(define_mode_iterator BND [(BND32 "!TARGET_LP64")
+			   (BND64 "TARGET_LP64")])
+
+;; Pointer mode corresponding to bound mode.
+(define_mode_attr bnd_ptr [(BND32 "SI") (BND64 "DI")])
+
+;; MPX check types
+(define_int_iterator BNDCHECK [UNSPEC_BNDCL UNSPEC_BNDCU UNSPEC_BNDCN])
+
+;; Check name
+(define_int_attr bndcheck [(UNSPEC_BNDCL "cl")
+			   (UNSPEC_BNDCU "cu")
+			   (UNSPEC_BNDCN "cn")])
+
 ;; Instruction suffix for integer modes.
 (define_mode_attr imodesuffix [(QI "b") (HI "w") (SI "l") (DI "q")])
 
@@ -5281,7 +5326,7 @@ 
 
 (define_insn_and_split "*lea<mode>"
   [(set (match_operand:SWI48 0 "register_operand" "=r")
-	(match_operand:SWI48 1 "lea_address_operand" "p"))]
+	(match_operand:SWI48 1 "address_no_seg_operand" "p"))]
   ""
 {
   if (SImode_address_operand (operands[1], VOIDmode))
@@ -10680,10 +10725,10 @@ 
 		      (label_ref (match_operand 0))
 		      (pc)))]
   ""
-  "%+j%C1\t%l0"
+  "%!%+j%C1\t%l0"
   [(set_attr "type" "ibr")
    (set_attr "modrm" "0")
-   (set (attr "length")
+   (set (attr "length_nobnd")
 	   (if_then_else (and (ge (minus (match_dup 0) (pc))
 				  (const_int -126))
 			      (lt (minus (match_dup 0) (pc))
@@ -10698,10 +10743,10 @@ 
 		      (pc)
 		      (label_ref (match_operand 0))))]
   ""
-  "%+j%c1\t%l0"
+  "%!%+j%c1\t%l0"
   [(set_attr "type" "ibr")
    (set_attr "modrm" "0")
-   (set (attr "length")
+   (set (attr "length_nobnd")
 	   (if_then_else (and (ge (minus (match_dup 0) (pc))
 				  (const_int -126))
 			      (lt (minus (match_dup 0) (pc))
@@ -11164,9 +11209,9 @@ 
   [(set (pc)
 	(label_ref (match_operand 0)))]
   ""
-  "jmp\t%l0"
+  "%!jmp\t%l0"
   [(set_attr "type" "ibr")
-   (set (attr "length")
+   (set (attr "length_nobnd")
 	   (if_then_else (and (ge (minus (match_dup 0) (pc))
 				  (const_int -126))
 			      (lt (minus (match_dup 0) (pc))
@@ -11186,7 +11231,7 @@ 
 (define_insn "*indirect_jump"
   [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))]
   ""
-  "jmp\t%A0"
+  "%!jmp\t%A0"
   [(set_attr "type" "ibr")
    (set_attr "length_immediate" "0")])
 
@@ -11235,7 +11280,7 @@ 
   [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))
    (use (label_ref (match_operand 1)))]
   ""
-  "jmp\t%A0"
+  "%!jmp\t%A0"
   [(set_attr "type" "ibr")
    (set_attr "length_immediate" "0")])
 
@@ -11622,8 +11667,8 @@ 
 (define_insn "simple_return_internal"
   [(simple_return)]
   "reload_completed"
-  "ret"
-  [(set_attr "length" "1")
+  "%!ret"
+  [(set_attr "length_nobnd" "1")
    (set_attr "atom_unit" "jeu")
    (set_attr "length_immediate" "0")
    (set_attr "modrm" "0")])
@@ -11635,7 +11680,12 @@ 
   [(simple_return)
    (unspec [(const_int 0)] UNSPEC_REP)]
   "reload_completed"
-  "rep%; ret"
+{
+  if (ix86_bnd_prefixed_insn_p (insn))
+    return "%!ret";
+
+  return "rep%; ret";
+}
   [(set_attr "length" "2")
    (set_attr "atom_unit" "jeu")
    (set_attr "length_immediate" "0")
@@ -11646,8 +11696,8 @@ 
   [(simple_return)
    (use (match_operand:SI 0 "const_int_operand"))]
   "reload_completed"
-  "ret\t%0"
-  [(set_attr "length" "3")
+  "%!ret\t%0"
+  [(set_attr "length_nobnd" "3")
    (set_attr "atom_unit" "jeu")
    (set_attr "length_immediate" "2")
    (set_attr "modrm" "0")])
@@ -11656,7 +11706,7 @@ 
   [(simple_return)
    (use (match_operand:SI 0 "register_operand" "r"))]
   "reload_completed"
-  "jmp\t%A0"
+  "%!jmp\t%A0"
   [(set_attr "type" "ibr")
    (set_attr "length_immediate" "0")])
 
@@ -18119,6 +18169,131 @@ 
   [(set_attr "type" "other")
    (set_attr "length" "3")])
 
+;; MPX instructions
+
+(define_expand "<mode>_mk"
+  [(set (match_operand:BND 0 "register_operand")
+    (unspec:BND
+      [(mem:<bnd_ptr>
+       (match_par_dup 3
+        [(match_operand:<bnd_ptr> 1 "register_operand")
+	 (match_operand:<bnd_ptr> 2 "address_mpx_no_base_operand")]))]
+      UNSPEC_BNDMK))]
+  "TARGET_MPX"
+{
+  operands[3] = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, operands[1],
+						  operands[2]),
+                                UNSPEC_BNDMK_ADDR);
+})
+
+(define_insn "*<mode>_mk"
+  [(set (match_operand:BND 0 "register_operand" "=B")
+    (unspec:BND
+      [(match_operator:<bnd_ptr> 3 "bnd_mem_operator"
+        [(unspec:<bnd_ptr>
+	   [(match_operand:<bnd_ptr> 1 "register_operand" "r")
+            (match_operand:<bnd_ptr> 2 "address_mpx_no_base_operand" "Tb")]
+	   UNSPEC_BNDMK_ADDR)])]
+      UNSPEC_BNDMK))]
+  "TARGET_MPX"
+  "bndmk\t{%3, %0|%0, %3}"
+  [(set_attr "type" "mpxmk")])
+
+(define_expand "mov<mode>"
+  [(set (match_operand:BND 0 "general_operand")
+        (match_operand:BND 1 "general_operand"))]
+  "TARGET_MPX"
+{
+  ix86_expand_move (<MODE>mode, operands);DONE;
+})
+
+(define_insn "*mov<mode>_internal_mpx"
+  [(set (match_operand:BND 0 "nonimmediate_operand" "=B,m")
+        (match_operand:BND 1 "general_operand" "Bm,B"))]
+  "TARGET_MPX"
+  "bndmov\t{%1, %0|%0, %1}"
+  [(set_attr "type" "mpxmov")])
+
+(define_expand "<mode>_<bndcheck>"
+  [(parallel [(unspec [(match_operand:BND 0 "register_operand")
+                       (match_operand:<bnd_ptr> 1 "address_no_seg_operand")] BNDCHECK)
+              (set (match_dup 2)
+                   (unspec:BLK [(match_dup 2)] UNSPEC_MPX_FENCE))])]
+  "TARGET_MPX"
+{
+  operands[2] = gen_rtx_MEM (BLKmode, operands[1]);
+  MEM_VOLATILE_P (operands[2]) = 1;
+})
+
+(define_insn "*<mode>_<bndcheck>"
+  [(parallel [(unspec [(match_operand:BND 0 "register_operand" "B")
+                       (match_operand:<bnd_ptr> 1 "address_no_seg_operand" "p")] BNDCHECK)
+              (set (match_operand:BLK 2 "bnd_mem_operator")
+                   (unspec:BLK [(match_dup 2)] UNSPEC_MPX_FENCE))])]
+  "TARGET_MPX"
+  "bnd<bndcheck>\t{%a1, %0|%0, %a1}"
+  [(set_attr "type" "mpxchk")])
+
+(define_expand "<mode>_ldx"
+  [(parallel [(set:BND (match_operand:BND 0 "register_operand")
+                       (unspec:BND
+		         [(mem:<bnd_ptr>
+			   (match_par_dup 3
+			     [(match_operand:<bnd_ptr> 1 "address_mpx_no_index_operand")
+	                      (match_operand:<bnd_ptr> 2 "register_operand")]))]
+			 UNSPEC_BNDLDX))
+              (use (mem:BLK (match_dup 1)))])]
+  "TARGET_MPX"
+{
+  operands[3] = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, operands[1],
+                                                  operands[2]),
+				UNSPEC_BNDLDX_ADDR);
+})
+
+(define_insn "*<mode>_ldx"
+  [(parallel [(set:BND (match_operand:BND 0 "register_operand" "=B")
+                       (unspec:BND
+		         [(match_operator:<bnd_ptr> 3 "bnd_mem_operator"
+			   [(unspec:<bnd_ptr>
+			     [(match_operand:<bnd_ptr> 1 "address_mpx_no_index_operand" "Ti")
+	                      (match_operand:<bnd_ptr> 2 "register_operand" "l")]
+			    UNSPEC_BNDLDX_ADDR)])]
+			 UNSPEC_BNDLDX))
+              (use (mem:BLK (match_dup 1)))])]
+  "TARGET_MPX"
+  "bndldx\t{%3, %0|%0, %3}"
+  [(set_attr "type" "mpxld")])
+
+(define_expand "<mode>_stx"
+  [(parallel [(unspec [(mem:<bnd_ptr>
+			 (match_par_dup 3
+			   [(match_operand:<bnd_ptr> 0 "address_mpx_no_index_operand")
+	                    (match_operand:<bnd_ptr> 1 "register_operand")]))
+	               (match_operand:BND 2 "register_operand")] UNSPEC_BNDSTX)
+              (set (match_dup 4)
+                   (unspec:BLK [(match_dup 4)] UNSPEC_MPX_FENCE))])]
+  "TARGET_MPX"
+{
+  operands[3] = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, operands[0],
+                                                  operands[1]),
+				UNSPEC_BNDLDX_ADDR);
+  operands[4] = gen_rtx_MEM (BLKmode, operands[0]);
+  MEM_VOLATILE_P (operands[4]) = 1;
+})
+
+(define_insn "*<mode>_stx"
+  [(parallel [(unspec [(match_operator:<bnd_ptr> 3 "bnd_mem_operator"
+			 [(unspec:<bnd_ptr>
+			  [(match_operand:<bnd_ptr> 0 "address_mpx_no_index_operand" "Ti")
+	                   (match_operand:<bnd_ptr> 1 "register_operand" "l")]
+			 UNSPEC_BNDLDX_ADDR)])
+	               (match_operand:BND 2 "register_operand" "B")] UNSPEC_BNDSTX)
+              (set (match_operand:BLK 4 "bnd_mem_operator")
+                   (unspec:BLK [(match_dup 4)] UNSPEC_MPX_FENCE))])]
+  "TARGET_MPX"
+  "bndstx\t{%2, %3|%3, %2}"
+  [(set_attr "type" "mpxst")])
+
 (include "mmx.md")
 (include "sse.md")
 (include "sync.md")
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 5495c29..023fa27 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -665,6 +665,10 @@  mrtm
 Target Report Mask(ISA_RTM) Var(ix86_isa_flags) Save
 Support RTM built-in functions and code generation
 
+mmpx
+Target Report Mask(ISA_MPX) Var(ix86_isa_flags) Save
+Support MPX code generation
+
 mstack-protector-guard=
 Target RejectNegative Joined Enum(stack_protector_guard) Var(ix86_stack_protector_guard) Init(SSP_TLS)
 Use given stack-protector guard
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index 18f425c..f16afd6 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -865,7 +865,7 @@ 
 ;; Return true if op if a valid address for LEA, and does not contain
 ;; a segment override.  Defined as a special predicate to allow
 ;; mode-less const_int operands pass to address_operand.
-(define_special_predicate "lea_address_operand"
+(define_special_predicate "address_no_seg_operand"
   (match_operand 0 "address_operand")
 {
   struct ix86_address parts;
@@ -922,9 +922,74 @@ 
   return true;
 })
 
+;; Return true if op is valid MPX address operand without base
+(define_predicate "address_mpx_no_base_operand"
+  (match_operand 0 "address_operand")
+{
+  struct ix86_address parts;
+  int ok;
+
+  ok = ix86_decompose_address (op, &parts);
+  gcc_assert (ok);
+
+  if (parts.index && parts.base)
+    return false;
+
+  if (parts.seg != SEG_DEFAULT)
+    return false;
+
+  /* Do not support (%rip).  */
+  if (parts.disp && flag_pic && TARGET_64BIT
+      && SYMBOLIC_CONST (parts.disp))
+    {
+      if (GET_CODE (parts.disp) != CONST
+	  || GET_CODE (XEXP (parts.disp, 0)) != PLUS
+	  || GET_CODE (XEXP (XEXP (parts.disp, 0), 0)) != UNSPEC
+	  || !CONST_INT_P (XEXP (XEXP (parts.disp, 0), 1))
+	  || (XINT (XEXP (XEXP (parts.disp, 0), 0), 1) != UNSPEC_DTPOFF
+	      && XINT (XEXP (XEXP (parts.disp, 0), 0), 1) != UNSPEC_NTPOFF))
+	return false;
+    }
+
+  return true;
+})
+
+;; Return true if op is valid MPX address operand without index
+(define_predicate "address_mpx_no_index_operand"
+  (match_operand 0 "address_operand")
+{
+  struct ix86_address parts;
+  int ok;
+
+  ok = ix86_decompose_address (op, &parts);
+  gcc_assert (ok);
+
+  if (parts.index)
+    return false;
+
+  if (parts.seg != SEG_DEFAULT)
+    return false;
+
+  /* Do not support (%rip).  */
+  if (parts.disp && flag_pic && TARGET_64BIT
+      && SYMBOLIC_CONST (parts.disp)
+      && (GET_CODE (parts.disp) != CONST
+	  || GET_CODE (XEXP (parts.disp, 0)) != PLUS
+	  || GET_CODE (XEXP (XEXP (parts.disp, 0), 0)) != UNSPEC
+	  || !CONST_INT_P (XEXP (XEXP (parts.disp, 0), 1))
+	  || (XINT (XEXP (XEXP (parts.disp, 0), 0), 1) != UNSPEC_DTPOFF
+	      && XINT (XEXP (XEXP (parts.disp, 0), 0), 1) != UNSPEC_NTPOFF)))
+    return false;
+
+  return true;
+})
+
 (define_predicate "vsib_mem_operator"
   (match_code "mem"))
 
+(define_predicate "bnd_mem_operator"
+  (match_code "mem"))
+
 ;; Return true if the rtx is known to be at least 32 bits aligned.
 (define_predicate "aligned_operand"
   (match_operand 0 "general_operand")
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 6036f92..5df2c78 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -652,7 +652,7 @@  Objective-C and Objective-C++ Dialects}.
 -mavx2 -mavx512f -mavx512pf -mavx512er -mavx512cd @gol
 -maes -mpclmul -mfsgsbase -mrdrnd -mf16c -mfma @gol
 -msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlzcnt @gol
--mbmi2 -mfxsr -mxsave -mxsaveopt -mrtm -mlwp -mthreads @gol
+-mbmi2 -mfxsr -mxsave -mxsaveopt -mrtm -mlwp -mmpx -mthreads @gol
 -mno-align-stringops  -minline-all-stringops @gol
 -minline-stringops-dynamically -mstringop-strategy=@var{alg} @gol
 -mmemcpy-strategy=@var{strategy} -mmemset-strategy=@var{strategy}
@@ -14470,6 +14470,8 @@  preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @itemx -mrtm
 @itemx -mtbm
 @itemx -mno-tbm
+@itemx -mmpx
+@itemx -mno-mpx
 @opindex mmmx
 @opindex mno-mmx
 @opindex msse
@@ -14479,7 +14481,7 @@  preferred alignment to @option{-mpreferred-stack-boundary=2}.
 These switches enable or disable the use of instructions in the MMX, SSE,
 SSE2, SSE3, SSSE3, SSE4.1, AVX, AVX2, AVX512F, AVX512PF, AVX512ER, AVX512CD,
 AES, PCLMUL, FSGSBASE, RDRND, F16C, FMA, SSE4A, FMA4, XOP, LWP, ABM, BMI, BMI2,
-FXSR, XSAVE, XSAVEOPT, LZCNT, RTM or 3DNow!@:
+FXSR, XSAVE, XSAVEOPT, LZCNT, RTM, MPX or 3DNow!@:
 extended instruction sets.
 These extensions are also available as built-in functions: see
 @ref{X86 Built-in Functions}, for details of the functions enabled and
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 77a9c70..df2bb68 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -1295,6 +1295,12 @@  These modes stand for a complex number represented as a pair of integer
 values.  The integer values are in @code{QImode}, @code{HImode},
 @code{SImode}, @code{DImode}, @code{TImode}, and @code{OImode},
 respectively.
+
+@findex BND32mode
+@findex BND64mode
+@item BND32mode BND64mode
+These modes stand for bounds for pointer of 32 and 64 bit size respectively.
+Mode size is double pointer mode size.
 @end table
 
 The machine description defines @code{Pmode} as a C macro which expands