Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better handling of function call symbol tables #3

Merged
merged 1 commit into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cfgs/generic_rv64/arch_overlay/csr/marchid.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
marchid:
fields:
Architecture:
reset_value: 0xcafebabe
description: My custom description.
31 changes: 22 additions & 9 deletions lib/arch_def.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ def type
parent: "#{csr.name}.#{name}"
)

sym_table.push # for consistency with template functions

begin
case ast.return_value(sym_table)
when 0
Expand All @@ -148,6 +150,8 @@ def type
warn "In parsing #{csr.name}.#{name}::type()"
warn " Return of type() function cannot be evaluated at compile time"
raise e
ensure
sym_table.pop
end
end
end
Expand Down Expand Up @@ -218,13 +222,20 @@ def reset_value_func
def reset_value
return @reset_value unless @reset_value.nil?

@reset_value =
if @data.key?("reset_value")
@data["reset_value"]
else
puts "evaluating #{name}"
reset_value_func.return_value(arch_def.sym_table)
end
symtab = arch_def.sym_table

symtab.push # for consistency with template functions

begin
@reset_value =
if @data.key?("reset_value")
@data["reset_value"]
else
reset_value_func.return_value(arch_def.sym_table)
end
ensure
symtab.pop
end
end

# @param effective_xlen [Integer] The effective xlen, needed since some fields change location with XLEN. If the field location is not determined by XLEN, then this parameter can be nil
Expand Down Expand Up @@ -385,7 +396,6 @@ def length(effective_xlen = nil)

effective_xlen
else
puts arch_def.implemented_csrs.map { |c| c.name }
raise "CSR #{name} is not implemented" if arch_def.implemented_csrs.none? { |c| c.name == name }
raise "CSR #{name} is not implemented" if arch_def.config_params["SXLEN"].nil?

Expand Down Expand Up @@ -1213,6 +1223,9 @@ class ArchDef
# @return [Idl::Compiler] The IDL compiler
attr_reader :idl_compiler

# @return [Idl::AstNode] Abstract syntax tree of global scope
attr_reader :global_ast

# Initialize a new configured architecture defintiion
#
# @params config_name [#to_s] The name of a configuration, which must correspond
Expand All @@ -1237,7 +1250,7 @@ def initialize(config_name)
@idl_compiler = Idl::Compiler.new(self)

# load the globals into the symbol table
@idl_compiler.compile_file(
@global_ast = @idl_compiler.compile_file(
$root / "arch" / "isa" / "globals.isa",
@sym_table
)
Expand Down
137 changes: 50 additions & 87 deletions lib/idl/ast.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,6 @@ def has_template_ancestor?
# @return [Boolean] whether or not this SyntaxNode represents a function name (overriden in the parser)
def is_function_name? = false

# @return [Boolean] whether or not this SyntaxNode is being parsed as a template argument
# without being enclosed in parenthesis
def parsing_in_template?
# since this is called in the middle of parsing, the parent pointer hasn't been set up yet
puts self.class.ancestors
puts "text = #{text_value}"
puts parent.class.name
exit
if parent.nil?
nil
elsif parent.is_a?(ParenExpressionAst)
false # once we hit a paren expression, we are cleared
elsif parent.is_a?(BitsTypeAst)
puts "FOund bits!!"
true # must be the expression on the BitsType
else
parent.parsing_in_template?
end
end

# Fix up left recursion for the PEG
#
# This is the default for anything that isn't a left-recursive binary op
Expand Down Expand Up @@ -442,7 +422,6 @@ class GlobalWithInitializationAst < AstNode
include Executable

def type_check(symtab)
puts "global #{text_value}"
single_declaration_with_initialization.type_check(symtab)
end

Expand Down Expand Up @@ -942,11 +921,15 @@ def rhs
end

def execute(symtab)
var = symtab.get(var.text_value)
if var.is_a?(CsrWriteAst)
value_error "CSR writes are never compile-time-known"
else
variable = symtab.get(var.text_value)

internal_error "Call type check first" if var.nil?
internal_error "No variable #{var.text_value}" if variable.nil?

var.value = rval.value(symtab)
variable.value = rval.value(symtab)
end
end

# @!macro to_idl
Expand Down Expand Up @@ -1209,7 +1192,7 @@ def type_check(symtab)
end

def execute(symtab)
values = functin_call.execute(symtab)
values = function_call.execute(symtab)

i = 0
vars.each do |v|
Expand Down Expand Up @@ -1520,7 +1503,9 @@ def value(symtab)
element_name = expression.text_value.split(":")[2]
etype.enum_class.value(element_name)
when :csr
internal_error "TODO"
expression.value(symtab)
else
internal_error "TODO: Bits cast for #{etype.kind}"
end
end

Expand Down Expand Up @@ -2334,7 +2319,21 @@ def expected_return_type(symtab)

symtab.get("__expected_return_type")
else
func_def.return_type(symtab)
# need to find the type to get the right symbol table
func_type = symtab.get_global(func_def.name)
internal_error "Couldn't find function type for '#{func_def.name}' #{symtab.keys} " if func_type.nil?

# to get the return type, we need to find the template values in case this is
# a templated function definition
#
# that information should be up the stack in the symbol table
template_values = symtab.find_all(single_scope: true) do |o|
o.is_a?(Var) && o.template_value_for?(func_def.name)
end
unless template_values.size == func_type.template_names.size
internal_error "Did not find correct number of template arguments (found #{template_values.size}, need #{func_type.template_names.size}) #{symtab.keys_pretty}"
end
func_type.return_type(template_values.sort { |a, b| a.template_index <=> b.template_index }.map(&:value))
end
end

Expand Down Expand Up @@ -2622,7 +2621,7 @@ def type_check(symtab)
end
end

if func_def_type.return_type(template_values(symtab), arg_nodes, symtab).nil?
if func_def_type.return_type(template_values(symtab)).nil?
internal_error "No type determined for function"
end

Expand All @@ -2632,12 +2631,13 @@ def type_check(symtab)
# @!macro type
def type(symtab)
func_def_type = symtab.get(name)
func_def_type.return_type(template_values(symtab), arg_nodes, symtab)
func_def_type.return_type(template_values(symtab))
end

# @!macro value
def value(symtab)
func_def_type = symtab.get(name)
type_error "not a function" unless func_def_type.is_a?(FunctionType)
if func_def_type.builtin?
if name == "implemented?"
extname = arg_nodes[0].text_value
Expand All @@ -2647,38 +2647,20 @@ def value(symtab)
end
end

symtab.push

begin
template_arg_nodes.each_with_index do |targ, idx|
targ_name = func_def_type.template_names[idx]
targ_type = func_def_type.template_types[idx]
symtab.add(targ_name, Var.new(targ_name, targ_type, targ.value(symtab)))
end

arg_nodes.each_with_index do |arg, idx|
arg_name = func_def_type.argument_name(idx, template_values(symtab))
arg_type = func_def_type.argument_type(idx, template_values(symtab), arg_nodes, symtab)
begin
symtab.add!(arg_name, Var.new(arg_name, arg_type, arg.value(symtab)))
rescue SymbolTable::DuplicateSymError
type_error "Argument '#{arg_name}' shadows another symbol (level = #{symtab.levels})"
end
end

v = func_def_type.body.return_value(symtab)
ensure
symtab.pop
template_values = []
template_arg_nodes.each_with_index do |targ, idx|
# targ_name = func_def_type.template_names[idx]
# targ_type = func_def_type.template_types[idx]
template_values << targ.value(symtab)
end

v
func_def_type.return_value(template_values, arg_nodes, symtab)
end
alias execute value

def name
function_name.text_value
end

end

# class ExecutionAst < AstNode
Expand Down Expand Up @@ -2747,11 +2729,13 @@ def statements

# @!macro type_check
def type_check(symtab)
internal_error "Function bodies should be at global + 1 scope" unless symtab.levels == 2

return_value_might_be_known = true

statements.each do |s|
s.type_check(symtab)
next if return_value_might_be_known
next unless return_value_might_be_known

begin
if s.is_a?(Returns)
Expand All @@ -2771,6 +2755,8 @@ def type_check(symtab)
#
# @note arguments and template arguments must be put on the symtab before calling
def return_value(symtab)
internal_error "Function bodies should be at global + 1 scope" unless symtab.levels == 2

# go through the statements, and return the first one that has a return value
statements.each do |s|
if s.is_a?(Returns)
Expand All @@ -2781,27 +2767,10 @@ def return_value(symtab)
end
end

internal_error "No function body statement returned a value"
value_error "No function body statement returned a value"
end
alias execute return_value

# @return [Array] An array of all possible return values
#
# @note arguments and template arguments must be put on the symtab before calling
def return_values(symtab)
# go through the statements, and find all return values
rts = []
statements.each do |s|
if s.is_a?(Returns)
rts += s.return_values(symtab)
else
s.execute(symtab)
end
end

rts
end

def to_idl
result = ""
# go through the statements, and return the first one that has a return value
Expand Down Expand Up @@ -2866,21 +2835,12 @@ def arguments_list_str
list
end

# return an array of all the return types, in order
# function (or template instance) must be resolved
def return_types(symtab)
t = return_type(symtab)
if t.kind == :tuple
t.tuple_types
elsif t.kind == :void
[]
else
[t]
end
end

# return the return type, which may be a tuple of multiple types
def return_type(symtab)
unless symtab.levels == 2
internal_error "Function bodies should be at global + 1 scope (at global + #{symtab.levels - 1})"
end

if templated?
template_names.each do |tname|
internal_error "Template values missing" unless symtab.get(tname)
Expand Down Expand Up @@ -2930,6 +2890,8 @@ def name

# @param [Array<Integer>] template values to apply
def type_check_template_instance(symtab)
internal_error "Function definitions should be at global + 1 scope" unless symtab.levels == 2

internal_error "Not a template function" unless templated?

template_names.each do |tname|
Expand All @@ -2945,6 +2907,8 @@ def type_check_template_instance(symtab)
# uncalled functions, which avoids dealing with mentions of CSRs that
# may not exist in a given implmentation
def type_check_from_call(symtab)
internal_error "Function definitions should be at global + 1 scope" unless symtab.levels == 2

global_scope = symtab.deep_clone
global_scope.pop while global_scope.levels != 1

Expand All @@ -2965,7 +2929,7 @@ def type_check(symtab)
def_type = FunctionType.new(
name,
self,
symtab.deep_clone
symtab
)

# recursion isn't supported (doesn't map well to hardware), so we can add the function after type checking the body
Expand Down Expand Up @@ -3104,7 +3068,6 @@ def return_value(symtab)
v = s.s.return_value(symtab)
unless v.nil?
symtab.pop
puts "value = #{v}"
return v
end
else
Expand Down
Loading
Loading