@@ -340,14 +340,67 @@ impl<'f> Context<'f> {
340
340
self . insert_instruction_with_typevars ( enable_side_effects, None ) ;
341
341
}
342
342
343
- /// Merge two values a and b from separate basic blocks to a single value. This
344
- /// function would return the result of `if c { a } else { b }` as `c*a + (!c)*b`.
343
+ /// Merge two values a and b from separate basic blocks to a single value.
344
+ /// If these two values are numeric, the result will be
345
+ /// `then_condition * then_value + else_condition * else_value`.
346
+ /// Otherwise, if the values being merged are arrays, a new array will be made
347
+ /// recursively from combining each element of both input arrays.
348
+ ///
349
+ /// It is currently an error to call this function on reference or function values
350
+ /// as it is less clear how to merge these.
345
351
fn merge_values (
346
352
& mut self ,
347
353
then_condition : ValueId ,
348
354
else_condition : ValueId ,
349
355
then_value : ValueId ,
350
356
else_value : ValueId ,
357
+ ) -> ValueId {
358
+ match self . inserter . function . dfg . type_of_value ( then_value) {
359
+ Type :: Numeric ( _) => {
360
+ self . merge_numeric_values ( then_condition, else_condition, then_value, else_value)
361
+ }
362
+ Type :: Array ( element_types, len) => {
363
+ let mut merged = im:: Vector :: new ( ) ;
364
+
365
+ for i in 0 ..len {
366
+ for ( element_index, element_type) in element_types. iter ( ) . enumerate ( ) {
367
+ let index = ( ( i * element_types. len ( ) + element_index) as u128 ) . into ( ) ;
368
+ let index = self . inserter . function . dfg . make_constant ( index, Type :: field ( ) ) ;
369
+
370
+ let typevars = Some ( vec ! [ element_type. clone( ) ] ) ;
371
+
372
+ let mut get_element = |array, typevars| {
373
+ let get = Instruction :: ArrayGet { array, index } ;
374
+ self . insert_instruction_with_typevars ( get, typevars) . first ( )
375
+ } ;
376
+
377
+ let then_element = get_element ( then_value, typevars. clone ( ) ) ;
378
+ let else_element = get_element ( else_value, typevars) ;
379
+
380
+ merged. push_back ( self . merge_values (
381
+ then_condition,
382
+ else_condition,
383
+ then_element,
384
+ else_element,
385
+ ) ) ;
386
+ }
387
+ }
388
+
389
+ self . inserter . function . dfg . make_array ( merged, element_types)
390
+ }
391
+ Type :: Reference => panic ! ( "Cannot return references from an if expression" ) ,
392
+ Type :: Function => panic ! ( "Cannot return functions from an if expression" ) ,
393
+ }
394
+ }
395
+
396
+ /// Merge two numeric values a and b from separate basic blocks to a single value. This
397
+ /// function would return the result of `if c { a } else { b }` as `c*a + (!c)*b`.
398
+ fn merge_numeric_values (
399
+ & mut self ,
400
+ then_condition : ValueId ,
401
+ else_condition : ValueId ,
402
+ then_value : ValueId ,
403
+ else_value : ValueId ,
351
404
) -> ValueId {
352
405
let block = self . inserter . function . entry_block ( ) ;
353
406
let mul = Instruction :: binary ( BinaryOp :: Mul , then_condition, then_value) ;
0 commit comments