From 33fe341981479b7f661f8ed0fbf6d1b0276a7f87 Mon Sep 17 00:00:00 2001 From: Henny Sipma Date: Tue, 21 Oct 2025 18:33:29 -0700 Subject: [PATCH 1/6] AST: add check for constant-value expression --- chb/ast/ASTNode.py | 76 ++++++++++++++++++++++++++++++++++- chb/ast/ASTSymbolTable.py | 4 ++ chb/ast/AbstractSyntaxTree.py | 2 + 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/chb/ast/ASTNode.py b/chb/ast/ASTNode.py index aed63174..d098876f 100644 --- a/chb/ast/ASTNode.py +++ b/chb/ast/ASTNode.py @@ -1003,7 +1003,8 @@ def address_taken(self) -> Set[str]: return self.lhs.address_taken().union(self.rhs.address_taken()) def variables_used(self) -> Set[str]: - return self.lhs.variables_used().union(self.rhs.variables_used()) + lhsvars = set([]) if self.lhs.is_variable else self.lhs.variables_used() + return self.rhs.variables_used().union(lhsvars) def callees(self) -> Set[str]: return set([]) @@ -1051,6 +1052,12 @@ def tgt(self) -> "ASTExpr": def arguments(self) -> List["ASTExpr"]: return self._args + def variables_used(self) -> Set[str]: + result: Set[str] = set([]) + for arg in self.arguments: + result = result.union(arg.variables_used()) + return result + def accept(self, visitor: "ASTVisitor") -> None: visitor.visit_call_instr(self) @@ -1142,6 +1149,10 @@ def lvalid(self) -> int: def lhost(self) -> "ASTLHost": return self._lhost + @property + def is_constant_value_expression(self) -> bool: + return self.lhost.is_constant_value_expression + @property def offset(self) -> "ASTOffset": return self._offset @@ -1204,6 +1215,14 @@ def is_variable(self) -> bool: def is_global(self) -> bool: return False + @property + def is_ssa(self) -> bool: + return False + + @property + def is_constant_value_expression(self) -> bool: + return self.is_ssa + @abstractmethod def transform(self, transformer: "ASTTransformer") -> "ASTLHost": ... @@ -1226,12 +1245,14 @@ def __init__( vtype: Optional["ASTTyp"], parameter: Optional[int] = None, globaladdress: Optional[int] = None, + ssa: bool = False, vdescr: Optional[str] = None) -> None: ASTNode.__init__(self, "varinfo") self._vname = vname self._vtype = vtype self._parameter = parameter self._globaladdress = globaladdress + self._ssa = ssa self._vdescr = vdescr # describes what the variable holds @property @@ -1258,6 +1279,10 @@ def globaladdress(self) -> Optional[int]: def is_global(self) -> bool: return self.globaladdress is not None + @property + def is_ssa(self) -> bool: + return self._ssa + @property def vdescr(self) -> Optional[str]: return self._vdescr @@ -1304,6 +1329,10 @@ def varinfo(self) -> "ASTVarInfo": def is_global(self) -> bool: return self.varinfo.is_global + @property + def is_ssa(self) -> bool: + return self.varinfo.is_ssa + @property def vname(self) -> str: return self.varinfo.vname @@ -1625,6 +1654,10 @@ def is_integer_constant(self) -> bool: def is_integer_constant_zero(self) -> bool: return False + @property + def is_constant_value_expression(self) -> bool: + return False + @property def is_global_address(self) -> bool: return False @@ -1692,6 +1725,10 @@ def __init__(self, exprid: int, tag: str) -> None: def is_ast_constant(self) -> bool: return True + @property + def is_constant_value_expression(self) -> bool: + return True + def use(self) -> List[str]: return [] @@ -1886,6 +1923,10 @@ def is_ast_lval_expr(self) -> bool: def lval(self) -> "ASTLval": return self._lval + @property + def is_constant_value_expression(self) -> bool: + return self.lval.is_constant_value_expression + def accept(self, visitor: "ASTVisitor") -> None: visitor.visit_lval_expression(self) @@ -1921,6 +1962,10 @@ def __init__(self, exprid: int, tgttyp: "ASTTyp") -> None: def tgt_type(self) -> "ASTTyp": return self._tgttyp + @property + def is_constant_value_expression(self) -> bool: + return True + def accept(self, visitor: "ASTVisitor") -> None: visitor.visit_sizeof_expression(self) @@ -1956,6 +2001,10 @@ def cast_tgt_type(self) -> "ASTTyp": def cast_expr(self) -> "ASTExpr": return self._exp + @property + def is_constant_value_expression(self) -> bool: + return self.cast_expr.is_constant_value_expression + def accept(self, visitor: "ASTVisitor") -> None: visitor.visit_cast_expression(self) @@ -2002,6 +2051,10 @@ def op(self) -> str: def exp1(self) -> "ASTExpr": return self._exp + @property + def is_constant_value_expression(self) -> bool: + return self.exp1.is_constant_value_expression + def accept(self, visitor: "ASTVisitor") -> None: visitor.visit_unary_expression(self) @@ -2058,6 +2111,12 @@ def exp1(self) -> "ASTExpr": def exp2(self) -> "ASTExpr": return self._exp2 + @property + def is_constant_value_expression(self) -> bool: + return ( + self.exp1.is_constant_value_expression + and self.exp2.is_constant_value_expression) + def accept(self, visitor: "ASTVisitor") -> None: visitor.visit_binary_expression(self) @@ -2119,6 +2178,13 @@ def exp2(self) -> "ASTExpr": def exp3(self) -> "ASTExpr": return self._exp3 + @property + def is_constant_value_expression(self) -> bool: + return ( + self.exp1.is_constant_value_expression + and self.exp2.is_constant_value_expression + and self.exp3.is_constant_value_expression) + def accept(self, visitor: "ASTVisitor") -> None: visitor.visit_question_expression(self) @@ -2164,6 +2230,10 @@ def is_ast_addressof(self) -> bool: def lval(self) -> "ASTLval": return self._lval + @property + def is_constant_value_expression(self) -> bool: + return True + def accept(self, visitor: "ASTVisitor") -> None: visitor.visit_address_of_expression(self) @@ -2203,6 +2273,10 @@ def is_ast_startof(self) -> bool: def lval(self) -> "ASTLval": return self._lval + @property + def is_constant_value_expression(self) -> bool: + return True + def accept(self, visitor: "ASTVisitor") -> None: visitor.visit_start_of_expression(self) diff --git a/chb/ast/ASTSymbolTable.py b/chb/ast/ASTSymbolTable.py index 11b8bced..22f8b28c 100644 --- a/chb/ast/ASTSymbolTable.py +++ b/chb/ast/ASTSymbolTable.py @@ -63,6 +63,7 @@ def add_symbol( vtype: Optional[AST.ASTTyp] = None, parameter: Optional[int] = None, globaladdress: Optional[int] = None, + ssa: bool = False, llref: bool = False, vdescr: Optional[str] = None) -> AST.ASTVarInfo: @@ -104,6 +105,7 @@ def add_symbol( vtype=vtype, parameter=parameter, globaladdress=globaladdress, + ssa=ssa, vdescr=vdescr) self._table[vname] = varinfo return varinfo @@ -257,6 +259,7 @@ def add_symbol( vtype: Optional[AST.ASTTyp] = None, parameter: Optional[int] = None, globaladdress: Optional[int] = None, + ssa: bool = False, llref: bool = False, vdescr: Optional[str] = None) -> AST.ASTVarInfo: if parameter is not None: @@ -266,6 +269,7 @@ def add_symbol( vname, vtype=vtype, globaladdress=globaladdress, + ssa=ssa, vdescr=vdescr) if globaladdress is not None: self._symbolicnames[vinfo.vname] = vinfo diff --git a/chb/ast/AbstractSyntaxTree.py b/chb/ast/AbstractSyntaxTree.py index 8564e3b9..781a86c5 100644 --- a/chb/ast/AbstractSyntaxTree.py +++ b/chb/ast/AbstractSyntaxTree.py @@ -204,12 +204,14 @@ def add_symbol( vtype: Optional[AST.ASTTyp] = None, parameter: Optional[int] = None, globaladdress: Optional[int] = None, + ssa: bool = False, vdescr: Optional[str] = None) -> AST.ASTVarInfo: return self.symboltable.add_symbol( name, vtype=vtype, parameter=parameter, globaladdress=globaladdress, + ssa=ssa, vdescr=vdescr) def add_compinfo(self, cinfo: AST.ASTCompInfo) -> None: From a6f6219ad42107289d5b2ed0a0b5f6249c48a7e5 Mon Sep 17 00:00:00 2001 From: Henny Sipma Date: Tue, 21 Oct 2025 18:37:15 -0700 Subject: [PATCH 2/6] ASTI: prune variables not used from the lifting --- chb/astinterface/ASTICodeTransformer.py | 23 ++++++++++++++++------- chb/astinterface/ASTInterface.py | 8 +++++--- chb/astinterface/ASTInterfaceFunction.py | 8 +++++++- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/chb/astinterface/ASTICodeTransformer.py b/chb/astinterface/ASTICodeTransformer.py index fa262604..a8252c55 100644 --- a/chb/astinterface/ASTICodeTransformer.py +++ b/chb/astinterface/ASTICodeTransformer.py @@ -47,8 +47,10 @@ class ASTICodeTransformer(ASTIdentityTransformer): def __init__( self, - astinterface: "ASTInterface") -> None: + astinterface: "ASTInterface", + variablesused: List[str] = []) -> None: self._astinterface = astinterface + self._variablesused = variablesused @property def astinterface(self) -> "ASTInterface": @@ -58,6 +60,10 @@ def astinterface(self) -> "ASTInterface": def provenance(self) -> "ASTIProvenance": return self.astinterface.astiprovenance + @property + def variables_used(self) -> List[str]: + return self._variablesused + def transform_stmt(self, stmt: AST.ASTStmt) -> AST.ASTStmt: return stmt.transform(self) @@ -98,12 +104,6 @@ def transform_instruction_sequence_stmt( and not self.provenance.has_expose_instruction(instr.instrid)): chklogger.logger.info( "Remove [%s]: has ssa value", str(instr)) - elif self.provenance.has_active_lval_defuse_high(instr.lhs.lvalid): - chklogger.logger.info( - "Transform [%s]: active lval_defuse_high: %s", - str(instr), - self.provenance.active_lval_defuse_high(instr.lhs.lvalid)) - instrs.append(instr) elif self.provenance.has_lval_store(instr.lhs.lvalid): chklogger.logger.info( "Transform [%s]: lval_store", str(instr)) @@ -116,6 +116,15 @@ def transform_instruction_sequence_stmt( chklogger.logger.info( "Transform [%s]: global lhs", str(instr)) instrs.append(instr) + elif str(instr.lhs) not in self.variables_used: + chklogger.logger.info( + "Remove [%s]: lhs is not used") + elif self.provenance.has_active_lval_defuse_high(instr.lhs.lvalid): + chklogger.logger.info( + "Transform [%s]: active lval_defuse_high: %s", + str(instr), + self.provenance.active_lval_defuse_high(instr.lhs.lvalid)) + instrs.append(instr) else: chklogger.logger.info("Transform [%s]: remove", str(instr)) else: diff --git a/chb/astinterface/ASTInterface.py b/chb/astinterface/ASTInterface.py index 6ddeef4b..4b504572 100644 --- a/chb/astinterface/ASTInterface.py +++ b/chb/astinterface/ASTInterface.py @@ -561,12 +561,14 @@ def add_symbol( name: str, vtype: Optional[AST.ASTTyp] = None, parameter: Optional[int] = None, - globaladdress: Optional[int] = None) -> AST.ASTVarInfo: + globaladdress: Optional[int] = None, + ssa:bool = False) -> AST.ASTVarInfo: return self.astree.add_symbol( name, vtype=vtype, parameter=parameter, - globaladdress=globaladdress) + globaladdress=globaladdress, + ssa=ssa) def add_formal( self, @@ -1050,7 +1052,7 @@ def mk_ssa_register_varinfo( ssaid = self._ssa_prefix_counters[ssaprefix] self._ssa_prefix_counters[ssaprefix] += 1 vname = ssaprefix + "_" + str(ssaid) - varinfo = self.add_symbol(vname, vtype=vtype) + varinfo = self.add_symbol(vname, vtype=vtype, ssa=True) self._ssa_intros.setdefault(iaddr, {}) self._ssa_intros[iaddr][name] = varinfo if save_loc: diff --git a/chb/astinterface/ASTInterfaceFunction.py b/chb/astinterface/ASTInterfaceFunction.py index 0d197c97..f2d974b3 100644 --- a/chb/astinterface/ASTInterfaceFunction.py +++ b/chb/astinterface/ASTInterfaceFunction.py @@ -222,7 +222,13 @@ def mk_high_level_ast( annotations=self.astinterface.annotations) print(iprettyprinter.to_c(ast)) - codetransformer = ASTICodeTransformer(self.astinterface) + variablesused = ast.variables_used() + + codetransformer = ASTICodeTransformer(self.astinterface, list(variablesused)) + transformedcode = codetransformer.transform_stmt(ast) + + variablesused = transformedcode.variables_used() + codetransformer = ASTICodeTransformer(self.astinterface, list(variablesused)) transformedcode = codetransformer.transform_stmt(ast) if self.verbose: From 66a9e00872c4e4fcdc4a8df906b8c6fb48540cb1 Mon Sep 17 00:00:00 2001 From: Henny Sipma Date: Tue, 21 Oct 2025 18:39:03 -0700 Subject: [PATCH 3/6] USER: add loopcounter to mods; add const-global-variables annotation --- chb/userdata/UserHints.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/chb/userdata/UserHints.py b/chb/userdata/UserHints.py index 5ae8407c..cf2efe86 100644 --- a/chb/userdata/UserHints.py +++ b/chb/userdata/UserHints.py @@ -572,6 +572,10 @@ def arraysize(self) -> Optional[int]: def ispointer(self) -> bool: return "ptrto" in self.mods + @property + def is_loopcounter(self) -> bool: + return "loopcounter" in self.mods + def to_xml(self, node: ET.Element) -> None: xvintro = ET.Element("vintro") node.append(xvintro) @@ -583,6 +587,8 @@ def to_xml(self, node: ET.Element) -> None: xvintro.set("arraysize", str(self.arraysize)) elif self.ispointer: xvintro.set("ptrto", "yes") + if self.is_loopcounter: + xvintro.set("loopcounter", "yes") def __str__(self) -> str: return ( @@ -720,6 +726,10 @@ def remove_reaching_definitions(self) -> List[RemoveReachingDefinitions]: result.append(rrd) return result + @property + def const_global_variables(self) -> List[str]: + return self.fnannotation.get("const-global-variables", []) + def has_register_variable_introduction(self, iaddr: str) -> bool: return iaddr in self.register_variable_introductions @@ -761,6 +771,13 @@ def to_xml(self, node: ET.Element) -> None: node.append(xrrds) for rd in self.remove_reaching_definitions: rd.to_xml(xrrds) + if len(self.const_global_variables) > 0: + xcgvars = ET.Element("const-global-variables") + node.append(xcgvars) + for name in self.const_global_variables: + xcgvar = ET.Element("gvar") + xcgvar.set("name", name) + xcgvars.append(xcgvar) def __str__(self) -> str: lines: List[str] = [] From 9e011978421dd621aba7374ff5c338a0c86f8d0b Mon Sep 17 00:00:00 2001 From: Henny Sipma Date: Tue, 21 Oct 2025 18:41:22 -0700 Subject: [PATCH 4/6] XPR: add checks for loopcounter; extend ssa-value recording --- chb/invariants/XSymbol.py | 3 +++ chb/invariants/XVariable.py | 4 ++++ chb/invariants/XXpr.py | 24 ++++++++++++++++++++++++ chb/invariants/XXprUtil.py | 16 +++++++++++++++- 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/chb/invariants/XSymbol.py b/chb/invariants/XSymbol.py index fc535953..9c48733f 100644 --- a/chb/invariants/XSymbol.py +++ b/chb/invariants/XSymbol.py @@ -63,6 +63,9 @@ def name(self) -> str: def attrs(self) -> List[str]: return self.tags[1:] + def has_attribute(self, attr: str) -> bool: + return attr in self.attrs + @property def seqnr(self) -> int: return self.args[0] diff --git a/chb/invariants/XVariable.py b/chb/invariants/XVariable.py index f6e8ab7c..9b64304d 100644 --- a/chb/invariants/XVariable.py +++ b/chb/invariants/XVariable.py @@ -82,6 +82,10 @@ def type(self) -> str: def is_tmp(self) -> bool: return (self.seqnr == -1) + @property + def is_loop_counter(self) -> bool: + return self.symbol.has_attribute("lc") + @property def is_constant_value_variable(self) -> bool: return self.has_denotation() and self.denotation.is_auxiliary_variable diff --git a/chb/invariants/XXpr.py b/chb/invariants/XXpr.py index 8326b542..511ef2e5 100644 --- a/chb/invariants/XXpr.py +++ b/chb/invariants/XXpr.py @@ -294,6 +294,14 @@ def has_variables_with_property( self, p: Callable[[XVariable], bool]) -> bool: return False + def all_variables_with_property( + self, p: Callable[[XVariable], bool]) -> bool: + return False + + @property + def is_loop_counter_expression(self) -> bool: + return self.all_variables_with_property(lambda v: v.is_loop_counter) + def negated_value(self) -> int: raise UF.CHBError("Get_negated_value not supported for " + str(self)) @@ -349,6 +357,10 @@ def __init__( def variable(self) -> XVariable: return self.xd.variable(self.args[0]) + @property + def is_loop_counter(self) -> bool: + return self.variable.is_loop_counter + @property def is_constant_value_variable(self) -> bool: return self.variable.is_constant_value_variable @@ -447,6 +459,10 @@ def has_variables_with_property( self, p: Callable[[XVariable], bool]) -> bool: return p(self.variable) + def all_variables_with_property( + self, p: Callable[[XVariable], bool]) -> bool: + return p(self.variable) + def argument_index(self) -> int: if self.is_argument_value: return self.variable.denotation.argument_index() @@ -577,6 +593,10 @@ def intvalue(self) -> int: raise UF.CHBError( "Constant is not an integer constant: " + str(self)) + def all_variables_with_property( + self, p: Callable[[XVariable], bool]) -> bool: + return True + @property def is_constant(self) -> bool: return True @@ -759,6 +779,10 @@ def has_variables_with_property( self, p: Callable[[XVariable], bool]) -> bool: return any([op.has_variables_with_property(p) for op in self.operands]) + def all_variables_with_property( + self, p: Callable[[XVariable], bool]) -> bool: + return all([op.all_variables_with_property(p) for op in self.operands]) + @property def is_stack_address(self) -> bool: args = self.operands diff --git a/chb/invariants/XXprUtil.py b/chb/invariants/XXprUtil.py index 12cd92ae..093f0af8 100644 --- a/chb/invariants/XXprUtil.py +++ b/chb/invariants/XXprUtil.py @@ -1848,12 +1848,26 @@ def xvariable_to_ast_lval( bctype = xdata.function.register_lhs_type(iaddr, str(xv)) if bctype is not None: ctype = bctype.convert(astree.typconverter) + + # Note: Ideally the rhs parameter should be replaced with an astrhs + # parameter supplied by all of the instructions. The replacement would + # avoid having to compute the astrhs twice. Furthermore, for some + # instructions the rhs may be computed in a non-standard way, causing + # the assigned value to diverge from the value computed here. if ( rhs is not None and (rhs.is_constant - or (rhs.is_constant_value_variable))): + or (rhs.is_constant_value_variable) + or (rhs.is_loop_counter_expression))): astrhs: Optional[AST.ASTExpr] = xxpr_to_ast_def_expr( rhs, xdata, iaddr, astree, anonymous=anonymous) + + elif rhs is not None: + astrhs = xxpr_to_ast_def_expr( + rhs, xdata, iaddr, astree, anonymous=anonymous) + if not astrhs.is_constant_value_expression: + astrhs = None + else: astrhs = None From 44cfdf32d6b2b889ab10d2c8d63f57d032579178 Mon Sep 17 00:00:00 2001 From: Henny Sipma Date: Tue, 21 Oct 2025 18:44:21 -0700 Subject: [PATCH 5/6] ARM: add rhs to lhs ast-prov conversion --- chb/app/CHVersion.py | 2 +- chb/arm/opcodes/ARMAdd.py | 2 +- chb/arm/opcodes/ARMArithmeticShiftRight.py | 2 +- chb/arm/opcodes/ARMLogicalShiftLeft.py | 2 +- chb/arm/opcodes/ARMLogicalShiftRight.py | 2 +- chb/arm/opcodes/ARMReverseSubtract.py | 2 +- chb/arm/opcodes/ARMStoreRegisterHalfword.py | 15 +++++++++++++-- chb/arm/opcodes/ARMSubtract.py | 2 +- chb/arm/opcodes/ARMTestEquivalence.py | 4 ++++ 9 files changed, 24 insertions(+), 9 deletions(-) diff --git a/chb/app/CHVersion.py b/chb/app/CHVersion.py index 4f472907..b2462c4b 100644 --- a/chb/app/CHVersion.py +++ b/chb/app/CHVersion.py @@ -1 +1 @@ -chbversion: str = "0.3.0-20251012" +chbversion: str = "0.3.0-20251021" diff --git a/chb/arm/opcodes/ARMAdd.py b/chb/arm/opcodes/ARMAdd.py index 80a794cc..37f4ce3b 100644 --- a/chb/arm/opcodes/ARMAdd.py +++ b/chb/arm/opcodes/ARMAdd.py @@ -319,7 +319,7 @@ def has_cast() -> bool: defuses = xdata.defuses defuseshigh = xdata.defuseshigh - hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree, rhs=rhs) if str(lhs) == "PC": chklogger.logger.info( diff --git a/chb/arm/opcodes/ARMArithmeticShiftRight.py b/chb/arm/opcodes/ARMArithmeticShiftRight.py index 1d606f55..d916162e 100644 --- a/chb/arm/opcodes/ARMArithmeticShiftRight.py +++ b/chb/arm/opcodes/ARMArithmeticShiftRight.py @@ -220,7 +220,7 @@ def ast_prov( defuses = xdata.defuses defuseshigh = xdata.defuseshigh - hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree, rhs=rhs) hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) hl_assign = astree.mk_assign( diff --git a/chb/arm/opcodes/ARMLogicalShiftLeft.py b/chb/arm/opcodes/ARMLogicalShiftLeft.py index 13248b00..ac2ca1e4 100644 --- a/chb/arm/opcodes/ARMLogicalShiftLeft.py +++ b/chb/arm/opcodes/ARMLogicalShiftLeft.py @@ -245,7 +245,7 @@ def ast_prov( defuses = xdata.defuses defuseshigh = xdata.defuseshigh - hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree, rhs=rhs) hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) hl_assign = astree.mk_assign( diff --git a/chb/arm/opcodes/ARMLogicalShiftRight.py b/chb/arm/opcodes/ARMLogicalShiftRight.py index c1868f91..9bd5ee72 100644 --- a/chb/arm/opcodes/ARMLogicalShiftRight.py +++ b/chb/arm/opcodes/ARMLogicalShiftRight.py @@ -234,7 +234,7 @@ def ast_prov( defuses = xdata.defuses defuseshigh = xdata.defuseshigh - hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree, rhs=rhs) hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) hl_assign = astree.mk_assign( diff --git a/chb/arm/opcodes/ARMReverseSubtract.py b/chb/arm/opcodes/ARMReverseSubtract.py index 6714c978..a611e7dc 100644 --- a/chb/arm/opcodes/ARMReverseSubtract.py +++ b/chb/arm/opcodes/ARMReverseSubtract.py @@ -246,7 +246,7 @@ def ast_prov( defuses = xdata.defuses defuseshigh = xdata.defuseshigh - hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree, rhs=rhs) hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) hl_assign = astree.mk_assign( diff --git a/chb/arm/opcodes/ARMStoreRegisterHalfword.py b/chb/arm/opcodes/ARMStoreRegisterHalfword.py index 36cfab96..8f4f3feb 100644 --- a/chb/arm/opcodes/ARMStoreRegisterHalfword.py +++ b/chb/arm/opcodes/ARMStoreRegisterHalfword.py @@ -145,7 +145,19 @@ def is_cxaddr_ok(self) -> bool: @property def annotation(self) -> str: wbu = self.writeback_update() - clhs = str(self.cvmem) if self.is_cvmem_ok else "None" + if self.is_cvmem_ok: + clhs = str(self.cvmem) + elif self.is_cxaddr_ok: + if self.cxaddr.is_addressof_var: + lhsvar = self.cxaddr.get_addressof_var + if lhsvar is not None: + clhs = str(lhsvar) + else: + clhs = "*(" + str(self.cxaddr) + ")" + else: + clhs = "*(" + str(self.cxaddr) + ")" + else: + clhs = "None" crhs = str(self.cxrt) if self.is_cxrt_ok else "None" assignc = "(C: " + clhs + " := " + crhs + ")" if self.is_vmem_ok: @@ -165,7 +177,6 @@ def annotation(self) -> str: return self.add_instruction_condition(assignment + wbu) - @armregistry.register_tag("STRH", ARMOpcode) class ARMStoreRegisterHalfword(ARMOpcode): """Stores the least significant halfword from a register into memory. diff --git a/chb/arm/opcodes/ARMSubtract.py b/chb/arm/opcodes/ARMSubtract.py index 9c7c85f9..52d6ec98 100644 --- a/chb/arm/opcodes/ARMSubtract.py +++ b/chb/arm/opcodes/ARMSubtract.py @@ -236,7 +236,7 @@ def ast_prov( defuses = xdata.defuses defuseshigh = xdata.defuseshigh - hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree, rhs=rhs) # resulting expression is a stack address if str(rhs1) == "SP" and xrhs.is_stack_address: diff --git a/chb/arm/opcodes/ARMTestEquivalence.py b/chb/arm/opcodes/ARMTestEquivalence.py index b917c0f0..2a9eda32 100644 --- a/chb/arm/opcodes/ARMTestEquivalence.py +++ b/chb/arm/opcodes/ARMTestEquivalence.py @@ -90,6 +90,10 @@ def __init__(self, d: "ARMDictionary", ixval: IndexedTableValue) -> None: def operands(self) -> List[ARMOperand]: return [self.armd.arm_operand(i) for i in self.args] + @property + def opargs(self) -> List[ARMOperand]: + return [self.armd.arm_operand(i) for i in self.args] + def annotation(self, xdata: InstrXData) -> str: xd = ARMTestEquivalenceXData(xdata) if xd.is_ok: From d7d251eebcf0fd0bf3b04325fb4f63b75024df07 Mon Sep 17 00:00:00 2001 From: Henny Sipma Date: Wed, 22 Oct 2025 11:23:33 -0700 Subject: [PATCH 6/6] AST: extend variables used to switch stmt --- chb/app/CHVersion.py | 2 +- chb/ast/ASTNode.py | 14 ++++++++++---- chb/astinterface/ASTICodeTransformer.py | 10 +++++++--- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/chb/app/CHVersion.py b/chb/app/CHVersion.py index b2462c4b..62bec65c 100644 --- a/chb/app/CHVersion.py +++ b/chb/app/CHVersion.py @@ -1 +1 @@ -chbversion: str = "0.3.0-20251021" +chbversion: str = "0.3.0-20251022" diff --git a/chb/ast/ASTNode.py b/chb/ast/ASTNode.py index d098876f..c7b66ff5 100644 --- a/chb/ast/ASTNode.py +++ b/chb/ast/ASTNode.py @@ -494,24 +494,24 @@ def ctype(self, ctyper: "ASTCTyper") -> Optional["ASTTyp"]: return ctyper.ctype_block_stmt(self) def is_empty(self) -> bool: - return all(s.is_empty() for s in self.stmts) + return self.is_stmt_label or all(s.is_empty() for s in self.stmts) def address_taken(self) -> Set[str]: - if self.is_empty(): + if self.is_stmt_label or self.is_empty(): return set([]) else: return self.stmts[0].address_taken().union( *(s.address_taken() for s in self.stmts[1:])) def variables_used(self) -> Set[str]: - if self.is_empty(): + if self.is_stmt_label or self.is_empty(): return set([]) else: return self.stmts[0].variables_used().union( *(s.variables_used() for s in self.stmts[1:])) def callees(self) -> Set[str]: - if self.is_empty(): + if self.is_stmt_label or self.is_empty(): return set([]) else: return self.stmts[0].callees().union( @@ -749,6 +749,9 @@ def cases(self) -> "ASTStmt": def merge_address(self) -> Optional[str]: return self._mergeaddress + def variables_used(self) -> Set[str]: + return self.cases.variables_used().union(self.switchexpr.variables_used()) + def accept(self, visitor: "ASTVisitor") -> None: visitor.visit_switch_stmt(self) @@ -772,6 +775,9 @@ def __init__(self, locationid: int, tag: str) -> None: def is_stmt_label(self) -> bool: return True + def is_empty(self) -> bool: + return True + @property def locationid(self) -> int: return self._locationid diff --git a/chb/astinterface/ASTICodeTransformer.py b/chb/astinterface/ASTICodeTransformer.py index a8252c55..410c6ad6 100644 --- a/chb/astinterface/ASTICodeTransformer.py +++ b/chb/astinterface/ASTICodeTransformer.py @@ -51,6 +51,9 @@ def __init__( variablesused: List[str] = []) -> None: self._astinterface = astinterface self._variablesused = variablesused + chklogger.logger.info( + "ASTICodeTransformer: variables used: [%s]", + ", ".join(self._variablesused)) @property def astinterface(self) -> "ASTInterface": @@ -103,7 +106,8 @@ def transform_instruction_sequence_stmt( self.astinterface.has_ssa_value(str(instr.lhs)) and not self.provenance.has_expose_instruction(instr.instrid)): chklogger.logger.info( - "Remove [%s]: has ssa value", str(instr)) + "Remove [%s]: has ssa value: %s", + str(instr), str(self.astinterface.get_ssa_value(str(instr.lhs)))) elif self.provenance.has_lval_store(instr.lhs.lvalid): chklogger.logger.info( "Transform [%s]: lval_store", str(instr)) @@ -118,7 +122,7 @@ def transform_instruction_sequence_stmt( instrs.append(instr) elif str(instr.lhs) not in self.variables_used: chklogger.logger.info( - "Remove [%s]: lhs is not used") + "Remove [%s]: lhs is not used: %s", str(instr), str(instr.lhs)) elif self.provenance.has_active_lval_defuse_high(instr.lhs.lvalid): chklogger.logger.info( "Transform [%s]: active lval_defuse_high: %s", @@ -126,7 +130,7 @@ def transform_instruction_sequence_stmt( self.provenance.active_lval_defuse_high(instr.lhs.lvalid)) instrs.append(instr) else: - chklogger.logger.info("Transform [%s]: remove", str(instr)) + chklogger.logger.info("Transform [%s]: remove (by default)", str(instr)) else: chklogger.logger.info( "Transform [%s]: include by default", str(instr))