From 30b5412d92e7202566bfa039f81344a3638d25c6 Mon Sep 17 00:00:00 2001 From: Vasileios Kalintiris Date: Mon, 1 Jun 2015 15:48:09 +0000 Subject: [PATCH] [mips][FastISel] Clobber HI0/LO0 registers in MUL instructions. Summary: The contents of the HI/LO registers are unpredictable after the execution of the MUL instruction. In addition to implicitly defining these registers in the MUL instruction definition, we have to mark those registers as dead too. Without this the fast register allocator is running out of registers when the MUL instruction is followed by another one that tries to allocate the AC0 register. Based on a patch by Reed Kotler. Reviewers: dsanders, rkotler Subscribers: llvm-commits, rfuhler Differential Revision: http://reviews.llvm.org/D9825 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238755 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Mips/MipsFastISel.cpp | 33 +++++++++++++++++++++++++++++ test/CodeGen/Mips/Fast-ISel/mul1.ll | 18 ++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 test/CodeGen/Mips/Fast-ISel/mul1.ll diff --git a/lib/Target/Mips/MipsFastISel.cpp b/lib/Target/Mips/MipsFastISel.cpp index 4faee10744b..17d9f86808f 100644 --- a/lib/Target/Mips/MipsFastISel.cpp +++ b/lib/Target/Mips/MipsFastISel.cpp @@ -156,6 +156,12 @@ private: unsigned MemReg, int64_t MemOffset) { return emitInst(Opc, DstReg).addReg(MemReg).addImm(MemOffset); } + + unsigned fastEmitInst_rr(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + unsigned Op1, bool Op1IsKill); + // for some reason, this default is not generated by tablegen // so we explicitly generate it here. // @@ -1563,6 +1569,33 @@ void MipsFastISel::simplifyAddress(Address &Addr) { } } +unsigned MipsFastISel::fastEmitInst_rr(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + unsigned Op1, bool Op1IsKill) { + // We treat the MUL instruction in a special way because it clobbers + // the HI0 & LO0 registers. The TableGen definition of this instruction can + // mark these registers only as implicitly defined. As a result, the + // register allocator runs out of registers when this instruction is + // followed by another instruction that defines the same registers too. + // We can fix this by explicitly marking those registers as dead. + 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) { diff --git a/test/CodeGen/Mips/Fast-ISel/mul1.ll b/test/CodeGen/Mips/Fast-ISel/mul1.ll new file mode 100644 index 00000000000..0ee044bea0a --- /dev/null +++ b/test/CodeGen/Mips/Fast-ISel/mul1.ll @@ -0,0 +1,18 @@ +; RUN: llc < %s -march=mipsel -mcpu=mips32 -O0 \ +; RUN: -fast-isel -mips-fast-isel -relocation-model=pic +; RUN: llc < %s -march=mipsel -mcpu=mips32r2 -O0 \ +; RUN: -fast-isel -mips-fast-isel -relocation-model=pic + +; 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. + +declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32) + +define i32 @foo(i32 %a, i32 %b) { +entry: + %0 = mul i32 %a, %b + %1 = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %0, i32 %b) + %2 = extractvalue { i32, i1 } %1, 0 + ret i32 %2 +}