Skip to content

Commit 6a25462

Browse files
author
Chris Dodd
authored
Move exit; statement to actions in actionSynthesis (#1920)
* added .gdbinit with useful pretty printers * Move exit; statement to actions in actionSynthesis
1 parent 60be53f commit 6a25462

File tree

3 files changed

+336
-23
lines changed

3 files changed

+336
-23
lines changed

.gdbinit

+313
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
# vi: ft=python
2+
set print static-members off
3+
set print object
4+
set unwindonsignal on
5+
set unwind-on-terminating-exception on
6+
set python print-stack full
7+
8+
if $_isvoid($bpnum)
9+
break ErrorReporter::emit_message
10+
disable
11+
break Util::P4CExceptionBase::P4CExceptionBase<>
12+
break Util::P4CExceptionBase::traceCreation
13+
break BaseCompileContext::getDefaultErrorDiagnosticAction
14+
end
15+
16+
define pn
17+
if $argc == 2
18+
call ::dbprint($arg0 $arg1)
19+
else
20+
call ::dbprint($arg0)
21+
end
22+
end
23+
document pn
24+
print a IR::Node pointer
25+
end
26+
define d
27+
if $argc == 2
28+
call ::dump($arg0 $arg1)
29+
else
30+
call ::dump($arg0)
31+
end
32+
end
33+
document d
34+
dump IR::Node tree or Visitor::Context
35+
end
36+
define dnt
37+
if $argc == 2
38+
call ::dump_notype($arg0 $arg1)
39+
else
40+
call ::dump_notype($arg0)
41+
end
42+
end
43+
document dnt
44+
dump IR::Node tree, skipping 'type' fields
45+
end
46+
define dsrc
47+
if $argc == 2
48+
call ::dump_src($arg0 $arg1)
49+
else
50+
call ::dump_src($arg0)
51+
end
52+
end
53+
document dsrc
54+
dump IR::Node tree, skipping 'type' fields, and printing source info
55+
end
56+
57+
python
58+
import sys
59+
import re
60+
61+
def template_split(s):
62+
parts = []
63+
bracket_level = 0
64+
current = []
65+
for c in (s):
66+
if c == "," and bracket_level == 1:
67+
parts.append("".join(current))
68+
current = []
69+
else:
70+
if c == '>':
71+
bracket_level -= 1
72+
if bracket_level > 0:
73+
current.append(c)
74+
if c == '<':
75+
bracket_level += 1
76+
parts.append("".join(current))
77+
return parts
78+
79+
TYPE_CACHE = {}
80+
81+
def lookup_type(typename):
82+
"""Return a gdb.Type object represents given `typename`.
83+
For example, x.cast(ty('Buffer'))"""
84+
if typename in TYPE_CACHE:
85+
return TYPE_CACHE[typename]
86+
87+
m0 = re.match(r"^(.*\S)\s*const$", typename)
88+
m1 = re.match(r"^(.*\S)\s*[*|&]$", typename)
89+
if m0 is not None:
90+
tp = lookup_type(m0.group(1))
91+
elif m1 is None:
92+
tp = gdb.lookup_type(typename)
93+
else:
94+
if m1.group(0).endswith('*'):
95+
tp = lookup_type(m1.group(1)).pointer()
96+
else:
97+
tp = lookup_type(m1.group(1)).reference()
98+
TYPE_CACHE[typename] = tp
99+
return tp
100+
101+
class ordered_map_Printer:
102+
"Print an ordered_map<>"
103+
def __init__(self, val):
104+
self.val = val
105+
self.args = template_split(val.type.tag)
106+
self.eltype = gdb.lookup_type('std::pair<' + self.args[0] + ' const,' + self.args[1] + '>')
107+
def to_string(self):
108+
return "ordered_map<..>"
109+
class _iter:
110+
def __init__(self, eltype, it, e):
111+
self.eltype = eltype
112+
self.it = it
113+
self.e = e
114+
def __iter__(self):
115+
return self
116+
def __next__(self):
117+
if self.it == self.e:
118+
raise StopIteration
119+
el = (self.it + 1).cast(self.eltype.pointer()).dereference()
120+
self.it = self.it.dereference()['_M_next']
121+
return ("[" + str(el['first']) + "]", el['second']);
122+
def next(self): return self.__next__()
123+
def children(self):
124+
return self._iter(self.eltype, self.val['data']['_M_impl']['_M_node']['_M_next'],
125+
self.val['data']['_M_impl']['_M_node'].address)
126+
127+
class ordered_set_Printer:
128+
"Print an ordered_set<>"
129+
def __init__(self, val):
130+
self.val = val
131+
self.args = template_split(val.type.tag)
132+
self.eltypestr = self.args[0]
133+
self.eltype = lookup_type(self.args[0])
134+
self.isptr = True if re.match(r"^.*[*]$", self.args[0]) else False
135+
def to_string(self):
136+
return "ordered_set<..>"
137+
class _iter:
138+
def __init__(self, eltype, eltypestr, isptr, it, e):
139+
self.eltype = eltype
140+
self.eltypestr = eltypestr
141+
self.isptr = isptr
142+
self.it = it
143+
self.e = e
144+
self.idx = 0
145+
def __iter__(self):
146+
return self
147+
def __next__(self):
148+
if self.it == self.e:
149+
raise StopIteration
150+
el = (self.it + 1).cast(self.eltype.pointer()).dereference()
151+
self.it = self.it.dereference()['_M_next']
152+
idx = self.idx
153+
self.idx = idx + 1
154+
if self.isptr:
155+
return ("[%d]" % idx, "(" + self.eltypestr + ")" + str(el))
156+
return ("[%d]" % idx, el);
157+
def next(self): return self.__next__()
158+
def children(self):
159+
return self._iter(self.eltype, self.eltypestr, self.isptr,
160+
self.val['data']['_M_impl']['_M_node']['_M_next'],
161+
self.val['data']['_M_impl']['_M_node'].address)
162+
163+
class cstringPrinter(object):
164+
"Print a cstring"
165+
def __init__(self, val):
166+
self.val = val
167+
def to_string(self):
168+
if self.val['str']:
169+
return str(self.val['str'])
170+
else:
171+
return "nullptr"
172+
173+
class SourceInfoPrinter(object):
174+
"Print a Util::SourceInfo"
175+
def __init__(self, val):
176+
self.val = val
177+
def to_string(self):
178+
return (str(self.val['start']['lineNumber']) + ':' +
179+
str(self.val['start']['columnNumber']) + '-' +
180+
str(self.val['end']['lineNumber']) + ':' +
181+
str(self.val['end']['columnNumber']))
182+
183+
class bitvecPrinter(object):
184+
"Print a bitvec"
185+
def __init__(self, val):
186+
self.val = val
187+
def to_string(self):
188+
data = self.val['data']
189+
rv = ""
190+
size = self.val['size']
191+
ptr = self.val['ptr']
192+
unitsize = ptr.type.target().sizeof * 8
193+
while size > 1:
194+
data = ptr.dereference()
195+
i = 0
196+
while i < unitsize:
197+
if (rv.__len__() % 120 == 119): rv += ':'
198+
elif (rv.__len__() % 30 == 29): rv += ' '
199+
elif (rv.__len__() % 6 == 5): rv += '_'
200+
if (data & 1) == 0:
201+
rv += "0"
202+
else:
203+
rv += "1"
204+
data >>= 1
205+
i += 1
206+
ptr += 1
207+
size -= 1
208+
data = ptr.dereference()
209+
while rv == "" or data > 0:
210+
if (rv.__len__() % 120 == 119): rv += ':'
211+
elif (rv.__len__() % 30 == 29): rv += ' '
212+
elif (rv.__len__() % 6 == 5): rv += '_'
213+
if (data & 1) == 0:
214+
rv += "0"
215+
else:
216+
rv += "1"
217+
data >>= 1
218+
return rv
219+
220+
def vec_begin(vec):
221+
return vec['_M_impl']['_M_start']
222+
def vec_end(vec):
223+
return vec['_M_impl']['_M_finish']
224+
def vec_size(vec):
225+
return int(vec_end(vec) - vec_begin(vec))
226+
def vec_at(vec, i):
227+
return (vec_begin(vec) + i).dereference()
228+
229+
class safe_vector_Printer:
230+
"Print a safe_vector<>"
231+
def __init__(self, val):
232+
self.val = val
233+
def to_string(self):
234+
return "" if vec_size(self.val) > 0 else "[]"
235+
class _iter:
236+
def __init__(self, val):
237+
self.val = val
238+
self.size = vec_size(val)
239+
self.idx = 0
240+
def __iter__(self):
241+
return self
242+
def __next__(self):
243+
if self.idx >= self.size:
244+
raise StopIteration
245+
idx = self.idx
246+
self.idx = idx + 1
247+
return ("[%d]" % idx, vec_at(self.val, idx));
248+
def next(self): return self.__next__()
249+
def children(self):
250+
return self._iter(self.val)
251+
252+
def bvec_size(vec):
253+
sz = int(vec_end(vec)['_M_p'] - vec_begin(vec)['_M_p'])
254+
sz = sz * vec_begin(vec)['_M_p'].type.target().sizeof * 8
255+
sz = sz + int(vec_end(vec)['_M_offset'] - vec_begin(vec)['_M_offset'])
256+
return sz
257+
258+
class safe_vector_bool_Printer:
259+
"Print a safe_vector<bool>"
260+
def __init__(self, val):
261+
self.val = val
262+
def to_string(self):
263+
return "" if bvec_size(self.val) > 0 else "[]"
264+
class _iter:
265+
def __init__(self, val):
266+
self.val = val
267+
self.end = vec_end(val)
268+
self.ptr = vec_begin(val)['_M_p']
269+
self.offset = vec_begin(val)['_M_offset']
270+
self.idx = 0
271+
def __iter__(self):
272+
return self
273+
def __next__(self):
274+
if self.ptr == self.end['_M_p'] and self.offset >= self.end['_M_offset']:
275+
raise StopIteration
276+
ptr = self.ptr
277+
offset = self.offset
278+
idx = self.idx
279+
self.offset = offset + 1
280+
self.idx = idx + 1
281+
if self.offset == self.ptr.type.target().sizeof * 8:
282+
self.offset = 0
283+
self.ptr = self.ptr + 1
284+
return ("[%d]" % idx, (self.ptr.dereference() >> self.offset) & 1);
285+
def next(self): return self.__next__()
286+
def children(self):
287+
return self._iter(self.val)
288+
289+
def find_pp(val):
290+
if str(val.type.tag).startswith('ordered_map<'):
291+
return ordered_map_Printer(val)
292+
if str(val.type.tag).startswith('ordered_set<'):
293+
return ordered_set_Printer(val)
294+
if str(val.type.tag).startswith('safe_vector<bool'):
295+
return safe_vector_bool_Printer(val)
296+
if str(val.type.tag).startswith('safe_vector<'):
297+
return safe_vector_Printer(val)
298+
if val.type.tag == 'bitvec':
299+
return bitvecPrinter(val)
300+
if val.type.tag == 'cstring':
301+
return cstringPrinter(val)
302+
if val.type.tag == 'Util::SourceInfo':
303+
return SourceInfoPrinter(val)
304+
return None
305+
306+
try:
307+
while gdb.pretty_printers[-1].__name__ == "find_pp":
308+
gdb.pretty_printers = gdb.pretty_printers[:-1]
309+
except:
310+
pass
311+
312+
gdb.pretty_printers.append(find_pp)
313+
end

midend/actionSynthesis.cpp

+21-21
Original file line numberDiff line numberDiff line change
@@ -130,31 +130,26 @@ const IR::Node* DoSynthesizeActions::preorder(IR::BlockStatement* statement) {
130130
auto left = new IR::BlockStatement(statement->annotations); // leftover statements
131131

132132
for (auto c : statement->components) {
133-
if (c->is<IR::AssignmentStatement>()) {
134-
if (mustMove(c->to<IR::AssignmentStatement>())) {
135-
if (policy && !actbody->components.empty() &&
136-
!policy->can_combine(getContext(), actbody, c)) {
137-
auto action = createAction(actbody);
138-
left->push_back(action);
139-
actbody = new IR::BlockStatement; }
140-
actbody->push_back(c);
141-
actbody->srcInfo += c->srcInfo;
142-
continue; }
143-
} else if (c->is<IR::MethodCallStatement>()) {
144-
if (mustMove(c->to<IR::MethodCallStatement>())) {
145-
if (policy && !actbody->components.empty() &&
146-
!policy->can_combine(getContext(), actbody, c)) {
147-
auto action = createAction(actbody);
148-
left->push_back(action);
149-
actbody = new IR::BlockStatement; }
150-
actbody->push_back(c);
151-
actbody->srcInfo += c->srcInfo;
152-
continue;
153-
}
133+
bool moveToAction = false;
134+
if (auto *as = c->to<IR::AssignmentStatement>()) {
135+
moveToAction = mustMove(as);
136+
} else if (auto *mc = c->to<IR::MethodCallStatement>()) {
137+
moveToAction = mustMove(mc);
138+
} else if (c->is<IR::ExitStatement>()) {
139+
moveToAction = true;
154140
} else {
155141
// This may modify 'changes'
156142
visit(c);
157143
}
144+
if (moveToAction) {
145+
if (policy && !actbody->components.empty() &&
146+
!policy->can_combine(getContext(), actbody, c)) {
147+
auto action = createAction(actbody);
148+
left->push_back(action);
149+
actbody = new IR::BlockStatement; }
150+
actbody->push_back(c);
151+
actbody->srcInfo += c->srcInfo;
152+
continue; }
158153

159154
if (!actbody->components.empty()) {
160155
auto action = createAction(actbody);
@@ -186,6 +181,7 @@ const IR::Statement* DoSynthesizeActions::createAction(const IR::Statement* toAd
186181
} else {
187182
body = new IR::BlockStatement(toAdd->srcInfo, { toAdd });
188183
}
184+
LOG3("Adding new action " << name << body);
189185

190186
auto annos = new IR::Annotations();
191187
annos->add(new IR::Annotation(IR::Annotation::hiddenAnnotation, {}));
@@ -209,4 +205,8 @@ const IR::Node* DoSynthesizeActions::preorder(IR::MethodCallStatement* statement
209205
return statement;
210206
}
211207

208+
const IR::Node* DoSynthesizeActions::preorder(IR::ExitStatement* statement) {
209+
return createAction(statement);
210+
}
211+
212212
} // namespace P4

midend/actionSynthesis.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,11 @@ class DoSynthesizeActions : public Transform {
129129
const IR::Node* preorder(IR::P4Control* control) override;
130130
const IR::Node* preorder(IR::P4Action* action) override
131131
{ prune(); return action; } // skip actions
132-
// We do not handle return and exit: this pass should be called after
133-
// these have been removed
132+
// We do not handle return: this pass should be called after it has been removed
134133
const IR::Node* preorder(IR::BlockStatement* statement) override;
135134
const IR::Node* preorder(IR::AssignmentStatement* statement) override;
136135
const IR::Node* preorder(IR::MethodCallStatement* statement) override;
136+
const IR::Node* preorder(IR::ExitStatement* statement) override;
137137
const IR::Node* preorder(IR::Function* function) override
138138
{ prune(); return function; }
139139

0 commit comments

Comments
 (0)