gccrs icon indicating copy to clipboard operation
gccrs copied to clipboard

hir: Compile `MatchExpr` to if statements

Open goar5670 opened this issue 2 years ago • 5 comments

The main purpose of this commit is to refactor the old switch-based logic we had for compiling match expressions and use an if-statement-based approach.

So, naturally, the old logic was removed in this commit. That includes sort_tuple_patterns, simplify_tuple_match, PatternMerge and patterns_mergeable.

In the new approach, each arm is transformed into an if statement. And for any if statement, there are two main components: the condition and the then_block.

The entity responsible for handling the condition is CompileMatchArmCondition. It's a class that traverses down the arm pattern and the match scrutinee expression simultaneously. Whenever it meets a base-case in the pattern (i.e. expression or identifier but identifiers are not handled for now), it takes the respective field of the scrutinee and returns a backend comparison expression for them.

As for the then_block, it's compiled by SimplifyMatchExpr::compile_case_expr. This function transforms the HIR::Expr match case final expression into a backend block so it can be used easily inside the if_statement. In case the expr is of type BlockExpr, then we can easily compile it using CompileBlock::compile. Otherwise, we'll have to create a new block and add the expression as a statement.

Now we have the means of creating the if statements. All that's left is to glue the multiple match arms (if_statements) together, and that's where SimplifyMatchExpr::simplify_remaining_cases comes in. It compiles the condition and then_block with the help of the functions mentioned earlier. As for the else_block, it should contain the if_statements for the remaining match arms. So simplify_remaining_cases calculates the else_block recursively by calling itself. After that it returns the compiled if_statement with the condition, then_block, and else_block.

goar5670 avatar Mar 18 '23 19:03 goar5670

@philberty do you have any idea why it's failing? I think it's overflowing somewhere but I can't figure it out.

goar5670 avatar Mar 20 '23 11:03 goar5670

For reference this is the assert that fails:

template <typename storage>
inline wi::storage_ref
wi::int_traits < generic_wide_int <storage> >::
decompose (HOST_WIDE_INT *, unsigned int precision,
	   const generic_wide_int <storage> &x)
{
  gcc_checking_assert (precision == x.get_precision ());
  return wi::storage_ref (x.get_val (), x.get_len (), precision);
}

CohenArthur avatar Mar 21 '23 09:03 CohenArthur

Btw, this implementation also handles the path-to-tuple scrutinee and nested tuples. Added tests for that.

goar5670 avatar Apr 01 '23 18:04 goar5670

@goar5670 are you still working on this? No pressure/implied obligation intended

powerboat9 avatar Jun 03 '23 14:06 powerboat9

I think we should think about finishing this work off soon. GCC auto optimizes cases to switch blocks too and lets not worry about pattern exhaustiveness checks for now.

philberty avatar Sep 14 '23 21:09 philberty