1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 public class Main { main(String[] args)18 public static void main(String[] args) throws Exception { 19 assertEquals(40, $noinline$testEliminateIf(20, 40)); 20 assertEquals(30, $noinline$testEliminateIf(20, 10)); 21 assertEquals(40, $noinline$testEliminateIfTwiceInARow(20, 40)); 22 assertEquals(30, $noinline$testEliminateIfTwiceInARow(20, 10)); 23 assertEquals(40, $noinline$testEliminateIfThreePredecessors(20, 40)); 24 assertEquals(30, $noinline$testEliminateIfThreePredecessors(20, 10)); 25 assertEquals(40, $noinline$testEliminateIfOppositeCondition(20, 40)); 26 assertEquals(30, $noinline$testEliminateIfOppositeCondition(20, 10)); 27 assertEquals(40, $noinline$testEliminateIfParameter(20, 40, 20 < 40)); 28 assertEquals(30, $noinline$testEliminateIfParameter(20, 10, 20 < 10)); 29 assertEquals(40, $noinline$testEliminateIfParameterReverseCondition(20, 40, 20 < 40)); 30 assertEquals(30, $noinline$testEliminateIfParameterReverseCondition(20, 10, 20 < 10)); 31 assertEquals(40, $noinline$testEliminateIfParameterOppositeCondition(20, 40, 20 < 40)); 32 assertEquals(30, $noinline$testEliminateIfParameterOppositeCondition(20, 10, 20 < 10)); 33 assertEquals(40, $noinline$testEliminateIfParameterOppositeCondition_2(20, 40, 20 < 40)); 34 assertEquals(30, $noinline$testEliminateIfParameterOppositeCondition_2(20, 10, 20 < 10)); 35 36 assertEquals(2, $noinline$testEliminateIfFp(20.0, 40.0)); 37 assertEquals(3, $noinline$testEliminateIfFp(20.0, 10.0)); 38 assertEquals(3, $noinline$testEliminateIfFp(20.0, Double.NaN)); 39 assertEquals(3, $noinline$testEliminateIfFp(Double.NaN, 10.0)); 40 assertEquals(3, $noinline$testDoNotEliminateIfOppositeCondFpWrongBias(20.0, 40.0)); 41 assertEquals(2, $noinline$testDoNotEliminateIfOppositeCondFpWrongBias(20.0, 10.0)); 42 assertEquals(3, $noinline$testDoNotEliminateIfOppositeCondFpWrongBias(20.0, Double.NaN)); 43 assertEquals(3, $noinline$testDoNotEliminateIfOppositeCondFpWrongBias(Double.NaN, 10.0)); 44 } 45 $noinline$emptyMethod(int a)46 private static int $noinline$emptyMethod(int a) { 47 return a; 48 } 49 50 /// CHECK-START: int Main.$noinline$testEliminateIf(int, int) dead_code_elimination$after_gvn (before) 51 /// CHECK: If 52 /// CHECK: If 53 54 /// CHECK-START: int Main.$noinline$testEliminateIf(int, int) dead_code_elimination$after_gvn (after) 55 /// CHECK: If 56 /// CHECK-NOT: If $noinline$testEliminateIf(int a, int b)57 private static int $noinline$testEliminateIf(int a, int b) { 58 int result = 0; 59 if (a < b) { 60 $noinline$emptyMethod(a + b); 61 } else { 62 $noinline$emptyMethod(a - b); 63 } 64 if (a < b) { 65 result += $noinline$emptyMethod(a * 2); 66 } else { 67 result += $noinline$emptyMethod(b * 3); 68 } 69 return result; 70 } 71 72 /// CHECK-START: int Main.$noinline$testEliminateIfTwiceInARow(int, int) dead_code_elimination$after_gvn (before) 73 /// CHECK: If 74 /// CHECK: If 75 /// CHECK: If 76 77 /// CHECK-START: int Main.$noinline$testEliminateIfTwiceInARow(int, int) dead_code_elimination$after_gvn (after) 78 /// CHECK: If 79 /// CHECK-NOT: If $noinline$testEliminateIfTwiceInARow(int a, int b)80 private static int $noinline$testEliminateIfTwiceInARow(int a, int b) { 81 int result = 0; 82 if (a < b) { 83 $noinline$emptyMethod(a + b); 84 } else { 85 $noinline$emptyMethod(a - b); 86 } 87 if (a < b) { 88 $noinline$emptyMethod(a * 2); 89 } else { 90 $noinline$emptyMethod(b * 3); 91 } 92 if (a < b) { 93 result += $noinline$emptyMethod(40); 94 } else { 95 result += $noinline$emptyMethod(30); 96 } 97 return result; 98 } 99 100 /// CHECK-START: int Main.$noinline$testEliminateIfThreePredecessors(int, int) dead_code_elimination$after_gvn (before) 101 /// CHECK: If 102 /// CHECK: If 103 /// CHECK: If 104 105 /// CHECK-START: int Main.$noinline$testEliminateIfThreePredecessors(int, int) dead_code_elimination$after_gvn (after) 106 /// CHECK: If 107 /// CHECK: If 108 /// CHECK-NOT: If $noinline$testEliminateIfThreePredecessors(int a, int b)109 private static int $noinline$testEliminateIfThreePredecessors(int a, int b) { 110 int result = 0; 111 if (a < b) { 112 $noinline$emptyMethod(a + b); 113 } else { 114 if (b < 5) { 115 $noinline$emptyMethod(a - b); 116 } else { 117 $noinline$emptyMethod(a * b); 118 } 119 } 120 if (a < b) { 121 result += $noinline$emptyMethod(a * 2); 122 } else { 123 result += $noinline$emptyMethod(b * 3); 124 } 125 return result; 126 } 127 128 // Note that we can perform this optimization in dead_code_elimination$initial since we don't 129 // rely on gvn to de-duplicate the values. 130 131 /// CHECK-START: int Main.$noinline$testEliminateIfOppositeCondition(int, int) dead_code_elimination$initial (before) 132 /// CHECK: If 133 /// CHECK: If 134 135 /// CHECK-START: int Main.$noinline$testEliminateIfOppositeCondition(int, int) dead_code_elimination$initial (after) 136 /// CHECK: If 137 /// CHECK-NOT: If $noinline$testEliminateIfOppositeCondition(int a, int b)138 private static int $noinline$testEliminateIfOppositeCondition(int a, int b) { 139 int result = 0; 140 if (a < b) { 141 $noinline$emptyMethod(a + b); 142 } else { 143 $noinline$emptyMethod(a - b); 144 } 145 if (a >= b) { 146 result += $noinline$emptyMethod(b * 3); 147 } else { 148 result += $noinline$emptyMethod(a * 2); 149 } 150 return result; 151 } 152 153 // In this scenario, we have a BooleanNot before the If instructions so we have to wait until 154 // the following pass to perform the optimization. The BooleanNot is dead at this time (even 155 // when starting DCE), but RemoveDeadInstructions runs after SimplifyIfs so the optimization 156 // doesn't trigger. 157 158 /// CHECK-START: int Main.$noinline$testEliminateIfParameter(int, int, boolean) dead_code_elimination$initial (before) 159 /// CHECK: BooleanNot 160 /// CHECK: If 161 /// CHECK: BooleanNot 162 /// CHECK: If 163 164 /// CHECK-START: int Main.$noinline$testEliminateIfParameter(int, int, boolean) dead_code_elimination$initial (after) 165 /// CHECK: If 166 /// CHECK: Phi 167 /// CHECK: If 168 169 /// CHECK-START: int Main.$noinline$testEliminateIfParameter(int, int, boolean) dead_code_elimination$initial (after) 170 /// CHECK-NOT: BooleanNot 171 172 /// CHECK-START: int Main.$noinline$testEliminateIfParameter(int, int, boolean) dead_code_elimination$after_gvn (before) 173 /// CHECK: If 174 /// CHECK: Phi 175 /// CHECK: If 176 177 /// CHECK-START: int Main.$noinline$testEliminateIfParameter(int, int, boolean) dead_code_elimination$after_gvn (after) 178 /// CHECK: If 179 /// CHECK-NOT: If $noinline$testEliminateIfParameter(int a, int b, boolean condition)180 private static int $noinline$testEliminateIfParameter(int a, int b, boolean condition) { 181 int result = 0; 182 if (condition) { 183 $noinline$emptyMethod(a + b); 184 } else { 185 $noinline$emptyMethod(a - b); 186 } 187 if (condition) { 188 result += $noinline$emptyMethod(a * 2); 189 } else { 190 result += $noinline$emptyMethod(b * 3); 191 } 192 return result; 193 } 194 195 // Same in the following two cases: we do it in dead_code_elimination$initial since GVN is not 196 // needed. 197 198 /// CHECK-START: int Main.$noinline$testEliminateIfParameterReverseCondition(int, int, boolean) dead_code_elimination$initial (before) 199 /// CHECK: If 200 /// CHECK: If 201 202 /// CHECK-START: int Main.$noinline$testEliminateIfParameterReverseCondition(int, int, boolean) dead_code_elimination$initial (after) 203 /// CHECK: If 204 /// CHECK-NOT: If $noinline$testEliminateIfParameterReverseCondition( int a, int b, boolean condition)205 private static int $noinline$testEliminateIfParameterReverseCondition( 206 int a, int b, boolean condition) { 207 int result = 0; 208 if (!condition) { 209 $noinline$emptyMethod(a + b); 210 } else { 211 $noinline$emptyMethod(a - b); 212 } 213 if (!condition) { 214 result += $noinline$emptyMethod(b * 3); 215 } else { 216 result += $noinline$emptyMethod(a * 2); 217 } 218 return result; 219 } 220 221 /// CHECK-START: int Main.$noinline$testEliminateIfParameterOppositeCondition(int, int, boolean) dead_code_elimination$initial (before) 222 /// CHECK: If 223 /// CHECK: If 224 225 /// CHECK-START: int Main.$noinline$testEliminateIfParameterOppositeCondition(int, int, boolean) dead_code_elimination$initial (after) 226 /// CHECK: If 227 /// CHECK-NOT: If $noinline$testEliminateIfParameterOppositeCondition( int a, int b, boolean condition)228 private static int $noinline$testEliminateIfParameterOppositeCondition( 229 int a, int b, boolean condition) { 230 int result = 0; 231 if (condition) { 232 $noinline$emptyMethod(a + b); 233 } else { 234 $noinline$emptyMethod(a - b); 235 } 236 if (!condition) { 237 result += $noinline$emptyMethod(b * 3); 238 } else { 239 result += $noinline$emptyMethod(a * 2); 240 } 241 return result; 242 } 243 244 // In this scenario, we have a BooleanNot before the If instructions so we have to wait until 245 // the following pass to perform the optimization. The BooleanNot is dead at this time (even 246 // when starting DCE), but RemoveDeadInstructions runs after SimplifyIfs so the optimization 247 // doesn't trigger. 248 249 /// CHECK-START: int Main.$noinline$testEliminateIfParameterOppositeCondition_2(int, int, boolean) dead_code_elimination$initial (before) 250 /// CHECK: If 251 /// CHECK: BooleanNot 252 /// CHECK: If 253 254 /// CHECK-START: int Main.$noinline$testEliminateIfParameterOppositeCondition_2(int, int, boolean) dead_code_elimination$initial (after) 255 /// CHECK: If 256 /// CHECK: Phi 257 /// CHECK: If 258 259 /// CHECK-START: int Main.$noinline$testEliminateIfParameterOppositeCondition_2(int, int, boolean) dead_code_elimination$initial (after) 260 /// CHECK-NOT: BooleanNot 261 262 /// CHECK-START: int Main.$noinline$testEliminateIfParameterOppositeCondition_2(int, int, boolean) dead_code_elimination$after_gvn (before) 263 /// CHECK: If 264 /// CHECK: Phi 265 /// CHECK: If 266 267 /// CHECK-START: int Main.$noinline$testEliminateIfParameterOppositeCondition_2(int, int, boolean) dead_code_elimination$after_gvn (after) 268 /// CHECK: If 269 /// CHECK-NOT: If $noinline$testEliminateIfParameterOppositeCondition_2( int a, int b, boolean condition)270 private static int $noinline$testEliminateIfParameterOppositeCondition_2( 271 int a, int b, boolean condition) { 272 int result = 0; 273 if (!condition) { 274 $noinline$emptyMethod(a + b); 275 } else { 276 $noinline$emptyMethod(a - b); 277 } 278 if (condition) { 279 result += $noinline$emptyMethod(a * 2); 280 } else { 281 result += $noinline$emptyMethod(b * 3); 282 } 283 return result; 284 } 285 286 /// CHECK-START: int Main.$noinline$testEliminateIfFp(double, double) dead_code_elimination$after_gvn (before) 287 /// CHECK: If 288 /// CHECK: If 289 290 /// CHECK-START: int Main.$noinline$testEliminateIfFp(double, double) dead_code_elimination$after_gvn (after) 291 /// CHECK: If 292 /// CHECK-NOT: If $noinline$testEliminateIfFp(double a, double b)293 private static int $noinline$testEliminateIfFp(double a, double b) { 294 int result = 0; 295 if (a < b) { 296 $noinline$emptyMethod(0); 297 } else { 298 $noinline$emptyMethod(1); 299 } 300 if (a < b) { 301 result += $noinline$emptyMethod(2); 302 } else { 303 result += $noinline$emptyMethod(3); 304 } 305 return result; 306 } 307 308 /// CHECK-START: int Main.$noinline$testDoNotEliminateIfOppositeCondFpWrongBias(double, double) dead_code_elimination$initial (before) 309 /// CHECK: If 310 /// CHECK: If 311 312 /// CHECK-START: int Main.$noinline$testDoNotEliminateIfOppositeCondFpWrongBias(double, double) dead_code_elimination$initial (after) 313 /// CHECK: If 314 /// CHECK: If $noinline$testDoNotEliminateIfOppositeCondFpWrongBias(double a, double b)315 private static int $noinline$testDoNotEliminateIfOppositeCondFpWrongBias(double a, double b) { 316 int result = 0; 317 if (a < b) { 318 $noinline$emptyMethod(0); 319 } else { 320 $noinline$emptyMethod(1); 321 } 322 if (a >= b) { 323 result += $noinline$emptyMethod(2); 324 } else { 325 result += $noinline$emptyMethod(3); 326 } 327 return result; 328 } 329 assertEquals(int expected, int result)330 public static void assertEquals(int expected, int result) { 331 if (expected != result) { 332 throw new Error("Expected: " + expected + ", found: " + result); 333 } 334 } 335 } 336