[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.
This commit is contained in:
Zi Xuan Wu 2021-12-09 11:35:34 +08:00
parent ec63930c06
commit a556ec8861
12 changed files with 2514 additions and 2 deletions

View File

@ -40,6 +40,8 @@ public:
}
void Select(SDNode *N) override;
bool selectAddCarry(SDNode *N);
bool selectSubCarry(SDNode *N);
#include "CSKYGenDAGISel.inc"
};
@ -60,7 +62,12 @@ void CSKYDAGToDAGISel::Select(SDNode *N) {
switch (Opcode) {
default:
break;
// FIXME: Add selection nodes needed later.
case ISD::ADDCARRY:
IsSelected = selectAddCarry(N);
break;
case ISD::SUBCARRY:
IsSelected = selectSubCarry(N);
break;
}
if (IsSelected)
@ -70,6 +77,86 @@ void CSKYDAGToDAGISel::Select(SDNode *N) {
SelectCode(N);
}
bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) {
MachineSDNode *NewNode = nullptr;
auto Type0 = N->getValueType(0);
auto Type1 = N->getValueType(1);
auto Op0 = N->getOperand(0);
auto Op1 = N->getOperand(1);
auto Op2 = N->getOperand(2);
SDLoc Dl(N);
if (isNullConstant(Op2)) {
auto *CA = CurDAG->getMachineNode(
Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
NewNode = CurDAG->getMachineNode(
Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
{Op0, Op1, SDValue(CA, 0)});
} else if (isOneConstant(Op2)) {
auto *CA = CurDAG->getMachineNode(
Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
NewNode = CurDAG->getMachineNode(
Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
{Op0, Op1, SDValue(CA, 0)});
} else {
NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32
: CSKY::ADDC16,
Dl, {Type0, Type1}, {Op0, Op1, Op2});
}
ReplaceNode(N, NewNode);
return true;
}
static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget,
SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) {
auto NewCarryReg =
DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl,
MVT::i32, OldCarry);
auto NewCarry =
DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16,
Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0),
DAG->getTargetConstant(0, Dl, MVT::i32));
return SDValue(NewCarry, 0);
}
bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) {
MachineSDNode *NewNode = nullptr;
auto Type0 = N->getValueType(0);
auto Type1 = N->getValueType(1);
auto Op0 = N->getOperand(0);
auto Op1 = N->getOperand(1);
auto Op2 = N->getOperand(2);
SDLoc Dl(N);
if (isNullConstant(Op2)) {
auto *CA = CurDAG->getMachineNode(
Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
NewNode = CurDAG->getMachineNode(
Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
{Op0, Op1, SDValue(CA, 0)});
} else if (isOneConstant(Op2)) {
auto *CA = CurDAG->getMachineNode(
Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
NewNode = CurDAG->getMachineNode(
Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
{Op0, Op1, SDValue(CA, 0)});
} else {
auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2);
NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32
: CSKY::SUBC16,
Dl, {Type0, Type1}, {Op0, Op1, CarryIn});
}
auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1));
ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0));
ReplaceUses(SDValue(N, 1), CarryOut);
CurDAG->RemoveDeadNode(N);
return true;
}
FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) {
return new CSKYDAGToDAGISel(TM);
}

View File

@ -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());

View File

@ -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));
}

View File

@ -29,6 +29,31 @@ protected:
public:
explicit CSKYInstrInfo(CSKYSubtarget &STI);
unsigned isLoadFromStackSlot(const MachineInstr &MI,
int &FrameIndex) const override;
unsigned isStoreToStackSlot(const MachineInstr &MI,
int &FrameIndex) const override;
void storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI, Register SrcReg,
bool IsKill, int FrameIndex,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const override;
void loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI, Register DestReg,
int FrameIndex, const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const override;
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg,
bool KillSrc) const override;
// Materializes the given integer Val into DstReg.
Register movImm(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, int64_t Val,
MachineInstr::MIFlag Flag = MachineInstr::NoFlags) const;
};
} // namespace llvm

View File

@ -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

View File

@ -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);
}
}

View File

@ -38,6 +38,18 @@ public:
void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj,
unsigned FIOperandNum,
RegScavenger *RS) const override;
bool requiresFrameIndexScavenging(const MachineFunction &MF) const override {
return true;
}
bool requiresRegisterScavenging(const MachineFunction &MF) const override {
return true;
}
bool useFPForScavengingIndex(const MachineFunction &MF) const override {
return false;
}
};
} // namespace llvm

File diff suppressed because it is too large Load Diff

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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
}