From 70cd88fb7b5b77f8bbca7417e624d11b6e22a7e7 Mon Sep 17 00:00:00 2001 From: Bob Wilson Date: Wed, 5 Aug 2009 23:12:45 +0000 Subject: [PATCH] Add a new pre-allocation pass to assign adjacent registers for Neon instructions that have that constraint. This is currently just assigning a fixed set of registers, and it only handles VLDn for n=2,3,4 with DPR registers. I'm going to expand it to handle more operations next; we can make it smarter once everything is working correctly. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78256 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARM.h | 2 +- lib/Target/ARM/ARMTargetMachine.cpp | 3 + lib/Target/ARM/CMakeLists.txt | 1 + lib/Target/ARM/NEONPreAllocPass.cpp | 137 ++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 lib/Target/ARM/NEONPreAllocPass.cpp diff --git a/lib/Target/ARM/ARM.h b/lib/Target/ARM/ARM.h index d947678828f..582879bf025 100644 --- a/lib/Target/ARM/ARM.h +++ b/lib/Target/ARM/ARM.h @@ -103,7 +103,7 @@ FunctionPass *createARMObjectCodeEmitterPass(ARMBaseTargetMachine &TM, FunctionPass *createARMLoadStoreOptimizationPass(bool PreAlloc = false); FunctionPass *createARMConstantIslandPass(); - +FunctionPass *createNEONPreAllocPass(); FunctionPass *createThumb2ITBlockPass(); extern Target TheARMTarget, TheThumbTarget; diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp index a6e987b086b..a58089088eb 100644 --- a/lib/Target/ARM/ARMTargetMachine.cpp +++ b/lib/Target/ARM/ARMTargetMachine.cpp @@ -93,6 +93,9 @@ bool ARMBaseTargetMachine::addInstSelector(PassManagerBase &PM, bool ARMBaseTargetMachine::addPreRegAlloc(PassManagerBase &PM, CodeGenOpt::Level OptLevel) { + if (Subtarget.hasNEON()) + PM.add(createNEONPreAllocPass()); + // FIXME: temporarily disabling load / store optimization pass for Thumb mode. if (OptLevel != CodeGenOpt::None && !DisableLdStOpti && !Subtarget.isThumb()) PM.add(createARMLoadStoreOptimizationPass(true)); diff --git a/lib/Target/ARM/CMakeLists.txt b/lib/Target/ARM/CMakeLists.txt index f40a3bc59a0..033da81a188 100644 --- a/lib/Target/ARM/CMakeLists.txt +++ b/lib/Target/ARM/CMakeLists.txt @@ -26,6 +26,7 @@ add_llvm_target(ARMCodeGen ARMSubtarget.cpp ARMTargetAsmInfo.cpp ARMTargetMachine.cpp + NEONPreAllocPass.cpp Thumb1InstrInfo.cpp Thumb1RegisterInfo.cpp Thumb2ITBlockPass.cpp diff --git a/lib/Target/ARM/NEONPreAllocPass.cpp b/lib/Target/ARM/NEONPreAllocPass.cpp new file mode 100644 index 00000000000..1662b763945 --- /dev/null +++ b/lib/Target/ARM/NEONPreAllocPass.cpp @@ -0,0 +1,137 @@ +//===-- NEONPreAllocPass.cpp - Allocate adjacent NEON registers--*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "neon-prealloc" +#include "ARM.h" +#include "ARMInstrInfo.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +using namespace llvm; + +namespace { + class VISIBILITY_HIDDEN NEONPreAllocPass : public MachineFunctionPass { + const TargetInstrInfo *TII; + + public: + static char ID; + NEONPreAllocPass() : MachineFunctionPass(&ID) {} + + virtual bool runOnMachineFunction(MachineFunction &MF); + + virtual const char *getPassName() const { + return "NEON register pre-allocation pass"; + } + + private: + bool PreAllocNEONRegisters(MachineBasicBlock &MBB); + }; + + char NEONPreAllocPass::ID = 0; +} + +static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, + unsigned &NumRegs) { + switch (Opcode) { + default: + break; + + case ARM::VLD2d8: + case ARM::VLD2d16: + case ARM::VLD2d32: + case ARM::VLD2d64: + FirstOpnd = 0; + NumRegs = 2; + return true; + + case ARM::VLD3d8: + case ARM::VLD3d16: + case ARM::VLD3d32: + case ARM::VLD3d64: + FirstOpnd = 0; + NumRegs = 3; + return true; + + case ARM::VLD4d8: + case ARM::VLD4d16: + case ARM::VLD4d32: + case ARM::VLD4d64: + FirstOpnd = 0; + NumRegs = 4; + return true; + } + + return false; +} + +bool NEONPreAllocPass::PreAllocNEONRegisters(MachineBasicBlock &MBB) { + bool Modified = false; + + MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); + for (; MBBI != E; ++MBBI) { + MachineInstr *MI = &*MBBI; + unsigned FirstOpnd, NumRegs; + if (!isNEONMultiRegOp(MI->getOpcode(), FirstOpnd, NumRegs)) + continue; + + MachineBasicBlock::iterator NextI = next(MBBI); + for (unsigned R = 0; R < NumRegs; ++R) { + MachineOperand &MO = MI->getOperand(FirstOpnd + R); + assert(MO.isReg() && MO.getSubReg() == 0 && "unexpected operand"); + unsigned VirtReg = MO.getReg(); + assert(TargetRegisterInfo::isVirtualRegister(VirtReg) && + "expected a virtual register"); + + // For now, just assign a fixed set of adjacent registers. + // This leaves plenty of room for future improvements. + static const unsigned NEONDRegs[] = { + ARM::D0, ARM::D1, ARM::D2, ARM::D3 + }; + MO.setReg(NEONDRegs[R]); + + if (MO.isUse()) { + // Insert a copy from VirtReg. + AddDefaultPred(BuildMI(MBB, MBBI, MI->getDebugLoc(), + TII->get(ARM::FCPYD), MO.getReg()) + .addReg(VirtReg)); + if (MO.isKill()) { + MachineInstr *CopyMI = prior(MBBI); + CopyMI->findRegisterUseOperand(VirtReg)->setIsKill(); + } + MO.setIsKill(); + } else if (MO.isDef() && !MO.isDead()) { + // Add a copy to VirtReg. + AddDefaultPred(BuildMI(MBB, NextI, MI->getDebugLoc(), + TII->get(ARM::FCPYD), VirtReg) + .addReg(MO.getReg())); + } + } + } + + return Modified; +} + +bool NEONPreAllocPass::runOnMachineFunction(MachineFunction &MF) { + TII = MF.getTarget().getInstrInfo(); + + bool Modified = false; + for (MachineFunction::iterator MFI = MF.begin(), E = MF.end(); MFI != E; + ++MFI) { + MachineBasicBlock &MBB = *MFI; + Modified |= PreAllocNEONRegisters(MBB); + } + + return Modified; +} + +/// createNEONPreAllocPass - returns an instance of the NEON register +/// pre-allocation pass. +FunctionPass *llvm::createNEONPreAllocPass() { + return new NEONPreAllocPass(); +}