Class: Idl::AryElementAssignmentAst
- Includes:
- Executable
- Defined in:
- lib/idlc/ast.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/gen_adoc.rb,
lib/idlc/passes/find_src_registers.rb
Overview
represents an array element assignment
for example:
X[rs1] = XLEN'd0
Constant Summary
Constants inherited from AstNode
Idl::AstNode::Bits1Type, Idl::AstNode::Bits32Type, Idl::AstNode::Bits64Type, Idl::AstNode::BoolType, Idl::AstNode::ConstBoolType, Idl::AstNode::PossiblyUnknownBits1Type, Idl::AstNode::PossiblyUnknownBits32Type, Idl::AstNode::PossiblyUnknownBits64Type, Idl::AstNode::ReachableFunctionCacheType, Idl::AstNode::StringType, Idl::AstNode::VoidType
Instance Attribute Summary
Attributes inherited from AstNode
#children, #input, #interval, #parent
Class Method Summary collapse
Instance Method Summary collapse
- #const_eval?(symtab) ⇒ Boolean
-
#execute(symtab) ⇒ void
“execute” the statement by updating the variables in the symbol table.
- #find_dst_registers(symtab) ⇒ Object
- #gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object
- #idx ⇒ Object
-
#initialize(input, interval, lhs, idx, rhs) ⇒ AryElementAssignmentAst
constructor
A new instance of AryElementAssignmentAst.
- #lhs ⇒ Object
- #nullify_assignments(symtab) ⇒ Object
- #prune(symtab, forced_type: nil) ⇒ Object
- #rhs ⇒ Object
- #to_h ⇒ Object
- #to_idl ⇒ Object
-
#type_check(symtab, strict:) ⇒ void
type check this node and all children.
Methods included from Executable
Methods inherited from AstNode
#always_terminates?, #declaration?, #executable?, extract_base_var_name, #find_ancestor, #find_referenced_csrs, #find_src_registers, #freeze_tree, #gen_option_adoc, #input_file, input_from_source_yaml, #inspect, #internal_error, interval_from_source_yaml, #lineno, #lines_around, #pass_find_return_values, #path, #print_ast, #reachable_exceptions, #reachable_functions, #set_input_file, #set_input_file_unless_already_set, #source_line_file_offsets, #source_starting_offset, #source_yaml, #starting_line, #text_value, #truncation_warn, #type_error, #unindent, value_else, #value_else, value_error, #value_error, value_try, #value_try, write_back_nested
Constructor Details
#initialize(input, interval, lhs, idx, rhs) ⇒ AryElementAssignmentAst
Returns a new instance of AryElementAssignmentAst.
2952 2953 2954 |
# File 'lib/idlc/ast.rb', line 2952 def initialize(input, interval, lhs, idx, rhs) super(input, interval, [lhs, idx, rhs]) end |
Class Method Details
.from_h(yaml, source_mapper) ⇒ Object
3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 |
# File 'lib/idlc/ast.rb', line 3036 def self.from_h(yaml, source_mapper) raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "array_element_assignment" input = input_from_source_yaml(yaml.fetch("source"), source_mapper) interval = interval_from_source_yaml(yaml.fetch("source")) AryElementAssignmentAst.new( input, interval, T.cast(AstNode.from_h(yaml.fetch("array"), source_mapper), RvalueAst), T.cast(AstNode.from_h(yaml.fetch("index"), source_mapper), RvalueAst), T.cast(AstNode.from_h(yaml.fetch("value"), source_mapper), RvalueAst) ) end |
Instance Method Details
#const_eval?(symtab) ⇒ Boolean
2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 |
# File 'lib/idlc/ast.rb', line 2932 def const_eval?(symtab) return false if !lhs.const_eval?(symtab) if idx.const_eval?(symtab) && rhs.const_eval?(symtab) true else base_name = AstNode.extract_base_var_name(lhs) type_error "Cannot determine base variable for #{lhs.text_value}" if base_name.nil? lhs_var = symtab.get(base_name) type_error "array #{base_name} has not been declared" if lhs_var.nil? lhs_var.const_incompatible! false end end |
#execute(symtab) ⇒ void
This method returns an undefined value.
“execute” the statement by updating the variables in the symbol table
2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 |
# File 'lib/idlc/ast.rb', line 2991 def execute(symtab) lhs_type = lhs.type(symtab) return if lhs_type.global? case lhs_type.kind when :array idx_value = idx.value(symtab) lhs_value = lhs.value(symtab) value_result = value_try do lhs_value[idx_value] = rhs.value(symtab) end value_else(value_result) do lhs_value[idx_value] = nil value_error "right-hand side of array element assignment is unknown" end when :bits value_result = value_try do new_element = (lhs.value(symtab) & ~0) | ((rhs.value(symtab) & 1) << idx.value(symtab)) AstNode.write_back_nested(lhs, new_element, symtab) end value_else(value_result) do base_name = T.must(AstNode.extract_base_var_name(lhs)) v = symtab.get(base_name) internal_error "did not find array base '#{base_name}'" if v.nil? v.value = nil end else internal_error "unexpected type for array element assignment" end end |
#find_dst_registers(symtab) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/idlc/passes/find_src_registers.rb', line 108 def find_dst_registers(symtab) # Identify the base variable and the register index based on assignment shape. # F[rd] = v → lhs is IdAst(F), reg_idx = idx # F[rd][b] = v → lhs is AryElementAccessAst(F[rd]), reg_idx = lhs.index lhs_base, reg_idx = if lhs.is_a?(Idl::IdAst) [lhs, idx] elsif lhs.is_a?(Idl::AryElementAccessAst) && lhs.var.is_a?(Idl::IdAst) [lhs.var, lhs.index] else return [] end # Only proceed if the base variable is a global array of RegFileElementType. var_type = lhs_base.type(symtab) rescue nil return [] unless var_type&.kind == :array && var_type.sub_type.is_a?(RegFileElementType) && var_type.qualifiers.include?(:global) rf_name = var_type.sub_type.name value_result = value_try do return [[rf_name, reg_idx.value(symtab)]] end value_else(value_result) do if reg_idx.type(symtab).const? return [[rf_name, reg_idx.gen_cpp(symtab, 0)]] else raise ComplexRegDetermination end end end |
#gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object
258 259 260 |
# File 'lib/idlc/passes/gen_adoc.rb', line 258 def gen_adoc(indent = 0, indent_spaces: 2) "#{' ' * indent}#{lhs.gen_adoc(0, indent_spaces:)}[#{idx.gen_adoc(0, indent_spaces:)}] = #{rhs.gen_adoc(0, indent_spaces:)}" end |
#idx ⇒ Object
2949 |
# File 'lib/idlc/ast.rb', line 2949 def idx = @children[1] |
#lhs ⇒ Object
2948 |
# File 'lib/idlc/ast.rb', line 2948 def lhs = @children[0] |
#nullify_assignments(symtab) ⇒ Object
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/idlc/passes/prune.rb', line 145 def nullify_assignments(symtab) case lhs.type(symtab).kind when :array value_result = value_try do lhs_value = lhs.value(symtab) value_result2 = value_try do lhs_value[idx.value(symtab)] = nil end value_else(value_result2) do # index unknown: nullify entire array lhs_value.map! { |_v| nil } end end value_else(value_result) do # array var itself is unknown; nothing more to do end when :bits root = lhs root = root.var while root.is_a?(AryElementAccessAst) || root.is_a?(AryRangeAccessAst) var = symtab.get(root.name) var.value = nil unless var.nil? end end |
#prune(symtab, forced_type: nil) ⇒ Object
898 899 900 901 902 903 904 905 906 907 908 909 910 |
# File 'lib/idlc/passes/prune.rb', line 898 def prune(symtab, forced_type: nil) new_ast = AryElementAssignmentAst.new( input, interval, lhs.dup, idx.prune(symtab), rhs.prune(symtab) ) value_try do new_ast.execute(symtab) end # value_else: execute already sets nil on failure, nothing more to do new_ast end |
#rhs ⇒ Object
2950 |
# File 'lib/idlc/ast.rb', line 2950 def rhs = @children[2] |
#to_h ⇒ Object
3027 3028 3029 3030 3031 3032 3033 |
# File 'lib/idlc/ast.rb', line 3027 def to_h = { "kind" => "array_element_assignment", "array" => lhs.to_h, "index" => idx.to_h, "value" => rhs.to_h, "source" => source_yaml } |
#to_idl ⇒ Object
3024 |
# File 'lib/idlc/ast.rb', line 3024 def to_idl = "#{lhs.to_idl}[#{idx.to_idl}] = #{rhs.to_idl}" |
#type_check(symtab, strict:) ⇒ void
This method returns an undefined value.
type check this node and all children
Calls to #type and/or #value may depend on type_check being called first with the same symtab. If not, those functions may raise an AstNode::InternalError
2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 |
# File 'lib/idlc/ast.rb', line 2957 def type_check(symtab, strict:) lhs.type_check(symtab, strict:) unless [:array, :bits].include?(lhs.type(symtab).kind) type_error "#{lhs.text_value} must be an array or an integral type" end type_error "Assigning to a constant" if lhs.type(symtab).const? idx.type_check(symtab, strict:) type_error "Index must be integral" unless idx.type(symtab).integral? value_result = value_try do idx_value = idx.value(symtab) type_error "Array index (#{idx.text_value} = #{idx_value}) out of range (< #{lhs.type(symtab).width})" if idx_value >= lhs.type(symtab).width end # OK, doesn't need to be known rhs.type_check(symtab, strict:) case lhs.type(symtab).kind when :array unless rhs.type(symtab).convertable_to?(lhs.type(symtab).sub_type) type_error "Incompatible type in array assignment" end when :bits unless rhs.type(symtab).convertable_to?(Bits1Type) type_error "Incompatible type in integer slice assignment" end else internal_error "Unexpected type on array element assignment" end end |