Skip to content

Commit e56dba7

Browse files
committed
ARM: convert astprov to handle result types
1 parent b3ba4cc commit e56dba7

15 files changed

+479
-499
lines changed

chb/app/InstrXData.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,19 @@ def get_branch_conditions(self) -> Sequence[XXpr]:
456456
"XData does not have branch conditions: " + str(self))
457457

458458
def has_instruction_condition(self) -> bool:
459-
return "ic" in self.tags
459+
return any(s.startswith("ic:") for s in self.tags)
460+
461+
def get_instruction_condition(self) -> XXpr:
462+
for t in self.tags:
463+
if t.startswith("ic:"):
464+
index = int(t[3:])
465+
argval = self.args[index]
466+
if argval == -2:
467+
raise UF.CHBError(
468+
"Unexpected error value in instruction condition")
469+
return self.xprdictionary.xpr(argval)
470+
else:
471+
raise UF.CHBError("No instruction condition index found")
460472

461473
def has_condition_block_condition(self) -> bool:
462474
return "TF" in self.tags
@@ -465,7 +477,25 @@ def has_unknown_instruction_condition(self) -> bool:
465477
return "uc" in self.tags
466478

467479
def has_base_update(self) -> bool:
468-
return "bu" in self.tags
480+
return any(s.startswith("vbu:") for s in self.tags)
481+
482+
def get_base_update_var(self) -> XVariable:
483+
vbutag = next(t for t in self.tags if t.startswith("vbu:"))
484+
vix = int(vbutag[4:])
485+
vbuval = self.args[vix]
486+
if vbuval == -2:
487+
raise UF.CHBError(
488+
"Unexpected error value in base-update variable")
489+
return self.xprdictionary.variable(vbuval)
490+
491+
def get_base_update_xpr(self) -> XXpr:
492+
xbutag = next(t for t in self.tags if t.startswith("xbu:"))
493+
xix = int(xbutag[4:])
494+
xbuval = self.args[xix]
495+
if xbuval == -2:
496+
raise UF.CHBError(
497+
"Unexpected error value in base-update expression")
498+
return self.xprdictionary.xpr(xbuval)
469499

470500
@property
471501
def is_aggregate_jumptable(self) -> bool:

chb/arm/ARMCallOpcode.py

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from chb.app.InstrXData import InstrXData
3333

3434
from chb.arm.ARMDictionaryRecord import armregistry
35-
from chb.arm.ARMOpcode import ARMOpcode, simplify_result
35+
from chb.arm.ARMOpcode import ARMOpcode, ARMOpcodeXData, simplify_result
3636
from chb.arm.ARMOperand import ARMOperand
3737
from chb.arm.ARMOperandKind import ARMOperandKind, ARMAbsoluteOp
3838

@@ -64,18 +64,27 @@
6464
from chb.invariants.XXpr import XXpr, XprConstant, XprVariable
6565

6666

67-
class ARMCallOpcodeXData:
67+
class ARMCallOpcodeXData(ARMOpcodeXData):
68+
"""
69+
xdata format: a:x[2n]xr[n]dh, call (n arguments)
70+
-------------------------------------------------
71+
xprs[0..2n-1]: (arg location expr, arg value expr) * n
72+
xprs[2n]: call target expression
73+
rdefs[0..n-1]: arg location reaching definitions
74+
uses[0]: lhs
75+
useshigh[0]: lhs
76+
"""
6877

6978
def __init__(
7079
self,
7180
xdata: InstrXData,
7281
ixd: "InterfaceDictionary") -> None:
73-
self._xdata = xdata
82+
ARMOpcodeXData.__init__(self, xdata)
7483
self._ixd = ixd
7584

7685
@property
77-
def is_ok(self) -> bool:
78-
return self._xdata.is_ok
86+
def vrd(self) -> "XVariable":
87+
return self.var(0, "vrd")
7988

8089
@property
8190
def argument_count(self) -> int:
@@ -101,6 +110,12 @@ def arguments(self) -> List["XXpr"]:
101110
arguments.append(x)
102111
return arguments
103112

113+
@property
114+
def argumentxvars(self) -> List["XXpr"]:
115+
argcount = self.argument_count
116+
return [x for x in self._xdata.xprs_r[argcount:2 * argcount]
117+
if x is not None]
118+
104119
@property
105120
def calltarget(self) -> "CallTarget":
106121
return self._xdata.call_target(self._ixd)
@@ -109,7 +124,8 @@ def calltarget(self) -> "CallTarget":
109124
def annotation(self) -> str:
110125
tgt = str(self.calltarget)
111126
args = ", ".join(str(x) for x in self.arguments)
112-
return "call " + str(tgt) + "(" + args + ")"
127+
call = "call " + str(tgt) + "(" + args + ")"
128+
return self.add_instruction_condition(call)
113129

114130

115131
class ARMCallOpcode(ARMOpcode):
@@ -118,15 +134,7 @@ class ARMCallOpcode(ARMOpcode):
118134
tags[1]: <c>
119135
args[0]: index of target operand in armdictionary
120136
121-
xdata format: a:x[2n]xr[n]dh, call (n arguments)
122-
-------------------------------------------------
123-
xprs[0..2n-1]: (arg location expr, arg value expr) * n
124-
xprs[2n]: call target expression
125-
rdefs[0..n-1]: arg location reaching definitions
126-
uses[0]: lhs
127-
useshigh[0]: lhs
128-
129-
or (if call target is not known):
137+
(if call target is not known):
130138
xdata format: a:xxxxx
131139
---------------------
132140
vars[0]: return value variable
@@ -135,10 +143,7 @@ class ARMCallOpcode(ARMOpcode):
135143
rdefs[0]: target reaching definition
136144
"""
137145

138-
def __init__(
139-
self,
140-
d: "ARMDictionary",
141-
ixval: IndexedTableValue) -> None:
146+
def __init__(self, d: "ARMDictionary", ixval: IndexedTableValue) -> None:
142147
ARMOpcode.__init__(self, d, ixval)
143148

144149
@property
@@ -150,19 +155,10 @@ def opargs(self) -> List[ARMOperand]:
150155
return [self.armd.arm_operand(self.args[0])]
151156

152157
def lhs(self, xdata: InstrXData) -> List[XVariable]:
153-
if len(xdata.vars) > 0:
154-
return [xdata.vars[0]]
155-
else:
156-
return []
158+
return [ARMCallOpcodeXData(xdata, self.ixd).vrd]
157159

158160
def argument_count(self, xdata: InstrXData) -> int:
159-
if self.is_call_instruction(xdata):
160-
argcount = xdata.call_target_argument_count()
161-
if argcount is not None:
162-
return argcount
163-
chklogger.logger.warning(
164-
"Call instruction does not have argument count")
165-
return 0
161+
return ARMCallOpcodeXData(xdata, self.ixd).argument_count
166162

167163
def has_string_arguments(self, xdata: InstrXData) -> bool:
168164
return any([x.is_string_reference for x in self.arguments(xdata)])
@@ -175,7 +171,7 @@ def annotated_call_arguments(
175171
return [x.to_annotated_value() for x in self.arguments(xdata)]
176172

177173
def arguments(self, xdata: InstrXData) -> Sequence[XXpr]:
178-
return xdata.xprs[:self.argument_count(xdata)]
174+
return ARMCallOpcodeXData(xdata, self.ixd).arguments
179175

180176
def is_call(self, xdata: InstrXData) -> bool:
181177
return len(xdata.tags) >= 2 and xdata.tags[1] == "call"
@@ -206,11 +202,13 @@ def ast_call_prov(
206202
chklogger.logger.info("Inlined call omitted at %s", iaddr)
207203
return ([], [])
208204

205+
xd = ARMCallOpcodeXData(xdata, self.ixd)
206+
209207
annotations: List[str] = [iaddr, "BL"]
210208

211209
# low-level call data
212210

213-
lhs = xdata.vars[0]
211+
lhs = xd.vrd
214212
tgt = self.opargs[0]
215213

216214
if not lhs.is_register_variable:
@@ -224,7 +222,7 @@ def ast_call_prov(
224222
ll_lhs = astree.mk_register_variable_lval(str(lhsreg))
225223
(ll_tgt, _, _) = tgt.ast_rvalue(astree)
226224

227-
xprs = xdata.xprs
225+
xprs = xd.arguments
228226
rdefs = xdata.reachingdefs
229227
defuses = xdata.defuses
230228
defuseshigh = xdata.defuseshigh
@@ -284,7 +282,7 @@ def ast_call_prov(
284282

285283
# argument data
286284

287-
argcount = self.argument_count(xdata)
285+
argcount = xd.argument_count
288286

289287
ll_args: List[AST.ASTExpr] = []
290288
hl_args: List[AST.ASTExpr] = []
@@ -304,8 +302,8 @@ def ast_call_prov(
304302
if len(astargtypes) < argcount:
305303
astargtypes += ([None] * (argcount - len(astargtypes)))
306304

307-
xargs = xdata.xprs[:argcount]
308-
xvarargs = xdata.xprs[argcount:(2 * argcount)]
305+
xargs = xd.arguments
306+
xvarargs = xd.argumentxvars
309307
if len(rdefs) >= argcount:
310308
llrdefs = rdefs[:argcount]
311309
# x represents the (invariant-enhanced) argument value.
@@ -316,7 +314,8 @@ def ast_call_prov(
316314
# in bytes (note: not the stackpointer at function entry).
317315
# rdef represents the reaching definition for the argument
318316
# location.
319-
for (x, xv, rdef, argtype) in zip(xargs, xvarargs, llrdefs, astargtypes):
317+
for (x, xv, rdef, argtype) in zip(
318+
xargs, xvarargs, llrdefs, astargtypes):
320319

321320
# low-level argument
322321

chb/arm/ARMInstruction.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# ------------------------------------------------------------------------------
55
# The MIT License (MIT)
66
#
7-
# Copyright (c) 2021-2024 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
@@ -249,11 +249,7 @@ def has_condition_block_condition(self) -> bool:
249249
return self.xdata.has_condition_block_condition()
250250

251251
def get_instruction_condition(self) -> XXpr:
252-
if self.has_instruction_condition():
253-
return self.xdata.xprs[2]
254-
else:
255-
raise UF.CHBError(
256-
"Instruction does not have an instruction condition")
252+
return self.xdata.get_instruction_condition()
257253

258254
@property
259255
def memory_accesses(self) -> Sequence[MemoryAccess]:
@@ -392,7 +388,7 @@ def rdef_locations(self) -> Dict[str, List[List[str]]]:
392388
def lhs_types(self) -> Dict[str, "BCTyp"]:
393389
result: Dict[str, "BCTyp"] = {}
394390

395-
vars = self.xdata.vars
391+
vars = self.xdata.vars_r
396392
types = self.xdata.types
397393
if len(vars) == len(types):
398394
for (v, ty) in zip(vars, types):

chb/arm/ARMOpcode.py

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# ------------------------------------------------------------------------------
55
# The MIT License (MIT)
66
#
7-
# Copyright (c) 2021-2024 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
@@ -26,6 +26,8 @@
2626
# ------------------------------------------------------------------------------
2727
"""ARM opcodes."""
2828

29+
import inspect
30+
2931
from typing import List, Optional, Sequence, Tuple, TYPE_CHECKING
3032

3133
from chb.api.CallTarget import CallTarget
@@ -55,6 +57,8 @@
5557

5658
if TYPE_CHECKING:
5759
from chb.arm.ARMDictionary import ARMDictionary
60+
from chb.invariants.XVariable import XVariable
61+
from chb.invariants.XXpr import XXpr
5862
from chb.simulation.SimulationState import SimulationState
5963

6064

@@ -101,6 +105,68 @@ def get_extension(e: str) -> str:
101105
return e
102106

103107

108+
class ARMOpcodeXData:
109+
110+
def __init__(self, xdata: InstrXData) -> None:
111+
self._xdata = xdata
112+
113+
@property
114+
def xdata(self) -> InstrXData:
115+
return self._xdata
116+
117+
@property
118+
def is_ok(self) -> bool:
119+
return self.xdata.is_ok
120+
121+
def var(self, index: int, name: str) -> "XVariable":
122+
v = self.xdata.vars_r[index]
123+
if v is None:
124+
raise UF.CHBError(
125+
self.__class__.__name__ + ":" + name + " has an error value")
126+
return v
127+
128+
def xpr(self, index: int, name: str) -> "XXpr":
129+
x = self.xdata.xprs_r[index]
130+
if x is None:
131+
raise UF.CHBError(
132+
self.__class__.__name__ + ":" + name + " has an error value")
133+
return x
134+
135+
def add_instruction_condition(self, s: str) -> str:
136+
if self.xdata.has_unknown_instruction_condition():
137+
return "if ? then " + s
138+
elif self.xdata.has_instruction_condition():
139+
c = str(self.xdata.get_instruction_condition())
140+
return "if " + c + " then " + s
141+
else:
142+
return s
143+
144+
def is_writeback(self) -> bool:
145+
return self.xdata.has_base_update()
146+
147+
def get_base_update_var(self) -> "XVariable":
148+
if self.is_writeback:
149+
return self.get_base_update_var()
150+
else:
151+
raise UF.CHBError(
152+
self.__class__.__name__ + " does not have writeback")
153+
154+
def get_base_update_xpr(self) -> "XXpr":
155+
if self.is_writeback:
156+
return self.get_base_update_xpr()
157+
else:
158+
raise UF.CHBError(
159+
self.__class__.__name__ + " does not have writeback")
160+
161+
def writeback_update(self) -> str:
162+
if self.xdata.has_base_update():
163+
vbu = self.xdata.get_base_update_var()
164+
xbu = self.xdata.get_base_update_xpr()
165+
return "; " + str(vbu) + " := " + str(xbu)
166+
else:
167+
return ""
168+
169+
104170
class ARMOpcode(ARMDictionaryRecord):
105171

106172
def __init__(

0 commit comments

Comments
 (0)