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.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174696 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Reed Kotler 2013-02-08 03:57:41 +00:00
parent d2bcda7706
commit 61b97b8c17
4 changed files with 151 additions and 10 deletions

View File

@ -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(unsigned SP, int64_t Amount,
/// 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 {

View File

@ -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;

View File

@ -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(MachineBasicBlock::iterator II,
// 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(MachineBasicBlock::iterator II,
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);

View File

@ -0,0 +1,61 @@
; RUN: llc -march=mipsel -mcpu=mips16 -mips16-hard-float -soft-float -relocation-model=static < %s | FileCheck %s -check-prefix=1
@i = common global i32 0, align 4
@j = common global i32 0, align 4
@.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*, ...)