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 TypeConversions { 18 static byte static_byte; 19 static char static_char; 20 static int static_int; 21 static int unrelated_static_int; 22 assertIntEquals(int expected, int result)23 public static void assertIntEquals(int expected, int result) { 24 if (expected != result) { 25 throw new Error("Expected: " + expected + ", found: " + result); 26 } 27 } 28 29 /// CHECK-START: int TypeConversions.$noinline$loopPhiStoreLoadConversionInt8(int) load_store_elimination (before) 30 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 31 // The type conversion has already been eliminated. 32 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<Value>>] field_name:TypeConversions.static_byte 33 /// CHECK-DAG: StaticFieldSet field_name:TypeConversions.unrelated_static_int loop:B{{\d+}} 34 /// CHECK-DAG: <<GetB:b\d+>> StaticFieldGet field_name:TypeConversions.static_byte 35 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetB>>] field_name:TypeConversions.static_int 36 /// CHECK-DAG: <<GetI:i\d+>> StaticFieldGet field_name:TypeConversions.static_int field_type:Int32 37 /// CHECK-DAG: Return [<<GetI>>] 38 39 /// CHECK-START: int TypeConversions.$noinline$loopPhiStoreLoadConversionInt8(int) load_store_elimination (after) 40 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 41 /// CHECK-DAG: <<Conv:b\d+>> TypeConversion [<<Value>>] 42 /// CHECK-DAG: Return [<<Conv>>] 43 44 /// CHECK-START: int TypeConversions.$noinline$loopPhiStoreLoadConversionInt8(int) load_store_elimination (after) 45 /// CHECK-NOT: StaticFieldGet $noinline$loopPhiStoreLoadConversionInt8(int value)46 public static int $noinline$loopPhiStoreLoadConversionInt8(int value) { 47 static_byte = (byte) value; 48 // Irrelevant code but needed to make LSE use loop Phi placeholders. 49 for (int q = 1; q < 12; q++) { 50 unrelated_static_int = 24; 51 } 52 static_int = static_byte; 53 return static_int; 54 } 55 56 /// CHECK-START: int TypeConversions.$noinline$loopPhiStoreLoadConversionUint8(int) load_store_elimination (before) 57 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 58 // The type conversion has already been eliminated. 59 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<Value>>] field_name:TypeConversions.static_byte 60 /// CHECK-DAG: StaticFieldSet field_name:TypeConversions.unrelated_static_int loop:B{{\d+}} 61 // The `& 0xff` has already been merged with the load. 62 /// CHECK-DAG: <<GetA:a\d+>> StaticFieldGet field_name:TypeConversions.static_byte 63 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetA>>] field_name:TypeConversions.static_int 64 /// CHECK-DAG: <<GetI:i\d+>> StaticFieldGet field_name:TypeConversions.static_int field_type:Int32 65 /// CHECK-DAG: Return [<<GetI>>] 66 67 /// CHECK-START: int TypeConversions.$noinline$loopPhiStoreLoadConversionUint8(int) load_store_elimination (after) 68 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 69 /// CHECK-DAG: <<Conv:a\d+>> TypeConversion [<<Value>>] 70 /// CHECK-DAG: Return [<<Conv>>] 71 72 /// CHECK-START: int TypeConversions.$noinline$loopPhiStoreLoadConversionUint8(int) load_store_elimination (after) 73 /// CHECK-NOT: StaticFieldGet $noinline$loopPhiStoreLoadConversionUint8(int value)74 public static int $noinline$loopPhiStoreLoadConversionUint8(int value) { 75 static_byte = (byte) value; 76 // Irrelevant code but needed to make LSE use loop Phi placeholders. 77 for (int q = 1; q < 12; q++) { 78 unrelated_static_int = 24; 79 } 80 static_int = static_byte & 0xff; 81 return static_int; 82 } 83 84 /// CHECK-START: int TypeConversions.$noinline$loopPhiTwoStoreLoadConversions(int) load_store_elimination (before) 85 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 86 // The type conversion has already been eliminated. 87 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<Value>>] field_name:TypeConversions.static_byte 88 /// CHECK-DAG: StaticFieldSet field_name:TypeConversions.unrelated_static_int loop:B{{\d+}} 89 /// CHECK-DAG: <<GetB:b\d+>> StaticFieldGet field_name:TypeConversions.static_byte 90 // The type conversion has already been eliminated. 91 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetB>>] field_name:TypeConversions.static_int 92 /// CHECK-DAG: <<GetI1:i\d+>> StaticFieldGet field_name:TypeConversions.static_int field_type:Int32 93 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetI1>>] field_name:TypeConversions.static_char 94 /// CHECK-DAG: <<GetC:c\d+>> StaticFieldGet field_name:TypeConversions.static_char field_type:Uint16 95 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetC>>] field_name:TypeConversions.static_int 96 /// CHECK-DAG: <<GetI2:i\d+>> StaticFieldGet field_name:TypeConversions.static_int field_type:Int32 97 /// CHECK-DAG: Return [<<GetI2>>] 98 99 /// CHECK-START: int TypeConversions.$noinline$loopPhiTwoStoreLoadConversions(int) load_store_elimination (after) 100 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 101 /// CHECK-DAG: <<ConvB:b\d+>> TypeConversion [<<Value>>] 102 /// CHECK-DAG: <<ConvC:c\d+>> TypeConversion [<<ConvB>>] 103 /// CHECK-DAG: Return [<<ConvC>>] 104 105 /// CHECK-START: int TypeConversions.$noinline$loopPhiTwoStoreLoadConversions(int) load_store_elimination (after) 106 /// CHECK-NOT: StaticFieldGet $noinline$loopPhiTwoStoreLoadConversions(int value)107 public static int $noinline$loopPhiTwoStoreLoadConversions(int value) { 108 static_byte = (byte) value; 109 // Irrelevant code but needed to make LSE use loop Phi placeholders. 110 for (int q = 1; q < 12; q++) { 111 unrelated_static_int = 24; 112 } 113 // Note: We need to go through `static_int` so that the instruction 114 // simplifier eliminates the type conversion to `char`. 115 // TODO: Improve the instruction simplifier to eliminate the conversion 116 // for `static_char = (char) static_byte`. 117 static_int = static_byte; 118 static_char = (char) static_int; 119 static_int = static_char; 120 return static_int; 121 } 122 123 /// CHECK-START: int TypeConversions.$noinline$conditionalStoreLoadConversionInt8InLoop(int, boolean) load_store_elimination (before) 124 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 125 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<Value>>] field_name:TypeConversions.static_int 126 /// CHECK-DAG: <<GetI:i\d+>> StaticFieldGet field_name:TypeConversions.static_int field_type:Int32 loop:<<Loop:B\d+>> 127 // The type conversion has already been eliminated. 128 /// CHECK-DAG: StaticFieldSet field_name:TypeConversions.static_byte loop:<<Loop>> 129 /// CHECK-DAG: <<GetB:b\d+>> StaticFieldGet field_name:TypeConversions.static_byte loop:<<Loop>> 130 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetB>>] field_name:TypeConversions.static_int loop:<<Loop>> 131 /// CHECK-DAG: <<GetI2:i\d+>> StaticFieldGet field_name:TypeConversions.static_int field_type:Int32 loop:none 132 /// CHECK-DAG: Return [<<GetI2>>] 133 134 /// CHECK-START: int TypeConversions.$noinline$conditionalStoreLoadConversionInt8InLoop(int, boolean) load_store_elimination (after) 135 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 136 /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Value>>,<<Phi2:i\d+>>] loop:<<Loop:B\d+>> 137 /// CHECK-DAG: <<Conv:b\d+>> TypeConversion [<<Phi1>>] loop:<<Loop>> 138 /// CHECK-DAG: <<Phi2>> Phi [<<Phi1>>,<<Conv>>] loop:<<Loop>> 139 /// CHECK-DAG: Return [<<Phi1>>] 140 141 /// CHECK-START: int TypeConversions.$noinline$conditionalStoreLoadConversionInt8InLoop(int, boolean) load_store_elimination (after) 142 /// CHECK-NOT: StaticFieldGet $noinline$conditionalStoreLoadConversionInt8InLoop(int value, boolean cond)143 public static int $noinline$conditionalStoreLoadConversionInt8InLoop(int value, boolean cond) { 144 static_int = value; 145 for (int q = 1; q < 12; q++) { 146 if (cond) { 147 static_byte = (byte) static_int; 148 static_int = static_byte; 149 } 150 } 151 return static_int; 152 } 153 154 /// CHECK-START: int TypeConversions.$noinline$conditionalStoreLoadConversionUint8InLoop(int, boolean) load_store_elimination (before) 155 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 156 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<Value>>] field_name:TypeConversions.static_int 157 /// CHECK-DAG: <<GetI1:i\d+>> StaticFieldGet field_name:TypeConversions.static_int field_type:Int32 loop:<<Loop:B\d+>> 158 // The type conversion has already been eliminated. 159 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetI1>>] field_name:TypeConversions.static_byte loop:<<Loop>> 160 /// CHECK-DAG: <<GetA:a\d+>> StaticFieldGet field_name:TypeConversions.static_byte loop:<<Loop>> 161 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetA>>] field_name:TypeConversions.static_int loop:<<Loop>> 162 /// CHECK-DAG: <<GetI2:i\d+>> StaticFieldGet field_name:TypeConversions.static_int field_type:Int32 loop:none 163 /// CHECK-DAG: Return [<<GetI2>>] 164 165 /// CHECK-START: int TypeConversions.$noinline$conditionalStoreLoadConversionUint8InLoop(int, boolean) load_store_elimination (after) 166 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 167 /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Value>>,<<Phi2:i\d+>>] loop:<<Loop:B\d+>> 168 /// CHECK-DAG: <<Conv:a\d+>> TypeConversion [<<Phi1>>] loop:<<Loop>> 169 /// CHECK-DAG: <<Phi2>> Phi [<<Phi1>>,<<Conv>>] loop:<<Loop>> 170 /// CHECK-DAG: Return [<<Phi1>>] 171 172 /// CHECK-START: int TypeConversions.$noinline$conditionalStoreLoadConversionUint8InLoop(int, boolean) load_store_elimination (after) 173 /// CHECK-NOT: StaticFieldGet $noinline$conditionalStoreLoadConversionUint8InLoop(int value, boolean cond)174 public static int $noinline$conditionalStoreLoadConversionUint8InLoop(int value, boolean cond) { 175 static_int = value; 176 for (int q = 1; q < 12; q++) { 177 if (cond) { 178 static_byte = (byte) static_int; 179 static_int = static_byte & 0xff; 180 } 181 } 182 return static_int; 183 } 184 185 /// CHECK-START: int TypeConversions.$noinline$twoConditionalStoreLoadConversionsInLoop(int, boolean) load_store_elimination (before) 186 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 187 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<Value>>] field_name:TypeConversions.static_int 188 /// CHECK-DAG: <<GetI1:i\d+>> StaticFieldGet field_name:TypeConversions.static_int field_type:Int32 loop:<<Loop:B\d+>> 189 // The type conversion has already been eliminated. 190 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetI1>>] field_name:TypeConversions.static_byte loop:<<Loop>> 191 /// CHECK-DAG: <<GetB:b\d+>> StaticFieldGet field_name:TypeConversions.static_byte loop:<<Loop>> 192 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetB>>] field_name:TypeConversions.static_int loop:<<Loop>> 193 /// CHECK-DAG: <<GetI2:i\d+>> StaticFieldGet field_name:TypeConversions.static_int field_type:Int32 loop:<<Loop>> 194 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetI2>>] field_name:TypeConversions.static_char loop:<<Loop>> 195 /// CHECK-DAG: <<GetC:c\d+>> StaticFieldGet field_name:TypeConversions.static_char loop:<<Loop>> 196 /// CHECK-DAG: StaticFieldSet [{{l\d+}},<<GetC>>] field_name:TypeConversions.static_int loop:<<Loop>> 197 /// CHECK-DAG: <<GetI3:i\d+>> StaticFieldGet field_name:TypeConversions.static_int field_type:Int32 loop:none 198 /// CHECK-DAG: Return [<<GetI3>>] 199 200 /// CHECK-START: int TypeConversions.$noinline$twoConditionalStoreLoadConversionsInLoop(int, boolean) load_store_elimination (after) 201 /// CHECK-DAG: <<Value:i\d+>> ParameterValue 202 /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Value>>,<<Phi2:i\d+>>] loop:<<Loop:B\d+>> 203 /// CHECK-DAG: <<Conv1:b\d+>> TypeConversion [<<Phi1>>] loop:<<Loop>> 204 /// CHECK-DAG: <<Conv2:c\d+>> TypeConversion [<<Conv1>>] loop:<<Loop>> 205 /// CHECK-DAG: <<Phi2>> Phi [<<Phi1>>,<<Conv2>>] loop:<<Loop>> 206 /// CHECK-DAG: Return [<<Phi1>>] 207 208 /// CHECK-START: int TypeConversions.$noinline$twoConditionalStoreLoadConversionsInLoop(int, boolean) load_store_elimination (after) 209 /// CHECK-NOT: StaticFieldGet $noinline$twoConditionalStoreLoadConversionsInLoop(int value, boolean cond)210 public static int $noinline$twoConditionalStoreLoadConversionsInLoop(int value, boolean cond) { 211 static_int = value; 212 for (int q = 1; q < 12; q++) { 213 if (cond) { 214 static_byte = (byte) static_int; 215 // Note: We need to go through `static_int` so that the instruction 216 // simplifier eliminates the type conversion to `char`. 217 // TODO: Improve the instruction simplifier to eliminate the conversion 218 // for `static_char = (char) static_byte`. 219 static_int = static_byte; 220 static_char = (char) static_int; 221 static_int = static_char; 222 } 223 } 224 return static_int; 225 } 226 main()227 public static void main() { 228 assertIntEquals(42, $noinline$loopPhiStoreLoadConversionInt8(42)); 229 assertIntEquals(-42, $noinline$loopPhiStoreLoadConversionInt8(-42)); 230 assertIntEquals(-128, $noinline$loopPhiStoreLoadConversionInt8(128)); 231 assertIntEquals(127, $noinline$loopPhiStoreLoadConversionInt8(-129)); 232 233 assertIntEquals(42, $noinline$loopPhiStoreLoadConversionUint8(42)); 234 assertIntEquals(214, $noinline$loopPhiStoreLoadConversionUint8(-42)); 235 assertIntEquals(128, $noinline$loopPhiStoreLoadConversionUint8(128)); 236 assertIntEquals(127, $noinline$loopPhiStoreLoadConversionUint8(-129)); 237 238 assertIntEquals(42, $noinline$loopPhiTwoStoreLoadConversions(42)); 239 assertIntEquals(65494, $noinline$loopPhiTwoStoreLoadConversions(-42)); 240 assertIntEquals(65408, $noinline$loopPhiTwoStoreLoadConversions(128)); 241 assertIntEquals(127, $noinline$loopPhiTwoStoreLoadConversions(-129)); 242 assertIntEquals(0, $noinline$loopPhiTwoStoreLoadConversions(256)); 243 assertIntEquals(65535, $noinline$loopPhiTwoStoreLoadConversions(-257)); 244 245 assertIntEquals(42, $noinline$conditionalStoreLoadConversionInt8InLoop(42, false)); 246 assertIntEquals(42, $noinline$conditionalStoreLoadConversionInt8InLoop(42, true)); 247 assertIntEquals(-42, $noinline$conditionalStoreLoadConversionInt8InLoop(-42, false)); 248 assertIntEquals(-42, $noinline$conditionalStoreLoadConversionInt8InLoop(-42, true)); 249 assertIntEquals(128, $noinline$conditionalStoreLoadConversionInt8InLoop(128, false)); 250 assertIntEquals(-128, $noinline$conditionalStoreLoadConversionInt8InLoop(128, true)); 251 assertIntEquals(-129, $noinline$conditionalStoreLoadConversionInt8InLoop(-129, false)); 252 assertIntEquals(127, $noinline$conditionalStoreLoadConversionInt8InLoop(-129, true)); 253 254 assertIntEquals(42, $noinline$conditionalStoreLoadConversionUint8InLoop(42, false)); 255 assertIntEquals(42, $noinline$conditionalStoreLoadConversionUint8InLoop(42, true)); 256 assertIntEquals(-42, $noinline$conditionalStoreLoadConversionUint8InLoop(-42, false)); 257 assertIntEquals(214, $noinline$conditionalStoreLoadConversionUint8InLoop(-42, true)); 258 assertIntEquals(128, $noinline$conditionalStoreLoadConversionUint8InLoop(128, false)); 259 assertIntEquals(128, $noinline$conditionalStoreLoadConversionUint8InLoop(128, true)); 260 assertIntEquals(-129, $noinline$conditionalStoreLoadConversionUint8InLoop(-129, false)); 261 assertIntEquals(127, $noinline$conditionalStoreLoadConversionUint8InLoop(-129, true)); 262 263 assertIntEquals(42, $noinline$twoConditionalStoreLoadConversionsInLoop(42, false)); 264 assertIntEquals(42, $noinline$twoConditionalStoreLoadConversionsInLoop(42, true)); 265 assertIntEquals(-42, $noinline$twoConditionalStoreLoadConversionsInLoop(-42, false)); 266 assertIntEquals(65494, $noinline$twoConditionalStoreLoadConversionsInLoop(-42, true)); 267 assertIntEquals(128, $noinline$twoConditionalStoreLoadConversionsInLoop(128, false)); 268 assertIntEquals(65408, $noinline$twoConditionalStoreLoadConversionsInLoop(128, true)); 269 assertIntEquals(-129, $noinline$twoConditionalStoreLoadConversionsInLoop(-129, false)); 270 assertIntEquals(127, $noinline$twoConditionalStoreLoadConversionsInLoop(-129, true)); 271 assertIntEquals(256, $noinline$twoConditionalStoreLoadConversionsInLoop(256, false)); 272 assertIntEquals(0, $noinline$twoConditionalStoreLoadConversionsInLoop(256, true)); 273 assertIntEquals(-257, $noinline$twoConditionalStoreLoadConversionsInLoop(-257, false)); 274 assertIntEquals(65535, $noinline$twoConditionalStoreLoadConversionsInLoop(-257, true)); 275 } 276 } 277