diff mbox

[i386,Pointer,Bounds,Checker,2/x] Intel Memory Protection Extensions (MPX) instructions support

Message ID 20140917081724.GB3628@msticlxl57.ims.intel.com
State New
Headers show

Commit Message

Ilya Enkovich Sept. 17, 2014, 8:17 a.m. UTC
On 19 May 11:23, Jeff Law wrote:
> On 05/19/14 02:19, Ilya Enkovich wrote:
> >On 16 May 13:39, Jeff Law wrote:
> >>On 04/16/14 05:35, Ilya Enkovich wrote:
> >>>Hi,
> >>>
> >>>This patch introduces Intel MPX bound registers and instructions.  It was approved earlier for 4.9 and had no significant changes since then.  I'll assume patch is OK if no objections arise.
> >>>
> >>>Patch was bootstrapped and tested for linux-x86_64.
> OK for the trunk.  Please wait until entire set is approved before
> installing.
> 
> jeff
> 

Here is an updated version.  The only change is in <mode>_ldx expand.  It now has the second operand preparation code moved from ix86_expand_builtin as was proposed by Uros.

Thanks,
Ilya

Comments

Uros Bizjak Sept. 17, 2014, 9:46 a.m. UTC | #1
On Wed, Sep 17, 2014 at 10:17 AM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:

>> >>>This patch introduces Intel MPX bound registers and instructions.  It was approved earlier for 4.9 and had no significant changes since then.  I'll assume patch is OK if no objections arise.
>> >>>
>> >>>Patch was bootstrapped and tested for linux-x86_64.
>> OK for the trunk.  Please wait until entire set is approved before
>> installing.
>>
>> jeff
>>
>
> Here is an updated version.  The only change is in <mode>_ldx expand.  It now has the second operand preparation code moved from ix86_expand_builtin as was proposed by Uros.

How does this patch fit into current patch series?

Does your patch serie compile at every patch boundary? I am especially
interested in i386 target-dependent patches (30+).

Uros.
Ilya Enkovich Sept. 17, 2014, 10:11 a.m. UTC | #2
2014-09-17 13:46 GMT+04:00 Uros Bizjak <ubizjak@gmail.com>:
> On Wed, Sep 17, 2014 at 10:17 AM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
>
>>> >>>This patch introduces Intel MPX bound registers and instructions.  It was approved earlier for 4.9 and had no significant changes since then.  I'll assume patch is OK if no objections arise.
>>> >>>
>>> >>>Patch was bootstrapped and tested for linux-x86_64.
>>> OK for the trunk.  Please wait until entire set is approved before
>>> installing.
>>>
>>> jeff
>>>
>>
>> Here is an updated version.  The only change is in <mode>_ldx expand.  It now has the second operand preparation code moved from ix86_expand_builtin as was proposed by Uros.
>
> How does this patch fit into current patch series?
>
> Does your patch serie compile at every patch boundary? I am especially
> interested in i386 target-dependent patches (30+).

This one is the second from the series.  Few months ago I checked
compiler passes bootstrap and make check after each patch.  I didn't
run make check for each patch after the latest rebase due to decision
to not commit separate patches but to commit whole series instead.  So
I just checked it compiles at every patch boundary.

Thanks,
Ilya

>
> Uros.
diff mbox

Patch

diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
index 8e0a583..4e07d70 100644
--- a/gcc/config/i386/constraints.md
+++ b/gcc/config/i386/constraints.md
@@ -19,7 +19,7 @@ 
 
 ;;; Unused letters:
 ;;;           H
-;;;           h j            w  z
+;;;           h j               z
 
 ;; Integer register constraints.
 ;; It is not necessary to define 'r' here.
@@ -94,6 +94,9 @@ 
 (define_register_constraint "v" "TARGET_SSE ? ALL_SSE_REGS : NO_REGS"
  "Any EVEX encodable SSE register (@code{%xmm0-%xmm31}).")
 
+(define_register_constraint "w" "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
@@ -253,6 +256,8 @@ 
 ;; T prefix is used for different address constraints
 ;;   v - VSIB address
 ;;   s - address with no segment register
+;;   i - address with no index and no rip
+;;   b - address with no base and no rip
 
 (define_address_constraint "Tv"
   "VSIB address operand"
@@ -261,3 +266,11 @@ 
 (define_address_constraint "Ts"
   "Address operand without segment register"
   (match_operand 0 "address_no_seg_operand"))
+
+(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 2c05cec..a1e9289 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -399,6 +399,8 @@  ix86_target_macros_internal (HOST_WIDE_INT isa_flag,
     def_or_undef (parse_in, "__XSAVEC__");
   if (isa_flag & OPTION_MASK_ISA_XSAVES)
     def_or_undef (parse_in, "__XSAVES__");
+  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 07e5720..0e302e3 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 39462bd..c8ef2d2 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -231,6 +231,8 @@  extern void ix86_expand_sse2_mulv4si3 (rtx, rtx, rtx);
 extern void ix86_expand_sse2_mulvxdi3 (rtx, rtx, rtx);
 extern void ix86_expand_sse2_abs (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 929f1b1..01823ca 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2131,6 +2131,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.  */
@@ -2147,6 +2149,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.  */
@@ -2163,6 +2166,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.
@@ -2231,6 +2235,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 */
+  101, 102, 103, 104,			/* bound registers */
 };
 
 /* Define parameter passing and return registers.  */
@@ -2629,6 +2634,7 @@  ix86_target_string (HOST_WIDE_INT isa, int flags, const char *arch,
     { "-mclflushopt",   OPTION_MASK_ISA_CLFLUSHOPT },
     { "-mxsavec",	OPTION_MASK_ISA_XSAVEC },
     { "-mxsaves",	OPTION_MASK_ISA_XSAVES },
+    { "-mmpx",          OPTION_MASK_ISA_MPX },
   };
 
   /* Flag options.  */
@@ -3118,6 +3124,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)
 #define PTA_SHA			(HOST_WIDE_INT_1 << 45)
 #define PTA_PREFETCHWT1		(HOST_WIDE_INT_1 << 46)
 #define PTA_CLFLUSHOPT		(HOST_WIDE_INT_1 << 47)
@@ -3690,12 +3697,18 @@  ix86_option_override_internal (bool main_args_p,
 	if (processor_alias_table[i].flags & PTA_XSAVES
 	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_XSAVES))
 	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_XSAVES;
+        if (processor_alias_table[i].flags & PTA_MPX
+            && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_MPX))
+          opts->x_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 && (opts->x_ix86_isa_flags & OPTION_MASK_ISA_MPX))
+    error ("Intel MPX does not support x32");
+
   if (!strcmp (opts->x_ix86_arch_string, "generic"))
     error ("generic CPU can be used only for %stune=%s %s",
 	   prefix, suffix, sw);
@@ -4351,6 +4364,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] = "";
 }
 
 
@@ -9226,7 +9244,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);
@@ -9284,7 +9302,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.
@@ -14678,7 +14696,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:
@@ -14802,6 +14820,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
@@ -15344,6 +15363,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);
 	}
@@ -15486,7 +15510,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.  */
@@ -15516,6 +15540,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);
 
@@ -24967,13 +25010,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 "";
@@ -25010,9 +25053,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);
 
@@ -37328,6 +37371,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:
@@ -37676,6 +37720,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
@@ -38498,6 +38544,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++)
@@ -45316,6 +45366,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;
+}
+
 /* Calculate integer abs() using only SSE2 instructions.  */
 
 void
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 9e3ef94..a38c5d1 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -138,6 +138,8 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define TARGET_XSAVEOPT_P(x)	TARGET_ISA_XSAVEOPT_P(x)
 #define TARGET_PREFETCHWT1	TARGET_ISA_PREFETCHWT1
 #define TARGET_PREFETCHWT1_P(x)	TARGET_ISA_PREFETCHWT1_P(x)
+#define TARGET_MPX	TARGET_ISA_MPX
+#define TARGET_MPX_P(x)	TARGET_ISA_MPX_P(x)
 
 #define TARGET_LP64	TARGET_ABI_64
 #define TARGET_LP64_P(x)	TARGET_ABI_64_P(x)
@@ -945,7 +947,7 @@  extern const char *host_detect_local_cpu (int argc, const char **argv);
    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.  */
@@ -977,7 +979,9 @@  extern const char *host_detect_local_cpu (int argc, const char **argv);
 /*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
@@ -1011,7 +1015,9 @@  extern const char *host_detect_local_cpu (int argc, const char **argv);
 /*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
@@ -1027,7 +1033,8 @@  extern const char *host_detect_local_cpu (int argc, const char **argv);
    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,
@@ -1049,6 +1056,7 @@  extern const char *host_detect_local_cpu (int argc, const char **argv);
 
 #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)						\
@@ -1098,6 +1106,9 @@  extern const char *host_detect_local_cpu (int argc, const char **argv);
    || (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)
 
@@ -1204,6 +1215,9 @@  extern const char *host_detect_local_cpu (int argc, const char **argv);
 #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
@@ -1284,6 +1298,7 @@  enum reg_class
   SSE_FIRST_REG,
   SSE_REGS,
   EVEX_SSE_REGS,
+  BND_REGS,
   ALL_SSE_REGS,
   MMX_REGS,
   FP_TOP_SSE_REGS,
@@ -1341,6 +1356,7 @@  enum reg_class
    "SSE_FIRST_REG",			\
    "SSE_REGS",				\
    "EVEX_SSE_REGS",			\
+   "BND_REGS",				\
    "ALL_SSE_REGS",			\
    "MMX_REGS",				\
    "FP_TOP_SSE_REGS",			\
@@ -1360,37 +1376,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:
@@ -1466,6 +1483,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
@@ -1912,6 +1932,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
@@ -2022,7 +2045,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 3cb8b67..2c367b2 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
@@ -182,6 +183,16 @@ 
 
   ;; For AVX512F support
   UNSPEC_KMOV
+
+  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" [
@@ -365,6 +376,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
@@ -399,7 +412,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
@@ -435,7 +449,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)
@@ -490,13 +505,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)))
@@ -599,12 +618,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)
@@ -645,12 +671,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")
@@ -696,7 +726,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")
@@ -949,6 +979,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")])
 
@@ -10674,10 +10719,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))
@@ -10692,10 +10737,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))
@@ -11133,9 +11178,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))
@@ -11155,7 +11200,7 @@ 
 (define_insn "*indirect_jump"
   [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))]
   ""
-  "jmp\t%A0"
+  "%!jmp\t%A0"
   [(set_attr "type" "ibr")
    (set_attr "length_immediate" "0")])
 
@@ -11204,7 +11249,7 @@ 
   [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))
    (use (label_ref (match_operand 1)))]
   ""
-  "jmp\t%A0"
+  "%!jmp\t%A0"
   [(set_attr "type" "ibr")
    (set_attr "length_immediate" "0")])
 
@@ -11768,8 +11813,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")])
@@ -11781,7 +11826,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")
@@ -11792,8 +11842,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")])
@@ -11802,7 +11852,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")])
 
@@ -18366,6 +18416,144 @@ 
    (set_attr "atom_sse_attr" "fence")
    (set_attr "memory" "unknown")])
 
+;; 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" "=w")
+    (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" "=w,m")
+        (match_operand:BND 1 "general_operand" "wm,w"))]
+  "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" "w")
+                       (match_operand:<bnd_ptr> 1 "address_no_seg_operand" "Ts")] 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"
+{
+  /* Avoid registers which connot be used as index.  */
+  if (!index_register_operand (operands[2], Pmode))
+    {
+      rtx temp = gen_reg_rtx (Pmode);
+      emit_move_insn (temp, operands[2]);
+      operands[2] = temp;
+    }
+  /* If the second operand was a register originally then it
+     may have mode other than Pmode.  We need to extend in such
+     case because bndldx may work only with Pmode regs.  */
+  if (GET_MODE (operands[2]) != Pmode)
+    operands[2] = ix86_zero_extend_to_Pmode (operands[2]);
+
+  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" "=w")
+                       (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" "w")] 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 dc1302c..2fb94ae 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -793,6 +793,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 62970be..cd542b7 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -1027,9 +1027,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 4f327df..4f85c6d 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -677,7 +677,7 @@  Objective-C and Objective-C++ Dialects}.
 -maes -mpclmul -mfsgsbase -mrdrnd -mf16c -mfma -mprefetchwt1 @gol
 -mclflushopt -mxsavec -mxsaves @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}
@@ -15585,6 +15585,8 @@  preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @itemx -mno-xsavec
 @itemx -mxsaves
 @itemx -mno-xsaves
+@itemx -mmpx
+@itemx -mno-mpx
 @opindex mmmx
 @opindex mno-mmx
 @opindex msse
@@ -15594,7 +15596,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,
 SHA, AES, PCLMUL, FSGSBASE, RDRND, F16C, FMA, SSE4A, FMA4, XOP, LWP, ABM,
-BMI, BMI2, FXSR, XSAVE, XSAVEOPT, LZCNT, RTM, or 3DNow!@:
+BMI, BMI2, 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 c7de151..9bc16b8 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