Index: lib/Target/NDS32/InstPrinter/NDS32InstPrinter.h =================================================================== --- lib/Target/NDS32/InstPrinter/NDS32InstPrinter.h +++ lib/Target/NDS32/InstPrinter/NDS32InstPrinter.h @@ -34,6 +34,8 @@ const char *Modifier = nullptr); void printRegName(raw_ostream &OS, unsigned RegNo) const override; + + void printAddrImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); }; } Index: lib/Target/NDS32/InstPrinter/NDS32InstPrinter.cpp =================================================================== --- lib/Target/NDS32/InstPrinter/NDS32InstPrinter.cpp +++ lib/Target/NDS32/InstPrinter/NDS32InstPrinter.cpp @@ -48,3 +48,22 @@ void NDS32InstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { OS << markup(""); } + +// Print [Reg + Imm] addressing mode +void NDS32InstPrinter::printAddrImmOperand(const MCInst *MI, unsigned OpNum, + raw_ostream &O) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum + 1); + + O << markup("") << "]" << markup(">"); +} Index: lib/Target/NDS32/NDS32ISelDAGToDAG.cpp =================================================================== --- lib/Target/NDS32/NDS32ISelDAGToDAG.cpp +++ lib/Target/NDS32/NDS32ISelDAGToDAG.cpp @@ -60,6 +60,28 @@ bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) override; + bool selectAddrFrameIndex(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + bool selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base, + SDValue &Offset, unsigned OffsetBits, + unsigned ShiftBits) const; + + // Select [Reg + Imm15s << 2] addressing mode for word width load/store + // instruction. + bool SelectAddrImm15sWord(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + // Select [Reg + Imm15s << 1] addressing mode for half word width load/store + // instruction. + bool SelectAddrImm15sHalf(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + // Select [Reg + Imm15s ] addressing mode for byte width load/store + // instruction. + bool SelectAddrImm15sByte(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + // Include the pieces autogenerated from the target description. #include "NDS32GenDAGISel.inc" @@ -87,6 +109,111 @@ return true; } +/// Match frameindex +bool NDS32DAGToDAGISel::selectAddrFrameIndex(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (FrameIndexSDNode *FIN = dyn_cast(Addr)) { + EVT ValTy = Addr.getValueType(); + + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), ValTy); + return true; + // Allow addressing mode as TargetGlobalAddress, TargetExternalSymbol + } else if (!CurDAG->isBaseWithConstantOffset(Addr)) { + if (Addr.getOpcode() == NDS32ISD::Wrapper && + Addr.getOperand(0).getOpcode() != ISD::TargetGlobalAddress && + Addr.getOperand(0).getOpcode() != ISD::TargetExternalSymbol) { + Base = Addr.getOperand(0); + } else + Base = Addr; + + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); + return true; + } + + // Default split Addr out of addressing mode + // E.g. Reg = SP + 3, load [Reg] + Base = Addr; + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); + return true; +} + +/// Match frameindex + offset +bool NDS32DAGToDAGISel::selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base, + SDValue &Offset, + unsigned OffsetBits, + unsigned ShiftBits) const { + if (CurDAG->isBaseWithConstantOffset(Addr)) { + ConstantSDNode *CN = dyn_cast(Addr.getOperand(1)); + + if (isIntN(OffsetBits + ShiftBits, CN->getSExtValue())) { + EVT ValTy = Addr.getValueType(); + + // Return false if the offset not align on (1 << ShiftBits) + if (ShiftBits) + if (CN->getSExtValue() % (1 << ShiftBits) != 0) + return false; + + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = dyn_cast + (Addr.getOperand(0))) + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + else + Base = Addr.getOperand(0); + + Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), + ValTy); + return true; + } + } + return false; +} + +// Used on NDS32 Load/Store word aligned instructions (15-bit offset) +// Range with imm15s << 2 +bool NDS32DAGToDAGISel::SelectAddrImm15sWord(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if ((Addr.getOpcode() == ISD::ADD + || Addr.getOpcode() == ISD::OR) + && selectAddrFrameIndexOffset(Addr, Base, Offset, 15, 2)) + return true; + + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + return false; +} + +// Used on NDS32 Load/Store half word aligned instructions (15-bit offset) +// Range with imm15s << 1 with 2 byte alignment +bool NDS32DAGToDAGISel::SelectAddrImm15sHalf(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if ((Addr.getOpcode() == ISD::ADD + || Addr.getOpcode() == ISD::OR) + && selectAddrFrameIndexOffset(Addr, Base, Offset, 15, 1)) + return true; + + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + return false; +} + +// Used on NDS32 Load/Store byte aligned instructions (15-bit offset) +// Range with imm15s with byte alignment +bool NDS32DAGToDAGISel::SelectAddrImm15sByte(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if ((Addr.getOpcode() == ISD::ADD + || Addr.getOpcode() == ISD::OR) + && selectAddrFrameIndexOffset(Addr, Base, Offset, 15, 0)) + return true; + + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + return false; +} + void NDS32DAGToDAGISel::Select(SDNode *Node) { SDLoc dl(Node); Index: lib/Target/NDS32/NDS32InstrFormats.td =================================================================== --- lib/Target/NDS32/NDS32InstrFormats.td +++ lib/Target/NDS32/NDS32InstrFormats.td @@ -83,6 +83,41 @@ : 32Bit_5R5R15Imm<0b101111, outs, ins, asmstr, pattern>; +class 32Bit_5R20Addr opcode, dag outs, dag ins, + string asmstr, list pattern> + : 32BitInst { + bits<5> Rt; + bits<20> addr; + let Inst{24-20} = Rt; + let Inst{19-15} = addr{19-15}; // Ra + let Inst{14-0} = addr{14-0}; // imm15s +} + +class LWIForm pattern> + : 32Bit_5R20Addr<0b000010, outs, ins, asmstr, pattern>; + +class LHIForm pattern> + : 32Bit_5R20Addr<0b000001, outs, ins, asmstr, pattern>; + +class LBIForm pattern> + : 32Bit_5R20Addr<0b000000, outs, ins, asmstr, pattern>; + +class LHSIForm pattern> + : 32Bit_5R20Addr<0b010001, outs, ins, asmstr, pattern>; + +class LBSIForm pattern> + : 32Bit_5R20Addr<0b010000, outs, ins, asmstr, pattern>; + +class SWIForm pattern> + : 32Bit_5R20Addr<0b001010, outs, ins, asmstr, pattern>; + +class SHIForm pattern> + : 32Bit_5R20Addr<0b001001, outs, ins, asmstr, pattern>; + +class SBIForm pattern> + : 32Bit_5R20Addr<0b001000, outs, ins, asmstr, pattern>; + + class JREGForm pattern> : 32BitInst<0b100101, outs, ins, asmstr, pattern>; Index: lib/Target/NDS32/NDS32InstrInfo.td =================================================================== --- lib/Target/NDS32/NDS32InstrInfo.td +++ lib/Target/NDS32/NDS32InstrInfo.td @@ -251,6 +251,47 @@ def SDIVREM : DIVREM< "divsr", 0b10110>; +//===----------------------------------------------------------------------===// +// Load/Store Instructions +// + +let mayLoad = 1 in { +def LWI: LWIForm<(outs GPR:$Rt), (ins addr_imm15s_word:$addr), + "lwi\t$Rt, $addr", + [(set GPR:$Rt, (load addr_imm15s_word:$addr))]>; + +def LHI: LHIForm<(outs GPR:$Rt), (ins addr_imm15s_half:$addr), + "lhi\t$Rt, $addr", + [(set GPR:$Rt, (zextloadi16 addr_imm15s_half:$addr))]>; + +def LBI: LBIForm<(outs GPR:$Rt), (ins addr_imm15s_byte:$addr), + "lbi\t$Rt, $addr", + [(set GPR:$Rt, (zextloadi8 addr_imm15s_byte:$addr))]>; + +def LHSI: LHSIForm<(outs GPR:$Rt), (ins addr_imm15s_half:$addr), + "lhsi\t$Rt, $addr", + [(set GPR:$Rt, (sextloadi16 addr_imm15s_half:$addr))]>; + +def LBSI: LBSIForm<(outs GPR:$Rt), (ins addr_imm15s_byte:$addr), + "lbsi\t$Rt, $addr", + [(set GPR:$Rt, (sextloadi8 addr_imm15s_byte:$addr))]>; +} + +let mayStore = 1 in { +def SWI: SWIForm<(outs), (ins GPR:$Rt, addr_imm15s_word:$addr), + "swi\t$Rt, $addr", + [(store GPR:$Rt, addr_imm15s_word:$addr)]>; + +def SHI: SHIForm<(outs), (ins GPR:$Rt, addr_imm15s_half:$addr), + "shi\t$Rt, $addr", + [(truncstorei16 GPR:$Rt, addr_imm15s_half:$addr)]>; + +def SBI: SBIForm<(outs), (ins GPR:$Rt, addr_imm15s_byte:$addr), + "sbi\t$Rt, $addr", + [(truncstorei8 GPR:$Rt, addr_imm15s_byte:$addr)]>; +} + + class JREG_ret pat, bits<2> dt_it> : JREGForm<(outs), (ins), opstr, pat> { let Inst{24-15} = 0; Index: lib/Target/NDS32/NDS32Predicate.td =================================================================== --- lib/Target/NDS32/NDS32Predicate.td +++ lib/Target/NDS32/NDS32Predicate.td @@ -57,3 +57,43 @@ return Imm >= 0 && Imm < (1 << 15); }]> { } + + +//===----------------------------------------------------------------------===// +// Load/Store Operands Predicates +// + +class MemOperand : Operand { let OperandType = "OPERAND_MEMORY"; } + +// addr_imm15s_word := [reg + imm15s << 2] +def AddrImm15sWordAsmOperand : AsmOperandClass { let Name = "AddrImm15sWord"; } +def addr_imm15s_word : MemOperand, + ComplexPattern { + // 15-bit signed immediate operand. Note that for word size load/store + // immediate access range would be +/- (imm15s << 2). + + let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); + let PrintMethod = "printAddrImmOperand"; +} + +// addr_imm15s_half := [reg + imm15s << 1] +def AddrImm15sHalfAsmOperand : AsmOperandClass { let Name = "AddrImm15sHalf"; } +def addr_imm15s_half : MemOperand, + ComplexPattern { + // 15-bit signed immediate operand. Note that for word size load/store + // immediate access range would be +/- (imm15s << 1). + + let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); + let PrintMethod = "printAddrImmOperand"; +} + +// addr_imm15s_byte := [reg + imm15s] +def AddrImm15sByteAsmOperand : AsmOperandClass { let Name = "AddrImm15sByte"; } +def addr_imm15s_byte : MemOperand, + ComplexPattern { + // 15-bit signed immediate operand. Note that for word size load/store + // immediate access range would be +/- (imm15s). + + let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); + let PrintMethod = "printAddrImmOperand"; +} Index: lib/Target/NDS32/NDS32RegisterInfo.cpp =================================================================== --- lib/Target/NDS32/NDS32RegisterInfo.cpp +++ lib/Target/NDS32/NDS32RegisterInfo.cpp @@ -74,6 +74,30 @@ int SPAdj, unsigned FIOperandNum, RegScavenger *RS) const { assert(SPAdj == 0 && "Unexpected"); + + MachineInstr &MI = *II; + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + DebugLoc DL = MI.getDebugLoc(); + int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); + uint64_t stackSize = MF.getFrameInfo().getStackSize(); + int64_t Offset = MF.getFrameInfo().getObjectOffset(FrameIndex); + + DEBUG(errs() << "\nFunction : " << MF.getName() << "\n"; + errs() << "<--------->\n" << MI); + DEBUG(errs() << "FrameIndex : " << FrameIndex << "\n" + << "spOffset : " << Offset << "\n" + << "stackSize : " << stackSize << "\n"); + + unsigned BasePtr = NDS32::SP; + + Offset += stackSize; + + // Fold imm into offset + Offset += MI.getOperand(FIOperandNum + 1).getImm(); + + MI.getOperand(FIOperandNum).ChangeToRegister(BasePtr, false); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); return; } Index: test/CodeGen/NDS32/load-store-insns.ll =================================================================== --- /dev/null +++ test/CodeGen/NDS32/load-store-insns.ll @@ -0,0 +1,57 @@ +; RUN: llc < %s | FileCheck %s +target datalayout = "e-m:e-p:32:32-i64:64-a:0:32-n32-S64" +target triple = "nds32le---elf" + +; Function Attrs: noinline nounwind +define i32 @swi(i32 %a) #0 { +entry: + %a.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 +; CHECK: swi $r0, [$sp + (4)] + %0 = load i32, i32* %a.addr, align 4 + ret i32 %0 +} + +; Function Attrs: noinline nounwind +define signext i16 @shi_lhsi(i16 signext %a) #0 { +entry: + %a.addr = alloca i16, align 2 + store i16 %a, i16* %a.addr, align 2 + %0 = load i16, i16* %a.addr, align 2 +; CHECK: shi $r0, [$sp + (6)] +; CHECK: lhsi $r0, [$sp + (6)] + ret i16 %0 +} + +; Function Attrs: noinline nounwind +define zeroext i16 @shi_lhi(i16 zeroext %a) #0 { +entry: + %a.addr = alloca i16, align 2 + store i16 %a, i16* %a.addr, align 2 + %0 = load i16, i16* %a.addr, align 2 +; CHECK: shi $r0, [$sp + (6)] +; CHECK: lhi $r0, [$sp + (6)] + ret i16 %0 +} + +; Function Attrs: noinline nounwind +define signext i8 @sbi_lbsi(i8 signext %a) #0 { +entry: + %a.addr = alloca i8, align 1 + store i8 %a, i8* %a.addr, align 1 + %0 = load i8, i8* %a.addr, align 1 +; CHECK: sbi $r0, [$sp + (7)] +; CHECK: lbsi $r0, [$sp + (7)] + ret i8 %0 +} + +; Function Attrs: noinline nounwind +define zeroext i8 @sbi_lbi(i8 zeroext %a) #0 { +entry: + %a.addr = alloca i8, align 1 + store i8 %a, i8* %a.addr, align 1 + %0 = load i8, i8* %a.addr, align 1 +; CHECK: sbi $r0, [$sp + (7)] +; CHECK: lbi $r0, [$sp + (7)] + ret i8 %0 +}