| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -S --passes='simplifycfg<hoist-common-insts>' %s | FileCheck %s |
| |
| ;; Check that the two loads are hoisted to the common predecessor, skipping |
| ;; over the add/sub instructions. |
| |
| define void @f0(i1 %c, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f0( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[M:%.*]], align 2 |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw i16 [[TMP0]], 1 |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[ADD]], [[TMP1]] |
| ; CHECK-NEXT: br label [[IF_END:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: [[SUB:%.*]] = sub nsw i16 [[TMP0]], 1 |
| ; CHECK-NEXT: [[TMP2:%.*]] = add i16 [[SUB]], 3 |
| ; CHECK-NEXT: [[V:%.*]] = add i16 [[SUB]], [[TMP2]] |
| ; CHECK-NEXT: br label [[IF_END]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[UV:%.*]] = phi i16 [ [[V]], [[IF_ELSE]] ], [ [[U]], [[IF_THEN]] ] |
| ; CHECK-NEXT: store i16 [[UV]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 %c, label %if.then, label %if.else |
| |
| if.then: |
| %0 = load i16, ptr %b, align 2 |
| %add = add nsw i16 %0, 1 |
| %1 = load i16, ptr %m, align 2 |
| %u = add i16 %add, %1 |
| br label %if.end |
| |
| if.else: |
| %2 = load i16, ptr %b, align 2 |
| %sub = sub nsw i16 %2, 1 |
| %3 = load i16, ptr %m, align 2 |
| %4 = add i16 %sub, 3 |
| %v = add i16 %sub, %4 |
| br label %if.end |
| |
| if.end: |
| %uv = phi i16 [ %v, %if.else ], [ %u, %if.then ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| define void @f0_switch(i64 %i, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f0_switch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[M:%.*]], align 2 |
| ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [ |
| ; CHECK-NEXT: i64 1, label [[BB1:%.*]] |
| ; CHECK-NEXT: i64 2, label [[BB2:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw i16 [[TMP0]], 1 |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[ADD]], [[TMP1]] |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: [[SUB:%.*]] = sub nsw i16 [[TMP0]], 1 |
| ; CHECK-NEXT: [[TMP2:%.*]] = add i16 [[SUB]], 3 |
| ; CHECK-NEXT: [[V:%.*]] = add i16 [[SUB]], [[TMP2]] |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i16 [[TMP0]], 1 |
| ; CHECK-NEXT: [[TMP3:%.*]] = add i16 [[SUB2]], 3 |
| ; CHECK-NEXT: [[W:%.*]] = add i16 [[SUB2]], [[TMP3]] |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: [[UV:%.*]] = phi i16 [ [[U]], [[BB0]] ], [ [[V]], [[BB1]] ], [ [[W]], [[BB2]] ] |
| ; CHECK-NEXT: store i16 [[UV]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| switch i64 %i, label %bb0 [ |
| i64 1, label %bb1 |
| i64 2, label %bb2 |
| ] |
| |
| bb0: |
| %0 = load i16, ptr %b, align 2 |
| %add = add nsw i16 %0, 1 |
| %1 = load i16, ptr %m, align 2 |
| %u = add i16 %add, %1 |
| br label %end |
| |
| bb1: |
| %2 = load i16, ptr %b, align 2 |
| %sub = sub nsw i16 %2, 1 |
| %3 = load i16, ptr %m, align 2 |
| %4 = add i16 %sub, 3 |
| %v = add i16 %sub, %4 |
| br label %end |
| |
| bb2: |
| %5 = load i16, ptr %b, align 2 |
| %sub2 = sub nsw i16 %5, 1 |
| %6 = load i16, ptr %m, align 2 |
| %7 = add i16 %sub2, 3 |
| %w = add i16 %sub2, %7 |
| br label %end |
| |
| end: |
| %uv = phi i16 [ %u, %bb0 ], [ %v, %bb1 ], [ %w, %bb2 ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| ;; Check some instructions (e.g. add) can be reordered across instructions with side |
| ;; effects, while others (e.g. load) can't. |
| define void @f2(i1 %c, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f2( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[ADD_0:%.*]] = add nsw i16 [[TMP0]], 1 |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: call void @side_effects0() |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[M:%.*]], align 2 |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[ADD_0]], [[TMP1]] |
| ; CHECK-NEXT: br label [[IF_END:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: call void @no_side_effects0() |
| ; CHECK-NEXT: [[TMP2:%.*]] = load i16, ptr [[M]], align 2 |
| ; CHECK-NEXT: [[V:%.*]] = add i16 [[ADD_0]], [[TMP2]] |
| ; CHECK-NEXT: br label [[IF_END]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[UV:%.*]] = phi i16 [ [[V]], [[IF_ELSE]] ], [ [[U]], [[IF_THEN]] ] |
| ; CHECK-NEXT: store i16 [[UV]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 %c, label %if.then, label %if.else |
| |
| if.then: |
| %0 = load i16, ptr %b, align 2 |
| call void @side_effects0() |
| %add.0 = add nsw i16 %0, 1 |
| %1 = load i16, ptr %m, align 2 |
| %u = add i16 %add.0, %1 |
| br label %if.end |
| |
| if.else: |
| %2 = load i16, ptr %b, align 2 |
| call void @no_side_effects0() |
| %add.1 = add nsw i16 %2, 1 |
| %3 = load i16, ptr %m, align 2 |
| %v = add i16 %add.1, %3 |
| br label %if.end |
| |
| if.end: |
| %uv = phi i16 [ %v, %if.else ], [ %u, %if.then ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| define void @f2_switch(i64 %i, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f2_switch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[ADD_0:%.*]] = add nsw i16 [[TMP0]], 1 |
| ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [ |
| ; CHECK-NEXT: i64 1, label [[BB1:%.*]] |
| ; CHECK-NEXT: i64 2, label [[BB2:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: call void @side_effects0() |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[M:%.*]], align 2 |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[ADD_0]], [[TMP1]] |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: call void @no_side_effects0() |
| ; CHECK-NEXT: [[TMP2:%.*]] = load i16, ptr [[M]], align 2 |
| ; CHECK-NEXT: [[V:%.*]] = add i16 [[ADD_0]], [[TMP2]] |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: call void @no_side_effects0() |
| ; CHECK-NEXT: [[TMP3:%.*]] = load i16, ptr [[M]], align 2 |
| ; CHECK-NEXT: [[W:%.*]] = add i16 [[ADD_0]], [[TMP3]] |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: [[UV:%.*]] = phi i16 [ [[U]], [[BB0]] ], [ [[V]], [[BB1]] ], [ [[W]], [[BB2]] ] |
| ; CHECK-NEXT: store i16 [[UV]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| switch i64 %i, label %bb0 [ |
| i64 1, label %bb1 |
| i64 2, label %bb2 |
| ] |
| |
| bb0: |
| %0 = load i16, ptr %b, align 2 |
| call void @side_effects0() |
| %add.0 = add nsw i16 %0, 1 |
| %1 = load i16, ptr %m, align 2 |
| %u = add i16 %add.0, %1 |
| br label %end |
| |
| bb1: |
| %2 = load i16, ptr %b, align 2 |
| call void @no_side_effects0() |
| %add.1 = add nsw i16 %2, 1 |
| %3 = load i16, ptr %m, align 2 |
| %v = add i16 %add.1, %3 |
| br label %end |
| |
| bb2: |
| %4 = load i16, ptr %b, align 2 |
| call void @no_side_effects0() |
| %add.2 = add nsw i16 %4, 1 |
| %5 = load i16, ptr %m, align 2 |
| %w = add i16 %add.2, %5 |
| br label %end |
| |
| end: |
| %uv = phi i16 [ %u, %bb0 ], [ %v, %bb1 ], [ %w, %bb2 ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| ;; Check indeed it was the side effects that prevented hoisting the load |
| ;; in the previous test. |
| define void @f3(i1 %c, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f3( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[ADD_0:%.*]] = add nsw i16 [[TMP0]], 1 |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[M:%.*]], align 2 |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[ADD_0]], [[TMP1]] |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: call void @no_side_effects0() |
| ; CHECK-NEXT: br label [[IF_END:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: call void @no_side_effects1() |
| ; CHECK-NEXT: br label [[IF_END]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: store i16 [[U]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 %c, label %if.then, label %if.else |
| |
| if.then: |
| %0 = load i16, ptr %b, align 2 |
| call void @no_side_effects0() |
| %add.0 = add nsw i16 %0, 1 |
| %1 = load i16, ptr %m, align 2 |
| %u = add i16 %add.0, %1 |
| br label %if.end |
| |
| if.else: |
| %2 = load i16, ptr %b, align 2 |
| call void @no_side_effects1() |
| %add.1 = add nsw i16 %2, 1 |
| %3 = load i16, ptr %m, align 2 |
| %v = add i16 %add.1, %3 |
| br label %if.end |
| |
| if.end: |
| %uv = phi i16 [ %v, %if.else ], [ %u, %if.then ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| define void @f3_switch(i64 %i, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f3_switch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[ADD_0:%.*]] = add nsw i16 [[TMP0]], 1 |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[M:%.*]], align 2 |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[ADD_0]], [[TMP1]] |
| ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [ |
| ; CHECK-NEXT: i64 1, label [[BB1:%.*]] |
| ; CHECK-NEXT: i64 2, label [[BB2:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: call void @no_side_effects0() |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: call void @no_side_effects1() |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: call void @no_side_effects1() |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: [[UV:%.*]] = phi i16 [ [[U]], [[BB0]] ], [ [[U]], [[BB1]] ], [ [[U]], [[BB2]] ] |
| ; CHECK-NEXT: store i16 [[UV]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| switch i64 %i, label %bb0 [ |
| i64 1, label %bb1 |
| i64 2, label %bb2 |
| ] |
| |
| bb0: |
| %0 = load i16, ptr %b, align 2 |
| call void @no_side_effects0() |
| %add.0 = add nsw i16 %0, 1 |
| %1 = load i16, ptr %m, align 2 |
| %u = add i16 %add.0, %1 |
| br label %end |
| |
| bb1: |
| %2 = load i16, ptr %b, align 2 |
| call void @no_side_effects1() |
| %add.1 = add nsw i16 %2, 1 |
| %3 = load i16, ptr %m, align 2 |
| %v = add i16 %add.1, %3 |
| br label %end |
| |
| bb2: |
| %4 = load i16, ptr %b, align 2 |
| call void @no_side_effects1() |
| %add.2 = add nsw i16 %4, 1 |
| %5 = load i16, ptr %m, align 2 |
| %w = add i16 %add.2, %5 |
| br label %end |
| |
| end: |
| %uv = phi i16 [ %u, %bb0 ], [ %v, %bb1 ], [ %w, %bb2 ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| ;; Check some instructions (e.g. sdiv) are not speculatively executed. |
| |
| ;; Division by non-zero constant OK to speculate ... |
| define void @f4(i1 %c, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f4( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[DIV_0:%.*]] = sdiv i16 [[TMP0]], 2 |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[DIV_0]], [[TMP0]] |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: call void @side_effects0() |
| ; CHECK-NEXT: br label [[IF_END:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: call void @side_effects1() |
| ; CHECK-NEXT: br label [[IF_END]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: store i16 [[U]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 %c, label %if.then, label %if.else |
| |
| if.then: |
| %0 = load i16, ptr %b, align 2 |
| call void @side_effects0() |
| %div.0 = sdiv i16 %0, 2 |
| %u = add i16 %div.0, %0 |
| br label %if.end |
| |
| if.else: |
| %1 = load i16, ptr %b, align 2 |
| call void @side_effects1() |
| %div.1 = sdiv i16 %1, 2 |
| %v = add i16 %div.1, %1 |
| br label %if.end |
| |
| if.end: |
| %uv = phi i16 [ %v, %if.else ], [ %u, %if.then ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| define void @f4_switch(i64 %i, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f4_switch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[DIV_0:%.*]] = sdiv i16 [[TMP0]], 2 |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[DIV_0]], [[TMP0]] |
| ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [ |
| ; CHECK-NEXT: i64 1, label [[BB1:%.*]] |
| ; CHECK-NEXT: i64 2, label [[BB2:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: call void @side_effects0() |
| ; CHECK-NEXT: br label [[IF_END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: call void @side_effects1() |
| ; CHECK-NEXT: br label [[IF_END]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: call void @side_effects1() |
| ; CHECK-NEXT: br label [[IF_END]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[UV:%.*]] = phi i16 [ [[U]], [[BB0]] ], [ [[U]], [[BB1]] ], [ [[U]], [[BB2]] ] |
| ; CHECK-NEXT: store i16 [[UV]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| switch i64 %i, label %bb0 [ |
| i64 1, label %bb1 |
| i64 2, label %bb2 |
| ] |
| |
| bb0: |
| %0 = load i16, ptr %b, align 2 |
| call void @side_effects0() |
| %div.0 = sdiv i16 %0, 2 |
| %u = add i16 %div.0, %0 |
| br label %if.end |
| |
| bb1: |
| %1 = load i16, ptr %b, align 2 |
| call void @side_effects1() |
| %div.1 = sdiv i16 %1, 2 |
| %v = add i16 %div.1, %1 |
| br label %if.end |
| |
| bb2: |
| %2 = load i16, ptr %b, align 2 |
| call void @side_effects1() |
| %div.2 = sdiv i16 %2, 2 |
| %w = add i16 %div.2, %2 |
| br label %if.end |
| |
| if.end: |
| %uv = phi i16 [ %u, %bb0 ], [ %v, %bb1 ], [ %w, %bb2 ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| ;; ... but not a general division ... |
| define void @f5(i1 %c, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f5( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: call void @side_effects0() |
| ; CHECK-NEXT: [[DIV_0:%.*]] = sdiv i16 211, [[TMP0]] |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[DIV_0]], [[TMP0]] |
| ; CHECK-NEXT: br label [[IF_END:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: call void @side_effects1() |
| ; CHECK-NEXT: [[DIV_1:%.*]] = sdiv i16 211, [[TMP0]] |
| ; CHECK-NEXT: [[V:%.*]] = add i16 [[DIV_1]], [[TMP0]] |
| ; CHECK-NEXT: br label [[IF_END]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[UV:%.*]] = phi i16 [ [[V]], [[IF_ELSE]] ], [ [[U]], [[IF_THEN]] ] |
| ; CHECK-NEXT: store i16 [[UV]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 %c, label %if.then, label %if.else |
| |
| if.then: |
| %0 = load i16, ptr %b, align 2 |
| call void @side_effects0() |
| %div.0 = sdiv i16 211, %0 |
| %u = add i16 %div.0, %0 |
| br label %if.end |
| |
| if.else: |
| %1 = load i16, ptr %b, align 2 |
| call void @side_effects1() |
| %div.1 = sdiv i16 211, %1 |
| %v = add i16 %div.1, %1 |
| br label %if.end |
| |
| if.end: |
| %uv = phi i16 [ %v, %if.else ], [ %u, %if.then ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| define void @f5_switch(i64 %i, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f5_switch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [ |
| ; CHECK-NEXT: i64 1, label [[BB1:%.*]] |
| ; CHECK-NEXT: i64 2, label [[BB2:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: call void @side_effects0() |
| ; CHECK-NEXT: [[DIV_0:%.*]] = sdiv i16 211, [[TMP0]] |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[DIV_0]], [[TMP0]] |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: call void @side_effects1() |
| ; CHECK-NEXT: [[DIV_1:%.*]] = sdiv i16 211, [[TMP0]] |
| ; CHECK-NEXT: [[V:%.*]] = add i16 [[DIV_1]], [[TMP0]] |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: call void @side_effects1() |
| ; CHECK-NEXT: [[DIV_2:%.*]] = sdiv i16 211, [[TMP0]] |
| ; CHECK-NEXT: [[W:%.*]] = add i16 [[DIV_2]], [[TMP0]] |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: [[UV:%.*]] = phi i16 [ [[U]], [[BB0]] ], [ [[V]], [[BB1]] ], [ [[W]], [[BB2]] ] |
| ; CHECK-NEXT: store i16 [[UV]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| switch i64 %i, label %bb0 [ |
| i64 1, label %bb1 |
| i64 2, label %bb2 |
| ] |
| |
| bb0: |
| %0 = load i16, ptr %b, align 2 |
| call void @side_effects0() |
| %div.0 = sdiv i16 211, %0 |
| %u = add i16 %div.0, %0 |
| br label %end |
| |
| bb1: |
| %1 = load i16, ptr %b, align 2 |
| call void @side_effects1() |
| %div.1 = sdiv i16 211, %1 |
| %v = add i16 %div.1, %1 |
| br label %end |
| |
| bb2: |
| %2 = load i16, ptr %b, align 2 |
| call void @side_effects1() |
| %div.2 = sdiv i16 211, %2 |
| %w = add i16 %div.2, %2 |
| br label %end |
| |
| end: |
| %uv = phi i16 [ %u, %bb0 ], [ %v, %bb1 ], [ %w, %bb2 ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| ;; ... and it's also OK to hoist the division when there's no speculation happening. |
| define void @f6(i1 %c, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f6( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[DIV_0:%.*]] = sdiv i16 211, [[TMP0]] |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[DIV_0]], [[TMP0]] |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: call void @no_side_effects0() |
| ; CHECK-NEXT: br label [[IF_END:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: call void @no_side_effects1() |
| ; CHECK-NEXT: br label [[IF_END]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: store i16 [[U]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 %c, label %if.then, label %if.else |
| |
| if.then: |
| %0 = load i16, ptr %b, align 2 |
| call void @no_side_effects0() |
| %div.0 = sdiv i16 211, %0 |
| %u = add i16 %div.0, %0 |
| br label %if.end |
| |
| if.else: |
| %1 = load i16, ptr %b, align 2 |
| call void @no_side_effects1() |
| %div.1 = sdiv i16 211, %1 |
| %v = add i16 %div.1, %1 |
| br label %if.end |
| |
| if.end: |
| %uv = phi i16 [ %v, %if.else ], [ %u, %if.then ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| define void @f6_switch(i64 %i, ptr nocapture noundef %d, ptr nocapture noundef readonly %m, ptr nocapture noundef readonly %b) { |
| ; CHECK-LABEL: @f6_switch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[DIV_0:%.*]] = sdiv i16 211, [[TMP0]] |
| ; CHECK-NEXT: [[U:%.*]] = add i16 [[DIV_0]], [[TMP0]] |
| ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [ |
| ; CHECK-NEXT: i64 1, label [[BB1:%.*]] |
| ; CHECK-NEXT: i64 2, label [[BB2:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: call void @no_side_effects0() |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: call void @no_side_effects1() |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: call void @no_side_effects1() |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: [[UV:%.*]] = phi i16 [ [[U]], [[BB0]] ], [ [[U]], [[BB1]] ], [ [[U]], [[BB2]] ] |
| ; CHECK-NEXT: store i16 [[UV]], ptr [[D:%.*]], align 2 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| switch i64 %i, label %bb0 [ |
| i64 1, label %bb1 |
| i64 2, label %bb2 |
| ] |
| |
| bb0: |
| %0 = load i16, ptr %b, align 2 |
| call void @no_side_effects0() |
| %div.0 = sdiv i16 211, %0 |
| %u = add i16 %div.0, %0 |
| br label %end |
| |
| bb1: |
| %1 = load i16, ptr %b, align 2 |
| call void @no_side_effects1() |
| %div.1 = sdiv i16 211, %1 |
| %v = add i16 %div.1, %1 |
| br label %end |
| |
| bb2: |
| %2 = load i16, ptr %b, align 2 |
| call void @no_side_effects1() |
| %div.2 = sdiv i16 211, %2 |
| %w = add i16 %div.2, %2 |
| br label %end |
| |
| end: |
| %uv = phi i16 [ %u, %bb0 ], [ %v, %bb1 ], [ %w, %bb2 ] |
| store i16 %uv, ptr %d, align 2 |
| ret void |
| } |
| |
| ;; No reorder of store over a load. |
| define i16 @f7(i1 %c, ptr %a, ptr %b) { |
| ; CHECK-LABEL: @f7( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[VA:%.*]] = load i16, ptr [[A:%.*]], align 2 |
| ; CHECK-NEXT: store i16 0, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: br label [[IF_END:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: [[VB:%.*]] = load i16, ptr [[B]], align 2 |
| ; CHECK-NEXT: store i16 0, ptr [[B]], align 2 |
| ; CHECK-NEXT: br label [[IF_END]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[V:%.*]] = phi i16 [ [[VA]], [[IF_THEN]] ], [ [[VB]], [[IF_ELSE]] ] |
| ; CHECK-NEXT: ret i16 [[V]] |
| ; |
| entry: |
| br i1 %c, label %if.then, label %if.else |
| |
| if.then: |
| %va = load i16, ptr %a, align 2 |
| store i16 0, ptr %b, align 2 |
| br label %if.end |
| |
| if.else: |
| %vb = load i16, ptr %b, align 2 |
| store i16 0, ptr %b, align 2 |
| br label %if.end |
| |
| if.end: |
| %v = phi i16 [ %va, %if.then ], [ %vb, %if.else ] |
| ret i16 %v |
| } |
| |
| define i16 @f7_switch(i64 %i, ptr %a, ptr %b) { |
| ; CHECK-LABEL: @f7_switch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [ |
| ; CHECK-NEXT: i64 1, label [[BB1:%.*]] |
| ; CHECK-NEXT: i64 2, label [[BB2:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: [[VA:%.*]] = load i16, ptr [[A:%.*]], align 2 |
| ; CHECK-NEXT: store i16 0, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: [[VB:%.*]] = load i16, ptr [[B]], align 2 |
| ; CHECK-NEXT: store i16 0, ptr [[B]], align 2 |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: [[VC:%.*]] = load i16, ptr [[B]], align 2 |
| ; CHECK-NEXT: store i16 0, ptr [[B]], align 2 |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: [[V:%.*]] = phi i16 [ [[VA]], [[BB0]] ], [ [[VB]], [[BB1]] ], [ [[VC]], [[BB2]] ] |
| ; CHECK-NEXT: ret i16 [[V]] |
| ; |
| entry: |
| switch i64 %i, label %bb0 [ |
| i64 1, label %bb1 |
| i64 2, label %bb2 |
| ] |
| |
| bb0: |
| %va = load i16, ptr %a, align 2 |
| store i16 0, ptr %b, align 2 |
| br label %end |
| |
| bb1: |
| %vb = load i16, ptr %b, align 2 |
| store i16 0, ptr %b, align 2 |
| br label %end |
| |
| bb2: |
| %vc = load i16, ptr %b, align 2 |
| store i16 0, ptr %b, align 2 |
| br label %end |
| |
| end: |
| %v = phi i16 [ %va, %bb0 ], [ %vb, %bb1 ], [ %vc, %bb2 ] |
| ret i16 %v |
| } |
| |
| ;; Can reorder load over another load |
| define i16 @f8(i1 %cond, ptr %a, ptr %b, ptr %c) { |
| ; CHECK-LABEL: @f8( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[C_0:%.*]] = load i16, ptr [[C:%.*]], align 2 |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[VA:%.*]] = load i16, ptr [[A:%.*]], align 2 |
| ; CHECK-NEXT: br label [[IF_END:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: [[VB:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: br label [[IF_END]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[V:%.*]] = phi i16 [ [[VA]], [[IF_THEN]] ], [ [[VB]], [[IF_ELSE]] ] |
| ; CHECK-NEXT: [[U:%.*]] = phi i16 [ [[C_0]], [[IF_THEN]] ], [ [[C_0]], [[IF_ELSE]] ] |
| ; CHECK-NEXT: [[W:%.*]] = add i16 [[V]], [[U]] |
| ; CHECK-NEXT: ret i16 [[W]] |
| ; |
| entry: |
| br i1 %cond, label %if.then, label %if.else |
| |
| if.then: |
| %va = load i16, ptr %a, align 2 |
| %c.0 = load i16, ptr %c |
| br label %if.end |
| |
| if.else: |
| %vb = load i16, ptr %b, align 2 |
| %c.1 = load i16, ptr %c |
| br label %if.end |
| |
| if.end: |
| %v = phi i16 [ %va, %if.then ], [ %vb, %if.else ] |
| %u = phi i16 [ %c.0, %if.then ], [ %c.1, %if.else ] |
| |
| %w = add i16 %v, %u |
| |
| ret i16 %w |
| } |
| |
| define i16 @f8_switch(i64 %i, ptr %a, ptr %b, ptr %c) { |
| ; CHECK-LABEL: @f8_switch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[C_0:%.*]] = load i16, ptr [[C:%.*]], align 2 |
| ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [ |
| ; CHECK-NEXT: i64 1, label [[BB1:%.*]] |
| ; CHECK-NEXT: i64 2, label [[BB2:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: [[VA:%.*]] = load i16, ptr [[A:%.*]], align 2 |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: [[VB:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: [[VC:%.*]] = load i16, ptr [[B]], align 2 |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: [[V:%.*]] = phi i16 [ [[VA]], [[BB0]] ], [ [[VB]], [[BB1]] ], [ [[VC]], [[BB2]] ] |
| ; CHECK-NEXT: [[U:%.*]] = phi i16 [ [[C_0]], [[BB0]] ], [ [[C_0]], [[BB1]] ], [ [[C_0]], [[BB2]] ] |
| ; CHECK-NEXT: [[W:%.*]] = add i16 [[V]], [[U]] |
| ; CHECK-NEXT: ret i16 [[W]] |
| ; |
| entry: |
| switch i64 %i, label %bb0 [ |
| i64 1, label %bb1 |
| i64 2, label %bb2 |
| ] |
| |
| bb0: |
| %va = load i16, ptr %a, align 2 |
| %c.0 = load i16, ptr %c |
| br label %end |
| |
| bb1: |
| %vb = load i16, ptr %b, align 2 |
| %c.1 = load i16, ptr %c |
| br label %end |
| |
| bb2: |
| %vc = load i16, ptr %b, align 2 |
| %c.2 = load i16, ptr %c |
| br label %end |
| |
| end: |
| %v = phi i16 [ %va, %bb0 ], [ %vb, %bb1 ], [ %vc, %bb2 ] |
| %u = phi i16 [ %c.0, %bb0 ], [ %c.1, %bb1 ], [ %c.2, %bb2 ] |
| |
| %w = add i16 %v, %u |
| |
| ret i16 %w |
| } |
| |
| ;; Currently won't reorder volatile and non-volatile loads. |
| define i16 @f9(i1 %cond, ptr %a, ptr %b, ptr %c) { |
| ; CHECK-LABEL: @f9( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[VA:%.*]] = load volatile i16, ptr [[A:%.*]], align 2 |
| ; CHECK-NEXT: [[C_0:%.*]] = load i16, ptr [[C:%.*]], align 2 |
| ; CHECK-NEXT: br label [[IF_END:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: [[VB:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[C_1:%.*]] = load i16, ptr [[C]], align 2 |
| ; CHECK-NEXT: br label [[IF_END]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[V:%.*]] = phi i16 [ [[VA]], [[IF_THEN]] ], [ [[VB]], [[IF_ELSE]] ] |
| ; CHECK-NEXT: [[U:%.*]] = phi i16 [ [[C_0]], [[IF_THEN]] ], [ [[C_1]], [[IF_ELSE]] ] |
| ; CHECK-NEXT: [[W:%.*]] = add i16 [[V]], [[U]] |
| ; CHECK-NEXT: ret i16 [[W]] |
| ; |
| entry: |
| br i1 %cond, label %if.then, label %if.else |
| |
| if.then: |
| %va = load volatile i16, ptr %a, align 2 |
| %c.0 = load i16, ptr %c |
| br label %if.end |
| |
| if.else: |
| %vb = load i16, ptr %b, align 2 |
| %c.1 = load i16, ptr %c |
| br label %if.end |
| |
| if.end: |
| %v = phi i16 [ %va, %if.then ], [ %vb, %if.else ] |
| %u = phi i16 [ %c.0, %if.then ], [ %c.1, %if.else ] |
| |
| %w = add i16 %v, %u |
| |
| ret i16 %w |
| } |
| |
| define i16 @f9_switch(i64 %i, ptr %a, ptr %b, ptr %c) { |
| ; CHECK-LABEL: @f9_switch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [ |
| ; CHECK-NEXT: i64 1, label [[BB1:%.*]] |
| ; CHECK-NEXT: i64 2, label [[BB2:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: [[VA:%.*]] = load volatile i16, ptr [[A:%.*]], align 2 |
| ; CHECK-NEXT: [[C_0:%.*]] = load i16, ptr [[C:%.*]], align 2 |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: [[VB:%.*]] = load i16, ptr [[B:%.*]], align 2 |
| ; CHECK-NEXT: [[C_1:%.*]] = load i16, ptr [[C]], align 2 |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: [[VC:%.*]] = load i16, ptr [[B]], align 2 |
| ; CHECK-NEXT: [[C_2:%.*]] = load i16, ptr [[C]], align 2 |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: [[V:%.*]] = phi i16 [ [[VA]], [[BB0]] ], [ [[VB]], [[BB1]] ], [ [[VC]], [[BB2]] ] |
| ; CHECK-NEXT: [[U:%.*]] = phi i16 [ [[C_0]], [[BB0]] ], [ [[C_1]], [[BB1]] ], [ [[C_2]], [[BB2]] ] |
| ; CHECK-NEXT: [[W:%.*]] = add i16 [[V]], [[U]] |
| ; CHECK-NEXT: ret i16 [[W]] |
| ; |
| entry: |
| switch i64 %i, label %bb0 [ |
| i64 1, label %bb1 |
| i64 2, label %bb2 |
| ] |
| |
| bb0: |
| %va = load volatile i16, ptr %a, align 2 |
| %c.0 = load i16, ptr %c |
| br label %end |
| |
| bb1: |
| %vb = load i16, ptr %b, align 2 |
| %c.1 = load i16, ptr %c |
| br label %end |
| |
| bb2: |
| %vc = load i16, ptr %b, align 2 |
| %c.2 = load i16, ptr %c |
| br label %end |
| |
| end: |
| %v = phi i16 [ %va, %bb0 ], [ %vb, %bb1 ], [ %vc, %bb2 ] |
| %u = phi i16 [ %c.0, %bb0 ], [ %c.1, %bb1 ], [ %c.2, %bb2 ] |
| |
| %w = add i16 %v, %u |
| |
| ret i16 %w |
| } |
| |
| ;; Don't hoist stacksaves across inalloca allocas |
| define void @f10(i1 %cond) { |
| ; CHECK-LABEL: @f10( |
| ; CHECK-NEXT: [[SS:%.*]] = call ptr @llvm.stacksave.p0() |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: [[I1:%.*]] = alloca inalloca i32, align 4 |
| ; CHECK-NEXT: [[SS2:%.*]] = call ptr @llvm.stacksave.p0() |
| ; CHECK-NEXT: [[I2:%.*]] = alloca inalloca i64, align 8 |
| ; CHECK-NEXT: call void @inalloca_i64(ptr inalloca(i64) [[I2]]) |
| ; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr [[SS2]]) |
| ; CHECK-NEXT: call void @inalloca_i32(ptr inalloca(i32) [[I1]]) |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: [[I3:%.*]] = alloca inalloca i64, align 8 |
| ; CHECK-NEXT: [[SS3:%.*]] = call ptr @llvm.stacksave.p0() |
| ; CHECK-NEXT: [[I4:%.*]] = alloca inalloca i64, align 8 |
| ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @inalloca_i64(ptr inalloca(i64) [[I4]]) |
| ; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr [[SS3]]) |
| ; CHECK-NEXT: [[TMP2:%.*]] = call ptr @inalloca_i64(ptr inalloca(i64) [[I3]]) |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr [[SS]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %ss = call ptr @llvm.stacksave() |
| br i1 %cond, label %bb1, label %bb2 |
| |
| bb1: |
| %i1 = alloca inalloca i32 |
| %ss2 = call ptr @llvm.stacksave() |
| %i2 = alloca inalloca i64 |
| call void @inalloca_i64(ptr inalloca(i64) %i2) |
| call void @llvm.stackrestore(ptr %ss2) |
| call void @inalloca_i32(ptr inalloca(i32) %i1) |
| br label %end |
| |
| bb2: |
| %i3 = alloca inalloca i64 |
| %ss3 = call ptr @llvm.stacksave() |
| %i4 = alloca inalloca i64 |
| call ptr @inalloca_i64(ptr inalloca(i64) %i4) |
| call void @llvm.stackrestore(ptr %ss3) |
| call ptr @inalloca_i64(ptr inalloca(i64) %i3) |
| br label %end |
| |
| end: |
| call void @llvm.stackrestore(ptr %ss) |
| ret void |
| } |
| |
| define void @f10_switch(i64 %i) { |
| ; CHECK-LABEL: @f10_switch( |
| ; CHECK-NEXT: [[SS:%.*]] = call ptr @llvm.stacksave.p0() |
| ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [ |
| ; CHECK-NEXT: i64 1, label [[BB1:%.*]] |
| ; CHECK-NEXT: i64 2, label [[BB2:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: [[I1:%.*]] = alloca inalloca i32, align 4 |
| ; CHECK-NEXT: [[SS2:%.*]] = call ptr @llvm.stacksave.p0() |
| ; CHECK-NEXT: [[I2:%.*]] = alloca inalloca i64, align 8 |
| ; CHECK-NEXT: call void @inalloca_i64(ptr inalloca(i64) [[I2]]) |
| ; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr [[SS2]]) |
| ; CHECK-NEXT: call void @inalloca_i32(ptr inalloca(i32) [[I1]]) |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: [[I3:%.*]] = alloca inalloca i64, align 8 |
| ; CHECK-NEXT: [[SS3:%.*]] = call ptr @llvm.stacksave.p0() |
| ; CHECK-NEXT: [[I4:%.*]] = alloca inalloca i64, align 8 |
| ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @inalloca_i64(ptr inalloca(i64) [[I4]]) |
| ; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr [[SS3]]) |
| ; CHECK-NEXT: [[TMP2:%.*]] = call ptr @inalloca_i64(ptr inalloca(i64) [[I3]]) |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: [[I5:%.*]] = alloca inalloca i64, align 8 |
| ; CHECK-NEXT: [[SS4:%.*]] = call ptr @llvm.stacksave.p0() |
| ; CHECK-NEXT: [[I6:%.*]] = alloca inalloca i64, align 8 |
| ; CHECK-NEXT: [[TMP3:%.*]] = call ptr @inalloca_i64(ptr inalloca(i64) [[I6]]) |
| ; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr [[SS4]]) |
| ; CHECK-NEXT: [[TMP4:%.*]] = call ptr @inalloca_i64(ptr inalloca(i64) [[I5]]) |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr [[SS]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %ss = call ptr @llvm.stacksave() |
| switch i64 %i, label %bb0 [ |
| i64 1, label %bb1 |
| i64 2, label %bb2 |
| ] |
| |
| bb0: |
| %i1 = alloca inalloca i32 |
| %ss2 = call ptr @llvm.stacksave() |
| %i2 = alloca inalloca i64 |
| call void @inalloca_i64(ptr inalloca(i64) %i2) |
| call void @llvm.stackrestore(ptr %ss2) |
| call void @inalloca_i32(ptr inalloca(i32) %i1) |
| br label %end |
| |
| bb1: |
| %i3 = alloca inalloca i64 |
| %ss3 = call ptr @llvm.stacksave() |
| %i4 = alloca inalloca i64 |
| call ptr @inalloca_i64(ptr inalloca(i64) %i4) |
| call void @llvm.stackrestore(ptr %ss3) |
| call ptr @inalloca_i64(ptr inalloca(i64) %i3) |
| br label %end |
| |
| bb2: |
| %i5 = alloca inalloca i64 |
| %ss4 = call ptr @llvm.stacksave() |
| %i6 = alloca inalloca i64 |
| call ptr @inalloca_i64(ptr inalloca(i64) %i6) |
| call void @llvm.stackrestore(ptr %ss4) |
| call ptr @inalloca_i64(ptr inalloca(i64) %i5) |
| br label %end |
| |
| end: |
| call void @llvm.stackrestore(ptr %ss) |
| ret void |
| } |
| |
| declare void @side_effects0() |
| declare void @side_effects1() |
| declare void @no_side_effects0() readonly nounwind willreturn |
| declare void @no_side_effects1() readonly nounwind willreturn |
| declare void @inalloca_i64(ptr inalloca(i64)) |
| declare void @inalloca_i32(ptr inalloca(i32)) |
| declare ptr @llvm.stacksave() |
| declare void @llvm.stackrestore(ptr) |