Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -94,6 +94,7 @@ bool selectLoad(const Instruction *I); bool selectStore(const Instruction *I); bool selectBranch(const Instruction *I); + bool selectSelect(const Instruction *I); bool selectCmp(const Instruction *I); bool selectFPExt(const Instruction *I); bool selectFPTrunc(const Instruction *I); @@ -165,6 +166,9 @@ return 0; } + unsigned fastEmitInst_rr(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, unsigned Op0, + bool Op0IsKill, unsigned Op1, bool Op1IsKill); // Call handling routines. private: CCAssignFn *CCAssignFnForCall(CallingConv::ID CC) const; @@ -910,6 +914,59 @@ return true; } +bool MipsFastISel::selectSelect(const Instruction *I) { + assert(isa(I) && "Expected a select instruction."); + MVT VT; + if (!isTypeSupported(I->getType(), VT)) + return false; + + unsigned CondMovOpc; + const TargetRegisterClass *RC; + switch (VT.SimpleTy) { + default: + return false; + case MVT::i1: + case MVT::i8: + case MVT::i16: + case MVT::i32: + CondMovOpc = Mips::MOVN_I_I; + RC = &Mips::GPR32RegClass; + break; + case MVT::f32: + CondMovOpc = Mips::MOVN_I_S; + RC = &Mips::FGR32RegClass; + break; + case MVT::f64: + CondMovOpc = Mips::MOVN_I_D32; + RC = &Mips::AFGR64RegClass; + break; + } + + const SelectInst *SI = cast(I); + const Value *Cond = SI->getCondition(); + (void)Cond; + unsigned Src1Reg = getRegForValue(SI->getTrueValue()); + unsigned Src2Reg = getRegForValue(SI->getFalseValue()); + unsigned CondReg = getRegForValue(Cond); + + if (!Src1Reg || !Src2Reg || !CondReg) + return false; + + unsigned ResultReg = createResultReg(RC); + unsigned TempReg = createResultReg(RC); + + if (!ResultReg || !TempReg) + return false; + emitInst(TargetOpcode::COPY, TempReg).addReg(Src2Reg); + MachineInstrBuilder MI = emitInst(CondMovOpc, ResultReg) + .addReg(Src1Reg) + .addReg(CondReg) + .addReg(TempReg, RegState::Implicit); + MI->tieOperands(0, 3); + updateValueMap(I, ResultReg); + return true; +} + // Attempt to fast-select a floating-point truncate instruction. bool MipsFastISel::selectFPTrunc(const Instruction *I) { if (UnsupportedFPMode) @@ -1567,6 +1624,8 @@ case Instruction::ICmp: case Instruction::FCmp: return selectCmp(I); + case Instruction::Select: + return selectSelect(I); } return false; } @@ -1598,6 +1657,26 @@ return; } +unsigned MipsFastISel::fastEmitInst_rr(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + unsigned Op1, bool Op1IsKill) { + if (MachineInstOpcode == Mips::MUL) { + unsigned ResultReg = createResultReg(RC); + const MCInstrDesc &II = TII.get(MachineInstOpcode); + Op0 = constrainOperandRegClass(II, Op0, II.getNumDefs()); + Op1 = constrainOperandRegClass(II, Op1, II.getNumDefs() + 1); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, ResultReg) + .addReg(Op0, getKillRegState(Op0IsKill)) + .addReg(Op1, getKillRegState(Op1IsKill)) + .addReg(Mips::HI0, RegState::ImplicitDefine | RegState::Dead) + .addReg(Mips::LO0, RegState::ImplicitDefine | RegState::Dead); + return ResultReg; + } + return FastISel::fastEmitInst_rr(MachineInstOpcode, RC, Op0, Op0IsKill, Op1, + Op1IsKill); +} + namespace llvm { FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) { Index: test/CodeGen/Mips/Fast-ISel/mul1.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/mul1.ll @@ -0,0 +1,27 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O2 -mips-fast-isel -fast-isel -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s + +declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32) + +declare void @hoo(i32 signext) + +@j = global i32 0, align 4 +@i = global i32 0, align 4 + +define void @foo() { +entry: +; CHECK: .ent foo +; The test is just to make sure it is able to allocate +; registers for this example. There was an issue with allocating AC0 +; after a mul instruction. +; + %xyzj = load i32* @j + %xyzi = load i32* @i + %mul647 = mul nsw i32 %xyzi, %xyzj + %0 = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %mul647, i32 %xyzi) + %1 = extractvalue { i32, i1 } %0, 0 + call void @hoo(i32 %1) + ret void + +} + Index: test/CodeGen/Mips/Fast-ISel/sel1.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/sel1.ll @@ -0,0 +1,269 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O2 -mips-fast-isel -fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s + +@j = global i32 1, align 4 +@k = global i32 46, align 4 +@l = global i32 49, align 4 +@m = global i32 0, align 4 +@fk = global float 0x4012449BA0000000, align 4 +@fl = global float 0x405ED5C280000000, align 4 +@dk = global double 0x40D6DC4EF9DB22D1, align 8 +@dl = global double 9.991234e+02, align 8 +@i = common global i32 0, align 4 +@ii = common global i32 0, align 4 +@fi = common global float 0.000000e+00, align 4 +@fii = common global float 0.000000e+00, align 4 +@di = common global double 0.000000e+00, align 8 +@dii = common global double 0.000000e+00, align 8 +@.str = private unnamed_addr constant [7 x i8] c"%i %i\0A\00", align 1 +@.str1 = private unnamed_addr constant [7 x i8] c"%f %f\0A\00", align 1 + +; Function Attrs: noinline nounwind +define void @foo() #0 { +entry: +; CHECK: .ent foo + %0 = load i32* @j, align 4, !tbaa !2 + %tobool = icmp ne i32 %0, 0 + %1 = load i32* @k, align 4, !tbaa !2 + %2 = load i32* @l, align 4, !tbaa !2 + %cond = select i1 %tobool, i32 %1, i32 %2 + store i32 %cond, i32* @i, align 4, !tbaa !2 +; CHECK: lui $[[GOT1:[0-9]+]], %hi(_gp_disp) +; CHECK: addiu $[[GOT2:[0-9]+]], $[[GOT1]], %lo(_gp_disp) +; CHECK: addu $[[GOT:[0-9]+]], $[[GOT2:[0-9]+]], $25 +; CHECK-DAG: lw $[[I_ADDR:[0-9]+]], %got(i)($[[GOT]]) +; CHECK-DAG: lw $[[L_ADDR:[0-9]+]], %got(l)($[[GOT]]) +; CHECK-DAG: lw $[[K_ADDR:[0-9]+]], %got(k)($[[GOT]]) +; CHECK-DAG: lw $[[J_ADDR:[0-9]+]], %got(j)($[[GOT]]) +; CHECK-DAG: lw $[[J:[0-9]+]], 0($[[J_ADDR]]) +; CHECK-DAG: xor $[[TMP1:[0-9]+]], $[[J]], $zero +; CHECK-DAG: sltu $[[COND:[0-9]+]], $zero, $[[TMP1]] +; CHECK-DAG: lw $[[K:[0-9]+]], 0($[[K_ADDR]]) +; CHECK-DAG: lw $[[RES:[0-9]+]], 0($[[L_ADDR]]) +; CHECK-DAG: movn $[[RES]], $[[K]], $[[COND]] +; CHECK-DAG: sw $[[RES]], 0($[[I_ADDR]]) + + + ret void +} + +; Function Attrs: noinline nounwind +define void @foo2() #0 { +entry: +; CHECK: .ent foo2 + %0 = load i32* @m, align 4, !tbaa !2 + %tobool = icmp ne i32 %0, 0 + %1 = load i32* @k, align 4, !tbaa !2 + %2 = load i32* @l, align 4, !tbaa !2 + %cond = select i1 %tobool, i32 %1, i32 %2 + store i32 %cond, i32* @ii, align 4, !tbaa !2 +; CHECK: lui $[[GOT1:[0-9]+]], %hi(_gp_disp) +; CHECK: addiu $[[GOT2:[0-9]+]], $[[GOT1]], %lo(_gp_disp) +; CHECK: addu $[[GOT:[0-9]+]], $[[GOT2:[0-9]+]], $25 +; CHECK-DAG: lw $[[II_ADDR:[0-9]+]], %got(ii)($[[GOT]]) +; CHECK-DAG: lw $[[L_ADDR:[0-9]+]], %got(l)($[[GOT]]) +; CHECK-DAG: lw $[[K_ADDR:[0-9]+]], %got(k)($[[GOT]]) +; CHECK-DAG: lw $[[M_ADDR:[0-9]+]], %got(m)($[[GOT]]) +; CHECK-DAG: lw $[[M:[0-9]+]], 0($[[M_ADDR]]) +; CHECK-DAG: xor $[[TMP1:[0-9]+]], $[[M]], $zero +; CHECK-DAG: sltu $[[COND:[0-9]+]], $zero, $[[TMP1]] +; CHECK-DAG: lw $[[K:[0-9]+]], 0($[[K_ADDR]]) +; CHECK-DAG: lw $[[RES:[0-9]+]], 0($[[L_ADDR]]) +; CHECK-DAG: movn $[[RES]], $[[K]], $[[COND]] +; CHECK-DAG: sw $[[RES]], 0($[[II_ADDR]]) + + ret void +} + +; Function Attrs: noinline nounwind +define void @foof() #0 { +entry: +; CHECK: .ent foof + %0 = load i32* @j, align 4, !tbaa !2 + %tobool = icmp ne i32 %0, 0 + %1 = load float* @fk, align 4, !tbaa !6 + %2 = load float* @fl, align 4, !tbaa !6 + %cond = select i1 %tobool, float %1, float %2 + store float %cond, float* @fi, align 4, !tbaa !6 +; CHECK: lui $[[GOT1:[0-9]+]], %hi(_gp_disp) +; CHECK: addiu $[[GOT2:[0-9]+]], $[[GOT1]], %lo(_gp_disp) +; CHECK: addu $[[GOT:[0-9]+]], $[[GOT2:[0-9]+]], $25 +; CHECK-DAG: lw $[[FI_ADDR:[0-9]+]], %got(fi)($[[GOT]]) +; CHECK-DAG: lw $[[FL_ADDR:[0-9]+]], %got(fl)($[[GOT]]) +; CHECK-DAG: lw $[[FK_ADDR:[0-9]+]], %got(fk)($[[GOT]]) +; CHECK-DAG: lw $[[J_ADDR:[0-9]+]], %got(j)($[[GOT]]) +; CHECK-DAG: lw $[[J:[0-9]+]], 0($[[J_ADDR]]) +; CHECK-DAG: xor $[[TMP1:[0-9]+]], $[[J]], $zero +; CHECK-DAG: sltu $[[COND:[0-9]+]], $zero, $[[TMP1]] +; CHECK-DAG: lwc1 $[[FK:f[0-9]+]], 0($[[FK_ADDR]]) +; CHECK-DAG: lwc1 $[[FRES:f[0-9]+]], 0($[[FL_ADDR]]) +; CHECK-DAG: movn.s $[[FRES]], $[[FK]], $1 +; CHECK-DAG: swc1 $[[FRES]], 0($[[FI_ADDR]]) + + ret void +} + +; Function Attrs: noinline nounwind +define void @foof2() #0 { +entry: +; CHECK: .ent foof2 + %0 = load i32* @m, align 4, !tbaa !2 + %tobool = icmp ne i32 %0, 0 + %1 = load float* @fk, align 4, !tbaa !6 + %2 = load float* @fl, align 4, !tbaa !6 + %cond = select i1 %tobool, float %1, float %2 + store float %cond, float* @fii, align 4, !tbaa !6 +; CHECK: lui $[[GOT1:[0-9]+]], %hi(_gp_disp) +; CHECK: addiu $[[GOT2:[0-9]+]], $[[GOT1]], %lo(_gp_disp) +; CHECK: addu $[[GOT:[0-9]+]], $[[GOT2:[0-9]+]], $25 +; CHECK-DAG: lw $[[FII_ADDR:[0-9]+]], %got(fii)($[[GOT]]) +; CHECK-DAG: lw $[[FL_ADDR:[0-9]+]], %got(fl)($[[GOT]]) +; CHECK-DAG: lw $[[FK_ADDR:[0-9]+]], %got(fk)($[[GOT]]) +; CHECK-DAG: lw $[[M_ADDR:[0-9]+]], %got(m)($[[GOT]]) +; CHECK-DAG: lw $[[M:[0-9]+]], 0($[[M_ADDR]]) +; CHECK-DAG: xor $[[TMP1:[0-9]+]], $[[M]], $zero +; CHECK-DAG: sltu $[[COND:[0-9]+]], $zero, $[[TMP1]] +; CHECK-DAG: lwc1 $[[FK:f[0-9]+]], 0($[[FK_ADDR]]) +; CHECK-DAG: lwc1 $[[FRES:f[0-9]+]], 0($[[FL_ADDR]]) +; CHECK-DAG: movn.s $[[FRES]], $[[FK]], $1 +; CHECK-DAG: swc1 $[[FRES]], 0($[[FII_ADDR]]) + ret void +} + +; Function Attrs: noinline nounwind +define void @food() #0 { +entry: +; CHECK: .ent food + %0 = load i32* @j, align 4, !tbaa !2 + %tobool = icmp ne i32 %0, 0 + %1 = load double* @dk, align 8, !tbaa !8 + %2 = load double* @dl, align 8, !tbaa !8 + %cond = select i1 %tobool, double %1, double %2 + store double %cond, double* @di, align 8, !tbaa !8 + ret void +; CHECK: lui $[[GOT1:[0-9]+]], %hi(_gp_disp) +; CHECK: addiu $[[GOT2:[0-9]+]], $[[GOT1]], %lo(_gp_disp) +; CHECK: addu $[[GOT:[0-9]+]], $[[GOT2:[0-9]+]], $25 +; CHECK-DAG: lw $[[DI_ADDR:[0-9]+]], %got(di)($[[GOT]]) +; CHECK-DAG: lw $[[DL_ADDR:[0-9]+]], %got(dl)($[[GOT]]) +; CHECK-DAG: lw $[[DK_ADDR:[0-9]+]], %got(dk)($[[GOT]]) +; CHECK-DAG: lw $[[J_ADDR:[0-9]+]], %got(j)($[[GOT]]) +; CHECK-DAG: lw $[[J:[0-9]+]], 0($[[J_ADDR]]) +; CHECK-DAG: xor $[[TMP1:[0-9]+]], $[[J]], $zero +; CHECK-DAG: sltu $[[COND:[0-9]+]], $zero, $[[TMP1]] +; CHECK-DAG: ldc1 $[[DK:f[0-9]+]], 0($[[DK_ADDR]]) +; CHECK-DAG: ldc1 $[[DRES:f[0-9]+]], 0($[[DL_ADDR]]) +; CHECK-DAG: movn.d $[[DRES]], $[[DK]], $1 +; CHECK-DAG: sdc1 $[[DRES]], 0($[[DI_ADDR]]) + +} + +; Function Attrs: noinline nounwind +define void @food2() #0 { +entry: +; CHECK: .ent food2 + %0 = load i32* @m, align 4, !tbaa !2 + %tobool = icmp ne i32 %0, 0 + %1 = load double* @dk, align 8, !tbaa !8 + %2 = load double* @dl, align 8, !tbaa !8 + %cond = select i1 %tobool, double %1, double %2 + store double %cond, double* @dii, align 8, !tbaa !8 +; CHECK: lui $[[GOT1:[0-9]+]], %hi(_gp_disp) +; CHECK: addiu $[[GOT2:[0-9]+]], $[[GOT1]], %lo(_gp_disp) +; CHECK: addu $[[GOT:[0-9]+]], $[[GOT2:[0-9]+]], $25 +; CHECK-DAG: lw $[[DII_ADDR:[0-9]+]], %got(dii)($[[GOT]]) +; CHECK-DAG: lw $[[DL_ADDR:[0-9]+]], %got(dl)($[[GOT]]) +; CHECK-DAG: lw $[[DK_ADDR:[0-9]+]], %got(dk)($[[GOT]]) +; CHECK-DAG: lw $[[M_ADDR:[0-9]+]], %got(m)($[[GOT]]) +; CHECK-DAG: lw $[[M:[0-9]+]], 0($[[M_ADDR]]) +; CHECK-DAG: xor $[[TMP1:[0-9]+]], $[[M]], $zero +; CHECK-DAG: sltu $[[COND:[0-9]+]], $zero, $[[TMP1]] +; CHECK-DAG: ldc1 $[[DK:f[0-9]+]], 0($[[DK_ADDR]]) +; CHECK-DAG: ldc1 $[[DRES:f[0-9]+]], 0($[[DL_ADDR]]) +; CHECK-DAG: movn.d $[[DRES]], $[[DK]], $1 +; CHECK-DAG: sdc1 $[[DRES]], 0($[[DII_ADDR]]) + ret void +} + +; Function Attrs: nounwind +define i32 @main() #1 { +entry: + tail call void @foo() + tail call void @foof() + tail call void @food() + tail call void @foo2() + tail call void @foof2() + tail call void @food2() + %0 = load i32* @i, align 4, !tbaa !2 + %1 = load i32* @k, align 4, !tbaa !2 + %cmp = icmp eq i32 %0, %1 + br i1 %cmp, label %if.end, label %return + +if.end: ; preds = %entry + %2 = load i32* @ii, align 4, !tbaa !2 + %3 = load i32* @l, align 4, !tbaa !2 + %cmp1 = icmp eq i32 %2, %3 + br i1 %cmp1, label %if.end3, label %return + +if.end3: ; preds = %if.end + %4 = load float* @fi, align 4, !tbaa !6 + %5 = load float* @fk, align 4, !tbaa !6 + %cmp4 = fcmp une float %4, %5 + br i1 %cmp4, label %return, label %if.end6 + +if.end6: ; preds = %if.end3 + %6 = load float* @fii, align 4, !tbaa !6 + %7 = load float* @fl, align 4, !tbaa !6 + %cmp7 = fcmp une float %6, %7 + br i1 %cmp7, label %return, label %if.end9 + +if.end9: ; preds = %if.end6 + %8 = load double* @di, align 8, !tbaa !8 + %9 = load double* @dk, align 8, !tbaa !8 + %cmp10 = fcmp une double %8, %9 + br i1 %cmp10, label %return, label %if.end12 + +if.end12: ; preds = %if.end9 + %10 = load double* @dii, align 8, !tbaa !8 + %11 = load double* @dl, align 8, !tbaa !8 + %cmp13 = fcmp une double %10, %11 + br i1 %cmp13, label %return, label %if.end15 + +if.end15: ; preds = %if.end12 + %call = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([7 x i8]* @.str, i32 0, i32 0), i32 signext %0, i32 signext %2) #2 + %12 = load float* @fi, align 4, !tbaa !6 + %conv = fpext float %12 to double + %13 = load float* @fii, align 4, !tbaa !6 + %conv16 = fpext float %13 to double + %call17 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([7 x i8]* @.str1, i32 0, i32 0), double %conv, double %conv16) #2 + %14 = load double* @di, align 8, !tbaa !8 + %15 = load float* @fii, align 4, !tbaa !6 + %conv18 = fpext float %15 to double + %call19 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([7 x i8]* @.str1, i32 0, i32 0), double %14, double %conv18) #2 + br label %return + +return: ; preds = %if.end12, %if.end9, %if.end6, %if.end3, %if.end, %entry, %if.end15 + %retval.0 = phi i32 [ 0, %if.end15 ], [ 1, %entry ], [ 2, %if.end ], [ 3, %if.end3 ], [ 4, %if.end6 ], [ 5, %if.end9 ], [ 6, %if.end12 ] + ret i32 %retval.0 +} + +; Function Attrs: nounwind +declare i32 @printf(i8* nocapture readonly, ...) #1 + +attributes #0 = { noinline 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 "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 #2 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"PIC Level", i32 2} +!1 = !{!"clang version 3.6.0 (gitosis@dmz-portal.mips.com:clang.git 4c9b4e89d2773b52d0bae2dcb8e87c2fdf0f5e29) (gitosis@dmz-portal.mips.com:llvm.git 903e698ccf2ab6546589d63788bf7fc6d3bbcd5d)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C/C++ TBAA"} +!6 = !{!7, !7, i64 0} +!7 = !{!"float", !4, i64 0} +!8 = !{!9, !9, i64 0} +!9 = !{!"double", !4, i64 0}