Index: llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -337,8 +337,21 @@ // The input is widened to the same size. Convert to the widened value. // Make sure that the outgoing value is not a vector, because this would // make us bitcast between two vectors which are legalized in different ways. - if (NOutVT.bitsEq(NInVT) && !NOutVT.isVector()) - return DAG.getNode(ISD::BITCAST, dl, NOutVT, GetWidenedVector(InOp)); + if (NOutVT.bitsEq(NInVT) && !NOutVT.isVector()) { + SDValue Res = + DAG.getNode(ISD::BITCAST, dl, NOutVT, GetWidenedVector(InOp)); + + // For big endian targets we need to shift the casted value or the + // interesting bits will end up at the wrong place. + if (DAG.getDataLayout().isBigEndian()) { + unsigned ShiftAmt = NInVT.getSizeInBits() - InVT.getSizeInBits(); + EVT ShiftAmtTy = TLI.getShiftAmountTy(NOutVT, DAG.getDataLayout()); + assert(ShiftAmt < NOutVT.getSizeInBits() && "Too large shift amount!"); + Res = DAG.getNode(ISD::SRL, dl, NOutVT, Res, + DAG.getConstant(ShiftAmt, dl, ShiftAmtTy)); + } + return Res; + } // If the output type is also a vector and widening it to the same size // as the widened input type would be a legal type, we can widen the bitcast // and handle the promotion after. Index: llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -3457,7 +3457,7 @@ switch (getTypeAction(InVT)) { case TargetLowering::TypeLegal: break; - case TargetLowering::TypePromoteInteger: + case TargetLowering::TypePromoteInteger: { // If the incoming type is a vector that is being promoted, then // we know that the elements are arranged differently and that we // must perform the conversion using a stack slot. @@ -3466,11 +3466,24 @@ // If the InOp is promoted to the same size, convert it. Otherwise, // fall out of the switch and widen the promoted input. - InOp = GetPromotedInteger(InOp); - InVT = InOp.getValueType(); - if (WidenVT.bitsEq(InVT)) - return DAG.getNode(ISD::BITCAST, dl, WidenVT, InOp); + SDValue NInOp = GetPromotedInteger(InOp); + EVT NInVT = NInOp.getValueType(); + if (WidenVT.bitsEq(NInVT)) { + // For big endian targets we need to shift the input integer or the + // interesting bits will end up at the wrong place. + if (DAG.getDataLayout().isBigEndian()) { + unsigned ShiftAmt = NInVT.getSizeInBits() - InVT.getSizeInBits(); + EVT ShiftAmtTy = TLI.getShiftAmountTy(NInVT, DAG.getDataLayout()); + assert(ShiftAmt < WidenVT.getSizeInBits() && "Too large shift amount!"); + NInOp = DAG.getNode(ISD::SHL, dl, NInVT, NInOp, + DAG.getConstant(ShiftAmt, dl, ShiftAmtTy)); + } + return DAG.getNode(ISD::BITCAST, dl, WidenVT, NInOp); + } + InOp = NInOp; + InVT = NInVT; break; + } case TargetLowering::TypeSoftenFloat: case TargetLowering::TypePromoteFloat: case TargetLowering::TypeExpandInteger: Index: llvm/test/CodeGen/ARM/legalize-bitcast.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/ARM/legalize-bitcast.ll @@ -0,0 +1,36 @@ +; RUN: llc -O0 -mtriple=armebv7 -target-abi apcs -o - %s -stop-before=finalize-isel | FileCheck %s + +@vec6_p = external global <6 x i16> + +define i32 @vec_to_int() { +; CHECK-LABEL: name: vec_to_int +; CHECK-LABEL: bb.1.bb.1: +; CHECK: [[REG0:%[0-9]+]]:qpr = VREV32q16 {{%[0-9]+}} +; CHECK: [[REG1:%[0-9]+]]:dpr = COPY [[REG0]].dsub_1 +; CHECK: {{%[0-9]+}}:gpr = VGETLNi32 killed [[REG1]], 0 +bb.0: + %vec6 = load <6 x i16>, <6 x i16>* @vec6_p, align 1 + br label %bb.1 + +bb.1: + %0 = bitcast <6 x i16> %vec6 to i96 + %1 = trunc i96 %0 to i32 + ret i32 %1 +} + +define i16 @int_to_vec(i80 %in) { +; CHECK-LABEL: name: int_to_vec +; CHECK: [[REG0:%[0-9]+]]:gpr = COPY $r0 +; CHECK: [[REG1:%[0-9]+]]:gpr = MOVsi [[REG0]], 130 +; CHECK: [[REG2:%[0-9]+]]:gpr = ORRrsi killed [[REG1]], %1, 131 +; CHECK: [[REG3:%[0-9]+]]:dpr = VSETLNi32 {{%[0-9]+}}, killed [[REG2]], 0 +; CHECK: [[REG4:%[0-9]+]]:qpr = INSERT_SUBREG {{%[0-9]+}}, killed [[REG3]], %subreg.dsub_0 +; CHECK: [[REG5:%[0-9]+]]:qpr = VREV32q16 killed [[REG4]] +; CHECK: [[REG6:%[0-9]+]]:dpr = COPY [[REG5]].dsub_0 +; CHECK: [[REG7:%[0-9]+]]:gpr = VGETLNu16 killed [[REG6]], 0 +; CHECK: $r0 = COPY [[REG7]] +; CHECK: BX_RET 14, $noreg, implicit $r0 + %vec = bitcast i80 %in to <5 x i16> + %e0 = extractelement <5 x i16> %vec, i32 0 + ret i16 %e0 +}