aboutsummaryrefslogtreecommitdiff
path: root/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp
diff options
context:
space:
mode:
authorMarkus Böck <markus.boeck02@gmail.com>2025-10-03 15:05:59 +0200
committerGitHub <noreply@github.com>2025-10-03 15:05:59 +0200
commit6bdf2cb2024e3a1f9596189f567b13665a19d1b1 (patch)
tree3ac994fac8518ac79aadcc9f815cef36fdb48d77 /llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp
parentbbae6a460c9fe41bdbf1f93f36928301d53c7db0 (diff)
downloadllvm-6bdf2cb2024e3a1f9596189f567b13665a19d1b1.zip
llvm-6bdf2cb2024e3a1f9596189f567b13665a19d1b1.tar.gz
llvm-6bdf2cb2024e3a1f9596189f567b13665a19d1b1.tar.bz2
[mlir][NFC] Remove redundant insertion point changes (#161837)
These insertion points were added in https://github.com/llvm/llvm-project/pull/146551 and https://github.com/llvm/llvm-project/pull/146908 to support the one-shot dialect conversion driver which performs changes to the IR immediately and would otherwise invalidate previous insertion points. Since then, the insertion point has been made resilient against op erasure (https://github.com/llvm/llvm-project/pull/146955) making the changes now redundant.
Diffstat (limited to 'llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp')
0 files changed, 0 insertions, 0 deletions
an class="hl opt">+ descr->sizeof_register[regnum]); } /* Size. */ if (regnum < 0) gdb_printf (file, " %5s ", "Size"); else gdb_printf (file, " %5ld", descr->sizeof_register[regnum]); /* Type. */ { const char *t; std::string name_holder; if (regnum < 0) t = "Type"; else { static const char blt[] = "builtin_type"; t = register_type (m_gdbarch, regnum)->name (); if (t == NULL) { if (!footnote_register_type_name_null) footnote_register_type_name_null = ++footnote_nr; name_holder = string_printf ("*%d", footnote_register_type_name_null); t = name_holder.c_str (); } /* Chop a leading builtin_type. */ if (startswith (t, blt)) t += strlen (blt); } gdb_printf (file, " %-15s", t); } /* Leading space always present. */ gdb_printf (file, " "); dump_reg (file, regnum); gdb_printf (file, "\n"); } if (footnote_register_offset) gdb_printf (file, "*%d: Inconsistent register offsets.\n", footnote_register_offset); if (footnote_register_type_name_null) gdb_printf (file, "*%d: Register type's name NULL.\n", footnote_register_type_name_null); } #if GDB_SELF_TEST #include "gdbsupport/selftest.h" #include "selftest-arch.h" #include "target-float.h" namespace selftests { static size_t regcaches_size () { size_t size = 0; for (auto pid_ptid_regc_map_it = regcaches.cbegin (); pid_ptid_regc_map_it != regcaches.cend (); ++pid_ptid_regc_map_it) { const pid_ptid_regcache_map &pid_ptid_regc_map = pid_ptid_regc_map_it->second; for (auto ptid_regc_map_it = pid_ptid_regc_map.cbegin (); ptid_regc_map_it != pid_ptid_regc_map.cend (); ++ptid_regc_map_it) { const ptid_regcache_map &ptid_regc_map = ptid_regc_map_it->second; size += ptid_regc_map.size (); } } return size; } /* Return the count of regcaches for (TARGET, PTID) in REGCACHES. */ static int regcache_count (process_stratum_target *target, ptid_t ptid) { /* Look up map for target. */ auto pid_ptid_regc_map_it = regcaches.find (target); if (pid_ptid_regc_map_it != regcaches.end ()) { pid_ptid_regcache_map &pid_ptid_regc_map = pid_ptid_regc_map_it->second; /* Look map for pid. */ auto ptid_regc_map_it = pid_ptid_regc_map.find (ptid.pid ()); if (ptid_regc_map_it != pid_ptid_regc_map.end ()) { ptid_regcache_map &ptid_regc_map = ptid_regc_map_it->second; auto range = ptid_regc_map.equal_range (ptid); return std::distance (range.first, range.second); } } return 0; }; /* Wrapper around get_thread_arch_aspace_regcache that does some self checks. */ static void get_thread_arch_aspace_regcache_and_check (inferior *inf_for_target_calls, ptid_t ptid) { /* We currently only test with a single gdbarch. Any gdbarch will do, so use the current inferior's gdbarch. Also use the current inferior's address space. */ gdbarch *arch = inf_for_target_calls->gdbarch; address_space *aspace = inf_for_target_calls->aspace; regcache *regcache = get_thread_arch_aspace_regcache (inf_for_target_calls, ptid, arch, aspace); SELF_CHECK (regcache != NULL); SELF_CHECK (regcache->ptid () == ptid); SELF_CHECK (regcache->arch () == arch); SELF_CHECK (regcache->aspace () == aspace); } /* The data that the regcaches selftests must hold onto for the duration of the test. */ struct regcache_test_data { regcache_test_data () /* The specific arch doesn't matter. */ : test_ctx_1 (current_inferior ()->gdbarch), test_ctx_2 (current_inferior ()->gdbarch) { /* Ensure the regcaches container is empty at the start. */ registers_changed (); } ~regcache_test_data () { /* Make sure to leave the global regcaches container empty. */ registers_changed (); } scoped_mock_context<test_target_ops> test_ctx_1; scoped_mock_context<test_target_ops> test_ctx_2; }; using regcache_test_data_up = std::unique_ptr<regcache_test_data>; /* Set up a few regcaches from two different targets, for use in regcache-management tests. Return a pointer, because the `regcache_test_data` type is not moveable. */ static regcache_test_data_up populate_regcaches_for_test () { regcache_test_data_up data (new regcache_test_data); size_t expected_regcache_size = 0; SELF_CHECK (regcaches_size () == 0); /* Populate the regcache container with a few regcaches for the two test targets. */ for (int pid : { 1, 2 }) { for (long lwp : { 1, 2, 3 }) { get_thread_arch_aspace_regcache_and_check (&data->test_ctx_1.mock_inferior, ptid_t (pid, lwp)); expected_regcache_size++; SELF_CHECK (regcaches_size () == expected_regcache_size); get_thread_arch_aspace_regcache_and_check (&data->test_ctx_2.mock_inferior, ptid_t (pid, lwp)); expected_regcache_size++; SELF_CHECK (regcaches_size () == expected_regcache_size); } } return data; } static void get_thread_arch_aspace_regcache_test () { /* populate_regcaches_for_test already tests most of the get_thread_arch_aspace_regcache functionality. */ regcache_test_data_up data = populate_regcaches_for_test (); size_t regcaches_size_before = regcaches_size (); /* Test that getting an existing regcache doesn't create a new one. */ get_thread_arch_aspace_regcache_and_check (&data->test_ctx_1.mock_inferior, ptid_t (2, 2)); SELF_CHECK (regcaches_size () == regcaches_size_before); } /* Test marking all regcaches of all targets as changed. */ static void registers_changed_ptid_all_test () { regcache_test_data_up data = populate_regcaches_for_test (); registers_changed_ptid (nullptr, minus_one_ptid); SELF_CHECK (regcaches_size () == 0); } /* Test marking regcaches of a specific target as changed. */ static void registers_changed_ptid_target_test () { regcache_test_data_up data = populate_regcaches_for_test (); registers_changed_ptid (&data->test_ctx_1.mock_target, minus_one_ptid); SELF_CHECK (regcaches_size () == 6); /* Check that we deleted the regcache for the right target. */ SELF_CHECK (regcache_count (&data->test_ctx_1.mock_target, ptid_t (2, 2)) == 0); SELF_CHECK (regcache_count (&data->test_ctx_2.mock_target, ptid_t (2, 2)) == 1); } /* Test marking regcaches of a specific (target, pid) as changed. */ static void registers_changed_ptid_target_pid_test () { regcache_test_data_up data = populate_regcaches_for_test (); registers_changed_ptid (&data->test_ctx_1.mock_target, ptid_t (2)); SELF_CHECK (regcaches_size () == 9); /* Regcaches from target1 should not exist, while regcaches from target2 should exist. */ SELF_CHECK (regcache_count (&data->test_ctx_1.mock_target, ptid_t (2, 2)) == 0); SELF_CHECK (regcache_count (&data->test_ctx_2.mock_target, ptid_t (2, 2)) == 1); } /* Test marking regcaches of a specific (target, ptid) as changed. */ static void registers_changed_ptid_target_ptid_test () { regcache_test_data_up data = populate_regcaches_for_test (); registers_changed_ptid (&data->test_ctx_1.mock_target, ptid_t (2, 2)); SELF_CHECK (regcaches_size () == 11); /* Check that we deleted the regcache for the right target. */ SELF_CHECK (regcache_count (&data->test_ctx_1.mock_target, ptid_t (2, 2)) == 0); SELF_CHECK (regcache_count (&data->test_ctx_2.mock_target, ptid_t (2, 2)) == 1); } class target_ops_no_register : public test_target_ops { public: target_ops_no_register () : test_target_ops {} {} void reset () { fetch_registers_called = 0; store_registers_called = 0; xfer_partial_called = 0; } void fetch_registers (regcache *regs, int regno) override; void store_registers (regcache *regs, int regno) override; enum target_xfer_status xfer_partial (enum target_object object, const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) override; unsigned int fetch_registers_called = 0; unsigned int store_registers_called = 0; unsigned int xfer_partial_called = 0; }; void target_ops_no_register::fetch_registers (regcache *regs, int regno) { /* Mark register available. */ regs->raw_supply_zeroed (regno); this->fetch_registers_called++; } void target_ops_no_register::store_registers (regcache *regs, int regno) { this->store_registers_called++; } enum target_xfer_status target_ops_no_register::xfer_partial (enum target_object object, const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) { this->xfer_partial_called++; *xfered_len = len; return TARGET_XFER_OK; } class readwrite_regcache : public regcache { public: readwrite_regcache (inferior *inf_for_target_calls, struct gdbarch *gdbarch) : regcache (inf_for_target_calls, gdbarch, nullptr) {} }; /* Return true if regcache::cooked_{read,write}_test should be skipped for GDBARCH. */ static bool selftest_skiparch (struct gdbarch *gdbarch) { const char *name = gdbarch_bfd_arch_info (gdbarch)->printable_name; /* Avoid warning: Running selftest regcache::cooked_{read,write}_test::m68hc11. warning: No frame soft register found in the symbol table. Stack backtrace will not work. We could instead capture the output and then filter out the warning, but that seems more trouble than it's worth. */ return (strcmp (name, "m68hc11") == 0 || strcmp (name, "m68hc12") == 0 || strcmp (name, "m68hc12:HCS12") == 0); } /* Test regcache::cooked_read gets registers from raw registers and memory instead of target to_{fetch,store}_registers. */ static void cooked_read_test (struct gdbarch *gdbarch) { if (selftest_skiparch (gdbarch)) return; scoped_mock_context<target_ops_no_register> mockctx (gdbarch); /* Test that read one raw register from regcache_no_target will go to the target layer. */ /* Find a raw register which size isn't zero. */ int nonzero_regnum; for (nonzero_regnum = 0; nonzero_regnum < gdbarch_num_regs (gdbarch); nonzero_regnum++) { if (register_size (gdbarch, nonzero_regnum) != 0) break; } readwrite_regcache readwrite (&mockctx.mock_inferior, gdbarch); readwrite.set_ptid (mockctx.mock_ptid); gdb::def_vector<gdb_byte> buf (register_size (gdbarch, nonzero_regnum)); readwrite.raw_read (nonzero_regnum, buf.data ()); /* raw_read calls target_fetch_registers. */ SELF_CHECK (mockctx.mock_target.fetch_registers_called > 0); mockctx.mock_target.reset (); /* Mark all raw registers valid, so the following raw registers accesses won't go to target. */ for (auto i = 0; i < gdbarch_num_regs (gdbarch); i++) readwrite.raw_update (i); mockctx.mock_target.reset (); /* Then, read all raw and pseudo registers, and don't expect calling to_{fetch,store}_registers. */ for (int regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++) { if (register_size (gdbarch, regnum) == 0) continue; gdb::def_vector<gdb_byte> inner_buf (register_size (gdbarch, regnum)); SELF_CHECK (REG_VALID == readwrite.cooked_read (regnum, inner_buf.data ())); SELF_CHECK (mockctx.mock_target.fetch_registers_called == 0); SELF_CHECK (mockctx.mock_target.store_registers_called == 0); SELF_CHECK (mockctx.mock_target.xfer_partial_called == 0); mockctx.mock_target.reset (); } readonly_detached_regcache readonly (readwrite); /* GDB may go to target layer to fetch all registers and memory for readonly regcache. */ mockctx.mock_target.reset (); for (int regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++) { if (register_size (gdbarch, regnum) == 0) continue; gdb::def_vector<gdb_byte> inner_buf (register_size (gdbarch, regnum)); enum register_status status = readonly.cooked_read (regnum, inner_buf.data ()); if (regnum < gdbarch_num_regs (gdbarch)) { auto bfd_arch = gdbarch_bfd_arch_info (gdbarch)->arch; if (bfd_arch == bfd_arch_amdgcn || bfd_arch == bfd_arch_frv || bfd_arch == bfd_arch_h8300 || bfd_arch == bfd_arch_m32c || bfd_arch == bfd_arch_sh || bfd_arch == bfd_arch_alpha || bfd_arch == bfd_arch_v850 || bfd_arch == bfd_arch_msp430 || bfd_arch == bfd_arch_mep || bfd_arch == bfd_arch_mips || bfd_arch == bfd_arch_v850_rh850 || bfd_arch == bfd_arch_tic6x || bfd_arch == bfd_arch_mn10300 || bfd_arch == bfd_arch_rl78 || bfd_arch == bfd_arch_score || bfd_arch == bfd_arch_riscv || bfd_arch == bfd_arch_csky) { /* Raw registers. If raw registers are not in save_reggroup, their status are unknown. */ if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup)) SELF_CHECK (status == REG_VALID); else SELF_CHECK (status == REG_UNKNOWN); } else SELF_CHECK (status == REG_VALID); } else { if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup)) SELF_CHECK (status == REG_VALID); else { /* If pseudo registers are not in save_reggroup, some of them can be computed from saved raw registers, but some of them are unknown. */ auto bfd_arch = gdbarch_bfd_arch_info (gdbarch)->arch; if (bfd_arch == bfd_arch_frv || bfd_arch == bfd_arch_m32c || bfd_arch == bfd_arch_mep || bfd_arch == bfd_arch_sh) SELF_CHECK (status == REG_VALID || status == REG_UNKNOWN); else if (bfd_arch == bfd_arch_mips || bfd_arch == bfd_arch_h8300) SELF_CHECK (status == REG_UNKNOWN); else SELF_CHECK (status == REG_VALID); } } SELF_CHECK (mockctx.mock_target.fetch_registers_called == 0); SELF_CHECK (mockctx.mock_target.store_registers_called == 0); SELF_CHECK (mockctx.mock_target.xfer_partial_called == 0); mockctx.mock_target.reset (); } } /* Test regcache::cooked_write by writing some expected contents to registers, and checking that contents read from registers and the expected contents are the same. */ static void cooked_write_test (struct gdbarch *gdbarch) { if (selftest_skiparch (gdbarch)) return; /* Create a mock environment. A process_stratum target pushed. */ scoped_mock_context<target_ops_no_register> ctx (gdbarch); readwrite_regcache readwrite (&ctx.mock_inferior, gdbarch); readwrite.set_ptid (ctx.mock_ptid); const int num_regs = gdbarch_num_cooked_regs (gdbarch); for (auto regnum = 0; regnum < num_regs; regnum++) { if (register_size (gdbarch, regnum) == 0 || gdbarch_cannot_store_register (gdbarch, regnum)) continue; auto bfd_arch = gdbarch_bfd_arch_info (gdbarch)->arch; if (bfd_arch == bfd_arch_sparc /* SPARC64_CWP_REGNUM, SPARC64_PSTATE_REGNUM, SPARC64_ASI_REGNUM and SPARC64_CCR_REGNUM are hard to test. */ && gdbarch_ptr_bit (gdbarch) == 64 && (regnum >= gdbarch_num_regs (gdbarch) && regnum <= gdbarch_num_regs (gdbarch) + 4)) continue; std::vector<gdb_byte> expected (register_size (gdbarch, regnum), 0); std::vector<gdb_byte> buf (register_size (gdbarch, regnum), 0); const auto type = register_type (gdbarch, regnum); if (type->code () == TYPE_CODE_FLT || type->code () == TYPE_CODE_DECFLOAT) { /* Generate valid float format. */ target_float_from_string (expected.data (), type, "1.25"); } else if (type->code () == TYPE_CODE_INT || type->code () == TYPE_CODE_ARRAY || type->code () == TYPE_CODE_PTR || type->code () == TYPE_CODE_UNION || type->code () == TYPE_CODE_STRUCT) { if (bfd_arch == bfd_arch_ia64 || (regnum >= gdbarch_num_regs (gdbarch) && (bfd_arch == bfd_arch_xtensa || bfd_arch == bfd_arch_bfin || bfd_arch == bfd_arch_m32c /* m68hc11 pseudo registers are in memory. */ || bfd_arch == bfd_arch_m68hc11 || bfd_arch == bfd_arch_m68hc12 || bfd_arch == bfd_arch_s390)) || (bfd_arch == bfd_arch_frv /* FRV pseudo registers except iacc0. */ && regnum > gdbarch_num_regs (gdbarch))) { /* Skip setting the expected values for some architecture registers. */ } else if (bfd_arch == bfd_arch_rl78 && regnum == 40) { /* RL78_PC_REGNUM */ for (auto j = 0; j < register_size (gdbarch, regnum) - 1; j++) expected[j] = j; } else { for (auto j = 0; j < register_size (gdbarch, regnum); j++) expected[j] = j; } } else if (type->code () == TYPE_CODE_FLAGS) { /* No idea how to test flags. */ continue; } else { /* If we don't know how to create the expected value for the this type, make it fail. */ SELF_CHECK (0); } readwrite.cooked_write (regnum, expected.data ()); SELF_CHECK (readwrite.cooked_read (regnum, buf.data ()) == REG_VALID); SELF_CHECK (expected == buf); } } /* Verify that when two threads with the same ptid exist (from two different targets) and one of them changes ptid, we only update the appropriate regcaches. */ static void regcache_thread_ptid_changed () { /* This test relies on the global regcache list to initially be empty. */ registers_changed (); /* Any arch will do. */ gdbarch *arch = current_inferior ()->gdbarch; /* Prepare two targets with one thread each, with the same ptid. */ scoped_mock_context<test_target_ops> target1 (arch); scoped_mock_context<test_target_ops> target2 (arch); ptid_t old_ptid (111, 222); ptid_t new_ptid (111, 333); target1.mock_inferior.pid = old_ptid.pid (); target1.mock_thread.ptid = old_ptid; target1.mock_inferior.ptid_thread_map.clear (); target1.mock_inferior.ptid_thread_map[old_ptid] = &target1.mock_thread; target2.mock_inferior.pid = old_ptid.pid (); target2.mock_thread.ptid = old_ptid; target2.mock_inferior.ptid_thread_map.clear (); target2.mock_inferior.ptid_thread_map[old_ptid] = &target2.mock_thread; gdb_assert (regcaches.empty ()); /* Populate the regcaches container. */ get_thread_arch_aspace_regcache (&target1.mock_inferior, old_ptid, arch, nullptr); get_thread_arch_aspace_regcache (&target2.mock_inferior, old_ptid, arch, nullptr); gdb_assert (regcaches.size () == 2); gdb_assert (regcache_count (&target1.mock_target, old_ptid) == 1); gdb_assert (regcache_count (&target1.mock_target, new_ptid) == 0); gdb_assert (regcache_count (&target2.mock_target, old_ptid) == 1); gdb_assert (regcache_count (&target2.mock_target, new_ptid) == 0); thread_change_ptid (&target1.mock_target, old_ptid, new_ptid); gdb_assert (regcaches.size () == 2); gdb_assert (regcache_count (&target1.mock_target, old_ptid) == 0); gdb_assert (regcache_count (&target1.mock_target, new_ptid) == 1); gdb_assert (regcache_count (&target2.mock_target, old_ptid) == 1); gdb_assert (regcache_count (&target2.mock_target, new_ptid) == 0); /* Leave the regcache list empty. */ registers_changed (); gdb_assert (regcaches.empty ()); } } // namespace selftests #endif /* GDB_SELF_TEST */ void _initialize_regcache (); void _initialize_regcache () { struct cmd_list_element *c; gdb::observers::target_changed.attach (regcache_observer_target_changed, "regcache"); gdb::observers::thread_ptid_changed.attach (regcache_thread_ptid_changed, "regcache"); cmd_list_element *maintenance_flush_register_cache_cmd = add_cmd ("register-cache", class_maintenance, reg_flush_command, _("Force gdb to flush its register and frame cache."), &maintenanceflushlist); c = add_com_alias ("flushregs", maintenance_flush_register_cache_cmd, class_maintenance, 0); deprecate_cmd (c, "maintenance flush register-cache"); #if GDB_SELF_TEST selftests::register_test ("get_thread_arch_aspace_regcache", selftests::get_thread_arch_aspace_regcache_test); selftests::register_test ("registers_changed_ptid_all", selftests::registers_changed_ptid_all_test); selftests::register_test ("registers_changed_ptid_target", selftests::registers_changed_ptid_target_test); selftests::register_test ("registers_changed_ptid_target_pid", selftests::registers_changed_ptid_target_pid_test); selftests::register_test ("registers_changed_ptid_target_ptid", selftests::registers_changed_ptid_target_ptid_test); selftests::register_test_foreach_arch ("regcache::cooked_read_test", selftests::cooked_read_test); selftests::register_test_foreach_arch ("regcache::cooked_write_test", selftests::cooked_write_test); selftests::register_test ("regcache_thread_ptid_changed", selftests::regcache_thread_ptid_changed); #endif }