//===- BlackfinRegisterInfo.cpp - Blackfin Register Information -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Blackfin implementation of the TargetRegisterInfo
// class.
//
//===----------------------------------------------------------------------===//
#include "Blackfin.h"
#include "BlackfinRegisterInfo.h"
#include "BlackfinSubtarget.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Type.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#define GET_REGINFO_TARGET_DESC
#include "BlackfinGenRegisterInfo.inc"
using namespace llvm;
BlackfinRegisterInfo::BlackfinRegisterInfo(BlackfinSubtarget &st,
const TargetInstrInfo &tii)
: BlackfinGenRegisterInfo(BF::RETS), Subtarget(st), TII(tii) {}
const unsigned*
BlackfinRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
using namespace BF;
static const unsigned CalleeSavedRegs[] = {
FP,
R4, R5, R6, R7,
P3, P4, P5,
0 };
return CalleeSavedRegs;
}
BitVector
BlackfinRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
using namespace BF;
BitVector Reserved(getNumRegs());
Reserved.set(AZ);
Reserved.set(AN);
Reserved.set(AQ);
Reserved.set(AC0);
Reserved.set(AC1);
Reserved.set(AV0);
Reserved.set(AV0S);
Reserved.set(AV1);
Reserved.set(AV1S);
Reserved.set(V);
Reserved.set(VS);
Reserved.set(CYCLES).set(CYCLES2);
Reserved.set(L0);
Reserved.set(L1);
Reserved.set(L2);
Reserved.set(L3);
Reserved.set(SP);
Reserved.set(RETS);
if (TFI->hasFP(MF))
Reserved.set(FP);
return Reserved;
}
bool BlackfinRegisterInfo::
requiresRegisterScavenging(const MachineFunction &MF) const {
return true;
}
// Emit instructions to add delta to D/P register. ScratchReg must be of the
// same class as Reg (P).
void BlackfinRegisterInfo::adjustRegister(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
DebugLoc DL,
unsigned Reg,
unsigned ScratchReg,
int delta) const {
if (!delta)
return;
if (isInt<7>(delta)) {
BuildMI(MBB, I, DL, TII.get(BF::ADDpp_imm7), Reg)
.addReg(Reg) // No kill on two-addr operand
.addImm(delta);
return;
}
// We must load delta into ScratchReg and add that.
loadConstant(MBB, I, DL, ScratchReg, delta);
if (BF::PRegClass.contains(Reg)) {
assert(BF::PRegClass.contains(ScratchReg) &&
"ScratchReg must be a P register");
BuildMI(MBB, I, DL, TII.get(BF::ADDpp), Reg)
.addReg(Reg, RegState::Kill)
.addReg(ScratchReg, RegState::Kill);
} else {
assert(BF::DRegClass.contains(Reg) && "Reg must be a D or P register");
assert(BF::DRegClass.contains(ScratchReg) &&
"ScratchReg must be a D register");
BuildMI(MBB, I, DL, TII.get(BF::ADD), Reg)
.addReg(Reg, RegState::Kill)
.addReg(ScratchReg, RegState::Kill);
}
}
// Emit instructions to load a constant into D/P register
void BlackfinRegisterInfo::loadConstant(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
DebugLoc DL,
unsigned Reg,
int value) const {
if (isInt<7>(value)) {
BuildMI(MBB, I, DL, TII.get(BF::LOADimm7), Reg).addImm(value);
return;
}
if (isUInt<16>(value)) {
BuildMI(MBB, I, DL, TII.get(BF::LOADuimm16), Reg).addImm(value);
return;
}
if (isInt<16>(value)) {
BuildMI(MBB, I, DL, TII.get(BF::LOADimm16), Reg).addImm(value);
return;
}
// We must split into halves
BuildMI(MBB, I, DL,
TII.get(BF::LOAD16i), getSubReg(Reg, BF::hi16))
.addImm((value >> 16) & 0xffff)
.addReg(Reg, RegState::ImplicitDefine);
BuildMI(MBB, I, DL,
TII.get(BF::LOAD16i), getSubReg(Reg, BF::lo16))
.addImm(value & 0xffff)
.addReg(Reg, RegState::ImplicitKill)
.addReg(Reg, RegState::ImplicitDefine);
}
void BlackfinRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
if (!TFI->hasReservedCallFrame(MF)) {
int64_t Amount = I->getOperand(0).getImm();
if (Amount != 0) {
assert(Amount%4 == 0 && "Unaligned call frame size");
if (I->getOpcode() == BF::ADJCALLSTACKDOWN) {
adjustRegister(MBB, I, I->getDebugLoc(), BF::SP, BF::P1, -Amount);
} else {
assert(I->getOpcode() == BF::ADJCALLSTACKUP &&
"Unknown call frame pseudo instruction");
adjustRegister(MBB, I, I->getDebugLoc(), BF::SP, BF::P1, Amount);
}
}
}
MBB.erase(I);
}
/// findScratchRegister - Find a 'free' register. Try for a call-clobbered
/// register first and then a spilled callee-saved register if that fails.
static unsigned findScratchRegister(MachineBasicBlock::iterator II,
RegScavenger *RS,
const TargetRegisterClass *RC,
int SPAdj) {
assert(RS && "Register scavenging must be on");
unsigned Reg = RS->FindUnusedReg(RC);
if (Reg == 0)
Reg = RS->scavengeRegister(RC, II, SPAdj);
return Reg;
}
void
BlackfinRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, RegScavenger *RS) const {
MachineInstr &MI = *II;
MachineBasicBlock &MBB = *MI.getParent();
MachineFunction &MF = *MBB.getParent();
const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
DebugLoc DL = MI.getDebugLoc();
unsigned FIPos;
for (FIPos=0; !MI.getOperand(FIPos).isFI(); ++FIPos) {
assert(FIPos < MI.getNumOperands() &&
"Instr doesn't have FrameIndex operand!");
}
int FrameIndex = MI.getOperand(FIPos).getIndex();
assert(FIPos+1 < MI.getNumOperands() && MI.getOperand(FIPos+1).isImm());
int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex)
+ MI.getOperand(FIPos+1).getImm();
unsigned BaseReg = BF::FP;
if (TFI->hasFP(MF)) {
assert(SPAdj==0 && "Unexpected SP adjust in function with frame pointer");
} else {
BaseReg = BF::SP;
Offset += MF.getFrameInfo()->getStackSize() + SPAdj;
}
bool isStore = false;
switch (MI.getOpcode()) {
case BF::STORE32fi:
isStore = true;
case BF::LOAD32fi: {
assert(Offset%4 == 0 && "Unaligned i32 stack access");
assert(FIPos==1 && "Bad frame index operand");
MI.getOperand(FIPos).ChangeToRegister(BaseReg, false);
MI.getOperand(FIPos+1).setImm(Offset);
if (isUInt<6>(Offset)) {
MI.setDesc(TII.get(isStore
? BF::STORE32p_uimm6m4
: BF::LOAD32p_uimm6m4));
return;
}
if (BaseReg == BF::FP && isUInt<7>(-Offset)) {
MI.setDesc(TII.get(isStore
? BF::STORE32fp_nimm7m4
: BF::LOAD32fp_nimm7m4));
MI.getOperand(FIPos+1).setImm(-Offset);
return;
}
if (isInt<18>(Offset)) {
MI.setDesc(TII.get(isStore
? BF::STORE32p_imm18m4
: BF::LOAD32p_imm18m4));
return;
}
// Use RegScavenger to calculate proper offset...
MI.dump();
llvm_unreachable("Stack frame offset too big");
break;
}
case BF::ADDpp: {
assert(MI.getOperand(0).isReg() && "ADD instruction needs a register");
unsigned DestReg = MI.getOperand(0).getReg();
// We need to produce a stack offset in a P register. We emit:
// P0 = offset;
// P0 = BR + P0;
assert(FIPos==1 && "Bad frame index operand");
loadConstant(MBB, II, DL, DestReg, Offset);
MI.getOperand(1).ChangeToRegister(DestReg, false, false, true);
MI.getOperand(2).ChangeToRegister(BaseReg, false);
break;
}
case BF::STORE16fi:
isStore = true;
case BF::LOAD16fi: {
assert(Offset%2 == 0 && "Unaligned i16 stack access");
assert(FIPos==1 && "Bad frame index operand");
// We need a P register to use as an address
unsigned ScratchReg = findScratchRegister(II, RS, &BF::PRegClass, SPAdj);
assert(ScratchReg && "Could not scavenge register");
loadConstant(MBB, II, DL, ScratchReg, Offset);
BuildMI(MBB, II, DL, TII.get(BF::ADDpp), ScratchReg)
.addReg(ScratchReg, RegState::Kill)
.addReg(BaseReg);
MI.setDesc(TII.get(isStore ? BF::STORE16pi : BF::LOAD16pi));
MI.getOperand(1).ChangeToRegister(ScratchReg, false, false, true);
MI.RemoveOperand(2);
break;
}
case BF::STORE8fi: {
// This is an AnyCC spill, we need a scratch register.
assert(FIPos==1 && "Bad frame index operand");
MachineOperand SpillReg = MI.getOperand(0);
unsigned ScratchReg = findScratchRegister(II, RS, &BF::DRegClass, SPAdj);
assert(ScratchReg && "Could not scavenge register");
if (SpillReg.getReg()==BF::NCC) {
BuildMI(MBB, II, DL, TII.get(BF::MOVENCC_z), ScratchReg)
.addOperand(SpillReg);
BuildMI(MBB, II, DL, TII.get(BF::BITTGL), ScratchReg)
.addReg(ScratchReg).addImm(0);
} else {
BuildMI(MBB, II, DL, TII.get(BF::MOVECC_zext), ScratchReg)
.addOperand(SpillReg);
}
// STORE D
MI.setDesc(TII.get(BF::STORE8p_imm16));
MI.getOperand(0).ChangeToRegister(ScratchReg, false, false, true);
MI.getOperand(FIPos).ChangeToRegister(BaseReg, false);
MI.getOperand(FIPos+1).setImm(Offset);
break;
}
case BF::LOAD8fi: {
// This is an restore, we need a scratch register.
assert(FIPos==1 && "Bad frame index operand");
MachineOperand SpillReg = MI.getOperand(0);
unsigned ScratchReg = findScratchRegister(II, RS, &BF::DRegClass, SPAdj);
assert(ScratchReg && "Could not scavenge register");
MI.setDesc(TII.get(BF::LOAD32p_imm16_8z));
MI.getOperand(0).ChangeToRegister(ScratchReg, true);
MI.getOperand(FIPos).ChangeToRegister(BaseReg, false);
MI.getOperand(FIPos+1).setImm(Offset);
++II;
if (SpillReg.getReg()==BF::CC) {
// CC = D
BuildMI(MBB, II, DL, TII.get(BF::MOVECC_nz), BF::CC)
.addReg(ScratchReg, RegState::Kill);
} else {
// Restore NCC (CC = D==0)
BuildMI(MBB, II, DL, TII.get(BF::SETEQri_not), BF::NCC)
.addReg(ScratchReg, RegState::Kill)
.addImm(0);
}
break;
}
default:
llvm_unreachable("Cannot eliminate frame index");
break;
}
}
unsigned
BlackfinRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
return TFI->hasFP(MF) ? BF::FP : BF::SP;
}
unsigned BlackfinRegisterInfo::getEHExceptionRegister() const {
llvm_unreachable("What is the exception register");
return 0;
}
unsigned BlackfinRegisterInfo::getEHHandlerRegister() const {
llvm_unreachable("What is the exception handler register");
return 0;
}