1; Test 8-bit conditional stores that are presented as selects. 2; 3; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s 4 5declare void @foo(i8 *) 6 7; Test the simple case, with the loaded value first. 8define void @f1(i8 *%ptr, i8 %alt, i32 %limit) { 9; CHECK-LABEL: f1: 10; CHECK-NOT: %r2 11; CHECK: jl [[LABEL:[^ ]*]] 12; CHECK-NOT: %r2 13; CHECK: stc %r3, 0(%r2) 14; CHECK: [[LABEL]]: 15; CHECK: br %r14 16 %cond = icmp ult i32 %limit, 42 17 %orig = load i8 *%ptr 18 %res = select i1 %cond, i8 %orig, i8 %alt 19 store i8 %res, i8 *%ptr 20 ret void 21} 22 23; ...and with the loaded value second 24define void @f2(i8 *%ptr, i8 %alt, i32 %limit) { 25; CHECK-LABEL: f2: 26; CHECK-NOT: %r2 27; CHECK: jhe [[LABEL:[^ ]*]] 28; CHECK-NOT: %r2 29; CHECK: stc %r3, 0(%r2) 30; CHECK: [[LABEL]]: 31; CHECK: br %r14 32 %cond = icmp ult i32 %limit, 42 33 %orig = load i8 *%ptr 34 %res = select i1 %cond, i8 %alt, i8 %orig 35 store i8 %res, i8 *%ptr 36 ret void 37} 38 39; Test cases where the value is explicitly sign-extended to 32 bits, with the 40; loaded value first. 41define void @f3(i8 *%ptr, i32 %alt, i32 %limit) { 42; CHECK-LABEL: f3: 43; CHECK-NOT: %r2 44; CHECK: jl [[LABEL:[^ ]*]] 45; CHECK-NOT: %r2 46; CHECK: stc %r3, 0(%r2) 47; CHECK: [[LABEL]]: 48; CHECK: br %r14 49 %cond = icmp ult i32 %limit, 42 50 %orig = load i8 *%ptr 51 %ext = sext i8 %orig to i32 52 %res = select i1 %cond, i32 %ext, i32 %alt 53 %trunc = trunc i32 %res to i8 54 store i8 %trunc, i8 *%ptr 55 ret void 56} 57 58; ...and with the loaded value second 59define void @f4(i8 *%ptr, i32 %alt, i32 %limit) { 60; CHECK-LABEL: f4: 61; CHECK-NOT: %r2 62; CHECK: jhe [[LABEL:[^ ]*]] 63; CHECK-NOT: %r2 64; CHECK: stc %r3, 0(%r2) 65; CHECK: [[LABEL]]: 66; CHECK: br %r14 67 %cond = icmp ult i32 %limit, 42 68 %orig = load i8 *%ptr 69 %ext = sext i8 %orig to i32 70 %res = select i1 %cond, i32 %alt, i32 %ext 71 %trunc = trunc i32 %res to i8 72 store i8 %trunc, i8 *%ptr 73 ret void 74} 75 76; Test cases where the value is explicitly zero-extended to 32 bits, with the 77; loaded value first. 78define void @f5(i8 *%ptr, i32 %alt, i32 %limit) { 79; CHECK-LABEL: f5: 80; CHECK-NOT: %r2 81; CHECK: jl [[LABEL:[^ ]*]] 82; CHECK-NOT: %r2 83; CHECK: stc %r3, 0(%r2) 84; CHECK: [[LABEL]]: 85; CHECK: br %r14 86 %cond = icmp ult i32 %limit, 42 87 %orig = load i8 *%ptr 88 %ext = zext i8 %orig to i32 89 %res = select i1 %cond, i32 %ext, i32 %alt 90 %trunc = trunc i32 %res to i8 91 store i8 %trunc, i8 *%ptr 92 ret void 93} 94 95; ...and with the loaded value second 96define void @f6(i8 *%ptr, i32 %alt, i32 %limit) { 97; CHECK-LABEL: f6: 98; CHECK-NOT: %r2 99; CHECK: jhe [[LABEL:[^ ]*]] 100; CHECK-NOT: %r2 101; CHECK: stc %r3, 0(%r2) 102; CHECK: [[LABEL]]: 103; CHECK: br %r14 104 %cond = icmp ult i32 %limit, 42 105 %orig = load i8 *%ptr 106 %ext = zext i8 %orig to i32 107 %res = select i1 %cond, i32 %alt, i32 %ext 108 %trunc = trunc i32 %res to i8 109 store i8 %trunc, i8 *%ptr 110 ret void 111} 112 113; Test cases where the value is explicitly sign-extended to 64 bits, with the 114; loaded value first. 115define void @f7(i8 *%ptr, i64 %alt, i32 %limit) { 116; CHECK-LABEL: f7: 117; CHECK-NOT: %r2 118; CHECK: jl [[LABEL:[^ ]*]] 119; CHECK-NOT: %r2 120; CHECK: stc %r3, 0(%r2) 121; CHECK: [[LABEL]]: 122; CHECK: br %r14 123 %cond = icmp ult i32 %limit, 42 124 %orig = load i8 *%ptr 125 %ext = sext i8 %orig to i64 126 %res = select i1 %cond, i64 %ext, i64 %alt 127 %trunc = trunc i64 %res to i8 128 store i8 %trunc, i8 *%ptr 129 ret void 130} 131 132; ...and with the loaded value second 133define void @f8(i8 *%ptr, i64 %alt, i32 %limit) { 134; CHECK-LABEL: f8: 135; CHECK-NOT: %r2 136; CHECK: jhe [[LABEL:[^ ]*]] 137; CHECK-NOT: %r2 138; CHECK: stc %r3, 0(%r2) 139; CHECK: [[LABEL]]: 140; CHECK: br %r14 141 %cond = icmp ult i32 %limit, 42 142 %orig = load i8 *%ptr 143 %ext = sext i8 %orig to i64 144 %res = select i1 %cond, i64 %alt, i64 %ext 145 %trunc = trunc i64 %res to i8 146 store i8 %trunc, i8 *%ptr 147 ret void 148} 149 150; Test cases where the value is explicitly zero-extended to 64 bits, with the 151; loaded value first. 152define void @f9(i8 *%ptr, i64 %alt, i32 %limit) { 153; CHECK-LABEL: f9: 154; CHECK-NOT: %r2 155; CHECK: jl [[LABEL:[^ ]*]] 156; CHECK-NOT: %r2 157; CHECK: stc %r3, 0(%r2) 158; CHECK: [[LABEL]]: 159; CHECK: br %r14 160 %cond = icmp ult i32 %limit, 42 161 %orig = load i8 *%ptr 162 %ext = zext i8 %orig to i64 163 %res = select i1 %cond, i64 %ext, i64 %alt 164 %trunc = trunc i64 %res to i8 165 store i8 %trunc, i8 *%ptr 166 ret void 167} 168 169; ...and with the loaded value second 170define void @f10(i8 *%ptr, i64 %alt, i32 %limit) { 171; CHECK-LABEL: f10: 172; CHECK-NOT: %r2 173; CHECK: jhe [[LABEL:[^ ]*]] 174; CHECK-NOT: %r2 175; CHECK: stc %r3, 0(%r2) 176; CHECK: [[LABEL]]: 177; CHECK: br %r14 178 %cond = icmp ult i32 %limit, 42 179 %orig = load i8 *%ptr 180 %ext = zext i8 %orig to i64 181 %res = select i1 %cond, i64 %alt, i64 %ext 182 %trunc = trunc i64 %res to i8 183 store i8 %trunc, i8 *%ptr 184 ret void 185} 186 187; Check the high end of the STC range. 188define void @f11(i8 *%base, i8 %alt, i32 %limit) { 189; CHECK-LABEL: f11: 190; CHECK-NOT: %r2 191; CHECK: jl [[LABEL:[^ ]*]] 192; CHECK-NOT: %r2 193; CHECK: stc %r3, 4095(%r2) 194; CHECK: [[LABEL]]: 195; CHECK: br %r14 196 %ptr = getelementptr i8 *%base, i64 4095 197 %cond = icmp ult i32 %limit, 42 198 %orig = load i8 *%ptr 199 %res = select i1 %cond, i8 %orig, i8 %alt 200 store i8 %res, i8 *%ptr 201 ret void 202} 203 204; Check the next byte up, which should use STCY instead of STC. 205define void @f12(i8 *%base, i8 %alt, i32 %limit) { 206; CHECK-LABEL: f12: 207; CHECK-NOT: %r2 208; CHECK: jl [[LABEL:[^ ]*]] 209; CHECK-NOT: %r2 210; CHECK: stcy %r3, 4096(%r2) 211; CHECK: [[LABEL]]: 212; CHECK: br %r14 213 %ptr = getelementptr i8 *%base, i64 4096 214 %cond = icmp ult i32 %limit, 42 215 %orig = load i8 *%ptr 216 %res = select i1 %cond, i8 %orig, i8 %alt 217 store i8 %res, i8 *%ptr 218 ret void 219} 220 221; Check the high end of the STCY range. 222define void @f13(i8 *%base, i8 %alt, i32 %limit) { 223; CHECK-LABEL: f13: 224; CHECK-NOT: %r2 225; CHECK: jl [[LABEL:[^ ]*]] 226; CHECK-NOT: %r2 227; CHECK: stcy %r3, 524287(%r2) 228; CHECK: [[LABEL]]: 229; CHECK: br %r14 230 %ptr = getelementptr i8 *%base, i64 524287 231 %cond = icmp ult i32 %limit, 42 232 %orig = load i8 *%ptr 233 %res = select i1 %cond, i8 %orig, i8 %alt 234 store i8 %res, i8 *%ptr 235 ret void 236} 237 238; Check the next byte up, which needs separate address logic. 239; Other sequences besides this one would be OK. 240define void @f14(i8 *%base, i8 %alt, i32 %limit) { 241; CHECK-LABEL: f14: 242; CHECK-NOT: %r2 243; CHECK: jl [[LABEL:[^ ]*]] 244; CHECK-NOT: %r2 245; CHECK: agfi %r2, 524288 246; CHECK: stc %r3, 0(%r2) 247; CHECK: [[LABEL]]: 248; CHECK: br %r14 249 %ptr = getelementptr i8 *%base, i64 524288 250 %cond = icmp ult i32 %limit, 42 251 %orig = load i8 *%ptr 252 %res = select i1 %cond, i8 %orig, i8 %alt 253 store i8 %res, i8 *%ptr 254 ret void 255} 256 257; Check the low end of the STCY range. 258define void @f15(i8 *%base, i8 %alt, i32 %limit) { 259; CHECK-LABEL: f15: 260; CHECK-NOT: %r2 261; CHECK: jl [[LABEL:[^ ]*]] 262; CHECK-NOT: %r2 263; CHECK: stcy %r3, -524288(%r2) 264; CHECK: [[LABEL]]: 265; CHECK: br %r14 266 %ptr = getelementptr i8 *%base, i64 -524288 267 %cond = icmp ult i32 %limit, 42 268 %orig = load i8 *%ptr 269 %res = select i1 %cond, i8 %orig, i8 %alt 270 store i8 %res, i8 *%ptr 271 ret void 272} 273 274; Check the next byte down, which needs separate address logic. 275; Other sequences besides this one would be OK. 276define void @f16(i8 *%base, i8 %alt, i32 %limit) { 277; CHECK-LABEL: f16: 278; CHECK-NOT: %r2 279; CHECK: jl [[LABEL:[^ ]*]] 280; CHECK-NOT: %r2 281; CHECK: agfi %r2, -524289 282; CHECK: stc %r3, 0(%r2) 283; CHECK: [[LABEL]]: 284; CHECK: br %r14 285 %ptr = getelementptr i8 *%base, i64 -524289 286 %cond = icmp ult i32 %limit, 42 287 %orig = load i8 *%ptr 288 %res = select i1 %cond, i8 %orig, i8 %alt 289 store i8 %res, i8 *%ptr 290 ret void 291} 292 293; Check that STCY allows an index. 294define void @f17(i64 %base, i64 %index, i8 %alt, i32 %limit) { 295; CHECK-LABEL: f17: 296; CHECK-NOT: %r2 297; CHECK: jl [[LABEL:[^ ]*]] 298; CHECK-NOT: %r2 299; CHECK: stcy %r4, 4096(%r3,%r2) 300; CHECK: [[LABEL]]: 301; CHECK: br %r14 302 %add1 = add i64 %base, %index 303 %add2 = add i64 %add1, 4096 304 %ptr = inttoptr i64 %add2 to i8 * 305 %cond = icmp ult i32 %limit, 42 306 %orig = load i8 *%ptr 307 %res = select i1 %cond, i8 %orig, i8 %alt 308 store i8 %res, i8 *%ptr 309 ret void 310} 311 312; Check that volatile loads are not matched. 313define void @f18(i8 *%ptr, i8 %alt, i32 %limit) { 314; CHECK-LABEL: f18: 315; CHECK: lb {{%r[0-5]}}, 0(%r2) 316; CHECK: {{jl|jnl}} [[LABEL:[^ ]*]] 317; CHECK: [[LABEL]]: 318; CHECK: stc {{%r[0-5]}}, 0(%r2) 319; CHECK: br %r14 320 %cond = icmp ult i32 %limit, 42 321 %orig = load volatile i8 *%ptr 322 %res = select i1 %cond, i8 %orig, i8 %alt 323 store i8 %res, i8 *%ptr 324 ret void 325} 326 327; ...likewise stores. In this case we should have a conditional load into %r3. 328define void @f19(i8 *%ptr, i8 %alt, i32 %limit) { 329; CHECK-LABEL: f19: 330; CHECK: jhe [[LABEL:[^ ]*]] 331; CHECK: lb %r3, 0(%r2) 332; CHECK: [[LABEL]]: 333; CHECK: stc %r3, 0(%r2) 334; CHECK: br %r14 335 %cond = icmp ult i32 %limit, 42 336 %orig = load i8 *%ptr 337 %res = select i1 %cond, i8 %orig, i8 %alt 338 store volatile i8 %res, i8 *%ptr 339 ret void 340} 341 342; Check that atomic loads are not matched. The transformation is OK for 343; the "unordered" case tested here, but since we don't try to handle atomic 344; operations at all in this context, it seems better to assert that than 345; to restrict the test to a stronger ordering. 346define void @f20(i8 *%ptr, i8 %alt, i32 %limit) { 347; FIXME: should use a normal load instead of CS. 348; CHECK-LABEL: f20: 349; CHECK: cs {{%r[0-9]+}}, 350; CHECK: jl 351; CHECK: {{jl|jnl}} [[LABEL:[^ ]*]] 352; CHECK: [[LABEL]]: 353; CHECK: stc {{%r[0-9]+}}, 354; CHECK: br %r14 355 %cond = icmp ult i32 %limit, 42 356 %orig = load atomic i8 *%ptr unordered, align 1 357 %res = select i1 %cond, i8 %orig, i8 %alt 358 store i8 %res, i8 *%ptr 359 ret void 360} 361 362; ...likewise stores. 363define void @f21(i8 *%ptr, i8 %alt, i32 %limit) { 364; FIXME: should use a normal store instead of CS. 365; CHECK-LABEL: f21: 366; CHECK: jhe [[LABEL:[^ ]*]] 367; CHECK: lb %r3, 0(%r2) 368; CHECK: [[LABEL]]: 369; CHECK: cs {{%r[0-9]+}}, 370; CHECK: br %r14 371 %cond = icmp ult i32 %limit, 42 372 %orig = load i8 *%ptr 373 %res = select i1 %cond, i8 %orig, i8 %alt 374 store atomic i8 %res, i8 *%ptr unordered, align 1 375 ret void 376} 377 378; Try a frame index base. 379define void @f22(i8 %alt, i32 %limit) { 380; CHECK-LABEL: f22: 381; CHECK: brasl %r14, foo@PLT 382; CHECK-NOT: %r15 383; CHECK: jl [[LABEL:[^ ]*]] 384; CHECK-NOT: %r15 385; CHECK: stc {{%r[0-9]+}}, {{[0-9]+}}(%r15) 386; CHECK: [[LABEL]]: 387; CHECK: brasl %r14, foo@PLT 388; CHECK: br %r14 389 %ptr = alloca i8 390 call void @foo(i8 *%ptr) 391 %cond = icmp ult i32 %limit, 42 392 %orig = load i8 *%ptr 393 %res = select i1 %cond, i8 %orig, i8 %alt 394 store i8 %res, i8 *%ptr 395 call void @foo(i8 *%ptr) 396 ret void 397} 398