diff --git a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp --- a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp @@ -347,6 +347,12 @@ Known = Known.sext(BitWidth); break; } + case TargetOpcode::G_SEXT_INREG: { + computeKnownBitsImpl(MI.getOperand(1).getReg(), Known, DemandedElts, + Depth + 1); + Known = Known.sextInReg(MI.getOperand(2).getImm()); + break; + } case TargetOpcode::G_ANYEXT: { computeKnownBitsImpl(MI.getOperand(1).getReg(), Known, DemandedElts, Depth + 1); diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-redundant-and.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-redundant-and.mir --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-redundant-and.mir +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-redundant-and.mir @@ -142,3 +142,24 @@ $sgpr0 = COPY %6(s32) SI_RETURN_TO_EPILOG implicit $sgpr0 ... +--- +name: test_sext_inreg +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: test_sext_inreg + ; CHECK: %cst_1:_(s32) = G_CONSTANT i32 -5 + ; CHECK: $sgpr0 = COPY %cst_1(s32) + ; CHECK: SI_RETURN_TO_EPILOG implicit $sgpr0 + %cst_1:_(s32) = G_CONSTANT i32 -5 + + ; 000 ... 1011 + %cst_11:_(s32) = G_CONSTANT i32 11 + + ; Sext from the 4th bit -> 111 ... 1011 = -5 + %sext_inreg_11:_(s32) = G_SEXT_INREG %cst_11, 4 + + %and:_(s32) = G_AND %cst_1(s32), %sext_inreg_11(s32) + $sgpr0 = COPY %and(s32) + SI_RETURN_TO_EPILOG implicit $sgpr0 +... diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp --- a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp @@ -701,6 +701,78 @@ EXPECT_EQ((uint64_t)0xfffffffe, Res.Zero.getZExtValue()); } +TEST_F(AArch64GISelMITest, TestKnownBitsSextInReg) { + StringRef MIRString = R"( + ; 000...0001 + %one:_(s32) = G_CONSTANT i32 1 + + ; 000...0010 + %two:_(s32) = G_CONSTANT i32 2 + + ; 000...1010 + %ten:_(s32) = G_CONSTANT i32 10 + + ; ???...???? + %w0:_(s32) = COPY $w0 + + ; ???...?1? + %or:_(s32) = G_OR %w0, %two + + ; All bits are known. + %inreg1:_(s32) = G_SEXT_INREG %one, 1 + %copy_inreg1:_(s32) = COPY %inreg1 + + ; All bits unknown + %inreg2:_(s32) = G_SEXT_INREG %or, 1 + %copy_inreg2:_(s32) = COPY %inreg2 + + ; Extending from the only (known) set bit + ; 111...11? + %inreg3:_(s32) = G_SEXT_INREG %or, 2 + %copy_inreg3:_(s32) = COPY %inreg3 + + ; Extending from a known set bit, overwriting all of the high set bits. + ; 111...1110 + %inreg4:_(s32) = G_SEXT_INREG %ten, 2 + %copy_inreg4:_(s32) = COPY %inreg4 + +)"; + setUp(MIRString); + if (!TM) + return; + GISelKnownBits Info(*MF); + KnownBits Res; + auto GetKB = [&](unsigned Idx) { + Register CopyReg = Copies[Idx]; + auto *Copy = MRI->getVRegDef(CopyReg); + return Info.getKnownBits(Copy->getOperand(1).getReg()); + }; + + // Every bit is known to be a 1. + Res = GetKB(Copies.size() - 4); + EXPECT_EQ(32u, Res.getBitWidth()); + EXPECT_TRUE(Res.isAllOnes()); + + // All bits are unknown + Res = GetKB(Copies.size() - 3); + EXPECT_EQ(32u, Res.getBitWidth()); + EXPECT_TRUE(Res.isUnknown()); + + // Extending from the only known set bit + // 111...11? + Res = GetKB(Copies.size() - 2); + EXPECT_EQ(32u, Res.getBitWidth()); + EXPECT_EQ(0xFFFFFFFEu, Res.One.getZExtValue()); + EXPECT_EQ(0u, Res.Zero.getZExtValue()); + + // Extending from a known set bit, overwriting all of the high set bits. + // 111...1110 + Res = GetKB(Copies.size() - 1); + EXPECT_EQ(32u, Res.getBitWidth()); + EXPECT_EQ(0xFFFFFFFEu, Res.One.getZExtValue()); + EXPECT_EQ(1u, Res.Zero.getZExtValue()); +} + TEST_F(AArch64GISelMITest, TestKnownBitsMergeValues) { StringRef MIRString = R"( %val0:_(s16) = G_CONSTANT i16 35224