394 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s3 4; https://bugs.llvm.org/show_bug.cgi?id=381495 6; We are truncating from wider width, and then sign-extending7; back to the original width. Then we inequality-comparing orig and src.8; If they don't match, then we had signed truncation during truncation.9 10; This can be expressed in a several ways in IR:11; trunc + sext + icmp ne <- not canonical12; shl + ashr + icmp ne13; add + icmp ult/ule14; add + icmp uge/ugt15; However only the simplest form (with two shifts) gets lowered best.16 17; ---------------------------------------------------------------------------- ;18; shl + ashr + icmp ne19; ---------------------------------------------------------------------------- ;20 21define i1 @shifts_necmp_i16_i8(i16 %x) nounwind {22; CHECK-LABEL: shifts_necmp_i16_i8:23; CHECK: // %bb.0:24; CHECK-NEXT: sxtb w8, w025; CHECK-NEXT: and w8, w8, #0xffff26; CHECK-NEXT: cmp w8, w0, uxth27; CHECK-NEXT: cset w0, ne28; CHECK-NEXT: ret29 %tmp0 = shl i16 %x, 8 ; 16-830 %tmp1 = ashr exact i16 %tmp0, 8 ; 16-831 %tmp2 = icmp ne i16 %tmp1, %x32 ret i1 %tmp233}34 35define i1 @shifts_necmp_i32_i16(i32 %x) nounwind {36; CHECK-LABEL: shifts_necmp_i32_i16:37; CHECK: // %bb.0:38; CHECK-NEXT: cmp w0, w0, sxth39; CHECK-NEXT: cset w0, ne40; CHECK-NEXT: ret41 %tmp0 = shl i32 %x, 16 ; 32-1642 %tmp1 = ashr exact i32 %tmp0, 16 ; 32-1643 %tmp2 = icmp ne i32 %tmp1, %x44 ret i1 %tmp245}46 47define i1 @shifts_necmp_i32_i8(i32 %x) nounwind {48; CHECK-LABEL: shifts_necmp_i32_i8:49; CHECK: // %bb.0:50; CHECK-NEXT: cmp w0, w0, sxtb51; CHECK-NEXT: cset w0, ne52; CHECK-NEXT: ret53 %tmp0 = shl i32 %x, 24 ; 32-854 %tmp1 = ashr exact i32 %tmp0, 24 ; 32-855 %tmp2 = icmp ne i32 %tmp1, %x56 ret i1 %tmp257}58 59define i1 @shifts_necmp_i64_i32(i64 %x) nounwind {60; CHECK-LABEL: shifts_necmp_i64_i32:61; CHECK: // %bb.0:62; CHECK-NEXT: cmp x0, w0, sxtw63; CHECK-NEXT: cset w0, ne64; CHECK-NEXT: ret65 %tmp0 = shl i64 %x, 32 ; 64-3266 %tmp1 = ashr exact i64 %tmp0, 32 ; 64-3267 %tmp2 = icmp ne i64 %tmp1, %x68 ret i1 %tmp269}70 71define i1 @shifts_necmp_i64_i16(i64 %x) nounwind {72; CHECK-LABEL: shifts_necmp_i64_i16:73; CHECK: // %bb.0:74; CHECK-NEXT: cmp x0, w0, sxth75; CHECK-NEXT: cset w0, ne76; CHECK-NEXT: ret77 %tmp0 = shl i64 %x, 48 ; 64-1678 %tmp1 = ashr exact i64 %tmp0, 48 ; 64-1679 %tmp2 = icmp ne i64 %tmp1, %x80 ret i1 %tmp281}82 83define i1 @shifts_necmp_i64_i8(i64 %x) nounwind {84; CHECK-LABEL: shifts_necmp_i64_i8:85; CHECK: // %bb.0:86; CHECK-NEXT: cmp x0, w0, sxtb87; CHECK-NEXT: cset w0, ne88; CHECK-NEXT: ret89 %tmp0 = shl i64 %x, 56 ; 64-890 %tmp1 = ashr exact i64 %tmp0, 56 ; 64-891 %tmp2 = icmp ne i64 %tmp1, %x92 ret i1 %tmp293}94 95; ---------------------------------------------------------------------------- ;96; add + icmp ult97; ---------------------------------------------------------------------------- ;98 99define i1 @add_ultcmp_i16_i8(i16 %x) nounwind {100; CHECK-LABEL: add_ultcmp_i16_i8:101; CHECK: // %bb.0:102; CHECK-NEXT: and w8, w0, #0xffff103; CHECK-NEXT: sub w8, w8, #128104; CHECK-NEXT: lsr w8, w8, #8105; CHECK-NEXT: cmp w8, #255106; CHECK-NEXT: cset w0, lo107; CHECK-NEXT: ret108 %tmp0 = add i16 %x, -128 ; ~0U << (8-1)109 %tmp1 = icmp ult i16 %tmp0, -256 ; ~0U << 8110 ret i1 %tmp1111}112 113define i1 @add_ultcmp_i32_i16(i32 %x) nounwind {114; CHECK-LABEL: add_ultcmp_i32_i16:115; CHECK: // %bb.0:116; CHECK-NEXT: cmp w0, w0, sxth117; CHECK-NEXT: cset w0, ne118; CHECK-NEXT: ret119 %tmp0 = add i32 %x, -32768 ; ~0U << (16-1)120 %tmp1 = icmp ult i32 %tmp0, -65536 ; ~0U << 16121 ret i1 %tmp1122}123 124define i1 @add_ultcmp_i32_i8(i32 %x) nounwind {125; CHECK-LABEL: add_ultcmp_i32_i8:126; CHECK: // %bb.0:127; CHECK-NEXT: cmp w0, w0, sxtb128; CHECK-NEXT: cset w0, ne129; CHECK-NEXT: ret130 %tmp0 = add i32 %x, -128 ; ~0U << (8-1)131 %tmp1 = icmp ult i32 %tmp0, -256 ; ~0U << 8132 ret i1 %tmp1133}134 135define i1 @add_ultcmp_i64_i32(i64 %x) nounwind {136; CHECK-LABEL: add_ultcmp_i64_i32:137; CHECK: // %bb.0:138; CHECK-NEXT: cmp x0, w0, sxtw139; CHECK-NEXT: cset w0, ne140; CHECK-NEXT: ret141 %tmp0 = add i64 %x, -2147483648 ; ~0U << (32-1)142 %tmp1 = icmp ult i64 %tmp0, -4294967296 ; ~0U << 32143 ret i1 %tmp1144}145 146define i1 @add_ultcmp_i64_i16(i64 %x) nounwind {147; CHECK-LABEL: add_ultcmp_i64_i16:148; CHECK: // %bb.0:149; CHECK-NEXT: cmp x0, w0, sxth150; CHECK-NEXT: cset w0, ne151; CHECK-NEXT: ret152 %tmp0 = add i64 %x, -32768 ; ~0U << (16-1)153 %tmp1 = icmp ult i64 %tmp0, -65536 ; ~0U << 16154 ret i1 %tmp1155}156 157define i1 @add_ultcmp_i64_i8(i64 %x) nounwind {158; CHECK-LABEL: add_ultcmp_i64_i8:159; CHECK: // %bb.0:160; CHECK-NEXT: cmp x0, w0, sxtb161; CHECK-NEXT: cset w0, ne162; CHECK-NEXT: ret163 %tmp0 = add i64 %x, -128 ; ~0U << (8-1)164 %tmp1 = icmp ult i64 %tmp0, -256 ; ~0U << 8165 ret i1 %tmp1166}167 168; Slightly more canonical variant169define i1 @add_ulecmp_i16_i8(i16 %x) nounwind {170; CHECK-LABEL: add_ulecmp_i16_i8:171; CHECK: // %bb.0:172; CHECK-NEXT: and w8, w0, #0xffff173; CHECK-NEXT: sub w8, w8, #128174; CHECK-NEXT: lsr w8, w8, #8175; CHECK-NEXT: cmp w8, #255176; CHECK-NEXT: cset w0, lo177; CHECK-NEXT: ret178 %tmp0 = add i16 %x, -128 ; ~0U << (8-1)179 %tmp1 = icmp ule i16 %tmp0, -257 ; ~0U << 8 - 1180 ret i1 %tmp1181}182 183; ---------------------------------------------------------------------------- ;184; add + icmp uge185; ---------------------------------------------------------------------------- ;186 187define i1 @add_ugecmp_i16_i8(i16 %x) nounwind {188; CHECK-LABEL: add_ugecmp_i16_i8:189; CHECK: // %bb.0:190; CHECK-NEXT: sxtb w8, w0191; CHECK-NEXT: and w8, w8, #0xffff192; CHECK-NEXT: cmp w8, w0, uxth193; CHECK-NEXT: cset w0, ne194; CHECK-NEXT: ret195 %tmp0 = add i16 %x, 128 ; 1U << (8-1)196 %tmp1 = icmp uge i16 %tmp0, 256 ; 1U << 8197 ret i1 %tmp1198}199 200define i1 @add_ugecmp_i32_i16(i32 %x) nounwind {201; CHECK-LABEL: add_ugecmp_i32_i16:202; CHECK: // %bb.0:203; CHECK-NEXT: cmp w0, w0, sxth204; CHECK-NEXT: cset w0, ne205; CHECK-NEXT: ret206 %tmp0 = add i32 %x, 32768 ; 1U << (16-1)207 %tmp1 = icmp uge i32 %tmp0, 65536 ; 1U << 16208 ret i1 %tmp1209}210 211define i1 @add_ugecmp_i32_i8(i32 %x) nounwind {212; CHECK-LABEL: add_ugecmp_i32_i8:213; CHECK: // %bb.0:214; CHECK-NEXT: cmp w0, w0, sxtb215; CHECK-NEXT: cset w0, ne216; CHECK-NEXT: ret217 %tmp0 = add i32 %x, 128 ; 1U << (8-1)218 %tmp1 = icmp uge i32 %tmp0, 256 ; 1U << 8219 ret i1 %tmp1220}221 222define i1 @add_ugecmp_i64_i32(i64 %x) nounwind {223; CHECK-LABEL: add_ugecmp_i64_i32:224; CHECK: // %bb.0:225; CHECK-NEXT: cmp x0, w0, sxtw226; CHECK-NEXT: cset w0, ne227; CHECK-NEXT: ret228 %tmp0 = add i64 %x, 2147483648 ; 1U << (32-1)229 %tmp1 = icmp uge i64 %tmp0, 4294967296 ; 1U << 32230 ret i1 %tmp1231}232 233define i1 @add_ugecmp_i64_i16(i64 %x) nounwind {234; CHECK-LABEL: add_ugecmp_i64_i16:235; CHECK: // %bb.0:236; CHECK-NEXT: cmp x0, w0, sxth237; CHECK-NEXT: cset w0, ne238; CHECK-NEXT: ret239 %tmp0 = add i64 %x, 32768 ; 1U << (16-1)240 %tmp1 = icmp uge i64 %tmp0, 65536 ; 1U << 16241 ret i1 %tmp1242}243 244define i1 @add_ugecmp_i64_i8(i64 %x) nounwind {245; CHECK-LABEL: add_ugecmp_i64_i8:246; CHECK: // %bb.0:247; CHECK-NEXT: cmp x0, w0, sxtb248; CHECK-NEXT: cset w0, ne249; CHECK-NEXT: ret250 %tmp0 = add i64 %x, 128 ; 1U << (8-1)251 %tmp1 = icmp uge i64 %tmp0, 256 ; 1U << 8252 ret i1 %tmp1253}254 255; Slightly more canonical variant256define i1 @add_ugtcmp_i16_i8(i16 %x) nounwind {257; CHECK-LABEL: add_ugtcmp_i16_i8:258; CHECK: // %bb.0:259; CHECK-NEXT: sxtb w8, w0260; CHECK-NEXT: and w8, w8, #0xffff261; CHECK-NEXT: cmp w8, w0, uxth262; CHECK-NEXT: cset w0, ne263; CHECK-NEXT: ret264 %tmp0 = add i16 %x, 128 ; 1U << (8-1)265 %tmp1 = icmp ugt i16 %tmp0, 255 ; (1U << 8) - 1266 ret i1 %tmp1267}268 269; Negative tests270; ---------------------------------------------------------------------------- ;271 272; Adding not a constant273define i1 @add_ugecmp_bad_i16_i8_add(i16 %x, i16 %y) nounwind {274; CHECK-LABEL: add_ugecmp_bad_i16_i8_add:275; CHECK: // %bb.0:276; CHECK-NEXT: add w8, w0, w1277; CHECK-NEXT: and w8, w8, #0xffff278; CHECK-NEXT: cmp w8, #255279; CHECK-NEXT: cset w0, hi280; CHECK-NEXT: ret281 %tmp0 = add i16 %x, %y282 %tmp1 = icmp uge i16 %tmp0, 256 ; 1U << 8283 ret i1 %tmp1284}285 286; Comparing not with a constant287define i1 @add_ugecmp_bad_i16_i8_cmp(i16 %x, i16 %y) nounwind {288; CHECK-LABEL: add_ugecmp_bad_i16_i8_cmp:289; CHECK: // %bb.0:290; CHECK-NEXT: add w8, w0, #128291; CHECK-NEXT: and w8, w8, #0xffff292; CHECK-NEXT: cmp w8, w1, uxth293; CHECK-NEXT: cset w0, hs294; CHECK-NEXT: ret295 %tmp0 = add i16 %x, 128 ; 1U << (8-1)296 %tmp1 = icmp uge i16 %tmp0, %y297 ret i1 %tmp1298}299 300; Second constant is not larger than the first one301define i1 @add_ugecmp_bad_i8_i16(i16 %x) nounwind {302; CHECK-LABEL: add_ugecmp_bad_i8_i16:303; CHECK: // %bb.0:304; CHECK-NEXT: add w8, w0, #128305; CHECK-NEXT: and w8, w8, #0xffff306; CHECK-NEXT: cmp w8, #127307; CHECK-NEXT: cset w0, hi308; CHECK-NEXT: ret309 %tmp0 = add i16 %x, 128 ; 1U << (8-1)310 %tmp1 = icmp uge i16 %tmp0, 128 ; 1U << (8-1)311 ret i1 %tmp1312}313 314; First constant is not power of two315define i1 @add_ugecmp_bad_i16_i8_c0notpoweroftwo(i16 %x) nounwind {316; CHECK-LABEL: add_ugecmp_bad_i16_i8_c0notpoweroftwo:317; CHECK: // %bb.0:318; CHECK-NEXT: add w8, w0, #192319; CHECK-NEXT: and w8, w8, #0xffff320; CHECK-NEXT: cmp w8, #255321; CHECK-NEXT: cset w0, hi322; CHECK-NEXT: ret323 %tmp0 = add i16 %x, 192 ; (1U << (8-1)) + (1U << (8-1-1))324 %tmp1 = icmp uge i16 %tmp0, 256 ; 1U << 8325 ret i1 %tmp1326}327 328; Second constant is not power of two329define i1 @add_ugecmp_bad_i16_i8_c1notpoweroftwo(i16 %x) nounwind {330; CHECK-LABEL: add_ugecmp_bad_i16_i8_c1notpoweroftwo:331; CHECK: // %bb.0:332; CHECK-NEXT: add w8, w0, #128333; CHECK-NEXT: and w8, w8, #0xffff334; CHECK-NEXT: cmp w8, #767335; CHECK-NEXT: cset w0, hi336; CHECK-NEXT: ret337 %tmp0 = add i16 %x, 128 ; 1U << (8-1)338 %tmp1 = icmp uge i16 %tmp0, 768 ; (1U << 8)) + (1U << (8+1))339 ret i1 %tmp1340}341 342; Magic check fails, 64 << 1 != 256343define i1 @add_ugecmp_bad_i16_i8_magic(i16 %x) nounwind {344; CHECK-LABEL: add_ugecmp_bad_i16_i8_magic:345; CHECK: // %bb.0:346; CHECK-NEXT: add w8, w0, #64347; CHECK-NEXT: and w8, w8, #0xffff348; CHECK-NEXT: cmp w8, #255349; CHECK-NEXT: cset w0, hi350; CHECK-NEXT: ret351 %tmp0 = add i16 %x, 64 ; 1U << (8-1-1)352 %tmp1 = icmp uge i16 %tmp0, 256 ; 1U << 8353 ret i1 %tmp1354}355 356; Bad 'destination type'357define i1 @add_ugecmp_bad_i16_i4(i16 %x) nounwind {358; CHECK-LABEL: add_ugecmp_bad_i16_i4:359; CHECK: // %bb.0:360; CHECK-NEXT: add w8, w0, #8361; CHECK-NEXT: and w8, w8, #0xffff362; CHECK-NEXT: cmp w8, #15363; CHECK-NEXT: cset w0, hi364; CHECK-NEXT: ret365 %tmp0 = add i16 %x, 8 ; 1U << (4-1)366 %tmp1 = icmp uge i16 %tmp0, 16 ; 1U << 4367 ret i1 %tmp1368}369 370; Bad storage type371define i1 @add_ugecmp_bad_i24_i8(i24 %x) nounwind {372; CHECK-LABEL: add_ugecmp_bad_i24_i8:373; CHECK: // %bb.0:374; CHECK-NEXT: add w8, w0, #128375; CHECK-NEXT: and w8, w8, #0xffffff376; CHECK-NEXT: cmp w8, #255377; CHECK-NEXT: cset w0, hi378; CHECK-NEXT: ret379 %tmp0 = add i24 %x, 128 ; 1U << (8-1)380 %tmp1 = icmp uge i24 %tmp0, 256 ; 1U << 8381 ret i1 %tmp1382}383 384; Slightly more canonical variant385define i1 @add_ugtcmp_bad_i16_i8(i16 %x) nounwind {386; CHECK-LABEL: add_ugtcmp_bad_i16_i8:387; CHECK: // %bb.0:388; CHECK-NEXT: mov w0, wzr389; CHECK-NEXT: ret390 %tmp0 = add i16 %x, 128 ; 1U << (8-1)391 %tmp1 = icmp ugt i16 %tmp0, -1 ; when we +1 it, it will wrap to 0392 ret i1 %tmp1393}394