Index: lib/Target/PowerPC/PPCISelDAGToDAG.cpp =================================================================== --- lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -1331,6 +1331,34 @@ return std::make_pair(Interesting, &Bits); } + case ISD::TRUNCATE: { + EVT FromType = V.getOperand(0).getValueType(); + EVT ToType = V.getValueType(); + // We support only the case with truncate from i64 to i32. + if (FromType != MVT::i64 || ToType != MVT::i32) + break; + const unsigned NumAllBits = FromType.getSizeInBits(); + SmallVector *InBits; + std::tie(Interesting, InBits) = getValueBits(V.getOperand(0), + NumAllBits); + const unsigned NumValidBits = ToType.getSizeInBits(); + + // A 32-bit instruction cannot touch upper 32-bit part of 64-bit value. + // So, we cannot include this truncate. + bool UseUpper32bit = false; + for (unsigned i = 0; i < NumValidBits; ++i) + if ((*InBits)[i].hasValue() && (*InBits)[i].getValueBitIndex() >= 32) { + UseUpper32bit = true; + break; + } + if (UseUpper32bit) + break; + + for (unsigned i = 0; i < NumValidBits; ++i) + Bits[i] = (*InBits)[i]; + + return std::make_pair(Interesting, &Bits); + } case ISD::AssertZext: { // For AssertZext, we look through the operand and // mark the bits known to be zero. @@ -1676,6 +1704,17 @@ return ExtVal; } + SDValue TruncateToInt32(SDValue V, const SDLoc &dl) { + if (V.getValueSizeInBits() == 32) + return V; + + assert(V.getValueSizeInBits() == 64); + SDValue SubRegIdx = CurDAG->getTargetConstant(PPC::sub_32, dl, MVT::i32); + SDValue SubVal = SDValue(CurDAG->getMachineNode(PPC::EXTRACT_SUBREG, dl, + MVT::i32, V, SubRegIdx), 0); + return SubVal; + } + // Depending on the number of groups for a particular value, it might be // better to rotate, mask explicitly (using andi/andis), and then or the // result. Select this part of the result first. @@ -1734,12 +1773,12 @@ SDValue VRot; if (VRI.RLAmt) { SDValue Ops[] = - { VRI.V, getI32Imm(VRI.RLAmt, dl), getI32Imm(0, dl), - getI32Imm(31, dl) }; + { TruncateToInt32(VRI.V, dl), getI32Imm(VRI.RLAmt, dl), + getI32Imm(0, dl), getI32Imm(31, dl) }; VRot = SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, Ops), 0); } else { - VRot = VRI.V; + VRot = TruncateToInt32(VRI.V, dl); } SDValue ANDIVal, ANDISVal; @@ -1791,12 +1830,12 @@ if (VRI.RLAmt) { if (InstCnt) *InstCnt += 1; SDValue Ops[] = - { VRI.V, getI32Imm(VRI.RLAmt, dl), getI32Imm(0, dl), - getI32Imm(31, dl) }; + { TruncateToInt32(VRI.V, dl), getI32Imm(VRI.RLAmt, dl), + getI32Imm(0, dl), getI32Imm(31, dl) }; Res = SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, Ops), 0); } else { - Res = VRI.V; + Res = TruncateToInt32(VRI.V, dl); } // Now, remove all groups with this underlying value and rotation factor. @@ -1811,13 +1850,13 @@ for (auto &BG : BitGroups) { if (!Res) { SDValue Ops[] = - { BG.V, getI32Imm(BG.RLAmt, dl), + { TruncateToInt32(BG.V, dl), getI32Imm(BG.RLAmt, dl), getI32Imm(Bits.size() - BG.EndIdx - 1, dl), getI32Imm(Bits.size() - BG.StartIdx - 1, dl) }; Res = SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, Ops), 0); } else { SDValue Ops[] = - { Res, BG.V, getI32Imm(BG.RLAmt, dl), + { Res, TruncateToInt32(BG.V, dl), getI32Imm(BG.RLAmt, dl), getI32Imm(Bits.size() - BG.EndIdx - 1, dl), getI32Imm(Bits.size() - BG.StartIdx - 1, dl) }; Res = SDValue(CurDAG->getMachineNode(PPC::RLWIMI, dl, MVT::i32, Ops), 0); Index: test/CodeGen/PowerPC/bitfieldinsert.ll =================================================================== --- test/CodeGen/PowerPC/bitfieldinsert.ll +++ test/CodeGen/PowerPC/bitfieldinsert.ll @@ -60,3 +60,61 @@ ret void } +; test cases which include ISD::TRUNCATE +; equivalent C code +; struct s64b { +; int a:4; +; int b:16; +; int c:24; +; }; +; void bitfieldinsert64b(struct s64b *p, unsigned char v) { +; p->b = v; +; } + +%struct.s64b = type { i24, i24 } + +define void @bitfieldinsert64b(%struct.s64b* nocapture %p, i8 zeroext %v) { +; CHECK-LABEL: @bitfieldinsert64b +; CHECK: lwz [[REG1:[0-9]+]], 0(3) +; CHECK-NEXT: rlwimi [[REG1]], 4, 4, 12, 27 +; CHECK-NEXT: stw [[REG1]], 0(3) +; CHECK-NEXT: blr +entry: + %conv = zext i8 %v to i32 + %0 = bitcast %struct.s64b* %p to i32* + %bf.load = load i32, i32* %0, align 4 + %bf.shl = shl nuw nsw i32 %conv, 4 + %bf.clear = and i32 %bf.load, -1048561 + %bf.set = or i32 %bf.clear, %bf.shl + store i32 %bf.set, i32* %0, align 4 + ret void +} + +; equivalent C code +; struct s64c { +; int a:5; +; int b:16; +; long c:10; +; }; +; void bitfieldinsert64c(struct s64c *p, unsigned short v) { +; p->b = v; +; } + +%struct.s64c = type { i32, [4 x i8] } + +define void @bitfieldinsert64c(%struct.s64c* nocapture %p, i16 zeroext %v) { +; CHECK-LABEL: @bitfieldinsert64c +; CHECK: lwz [[REG1:[0-9]+]], 0(3) +; CHECK-NEXT: rlwimi [[REG1]], 4, 5, 11, 26 +; CHECK-NEXT: stw [[REG1]], 0(3) +; CHECK-NEXT: blr +entry: + %conv = zext i16 %v to i32 + %0 = getelementptr inbounds %struct.s64c, %struct.s64c* %p, i64 0, i32 0 + %bf.load = load i32, i32* %0, align 8 + %bf.shl = shl nuw nsw i32 %conv, 5 + %bf.clear = and i32 %bf.load, -2097121 + %bf.set = or i32 %bf.clear, %bf.shl + store i32 %bf.set, i32* %0, align 8 + ret void +}