Skip to content

Commit 89c9f7e

Browse files
authored
[mlir][emitc] Inline expressions with side-effects (llvm#161356)
So far the translator only inlined expressions having no side effects, as rescheduling their evaluation doesn't break semantics. This patch adds inlining of expressions containing side effects if defined just before their use, e.g., ```mlir %c = emitc.expression %a, %b : (i32, !emitc.ptr<i32>) -> i32 { %e = emitc.sub %a, %b : (!emitc.ptr<i32>, i32) -> !emitc.ptr<i32> %d = emitc.apply "*"(%e) : (!emitc.ptr<i32>) -> i32 emitc.yield %d : i32 } emitc.return %c : i32 ``` This restriction is meant to keep the translator as simple as possible, leaving it to transformations to analyze and reorder ops as needed in more complicated cases. The patch handles inlining into `emitc.return`, `emitc.if`, `emitc.switch` and (to some extent) `emitc.assign`.
1 parent 1389980 commit 89c9f7e

File tree

2 files changed

+240
-26
lines changed

2 files changed

+240
-26
lines changed

mlir/lib/Target/Cpp/TranslateToCpp.cpp

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -357,11 +357,6 @@ static bool shouldBeInlined(ExpressionOp expressionOp) {
357357
if (expressionOp.getDoNotInline())
358358
return false;
359359

360-
// Do not inline expressions with side effects to prevent side-effect
361-
// reordering.
362-
if (expressionOp.hasSideEffects())
363-
return false;
364-
365360
// Do not inline expressions with multiple uses.
366361
Value result = expressionOp.getResult();
367362
if (!result.hasOneUse())
@@ -377,7 +372,34 @@ static bool shouldBeInlined(ExpressionOp expressionOp) {
377372
// Do not inline expressions used by other expressions or by ops with the
378373
// CExpressionInterface. If this was intended, the user could have been merged
379374
// into the expression op.
380-
return !isa<emitc::ExpressionOp, emitc::CExpressionInterface>(*user);
375+
if (isa<emitc::ExpressionOp, emitc::CExpressionInterface>(*user))
376+
return false;
377+
378+
// Expressions with no side-effects can safely be inlined.
379+
if (!expressionOp.hasSideEffects())
380+
return true;
381+
382+
// Expressions with side-effects can be only inlined if side-effect ordering
383+
// in the program is provably retained.
384+
385+
// Require the user to immediately follow the expression.
386+
if (++Block::iterator(expressionOp) != Block::iterator(user))
387+
return false;
388+
389+
// These single-operand ops are safe.
390+
if (isa<emitc::IfOp, emitc::SwitchOp, emitc::ReturnOp>(user))
391+
return true;
392+
393+
// For assignment look for specific cases to inline as evaluation order of
394+
// its lvalue and rvalue is undefined in C.
395+
if (auto assignOp = dyn_cast<emitc::AssignOp>(user)) {
396+
// Inline if this assignment is of the form `<var> = <expression>`.
397+
if (expressionOp.getResult() == assignOp.getValue() &&
398+
isa_and_present<VariableOp>(assignOp.getVar().getDefiningOp()))
399+
return true;
400+
}
401+
402+
return false;
381403
}
382404

383405
static LogicalResult printConstantOp(CppEmitter &emitter, Operation *operation,

mlir/test/Target/Cpp/expressions.mlir

Lines changed: 212 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -315,16 +315,13 @@ func.func @different_expressions(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32)
315315
}
316316

317317
// CPP-DEFAULT: int32_t expression_with_dereference(int32_t [[VAL_1:v[0-9]+]], int32_t* [[VAL_2]]) {
318-
// CPP-DEFAULT-NEXT: int32_t [[VAL_3:v[0-9]+]] = *([[VAL_2]] - [[VAL_1]]);
319-
// CPP-DEFAULT-NEXT: return [[VAL_3]];
318+
// CPP-DEFAULT-NEXT: return *([[VAL_2]] - [[VAL_1]]);
320319
// CPP-DEFAULT-NEXT: }
321320

322321
// CPP-DECLTOP: int32_t expression_with_dereference(int32_t [[VAL_1:v[0-9]+]], int32_t* [[VAL_2]]) {
323-
// CPP-DECLTOP-NEXT: int32_t [[VAL_3:v[0-9]+]];
324-
// CPP-DECLTOP-NEXT: [[VAL_3]] = *([[VAL_2]] - [[VAL_1]]);
325-
// CPP-DECLTOP-NEXT: return [[VAL_3]];
322+
// CPP-DECLTOP-NEXT: return *([[VAL_2]] - [[VAL_1]]);
326323
// CPP-DECLTOP-NEXT: }
327-
func.func @expression_with_dereference(%arg1: i32, %arg2: !emitc.ptr<i32>) -> i32 {
324+
emitc.func @expression_with_dereference(%arg1: i32, %arg2: !emitc.ptr<i32>) -> i32 {
328325
%c = emitc.expression %arg1, %arg2 : (i32, !emitc.ptr<i32>) -> i32 {
329326
%e = emitc.sub %arg2, %arg1 : (!emitc.ptr<i32>, i32) -> !emitc.ptr<i32>
330327
%d = emitc.apply "*"(%e) : (!emitc.ptr<i32>) -> i32
@@ -384,19 +381,16 @@ func.func @expression_with_subscript_user(%arg0: !emitc.ptr<!emitc.opaque<"void"
384381
// CPP-DEFAULT: bool expression_with_load(int32_t [[VAL_1:v.+]], int32_t [[VAL_2:v.+]], int32_t* [[VAL_3:v.+]]) {
385382
// CPP-DEFAULT-NEXT: int64_t [[VAL_4:v.+]] = 0;
386383
// CPP-DEFAULT-NEXT: int32_t [[VAL_5:v.+]] = 42;
387-
// CPP-DEFAULT-NEXT: bool [[VAL_6:v.+]] = [[VAL_5]] + [[VAL_2]] < [[VAL_3]][[[VAL_4]]] + [[VAL_1]];
388-
// CPP-DEFAULT-NEXT: return [[VAL_6]];
384+
// CPP-DEFAULT-NEXT: return [[VAL_5]] + [[VAL_2]] < [[VAL_3]][[[VAL_4]]] + [[VAL_1]];
389385

390386
// CPP-DECLTOP: bool expression_with_load(int32_t [[VAL_1:v.+]], int32_t [[VAL_2:v.+]], int32_t* [[VAL_3:v.+]]) {
391387
// CPP-DECLTOP-NEXT: int64_t [[VAL_4:v.+]];
392388
// CPP-DECLTOP-NEXT: int32_t [[VAL_5:v.+]];
393-
// CPP-DECLTOP-NEXT: bool [[VAL_6:v.+]];
394389
// CPP-DECLTOP-NEXT: [[VAL_4]] = 0;
395390
// CPP-DECLTOP-NEXT: [[VAL_5]] = 42;
396-
// CPP-DECLTOP-NEXT: [[VAL_6]] = [[VAL_5]] + [[VAL_2]] < [[VAL_3]][[[VAL_4]]] + [[VAL_1]];
397-
// CPP-DECLTOP-NEXT: return [[VAL_6]];
391+
// CPP-DECLTOP-NEXT: return [[VAL_5]] + [[VAL_2]] < [[VAL_3]][[[VAL_4]]] + [[VAL_1]];
398392

399-
func.func @expression_with_load(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr<i32>) -> i1 {
393+
emitc.func @expression_with_load(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr<i32>) -> i1 {
400394
%c0 = "emitc.constant"() {value = 0 : i64} : () -> i64
401395
%0 = "emitc.variable"() <{value = #emitc.opaque<"42">}> : () -> !emitc.lvalue<i32>
402396
%ptr = emitc.subscript %arg2[%c0] : (!emitc.ptr<i32>, i64) -> !emitc.lvalue<i32>
@@ -408,22 +402,19 @@ func.func @expression_with_load(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr<i32>)
408402
%e = emitc.cmp lt, %b, %d :(i32, i32) -> i1
409403
yield %e : i1
410404
}
411-
return %result : i1
405+
emitc.return %result : i1
412406
}
413407

414408
// CPP-DEFAULT: bool expression_with_load_and_call(int32_t* [[VAL_1:v.+]]) {
415409
// CPP-DEFAULT-NEXT: int64_t [[VAL_2:v.+]] = 0;
416-
// CPP-DEFAULT-NEXT: bool [[VAL_3:v.+]] = [[VAL_1]][[[VAL_2]]] + bar([[VAL_1]][[[VAL_2]]]) < [[VAL_1]][[[VAL_2]]];
417-
// CPP-DEFAULT-NEXT: return [[VAL_3]];
410+
// CPP-DEFAULT-NEXT: return [[VAL_1]][[[VAL_2]]] + bar([[VAL_1]][[[VAL_2]]]) < [[VAL_1]][[[VAL_2]]];
418411

419412
// CPP-DECLTOP: bool expression_with_load_and_call(int32_t* [[VAL_1:v.+]]) {
420413
// CPP-DECLTOP-NEXT: int64_t [[VAL_2:v.+]];
421-
// CPP-DECLTOP-NEXT: bool [[VAL_3:v.+]];
422414
// CPP-DECLTOP-NEXT: [[VAL_2]] = 0;
423-
// CPP-DECLTOP-NEXT: [[VAL_3]] = [[VAL_1]][[[VAL_2]]] + bar([[VAL_1]][[[VAL_2]]]) < [[VAL_1]][[[VAL_2]]];
424-
// CPP-DECLTOP-NEXT: return [[VAL_3]];
415+
// CPP-DECLTOP-NEXT: return [[VAL_1]][[[VAL_2]]] + bar([[VAL_1]][[[VAL_2]]]) < [[VAL_1]][[[VAL_2]]];
425416

426-
func.func @expression_with_load_and_call(%arg0: !emitc.ptr<i32>) -> i1 {
417+
emitc.func @expression_with_load_and_call(%arg0: !emitc.ptr<i32>) -> i1 {
427418
%c0 = "emitc.constant"() {value = 0 : i64} : () -> i64
428419
%ptr = emitc.subscript %arg0[%c0] : (!emitc.ptr<i32>, i64) -> !emitc.lvalue<i32>
429420
%result = emitc.expression %ptr : (!emitc.lvalue<i32>) -> i1 {
@@ -435,7 +426,7 @@ func.func @expression_with_load_and_call(%arg0: !emitc.ptr<i32>) -> i1 {
435426
%f = emitc.cmp lt, %e, %b :(i32, i32) -> i1
436427
yield %f : i1
437428
}
438-
return %result : i1
429+
emitc.return %result : i1
439430
}
440431

441432

@@ -458,3 +449,204 @@ emitc.func @expression_with_call_opaque_with_args_array(%0 : i32, %1 : i32) {
458449
}
459450
return
460451
}
452+
453+
// CPP-DEFAULT: void inline_side_effects_into_assign(int32_t [[VAL_1:v[0-9]+]], int32_t* [[VAL_2:v[0-9]+]]) {
454+
// CPP-DEFAULT-NEXT: int64_t [[VAL_3:v[0-9]+]] = 0;
455+
// CPP-DEFAULT-NEXT: int32_t [[VAL_4:v[0-9]+]] = 42;
456+
// CPP-DEFAULT-NEXT: [[VAL_4]] = [[VAL_4]] * [[VAL_1]] + [[VAL_2]][[[VAL_3]]];
457+
// CPP-DEFAULT-NEXT: return;
458+
// CPP-DEFAULT-NEXT: }
459+
460+
// CPP-DECLTOP: void inline_side_effects_into_assign(int32_t [[VAL_1:v[0-9]+]], int32_t* [[VAL_2:v[0-9]+]]) {
461+
// CPP-DECLTOP-NEXT: int64_t [[VAL_3:v[0-9]+]];
462+
// CPP-DECLTOP-NEXT: int32_t [[VAL_4:v[0-9]+]];
463+
// CPP-DECLTOP-NEXT: [[VAL_3]] = 0;
464+
// CPP-DECLTOP-NEXT: [[VAL_4]] = 42;
465+
// CPP-DECLTOP-NEXT: [[VAL_4]] = [[VAL_4]] * [[VAL_1]] + [[VAL_2]][[[VAL_3]]];
466+
// CPP-DECLTOP-NEXT: return;
467+
// CPP-DECLTOP-NEXT: }
468+
469+
emitc.func @inline_side_effects_into_assign(%arg0: i32, %arg1: !emitc.ptr<i32>) {
470+
%c0 = "emitc.constant"() {value = 0 : i64} : () -> i64
471+
%0 = "emitc.variable"() <{value = #emitc.opaque<"42">}> : () -> !emitc.lvalue<i32>
472+
%ptr = emitc.subscript %arg1[%c0] : (!emitc.ptr<i32>, i64) -> !emitc.lvalue<i32>
473+
%result = emitc.expression %arg0, %0, %ptr : (i32, !emitc.lvalue<i32>, !emitc.lvalue<i32>) -> i32 {
474+
%a = emitc.load %0 : !emitc.lvalue<i32>
475+
%b = emitc.mul %a, %arg0 : (i32, i32) -> i32
476+
%c = emitc.load %ptr : !emitc.lvalue<i32>
477+
%d = emitc.add %b, %c : (i32, i32) -> i32
478+
yield %d : i32
479+
}
480+
emitc.assign %result : i32 to %0 : !emitc.lvalue<i32>
481+
emitc.return
482+
}
483+
484+
// CPP-DEFAULT: void do_not_inline_side_effects_into_assign(int32_t [[VAL_1:v[0-9]+]], int32_t* [[VAL_2:v[0-9]+]]) {
485+
// CPP-DEFAULT-NEXT: int64_t [[VAL_3:v[0-9]+]] = 0;
486+
// CPP-DEFAULT-NEXT: int32_t [[VAL_4:v[0-9]+]] = 42;
487+
// CPP-DEFAULT-NEXT: int32_t [[VAL_5:v[0-9]+]] = [[VAL_4]] * [[VAL_1]];
488+
// CPP-DEFAULT-NEXT: [[VAL_2]][[[VAL_3]]] = [[VAL_5]];
489+
// CPP-DEFAULT-NEXT: return;
490+
// CPP-DEFAULT-NEXT: }
491+
492+
// CPP-DECLTOP: void do_not_inline_side_effects_into_assign(int32_t [[VAL_1:v[0-9]+]], int32_t* [[VAL_2:v[0-9]+]]) {
493+
// CPP-DECLTOP-NEXT: int64_t [[VAL_3:v[0-9]+]];
494+
// CPP-DECLTOP-NEXT: int32_t [[VAL_4:v[0-9]+]];
495+
// CPP-DECLTOP-NEXT: int32_t [[VAL_5:v[0-9]+]];
496+
// CPP-DECLTOP-NEXT: [[VAL_3]] = 0;
497+
// CPP-DECLTOP-NEXT: [[VAL_4]] = 42;
498+
// CPP-DECLTOP-NEXT: [[VAL_5:v[0-9]+]] = [[VAL_4]] * [[VAL_1]];
499+
// CPP-DECLTOP-NEXT: [[VAL_2]][[[VAL_3]]] = [[VAL_5]];
500+
// CPP-DECLTOP-NEXT: return;
501+
// CPP-DECLTOP-NEXT: }
502+
503+
emitc.func @do_not_inline_side_effects_into_assign(%arg0: i32, %arg1: !emitc.ptr<i32>) {
504+
%c0 = "emitc.constant"() {value = 0 : i64} : () -> i64
505+
%0 = "emitc.variable"() <{value = #emitc.opaque<"42">}> : () -> !emitc.lvalue<i32>
506+
%ptr = emitc.subscript %arg1[%c0] : (!emitc.ptr<i32>, i64) -> !emitc.lvalue<i32>
507+
%result = emitc.expression %arg0, %0 : (i32, !emitc.lvalue<i32>) -> i32 {
508+
%a = emitc.load %0 : !emitc.lvalue<i32>
509+
%b = emitc.mul %a, %arg0 : (i32, i32) -> i32
510+
yield %b : i32
511+
}
512+
emitc.assign %result : i32 to %ptr : !emitc.lvalue<i32>
513+
emitc.return
514+
}
515+
516+
// CPP-DEFAULT: int32_t do_not_inline_non_preceding_side_effects(int32_t [[VAL_1:v[0-9]+]], int32_t* [[VAL_2:v[0-9]+]]) {
517+
// CPP-DEFAULT-NEXT: int64_t [[VAL_3:v[0-9]+]] = 0;
518+
// CPP-DEFAULT-NEXT: int32_t [[VAL_4:v[0-9]+]] = 42;
519+
// CPP-DEFAULT-NEXT: int32_t [[VAL_5:v[0-9]+]] = [[VAL_4]] * [[VAL_1]];
520+
// CPP-DEFAULT-NEXT: [[VAL_2]][[[VAL_3]]] = [[VAL_1]];
521+
// CPP-DEFAULT-NEXT: return [[VAL_5]];
522+
// CPP-DEFAULT-NEXT: }
523+
524+
// CPP-DECLTOP: int32_t do_not_inline_non_preceding_side_effects(int32_t [[VAL_1:v[0-9]+]], int32_t* [[VAL_2:v[0-9]+]]) {
525+
// CPP-DECLTOP-NEXT: int64_t [[VAL_3:v[0-9]+]];
526+
// CPP-DECLTOP-NEXT: int32_t [[VAL_4:v[0-9]+]];
527+
// CPP-DECLTOP-NEXT: int32_t [[VAL_5:v[0-9]+]];
528+
// CPP-DECLTOP-NEXT: [[VAL_3:v[0-9]+]] = 0;
529+
// CPP-DECLTOP-NEXT: [[VAL_4:v[0-9]+]] = 42;
530+
// CPP-DECLTOP-NEXT: [[VAL_5:v[0-9]+]] = [[VAL_4]] * [[VAL_1]];
531+
// CPP-DECLTOP-NEXT: [[VAL_2]][[[VAL_3]]] = [[VAL_1]];
532+
// CPP-DECLTOP-NEXT: return [[VAL_5]];
533+
// CPP-DECLTOP-NEXT: }
534+
535+
emitc.func @do_not_inline_non_preceding_side_effects(%arg0: i32, %arg1: !emitc.ptr<i32>) -> i32 {
536+
%c0 = "emitc.constant"() {value = 0 : i64} : () -> i64
537+
%0 = "emitc.variable"() <{value = #emitc.opaque<"42">}> : () -> !emitc.lvalue<i32>
538+
%ptr = emitc.subscript %arg1[%c0] : (!emitc.ptr<i32>, i64) -> !emitc.lvalue<i32>
539+
%result = emitc.expression %arg0, %0 : (i32, !emitc.lvalue<i32>) -> i32 {
540+
%a = emitc.load %0 : !emitc.lvalue<i32>
541+
%b = emitc.mul %a, %arg0 : (i32, i32) -> i32
542+
yield %b : i32
543+
}
544+
emitc.assign %arg0 : i32 to %ptr : !emitc.lvalue<i32>
545+
emitc.return %result : i32
546+
}
547+
548+
// CPP-DEFAULT: int32_t inline_side_effects_into_if(int32_t [[VAL_1:v[0-9]+]], int32_t [[VAL_2:v[0-9]+]], int32_t [[VAL_3:v[0-9]+]]) {
549+
// CPP-DEFAULT-NEXT: int32_t [[VAL_4:v[0-9]+]];
550+
// CPP-DEFAULT-NEXT: if (bar([[VAL_1]], [[VAL_2]]) < [[VAL_3]]) {
551+
// CPP-DEFAULT-NEXT: [[VAL_4]] = [[VAL_1]];
552+
// CPP-DEFAULT-NEXT: } else {
553+
// CPP-DEFAULT-NEXT: [[VAL_4]] = [[VAL_2]];
554+
// CPP-DEFAULT-NEXT: }
555+
// CPP-DEFAULT-NEXT: int32_t [[VAL_5:v[0-9]+]] = [[VAL_4]];
556+
// CPP-DEFAULT-NEXT: return [[VAL_5]];
557+
// CPP-DEFAULT-NEXT: }
558+
559+
// CPP-DECLTOP: int32_t inline_side_effects_into_if(int32_t [[VAL_1:v[0-9]+]], int32_t [[VAL_2:v[0-9]+]], int32_t [[VAL_3:v[0-9]+]]) {
560+
// CPP-DECLTOP-NEXT: int32_t [[VAL_4:v[0-9]+]];
561+
// CPP-DECLTOP-NEXT: int32_t [[VAL_5:v[0-9]+]];
562+
// CPP-DECLTOP-NEXT: ;
563+
// CPP-DECLTOP-NEXT: if (bar([[VAL_1]], [[VAL_2]]) < [[VAL_3]]) {
564+
// CPP-DECLTOP-NEXT: [[VAL_4]] = [[VAL_1]];
565+
// CPP-DECLTOP-NEXT: } else {
566+
// CPP-DECLTOP-NEXT: [[VAL_4]] = [[VAL_2]];
567+
// CPP-DECLTOP-NEXT: }
568+
// CPP-DECLTOP-NEXT: [[VAL_5]] = [[VAL_4]];
569+
// CPP-DECLTOP-NEXT: return [[VAL_5]];
570+
// CPP-DECLTOP-NEXT: }
571+
572+
func.func @inline_side_effects_into_if(%arg0: i32, %arg1: i32, %arg2: i32) -> i32 {
573+
%v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue<i32>
574+
%cond = emitc.expression %arg0, %arg1, %arg2 : (i32, i32, i32) -> i1 {
575+
%a = emitc.call_opaque "bar" (%arg0, %arg1) : (i32, i32) -> (i32)
576+
%b = emitc.cmp lt, %a, %arg2 :(i32, i32) -> i1
577+
emitc.yield %b : i1
578+
}
579+
emitc.if %cond {
580+
emitc.assign %arg0 : i32 to %v : !emitc.lvalue<i32>
581+
emitc.yield
582+
} else {
583+
emitc.assign %arg1 : i32 to %v : !emitc.lvalue<i32>
584+
emitc.yield
585+
}
586+
%v_load = emitc.load %v : !emitc.lvalue<i32>
587+
return %v_load : i32
588+
}
589+
590+
// CPP-DEFAULT: void inline_side_effects_into_switch(int32_t [[VAL_1:v[0-9]+]], int32_t [[VAL_2:v[0-9]+]], int32_t [[VAL_3:v[0-9]+]]) {
591+
// CPP-DEFAULT-NEXT: switch (bar([[VAL_1]], [[VAL_2]]) + [[VAL_3]]) {
592+
// CPP-DEFAULT-NEXT: case 2: {
593+
// CPP-DEFAULT-NEXT: int32_t [[VAL_4:v[0-9]+]] = func_b();
594+
// CPP-DEFAULT-NEXT: break;
595+
// CPP-DEFAULT-NEXT: }
596+
// CPP-DEFAULT-NEXT: case 5: {
597+
// CPP-DEFAULT-NEXT: int32_t [[VAL_5:v[0-9]+]] = func_a();
598+
// CPP-DEFAULT-NEXT: break;
599+
// CPP-DEFAULT-NEXT: }
600+
// CPP-DEFAULT-NEXT: default: {
601+
// CPP-DEFAULT-NEXT: float [[VAL_6:v[0-9]+]] = 4.200000000e+01f;
602+
// CPP-DEFAULT-NEXT: func2([[VAL_6]]);
603+
// CPP-DEFAULT-NEXT: break;
604+
// CPP-DEFAULT-NEXT: }
605+
// CPP-DEFAULT-NEXT: }
606+
// CPP-DEFAULT-NEXT: return;
607+
// CPP-DEFAULT-NEXT: }
608+
609+
// CPP-DECLTOP: void inline_side_effects_into_switch(int32_t [[VAL_1:v[0-9]+]], int32_t [[VAL_2:v[0-9]+]], int32_t [[VAL_3:v[0-9]+]]) {
610+
// CPP-DECLTOP-NEXT: float [[VAL_6:v[0-9]+]];
611+
// CPP-DECLTOP-NEXT: int32_t [[VAL_4:v[0-9]+]];
612+
// CPP-DECLTOP-NEXT: int32_t [[VAL_5:v[0-9]+]];
613+
// CPP-DECLTOP-NEXT: switch (bar([[VAL_1]], [[VAL_2]]) + [[VAL_3]]) {
614+
// CPP-DECLTOP-NEXT: case 2: {
615+
// CPP-DECLTOP-NEXT: [[VAL_4]] = func_b();
616+
// CPP-DECLTOP-NEXT: break;
617+
// CPP-DECLTOP-NEXT: }
618+
// CPP-DECLTOP-NEXT: case 5: {
619+
// CPP-DECLTOP-NEXT: [[VAL_5]] = func_a();
620+
// CPP-DECLTOP-NEXT: break;
621+
// CPP-DECLTOP-NEXT: }
622+
// CPP-DECLTOP-NEXT: default: {
623+
// CPP-DECLTOP-NEXT: [[VAL_6]] = 4.200000000e+01f;
624+
// CPP-DECLTOP-NEXT: func2([[VAL_6]]);
625+
// CPP-DECLTOP-NEXT: break;
626+
// CPP-DECLTOP-NEXT: }
627+
// CPP-DECLTOP-NEXT: }
628+
// CPP-DECLTOP-NEXT: return;
629+
// CPP-DECLTOP-NEXT: }
630+
631+
func.func @inline_side_effects_into_switch(%arg0: i32, %arg1: i32, %arg2: i32) {
632+
%0 = emitc.expression %arg0, %arg1, %arg2 : (i32, i32, i32) -> i32 {
633+
%a = emitc.call_opaque "bar" (%arg0, %arg1) : (i32, i32) -> (i32)
634+
%b = emitc.add %a, %arg2 :(i32, i32) -> i32
635+
emitc.yield %b : i32
636+
}
637+
emitc.switch %0 : i32
638+
case 2 {
639+
%1 = emitc.call_opaque "func_b" () : () -> i32
640+
emitc.yield
641+
}
642+
case 5 {
643+
%2 = emitc.call_opaque "func_a" () : () -> i32
644+
emitc.yield
645+
}
646+
default {
647+
%3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32
648+
emitc.call_opaque "func2" (%3) : (f32) -> ()
649+
emitc.yield
650+
}
651+
return
652+
}

0 commit comments

Comments
 (0)