all of the features in the current working draft of the upcoming C++ standard, provisionally named C++1y. The code generator's performance is greatly increased, and the loop auto-vectorizer is now enabled at -Os and -O2 in addition to -O3. The PowerPC backend has made several major improvements to code generation quality and compile time, and the X86, SPARC, ARM32, Aarch64 and SystemZ backends have all seen major feature work. Release notes for llvm and clang can be found here: <http://llvm.org/releases/3.4/docs/ReleaseNotes.html> <http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html> MFC after: 1 month
207 lines
8.2 KiB
C++
207 lines
8.2 KiB
C++
//===---- RemoteMemoryManager.cpp - Recording memory manager --------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This memory manager allocates local storage and keeps a record of each
|
|
// allocation. Iterators are provided for all data and code allocations.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "lli"
|
|
#include "RemoteMemoryManager.h"
|
|
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
|
#include "llvm/ExecutionEngine/ObjectImage.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/Format.h"
|
|
|
|
using namespace llvm;
|
|
|
|
RemoteMemoryManager::~RemoteMemoryManager() {
|
|
for (SmallVector<Allocation, 2>::iterator
|
|
I = AllocatedSections.begin(), E = AllocatedSections.end();
|
|
I != E; ++I)
|
|
sys::Memory::releaseMappedMemory(I->MB);
|
|
}
|
|
|
|
uint8_t *RemoteMemoryManager::
|
|
allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID,
|
|
StringRef SectionName) {
|
|
// The recording memory manager is just a local copy of the remote target.
|
|
// The alignment requirement is just stored here for later use. Regular
|
|
// heap storage is sufficient here, but we're using mapped memory to work
|
|
// around a bug in MCJIT.
|
|
sys::MemoryBlock Block = allocateSection(Size);
|
|
// AllocatedSections will own this memory.
|
|
AllocatedSections.push_back( Allocation(Block, Alignment, true) );
|
|
// UnmappedSections has the same information but does not own the memory.
|
|
UnmappedSections.push_back( Allocation(Block, Alignment, true) );
|
|
return (uint8_t*)Block.base();
|
|
}
|
|
|
|
uint8_t *RemoteMemoryManager::
|
|
allocateDataSection(uintptr_t Size, unsigned Alignment,
|
|
unsigned SectionID, StringRef SectionName,
|
|
bool IsReadOnly) {
|
|
// The recording memory manager is just a local copy of the remote target.
|
|
// The alignment requirement is just stored here for later use. Regular
|
|
// heap storage is sufficient here, but we're using mapped memory to work
|
|
// around a bug in MCJIT.
|
|
sys::MemoryBlock Block = allocateSection(Size);
|
|
// AllocatedSections will own this memory.
|
|
AllocatedSections.push_back( Allocation(Block, Alignment, false) );
|
|
// UnmappedSections has the same information but does not own the memory.
|
|
UnmappedSections.push_back( Allocation(Block, Alignment, false) );
|
|
return (uint8_t*)Block.base();
|
|
}
|
|
|
|
sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) {
|
|
error_code ec;
|
|
sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size,
|
|
&Near,
|
|
sys::Memory::MF_READ |
|
|
sys::Memory::MF_WRITE,
|
|
ec);
|
|
assert(!ec && MB.base());
|
|
|
|
// FIXME: This is part of a work around to keep sections near one another
|
|
// when MCJIT performs relocations after code emission but before
|
|
// the generated code is moved to the remote target.
|
|
// Save this address as the basis for our next request
|
|
Near = MB;
|
|
return MB;
|
|
}
|
|
|
|
void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE,
|
|
const ObjectImage *Obj) {
|
|
// The client should have called setRemoteTarget() before triggering any
|
|
// code generation.
|
|
assert(Target);
|
|
if (!Target)
|
|
return;
|
|
|
|
// FIXME: Make this function thread safe.
|
|
|
|
// Lay out our sections in order, with all the code sections first, then
|
|
// all the data sections.
|
|
uint64_t CurOffset = 0;
|
|
unsigned MaxAlign = Target->getPageAlignment();
|
|
SmallVector<std::pair<Allocation, uint64_t>, 16> Offsets;
|
|
unsigned NumSections = UnmappedSections.size();
|
|
// We're going to go through the list twice to separate code and data, but
|
|
// it's a very small list, so that's OK.
|
|
for (size_t i = 0, e = NumSections; i != e; ++i) {
|
|
Allocation &Section = UnmappedSections[i];
|
|
if (Section.IsCode) {
|
|
unsigned Size = Section.MB.size();
|
|
unsigned Align = Section.Alignment;
|
|
DEBUG(dbgs() << "code region: size " << Size
|
|
<< ", alignment " << Align << "\n");
|
|
// Align the current offset up to whatever is needed for the next
|
|
// section.
|
|
CurOffset = (CurOffset + Align - 1) / Align * Align;
|
|
// Save off the address of the new section and allocate its space.
|
|
Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset));
|
|
CurOffset += Size;
|
|
}
|
|
}
|
|
// Adjust to keep code and data aligned on seperate pages.
|
|
CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign;
|
|
for (size_t i = 0, e = NumSections; i != e; ++i) {
|
|
Allocation &Section = UnmappedSections[i];
|
|
if (!Section.IsCode) {
|
|
unsigned Size = Section.MB.size();
|
|
unsigned Align = Section.Alignment;
|
|
DEBUG(dbgs() << "data region: size " << Size
|
|
<< ", alignment " << Align << "\n");
|
|
// Align the current offset up to whatever is needed for the next
|
|
// section.
|
|
CurOffset = (CurOffset + Align - 1) / Align * Align;
|
|
// Save off the address of the new section and allocate its space.
|
|
Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset));
|
|
CurOffset += Size;
|
|
}
|
|
}
|
|
|
|
// Allocate space in the remote target.
|
|
uint64_t RemoteAddr;
|
|
if (Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr))
|
|
report_fatal_error(Target->getErrorMsg());
|
|
|
|
// Map the section addresses so relocations will get updated in the local
|
|
// copies of the sections.
|
|
for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
|
|
uint64_t Addr = RemoteAddr + Offsets[i].second;
|
|
EE->mapSectionAddress(const_cast<void*>(Offsets[i].first.MB.base()), Addr);
|
|
|
|
DEBUG(dbgs() << " Mapping local: " << Offsets[i].first.MB.base()
|
|
<< " to remote: 0x" << format("%llx", Addr) << "\n");
|
|
|
|
MappedSections[Addr] = Offsets[i].first;
|
|
}
|
|
|
|
UnmappedSections.clear();
|
|
}
|
|
|
|
bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) {
|
|
// FIXME: Make this function thread safe.
|
|
for (DenseMap<uint64_t, Allocation>::iterator
|
|
I = MappedSections.begin(), E = MappedSections.end();
|
|
I != E; ++I) {
|
|
uint64_t RemoteAddr = I->first;
|
|
const Allocation &Section = I->second;
|
|
if (Section.IsCode) {
|
|
Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size());
|
|
|
|
DEBUG(dbgs() << " loading code: " << Section.MB.base()
|
|
<< " to remote: 0x" << format("%llx", RemoteAddr) << "\n");
|
|
} else {
|
|
Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size());
|
|
|
|
DEBUG(dbgs() << " loading data: " << Section.MB.base()
|
|
<< " to remote: 0x" << format("%llx", RemoteAddr) << "\n");
|
|
}
|
|
}
|
|
|
|
MappedSections.clear();
|
|
|
|
return false;
|
|
}
|
|
|
|
void RemoteMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); }
|
|
void RemoteMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); }
|
|
void RemoteMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); }
|
|
void RemoteMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); }
|
|
uint8_t *RemoteMemoryManager::getGOTBase() const {
|
|
llvm_unreachable("Unexpected!");
|
|
return 0;
|
|
}
|
|
uint8_t *RemoteMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){
|
|
llvm_unreachable("Unexpected!");
|
|
return 0;
|
|
}
|
|
uint8_t *RemoteMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize,
|
|
unsigned Alignment) {
|
|
llvm_unreachable("Unexpected!");
|
|
return 0;
|
|
}
|
|
void RemoteMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart,
|
|
uint8_t *FunctionEnd) {
|
|
llvm_unreachable("Unexpected!");
|
|
}
|
|
uint8_t *RemoteMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) {
|
|
llvm_unreachable("Unexpected!");
|
|
return 0;
|
|
}
|
|
uint8_t *RemoteMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) {
|
|
llvm_unreachable("Unexpected!");
|
|
return 0;
|
|
}
|
|
void RemoteMemoryManager::deallocateFunctionBody(void *Body) {
|
|
llvm_unreachable("Unexpected!");
|
|
}
|