Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -1275,10 +1275,13 @@ return false; } - static const MCPhysReg GPR32ArgRegs[] = {Mips::A0, Mips::A1, Mips::A2, - Mips::A3}; - static const MCPhysReg FGR32ArgRegs[] = {Mips::F12, Mips::F14}; - static const MCPhysReg AFGR64ArgRegs[] = {Mips::D6, Mips::D7}; + const ArrayRef GPR32ArgRegs = {Mips::A0, Mips::A1, Mips::A2, + Mips::A3}; + const ArrayRef FGR32ArgRegs = {Mips::F12, Mips::F14}; + const ArrayRef AFGR64ArgRegs = {Mips::D6, Mips::D7}; + ArrayRef::iterator NextGPR32 = GPR32ArgRegs.begin(); + ArrayRef::iterator NextFGR32 = FGR32ArgRegs.begin(); + ArrayRef::iterator NextAFGR64 = AFGR64ArgRegs.begin(); struct AllocatedReg { const TargetRegisterClass *RC; @@ -1287,18 +1290,11 @@ : RC(RC), Reg(Reg) {} }; - // Only handle simple cases. i.e. Up to four integer arguments. - // Supporting floating point significantly complicates things so we leave - // that out for now. + // Only handle simple cases. i.e. All arguments are directly mapped to + // registers of the appropriate type. SmallVector Allocation; unsigned Idx = 1; - bool HasAllocatedNonFGR = false; for (const auto &FormalArg : F->args()) { - if (Idx > 4) { - DEBUG(dbgs() << ".. gave up (too many arguments)\n"); - return false; - } - if (F->getAttributes().hasAttribute(Idx, Attribute::InReg) || F->getAttributes().hasAttribute(Idx, Attribute::StructRet) || F->getAttributes().hasAttribute(Idx, Attribute::ByVal)) { @@ -1330,9 +1326,18 @@ DEBUG(dbgs() << ".. .. gave up (i8/i16 arg is not extended)\n"); return false; } - DEBUG(dbgs() << ".. .. GPR32(" << GPR32ArgRegs[Idx - 1] << ")\n"); - Allocation.emplace_back(&Mips::GPR32RegClass, GPR32ArgRegs[Idx - 1]); - HasAllocatedNonFGR = true; + + if (NextGPR32 == GPR32ArgRegs.end()) { + DEBUG(dbgs() << ".. .. gave up (ran out of GPR32 arguments)\n"); + return false; + } + + DEBUG(dbgs() << ".. .. GPR32(" << *NextGPR32 << ")\n"); + Allocation.emplace_back(&Mips::GPR32RegClass, *NextGPR32++); + + // Allocating any GPR32 prohibits further use of floating point arguments. + NextFGR32 = FGR32ArgRegs.end(); + NextAFGR64 = AFGR64ArgRegs.end(); break; case MVT::i32: @@ -1341,29 +1346,50 @@ DEBUG(dbgs() << ".. .. gave up (i32 arg is zero extended)\n"); return false; } - DEBUG(dbgs() << ".. .. GPR32(" << GPR32ArgRegs[Idx - 1] << ")\n"); - Allocation.emplace_back(&Mips::GPR32RegClass, GPR32ArgRegs[Idx - 1]); - HasAllocatedNonFGR = true; + + if (NextGPR32 == GPR32ArgRegs.end()) { + DEBUG(dbgs() << ".. .. gave up (ran out of GPR32 arguments)\n"); + return false; + } + + DEBUG(dbgs() << ".. .. GPR32(" << *NextGPR32 << ")\n"); + Allocation.emplace_back(&Mips::GPR32RegClass, *NextGPR32++); + + // Allocating any GPR32 prohibits further use of floating point arguments. + NextFGR32 = FGR32ArgRegs.end(); + NextAFGR64 = AFGR64ArgRegs.end(); break; case MVT::f32: - if (Idx > 2 || HasAllocatedNonFGR) { - DEBUG(dbgs() << ".. .. gave up (f32 arg needed i32)\n"); + if (NextFGR32 == FGR32ArgRegs.end()) { + DEBUG(dbgs() << ".. .. gave up (ran out of FGR32 arguments)\n"); return false; - } else { - DEBUG(dbgs() << ".. .. FGR32(" << FGR32ArgRegs[Idx - 1] << ")\n"); - Allocation.emplace_back(&Mips::FGR32RegClass, FGR32ArgRegs[Idx - 1]); } + DEBUG(dbgs() << ".. .. FGR32(" << *NextFGR32 << ")\n"); + Allocation.emplace_back(&Mips::FGR32RegClass, *NextFGR32++); + // Allocating an FGR32 also allocates the super-register AFGR64, and + // ABI rules require us to skip the corresponding GPR32. + if (NextGPR32 != GPR32ArgRegs.end()) + NextGPR32++; + if (NextAFGR64 != AFGR64ArgRegs.end()) + NextAFGR64++; break; case MVT::f64: - if (Idx > 2 || HasAllocatedNonFGR) { - DEBUG(dbgs() << ".. .. gave up (f64 arg needed 2xi32)\n"); + if (NextAFGR64 == AFGR64ArgRegs.end()) { + DEBUG(dbgs() << ".. .. gave up (ran out of AFGR64 arguments)\n"); return false; - } else { - DEBUG(dbgs() << ".. .. AFGR64(" << AFGR64ArgRegs[Idx - 1] << ")\n"); - Allocation.emplace_back(&Mips::AFGR64RegClass, AFGR64ArgRegs[Idx - 1]); } + DEBUG(dbgs() << ".. .. AFGR64(" << *NextAFGR64 << ")\n"); + Allocation.emplace_back(&Mips::AFGR64RegClass, *NextAFGR64++); + // Allocating an FGR32 also allocates the super-register AFGR64, and + // ABI rules require us to skip the corresponding GPR32 pair. + if (NextGPR32 != GPR32ArgRegs.end()) + NextGPR32++; + if (NextGPR32 != GPR32ArgRegs.end()) + NextGPR32++; + if (NextFGR32 != FGR32ArgRegs.end()) + NextFGR32++; break; default: Index: test/CodeGen/Mips/Fast-ISel/sel1.ll =================================================================== --- test/CodeGen/Mips/Fast-ISel/sel1.ll +++ test/CodeGen/Mips/Fast-ISel/sel1.ll @@ -80,6 +80,20 @@ ret float %res } +define float @sel_float2(float %k, float %l, i32 %j) { +entry: + ; CHECK-LABEL: sel_float2: + + ; CHECK-DAG: xor $[[T0:[0-9]+]], $6, $zero + ; CHECK: sltu $[[T1:[0-9]+]], $zero, $[[T0]] + ; CHECK-NEXT: andi $[[T2:[0-9]+]], $[[T1]], 1 + ; CHECK: movn.s $f14, $f12, $[[T2]] + ; CHECK: mov.s $f0, $f14 + %cond = icmp ne i32 %j, 0 + %res = select i1 %cond, float %k, float %l + ret float %res +} + define double @sel_double(i32 %j, double %k, double %l) { entry: ; CHECK-LABEL: sel_double: @@ -95,3 +109,18 @@ %res = select i1 %cond, double %k, double %l ret double %res } + +define double @sel_double2(double %k, double %l, i32 %j) { +entry: + ; CHECK-LABEL: sel_double2: + + ; CHECK-DAG: lw $[[SEL:[0-9]+]], 16($sp) + ; CHECK-DAG: xor $[[T0:[0-9]+]], $[[SEL]], $zero + ; CHECK: sltu $[[T1:[0-9]+]], $zero, $[[T0]] + ; CHECK-NEXT: andi $[[T2:[0-9]+]], $[[T1]], 1 + ; CHECK: movn.d $f14, $f12, $[[T2]] + ; CHECK: mov.d $f0, $f14 + %cond = icmp ne i32 %j, 0 + %res = select i1 %cond, double %k, double %l + ret double %res +}