diff options
author | ienkovich <ienkovich@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-05 12:42:03 +0000 |
---|---|---|
committer | ienkovich <ienkovich@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-05 12:42:03 +0000 |
commit | 058a1b7aa18100b0cabbfa6c4b1fb6c97b8131a2 (patch) | |
tree | df7b4d3afe0e30fdad56e3feeb2db22600eaaec8 /gcc/config/i386 | |
parent | 6fe9a05b73f4b5671a42b2a7e05d01329f7424e0 (diff) | |
download | gcc-058a1b7aa18100b0cabbfa6c4b1fb6c97b8131a2.tar.gz |
gcc/
2014-11-05 Ilya Enkovich <ilya.enkovich@intel.com>
* ipa-chkp.c: New.
* ipa-chkp.h: New.
* tree-chkp.c: New.
* tree-chkp.h: New.
* tree-chkp-opt.c: New.
* rtl-chkp.c: New.
* rtl-chkp.h: New.
* Makefile.in (OBJS): Add ipa-chkp.o, rtl-chkp.o, tree-chkp.o
tree-chkp-opt.o.
(GTFILES): Add tree-chkp.c.
* mode-classes.def (MODE_POINTER_BOUNDS): New.
* tree.def (POINTER_BOUNDS_TYPE): New.
* genmodes.c (complete_mode): Support MODE_POINTER_BOUNDS.
(POINTER_BOUNDS_MODE): New.
(make_pointer_bounds_mode): New.
* machmode.h (POINTER_BOUNDS_MODE_P): New.
* stor-layout.c (int_mode_for_mode): Support MODE_POINTER_BOUNDS.
(layout_type): Support POINTER_BOUNDS_TYPE.
* tree-pretty-print.c (dump_generic_node): Support POINTER_BOUNDS_TYPE.
* tree-core.h (tree_index): Add TI_POINTER_BOUNDS_TYPE.
* tree.c (build_int_cst_wide): Support POINTER_BOUNDS_TYPE.
(type_contains_placeholder_1): Likewise.
(build_common_tree_nodes): Initialize
pointer_bounds_type_node.
* tree.h (POINTER_BOUNDS_TYPE_P): New.
(pointer_bounds_type_node): New.
(POINTER_BOUNDS_P): New.
(BOUNDED_TYPE_P): New.
(BOUNDED_P): New.
(CALL_WITH_BOUNDS_P): New.
* gimple.h (gf_mask): Add GF_CALL_WITH_BOUNDS.
(gimple_call_with_bounds_p): New.
(gimple_call_set_with_bounds): New.
(gimple_return_retbnd): New.
(gimple_return_set_retbnd): New
* gimple.c (gimple_build_return): Increase number of ops
for return statement.
(gimple_build_call_from_tree): Propagate CALL_WITH_BOUNDS_P
flag.
* gimple-pretty-print.c (dump_gimple_return): Print second op.
* rtl.h (CALL_EXPR_WITH_BOUNDS_P): New.
* gimplify.c (gimplify_init_constructor): Avoid infinite
loop during gimplification of bounds initializer.
* calls.c: Include tree-chkp.h, rtl-chkp.h, bitmap.h.
(special_function_p): Use original decl name when analyzing
instrumentation clone.
(arg_data): Add fields special_slot, pointer_arg and
pointer_offset.
(store_bounds): New.
(emit_call_1): Propagate instrumentation flag for CALL.
(initialize_argument_information): Compute pointer_arg,
pointer_offset and special_slot for pointer bounds arguments.
(finalize_must_preallocate): Preallocate when storing bounds
in bounds table.
(compute_argument_addresses): Skip pointer bounds.
(expand_call): Store bounds into tables separately. Return
result joined with resulting bounds.
* cfgexpand.c: Include tree-chkp.h, rtl-chkp.h.
(expand_call_stmt): Propagate bounds flag for CALL_EXPR.
(expand_return): Add returned bounds arg. Handle returned bounds.
(expand_gimple_stmt_1): Adjust to new expand_return signature.
(gimple_expand_cfg): Reset rtx bounds map.
* expr.c: Include tree-chkp.h, rtl-chkp.h.
(expand_assignment): Handle returned bounds.
(store_expr_with_bounds): New. Replaces store_expr with new bounds
target argument. Handle bounds returned by calls.
(store_expr): Now wraps store_expr_with_bounds.
* expr.h (store_expr_with_bounds): New.
* function.c: Include tree-chkp.h, rtl-chkp.h.
(bounds_parm_data): New.
(use_register_for_decl): Do not registerize decls used for bounds
stores and loads.
(assign_parms_augmented_arg_list): Add bounds of the result
structure pointer as the second argument.
(assign_parm_find_entry_rtl): Mark bounds are never passed on
the stack.
(assign_parm_is_stack_parm): Likewise.
(assign_parm_load_bounds): New.
(assign_bounds): New.
(assign_parms): Load bounds and determine a location for
returned bounds.
(diddle_return_value_1): New.
(diddle_return_value): Handle returned bounds.
* function.h (rtl_data): Add field for returned bounds.
* varasm.c: Include tree-chkp.h.
(output_constant): Support POINTER_BOUNDS_TYPE.
(output_constant_pool_2): Support MODE_POINTER_BOUNDS.
(ultimate_transparent_alias_target): Move up.
(make_decl_rtl): For instrumented function use
name of the original decl.
(assemble_start_function): Mark function as global
in case it is instrumentation clone of the global
function.
(do_assemble_alias): Follow transparent alias chain
for identifier. Check if original alias is public.
(maybe_assemble_visibility): Use visibility of the
original function for instrumented version.
(default_unique_section): Likewise.
* emit-rtl.c (immed_double_const): Support MODE_POINTER_BOUNDS.
(init_emit_once): Build pointer bounds zero constants.
* explow.c (trunc_int_for_mode): Support MODE_POINTER_BOUNDS.
* target.def (builtin_chkp_function): New.
(chkp_bound_type): New.
(chkp_bound_mode): New.
(chkp_make_bounds_constant): New.
(chkp_initialize_bounds): New.
(load_bounds_for_arg): New.
(store_bounds_for_arg): New.
(load_returned_bounds): New.
(store_returned_bounds): New.
(chkp_function_value_bounds): New.
(setup_incoming_vararg_bounds): New.
(function_arg): Update hook description with new possible return
value CONST_INT.
* targhooks.h (default_load_bounds_for_arg): New.
(default_store_bounds_for_arg): New.
(default_load_returned_bounds): New.
(default_store_returned_bounds): New.
(default_chkp_bound_type): New.
(default_chkp_bound_mode): New.
(default_builtin_chkp_function): New.
(default_chkp_function_value_bounds): New.
(default_chkp_make_bounds_constant): New.
(default_chkp_initialize_bounds): New.
(default_setup_incoming_vararg_bounds): New.
* targhooks.c (default_load_bounds_for_arg): New.
(default_store_bounds_for_arg): New.
(default_load_returned_bounds): New.
(default_store_returned_bounds): New.
(default_chkp_bound_type): New.
(default_chkp_bound_mode); New.
(default_builtin_chkp_function): New.
(default_chkp_function_value_bounds): New.
(default_chkp_make_bounds_constant): New.
(default_chkp_initialize_bounds): New.
(default_setup_incoming_vararg_bounds): New.
* builtin-types.def (BT_BND): New.
(BT_FN_PTR_CONST_PTR): New.
(BT_FN_CONST_PTR_CONST_PTR): New.
(BT_FN_BND_CONST_PTR): New.
(BT_FN_CONST_PTR_BND): New.
(BT_FN_PTR_CONST_PTR_SIZE): New.
(BT_FN_PTR_CONST_PTR_CONST_PTR): New.
(BT_FN_VOID_PTRPTR_CONST_PTR): New.
(BT_FN_VOID_CONST_PTR_SIZE): New.
(BT_FN_VOID_PTR_BND): New.
(BT_FN_CONST_PTR_CONST_PTR_CONST_PTR): New.
(BT_FN_BND_CONST_PTR_SIZE): New.
(BT_FN_PTR_CONST_PTR_CONST_PTR_SIZE): New.
(BT_FN_VOID_CONST_PTR_BND_CONST_PTR): New.
* chkp-builtins.def: New.
* builtins.def: include chkp-builtins.def.
(DEF_CHKP_BUILTIN): New.
* builtins.c: Include tree-chkp.h and rtl-chkp.h.
(expand_builtin): Support BUILT_IN_CHKP_INIT_PTR_BOUNDS,
BUILT_IN_CHKP_NULL_PTR_BOUNDS, BUILT_IN_CHKP_COPY_PTR_BOUNDS,
BUILT_IN_CHKP_CHECK_PTR_LBOUNDS, BUILT_IN_CHKP_CHECK_PTR_UBOUNDS,
BUILT_IN_CHKP_CHECK_PTR_BOUNDS, BUILT_IN_CHKP_SET_PTR_BOUNDS,
BUILT_IN_CHKP_NARROW_PTR_BOUNDS, BUILT_IN_CHKP_STORE_PTR_BOUNDS,
BUILT_IN_CHKP_GET_PTR_LBOUND, BUILT_IN_CHKP_GET_PTR_UBOUND,
BUILT_IN_CHKP_BNDMK, BUILT_IN_CHKP_BNDSTX, BUILT_IN_CHKP_BNDCL,
BUILT_IN_CHKP_BNDCU, BUILT_IN_CHKP_BNDLDX, BUILT_IN_CHKP_BNDRET,
BUILT_IN_CHKP_INTERSECT, BUILT_IN_CHKP_NARROW,
BUILT_IN_CHKP_EXTRACT_LOWER, BUILT_IN_CHKP_EXTRACT_UPPER.
(std_expand_builtin_va_start): Init bounds for va_list.
* cppbuiltin.c (define_builtin_macros_for_compilation_flags): Add
__CHKP__ macro when Pointer Bounds Checker is on.
* params.def (PARAM_CHKP_MAX_CTOR_SIZE): New.
* passes.def (pass_ipa_chkp_versioning): New.
(pass_early_local_passes): Renamed to pass_build_ssa_passes.
(pass_fixup_cfg): Moved to pass_chkp_instrumentation_passes.
(pass_chkp_instrumentation_passes): New.
(pass_ipa_chkp_produce_thunks): New.
(pass_local_optimization_passes): New.
(pass_chkp_opt): New.
* tree-pass.h (make_pass_ipa_chkp_versioning): New.
(make_pass_ipa_chkp_produce_thunks): New.
(make_pass_chkp): New.
(make_pass_chkp_opt): New.
(make_pass_early_local_passes): Renamed to ...
(make_pass_build_ssa_passes): This.
(make_pass_chkp_instrumentation_passes): New.
(make_pass_local_optimization_passes): New.
* passes.c (pass_manager::execute_early_local_passes): Execute
early passes in three steps.
(execute_all_early_local_passes): Renamed to ...
(execute_build_ssa_passes): This.
(pass_data_early_local_passes): Renamed to ...
(pass_data_build_ssa_passes): This.
(pass_early_local_passes): Renamed to ...
(pass_build_ssa_passes): This.
(pass_data_chkp_instrumentation_passes): New.
(pass_chkp_instrumentation_passes): New.
(pass_data_local_optimization_passes): New.
(pass_local_optimization_passes): New.
(make_pass_early_local_passes): Renamed to ...
(make_pass_build_ssa_passes): This.
(make_pass_chkp_instrumentation_passes): New.
(make_pass_local_optimization_passes): New.
* c-family/c.opt (fcheck-pointer-bounds): New.
(fchkp-check-incomplete-type): New.
(fchkp-zero-input-bounds-for-main): New.
(fchkp-first-field-has-own-bounds): New.
(fchkp-narrow-bounds): New.
(fchkp-narrow-to-innermost-array): New.
(fchkp-optimize): New.
(fchkp-use-fast-string-functions): New.
(fchkp-use-nochk-string-functions): New.
(fchkp-use-static-bounds): New.
(fchkp-use-static-const-bounds): New.
(fchkp-treat-zero-dynamic-size-as-infinite): New.
(fchkp-check-read): New.
(fchkp-check-write): New.
(fchkp-store-bounds): New.
(fchkp-instrument-calls): New.
(fchkp-instrument-marked-only): New.
(Wchkp): New.
* c-family/c-common.c (handle_bnd_variable_size_attribute): New.
(handle_bnd_legacy): New.
(handle_bnd_instrument): New.
(c_common_attribute_table): Add bnd_variable_size, bnd_legacy
and bnd_instrument. Fix documentation.
(c_common_format_attribute_table): Likewsie.
* toplev.c: include tree-chkp.h.
(process_options): Check Pointer Bounds Checker is supported.
(compile_file): Add chkp_finish_file call.
* ipa-cp.c (initialize_node_lattices): Use cgraph_local_p
to handle instrumentation clones properly.
(propagate_constants_accross_call): Do not propagate
through instrumentation thunks.
* ipa-pure-const.c (propagate_pure_const): Support
IPA_REF_CHKP.
* ipa-inline.c (early_inliner): Check edge has summary allocated.
* ipa-split.c: Include tree-chkp.h.
(find_retbnd): New.
(split_part_set_ssa_name_p): New.
(consider_split): Do not split retbnd and retval
producers.
(insert_bndret_call_after): new.
(split_function): Propagate Pointer Bounds Checker
instrumentation marks and handle returned bounds.
* tree-ssa-sccvn.h (vn_reference_op_struct): Transform opcode
into bit field and add with_bounds field.
* tree-ssa-sccvn.c (copy_reference_ops_from_call): Set
with_bounds field for instrumented calls.
* tree-ssa-pre.c (create_component_ref_by_pieces_1): Restore
CALL_WITH_BOUNDS_P flag for calls.
* tree-ssa-ccp.c: Include tree-chkp.h.
(insert_clobber_before_stack_restore): Handle
BUILT_IN_CHKP_BNDRET calls.
* tree-ssa-dce.c: Include tree-chkp.h.
(propagate_necessity): For free call fed by alloc check
bounds are also provided by the same alloc.
(eliminate_unnecessary_stmts): Handle BUILT_IN_CHKP_BNDRET
used by free calls.
* tree-inline.c: Include tree-chkp.h.
(declare_return_variable): Add arg holding
returned bounds slot. Create and initialize returned bounds var.
(remap_gimple_stmt): Handle returned bounds.
Return sequence of statements instead of a single statement.
(insert_init_stmt): Add declaration.
(remap_gimple_seq): Adjust to new remap_gimple_stmt signature.
(copy_bb): Adjust to changed return type of remap_gimple_stmt.
Properly handle bounds in va_arg_pack and va_arg_pack_len.
(expand_call_inline): Handle returned bounds. Add bounds copy
for generated mem to mem assignments.
* tree-inline.h (copy_body_data): Add fields retbnd and
assign_stmts.
* value-prof.c: Include tree-chkp.h.
(gimple_ic): Support returned bounds.
* ipa.c (cgraph_build_static_cdtor_1): Support contructors
with "chkp ctor" and "bnd_legacy" attributes.
(symtab_remove_unreachable_nodes): Keep initial values for
pointer bounds to be used for checks eliminations.
(process_references): Handle IPA_REF_CHKP.
(walk_polymorphic_call_targets): Likewise.
* ipa-visibility.c (cgraph_externally_visible_p): Mark
instrumented 'main' as externally visible.
(function_and_variable_visibility): Filter instrumentation
thunks.
* cgraph.h (cgraph_thunk_info): Add add_pointer_bounds_args
field.
(cgraph_node): Add instrumented_version, orig_decl and
instrumentation_clone fields.
(symtab_node::get_alias_target): Allow IPA_REF_CHKP reference.
(varpool_node): Add need_bounds_init field.
(cgraph_local_p): New.
* cgraph.c: Include tree-chkp.h.
(cgraph_node::remove): Fix instrumented_version
of the referenced node if any.
(cgraph_node::dump): Dump instrumentation_clone and
instrumented_version fields.
(cgraph_node::verify_node): Check correctness of IPA_REF_CHKP
references and instrumentation thunks.
(cgraph_can_remove_if_no_direct_calls_and_refs_p): Keep
all not instrumented instrumentation clones alive.
(cgraph_redirect_edge_call_stmt_to_callee): Support
returned bounds.
* cgraphbuild.c (rebuild_cgraph_edges): Rebuild IPA_REF_CHKP
reference.
(cgraph_rebuild_references): Likewise.
* cgraphunit.c: Include tree-chkp.h.
(assemble_thunks_and_aliases): Skip thunks calling instrumneted
function version.
(varpool_finalize_decl): Register statically initialized decls
in Pointer Bounds Checker.
(walk_polymorphic_call_targets): Do not mark generated call to
__builtin_unreachable as with_bounds.
(output_weakrefs): If there are both instrumented and original
versions, output only one of them.
(cgraph_node::expand_thunk): Set with_bounds flag
for created call statement.
* ipa-ref.h (ipa_ref_use): Add IPA_REF_CHKP.
(ipa_ref): increase size of use field.
* symtab.c (ipa_ref_use_name): Add element for IPA_REF_CHKP.
* varpool.c (dump_varpool_node): Dump need_bounds_init field.
(ctor_for_folding): Do not fold constant bounds vars.
* lto-streamer.h (LTO_minor_version): Change minor version from
0 to 1.
* lto-cgraph.c (compute_ltrans_boundary): Keep initial values for
pointer bounds.
(lto_output_node): Output instrumentation_clone,
thunk.add_pointer_bounds_args and orig_decl field.
(lto_output_ref): Adjust to new ipa_ref::use field size.
(input_overwrite_node): Read instrumentation_clone field.
(input_node): Read thunk.add_pointer_bounds_args and orig_decl
fields.
(input_ref): Adjust to new ipa_ref::use field size.
(input_cgraph_1): Compute instrumented_version fields and restore
IDENTIFIER_TRANSPARENT_ALIAS chains.
(lto_output_varpool_node): Output
need_bounds_init value.
(input_varpool_node): Read need_bounds_init value.
* lto-partition.c (add_symbol_to_partition_1): Keep original
and instrumented versions together.
(privatize_symbol_name): Restore transparent alias chain if required.
(add_references_to_partition): Add references to pointer bounds vars.
* dbxout.c (dbxout_type): Ignore POINTER_BOUNDS_TYPE.
* dwarf2out.c (gen_subprogram_die): Ignore bound args.
(gen_type_die_with_usage): Skip pointer bounds.
(dwarf2out_global_decl): Likewise.
(is_base_type): Support POINTER_BOUNDS_TYPE.
(gen_formal_types_die): Skip pointer bounds.
(gen_decl_die): Likewise.
* var-tracking.c (vt_add_function_parameters): Skip
bounds parameters.
* ipa-icf.c (sem_function::merge): Do not merge when instrumentation
thunk still exists.
(sem_variable::merge): Reset need_bounds_init flag.
* doc/extend.texi: Document Pointer Bounds Checker built-in functions
and attributes.
* doc/tm.texi.in (TARGET_LOAD_BOUNDS_FOR_ARG): New.
(TARGET_STORE_BOUNDS_FOR_ARG): New.
(TARGET_LOAD_RETURNED_BOUNDS): New.
(TARGET_STORE_RETURNED_BOUNDS): New.
(TARGET_CHKP_FUNCTION_VALUE_BOUNDS): New.
(TARGET_SETUP_INCOMING_VARARG_BOUNDS): New.
(TARGET_BUILTIN_CHKP_FUNCTION): New.
(TARGET_CHKP_BOUND_TYPE): New.
(TARGET_CHKP_BOUND_MODE): New.
(TARGET_CHKP_MAKE_BOUNDS_CONSTANT): New.
(TARGET_CHKP_INITIALIZE_BOUNDS): New.
* doc/tm.texi: Regenerated.
* doc/rtl.texi (MODE_POINTER_BOUNDS): New.
(BND32mode): New.
(BND64mode): New.
* doc/invoke.texi (-mmpx): New.
(-mno-mpx): New.
(chkp-max-ctor-size): New.
* config/i386/constraints.md (w): New.
(Ti): New.
(Tb): New.
* config/i386/i386-c.c (ix86_target_macros_internal): Add __MPX__.
* config/i386/i386-modes.def (BND32): New.
(BND64): New.
* config/i386/i386-protos.h (ix86_bnd_prefixed_insn_p): New.
* config/i386/i386.c: Include tree-chkp.h, rtl-chkp.h, tree-iterator.h.
(regclass_map): Add bound registers.
(dbx_register_map): Likewise.
(dbx64_register_map): Likewise.
(svr4_dbx_register_map): Likewise.
(isa_opts): Add -mmpx.
(PTA_MPX): New.
(ix86_option_override_internal): Support MPX ISA.
(ix86_conditional_register_usage): Support bound registers.
(ix86_code_end): Add MPX bnd prefix.
(output_set_got): Likewise.
(print_reg): Avoid prefixes for bound registers.
(ix86_print_operand): Add '!' (MPX bnd) print prefix support.
(ix86_print_operand_punct_valid_p): Likewise.
(ix86_print_operand_address): Support UNSPEC_BNDMK_ADDR and
UNSPEC_BNDLDX_ADDR.
(ix86_output_call_insn): Add MPX bnd prefix to branch instructions.
(ix86_class_likely_spilled_p): Add bound regs support.
(ix86_hard_regno_mode_ok): Likewise.
(x86_order_regs_for_local_alloc): Likewise.
(ix86_bnd_prefixed_insn_p): New.
(ix86_builtins): Add
IX86_BUILTIN_BNDMK, IX86_BUILTIN_BNDSTX,
IX86_BUILTIN_BNDLDX, IX86_BUILTIN_BNDCL,
IX86_BUILTIN_BNDCU, IX86_BUILTIN_BNDRET,
IX86_BUILTIN_BNDNARROW, IX86_BUILTIN_BNDINT,
IX86_BUILTIN_SIZEOF, IX86_BUILTIN_BNDLOWER,
IX86_BUILTIN_BNDUPPER.
(builtin_isa): Add leaf_p and nothrow_p fields.
(def_builtin): Initialize leaf_p and nothrow_p.
(ix86_add_new_builtins): Handle leaf_p and nothrow_p
flags.
(bdesc_mpx): New.
(bdesc_mpx_const): New.
(ix86_init_mpx_builtins): New.
(ix86_init_builtins): Call ix86_init_mpx_builtins.
(ix86_emit_cmove): New.
(ix86_emit_move_max): New.
(ix86_expand_builtin): Expand IX86_BUILTIN_BNDMK,
IX86_BUILTIN_BNDSTX, IX86_BUILTIN_BNDLDX,
IX86_BUILTIN_BNDCL, IX86_BUILTIN_BNDCU,
IX86_BUILTIN_BNDRET, IX86_BUILTIN_BNDNARROW,
IX86_BUILTIN_BNDINT, IX86_BUILTIN_SIZEOF,
IX86_BUILTIN_BNDLOWER, IX86_BUILTIN_BNDUPPER.
(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.
(ix86_option_override_internal): Do not
support x32 with MPX.
(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_setup_incoming_vararg_bounds): New.
(ix86_va_start): Initialize bounds for pointers in va_list.
(TARGET_SETUP_INCOMING_VARARG_BOUNDS): New.
* config/i386/i386.h (TARGET_MPX): New.
(TARGET_MPX_P): New.
(FIRST_PSEUDO_REGISTER): Fix to new value.
(FIXED_REGISTERS): Add bound registers.
(CALL_USED_REGISTERS): Likewise.
(REG_ALLOC_ORDER): Likewise.
(HARD_REGNO_NREGS): Likewise.
(VALID_BND_REG_MODE): New.
(FIRST_BND_REG): New.
(LAST_BND_REG): New.
(reg_class): Add BND_REGS.
(REG_CLASS_NAMES): Likewise.
(REG_CLASS_CONTENTS): Likewise.
(BND_REGNO_P): New.
(ANY_BND_REG_P): New.
(BNDmode): New.
(HI_REGISTER_NAMES): Add bound registers.
(ix86_args): Add bnd_regno, bnds_in_bt, force_bnd_pass and
stdarg fields.
* config/i386/i386.md (UNSPEC_BNDMK): New.
(UNSPEC_BNDMK_ADDR): New.
(UNSPEC_BNDSTX): New.
(UNSPEC_BNDLDX): New.
(UNSPEC_BNDLDX_ADDR): New.
(UNSPEC_BNDCL): New.
(UNSPEC_BNDCU): New.
(UNSPEC_BNDCN): New.
(UNSPEC_MPX_FENCE): New.
(UNSPEC_SIZEOF): New.
(BND0_REG): New.
(BND1_REG): New.
(type): Add mpxmov, mpxmk, mpxchk, mpxld, mpxst.
(length_immediate): Support mpxmov, mpxmk, mpxchk, mpxld, mpxst.
(prefix_rep): Check for bnd prefix.
(prefix_0f): Support mpxmov, mpxmk, mpxchk, mpxld, mpxst.
(length_nobnd): New.
(length): Use length_nobnd when specified.
(memory): Support mpxmov, mpxmk, mpxchk, mpxld, mpxst.
(BND): New.
(bnd_ptr): New.
(BNDCHECK): New.
(bndcheck): New.
(*jcc_1): Add MPX bnd prefix.
(*jcc_2): Likewise.
(jump): Likewise.
(*indirect_jump): Likewise.
(*tablejump_1): Likewise.
(simple_return_internal): Likewise.
(simple_return_internal_long): Likewise.
(simple_return_pop_internal): Likewise.
(simple_return_indirect_internal): Likewise.
(<mode>_mk): New.
(*<mode>_mk): New.
(mov<mode>): New.
(*mov<mode>_internal_mpx): New.
(<mode>_<bndcheck>): New.
(*<mode>_<bndcheck>): New.
(<mode>_ldx): New.
(*<mode>_ldx): New.
(<mode>_stx): New.
(*<mode>_stx): New.
move_size_reloc_<mode>): New.
* config/i386/predicates.md (address_mpx_no_base_operand): New.
(address_mpx_no_index_operand): New.
(bnd_mem_operator): New.
(symbol_operand): New.
(x86_64_immediate_size_operand): New.
* config/i386/i386.opt (mmpx): New.
* config/i386/i386-builtin-types.def (BND): New.
(ULONG): New.
(BND_FTYPE_PCVOID_ULONG): New.
(VOID_FTYPE_BND_PCVOID): New.
(VOID_FTYPE_PCVOID_PCVOID_BND): New.
(BND_FTYPE_PCVOID_PCVOID): New.
(BND_FTYPE_PCVOID): New.
(BND_FTYPE_BND_BND): New.
(PVOID_FTYPE_PVOID_PVOID_ULONG): New.
(PVOID_FTYPE_PCVOID_BND_ULONG): New.
(ULONG_FTYPE_VOID): New.
(PVOID_FTYPE_BND): New.
gcc/testsuite/
2014-11-05 Ilya Enkovich <ilya.enkovich@intel.com>
* gcc.target/i386/chkp-builtins-1.c: New.
* gcc.target/i386/chkp-builtins-2.c: New.
* gcc.target/i386/chkp-builtins-3.c: New.
* gcc.target/i386/chkp-builtins-4.c: New.
* gcc.target/i386/chkp-remove-bndint-1.c: New.
* gcc.target/i386/chkp-remove-bndint-2.c: New.
* gcc.target/i386/chkp-const-check-1.c: New.
* gcc.target/i386/chkp-const-check-2.c: New.
* gcc.target/i386/chkp-lifetime-1.c: New.
* gcc.dg/pr37858.c: Replace early_local_cleanups pass name
with build_ssa_passes.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@217125 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/i386')
-rw-r--r-- | gcc/config/i386/constraints.md | 15 | ||||
-rw-r--r-- | gcc/config/i386/i386-builtin-types.def | 14 | ||||
-rw-r--r-- | gcc/config/i386/i386-c.c | 2 | ||||
-rw-r--r-- | gcc/config/i386/i386-modes.def | 3 | ||||
-rw-r--r-- | gcc/config/i386/i386-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 1106 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 103 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 259 | ||||
-rw-r--r-- | gcc/config/i386/i386.opt | 4 | ||||
-rw-r--r-- | gcc/config/i386/predicates.md | 77 |
10 files changed, 1506 insertions, 79 deletions
diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md index 8e0a58355ec..4e07d705001 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-builtin-types.def b/gcc/config/i386/i386-builtin-types.def index 8315c5e5f06..864d0ea23a7 100644 --- a/gcc/config/i386/i386-builtin-types.def +++ b/gcc/config/i386/i386-builtin-types.def @@ -47,6 +47,7 @@ DEF_PRIMITIVE_TYPE (UCHAR, unsigned_char_type_node) DEF_PRIMITIVE_TYPE (QI, char_type_node) DEF_PRIMITIVE_TYPE (HI, intHI_type_node) DEF_PRIMITIVE_TYPE (SI, intSI_type_node) +DEF_PRIMITIVE_TYPE (BND, pointer_bounds_type_node) # ??? Logically this should be intDI_type_node, but that maps to "long" # with 64-bit, and that's not how the emmintrin.h is written. Again, # changing this would change name mangling. @@ -61,6 +62,7 @@ DEF_PRIMITIVE_TYPE (USHORT, short_unsigned_type_node) DEF_PRIMITIVE_TYPE (INT, integer_type_node) DEF_PRIMITIVE_TYPE (UINT, unsigned_type_node) DEF_PRIMITIVE_TYPE (UNSIGNED, unsigned_type_node) +DEF_PRIMITIVE_TYPE (ULONG, long_unsigned_type_node) DEF_PRIMITIVE_TYPE (LONGLONG, long_long_integer_type_node) DEF_PRIMITIVE_TYPE (ULONGLONG, long_long_unsigned_type_node) DEF_PRIMITIVE_TYPE (UINT8, unsigned_char_type_node) @@ -1242,3 +1244,15 @@ DEF_FUNCTION_TYPE_ALIAS (V2DI_FTYPE_V2DI_V2DI, TF) DEF_FUNCTION_TYPE_ALIAS (V4SF_FTYPE_V4SF_V4SF, TF) DEF_FUNCTION_TYPE_ALIAS (V4SI_FTYPE_V4SI_V4SI, TF) DEF_FUNCTION_TYPE_ALIAS (V8HI_FTYPE_V8HI_V8HI, TF) + +# MPX builtins +DEF_FUNCTION_TYPE (BND, PCVOID, ULONG) +DEF_FUNCTION_TYPE (VOID, PCVOID, BND) +DEF_FUNCTION_TYPE (VOID, PCVOID, BND, PCVOID) +DEF_FUNCTION_TYPE (BND, PCVOID, PCVOID) +DEF_FUNCTION_TYPE (BND, PCVOID) +DEF_FUNCTION_TYPE (BND, BND, BND) +DEF_FUNCTION_TYPE (PVOID, PVOID, PVOID, ULONG) +DEF_FUNCTION_TYPE (PVOID, PCVOID, BND, ULONG) +DEF_FUNCTION_TYPE (ULONG, VOID) +DEF_FUNCTION_TYPE (PVOID, BND) diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c index a3858edb240..0a0775dbbcc 100644 --- a/gcc/config/i386/i386-c.c +++ b/gcc/config/i386/i386-c.c @@ -405,6 +405,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 c24abe6fea7..37752386cb5 100644 --- a/gcc/config/i386/i386-modes.def +++ b/gcc/config/i386/i386-modes.def @@ -90,6 +90,9 @@ VECTOR_MODE (INT, QI, 12); /* V12QI */ VECTOR_MODE (INT, QI, 14); /* V14QI */ VECTOR_MODE (INT, HI, 6); /* V6HI */ +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 c9cee996e2b..d14a107e8c2 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -232,6 +232,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 c528599f868..8f03aa25e1e 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -99,6 +99,9 @@ along with GCC; see the file COPYING3. If not see #include "shrink-wrap.h" #include "builtins.h" #include "rtl-iter.h" +#include "tree-iterator.h" +#include "tree-chkp.h" +#include "rtl-chkp.h" static rtx legitimize_dllimport_symbol (rtx, bool); static rtx legitimize_pe_coff_extern_decl (rtx, bool); @@ -2145,6 +2148,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. */ @@ -2161,6 +2166,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. */ @@ -2177,6 +2183,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. @@ -2245,6 +2252,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. */ @@ -2646,6 +2654,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. */ @@ -3135,6 +3144,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) @@ -3720,12 +3730,21 @@ ix86_option_override_internal (bool main_args_p, if (processor_alias_table[i].flags & PTA_AVX512VL && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX512VL)) opts->x_ix86_isa_flags |= OPTION_MASK_ISA_AVX512VL; + 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 (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); @@ -4388,6 +4407,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] = ""; } @@ -6286,10 +6310,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 = stdarg_p (fntype); 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 @@ -7224,13 +7253,17 @@ construct_container (machine_mode mode, machine_mode orig_mode, /* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. (TYPE is null for libcalls where that information - may not be available.) */ + may not be available.) -static void + Return a number of integer regsiters advanced over. */ + +static int function_arg_advance_32 (CUMULATIVE_ARGS *cum, machine_mode mode, const_tree type, HOST_WIDE_INT bytes, HOST_WIDE_INT words) { + int res = 0; + switch (mode) { default: @@ -7248,7 +7281,8 @@ function_arg_advance_32 (CUMULATIVE_ARGS *cum, 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; @@ -7319,9 +7353,11 @@ function_arg_advance_32 (CUMULATIVE_ARGS *cum, machine_mode mode, } break; } + + return res; } -static void +static int function_arg_advance_64 (CUMULATIVE_ARGS *cum, machine_mode mode, const_tree type, HOST_WIDE_INT words, bool named) { @@ -7330,7 +7366,7 @@ function_arg_advance_64 (CUMULATIVE_ARGS *cum, machine_mode mode, /* 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; if (!examine_argument (mode, type, 0, &int_nregs, &sse_nregs) && sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs) @@ -7339,16 +7375,18 @@ function_arg_advance_64 (CUMULATIVE_ARGS *cum, machine_mode mode, 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) { @@ -7360,7 +7398,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 @@ -7373,6 +7413,7 @@ ix86_function_arg_advance (cumulative_args_t cum_v, 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); @@ -7383,12 +7424,51 @@ ix86_function_arg_advance (cumulative_args_t cum_v, 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. @@ -7623,6 +7703,23 @@ ix86_function_arg (cumulative_args_t cum_v, machine_mode omode, HOST_WIDE_INT bytes, words; rtx arg; + /* All pointer bounds argumntas are handled separately here. */ + if ((type && POINTER_BOUNDS_TYPE_P (type)) + || POINTER_BOUNDS_MODE_P (mode)) + { + /* Return NULL if bounds are forced to go in Bounds Table. */ + if (cum->bnds_in_bt) + arg = NULL; + /* Return the next available bound reg if any. */ + else if (cum->bnd_regno <= LAST_BND_REG) + arg = gen_rtx_REG (BNDmode, cum->bnd_regno); + /* Return the next special slot number otherwise. */ + else + arg = GEN_INT (cum->bnd_regno - LAST_BND_REG - 1); + + return arg; + } + if (mode == BLKmode) bytes = int_size_in_bytes (type); else @@ -7896,6 +7993,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: @@ -8072,7 +8172,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); @@ -8090,6 +8193,57 @@ 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; + rtx bounds[2]; + bitmap_iterator bi; + unsigned i, bnd_no = 0; + + bitmap_obstack_initialize (NULL); + slots = BITMAP_ALLOC (NULL); + chkp_find_bound_slots (valtype, slots); + + 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); + bitmap_obstack_release (NULL); + } + else + res = NULL_RTX; + + return res; +} + /* Pointer function arguments and return values are promoted to word_mode. */ @@ -8136,6 +8290,9 @@ ix86_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) const machine_mode mode = type_natural_mode (type, NULL, true); HOST_WIDE_INT size; + if (POINTER_BOUNDS_TYPE_P (type)) + return false; + if (TARGET_64BIT) { if (ix86_function_type_abi (fntype) == MS_ABI) @@ -8451,6 +8608,71 @@ ix86_setup_incoming_varargs (cumulative_args_t cum_v, machine_mode mode, setup_incoming_varargs_64 (&next_cum); } +static void +ix86_setup_incoming_vararg_bounds (cumulative_args_t cum_v, + enum machine_mode mode, + tree type, + int *pretend_size ATTRIBUTE_UNUSED, + int no_rtl) +{ + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); + CUMULATIVE_ARGS next_cum; + tree fntype; + rtx save_area; + int bnd_reg, i, max; + + gcc_assert (!no_rtl); + + /* Do nothing if we use plain pointer to argument area. */ + if (!TARGET_64BIT || cum->call_abi == MS_ABI) + return; + + fntype = TREE_TYPE (current_function_decl); + + /* For varargs, we do not want to skip the dummy va_dcl argument. + For stdargs, we do want to skip the last named argument. */ + next_cum = *cum; + if (stdarg_p (fntype)) + ix86_function_arg_advance (pack_cumulative_args (&next_cum), mode, type, + true); + save_area = frame_pointer_rtx; + + max = cum->regno + cfun->va_list_gpr_size / UNITS_PER_WORD; + if (max > X86_64_REGPARM_MAX) + max = X86_64_REGPARM_MAX; + + bnd_reg = cum->bnd_regno + cum->force_bnd_pass; + if (chkp_function_instrumented_p (current_function_decl)) + for (i = cum->regno; i < max; i++) + { + rtx addr = plus_constant (Pmode, save_area, i * UNITS_PER_WORD); + rtx reg = gen_rtx_REG (DImode, + x86_64_int_parameter_registers[i]); + rtx ptr = reg; + rtx bounds; + + if (bnd_reg <= LAST_BND_REG) + bounds = gen_rtx_REG (BNDmode, bnd_reg); + else + { + rtx ldx_addr = + plus_constant (Pmode, arg_pointer_rtx, + (LAST_BND_REG - bnd_reg) * GET_MODE_SIZE (Pmode)); + bounds = gen_reg_rtx (BNDmode); + emit_insn (BNDmode == BND64mode + ? gen_bnd64_ldx (bounds, ldx_addr, ptr) + : gen_bnd32_ldx (bounds, ldx_addr, ptr)); + } + + emit_insn (BNDmode == BND64mode + ? gen_bnd64_stx (addr, ptr, bounds) + : gen_bnd32_stx (addr, ptr, bounds)); + + bnd_reg++; + } +} + + /* Checks if TYPE is of kind va_list char *. */ static bool @@ -8525,6 +8747,13 @@ ix86_va_start (tree valist, rtx nextarg) crtl->args.arg_offset_rtx, NULL_RTX, 0, OPTAB_LIB_WIDEN); convert_move (va_r, next, 0); + + /* Store zero bounds for va_list. */ + if (chkp_function_instrumented_p (current_function_decl)) + chkp_expand_bounds_reset_for_mem (valist, + make_tree (TREE_TYPE (valist), + next)); + } return; } @@ -8578,6 +8807,11 @@ ix86_va_start (tree valist, rtx nextarg) t = make_tree (type, ovf_rtx); if (words != 0) t = fold_build_pointer_plus_hwi (t, words * UNITS_PER_WORD); + + /* Store zero bounds for overflow area pointer. */ + if (chkp_function_instrumented_p (current_function_decl)) + chkp_expand_bounds_reset_for_mem (ovf, t); + t = build2 (MODIFY_EXPR, type, ovf, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); @@ -8590,6 +8824,11 @@ ix86_va_start (tree valist, rtx nextarg) t = make_tree (type, frame_pointer_rtx); if (!ix86_varargs_gpr_size) t = fold_build_pointer_plus_hwi (t, -8 * X86_64_REGPARM_MAX); + + /* Store zero bounds for save area pointer. */ + if (chkp_function_instrumented_p (current_function_decl)) + chkp_expand_bounds_reset_for_mem (sav, t); + t = build2 (MODIFY_EXPR, type, sav, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); @@ -9343,7 +9582,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); @@ -9401,7 +9640,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. @@ -12584,6 +12823,10 @@ darwin_local_data_pic (rtx disp) static bool ix86_legitimate_constant_p (machine_mode, rtx x) { + /* Pointer bounds constants are not valid. */ + if (POINTER_BOUNDS_MODE_P (GET_MODE (x))) + return false; + switch (GET_CODE (x)) { case CONST: @@ -14833,7 +15076,7 @@ print_reg (rtx x, int code, FILE *file) case 8: case 4: case 12: - if (! ANY_FP_REG_P (x) && ! ANY_MASK_REG_P (x)) + if (! ANY_FP_REG_P (x) && ! ANY_MASK_REG_P (x) && ! ANY_BND_REG_P (x)) putc (code == 8 && TARGET_64BIT ? 'r' : 'e', file); /* FALLTHRU */ case 16: @@ -14922,6 +15165,7 @@ print_reg (rtx x, int code, FILE *file) ~ -- 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 @@ -15464,6 +15708,11 @@ ix86_print_operand (FILE *file, rtx x, int code) fputs ("addr32 ", file); return; + case '!': + if (ix86_bnd_prefixed_insn_p (current_output_insn)) + fputs ("bnd ", file); + return; + default: output_operand_lossage ("invalid operand code '%c'", code); } @@ -15606,7 +15855,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. */ @@ -15636,6 +15885,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); @@ -25151,8 +25419,21 @@ 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); + { + /* We should add bounds as destination register in case + pointer with bounds may be returned. */ + if (TARGET_MPX && SCALAR_INT_MODE_P (GET_MODE (retval))) + { + rtx b0 = gen_rtx_REG (BND64mode, FIRST_BND_REG); + rtx b1 = gen_rtx_REG (BND64mode, FIRST_BND_REG + 1); + retval = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (3, retval, b0, b1)); + chkp_put_regs_to_expr_list (retval); + } + + call = gen_rtx_SET (VOIDmode, retval, call); + } vec[vec_len++] = call; if (pop) @@ -25199,13 +25480,13 @@ ix86_output_call_insn (rtx_insn *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 ""; @@ -25242,9 +25523,9 @@ ix86_output_call_insn (rtx_insn *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); @@ -29959,6 +30240,19 @@ enum ix86_builtins IX86_BUILTIN_XABORT, IX86_BUILTIN_XTEST, + /* MPX */ + IX86_BUILTIN_BNDMK, + IX86_BUILTIN_BNDSTX, + IX86_BUILTIN_BNDLDX, + IX86_BUILTIN_BNDCL, + IX86_BUILTIN_BNDCU, + IX86_BUILTIN_BNDRET, + IX86_BUILTIN_BNDNARROW, + IX86_BUILTIN_BNDINT, + IX86_BUILTIN_SIZEOF, + IX86_BUILTIN_BNDLOWER, + IX86_BUILTIN_BNDUPPER, + /* BMI instructions. */ IX86_BUILTIN_BEXTR32, IX86_BUILTIN_BEXTR64, @@ -30036,6 +30330,8 @@ struct builtin_isa { enum ix86_builtin_func_type tcode; /* type to use in the declaration */ HOST_WIDE_INT isa; /* isa_flags this builtin is defined for */ bool const_p; /* true if the declaration is constant */ + bool leaf_p; /* true if the declaration has leaf attribute */ + bool nothrow_p; /* true if the declaration has nothrow attribute */ bool set_and_not_built_p; }; @@ -30087,6 +30383,8 @@ def_builtin (HOST_WIDE_INT mask, const char *name, ix86_builtins[(int) code] = NULL_TREE; ix86_builtins_isa[(int) code].tcode = tcode; ix86_builtins_isa[(int) code].name = name; + ix86_builtins_isa[(int) code].leaf_p = false; + ix86_builtins_isa[(int) code].nothrow_p = false; ix86_builtins_isa[(int) code].const_p = false; ix86_builtins_isa[(int) code].set_and_not_built_p = true; } @@ -30137,6 +30435,11 @@ ix86_add_new_builtins (HOST_WIDE_INT isa) ix86_builtins[i] = decl; if (ix86_builtins_isa[i].const_p) TREE_READONLY (decl) = 1; + if (ix86_builtins_isa[i].leaf_p) + DECL_ATTRIBUTES (decl) = build_tree_list (get_identifier ("leaf"), + NULL_TREE); + if (ix86_builtins_isa[i].nothrow_p) + TREE_NOTHROW (decl) = 1; } } } @@ -32558,6 +32861,27 @@ static const struct builtin_description bdesc_round_args[] = { OPTION_MASK_ISA_AVX512DQ, CODE_FOR_avx512dq_rangepv8df_mask_round, "__builtin_ia32_rangepd512_mask", IX86_BUILTIN_RANGEPD512, UNKNOWN, (int) V8DF_FTYPE_V8DF_V8DF_INT_V8DF_QI_INT }, }; +/* Bultins for MPX. */ +static const struct builtin_description bdesc_mpx[] = +{ + { OPTION_MASK_ISA_MPX, (enum insn_code)0, "__builtin_ia32_bndstx", IX86_BUILTIN_BNDSTX, UNKNOWN, (int) VOID_FTYPE_PCVOID_BND_PCVOID }, + { OPTION_MASK_ISA_MPX, (enum insn_code)0, "__builtin_ia32_bndcl", IX86_BUILTIN_BNDCL, UNKNOWN, (int) VOID_FTYPE_PCVOID_BND }, + { OPTION_MASK_ISA_MPX, (enum insn_code)0, "__builtin_ia32_bndcu", IX86_BUILTIN_BNDCU, UNKNOWN, (int) VOID_FTYPE_PCVOID_BND }, +}; + +/* Const builtins for MPX. */ +static const struct builtin_description bdesc_mpx_const[] = +{ + { OPTION_MASK_ISA_MPX, (enum insn_code)0, "__builtin_ia32_bndmk", IX86_BUILTIN_BNDMK, UNKNOWN, (int) BND_FTYPE_PCVOID_ULONG }, + { OPTION_MASK_ISA_MPX, (enum insn_code)0, "__builtin_ia32_bndldx", IX86_BUILTIN_BNDLDX, UNKNOWN, (int) BND_FTYPE_PCVOID_PCVOID }, + { OPTION_MASK_ISA_MPX, (enum insn_code)0, "__builtin_ia32_narrow_bounds", IX86_BUILTIN_BNDNARROW, UNKNOWN, (int) PVOID_FTYPE_PCVOID_BND_ULONG }, + { OPTION_MASK_ISA_MPX, (enum insn_code)0, "__builtin_ia32_bndint", IX86_BUILTIN_BNDINT, UNKNOWN, (int) BND_FTYPE_BND_BND }, + { OPTION_MASK_ISA_MPX, (enum insn_code)0, "__builtin_ia32_sizeof", IX86_BUILTIN_SIZEOF, UNKNOWN, (int) ULONG_FTYPE_VOID }, + { OPTION_MASK_ISA_MPX, (enum insn_code)0, "__builtin_ia32_bndlower", IX86_BUILTIN_BNDLOWER, UNKNOWN, (int) PVOID_FTYPE_BND }, + { OPTION_MASK_ISA_MPX, (enum insn_code)0, "__builtin_ia32_bndupper", IX86_BUILTIN_BNDUPPER, UNKNOWN, (int) PVOID_FTYPE_BND }, + { OPTION_MASK_ISA_MPX, (enum insn_code)0, "__builtin_ia32_bndret", IX86_BUILTIN_BNDRET, UNKNOWN, (int) BND_FTYPE_PCVOID }, +}; + /* FMA4 and XOP. */ #define MULTI_ARG_4_DF2_DI_I V2DF_FTYPE_V2DF_V2DF_V2DI_INT #define MULTI_ARG_4_DF2_DI_I1 V4DF_FTYPE_V4DF_V4DF_V4DI_INT @@ -33559,6 +33883,67 @@ ix86_init_mmx_sse_builtins (void) } } +static void +ix86_init_mpx_builtins () +{ + const struct builtin_description * d; + enum ix86_builtin_func_type ftype; + tree decl; + size_t i; + + for (i = 0, d = bdesc_mpx; + i < ARRAY_SIZE (bdesc_mpx); + i++, d++) + { + if (d->name == 0) + continue; + + ftype = (enum ix86_builtin_func_type) d->flag; + decl = def_builtin (d->mask, d->name, ftype, d->code); + + /* With no leaf and nothrow flags for MPX builtins + abnormal edges may follow its call when setjmp + presents in the function. Since we may have a lot + of MPX builtins calls it causes lots of useless + edges and enormous PHI nodes. To avoid this we mark + MPX builtins as leaf and nothrow. */ + if (decl) + { + DECL_ATTRIBUTES (decl) = build_tree_list (get_identifier ("leaf"), + NULL_TREE); + TREE_NOTHROW (decl) = 1; + } + else + { + ix86_builtins_isa[(int)d->code].leaf_p = true; + ix86_builtins_isa[(int)d->code].nothrow_p = true; + } + } + + for (i = 0, d = bdesc_mpx_const; + i < ARRAY_SIZE (bdesc_mpx_const); + i++, d++) + { + if (d->name == 0) + continue; + + ftype = (enum ix86_builtin_func_type) d->flag; + decl = def_builtin_const (d->mask, d->name, ftype, d->code); + + if (decl) + { + DECL_ATTRIBUTES (decl) = build_tree_list (get_identifier ("leaf"), + NULL_TREE); + TREE_NOTHROW (decl) = 1; + } + else + { + ix86_builtins_isa[(int)d->code].leaf_p = true; + ix86_builtins_isa[(int)d->code].nothrow_p = true; + } + } +} + /* This adds a condition to the basic_block NEW_BB in function FUNCTION_DECL to return a pointer to VERSION_DECL if the outcome of the expression formed by PREDICATE_CHAIN is true. This function will be called during @@ -35097,6 +35482,7 @@ ix86_init_builtins (void) ix86_init_tm_builtins (); ix86_init_mmx_sse_builtins (); + ix86_init_mpx_builtins (); if (TARGET_LP64) ix86_init_builtins_va_builtins_abi (); @@ -37723,6 +38109,37 @@ ix86_expand_vec_set_builtin (tree exp) return target; } +/* Emit conditional move of SRC to DST with condition + OP1 CODE OP2. */ +static void +ix86_emit_cmove (rtx dst, rtx src, enum rtx_code code, rtx op1, rtx op2) +{ + rtx t; + + if (TARGET_CMOVE) + { + t = ix86_expand_compare (code, op1, op2); + emit_insn (gen_rtx_SET (VOIDmode, dst, + gen_rtx_IF_THEN_ELSE (GET_MODE (dst), t, + src, dst))); + } + else + { + rtx nomove = gen_label_rtx (); + emit_cmp_and_jump_insns (op1, op2, reverse_condition (code), + const0_rtx, GET_MODE (op1), 1, nomove); + emit_move_insn (dst, src); + emit_label (nomove); + } +} + +/* Choose max of DST and SRC and put it to DST. */ +static void +ix86_emit_move_max (rtx dst, rtx src) +{ + ix86_emit_cmove (dst, src, LTU, dst, src); +} + /* Expand an expression EXP that calls a built-in function, with result going to TARGET if that's convenient (and in mode MODE if that's convenient). @@ -37788,6 +38205,343 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget, switch (fcode) { + case IX86_BUILTIN_BNDMK: + if (!target + || GET_MODE (target) != BNDmode + || !register_operand (target, BNDmode)) + target = gen_reg_rtx (BNDmode); + + arg0 = CALL_EXPR_ARG (exp, 0); + arg1 = CALL_EXPR_ARG (exp, 1); + + op0 = expand_normal (arg0); + op1 = expand_normal (arg1); + + if (!register_operand (op0, Pmode)) + op0 = ix86_zero_extend_to_Pmode (op0); + if (!register_operand (op1, Pmode)) + op1 = ix86_zero_extend_to_Pmode (op1); + + /* Builtin arg1 is size of block but instruction op1 should + be (size - 1). */ + op1 = expand_simple_binop (Pmode, PLUS, op1, constm1_rtx, + NULL_RTX, 1, OPTAB_DIRECT); + + emit_insn (BNDmode == BND64mode + ? gen_bnd64_mk (target, op0, op1) + : gen_bnd32_mk (target, op0, op1)); + return target; + + case IX86_BUILTIN_BNDSTX: + arg0 = CALL_EXPR_ARG (exp, 0); + arg1 = CALL_EXPR_ARG (exp, 1); + arg2 = CALL_EXPR_ARG (exp, 2); + + op0 = expand_normal (arg0); + op1 = expand_normal (arg1); + op2 = expand_normal (arg2); + + if (!register_operand (op0, Pmode)) + op0 = ix86_zero_extend_to_Pmode (op0); + if (!register_operand (op1, BNDmode)) + op1 = copy_to_mode_reg (BNDmode, op1); + if (!register_operand (op2, Pmode)) + op2 = ix86_zero_extend_to_Pmode (op2); + + emit_insn (BNDmode == BND64mode + ? gen_bnd64_stx (op2, op0, op1) + : gen_bnd32_stx (op2, op0, op1)); + return 0; + + case IX86_BUILTIN_BNDLDX: + if (!target + || GET_MODE (target) != BNDmode + || !register_operand (target, BNDmode)) + target = gen_reg_rtx (BNDmode); + + arg0 = CALL_EXPR_ARG (exp, 0); + arg1 = CALL_EXPR_ARG (exp, 1); + + op0 = expand_normal (arg0); + op1 = expand_normal (arg1); + + if (!register_operand (op0, Pmode)) + op0 = ix86_zero_extend_to_Pmode (op0); + if (!register_operand (op1, Pmode)) + op1 = ix86_zero_extend_to_Pmode (op1); + + emit_insn (BNDmode == BND64mode + ? gen_bnd64_ldx (target, op0, op1) + : gen_bnd32_ldx (target, op0, op1)); + return target; + + case IX86_BUILTIN_BNDCL: + arg0 = CALL_EXPR_ARG (exp, 0); + arg1 = CALL_EXPR_ARG (exp, 1); + + op0 = expand_normal (arg0); + op1 = expand_normal (arg1); + + if (!register_operand (op0, Pmode)) + op0 = ix86_zero_extend_to_Pmode (op0); + if (!register_operand (op1, BNDmode)) + op1 = copy_to_mode_reg (BNDmode, op1); + + emit_insn (BNDmode == BND64mode + ? gen_bnd64_cl (op1, op0) + : gen_bnd32_cl (op1, op0)); + return 0; + + case IX86_BUILTIN_BNDCU: + arg0 = CALL_EXPR_ARG (exp, 0); + arg1 = CALL_EXPR_ARG (exp, 1); + + op0 = expand_normal (arg0); + op1 = expand_normal (arg1); + + if (!register_operand (op0, Pmode)) + op0 = ix86_zero_extend_to_Pmode (op0); + if (!register_operand (op1, BNDmode)) + op1 = copy_to_mode_reg (BNDmode, op1); + + emit_insn (BNDmode == BND64mode + ? gen_bnd64_cu (op1, op0) + : gen_bnd32_cu (op1, op0)); + return 0; + + case IX86_BUILTIN_BNDRET: + arg0 = CALL_EXPR_ARG (exp, 0); + gcc_assert (TREE_CODE (arg0) == SSA_NAME); + target = chkp_get_rtl_bounds (arg0); + + /* If no bounds were specified for returned value, + then use INIT bounds. It usually happens when + some built-in function is expanded. */ + if (!target) + { + rtx t1 = gen_reg_rtx (Pmode); + rtx t2 = gen_reg_rtx (Pmode); + target = gen_reg_rtx (BNDmode); + emit_move_insn (t1, const0_rtx); + emit_move_insn (t2, constm1_rtx); + emit_insn (BNDmode == BND64mode + ? gen_bnd64_mk (target, t1, t2) + : gen_bnd32_mk (target, t1, t2)); + } + + gcc_assert (target && REG_P (target)); + return target; + + case IX86_BUILTIN_BNDNARROW: + { + rtx m1, m1h1, m1h2, lb, ub, t1; + + /* Return value and lb. */ + arg0 = CALL_EXPR_ARG (exp, 0); + /* Bounds. */ + arg1 = CALL_EXPR_ARG (exp, 1); + /* Size. */ + arg2 = CALL_EXPR_ARG (exp, 2); + + lb = expand_normal (arg0); + op1 = expand_normal (arg1); + op2 = expand_normal (arg2); + + /* Size was passed but we need to use (size - 1) as for bndmk. */ + op2 = expand_simple_binop (Pmode, PLUS, op2, constm1_rtx, + NULL_RTX, 1, OPTAB_DIRECT); + + /* Add LB to size and inverse to get UB. */ + op2 = expand_simple_binop (Pmode, PLUS, op2, lb, + op2, 1, OPTAB_DIRECT); + ub = expand_simple_unop (Pmode, NOT, op2, op2, 1); + + if (!register_operand (lb, Pmode)) + lb = ix86_zero_extend_to_Pmode (lb); + if (!register_operand (ub, Pmode)) + ub = ix86_zero_extend_to_Pmode (ub); + + /* We need to move bounds to memory before any computations. */ + if (MEM_P (op1)) + m1 = op1; + else + { + m1 = assign_386_stack_local (BNDmode, SLOT_TEMP); + emit_move_insn (m1, op1); + } + + /* Generate mem expression to be used for access to LB and UB. */ + m1h1 = adjust_address (m1, Pmode, 0); + m1h2 = adjust_address (m1, Pmode, GET_MODE_SIZE (Pmode)); + + t1 = gen_reg_rtx (Pmode); + + /* Compute LB. */ + emit_move_insn (t1, m1h1); + ix86_emit_move_max (t1, lb); + emit_move_insn (m1h1, t1); + + /* Compute UB. UB is stored in 1's complement form. Therefore + we also use max here. */ + emit_move_insn (t1, m1h2); + ix86_emit_move_max (t1, ub); + emit_move_insn (m1h2, t1); + + op2 = gen_reg_rtx (BNDmode); + emit_move_insn (op2, m1); + + return chkp_join_splitted_slot (lb, op2); + } + + case IX86_BUILTIN_BNDINT: + { + rtx res, rh1, rh2, lb1, lb2, ub1, ub2; + + if (!target + || GET_MODE (target) != BNDmode + || !register_operand (target, BNDmode)) + target = gen_reg_rtx (BNDmode); + + arg0 = CALL_EXPR_ARG (exp, 0); + arg1 = CALL_EXPR_ARG (exp, 1); + + op0 = expand_normal (arg0); + op1 = expand_normal (arg1); + + res = assign_386_stack_local (BNDmode, SLOT_TEMP); + rh1 = adjust_address (res, Pmode, 0); + rh2 = adjust_address (res, Pmode, GET_MODE_SIZE (Pmode)); + + /* Put first bounds to temporaries. */ + lb1 = gen_reg_rtx (Pmode); + ub1 = gen_reg_rtx (Pmode); + if (MEM_P (op0)) + { + emit_move_insn (lb1, adjust_address (op0, Pmode, 0)); + emit_move_insn (ub1, adjust_address (op0, Pmode, + GET_MODE_SIZE (Pmode))); + } + else + { + emit_move_insn (res, op0); + emit_move_insn (lb1, rh1); + emit_move_insn (ub1, rh2); + } + + /* Put second bounds to temporaries. */ + lb2 = gen_reg_rtx (Pmode); + ub2 = gen_reg_rtx (Pmode); + if (MEM_P (op1)) + { + emit_move_insn (lb2, adjust_address (op1, Pmode, 0)); + emit_move_insn (ub2, adjust_address (op1, Pmode, + GET_MODE_SIZE (Pmode))); + } + else + { + emit_move_insn (res, op1); + emit_move_insn (lb2, rh1); + emit_move_insn (ub2, rh2); + } + + /* Compute LB. */ + ix86_emit_move_max (lb1, lb2); + emit_move_insn (rh1, lb1); + + /* Compute UB. UB is stored in 1's complement form. Therefore + we also use max here. */ + ix86_emit_move_max (ub1, ub2); + emit_move_insn (rh2, ub1); + + emit_move_insn (target, res); + + return target; + } + + case IX86_BUILTIN_SIZEOF: + { + tree name; + rtx symbol; + + if (!target + || GET_MODE (target) != Pmode + || !register_operand (target, Pmode)) + target = gen_reg_rtx (Pmode); + + arg0 = CALL_EXPR_ARG (exp, 0); + gcc_assert (TREE_CODE (arg0) == VAR_DECL); + + name = DECL_ASSEMBLER_NAME (arg0); + symbol = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (name)); + + emit_insn (Pmode == SImode + ? gen_move_size_reloc_si (target, symbol) + : gen_move_size_reloc_di (target, symbol)); + + return target; + } + + case IX86_BUILTIN_BNDLOWER: + { + rtx mem, hmem; + + if (!target + || GET_MODE (target) != Pmode + || !register_operand (target, Pmode)) + target = gen_reg_rtx (Pmode); + + arg0 = CALL_EXPR_ARG (exp, 0); + op0 = expand_normal (arg0); + + /* We need to move bounds to memory first. */ + if (MEM_P (op0)) + mem = op0; + else + { + mem = assign_386_stack_local (BNDmode, SLOT_TEMP); + emit_move_insn (mem, op0); + } + + /* Generate mem expression to access LB and load it. */ + hmem = adjust_address (mem, Pmode, 0); + emit_move_insn (target, hmem); + + return target; + } + + case IX86_BUILTIN_BNDUPPER: + { + rtx mem, hmem, res; + + if (!target + || GET_MODE (target) != Pmode + || !register_operand (target, Pmode)) + target = gen_reg_rtx (Pmode); + + arg0 = CALL_EXPR_ARG (exp, 0); + op0 = expand_normal (arg0); + + /* We need to move bounds to memory first. */ + if (MEM_P (op0)) + mem = op0; + else + { + mem = assign_386_stack_local (BNDmode, SLOT_TEMP); + emit_move_insn (mem, op0); + } + + /* Generate mem expression to access UB. */ + hmem = adjust_address (mem, Pmode, GET_MODE_SIZE (Pmode)); + + /* We need to inverse all bits of UB. */ + res = expand_simple_unop (Pmode, NOT, hmem, target, 1); + + if (res != target) + emit_move_insn (target, res); + + return target; + } + case IX86_BUILTIN_MASKMOVQ: case IX86_BUILTIN_MASKMOVDQU: icode = (fcode == IX86_BUILTIN_MASKMOVQ @@ -39072,6 +39826,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. */ @@ -40192,6 +41133,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: @@ -40539,6 +41481,8 @@ ix86_hard_regno_mode_ok (int regno, machine_mode mode) if (MASK_REGNO_P (regno)) return (VALID_MASK_REG_MODE (mode) || (TARGET_AVX512BW && VALID_MASK_AVX512BW_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 @@ -41370,6 +42314,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++) @@ -48559,6 +49507,27 @@ 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) +{ + /* 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. */ void @@ -50163,6 +51132,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 @@ -50588,6 +51624,36 @@ 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 + +#undef TARGET_SETUP_INCOMING_VARARG_BOUNDS +#define TARGET_SETUP_INCOMING_VARARG_BOUNDS ix86_setup_incoming_vararg_bounds + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-i386.h" diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 61beb6676c5..53dfd223cda 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -144,6 +144,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) @@ -943,7 +945,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. */ @@ -975,7 +977,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 @@ -1009,7 +1013,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 @@ -1025,7 +1031,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, @@ -1046,8 +1053,8 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); applied to them. */ #define HARD_REGNO_NREGS(REGNO, MODE) \ - (STACK_REGNO_P (REGNO) || SSE_REGNO_P (REGNO) \ - || MMX_REGNO_P (REGNO) || MASK_REGNO_P (REGNO) \ + (STACK_REGNO_P (REGNO) || SSE_REGNO_P (REGNO) || MMX_REGNO_P (REGNO) \ + || MASK_REGNO_P (REGNO) || BND_REGNO_P (REGNO) \ ? (COMPLEX_MODE_P (MODE) ? 2 : 1) \ : ((MODE) == XFmode \ ? (TARGET_64BIT ? 2 : 3) \ @@ -1102,6 +1109,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) @@ -1210,6 +1220,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 @@ -1292,6 +1305,7 @@ enum reg_class SSE_FIRST_REG, SSE_REGS, EVEX_SSE_REGS, + BND_REGS, ALL_SSE_REGS, MMX_REGS, FP_TOP_SSE_REGS, @@ -1349,6 +1363,7 @@ enum reg_class "SSE_FIRST_REG", \ "SSE_REGS", \ "EVEX_SSE_REGS", \ + "BND_REGS", \ "ALL_SSE_REGS", \ "MMX_REGS", \ "FP_TOP_SSE_REGS", \ @@ -1368,37 +1383,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: @@ -1475,6 +1491,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 @@ -1644,6 +1663,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; @@ -1921,6 +1944,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 @@ -2031,7 +2057,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 f8dd5475ede..7e26c693d67 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 @@ -78,6 +79,7 @@ UNSPEC_PLTOFF UNSPEC_MACHOPIC_OFFSET UNSPEC_PCREL + UNSPEC_SIZEOF ;; Prologue support UNSPEC_STACK_ALLOC @@ -182,6 +184,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 +377,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 +413,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 +450,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 +506,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 +619,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 +672,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 +727,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") @@ -964,6 +995,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")]) @@ -10832,10 +10878,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)) @@ -10850,10 +10896,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)) @@ -11291,9 +11337,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)) @@ -11313,7 +11359,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")]) @@ -11362,7 +11408,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")]) @@ -11907,8 +11953,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")]) @@ -11920,7 +11966,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") @@ -11931,8 +11982,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")]) @@ -11941,7 +11992,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")]) @@ -18611,6 +18662,174 @@ (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 it 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" +{ + /* Avoid registers which connot be used as index. */ + if (!index_register_operand (operands[1], Pmode)) + { + rtx temp = gen_reg_rtx (Pmode); + emit_move_insn (temp, operands[1]); + operands[1] = temp; + } + + /* If it was a register originally then it may have + mode other than Pmode. We need to extend in such + case because bndstx may work only with Pmode regs. */ + if (GET_MODE (operands[1]) != Pmode) + operands[1] = ix86_zero_extend_to_Pmode (operands[1]); + + 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")]) + +(define_insn "move_size_reloc_<mode>" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (unspec:SWI48 + [(match_operand:SWI48 1 "symbol_operand")] + UNSPEC_SIZEOF))] + "TARGET_MPX" +{ + if (x86_64_immediate_size_operand (operands[1], VOIDmode)) + return "mov{l}\t{%1@SIZE, %k0|%k0, %1@SIZE}"; + else + return "movabs{q}\t{%1@SIZE, %0|%0, %1@SIZE}"; +} + [(set_attr "type" "imov") + (set_attr "mode" "<MODE>")]) + (include "mmx.md") (include "sse.md") (include "sync.md") diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt index acf6b375157..5dfa9bf8b96 100644 --- a/gcc/config/i386/i386.opt +++ b/gcc/config/i386/i386.opt @@ -814,6 +814,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 7d0b51e1d14..bdcdf180995 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -124,6 +124,10 @@ (match_test "TARGET_64BIT") (match_test "REGNO (op) > BX_REG"))) +;; Return true if VALUE is symbol reference +(define_predicate "symbol_operand" + (match_code "symbol_ref")) + ;; Return true if VALUE can be stored in a sign extended immediate field. (define_predicate "x86_64_immediate_operand" (match_code "const_int,symbol_ref,label_ref,const") @@ -336,6 +340,14 @@ return false; }) +;; Return true if size of VALUE can be stored in a sign +;; extended immediate field. +(define_predicate "x86_64_immediate_size_operand" + (and (match_code "symbol_ref") + (ior (not (match_test "TARGET_64BIT")) + (match_test "ix86_cmodel == CM_SMALL") + (match_test "ix86_cmodel == CM_KERNEL")))) + ;; Return true if OP is general operand representable on x86_64. (define_predicate "x86_64_general_operand" (if_then_else (match_test "TARGET_64BIT") @@ -1006,9 +1018,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") |