def __copy__(self): cls = self.__class__ result = cls.__new__(cls) result.__dict__.update(self.__dict__) result.type_params = copy.copy(self.type_params) result.params = [] for param in self.params: result.params.append(copy.copy(param)) return result
def eval(self, p4_state): val = p4_state.resolve_expr(self.val) if self.instance_type is None: # no type defined, return just the value return val else: instance = gen_instance("None", self.instance_type) if isinstance(val, P4ComplexInstance): # copy the reference if we initialize with another complex type return copy.copy(val) if isinstance(instance, P4ComplexInstance): if isinstance(val, dict): instance.setValid() for name, val in val.items(): val_expr = p4_state.resolve_expr(val) instance.set_or_add_var(name, val_expr) elif isinstance(val, list): instance.set_list(val) else: raise RuntimeError( f"P4StructInitializer members {val} not supported!") return instance else: # cast the value we assign to the instance we create # TODO: I do not like this, there must be a better way to do this if isinstance(val, int) and isinstance( instance, (z3.BitVecSortRef, z3.BitVecRef)): val = z3_cast(val, instance.sort()) return val
def init_type_params(self, ctx, *args, **kwargs): # TODO Figure out what to actually do here init_ctrl = copy.copy(self) # the type params sometimes include the return type also # it is typically the first value, but is bound somewhere else for idx, t_param in enumerate(init_ctrl.type_params): init_ctrl.type_ctx[t_param] = args[idx] return init_ctrl
def __copy__(self): cls = self.__class__ result = cls.__new__(cls) result.__dict__.update(self.__dict__) result.params = copy.deepcopy(result.params) for idx, val in enumerate(result.params): result.params[idx] = copy.copy(val) return result
def eval(self, p4_state): log.debug("Assigning %s to %s ", self.rval, self.lval) rval_expr = p4_state.resolve_expr(self.rval) # in assignments all complex types values are copied if isinstance(rval_expr, StructInstance): rval_expr = copy.copy(rval_expr) if isinstance(rval_expr, int): lval = p4_state.resolve_expr(self.lval) rval_expr = z3_cast(rval_expr, lval.sort()) p4_state.set_or_add_var(self.lval, rval_expr)
def initialize(self, context, *args, **kwargs): ctrl_copy = copy.copy(self) ctrl_copy.merged_consts = merge_parameters(ctrl_copy.const_params, *args, **kwargs) # also bind types, because for reasons you can bind types everywhere... for idx, const_param in enumerate(ctrl_copy.const_params): # this means the type is generic p4_type = resolve_type(context, const_param.p4_type) if p4_type is None: # grab the type of the input arguments ctrl_copy.type_context[const_param.p4_type] = args[idx].sort() return ctrl_copy
def copy_in(self, ctx, merged_args): param_buffer = OrderedDict() var_buffer = OrderedDict() for param_name, arg in merged_args.items(): # We need to resolve array indices appropriately arg_expr, _ = resolve_index(ctx, arg.p4_val) try: param_val = ctx.resolve_reference(param_name) var_buffer[param_name] = (arg.mode, arg_expr, param_val) except RuntimeError: # if the variable name does not exist, set the value to None var_buffer[param_name] = (arg.mode, arg_expr, None) # Sometimes expressions are passed, resolve those first arg_expr = ctx.resolve_expr(arg_expr) # it can happen that we receive a list # infer the type, generate, and set try: p4_type = ctx.resolve_type(arg.p4_type) except KeyError: # this is a generic type, we need to bind for this scope # FIXME: Clean this up p4_type = arg_expr.sort() ctx.add_type(arg.p4_type, p4_type) if isinstance(arg_expr, list): # if the type is undefined, do nothing if isinstance(p4_type, P4ComplexType): arg_instance = ctx.gen_instance(UNDEF_LABEL, p4_type) arg_instance.set_list(arg_expr) arg_expr = arg_instance # it is possible to pass an int as value, we need to cast it elif isinstance(arg_expr, int): arg_expr = z3_cast(arg_expr, p4_type) # need to work with an independent copy # the purpose is to handle indirect assignments in an action if arg.mode in ("in", "inout") and isinstance( arg_expr, StructInstance): arg_expr = copy.copy(arg_expr) if arg.mode == "out": # outs are left-values so the arg must be a string # infer the type value at runtime, param does not work yet # outs reset the input # In the case that the instance is a complex type make sure # to propagate the variable through all its members log.debug("Resetting %s to %s", arg_expr, param_name) arg_expr = ctx.gen_instance(UNDEF_LABEL, p4_type) log.debug("Copy-in: %s to %s", arg_expr, param_name) # buffer the value, do NOT set it yet param_buffer[param_name] = arg_expr return param_buffer, var_buffer
def bind_to_ctrl_type(self, ctx, ctrl_type): # TODO Figure out what to actually do here # FIXME: A hack to deal with lack of input params if len(ctrl_type.params) < len(self.type_params): return self init_ctrl = copy.copy(self) # the type params sometimes include the return type also # it is typically the first value, but is bound somewhere else for idx, t_param in enumerate(init_ctrl.type_params): sub_type = ctx.resolve_type(ctrl_type.params[idx].p4_type) init_ctrl.type_ctx[t_param] = sub_type for param_idx, param in enumerate(init_ctrl.params): if isinstance(param.p4_type, str) and param.p4_type == t_param: init_ctrl.params[param_idx] = ctrl_type.params[idx] return init_ctrl
def eval(self, ctx): # An assignment, written with the = sign, first evaluates its left # sub-expression to an l-value, then evaluates its right sub-expression # to a value, and finally copies the value into the l-value. Derived # types (e.g. structs) are copied recursively, and all components of # headers are copied, including “validity” bits. Assignment is not # defined for extern values. log.debug("Assigning %s to %s ", self.rval, self.lval) lval, _ = resolve_index(ctx, self.lval) rval_expr = ctx.resolve_expr(self.rval) # in assignments all complex types values are copied if isinstance(rval_expr, StructInstance): rval_expr = copy.copy(rval_expr) if isinstance(rval_expr, int): rval_expr = z3_cast(rval_expr, ctx.resolve_expr(self.lval).sort()) ctx.set_or_add_var(lval, rval_expr)
def initialize(self, *args, **kwargs): # TODO Figure out what to actually do here init_method = copy.copy(self) # deepcopy is important to ensure independent type inference # the type params sometimes include the return type also # it is typically the first value, but is bound somewhere else if len(args) < len(init_method.type_params): type_list = init_method.type_params[1:] else: type_list = init_method.type_params for idx, t_param in enumerate(type_list): if init_method.return_type == t_param: init_method.return_type = args[idx] for method_param in init_method.params: if method_param.p4_type == t_param: method_param.p4_type = args[idx] return init_method
def eval(self, p4_state): log.debug("Assigning %s to %s ", self.rval, self.lval) rval_expr = p4_state.resolve_expr(self.rval) # in assignments all complex types values are copied if isinstance(rval_expr, P4ComplexInstance): rval_expr = copy.copy(rval_expr) # make sure the assignment is aligned appropriately # this can happen because we also evaluate before the # BindTypeVariables pass # we can only align if tmp_val is a bitvector # example test: instance_overwrite.p4 lval = p4_state.resolve_expr(self.lval) if isinstance(rval_expr, int) and isinstance( lval, (z3.BitVecSortRef, z3.BitVecRef)): rval_expr = z3_cast(rval_expr, lval.sort()) p4_state.set_or_add_var(self.lval, rval_expr) p4z3_expr = p4_state.pop_next_expr() return p4z3_expr.eval(p4_state)
def set_context(self, p4_state, merged_args, ref_criteria): param_buffer = OrderedDict() for param_name, arg in merged_args.items(): # Sometimes expressions are passed, resolve those first arg_expr = p4_state.resolve_expr(arg.p4_val) # for now use the param name, not the arg_name constructed here # FIXME: there are some passes that rename causing issues arg_name = f"{self.name}_{param_name}" # it can happen that we receive a list # infer the type, generate, and set if isinstance(arg_expr, list): # if the type is undefined, do nothing if isinstance(arg.p4_type, P4ComplexType): arg_instance = gen_instance(arg_name, arg.p4_type) arg_instance.set_list(arg_expr) arg_expr = arg_instance if arg.is_ref == "inout": if isinstance(arg_expr, P4ComplexInstance): arg_expr = copy.copy(arg_expr) if arg.is_ref == "out": # outs are left-values so the arg must be a string # infer the type value at runtime, param does not work yet # outs reset the input # In the case that the instance is a complex type make sure # to propagate the variable through all its members log.debug("Resetting %s to %s", arg_expr, param_name) if isinstance(arg_expr, P4ComplexInstance): arg_expr = arg_expr.p4z3_type.instantiate(param_name) # FIXME: This should not be needed arg_expr.deactivate() else: arg_expr = z3.Const(f"undefined", arg_expr.sort()) log.debug("Copy-in: %s to %s", arg_expr, param_name) # it is possible to pass an int as value, we need to cast it if isinstance(arg_expr, int) and isinstance( arg.p4_type, (z3.BitVecSortRef, z3.BitVecRef)): arg_expr = z3_cast(arg_expr, arg.p4_type) # buffer the value, do NOT set it yet param_buffer[param_name] = arg_expr # now we can set the arguments without influencing subsequent variables for param_name, param_val in param_buffer.items(): p4_state.set_or_add_var(param_name, param_val)
def copy_in(self, p4_state, merged_args): param_buffer = OrderedDict() for param_name, arg in merged_args.items(): # Sometimes expressions are passed, resolve those first arg_expr = p4_state.resolve_expr(arg.p4_val) # for now use the param name, not the arg_name constructed here # FIXME: there are some passes that rename causing issues arg_name = "undefined" # f"{self.name}_{param_name}" # it can happen that we receive a list # infer the type, generate, and set p4_type = resolve_type(p4_state, arg.p4_type) if isinstance(arg_expr, list): # if the type is undefined, do nothing if isinstance(p4_type, P4ComplexType): arg_instance = gen_instance(p4_state, arg_name, p4_type) arg_instance.set_list(arg_expr) arg_expr = arg_instance # it is possible to pass an int as value, we need to cast it elif isinstance(arg_expr, int): arg_expr = z3_cast(arg_expr, p4_type) # need to work with an independent copy # the purpose is to handle indirect assignments in an action if arg.mode in ("in", "inout") and isinstance( arg_expr, StructInstance): arg_expr = copy.copy(arg_expr) if arg.mode == "out": # outs are left-values so the arg must be a string # infer the type value at runtime, param does not work yet # outs reset the input # In the case that the instance is a complex type make sure # to propagate the variable through all its members log.debug("Resetting %s to %s", arg_expr, param_name) arg_expr = gen_instance(p4_state, arg_name, p4_type) log.debug("Copy-in: %s to %s", arg_expr, param_name) # buffer the value, do NOT set it yet param_buffer[param_name] = arg_expr return param_buffer
def init_type_params(self, ctx, *args, **kwargs): init_method = copy.copy(self) for idx, t_param in enumerate(init_method.type_params): arg = ctx.resolve_type(args[idx]) init_method.type_ctx[t_param] = arg return init_method
def init_type_params(self, context, *args, **kwargs): init_method = copy.copy(self) for idx, t_param in enumerate(init_method.type_params): arg = resolve_type(context, args[idx]) init_method.type_context[t_param] = arg return init_method
def init_type_params(self, _ctx, *args, **kwargs): init_package = copy.copy(self) for idx, t_param in enumerate(init_package.type_params): init_package.type_ctx[t_param] = args[idx] return init_package