mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-20 11:33:24 +02:00
cd46ca19fb
Summary: MRI::eliminateFrameIndex can emit several instructions to do address calculations; these can usually be stackified. Because instructions with FI operands can have subsequent operands which may be expression trees, find the top of the leftmost tree and insert the code before it, to keep the LIFO property. Also use stackified registers when writing back the SP value to memory in the epilog; it's unnecessary because SP will not be used after the epilog, and it results in better code. Differential Revision: http://reviews.llvm.org/D18234 llvm-svn: 263725
177 lines
6.6 KiB
C++
177 lines
6.6 KiB
C++
//===-- WebAssemblyRegisterInfo.cpp - WebAssembly Register Information ----===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// \brief This file contains the WebAssembly implementation of the
|
|
/// TargetRegisterInfo class.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "WebAssemblyRegisterInfo.h"
|
|
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
|
#include "WebAssemblyFrameLowering.h"
|
|
#include "WebAssemblyInstrInfo.h"
|
|
#include "WebAssemblyMachineFunctionInfo.h"
|
|
#include "WebAssemblySubtarget.h"
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Target/TargetFrameLowering.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "wasm-reg-info"
|
|
|
|
#define GET_REGINFO_TARGET_DESC
|
|
#include "WebAssemblyGenRegisterInfo.inc"
|
|
|
|
WebAssemblyRegisterInfo::WebAssemblyRegisterInfo(const Triple &TT)
|
|
: WebAssemblyGenRegisterInfo(0), TT(TT) {}
|
|
|
|
const MCPhysReg *
|
|
WebAssemblyRegisterInfo::getCalleeSavedRegs(const MachineFunction *) const {
|
|
static const MCPhysReg CalleeSavedRegs[] = {0};
|
|
return CalleeSavedRegs;
|
|
}
|
|
|
|
BitVector
|
|
WebAssemblyRegisterInfo::getReservedRegs(const MachineFunction & /*MF*/) const {
|
|
BitVector Reserved(getNumRegs());
|
|
for (auto Reg : {WebAssembly::SP32, WebAssembly::SP64, WebAssembly::FP32,
|
|
WebAssembly::FP64})
|
|
Reserved.set(Reg);
|
|
return Reserved;
|
|
}
|
|
|
|
static bool isStackifiedVReg(const WebAssemblyFunctionInfo *WFI,
|
|
const MachineOperand& Op) {
|
|
if (Op.isReg()) {
|
|
unsigned Reg = Op.getReg();
|
|
return TargetRegisterInfo::isVirtualRegister(Reg) &&
|
|
WFI->isVRegStackified(Reg);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool canStackifyOperand(const MachineInstr& Inst) {
|
|
unsigned Op = Inst.getOpcode();
|
|
return Op != TargetOpcode::PHI &&
|
|
Op != TargetOpcode::INLINEASM &&
|
|
Op != TargetOpcode::DBG_VALUE;
|
|
}
|
|
|
|
// Determine if the FI sequence can be stackified, and if so, where the code can
|
|
// be inserted. If stackification is possible, returns true and ajusts II to
|
|
// point to the insertion point.
|
|
bool findInsertPt(const WebAssemblyFunctionInfo *WFI, MachineBasicBlock &MBB,
|
|
unsigned OperandNum, MachineBasicBlock::iterator &II) {
|
|
if (!canStackifyOperand(*II)) return false;
|
|
|
|
MachineBasicBlock::iterator InsertPt(II);
|
|
int StackCount = 0;
|
|
// Operands are popped in reverse order, so any operands after FIOperand
|
|
// impose a constraint
|
|
for (unsigned i = OperandNum; i < II->getNumOperands(); i++) {
|
|
if (isStackifiedVReg(WFI, II->getOperand(i))) ++StackCount;
|
|
}
|
|
// Walk backwards, tracking stack depth. When it reaches 0 we have reached the
|
|
// top of the subtree.
|
|
while (StackCount) {
|
|
if (InsertPt == MBB.begin()) return false;
|
|
--InsertPt;
|
|
for (const auto &def : InsertPt->defs())
|
|
if (isStackifiedVReg(WFI, def)) --StackCount;
|
|
for (const auto &use : InsertPt->explicit_uses())
|
|
if (isStackifiedVReg(WFI, use)) ++StackCount;
|
|
}
|
|
II = InsertPt;
|
|
return true;
|
|
}
|
|
|
|
void WebAssemblyRegisterInfo::eliminateFrameIndex(
|
|
MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum,
|
|
RegScavenger * /*RS*/) const {
|
|
assert(SPAdj == 0);
|
|
MachineInstr &MI = *II;
|
|
|
|
MachineBasicBlock &MBB = *MI.getParent();
|
|
MachineFunction &MF = *MBB.getParent();
|
|
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
|
|
const MachineFrameInfo &MFI = *MF.getFrameInfo();
|
|
int64_t FrameOffset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex);
|
|
|
|
if (MI.mayLoadOrStore() && FIOperandNum == WebAssembly::MemOpAddressOperandNo) {
|
|
// If this is the address operand of a load or store, make it relative to SP
|
|
// and fold the frame offset directly in.
|
|
assert(FrameOffset >= 0 && MI.getOperand(1).getImm() >= 0);
|
|
int64_t Offset = MI.getOperand(1).getImm() + FrameOffset;
|
|
|
|
if (static_cast<uint64_t>(Offset) > std::numeric_limits<uint32_t>::max()) {
|
|
// If this happens the program is invalid, but better to error here than
|
|
// generate broken code.
|
|
report_fatal_error("Memory offset field overflow");
|
|
}
|
|
MI.getOperand(FIOperandNum - 1).setImm(Offset);
|
|
MI.getOperand(FIOperandNum)
|
|
.ChangeToRegister(WebAssembly::SP32, /*IsDef=*/false);
|
|
} else {
|
|
// Otherwise calculate the address
|
|
auto &MRI = MF.getRegInfo();
|
|
const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
|
|
|
|
unsigned FIRegOperand = WebAssembly::SP32;
|
|
if (FrameOffset) {
|
|
// Create i32.add SP, offset and make it the operand. We want to stackify
|
|
// this sequence, but we need to preserve the LIFO expr stack ordering
|
|
// (i.e. we can't insert our code in between MI and any operands it
|
|
// pops before FIOperand).
|
|
auto *WFI = MF.getInfo<WebAssemblyFunctionInfo>();
|
|
bool CanStackifyFI = findInsertPt(WFI, MBB, FIOperandNum, II);
|
|
|
|
unsigned OffsetOp = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
|
|
BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::CONST_I32),
|
|
OffsetOp)
|
|
.addImm(FrameOffset);
|
|
if (CanStackifyFI) {
|
|
WFI->stackifyVReg(OffsetOp);
|
|
FIRegOperand = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
|
|
WFI->stackifyVReg(FIRegOperand);
|
|
} else {
|
|
FIRegOperand = OffsetOp;
|
|
}
|
|
BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::ADD_I32),
|
|
FIRegOperand)
|
|
.addReg(WebAssembly::SP32)
|
|
.addReg(OffsetOp);
|
|
}
|
|
MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*IsDef=*/false);
|
|
}
|
|
}
|
|
|
|
unsigned
|
|
WebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
|
|
static const unsigned Regs[2][2] = {
|
|
/* !isArch64Bit isArch64Bit */
|
|
/* !hasFP */ {WebAssembly::SP32, WebAssembly::SP64},
|
|
/* hasFP */ {WebAssembly::FP32, WebAssembly::FP64}};
|
|
const WebAssemblyFrameLowering *TFI = getFrameLowering(MF);
|
|
return Regs[TFI->hasFP(MF)][TT.isArch64Bit()];
|
|
}
|
|
|
|
const TargetRegisterClass *
|
|
WebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF,
|
|
unsigned Kind) const {
|
|
assert(Kind == 0 && "Only one kind of pointer on WebAssembly");
|
|
if (MF.getSubtarget<WebAssemblySubtarget>().hasAddr64())
|
|
return &WebAssembly::I64RegClass;
|
|
return &WebAssembly::I32RegClass;
|
|
}
|