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