44# ------------------------------------------------------------------------------
55# The MIT License (MIT)
66#
7- # Copyright (c) 2021-2023 Aarno Labs LLC
7+ # Copyright (c) 2021-2025 Aarno Labs LLC
88#
99# Permission is hereby granted, free of charge, to any person obtaining a copy
1010# of this software and associated documentation files (the "Software"), to deal
2525# SOFTWARE.
2626# ------------------------------------------------------------------------------
2727
28- from typing import List , TYPE_CHECKING
28+ from typing import Iterable , List , Tuple , TYPE_CHECKING
2929
3030from chb .app .InstrXData import InstrXData
3131
3232from chb .arm .ARMDictionaryRecord import armregistry
33- from chb .arm .ARMOpcode import ARMOpcode , simplify_result
33+ from chb .arm .ARMOpcode import ARMOpcode , ARMOpcodeXData , simplify_result
3434from chb .arm .ARMOperand import ARMOperand
3535
36- import chb .util .fileutil as UF
36+ import chb .ast .ASTNode as AST
37+ from chb .astinterface .ASTInterface import ASTInterface
38+
39+ import chb .invariants .XXprUtil as XU
3740
41+ import chb .util .fileutil as UF
3842from chb .util .IndexedTable import IndexedTableValue
43+ from chb .util .loggingutil import chklogger
3944
4045if TYPE_CHECKING :
4146 from chb .arm .ARMDictionary import ARMDictionary
47+ from chb .invariants .XVariable import XVariable
48+ from chb .invariants .XXpr import XXpr
49+
50+
51+ class ARMLoadMultipleIncrementBeforeXData (ARMOpcodeXData ):
52+ """Data format:
53+ - variables:
54+ 0: baselhs
55+ 1..n: lhsvars
56+
57+ - expressions:
58+ 0: baserhs
59+ 1..n: memrhss
60+ n+1..2n: rmemrhss (memrhss, rewritten)
61+ 2n+1..3n: xaddrs
62+
63+ - c expressions:
64+ 0..n-1: cmemrhss
65+ """
66+
67+ def __init__ (self , xdata : InstrXData ) -> None :
68+ ARMOpcodeXData .__init__ (self , xdata )
69+
70+ @property
71+ def regcount (self ) -> int :
72+ return len (self .xdata .vars_r ) - 1
73+
74+ def has_index (self , index : int ) -> bool :
75+ """returns true if index is between 1 and regcount (inclusive)."""
76+
77+ return index > 0 and index <= self .regcount
78+
79+ @property
80+ def memrhs_range (self ) -> Iterable [int ]:
81+ return range (1 , self .regcount + 1 )
82+
83+ @property
84+ def rmemrhs_range (self ) -> Iterable [int ]:
85+ return range (self .regcount + 1 , (2 * self .regcount ) + 1 )
86+
87+ @property
88+ def xaddr_range (self ) -> Iterable [int ]:
89+ return range ((2 * self .regcount ) + 1 , (3 * self .regcount ) + 1 )
90+
91+ @property
92+ def baselhs (self ) -> "XVariable" :
93+ return self .var (0 , "baselhs" )
94+
95+ @property
96+ def lhsvars (self ) -> List ["XVariable" ]:
97+ return [self .var (i , "lhsvar" ) for i in range (1 , self .regcount + 1 )]
98+
99+ def lhsvar (self , index : int ) -> "XVariable" :
100+ """returns the lhsvar at (1-based) position index"""
101+
102+ if self .has_index (index ):
103+ return self .lhsvars [index ]
104+ else :
105+ raise UF .CHBError ("LDMIB: index out of bounds: " + str (index ))
106+
107+ @property
108+ def baserhs (self ) -> "XXpr" :
109+ return self .xpr (0 , "baserhs" )
110+
111+ @property
112+ def memrhss (self ) -> List ["XXpr" ]:
113+ return [self .xpr (i , "memrhs" ) for i in self .memrhs_range ]
114+
115+ @property
116+ def are_memrhss_ok (self ) -> bool :
117+ return all (self .is_xpr_ok (i ) for i in self .memrhs_range )
118+
119+ def memrhs (self , index ) -> "XXpr" :
120+ """returns the rhs expression at (1-based) position index"""
121+
122+ if self .has_index (index ):
123+ if self .are_memrhss_ok :
124+ return self .memrhss [index - 1 ]
125+ else :
126+ raise UF .CHBError ("LDMIB: memrhss have error values" )
127+ else :
128+ raise UF .CHBError ("LDMIB: index out of bounds for memrhs" )
129+
130+ @property
131+ def rmemrhss (self ) -> List ["XXpr" ]:
132+ return [self .xpr (i , "rmemrhs" ) for i in self .rmemrhs_range ]
133+
134+ @property
135+ def are_rmemrhss_ok (self ) -> bool :
136+ return all (self .is_xpr_ok (i ) for i in self .rmemrhs_range )
137+
138+ def rmemrhs (self , index ) -> "XXpr" :
139+ """returns the rewritten rhs expr at (1-based) position index"""
140+
141+ if self .has_index (index ):
142+ if self .are_rmemrhss_ok :
143+ return self .rmemrhss [index - 1 ]
144+ else :
145+ raise UF .CHBError ("LDMIB: rmemrhss have error values" )
146+ else :
147+ raise UF .CHBError ("LDMIB: index out of bounds for rmemrhs" )
148+
149+ @property
150+ def xaddrs (self ) -> List ["XXpr" ]:
151+ return [self .xpr (i , "xaddr" ) for i in self .xaddr_range ]
152+
153+ @property
154+ def are_xaddrs_ok (self ) -> bool :
155+ return all (self .is_xpr_ok (i ) for i in self .xaddr_range )
156+
157+ def xaddr (self , index ) -> "XXpr" :
158+ """returns the rhs addr at (1-based) position index"""
159+
160+ if self .has_index (index ):
161+ if self .are_xaddrs_ok :
162+ return self .xaddrs [index - 1 ]
163+ else :
164+ raise UF .CHBError ("LDMIB: xaddrs have error values" )
165+ else :
166+ raise UF .CHBError ("LDMIB: index out of bounds for xaddr" )
167+
168+ @property
169+ def cmemrhss (self ) -> List ["XXpr" ]:
170+ return [self .cxpr (i , "cmemrhs" ) for i in range (0 , self .regcount )]
171+
172+ @property
173+ def are_cmemrhss_ok (self ) -> bool :
174+ return all (self .is_cxpr_ok (i ) for i in range (0 , self .regcount ))
175+
176+ def cmemrhs (self , index ) -> "XXpr" :
177+ """returns the rhs addr at (1-based) position index"""
178+
179+ if self .has_index (index ):
180+ if self .are_cmemrhss_ok :
181+ return self .cmemrhss [index - 1 ]
182+ else :
183+ raise UF .CHBError ("LDMIB: cmemrhss have error values" )
184+ else :
185+ raise UF .CHBError ("LDMIB: index out of bounds cmemrhs" )
186+
187+ @property
188+ def annotation (self ) -> str :
189+ if self .are_rmemrhss_ok :
190+ pairs = list (zip (self .lhsvars , self .rmemrhss ))
191+ elif self .are_memrhss_ok :
192+ pairs = list (zip (self .lhsvars , self .memrhss ))
193+ else :
194+ pairs = []
195+ if len (pairs ) > 0 :
196+ assigns = "; " .join (str (v ) + " := " + str (x ) for (x , v ) in pairs )
197+ else :
198+ assigns = "unknown rhs memory"
199+ wbu = self .writeback_update ()
200+ return self .add_instruction_condition (assigns + wbu )
201+
42202
43203
44204@armregistry .register_tag ("LDMIB" , ARMOpcode )
45205class ARMLoadMultipleIncrementBefore (ARMOpcode ):
46206 """Loads multiple registers from consecutive memory locations.
47207
48- LDMDB <c> <Rn>, <registers>
208+ LDMIB <c> <Rn>, <registers>
49209
50210 tags[1]: <c>
51211 args[0]: writeback
@@ -63,19 +223,154 @@ def __init__(
63223
64224 @property
65225 def operands (self ) -> List [ARMOperand ]:
66- return [self .armd .arm_operand (i ) for i in self .args [1 :- 1 ]]
226+ return [self .armd .arm_operand (i ) for i in self .args [1 :]]
227+
228+ @property
229+ def opargs (self ) -> List [ARMOperand ]:
230+ return [self .armd .arm_operand (i ) for i in self .args [1 :]]
231+
232+ @property
233+ def operandstring (self ) -> str :
234+ return (
235+ str (self .armd .arm_operand (self .args [1 ]))
236+ + ("!" if self .args [0 ] == 1 else "" )
237+ + ", "
238+ + str (self .armd .arm_operand (self .args [2 ])))
239+
240+ @property
241+ def writeback (self ) -> bool :
242+ return self .args [0 ] == 1
67243
68244 def is_load_instruction (self , xdata : InstrXData ) -> bool :
69245 return True
70246
71247 def annotation (self , xdata : InstrXData ) -> str :
72- """xdata format: a:v..x.. .
248+ xd = ARMLoadMultipleIncrementBeforeXData (xdata )
249+ return xd .annotation
73250
74- vars[0..]: lhs variables
75- xprs[0..]: rhs expressions
76- """
251+ def ast_prov (
252+ self ,
253+ astree : ASTInterface ,
254+ iaddr : str ,
255+ bytestring : str ,
256+ xdata : InstrXData ) -> Tuple [
257+ List [AST .ASTInstruction ], List [AST .ASTInstruction ]]:
77258
78- return (
79- '; ' .join (str (v )
80- + " := "
81- + str (x ) for (v , x ) in zip (xdata .vars , xdata .xprs )))
259+ xd = ARMLoadMultipleIncrementBeforeXData (xdata )
260+
261+ if xd .are_cmemrhss_ok :
262+ rhsexprs = xd .cmemrhss
263+ elif xd .are_rmemrhss_ok :
264+ rhsexprs = xd .rmemrhss
265+ elif xd .are_memrhss_ok :
266+ rhsexprs = xd .memrhss
267+
268+ else :
269+ chklogger .logger .error (
270+ "LDMIB: Error value encountered at address %s" , iaddr )
271+ return ([], [])
272+
273+ baselhs = xd .baselhs
274+ lhsvars = xd .lhsvars
275+ baserhs = xd .baserhs
276+
277+ baserdef = xdata .reachingdefs [0 ]
278+ memrdefs = xdata .reachingdefs [1 :]
279+ baseuses = xdata .defuses [0 ]
280+ reguses = xdata .defuses [1 :]
281+ baseuseshigh = xdata .defuseshigh [0 ]
282+ reguseshigh = xdata .defuseshigh [1 :]
283+
284+ annotations : List [str ] = [iaddr , "LDMIB" ]
285+
286+ ll_instrs : List [AST .ASTInstruction ] = []
287+ hl_instrs : List [AST .ASTInstruction ] = []
288+
289+ # low-level assignments
290+
291+ (baselval , _ , _ ) = self .opargs [0 ].ast_lvalue (astree )
292+ (baserval , _ , _ ) = self .opargs [0 ].ast_rvalue (astree )
293+
294+ regsop = self .opargs [1 ]
295+ registers = regsop .registers
296+ base_offset = 0
297+ for (i , r ) in enumerate (registers ):
298+
299+ # low-level assignments
300+
301+ base_offset += 4
302+
303+ base_offset_c = astree .mk_integer_constant (base_offset )
304+ addr = astree .mk_binary_op ("plus" , baserval , base_offset_c )
305+ ll_lhs = astree .mk_variable_lval (r )
306+ ll_rhs = astree .mk_memref_expr (addr )
307+ ll_assign = astree .mk_assign (
308+ ll_lhs ,
309+ ll_rhs ,
310+ iaddr = iaddr ,
311+ bytestring = bytestring ,
312+ annotations = annotations )
313+ ll_instrs .append (ll_assign )
314+
315+ # high-level assignments
316+
317+ lhs = lhsvars [i ]
318+ rhs = rhsexprs [i ]
319+ hl_lhs = XU .xvariable_to_ast_lval (lhs , xdata , iaddr , astree )
320+ hl_rhs = XU .xxpr_to_ast_def_expr (rhs , xdata , iaddr , astree )
321+ hl_assign = astree .mk_assign (
322+ hl_lhs ,
323+ hl_rhs ,
324+ iaddr = iaddr ,
325+ bytestring = bytestring ,
326+ annotations = annotations )
327+ hl_instrs .append (hl_assign )
328+
329+ astree .add_instr_mapping (hl_assign , ll_assign )
330+ astree .add_instr_address (hl_assign , [iaddr ])
331+ astree .add_expr_mapping (hl_rhs , ll_rhs )
332+ astree .add_lval_mapping (hl_lhs , ll_lhs )
333+ astree .add_expr_reachingdefs (ll_rhs , [memrdefs [i ]])
334+ astree .add_lval_defuses (hl_lhs , reguses [i ])
335+ astree .add_lval_defuses_high (hl_lhs , reguseshigh [i ])
336+
337+ if self .writeback :
338+
339+ # low-level base assignment
340+
341+ baseincr = 4 * xd .regcount
342+ baseincr_c = astree .mk_integer_constant (baseincr )
343+
344+ ll_base_lhs = baselval
345+ ll_base_rhs = astree .mk_binary_op ("plus" , baserval , baseincr_c )
346+ ll_base_assign = astree .mk_assign (
347+ ll_base_lhs ,
348+ ll_base_rhs ,
349+ iaddr = iaddr ,
350+ bytestring = bytestring ,
351+ annotations = annotations )
352+ ll_instrs .append (ll_base_assign )
353+
354+ # high-level base assignment
355+
356+ baseresult = xd .get_base_update_xpr ()
357+ hl_base_lhs = XU .xvariable_to_ast_lval (baselhs , xdata , iaddr , astree )
358+ hl_base_rhs = XU .xxpr_to_ast_def_expr (
359+ baseresult , xdata , iaddr , astree )
360+ hl_base_assign = astree .mk_assign (
361+ hl_base_lhs ,
362+ hl_base_rhs ,
363+ iaddr = iaddr ,
364+ bytestring = bytestring ,
365+ annotations = annotations )
366+ hl_instrs .append (hl_base_assign )
367+
368+ astree .add_instr_mapping (hl_base_assign , ll_base_assign )
369+ astree .add_instr_address (hl_base_assign , [iaddr ])
370+ astree .add_expr_mapping (hl_base_rhs , ll_base_rhs )
371+ astree .add_lval_mapping (hl_base_lhs , ll_base_lhs )
372+ astree .add_expr_reachingdefs (ll_base_rhs , [baserdef ])
373+ astree .add_lval_defuses (hl_base_lhs , baseuses )
374+ astree .add_lval_defuses_high (hl_base_lhs , baseuseshigh )
375+
376+ return (hl_instrs , ll_instrs )
0 commit comments