From a556ec8861df920bfaee3057df8aac739aa59b24 Mon Sep 17 00:00:00 2001 From: Zi Xuan Wu Date: Thu, 9 Dec 2021 11:35:34 +0800 Subject: [PATCH] [CSKY] Complete codegen of basic arithmetic and load/store operations Complete basic arithmetic operations such as add/sub/mul/div, and it also includes converions and some specific operations such as bswap.Add load/store patterns to generate different addressing mode instructions. Also enable some infra such as copy physical register and eliminate frame index. --- llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp | 89 +- llvm/lib/Target/CSKY/CSKYISelLowering.cpp | 40 + llvm/lib/Target/CSKY/CSKYInstrInfo.cpp | 288 ++++++ llvm/lib/Target/CSKY/CSKYInstrInfo.h | 25 + llvm/lib/Target/CSKY/CSKYInstrInfo.td | 101 ++ llvm/lib/Target/CSKY/CSKYRegisterInfo.cpp | 179 ++++ llvm/lib/Target/CSKY/CSKYRegisterInfo.h | 12 + llvm/test/CodeGen/CSKY/base-i.ll | 1053 ++++++++++++++++++++- llvm/test/CodeGen/CSKY/cvt-i.ll | 216 +++++ llvm/test/CodeGen/CSKY/intrinsic.ll | 36 + llvm/test/CodeGen/CSKY/ldst-i.ll | 449 +++++++++ llvm/test/CodeGen/CSKY/rotl.ll | 28 + 12 files changed, 2514 insertions(+), 2 deletions(-) create mode 100644 llvm/test/CodeGen/CSKY/cvt-i.ll create mode 100644 llvm/test/CodeGen/CSKY/intrinsic.ll create mode 100644 llvm/test/CodeGen/CSKY/ldst-i.ll create mode 100644 llvm/test/CodeGen/CSKY/rotl.ll diff --git a/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp b/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp index fc9ef8bfd9d9..8dc91904b8cc 100644 --- a/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp +++ b/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp @@ -40,6 +40,8 @@ public: } void Select(SDNode *N) override; + bool selectAddCarry(SDNode *N); + bool selectSubCarry(SDNode *N); #include "CSKYGenDAGISel.inc" }; @@ -60,7 +62,12 @@ void CSKYDAGToDAGISel::Select(SDNode *N) { switch (Opcode) { default: break; - // FIXME: Add selection nodes needed later. + case ISD::ADDCARRY: + IsSelected = selectAddCarry(N); + break; + case ISD::SUBCARRY: + IsSelected = selectSubCarry(N); + break; } if (IsSelected) @@ -70,6 +77,86 @@ void CSKYDAGToDAGISel::Select(SDNode *N) { SelectCode(N); } +bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) { + MachineSDNode *NewNode = nullptr; + auto Type0 = N->getValueType(0); + auto Type1 = N->getValueType(1); + auto Op0 = N->getOperand(0); + auto Op1 = N->getOperand(1); + auto Op2 = N->getOperand(2); + + SDLoc Dl(N); + + if (isNullConstant(Op2)) { + auto *CA = CurDAG->getMachineNode( + Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); + NewNode = CurDAG->getMachineNode( + Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, + {Op0, Op1, SDValue(CA, 0)}); + } else if (isOneConstant(Op2)) { + auto *CA = CurDAG->getMachineNode( + Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); + NewNode = CurDAG->getMachineNode( + Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, + {Op0, Op1, SDValue(CA, 0)}); + } else { + NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32 + : CSKY::ADDC16, + Dl, {Type0, Type1}, {Op0, Op1, Op2}); + } + ReplaceNode(N, NewNode); + return true; +} + +static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget, + SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) { + auto NewCarryReg = + DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl, + MVT::i32, OldCarry); + auto NewCarry = + DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16, + Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0), + DAG->getTargetConstant(0, Dl, MVT::i32)); + return SDValue(NewCarry, 0); +} + +bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) { + MachineSDNode *NewNode = nullptr; + auto Type0 = N->getValueType(0); + auto Type1 = N->getValueType(1); + auto Op0 = N->getOperand(0); + auto Op1 = N->getOperand(1); + auto Op2 = N->getOperand(2); + + SDLoc Dl(N); + + if (isNullConstant(Op2)) { + auto *CA = CurDAG->getMachineNode( + Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); + NewNode = CurDAG->getMachineNode( + Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, + {Op0, Op1, SDValue(CA, 0)}); + } else if (isOneConstant(Op2)) { + auto *CA = CurDAG->getMachineNode( + Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); + NewNode = CurDAG->getMachineNode( + Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, + {Op0, Op1, SDValue(CA, 0)}); + } else { + auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2); + NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32 + : CSKY::SUBC16, + Dl, {Type0, Type1}, {Op0, Op1, CarryIn}); + } + auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1)); + + ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0)); + ReplaceUses(SDValue(N, 1), CarryOut); + CurDAG->RemoveDeadNode(N); + + return true; +} + FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) { return new CSKYDAGToDAGISel(TM); } diff --git a/llvm/lib/Target/CSKY/CSKYISelLowering.cpp b/llvm/lib/Target/CSKY/CSKYISelLowering.cpp index ac6d069e592c..a1f7cc685d4c 100644 --- a/llvm/lib/Target/CSKY/CSKYISelLowering.cpp +++ b/llvm/lib/Target/CSKY/CSKYISelLowering.cpp @@ -37,6 +37,46 @@ CSKYTargetLowering::CSKYTargetLowering(const TargetMachine &TM, // Register Class addRegisterClass(MVT::i32, &CSKY::GPRRegClass); + setOperationAction(ISD::ADDCARRY, MVT::i32, Legal); + setOperationAction(ISD::SUBCARRY, MVT::i32, Legal); + setOperationAction(ISD::BITREVERSE, MVT::i32, Legal); + + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::UREM, MVT::i32, Expand); + setOperationAction(ISD::UDIVREM, MVT::i32, Expand); + setOperationAction(ISD::SDIVREM, MVT::i32, Expand); + setOperationAction(ISD::CTTZ, MVT::i32, Expand); + setOperationAction(ISD::CTPOP, MVT::i32, Expand); + setOperationAction(ISD::ROTR, MVT::i32, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + setOperationAction(ISD::MULHS, MVT::i32, Expand); + setOperationAction(ISD::MULHU, MVT::i32, Expand); + + setLoadExtAction(ISD::EXTLOAD, MVT::i32, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, MVT::i1, Promote); + + if (!Subtarget.hasE2()) { + setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i8, Expand); + setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i16, Expand); + setOperationAction(ISD::CTLZ, MVT::i32, Expand); + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + } + + if (!Subtarget.has2E3()) { + setOperationAction(ISD::ABS, MVT::i32, Expand); + setOperationAction(ISD::BITREVERSE, MVT::i32, Expand); + setOperationAction(ISD::SDIV, MVT::i32, Expand); + setOperationAction(ISD::UDIV, MVT::i32, Expand); + } + // Compute derived properties from the register classes. computeRegisterProperties(STI.getRegisterInfo()); diff --git a/llvm/lib/Target/CSKY/CSKYInstrInfo.cpp b/llvm/lib/Target/CSKY/CSKYInstrInfo.cpp index e12235cf9478..6fcb136cd99b 100644 --- a/llvm/lib/Target/CSKY/CSKYInstrInfo.cpp +++ b/llvm/lib/Target/CSKY/CSKYInstrInfo.cpp @@ -11,6 +11,8 @@ //===----------------------------------------------------------------------===// #include "CSKYInstrInfo.h" +#include "CSKYMachineFunctionInfo.h" +#include "CSKYTargetMachine.h" #include "llvm/MC/MCContext.h" #define DEBUG_TYPE "csky-instr-info" @@ -23,3 +25,289 @@ using namespace llvm; CSKYInstrInfo::CSKYInstrInfo(CSKYSubtarget &STI) : CSKYGenInstrInfo(CSKY::ADJCALLSTACKDOWN, CSKY::ADJCALLSTACKUP), STI(STI) { } + +Register CSKYInstrInfo::movImm(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, int64_t Val, + MachineInstr::MIFlag Flag) const { + assert(isUInt<32>(Val) && "should be uint32"); + + MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); + + Register DstReg; + if (STI.hasE2()) { + DstReg = MRI.createVirtualRegister(&CSKY::GPRRegClass); + + if (isUInt<16>(Val)) { + BuildMI(MBB, MBBI, DL, get(CSKY::MOVI32), DstReg) + .addImm(Val & 0xFFFF) + .setMIFlags(Flag); + } else if (isShiftedUInt<16, 16>(Val)) { + BuildMI(MBB, MBBI, DL, get(CSKY::MOVIH32), DstReg) + .addImm((Val >> 16) & 0xFFFF) + .setMIFlags(Flag); + } else { + BuildMI(MBB, MBBI, DL, get(CSKY::MOVIH32), DstReg) + .addImm((Val >> 16) & 0xFFFF) + .setMIFlags(Flag); + BuildMI(MBB, MBBI, DL, get(CSKY::ORI32), DstReg) + .addReg(DstReg) + .addImm(Val & 0xFFFF) + .setMIFlags(Flag); + } + + } else { + DstReg = MRI.createVirtualRegister(&CSKY::mGPRRegClass); + if (isUInt<8>(Val)) { + BuildMI(MBB, MBBI, DL, get(CSKY::MOVI16), DstReg) + .addImm(Val & 0xFF) + .setMIFlags(Flag); + } else if (isUInt<16>(Val)) { + BuildMI(MBB, MBBI, DL, get(CSKY::MOVI16), DstReg) + .addImm((Val >> 8) & 0xFF) + .setMIFlags(Flag); + BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg) + .addReg(DstReg) + .addImm(8) + .setMIFlags(Flag); + if ((Val & 0xFF) != 0) + BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg) + .addReg(DstReg) + .addImm(Val & 0xFF) + .setMIFlags(Flag); + } else if (isUInt<24>(Val)) { + BuildMI(MBB, MBBI, DL, get(CSKY::MOVI16), DstReg) + .addImm((Val >> 16) & 0xFF) + .setMIFlags(Flag); + BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg) + .addReg(DstReg) + .addImm(8) + .setMIFlags(Flag); + if (((Val >> 8) & 0xFF) != 0) + BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg) + .addReg(DstReg) + .addImm((Val >> 8) & 0xFF) + .setMIFlags(Flag); + BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg) + .addReg(DstReg) + .addImm(8) + .setMIFlags(Flag); + if ((Val & 0xFF) != 0) + BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg) + .addReg(DstReg) + .addImm(Val & 0xFF) + .setMIFlags(Flag); + } else { + BuildMI(MBB, MBBI, DL, get(CSKY::MOVI16), DstReg) + .addImm((Val >> 24) & 0xFF) + .setMIFlags(Flag); + BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg) + .addReg(DstReg) + .addImm(8) + .setMIFlags(Flag); + if (((Val >> 16) & 0xFF) != 0) + BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg) + .addReg(DstReg) + .addImm((Val >> 16) & 0xFF) + .setMIFlags(Flag); + BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg) + .addReg(DstReg) + .addImm(8) + .setMIFlags(Flag); + if (((Val >> 8) & 0xFF) != 0) + BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg) + .addReg(DstReg) + .addImm((Val >> 8) & 0xFF) + .setMIFlags(Flag); + BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg) + .addReg(DstReg) + .addImm(8) + .setMIFlags(Flag); + if ((Val & 0xFF) != 0) + BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg) + .addReg(DstReg) + .addImm(Val & 0xFF) + .setMIFlags(Flag); + } + } + + return DstReg; +} + +unsigned CSKYInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, + int &FrameIndex) const { + switch (MI.getOpcode()) { + default: + return 0; + case CSKY::LD16B: + case CSKY::LD16H: + case CSKY::LD16W: + case CSKY::LD32B: + case CSKY::LD32BS: + case CSKY::LD32H: + case CSKY::LD32HS: + case CSKY::LD32W: + case CSKY::RESTORE_CARRY: + break; + } + + if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() && + MI.getOperand(2).getImm() == 0) { + FrameIndex = MI.getOperand(1).getIndex(); + return MI.getOperand(0).getReg(); + } + + return 0; +} + +unsigned CSKYInstrInfo::isStoreToStackSlot(const MachineInstr &MI, + int &FrameIndex) const { + switch (MI.getOpcode()) { + default: + return 0; + case CSKY::ST16B: + case CSKY::ST16H: + case CSKY::ST16W: + case CSKY::ST32B: + case CSKY::ST32H: + case CSKY::ST32W: + case CSKY::SPILL_CARRY: + break; + } + + if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() && + MI.getOperand(2).getImm() == 0) { + FrameIndex = MI.getOperand(1).getIndex(); + return MI.getOperand(0).getReg(); + } + + return 0; +} + +void CSKYInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + Register SrcReg, bool IsKill, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL; + if (I != MBB.end()) + DL = I->getDebugLoc(); + + MachineFunction &MF = *MBB.getParent(); + CSKYMachineFunctionInfo *CFI = MF.getInfo(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + + unsigned Opcode = 0; + + if (CSKY::GPRRegClass.hasSubClassEq(RC)) { + Opcode = CSKY::ST32W; // Optimize for 16bit + } else if (CSKY::CARRYRegClass.hasSubClassEq(RC)) { + Opcode = CSKY::SPILL_CARRY; + CFI->setSpillsCR(); + } else { + llvm_unreachable("Unknown RegisterClass"); + } + + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOStore, + MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); + + BuildMI(MBB, I, DL, get(Opcode)) + .addReg(SrcReg, getKillRegState(IsKill)) + .addFrameIndex(FI) + .addImm(0) + .addMemOperand(MMO); +} + +void CSKYInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + Register DestReg, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL; + if (I != MBB.end()) + DL = I->getDebugLoc(); + + MachineFunction &MF = *MBB.getParent(); + CSKYMachineFunctionInfo *CFI = MF.getInfo(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + + unsigned Opcode = 0; + + if (CSKY::GPRRegClass.hasSubClassEq(RC)) { + Opcode = CSKY::LD32W; + } else if (CSKY::CARRYRegClass.hasSubClassEq(RC)) { + Opcode = CSKY::RESTORE_CARRY; + CFI->setSpillsCR(); + } else { + llvm_unreachable("Unknown RegisterClass"); + } + + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad, + MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); + + BuildMI(MBB, I, DL, get(Opcode), DestReg) + .addFrameIndex(FI) + .addImm(0) + .addMemOperand(MMO); +} + +void CSKYInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + const DebugLoc &DL, MCRegister DestReg, + MCRegister SrcReg, bool KillSrc) const { + + MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); + + if (CSKY::GPRRegClass.contains(SrcReg) && + CSKY::CARRYRegClass.contains(DestReg)) { + if (STI.hasE2()) { + BuildMI(MBB, I, DL, get(CSKY::BTSTI32), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)) + .addImm(0); + } else { + assert(SrcReg < CSKY::R8); + BuildMI(MBB, I, DL, get(CSKY::BTSTI16), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)) + .addImm(0); + } + return; + } + + if (CSKY::CARRYRegClass.contains(SrcReg) && + CSKY::GPRRegClass.contains(DestReg)) { + + if (STI.hasE2()) { + BuildMI(MBB, I, DL, get(CSKY::MVC32), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + } else { + assert(DestReg < CSKY::R16); + assert(DestReg < CSKY::R8); + BuildMI(MBB, I, DL, get(CSKY::MOVI16), DestReg).addImm(0); + BuildMI(MBB, I, DL, get(CSKY::ADDC16)) + .addReg(DestReg, RegState::Define) + .addReg(SrcReg, RegState::Define) + .addReg(DestReg, getKillRegState(true)) + .addReg(DestReg, getKillRegState(true)) + .addReg(SrcReg, getKillRegState(true)); + BuildMI(MBB, I, DL, get(CSKY::BTSTI16)) + .addReg(SrcReg, RegState::Define | getDeadRegState(KillSrc)) + .addReg(DestReg) + .addImm(0); + } + return; + } + + unsigned Opcode = 0; + if (CSKY::GPRRegClass.contains(DestReg, SrcReg)) + Opcode = CSKY::MOV32; + else { + LLVM_DEBUG(dbgs() << "src = " << SrcReg << ", dst = " << DestReg); + LLVM_DEBUG(I->dump()); + llvm_unreachable("Unknown RegisterClass"); + } + + BuildMI(MBB, I, DL, get(Opcode), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); +} diff --git a/llvm/lib/Target/CSKY/CSKYInstrInfo.h b/llvm/lib/Target/CSKY/CSKYInstrInfo.h index 04be9da27b57..450641d96b74 100644 --- a/llvm/lib/Target/CSKY/CSKYInstrInfo.h +++ b/llvm/lib/Target/CSKY/CSKYInstrInfo.h @@ -29,6 +29,31 @@ protected: public: explicit CSKYInstrInfo(CSKYSubtarget &STI); + + unsigned isLoadFromStackSlot(const MachineInstr &MI, + int &FrameIndex) const override; + unsigned isStoreToStackSlot(const MachineInstr &MI, + int &FrameIndex) const override; + + void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, Register SrcReg, + bool IsKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; + + void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, Register DestReg, + int FrameIndex, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; + + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg, + bool KillSrc) const override; + + // Materializes the given integer Val into DstReg. + Register movImm(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, int64_t Val, + MachineInstr::MIFlag Flag = MachineInstr::NoFlags) const; }; } // namespace llvm diff --git a/llvm/lib/Target/CSKY/CSKYInstrInfo.td b/llvm/lib/Target/CSKY/CSKYInstrInfo.td index 32e6cfd7e40f..30d9206eec68 100644 --- a/llvm/lib/Target/CSKY/CSKYInstrInfo.td +++ b/llvm/lib/Target/CSKY/CSKYInstrInfo.td @@ -52,6 +52,11 @@ class OImmAsmOperand : ImmAsmOperand<"O", width, suffix> { } +def to_tframeindex : SDNodeXForm(N); + return CurDAG->getTargetFrameIndex(FI->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout())); +}]>; + class oimm : Operand, ImmLeaf(Imm - 1);"> { let EncoderMethod = "getOImmOpValue"; @@ -972,6 +977,102 @@ def TRAP32 : CSKY32Inst { + def : Pat<(Type (LoadOp GPR:$rs1)), (Inst GPR:$rs1, 0)>; + def : Pat<(Type (LoadOp (i32 frameindex:$rs1))), (Inst (i32 (to_tframeindex tframeindex:$rs1)), 0)>; + def : Pat<(Type (LoadOp (add GPR:$rs1, imm_type:$uimm))), + (Inst GPR:$rs1, imm_type:$uimm)>; + def : Pat<(Type (LoadOp (add frameindex:$rs1, imm_type:$uimm))), + (Inst (i32 (to_tframeindex tframeindex:$rs1)), imm_type:$uimm)>; + def : Pat<(Type (LoadOp (eqToAdd frameindex:$rs1, imm_type:$uimm))), + (Inst (i32 (to_tframeindex tframeindex:$rs1)), imm_type:$uimm)>; + def : Pat<(Type (LoadOp (add GPR:$rs1, tglobaladdr:$gd))), + (Inst GPR:$rs1, tglobaladdr:$gd)>; +} + +defm : LdPat; +defm : LdPat; +let Predicates = [iHasE2] in { + defm : LdPat; +} +defm : LdPat; +defm : LdPat; +let Predicates = [iHasE2] in { +defm : LdPat; +} +defm : LdPat; + +multiclass LdrPat { + def : Pat<(Type (LoadOp (add GPR:$rs1, GPR:$rs2))), (Inst GPR:$rs1, GPR:$rs2, 0)>; + def : Pat<(Type (LoadOp (add GPR:$rs1, (shl GPR:$rs2, (i32 1))))), (Inst GPR:$rs1, GPR:$rs2, 1)>; + def : Pat<(Type (LoadOp (add GPR:$rs1, (shl GPR:$rs2, (i32 2))))), (Inst GPR:$rs1, GPR:$rs2, 2)>; + def : Pat<(Type (LoadOp (add GPR:$rs1, (shl GPR:$rs2, (i32 3))))), (Inst GPR:$rs1, GPR:$rs2, 3)>; +} + +let Predicates = [iHas2E3] in { + defm : LdrPat; + defm : LdrPat; + defm : LdrPat; + defm : LdrPat; + defm : LdrPat; + defm : LdrPat; + defm : LdrPat; +} + +multiclass StPat { + def : Pat<(StoreOp Type:$rs2, GPR:$rs1), (Inst Type:$rs2, GPR:$rs1, 0)>; + def : Pat<(StoreOp Type:$rs2, frameindex:$rs1), (Inst Type:$rs2, (i32 (to_tframeindex tframeindex:$rs1)), 0)>; + def : Pat<(StoreOp Type:$rs2, (add GPR:$rs1, imm_type:$uimm12)), + (Inst Type:$rs2, GPR:$rs1, imm_type:$uimm12)>; + def : Pat<(StoreOp Type:$rs2, (add frameindex:$rs1, imm_type:$uimm12)), + (Inst Type:$rs2, (i32 (to_tframeindex tframeindex:$rs1)), imm_type:$uimm12)>; + def : Pat<(StoreOp Type:$rs2, (eqToAdd frameindex:$rs1, imm_type:$uimm12)), + (Inst Type:$rs2, (i32 (to_tframeindex tframeindex:$rs1)), imm_type:$uimm12)>; +} + +defm : StPat; +defm : StPat; +defm : StPat; + +multiclass StrPat { + def : Pat<(StoreOp Type:$rz, (add GPR:$rs1, GPR:$rs2)), (Inst Type:$rz, GPR:$rs1, GPR:$rs2, 0)>; + def : Pat<(StoreOp Type:$rz, (add GPR:$rs1, (shl GPR:$rs2, (i32 1)))), (Inst Type:$rz, GPR:$rs1, GPR:$rs2, 1)>; + def : Pat<(StoreOp Type:$rz, (add GPR:$rs1, (shl GPR:$rs2, (i32 2)))), (Inst Type:$rz, GPR:$rs1, GPR:$rs2, 2)>; + def : Pat<(StoreOp Type:$rz, (add GPR:$rs1, (shl GPR:$rs2, (i32 3)))), (Inst Type:$rz, GPR:$rs1, GPR:$rs2, 3)>; +} + +let Predicates = [iHas2E3] in { + defm : StrPat; + defm : StrPat; + defm : StrPat; + + // Sext & Zext Patterns + def : Pat<(sext_inreg GPR:$src, i1), (SEXT32 GPR:$src, 0, 0)>; + def : Pat<(and GPR:$src, 255), (ZEXT32 GPR:$src, 7, 0)>; + def : Pat<(and GPR:$src, 65535), (ZEXT32 GPR:$src, 15, 0)>; +} + +// Constant materialize patterns. +let Predicates = [iHasE2] in + def : Pat<(i32 imm:$imm), + (ORI32 (MOVIH32 (uimm32_hi16 imm:$imm)), (uimm32_lo16 imm:$imm))>; + + +// Other operations. +let Predicates = [iHasE2] in { + def : Pat<(rotl GPR:$rs1, GPR:$rs2), + (ROTL32 GPR:$rs1, (ANDI32 GPR:$rs2, 0x1f))>; + let Predicates = [iHas2E3] in { + def : Pat<(bitreverse GPR:$rx), (BREV32 GPR:$rx)>; + def : Pat<(bswap GPR:$rx), (REVB32 GPR:$rx)>; + } + def : Pat<(i32 (ctlz GPR:$rx)), (FF1 GPR:$rx)>; +} //===----------------------------------------------------------------------===// // Pseudo for assembly diff --git a/llvm/lib/Target/CSKY/CSKYRegisterInfo.cpp b/llvm/lib/Target/CSKY/CSKYRegisterInfo.cpp index a1d45fea534b..d3b270e1a7bc 100644 --- a/llvm/lib/Target/CSKY/CSKYRegisterInfo.cpp +++ b/llvm/lib/Target/CSKY/CSKYRegisterInfo.cpp @@ -88,8 +88,187 @@ CSKYRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { return CSR_I32_SaveList; } +static bool IsLegalOffset(const CSKYInstrInfo *TII, MachineInstr *MI, + int &Offset) { + const MCInstrDesc &Desc = MI->getDesc(); + unsigned AddrMode = (Desc.TSFlags & CSKYII::AddrModeMask); + unsigned i = 0; + for (; !MI->getOperand(i).isFI(); ++i) { + assert(i + 1 < MI->getNumOperands() && + "Instr doesn't have FrameIndex operand!"); + } + + if (MI->getOpcode() == CSKY::ADDI32) { + if (!isUInt<12>(std::abs(Offset) - 1)) + return false; + if (Offset < 0) { + MI->setDesc(TII->get(CSKY::SUBI32)); + Offset = -Offset; + } + + return true; + } + + if (MI->getOpcode() == CSKY::ADDI16XZ) + return false; + + if (Offset < 0) + return false; + + unsigned NumBits = 0; + unsigned Scale = 1; + switch (AddrMode) { + case CSKYII::AddrMode32B: + Scale = 1; + NumBits = 12; + break; + case CSKYII::AddrMode32H: + Scale = 2; + NumBits = 12; + break; + case CSKYII::AddrMode32WD: + Scale = 4; + NumBits = 12; + break; + case CSKYII::AddrMode16B: + Scale = 1; + NumBits = 5; + break; + case CSKYII::AddrMode16H: + Scale = 2; + NumBits = 5; + break; + case CSKYII::AddrMode16W: + Scale = 4; + NumBits = 5; + break; + case CSKYII::AddrMode32SDF: + Scale = 4; + NumBits = 8; + break; + default: + llvm_unreachable("Unsupported addressing mode!"); + } + + // Cannot encode offset. + if ((Offset & (Scale - 1)) != 0) + return false; + + unsigned Mask = (1 << NumBits) - 1; + if ((unsigned)Offset <= Mask * Scale) + return true; + + // Offset out of range. + return false; +} + void CSKYRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, RegScavenger *RS) const { assert(SPAdj == 0 && "Unexpected non-zero SPAdj value"); + + MachineInstr *MI = &*II; + MachineBasicBlock &MBB = *MI->getParent(); + MachineFunction &MF = *MI->getParent()->getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + const CSKYInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + const CSKYSubtarget &STI = MF.getSubtarget(); + + switch (MI->getOpcode()) { + default: + break; + case CSKY::RESTORE_CARRY: { + Register NewReg = STI.hasE2() + ? MRI.createVirtualRegister(&CSKY::GPRRegClass) + : MRI.createVirtualRegister(&CSKY::mGPRRegClass); + + auto *Temp = BuildMI(MBB, II, DL, TII->get(CSKY::LD32W), NewReg) + .add(MI->getOperand(1)) + .add(MI->getOperand(2)) + .getInstr(); + + BuildMI(MBB, II, DL, TII->get(STI.hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16), + MI->getOperand(0).getReg()) + .addReg(NewReg, getKillRegState(true)) + .addImm(0); + + MI = Temp; + + MBB.erase(II); + break; + } + case CSKY::SPILL_CARRY: { + Register NewReg; + if (STI.hasE2()) { + NewReg = MRI.createVirtualRegister(&CSKY::GPRRegClass); + BuildMI(MBB, II, DL, TII->get(CSKY::MVC32), NewReg) + .add(MI->getOperand(0)); + } else { + NewReg = MRI.createVirtualRegister(&CSKY::mGPRRegClass); + BuildMI(MBB, II, DL, TII->get(CSKY::MOVI16), NewReg).addImm(0); + BuildMI(MBB, II, DL, TII->get(CSKY::ADDC16)) + .addReg(NewReg, RegState::Define) + .addReg(MI->getOperand(0).getReg(), RegState::Define) + .addReg(NewReg, getKillRegState(true)) + .addReg(NewReg, getKillRegState(true)) + .addReg(MI->getOperand(0).getReg()); + + BuildMI(MBB, II, DL, TII->get(CSKY::BTSTI16), MI->getOperand(0).getReg()) + .addReg(NewReg) + .addImm(0); + } + + MI = BuildMI(MBB, II, DL, TII->get(CSKY::ST32W)) + .addReg(NewReg, getKillRegState(true)) + .add(MI->getOperand(1)) + .add(MI->getOperand(2)) + .getInstr(); + + MBB.erase(II); + + break; + } + } + + int FrameIndex = MI->getOperand(FIOperandNum).getIndex(); + Register FrameReg; + int Offset = getFrameLowering(MF) + ->getFrameIndexReference(MF, FrameIndex, FrameReg) + .getFixed() + + MI->getOperand(FIOperandNum + 1).getImm(); + + if (!isInt<32>(Offset)) + report_fatal_error( + "Frame offsets outside of the signed 32-bit range not supported"); + + bool FrameRegIsKill = false; + MachineBasicBlock::iterator NewII(MI); + if (!IsLegalOffset(TII, MI, Offset)) { + assert(isInt<32>(Offset) && "Int32 expected"); + // The offset won't fit in an immediate, so use a scratch register instead + // Modify Offset and FrameReg appropriately + assert(Offset >= 0); + Register ScratchReg = TII->movImm(MBB, NewII, DL, Offset); + BuildMI(MBB, NewII, DL, + TII->get(STI.hasE2() ? CSKY::ADDU32 : CSKY::ADDU16XZ), ScratchReg) + .addReg(ScratchReg, RegState::Kill) + .addReg(FrameReg); + + Offset = 0; + FrameReg = ScratchReg; + FrameRegIsKill = true; + } + + if (Offset == 0 && + (MI->getOpcode() == CSKY::ADDI32 || MI->getOpcode() == CSKY::ADDI16XZ)) { + MI->setDesc(TII->get(TargetOpcode::COPY)); + MI->getOperand(FIOperandNum) + .ChangeToRegister(FrameReg, false, false, FrameRegIsKill); + MI->RemoveOperand(FIOperandNum + 1); + } else { + MI->getOperand(FIOperandNum) + .ChangeToRegister(FrameReg, false, false, FrameRegIsKill); + MI->getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); + } } \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/CSKYRegisterInfo.h b/llvm/lib/Target/CSKY/CSKYRegisterInfo.h index 779ea6493c7e..5b3b62ec0db2 100644 --- a/llvm/lib/Target/CSKY/CSKYRegisterInfo.h +++ b/llvm/lib/Target/CSKY/CSKYRegisterInfo.h @@ -38,6 +38,18 @@ public: void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, unsigned FIOperandNum, RegScavenger *RS) const override; + + bool requiresFrameIndexScavenging(const MachineFunction &MF) const override { + return true; + } + + bool requiresRegisterScavenging(const MachineFunction &MF) const override { + return true; + } + + bool useFPForScavengingIndex(const MachineFunction &MF) const override { + return false; + } }; } // namespace llvm diff --git a/llvm/test/CodeGen/CSKY/base-i.ll b/llvm/test/CodeGen/CSKY/base-i.ll index c1fa0f63eae4..c630ac7eae22 100644 --- a/llvm/test/CodeGen/CSKY/base-i.ll +++ b/llvm/test/CodeGen/CSKY/base-i.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -verify-machineinstrs -csky-no-aliases -mattr=+e2 < %s -mtriple=csky | FileCheck %s +; RUN: llc -verify-machineinstrs -csky-no-aliases -mattr=+e2 -mattr=+2e3 < %s -mtriple=csky | FileCheck %s define i32 @addRR(i32 %x, i32 %y) { ; CHECK-LABEL: addRR: @@ -31,3 +31,1054 @@ entry: %add = add nsw i32 %x, 4097 ret i32 %add } + +define i64 @ADD_LONG(i64 %x, i64 %y) { +; CHECK-LABEL: ADD_LONG: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: clrc32 +; CHECK-NEXT: addc32 a0, a2, a0 +; CHECK-NEXT: addc32 a1, a3, a1 +; CHECK-NEXT: rts16 +entry: + %add = add nsw i64 %y, %x + ret i64 %add +} + +define i64 @ADD_LONG_I(i64 %x) { +; CHECK-LABEL: ADD_LONG_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: clrc32 +; CHECK-NEXT: movi16 a2, 1 +; CHECK-NEXT: addc16 a0, a2 +; CHECK-NEXT: movi16 a2, 0 +; CHECK-NEXT: addc16 a1, a2 +; CHECK-NEXT: rts16 +entry: + %add = add nsw i64 %x, 1 + ret i64 %add +} + +define i16 @ADD_SHORT(i16 %x, i16 %y) { +; CHECK-LABEL: ADD_SHORT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addu16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %add = add nsw i16 %y, %x + ret i16 %add +} + +define i16 @ADD_SHORT_I(i16 %x) { +; CHECK-LABEL: ADD_SHORT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addi16 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %add = add nsw i16 %x, 1 + ret i16 %add +} + +define i8 @ADD_CHAR(i8 %x, i8 %y) { +; CHECK-LABEL: ADD_CHAR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addu16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %add = add nsw i8 %y, %x + ret i8 %add +} + +define i8 @ADD_CHAR_I(i8 %x) { +; CHECK-LABEL: ADD_CHAR_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addi16 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %add = add nsw i8 %x, 1 + ret i8 %add +} + + +define i32 @subRR(i32 %x, i32 %y) { +; CHECK-LABEL: subRR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: subu16 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %sub = sub nsw i32 %y, %x + ret i32 %sub +} + +define i32 @subRI(i32 %x) { +; CHECK-LABEL: subRI: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movih32 a1, 65535 +; CHECK-NEXT: ori32 a1, a1, 65526 +; CHECK-NEXT: addu16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %sub = sub nsw i32 %x, 10 + ret i32 %sub +} + +define i32 @subRI_X(i32 %x) { +; CHECK-LABEL: subRI_X: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movih32 a1, 65535 +; CHECK-NEXT: ori32 a1, a1, 61439 +; CHECK-NEXT: addu16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %sub = sub nsw i32 %x, 4097 + ret i32 %sub +} + +define i64 @SUB_LONG(i64 %x, i64 %y) { +; CHECK-LABEL: SUB_LONG: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: setc32 +; CHECK-NEXT: subc32 a0, a2, a0 +; CHECK-NEXT: mvcv16 a2 +; CHECK-NEXT: btsti32 a2, 0 +; CHECK-NEXT: mvcv16 a2 +; CHECK-NEXT: btsti32 a2, 0 +; CHECK-NEXT: subc32 a1, a3, a1 +; CHECK-NEXT: rts16 +entry: + %sub = sub nsw i64 %y, %x + ret i64 %sub +} + +define i64 @SUB_LONG_I(i64 %x) { +; CHECK-LABEL: SUB_LONG_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: clrc32 +; CHECK-NEXT: movih32 a2, 65535 +; CHECK-NEXT: ori32 a2, a2, 65535 +; CHECK-NEXT: addc16 a0, a2 +; CHECK-NEXT: addc16 a1, a2 +; CHECK-NEXT: rts16 +entry: + %sub = sub nsw i64 %x, 1 + ret i64 %sub +} + +define i16 @SUB_SHORT(i16 %x, i16 %y) { +; CHECK-LABEL: SUB_SHORT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: subu16 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %sub = sub nsw i16 %y, %x + ret i16 %sub +} + +define i16 @SUB_SHORT_I(i16 %x) { +; CHECK-LABEL: SUB_SHORT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movih32 a1, 65535 +; CHECK-NEXT: ori32 a1, a1, 65535 +; CHECK-NEXT: addu16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %sub = sub nsw i16 %x, 1 + ret i16 %sub +} + +define i8 @SUB_CHAR(i8 %x, i8 %y) { +; CHECK-LABEL: SUB_CHAR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: subu16 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %sub = sub nsw i8 %y, %x + ret i8 %sub +} + +define i8 @SUB_CHAR_I(i8 %x) { +; CHECK-LABEL: SUB_CHAR_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movih32 a1, 65535 +; CHECK-NEXT: ori32 a1, a1, 65535 +; CHECK-NEXT: addu16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %sub = sub nsw i8 %x, 1 + ret i8 %sub +} + +define i32 @mulRR(i32 %x, i32 %y) { +; CHECK-LABEL: mulRR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %mul = mul nsw i32 %y, %x + ret i32 %mul +} + +define i32 @mulRI(i32 %x) { +; CHECK-LABEL: mulRI: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi16 a1, 10 +; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %mul = mul nsw i32 %x, 10 + ret i32 %mul +} + +define i32 @mulRI_X(i32 %x) { +; CHECK-LABEL: mulRI_X: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi32 a1, 4097 +; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %mul = mul nsw i32 %x, 4097 + ret i32 %mul +} + +define i16 @MUL_SHORT(i16 %x, i16 %y) { +; CHECK-LABEL: MUL_SHORT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %mul = mul nsw i16 %y, %x + ret i16 %mul +} + +define i16 @MUL_SHORT_I(i16 %x) { +; CHECK-LABEL: MUL_SHORT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi16 a1, 3 +; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %mul = mul nsw i16 %x, 3 + ret i16 %mul +} + +define i8 @MUL_CHAR(i8 %x, i8 %y) { +; CHECK-LABEL: MUL_CHAR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %mul = mul nsw i8 %y, %x + ret i8 %mul +} + +define i8 @MUL_CHAR_I(i8 %x) { +; CHECK-LABEL: MUL_CHAR_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movih32 a1, 65535 +; CHECK-NEXT: ori32 a1, a1, 65533 +; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %mul = mul nsw i8 %x, -3 + ret i8 %mul +} + +define i32 @udivRR(i32 %x, i32 %y) { +; CHECK-LABEL: udivRR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: divu32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %udiv = udiv i32 %y, %x + ret i32 %udiv +} + +define i32 @udivRI(i32 %x) { +; CHECK-LABEL: udivRI: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi16 a1, 10 +; CHECK-NEXT: divu32 a0, a0, a1 +; CHECK-NEXT: rts16 +entry: + %udiv = udiv i32 %x, 10 + ret i32 %udiv +} + +define i32 @udivRI_X(i32 %x) { +; CHECK-LABEL: udivRI_X: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi32 a1, 4097 +; CHECK-NEXT: divu32 a0, a0, a1 +; CHECK-NEXT: rts16 +entry: + %udiv = udiv i32 %x, 4097 + ret i32 %udiv +} + +define i16 @UDIV_SHORT(i16 %x, i16 %y) { +; CHECK-LABEL: UDIV_SHORT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zexth16 a0, a0 +; CHECK-NEXT: zexth16 a1, a1 +; CHECK-NEXT: divu32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %udiv = udiv i16 %y, %x + ret i16 %udiv +} + +define i16 @UDIV_SHORT_I(i16 %x) { +; CHECK-LABEL: UDIV_SHORT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zexth16 a0, a0 +; CHECK-NEXT: movi32 a1, 43691 +; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: lsri16 a0, a0, 17 +; CHECK-NEXT: rts16 +entry: + %udiv = udiv i16 %x, 3 + ret i16 %udiv +} + +define i8 @UDIV_CHAR(i8 %x, i8 %y) { +; CHECK-LABEL: UDIV_CHAR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zextb16 a0, a0 +; CHECK-NEXT: zextb16 a1, a1 +; CHECK-NEXT: divu32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %udiv = udiv i8 %y, %x + ret i8 %udiv +} + +define i8 @UDIV_CHAR_I(i8 %x) { +; CHECK-LABEL: UDIV_CHAR_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zextb16 a0, a0 +; CHECK-NEXT: movi16 a1, 171 +; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: lsri16 a0, a0, 9 +; CHECK-NEXT: rts16 +entry: + %udiv = udiv i8 %x, 3 + ret i8 %udiv +} + +define i32 @sdivRR(i32 %x, i32 %y) { +; CHECK-LABEL: sdivRR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: divs32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %sdiv = sdiv i32 %y, %x + ret i32 %sdiv +} + +define i32 @sdivRI(i32 %x) { +; CHECK-LABEL: sdivRI: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi16 a1, 10 +; CHECK-NEXT: divs32 a0, a0, a1 +; CHECK-NEXT: rts16 +entry: + %sdiv = sdiv i32 %x, 10 + ret i32 %sdiv +} + +define i32 @sdivRI_X(i32 %x) { +; CHECK-LABEL: sdivRI_X: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi32 a1, 4097 +; CHECK-NEXT: divs32 a0, a0, a1 +; CHECK-NEXT: rts16 +entry: + %sdiv = sdiv i32 %x, 4097 + ret i32 %sdiv +} + +define i16 @SDIV_SHORT(i16 %x, i16 %y) { +; CHECK-LABEL: SDIV_SHORT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sexth16 a0, a0 +; CHECK-NEXT: sexth16 a1, a1 +; CHECK-NEXT: divs32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %sdiv = sdiv i16 %y, %x + ret i16 %sdiv +} + +define i16 @SDIV_SHORT_I(i16 %x) { +; CHECK-LABEL: SDIV_SHORT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sexth16 a0, a0 +; CHECK-NEXT: movi32 a1, 21846 +; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: lsri16 a1, a0, 31 +; CHECK-NEXT: lsri16 a0, a0, 16 +; CHECK-NEXT: addu16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %sdiv = sdiv i16 %x, 3 + ret i16 %sdiv +} + +define i8 @SDIV_CHAR(i8 %x, i8 %y) { +; CHECK-LABEL: SDIV_CHAR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sextb16 a0, a0 +; CHECK-NEXT: sextb16 a1, a1 +; CHECK-NEXT: divs32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %sdiv = sdiv i8 %y, %x + ret i8 %sdiv +} + +define i8 @SDIV_CHAR_I(i8 %x) { +; CHECK-LABEL: SDIV_CHAR_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sextb16 a1, a0 +; CHECK-NEXT: movi16 a2, 85 +; CHECK-NEXT: mult16 a1, a2 +; CHECK-NEXT: lsri16 a1, a1, 8 +; CHECK-NEXT: subu16 a0, a1, a0 +; CHECK-NEXT: andi32 a1, a0, 128 +; CHECK-NEXT: lsri16 a1, a1, 7 +; CHECK-NEXT: sextb16 a0, a0 +; CHECK-NEXT: asri16 a0, a0, 1 +; CHECK-NEXT: addu16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %sdiv = sdiv i8 %x, -3 + ret i8 %sdiv +} + +define i32 @shlRR(i32 %x, i32 %y) { +; CHECK-LABEL: shlRR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lsl32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %shl = shl nsw i32 %y, %x + ret i32 %shl +} + +define i32 @shlRI(i32 %x) { +; CHECK-LABEL: shlRI: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lsli16 a0, a0, 10 +; CHECK-NEXT: rts16 +entry: + %shl = shl nsw i32 %x, 10 + ret i32 %shl +} + + +define i64 @SHL_LONG_I(i64 %x) { +; CHECK-LABEL: SHL_LONG_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lsri16 a2, a0, 25 +; CHECK-NEXT: lsli16 a1, a1, 7 +; CHECK-NEXT: or16 a1, a2 +; CHECK-NEXT: lsli16 a0, a0, 7 +; CHECK-NEXT: rts16 +entry: + %shl = shl nsw i64 %x, 7 + ret i64 %shl +} + +define i16 @SHL_SHORT(i16 %x, i16 %y) { +; CHECK-LABEL: SHL_SHORT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zexth16 a0, a0 +; CHECK-NEXT: lsl32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %shl = shl nsw i16 %y, %x + ret i16 %shl +} + +define i16 @SHL_SHORT_I(i16 %x) { +; CHECK-LABEL: SHL_SHORT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lsli16 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %shl = shl nsw i16 %x, 1 + ret i16 %shl +} + +define i8 @SHL_CHAR(i8 %x, i8 %y) { +; CHECK-LABEL: SHL_CHAR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zextb16 a0, a0 +; CHECK-NEXT: lsl32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %shl = shl nsw i8 %y, %x + ret i8 %shl +} + +define i8 @SHL_CHAR_I(i8 %x) { +; CHECK-LABEL: SHL_CHAR_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lsli16 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %shl = shl nsw i8 %x, 1 + ret i8 %shl +} + +define i32 @andRR(i32 %x, i32 %y) { +; CHECK-LABEL: andRR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: and16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %and = and i32 %y, %x + ret i32 %and +} + +define i32 @andRI(i32 %x) { +; CHECK-LABEL: andRI: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a0, a0, 10 +; CHECK-NEXT: rts16 +entry: + %and = and i32 %x, 10 + ret i32 %and +} + +define i32 @andRI_X(i32 %x) { +; CHECK-LABEL: andRI_X: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi32 a1, 4097 +; CHECK-NEXT: and16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %and = and i32 %x, 4097 + ret i32 %and +} + +define i64 @AND_LONG(i64 %x, i64 %y) { +; CHECK-LABEL: AND_LONG: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: and16 a0, a2 +; CHECK-NEXT: and16 a1, a3 +; CHECK-NEXT: rts16 +entry: + %and = and i64 %y, %x + ret i64 %and +} + +define i64 @AND_LONG_I(i64 %x) { +; CHECK-LABEL: AND_LONG_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a0, a0, 1 +; CHECK-NEXT: movi16 a1, 0 +; CHECK-NEXT: rts16 +entry: + %and = and i64 %x, 1 + ret i64 %and +} + +define i16 @AND_SHORT(i16 %x, i16 %y) { +; CHECK-LABEL: AND_SHORT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: and16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %and = and i16 %y, %x + ret i16 %and +} + +define i16 @AND_SHORT_I(i16 %x) { +; CHECK-LABEL: AND_SHORT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %and = and i16 %x, 1 + ret i16 %and +} + +define i8 @AND_CHAR(i8 %x, i8 %y) { +; CHECK-LABEL: AND_CHAR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: and16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %and = and i8 %y, %x + ret i8 %and +} + +define i8 @AND_CHAR_I(i8 %x) { +; CHECK-LABEL: AND_CHAR_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %and = and i8 %x, 1 + ret i8 %and +} + +define i32 @ashrRR(i32 %x, i32 %y) { +; CHECK-LABEL: ashrRR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: asr32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %ashr = ashr i32 %y, %x + ret i32 %ashr +} + +define i32 @ashrRI(i32 %x) { +; CHECK-LABEL: ashrRI: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: asri16 a0, a0, 10 +; CHECK-NEXT: rts16 +entry: + %ashr = ashr i32 %x, 10 + ret i32 %ashr +} + + +define i64 @ASHR_LONG_I(i64 %x) { +; CHECK-LABEL: ASHR_LONG_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lsli16 a2, a1, 25 +; CHECK-NEXT: lsri16 a0, a0, 7 +; CHECK-NEXT: or16 a0, a2 +; CHECK-NEXT: asri16 a1, a1, 7 +; CHECK-NEXT: rts16 +entry: + %ashr = ashr i64 %x, 7 + ret i64 %ashr +} + +define i16 @ASHR_SHORT(i16 %x, i16 %y) { +; CHECK-LABEL: ASHR_SHORT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sexth16 a1, a1 +; CHECK-NEXT: zexth16 a0, a0 +; CHECK-NEXT: asr32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %ashr = ashr i16 %y, %x + ret i16 %ashr +} + +define i16 @ASHR_SHORT_I(i16 %x) { +; CHECK-LABEL: ASHR_SHORT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sexth16 a0, a0 +; CHECK-NEXT: asri16 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %ashr = ashr i16 %x, 1 + ret i16 %ashr +} + +define i8 @ASHR_CHAR(i8 %x, i8 %y) { +; CHECK-LABEL: ASHR_CHAR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sextb16 a1, a1 +; CHECK-NEXT: zextb16 a0, a0 +; CHECK-NEXT: asr32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %ashr = ashr i8 %y, %x + ret i8 %ashr +} + +define i8 @ASHR_CHAR_I(i8 %x) { +; CHECK-LABEL: ASHR_CHAR_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sextb16 a0, a0 +; CHECK-NEXT: asri16 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %ashr = ashr i8 %x, 1 + ret i8 %ashr +} + + +define i32 @lshrRR(i32 %x, i32 %y) { +; CHECK-LABEL: lshrRR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lsr32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %lshr = lshr i32 %y, %x + ret i32 %lshr +} + +define i32 @lshrRI(i32 %x) { +; CHECK-LABEL: lshrRI: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lsri16 a0, a0, 10 +; CHECK-NEXT: rts16 +entry: + %lshr = lshr i32 %x, 10 + ret i32 %lshr +} + +define i64 @LSHR_LONG_I(i64 %x) { +; CHECK-LABEL: LSHR_LONG_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lsli16 a2, a1, 25 +; CHECK-NEXT: lsri16 a0, a0, 7 +; CHECK-NEXT: or16 a0, a2 +; CHECK-NEXT: lsri16 a1, a1, 7 +; CHECK-NEXT: rts16 +entry: + %lshr = lshr i64 %x, 7 + ret i64 %lshr +} + +define i16 @LSHR_SHORT(i16 %x, i16 %y) { +; CHECK-LABEL: LSHR_SHORT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zexth16 a1, a1 +; CHECK-NEXT: zexth16 a0, a0 +; CHECK-NEXT: lsr32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %lshr = lshr i16 %y, %x + ret i16 %lshr +} + +define i16 @LSHR_SHORT_I(i16 %x) { +; CHECK-LABEL: LSHR_SHORT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi32 a1, 65534 +; CHECK-NEXT: and16 a0, a1 +; CHECK-NEXT: lsri16 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %lshr = lshr i16 %x, 1 + ret i16 %lshr +} + +define i8 @LSHR_CHAR(i8 %x, i8 %y) { +; CHECK-LABEL: LSHR_CHAR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zextb16 a1, a1 +; CHECK-NEXT: zextb16 a0, a0 +; CHECK-NEXT: lsr32 a0, a1, a0 +; CHECK-NEXT: rts16 +entry: + %lshr = lshr i8 %y, %x + ret i8 %lshr +} + +define i8 @LSHR_CHAR_I(i8 %x) { +; CHECK-LABEL: LSHR_CHAR_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a0, a0, 254 +; CHECK-NEXT: lsri16 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %lshr = lshr i8 %x, 1 + ret i8 %lshr +} + +define i1 @LSHR_BIT(i1 %x, i1 %y) { +; CHECK-LABEL: LSHR_BIT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mov16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %lshr = lshr i1 %y, %x + ret i1 %lshr +} + +define i1 @LSHR_BIT_I(i1 %x) { +; CHECK-LABEL: LSHR_BIT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rts16 +entry: + %lshr = lshr i1 %x, 1 + ret i1 %lshr +} + +define i32 @orRR(i32 %x, i32 %y) { +; CHECK-LABEL: orRR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: or16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %or = or i32 %y, %x + ret i32 %or +} + +define i32 @orRI(i32 %x) { +; CHECK-LABEL: orRI: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ori32 a0, a0, 10 +; CHECK-NEXT: rts16 +entry: + %or = or i32 %x, 10 + ret i32 %or +} + +define i32 @orRI_X(i32 %x) { +; CHECK-LABEL: orRI_X: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ori32 a0, a0, 4097 +; CHECK-NEXT: rts16 +entry: + %or = or i32 %x, 4097 + ret i32 %or +} + +define i64 @OR_LONG(i64 %x, i64 %y) { +; CHECK-LABEL: OR_LONG: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: or16 a0, a2 +; CHECK-NEXT: or16 a1, a3 +; CHECK-NEXT: rts16 +entry: + %or = or i64 %y, %x + ret i64 %or +} + +define i64 @OR_LONG_I(i64 %x) { +; CHECK-LABEL: OR_LONG_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ori32 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %or = or i64 %x, 1 + ret i64 %or +} + +define i16 @OR_SHORT(i16 %x, i16 %y) { +; CHECK-LABEL: OR_SHORT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: or16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %or = or i16 %y, %x + ret i16 %or +} + +define i16 @OR_SHORT_I(i16 %x) { +; CHECK-LABEL: OR_SHORT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ori32 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %or = or i16 %x, 1 + ret i16 %or +} + +define i8 @OR_CHAR(i8 %x, i8 %y) { +; CHECK-LABEL: OR_CHAR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: or16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %or = or i8 %y, %x + ret i8 %or +} + +define i8 @OR_CHAR_I(i8 %x) { +; CHECK-LABEL: OR_CHAR_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ori32 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %or = or i8 %x, 1 + ret i8 %or +} + + +define i32 @xorRR(i32 %x, i32 %y) { +; CHECK-LABEL: xorRR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xor16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %xor = xor i32 %y, %x + ret i32 %xor +} + +define i32 @xorRI(i32 %x) { +; CHECK-LABEL: xorRI: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xori32 a0, a0, 10 +; CHECK-NEXT: rts16 +entry: + %xor = xor i32 %x, 10 + ret i32 %xor +} + +define i32 @xorRI_X(i32 %x) { +; CHECK-LABEL: xorRI_X: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi32 a1, 4097 +; CHECK-NEXT: xor16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %xor = xor i32 %x, 4097 + ret i32 %xor +} + +define i64 @XOR_LONG(i64 %x, i64 %y) { +; CHECK-LABEL: XOR_LONG: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xor16 a0, a2 +; CHECK-NEXT: xor16 a1, a3 +; CHECK-NEXT: rts16 +entry: + %xor = xor i64 %y, %x + ret i64 %xor +} + +define i64 @XOR_LONG_I(i64 %x) { +; CHECK-LABEL: XOR_LONG_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xori32 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %xor = xor i64 %x, 1 + ret i64 %xor +} + +define i16 @XOR_SHORT(i16 %x, i16 %y) { +; CHECK-LABEL: XOR_SHORT: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xor16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %xor = xor i16 %y, %x + ret i16 %xor +} + +define i16 @XOR_SHORT_I(i16 %x) { +; CHECK-LABEL: XOR_SHORT_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xori32 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %xor = xor i16 %x, 1 + ret i16 %xor +} + +define i8 @XOR_CHAR(i8 %x, i8 %y) { +; CHECK-LABEL: XOR_CHAR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xor16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %xor = xor i8 %y, %x + ret i8 %xor +} + +define i8 @XOR_CHAR_I(i8 %x) { +; CHECK-LABEL: XOR_CHAR_I: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xori32 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %xor = xor i8 %x, 1 + ret i8 %xor +} + +; i64 --> i32/i16/i8/i1 +define i32 @truncR_i64_0(i64 %x) { +; CHECK-LABEL: truncR_i64_0: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rts16 +entry: + %trunc = trunc i64 %x to i32 + ret i32 %trunc +} + +define i16 @truncR_i64_1(i64 %x) { +; CHECK-LABEL: truncR_i64_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rts16 +entry: + %trunc = trunc i64 %x to i16 + ret i16 %trunc +} + +define i8 @truncR_i64_2(i64 %x) { +; CHECK-LABEL: truncR_i64_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rts16 +entry: + %trunc = trunc i64 %x to i8 + ret i8 %trunc +} + +define i1 @truncR_i64_3(i64 %x) { +; CHECK-LABEL: truncR_i64_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rts16 +entry: + %trunc = trunc i64 %x to i1 + ret i1 %trunc +} + + +; i32 --> i16/i8/i1 +define i16 @truncR_i32_1(i32 %x) { +; CHECK-LABEL: truncR_i32_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rts16 +entry: + %trunc = trunc i32 %x to i16 + ret i16 %trunc +} + +define i8 @truncR_i32_2(i32 %x) { +; CHECK-LABEL: truncR_i32_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rts16 +entry: + %trunc = trunc i32 %x to i8 + ret i8 %trunc +} + +define i1 @truncR_i32_3(i32 %x) { +; CHECK-LABEL: truncR_i32_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rts16 +entry: + %trunc = trunc i32 %x to i1 + ret i1 %trunc +} + +; i16 --> i8/i1 +define i8 @truncR_i16_2(i16 %x) { +; CHECK-LABEL: truncR_i16_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rts16 +entry: + %trunc = trunc i16 %x to i8 + ret i8 %trunc +} + +define i1 @truncR_i16_3(i16 %x) { +; CHECK-LABEL: truncR_i16_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rts16 +entry: + %trunc = trunc i16 %x to i1 + ret i1 %trunc +} + + +;i8 --> i1 +define i1 @truncR_i8_3(i8 %x) { +; CHECK-LABEL: truncR_i8_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rts16 +entry: + %trunc = trunc i8 %x to i1 + ret i1 %trunc +} diff --git a/llvm/test/CodeGen/CSKY/cvt-i.ll b/llvm/test/CodeGen/CSKY/cvt-i.ll new file mode 100644 index 000000000000..b6f045de2f29 --- /dev/null +++ b/llvm/test/CodeGen/CSKY/cvt-i.ll @@ -0,0 +1,216 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -csky-no-aliases -mattr=+e2 -mattr=+2e3 < %s -mtriple=csky | FileCheck %s + +; i32/i16/i8/i1 --> i64 +define i64 @zextR_i64_0(i32 %x) { +; CHECK-LABEL: zextR_i64_0: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi16 a1, 0 +; CHECK-NEXT: rts16 +entry: + %zext = zext i32 %x to i64 + ret i64 %zext +} + +define i64 @zextR_i64_1(i16 %x) { +; CHECK-LABEL: zextR_i64_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zexth16 a0, a0 +; CHECK-NEXT: movi16 a1, 0 +; CHECK-NEXT: rts16 +entry: + %zext = zext i16 %x to i64 + ret i64 %zext +} + +define i64 @zextR_i64_2(i8 %x) { +; CHECK-LABEL: zextR_i64_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zextb16 a0, a0 +; CHECK-NEXT: movi16 a1, 0 +; CHECK-NEXT: rts16 +entry: + %zext = zext i8 %x to i64 + ret i64 %zext +} + +define i64 @zextR_i64_3(i1 %x) { +; CHECK-LABEL: zextR_i64_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a0, a0, 1 +; CHECK-NEXT: movi16 a1, 0 +; CHECK-NEXT: rts16 +entry: + %zext = zext i1 %x to i64 + ret i64 %zext +} + +; i16/i8/i1 --> i32 +define i32 @zextR_i32_1(i16 %x) { +; CHECK-LABEL: zextR_i32_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zexth16 a0, a0 +; CHECK-NEXT: rts16 +entry: + %zext = zext i16 %x to i32 + ret i32 %zext +} + +define i32 @zextR_i32_2(i8 %x) { +; CHECK-LABEL: zextR_i32_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zextb16 a0, a0 +; CHECK-NEXT: rts16 +entry: + %zext = zext i8 %x to i32 + ret i32 %zext +} + +define i32 @zextR_i32_3(i1 %x) { +; CHECK-LABEL: zextR_i32_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %zext = zext i1 %x to i32 + ret i32 %zext +} + +; i8/i1 --> i16 +define i16 @zextR_i16_2(i8 %x) { +; CHECK-LABEL: zextR_i16_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: zextb16 a0, a0 +; CHECK-NEXT: rts16 +entry: + %zext = zext i8 %x to i16 + ret i16 %zext +} + +define i16 @zextR_i16_3(i1 %x) { +; CHECK-LABEL: zextR_i16_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %zext = zext i1 %x to i16 + ret i16 %zext +} + +;i1 --> i8 +define i8 @zextR_i8_3(i1 %x) { +; CHECK-LABEL: zextR_i8_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a0, a0, 1 +; CHECK-NEXT: rts16 +entry: + %zext = zext i1 %x to i8 + ret i8 %zext +} + +; i32/i16/i8/i1 --> i64 +define i64 @sextR_i64_0(i32 %x) { +; CHECK-LABEL: sextR_i64_0: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: asri16 a1, a0, 31 +; CHECK-NEXT: rts16 +entry: + %sext = sext i32 %x to i64 + ret i64 %sext +} + +define i64 @sextR_i64_1(i16 %x) { +; CHECK-LABEL: sextR_i64_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sexth16 a0, a0 +; CHECK-NEXT: asri16 a1, a0, 31 +; CHECK-NEXT: rts16 +entry: + %sext = sext i16 %x to i64 + ret i64 %sext +} + +define i64 @sextR_i64_2(i8 %x) { +; CHECK-LABEL: sextR_i64_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sextb16 a0, a0 +; CHECK-NEXT: asri16 a1, a0, 31 +; CHECK-NEXT: rts16 +entry: + %sext = sext i8 %x to i64 + ret i64 %sext +} + +define i64 @sextR_i64_3(i1 %x) { +; CHECK-LABEL: sextR_i64_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sext32 a0, a0, 0, 0 +; CHECK-NEXT: mov16 a1, a0 +; CHECK-NEXT: rts16 +entry: + %sext = sext i1 %x to i64 + ret i64 %sext +} + +; i16/i8/i1 --> i32 +define i32 @sextR_i32_1(i16 %x) { +; CHECK-LABEL: sextR_i32_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sexth16 a0, a0 +; CHECK-NEXT: rts16 +entry: + %sext = sext i16 %x to i32 + ret i32 %sext +} + +define i32 @sextR_i32_2(i8 %x) { +; CHECK-LABEL: sextR_i32_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sextb16 a0, a0 +; CHECK-NEXT: rts16 +entry: + %sext = sext i8 %x to i32 + ret i32 %sext +} + +define i32 @sextR_i32_3(i1 %x) { +; CHECK-LABEL: sextR_i32_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sext32 a0, a0, 0, 0 +; CHECK-NEXT: rts16 +entry: + %sext = sext i1 %x to i32 + ret i32 %sext +} + +; i8/i1 --> i16 +define i16 @sextR_i16_2(i8 %x) { +; CHECK-LABEL: sextR_i16_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sextb16 a0, a0 +; CHECK-NEXT: rts16 +entry: + %sext = sext i8 %x to i16 + ret i16 %sext +} + +define i16 @sextR_i16_3(i1 %x) { +; CHECK-LABEL: sextR_i16_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sext32 a0, a0, 0, 0 +; CHECK-NEXT: rts16 +entry: + %sext = sext i1 %x to i16 + ret i16 %sext +} + +;i1 --> i8 +define i8 @sextR_i8_3(i1 %x) { +; CHECK-LABEL: sextR_i8_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: sext32 a0, a0, 0, 0 +; CHECK-NEXT: rts16 +entry: + %sext = sext i1 %x to i8 + ret i8 %sext +} diff --git a/llvm/test/CodeGen/CSKY/intrinsic.ll b/llvm/test/CodeGen/CSKY/intrinsic.ll new file mode 100644 index 000000000000..efe2f8bfb8a9 --- /dev/null +++ b/llvm/test/CodeGen/CSKY/intrinsic.ll @@ -0,0 +1,36 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -csky-no-aliases -mattr=+e2 -mattr=+2e3 < %s -mtriple=csky | FileCheck %s + +define i32 @ctlz(i32 %x) { +; CHECK-LABEL: ctlz: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ff1.32 a0, a0 +; CHECK-NEXT: rts16 +entry: + %nlz = call i32 @llvm.ctlz.i32(i32 %x, i1 1) + ret i32 %nlz +} + +define i32 @bswap(i32 %x) { +; CHECK-LABEL: bswap: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: revb16 a0, a0 +; CHECK-NEXT: rts16 +entry: + %revb32 = call i32 @llvm.bswap.i32(i32 %x) + ret i32 %revb32 +} + +define i32 @bitreverse(i32 %x) { +; CHECK-LABEL: bitreverse: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: brev32 a0, a0 +; CHECK-NEXT: rts16 +entry: + %brev32 = call i32 @llvm.bitreverse.i32(i32 %x) + ret i32 %brev32 +} + +declare i32 @llvm.bswap.i32(i32) +declare i32 @llvm.ctlz.i32 (i32, i1) +declare i32 @llvm.bitreverse.i32(i32) diff --git a/llvm/test/CodeGen/CSKY/ldst-i.ll b/llvm/test/CodeGen/CSKY/ldst-i.ll new file mode 100644 index 000000000000..bf231dba968a --- /dev/null +++ b/llvm/test/CodeGen/CSKY/ldst-i.ll @@ -0,0 +1,449 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -csky-no-aliases -mattr=+2e3 < %s -mtriple=csky | FileCheck %s + +define signext i1 @load_I_bits(i1* nocapture readonly %a) local_unnamed_addr #0 { +; CHECK-LABEL: load_I_bits: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ld16.b a0, (a0, 3) +; CHECK-NEXT: sext32 a0, a0, 0, 0 +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i1, i1* %a, i64 3 + %0 = load i1, i1* %arrayidx, align 1 + ret i1 %0 +} + +define zeroext i1 @load_I_bit_(i1* nocapture readonly %a) local_unnamed_addr #0 { +; CHECK-LABEL: load_I_bit_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ld16.b a0, (a0, 3) +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i1, i1* %a, i64 3 + %0 = load i1, i1* %arrayidx, align 1 + ret i1 %0 +} + +define signext i8 @load_I_bs(i8* nocapture readonly %a) local_unnamed_addr #0 { +; CHECK-LABEL: load_I_bs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ld32.bs a0, (a0, 3) +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i8, i8* %a, i64 3 + %0 = load i8, i8* %arrayidx, align 1 + ret i8 %0 +} + +define zeroext i8 @load_I_b_(i8* nocapture readonly %a) local_unnamed_addr #0 { +; CHECK-LABEL: load_I_b_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ld16.b a0, (a0, 3) +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i8, i8* %a, i64 3 + %0 = load i8, i8* %arrayidx, align 1 + ret i8 %0 +} + +define signext i16 @load_I_hs(i16* nocapture readonly %a) local_unnamed_addr #0 { +; CHECK-LABEL: load_I_hs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ld32.hs a0, (a0, 6) +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i16, i16* %a, i64 3 + %0 = load i16, i16* %arrayidx, align 2 + ret i16 %0 +} + +define zeroext i16 @load_I_h_(i16* nocapture readonly %a) local_unnamed_addr #0 { +; CHECK-LABEL: load_I_h_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ld16.h a0, (a0, 6) +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i16, i16* %a, i64 3 + %0 = load i16, i16* %arrayidx, align 2 + ret i16 %0 +} + +define i32 @load_I_w(i32* nocapture readonly %a) local_unnamed_addr #0 { +; CHECK-LABEL: load_I_w: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ld16.w a0, (a0, 12) +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i32, i32* %a, i64 3 + %0 = load i32, i32* %arrayidx, align 4 + ret i32 %0 +} + +define i64 @load_I_d(i64* nocapture readonly %a) local_unnamed_addr #0 { +; CHECK-LABEL: load_I_d: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ld16.w a2, (a0, 24) +; CHECK-NEXT: ld16.w a1, (a0, 28) +; CHECK-NEXT: mov16 a0, a2 +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i64, i64* %a, i64 3 + %0 = load i64, i64* %arrayidx, align 4 + ret i64 %0 +} + +define i8 @load_I_i8_anyext(i8* %p) { +; CHECK-LABEL: load_I_i8_anyext: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ld16.b a0, (a0, 0) +; CHECK-NEXT: rts16 +entry: + %ret = load i8, i8* %p, align 1 + ret i8 %ret +} + +define signext i1 @load_R_bits(i1* nocapture readonly %a, i32 %b) local_unnamed_addr #0 { +; CHECK-LABEL: load_R_bits: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ldr32.bs a0, (a0, a1 << 0) +; CHECK-NEXT: sext32 a0, a0, 0, 0 +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i1, i1* %a, i64 %idxprom + %0 = load i1, i1* %arrayidx, align 1 + ret i1 %0 +} + +define zeroext i1 @load_R_bit_(i1* nocapture readonly %a, i32 %b) local_unnamed_addr #0 { +; CHECK-LABEL: load_R_bit_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ldr32.b a0, (a0, a1 << 0) +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i1, i1* %a, i64 %idxprom + %0 = load i1, i1* %arrayidx, align 1 + ret i1 %0 +} + + +define signext i8 @load_R_bs(i8* nocapture readonly %a, i32 %b) local_unnamed_addr #0 { +; CHECK-LABEL: load_R_bs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ldr32.bs a0, (a0, a1 << 0) +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i8, i8* %a, i64 %idxprom + %0 = load i8, i8* %arrayidx, align 1 + ret i8 %0 +} + +define zeroext i8 @load_R_b_(i8* nocapture readonly %a, i32 %b) local_unnamed_addr #0 { +; CHECK-LABEL: load_R_b_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ldr32.b a0, (a0, a1 << 0) +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i8, i8* %a, i64 %idxprom + %0 = load i8, i8* %arrayidx, align 1 + ret i8 %0 +} + +define signext i16 @load_R_hs(i16* nocapture readonly %a, i32 %b) local_unnamed_addr #0 { +; CHECK-LABEL: load_R_hs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ldr32.hs a0, (a0, a1 << 1) +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i16, i16* %a, i64 %idxprom + %0 = load i16, i16* %arrayidx, align 2 + ret i16 %0 +} + +define zeroext i16 @load_R_h_(i16* nocapture readonly %a, i32 %b) local_unnamed_addr #0 { +; CHECK-LABEL: load_R_h_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ldr32.h a0, (a0, a1 << 1) +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i16, i16* %a, i64 %idxprom + %0 = load i16, i16* %arrayidx, align 2 + ret i16 %0 +} + +define i32 @load_R_w(i32* nocapture readonly %a, i32 %b) local_unnamed_addr #0 { +; CHECK-LABEL: load_R_w: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ldr32.w a0, (a0, a1 << 2) +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i32, i32* %a, i64 %idxprom + %0 = load i32, i32* %arrayidx, align 4 + ret i32 %0 +} + +define i64 @load_R_d(i64* nocapture readonly %a, i32 %b) local_unnamed_addr #0 { +; CHECK-LABEL: load_R_d: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ixd32 a2, a0, a1 +; CHECK-NEXT: ldr32.w a0, (a0, a1 << 3) +; CHECK-NEXT: ld16.w a1, (a2, 4) +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i64, i64* %a, i64 %idxprom + %0 = load i64, i64* %arrayidx, align 4 + ret i64 %0 +} + +define i8 @loadR_i8_anyext(i8* %c, i32 %a) { +; CHECK-LABEL: loadR_i8_anyext: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ldr32.bs a0, (a0, a1 << 0) +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %a to i64 + %arrayidx = getelementptr inbounds i8, i8* %c, i64 %idxprom + %0 = load i8, i8* %arrayidx, align 1 + ret i8 %0 +} + +define signext i1 @store_I_bits(i1* %a, i1 %b) local_unnamed_addr #0 { +; CHECK-LABEL: store_I_bits: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a1, a1, 1 +; CHECK-NEXT: st16.b a1, (a0, 3) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i1, i1* %a, i64 3 + store i1 %b, i1* %arrayidx, align 1 + ret i1 0 +} + +define zeroext i1 @store_I_bit_(i1* %a, i1 %b) local_unnamed_addr #0 { +; CHECK-LABEL: store_I_bit_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a1, a1, 1 +; CHECK-NEXT: st16.b a1, (a0, 3) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i1, i1* %a, i64 3 + store i1 %b, i1* %arrayidx, align 1 + ret i1 0 +} + +define signext i8 @store_I_bs(i8* %a, i8 %b) local_unnamed_addr #0 { +; CHECK-LABEL: store_I_bs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: st16.b a1, (a0, 3) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i8, i8* %a, i64 3 + store i8 %b, i8* %arrayidx, align 1 + ret i8 0 +} + +define zeroext i8 @store_I_b_(i8* %a, i8 %b) local_unnamed_addr #0 { +; CHECK-LABEL: store_I_b_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: st16.b a1, (a0, 3) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i8, i8* %a, i64 3 + store i8 %b, i8* %arrayidx, align 1 + ret i8 0 +} + +define signext i16 @store_I_hs(i16* %a, i16 %b) local_unnamed_addr #0 { +; CHECK-LABEL: store_I_hs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: st16.h a1, (a0, 6) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i16, i16* %a, i64 3 + store i16 %b, i16* %arrayidx, align 2 + ret i16 0 +} + +define zeroext i16 @store_I_h_(i16* %a, i16 %b) local_unnamed_addr #0 { +; CHECK-LABEL: store_I_h_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: st16.h a1, (a0, 6) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i16, i16* %a, i64 3 + store i16 %b, i16* %arrayidx, align 2 + ret i16 0 +} + +define i32 @store_I_w(i32* %a, i32 %b) local_unnamed_addr #0 { +; CHECK-LABEL: store_I_w: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: st16.w a1, (a0, 12) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i32, i32* %a, i64 3 + store i32 %b, i32* %arrayidx, align 4 + ret i32 0 +} + +define i64 @store_I_d(i64* %a, i64 %b) local_unnamed_addr #0 { +; CHECK-LABEL: store_I_d: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: st16.w a2, (a0, 28) +; CHECK-NEXT: st16.w a1, (a0, 24) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: movi16 a1, 0 +; CHECK-NEXT: rts16 +entry: + %arrayidx = getelementptr inbounds i64, i64* %a, i64 3 + store i64 %b, i64* %arrayidx, align 4 + ret i64 0 +} + +define i8 @store_I_i8_anyext(i8* %p, i8 %b) { +; CHECK-LABEL: store_I_i8_anyext: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: st16.b a1, (a0, 0) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + store i8 %b, i8* %p, align 1 + ret i8 0 +} + +define signext i1 @store_R_bits(i1* %a, i32 %b, i1 %c) local_unnamed_addr #0 { +; CHECK-LABEL: store_R_bits: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a2, a2, 1 +; CHECK-NEXT: str32.b a2, (a0, a1 << 0) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i1, i1* %a, i64 %idxprom + store i1 %c, i1* %arrayidx, align 1 + ret i1 0 +} + +define zeroext i1 @store_R_bit_(i1* %a, i32 %b, i1 %c) local_unnamed_addr #0 { +; CHECK-LABEL: store_R_bit_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a2, a2, 1 +; CHECK-NEXT: str32.b a2, (a0, a1 << 0) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i1, i1* %a, i64 %idxprom + store i1 %c, i1* %arrayidx, align 1 + ret i1 0 +} + + +define signext i8 @store_R_bs(i8* %a, i32 %b, i8 %c) local_unnamed_addr #0 { +; CHECK-LABEL: store_R_bs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: str32.b a2, (a0, a1 << 0) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i8, i8* %a, i64 %idxprom + store i8 %c, i8* %arrayidx, align 1 + ret i8 0 +} + +define zeroext i8 @store_R_b_(i8* %a, i32 %b, i8 %c) local_unnamed_addr #0 { +; CHECK-LABEL: store_R_b_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: str32.b a2, (a0, a1 << 0) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i8, i8* %a, i64 %idxprom + store i8 %c, i8* %arrayidx, align 1 + ret i8 0 +} + +define signext i16 @store_R_hs(i16* %a, i32 %b, i16 %c) local_unnamed_addr #0 { +; CHECK-LABEL: store_R_hs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: str32.h a2, (a0, a1 << 1) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i16, i16* %a, i64 %idxprom + store i16 %c, i16* %arrayidx, align 2 + ret i16 0 +} + +define zeroext i16 @store_R_h_(i16* %a, i32 %b, i16 %c) local_unnamed_addr #0 { +; CHECK-LABEL: store_R_h_: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: str32.h a2, (a0, a1 << 1) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i16, i16* %a, i64 %idxprom + store i16 %c, i16* %arrayidx, align 2 + ret i16 0 +} + +define i32 @store_R_w(i32* %a, i32 %b, i32 %c) local_unnamed_addr #0 { +; CHECK-LABEL: store_R_w: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: str32.w a2, (a0, a1 << 2) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i32, i32* %a, i64 %idxprom + store i32 %c, i32* %arrayidx, align 4 + ret i32 0 +} + +define i64 @store_R_d(i64* %a, i32 %b, i64 %c) local_unnamed_addr #0 { +; CHECK-LABEL: store_R_d: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ixd32 t0, a0, a1 +; CHECK-NEXT: str32.w a2, (a0, a1 << 3) +; CHECK-NEXT: st32.w a3, (t0, 4) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: movi16 a1, 0 +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %b to i64 + %arrayidx = getelementptr inbounds i64, i64* %a, i64 %idxprom + store i64 %c, i64* %arrayidx, align 4 + ret i64 0 +} + +define i8 @storeR_i8_anyext(i8* %c, i32 %a, i8 %d) { +; CHECK-LABEL: storeR_i8_anyext: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: str32.b a2, (a0, a1 << 0) +; CHECK-NEXT: movi16 a0, 0 +; CHECK-NEXT: rts16 +entry: + %idxprom = sext i32 %a to i64 + %arrayidx = getelementptr inbounds i8, i8* %c, i64 %idxprom + store i8 %d, i8* %arrayidx, align 1 + ret i8 0 +} diff --git a/llvm/test/CodeGen/CSKY/rotl.ll b/llvm/test/CodeGen/CSKY/rotl.ll new file mode 100644 index 000000000000..22f577afb07f --- /dev/null +++ b/llvm/test/CodeGen/CSKY/rotl.ll @@ -0,0 +1,28 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -csky-no-aliases -mattr=+e2 < %s -mtriple=csky | FileCheck %s + +define i32 @ROTLI32(i32 %x) { +; CHECK-LABEL: ROTLI32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: rotli32 a0, a0, 4 +; CHECK-NEXT: rts16 +entry: + %shl = shl i32 %x, 4 + %shr = lshr i32 %x, 28 + %or = or i32 %shl, %shr + ret i32 %or +} + +define i32 @ROTL32(i32 %x, i32 %y) { +; CHECK-LABEL: ROTL32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: andi32 a1, a1, 31 +; CHECK-NEXT: rotl16 a0, a1 +; CHECK-NEXT: rts16 +entry: + %0 = shl i32 %x, %y + %1 = sub i32 32, %y + %2 = lshr i32 %x, %1 + %3 = or i32 %2, %0 + ret i32 %3 +} -- GitLab