5 # for linex, and should be used in the future
8 redef class AnalysisManager
9 fun do_range_analysis
(ast
: AListing, cfg
: CFG)
11 var range_init_analysis
= new InitRangeAnalysis(ast
)
12 range_init_analysis
.analyze
(ast
)
14 cfg
.start
.backup_ranges_out
= range_init_analysis
.set
16 var range_analysis
= new RangeAnalysis
17 range_analysis
.analyze
(cfg
)
22 super FineFlowAnalysis[RangeMap]
24 var current_range
: nullable ValRange = null
25 var current_var
: nullable Var = null
27 redef fun empty_set
do return new RangeMap
28 redef fun is_forward
do return true
34 node
.accept_range_analysis
(self,
35 current_in
, current_out
.as(not null))
41 if a
== null and b
== null then return null
42 if a
== null then return b
.copy
43 if b
== null then return a
.copy
50 n
[k
] = new ValRange(v
.min
.min
(u
.min
), v
.max
.max
(u
.max
))
57 redef fun line_in
(line
) do return line
.ranges_in
58 redef fun line_out
(line
) do return line
.ranges_out
59 redef fun line_in
=(line
, s
) do line
.ranges_in
= s
60 redef fun line_out
=(line
, s
) do line
.ranges_out
= s
62 redef fun backup_in
(bb
) do return bb
.backup_ranges_in
63 redef fun backup_out
(bb
) do return bb
.backup_ranges_out
64 redef fun backup_in
=(bb
, s
) do bb
.backup_ranges_in
= s
65 redef fun backup_out
=(bb
, s
) do bb
.backup_ranges_out
= s
68 class InitRangeAnalysis
69 super StaticAnalysis[RangeMap]
71 var current_line
: ALine
76 current_line
= prog
.n_lines
.first
80 if node
isa ALine then current_line
= node
81 node
.accept_init_range_analysis
(self, set
)
86 var ranges_in
: nullable RangeMap = null
87 var ranges_out
: nullable RangeMap = null
90 redef class BasicBlock
91 var backup_ranges_in
: nullable RangeMap = null
92 var backup_ranges_out
: nullable RangeMap = null
94 redef fun dot_node_header
96 if backup_ranges_in
!= null then
97 return "{super}-- ranges in = {backup_ranges_in.as(not null)}\\l"
98 else if not lines
.is_empty
and lines
.first
.ranges_in
!= null then
99 return "{super}-- ranges in = {lines.first.ranges_in.as(not null)}\\l"
102 redef fun dot_node_footer
104 if backup_ranges_out
!= null then
105 return "{super}-- ranges out = {backup_ranges_out.as(not null)}\\l"
106 else if not lines
.is_empty
and lines
.last
.ranges_out
!= null then
107 return "{super}-- ranges out = {lines.last.ranges_out.as(not null)}\\l"
120 init from
(o
: ValRange)
132 if min
== max
then return min
.to_s
133 return "[{min}..{max}]"
136 redef fun ==(o
) do return o
!= null and o
isa ValRange and
137 min
== o
.min
and max
== o
.max
139 fun ponctual
: Bool do return min
== max
142 super HashMap[Var, ValRange]
145 if o
== null or not o
isa RangeMap then return false
146 if o
.length
!= length
then return false
148 for k
, v
in self do if not o
.has_key
(k
) or o
[k
] != v
then return false
160 redef fun to_s
do return "\{{join(", ", ":")}\}"
164 fun accept_range_analysis
(v
: RangeAnalysis,
165 ins
: nullable RangeMap, outs
: RangeMap) do visit_all
(v
)
166 fun accept_init_range_analysis
(v
: InitRangeAnalysis,
167 set
: RangeMap) do visit_all
(v
)
170 redef class AInstruction
171 redef fun accept_range_analysis
(v
, ins
, outs
)
174 if ins
!= null then outs
.recover_with
(ins
)
178 redef class ALoadInstruction
179 redef fun accept_range_analysis
(v
, ins
, outs
)
183 if ins
!= null then outs
.recover_with
(ins
)
184 var variable
= def_var
185 #var add = new RangeMap[Var, ValRange](variable,
187 # kill every set for variable
188 # (is automatic by HashMap)
190 if variable
!= null then
192 var cr
= v
.current_range
196 outs
.keys
.remove
(variable
)
199 v
.current_range
= null
203 redef class AStoreInstruction
204 redef fun accept_range_analysis
(v
, ins
, outs
)
208 if ins
!= null then outs
.recover_with
(ins
)
209 var src
= src_var
# reg
210 var def
= def_var
# mem
213 if src
!= null and ins
!= null and ins
.has_key
(src
) then # we know the source and dest
217 outs
.keys
.remove
(def
)
223 redef class AInputInstruction
224 redef fun accept_range_analysis
(v
, ins
, outs
)
228 if ins
!= null then outs
.recover_with
(ins
)
230 var def
= def_var
# mem
232 if def
!= null and outs
.has_key
(def
) then
233 outs
.keys
.remove
(def
)
239 redef class AArithmeticInstruction
240 fun do_arithmetic
(rv
, rm
: ValRange): nullable ValRange do return null
242 redef fun accept_range_analysis
(v
, ins
, outs
)
244 v
.current_range
= null
247 if ins
!= null then outs
.recover_with
(ins
)
251 var cr
= v
.current_range
253 if cr
!= null and ins
.has_key
(reg
) then
254 # and ins.has_key(mem) then
255 var r
= do_arithmetic
(ins
[reg
], cr
)
258 # this prevents infinite loops
259 # we assume that the max for a student program in 50
260 if r
.max
> 50 then r
.max
= 50
261 if r
.min
< -50 then r
.min
= -50
265 outs
.keys
.remove
(reg
)
268 outs
.keys
.remove
(reg
)
273 redef class AAddInstruction
274 redef fun do_arithmetic
(rv
, rm
) do return new ValRange(rv
.min
+rm
.min
, rv
.max
+rm
.max
)
277 redef class ASubInstruction
278 redef fun do_arithmetic
(rv
, rm
) do return new ValRange(rv
.min-rm
.max
, rv
.max-rm
.min
)
281 redef class ANegInstruction
282 redef fun accept_range_analysis
(v
, ins
, outs
)
284 v
.current_range
= null
287 if ins
!= null then outs
.recover_with
(ins
)
290 if ins
.has_key
(reg
) then
292 outs
[reg
] = new ValRange(-rm
.max
, -rm
.min
)
297 redef class AAnyOperand
298 redef fun accept_range_analysis
(v
, ins
, outs
)
300 if addressing_mode
== "i" then # immediate
302 v
.current_range
= new ValRange(n_value
.to_i
, n_value
.to_i
)
304 else if addressing_mode
== "d" then # direct
305 var ci
= v
.current_in
306 var address
= n_value
.to_i
307 var variable
= new MemVar(address
)
308 v
.current_var
= variable
309 if ci
!= null and ci
.has_key
(variable
) then
310 var value
= ci
[variable
]
311 v
.current_range
= new ValRange(value
.min
, value
.max
)
316 v
.current_range
= null
320 redef class AMovInstruction
321 # Almost impossible to guess so, topped
322 redef fun accept_range_analysis
(v
, ins
, outs
)
324 v
.current_range
= null
327 if ins
!= null then outs
.recover_with
(ins
)
329 var reg
= new RegisterVar('A')
330 if outs
.has_key
(reg
) then
331 outs
.keys
.remove
(reg
)
336 redef class AWordDirective
337 redef fun accept_init_range_analysis
(v
, set
)
339 var variable
= new MemVar(v
.current_line
.address
)
340 var value
= new ValRange.at
(n_value
.to_i
)
341 set
[variable
] = value
345 redef class AByteDirective
346 redef fun accept_init_range_analysis
(v
, set
)
348 var variable
= new MemVar(v
.current_line
.address
)
349 var value
= new ValRange.at
(n_value
.to_i
)
350 set
[variable
] = value