diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -3111,15 +3111,29 @@ switch (VT.SimpleTy) { case MVT::i8: + // Can always select i8s, no shift, mask the immediate value to + // deal with sign-extended value from lowering. + Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); + Imm = CurDAG->getTargetConstant(ImmVal & 0xFF, DL, MVT::i32); + return true; + case MVT::i16: + // i16 values get sign-extended to 32-bits during lowering, so need to + // check for "negative" values when shifting. if ((ImmVal & 0xFF) == ImmVal) { Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); Imm = CurDAG->getTargetConstant(ImmVal, DL, MVT::i32); return true; + } else if (((ImmVal & 0xFF) == 0) && + ((int32_t)ImmVal >= -32768) && + ((int32_t)ImmVal <= 32512)) { + Shift = CurDAG->getTargetConstant(8, DL, MVT::i32); + Imm = CurDAG->getTargetConstant((ImmVal/256) & 0xFF, DL, MVT::i32); + return true; } break; - case MVT::i16: case MVT::i32: case MVT::i64: + // Range of immediate won't trigger signedness problems for 32/64b. if ((ImmVal & 0xFF) == ImmVal) { Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); Imm = CurDAG->getTargetConstant(ImmVal, DL, MVT::i32); diff --git a/llvm/test/CodeGen/AArch64/sve-int-imm.ll b/llvm/test/CodeGen/AArch64/sve-int-imm.ll --- a/llvm/test/CodeGen/AArch64/sve-int-imm.ll +++ b/llvm/test/CodeGen/AArch64/sve-int-imm.ll @@ -75,6 +75,26 @@ ret %res } +define @add_i8_signedness( %a) { +; CHECK-LABEL: add_i8_signedness +; CHECK: add z0.b, z0.b, #255 +; CHECK-NEXT: ret + %elt = insertelement undef, i8 255, i32 0 + %splat = shufflevector %elt, undef, zeroinitializer + %res = add %a, %splat + ret %res +} + +define @add_i16_signedness( %a) { +; CHECK-LABEL: add_i16_signedness +; CHECK: add z0.h, z0.h, #65280 +; CHECK-NEXT: ret + %elt = insertelement undef, i16 65280, i32 0 + %splat = shufflevector %elt, undef, zeroinitializer + %res = add %a, %splat + ret %res +} + ; SUBR define @subr_i8_low( %a) { ; CHECK-LABEL: subr_i8_low