1 /* 2 * Copyright (C) 2016 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 19 // A dummy value to defeat inlining of these routines. 20 static boolean doThrow = false; 21 assertIntEquals(int expected, int result)22 public static void assertIntEquals(int expected, int result) { 23 if (expected != result) { 24 throw new Error("Expected: " + expected + ", found: " + result); 25 } 26 } 27 assertLongEquals(long expected, long result)28 public static void assertLongEquals(long expected, long result) { 29 if (expected != result) { 30 throw new Error("Expected: " + expected + ", found: " + result); 31 } 32 } 33 34 /** 35 * Test transformation of Not/Not/And into Or/Not. 36 */ 37 38 /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (before) 39 /// CHECK: <<P1:i\d+>> ParameterValue 40 /// CHECK: <<P2:i\d+>> ParameterValue 41 /// CHECK: <<Not1:i\d+>> Not [<<P1>>] 42 /// CHECK: <<Not2:i\d+>> Not [<<P2>>] 43 /// CHECK: <<And:i\d+>> And [<<Not1>>,<<Not2>>] 44 /// CHECK: Return [<<And>>] 45 46 /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after) 47 /// CHECK: <<P1:i\d+>> ParameterValue 48 /// CHECK: <<P2:i\d+>> ParameterValue 49 /// CHECK: <<Or:i\d+>> Or [<<P1>>,<<P2>>] 50 /// CHECK: <<Not:i\d+>> Not [<<Or>>] 51 /// CHECK: Return [<<Not>>] 52 53 /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after) 54 /// CHECK: Not 55 /// CHECK-NOT: Not 56 57 /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after) 58 /// CHECK-NOT: And 59 $opt$noinline$andToOr(int a, int b)60 public static int $opt$noinline$andToOr(int a, int b) { 61 if (doThrow) throw new Error(); 62 return ~a & ~b; 63 } 64 65 /** 66 * Test transformation of Not/Not/And into Or/Not for boolean negations. 67 * Note that the graph before this instruction simplification pass does not 68 * contain `HBooleanNot` instructions. This is because this transformation 69 * follows the optimization of `HSelect` to `HBooleanNot` occurring in the 70 * same pass. 71 */ 72 73 /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (before) 74 /// CHECK: <<P1:z\d+>> ParameterValue 75 /// CHECK: <<P2:z\d+>> ParameterValue 76 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 77 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 78 /// CHECK: <<Select1:i\d+>> Select [<<Const1>>,<<Const0>>,<<P1>>] 79 /// CHECK: <<Select2:i\d+>> Select [<<Const1>>,<<Const0>>,<<P2>>] 80 /// CHECK: <<And:i\d+>> And [<<Select2>>,<<Select1>>] 81 /// CHECK: Return [<<And>>] 82 83 /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (after) 84 /// CHECK: <<Cond1:z\d+>> ParameterValue 85 /// CHECK: <<Cond2:z\d+>> ParameterValue 86 /// CHECK: <<Or:i\d+>> Or [<<Cond2>>,<<Cond1>>] 87 /// CHECK: <<BooleanNot:z\d+>> BooleanNot [<<Or>>] 88 /// CHECK: Return [<<BooleanNot>>] 89 90 /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (after) 91 /// CHECK: BooleanNot 92 /// CHECK-NOT: BooleanNot 93 94 /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (after) 95 /// CHECK-NOT: And 96 $opt$noinline$booleanAndToOr(boolean a, boolean b)97 public static boolean $opt$noinline$booleanAndToOr(boolean a, boolean b) { 98 if (doThrow) throw new Error(); 99 return !a & !b; 100 } 101 102 /** 103 * Test transformation of Not/Not/Or into And/Not. 104 */ 105 106 /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (before) 107 /// CHECK: <<P1:j\d+>> ParameterValue 108 /// CHECK: <<P2:j\d+>> ParameterValue 109 /// CHECK: <<Not1:j\d+>> Not [<<P1>>] 110 /// CHECK: <<Not2:j\d+>> Not [<<P2>>] 111 /// CHECK: <<Or:j\d+>> Or [<<Not1>>,<<Not2>>] 112 /// CHECK: Return [<<Or>>] 113 114 /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after) 115 /// CHECK: <<P1:j\d+>> ParameterValue 116 /// CHECK: <<P2:j\d+>> ParameterValue 117 /// CHECK: <<And:j\d+>> And [<<P1>>,<<P2>>] 118 /// CHECK: <<Not:j\d+>> Not [<<And>>] 119 /// CHECK: Return [<<Not>>] 120 121 /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after) 122 /// CHECK: Not 123 /// CHECK-NOT: Not 124 125 /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after) 126 /// CHECK-NOT: Or 127 $opt$noinline$orToAnd(long a, long b)128 public static long $opt$noinline$orToAnd(long a, long b) { 129 if (doThrow) throw new Error(); 130 return ~a | ~b; 131 } 132 133 /** 134 * Test transformation of Not/Not/Or into Or/And for boolean negations. 135 * Note that the graph before this instruction simplification pass does not 136 * contain `HBooleanNot` instructions. This is because this transformation 137 * follows the optimization of `HSelect` to `HBooleanNot` occurring in the 138 * same pass. 139 */ 140 141 /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (before) 142 /// CHECK: <<P1:z\d+>> ParameterValue 143 /// CHECK: <<P2:z\d+>> ParameterValue 144 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 145 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 146 /// CHECK: <<Select1:i\d+>> Select [<<Const1>>,<<Const0>>,<<P1>>] 147 /// CHECK: <<Select2:i\d+>> Select [<<Const1>>,<<Const0>>,<<P2>>] 148 /// CHECK: <<Or:i\d+>> Or [<<Select2>>,<<Select1>>] 149 /// CHECK: Return [<<Or>>] 150 151 /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (after) 152 /// CHECK: <<Cond1:z\d+>> ParameterValue 153 /// CHECK: <<Cond2:z\d+>> ParameterValue 154 /// CHECK: <<And:i\d+>> And [<<Cond2>>,<<Cond1>>] 155 /// CHECK: <<BooleanNot:z\d+>> BooleanNot [<<And>>] 156 /// CHECK: Return [<<BooleanNot>>] 157 158 /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (after) 159 /// CHECK: BooleanNot 160 /// CHECK-NOT: BooleanNot 161 162 /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (after) 163 /// CHECK-NOT: Or 164 $opt$noinline$booleanOrToAnd(boolean a, boolean b)165 public static boolean $opt$noinline$booleanOrToAnd(boolean a, boolean b) { 166 if (doThrow) throw new Error(); 167 return !a | !b; 168 } 169 170 /** 171 * Test that the transformation copes with inputs being separated from the 172 * bitwise operations. 173 * This is a regression test. The initial logic was inserting the new bitwise 174 * operation incorrectly. 175 */ 176 177 /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (before) 178 /// CHECK: <<P1:i\d+>> ParameterValue 179 /// CHECK: <<P2:i\d+>> ParameterValue 180 /// CHECK: <<Cst1:i\d+>> IntConstant 1 181 /// CHECK: <<AddP1:i\d+>> Add [<<P1>>,<<Cst1>>] 182 /// CHECK: <<Not1:i\d+>> Not [<<AddP1>>] 183 /// CHECK: <<AddP2:i\d+>> Add [<<P2>>,<<Cst1>>] 184 /// CHECK: <<Not2:i\d+>> Not [<<AddP2>>] 185 /// CHECK: <<Or:i\d+>> Or [<<Not1>>,<<Not2>>] 186 /// CHECK: Return [<<Or>>] 187 188 /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after) 189 /// CHECK: <<P1:i\d+>> ParameterValue 190 /// CHECK: <<P2:i\d+>> ParameterValue 191 /// CHECK: <<Cst1:i\d+>> IntConstant 1 192 /// CHECK: <<AddP1:i\d+>> Add [<<P1>>,<<Cst1>>] 193 /// CHECK: <<AddP2:i\d+>> Add [<<P2>>,<<Cst1>>] 194 /// CHECK: <<And:i\d+>> And [<<AddP1>>,<<AddP2>>] 195 /// CHECK: <<Not:i\d+>> Not [<<And>>] 196 /// CHECK: Return [<<Not>>] 197 198 /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after) 199 /// CHECK: Not 200 /// CHECK-NOT: Not 201 202 /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after) 203 /// CHECK-NOT: Or 204 $opt$noinline$regressInputsAway(int a, int b)205 public static int $opt$noinline$regressInputsAway(int a, int b) { 206 if (doThrow) throw new Error(); 207 int a1 = a + 1; 208 int not_a1 = ~a1; 209 int b1 = b + 1; 210 int not_b1 = ~b1; 211 return not_a1 | not_b1; 212 } 213 214 /** 215 * Test transformation of Not/Not/Xor into Xor. 216 */ 217 218 // See first note above. 219 /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (before) 220 /// CHECK: <<P1:i\d+>> ParameterValue 221 /// CHECK: <<P2:i\d+>> ParameterValue 222 /// CHECK: <<Not1:i\d+>> Not [<<P1>>] 223 /// CHECK: <<Not2:i\d+>> Not [<<P2>>] 224 /// CHECK: <<Xor:i\d+>> Xor [<<Not1>>,<<Not2>>] 225 /// CHECK: Return [<<Xor>>] 226 227 /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after) 228 /// CHECK: <<P1:i\d+>> ParameterValue 229 /// CHECK: <<P2:i\d+>> ParameterValue 230 /// CHECK: <<Xor:i\d+>> Xor [<<P1>>,<<P2>>] 231 /// CHECK: Return [<<Xor>>] 232 233 /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after) 234 /// CHECK-NOT: Not 235 $opt$noinline$notXorToXor(int a, int b)236 public static int $opt$noinline$notXorToXor(int a, int b) { 237 if (doThrow) throw new Error(); 238 return ~a ^ ~b; 239 } 240 241 /** 242 * Test transformation of Not/Not/Xor into Xor for boolean negations. 243 * Note that the graph before this instruction simplification pass does not 244 * contain `HBooleanNot` instructions. This is because this transformation 245 * follows the optimization of `HSelect` to `HBooleanNot` occurring in the 246 * same pass. 247 */ 248 249 /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier_after_bce (before) 250 /// CHECK: <<P1:z\d+>> ParameterValue 251 /// CHECK: <<P2:z\d+>> ParameterValue 252 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 253 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 254 /// CHECK: <<Select1:i\d+>> Select [<<Const1>>,<<Const0>>,<<P1>>] 255 /// CHECK: <<Select2:i\d+>> Select [<<Const1>>,<<Const0>>,<<P2>>] 256 /// CHECK: <<Xor:i\d+>> Xor [<<Select2>>,<<Select1>>] 257 /// CHECK: Return [<<Xor>>] 258 259 /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier_after_bce (after) 260 /// CHECK: <<Cond1:z\d+>> ParameterValue 261 /// CHECK: <<Cond2:z\d+>> ParameterValue 262 /// CHECK: <<Xor:i\d+>> Xor [<<Cond2>>,<<Cond1>>] 263 /// CHECK: Return [<<Xor>>] 264 265 /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier_after_bce (after) 266 /// CHECK-NOT: BooleanNot 267 $opt$noinline$booleanNotXorToXor(boolean a, boolean b)268 public static boolean $opt$noinline$booleanNotXorToXor(boolean a, boolean b) { 269 if (doThrow) throw new Error(); 270 return !a ^ !b; 271 } 272 273 /** 274 * Check that no transformation is done when one Not has multiple uses. 275 */ 276 277 /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (before) 278 /// CHECK: <<P1:i\d+>> ParameterValue 279 /// CHECK: <<P2:i\d+>> ParameterValue 280 /// CHECK: <<One:i\d+>> IntConstant 1 281 /// CHECK: <<Not2:i\d+>> Not [<<P2>>] 282 /// CHECK: <<And2:i\d+>> And [<<Not2>>,<<One>>] 283 /// CHECK: <<Not1:i\d+>> Not [<<P1>>] 284 /// CHECK: <<And1:i\d+>> And [<<Not1>>,<<Not2>>] 285 /// CHECK: <<Add:i\d+>> Add [<<And2>>,<<And1>>] 286 /// CHECK: Return [<<Add>>] 287 288 /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after) 289 /// CHECK: <<P1:i\d+>> ParameterValue 290 /// CHECK: <<P2:i\d+>> ParameterValue 291 /// CHECK: <<One:i\d+>> IntConstant 1 292 /// CHECK: <<Not2:i\d+>> Not [<<P2>>] 293 /// CHECK: <<And2:i\d+>> And [<<Not2>>,<<One>>] 294 /// CHECK: <<Not1:i\d+>> Not [<<P1>>] 295 /// CHECK: <<And1:i\d+>> And [<<Not1>>,<<Not2>>] 296 /// CHECK: <<Add:i\d+>> Add [<<And2>>,<<And1>>] 297 /// CHECK: Return [<<Add>>] 298 299 /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after) 300 /// CHECK-NOT: Or 301 $opt$noinline$notMultipleUses(int a, int b)302 public static int $opt$noinline$notMultipleUses(int a, int b) { 303 if (doThrow) throw new Error(); 304 int tmp = ~b; 305 return (tmp & 0x1) + (~a & tmp); 306 } 307 main(String[] args)308 public static void main(String[] args) { 309 assertIntEquals(~0xff, $opt$noinline$andToOr(0xf, 0xff)); 310 assertLongEquals(~0xf, $opt$noinline$orToAnd(0xf, 0xff)); 311 assertIntEquals(0xf0, $opt$noinline$notXorToXor(0xf, 0xff)); 312 assertIntEquals(~0xff, $opt$noinline$notMultipleUses(0xf, 0xff)); 313 } 314 } 315