SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const { unsigned Opc = Op.getOpcode(); SDNode* N = Op.getNode(); EVT VT = Op.getValueType(); DebugLoc dl = N->getDebugLoc(); // Expand non-constant shifts to loops: if (!isa<ConstantSDNode>(N->getOperand(1))) switch (Opc) { default: assert(0 && "Invalid shift opcode!"); case ISD::SHL: return DAG.getNode(AVRISD::SHL, dl, VT, N->getOperand(0), N->getOperand(1)); case ISD::SRA: return DAG.getNode(AVRISD::SRA, dl, VT, N->getOperand(0), N->getOperand(1)); case ISD::SRL: return DAG.getNode(AVRISD::SRL, dl, VT, N->getOperand(0), N->getOperand(1)); } uint64_t ShiftAmount = N->getConstantOperandVal(1); // Expand the stuff into sequence of shifts. // FIXME: for some shift amounts this might be done better! // E.g.: foo >> (8 + N) => sxt(swpb(foo)) >> N SDValue Victim = N->getOperand(0); unsigned int TargetOpcode = 0; switch(Opc) { case ISD::SHL: TargetOpcode = AVRISD::SHLC; break; case ISD::SRA: TargetOpcode = AVRISD::SRAC; break; case ISD::SRL: TargetOpcode = AVRISD::SRLC; break; } while (ShiftAmount--) Victim = DAG.getNode(TargetOpcode, dl, VT, Victim); return Victim; }