Index: lib/Target/NDS32/InstPrinter/NDS32InstPrinter.h =================================================================== --- lib/Target/NDS32/InstPrinter/NDS32InstPrinter.h +++ lib/Target/NDS32/InstPrinter/NDS32InstPrinter.h @@ -38,6 +38,12 @@ void printAddrImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printAddrRegShift(const MCInst *MI, unsigned OpNum, raw_ostream &O); + + void printAddrRegOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + void printAddrImmOffsetOperand(const MCInst *MI, unsigned OpNum, + raw_ostream &O); + void printAddrRegOffsetOperand(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 @@ -87,3 +87,33 @@ } O << "]" << markup(">"); } + +// print [Reg] operand in ([Reg], Offset) addressing mode +void NDS32InstPrinter::printAddrRegOperand(const MCInst *MI, unsigned OpNum, + raw_ostream &O) { + const MCOperand &MO1 = MI->getOperand(OpNum); + O << markup(""); +} + +// print immediate operand in ([Reg], Imm) addressing mode +void NDS32InstPrinter::printAddrImmOffsetOperand(const MCInst *MI, + unsigned OpNum, + raw_ostream &O) { + const MCOperand &MO1 = MI->getOperand(OpNum); + + O << markup(""); +} + +// print RegA operand in ([Reg], RegA) addressing mode +void NDS32InstPrinter::printAddrRegOffsetOperand(const MCInst *MI, + unsigned OpNum, + raw_ostream &O) { + const MCOperand &MO1 = MI->getOperand(OpNum); + + O << '$'; + printRegName(O, MO1.getReg()); +} Index: lib/Target/NDS32/NDS32ISelDAGToDAG.cpp =================================================================== --- lib/Target/NDS32/NDS32ISelDAGToDAG.cpp +++ lib/Target/NDS32/NDS32ISelDAGToDAG.cpp @@ -86,12 +86,34 @@ bool SelectLdStRegShift(SDValue N, SDValue &Base, SDValue &OffsetReg, SDValue &Shift); + // Select addressing mode for [Reg] + bool SelectAddrReg(SDValue N, SDValue &Base); + + // Select offset operand as Reg in ([Reg], Reg) POST_INC addressing mode + bool SelectAddrOffsetReg(SDNode *Op, SDValue N, + SDValue &Offset, SDValue &Opc); + // Select addressing mode for imm15s word width load/store POST_INC + // instructions. + bool SelectAddrImm15sWordPostInc(SDNode *Op, SDValue N, + SDValue &Offset, SDValue &Opc) const; + // Select addressing mode for imm15s half width load/store POST_INC + // instructions. + bool SelectAddrImm15sHalfPostInc(SDNode *Op, SDValue N, + SDValue &Offset, SDValue &Opc) const; + // Select addressing mode for imm15s byte width load/store post POST_NIC + // instructions. + bool SelectAddrImm15sBytePostInc(SDNode *Op, SDValue N, + SDValue &Offset, SDValue &Opc) const; + // Include the pieces autogenerated from the target description. #include "NDS32GenDAGISel.inc" private: void Select(SDNode *N) override; + bool tryIndexedLoad(SDNode *Op); + bool tryIndexedStore(SDNode *Op); + // getImm - Return a target constant with the specified value. inline SDValue getImm(const SDNode *Node, uint64_t Imm) { return CurDAG->getTargetConstant(Imm, SDLoc(Node), Node->getValueType(0)); @@ -273,6 +295,195 @@ return true; } +bool NDS32DAGToDAGISel::SelectAddrReg(SDValue N, SDValue &Base) { + Base = N; + return true; +} + +bool NDS32DAGToDAGISel::SelectAddrOffsetReg(SDNode *Op, SDValue N, + SDValue &Offset, SDValue &Opc) { + Offset = N; + return true; +} + +static bool SelectAddrPostInc (SDNode *Op) { + unsigned Opcode = Op->getOpcode(); + ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) + ? cast(Op)->getAddressingMode() + : cast(Op)->getAddressingMode(); + + return (AM == ISD::POST_INC); +} + +// For selecting post increment load/store word instructions +bool NDS32DAGToDAGISel::SelectAddrImm15sWordPostInc(SDNode *Op, + SDValue N, + SDValue &Offset, + SDValue &Opc) const { + ConstantSDNode *CN = dyn_cast(N); + int Val = CN->getSExtValue(); + + if (SelectAddrPostInc (Op) + && isIntN(17, Val) + && ((Val % 4) == 0)) { + Offset = CurDAG->getTargetConstant(Val, SDLoc(Op), MVT::i32); + Opc = Offset; + return true; + } + + Offset = N; + Opc = Offset; + return false; +} + +// For selecting post increment load/store word instructions +bool NDS32DAGToDAGISel::SelectAddrImm15sHalfPostInc(SDNode *Op, + SDValue N, + SDValue &Offset, + SDValue &Opc) const { + ConstantSDNode *CN = dyn_cast(N); + int Val = CN->getSExtValue(); + if (SelectAddrPostInc (Op) + && isIntN(16, Val) + && ((Val % 2) == 0)) { + Offset = CurDAG->getTargetConstant(Val, SDLoc(Op), MVT::i32); + Opc = Offset; + return true; + } + + Offset = N; + Opc = Offset; + return false; +} + +// For selecting post increment load/store word instructions +bool NDS32DAGToDAGISel::SelectAddrImm15sBytePostInc(SDNode *Op, + SDValue N, + SDValue &Offset, + SDValue &Opc) const { + ConstantSDNode *CN = dyn_cast(N); + int Val = CN->getSExtValue(); + + if (SelectAddrPostInc (Op) + && isIntN(15, Val)) { + Offset = CurDAG->getTargetConstant(Val, SDLoc(Op), MVT::i32); + Opc = Offset; + return true; + } + + Offset = N; + Opc = Offset; + return false; +} + +bool NDS32DAGToDAGISel::tryIndexedLoad(SDNode *N) { + LoadSDNode *LD = cast(N); + ISD::MemIndexedMode AM = LD->getAddressingMode(); + + if (AM == ISD::UNINDEXED) + return false; + + unsigned Opcode = 0; + bool Match = false; + SDValue Offset; + SDValue Opc; + + MVT VT = LD->getMemoryVT().getSimpleVT(); + if ((AM == ISD::POST_INC) && (VT == MVT::i32)) { + if (SelectAddrImm15sWordPostInc (N, LD->getOffset(), Offset, Opc)) { + Opcode = NDS32::LWI_BI; + } else { + Opcode = NDS32::LW_BI; + } + Match = true; + } + else if ((AM == ISD::POST_INC) && (VT == MVT::i16)) { + if (SelectAddrImm15sHalfPostInc (N, LD->getOffset(), Offset, Opc)) { + Opcode = (LD->getExtensionType() == ISD::SEXTLOAD) + ? NDS32::LHSI_BI : NDS32::LHI_BI; + } else { + Opcode = (LD->getExtensionType() == ISD::SEXTLOAD) + ? NDS32::LHS_BI : NDS32::LH_BI; + } + Match = true; + } + else if ((AM == ISD::POST_INC) && (VT == MVT::i8)) { + if (SelectAddrImm15sBytePostInc (N, LD->getOffset(), Offset, Opc)) { + Opcode = (LD->getExtensionType() == ISD::SEXTLOAD) + ? NDS32::LBSI_BI : NDS32::LBI_BI; + } else { + Opcode = (LD->getExtensionType() == ISD::SEXTLOAD) + ? NDS32::LBS_BI : NDS32::LB_BI; + } + Match = true; + } + + if (Match) { + SDValue Chain = LD->getChain(); + SDValue Base = LD->getBasePtr(); + SDValue Ops[]= { Base, Offset, CurDAG->getRegister(0, MVT::i32), Chain }; + + ReplaceNode(N, CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, + MVT::i32, MVT::Other, Ops)); + return true; + } + + return false; +} + +bool NDS32DAGToDAGISel::tryIndexedStore(SDNode *N) { + StoreSDNode *ST = cast(N); + ISD::MemIndexedMode AM = ST->getAddressingMode(); + + if (AM == ISD::UNINDEXED) + return false; + + unsigned Opcode = 0; + bool Match = false; + SDValue Offset; + SDValue Opc; + + MVT VT = ST->getMemoryVT().getSimpleVT(); + if ((AM == ISD::POST_INC) && (VT == MVT::i32)) { + if (SelectAddrImm15sWordPostInc(N, ST->getOffset(), Offset, Opc)) { + Opcode = NDS32::SWI_BI; + } else { + Opcode = NDS32::SW_BI; + } + Match = true; + } + else if ((AM == ISD::POST_INC) && (VT == MVT::i16)) { + if (SelectAddrImm15sHalfPostInc(N, ST->getOffset(), Offset, Opc)) { + Opcode = NDS32::SHI_BI; + } else { + Opcode = NDS32::SH_BI; + } + Match = true; + } + else if ((AM == ISD::POST_INC) && (VT == MVT::i8)) { + if (SelectAddrImm15sBytePostInc(N, ST->getOffset(), Offset, Opc)) { + Opcode = NDS32::SBI_BI; + } else { + Opcode = NDS32::SB_BI; + } + Match = true; + } + + if (Match) { + SDValue Chain = ST->getChain(); + SDValue Base = ST->getBasePtr(); + SDValue Value = ST->getValue(); + SDValue Ops[]= { Value, Base, Offset, CurDAG->getRegister(0, MVT::i32), + Chain }; + + ReplaceNode(N, CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, + MVT::Other, Ops)); + return true; + } + + return false; +} + void NDS32DAGToDAGISel::Select(SDNode *Node) { SDLoc dl(Node); @@ -308,8 +519,12 @@ return; } case ISD::LOAD: + if (tryIndexedLoad(Node)) + return; break; case ISD::STORE: + if (tryIndexedStore(Node)) + return; break; case ISD::ADD: // Other cases are autogenerated. Index: lib/Target/NDS32/NDS32ISelLowering.h =================================================================== --- lib/Target/NDS32/NDS32ISelLowering.h +++ lib/Target/NDS32/NDS32ISelLowering.h @@ -149,6 +149,12 @@ const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &dl, SelectionDAG &DAG) const override; + + bool getPostIndexedAddressParts(SDNode *N, SDNode *Op, + SDValue &Base, + SDValue &Offset, + ISD::MemIndexedMode &AM, + SelectionDAG &DAG) const override; }; } // namespace llvm Index: lib/Target/NDS32/NDS32ISelLowering.cpp =================================================================== --- lib/Target/NDS32/NDS32ISelLowering.cpp +++ lib/Target/NDS32/NDS32ISelLowering.cpp @@ -482,3 +482,49 @@ } return nullptr; } + +static bool getNDS32IndexedAddressParts(SDNode *Ptr, EVT VT, SDValue &Base, + SDValue &Offset, SelectionDAG &DAG) { + if (Ptr->getOpcode() != ISD::ADD) + return false; + + Base = Ptr->getOperand(0); + ConstantSDNode *RHS = dyn_cast(Ptr->getOperand(1)); + + if (!RHS) return false; + + // We don't have to check the immediate limitation here. + // If ([reg], imm) couldn't fit immediate limitation, + // It could match to ([reg], reg) addressing mode. + + Base = Ptr->getOperand(0); + Offset = Ptr->getOperand(1); + + return true; +} + +bool NDS32TargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op, + SDValue &Base, + SDValue &Offset, + ISD::MemIndexedMode &AM, + SelectionDAG &DAG) const { + EVT VT; + SDValue Ptr; + if (LoadSDNode *LD = dyn_cast(N)) { + VT = LD->getMemoryVT(); + Ptr = LD->getBasePtr(); + } else if (StoreSDNode *ST = dyn_cast(N)) { + VT = ST->getMemoryVT(); + Ptr = ST->getBasePtr(); + } else + return false; + + bool isLegal = false; + + isLegal = getNDS32IndexedAddressParts(Op, VT, Base, Offset, DAG); + if (!isLegal) + return false; + + AM = ISD::POST_INC; + return true; +} Index: lib/Target/NDS32/NDS32InstrFormats.td =================================================================== --- lib/Target/NDS32/NDS32InstrFormats.td +++ lib/Target/NDS32/NDS32InstrFormats.td @@ -134,6 +134,42 @@ : 32Bit_5R20Addr<0b001000, outs, ins, asmstr, pattern>; +class 32Bit_5R5R15IMM_BI opcode, dag outs, dag ins, + string asmstr, list pattern> + : 32BitInst { + bits<5> Rt; + bits<5> addr; + bits<15> offset; + let Inst{24-20} = Rt; + let Inst{19-15} = addr; // Ra + let Inst{14-0} = offset; // imm15s +} + +class LWI_BIForm pattern> + : 32Bit_5R5R15IMM_BI<0b000110, outs, ins, asmstr, pattern>; + +class LHI_BIForm pattern> + : 32Bit_5R5R15IMM_BI<0b000101, outs, ins, asmstr, pattern>; + +class LBI_BIForm pattern> + : 32Bit_5R5R15IMM_BI<0b000100, outs, ins, asmstr, pattern>; + +class LHSI_BIForm pattern> + : 32Bit_5R5R15IMM_BI<0b010101, outs, ins, asmstr, pattern>; + +class LBSI_BIForm pattern> + : 32Bit_5R5R15IMM_BI<0b010100, outs, ins, asmstr, pattern>; + +class SWI_BIForm pattern> + : 32Bit_5R5R15IMM_BI<0b001110, outs, ins, asmstr, pattern>; + +class SHI_BIForm pattern> + : 32Bit_5R5R15IMM_BI<0b001101, outs, ins, asmstr, pattern>; + +class SBI_BIForm pattern> + : 32Bit_5R5R15IMM_BI<0b001100, outs, ins, asmstr, pattern>; + + class MEMForm pattern, bits<8> subop_encode> : 32BitInst<0b011100, outs, ins, asmstr, pattern> { @@ -146,6 +182,19 @@ let Inst{7-0} = subop_encode; } +class MEMForm_BI pattern, + bits<8> subop_encode> + : 32BitInst<0b011100, outs, ins, asmstr, pattern> { + bits<5> Rt; + bits<5> addr; + bits<5> offset; + let Inst{24-20} = Rt; + let Inst{19-15} = addr; // Ra + let Inst{14-10} = offset; // Rb + let Inst{9-8} = 0; // sv + let Inst{7-0} = subop_encode; +} + class JIForm pattern> : 32BitInst<0b100100, outs, ins, asmstr, pattern>; Index: lib/Target/NDS32/NDS32InstrInfo.td =================================================================== --- lib/Target/NDS32/NDS32InstrInfo.td +++ lib/Target/NDS32/NDS32InstrInfo.td @@ -294,6 +294,36 @@ def LBSI: LBSIForm<(outs GPR:$Rt), (ins addr_imm15s_byte:$addr), "lbsi\t$Rt, $addr", [(set GPR:$Rt, (sextloadi8 addr_imm15s_byte:$addr))]>; + +def LWI_BI: LWI_BIForm<(outs GPR:$Rt, GPR:$Ra_wb), + (ins addr_reg:$addr, offset_imm15s_word:$offset), + "lwi.bi\t$Rt, $addr, $offset", []> { + let Constraints = "$addr.base = $Ra_wb"; +} + +def LHI_BI: LHI_BIForm<(outs GPR:$Rt, GPR:$Ra_wb), + (ins addr_reg:$addr, offset_imm15s_half:$offset), + "lhi.bi\t$Rt, $addr, $offset", []> { + let Constraints = "$addr.base = $Ra_wb"; +} + +def LBI_BI: LBI_BIForm<(outs GPR:$Rt, GPR:$Ra_wb), + (ins addr_reg:$addr, offset_imm15s_byte:$offset), + "lbi.bi\t$Rt, $addr, $offset", []> { + let Constraints = "$addr.base = $Ra_wb"; +} + +def LHSI_BI: LHSI_BIForm<(outs GPR:$Rt, GPR:$Ra_wb), + (ins addr_reg:$addr, offset_imm15s_half:$offset), + "lhsi.bi\t$Rt, $addr, $offset", []> { + let Constraints = "$addr.base = $Ra_wb"; +} + +def LBSI_BI: LBSI_BIForm<(outs GPR:$Rt, GPR:$Ra_wb), + (ins addr_reg:$addr, offset_imm15s_byte:$offset), + "lbsi.bi\t$Rt, $addr, $offset", []> { + let Constraints = "$addr.base = $Ra_wb"; +} } let mayStore = 1 in { @@ -308,6 +338,27 @@ def SBI: SBIForm<(outs), (ins GPR:$Rt, addr_imm15s_byte:$addr), "sbi\t$Rt, $addr", [(truncstorei8 GPR:$Rt, addr_imm15s_byte:$addr)]>; + +def SWI_BI: SWI_BIForm<(outs GPR:$Ra_wb), + (ins GPR:$Rt, addr_reg:$addr, + offset_imm15s_word:$offset), + "swi.bi\t$Rt, $addr, $offset", []> { + let Constraints = "$addr.base = $Ra_wb,@earlyclobber $Ra_wb"; +} + +def SHI_BI: SHI_BIForm<(outs GPR:$Ra_wb), + (ins GPR:$Rt, addr_reg:$addr, + offset_imm15s_half:$offset), + "shi.bi\t$Rt, $addr, $offset", []> { + let Constraints = "$addr.base = $Ra_wb,@earlyclobber $Ra_wb"; +} + +def SBI_BI: SBI_BIForm<(outs GPR:$Ra_wb), + (ins GPR:$Rt, addr_reg:$addr, + offset_imm15s_byte:$offset), + "sbi.bi\t$Rt, $addr, $offset", []> { + let Constraints = "$addr.base = $Ra_wb,@earlyclobber $Ra_wb"; +} } @@ -335,6 +386,36 @@ def SB : MEM_store< "sb", truncstorei8, 0b00001000>; +let mayLoad = 1 in +class MEM_load_post subop_encode> : + MEMForm_BI<(outs GPR:$Rt, GPR:$Ra_wb), + (ins addr_reg:$addr, offset_reg:$offset), + !strconcat(opstr, "\t$Rt, $addr, $offset"), + [], subop_encode> { + let Constraints = "$addr.base = $Ra_wb"; +} + +def LW_BI : MEM_load_post< "lw.bi", 0b00000110>; +def LH_BI : MEM_load_post< "lh.bi", 0b00000101>; +def LB_BI : MEM_load_post< "lb.bi", 0b00000100>; +def LHS_BI : MEM_load_post< "lhs.bi", 0b00010101>; +def LBS_BI : MEM_load_post< "lbs.bi", 0b00010100>; + + +let mayStore = 1 in +class MEM_store_post subop_encode> : + MEMForm_BI<(outs GPR:$Ra_wb), + (ins GPR:$Rt, addr_reg:$addr, offset_reg:$offset), + !strconcat(opstr, "\t$Rt, $addr, $offset"), + [], subop_encode> { + let Constraints = "$addr.base = $Ra_wb,@earlyclobber $Ra_wb"; +} + +def SW_BI : MEM_store_post< "sw.bi", 0b00001110>; +def SH_BI : MEM_store_post< "sh.bi", 0b00001101>; +def SB_BI : MEM_store_post< "sb.bi", 0b00001100>; + + //===----------------------------------------------------------------------===// // Control Flow Instructions // Index: lib/Target/NDS32/NDS32Predicate.td =================================================================== --- lib/Target/NDS32/NDS32Predicate.td +++ lib/Target/NDS32/NDS32Predicate.td @@ -138,6 +138,58 @@ } +// addr_reg := [reg] +// use single reg as memory access address +def MemNoOffsetAsmOperand : AsmOperandClass { let Name = "MemNoOffset"; } +def addr_reg : MemOperand, + ComplexPattern { + let MIOperandInfo = (ops GPR:$base); + let PrintMethod = "printAddrRegOperand"; +} + +// offset operand as Reg for ([Reg], [Reg]) POST_INC addressing mode +def MemRegOffsetAsmOperand : AsmOperandClass { let Name = "MemRegOffset"; } +def offset_reg : MemOperand, + ComplexPattern { + let MIOperandInfo = (ops GPR, GPR); + let PrintMethod = "printAddrRegOffsetOperand"; +} + +// addressing mode operand for [Reg], (imm15s << 2) POST_INC addressing mode +def OffsetImm15sWordAsmOperand : AsmOperandClass { let Name = "OffsetImm15sWord"; } +def offset_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, i32imm); + let PrintMethod = "printAddrImmOffsetOperand"; +} + +// addressing mode operand for [Reg], (imm15s << 1) POST_INC addressing mode +def OffsetImm15sHalfAsmOperand : AsmOperandClass { let Name = "OffsetImm15sHalf"; } +def offset_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, i32imm); + let PrintMethod = "printAddrImmOffsetOperand"; +} + +// addressing mode operand for [Reg], (imm15s) POST_INC addressing mode +def OffsetImm15sByteAsmOperand : AsmOperandClass { let Name = "OffsetImm15sByte"; } +def offset_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, i32imm); + let PrintMethod = "printAddrImmOffsetOperand"; +} + + //===----------------------------------------------------------------------===// // Branch/Jump target Operands Predicates // Index: test/CodeGen/NDS32/post-inc.ll =================================================================== --- /dev/null +++ test/CodeGen/NDS32/post-inc.ll @@ -0,0 +1,170 @@ +; RUN: llc < %s | FileCheck %s +target datalayout = "e-m:e-p:32:32-i64:64-a:0:32-n32-S64" +target triple = "nds32le---elf" + +@a = common local_unnamed_addr global [100 x i32] zeroinitializer, align 4 +@a1 = common local_unnamed_addr global [100 x i32] zeroinitializer, align 4 +@b = common local_unnamed_addr global [100 x i16] zeroinitializer, align 2 +@b1 = common local_unnamed_addr global [100 x i16] zeroinitializer, align 2 +@c = common local_unnamed_addr global [100 x i8] zeroinitializer, align 1 +@c1 = common local_unnamed_addr global [100 x i8] zeroinitializer, align 1 + +; Function Attrs: norecurse nounwind +define i32 @lwi_bi_swi_bi() local_unnamed_addr #0 { +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %sum.010 = phi i32 [ 0, %entry ], [ %add, %for.body ] + %i.09 = phi i32 [ 99, %entry ], [ %sub, %for.body ] + %arrayidx = getelementptr inbounds [100 x i32], [100 x i32]* @a, i32 0, i32 %i.09 + %0 = load i32, i32* %arrayidx, align 4 +; CHECK: lwi.bi $r5, [$r3], -4 + %add = add i32 %0, %sum.010 + %arrayidx1 = getelementptr inbounds [100 x i32], [100 x i32]* @a1, i32 0, i32 %i.09 + store i32 %add, i32* %arrayidx1, align 4 +; CHECK: swi.bi $r0, [$r2], -4 + %sub = add nsw i32 %i.09, -1 + %cmp = icmp sgt i32 %i.09, 1 + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body + ret i32 %add +} + +; Function Attrs: norecurse nounwind +define zeroext i16 @lhi_bi_shi_bi() local_unnamed_addr #0 { +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %sum.012 = phi i32 [ 0, %entry ], [ %add, %for.body ] + %i.011 = phi i32 [ 99, %entry ], [ %sub, %for.body ] + %arrayidx = getelementptr inbounds [100 x i16], [100 x i16]* @b, i32 0, i32 %i.011 + %0 = load i16, i16* %arrayidx, align 2 +; CHECK: lhi.bi $r16, [$r3], -2 + %conv = zext i16 %0 to i32 + %conv1 = and i32 %sum.012, 65535 + %add = add nuw nsw i32 %conv, %conv1 + %conv2 = trunc i32 %add to i16 + %arrayidx3 = getelementptr inbounds [100 x i16], [100 x i16]* @b1, i32 0, i32 %i.011 + store i16 %conv2, i16* %arrayidx3, align 2 +; CHECK: shi.bi $r0, [$r2], -2 + %sub = add nsw i32 %i.011, -1 + %cmp = icmp sgt i32 %i.011, 1 + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body + ret i16 %conv2 +} + +; Function Attrs: norecurse nounwind +define zeroext i8 @lbi_bi_sbi_bi(i32 %k) local_unnamed_addr #0 { +entry: + %cmp10 = icmp sgt i32 %k, 0 + br i1 %cmp10, label %for.body.preheader, label %for.end + +for.body.preheader: ; preds = %entry + br label %for.body + +for.body: ; preds = %for.body.preheader, %for.body + %sum.012 = phi i32 [ %add, %for.body ], [ 0, %for.body.preheader ] + %i.011 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] + %arrayidx = getelementptr inbounds [100 x i8], [100 x i8]* @c, i32 0, i32 %i.011 + %0 = load i8, i8* %arrayidx, align 1 +; CHECK: lbi.bi $r4, [$r3], 1 + %conv = zext i8 %0 to i32 + %conv1 = and i32 %sum.012, 255 + %add = add nuw nsw i32 %conv, %conv1 + %conv2 = trunc i32 %add to i8 + %arrayidx3 = getelementptr inbounds [100 x i8], [100 x i8]* @c1, i32 0, i32 %i.011 + store i8 %conv2, i8* %arrayidx3, align 1 +; CHECK: sbi.bi $r1, [$r2], 1 + %inc = add nuw nsw i32 %i.011, 1 + %exitcond = icmp eq i32 %inc, %k + br i1 %exitcond, label %for.end.loopexit, label %for.body + +for.end.loopexit: ; preds = %for.body + br label %for.end + +for.end: ; preds = %for.end.loopexit, %entry + %sum.0.lcssa = phi i8 [ 0, %entry ], [ %conv2, %for.end.loopexit ] + ret i8 %sum.0.lcssa +} + +; Function Attrs: norecurse nounwind +define i32 @lw_bi_sw_bi() local_unnamed_addr #0 { +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %sum.012 = phi i32 [ 0, %entry ], [ %add, %for.body ] + %i.011 = phi i32 [ 0, %entry ], [ %add3, %for.body ] + %arrayidx = getelementptr inbounds [100 x i32], [100 x i32]* @a, i32 0, i32 %i.011 + %0 = load i32, i32* %arrayidx, align 4 +; CHECK: lw.bi $r17, [$r2], $r3 + %add = add i32 %0, %sum.012 + %arrayidx2 = getelementptr inbounds [100 x i32], [100 x i32]* @a1, i32 0, i32 %i.011 + store i32 %0, i32* %arrayidx2, align 4 +; CHECK: sw.bi $r17, [$r1], $r3 + %add3 = add nuw nsw i32 %i.011, 10000000 + %cmp = icmp slt i32 %add3, 1000000000 + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body + ret i32 %add +} + +; Function Attrs: norecurse nounwind +define zeroext i16 @lh_bi_sh_bi() local_unnamed_addr #0 { +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %sum.014 = phi i32 [ 0, %entry ], [ %add, %for.body ] + %i.013 = phi i32 [ 0, %entry ], [ %add5, %for.body ] + %arrayidx = getelementptr inbounds [100 x i16], [100 x i16]* @b, i32 0, i32 %i.013 + %0 = load i16, i16* %arrayidx, align 2 +; CHECK: lh.bi $r18, [$r2], $r4 + %conv = zext i16 %0 to i32 + %conv1 = and i32 %sum.014, 65535 + %add = add nuw nsw i32 %conv, %conv1 + %arrayidx4 = getelementptr inbounds [100 x i16], [100 x i16]* @b1, i32 0, i32 %i.013 + store i16 %0, i16* %arrayidx4, align 2 +; CHECK: sh.bi $r18, [$r0], $r4 + %add5 = add nuw nsw i32 %i.013, 10000000 + %cmp = icmp slt i32 %add5, 1000000000 + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body + %conv2 = trunc i32 %add to i16 + ret i16 %conv2 +} + +; Function Attrs: norecurse nounwind +define zeroext i8 @lb_bi_sb_bi() local_unnamed_addr #0 { +entry: + br label %for.body + +for.body: ; preds = %for.body, %entry + %sum.015 = phi i32 [ 0, %entry ], [ %add2, %for.body ] + %j.014 = phi i32 [ 0, %entry ], [ %add, %for.body ] + %i.013 = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %add = add nuw nsw i32 %j.014, 1000000 + %arrayidx = getelementptr inbounds [100 x i8], [100 x i8]* @c, i32 0, i32 %add + %0 = load i8, i8* %arrayidx, align 1 +; CHECK: lb.bi $r5, [$r2], $r0 + %conv = zext i8 %0 to i32 + %conv1 = and i32 %sum.015, 255 + %add2 = add nuw nsw i32 %conv, %conv1 + %arrayidx5 = getelementptr inbounds [100 x i8], [100 x i8]* @c1, i32 0, i32 %add + store i8 %0, i8* %arrayidx5, align 1 +; CHECK: sb.bi $r5, [$r1], $r0 + %inc = add nuw nsw i32 %i.013, 1 + %exitcond = icmp eq i32 %inc, 100000000 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + %conv3 = trunc i32 %add2 to i8 + ret i8 %conv3 +}