Line data Source code
1 : // Copyright (C) 2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-bir-drop-analysis.h"
20 : #include "rust-bir.h"
21 : #include "rust-hir-map.h"
22 :
23 : #include <unordered_set>
24 :
25 : namespace Rust {
26 : namespace BIR {
27 :
28 : namespace {
29 :
30 : struct BasicBlockIdHash
31 : {
32 63 : size_t operator() (BasicBlockId id) const
33 : {
34 63 : return std::hash<uint32_t> () (id.value);
35 : }
36 : };
37 :
38 : } // namespace
39 :
40 : DropAnalysis &
41 116 : DropAnalysis::get ()
42 : {
43 116 : static DropAnalysis instance;
44 116 : return instance;
45 : }
46 :
47 : void
48 14 : DropAnalysis::clear ()
49 : {
50 14 : definitely_dead.clear ();
51 14 : }
52 :
53 : bool
54 55 : DropAnalysis::is_definitely_dead (HirId id) const
55 : {
56 55 : return definitely_dead.find (id) != definitely_dead.end ();
57 : }
58 :
59 : void
60 47 : DropAnalysis::analyze (Function &function)
61 : {
62 47 : std::vector<BasicBlockId> block_order;
63 47 : std::unordered_set<BasicBlockId, BasicBlockIdHash> visited;
64 :
65 47 : BasicBlockId current = ENTRY_BASIC_BLOCK;
66 :
67 63 : while (current != INVALID_BB)
68 : {
69 : // A repeated block indicates a cycle in straight-line control flow.
70 63 : if (!visited.insert (current).second)
71 : return;
72 :
73 63 : block_order.push_back (current);
74 :
75 63 : const BasicBlock &block = function.basic_blocks[current];
76 :
77 63 : if (block.successors.empty ())
78 : break;
79 :
80 21 : if (block.successors.size () != 1)
81 : return;
82 :
83 16 : current = block.successors.front ();
84 : }
85 :
86 42 : std::vector<bool> initialized (function.place_db.size (), false);
87 :
88 51 : for (PlaceId argument : function.arguments)
89 9 : initialized[argument.value] = true;
90 :
91 100 : for (BasicBlockId block_id : block_order)
92 : {
93 58 : BasicBlock &block = function.basic_blocks[block_id];
94 :
95 826 : for (Statement &statement : block.statements)
96 : {
97 768 : PlaceId place = statement.get_place ();
98 :
99 768 : switch (statement.get_kind ())
100 : {
101 143 : case Statement::Kind::STORAGE_LIVE:
102 143 : initialized[place.value] = false;
103 143 : break;
104 :
105 189 : case Statement::Kind::ASSIGNMENT:
106 189 : {
107 189 : PlaceId lhs = place;
108 189 : AbstractExpr &expr = statement.get_expr ();
109 :
110 189 : if (expr.get_kind () == ExprKind::ASSIGNMENT)
111 : {
112 109 : PlaceId rhs = static_cast<Assignment &> (expr).get_rhs ();
113 109 : const Place &rhs_place = function.place_db[rhs];
114 :
115 109 : if (rhs_place.kind == Place::VARIABLE
116 109 : && rhs_place.should_be_moved ())
117 24 : initialized[rhs.value] = false;
118 : }
119 :
120 189 : initialized[lhs.value] = true;
121 189 : break;
122 : }
123 :
124 152 : case Statement::Kind::DROP:
125 152 : statement.set_drop_style (initialized[place.value]
126 : ? Statement::DropStyle::STATIC
127 : : Statement::DropStyle::DEAD);
128 :
129 152 : if (statement.get_drop_style () == Statement::DropStyle::DEAD)
130 : {
131 23 : const Place &dropped_place = function.place_db[place];
132 :
133 23 : if (dropped_place.kind == Place::VARIABLE)
134 : {
135 23 : auto hir_id
136 23 : = Analysis::Mappings::get ().lookup_node_to_hir (
137 : static_cast<NodeId> (
138 23 : dropped_place.variable_or_field_index));
139 :
140 23 : if (hir_id.has_value ())
141 23 : definitely_dead.insert (hir_id.value ());
142 : }
143 : }
144 :
145 152 : initialized[place.value] = false;
146 152 : break;
147 :
148 143 : case Statement::Kind::STORAGE_DEAD:
149 143 : initialized[place.value] = false;
150 143 : break;
151 :
152 : case Statement::Kind::SWITCH:
153 : case Statement::Kind::RETURN:
154 : case Statement::Kind::GOTO:
155 : case Statement::Kind::USER_TYPE_ASCRIPTION:
156 : case Statement::Kind::FAKE_READ:
157 : break;
158 : }
159 : }
160 : }
161 47 : }
162 :
163 : } // namespace BIR
164 : } // namespace Rust
|