[llvm] a556ec8 - [CSKY] Complete codegen of basic arithmetic and load/store operations

Zi Xuan Wu via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 8 19:41:04 PST 2021


Author: Zi Xuan Wu
Date: 2021-12-09T11:40:20+08:00
New Revision: a556ec8861df920bfaee3057df8aac739aa59b24

URL: https://github.com/llvm/llvm-project/commit/a556ec8861df920bfaee3057df8aac739aa59b24
DIFF: https://github.com/llvm/llvm-project/commit/a556ec8861df920bfaee3057df8aac739aa59b24.diff

LOG: [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.

Added: 
    llvm/test/CodeGen/CSKY/cvt-i.ll
    llvm/test/CodeGen/CSKY/intrinsic.ll
    llvm/test/CodeGen/CSKY/ldst-i.ll
    llvm/test/CodeGen/CSKY/rotl.ll

Modified: 
    llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp
    llvm/lib/Target/CSKY/CSKYISelLowering.cpp
    llvm/lib/Target/CSKY/CSKYInstrInfo.cpp
    llvm/lib/Target/CSKY/CSKYInstrInfo.h
    llvm/lib/Target/CSKY/CSKYInstrInfo.td
    llvm/lib/Target/CSKY/CSKYRegisterInfo.cpp
    llvm/lib/Target/CSKY/CSKYRegisterInfo.h
    llvm/test/CodeGen/CSKY/base-i.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp b/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp
index fc9ef8bfd9d9f..8dc91904b8cc1 100644
--- a/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp
+++ b/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp
@@ -40,6 +40,8 @@ class CSKYDAGToDAGISel : public SelectionDAGISel {
   }
 
   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 ac6d069e592c7..a1f7cc685d4c6 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 e12235cf9478f..6fcb136cd99b2 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<CSKYMachineFunctionInfo>();
+  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<CSKYMachineFunctionInfo>();
+  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 04be9da27b575..450641d96b74c 100644
--- a/llvm/lib/Target/CSKY/CSKYInstrInfo.h
+++ b/llvm/lib/Target/CSKY/CSKYInstrInfo.h
@@ -29,6 +29,31 @@ class CSKYInstrInfo : public CSKYGenInstrInfo {
 
 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 32e6cfd7e40f0..30d9206eec68d 100644
--- a/llvm/lib/Target/CSKY/CSKYInstrInfo.td
+++ b/llvm/lib/Target/CSKY/CSKYInstrInfo.td
@@ -52,6 +52,11 @@ class OImmAsmOperand<int width, string suffix = "">
     : ImmAsmOperand<"O", width, suffix> {
 }
 
+def to_tframeindex : SDNodeXForm<frameindex, [{
+  auto FI = cast<FrameIndexSDNode>(N);
+  return CurDAG->getTargetFrameIndex(FI->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
+}]>;
+
 class oimm<int num> : Operand<i32>,
   ImmLeaf<i32, "return isUInt<"#num#">(Imm - 1);"> {
   let EncoderMethod = "getOImmOpValue";
@@ -972,6 +977,102 @@ def TRAP32 : CSKY32Inst<AddrModeNone, 0x30, (outs), (ins uimm2:$imm2), "trap32 $
 
 }
 
+//===----------------------------------------------------------------------===//
+// Instruction Patterns.
+//===----------------------------------------------------------------------===//
+
+// Load & Store Patterns
+multiclass LdPat<PatFrag LoadOp, ImmLeaf imm_type, Instruction Inst, ValueType Type> {
+  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<extloadi8, uimm12, LD32B, i32>;
+defm : LdPat<zextloadi8, uimm12, LD32B, i32>;
+let Predicates = [iHasE2] in {
+  defm : LdPat<sextloadi8, uimm12, LD32BS, i32>;
+}
+defm : LdPat<extloadi16, uimm12_1, LD32H, i32>;
+defm : LdPat<zextloadi16, uimm12_1, LD32H, i32>;
+let Predicates = [iHasE2] in {
+defm : LdPat<sextloadi16, uimm12_1, LD32HS, i32>;
+}
+defm : LdPat<load, uimm12_2, LD32W, i32>;
+
+multiclass LdrPat<PatFrag LoadOp, Instruction Inst, ValueType Type> {
+  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<zextloadi8, LDR32B, i32>;
+  defm : LdrPat<sextloadi8, LDR32BS, i32>;
+  defm : LdrPat<extloadi8, LDR32BS, i32>;
+  defm : LdrPat<zextloadi16, LDR32H, i32>;
+  defm : LdrPat<sextloadi16, LDR32HS, i32>;
+  defm : LdrPat<extloadi16, LDR32HS, i32>;
+  defm : LdrPat<load, LDR32W, i32>;
+}
+
+multiclass StPat<PatFrag StoreOp, ValueType Type, ImmLeaf imm_type, Instruction Inst> {
+  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<truncstorei8, i32, uimm12, ST32B>;
+defm : StPat<truncstorei16, i32, uimm12_1, ST32H>;
+defm : StPat<store, i32, uimm12_2, ST32W>;
+
+multiclass StrPat<PatFrag StoreOp, ValueType Type, Instruction Inst> {
+  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<truncstorei8, i32, STR32B>;
+  defm : StrPat<truncstorei16, i32, STR32H>;
+  defm : StrPat<store, i32, STR32W>;
+
+  // 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 a1d45fea534b4..d3b270e1a7bc5 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<CSKYSubtarget>().getInstrInfo();
+  DebugLoc DL = MI->getDebugLoc();
+  const CSKYSubtarget &STI = MF.getSubtarget<CSKYSubtarget>();
+
+  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 779ea6493c7e0..5b3b62ec0db27 100644
--- a/llvm/lib/Target/CSKY/CSKYRegisterInfo.h
+++ b/llvm/lib/Target/CSKY/CSKYRegisterInfo.h
@@ -38,6 +38,18 @@ class CSKYRegisterInfo : public CSKYGenRegisterInfo {
   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 c1fa0f63eae42..c630ac7eae222 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 0000000000000..b6f045de2f291
--- /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 0000000000000..efe2f8bfb8a95
--- /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 0000000000000..bf231dba968ad
--- /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 0000000000000..22f577afb07f0
--- /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
+}


        


More information about the llvm-commits mailing list