From patchwork Sat May 2 11:55:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 1281612 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gcc.gnu.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=QH+LEmVu; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49Dncp3K6fz9sP7 for ; Sat, 2 May 2020 21:55:36 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7983D3870854; Sat, 2 May 2020 11:55:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7983D3870854 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1588420533; bh=g5c0Bo0A8N2uKR7fEMNILlCq5tMOVk2ODSBtSeVYMdk=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=QH+LEmVupcOwvbHsciOvHmTV8AVqdHmgxKLemh39LYcRDFmrPW0Earx26loNY+Sje IUIls/V2s7xewkbRjmbQidqmtF+KOG3lvNWNcxO3SIbs0/+Ff5SabdqUhFN8HncOex y0ifCS4xO3E9ChwE23cO1TbI9QuX70MH8Ymr4qSU= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pl1-x644.google.com (mail-pl1-x644.google.com [IPv6:2607:f8b0:4864:20::644]) by sourceware.org (Postfix) with ESMTPS id 1B4683870842 for ; Sat, 2 May 2020 11:55:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 1B4683870842 Received: by mail-pl1-x644.google.com with SMTP id x6so17330plv.8 for ; Sat, 02 May 2020 04:55:29 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=g5c0Bo0A8N2uKR7fEMNILlCq5tMOVk2ODSBtSeVYMdk=; b=aFrSMm+3VbLkAIZDV7SRTVNAgeP30wKK224lRZvYhIWAGnlLmNn9DVR267OoOGQ3OS XUkXJZ/yhBWE629S11JFjceLtNFAigWnVOewaj6hA4AyEGFG0ygHYK07b+iEoFJauaMG FUQlWD3IQikdn+P+koZSR7GSI9GrakEsRrJuTQtVQkGnP6MTljJ9tLxzc2bSQHhxGN5N Te7+zRbUNUnhQ7hqgP9kkrm8HqOXwvHnOFZjW8BUFjq5++SZv1R72NGls27mOSsGKvhx lBgUliVT3IUcJaYdVBBb6WUvmAN4SL8iFsxyvWaxA4ke6pfEJc6x83XTDeUpmdXIVgOl 3a2g== X-Gm-Message-State: AGi0PuY9nlJB1qDZDrXwbZixvnK1YEwGZnIMqVwf8Kcb8X1Yd4TiUZOx 0biVn5UWxijkswnF1ek31NWdLfmO X-Google-Smtp-Source: APiQypJFcT0MWm5ces3lDsPK5ebIDg6tkL5xe4jpUO3DlLT5gzvk9LxMCW5iVHc72s/j0FyQff4Czw== X-Received: by 2002:a17:902:d70f:: with SMTP id w15mr9396107ply.55.1588420527597; Sat, 02 May 2020 04:55:27 -0700 (PDT) Received: from gnu-cfl-2.localdomain (c-69-181-90-243.hsd1.ca.comcast.net. [69.181.90.243]) by smtp.gmail.com with ESMTPSA id x66sm4427839pfb.173.2020.05.02.04.55.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 02 May 2020 04:55:27 -0700 (PDT) Received: from gnu-cfl-2.localdomain (localhost [IPv6:::1]) by gnu-cfl-2.localdomain (Postfix) with ESMTP id DEB451A00D4; Sat, 2 May 2020 04:55:25 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH] x86: Add UNSPECV_PATCHABLE_AREA Date: Sat, 2 May 2020 04:55:25 -0700 Message-Id: <20200502115525.3527-1-hjl.tools@gmail.com> X-Mailer: git-send-email 2.26.2 MIME-Version: 1.0 X-Spam-Status: No, score=-25.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: "H.J. Lu via Gcc-patches" From: "H.J. Lu" Reply-To: "H.J. Lu" Cc: Jakub Jelinek , Richard Biener , Uros Bizjak Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" Currently patchable area is at the wrong place. It is placed immediately after function label, before both .cfi_startproc and ENDBR. This patch adds UNSPECV_PATCHABLE_AREA for pseudo patchable area instruction and changes ENDBR insertion pass to also insert patchable area instruction. TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY is defined to avoid placing patchable area before .cfi_startproc and ENDBR. OK for master? Thanks. H.J. --- gcc/ PR target/93492 * config/i386/i386-features.c (rest_of_insert_endbranch): Renamed to ... (rest_of_insert_endbr_and_patchable_area): Change return type to void. Add need_endbr and patchable_area_size arguments. Don't call timevar_push nor timevar_pop. Replace endbr_queued_at_entrance with insn_queued_at_entrance. Insert UNSPECV_PATCHABLE_AREA for patchable area. (pass_data_insert_endbranch): Renamed to ... (pass_data_insert_endbr_and_patchable_area): This. Change pass name to endbr_and_patchable_area. (pass_insert_endbranch): Renamed to ... (pass_insert_endbr_and_patchable_area): This. Add need_endbr and patchable_area_size;. (pass_insert_endbr_and_patchable_area::gate): Set and check need_endbr and patchable_area_size. (pass_insert_endbr_and_patchable_area::execute): Call timevar_push and timevar_pop. Pass need_endbr and patchable_area_size to rest_of_insert_endbr_and_patchable_area. (make_pass_insert_endbranch): Renamed to ... (make_pass_insert_endbr_and_patchable_area): This. * config/i386/i386-passes.def: Replace pass_insert_endbranch with pass_insert_endbr_and_patchable_area. * config/i386/i386-protos.h (ix86_output_patchable_area): New. (make_pass_insert_endbranch): Renamed to ... (make_pass_insert_endbr_and_patchable_area): This. * config/i386/i386.c (ix86_asm_output_function_label): Set function_label_emitted to true. (ix86_print_patchable_function_entry): New function. (ix86_output_patchable_area): Likewise. (x86_function_profiler): Replace endbr_queued_at_entrance with insn_queued_at_entrance. Generate ENDBR only for TYPE_ENDBR. Call ix86_output_patchable_area to generate patchable area if needed. (TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY): New. * i386.h (queued_insn_type): New. (machine_function): Add function_label_emitted. Replace endbr_queued_at_entrance with insn_queued_at_entrance. * config/i386/i386.md (UNSPECV_PATCHABLE_AREA): New. (patchable_area): New. gcc/testsuite/ PR target/93492 * gcc.target/i386/pr93492-1.c: New test. * gcc.target/i386/pr93492-2.c: Likewise. * gcc.target/i386/pr93492-3.c: Likewise. * gcc.target/i386/pr93492-4.c: Likewise. * gcc.target/i386/pr93492-5.c: Likewise. --- gcc/config/i386/i386-features.c | 142 ++++++++++++++-------- gcc/config/i386/i386-passes.def | 2 +- gcc/config/i386/i386-protos.h | 5 +- gcc/config/i386/i386.c | 51 +++++++- gcc/config/i386/i386.h | 14 ++- gcc/config/i386/i386.md | 17 +++ gcc/testsuite/gcc.target/i386/pr93492-1.c | 73 +++++++++++ gcc/testsuite/gcc.target/i386/pr93492-2.c | 12 ++ gcc/testsuite/gcc.target/i386/pr93492-3.c | 13 ++ gcc/testsuite/gcc.target/i386/pr93492-4.c | 11 ++ gcc/testsuite/gcc.target/i386/pr93492-5.c | 12 ++ 11 files changed, 296 insertions(+), 56 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr93492-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr93492-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr93492-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr93492-4.c create mode 100644 gcc/testsuite/gcc.target/i386/pr93492-5.c diff --git a/gcc/config/i386/i386-features.c b/gcc/config/i386/i386-features.c index 78fb373db6e..41cc8b583b6 100644 --- a/gcc/config/i386/i386-features.c +++ b/gcc/config/i386/i386-features.c @@ -1941,48 +1941,83 @@ make_pass_stv (gcc::context *ctxt) return new pass_stv (ctxt); } -/* Inserting ENDBRANCH instructions. */ +/* Inserting ENDBR and pseudo patchable-area instructions. */ -static unsigned int -rest_of_insert_endbranch (void) +static void +rest_of_insert_endbr_and_patchable_area (bool need_endbr, + unsigned int patchable_area_size) { - timevar_push (TV_MACH_DEP); - - rtx cet_eb; + rtx endbr; rtx_insn *insn; + rtx_insn *endbr_insn = NULL; basic_block bb; - /* Currently emit EB if it's a tracking function, i.e. 'nocf_check' is - absent among function attributes. Later an optimization will be - introduced to make analysis if an address of a static function is - taken. A static function whose address is not taken will get a - nocf_check attribute. This will allow to reduce the number of EB. */ - - if (!lookup_attribute ("nocf_check", - TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl))) - && (!flag_manual_endbr - || lookup_attribute ("cf_check", - DECL_ATTRIBUTES (cfun->decl))) - && (!cgraph_node::get (cfun->decl)->only_called_directly_p () - || ix86_cmodel == CM_LARGE - || ix86_cmodel == CM_LARGE_PIC - || flag_force_indirect_call - || (TARGET_DLLIMPORT_DECL_ATTRIBUTES - && DECL_DLLIMPORT_P (cfun->decl)))) - { - /* Queue ENDBR insertion to x86_function_profiler. */ + if (need_endbr) + { + /* Currently emit EB if it's a tracking function, i.e. 'nocf_check' + is absent among function attributes. Later an optimization will + be introduced to make analysis if an address of a static function + is taken. A static function whose address is not taken will get + a nocf_check attribute. This will allow to reduce the number of + EB. */ + if (!lookup_attribute ("nocf_check", + TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl))) + && (!flag_manual_endbr + || lookup_attribute ("cf_check", + DECL_ATTRIBUTES (cfun->decl))) + && (!cgraph_node::get (cfun->decl)->only_called_directly_p () + || ix86_cmodel == CM_LARGE + || ix86_cmodel == CM_LARGE_PIC + || flag_force_indirect_call + || (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && DECL_DLLIMPORT_P (cfun->decl)))) + { + if (crtl->profile && flag_fentry) + { + /* Queue ENDBR insertion to x86_function_profiler. + NB: Any patchable-area insn will be inserted after + ENDBR. */ + cfun->machine->insn_queued_at_entrance = TYPE_ENDBR; + } + else + { + endbr = gen_nop_endbr (); + bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; + rtx_insn *insn = BB_HEAD (bb); + endbr_insn = emit_insn_before (endbr, insn); + } + } + } + + if (patchable_area_size) + { if (crtl->profile && flag_fentry) - cfun->machine->endbr_queued_at_entrance = true; + { + /* Queue patchable-area insertion to x86_function_profiler. + NB: If there is a queued ENDBR, x86_function_profiler + will also handle patchable-area. */ + if (!cfun->machine->insn_queued_at_entrance) + cfun->machine->insn_queued_at_entrance = TYPE_PATCHABLE_AREA; + } else { - cet_eb = gen_nop_endbr (); - - bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; - insn = BB_HEAD (bb); - emit_insn_before (cet_eb, insn); + rtx patchable_area + = gen_patchable_area (GEN_INT (patchable_area_size), + GEN_INT (crtl->patch_area_entry == 0)); + if (endbr_insn) + emit_insn_after (patchable_area, endbr_insn); + else + { + bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; + insn = BB_HEAD (bb); + emit_insn_before (patchable_area, insn); + } } } + if (!need_endbr) + return; + bb = 0; FOR_EACH_BB_FN (bb, cfun) { @@ -1991,7 +2026,6 @@ rest_of_insert_endbranch (void) { if (CALL_P (insn)) { - bool need_endbr; need_endbr = find_reg_note (insn, REG_SETJMP, NULL) != NULL; if (!need_endbr && !SIBLING_CALL_P (insn)) { @@ -2022,8 +2056,8 @@ rest_of_insert_endbranch (void) /* Generate ENDBRANCH after CALL, which can return more than twice, setjmp-like functions. */ - cet_eb = gen_nop_endbr (); - emit_insn_after_setloc (cet_eb, insn, INSN_LOCATION (insn)); + endbr = gen_nop_endbr (); + emit_insn_after_setloc (endbr, insn, INSN_LOCATION (insn)); continue; } @@ -2053,31 +2087,30 @@ rest_of_insert_endbranch (void) dest_blk = e->dest; insn = BB_HEAD (dest_blk); gcc_assert (LABEL_P (insn)); - cet_eb = gen_nop_endbr (); - emit_insn_after (cet_eb, insn); + endbr = gen_nop_endbr (); + emit_insn_after (endbr, insn); } continue; } if (LABEL_P (insn) && LABEL_PRESERVE_P (insn)) { - cet_eb = gen_nop_endbr (); - emit_insn_after (cet_eb, insn); + endbr = gen_nop_endbr (); + emit_insn_after (endbr, insn); continue; } } } - timevar_pop (TV_MACH_DEP); - return 0; + return; } namespace { -const pass_data pass_data_insert_endbranch = +const pass_data pass_data_insert_endbr_and_patchable_area = { RTL_PASS, /* type. */ - "cet", /* name. */ + "endbr_and_patchable_area", /* name. */ OPTGROUP_NONE, /* optinfo_flags. */ TV_MACH_DEP, /* tv_id. */ 0, /* properties_required. */ @@ -2087,32 +2120,41 @@ const pass_data pass_data_insert_endbranch = 0, /* todo_flags_finish. */ }; -class pass_insert_endbranch : public rtl_opt_pass +class pass_insert_endbr_and_patchable_area : public rtl_opt_pass { public: - pass_insert_endbranch (gcc::context *ctxt) - : rtl_opt_pass (pass_data_insert_endbranch, ctxt) + pass_insert_endbr_and_patchable_area (gcc::context *ctxt) + : rtl_opt_pass (pass_data_insert_endbr_and_patchable_area, ctxt) {} /* opt_pass methods: */ virtual bool gate (function *) { - return ((flag_cf_protection & CF_BRANCH)); + need_endbr = (flag_cf_protection & CF_BRANCH) != 0; + patchable_area_size = crtl->patch_area_size - crtl->patch_area_entry; + return need_endbr || patchable_area_size; } virtual unsigned int execute (function *) { - return rest_of_insert_endbranch (); + timevar_push (TV_MACH_DEP); + rest_of_insert_endbr_and_patchable_area (need_endbr, + patchable_area_size); + timevar_pop (TV_MACH_DEP); + return 0; } -}; // class pass_insert_endbranch +private: + bool need_endbr; + unsigned int patchable_area_size; +}; // class pass_insert_endbr_and_patchable_area } // anon namespace rtl_opt_pass * -make_pass_insert_endbranch (gcc::context *ctxt) +make_pass_insert_endbr_and_patchable_area (gcc::context *ctxt) { - return new pass_insert_endbranch (ctxt); + return new pass_insert_endbr_and_patchable_area (ctxt); } /* At entry of the nearest common dominator for basic blocks with diff --git a/gcc/config/i386/i386-passes.def b/gcc/config/i386/i386-passes.def index 41386a13d88..d83c7b956b1 100644 --- a/gcc/config/i386/i386-passes.def +++ b/gcc/config/i386/i386-passes.def @@ -30,6 +30,6 @@ along with GCC; see the file COPYING3. If not see CONSTM1_RTX generated by the STV pass can be CSEed. */ INSERT_PASS_BEFORE (pass_cse2, 1, pass_stv, true /* timode_p */); - INSERT_PASS_BEFORE (pass_shorten_branches, 1, pass_insert_endbranch); + INSERT_PASS_BEFORE (pass_shorten_branches, 1, pass_insert_endbr_and_patchable_area); INSERT_PASS_AFTER (pass_combine, 1, pass_remove_partial_avx_dependency); diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 39fcaa0ad5f..e5574496bb7 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -89,6 +89,8 @@ extern const char *output_fp_compare (rtx_insn *, rtx*, bool, bool); extern const char *output_adjust_stack_and_probe (rtx); extern const char *output_probe_stack_range (rtx, rtx); +extern void ix86_output_patchable_area (unsigned int, bool); + extern void ix86_expand_clear (rtx); extern void ix86_expand_move (machine_mode, rtx[]); extern void ix86_expand_vector_move (machine_mode, rtx[]); @@ -378,6 +380,7 @@ class rtl_opt_pass; extern rtl_opt_pass *make_pass_insert_vzeroupper (gcc::context *); extern rtl_opt_pass *make_pass_stv (gcc::context *); -extern rtl_opt_pass *make_pass_insert_endbranch (gcc::context *); +extern rtl_opt_pass *make_pass_insert_endbr_and_patchable_area + (gcc::context *); extern rtl_opt_pass *make_pass_remove_partial_avx_dependency (gcc::context *); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index c4a538ed0c8..bdfe149e39e 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1562,6 +1562,9 @@ ix86_asm_output_function_label (FILE *asm_out_file, const char *fname, { bool is_ms_hook = ix86_function_ms_hook_prologue (decl); + if (cfun) + cfun->machine->function_label_emitted = true; + if (is_ms_hook) { int i, filler_count = (TARGET_64BIT ? 32 : 16); @@ -9368,6 +9371,38 @@ ix86_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED) } } +/* Implement TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY. */ + +void +ix86_print_patchable_function_entry (FILE *file, + unsigned HOST_WIDE_INT patch_area_size, + bool record_p) +{ + if (cfun->machine->function_label_emitted) + { + /* NB: When ix86_print_patchable_function_entry is called after + function table has been emitted, we have inserted or queued + a pseudo UNSPECV_PATCHABLE_AREA instruction at the proper + place. There is nothing to do here. */ + return; + } + + default_print_patchable_function_entry (file, patch_area_size, + record_p); +} + +/* Output patchable area. NB: default_print_patchable_function_entry + isn't available in i386.md. */ + +void +ix86_output_patchable_area (unsigned int patch_area_size, + bool record_p) +{ + default_print_patchable_function_entry (asm_out_file, + patch_area_size, + record_p); +} + /* Return a scratch register to use in the split stack prologue. The split stack prologue is used for -fsplit-stack. It is the first instructions in the function, even before the regular prologue. @@ -20415,8 +20450,16 @@ current_fentry_section (const char **name) void x86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) { - if (cfun->machine->endbr_queued_at_entrance) - fprintf (file, "\t%s\n", TARGET_64BIT ? "endbr64" : "endbr32"); + if (cfun->machine->insn_queued_at_entrance) + { + if (cfun->machine->insn_queued_at_entrance == TYPE_ENDBR) + fprintf (file, "\t%s\n", TARGET_64BIT ? "endbr64" : "endbr32"); + unsigned int patch_area_size + = crtl->patch_area_size - crtl->patch_area_entry; + if (patch_area_size) + ix86_output_patchable_area (patch_area_size, + crtl->patch_area_entry == 0); + } const char *mcount_name = MCOUNT_NAME; @@ -23013,6 +23056,10 @@ ix86_run_selftests (void) #undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE ix86_output_function_epilogue +#undef TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY +#define TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY \ + ix86_print_patchable_function_entry + #undef TARGET_ENCODE_SECTION_INFO #ifndef SUBTARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO ix86_encode_section_info diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 08245f64322..77575875192 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2757,6 +2757,13 @@ enum function_type TYPE_EXCEPTION }; +enum queued_insn_type +{ + TYPE_NONE = 0, + TYPE_ENDBR, + TYPE_PATCHABLE_AREA +}; + struct GTY(()) machine_function { struct stack_local_entry *stack_locals; int varargs_gpr_size; @@ -2847,8 +2854,11 @@ struct GTY(()) machine_function { /* Nonzero if the function places outgoing arguments on stack. */ BOOL_BITFIELD outgoing_args_on_stack : 1; - /* If true, ENDBR is queued at function entrance. */ - BOOL_BITFIELD endbr_queued_at_entrance : 1; + /* If true, ENDBR or patchable area is queued at function entrance. */ + ENUM_BITFIELD(queued_insn_type) insn_queued_at_entrance : 2; + + /* If true, the function label has been emitted. */ + BOOL_BITFIELD function_label_emitted : 1; /* True if the function needs a stack frame. */ BOOL_BITFIELD stack_frame_required : 1; diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index b426c21d3dd..f7ca55ab4de 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -300,6 +300,9 @@ (define_c_enum "unspecv" [ ;; For ENQCMD and ENQCMDS support UNSPECV_ENQCMD UNSPECV_ENQCMDS + + ;; For patchable area support + UNSPECV_PATCHABLE_AREA ]) ;; Constants to represent rounding modes in the ROUND instruction @@ -21135,6 +21138,20 @@ (define_insn "speculation_barrier" [(set_attr "type" "other") (set_attr "length" "3")]) +(define_insn "patchable_area" + [(unspec_volatile [(match_operand 0 "const_int_operand") + (match_operand 1 "const_int_operand")] + UNSPECV_PATCHABLE_AREA)] + "" +{ + ix86_output_patchable_area (INTVAL (operands[0]), + INTVAL (operands[1]) != 0); + return ""; +} + [(set (attr "length") (symbol_ref "INTVAL (operands[0])")) + (set_attr "length_immediate" "0") + (set_attr "modrm" "0")]) + (include "mmx.md") (include "sse.md") (include "sync.md") diff --git a/gcc/testsuite/gcc.target/i386/pr93492-1.c b/gcc/testsuite/gcc.target/i386/pr93492-1.c new file mode 100644 index 00000000000..f978d2e5220 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr93492-1.c @@ -0,0 +1,73 @@ +/* { dg-do "compile" } */ +/* { dg-options "-O1 -fcf-protection -mmanual-endbr" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* Note: this test only checks the instructions in the function bodies, + not the placement of the patch label or nops before the function. */ + +/* +**f10_none: +** nop +** ret +*/ +void +__attribute__ ((nocf_check,patchable_function_entry (1, 0))) +f10_none (void) +{ +} + +/* +**f10_endbr: +** endbr(32|64) +** nop +** ret +*/ +void +__attribute__ ((cf_check,patchable_function_entry (1, 0))) +f10_endbr (void) +{ +} + +/* +**f11_none: +** ret +*/ +void +__attribute__ ((nocf_check,patchable_function_entry (1, 1))) +f11_none (void) +{ +} + +/* +**f11_endbr: +** endbr(32|64) +** ret +*/ +void +__attribute__ ((cf_check,patchable_function_entry (1, 1))) +f11_endbr (void) +{ +} + +/* +**f21_none: +** nop +** ret +*/ +void +__attribute__ ((nocf_check,patchable_function_entry (2, 1))) +f21_none (void) +{ +} + +/* +**f21_endbr: +** endbr(32|64) +** nop +** ret +*/ +void +__attribute__ ((cf_check,patchable_function_entry (2, 1))) +f21_endbr (void) +{ +} diff --git a/gcc/testsuite/gcc.target/i386/pr93492-2.c b/gcc/testsuite/gcc.target/i386/pr93492-2.c new file mode 100644 index 00000000000..ec26d4cc367 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr93492-2.c @@ -0,0 +1,12 @@ +/* { dg-do "compile" } */ +/* { dg-options "-O1 -fcf-protection -mmanual-endbr -fasynchronous-unwind-tables" } */ + +/* Test the placement of the .LPFE1 label. */ + +void +__attribute__ ((cf_check,patchable_function_entry (1, 0))) +f10_endbr (void) +{ +} + +/* { dg-final { scan-assembler "\t\.cfi_startproc\n\tendbr(32|64)\n.*\.LPFE1:\n\tnop\n\tret\n" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr93492-3.c b/gcc/testsuite/gcc.target/i386/pr93492-3.c new file mode 100644 index 00000000000..1f03c627120 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr93492-3.c @@ -0,0 +1,13 @@ +/* { dg-do "compile" } */ +/* { dg-require-effective-target mfentry } */ +/* { dg-options "-O1 -fcf-protection -mmanual-endbr -mfentry -pg -fasynchronous-unwind-tables" } */ + +/* Test the placement of the .LPFE1 label. */ + +void +__attribute__ ((cf_check,patchable_function_entry (1, 0))) +f10_endbr (void) +{ +} + +/* { dg-final { scan-assembler "\t\.cfi_startproc\n\tendbr(32|64)\n.*\.LPFE1:\n\tnop\n1:\tcall\t__fentry__\n\tret\n" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr93492-4.c b/gcc/testsuite/gcc.target/i386/pr93492-4.c new file mode 100644 index 00000000000..d193df8e66d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr93492-4.c @@ -0,0 +1,11 @@ +/* { dg-do "compile" } */ +/* { dg-options "-O1 -fpatchable-function-entry=1 -fasynchronous-unwind-tables" } */ + +/* Test the placement of the .LPFE1 label. */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler "\t\.cfi_startproc\n.*\.LPFE1:\n\tnop\n\tret\n" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr93492-5.c b/gcc/testsuite/gcc.target/i386/pr93492-5.c new file mode 100644 index 00000000000..d04077c6007 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr93492-5.c @@ -0,0 +1,12 @@ +/* { dg-do "compile" } */ +/* { dg-require-effective-target mfentry } */ +/* { dg-options "-O1 -fpatchable-function-entry=1 -mfentry -pg -fasynchronous-unwind-tables" } */ + +/* Test the placement of the .LPFE1 label. */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler "\t\.cfi_startproc\n.*\.LPFE1:\n\tnop\n1:\tcall\t__fentry__\n\tret\n" } } */