From: Ilya Enkovich <enkovich.gnu@gmail.com>
To: Richard Biener <rguenther@suse.de>
Cc: Uros Bizjak <ubizjak@gmail.com>,
"gcc-patches@gcc.gnu.org" <gcc-patches@gcc.gnu.org>,
Jeff Law <law@redhat.com>
Subject: Re: [PATCH, i386, Pointer Bounds Checker 32/x] Pointer Bounds Checker hooks for i386 target
Date: Tue, 23 Sep 2014 14:10:00 -0000 [thread overview]
Message-ID: <20140923141008.GE35262@msticlxl57.ims.intel.com> (raw)
In-Reply-To: <alpine.LSU.2.11.1409230945090.20733@zhemvz.fhfr.qr>
On 23 Sep 09:51, Richard Biener wrote:
> On Mon, 22 Sep 2014, Uros Bizjak wrote:
>
> > On Mon, Sep 22, 2014 at 5:30 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
> > > On 19 Sep 18:21, Uros Bizjak wrote:
> > >> On Fri, Sep 19, 2014 at 2:53 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
> > > +static int
> > > +ix86_initialize_bounds (tree var, tree lb, tree ub, tree *stmts)
> > > +{
> > > + tree size_ptr = build_pointer_type (size_type_node);
> > > + tree lhs, modify, var_p;
> > > +
> > > + ub = build1 (BIT_NOT_EXPR, size_type_node, ub);
> > > + var_p = build1 (CONVERT_EXPR, size_ptr,
> > > + build_fold_addr_expr (var));
>
> Please use fold_convert (size_ptr, build_fold_addr_expr (var)).
>
> Is 'var' always accessed via a size_t effective type? Watch out
> for TBAA issues if not. (if it is, why is 'var' not of type
> size_t or size_t[]?)
var has pointer bounds type. I have to initialize it by parts and thus access it as a couple of integers having size of a pointer (I use integer instead of pointer because non poiner arithmetic is used). Size type is not the best for this purpose and therefore I replace it with pointer_sized_int_node.
So I have accesses of var's parts as integers and accesses of whole var as bounds. Should I expect some problems from TBAA here? How can I avoid problems with TBAA if any exists?
>
> > > + lhs = build1 (INDIRECT_REF, size_type_node, var_p);
> > > + modify = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, lb);
> > > + append_to_statement_list (modify, stmts);
> > > +
> > > + lhs = build1 (INDIRECT_REF, size_type_node,
> > > + build2 (POINTER_PLUS_EXPR, size_ptr, var_p,
> > > + TYPE_SIZE_UNIT (size_type_node)));
> > > + modify = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, ub);
> > > + append_to_statement_list (modify, stmts);
>
> This was used from inside the gimplifier? Thus this is why you
> build GENERIC here and not GIMPLE?
>
> Didn't spot any other "tree" stuff.
>
> Richard.
>
I build GENERIC to pass it to cgraph_build_static_cdtor. Below is a new version.
Thanks,
Ilya
--
2014-09-23 Ilya Enkovich <ilya.enkovich@intel.com>
* config/i386/i386.c: Include tree-iterator.h.
(ix86_function_value_bounds): New.
(ix86_builtin_mpx_function): New.
(ix86_get_arg_address_for_bt): New.
(ix86_load_bounds): New.
(ix86_store_bounds): New.
(ix86_load_returned_bounds): New.
(ix86_store_returned_bounds): New.
(ix86_mpx_bound_mode): New.
(ix86_make_bounds_constant): New.
(ix86_initialize_bounds):
(TARGET_LOAD_BOUNDS_FOR_ARG): New.
(TARGET_STORE_BOUNDS_FOR_ARG): New.
(TARGET_LOAD_RETURNED_BOUNDS): New.
(TARGET_STORE_RETURNED_BOUNDS): New.
(TARGET_CHKP_BOUND_MODE): New.
(TARGET_BUILTIN_CHKP_FUNCTION): New.
(TARGET_CHKP_FUNCTION_VALUE_BOUNDS): New.
(TARGET_CHKP_MAKE_BOUNDS_CONSTANT): New.
(TARGET_CHKP_INITIALIZE_BOUNDS): New.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index d493983..64bf5b4 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -85,6 +85,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-vectorizer.h"
#include "shrink-wrap.h"
#include "builtins.h"
+#include "tree-iterator.h"
#include "tree-chkp.h"
#include "rtl-chkp.h"
@@ -8001,6 +8002,51 @@ ix86_function_value (const_tree valtype, const_tree fntype_or_decl, bool)
return ix86_function_value_1 (valtype, fntype_or_decl, orig_mode, mode);
}
+/* Return an RTX representing a place where a function returns
+ or recieves pointer bounds or NULL if no bounds are returned.
+
+ VALTYPE is a data type of a value returned by the function.
+
+ FN_DECL_OR_TYPE is a tree node representing FUNCTION_DECL
+ or FUNCTION_TYPE of the function.
+
+ If OUTGOING is false, return a place in which the caller will
+ see the return value. Otherwise, return a place where a
+ function returns a value. */
+
+static rtx
+ix86_function_value_bounds (const_tree valtype,
+ const_tree fntype_or_decl ATTRIBUTE_UNUSED,
+ bool outgoing ATTRIBUTE_UNUSED)
+{
+ rtx res = NULL_RTX;
+
+ if (BOUNDED_TYPE_P (valtype))
+ res = gen_rtx_REG (BNDmode, FIRST_BND_REG);
+ else if (chkp_type_has_pointer (valtype))
+ {
+ bitmap slots = chkp_find_bound_slots (valtype);
+ rtx bounds[2];
+ bitmap_iterator bi;
+ unsigned i, bnd_no = 0;
+
+ EXECUTE_IF_SET_IN_BITMAP (slots, 0, i, bi)
+ {
+ rtx reg = gen_rtx_REG (BNDmode, FIRST_BND_REG + bnd_no);
+ rtx offs = GEN_INT (i * POINTER_SIZE / BITS_PER_UNIT);
+ gcc_assert (bnd_no < 2);
+ bounds[bnd_no++] = gen_rtx_EXPR_LIST (VOIDmode, reg, offs);
+ }
+
+ res = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (bnd_no, bounds));
+ BITMAP_FREE (slots);
+ }
+ else
+ res = NULL_RTX;
+
+ return res;
+}
+
/* Pointer function arguments and return values are promoted to
word_mode. */
@@ -36754,6 +36800,193 @@ static tree ix86_get_builtin (enum ix86_builtins code)
return NULL_TREE;
}
+/* Return function decl for target specific builtin
+ for given MPX builtin passed i FCODE. */
+static tree
+ix86_builtin_mpx_function (unsigned fcode)
+{
+ switch (fcode)
+ {
+ case BUILT_IN_CHKP_BNDMK:
+ return ix86_builtins[IX86_BUILTIN_BNDMK];
+
+ case BUILT_IN_CHKP_BNDSTX:
+ return ix86_builtins[IX86_BUILTIN_BNDSTX];
+
+ case BUILT_IN_CHKP_BNDLDX:
+ return ix86_builtins[IX86_BUILTIN_BNDLDX];
+
+ case BUILT_IN_CHKP_BNDCL:
+ return ix86_builtins[IX86_BUILTIN_BNDCL];
+
+ case BUILT_IN_CHKP_BNDCU:
+ return ix86_builtins[IX86_BUILTIN_BNDCU];
+
+ case BUILT_IN_CHKP_BNDRET:
+ return ix86_builtins[IX86_BUILTIN_BNDRET];
+
+ case BUILT_IN_CHKP_INTERSECT:
+ return ix86_builtins[IX86_BUILTIN_BNDINT];
+
+ case BUILT_IN_CHKP_NARROW:
+ return ix86_builtins[IX86_BUILTIN_BNDNARROW];
+
+ case BUILT_IN_CHKP_SIZEOF:
+ return ix86_builtins[IX86_BUILTIN_SIZEOF];
+
+ case BUILT_IN_CHKP_EXTRACT_LOWER:
+ return ix86_builtins[IX86_BUILTIN_BNDLOWER];
+
+ case BUILT_IN_CHKP_EXTRACT_UPPER:
+ return ix86_builtins[IX86_BUILTIN_BNDUPPER];
+
+ default:
+ return NULL_TREE;
+ }
+
+ gcc_unreachable ();
+}
+
+/* Helper function for ix86_load_bounds and ix86_store_bounds.
+
+ Return an address to be used to load/store bounds for pointer
+ passed in SLOT.
+
+ SLOT_NO is an integer constant holding number of a target
+ dependent special slot to be used in case SLOT is not a memory.
+
+ SPECIAL_BASE is a pointer to be used as a base of fake address
+ to access special slots in Bounds Table. SPECIAL_BASE[-1],
+ SPECIAL_BASE[-2] etc. will be used as fake pointer locations. */
+
+static rtx
+ix86_get_arg_address_for_bt (rtx slot, rtx slot_no, rtx special_base)
+{
+ rtx addr = NULL;
+
+ /* NULL slot means we pass bounds for pointer not passed to the
+ function at all. Register slot means we pass pointer in a
+ register. In both these cases bounds are passed via Bounds
+ Table. Since we do not have actual pointer stored in memory,
+ we have to use fake addresses to access Bounds Table. We
+ start with (special_base - sizeof (void*)) and decrease this
+ address by pointer size to get addresses for other slots. */
+ if (!slot || REG_P (slot))
+ {
+ gcc_assert (CONST_INT_P (slot_no));
+ addr = plus_constant (Pmode, special_base,
+ -(INTVAL (slot_no) + 1) * GET_MODE_SIZE (Pmode));
+ }
+ /* If pointer is passed in a memory then its address is used to
+ access Bounds Table. */
+ else if (MEM_P (slot))
+ {
+ addr = XEXP (slot, 0);
+ if (!register_operand (addr, Pmode))
+ addr = copy_addr_to_reg (addr);
+ }
+ else
+ gcc_unreachable ();
+
+ return addr;
+}
+
+/* Expand pass uses this hook to load bounds for function parameter
+ PTR passed in SLOT in case its bounds are not passed in a register.
+
+ If SLOT is a memory, then bounds are loaded as for regular pointer
+ loaded from memory. PTR may be NULL in case SLOT is a memory.
+ In such case value of PTR (if required) may be loaded from SLOT.
+
+ If SLOT is NULL or a register then SLOT_NO is an integer constant
+ holding number of the target dependent special slot which should be
+ used to obtain bounds.
+
+ Return loaded bounds. */
+
+static rtx
+ix86_load_bounds (rtx slot, rtx ptr, rtx slot_no)
+{
+ rtx reg = gen_reg_rtx (BNDmode);
+ rtx addr;
+
+ /* Get address to be used to access Bounds Table. Special slots start
+ at the location of return address of the current function. */
+ addr = ix86_get_arg_address_for_bt (slot, slot_no, arg_pointer_rtx);
+
+ /* Load pointer value from a memory if we don't have it. */
+ if (!ptr)
+ {
+ gcc_assert (MEM_P (slot));
+ ptr = copy_addr_to_reg (slot);
+ }
+
+ emit_insn (BNDmode == BND64mode
+ ? gen_bnd64_ldx (reg, addr, ptr)
+ : gen_bnd32_ldx (reg, addr, ptr));
+
+ return reg;
+}
+
+/* Expand pass uses this hook to store BOUNDS for call argument PTR
+ passed in SLOT in case BOUNDS are not passed in a register.
+
+ If SLOT is a memory, then BOUNDS are stored as for regular pointer
+ stored in memory. PTR may be NULL in case SLOT is a memory.
+ In such case value of PTR (if required) may be loaded from SLOT.
+
+ If SLOT is NULL or a register then SLOT_NO is an integer constant
+ holding number of the target dependent special slot which should be
+ used to store BOUNDS. */
+
+static void
+ix86_store_bounds (rtx ptr, rtx slot, rtx bounds, rtx slot_no)
+{
+ rtx addr;
+
+ /* Get address to be used to access Bounds Table. Special slots start
+ at the location of return address of a called function. */
+ addr = ix86_get_arg_address_for_bt (slot, slot_no, stack_pointer_rtx);
+
+ /* Load pointer value from a memory if we don't have it. */
+ if (!ptr)
+ {
+ gcc_assert (MEM_P (slot));
+ ptr = copy_addr_to_reg (slot);
+ }
+
+ gcc_assert (POINTER_BOUNDS_MODE_P (GET_MODE (bounds)));
+ if (!register_operand (bounds, BNDmode))
+ bounds = copy_to_mode_reg (BNDmode, bounds);
+
+ emit_insn (BNDmode == BND64mode
+ ? gen_bnd64_stx (addr, ptr, bounds)
+ : gen_bnd32_stx (addr, ptr, bounds));
+}
+
+/* Load and return bounds returned by function in SLOT. */
+
+static rtx
+ix86_load_returned_bounds (rtx slot)
+{
+ rtx res;
+
+ gcc_assert (REG_P (slot));
+ res = gen_reg_rtx (BNDmode);
+ emit_move_insn (res, slot);
+
+ return res;
+}
+
+/* Store BOUNDS returned by function into SLOT. */
+
+static void
+ix86_store_returned_bounds (rtx slot, rtx bounds)
+{
+ gcc_assert (REG_P (slot));
+ emit_move_insn (slot, bounds);
+}
+
/* Returns a function decl for a vectorized version of the builtin function
with builtin function code FN and the result vector type TYPE, or NULL_TREE
if it is not available. */
@@ -47480,6 +47713,73 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
atomic_feraiseexcept_call);
}
+/* Return mode to be used for bounds or VOIDmode
+ if bounds are not supported. */
+
+static enum machine_mode
+ix86_mpx_bound_mode ()
+{
+ /* Do not support pointer checker if MPX
+ is not enabled. */
+ if (!TARGET_MPX)
+ {
+ if (flag_check_pointer_bounds)
+ warning (0, "Pointer Checker requires MPX support on this target."
+ " Use -mmpx options to enable MPX.");
+ return VOIDmode;
+ }
+
+ return BNDmode;
+}
+
+/* Return constant used to statically initialize constant bounds.
+
+ This function is used to create special bound values. For now
+ only INIT bounds and NONE bounds are expected. More special
+ values may be added later. */
+
+static tree
+ix86_make_bounds_constant (HOST_WIDE_INT lb, HOST_WIDE_INT ub)
+{
+ tree low = lb ? build_minus_one_cst (pointer_sized_int_node)
+ : build_zero_cst (pointer_sized_int_node);
+ tree high = ub ? build_zero_cst (pointer_sized_int_node)
+ : build_minus_one_cst (pointer_sized_int_node);
+
+ /* This function is supposed to be used to create INIT and
+ NONE bounds only. */
+ gcc_assert ((lb == 0 && ub == -1)
+ || (lb == -1 && ub == 0));
+
+ return build_complex (NULL, low, high);
+}
+
+/* Generate a list of statements STMTS to initialize pointer bounds
+ variable VAR with bounds LB and UB. Return the number of generated
+ statements. */
+
+static int
+ix86_initialize_bounds (tree var, tree lb, tree ub, tree *stmts)
+{
+ tree bnd_ptr = build_pointer_type (pointer_sized_int_node);
+ tree lhs, modify, var_p;
+
+ ub = build1 (BIT_NOT_EXPR, pointer_sized_int_node, ub);
+ var_p = fold_convert (bnd_ptr, build_fold_addr_expr (var));
+
+ lhs = build1 (INDIRECT_REF, pointer_sized_int_node, var_p);
+ modify = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, lb);
+ append_to_statement_list (modify, stmts);
+
+ lhs = build1 (INDIRECT_REF, pointer_sized_int_node,
+ build2 (POINTER_PLUS_EXPR, bnd_ptr, var_p,
+ TYPE_SIZE_UNIT (pointer_sized_int_node)));
+ modify = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, ub);
+ append_to_statement_list (modify, stmts);
+
+ return 2;
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
@@ -47897,6 +48197,33 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
#undef TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS
#define TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS true
+#undef TARGET_LOAD_BOUNDS_FOR_ARG
+#define TARGET_LOAD_BOUNDS_FOR_ARG ix86_load_bounds
+
+#undef TARGET_STORE_BOUNDS_FOR_ARG
+#define TARGET_STORE_BOUNDS_FOR_ARG ix86_store_bounds
+
+#undef TARGET_LOAD_RETURNED_BOUNDS
+#define TARGET_LOAD_RETURNED_BOUNDS ix86_load_returned_bounds
+
+#undef TARGET_STORE_RETURNED_BOUNDS
+#define TARGET_STORE_RETURNED_BOUNDS ix86_store_returned_bounds
+
+#undef TARGET_CHKP_BOUND_MODE
+#define TARGET_CHKP_BOUND_MODE ix86_mpx_bound_mode
+
+#undef TARGET_BUILTIN_CHKP_FUNCTION
+#define TARGET_BUILTIN_CHKP_FUNCTION ix86_builtin_mpx_function
+
+#undef TARGET_CHKP_FUNCTION_VALUE_BOUNDS
+#define TARGET_CHKP_FUNCTION_VALUE_BOUNDS ix86_function_value_bounds
+
+#undef TARGET_CHKP_MAKE_BOUNDS_CONSTANT
+#define TARGET_CHKP_MAKE_BOUNDS_CONSTANT ix86_make_bounds_constant
+
+#undef TARGET_CHKP_INITIALIZE_BOUNDS
+#define TARGET_CHKP_INITIALIZE_BOUNDS ix86_initialize_bounds
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
#include "gt-i386.h"
next prev parent reply other threads:[~2014-09-23 14:10 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-18 19:34 Uros Bizjak
2014-09-19 3:10 ` Jeff Law
2014-09-19 12:16 ` Ilya Enkovich
2014-09-19 12:53 ` Ilya Enkovich
2014-09-19 16:21 ` Uros Bizjak
2014-09-22 15:30 ` Ilya Enkovich
2014-09-22 18:51 ` Uros Bizjak
2014-09-23 6:48 ` Ilya Enkovich
2014-09-23 7:29 ` Uros Bizjak
2014-09-23 7:55 ` Richard Biener
2014-09-23 14:10 ` Ilya Enkovich [this message]
2014-09-23 14:16 ` Richard Biener
2014-09-23 17:17 ` Jeff Law
2014-09-24 14:42 ` Ilya Enkovich
2014-09-22 18:54 ` Jeff Law
-- strict thread matches above, loose matches on Subject: below --
2014-06-11 14:01 Ilya Enkovich
2014-09-15 7:17 ` Ilya Enkovich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140923141008.GE35262@msticlxl57.ims.intel.com \
--to=enkovich.gnu@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=law@redhat.com \
--cc=rguenther@suse.de \
--cc=ubizjak@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).