[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