Index: lib/Target/AArch64/AArch64ISelDAGToDAG.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -1875,23 +1875,52 @@ uint64_t MSB = cast(Op.getOperand(3).getNode())->getZExtValue(); - if (Op.getOperand(1) == Orig) - return getUsefulBitsFromBitfieldMoveOpd(Op, UsefulBits, Imm, MSB, Depth); - APInt OpUsefulBits(UsefulBits); OpUsefulBits = 1; + APInt ResultUsefulBits(UsefulBits.getBitWidth(), 0); + ResultUsefulBits.flipAllBits(); + APInt Mask(UsefulBits.getBitWidth(), 0); + + getUsefulBits(Op, ResultUsefulBits, Depth + 1); + if (MSB >= Imm) { - OpUsefulBits = OpUsefulBits.shl(MSB - Imm + 1); + // The instruction is a BFXIL. + uint64_t Width = MSB - Imm + 1; + uint64_t LSB = Imm; + + OpUsefulBits = OpUsefulBits.shl(Width); --OpUsefulBits; - UsefulBits &= ~OpUsefulBits; - getUsefulBits(Op, UsefulBits, Depth + 1); + + if (Op.getOperand(1) == Orig) { + // Copy the low bits from the result to bits starting from LSB. + Mask = ResultUsefulBits & OpUsefulBits; + Mask = Mask.shl(LSB); + } + + if (Op.getOperand(0) == Orig) + // Bits starting from LSB in the input contribute to the result. + Mask |= (ResultUsefulBits & ~OpUsefulBits); } else { - OpUsefulBits = OpUsefulBits.shl(MSB + 1); + // The instruction is a BFI. + uint64_t Width = MSB + 1; + uint64_t LSB = UsefulBits.getBitWidth() - Imm; + + OpUsefulBits = OpUsefulBits.shl(Width); --OpUsefulBits; - UsefulBits = ~(OpUsefulBits.shl(OpUsefulBits.getBitWidth() - Imm)); - getUsefulBits(Op, UsefulBits, Depth + 1); + OpUsefulBits = OpUsefulBits.shl(LSB); + + if (Op.getOperand(1) == Orig) { + // Copy the bits from the result to the zero bits. + Mask = ResultUsefulBits & OpUsefulBits; + Mask = Mask.lshr(LSB); + } + + if (Op.getOperand(0) == Orig) + Mask |= (ResultUsefulBits & ~OpUsefulBits); } + + UsefulBits &= Mask; } static void getUsefulBitsForUse(SDNode *UserNode, APInt &UsefulBits, Index: test/CodeGen/AArch64/arm64-bitfield-extract.ll =================================================================== --- test/CodeGen/AArch64/arm64-bitfield-extract.ll +++ test/CodeGen/AArch64/arm64-bitfield-extract.ll @@ -530,3 +530,34 @@ ret i16 %conv19 } + +; The following test excercises the case where we have a BFI +; instruction with the same input in both operands. We need to +; track the useful bits through both operands. +; CHECK-LABEL: sameOperandBFI +; CHECK: lsr +; CHECK: and +; CHECK: bfi +; CHECK: bfi +define void @sameOperandBFI(i64 %src, i64 %src2, i16 *%ptr) { +entry: + %shr.i315 = lshr i64 %src, 47 + %shr.i306.tr = trunc i64 %src2 to i32 + br i1 undef, label %if.end318, label %if.else + +if.else: + %0 = getelementptr inbounds [4 x i8], [4 x i8]* undef, i64 0, i64 0 + %retval.0.i272 = and i32 %shr.i306.tr, 3 + %retval.0.i275345 = shl nuw nsw i64 %shr.i315, 2 + %retval.0.i275 = trunc i64 %retval.0.i275345 to i32 + %conv56 = and i32 %retval.0.i275, 12 + %or59 = or i32 %conv56, %retval.0.i272 + %shl.i246 = shl nuw nsw i32 %or59, 4 + %or.i247 = or i32 %shl.i246, %or59 + %conv2.i248 = trunc i32 %or.i247 to i16 + store i16 %conv2.i248, i16* %ptr, align 4 + br label %if.end318 + +if.end318: + ret void +}