Ping
2014-06-11 18:03 GMT+04:00 Ilya Enkovich <enkovich....@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.enkov...@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; >