[PATCH, i386, Pointer Bounds Checker 33/x] MPX ABI

Ilya Enkovich enkovich.gnu@gmail.com
Mon Sep 15 07:17:00 GMT 2014


Ping

2014-06-11 18:03 GMT+04:00 Ilya Enkovich <enkovich.gnu@gmail.com>:
> Hi,
>
> This patch adds MPX ABI support for i386 target.
>
> Bootstrapped and tested on linux-x86_64.
>
> Thanks,
> Ilya
> --
> gcc/
>
> 2014-06-11  Ilya Enkovich  <ilya.enkovich@intel.com>
>
>         * config/i386/i386.c (ix86_option_override_internal): Do not
>         support x32 with MPX.
>         is not available.
>         (init_cumulative_args): Init stdarg, bnd_regno, bnds_in_bt
>         and force_bnd_pass.
>         (function_arg_advance_32): Return number of used integer
>         registers.
>         (function_arg_advance_64): Likewise.
>         (function_arg_advance_ms_64): Likewise.
>         (ix86_function_arg_advance): Handle pointer bounds.
>         (ix86_function_arg): Likewise.
>         (ix86_function_value_regno_p): Mark fisrt bounds registers as
>         possible function value.
>         (ix86_function_value_1): Handle pointer bounds type/mode
>         (ix86_return_in_memory): Likewise.
>         (ix86_print_operand): Analyse insn to decide abounf"bnd" prefix.
>         (ix86_expand_call): Generate returned bounds.
>         (ix86_bnd_prefixed_insn_p): Check if we have instrumented call
>         or function.
>         * config/i386/i386.h (ix86_args): Add bnd_regno, bnds_in_bt,
>         force_bnd_pass and stdarg fields.
>         * config/i386/i386.md (UNSPEC_BNDRET): New.
>         (*call_value): Add returned bounds.
>         (*sibcall_value): Likewise.
>         (*call_value_rex64_ms_sysv): Likewise.
>         (*call_value_pop): Likewise.
>         (*sibcall_value_pop): Likewise.
>         * config/i386/predicates.md (call_rex64_ms_sysv_operation): Adjust
>         to changed call patterns.
>
>
> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> index dac83d0..a67e6e7 100644
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
> @@ -3693,6 +3693,9 @@ ix86_option_override_internal (bool main_args_p,
>    if (TARGET_X32 && (opts->x_ix86_isa_flags & OPTION_MASK_ISA_MPX))
>      error ("Intel MPX does not support x32");
>
> +  if (TARGET_X32 && (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);
> @@ -6170,10 +6173,15 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
>       FIXME: once typesytem is fixed, we won't need this code anymore.  */
>    if (i && i->local && i->can_change_signature)
>      fntype = TREE_TYPE (fndecl);
> +  cum->stdarg = fntype ? stdarg_p (fntype) : false;
>    cum->maybe_vaarg = (fntype
>                       ? (!prototype_p (fntype) || stdarg_p (fntype))
>                       : !libname);
>
> +  cum->bnd_regno = FIRST_BND_REG;
> +  cum->bnds_in_bt = 0;
> +  cum->force_bnd_pass = 0;
> +
>    if (!TARGET_64BIT)
>      {
>        /* If there are variable arguments, then we won't pass anything
> @@ -7108,11 +7116,13 @@ construct_container (enum machine_mode mode, enum machine_mode orig_mode,
>     and data type TYPE.  (TYPE is null for libcalls where that information
>     may not be available.)  */
>
> -static void
> +static int
>  function_arg_advance_32 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
>                          const_tree type, HOST_WIDE_INT bytes,
>                          HOST_WIDE_INT words)
>  {
> +  int res = 0;
> +
>    switch (mode)
>      {
>      default:
> @@ -7130,7 +7140,8 @@ function_arg_advance_32 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
>        cum->words += words;
>        cum->nregs -= words;
>        cum->regno += words;
> -
> +      if (cum->nregs >= 0)
> +       res = words;
>        if (cum->nregs <= 0)
>         {
>           cum->nregs = 0;
> @@ -7201,36 +7212,42 @@ function_arg_advance_32 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
>         }
>        break;
>      }
> +
> +  return res;
>  }
>
> -static void
> +static int
>  function_arg_advance_64 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
>                          const_tree type, HOST_WIDE_INT words, bool named)
>  {
> -  int int_nregs, sse_nregs;
> +  int int_nregs, sse_nregs, exam;
>
>    /* Unnamed 512 and 256bit vector mode parameters are passed on stack.  */
>    if (!named && (VALID_AVX512F_REG_MODE (mode)
>                  || VALID_AVX256_REG_MODE (mode)))
> -    return;
> +    return 0;
> +
> +  exam = examine_argument (mode, type, 0, &int_nregs, &sse_nregs);
>
> -  if (examine_argument (mode, type, 0, &int_nregs, &sse_nregs)
> +  if (exam
>        && sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs)
>      {
>        cum->nregs -= int_nregs;
>        cum->sse_nregs -= sse_nregs;
>        cum->regno += int_nregs;
>        cum->sse_regno += sse_nregs;
> +      return int_nregs;
>      }
>    else
>      {
>        int align = ix86_function_arg_boundary (mode, type) / BITS_PER_WORD;
>        cum->words = (cum->words + align - 1) & ~(align - 1);
>        cum->words += words;
> +      return 0;
>      }
>  }
>
> -static void
> +static int
>  function_arg_advance_ms_64 (CUMULATIVE_ARGS *cum, HOST_WIDE_INT bytes,
>                             HOST_WIDE_INT words)
>  {
> @@ -7242,7 +7259,9 @@ function_arg_advance_ms_64 (CUMULATIVE_ARGS *cum, HOST_WIDE_INT bytes,
>      {
>        cum->nregs -= 1;
>        cum->regno += 1;
> +      return 1;
>      }
> +  return 0;
>  }
>
>  /* Update the data in CUM to advance over an argument of mode MODE and
> @@ -7255,6 +7274,7 @@ ix86_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
>  {
>    CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
>    HOST_WIDE_INT bytes, words;
> +  int nregs;
>
>    if (mode == BLKmode)
>      bytes = int_size_in_bytes (type);
> @@ -7265,12 +7285,51 @@ ix86_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
>    if (type)
>      mode = type_natural_mode (type, NULL, false);
>
> +  if ((type && POINTER_BOUNDS_TYPE_P (type))
> +      || POINTER_BOUNDS_MODE_P (mode))
> +    {
> +      /* If we pass bounds in BT then just update remained bounds count.  */
> +      if (cum->bnds_in_bt)
> +       {
> +         cum->bnds_in_bt--;
> +         return;
> +       }
> +
> +      /* Update remained number of bounds to force.  */
> +      if (cum->force_bnd_pass)
> +       cum->force_bnd_pass--;
> +
> +      cum->bnd_regno++;
> +
> +      return;
> +    }
> +
> +  /* The first arg not going to Bounds Tables resets this counter.  */
> +  cum->bnds_in_bt = 0;
> +  /* For unnamed args we always pass bounds to avoid bounds mess when
> +     passed and received types do not match.  If bounds do not follow
> +     unnamed arg, still pretend required number of bounds were passed.  */
> +  if (cum->force_bnd_pass)
> +    {
> +      cum->bnd_regno += cum->force_bnd_pass;
> +      cum->force_bnd_pass = 0;
> +    }
> +
>    if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
> -    function_arg_advance_ms_64 (cum, bytes, words);
> +    nregs = function_arg_advance_ms_64 (cum, bytes, words);
>    else if (TARGET_64BIT)
> -    function_arg_advance_64 (cum, mode, type, words, named);
> +    nregs = function_arg_advance_64 (cum, mode, type, words, named);
>    else
> -    function_arg_advance_32 (cum, mode, type, bytes, words);
> +    nregs = function_arg_advance_32 (cum, mode, type, bytes, words);
> +
> +  /* For stdarg we expect bounds to be passed for each value passed
> +     in register.  */
> +  if (cum->stdarg)
> +    cum->force_bnd_pass = nregs;
> +  /* For pointers passed in memory we expect bounds passed in Bounds
> +     Table.  */
> +  if (!nregs)
> +    cum->bnds_in_bt = chkp_type_bounds_count (type);
>  }
>
>  /* Define where to put the arguments to a function.
> @@ -7511,17 +7570,31 @@ ix86_function_arg (cumulative_args_t cum_v, enum machine_mode omode,
>      bytes = GET_MODE_SIZE (mode);
>    words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
>
> -  /* To simplify the code below, represent vector types with a vector mode
> -     even if MMX/SSE are not active.  */
> -  if (type && TREE_CODE (type) == VECTOR_TYPE)
> -    mode = type_natural_mode (type, cum, false);
>
> -  if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
> -    arg = function_arg_ms_64 (cum, mode, omode, named, bytes);
> -  else if (TARGET_64BIT)
> -    arg = function_arg_64 (cum, mode, omode, type, named);
> +  if ((type && POINTER_BOUNDS_TYPE_P (type))
> +      || POINTER_BOUNDS_MODE_P (mode))
> +    {
> +      if (cum->bnds_in_bt)
> +       arg = NULL;
> +      else if (cum->bnd_regno <= LAST_BND_REG)
> +       arg = gen_rtx_REG (BNDmode, cum->bnd_regno);
> +      else
> +       arg = GEN_INT (cum->bnd_regno - LAST_BND_REG - 1);
> +    }
>    else
> -    arg = function_arg_32 (cum, mode, omode, type, bytes, words);
> +    {
> +      /* To simplify the code below, represent vector types with a vector mode
> +        even if MMX/SSE are not active.  */
> +      if (type && TREE_CODE (type) == VECTOR_TYPE)
> +       mode = type_natural_mode (type, cum, false);
> +
> +      if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
> +       arg = function_arg_ms_64 (cum, mode, omode, named, bytes);
> +      else if (TARGET_64BIT)
> +       arg = function_arg_64 (cum, mode, omode, type, named);
> +      else
> +       arg = function_arg_32 (cum, mode, omode, type, bytes, words);
> +    }
>
>    return arg;
>  }
> @@ -7777,6 +7850,9 @@ ix86_function_value_regno_p (const unsigned int regno)
>      case SI_REG:
>        return TARGET_64BIT && ix86_abi != MS_ABI;
>
> +    case FIRST_BND_REG:
> +      return chkp_function_instrumented_p (current_function_decl);
> +
>        /* Complex values are returned in %st(0)/%st(1) pair.  */
>      case ST0_REG:
>      case ST1_REG:
> @@ -7953,7 +8029,10 @@ ix86_function_value_1 (const_tree valtype, const_tree fntype_or_decl,
>      fn = fntype_or_decl;
>    fntype = fn ? TREE_TYPE (fn) : fntype_or_decl;
>
> -  if (TARGET_64BIT && ix86_function_type_abi (fntype) == MS_ABI)
> +  if ((valtype && POINTER_BOUNDS_TYPE_P (valtype))
> +      || POINTER_BOUNDS_MODE_P (mode))
> +    return gen_rtx_REG (BNDmode, FIRST_BND_REG);
> +  else if (TARGET_64BIT && ix86_function_type_abi (fntype) == MS_ABI)
>      return function_value_ms_64 (orig_mode, mode, valtype);
>    else if (TARGET_64BIT)
>      return function_value_64 (orig_mode, mode, valtype);
> @@ -8122,6 +8201,9 @@ ix86_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
>  #else
>    const enum machine_mode mode = type_natural_mode (type, NULL, true);
>
> +  if (POINTER_BOUNDS_TYPE_P (type))
> +    return false;
> +
>    if (TARGET_64BIT)
>      {
>        if (ix86_function_type_abi (fntype) == MS_ABI)
> @@ -15380,7 +15462,7 @@ ix86_print_operand (FILE *file, rtx x, int code)
>           return;
>
>         case '!':
> -         if (ix86_bnd_prefixed_insn_p (NULL_RTX))
> +         if (ix86_bnd_prefixed_insn_p (current_output_insn))
>             fputs ("bnd ", file);
>           return;
>
> @@ -24964,10 +25046,32 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
>      }
>
>    call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
> +
>    if (retval)
> -    call = gen_rtx_SET (VOIDmode, retval, call);
> +    {
> +      /* For instrumented code we may have GPR + BR in parallel but
> +        it will confuse DF and we need to put each reg
> +        under EXPR_LIST.  */
> +      if (chkp_function_instrumented_p (current_function_decl))
> +       chkp_put_regs_to_expr_list (retval);
> +
> +      call = gen_rtx_SET (VOIDmode, retval, call);
> +    }
>    vec[vec_len++] = call;
>
> +  /* b0 and b1 registers hold bounds for returned value.  */
> +  if (retval)
> +    {
> +      rtx b0 = gen_rtx_REG (BND64mode, FIRST_BND_REG);
> +      rtx unspec0 = gen_rtx_UNSPEC (BND64mode,
> +                                   gen_rtvec (1, b0), UNSPEC_BNDRET);
> +      rtx b1 = gen_rtx_REG (BND64mode, FIRST_BND_REG + 1);
> +      rtx unspec1 = gen_rtx_UNSPEC (BND64mode,
> +                                   gen_rtvec (1, b1), UNSPEC_BNDRET);
> +      vec[vec_len++] = gen_rtx_SET (BND64mode, b0, unspec0);
> +      vec[vec_len++] = gen_rtx_SET (BND64mode, b1, unspec1);
> +    }
> +
>    if (pop)
>      {
>        pop = gen_rtx_PLUS (Pmode, stack_pointer_rtx, pop);
> @@ -45839,9 +45943,18 @@ ix86_expand_sse2_mulvxdi3 (rtx op0, rtx op1, rtx op2)
>     bnd by default for current function.  */
>
>  bool
> -ix86_bnd_prefixed_insn_p (rtx insn ATTRIBUTE_UNUSED)
> +ix86_bnd_prefixed_insn_p (rtx insn)
>  {
> -  return false;
> +  /* For call insns check special flag.  */
> +  if (insn && CALL_P (insn))
> +    {
> +      rtx call = get_call_rtx_from (insn);
> +      if (call)
> +       return CALL_EXPR_WITH_BOUNDS_P (call);
> +    }
> +
> +  /* All other insns are prefixed only if function is instrumented.  */
> +  return chkp_function_instrumented_p (current_function_decl);
>  }
>
>  /* Calculate integer abs() using only SSE2 instructions.  */
> diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
> index e0ced33..759d1f8 100644
> --- a/gcc/config/i386/i386.h
> +++ b/gcc/config/i386/i386.h
> @@ -1645,6 +1645,10 @@ typedef struct ix86_args {
>    int float_in_sse;            /* Set to 1 or 2 for 32bit targets if
>                                    SFmode/DFmode arguments should be passed
>                                    in SSE registers.  Otherwise 0.  */
> +  int bnd_regno;                /* next available bnd register number */
> +  int bnds_in_bt;               /* number of bounds expected in BT.  */
> +  int force_bnd_pass;           /* number of bounds expected for stdarg arg.  */
> +  int stdarg;                   /* Set to 1 if function is stdarg.  */
>    enum calling_abi call_abi;   /* Set to SYSV_ABI for sysv abi. Otherwise
>                                    MS_ABI for ms abi.  */
>  } CUMULATIVE_ARGS;
> diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
> index 5fd556b..fb9f8e3 100644
> --- a/gcc/config/i386/i386.md
> +++ b/gcc/config/i386/i386.md
> @@ -193,6 +193,7 @@
>    UNSPEC_BNDCU
>    UNSPEC_BNDCN
>    UNSPEC_MPX_FENCE
> +  UNSPEC_BNDRET
>  ])
>
>  (define_c_enum "unspecv" [
> @@ -11481,7 +11482,9 @@
>  (define_insn "*call_value"
>    [(set (match_operand 0)
>         (call (mem:QI (match_operand:W 1 "call_insn_operand" "<c>zw"))
> -             (match_operand 2)))]
> +             (match_operand 2)))
> +   (set (reg:BND64 BND0_REG) (unspec [(reg:BND64 BND0_REG)] UNSPEC_BNDRET))
> +   (set (reg:BND64 BND1_REG) (unspec [(reg:BND64 BND1_REG)] UNSPEC_BNDRET))]
>    "!SIBLING_CALL_P (insn)"
>    "* return ix86_output_call_insn (insn, operands[1]);"
>    [(set_attr "type" "callv")])
> @@ -11489,7 +11492,9 @@
>  (define_insn "*sibcall_value"
>    [(set (match_operand 0)
>         (call (mem:QI (match_operand:W 1 "sibcall_insn_operand" "Uz"))
> -             (match_operand 2)))]
> +             (match_operand 2)))
> +   (set (reg:BND64 BND0_REG) (unspec [(reg:BND64 BND0_REG)] UNSPEC_BNDRET))
> +   (set (reg:BND64 BND1_REG) (unspec [(reg:BND64 BND1_REG)] UNSPEC_BNDRET))]
>    "SIBLING_CALL_P (insn)"
>    "* return ix86_output_call_insn (insn, operands[1]);"
>    [(set_attr "type" "callv")])
> @@ -11499,6 +11504,8 @@
>      [(set (match_operand 0)
>           (call (mem:QI (match_operand:DI 1 "call_insn_operand" "rzw"))
>                 (match_operand 2)))
> +     (set (reg:BND64 BND0_REG) (unspec [(reg:BND64 BND0_REG)] UNSPEC_BNDRET))
> +     (set (reg:BND64 BND1_REG) (unspec [(reg:BND64 BND1_REG)] UNSPEC_BNDRET))
>       (unspec [(const_int 0)] UNSPEC_MS_TO_SYSV_CALL)])]
>   "TARGET_64BIT && !SIBLING_CALL_P (insn)"
>    "* return ix86_output_call_insn (insn, operands[1]);"
> @@ -11522,6 +11529,8 @@
>    [(set (match_operand 0)
>         (call (mem:QI (match_operand:SI 1 "call_insn_operand" "lzm"))
>               (match_operand 2)))
> +   (set (reg:BND64 BND0_REG) (unspec [(reg:BND64 BND0_REG)] UNSPEC_BNDRET))
> +   (set (reg:BND64 BND1_REG) (unspec [(reg:BND64 BND1_REG)] UNSPEC_BNDRET))
>     (set (reg:SI SP_REG)
>         (plus:SI (reg:SI SP_REG)
>                  (match_operand:SI 3 "immediate_operand" "i")))]
> @@ -11533,6 +11542,8 @@
>    [(set (match_operand 0)
>         (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "Uz"))
>               (match_operand 2)))
> +   (set (reg:BND64 BND0_REG) (unspec [(reg:BND64 BND0_REG)] UNSPEC_BNDRET))
> +   (set (reg:BND64 BND1_REG) (unspec [(reg:BND64 BND1_REG)] UNSPEC_BNDRET))
>     (set (reg:SI SP_REG)
>         (plus:SI (reg:SI SP_REG)
>                  (match_operand:SI 3 "immediate_operand" "i")))]
> diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
> index e4c5d21..8cb15a2 100644
> --- a/gcc/config/i386/predicates.md
> +++ b/gcc/config/i386/predicates.md
> @@ -611,14 +611,17 @@
>    (match_code "parallel")
>  {
>    unsigned creg_size = ARRAY_SIZE (x86_64_ms_sysv_extra_clobbered_registers);
> +  unsigned adop = GET_CODE (XVECEXP (op, 0, 0)) == SET
> +                  ? 4
> +                 : 2;
>    unsigned i;
>
> -  if ((unsigned) XVECLEN (op, 0) != creg_size + 2)
> +  if ((unsigned) XVECLEN (op, 0) != creg_size + adop)
>      return false;
>
>    for (i = 0; i < creg_size; i++)
>      {
> -      rtx elt = XVECEXP (op, 0, i+2);
> +      rtx elt = XVECEXP (op, 0, i+adop);
>        enum machine_mode mode;
>        unsigned regno;
>



More information about the Gcc-patches mailing list