}
break;
+ case ISD::BSWAP:
+ Tmp1 = LegalizeOp(Node->getOperand(0)); // Op
+ switch (TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0))) {
+ case TargetLowering::Legal:
+ if (Tmp1 != Node->getOperand(0))
+ Result = DAG.getNode(Node->getOpcode(), Node->getValueType(0), Tmp1);
+ break;
+ case TargetLowering::Promote: {
+ MVT::ValueType OVT = Tmp1.getValueType();
+ MVT::ValueType NVT = TLI.getTypeToPromoteTo(Node->getOpcode(), OVT);
+ unsigned DiffBits = getSizeInBits(NVT) - getSizeInBits(OVT);
+
+ Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, NVT, Tmp1);
+ Tmp1 = DAG.getNode(ISD::BSWAP, NVT, Tmp1);
+ Result = DAG.getNode(ISD::SRL, NVT, Tmp1,
+ DAG.getConstant(DiffBits, TLI.getShiftAmountTy()));
+ break;
+ }
+ case TargetLowering::Custom:
+ assert(0 && "Cannot custom legalize this yet!");
+ case TargetLowering::Expand: {
+ MVT::ValueType VT = Tmp1.getValueType();
+ switch (VT) {
+ default: assert(0 && "Unhandled Expand type in BSWAP!"); abort();
+ case MVT::i16:
+ Tmp2 = DAG.getNode(ISD::SHL, VT, Tmp1,
+ DAG.getConstant(8, TLI.getShiftAmountTy()));
+ Tmp1 = DAG.getNode(ISD::SRL, VT, Tmp1,
+ DAG.getConstant(8, TLI.getShiftAmountTy()));
+ Result = DAG.getNode(ISD::OR, VT, Tmp1, Tmp2);
+ break;
+ case MVT::i32:
+ Tmp4 = DAG.getNode(ISD::SHL, VT, Tmp1,
+ DAG.getConstant(24, TLI.getShiftAmountTy()));
+ Tmp3 = DAG.getNode(ISD::SHL, VT, Tmp1,
+ DAG.getConstant(8, TLI.getShiftAmountTy()));
+ Tmp2 = DAG.getNode(ISD::SRL, VT, Tmp1,
+ DAG.getConstant(8, TLI.getShiftAmountTy()));
+ Tmp1 = DAG.getNode(ISD::SRL, VT, Tmp1,
+ DAG.getConstant(24, TLI.getShiftAmountTy()));
+ Tmp3 = DAG.getNode(ISD::AND, VT, Tmp3, DAG.getConstant(0xFF0000, VT));
+ Tmp2 = DAG.getNode(ISD::AND, VT, Tmp2, DAG.getConstant(0xFF00, VT));
+ Tmp4 = DAG.getNode(ISD::OR, VT, Tmp4, Tmp3);
+ Tmp2 = DAG.getNode(ISD::OR, VT, Tmp2, Tmp1);
+ Result = DAG.getNode(ISD::OR, VT, Tmp4, Tmp2);
+ break;
+ }
+ break;
+ }
+ }
+ break;
+
case ISD::CTPOP:
case ISD::CTTZ:
case ISD::CTLZ:
AddLegalizedOperand(Op.getValue(1), Result.getValue(1));
break;
}
+ case ISD::BSWAP:
+ Tmp1 = Node->getOperand(0);
+ Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, NVT, Tmp1);
+ Tmp1 = DAG.getNode(ISD::BSWAP, NVT, Tmp1);
+ Result = DAG.getNode(ISD::SRL, NVT, Tmp1,
+ DAG.getConstant(getSizeInBits(NVT) - getSizeInBits(VT),
+ TLI.getShiftAmountTy()));
+ break;
case ISD::CTPOP:
case ISD::CTTZ:
case ISD::CTLZ:
Lo = DAG.getNode(ISD::SIGN_EXTEND_INREG, NVT, Lo, Node->getOperand(1));
break;
+ case ISD::BSWAP: {
+ ExpandOp(Node->getOperand(0), Lo, Hi);
+ SDOperand TempLo = DAG.getNode(ISD::BSWAP, NVT, Hi);
+ Hi = DAG.getNode(ISD::BSWAP, NVT, Lo);
+ Lo = TempLo;
+ break;
+ }
+
case ISD::CTPOP:
ExpandOp(Node->getOperand(0), Lo, Hi);
Lo = DAG.getNode(ISD::ADD, NVT, // ctpop(HL) -> ctpop(H)+ctpop(L)
DAG.setRoot(Tmp.getValue(1));
return 0;
}
+ case Intrinsic::bswap_i16:
+ setValue(&I, DAG.getNode(ISD::BSWAP,
+ getValue(I.getOperand(1)).getValueType(),
+ getValue(I.getOperand(1))));
+ return 0;
+ case Intrinsic::bswap_i32:
+ setValue(&I, DAG.getNode(ISD::BSWAP,
+ getValue(I.getOperand(1)).getValueType(),
+ getValue(I.getOperand(1))));
+ return 0;
+ case Intrinsic::bswap_i64:
+ setValue(&I, DAG.getNode(ISD::BSWAP,
+ getValue(I.getOperand(1)).getValueType(),
+ getValue(I.getOperand(1))));
+ return 0;
case Intrinsic::cttz:
setValue(&I, DAG.getNode(ISD::CTTZ,
getValue(I.getOperand(1)).getValueType(),
setOperationAction(ISD::CTTZ , MVT::i64 , Expand);
setOperationAction(ISD::CTLZ , MVT::i64 , Expand);
}
+ setOperationAction(ISD::BSWAP , MVT::i64, Expand);
setOperationAction(ISD::ROTL , MVT::i64, Expand);
setOperationAction(ISD::ROTR , MVT::i64, Expand);
setOperationAction(ISD::CTLZ , MVT::i64 , Expand);
setOperationAction(ISD::ROTL , MVT::i64 , Expand);
setOperationAction(ISD::ROTR , MVT::i64 , Expand);
+ setOperationAction(ISD::BSWAP, MVT::i64 , Expand); // mux @rev
// Not implemented yet.
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::CTLZ , MVT::i64 , Expand);
setOperationAction(ISD::ROTL , MVT::i64 , Expand);
setOperationAction(ISD::ROTR , MVT::i64 , Expand);
+ setOperationAction(ISD::BSWAP, MVT::i64 , Expand); // mux @rev
// FIXME: implement mulhs (xma.h) and mulhu (xma.hu)
setOperationAction(ISD::MULHS , MVT::i64 , Expand);
setOperationAction(ISD::MULHU , MVT::i64 , Expand);
setOperationAction(ISD::FSQRT, MVT::f32, Expand);
}
- // PowerPC does not have CTPOP or CTTZ
+ // PowerPC does not have BSWAP, CTPOP or CTTZ
+ setOperationAction(ISD::BSWAP, MVT::i32 , Expand);
setOperationAction(ISD::CTPOP, MVT::i32 , Expand);
setOperationAction(ISD::CTTZ , MVT::i32 , Expand);
setOperationAction(ISD::CTLZ , MVT::i32, Expand);
setOperationAction(ISD::ROTL , MVT::i32, Expand);
setOperationAction(ISD::ROTR , MVT::i32, Expand);
+ setOperationAction(ISD::BSWAP, MVT::i32, Expand);
setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
setOperationAction(ISD::CTLZ , MVT::i32, Expand);
setOperationAction(ISD::ROTL , MVT::i32, Expand);
setOperationAction(ISD::ROTR , MVT::i32, Expand);
+ setOperationAction(ISD::BSWAP, MVT::i32, Expand);
setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
[SDNPCommutative, SDNPAssociative]>;
def sext_inreg : SDNode<"ISD::SIGN_EXTEND_INREG", SDTExtInreg>;
+def bswap : SDNode<"ISD::BSWAP" , SDTIntUnaryOp>;
def ctlz : SDNode<"ISD::CTLZ" , SDTIntUnaryOp>;
def cttz : SDNode<"ISD::CTTZ" , SDTIntUnaryOp>;
def ctpop : SDNode<"ISD::CTPOP" , SDTIntUnaryOp>;
setOperationAction(ISD::READCYCLECOUNTER , MVT::i64 , Custom);
if (!X86DAGIsel) {
+ setOperationAction(ISD::BSWAP , MVT::i32 , Expand);
setOperationAction(ISD::ROTL , MVT::i8 , Expand);
setOperationAction(ISD::ROTR , MVT::i8 , Expand);
setOperationAction(ISD::ROTL , MVT::i16 , Expand);
setOperationAction(ISD::ROTL , MVT::i32 , Expand);
setOperationAction(ISD::ROTR , MVT::i32 , Expand);
}
+ setOperationAction(ISD::BSWAP , MVT::i16 , Expand);
setOperationAction(ISD::READIO , MVT::i1 , Expand);
setOperationAction(ISD::READIO , MVT::i8 , Expand);
let isTwoAddress = 1 in // R32 = bswap R32
def BSWAP32r : I<0xC8, AddRegFrm,
- (ops R32:$dst, R32:$src), "bswap{l} $dst", []>, TB;
+ (ops R32:$dst, R32:$src),
+ "bswap{l} $dst",
+ [(set R32:$dst, (bswap R32:$src))]>, TB;
def XCHG8rr : I<0x86, MRMDestReg, // xchg R8, R8
(ops R8:$src1, R8:$src2),
--- /dev/null
+; bswap should be constant folded when it is passed a constant argument
+
+; RUN: llvm-as < %s | llc -march=x86 -enable-x86-dag-isel | grep bswapl | wc -l | grep 3 &&
+; RUN: llvm-as < %s | llc -march=x86 -enable-x86-dag-isel | grep rolw | wc -l | grep 1
+
+declare ushort %llvm.bswap.i16(ushort)
+declare uint %llvm.bswap.i32(uint)
+declare ulong %llvm.bswap.i64(ulong)
+
+ushort %W(ushort %A) {
+ %Z = call ushort %llvm.bswap.i16(ushort %A)
+ ret ushort %Z
+}
+
+uint %X(uint %A) {
+ %Z = call uint %llvm.bswap.i32(uint %A)
+ ret uint %Z
+}
+
+ulong %Y(ulong %A) {
+ %Z = call ulong %llvm.bswap.i64(ulong %A)
+ ret ulong %Z
+}