Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -4,6 +4,7 @@ #include "llvm/CodeGen/FunctionLoweringInfo.h" #include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/Target/TargetInstrInfo.h" @@ -71,8 +72,19 @@ private: bool EmitStore(MVT VT, unsigned SrcReg, Address &Addr, unsigned Alignment = 0); + + bool EmitLoad(MVT VT, unsigned &ResultReg, Address &Addr, + unsigned Alignment = 0, bool IsZExt = true); + + bool SelectLoad(const Instruction *I); bool SelectRet(const Instruction *I); bool SelectStore(const Instruction *I); + bool SelectIntExt(const Instruction *I); + bool SelectTrunc(const Instruction *I); + bool SelectFPExt(const Instruction *I); + bool SelectFPTrunc(const Instruction *I); + bool SelectFPToI(const Instruction *I, bool IsSigned); + bool SelectCmp(const Instruction *I); bool isTypeLegal(Type *Ty, MVT &VT); bool isLoadTypeLegal(Type *Ty, MVT &VT); @@ -82,6 +94,10 @@ unsigned MaterializeInt(const Constant *C, MVT VT); unsigned Materialize32BitInt(int64_t Imm, const TargetRegisterClass *RC); + bool EmitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg); + + bool EmitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg); + // for some reason, this default is not generated by tablegen // so we explicitly generate it here. // @@ -105,6 +121,11 @@ return EmitInst(Opc).addReg(SrcReg).addReg(MemReg).addImm(MemOffset); } + MachineInstrBuilder EmitInstLoadMem(unsigned Opc, unsigned DstReg, + unsigned MemReg, int64_t MemOffset) { + return EmitInst(Opc, DstReg).addReg(MemReg).addImm(MemOffset); + } + #include "MipsGenFastISel.inc" }; @@ -126,6 +147,8 @@ // We will extend this in a later patch: // If this is a type than can be sign or zero-extended to a basic operation // go ahead and accept it now. + if (VT == MVT::i8 || VT == MVT::i16) + return true; return false; } @@ -162,19 +185,133 @@ return 0; } +bool MipsFastISel::EmitLoad(MVT VT, unsigned &ResultReg, Address &Addr, + unsigned Alignment, bool IsZExt) { + // + // more cases will be handled here in following patches. + // + if (!IsZExt) + return false; // this is not needed yet. + unsigned Opc; + switch (VT.SimpleTy) { + case MVT::i32: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LW; + break; + } + case MVT::i16: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LH; + break; + } + case MVT::i8: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LB; + break; + } + case MVT::f32: { + ResultReg = createResultReg(&Mips::FGR32RegClass); + Opc = Mips::LWC1; + break; + } + case MVT::f64: { + ResultReg = createResultReg(&Mips::FGR32RegClass); + Opc = Mips::LDC1; + break; + } + default: + return false; + } + EmitInstLoadMem(Opc, ResultReg, Addr.Base.Reg, Addr.Offset); + return true; +} + bool MipsFastISel::EmitStore(MVT VT, unsigned SrcReg, Address &Addr, unsigned Alignment) { // // more cases will be handled here in following patches. // - if (VT == MVT::i32) - EmitInstStore(Mips::SW, SrcReg, Addr.Base.Reg, Addr.Offset); - else if (VT == MVT::f32) - EmitInstStore(Mips::SWC1, SrcReg, Addr.Base.Reg, Addr.Offset); - else if (VT == MVT::f64) - EmitInstStore(Mips::SDC1, SrcReg, Addr.Base.Reg, Addr.Offset); - else + unsigned Opc; + switch (VT.SimpleTy) { + case MVT::i8: + Opc = Mips::SB; + break; + case MVT::i16: + Opc = Mips::SH; + break; + case MVT::i32: + Opc = Mips::SW; + break; + case MVT::f32: + Opc = Mips::SWC1; + break; + case MVT::f64: + Opc = Mips::SDC1; + break; + default: return false; + } + EmitInstStore(Opc, SrcReg, Addr.Base.Reg, Addr.Offset); + return true; +} + +// Attempt to emit an integer extend of SrcReg into DestReg. Both +// signed and zero extensions are supported. Return false if we +// can't handle it. +bool MipsFastISel::EmitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + if ((DestVT != MVT::i32) && (DestVT != MVT::i16)) + return false; + switch (SrcVT.SimpleTy) { + default: + return false; + case MVT::i8: + EmitInst(Mips::SEB, DestReg).addReg(SrcReg); + break; + case MVT::i16: + EmitInst(Mips::SEH, DestReg).addReg(SrcReg); + break; + } + return true; +} + +bool MipsFastISel::EmitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + switch (SrcVT.SimpleTy) { + default: + return false; + case MVT::i1: + EmitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(1); + break; + case MVT::i8: + EmitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(0xff); + break; + case MVT::i16: + EmitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(0xffff); + break; + } + return true; +} + +bool MipsFastISel::SelectLoad(const Instruction *I) { + // Atomic loads need special handling. + if (cast(I)->isAtomic()) + return false; + + // Verify we have a legal type before going any further. + MVT VT; + if (!isLoadTypeLegal(I->getType(), VT)) + return false; + + // See if we can handle this address. + Address Addr; + if (!ComputeAddress(I->getOperand(0), Addr)) + return false; + + unsigned ResultReg; + if (!EmitLoad(VT, ResultReg, Addr, cast(I)->getAlignment())) + return false; + UpdateValueMap(I, ResultReg); return true; } @@ -218,16 +355,278 @@ return true; } +// Attempt to fast-select a floating-point extend instruction. +bool MipsFastISel::SelectFPExt(const Instruction *I) { + Value *Src = I->getOperand(0); + EVT SrcVT = TLI.getValueType(Src->getType(), true); + EVT DestVT = TLI.getValueType(I->getType(), true); + + if (SrcVT != MVT::f32 || DestVT != MVT::f64) + return false; + + unsigned SrcReg = + getRegForValue(Src); // his must be a 32 bit floating point register class + // maybe we should handle this differently + if (!SrcReg) + return false; + + unsigned DestReg = createResultReg(&Mips::AFGR64RegClass); + EmitInst(Mips::CVT_D_S_MM, DestReg).addReg(SrcReg); + UpdateValueMap(I, DestReg); + return true; +} + +// Attempt to fast-select a floating-point truncate instruction. +bool MipsFastISel::SelectFPTrunc(const Instruction *I) { + Value *Src = I->getOperand(0); + EVT SrcVT = TLI.getValueType(Src->getType(), true); + EVT DestVT = TLI.getValueType(I->getType(), true); + + if (SrcVT != MVT::f64 || DestVT != MVT::f32) + return false; + + unsigned SrcReg = + getRegForValue(Src); // his must be a 32 bit floating point register class + // maybe we should handle this differently + if (!SrcReg) + return false; + + unsigned DestReg = createResultReg(&Mips::FGR32RegClass); + EmitInst(Mips::CVT_S_D32, DestReg).addReg(SrcReg); + UpdateValueMap(I, DestReg); + return true; +} + +bool MipsFastISel::SelectIntExt(const Instruction *I) { + // On ARM, in general, integer casts don't involve legal types; this code + // handles promotable integers. + Type *DestTy = I->getType(); + Value *Src = I->getOperand(0); + Type *SrcTy = Src->getType(); + + bool isZExt = isa(I); + unsigned SrcReg = getRegForValue(Src); + if (!SrcReg) + return false; + + EVT SrcEVT, DestEVT; + SrcEVT = TLI.getValueType(SrcTy, true); + DestEVT = TLI.getValueType(DestTy, true); + if (!SrcEVT.isSimple()) + return false; + if (!DestEVT.isSimple()) + return false; + + MVT SrcVT = SrcEVT.getSimpleVT(); + MVT DestVT = DestEVT.getSimpleVT(); + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + + if (isZExt) { + if (!EmitIntZExt(SrcVT, SrcReg, DestVT, ResultReg)) + return false; + } else { + if (!EmitIntSExt(SrcVT, SrcReg, DestVT, ResultReg)) + return false; + } + UpdateValueMap(I, ResultReg); + return true; +} + +bool MipsFastISel::SelectTrunc(const Instruction *I) { + // The high bits for a type smaller than the register size are assumed to be + // undefined. + Value *Op = I->getOperand(0); + + EVT SrcVT, DestVT; + SrcVT = TLI.getValueType(Op->getType(), true); + DestVT = TLI.getValueType(I->getType(), true); + + if (SrcVT != MVT::i32 && SrcVT != MVT::i16 && SrcVT != MVT::i8) + return false; + if (DestVT != MVT::i16 && DestVT != MVT::i8 && DestVT != MVT::i1) + return false; + + unsigned SrcReg = getRegForValue(Op); + if (!SrcReg) + return false; + + // Because the high bits are undefined, a truncate doesn't generate + // any code. + UpdateValueMap(I, SrcReg); + return true; +} + +// Attempt to fast-select a floating-point-to-integer conversion. +bool MipsFastISel::SelectFPToI(const Instruction *I, bool IsSigned) { + MVT DstVT, SrcVT; + if (!IsSigned) + return false; // we don't handle this case yet. there is no native + // instruction for this but it can be synthesized. + Type *DstTy = I->getType(); + if (!isTypeLegal(DstTy, DstVT)) + return false; + + if (DstVT != MVT::i32) + return false; + + Value *Src = I->getOperand(0); + Type *SrcTy = Src->getType(); + if (!isTypeLegal(SrcTy, SrcVT)) + return false; + + if (SrcVT != MVT::f32 && SrcVT != MVT::f64) + return false; + + unsigned SrcReg = getRegForValue(Src); + if (SrcReg == 0) + return false; + + // Determine the opcode for the conversion, which takes place + // entirely within FPRs. + unsigned DestReg = createResultReg(&Mips::GPR32RegClass); + unsigned TempReg = createResultReg(&Mips::FGR32RegClass); + unsigned Opc; + + if (SrcVT == MVT::f32) + Opc = Mips::TRUNC_W_S; + else + Opc = Mips::TRUNC_W_D32; + + // Generate the convert. + EmitInst(Opc, TempReg).addReg(SrcReg); + + EmitInst(Mips::MFC1, DestReg).addReg(TempReg); + + UpdateValueMap(I, DestReg); + return true; +} + +bool MipsFastISel::SelectCmp(const Instruction *I) { + const CmpInst *CI = cast(I); + const Value *Left = I->getOperand(0), *Right = I->getOperand(1); + unsigned LeftReg = getRegForValue(Left); + unsigned RightReg = getRegForValue(Right); + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + switch (CI->getPredicate()) { + default: + return false; + case CmpInst::ICMP_EQ: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + EmitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg); + EmitInst(Mips::SLTu, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::ICMP_NE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + EmitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg); + EmitInst(Mips::SLTu, ResultReg).addReg(Mips::ZERO).addReg(TempReg); + break; + } + case CmpInst::ICMP_UGT: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + EmitInst(Mips::SLTu, TempReg).addReg(RightReg).addReg(LeftReg); + EmitInst(Mips::ANDi, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::ICMP_ULT: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + EmitInst(Mips::SLTu, TempReg).addReg(LeftReg).addReg(RightReg); + EmitInst(Mips::ANDi, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::ICMP_UGE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + unsigned TempReg2 = createResultReg(&Mips::GPR32RegClass); + EmitInst(Mips::SLTu, TempReg).addReg(LeftReg).addReg(RightReg); + EmitInst(Mips::XORi, TempReg2).addReg(TempReg).addImm(1); + EmitInst(Mips::ANDi, ResultReg).addReg(TempReg2).addImm(1); + break; + } + case CmpInst::ICMP_ULE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + unsigned TempReg2 = createResultReg(&Mips::GPR32RegClass); + EmitInst(Mips::SLTu, TempReg).addReg(RightReg).addReg(LeftReg); + EmitInst(Mips::XORi, TempReg2).addReg(TempReg).addImm(1); + EmitInst(Mips::ANDi, ResultReg).addReg(TempReg2).addImm(1); + break; + } + case CmpInst::ICMP_SGT: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + EmitInst(Mips::SLT, TempReg).addReg(RightReg).addReg(LeftReg); + EmitInst(Mips::ANDi, ResultReg).addReg(TempReg).addImm(1); + break; + } break; + case CmpInst::ICMP_SLT: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + EmitInst(Mips::SLT, TempReg).addReg(LeftReg).addReg(RightReg); + EmitInst(Mips::ANDi, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::ICMP_SGE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + unsigned TempReg2 = createResultReg(&Mips::GPR32RegClass); + EmitInst(Mips::SLT, TempReg).addReg(LeftReg).addReg(RightReg); + EmitInst(Mips::XORi, TempReg2).addReg(TempReg).addImm(1); + EmitInst(Mips::ANDi, ResultReg).addReg(TempReg2).addImm(1); + break; + } + case CmpInst::ICMP_SLE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + unsigned TempReg2 = createResultReg(&Mips::GPR32RegClass); + EmitInst(Mips::SLT, TempReg).addReg(RightReg).addReg(LeftReg); + EmitInst(Mips::XORi, TempReg2).addReg(TempReg).addImm(1); + EmitInst(Mips::ANDi, ResultReg).addReg(TempReg2).addImm(1); + break; + } + case CmpInst::FCMP_OEQ: + case CmpInst::FCMP_ONE: + case CmpInst::FCMP_OGT: + case CmpInst::FCMP_OLT: + case CmpInst::FCMP_OLE: + case CmpInst::FCMP_UEQ: + case CmpInst::FCMP_UNE: + case CmpInst::FCMP_UGT: + case CmpInst::FCMP_ULT: + case CmpInst::FCMP_UGE: + case CmpInst::FCMP_ULE: + case CmpInst::FCMP_ORD: + case CmpInst::FCMP_UNO: + case CmpInst::FCMP_TRUE: + case CmpInst::FCMP_FALSE: + return false; + } + UpdateValueMap(I, ResultReg); + return true; +} + bool MipsFastISel::TargetSelectInstruction(const Instruction *I) { if (!TargetSupported) return false; switch (I->getOpcode()) { default: break; + case Instruction::Load: + return SelectLoad(I); case Instruction::Store: return SelectStore(I); case Instruction::Ret: return SelectRet(I); + case Instruction::Trunc: + return SelectTrunc(I); + case Instruction::ZExt: + case Instruction::SExt: + return SelectIntExt(I); + case Instruction::FPTrunc: + return SelectFPTrunc(I); + case Instruction::FPExt: + return SelectFPExt(I); + case Instruction::FPToSI: + return SelectFPToI(I, /*isSigned*/ true); + case Instruction::FPToUI: + return SelectFPToI(I, /*isSigned*/ false); + case Instruction::ICmp: + case Instruction::FCmp: + return SelectCmp(I); } return false; } Index: test/CodeGen/Mips/Fast-ISel/fpext.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/fpext.ll @@ -0,0 +1,21 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s + +@f = global float 0x40147E6B80000000, align 4 +@d_f = common global double 0.000000e+00, align 8 +@.str = private unnamed_addr constant [6 x i8] c"%f \0A\00", align 1 + +; Function Attrs: nounwind +define void @dv() #0 { +entry: + %0 = load float* @f, align 4 + %conv = fpext float %0 to double +; CHECK: cvt.d.s $f{{[0-9]+}}, $f{{[0-9]+}} + store double %conv, double* @d_f, align 8 + ret void +} + + +attributes #1 = { nounwind } + + Index: test/CodeGen/Mips/Fast-ISel/fpintconv.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/fpintconv.ll @@ -0,0 +1,63 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s + + +@f = global float 0x40D6E83280000000, align 4 +@d = global double 0x4132D68780000000, align 8 +@i_f = common global i32 0, align 4 +@i_d = common global i32 0, align 4 +@.str = private unnamed_addr constant [5 x i8] c"%i \0A\00", align 1 + +; Function Attrs: nounwind +define void @ifv() #0 { +entry: +; CHECK: .ent ifv + %0 = load float* @f, align 4, !tbaa !1 + %conv = fptosi float %0 to i32 +; CHECK: trunc.w.s $f{{[0-9]+}}, $f{{[0-9]+}} + store i32 %conv, i32* @i_f, align 4, !tbaa !5 + ret void +} + +; Function Attrs: nounwind +define void @idv() #0 { +entry: +; CHECK: .ent idv + %0 = load double* @d, align 8, !tbaa !7 + %conv = fptosi double %0 to i32 +; CHECK: trunc.w.d $f{{[0-9]+}}, $f{{[0-9]+}} + store i32 %conv, i32* @i_d, align 4, !tbaa !5 + ret void +} + +; Function Attrs: nounwind +define i32 @main() #0 { +entry: + %0 = load float* @f, align 4, !tbaa !1 + %conv.i = fptosi float %0 to i32 + store i32 %conv.i, i32* @i_f, align 4, !tbaa !5 + %call = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), i32 %conv.i) #1 + %1 = load double* @d, align 8, !tbaa !7 + %conv.i2 = fptosi double %1 to i32 + store i32 %conv.i2, i32* @i_d, align 4, !tbaa !5 + %call1 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), i32 %conv.i2) #1 + ret i32 0 +} + +; Function Attrs: nounwind +declare i32 @printf(i8* nocapture readonly, ...) #0 + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind } + +!llvm.ident = !{!0} + +!0 = metadata !{metadata !"clang version 3.5.0 (gitosis@dmz-portal.mips.com:clang.git f4545688eab4ddb6fb4dabe43d9d00f9d7db9602) (gitosis@dmz-portal.mips.com:llvm.git fe236d3fc6882ea8f4bfebdfee82766b0356506c)"} +!1 = metadata !{metadata !2, metadata !2, i64 0} +!2 = metadata !{metadata !"float", metadata !3, i64 0} +!3 = metadata !{metadata !"omnipotent char", metadata !4, i64 0} +!4 = metadata !{metadata !"Simple C/C++ TBAA"} +!5 = metadata !{metadata !6, metadata !6, i64 0} +!6 = metadata !{metadata !"int", metadata !3, i64 0} +!7 = metadata !{metadata !8, metadata !8, i64 0} +!8 = metadata !{metadata !"double", metadata !3, i64 0} Index: test/CodeGen/Mips/Fast-ISel/fptrunc.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/fptrunc.ll @@ -0,0 +1,20 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s + +@d = global double 0x40147E6B74DF0446, align 8 +@f = common global float 0.000000e+00, align 4 +@.str = private unnamed_addr constant [6 x i8] c"%f \0A\00", align 1 + +; Function Attrs: nounwind +define void @fv() #0 { +entry: + %0 = load double* @d, align 8 + %conv = fptrunc double %0 to float +; CHECK: cvt.s.d $f{{[0-9]+}}, $f{{[0-9]+}} + store float %conv, float* @f, align 4 + ret void +} + +attributes #1 = { nounwind } + + Index: test/CodeGen/Mips/Fast-ISel/icmpa.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/icmpa.ll @@ -0,0 +1,162 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s + +@c = global i32 4, align 4 +@d = global i32 9, align 4 +@uc = global i32 4, align 4 +@ud = global i32 9, align 4 +@b1 = common global i32 0, align 4 + +; Function Attrs: nounwind +define void @eq() #0 { +entry: +; CHECK: .ent eq + + %0 = load i32* @c, align 4 + %1 = load i32* @d, align 4 + %cmp = icmp eq i32 %0, %1 + %conv = zext i1 %cmp to i32 +; CHECK: xor ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; CHECK: sltu ${{[0-9]+}}, ${{[0-9]+}}, 1 +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 + + store i32 %conv, i32* @b1, align 4 + ret void +} + +; Function Attrs: nounwind +define void @ne() #0 { +entry: +; CHECK: .ent ne + %0 = load i32* @c, align 4 + %1 = load i32* @d, align 4 + %cmp = icmp ne i32 %0, %1 + %conv = zext i1 %cmp to i32 +; CHECK: xor ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; CHECK: sltu ${{[0-9]+}}, $zero, ${{[0-9]+}} +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 + + store i32 %conv, i32* @b1, align 4 + ret void +} + +; Function Attrs: nounwind +define void @ugt() #0 { +entry: +; CHECK: .ent ugt + %0 = load i32* @uc, align 4 + %1 = load i32* @ud, align 4 + %cmp = icmp ugt i32 %0, %1 + %conv = zext i1 %cmp to i32 +; CHECK: sltu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 + + store i32 %conv, i32* @b1, align 4 + ret void +} + +; Function Attrs: nounwind +define void @ult() #0 { +entry: +; CHECK: .ent ult + %0 = load i32* @uc, align 4 + %1 = load i32* @ud, align 4 + %cmp = icmp ult i32 %0, %1 + %conv = zext i1 %cmp to i32 +; CHECK: sltu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 + store i32 %conv, i32* @b1, align 4 + ret void +} + +; Function Attrs: nounwind +define void @uge() #0 { +entry: +; CHECK: .ent uge + %0 = load i32* @uc, align 4 + %1 = load i32* @ud, align 4 + %cmp = icmp uge i32 %0, %1 + %conv = zext i1 %cmp to i32 +; CHECK: sltu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; CHECK: xori ${{[0-9]+}}, ${{[0-9]+}}, 1 +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 + store i32 %conv, i32* @b1, align 4 + ret void +} + +; Function Attrs: nounwind +define void @ule() #0 { +entry: +; CHECK: .ent ule + %0 = load i32* @uc, align 4 + %1 = load i32* @ud, align 4 + %cmp = icmp ule i32 %0, %1 + %conv = zext i1 %cmp to i32 +; CHECK: sltu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; CHECK: xori ${{[0-9]+}}, ${{[0-9]+}}, 1 +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 + store i32 %conv, i32* @b1, align 4 + ret void +} + +; Function Attrs: nounwind +define void @sgt() #0 { +entry: +; CHECK: .ent sgt + %0 = load i32* @c, align 4 + %1 = load i32* @d, align 4 + %cmp = icmp sgt i32 %0, %1 + %conv = zext i1 %cmp to i32 +; CHECK: slt ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 + store i32 %conv, i32* @b1, align 4 + ret void +} + +; Function Attrs: nounwind +define void @slt() #0 { +entry: +; CHECK: .ent slt + %0 = load i32* @c, align 4 + %1 = load i32* @d, align 4 + %cmp = icmp slt i32 %0, %1 + %conv = zext i1 %cmp to i32 +; CHECK: slt ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 + store i32 %conv, i32* @b1, align 4 + ret void +} + +; Function Attrs: nounwind +define void @sge() #0 { +entry: +; CHECK: .ent sge + %0 = load i32* @c, align 4 + %1 = load i32* @d, align 4 + %cmp = icmp sge i32 %0, %1 + %conv = zext i1 %cmp to i32 + store i32 %conv, i32* @b1, align 4 +; CHECK: slt ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; CHECK: xori ${{[0-9]+}}, ${{[0-9]+}}, 1 +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 + ret void +} + +; Function Attrs: nounwind +define void @sle() #0 { +entry: +; CHECK: .ent sle + %0 = load i32* @c, align 4 + %1 = load i32* @d, align 4 + %cmp = icmp sle i32 %0, %1 + %conv = zext i1 %cmp to i32 +; CHECK: slt ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; CHECK: xori ${{[0-9]+}}, ${{[0-9]+}}, 1 +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 + store i32 %conv, i32* @b1, align 4 + ret void +} + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + + Index: test/CodeGen/Mips/Fast-ISel/loadstore2.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/loadstore2.ll @@ -0,0 +1,84 @@ +; ModuleID = 'loadstore2.c' +target datalayout = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64" +target triple = "mips--linux-gnu" + +@c2 = common global i8 0, align 1 +@c1 = common global i8 0, align 1 +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s + +@s2 = common global i16 0, align 2 +@s1 = common global i16 0, align 2 +@i2 = common global i32 0, align 4 +@i1 = common global i32 0, align 4 +@f2 = common global float 0.000000e+00, align 4 +@f1 = common global float 0.000000e+00, align 4 +@d2 = common global double 0.000000e+00, align 8 +@d1 = common global double 0.000000e+00, align 8 + +; Function Attrs: nounwind +define void @cfoo() #0 { +entry: + %0 = load i8* @c2, align 1 + store i8 %0, i8* @c1, align 1 +; CHECK: .ent cfoo +; CHECK: lb ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: sb ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: .end cfoo + + ret void +} + +; Function Attrs: nounwind +define void @sfoo() #0 { +entry: + %0 = load i16* @s2, align 2 + store i16 %0, i16* @s1, align 2 +; CHECK: .ent sfoo +; CHECK: lh ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: sh ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: .end sfoo + ret void +} + +; Function Attrs: nounwind +define void @ifoo() #0 { +entry: + %0 = load i32* @i2, align 4 + store i32 %0, i32* @i1, align 4 +; CHECK: .ent ifoo +; CHECK: lw ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: sw ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: .end ifoo + + ret void +} + +; Function Attrs: nounwind +define void @ffoo() #0 { +entry: + %0 = load float* @f2, align 4 + store float %0, float* @f1, align 4 +; CHECK: .ent ffoo +; CHECK: lwc1 $f{{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: swc1 $f{{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: .end ffoo + + ret void +} + +; Function Attrs: nounwind +define void @dfoo() #0 { +entry: + %0 = load double* @d2, align 8 + store double %0, double* @d1, align 8 +; CHECK: .ent dfoo +; CHECK: ldc1 $f{{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: sdc1 $f{{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: .end dfoo + ret void +} + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + + Index: test/CodeGen/Mips/Fast-ISel/loadstoreconv.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/loadstoreconv.ll @@ -0,0 +1,166 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s + +@b2 = global i8 0, align 1 +@b1 = global i8 1, align 1 +@uc1 = global i8 0, align 1 +@uc2 = global i8 -1, align 1 +@sc1 = global i8 -128, align 1 +@sc2 = global i8 127, align 1 +@ss1 = global i16 -32768, align 2 +@ss2 = global i16 32767, align 2 +@us1 = global i16 0, align 2 +@us2 = global i16 -1, align 2 +@ssi = global i16 0, align 2 +@ssj = global i16 0, align 2 +@i = global i32 0, align 4 +@j = global i32 0, align 4 +@.str = private unnamed_addr constant [4 x i8] c"%i\0A\00", align 1 +@.str1 = private unnamed_addr constant [7 x i8] c"%i %i\0A\00", align 1 + +; Function Attrs: nounwind +define void @_Z3b_iv() #0 { +entry: +; CHECK: .ent _Z3b_iv + %0 = load i8* @b1, align 1 + %tobool = trunc i8 %0 to i1 + %frombool = zext i1 %tobool to i8 + store i8 %frombool, i8* @b2, align 1 + %1 = load i8* @b2, align 1 + %tobool1 = trunc i8 %1 to i1 + %conv = zext i1 %tobool1 to i32 + store i32 %conv, i32* @i, align 4 +; CHECK: lb ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 +; CHECK: sb ${{[0-9]+}}, 0(${{[0-9]+}}) + + + + ret void +; CHECK: .end _Z3b_iv +} + +; Function Attrs: nounwind +define void @_Z4uc_iv() #0 { +entry: +; CHECK: .ent _Z4uc_iv + + %0 = load i8* @uc1, align 1 + %conv = zext i8 %0 to i32 + store i32 %conv, i32* @i, align 4 + %1 = load i8* @uc2, align 1 + %conv1 = zext i8 %1 to i32 +; CHECK: lb ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 255 + + store i32 %conv1, i32* @j, align 4 + ret void +; CHECK: .end _Z4uc_iv + +} + +; Function Attrs: nounwind +define void @_Z4sc_iv() #0 { +entry: +; CHECK: .ent _Z4sc_iv + + %0 = load i8* @sc1, align 1 + %conv = sext i8 %0 to i32 + store i32 %conv, i32* @i, align 4 + %1 = load i8* @sc2, align 1 + %conv1 = sext i8 %1 to i32 + store i32 %conv1, i32* @j, align 4 +; CHECK: lb ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: seb ${{[0-9]+}}, ${{[0-9]+}} + + ret void +; CHECK: .end _Z4sc_iv +} + +; Function Attrs: nounwind +define void @_Z4us_iv() #0 { +entry: +; CHECK: .ent _Z4us_iv + %0 = load i16* @us1, align 2 + %conv = zext i16 %0 to i32 + store i32 %conv, i32* @i, align 4 + %1 = load i16* @us2, align 2 + %conv1 = zext i16 %1 to i32 + store i32 %conv1, i32* @j, align 4 + ret void +; CHECK: lh ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 65535 +; CHECK: .end _Z4us_iv +} + +; Function Attrs: nounwind +define void @_Z4ss_iv() #0 { +entry: +; CHECK: .ent _Z4ss_iv + + %0 = load i16* @ss1, align 2 + %conv = sext i16 %0 to i32 + store i32 %conv, i32* @i, align 4 + %1 = load i16* @ss2, align 2 + %conv1 = sext i16 %1 to i32 + store i32 %conv1, i32* @j, align 4 +; CHECK: lh ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: seh ${{[0-9]+}}, ${{[0-9]+}} + + ret void +; CHECK: .end _Z4ss_iv +} + +; Function Attrs: nounwind +define void @_Z4b_ssv() #0 { +entry: +; CHECK: .ent _Z4b_ssv + %0 = load i8* @b2, align 1 + %tobool = trunc i8 %0 to i1 + %conv = zext i1 %tobool to i16 + store i16 %conv, i16* @ssi, align 2 + ret void +; CHECK: lb ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 1 +; CHECK: .end _Z4b_ssv +} + +; Function Attrs: nounwind +define void @_Z5uc_ssv() #0 { +entry: +; CHECK: .ent _Z5uc_ssv + %0 = load i8* @uc1, align 1 + %conv = zext i8 %0 to i16 + store i16 %conv, i16* @ssi, align 2 + %1 = load i8* @uc2, align 1 + %conv1 = zext i8 %1 to i16 +; CHECK: lb ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: andi ${{[0-9]+}}, ${{[0-9]+}}, 255 + + store i16 %conv1, i16* @ssj, align 2 + ret void +; CHECK: .end _Z5uc_ssv +} + +; Function Attrs: nounwind +define void @_Z5sc_ssv() #0 { +entry: +; CHECK: .ent _Z5sc_ssv + %0 = load i8* @sc1, align 1 + %conv = sext i8 %0 to i16 + store i16 %conv, i16* @ssi, align 2 + %1 = load i8* @sc2, align 1 + %conv1 = sext i8 %1 to i16 + store i16 %conv1, i16* @ssj, align 2 +; CHECK: lb ${{[0-9]+}}, 0(${{[0-9]+}}) +; CHECK: seb ${{[0-9]+}}, ${{[0-9]+}} + + ret void +; CHECK: .end _Z5sc_ssv +} + +declare i32 @printf(i8*, ...) #1 + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +