Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -1822,6 +1822,37 @@ } } } + + // Swap operands if one side is foldable. + auto FoldableCmpOperand = [&] (SDNode *N) { + if (ConstantSDNode *C = dyn_cast(N)) + return isLegalArithImmed(C->getZExtValue()); + if (!N->hasOneUse()) + return false; + if (N->getOpcode() == ISD::SHL || + N->getOpcode() == ISD::SRL || + N->getOpcode() == ISD::SRA) + return isa(N->getOperand(1)); + if (N->getOpcode() == ISD::SIGN_EXTEND_INREG) + return true; + if (N->getOpcode() == ISD::AND) { + // In the future, this should probably be enhanced to handle + // cases where the operand of the AND is an LSL (e.g. + // "(x << 1) & 510" is "uxtb #1"). But isel can't + // handle it anyway at the moment. + SDNode *AndRHS = N->getOperand(1).getNode(); + if (ConstantSDNode *RHSC = dyn_cast(AndRHS)) + return RHSC->getAPIntValue() == 0xFF || + RHSC->getAPIntValue() == 0xFFFF || + RHSC->getAPIntValue() == 0xFFFFFFFF; + } + return false; + }; + if (FoldableCmpOperand(LHS.getNode()) && !FoldableCmpOperand(RHS.getNode())) { + std::swap(LHS, RHS); + CC = ISD::getSetCCSwappedOperands(CC); + } + SDValue Cmp; AArch64CC::CondCode AArch64CC; if ((CC == ISD::SETEQ || CC == ISD::SETNE) && isa(RHS)) { Index: test/CodeGen/AArch64/cmp-commute.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/cmp-commute.ll @@ -0,0 +1,209 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s + +define i1 @shl_eq(i32 %x, i32 %y) nounwind { +; CHECK-LABEL: shl_eq: +; CHECK: // %bb.0: +; CHECK-NEXT: cmp w0, w1, lsl #2 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %yy = shl i32 %y, 2 + %cmp = icmp eq i32 %x, %yy + ret i1 %cmp +} + +define i1 @shl_eq_2(i32 %x, i32 %y) nounwind { +; CHECK-LABEL: shl_eq_2: +; CHECK: // %bb.0: +; CHECK-NEXT: cmp w0, w1, lsl #2 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %yy = shl i32 %y, 2 + %cmp = icmp eq i32 %yy, %x + ret i1 %cmp +} + +define i1 @shl_eq_small_const(i32 %y) nounwind { +; CHECK-LABEL: shl_eq_small_const: +; CHECK: // %bb.0: +; CHECK-NEXT: lsl w8, w0, #2 +; CHECK-NEXT: cmp w8, #124 // =124 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %yy = shl i32 %y, 2 + %cmp = icmp eq i32 124, %yy + ret i1 %cmp +} + +define i1 @shl_eq_big_const(i32 %y) nounwind { +; CHECK-LABEL: shl_eq_big_const: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, #24908 +; CHECK-NEXT: movk w8, #188, lsl #16 +; CHECK-NEXT: cmp w8, w0, lsl #2 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %yy = shl i32 %y, 2 + %cmp = icmp eq i32 12345676, %yy + ret i1 %cmp +} + +; FIXME: Fold this. +define i1 @shl_eq_big_const_instcombine(i32 %y) #0 { +; CHECK-LABEL: shl_eq_big_const_instcombine: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w9, #6227 +; CHECK-NEXT: and w8, w0, #0x3fffffff +; CHECK-NEXT: movk w9, #47, lsl #16 +; CHECK-NEXT: cmp w8, w9 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %yy.mask = and i32 %y, 1073741823 + %cmp = icmp eq i32 %yy.mask, 3086419 + ret i1 %cmp +} + +define i1 @lshr_eq(i32 %x, i32 %y) nounwind { +; CHECK-LABEL: lshr_eq: +; CHECK: // %bb.0: +; CHECK-NEXT: cmp w0, w1, lsr #2 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %yy = lshr i32 %y, 2 + %cmp = icmp eq i32 %x, %yy + ret i1 %cmp +} + +define i1 @lshr_eq_2(i32 %x, i32 %y) nounwind { +; CHECK-LABEL: lshr_eq_2: +; CHECK: // %bb.0: +; CHECK-NEXT: cmp w0, w1, lsr #2 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %yy = lshr i32 %y, 2 + %cmp = icmp eq i32 %yy, %x + ret i1 %cmp +} + +define i1 @and16_eq(i32 %x, i32 %y) nounwind { +; CHECK-LABEL: and16_eq: +; CHECK: // %bb.0: +; CHECK-NEXT: cmp w0, w1, uxth +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %yy = and i32 %y, 65535 + %cmp = icmp eq i32 %x, %yy + ret i1 %cmp +} + +define i1 @and16_eq_2(i32 %x, i32 %y) nounwind { +; CHECK-LABEL: and16_eq_2: +; CHECK: // %bb.0: +; CHECK-NEXT: cmp w0, w1, uxth +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %yy = and i32 %y, 65535 + %cmp = icmp eq i32 %yy, %x + ret i1 %cmp +} + +define i1 @and32_eq(i64 %x, i64 %y) nounwind { +; CHECK-LABEL: and32_eq: +; CHECK: // %bb.0: +; CHECK-NEXT: cmp x0, w1, uxtw +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %yy = and i64 %y, 4294967295 + %cmp = icmp eq i64 %x, %yy + ret i1 %cmp +} + +define i1 @and32_eq_2(i64 %x, i64 %y) nounwind { +; CHECK-LABEL: and32_eq_2: +; CHECK: // %bb.0: +; CHECK-NEXT: cmp x0, w1, uxtw +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %yy = and i64 %y, 4294967295 + %cmp = icmp eq i64 %yy, %x + ret i1 %cmp +} + +define i1 @shl_and32_eq(i64 %x, i64 %y) nounwind { +; CHECK-LABEL: shl_and32_eq: +; CHECK: // %bb.0: +; CHECK-NEXT: cmp x0, w1, uxtw #2 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %y2 = and i64 %y, 4294967295 + %yy = shl i64 %y2, 2 + %cmp = icmp eq i64 %x, %yy + ret i1 %cmp +} + +define i1 @shl_and32_eq_2(i64 %x, i64 %y) nounwind { +; CHECK-LABEL: shl_and32_eq_2: +; CHECK: // %bb.0: +; CHECK-NEXT: cmp x0, w1, uxtw #2 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %y2 = and i64 %y, 4294967295 + %yy = shl i64 %y2, 2 + %cmp = icmp eq i64 %yy, %x + ret i1 %cmp +} + +; FIXME: Fold this; it's equivalent to uxtw #2 +define i1 @shl_and32_eq_instcombine(i64 %x, i64 %y) { +; CHECK-LABEL: shl_and32_eq_instcombine: +; CHECK: // %bb.0: +; CHECK-NEXT: ubfiz x8, x1, #2, #32 +; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %y2 = shl i64 %y, 2 + %yy = and i64 %y2, 17179869180 + %cmp = icmp eq i64 %yy, %x + ret i1 %cmp +} + +; FIXME: Fold this; it's equivalent to uxtw #2 +define i1 @shl_and32_eq_instcombine_2(i64 %x, i64 %y) { +; CHECK-LABEL: shl_and32_eq_instcombine_2: +; CHECK: // %bb.0: +; CHECK-NEXT: ubfiz x8, x1, #2, #32 +; CHECK-NEXT: cmp x0, x8 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %y2 = shl i64 %y, 2 + %yy = and i64 %y2, 17179869180 + %cmp = icmp eq i64 %x, %yy + ret i1 %cmp +} + +; FIXME: This is equivalent to sxtw #1 +define i1 @sext_shift_eq(i32 %x, i32 %y) nounwind { +; CHECK-LABEL: sext_shift_eq: +; CHECK: // %bb.0: +; CHECK-NEXT: lsl w8, w1, #16 +; CHECK-NEXT: cmp w0, w8, asr #15 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %y2 = shl i32 %y, 16 + %yy = ashr i32 %y2, 15 + %cmp = icmp eq i32 %x, %yy + ret i1 %cmp +} + +define i1 @sext_shift_eq_2(i32 %x, i32 %y) nounwind { +; CHECK-LABEL: sext_shift_eq_2: +; CHECK: // %bb.0: +; CHECK-NEXT: lsl w8, w1, #16 +; CHECK-NEXT: cmp w0, w8, asr #15 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %y2 = shl i32 %y, 16 + %yy = ashr i32 %y2, 15 + %cmp = icmp eq i32 %yy, %x + ret i1 %cmp +} Index: test/CodeGen/AArch64/lack-of-signed-truncation-check.ll =================================================================== --- test/CodeGen/AArch64/lack-of-signed-truncation-check.ll +++ test/CodeGen/AArch64/lack-of-signed-truncation-check.ll @@ -35,8 +35,7 @@ define i1 @shifts_necmp_i32_i16(i32 %x) nounwind { ; CHECK-LABEL: shifts_necmp_i32_i16: ; CHECK: // %bb.0: -; CHECK-NEXT: sxth w8, w0 -; CHECK-NEXT: cmp w8, w0 +; CHECK-NEXT: cmp w0, w0, sxth ; CHECK-NEXT: cset w0, ne ; CHECK-NEXT: ret %tmp0 = shl i32 %x, 16 ; 32-16 @@ -48,8 +47,7 @@ define i1 @shifts_necmp_i32_i8(i32 %x) nounwind { ; CHECK-LABEL: shifts_necmp_i32_i8: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtb w8, w0 -; CHECK-NEXT: cmp w8, w0 +; CHECK-NEXT: cmp w0, w0, sxtb ; CHECK-NEXT: cset w0, ne ; CHECK-NEXT: ret %tmp0 = shl i32 %x, 24 ; 32-8 @@ -61,8 +59,7 @@ define i1 @shifts_necmp_i64_i32(i64 %x) nounwind { ; CHECK-LABEL: shifts_necmp_i64_i32: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtw x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxtw ; CHECK-NEXT: cset w0, ne ; CHECK-NEXT: ret %tmp0 = shl i64 %x, 32 ; 64-32 @@ -74,8 +71,7 @@ define i1 @shifts_necmp_i64_i16(i64 %x) nounwind { ; CHECK-LABEL: shifts_necmp_i64_i16: ; CHECK: // %bb.0: -; CHECK-NEXT: sxth x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxth ; CHECK-NEXT: cset w0, ne ; CHECK-NEXT: ret %tmp0 = shl i64 %x, 48 ; 64-16 @@ -87,8 +83,7 @@ define i1 @shifts_necmp_i64_i8(i64 %x) nounwind { ; CHECK-LABEL: shifts_necmp_i64_i8: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtb x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxtb ; CHECK-NEXT: cset w0, ne ; CHECK-NEXT: ret %tmp0 = shl i64 %x, 56 ; 64-8 @@ -196,8 +191,7 @@ define i1 @add_ugecmp_i32_i16(i32 %x) nounwind { ; CHECK-LABEL: add_ugecmp_i32_i16: ; CHECK: // %bb.0: -; CHECK-NEXT: sxth w8, w0 -; CHECK-NEXT: cmp w8, w0 +; CHECK-NEXT: cmp w0, w0, sxth ; CHECK-NEXT: cset w0, ne ; CHECK-NEXT: ret %tmp0 = add i32 %x, 32768 ; 1U << (16-1) @@ -208,8 +202,7 @@ define i1 @add_ugecmp_i32_i8(i32 %x) nounwind { ; CHECK-LABEL: add_ugecmp_i32_i8: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtb w8, w0 -; CHECK-NEXT: cmp w8, w0 +; CHECK-NEXT: cmp w0, w0, sxtb ; CHECK-NEXT: cset w0, ne ; CHECK-NEXT: ret %tmp0 = add i32 %x, 128 ; 1U << (8-1) @@ -220,8 +213,7 @@ define i1 @add_ugecmp_i64_i32(i64 %x) nounwind { ; CHECK-LABEL: add_ugecmp_i64_i32: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtw x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxtw ; CHECK-NEXT: cset w0, ne ; CHECK-NEXT: ret %tmp0 = add i64 %x, 2147483648 ; 1U << (32-1) @@ -232,8 +224,7 @@ define i1 @add_ugecmp_i64_i16(i64 %x) nounwind { ; CHECK-LABEL: add_ugecmp_i64_i16: ; CHECK: // %bb.0: -; CHECK-NEXT: sxth x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxth ; CHECK-NEXT: cset w0, ne ; CHECK-NEXT: ret %tmp0 = add i64 %x, 32768 ; 1U << (16-1) @@ -244,8 +235,7 @@ define i1 @add_ugecmp_i64_i8(i64 %x) nounwind { ; CHECK-LABEL: add_ugecmp_i64_i8: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtb x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxtb ; CHECK-NEXT: cset w0, ne ; CHECK-NEXT: ret %tmp0 = add i64 %x, 128 ; 1U << (8-1) Index: test/CodeGen/AArch64/signed-truncation-check.ll =================================================================== --- test/CodeGen/AArch64/signed-truncation-check.ll +++ test/CodeGen/AArch64/signed-truncation-check.ll @@ -35,8 +35,7 @@ define i1 @shifts_eqcmp_i32_i16(i32 %x) nounwind { ; CHECK-LABEL: shifts_eqcmp_i32_i16: ; CHECK: // %bb.0: -; CHECK-NEXT: sxth w8, w0 -; CHECK-NEXT: cmp w8, w0 +; CHECK-NEXT: cmp w0, w0, sxth ; CHECK-NEXT: cset w0, eq ; CHECK-NEXT: ret %tmp0 = shl i32 %x, 16 ; 32-16 @@ -48,8 +47,7 @@ define i1 @shifts_eqcmp_i32_i8(i32 %x) nounwind { ; CHECK-LABEL: shifts_eqcmp_i32_i8: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtb w8, w0 -; CHECK-NEXT: cmp w8, w0 +; CHECK-NEXT: cmp w0, w0, sxtb ; CHECK-NEXT: cset w0, eq ; CHECK-NEXT: ret %tmp0 = shl i32 %x, 24 ; 32-8 @@ -61,8 +59,7 @@ define i1 @shifts_eqcmp_i64_i32(i64 %x) nounwind { ; CHECK-LABEL: shifts_eqcmp_i64_i32: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtw x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxtw ; CHECK-NEXT: cset w0, eq ; CHECK-NEXT: ret %tmp0 = shl i64 %x, 32 ; 64-32 @@ -74,8 +71,7 @@ define i1 @shifts_eqcmp_i64_i16(i64 %x) nounwind { ; CHECK-LABEL: shifts_eqcmp_i64_i16: ; CHECK: // %bb.0: -; CHECK-NEXT: sxth x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxth ; CHECK-NEXT: cset w0, eq ; CHECK-NEXT: ret %tmp0 = shl i64 %x, 48 ; 64-16 @@ -87,8 +83,7 @@ define i1 @shifts_eqcmp_i64_i8(i64 %x) nounwind { ; CHECK-LABEL: shifts_eqcmp_i64_i8: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtb x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxtb ; CHECK-NEXT: cset w0, eq ; CHECK-NEXT: ret %tmp0 = shl i64 %x, 56 ; 64-8 @@ -198,8 +193,7 @@ define i1 @add_ultcmp_i32_i16(i32 %x) nounwind { ; CHECK-LABEL: add_ultcmp_i32_i16: ; CHECK: // %bb.0: -; CHECK-NEXT: sxth w8, w0 -; CHECK-NEXT: cmp w8, w0 +; CHECK-NEXT: cmp w0, w0, sxth ; CHECK-NEXT: cset w0, eq ; CHECK-NEXT: ret %tmp0 = add i32 %x, 32768 ; 1U << (16-1) @@ -210,8 +204,7 @@ define i1 @add_ultcmp_i32_i8(i32 %x) nounwind { ; CHECK-LABEL: add_ultcmp_i32_i8: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtb w8, w0 -; CHECK-NEXT: cmp w8, w0 +; CHECK-NEXT: cmp w0, w0, sxtb ; CHECK-NEXT: cset w0, eq ; CHECK-NEXT: ret %tmp0 = add i32 %x, 128 ; 1U << (8-1) @@ -222,8 +215,7 @@ define i1 @add_ultcmp_i64_i32(i64 %x) nounwind { ; CHECK-LABEL: add_ultcmp_i64_i32: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtw x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxtw ; CHECK-NEXT: cset w0, eq ; CHECK-NEXT: ret %tmp0 = add i64 %x, 2147483648 ; 1U << (32-1) @@ -234,8 +226,7 @@ define i1 @add_ultcmp_i64_i16(i64 %x) nounwind { ; CHECK-LABEL: add_ultcmp_i64_i16: ; CHECK: // %bb.0: -; CHECK-NEXT: sxth x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxth ; CHECK-NEXT: cset w0, eq ; CHECK-NEXT: ret %tmp0 = add i64 %x, 32768 ; 1U << (16-1) @@ -246,8 +237,7 @@ define i1 @add_ultcmp_i64_i8(i64 %x) nounwind { ; CHECK-LABEL: add_ultcmp_i64_i8: ; CHECK: // %bb.0: -; CHECK-NEXT: sxtb x8, w0 -; CHECK-NEXT: cmp x8, x0 +; CHECK-NEXT: cmp x0, w0, sxtb ; CHECK-NEXT: cset w0, eq ; CHECK-NEXT: ret %tmp0 = add i64 %x, 128 ; 1U << (8-1)