1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
// Make sure that the dead code of an `if` (and `else if`) is elminated when the condition is constant
// _only_ if the block does not contain any labels.
// For example,
// int a = 1;
// if (false) {
// L1:
// a = 2;
// } else {
// goto L1;
// }
// assert(a == 2);
// Note that a label is conssidered anything that lets us jump inside the body
// of the statement _apart from_ the actual statement (e.g. the `if).
// That generally is a normal label, but also specific cases for switch
// statements (see last tests).
// RUN: %ldc -O0 -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
extern(C): //to avoid name mangling.
// CHECK-LABEL: @foo
void foo()
{
// CHECK: %a = alloca
// CHECK: br
int a;
if (0)
{
L1:
a = 1;
}
else
{
goto L1;
}
}
// CHECK-LABEL: @bar
void bar(int a, int b)
{
int c;
if (0)
{
switch (a) {
case 10:
while (b) {
L2:
// CHECK: store i32 10, i32* %c
c = 10;
}
default: assert(0);
}
}
else
{
goto L2;
}
}
// CHECK-LABEL: @without_goto
void without_goto(int a, int b)
{
int c;
if (0)
{
switch (a) {
case 10:
while (b) {
L2:
// CHECK: store i32 10, i32* %c
c = 10;
}
default: assert(0);
}
}
else
{
a = 2;
}
}
// CHECK-LABEL: @fourth
void fourth(int a, int b, int c)
{
int j, d;
if (a)
{
goto L3;
}
else if (false)
{
for (j = 0; j <= c; ++j)
{
// Can't `goto` in a foreach because
// it always declares a variable.
L3:
foreach (i; 0..b)
{
// CHECK: store i32 10, i32* %d
d = 10;
}
}
}
}
// If a switch is outside the body of a statement "to-be-elided"
// but a case statement of it is inside that body, then that
// case acts as a label because we can jump inside the body without
// using the statement (i.e. using the switch to jump to the case).
// CHECK-LABEL: @case_as_label
void case_as_label(int a, int b)
{
// Note the `CHECK-NOT` trickery.
// CHECK-NOT: store i32 2, i32* %c
// CHECK: store i32 3, i32* %c
// CHECK-NOT: store i32 2, i32* %c
// CHECK: store i32 4, i32* %c
// CHECK-NOT: store i32 2, i32* %c
int c;
switch (a) {
case 1:
// Can elide
if (false) {
final switch (b) {
case 2:
c = 2;
}
}
goto case;
case 2:
// Can't elide
if (false) {
case 3:
c = 3;
}
// Can't elide
if (false) {
default:
c = 4;
}
}
}
// CHECK-LABEL: @case_as_label2
void case_as_label2(int a, int b)
{
// CHECK: store i32 2, i32* %c
// CHECK: store i32 3, i32* %c
int c;
final switch (a) {
// Can't elide
if (false) {
final switch (b) {
case 2:
c = 2;
}
// Test that `switch` in higher or equal nesting level
// with a `case` does not impact the handling of `case`s.
case 1:
c = 3;
}
}
}
|