@@ -61,6 +61,33 @@ class ARMMoveXData(ARMOpcodeXData):
6161
6262 - c expressions:
6363 0: cresult
64+
65+ Aggregates:
66+
67+ - expressions with predicate / ternary assignments
68+
69+ - nondet:
70+ - predicate: none
71+ - ternary:
72+ 0: true assign (constant)
73+ 1: false assign (constant)
74+
75+ - predicate:
76+ 0: p
77+ 1: xp
78+
79+ - ternary:
80+ 0: p
81+ 1: xp
82+ 2: true assign (constant)
83+ 3: false assign (constant)
84+
85+ - c expressions with predicate /ternary assignments
86+
87+ - nondet: none
88+
89+ - predicate/ternary:
90+ 0: p
6491 """
6592
6693 def __init__ (self , xdata : InstrXData ) -> None :
@@ -70,6 +97,22 @@ def __init__(self, xdata: InstrXData) -> None:
7097 def vrd (self ) -> "XVariable" :
7198 return self .var (0 , "vrd" )
7299
100+ @property
101+ def is_predicate_assign (self ) -> bool :
102+ return self .xdata .is_predicate_assignment
103+
104+ @property
105+ def is_nondet_predicate_assign (self ) -> bool :
106+ return self .xdata .is_nondet_predicate_assignment
107+
108+ @property
109+ def is_ternary_assign (self ) -> bool :
110+ return self .xdata .is_ternary_assignment
111+
112+ @property
113+ def is_nondet_ternary_assign (self ) -> bool :
114+ return self .xdata .is_nondet_ternary_assignment
115+
73116 @property
74117 def xrm (self ) -> "XXpr" :
75118 return self .xpr (0 , "xrm" )
@@ -90,6 +133,37 @@ def cresult(self) -> "XXpr":
90133 def is_cresult_ok (self ) -> bool :
91134 return self .is_cxpr_ok (0 )
92135
136+ @property
137+ def predicate (self ) -> "XXpr" :
138+ # known to be valid
139+ return self .xpr (0 , "p" ) # known to be valid
140+
141+ @property
142+ def xpredicate (self ) -> "XXpr" :
143+ return self .xpr (1 , "xp" ) # known to be valid
144+
145+ @property
146+ def cpredicate (self ) -> "XXpr" :
147+ return self .cxpr (0 , "cxp" )
148+
149+ @property
150+ def is_cpredicate_ok (self ) -> bool :
151+ return self .is_cxpr_ok (0 )
152+
153+ @property
154+ def tern_assign_true (self ) -> "XXpr" : # known to be valid
155+ if self .is_nondet_ternary_assign :
156+ return self .xpr (1 , "xp1" )
157+ else :
158+ return self .xpr (3 , "xp1" )
159+
160+ @property
161+ def tern_assign_false (self ) -> "XXpr" : # known to be valid
162+ if self .is_nondet_ternary_assign :
163+ return self .xpr (0 , "xp2" )
164+ else :
165+ return self .xpr (2 , "xp2" )
166+
93167 def has_instruction_condition (self ) -> bool :
94168 return self .xdata .has_instruction_condition ()
95169
@@ -102,10 +176,37 @@ def has_valid_instruction_c_condition(self) -> bool:
102176 def get_instruction_c_condition (self ) -> "XXpr" :
103177 return self .xdata .get_instruction_c_condition ()
104178
179+ def predicate_assignment_ann (self ) -> str :
180+ if self .is_nondet_predicate_assign :
181+ rhs = "? (unknown predicate)"
182+ else :
183+ crhs = (
184+ " (C:"
185+ + (str (self .cpredicate ) if self .is_cpredicate_ok else "?" )
186+ + ")" )
187+ rhs = str (self .xpredicate ) + crhs
188+ return str (self .vrd ) + " := " + rhs
189+
190+ def ternary_assignment_ann (self ) -> str :
191+ rhs = str (self .tern_assign_true ) + " : " + str (self .tern_assign_false )
192+ if self .is_nondet_ternary_assign :
193+ rhs = " ? " + rhs
194+ else :
195+ rhs = str (self .xpredicate ) + " ? " + rhs
196+ cpred = (
197+ " (C:"
198+ + (str (self .cpredicate ) if self .is_cpredicate_ok else "?" )
199+ + ")" )
200+ return str (self .vrd ) + " := " + rhs + cpred
201+
105202 @property
106203 def annotation (self ) -> str :
107204 if self .xdata .instruction_is_subsumed ():
108205 return "subsumed by " + self .xdata .subsumed_by ()
206+ if self .is_ternary_assign or self .is_nondet_ternary_assign :
207+ return self .ternary_assignment_ann ()
208+ if self .is_predicate_assign or self .is_nondet_predicate_assign :
209+ return self .predicate_assignment_ann ()
109210 if self .xdata .instruction_subsumes ():
110211 return "subsumes " + ", " .join (self .xdata .subsumes ())
111212 cx = " (C: " + (str (self .cresult ) if self .is_cresult_ok else "None" ) + ")"
@@ -209,6 +310,141 @@ def ast_prov_subsumed(
209310
210311 return ([], [ll_assign ])
211312
313+ def ast_prov_predicate_assign (
314+ self ,
315+ astree : ASTInterface ,
316+ iaddr : str ,
317+ bytestring : str ,
318+ xdata : InstrXData
319+ ) -> Tuple [List [AST .ASTInstruction ], List [AST .ASTInstruction ]]:
320+
321+ annotations : List [str ] = [iaddr , "MOV (predicate assign)" ]
322+
323+ # low-level assignment
324+
325+ (ll_lhs , _ , _ ) = self .opargs [0 ].ast_lvalue (astree )
326+ (ll_rhs , _ , _ ) = self .opargs [1 ].ast_rvalue (astree )
327+
328+ ll_assign = astree .mk_assign (
329+ ll_lhs ,
330+ ll_rhs ,
331+ iaddr = iaddr ,
332+ bytestring = bytestring ,
333+ annotations = annotations )
334+
335+ # high-level assignment
336+
337+ xd = ARMMoveXData (xdata )
338+
339+ if xd .is_nondet_predicate_assign :
340+ chklogger .logger .warning (
341+ "Predicate assignment without associated predicate at "
342+ + "address %s" , iaddr )
343+ return ([], [ll_assign ])
344+
345+ rhs = xd .cpredicate if xd .is_cpredicate_ok else xd .xpredicate
346+ lhs = xd .vrd
347+ rdefs = xdata .reachingdefs
348+ defuses = xdata .defuses
349+ defuseshigh = xdata .defuseshigh
350+
351+ hl_lhs = XU .xvariable_to_ast_lval (lhs , xdata , iaddr , astree , rhs = rhs )
352+ hl_rhs = XU .xxpr_to_ast_def_expr (rhs , xdata , iaddr , astree )
353+
354+ hl_assign = astree .mk_assign (
355+ hl_lhs ,
356+ hl_rhs ,
357+ iaddr = iaddr ,
358+ bytestring = bytestring ,
359+ annotations = annotations )
360+
361+ astree .add_instr_mapping (hl_assign , ll_assign )
362+ astree .add_instr_address (hl_assign , [iaddr ])
363+ astree .add_expr_mapping (hl_rhs , ll_rhs )
364+ astree .add_lval_mapping (hl_lhs , ll_lhs )
365+ astree .add_expr_reachingdefs (hl_rhs , rdefs [1 :])
366+ astree .add_expr_reachingdefs (ll_rhs , [rdefs [0 ]])
367+ astree .add_lval_defuses (hl_lhs , defuses [0 ])
368+ astree .add_lval_defuses_high (hl_lhs , defuseshigh [0 ])
369+
370+ if astree .has_register_variable_intro (iaddr ):
371+ rvintro = astree .get_register_variable_intro (iaddr )
372+ if rvintro .has_cast ():
373+ astree .add_expose_instruction (hl_assign .instrid )
374+
375+ return ([hl_assign ], [ll_assign ])
376+
377+
378+ def ast_prov_ternary_assign (
379+ self ,
380+ astree : ASTInterface ,
381+ iaddr : str ,
382+ bytestring : str ,
383+ xdata : InstrXData
384+ ) -> Tuple [List [AST .ASTInstruction ], List [AST .ASTInstruction ]]:
385+
386+ annotations : List [str ] = [iaddr , "MOV (ternary assign)" ]
387+
388+ # low-level assignment
389+
390+ (ll_lhs , _ , _ ) = self .opargs [0 ].ast_lvalue (astree )
391+ (ll_rhs , _ , _ ) = self .opargs [1 ].ast_rvalue (astree )
392+
393+ ll_assign = astree .mk_assign (
394+ ll_lhs ,
395+ ll_rhs ,
396+ iaddr = iaddr ,
397+ bytestring = bytestring ,
398+ annotations = annotations )
399+
400+ # high-level assignment
401+
402+ xd = ARMMoveXData (xdata )
403+
404+ if xd .is_nondet_ternary_assign :
405+ chklogger .logger .warning (
406+ "Ternary assignment without associated predicate at address %s" ,
407+ iaddr )
408+ return ([], [ll_assign ])
409+
410+ rhsp = xd .cpredicate if xd .is_cpredicate_ok else xd .xpredicate
411+ rhs1 = xd .tern_assign_true
412+ rhs2 = xd .tern_assign_false
413+ lhs = xd .vrd
414+ rdefs = xdata .reachingdefs
415+ defuses = xdata .defuses
416+ defuseshigh = xdata .defuseshigh
417+
418+ hl_lhs = XU .xvariable_to_ast_lval (lhs , xdata , iaddr , astree )
419+ hl_rhsp = XU .xxpr_to_ast_def_expr (rhsp , xdata , iaddr , astree )
420+ hl_rhs1 = XU .xxpr_to_ast_def_expr (rhs1 , xdata , iaddr , astree )
421+ hl_rhs2 = XU .xxpr_to_ast_def_expr (rhs2 , xdata , iaddr , astree )
422+ hl_rhs = astree .mk_question (hl_rhsp , hl_rhs1 , hl_rhs2 )
423+
424+ hl_assign = astree .mk_assign (
425+ hl_lhs ,
426+ hl_rhs ,
427+ iaddr = iaddr ,
428+ bytestring = bytestring ,
429+ annotations = annotations )
430+
431+ astree .add_instr_mapping (hl_assign , ll_assign )
432+ astree .add_instr_address (hl_assign , [iaddr ])
433+ astree .add_expr_mapping (hl_rhs , ll_rhs )
434+ astree .add_lval_mapping (hl_lhs , ll_lhs )
435+ astree .add_expr_reachingdefs (hl_rhs , rdefs [1 :])
436+ astree .add_expr_reachingdefs (ll_rhs , [rdefs [0 ]])
437+ astree .add_lval_defuses (hl_lhs , defuses [0 ])
438+ astree .add_lval_defuses_high (hl_lhs , defuseshigh [0 ])
439+
440+ if astree .has_register_variable_intro (iaddr ):
441+ rvintro = astree .get_register_variable_intro (iaddr )
442+ if rvintro .has_cast ():
443+ astree .add_expose_instruction (hl_assign .instrid )
444+
445+ return ([hl_assign ], [ll_assign ])
446+
447+
212448 def ast_prov (
213449 self ,
214450 astree : ASTInterface ,
@@ -232,10 +468,22 @@ def ast_prov(
232468 if xdata .instruction_is_subsumed ():
233469 return self .ast_prov_subsumed (astree , iaddr , bytestring , xdata )
234470
471+ xd = ARMMoveXData (xdata )
472+
235473 if xdata .instruction_subsumes ():
236- chklogger .logger .warning (
237- "MOV instruction at %s is part of an aggregate that is not yet supported" ,
238- iaddr )
474+ if xd .is_predicate_assign or xd .is_nondet_predicate_assign :
475+ return self .ast_prov_predicate_assign (
476+ astree , iaddr , bytestring , xdata )
477+
478+ elif xd .is_ternary_assign or xd .is_nondet_ternary_assign :
479+ return self .ast_prov_ternary_assign (
480+ astree , iaddr , bytestring , xdata )
481+
482+ else :
483+ chklogger .logger .warning (
484+ "MOV instruction at %s is part of an aggregate that is "
485+ + "not yet supported" ,
486+ iaddr )
239487 return ([], [])
240488
241489 # low-level assignment
0 commit comments