Index: lib/Target/NDS32/InstPrinter/NDS32InstPrinter.h =================================================================== --- lib/Target/NDS32/InstPrinter/NDS32InstPrinter.h +++ lib/Target/NDS32/InstPrinter/NDS32InstPrinter.h @@ -36,6 +36,8 @@ void printRegName(raw_ostream &OS, unsigned RegNo) const override; void printAddrImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + + void printAddrRegShift(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 @@ -67,3 +67,23 @@ O << " + " << markup("") << "]" << markup(">"); } + +// Print [Reg + Reg << Imm] addressing mode +void NDS32InstPrinter::printAddrRegShift(const MCInst *MI, unsigned Op, + raw_ostream &O) { + const MCOperand &MO1 = MI->getOperand(Op); + const MCOperand &MO2 = MI->getOperand(Op + 1); + const MCOperand &MO3 = MI->getOperand(Op + 2); + + O << markup(""); +} Index: lib/Target/NDS32/NDS32ISelDAGToDAG.cpp =================================================================== --- lib/Target/NDS32/NDS32ISelDAGToDAG.cpp +++ lib/Target/NDS32/NDS32ISelDAGToDAG.cpp @@ -82,7 +82,11 @@ bool SelectAddrImm15sByte(SDValue Addr, SDValue &Base, SDValue &Offset) const; - // Include the pieces autogenerated from the target description. + // Select [Reg + Reg << imm] addressing mode + bool SelectLdStRegShift(SDValue N, SDValue &Base, SDValue &OffsetReg, + SDValue &Shift); + + // Include the pieces autogenerated from the target description. #include "NDS32GenDAGISel.inc" private: @@ -214,6 +218,61 @@ return false; } +bool NDS32DAGToDAGISel::SelectLdStRegShift(SDValue N, SDValue &Base, + SDValue &OffsetReg, + SDValue &Shift) { + if (N.getOpcode() != ISD::ADD && + // ISD::OR that is equivalent to an ISD::ADD. + !CurDAG->isBaseWithConstantOffset(N)) + return false; + + unsigned ShAmt = 0; + + if (N.getOperand(1).getOpcode() == ISD::SHL) { + Base = N.getOperand(0); + + // Check to see if the RHS of the shift is a constant, if not, we can't fold + // it. + if (ConstantSDNode *Sh = + dyn_cast(N.getOperand(1).getOperand(1))) { + ShAmt = Sh->getZExtValue(); + if (ShAmt < 4) { + OffsetReg = N.getOperand(1).getOperand(0); + Shift = CurDAG->getTargetConstant(ShAmt, SDLoc(N), MVT::i32); + return true; + } else { + return false; + } + } + // Try matching (R shl C) + (R). + } else if (N.getOpcode() != ISD::SUB && (N.getOperand(0).hasOneUse())) { + if (N.getOperand(0).getOpcode() == ISD::SHL) { + Base = N.getOperand(1); + // Check to see if the RHS of the shift is a constant, if not, we can't + // fold it. + if (ConstantSDNode *Sh = + dyn_cast(N.getOperand(0).getOperand(1))) { + ShAmt = Sh->getZExtValue(); + if (ShAmt < 4) { + OffsetReg = N.getOperand(0).getOperand(0); + Shift = CurDAG->getTargetConstant(ShAmt, SDLoc(N), MVT::i32); + return true; + } else { + ShAmt = 0; + return false; + } + } + } + } + + // return [r + r] addressing mode + Base = N.getOperand(1); + OffsetReg = N.getOperand(0); + Shift = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32); + + return true; +} + void NDS32DAGToDAGISel::Select(SDNode *Node) { SDLoc dl(Node); @@ -235,7 +294,18 @@ switch (Node->getOpcode()) { default: break; case ISD::FrameIndex: { - break; + assert(Node->getValueType(0) == MVT::i32); + int FI = cast(Node)->getIndex(); + SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32); + if (Node->hasOneUse()) { + CurDAG->SelectNodeTo(Node, NDS32::ADDI, MVT::i32, TFI, + CurDAG->getTargetConstant(0, dl, MVT::i32)); + return; + } + ReplaceNode(Node, CurDAG->getMachineNode( + NDS32::ADDI, dl, MVT::i32, TFI, + CurDAG->getTargetConstant(0, dl, MVT::i32))); + return; } case ISD::LOAD: break; Index: lib/Target/NDS32/NDS32InstrFormats.td =================================================================== --- lib/Target/NDS32/NDS32InstrFormats.td +++ lib/Target/NDS32/NDS32InstrFormats.td @@ -134,6 +134,19 @@ : 32Bit_5R20Addr<0b001000, outs, ins, asmstr, pattern>; +class MEMForm pattern, + bits<8> subop_encode> + : 32BitInst<0b011100, outs, ins, asmstr, pattern> { + bits<5> Rt; + bits<12> addr; + let Inst{24-20} = Rt; + let Inst{19-15} = addr{11-7}; // Ra + let Inst{14-10} = addr{6-2}; // Rb + let Inst{9-8} = addr{1-0}; // sv + let Inst{7-0} = subop_encode; +} + + 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 @@ -311,6 +311,30 @@ } +let mayLoad = 1 in +class MEM_load subop_encode> : + MEMForm<(outs GPR:$Rt), (ins ldst_reg_shift:$addr), + !strconcat(opstr, "\t$Rt, $addr"), + [(set GPR:$Rt, (Op ldst_reg_shift:$addr))], subop_encode>; + +def LW : MEM_load< "lw", load, 0b00000010>; +def LH : MEM_load< "lh", zextloadi16, 0b00000001>; +def LHS : MEM_load< "lhs", sextloadi16, 0b00010001>; +def LB : MEM_load< "lb", zextloadi8, 0b00000000>; +def LBS : MEM_load< "lbs", sextloadi8, 0b00010000>; + + +let mayStore = 1 in +class MEM_store subop_encode> : + MEMForm<(outs), (ins GPR:$Rt, ldst_reg_shift:$addr), + !strconcat(opstr, "\t$Rt, $addr"), + [(Op GPR:$Rt, ldst_reg_shift:$addr)], subop_encode>; + +def SW : MEM_store< "sw", store, 0b00001010>; +def SH : MEM_store< "sh", truncstorei16, 0b00001001>; +def SB : MEM_store< "sb", truncstorei8, 0b00001000>; + + 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 @@ -117,3 +117,12 @@ let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); let PrintMethod = "printAddrImmOperand"; } + +// ldst_reg_shift := [reg + reg << sv] +// sv: shift value could be 0, 1, 2, 3 +def MemAddrRegShiftAsmOperand : AsmOperandClass { let Name = "AddrRegShift"; } +def ldst_reg_shift : MemOperand, + ComplexPattern { + let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$shift); + let PrintMethod = "printAddrRegShift"; +} Index: test/CodeGen/NDS32/load-store-insns.ll =================================================================== --- test/CodeGen/NDS32/load-store-insns.ll +++ test/CodeGen/NDS32/load-store-insns.ll @@ -55,3 +55,84 @@ ; CHECK: lbi $r0, [$sp + (7)] ret i8 %0 } + +; Function Attrs: noinline nounwind +define i32 @sw_lwi_lw(i32 %a) #0 { +entry: + %a.addr = alloca i32, align 4 + %b = alloca [100000 x i32], align 4 + store i32 %a, i32* %a.addr, align 4 + %arrayidx = getelementptr inbounds [100000 x i32], [100000 x i32]* %b, i32 0, i32 9999 + store i32 3, i32* %arrayidx, align 4 + %0 = load i32, i32* %a.addr, align 4 + %arrayidx1 = getelementptr inbounds [100000 x i32], [100000 x i32]* %b, i32 0, i32 %0 + %1 = load i32, i32* %arrayidx1, align 4 +; CHECK: sw $r2, [$r1 + $r0] +; CHECK: lwi $r1, [$sp + (400004)] +; CHECK: lw $r0, [$r0 + $r1 << 2] + ret i32 %1 +} + +; Function Attrs: noinline nounwind +define signext i16 @sh_lhs(i32 %a) #0 { +entry: + %a.addr = alloca i32, align 4 + %b = alloca [100000 x i16], align 2 + store i32 %a, i32* %a.addr, align 4 + %arrayidx = getelementptr inbounds [100000 x i16], [100000 x i16]* %b, i32 0, i32 9999 + store i16 3, i16* %arrayidx, align 2 + %0 = load i32, i32* %a.addr, align 4 + %arrayidx1 = getelementptr inbounds [100000 x i16], [100000 x i16]* %b, i32 0, i32 %0 + %1 = load i16, i16* %arrayidx1, align 2 +; CHECK: sh $r2, [$r1 + $r0] +; CHECK: lhs $r0, [$r0 + $r1 << 1] + ret i16 %1 +} + +; Function Attrs: noinline nounwind +define zeroext i16 @sh_lh(i32 %a) #0 { +entry: + %a.addr = alloca i32, align 4 + %b = alloca [100000 x i16], align 2 + store i32 %a, i32* %a.addr, align 4 + %arrayidx = getelementptr inbounds [100000 x i16], [100000 x i16]* %b, i32 0, i32 9999 + store i16 3, i16* %arrayidx, align 2 + %0 = load i32, i32* %a.addr, align 4 + %arrayidx1 = getelementptr inbounds [100000 x i16], [100000 x i16]* %b, i32 0, i32 %0 + %1 = load i16, i16* %arrayidx1, align 2 +; CHECK: sh $r2, [$r1 + $r0] +; CHECK: lh $r0, [$r0 + $r1 << 1] + ret i16 %1 +} + +; Function Attrs: noinline nounwind +define signext i8 @sb_lbs(i32 %a) #0 { +entry: + %a.addr = alloca i32, align 4 + %b = alloca [100000 x i8], align 1 + store i32 %a, i32* %a.addr, align 4 + %arrayidx = getelementptr inbounds [100000 x i8], [100000 x i8]* %b, i32 0, i32 9999 + store i8 3, i8* %arrayidx, align 1 + %0 = load i32, i32* %a.addr, align 4 + %arrayidx1 = getelementptr inbounds [100000 x i8], [100000 x i8]* %b, i32 0, i32 %0 + %1 = load i8, i8* %arrayidx1, align 1 +; CHECK: sb $r2, [$r1 + $r0] +; CHECK: lbs $r0, [$r1 + $r0] + ret i8 %1 +} + +; Function Attrs: noinline nounwind +define zeroext i8 @sb_lb(i32 %a) #0 { +entry: + %a.addr = alloca i32, align 4 + %b = alloca [100000 x i8], align 1 + store i32 %a, i32* %a.addr, align 4 + %arrayidx = getelementptr inbounds [100000 x i8], [100000 x i8]* %b, i32 0, i32 9999 + store i8 3, i8* %arrayidx, align 1 + %0 = load i32, i32* %a.addr, align 4 + %arrayidx1 = getelementptr inbounds [100000 x i8], [100000 x i8]* %b, i32 0, i32 %0 + %1 = load i8, i8* %arrayidx1, align 1 +; CHECK: sb $r2, [$r1 + $r0] +; CHECK: lb $r0, [$r1 + $r0] + ret i8 %1 +}