1 /* 2 * Copyright (C) 2025 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 { 18 private int intField; 19 main(String[] args)20 public static void main(String[] args) { 21 System.out.print("IfXLtzAElseB(-7): "); 22 $noinline$IfXLtzAElseB(-7); 23 System.out.print("IfXLtzAElseB(42): "); 24 $noinline$IfXLtzAElseB(42); 25 26 System.out.print("IfXLtzAElseB_Move(-7): "); 27 new Main().$noinline$IfXLtzAElseB_Move(-7); 28 System.out.print("IfXLtzAElseB_Move(42): "); 29 new Main().$noinline$IfXLtzAElseB_Move(42); 30 31 System.out.print("IfXLtzAElseB_EnvUse(-7): "); 32 $noinline$IfXLtzAElseB_EnvUse(-7); 33 System.out.print("IfXLtzAElseB_EnvUse(42): "); 34 $noinline$IfXLtzAElseB_EnvUse(42); 35 36 System.out.print("IfXNullAElseB(null): "); 37 $noinline$IfXNullAElseB(null); 38 System.out.print("IfXNullAElseB(new Object()): "); 39 $noinline$IfXNullAElseB(new Object()); 40 41 System.out.print("IfXNullAElseB_Move(null): "); 42 new Main().$noinline$IfXNullAElseB_Move(null); 43 System.out.print("IfXNullAElseB_Move(new Object()): "); 44 new Main().$noinline$IfXNullAElseB_Move(new Object()); 45 46 System.out.print("IfXNullAElseB_EnvUse(null): "); 47 new Main().$noinline$IfXNullAElseB_EnvUse(null); 48 System.out.print("IfXNullAElseB_EnvUse(new Object()): "); 49 new Main().$noinline$IfXNullAElseB_EnvUse(new Object()); 50 51 System.out.print("IfXNullAElseB_RefNoEnvInBlock(null, true): "); 52 new Main().$noinline$IfXNullAElseB_RefNoEnvInBlock(null, true); 53 System.out.print("IfXNullAElseB_RefNoEnvInBlock(new Object(), true): "); 54 new Main().$noinline$IfXNullAElseB_RefNoEnvInBlock(new Object(), true); 55 System.out.print("IfXNullAElseB_RefNoEnvInBlock(null, false): "); 56 new Main().$noinline$IfXNullAElseB_RefNoEnvInBlock(null, false); 57 System.out.print("IfXNullAElseB_RefNoEnvInBlock(new Object(), false): "); 58 new Main().$noinline$IfXNullAElseB_RefNoEnvInBlock(new Object(), false); 59 60 System.out.print("IfLt7_0AElseB_86LoadFromConstantTable(2.0, true): "); 61 new Main().$noinline$IfLt7_0AElseB_86LoadFromConstantTable(2.0, true); 62 System.out.print("IfLt7_0AElseB_86LoadFromConstantTable(10.0, true): "); 63 new Main().$noinline$IfLt7_0AElseB_86LoadFromConstantTable(10.0, true); 64 System.out.print("IfLt7_0AElseB_86LoadFromConstantTable(2.0, false): "); 65 new Main().$noinline$IfLt7_0AElseB_86LoadFromConstantTable(2.0, false); 66 System.out.print("IfLt7_0AElseB_86LoadFromConstantTable(10.0, false): "); 67 new Main().$noinline$IfLt7_0AElseB_86LoadFromConstantTable(10.0, false); 68 69 // Note: We do not test the code paths where `ConditionMoveWouldExtendReferenceLifetime()` 70 // in the "prepare_for_register_allocation" pass finds an instruction with environment 71 // between the `HCondition` and its user in this run-test. These are difficult to create 72 // from Java code and changes to other passes can easily invalidate such tests. Therefore 73 // we defer to using gtests for these cases. 74 } 75 $noinline$A()76 private static void $noinline$A() { 77 System.out.println("A"); 78 } 79 $noinline$B()80 private static void $noinline$B() { 81 System.out.println("B"); 82 } 83 $noinline$C()84 private static void $noinline$C() { 85 System.out.println("C"); 86 } 87 $inline$XLtz(int x)88 private static boolean $inline$XLtz(int x) { 89 // After inlining, this shall be turned to a `HSelect` and then simplified as `HLessThan`. 90 return x < 0; 91 } 92 $inline$XNull(Object x)93 private static boolean $inline$XNull(Object x) { 94 // After inlining, this shall be turned to a `HSelect` and then simplified as `HEqual`. 95 return x == null; 96 } 97 $inline$XLt7_0(double x)98 private static boolean $inline$XLt7_0(double x) { 99 return x < 7.0; 100 } 101 $noinline$ignore(int ignored)102 private static void $noinline$ignore(int ignored) {} 103 104 /// CHECK-START: void Main.$noinline$IfXLtzAElseB(int) prepare_for_register_allocation (before) 105 /// CHECK: <<Cond:z\d+>> {{GreaterThanOrEqual|LessThan}} emitted_at_use_site:false 106 /// CHECK-NEXT: If [<<Cond>>] 107 108 /// CHECK-START: void Main.$noinline$IfXLtzAElseB(int) prepare_for_register_allocation (after) 109 /// CHECK: <<Cond:z\d+>> {{GreaterThanOrEqual|LessThan}} emitted_at_use_site:true 110 /// CHECK-NEXT: If [<<Cond>>] 111 $noinline$IfXLtzAElseB(int x)112 public static void $noinline$IfXLtzAElseB(int x) { 113 if (x < 0) { 114 $noinline$A(); 115 } else { 116 $noinline$B(); 117 } 118 } 119 120 /// CHECK-START: void Main.$noinline$IfXLtzAElseB_Move(int) prepare_for_register_allocation (before) 121 /// CHECK: <<Cond:z\d+>> LessThan emitted_at_use_site:false 122 /// CHECK-NEXT: InstanceFieldGet 123 // On X86, there can be also X86ComputeBaseMethodAddress here. 124 /// CHECK: If [<<Cond>>] 125 126 /// CHECK-START: void Main.$noinline$IfXLtzAElseB_Move(int) prepare_for_register_allocation (after) 127 /// CHECK: InstanceFieldGet 128 // On X86, there can be also X86ComputeBaseMethodAddress here. 129 /// CHECK: <<Cond:z\d+>> LessThan emitted_at_use_site:true 130 /// CHECK-NEXT: If [<<Cond>>] 131 $noinline$IfXLtzAElseB_Move(int x)132 public void $noinline$IfXLtzAElseB_Move(int x) { 133 boolean cond = $inline$XLtz(x); 134 135 int value = intField; 136 if (cond) { 137 cond = false; // Avoid environment use below. 138 $noinline$A(); 139 } else { 140 cond = false; // Avoid environment use below. 141 $noinline$B(); 142 } 143 $noinline$ignore(value); 144 } 145 146 /// CHECK-START: void Main.$noinline$IfXLtzAElseB_EnvUse(int) prepare_for_register_allocation (before) 147 /// CHECK: LessThan emitted_at_use_site:false 148 149 /// CHECK-START: void Main.$noinline$IfXLtzAElseB_EnvUse(int) prepare_for_register_allocation (after) 150 /// CHECK-DAG: <<Cond:z\d+>> LessThan emitted_at_use_site:false 151 // Match an environment use. Use the fact that the <<Cond>> is in vreg 0. Otherwise we'd 152 // need to add a regex to match the earlier vregs which is difficult due to a regex eagerly 153 // consuming as much as possible but it could be curtailed by using the fact that there 154 // are no other boolean (`z`) values in the graph, for example with `{{([^z,]+,)*}}`. This 155 // would be much easier if we could put a variable inside the regex and make the entire 156 // env uses a single regex, `env:[[{{([^,]+,)*<<Cond>>(,[^,\]]+)*}}]]`. 157 /// CHECK-DAG: InvokeStaticOrDirect env:[[<<Cond>>{{(,[^,\]]+)*}}]] 158 $noinline$IfXLtzAElseB_EnvUse(int x)159 public static void $noinline$IfXLtzAElseB_EnvUse(int x) { 160 boolean cond = $inline$XLtz(x); 161 if (cond) { 162 $noinline$A(); 163 } else { 164 $noinline$B(); 165 } 166 } 167 168 /// CHECK-START: void Main.$noinline$IfXNullAElseB(java.lang.Object) prepare_for_register_allocation (before) 169 /// CHECK: <<Cond:z\d+>> {{Equal|NotEqual}} emitted_at_use_site:false 170 /// CHECK-NEXT: If [<<Cond>>] 171 172 /// CHECK-START: void Main.$noinline$IfXNullAElseB(java.lang.Object) prepare_for_register_allocation (after) 173 /// CHECK: <<Cond:z\d+>> {{Equal|NotEqual}} emitted_at_use_site:true 174 /// CHECK-NEXT: If [<<Cond>>] 175 $noinline$IfXNullAElseB(Object x)176 public static void $noinline$IfXNullAElseB(Object x) { 177 if (x == null) { 178 $noinline$A(); 179 } else { 180 $noinline$B(); 181 } 182 } 183 184 /// CHECK-START: void Main.$noinline$IfXNullAElseB_Move(java.lang.Object) prepare_for_register_allocation (before) 185 /// CHECK: <<Cond:z\d+>> Equal emitted_at_use_site:false 186 /// CHECK-NEXT: InstanceFieldGet 187 // On X86, there can be also X86ComputeBaseMethodAddress here. 188 /// CHECK: If [<<Cond>>] 189 190 /// CHECK-START: void Main.$noinline$IfXNullAElseB_Move(java.lang.Object) prepare_for_register_allocation (after) 191 /// CHECK: InstanceFieldGet 192 // On X86, there can be also X86ComputeBaseMethodAddress here. 193 /// CHECK: <<Cond:z\d+>> Equal emitted_at_use_site:true 194 /// CHECK-NEXT: If [<<Cond>>] 195 $noinline$IfXNullAElseB_Move(Object x)196 public void $noinline$IfXNullAElseB_Move(Object x) { 197 boolean cond = $inline$XNull(x); 198 199 int value = intField; 200 if (cond) { 201 cond = false; // Avoid environment use below. 202 $noinline$A(); 203 } else { 204 cond = false; // Avoid environment use below. 205 $noinline$B(); 206 } 207 $noinline$ignore(value); 208 } 209 210 /// CHECK-START: void Main.$noinline$IfXNullAElseB_EnvUse(java.lang.Object) prepare_for_register_allocation (before) 211 /// CHECK: Equal emitted_at_use_site:false 212 213 /// CHECK-START: void Main.$noinline$IfXNullAElseB_EnvUse(java.lang.Object) prepare_for_register_allocation (after) 214 /// CHECK: Equal emitted_at_use_site:false 215 $noinline$IfXNullAElseB_EnvUse(Object x)216 public static void $noinline$IfXNullAElseB_EnvUse(Object x) { 217 boolean cond = $inline$XNull(x); 218 if (cond) { 219 $noinline$A(); 220 } else { 221 $noinline$B(); 222 } 223 } 224 225 /// CHECK-START: void Main.$noinline$IfXNullAElseB_RefNoEnvInBlock(java.lang.Object, boolean) prepare_for_register_allocation (before) 226 /// CHECK: <<Cond:z\d+>> {{Equal|NotEqual}} emitted_at_use_site:false 227 /// CHECK: If [<<Cond>>] 228 229 /// CHECK-START: void Main.$noinline$IfXNullAElseB_RefNoEnvInBlock(java.lang.Object, boolean) prepare_for_register_allocation (after) 230 /// CHECK: <<Cond:z\d+>> {{Equal|NotEqual}} emitted_at_use_site:false 231 /// CHECK: If [<<Cond>>] 232 $noinline$IfXNullAElseB_RefNoEnvInBlock(Object x, boolean otherCond)233 public static void $noinline$IfXNullAElseB_RefNoEnvInBlock(Object x, boolean otherCond) { 234 boolean cond = $inline$XNull(x); 235 if (otherCond) { 236 if (cond) { 237 cond = false; // Avoid environment use below. 238 $noinline$A(); 239 } else { 240 cond = false; // Avoid environment use below. 241 $noinline$B(); 242 } 243 } else { 244 cond = false; // Avoid environment use below. 245 $noinline$C(); 246 } 247 } 248 249 /// CHECK-START: void Main.$noinline$IfLt7_0AElseB_86LoadFromConstantTable(double, boolean) prepare_for_register_allocation (before) 250 /// CHECK: <<Cond:z\d+>> {{LessThan|GreaterThanOrEqual}} emitted_at_use_site:false 251 /// CHECK: If [<<Cond>>] 252 253 /// CHECK-START: void Main.$noinline$IfLt7_0AElseB_86LoadFromConstantTable(double, boolean) prepare_for_register_allocation (after) 254 /// CHECK: <<Cond:z\d+>> {{LessThan|GreaterThanOrEqual}} emitted_at_use_site:true 255 /// CHECK-NEXT: If [<<Cond>>] 256 257 /// CHECK-START-X86: void Main.$noinline$IfLt7_0AElseB_86LoadFromConstantTable(double, boolean) prepare_for_register_allocation (after) 258 /// CHECK: X86ComputeBaseMethodAddress 259 // Note: X86ComputeBaseMethodAddress is not moved before X86LoadFromConstantTable because 260 // it has additional uses in all the `$noinline$` invokes. 261 /// CHECK: X86LoadFromConstantTable 262 /// CHECK-NEXT: <<Cond:z\d+>> {{LessThan|GreaterThanOrEqual}} emitted_at_use_site:true 263 /// CHECK-NEXT: If [<<Cond>>] 264 265 /// CHECK-START-X86: void Main.$noinline$IfLt7_0AElseB_86LoadFromConstantTable(double, boolean) prepare_for_register_allocation (after) 266 /// CHECK-DAG: <<MA:i\d+>> X86ComputeBaseMethodAddress 267 /// CHECK-DAG: InvokeStaticOrDirect [<<MA>>] 268 $noinline$IfLt7_0AElseB_86LoadFromConstantTable( double x, boolean otherCond)269 public static void $noinline$IfLt7_0AElseB_86LoadFromConstantTable( 270 double x, boolean otherCond) { 271 boolean cond = $inline$XLt7_0(x); 272 if (otherCond) { 273 if (cond) { 274 cond = false; // Avoid environment use below. 275 $noinline$A(); 276 } else { 277 cond = false; // Avoid environment use below. 278 $noinline$B(); 279 } 280 } else { 281 cond = false; // Avoid environment use below. 282 $noinline$C(); 283 } 284 } 285 } 286