[llvm] r174696 - When Mips16 frames grow large, the immediate field may exceed the maximum
Reed Kotler
rkotler at mips.com
Fri Feb 8 04:43:33 PST 2013
On 02/07/2013 10:46 PM, Hal Finkel wrote:
> ----- Original Message -----
>> From: "Reed Kotler" <rkotler at mips.com>
>> To: llvm-commits at cs.uiuc.edu
>> Sent: Thursday, February 7, 2013 9:57:41 PM
>> Subject: [llvm] r174696 - When Mips16 frames grow large, the immediate field may exceed the maximum
>>
>> Author: rkotler
>> Date: Thu Feb 7 21:57:41 2013
>> New Revision: 174696
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=174696&view=rev
>> Log:
>> When Mips16 frames grow large, the immediate field may exceed the
>> maximum
>> allowed size for the instruction. This code uses RegScavenger to fix
>> this.
>> We sometimes need 2 registers for Mips16 so we must handle things
>> differently than how register scavenger is normally used.
> Normally the reason that you can't get more than one register from the scavenger is that there is only one emergency spill slot. In your case, you're getting around this problem by not using the spill slot at all and simply "spilling" to other reserved registers?
>
> -Hal
Exactly. Mips16 is a processor mode which is using a different
instruction decoder in order to save space.
The full set of Mips32 (or Mips64) registers are available but only in a
limited way when in Mips16 mode.
There are only 8 registers which can be accessed as general registers so
there are many additional registers which would be free, if the
processor were in mips32 mode.
At the present time, I use these additional registers in an ad hoc way
as in this situation. In the future I hope to use them to avoid spills
to memory in a more general way.
Interestingly enough, SP is not a Mips16 register but there are a set of
instructions which implicitly use this register but I cannot for
example, directly add SP and another Mips16 register together. This
makes SP complicated to use when you are referencing elements on the
stack and you deal with the more general case in which the local stack
offsets can be large. Gcc decides to not deal with any of that
complexity and they just copy SP to a Mips16 register when they need to
do anything with the stack; like reference local stack data. This seems
way too wasteful to me since there are so few registers; so I have gone
the extra mile to deal with all the extra Sp induced complexities.
T8 is another non Mips16 register which is used implicitly in many
conditional test and branch instructions. I use it mostly as if it were
a condition code register and try and avoid copying it back to a Mips16
register. I had to write a lot of long patterns for various things like
conditional moves so that sets of instructions that implicitly use T8
can be strung together.
With good optimization, you should be able to save 40% on the memory
footprint by using Mips16 mode as opposed to Mips32 mode.
You can more or less freely switch back and forth between Mips16 and
Mips32 mode.
Micromips is another newer encoding which offers space savings too but
without any of these Mips16 complexities because it is essentially
identical to Mips32 mode at the .s level. But with micro mips, if you
generate code without worrying about the differences, you will probably
get little compression because it will be using the 32 bit variants much
of the time.
Both mips16 and micro mips have both 16 and 32 bit length instructions.
>>
>> Added:
>> llvm/trunk/test/CodeGen/Mips/largefr1.ll
>> Modified:
>> llvm/trunk/lib/Target/Mips/Mips16InstrInfo.cpp
>> llvm/trunk/lib/Target/Mips/Mips16InstrInfo.h
>> llvm/trunk/lib/Target/Mips/Mips16RegisterInfo.cpp
>>
>> Modified: llvm/trunk/lib/Target/Mips/Mips16InstrInfo.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/Mips16InstrInfo.cpp?rev=174696&r1=174695&r2=174696&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/Target/Mips/Mips16InstrInfo.cpp (original)
>> +++ llvm/trunk/lib/Target/Mips/Mips16InstrInfo.cpp Thu Feb 7
>> 21:57:41 2013
>> @@ -19,6 +19,7 @@
>> #include "llvm/ADT/StringRef.h"
>> #include "llvm/CodeGen/MachineInstrBuilder.h"
>> #include "llvm/CodeGen/MachineRegisterInfo.h"
>> +#include "llvm/CodeGen/RegisterScavenging.h"
>> #include "llvm/Support/CommandLine.h"
>> #include "llvm/Support/ErrorHandling.h"
>> #include "llvm/Support/TargetRegistry.h"
>> @@ -306,11 +307,79 @@ void Mips16InstrInfo::adjustStackPtr(uns
>> /// This function generates the sequence of instructions needed to
>> get the
>> /// result of adding register REG and immediate IMM.
>> unsigned
>> -Mips16InstrInfo::loadImmediate(int64_t Imm, MachineBasicBlock &MBB,
>> +Mips16InstrInfo::loadImmediate(unsigned FrameReg,
>> + int64_t Imm, MachineBasicBlock &MBB,
>> MachineBasicBlock::iterator II,
>> DebugLoc DL,
>> - unsigned *NewImm) const {
>> + unsigned &NewImm) const {
>> + //
>> + // given original instruction is:
>> + // Instr rx, T[offset] where offset is too big.
>> + //
>> + // lo = offset & 0xFFFF
>> + // hi = ((offset >> 16) + (lo >> 15)) & 0xFFFF;
>> + //
>> + // let T = temporary register
>> + // li T, hi
>> + // shl T, 16
>> + // add T, Rx, T
>> + //
>> + RegScavenger rs;
>> + int32_t lo = Imm & 0xFFFF;
>> + int32_t hi = ((Imm >> 16) + (lo >> 15)) & 0xFFFF;
>> + NewImm = lo;
>> + unsigned Reg =0;
>> + unsigned SpReg = 0;
>> + rs.enterBasicBlock(&MBB);
>> + rs.forward(II);
>> + //
>> + // we use T0 for the first register, if we need to save something
>> away.
>> + // we use T1 for the second register, if we need to save something
>> away.
>> + //
>> + unsigned FirstRegSaved =0, SecondRegSaved=0;
>> + unsigned FirstRegSavedTo = 0, SecondRegSavedTo = 0;
>>
>> - return 0;
>> + Reg = rs.FindUnusedReg(&Mips::CPU16RegsRegClass);
>> + if (Reg == 0) {
>> + FirstRegSaved = Reg = Mips::V0;
>> + FirstRegSavedTo = Mips::T0;
>> + copyPhysReg(MBB, II, DL, FirstRegSavedTo, FirstRegSaved, true);
>> + }
>> + else
>> + rs.setUsed(Reg);
>> + BuildMI(MBB, II, DL, get(Mips::LiRxImmX16), Reg).addImm(hi);
>> + BuildMI(MBB, II, DL, get(Mips::SllX16), Reg).addReg(Reg).
>> + addImm(16);
>> + if (FrameReg == Mips::SP) {
>> + SpReg = rs.FindUnusedReg(&Mips::CPU16RegsRegClass);
>> + if (SpReg == 0) {
>> + if (Reg != Mips::V1) {
>> + SecondRegSaved = SpReg = Mips::V1;
>> + SecondRegSavedTo = Mips::T1;
>> + }
>> + else {
>> + SecondRegSaved = SpReg = Mips::V0;
>> + SecondRegSavedTo = Mips::T0;
>> + }
>> + copyPhysReg(MBB, II, DL, SecondRegSavedTo, SecondRegSaved,
>> true);
>> + }
>> + else
>> + rs.setUsed(SpReg);
>> +
>> + copyPhysReg(MBB, II, DL, SpReg, Mips::SP, false);
>> + BuildMI(MBB, II, DL, get(Mips:: AdduRxRyRz16),
>> Reg).addReg(SpReg)
>> + .addReg(Reg);
>> + }
>> + else
>> + BuildMI(MBB, II, DL, get(Mips:: AdduRxRyRz16),
>> Reg).addReg(FrameReg)
>> + .addReg(Reg, RegState::Kill);
>> + if (FirstRegSaved || SecondRegSaved) {
>> + II = llvm::next(II);
>> + if (FirstRegSaved)
>> + copyPhysReg(MBB, II, DL, FirstRegSaved, FirstRegSavedTo,
>> true);
>> + if (SecondRegSaved)
>> + copyPhysReg(MBB, II, DL, SecondRegSaved, SecondRegSavedTo,
>> true);
>> + }
>> + return Reg;
>> }
>>
>> unsigned Mips16InstrInfo::GetAnalyzableBrOpc(unsigned Opc) const {
>>
>> Modified: llvm/trunk/lib/Target/Mips/Mips16InstrInfo.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/Mips16InstrInfo.h?rev=174696&r1=174695&r2=174696&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/Target/Mips/Mips16InstrInfo.h (original)
>> +++ llvm/trunk/lib/Target/Mips/Mips16InstrInfo.h Thu Feb 7 21:57:41
>> 2013
>> @@ -77,12 +77,14 @@ public:
>> void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock
>> &MBB,
>> MachineBasicBlock::iterator I) const;
>>
>> - /// Emit a series of instructions to load an immediate. If NewImm
>> is a
>> - /// non-NULL parameter, the last instruction is not emitted, but
>> instead
>> - /// its immediate operand is returned in NewImm.
>> - unsigned loadImmediate(int64_t Imm, MachineBasicBlock &MBB,
>> + /// Emit a series of instructions to load an immediate.
>> + // This is to adjust some FrameReg. We return the new register to
>> be used
>> + // in place of FrameReg and the adjusted immediate field (&NewImm)
>> + //
>> + unsigned loadImmediate(unsigned FrameReg,
>> + int64_t Imm, MachineBasicBlock &MBB,
>> MachineBasicBlock::iterator II, DebugLoc
>> DL,
>> - unsigned *NewImm) const;
>> + unsigned &NewImm) const;
>>
>> private:
>> virtual unsigned GetAnalyzableBrOpc(unsigned Opc) const;
>>
>> Modified: llvm/trunk/lib/Target/Mips/Mips16RegisterInfo.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/Mips16RegisterInfo.cpp?rev=174696&r1=174695&r2=174696&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/Target/Mips/Mips16RegisterInfo.cpp (original)
>> +++ llvm/trunk/lib/Target/Mips/Mips16RegisterInfo.cpp Thu Feb 7
>> 21:57:41 2013
>> @@ -1,3 +1,4 @@
>> +
>> //===-- Mips16RegisterInfo.cpp - MIPS16 Register Information -==
>> ----------===//
>> //
>> // The LLVM Compiler Infrastructure
>> @@ -12,6 +13,7 @@
>> //===----------------------------------------------------------------------===//
>>
>> #include "Mips16RegisterInfo.h"
>> +#include "Mips16InstrInfo.h"
>> #include "Mips.h"
>> #include "Mips16InstrInfo.h"
>> #include "MipsAnalyzeImmediate.h"
>> @@ -23,6 +25,7 @@
>> #include "llvm/CodeGen/MachineFrameInfo.h"
>> #include "llvm/CodeGen/MachineFunction.h"
>> #include "llvm/CodeGen/MachineInstrBuilder.h"
>> +#include "llvm/CodeGen/MachineRegisterInfo.h"
>> #include "llvm/CodeGen/ValueTypes.h"
>> #include "llvm/DebugInfo.h"
>> #include "llvm/IR/Constants.h"
>> @@ -140,6 +143,7 @@ void Mips16RegisterInfo::eliminateFI(Mac
>> // by adding the size of the stack:
>> // incoming argument, callee-saved register location or local
>> variable.
>> int64_t Offset;
>> + bool IsKill = false;
>> Offset = SPOffset + (int64_t)StackSize;
>> Offset += MI.getOperand(OpNo + 1).getImm();
>>
>> @@ -148,9 +152,14 @@ void Mips16RegisterInfo::eliminateFI(Mac
>>
>> if (!MI.isDebugValue() && ( ((FrameReg != Mips::SP) &&
>> !isInt<16>(Offset)) ||
>> ((FrameReg == Mips::SP) && !isInt<15>(Offset)) )) {
>> - llvm_unreachable("frame offset does not fit in instruction");
>> + MachineBasicBlock &MBB = *MI.getParent();
>> + DebugLoc DL = II->getDebugLoc();
>> + unsigned NewImm;
>> + FrameReg = TII.loadImmediate(FrameReg, Offset, MBB, II, DL,
>> NewImm);
>> + Offset = SignExtend64<16>(NewImm);
>> + IsKill = true;
>> }
>> - MI.getOperand(OpNo).ChangeToRegister(FrameReg, false);
>> + MI.getOperand(OpNo).ChangeToRegister(FrameReg, false, false,
>> IsKill);
>> MI.getOperand(OpNo + 1).ChangeToImmediate(Offset);
>>
>>
>>
>> Added: llvm/trunk/test/CodeGen/Mips/largefr1.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/largefr1.ll?rev=174696&view=auto
>> ==============================================================================
>> --- llvm/trunk/test/CodeGen/Mips/largefr1.ll (added)
>> +++ llvm/trunk/test/CodeGen/Mips/largefr1.ll Thu Feb 7 21:57:41 2013
>> @@ -0,0 +1,61 @@
>> +; RUN: llc -march=mipsel -mcpu=mips16 -mips16-hard-float -soft-float
>> -relocation-model=static < %s | FileCheck %s -check-prefix=1
>> +
>> + at i = common global i32 0, align 4
>> + at j = common global i32 0, align 4
>> + at .str = private unnamed_addr constant [8 x i8] c"%i %i \0A\00",
>> align 1
>> +
>> +define void @foo(i32* %p, i32 %i, i32 %j) nounwind {
>> +entry:
>> + %p.addr = alloca i32*, align 4
>> + %i.addr = alloca i32, align 4
>> + %j.addr = alloca i32, align 4
>> + store i32* %p, i32** %p.addr, align 4
>> + store i32 %i, i32* %i.addr, align 4
>> + store i32 %j, i32* %j.addr, align 4
>> + %0 = load i32* %j.addr, align 4
>> + %1 = load i32** %p.addr, align 4
>> + %2 = load i32* %i.addr, align 4
>> + %add.ptr = getelementptr inbounds i32* %1, i32 %2
>> + store i32 %0, i32* %add.ptr, align 4
>> + ret void
>> +}
>> +
>> +define i32 @main() nounwind {
>> +entry:
>> +; 1: main:
>> +; 1: 1: .word -797992
>> +; 1: li ${{[0-9]+}}, 12
>> +; 1: sll ${{[0-9]+}}, ${{[0-9]+}}, 16
>> +; 1: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}}
>> +; 2: move $sp, ${{[0-9]+}}
>> +; 2: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}}
>> +; 1: li ${{[0-9]+}}, 6
>> +; 1: sll ${{[0-9]+}}, ${{[0-9]+}}, 16
>> +; 1: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}}
>> +; 2: move $sp, ${{[0-9]+}}
>> +; 2: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}}
>> +; 1: addiu ${{[0-9]+}}, ${{[0-9]+}}, 6800
>> +; 1: li ${{[0-9]+}}, 1
>> +; 1: sll ${{[0-9]+}}, ${{[0-9]+}}, 16
>> +; 2: li ${{[0-9]+}}, 34463
>> + %retval = alloca i32, align 4
>> + %one = alloca [100000 x i32], align 4
>> + %two = alloca [100000 x i32], align 4
>> + store i32 0, i32* %retval
>> + %arrayidx = getelementptr inbounds [100000 x i32]* %one, i32 0,
>> i32 0
>> + call void @foo(i32* %arrayidx, i32 50, i32 9999)
>> + %arrayidx1 = getelementptr inbounds [100000 x i32]* %two, i32 0,
>> i32 0
>> + call void @foo(i32* %arrayidx1, i32 99999, i32 5555)
>> + %arrayidx2 = getelementptr inbounds [100000 x i32]* %one, i32 0,
>> i32 50
>> + %0 = load i32* %arrayidx2, align 4
>> + store i32 %0, i32* @i, align 4
>> + %arrayidx3 = getelementptr inbounds [100000 x i32]* %two, i32 0,
>> i32 99999
>> + %1 = load i32* %arrayidx3, align 4
>> + store i32 %1, i32* @j, align 4
>> + %2 = load i32* @i, align 4
>> + %3 = load i32* @j, align 4
>> + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds
>> ([8 x i8]* @.str, i32 0, i32 0), i32 %2, i32 %3)
>> + ret i32 0
>> +}
>> +
>> +declare i32 @printf(i8*, ...)
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>
More information about the llvm-commits
mailing list