Skip to content

Commit

Permalink
Compiler: micro-optimizations in merge_if_vars (#12432)
Browse files Browse the repository at this point in the history
* Don't create `MetaVar` unless needed

* Make check earlier to avoid extra Hash lookups

* Even less extra Hash lookups

* Compiler: avoid creating Set in merge_if_vars (#12433)
  • Loading branch information
asterite authored Sep 5, 2022
1 parent 8b801a5 commit 67fea7d
Showing 1 changed file with 66 additions and 63 deletions.
129 changes: 66 additions & 63 deletions src/compiler/crystal/semantic/main_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1887,85 +1887,88 @@ module Crystal
# - Don't use the type of a branch that is unreachable (ends with return,
# break or with a call that is NoReturn)
def merge_if_vars(node, cond_vars, then_vars, else_vars, before_then_vars, before_else_vars, then_unreachable, else_unreachable)
all_vars_names = Set(String).new
then_vars.each_key do |name|
all_vars_names << name
end
else_vars.each_key do |name|
all_vars_names << name
then_vars.each do |name, then_var|
else_var = else_vars[name]?

merge_if_var(name, node, cond_vars, then_var, else_var, before_then_vars, before_else_vars, then_unreachable, else_unreachable)
end

all_vars_names.each do |name|
cond_var = cond_vars[name]?
then_var = then_vars[name]?
before_then_var = before_then_vars[name]?
else_var = else_vars[name]?
before_else_var = before_else_vars[name]?
else_vars.each do |name, else_var|
next if then_vars.has_key?(name)

# Check whether the var didn't change at all
next if then_var.same?(else_var)
merge_if_var(name, node, cond_vars, nil, else_var, before_then_vars, before_else_vars, then_unreachable, else_unreachable)
end
end

if_var = MetaVar.new(name)
def merge_if_var(name, node, cond_vars, then_var, else_var, before_then_vars, before_else_vars, then_unreachable, else_unreachable)
# Check whether the var didn't change at all
return if then_var.same?(else_var)

# Only copy `nil_if_read` from each branch if it's not unreachable
then_var_nil_if_read = !then_unreachable && then_var.try(&.nil_if_read?)
else_var_nil_if_read = !else_unreachable && else_var.try(&.nil_if_read?)
cond_var = cond_vars[name]?

if_var.nil_if_read = !!(then_var_nil_if_read || else_var_nil_if_read)
# Only copy `nil_if_read` from each branch if it's not unreachable
then_var_nil_if_read = !then_unreachable && then_var.try(&.nil_if_read?)
else_var_nil_if_read = !else_unreachable && else_var.try(&.nil_if_read?)
if_var_nil_if_read = !!(then_var_nil_if_read || else_var_nil_if_read)

# Check if no types were changes in either then 'then' and 'else' branches
if cond_var && then_var.same?(before_then_var) && else_var.same?(before_else_var) && !then_unreachable && !else_unreachable
cond_var.nil_if_read = if_var.nil_if_read?
# Check if no types were changes in either then 'then' and 'else' branches
if cond_var && !then_unreachable && !else_unreachable
if then_var.same?(before_then_vars[name]?) &&
else_var.same?(before_else_vars[name]?)
cond_var.nil_if_read = if_var_nil_if_read
@vars[name] = cond_var
next
return
end
end

if then_var && else_var
if then_unreachable
if_var.bind_to conditional_no_return(node.then, then_var)
else
if_var.bind_to then_var
end
if_var = MetaVar.new(name)
if_var.nil_if_read = if_var_nil_if_read

if else_unreachable
if_var.bind_to conditional_no_return(node.else, else_var)
else
if_var.bind_to else_var
end
elsif then_var
if then_unreachable
if_var.bind_to conditional_no_return(node.then, then_var)
else
if_var.bind_to then_var
end
if then_var && else_var
if then_unreachable
if_var.bind_to conditional_no_return(node.then, then_var)
else
if_var.bind_to then_var
end

if cond_var
if_var.bind_to cond_var
elsif !else_unreachable
if_var.bind_to program.nil_var
if_var.nil_if_read = true
else
if_var.bind_to conditional_no_return(node.else, @program.nil_var)
end
elsif else_var
if else_unreachable
if_var.bind_to conditional_no_return(node.else, else_var)
else
if_var.bind_to else_var
end
if else_unreachable
if_var.bind_to conditional_no_return(node.else, else_var)
else
if_var.bind_to else_var
end
elsif then_var
if then_unreachable
if_var.bind_to conditional_no_return(node.then, then_var)
else
if_var.bind_to then_var
end

if cond_var
if_var.bind_to cond_var
elsif !then_unreachable
if_var.bind_to program.nil_var
if_var.nil_if_read = true
else
if_var.bind_to conditional_no_return(node.then, @program.nil_var)
end
if cond_var
if_var.bind_to cond_var
elsif !else_unreachable
if_var.bind_to program.nil_var
if_var.nil_if_read = true
else
if_var.bind_to conditional_no_return(node.else, @program.nil_var)
end
elsif else_var
if else_unreachable
if_var.bind_to conditional_no_return(node.else, else_var)
else
if_var.bind_to else_var
end

@vars[name] = if_var
if cond_var
if_var.bind_to cond_var
elsif !then_unreachable
if_var.bind_to program.nil_var
if_var.nil_if_read = true
else
if_var.bind_to conditional_no_return(node.then, @program.nil_var)
end
end

@vars[name] = if_var
end

def conditional_no_return(node, var)
Expand Down

0 comments on commit 67fea7d

Please sign in to comment.