mirror of
https://github.com/gcc-mirror/gcc.git
synced 2024-11-21 13:40:47 +00:00
bf43fe6aa9
My forthcoming patches for PR other/116613 make much more use of cloning of pretty_printers than before, so it makes sense as a preliminary patch for the result of pretty_printer::clone to be a std::unique_ptr, rather than add more manual uses of "delete". On doing so, I noticed various other places where naked new/delete is used for run-time configuration of diagnostics: * the output format (text vs SARIF) * client data hooks * the option manager * the URLifier Hence this patch also makes use of std::unique_ptr and ::make_unique for managing such client policy classes, and also for diagnostic_buffer's per-format implementations. Unfortunately we can't directly include <memory> in our internal headers but instead any of our TUs that make use of std::unique_ptr must #define INCLUDE_MEMORY before including system.h. Hence the bulk of this patch is taken up with adding a define of INCLUDE_MEMORY to hundreds of source files: everything that includes diagnostic.h or pretty-print.h (and thus anything transitively such as includers of lto-wrapper.h, c-tree.h, cp-tree.h and rtl-ssa.h). Thanks to Gaius Mulley for the parts of the patch that regenerated the m2 files. gcc/ada/ChangeLog: PR other/116613 * gcc-interface/misc.cc: Add #define INCLUDE_MEMORY * gcc-interface/trans.cc: Likewise. * gcc-interface/utils.cc: Likewise. gcc/analyzer/ChangeLog: PR other/116613 * analyzer-logging.cc: Add #define INCLUDE_MEMORY (logger::logger): Update for m_pp becoming a unique_ptr. (logger::~logger): Likewise. (logger::log_va_partial): Likewise. (logger::end_log_line): Likewise. * analyzer-logging.h (logger::get_printer): Likewise. (logger::m_pp): Convert to a unique_ptr. * analyzer.cc (make_label_text): Use diagnostic_context::clone_printer and use unique_ptr. (make_label_text_n): Likewise. * bar-chart.cc: Add #define INCLUDE_MEMORY * pending-diagnostic.cc (evdesc::event_desc::formatted_print): Use diagnostic_context::clone_printer and use unique_ptr. * sm-malloc.cc (sufficiently_similar_p): Likewise. * supergraph.cc (supergraph::dump_dot_to_file): Likewise. gcc/c-family/ChangeLog: PR other/116613 * c-ada-spec.cc: Add #define INCLUDE_MEMORY. * c-attribs.cc: Likewise. * c-common.cc: Likewise. * c-format.cc: Likewise. * c-gimplify.cc: Likewise. * c-indentation.cc: Likewise. * c-opts.cc: Likewise. * c-pch.cc: Likewise. * c-pragma.cc: Likewise. * c-pretty-print.cc: Likewise. Add #include "make-unique.h". (c_pretty_printer::clone): Use std::unique_ptr and ::make_unique. * c-pretty-print.h (c_pretty_printer::clone): Use std::unique_ptr. * c-type-mismatch.cc: Add #define INCLUDE_MEMORY. * c-warn.cc: Likewise. gcc/c/ChangeLog: PR other/116613 * c-aux-info.cc: Add #define INCLUDE_MEMORY. * c-convert.cc: Likewise. * c-errors.cc: Likewise. * c-fold.cc: Likewise. * c-lang.cc: Likewise. * c-objc-common.cc: Likewise. (pp_markup::element_quoted_type::print_type): Use unique_ptr. * c-typeck.cc: Add #define INCLUDE_MEMORY. * gimple-parser.cc: Likewise. gcc/cp/ChangeLog: PR other/116613 * call.cc: Add #define INCLUDE_MEMORY. * class.cc: Likewise. * constexpr.cc: Likewise. * constraint.cc: Likewise. * contracts.cc: Likewise. * coroutines.cc: Likewise. * cp-gimplify.cc: Likewise. * cp-lang.cc: Likewise. * cp-objcp-common.cc: Likewise. * cp-ubsan.cc: Likewise. * cvt.cc: Likewise. * cxx-pretty-print.cc: Likewise. Add #include "cp-tree.h". (cxx_pretty_printer::clone): Use std::unique_ptr and ::make_unique. * cxx-pretty-print.h (cxx_pretty_printer::clone): Use std::unique_ptr. * decl2.cc: Add #define INCLUDE_MEMORY. * dump.cc: Likewise. * except.cc: Likewise. * expr.cc: Likewise. * friend.cc: Likewise. * init.cc: Likewise. * lambda.cc: Likewise. * logic.cc: Likewise. * mangle.cc: Likewise. * method.cc: Likewise. * optimize.cc: Likewise. * pt.cc: Likewise. * ptree.cc: Likewise. * rtti.cc: Likewise. * search.cc: Likewise. * semantics.cc: Likewise. * tree.cc: Likewise. * typeck.cc: Likewise. * typeck2.cc: Likewise. * vtable-class-hierarchy.cc: Likewise. gcc/d/ChangeLog: PR other/116613 * d-attribs.cc: Add #define INCLUDE_MEMORY. * d-builtins.cc: Likewise. * d-codegen.cc: Likewise. * d-convert.cc: Likewise. * d-diagnostic.cc: Likewise. * d-frontend.cc: Likewise. * d-lang.cc: Likewise. * d-longdouble.cc: Likewise. * d-target.cc: Likewise. * decl.cc: Likewise. * expr.cc: Likewise. * intrinsics.cc: Likewise. * modules.cc: Likewise. * toir.cc: Likewise. * typeinfo.cc: Likewise. * types.cc: Likewise. gcc/fortran/ChangeLog: PR other/116613 * arith.cc: Add #define INCLUDE_MEMORY. * array.cc: Likewise. * bbt.cc: Likewise. * check.cc: Likewise. * class.cc: Likewise. * constructor.cc: Likewise. * convert.cc: Likewise. * cpp.cc: Likewise. * data.cc: Likewise. * decl.cc: Likewise. * dependency.cc: Likewise. * dump-parse-tree.cc: Likewise. * error.cc: Likewise. * expr.cc: Likewise. * f95-lang.cc: Likewise. * frontend-passes.cc: Likewise. * interface.cc: Likewise. * intrinsic.cc: Likewise. * io.cc: Likewise. * iresolve.cc: Likewise. * match.cc: Likewise. * matchexp.cc: Likewise. * misc.cc: Likewise. * module.cc: Likewise. * openmp.cc: Likewise. * options.cc: Likewise. * parse.cc: Likewise. * primary.cc: Likewise. * resolve.cc: Likewise. * scanner.cc: Likewise. * simplify.cc: Likewise. * st.cc: Likewise. * symbol.cc: Likewise. * target-memory.cc: Likewise. * trans-array.cc: Likewise. * trans-common.cc: Likewise. * trans-const.cc: Likewise. * trans-decl.cc: Likewise. * trans-expr.cc: Likewise. * trans-intrinsic.cc: Likewise. * trans-io.cc: Likewise. * trans-openmp.cc: Likewise. * trans-stmt.cc: Likewise. * trans-types.cc: Likewise. * trans.cc: Likewise. gcc/go/ChangeLog: PR other/116613 * go-backend.cc: Add #define INCLUDE_MEMORY. * go-lang.cc: Likewise. gcc/jit/ChangeLog: PR other/116613 * dummy-frontend.cc: Add #define INCLUDE_MEMORY. * jit-playback.cc: Likewise. * jit-recording.cc: Likewise. gcc/lto/ChangeLog: PR other/116613 * lto-common.cc: Add #define INCLUDE_MEMORY. * lto-dump.cc: Likewise. * lto-partition.cc: Likewise. * lto-symtab.cc: Likewise. * lto.cc: Likewise. gcc/m2/ChangeLog: PR other/116613 * gm2-gcc/gcc-consolidation.h: Add #define INCLUDE_MEMORY. * gm2-gcc/m2configure.cc: Likewise. * mc-boot/GASCII.cc: Regenerate. * mc-boot/GASCII.h: Ditto. * mc-boot/GArgs.cc: Ditto. * mc-boot/GArgs.h: Ditto. * mc-boot/GAssertion.cc: Ditto. * mc-boot/GAssertion.h: Ditto. * mc-boot/GBreak.cc: Ditto. * mc-boot/GBreak.h: Ditto. * mc-boot/GCOROUTINES.h: Ditto. * mc-boot/GCmdArgs.cc: Ditto. * mc-boot/GCmdArgs.h: Ditto. * mc-boot/GDebug.cc: Ditto. * mc-boot/GDebug.h: Ditto. * mc-boot/GDynamicStrings.cc: Ditto. * mc-boot/GDynamicStrings.h: Ditto. * mc-boot/GEnvironment.cc: Ditto. * mc-boot/GEnvironment.h: Ditto. * mc-boot/GFIO.cc: Ditto. * mc-boot/GFIO.h: Ditto. * mc-boot/GFormatStrings.cc: Ditto. * mc-boot/GFormatStrings.h: Ditto. * mc-boot/GFpuIO.cc: Ditto. * mc-boot/GFpuIO.h: Ditto. * mc-boot/GIO.cc: Ditto. * mc-boot/GIO.h: Ditto. * mc-boot/GIndexing.cc: Ditto. * mc-boot/GIndexing.h: Ditto. * mc-boot/GM2Dependent.cc: Ditto. * mc-boot/GM2Dependent.h: Ditto. * mc-boot/GM2EXCEPTION.cc: Ditto. * mc-boot/GM2EXCEPTION.h: Ditto. * mc-boot/GM2RTS.cc: Ditto. * mc-boot/GM2RTS.h: Ditto. * mc-boot/GMemUtils.cc: Ditto. * mc-boot/GMemUtils.h: Ditto. * mc-boot/GNumberIO.cc: Ditto. * mc-boot/GNumberIO.h: Ditto. * mc-boot/GPushBackInput.cc: Ditto. * mc-boot/GPushBackInput.h: Ditto. * mc-boot/GRTExceptions.cc: Ditto. * mc-boot/GRTExceptions.h: Ditto. * mc-boot/GRTco.h: Ditto. * mc-boot/GRTentity.h: Ditto. * mc-boot/GRTint.cc: Ditto. * mc-boot/GRTint.h: Ditto. * mc-boot/GSArgs.cc: Ditto. * mc-boot/GSArgs.h: Ditto. * mc-boot/GSFIO.cc: Ditto. * mc-boot/GSFIO.h: Ditto. * mc-boot/GSYSTEM.h: Ditto. * mc-boot/GSelective.h: Ditto. * mc-boot/GStdIO.cc: Ditto. * mc-boot/GStdIO.h: Ditto. * mc-boot/GStorage.cc: Ditto. * mc-boot/GStorage.h: Ditto. * mc-boot/GStrCase.cc: Ditto. * mc-boot/GStrCase.h: Ditto. * mc-boot/GStrIO.cc: Ditto. * mc-boot/GStrIO.h: Ditto. * mc-boot/GStrLib.cc: Ditto. * mc-boot/GStrLib.h: Ditto. * mc-boot/GStringConvert.cc: Ditto. * mc-boot/GStringConvert.h: Ditto. * mc-boot/GSysExceptions.h: Ditto. * mc-boot/GSysStorage.cc: Ditto. * mc-boot/GSysStorage.h: Ditto. * mc-boot/GTimeString.cc: Ditto. * mc-boot/GTimeString.h: Ditto. * mc-boot/GUnixArgs.h: Ditto. * mc-boot/Galists.cc: Ditto. * mc-boot/Galists.h: Ditto. * mc-boot/Gdecl.cc: Ditto. * mc-boot/Gdecl.h: Ditto. * mc-boot/Gdtoa.h: Ditto. * mc-boot/Gerrno.h: Ditto. * mc-boot/Gkeyc.cc: Ditto. * mc-boot/Gkeyc.h: Ditto. * mc-boot/Gldtoa.h: Ditto. * mc-boot/Glibc.h: Ditto. * mc-boot/Glibm.h: Ditto. * mc-boot/Glists.cc: Ditto. * mc-boot/Glists.h: Ditto. * mc-boot/GmcComment.cc: Ditto. * mc-boot/GmcComment.h: Ditto. * mc-boot/GmcComp.cc: Ditto. * mc-boot/GmcComp.h: Ditto. * mc-boot/GmcDebug.cc: Ditto. * mc-boot/GmcDebug.h: Ditto. * mc-boot/GmcError.cc: Ditto. * mc-boot/GmcError.h: Ditto. * mc-boot/GmcFileName.cc: Ditto. * mc-boot/GmcFileName.h: Ditto. * mc-boot/GmcLexBuf.cc: Ditto. * mc-boot/GmcLexBuf.h: Ditto. * mc-boot/GmcMetaError.cc: Ditto. * mc-boot/GmcMetaError.h: Ditto. * mc-boot/GmcOptions.cc: Ditto. * mc-boot/GmcOptions.h: Ditto. * mc-boot/GmcPreprocess.cc: Ditto. * mc-boot/GmcPreprocess.h: Ditto. * mc-boot/GmcPretty.cc: Ditto. * mc-boot/GmcPretty.h: Ditto. * mc-boot/GmcPrintf.cc: Ditto. * mc-boot/GmcPrintf.h: Ditto. * mc-boot/GmcQuiet.cc: Ditto. * mc-boot/GmcQuiet.h: Ditto. * mc-boot/GmcReserved.cc: Ditto. * mc-boot/GmcReserved.h: Ditto. * mc-boot/GmcSearch.cc: Ditto. * mc-boot/GmcSearch.h: Ditto. * mc-boot/GmcStack.cc: Ditto. * mc-boot/GmcStack.h: Ditto. * mc-boot/GmcStream.cc: Ditto. * mc-boot/GmcStream.h: Ditto. * mc-boot/Gmcflex.h: Ditto. * mc-boot/Gmcp1.cc: Ditto. * mc-boot/Gmcp1.h: Ditto. * mc-boot/Gmcp2.cc: Ditto. * mc-boot/Gmcp2.h: Ditto. * mc-boot/Gmcp3.cc: Ditto. * mc-boot/Gmcp3.h: Ditto. * mc-boot/Gmcp4.cc: Ditto. * mc-boot/Gmcp4.h: Ditto. * mc-boot/Gmcp5.cc: Ditto. * mc-boot/Gmcp5.h: Ditto. * mc-boot/GnameKey.cc: Ditto. * mc-boot/GnameKey.h: Ditto. * mc-boot/GsymbolKey.cc: Ditto. * mc-boot/GsymbolKey.h: Ditto. * mc-boot/Gtermios.h: Ditto. * mc-boot/Gtop.cc: Ditto. * mc-boot/Gvarargs.cc: Ditto. * mc-boot/Gvarargs.h: Ditto. * mc-boot/Gwlists.cc: Ditto. * mc-boot/Gwlists.h: Ditto. * mc-boot/Gwrapc.h: Ditto. * mc/keyc.mod (checkGccConfigSystem): Add #define INCLUDE_MEMORY. * pge-boot/GASCII.cc: Regenerate. * pge-boot/GASCII.h: Ditto. * pge-boot/GArgs.cc: Ditto. * pge-boot/GArgs.h: Ditto. * pge-boot/GAssertion.cc: Ditto. * pge-boot/GAssertion.h: Ditto. * pge-boot/GBreak.h: Ditto. * pge-boot/GCmdArgs.h: Ditto. * pge-boot/GDebug.cc: Ditto. * pge-boot/GDebug.h: Ditto. * pge-boot/GDynamicStrings.cc: Ditto. * pge-boot/GDynamicStrings.h: Ditto. * pge-boot/GEnvironment.h: Ditto. * pge-boot/GFIO.cc: Ditto. * pge-boot/GFIO.h: Ditto. * pge-boot/GFormatStrings.h: Ditto. * pge-boot/GFpuIO.h: Ditto. * pge-boot/GIO.cc: Ditto. * pge-boot/GIO.h: Ditto. * pge-boot/GIndexing.cc: Ditto. * pge-boot/GIndexing.h: Ditto. * pge-boot/GLists.cc: Ditto. * pge-boot/GLists.h: Ditto. * pge-boot/GM2Dependent.cc: Ditto. * pge-boot/GM2Dependent.h: Ditto. * pge-boot/GM2EXCEPTION.cc: Ditto. * pge-boot/GM2EXCEPTION.h: Ditto. * pge-boot/GM2RTS.cc: Ditto. * pge-boot/GM2RTS.h: Ditto. * pge-boot/GNameKey.cc: Ditto. * pge-boot/GNameKey.h: Ditto. * pge-boot/GNumberIO.cc: Ditto. * pge-boot/GNumberIO.h: Ditto. * pge-boot/GOutput.cc: Ditto. * pge-boot/GOutput.h: Ditto. * pge-boot/GPushBackInput.cc: Ditto. * pge-boot/GPushBackInput.h: Ditto. * pge-boot/GRTExceptions.cc: Ditto. * pge-boot/GRTExceptions.h: Ditto. * pge-boot/GSArgs.h: Ditto. * pge-boot/GSEnvironment.h: Ditto. * pge-boot/GSFIO.cc: Ditto. * pge-boot/GSFIO.h: Ditto. * pge-boot/GSYSTEM.h: Ditto. * pge-boot/GScan.h: Ditto. * pge-boot/GStdIO.cc: Ditto. * pge-boot/GStdIO.h: Ditto. * pge-boot/GStorage.cc: Ditto. * pge-boot/GStorage.h: Ditto. * pge-boot/GStrCase.cc: Ditto. * pge-boot/GStrCase.h: Ditto. * pge-boot/GStrIO.cc: Ditto. * pge-boot/GStrIO.h: Ditto. * pge-boot/GStrLib.cc: Ditto. * pge-boot/GStrLib.h: Ditto. * pge-boot/GStringConvert.h: Ditto. * pge-boot/GSymbolKey.cc: Ditto. * pge-boot/GSymbolKey.h: Ditto. * pge-boot/GSysExceptions.h: Ditto. * pge-boot/GSysStorage.cc: Ditto. * pge-boot/GSysStorage.h: Ditto. * pge-boot/GTimeString.h: Ditto. * pge-boot/GUnixArgs.h: Ditto. * pge-boot/Gbnflex.cc: Ditto. * pge-boot/Gbnflex.h: Ditto. * pge-boot/Gdtoa.h: Ditto. * pge-boot/Gerrno.h: Ditto. * pge-boot/Gldtoa.h: Ditto. * pge-boot/Glibc.h: Ditto. * pge-boot/Glibm.h: Ditto. * pge-boot/Gpge.cc: Ditto. * pge-boot/Gtermios.h: Ditto. * pge-boot/Gwrapc.h: Ditto. gcc/objc/ChangeLog: PR other/116613 * objc-act.cc: Add #define INCLUDE_MEMORY. * objc-encoding.cc: Likewise. * objc-gnu-runtime-abi-01.cc: Likewise. * objc-lang.cc: Likewise. * objc-next-runtime-abi-01.cc: Likewise. * objc-next-runtime-abi-02.cc: Likewise. * objc-runtime-shared-support.cc: Likewise. gcc/objcp/ChangeLog:: Add #define INCLUDE_MEMORY. PR other/116613 * objcp-decl.cc * objcp-lang.cc: Likewise. gcc/rust/ChangeLog: PR other/116613 * resolve/rust-ast-resolve-expr.cc: Add #define INCLUDE_MEMORY. * rust-attribs.cc: Likewise. * rust-system.h: Likewise. gcc/ChangeLog: PR other/116613 * asan.cc: Add #define INCLUDE_MEMORY. * attribs.cc: Likewise. (attr_access::array_as_string): Use diagnostic_context::clone_printer and use unique_ptr. * auto-profile.cc: Add #define INCLUDE_MEMORY. * calls.cc: Likewise. * cfganal.cc: Likewise. * cfgexpand.cc: Likewise. * cfghooks.cc: Likewise. * cfgloop.cc: Likewise. * cgraph.cc: Likewise. * cgraphclones.cc: Likewise. * cgraphunit.cc: Likewise. * collect-utils.cc: Likewise. * collect2.cc: Likewise. * common/config/aarch64/aarch64-common.cc: Likewise. * common/config/arm/arm-common.cc: Likewise. * common/config/avr/avr-common.cc: Likewise. * config/aarch64/aarch64-cc-fusion.cc: Likewise. * config/aarch64/aarch64-early-ra.cc: Likewise. * config/aarch64/aarch64-sve-builtins.cc: Likewise. * config/arc/arc.cc: Likewise. * config/arm/aarch-common.cc: Likewise. * config/arm/arm-mve-builtins.cc: Likewise. * config/avr/avr-devices.cc: Likewise. * config/avr/driver-avr.cc: Likewise. * config/bpf/bpf.cc: Likewise. * config/bpf/btfext-out.cc: Likewise. * config/bpf/core-builtins.cc: Likewise. * config/darwin.cc: Likewise. * config/i386/driver-i386.cc: Likewise. * config/i386/i386-builtins.cc: Likewise. * config/i386/i386-expand.cc: Likewise. * config/i386/i386-features.cc: Likewise. * config/i386/i386-options.cc: Likewise. * config/loongarch/loongarch-builtins.cc: Likewise. * config/mingw/winnt-cxx.cc: Likewise. * config/mingw/winnt.cc: Likewise. * config/mips/mips.cc: Likewise. * config/msp430/driver-msp430.cc: Likewise. * config/nvptx/mkoffload.cc: Likewise. * config/nvptx/nvptx.cc: Likewise. * config/riscv/riscv-avlprop.cc: Likewise. * config/riscv/riscv-vector-builtins.cc: Likewise. * config/riscv/riscv-vsetvl.cc: Likewise. * config/rs6000/driver-rs6000.cc: Likewise. * config/rs6000/host-darwin.cc: Likewise. * config/rs6000/rs6000-c.cc: Likewise. * config/s390/s390-c.cc: Likewise. * config/s390/s390.cc: Likewise. * config/sol2-cxx.cc: Likewise. * config/vms/vms-c.cc: Likewise. * config/xtensa/xtensa-dynconfig.cc: Likewise. * coroutine-passes.cc: Likewise. * coverage.cc: Likewise. * data-streamer-in.cc: Likewise. * data-streamer-out.cc: Likewise. * data-streamer.cc: Likewise. * diagnostic-buffer.h (diagnostic_buffer::~diagnostic_buffer): Delete. (diagnostic_buffer::m_per_format_buffer): Use std::unique_ptr. * diagnostic-client-data-hooks.h (make_compiler_data_hooks): Use std::unique_ptr for return type. * diagnostic-format-json.cc (json_output_format::make_per_format_buffer): Likewise. (diagnostic_output_format_init_json): Update for usage of std::unique_ptr in set_output_format. * diagnostic-format-sarif.cc (sarif_output_format::make_per_format_buffer): Use std::unique_ptr for return type. (diagnostic_output_format_init_sarif): Update for usage of std::unique_ptr. (test_message_with_embedded_link): Likewise for set_urlifier. * diagnostic-format-text.cc: Add #define INCLUDE_MEMORY. Include "make-unique.h". (diagnostic_text_output_format::set_buffer): Use std::unique_ptr. * diagnostic-format-text.h (diagnostic_text_output_format::set_buffer): Likewise. * diagnostic-format.h (diagnostic_output_format::make_per_format_buffer): Likewise. * diagnostic-global-context.cc: * diagnostic-macro-unwinding.cc: Likewise. * diagnostic-show-locus.cc: Likewise. * diagnostic-spec.cc: Likewise. * diagnostic.cc (diagnostic_context::set_output_format): Use std::unique_ptr for input. (diagnostic_context::set_client_data_hooks): Likewise. (diagnostic_context::set_option_manager): Likewise. (diagnostic_context::set_urlifier): Likewise. (diagnostic_context::set_diagnostic_buffer): Update for use of std::unique_ptr. (diagnostic_buffer::diagnostic_buffer): Likewise. (diagnostic_buffer::~diagnostic_buffer): Delete. * diagnostic.h: Complain if INCLUDE_MEMORY was not defined. (diagnostic_context::set_output_format): Use std::unique_ptr for input. (diagnostic_context::set_client_data_hooks): Likewise. (diagnostic_context::set_option_manager): Likewise. (diagnostic_context::set_urlifier): Likewise. (diagnostic_context::clone_printer): New. (diagnostic_context::m_printer): Update comment. (diagnostic_context::m_option_mgr): Likewise. (diagnostic_context::m_urlifier): Likewise. (diagnostic_context::m_edit_context_ptr): Likewise. (diagnostic_context::m_output_format): Likewise. (diagnostic_context::m_client_data_hooks): Likewise. (diagnostic_context::m_theme): Likewise. * digraph.cc: Add #define INCLUDE_MEMORY. * dwarf2out.cc: Likewise. * edit-context.cc: Likewise. * except.cc: Likewise. * expr.cc: Likewise. * file-prefix-map.cc: Likewise. * final.cc: Likewise. * fwprop.cc: Likewise. * gcc-plugin.h: Likewise. * gcc-rich-location.cc: Likewise. * gcc-urlifier.cc: Likewise. Add #include "make-unique.h". (make_gcc_urlifier): Use std::unique_ptr and ::make_unique. * gcc-urlifier.h (make_gcc_urlifier): Use std::unique_ptr. * gcc.cc: Add #define INCLUDE_MEMORY. Include "pretty-print-urlifier.h". * gcov-dump.cc: Add #define INCLUDE_MEMORY. * gcov-tool.cc: Likewise. * gengtype.cc (open_base_files): Likewise to output. * genmatch.cc: Likewise. * gimple-fold.cc: Likewise. * gimple-harden-conditionals.cc: Likewise. * gimple-harden-control-flow.cc: Likewise. * gimple-if-to-switch.cc: Likewise. * gimple-lower-bitint.cc: Likewise. * gimple-predicate-analysis.cc: Likewise. * gimple-pretty-print.cc: Likewise. * gimple-range-cache.cc: Likewise. * gimple-range-edge.cc: Likewise. * gimple-range-fold.cc: Likewise. * gimple-range-gori.cc: Likewise. * gimple-range-infer.cc: Likewise. * gimple-range-op.cc: Likewise. * gimple-range-path.cc: Likewise. * gimple-range-phi.cc: Likewise. * gimple-range-trace.cc: Likewise. * gimple-range.cc: Likewise. * gimple-ssa-backprop.cc: Likewise. * gimple-ssa-sprintf.cc: Likewise. * gimple-ssa-store-merging.cc: Likewise. * gimple-ssa-strength-reduction.cc: Likewise. * gimple-ssa-warn-access.cc: Likewise. * gimple-ssa-warn-alloca.cc: Likewise. * gimple-ssa-warn-restrict.cc: Likewise. * gimple-streamer-in.cc: Likewise. * gimple-streamer-out.cc: Likewise. * gimple.cc: Likewise. * gimplify.cc: Likewise. * graph.cc: Likewise. * graphviz.cc: Likewise. * input.cc: Likewise. * ipa-cp.cc: Likewise. * ipa-devirt.cc: Likewise. * ipa-fnsummary.cc: Likewise. * ipa-free-lang-data.cc: Likewise. * ipa-icf-gimple.cc: Likewise. * ipa-icf.cc: Likewise. * ipa-inline-analysis.cc: Likewise. * ipa-inline.cc: Likewise. * ipa-modref-tree.cc: Likewise. * ipa-modref.cc: Likewise. * ipa-param-manipulation.cc: Likewise. * ipa-polymorphic-call.cc: Likewise. * ipa-predicate.cc: Likewise. * ipa-profile.cc: Likewise. * ipa-prop.cc: Likewise. * ipa-pure-const.cc: Likewise. * ipa-reference.cc: Likewise. * ipa-split.cc: Likewise. * ipa-sra.cc: Likewise. * ipa-strub.cc: Likewise. * ipa-utils.cc: Likewise. * langhooks.cc: Likewise. * late-combine.cc: Likewise. * lto-cgraph.cc: Likewise. * lto-compress.cc: Likewise. * lto-opts.cc: Likewise. * lto-section-in.cc: Likewise. * lto-section-out.cc: Likewise. * lto-streamer-in.cc: Likewise. * lto-streamer-out.cc: Likewise. * lto-streamer.cc: Likewise. * lto-wrapper.cc: Likewise. Include "make-unique.h". (main): Use ::make_unique when creating option manager. * multiple_target.cc: Likewise. * omp-expand.cc: Likewise. * omp-general.cc: Likewise. * omp-low.cc: Likewise. * omp-oacc-neuter-broadcast.cc: Likewise. * omp-offload.cc: Likewise. * omp-simd-clone.cc: Likewise. * optc-gen.awk: Likewise in output. * optc-save-gen.awk: Likewise in output. * options-urls-cc-gen.awk: Likewise in output. * opts-common.cc: Likewise. * opts-global.cc: Likewise. * opts.cc: Likewise. * pair-fusion.cc: Likewise. * passes.cc: Likewise. * pointer-query.cc: Likewise. * predict.cc: Likewise. * pretty-print.cc (pretty_printer::clone): Use std::unique_ptr and ::make_unique. * pretty-print.h: Complain if INCLUDE_MEMORY is not defined. (pretty_printer::clone): Use std::unique_ptr. * print-rtl.cc: Add #define INCLUDE_MEMORY. * print-tree.cc: Likewise. * profile-count.cc: Likewise. * range-op-float.cc: Likewise. * range-op-ptr.cc: Likewise. * range-op.cc: Likewise. * range.cc: Likewise. * read-rtl-function.cc: Likewise. * rtl-error.cc: Likewise. * rtl-ssa/accesses.cc: Likewise. * rtl-ssa/blocks.cc: Likewise. * rtl-ssa/changes.cc: Likewise. * rtl-ssa/functions.cc: Likewise. * rtl-ssa/insns.cc: Likewise. * rtl-ssa/movement.cc: Likewise. * rtl-tests.cc: Likewise. * sanopt.cc: Likewise. * sched-rgn.cc: Likewise. * selftest-diagnostic-path.cc: Likewise. * selftest-diagnostic.cc: Likewise. * splay-tree-utils.cc: Likewise. * sreal.cc: Likewise. * stmt.cc: Likewise. * substring-locations.cc: Likewise. * symtab-clones.cc: Likewise. * symtab-thunks.cc: Likewise. * symtab.cc: Likewise. * text-art/box-drawing.cc: Likewise. * text-art/canvas.cc: Likewise. * text-art/ruler.cc: Likewise. * text-art/selftests.cc: Likewise. * text-art/theme.cc: Likewise. * toplev.cc: Likewise. Include "make-unique.h". (general_init): Use ::make_unique when setting option_manager. * trans-mem.cc: Add #define INCLUDE_MEMORY. * tree-affine.cc: Likewise. * tree-call-cdce.cc: Likewise. * tree-cfg.cc: Likewise. * tree-chrec.cc: Likewise. * tree-dfa.cc: Likewise. * tree-diagnostic-client-data-hooks.cc: Include "make-unique.h". (make_compiler_data_hooks): Use std::unique_ptr and ::make_unique. * tree-diagnostic.cc: Add #define INCLUDE_MEMORY. * tree-dump.cc: Likewise. * tree-inline.cc: Likewise. * tree-into-ssa.cc: Likewise. * tree-logical-location.cc: Likewise. * tree-nested.cc: Likewise. * tree-nrv.cc: Likewise. * tree-object-size.cc: Likewise. * tree-outof-ssa.cc: Likewise. * tree-pretty-print.cc: Likewise. * tree-profile.cc: Likewise. * tree-scalar-evolution.cc: Likewise. * tree-sra.cc: Likewise. * tree-ssa-address.cc: Likewise. * tree-ssa-alias.cc: Likewise. * tree-ssa-ccp.cc: Likewise. * tree-ssa-coalesce.cc: Likewise. * tree-ssa-copy.cc: Likewise. * tree-ssa-dce.cc: Likewise. * tree-ssa-dom.cc: Likewise. * tree-ssa-forwprop.cc: Likewise. * tree-ssa-ifcombine.cc: Likewise. * tree-ssa-loop-ch.cc: Likewise. * tree-ssa-loop-im.cc: Likewise. * tree-ssa-loop-manip.cc: Likewise. * tree-ssa-loop-niter.cc: Likewise. * tree-ssa-loop-split.cc: Likewise. * tree-ssa-math-opts.cc: Likewise. * tree-ssa-operands.cc: Likewise. * tree-ssa-phiprop.cc: Likewise. * tree-ssa-pre.cc: Likewise. * tree-ssa-propagate.cc: Likewise. * tree-ssa-reassoc.cc: Likewise. * tree-ssa-sccvn.cc: Likewise. * tree-ssa-scopedtables.cc: Likewise. * tree-ssa-sink.cc: Likewise. * tree-ssa-strlen.cc: Likewise. * tree-ssa-structalias.cc: Likewise. * tree-ssa-ter.cc: Likewise. * tree-ssa-uninit.cc: Likewise. * tree-ssa.cc: Likewise. * tree-ssanames.cc: Likewise. * tree-stdarg.cc: Likewise. * tree-streamer-in.cc: Likewise. * tree-streamer-out.cc: Likewise. * tree-streamer.cc: Likewise. * tree-switch-conversion.cc: Likewise. * tree-tailcall.cc: Likewise. * tree-vrp.cc: Likewise. * tree.cc: Likewise. * ubsan.cc: Likewise. * value-pointer-equiv.cc: Likewise. * value-prof.cc: Likewise. * value-query.cc: Likewise. * value-range-pretty-print.cc: Likewise. * value-range-storage.cc: Likewise. * value-range.cc: Likewise. * value-relation.cc: Likewise. * var-tracking.cc: Likewise. * varpool.cc: Likewise. * vr-values.cc: Likewise. * wide-int-print.cc: Likewise. gcc/testsuite/ChangeLog: PR other/116613 * gcc.dg/plugin/diagnostic_group_plugin.c: Update for use of std::unique_ptr. * gcc.dg/plugin/diagnostic_plugin_xhtml_format.c: Likewise. * gcc.dg/plugin/ggcplug.c: Likewise. libgcc/ChangeLog: PR other/116613 * libgcov-util.c: Add #define INCLUDE_MEMORY. Signed-off-by: David Malcolm <dmalcolm@redhat.com> Co-authored-by: Gaius Mulley <gaiusmod2@gmail.com> Signed-off-by: David Malcolm <dmalcolm@redhat.com>
647 lines
19 KiB
C++
647 lines
19 KiB
C++
/* Harden conditionals.
|
|
Copyright (C) 2021-2024 Free Software Foundation, Inc.
|
|
Contributed by Alexandre Oliva <oliva@adacore.com>.
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#define INCLUDE_MEMORY
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "backend.h"
|
|
#include "target.h"
|
|
#include "rtl.h"
|
|
#include "tree.h"
|
|
#include "fold-const.h"
|
|
#include "gimple.h"
|
|
#include "gimplify.h"
|
|
#include "tree-pass.h"
|
|
#include "ssa.h"
|
|
#include "gimple-iterator.h"
|
|
#include "tree-cfg.h"
|
|
#include "basic-block.h"
|
|
#include "cfghooks.h"
|
|
#include "cfgloop.h"
|
|
#include "tree-eh.h"
|
|
#include "sbitmap.h"
|
|
#include "diagnostic.h"
|
|
#include "intl.h"
|
|
|
|
namespace {
|
|
|
|
/* These passes introduces redundant, but reversed conditionals at
|
|
compares, such as those used in conditional branches, and those
|
|
that compute boolean results. This doesn't make much sense for
|
|
abstract CPUs, but this kind of hardening may avoid undesirable
|
|
execution paths on actual CPUs under such attacks as of power
|
|
deprivation. */
|
|
|
|
/* Define a pass to harden conditionals other than branches. */
|
|
|
|
const pass_data pass_data_harden_compares = {
|
|
GIMPLE_PASS,
|
|
"hardcmp",
|
|
OPTGROUP_NONE,
|
|
TV_NONE,
|
|
PROP_cfg | PROP_ssa, // properties_required
|
|
0, // properties_provided
|
|
0, // properties_destroyed
|
|
0, // properties_start
|
|
TODO_update_ssa
|
|
| TODO_cleanup_cfg
|
|
| TODO_verify_il, // properties_finish
|
|
};
|
|
|
|
class pass_harden_compares : public gimple_opt_pass
|
|
{
|
|
public:
|
|
pass_harden_compares (gcc::context *ctxt)
|
|
: gimple_opt_pass (pass_data_harden_compares, ctxt)
|
|
{}
|
|
opt_pass *clone () final override
|
|
{
|
|
return new pass_harden_compares (m_ctxt);
|
|
}
|
|
bool gate (function *) final override
|
|
{
|
|
return flag_harden_compares;
|
|
}
|
|
unsigned int execute (function *) final override;
|
|
};
|
|
|
|
/* Define a pass to harden conditionals in branches. This pass must
|
|
run after the above, otherwise it will re-harden the checks
|
|
introduced by the above. */
|
|
|
|
const pass_data pass_data_harden_conditional_branches = {
|
|
GIMPLE_PASS,
|
|
"hardcbr",
|
|
OPTGROUP_NONE,
|
|
TV_NONE,
|
|
PROP_cfg | PROP_ssa, // properties_required
|
|
0, // properties_provided
|
|
0, // properties_destroyed
|
|
0, // properties_start
|
|
TODO_update_ssa
|
|
| TODO_cleanup_cfg
|
|
| TODO_verify_il, // properties_finish
|
|
};
|
|
|
|
class pass_harden_conditional_branches : public gimple_opt_pass
|
|
{
|
|
public:
|
|
pass_harden_conditional_branches (gcc::context *ctxt)
|
|
: gimple_opt_pass (pass_data_harden_conditional_branches, ctxt)
|
|
{}
|
|
opt_pass *clone () final override
|
|
{
|
|
return new pass_harden_conditional_branches (m_ctxt);
|
|
}
|
|
bool gate (function *) final override
|
|
{
|
|
return flag_harden_conditional_branches;
|
|
}
|
|
unsigned int execute (function *) final override;
|
|
};
|
|
|
|
}
|
|
|
|
/* If VAL is an SSA name, return an SSA name holding the same value,
|
|
but without the compiler's knowing that it holds the same value, so
|
|
that uses thereof can't be optimized the way VAL might. Insert
|
|
stmts that initialize it before *GSIP, with LOC.
|
|
|
|
Otherwise, VAL must be an invariant, returned unchanged. */
|
|
|
|
static inline tree
|
|
detach_value (location_t loc, gimple_stmt_iterator *gsip, tree val)
|
|
{
|
|
if (TREE_CONSTANT (val) || TREE_CODE (val) != SSA_NAME)
|
|
{
|
|
gcc_checking_assert (is_gimple_min_invariant (val));
|
|
return val;
|
|
}
|
|
|
|
/* Create a SSA "copy" of VAL. It would be nice to have it named
|
|
after the corresponding variable, but sharing the same decl is
|
|
problematic when VAL is a DECL_BY_REFERENCE RESULT_DECL, and
|
|
copying just the identifier hits -fcompare-debug failures. */
|
|
tree ret = make_ssa_name (TREE_TYPE (val));
|
|
|
|
/* Some modes won't fit in general regs, so we fall back to memory
|
|
for them. ??? It would be ideal to try to identify an alternate,
|
|
wider or more suitable register class, and use the corresponding
|
|
constraint, but there's no logic to go from register class to
|
|
constraint, even if there is a corresponding constraint, and even
|
|
if we could enumerate constraints, we can't get to their string
|
|
either. So this will do for now. */
|
|
bool need_memory = true;
|
|
enum machine_mode mode = TYPE_MODE (TREE_TYPE (val));
|
|
if (mode != BLKmode)
|
|
for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
|
if (TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i)
|
|
&& targetm.hard_regno_mode_ok (i, mode))
|
|
{
|
|
need_memory = false;
|
|
break;
|
|
}
|
|
|
|
tree asminput = val;
|
|
tree asmoutput = ret;
|
|
const char *constraint_out = need_memory ? "=m" : "=g";
|
|
const char *constraint_in = need_memory ? "m" : "0";
|
|
|
|
if (need_memory)
|
|
{
|
|
tree temp = create_tmp_var (TREE_TYPE (val), "dtch");
|
|
mark_addressable (temp);
|
|
|
|
gassign *copyin = gimple_build_assign (temp, asminput);
|
|
gimple_set_location (copyin, loc);
|
|
gsi_insert_before (gsip, copyin, GSI_SAME_STMT);
|
|
|
|
asminput = asmoutput = temp;
|
|
}
|
|
|
|
/* Output an asm statement with matching input and output. It does
|
|
nothing, but after it the compiler no longer knows the output
|
|
still holds the same value as the input. */
|
|
vec<tree, va_gc> *inputs = NULL;
|
|
vec<tree, va_gc> *outputs = NULL;
|
|
vec_safe_push (outputs,
|
|
build_tree_list
|
|
(build_tree_list
|
|
(NULL_TREE, build_string (strlen (constraint_out),
|
|
constraint_out)),
|
|
asmoutput));
|
|
vec_safe_push (inputs,
|
|
build_tree_list
|
|
(build_tree_list
|
|
(NULL_TREE, build_string (strlen (constraint_in),
|
|
constraint_in)),
|
|
asminput));
|
|
gasm *detach = gimple_build_asm_vec ("", inputs, outputs,
|
|
NULL, NULL);
|
|
gimple_set_location (detach, loc);
|
|
gsi_insert_before (gsip, detach, GSI_SAME_STMT);
|
|
|
|
if (need_memory)
|
|
{
|
|
gassign *copyout = gimple_build_assign (ret, asmoutput);
|
|
gimple_set_location (copyout, loc);
|
|
gsi_insert_before (gsip, copyout, GSI_SAME_STMT);
|
|
SSA_NAME_DEF_STMT (ret) = copyout;
|
|
|
|
gassign *clobber = gimple_build_assign (asmoutput,
|
|
build_clobber
|
|
(TREE_TYPE (asmoutput)));
|
|
gimple_set_location (clobber, loc);
|
|
gsi_insert_before (gsip, clobber, GSI_SAME_STMT);
|
|
}
|
|
else
|
|
SSA_NAME_DEF_STMT (ret) = detach;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Build a cond stmt out of COP, LHS, RHS, insert it before *GSIP with
|
|
location LOC. *GSIP must be at the end of a basic block. The succ
|
|
edge out of the block becomes the true or false edge opposite to
|
|
that in FLAGS. Create a new block with a single trap stmt, in the
|
|
cold partition if the function is partitioned,, and a new edge to
|
|
it as the other edge for the cond. */
|
|
|
|
static inline void
|
|
insert_check_and_trap (location_t loc, gimple_stmt_iterator *gsip,
|
|
int flags, enum tree_code cop, tree lhs, tree rhs)
|
|
{
|
|
basic_block chk = gsi_bb (*gsip);
|
|
|
|
gcond *cond = gimple_build_cond (cop, lhs, rhs, NULL, NULL);
|
|
gimple_set_location (cond, loc);
|
|
gsi_insert_before (gsip, cond, GSI_SAME_STMT);
|
|
|
|
basic_block trp = create_empty_bb (chk);
|
|
trp->count = profile_count::zero ();
|
|
|
|
gimple_stmt_iterator gsit = gsi_after_labels (trp);
|
|
gcall *trap = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
|
|
gimple_call_set_ctrl_altering (trap, true);
|
|
gimple_set_location (trap, loc);
|
|
gsi_insert_before (&gsit, trap, GSI_SAME_STMT);
|
|
|
|
if (dump_file)
|
|
fprintf (dump_file,
|
|
"Adding reversed compare to block %i, and trap to block %i\n",
|
|
chk->index, trp->index);
|
|
|
|
if (BB_PARTITION (chk))
|
|
BB_SET_PARTITION (trp, BB_COLD_PARTITION);
|
|
|
|
int true_false_flag = flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
|
|
gcc_assert (true_false_flag);
|
|
int neg_true_false_flag = (~flags) & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
|
|
|
|
/* Remove the fallthru bit, and set the truth value for the
|
|
preexisting edge and for the newly-created one. In hardcbr,
|
|
FLAGS is taken from the edge of the original cond expr that we're
|
|
dealing with, so the reversed compare is expected to yield the
|
|
negated result, and the same result calls for a trap. In
|
|
hardcmp, we're comparing the boolean results of the original and
|
|
of the reversed compare, so we're passed FLAGS to trap on
|
|
equality. */
|
|
single_succ_edge (chk)->flags &= ~EDGE_FALLTHRU;
|
|
single_succ_edge (chk)->flags |= neg_true_false_flag;
|
|
single_succ_edge (chk)->probability = profile_probability::always ();
|
|
edge e = make_edge (chk, trp, true_false_flag);
|
|
e->goto_locus = loc;
|
|
e->probability = profile_probability::never ();
|
|
|
|
if (dom_info_available_p (CDI_DOMINATORS))
|
|
set_immediate_dominator (CDI_DOMINATORS, trp, chk);
|
|
if (current_loops)
|
|
add_bb_to_loop (trp, current_loops->tree_root);
|
|
}
|
|
|
|
/* Split edge E, and insert_check_and_trap (see above) in the
|
|
newly-created block, using already-detached copies of LHS's and
|
|
RHS's values (see detach_value above) for the COP compare. */
|
|
|
|
static inline void
|
|
insert_edge_check_and_trap (location_t loc, edge e,
|
|
enum tree_code cop, tree lhs, tree rhs)
|
|
{
|
|
int flags = e->flags;
|
|
basic_block src = e->src;
|
|
basic_block dest = e->dest;
|
|
location_t eloc = e->goto_locus;
|
|
|
|
basic_block chk = split_edge (e);
|
|
e = NULL;
|
|
|
|
single_pred_edge (chk)->goto_locus = loc;
|
|
single_succ_edge (chk)->goto_locus = eloc;
|
|
|
|
if (dump_file)
|
|
fprintf (dump_file,
|
|
"Splitting edge %i->%i into block %i\n",
|
|
src->index, dest->index, chk->index);
|
|
|
|
gimple_stmt_iterator gsik = gsi_after_labels (chk);
|
|
|
|
insert_check_and_trap (loc, &gsik, flags, cop, lhs, rhs);
|
|
}
|
|
|
|
/* Harden cond stmts at the end of FUN's blocks. */
|
|
|
|
unsigned int
|
|
pass_harden_conditional_branches::execute (function *fun)
|
|
{
|
|
/* Record the preexisting blocks, to avoid visiting newly-created
|
|
blocks. */
|
|
auto_sbitmap to_visit (last_basic_block_for_fn (fun));
|
|
bitmap_clear (to_visit);
|
|
|
|
basic_block bb;
|
|
FOR_EACH_BB_FN (bb, fun)
|
|
bitmap_set_bit (to_visit, bb->index);
|
|
|
|
sbitmap_iterator it;
|
|
unsigned i;
|
|
EXECUTE_IF_SET_IN_BITMAP (to_visit, 0, i, it)
|
|
{
|
|
bb = BASIC_BLOCK_FOR_FN (fun, i);
|
|
|
|
gimple_stmt_iterator gsi = gsi_last_bb (bb);
|
|
|
|
if (gsi_end_p (gsi))
|
|
continue;
|
|
|
|
gcond *cond = dyn_cast <gcond *> (gsi_stmt (gsi));
|
|
if (!cond)
|
|
continue;
|
|
|
|
/* Turn:
|
|
|
|
if (x op y) goto l1; else goto l2;
|
|
|
|
into:
|
|
|
|
if (x op y) goto l1'; else goto l2';
|
|
l1': if (x' cop y') goto l1'trap; else goto l1;
|
|
l1'trap: __builtin_trap ();
|
|
l2': if (x' cop y') goto l2; else goto l2'trap;
|
|
l2'trap: __builtin_trap ();
|
|
|
|
where cop is a complementary boolean operation to op; l1', l1'trap,
|
|
l2' and l2'trap are newly-created labels; and x' and y' hold the same
|
|
value as x and y, but in a way that does not enable the compiler to
|
|
optimize the redundant compare away.
|
|
*/
|
|
|
|
enum tree_code op = gimple_cond_code (cond);
|
|
tree lhs = gimple_cond_lhs (cond);
|
|
tree rhs = gimple_cond_rhs (cond);
|
|
location_t loc = gimple_location (cond);
|
|
|
|
enum tree_code cop = invert_tree_comparison (op, HONOR_NANS (lhs));
|
|
|
|
if (cop == ERROR_MARK)
|
|
/* ??? Can we do better? */
|
|
continue;
|
|
|
|
/* Detach the values before the compares. If we do so later,
|
|
the compiler may use values inferred from the compares. */
|
|
bool same_p = (lhs == rhs);
|
|
lhs = detach_value (loc, &gsi, lhs);
|
|
rhs = same_p ? lhs : detach_value (loc, &gsi, rhs);
|
|
|
|
insert_edge_check_and_trap (loc, EDGE_SUCC (bb, 0), cop, lhs, rhs);
|
|
insert_edge_check_and_trap (loc, EDGE_SUCC (bb, 1), cop, lhs, rhs);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Instantiate a hardcbr pass. */
|
|
|
|
gimple_opt_pass *
|
|
make_pass_harden_conditional_branches (gcc::context *ctxt)
|
|
{
|
|
return new pass_harden_conditional_branches (ctxt);
|
|
}
|
|
|
|
/* Return the fallthru edge of a block whose other edge is an EH
|
|
edge. If EHP is not NULL, store the EH edge in it. */
|
|
static inline edge
|
|
non_eh_succ_edge (basic_block bb, edge *ehp = NULL)
|
|
{
|
|
gcc_checking_assert (EDGE_COUNT (bb->succs) == 2);
|
|
|
|
edge ret = find_fallthru_edge (bb->succs);
|
|
|
|
int eh_idx = EDGE_SUCC (bb, 0) == ret;
|
|
edge eh = EDGE_SUCC (bb, eh_idx);
|
|
|
|
gcc_checking_assert (!(ret->flags & EDGE_EH)
|
|
&& (eh->flags & EDGE_EH));
|
|
|
|
if (ehp)
|
|
*ehp = eh;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Harden boolean-yielding compares in FUN. */
|
|
|
|
unsigned int
|
|
pass_harden_compares::execute (function *fun)
|
|
{
|
|
/* Record the preexisting blocks, to avoid visiting newly-created
|
|
blocks. */
|
|
auto_sbitmap to_visit (last_basic_block_for_fn (fun));
|
|
bitmap_clear (to_visit);
|
|
|
|
basic_block bb;
|
|
FOR_EACH_BB_FN (bb, fun)
|
|
bitmap_set_bit (to_visit, bb->index);
|
|
|
|
sbitmap_iterator it;
|
|
unsigned i;
|
|
EXECUTE_IF_SET_IN_BITMAP (to_visit, 0, i, it)
|
|
{
|
|
bb = BASIC_BLOCK_FOR_FN (fun, i);
|
|
|
|
for (gimple_stmt_iterator gsi = gsi_last_bb (bb);
|
|
!gsi_end_p (gsi); gsi_prev (&gsi))
|
|
{
|
|
gassign *asgn = dyn_cast <gassign *> (gsi_stmt (gsi));
|
|
if (!asgn)
|
|
continue;
|
|
|
|
/* Turn:
|
|
|
|
z = x op y;
|
|
|
|
into:
|
|
|
|
z = x op y;
|
|
z' = x' cop y';
|
|
if (z == z') __builtin_trap ();
|
|
|
|
where cop is a complementary boolean operation to op; and x'
|
|
and y' hold the same value as x and y, but in a way that does
|
|
not enable the compiler to optimize the redundant compare
|
|
away.
|
|
*/
|
|
|
|
enum tree_code op = gimple_assign_rhs_code (asgn);
|
|
|
|
enum tree_code cop;
|
|
|
|
switch (op)
|
|
{
|
|
case EQ_EXPR:
|
|
case NE_EXPR:
|
|
case GT_EXPR:
|
|
case GE_EXPR:
|
|
case LT_EXPR:
|
|
case LE_EXPR:
|
|
case LTGT_EXPR:
|
|
case UNEQ_EXPR:
|
|
case UNGT_EXPR:
|
|
case UNGE_EXPR:
|
|
case UNLT_EXPR:
|
|
case UNLE_EXPR:
|
|
case ORDERED_EXPR:
|
|
case UNORDERED_EXPR:
|
|
cop = invert_tree_comparison (op,
|
|
HONOR_NANS
|
|
(gimple_assign_rhs1 (asgn)));
|
|
|
|
if (cop == ERROR_MARK)
|
|
/* ??? Can we do better? */
|
|
continue;
|
|
|
|
break;
|
|
|
|
/* ??? Maybe handle these too? */
|
|
case TRUTH_NOT_EXPR:
|
|
/* ??? The code below assumes binary ops, it would have to
|
|
be adjusted for TRUTH_NOT_EXPR, since it's unary. */
|
|
case TRUTH_ANDIF_EXPR:
|
|
case TRUTH_ORIF_EXPR:
|
|
case TRUTH_AND_EXPR:
|
|
case TRUTH_OR_EXPR:
|
|
case TRUTH_XOR_EXPR:
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
/* These are the operands for the verification. */
|
|
tree lhs = gimple_assign_lhs (asgn);
|
|
tree op1 = gimple_assign_rhs1 (asgn);
|
|
tree op2 = gimple_assign_rhs2 (asgn);
|
|
location_t loc = gimple_location (asgn);
|
|
|
|
/* Vector booleans can't be used in conditional branches. ???
|
|
Can we do better? How to reduce compare and
|
|
reversed-compare result vectors to a single boolean? */
|
|
if (VECTOR_TYPE_P (TREE_TYPE (op1)))
|
|
continue;
|
|
|
|
/* useless_type_conversion_p enables conversions from 1-bit
|
|
integer types to boolean to be discarded. */
|
|
gcc_checking_assert (TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE
|
|
|| (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
|
|
&& TYPE_PRECISION (TREE_TYPE (lhs)) == 1));
|
|
|
|
tree rhs = copy_ssa_name (lhs);
|
|
|
|
/* Detach the values before the compares, so that the
|
|
compiler infers nothing from them, not even from a
|
|
throwing compare that didn't throw. */
|
|
bool same_p = (op1 == op2);
|
|
op1 = detach_value (loc, &gsi, op1);
|
|
op2 = same_p ? op1 : detach_value (loc, &gsi, op2);
|
|
|
|
gimple_stmt_iterator gsi_split = gsi;
|
|
/* Don't separate the original assignment from debug stmts
|
|
that might be associated with it, and arrange to split the
|
|
block after debug stmts, so as to make sure the split block
|
|
won't be debug stmts only. */
|
|
gsi_next_nondebug (&gsi_split);
|
|
|
|
bool throwing_compare_p = stmt_ends_bb_p (asgn);
|
|
if (throwing_compare_p)
|
|
{
|
|
basic_block nbb = split_edge (non_eh_succ_edge
|
|
(gimple_bb (asgn)));
|
|
gsi_split = gsi_start_bb (nbb);
|
|
|
|
if (dump_file)
|
|
fprintf (dump_file,
|
|
"Splitting non-EH edge from block %i into %i"
|
|
" after a throwing compare\n",
|
|
gimple_bb (asgn)->index, nbb->index);
|
|
}
|
|
|
|
gassign *asgnck = gimple_build_assign (rhs, cop, op1, op2);
|
|
gimple_set_location (asgnck, loc);
|
|
gsi_insert_before (&gsi_split, asgnck, GSI_SAME_STMT);
|
|
|
|
/* We wish to insert a cond_expr after the compare, so arrange
|
|
for it to be at the end of a block if it isn't, and for it
|
|
to have a single successor in case there's more than
|
|
one, as in PR104975. */
|
|
if (!gsi_end_p (gsi_split)
|
|
|| !single_succ_p (gsi_bb (gsi_split)))
|
|
{
|
|
if (!gsi_end_p (gsi_split))
|
|
gsi_prev (&gsi_split);
|
|
else
|
|
gsi_split = gsi_last_bb (gsi_bb (gsi_split));
|
|
basic_block obb = gsi_bb (gsi_split);
|
|
basic_block nbb = split_block (obb, gsi_stmt (gsi_split))->dest;
|
|
gsi_next (&gsi_split);
|
|
gcc_checking_assert (gsi_end_p (gsi_split));
|
|
|
|
single_succ_edge (bb)->goto_locus = loc;
|
|
|
|
if (dump_file)
|
|
fprintf (dump_file,
|
|
"Splitting block %i into %i"
|
|
" before the conditional trap branch\n",
|
|
obb->index, nbb->index);
|
|
}
|
|
|
|
/* If the check assignment must end a basic block, we can't
|
|
insert the conditional branch in the same block, so split
|
|
the block again, and prepare to insert the conditional
|
|
branch in the new block.
|
|
|
|
Also assign an EH region to the compare. Even though it's
|
|
unlikely that the hardening compare will throw after the
|
|
original compare didn't, the compiler won't even know that
|
|
it's the same compare operands, so add the EH edge anyway. */
|
|
if (throwing_compare_p)
|
|
{
|
|
add_stmt_to_eh_lp (asgnck, lookup_stmt_eh_lp (asgn));
|
|
edge eh = make_eh_edge (asgnck);
|
|
/* This compare looks like it could raise an exception,
|
|
but it's dominated by the original compare, that
|
|
would raise an exception first, so the EH edge from
|
|
this one is never really taken. */
|
|
eh->probability = profile_probability::never ();
|
|
if (eh->dest->count.initialized_p ())
|
|
eh->dest->count += eh->count ();
|
|
else
|
|
eh->dest->count = eh->count ();
|
|
|
|
edge ckeh;
|
|
basic_block nbb = split_edge (non_eh_succ_edge
|
|
(gimple_bb (asgnck), &ckeh));
|
|
gcc_checking_assert (eh == ckeh);
|
|
gsi_split = gsi_start_bb (nbb);
|
|
|
|
if (dump_file)
|
|
fprintf (dump_file,
|
|
"Splitting non-EH edge from block %i into %i after"
|
|
" the newly-inserted reversed throwing compare\n",
|
|
gimple_bb (asgnck)->index, nbb->index);
|
|
|
|
if (!gimple_seq_empty_p (phi_nodes (ckeh->dest)))
|
|
{
|
|
edge aseh;
|
|
non_eh_succ_edge (gimple_bb (asgn), &aseh);
|
|
|
|
gcc_checking_assert (aseh->dest == ckeh->dest);
|
|
|
|
for (gphi_iterator psi = gsi_start_phis (ckeh->dest);
|
|
!gsi_end_p (psi); gsi_next (&psi))
|
|
{
|
|
gphi *phi = psi.phi ();
|
|
add_phi_arg (phi, PHI_ARG_DEF_FROM_EDGE (phi, aseh), ckeh,
|
|
gimple_phi_arg_location_from_edge (phi, aseh));
|
|
}
|
|
|
|
if (dump_file)
|
|
fprintf (dump_file,
|
|
"Copying PHI args in EH block %i from %i to %i\n",
|
|
aseh->dest->index, aseh->src->index,
|
|
ckeh->src->index);
|
|
}
|
|
}
|
|
|
|
gcc_checking_assert (single_succ_p (gsi_bb (gsi_split)));
|
|
|
|
insert_check_and_trap (loc, &gsi_split, EDGE_TRUE_VALUE,
|
|
EQ_EXPR, lhs, rhs);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Instantiate a hardcmp pass. */
|
|
|
|
gimple_opt_pass *
|
|
make_pass_harden_compares (gcc::context *ctxt)
|
|
{
|
|
return new pass_harden_compares (ctxt);
|
|
}
|