mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-26 05:32:25 +00:00
Adding a basic ELF dynamic loader and MC-JIT for ELF. Functionality is currently basic and will be enhanced with future patches.
Patch developed by Andy Kaylor and Daniel Malea. Reviewed on llvm-commits. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@148231 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
810d6d3354
commit
a66a18505e
@ -1,4 +1,5 @@
|
||||
add_llvm_library(LLVMRuntimeDyld
|
||||
RuntimeDyld.cpp
|
||||
RuntimeDyldMachO.cpp
|
||||
RuntimeDyldELF.cpp
|
||||
)
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#define DEBUG_TYPE "dyld"
|
||||
#include "RuntimeDyldImpl.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
|
||||
@ -64,12 +65,36 @@ RuntimeDyld::~RuntimeDyld() {
|
||||
|
||||
bool RuntimeDyld::loadObject(MemoryBuffer *InputBuffer) {
|
||||
if (!Dyld) {
|
||||
if (RuntimeDyldMachO::isKnownFormat(InputBuffer))
|
||||
Dyld = new RuntimeDyldMachO(MM);
|
||||
else
|
||||
report_fatal_error("Unknown object format!");
|
||||
sys::LLVMFileType type = sys::IdentifyFileType(
|
||||
InputBuffer->getBufferStart(),
|
||||
static_cast<unsigned>(InputBuffer->getBufferSize()));
|
||||
switch (type) {
|
||||
case sys::ELF_Relocatable_FileType:
|
||||
case sys::ELF_Executable_FileType:
|
||||
case sys::ELF_SharedObject_FileType:
|
||||
case sys::ELF_Core_FileType:
|
||||
Dyld = new RuntimeDyldELF(MM);
|
||||
break;
|
||||
case sys::Mach_O_Object_FileType:
|
||||
case sys::Mach_O_Executable_FileType:
|
||||
case sys::Mach_O_FixedVirtualMemorySharedLib_FileType:
|
||||
case sys::Mach_O_Core_FileType:
|
||||
case sys::Mach_O_PreloadExecutable_FileType:
|
||||
case sys::Mach_O_DynamicallyLinkedSharedLib_FileType:
|
||||
case sys::Mach_O_DynamicLinker_FileType:
|
||||
case sys::Mach_O_Bundle_FileType:
|
||||
case sys::Mach_O_DynamicallyLinkedSharedLibStub_FileType:
|
||||
case sys::Mach_O_DSYMCompanion_FileType:
|
||||
Dyld = new RuntimeDyldMachO(MM);
|
||||
break;
|
||||
case sys::Unknown_FileType:
|
||||
case sys::Bitcode_FileType:
|
||||
case sys::Archive_FileType:
|
||||
case sys::COFF_FileType:
|
||||
report_fatal_error("Incompatible object format!");
|
||||
}
|
||||
} else {
|
||||
if(!Dyld->isCompatibleFormat(InputBuffer))
|
||||
if (!Dyld->isCompatibleFormat(InputBuffer))
|
||||
report_fatal_error("Incompatible object format!");
|
||||
}
|
||||
|
||||
|
282
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
Normal file
282
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
Normal file
@ -0,0 +1,282 @@
|
||||
//===-- RuntimeDyldELF.cpp - Run-time dynamic linker for MC-JIT ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implementation of ELF support for the MC-JIT runtime dynamic linker.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "dyld"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/IntervalMap.h"
|
||||
#include "RuntimeDyldImpl.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace {
|
||||
|
||||
// FIXME: this function should probably not live here...
|
||||
//
|
||||
// Returns the name and address of an unrelocated symbol in an ELF section
|
||||
void getSymbolInfo(symbol_iterator Sym, uint64_t &Addr, StringRef &Name) {
|
||||
//FIXME: error checking here required to catch corrupt ELF objects...
|
||||
error_code Err = Sym->getName(Name);
|
||||
|
||||
uint64_t AddrInSection;
|
||||
Err = Sym->getAddress(AddrInSection);
|
||||
|
||||
SectionRef empty_section;
|
||||
section_iterator Section(empty_section);
|
||||
Err = Sym->getSection(Section);
|
||||
|
||||
StringRef SectionContents;
|
||||
Section->getContents(SectionContents);
|
||||
|
||||
Addr = reinterpret_cast<uint64_t>(SectionContents.data()) + AddrInSection;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool RuntimeDyldELF::loadObject(MemoryBuffer *InputBuffer) {
|
||||
if (!isCompatibleFormat(InputBuffer))
|
||||
return true;
|
||||
|
||||
OwningPtr<ObjectFile> Obj(ObjectFile::createELFObjectFile(InputBuffer));
|
||||
|
||||
Arch = Obj->getArch();
|
||||
|
||||
// Map address in the Object file image to function names
|
||||
IntervalMap<uint64_t, StringRef>::Allocator A;
|
||||
IntervalMap<uint64_t, StringRef> FuncMap(A);
|
||||
|
||||
// This is a bit of a hack. The ObjectFile we've just loaded reports
|
||||
// section addresses as 0 and doesn't provide access to the section
|
||||
// offset (from which we could calculate the address. Instead,
|
||||
// we're storing the address when it comes up in the ST_Debug case
|
||||
// below.
|
||||
//
|
||||
StringMap<uint64_t> DebugSymbolMap;
|
||||
|
||||
symbol_iterator SymEnd = Obj->end_symbols();
|
||||
error_code Err;
|
||||
for (symbol_iterator Sym = Obj->begin_symbols();
|
||||
Sym != SymEnd; Sym.increment(Err)) {
|
||||
SymbolRef::Type Type;
|
||||
Sym->getType(Type);
|
||||
if (Type == SymbolRef::ST_Function) {
|
||||
StringRef Name;
|
||||
uint64_t Addr;
|
||||
getSymbolInfo(Sym, Addr, Name);
|
||||
|
||||
uint64_t Size;
|
||||
Err = Sym->getSize(Size);
|
||||
|
||||
uint8_t *Start;
|
||||
uint8_t *End;
|
||||
Start = reinterpret_cast<uint8_t*>(Addr);
|
||||
End = reinterpret_cast<uint8_t*>(Addr + Size - 1);
|
||||
|
||||
extractFunction(Name, Start, End);
|
||||
FuncMap.insert(Addr, Addr + Size - 1, Name);
|
||||
} else if (Type == SymbolRef::ST_Debug) {
|
||||
// This case helps us find section addresses
|
||||
StringRef Name;
|
||||
uint64_t Addr;
|
||||
getSymbolInfo(Sym, Addr, Name);
|
||||
DebugSymbolMap[Name] = Addr;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through the relocations for this object
|
||||
section_iterator SecEnd = Obj->end_sections();
|
||||
for (section_iterator Sec = Obj->begin_sections();
|
||||
Sec != SecEnd; Sec.increment(Err)) {
|
||||
StringRef SecName;
|
||||
uint64_t SecAddr;
|
||||
Sec->getName(SecName);
|
||||
// Ignore sections that aren't in our map
|
||||
if (DebugSymbolMap.find(SecName) == DebugSymbolMap.end()) {
|
||||
continue;
|
||||
}
|
||||
SecAddr = DebugSymbolMap[SecName];
|
||||
relocation_iterator RelEnd = Sec->end_relocations();
|
||||
for (relocation_iterator Rel = Sec->begin_relocations();
|
||||
Rel != RelEnd; Rel.increment(Err)) {
|
||||
uint64_t RelOffset;
|
||||
uint64_t RelType;
|
||||
int64_t RelAddend;
|
||||
SymbolRef RelSym;
|
||||
StringRef SymName;
|
||||
uint64_t SymAddr;
|
||||
uint64_t SymOffset;
|
||||
|
||||
Rel->getAddress(RelOffset);
|
||||
Rel->getType(RelType);
|
||||
Rel->getAdditionalInfo(RelAddend);
|
||||
Rel->getSymbol(RelSym);
|
||||
RelSym.getName(SymName);
|
||||
RelSym.getAddress(SymAddr);
|
||||
RelSym.getFileOffset(SymOffset);
|
||||
|
||||
// If this relocation is inside a function, we want to store the
|
||||
// function name and a function-relative offset
|
||||
IntervalMap<uint64_t, StringRef>::iterator ContainingFunc
|
||||
= FuncMap.find(SecAddr + RelOffset);
|
||||
if (ContainingFunc.valid()) {
|
||||
// Re-base the relocation to make it relative to the target function
|
||||
RelOffset = (SecAddr + RelOffset) - ContainingFunc.start();
|
||||
Relocations[SymName].push_back(RelocationEntry(ContainingFunc.value(),
|
||||
RelOffset,
|
||||
RelType,
|
||||
RelAddend,
|
||||
true));
|
||||
} else {
|
||||
Relocations[SymName].push_back(RelocationEntry(SecName,
|
||||
RelOffset,
|
||||
RelType,
|
||||
RelAddend,
|
||||
false));
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RuntimeDyldELF::resolveX86_64Relocation(StringRef Name,
|
||||
uint8_t *Addr,
|
||||
const RelocationEntry &RE) {
|
||||
uint8_t *TargetAddr;
|
||||
if (RE.IsFunctionRelative) {
|
||||
StringMap<sys::MemoryBlock>::iterator ContainingFunc
|
||||
= Functions.find(RE.Target);
|
||||
assert(ContainingFunc != Functions.end()
|
||||
&& "Function for relocation not found");
|
||||
TargetAddr = reinterpret_cast<uint8_t*>(ContainingFunc->getValue().base()) +
|
||||
RE.Offset;
|
||||
} else {
|
||||
// FIXME: Get the address of the target section and add that to RE.Offset
|
||||
assert(0 && ("Non-function relocation not implemented yet!"));
|
||||
}
|
||||
|
||||
switch (RE.Type) {
|
||||
default:
|
||||
assert(0 && ("Relocation type not implemented yet!"));
|
||||
break;
|
||||
case ELF::R_X86_64_64: {
|
||||
uint8_t **Target = reinterpret_cast<uint8_t**>(TargetAddr);
|
||||
*Target = Addr + RE.Addend;
|
||||
break;
|
||||
}
|
||||
case ELF::R_X86_64_32:
|
||||
case ELF::R_X86_64_32S: {
|
||||
uint64_t Value = reinterpret_cast<uint64_t>(Addr) + RE.Addend;
|
||||
// FIXME: Handle the possibility of this assertion failing
|
||||
assert((RE.Type == ELF::R_X86_64_32 && !(Value & 0xFFFFFFFF00000000)) ||
|
||||
(RE.Type == ELF::R_X86_64_32S &&
|
||||
(Value & 0xFFFFFFFF00000000) == 0xFFFFFFFF00000000));
|
||||
uint32_t TruncatedAddr = (Value & 0xFFFFFFFF);
|
||||
uint32_t *Target = reinterpret_cast<uint32_t*>(TargetAddr);
|
||||
*Target = TruncatedAddr;
|
||||
break;
|
||||
}
|
||||
case ELF::R_X86_64_PC32: {
|
||||
uint32_t *Placeholder = reinterpret_cast<uint32_t*>(TargetAddr);
|
||||
uint64_t RealOffset = *Placeholder +
|
||||
reinterpret_cast<uint64_t>(Addr) +
|
||||
RE.Addend - reinterpret_cast<uint64_t>(TargetAddr);
|
||||
assert((RealOffset & 0xFFFFFFFF) == RealOffset);
|
||||
uint32_t TruncOffset = (RealOffset & 0xFFFFFFFF);
|
||||
*Placeholder = TruncOffset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RuntimeDyldELF::resolveX86Relocation(StringRef Name,
|
||||
uint8_t *Addr,
|
||||
const RelocationEntry &RE) {
|
||||
uint8_t *TargetAddr;
|
||||
if (RE.IsFunctionRelative) {
|
||||
StringMap<sys::MemoryBlock>::iterator ContainingFunc
|
||||
= Functions.find(RE.Target);
|
||||
assert(ContainingFunc != Functions.end()
|
||||
&& "Function for relocation not found");
|
||||
TargetAddr = reinterpret_cast<uint8_t*>(
|
||||
ContainingFunc->getValue().base()) + RE.Offset;
|
||||
} else {
|
||||
// FIXME: Get the address of the target section and add that to RE.Offset
|
||||
assert(0 && ("Non-function relocation not implemented yet!"));
|
||||
}
|
||||
|
||||
switch (RE.Type) {
|
||||
case ELF::R_386_32: {
|
||||
uint8_t **Target = reinterpret_cast<uint8_t**>(TargetAddr);
|
||||
*Target = Addr + RE.Addend;
|
||||
break;
|
||||
}
|
||||
case ELF::R_386_PC32: {
|
||||
uint32_t *Placeholder = reinterpret_cast<uint32_t*>(TargetAddr);
|
||||
uint32_t RealOffset = *Placeholder + reinterpret_cast<uintptr_t>(Addr) +
|
||||
RE.Addend - reinterpret_cast<uintptr_t>(TargetAddr);
|
||||
*Placeholder = RealOffset;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// There are other relocation types, but it appears these are the
|
||||
// only ones currently used by the LLVM ELF object writer
|
||||
assert(0 && ("Relocation type not implemented yet!"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RuntimeDyldELF::resolveArmRelocation(StringRef Name,
|
||||
uint8_t *Addr,
|
||||
const RelocationEntry &RE) {
|
||||
}
|
||||
|
||||
void RuntimeDyldELF::resolveRelocation(StringRef Name,
|
||||
uint8_t *Addr,
|
||||
const RelocationEntry &RE) {
|
||||
switch (Arch) {
|
||||
case Triple::x86_64:
|
||||
resolveX86_64Relocation(Name, Addr, RE);
|
||||
break;
|
||||
case Triple::x86:
|
||||
resolveX86Relocation(Name, Addr, RE);
|
||||
break;
|
||||
case Triple::arm:
|
||||
resolveArmRelocation(Name, Addr, RE);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Unsupported CPU type!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RuntimeDyldELF::reassignSymbolAddress(StringRef Name, uint8_t *Addr) {
|
||||
SymbolTable[Name] = Addr;
|
||||
|
||||
RelocationList &Relocs = Relocations[Name];
|
||||
for (unsigned i = 0, e = Relocs.size(); i != e; ++i) {
|
||||
RelocationEntry &RE = Relocs[i];
|
||||
resolveRelocation(Name, Addr, RE);
|
||||
}
|
||||
}
|
||||
|
||||
bool RuntimeDyldELF::isCompatibleFormat(const MemoryBuffer *InputBuffer) const {
|
||||
StringRef Magic = InputBuffer->getBuffer().slice(0, ELF::EI_NIDENT);
|
||||
return (memcmp(Magic.data(), ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0;
|
||||
}
|
||||
} // namespace llvm
|
@ -94,6 +94,66 @@ public:
|
||||
virtual bool isCompatibleFormat(const MemoryBuffer *InputBuffer) const = 0;
|
||||
};
|
||||
|
||||
class RuntimeDyldELF : public RuntimeDyldImpl {
|
||||
// For each symbol, keep a list of relocations based on it. Anytime
|
||||
// its address is reassigned (the JIT re-compiled the function, e.g.),
|
||||
// the relocations get re-resolved.
|
||||
struct RelocationEntry {
|
||||
// Function or section this relocation is contained in.
|
||||
std::string Target;
|
||||
// Offset into the target function or section for the relocation.
|
||||
uint32_t Offset;
|
||||
// Relocation type
|
||||
uint32_t Type;
|
||||
// Addend encoded in the instruction itself, if any.
|
||||
int32_t Addend;
|
||||
// Has the relocation been recalcuated as an offset within a function?
|
||||
bool IsFunctionRelative;
|
||||
// Has this relocation been resolved previously?
|
||||
bool isResolved;
|
||||
|
||||
RelocationEntry(StringRef t,
|
||||
uint32_t offset,
|
||||
uint32_t type,
|
||||
int32_t addend,
|
||||
bool isFunctionRelative)
|
||||
: Target(t)
|
||||
, Offset(offset)
|
||||
, Type(type)
|
||||
, Addend(addend)
|
||||
, IsFunctionRelative(isFunctionRelative)
|
||||
, isResolved(false) { }
|
||||
};
|
||||
typedef SmallVector<RelocationEntry, 4> RelocationList;
|
||||
StringMap<RelocationList> Relocations;
|
||||
unsigned Arch;
|
||||
|
||||
void resolveX86_64Relocation(StringRef Name,
|
||||
uint8_t *Addr,
|
||||
const RelocationEntry &RE);
|
||||
|
||||
void resolveX86Relocation(StringRef Name,
|
||||
uint8_t *Addr,
|
||||
const RelocationEntry &RE);
|
||||
|
||||
void resolveArmRelocation(StringRef Name,
|
||||
uint8_t *Addr,
|
||||
const RelocationEntry &RE);
|
||||
|
||||
void resolveRelocation(StringRef Name,
|
||||
uint8_t *Addr,
|
||||
const RelocationEntry &RE);
|
||||
|
||||
public:
|
||||
RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {}
|
||||
|
||||
bool loadObject(MemoryBuffer *InputBuffer);
|
||||
|
||||
void reassignSymbolAddress(StringRef Name, uint8_t *Addr);
|
||||
|
||||
bool isCompatibleFormat(const MemoryBuffer *InputBuffer) const;
|
||||
};
|
||||
|
||||
|
||||
class RuntimeDyldMachO : public RuntimeDyldImpl {
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: mcjit
|
||||
|
||||
@.LC0 = internal global [10 x i8] c"argc: %d\0A\00" ; <[10 x i8]*> [#uses=1]
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
; XFAIL: mcjit
|
||||
|
||||
define i32 @foo(i32 %X, i32 %Y, double %A) {
|
||||
%cond212 = fcmp une double %A, 1.000000e+00 ; <i1> [#uses=1]
|
||||
|
@ -1,5 +1,6 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
; XFAIL: mcjit
|
||||
|
||||
define i32 @main() {
|
||||
call i32 @mylog( i32 4 ) ; <i32>:1 [#uses=0]
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
; <label>:0
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
; We were accidentally inverting the signedness of right shifts. Whoops.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
%X = fadd double 0.000000e+00, 1.000000e+00 ; <double> [#uses=1]
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
|
||||
define i32 @bar(i8* %X) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
; This testcase should return with an exit code of 1.
|
||||
;
|
||||
; RUN: not lli %s
|
||||
; RUN: not %lli %s
|
||||
; XFAIL: arm
|
||||
; XFAIL: mcjit
|
||||
|
||||
@test = global i64 0 ; <i64*> [#uses=1]
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
; RUN: lli %s test
|
||||
; RUN: %lli %s test
|
||||
; XFAIL: arm
|
||||
; XFAIL: mcjit
|
||||
|
||||
declare i32 @puts(i8*)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
target datalayout = "e-p:32:32"
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
; Testcase distilled from 256.bzip2.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
; Testcase distilled from 256.bzip2.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
|
||||
; This testcase failed to work because two variable sized allocas confused the
|
||||
|
@ -1,5 +1,6 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
; XFAIL: mcjit
|
||||
|
||||
;
|
||||
; Regression Test: EnvironmentTest.ll
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
|
||||
; This testcase exposes a bug in the local register allocator where it runs out
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
|
||||
@A = global i32 0 ; <i32*> [#uses=1]
|
||||
|
@ -1,6 +1,7 @@
|
||||
; PR672
|
||||
; RUN: lli %s
|
||||
; RUN: %lli %s
|
||||
; XFAIL: arm
|
||||
; XFAIL: mcjit-ia32
|
||||
|
||||
define i32 @main() {
|
||||
%f = bitcast i32 (i32, i32*, i32)* @check_tail to i32* ; <i32*> [#uses=1]
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli -force-interpreter %s
|
||||
; RUN: %lli -force-interpreter %s
|
||||
; PR1836
|
||||
|
||||
define i32 @main() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli -force-interpreter=true %s | grep 1
|
||||
; RUN: %lli -force-interpreter=true %s | grep 1
|
||||
|
||||
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
|
||||
target triple = "i686-pc-linux-gnu"
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli -force-interpreter=true %s
|
||||
; RUN: %lli -force-interpreter=true %s
|
||||
|
||||
define i32 @main() {
|
||||
%a = add i32 0, undef
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli -force-interpreter=true %s | grep 40091eb8
|
||||
; RUN: %lli -force-interpreter=true %s | grep 40091eb8
|
||||
;
|
||||
define i32 @test(double %x) {
|
||||
entry:
|
||||
|
@ -1,5 +1,6 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
; XFAIL: mcjit
|
||||
|
||||
@.LC0 = internal global [12 x i8] c"Hello World\00" ; <[12 x i8]*> [#uses=1]
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
; XFAIL: mcjit
|
||||
|
||||
@X = global i32 7 ; <i32*> [#uses=0]
|
||||
@msg = internal global [13 x i8] c"Hello World\0A\00" ; <[13 x i8]*> [#uses=1]
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
ret i32 0
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
|
||||
define i32 @bar() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
; RUN: lli -disable-lazy-compilation=false %s
|
||||
; RUN: %lli -disable-lazy-compilation=false %s
|
||||
; XFAIL: arm
|
||||
; XFAIL: mcjit
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
%A = add i8 0, 12 ; <i8> [#uses=1]
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
; test unconditional branch
|
||||
define i32 @main() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
; XFAIL: mcjit
|
||||
|
||||
declare void @exit(i32)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
define i32 @foo() {
|
||||
ret i32 0
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
; This tests to make sure that we can evaluate weird constant expressions
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: mcjit
|
||||
|
||||
define double @test(double* %DP, double %Arg) {
|
||||
%D = load double* %DP ; <double> [#uses=1]
|
||||
|
@ -1,5 +1,6 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
; XFAIL: arm
|
||||
; XFAIL: mcjit-ia32
|
||||
|
||||
define void @test(i8* %P, i16* %P.upgrd.1, i32* %P.upgrd.2, i64* %P.upgrd.3) {
|
||||
%V = load i8* %P ; <i8> [#uses=1]
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
%A = and i8 4, 8 ; <i8> [#uses=2]
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
; <label>:0
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
; test phi node
|
||||
@Y = global i32 6 ; <i32*> [#uses=1]
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
; test return instructions
|
||||
define void @test1() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
|
||||
define i32 @main() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
%int1 = add i32 0, 0 ; <i32> [#uses=6]
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: lli %s > /dev/null
|
||||
; RUN: %lli %s > /dev/null
|
||||
|
||||
define i32 @main() {
|
||||
%shamt = add i8 0, 1 ; <i8> [#uses=8]
|
||||
|
30
test/lit.cfg
30
test/lit.cfg
@ -141,6 +141,29 @@ for line in open(os.path.join(config.llvm_obj_root, 'test', 'site.exp')):
|
||||
if m:
|
||||
site_exp[m.group(1)] = m.group(2)
|
||||
|
||||
# Provide target_triple for use in XFAIL and XTARGET.
|
||||
config.target_triple = site_exp['target_triplet']
|
||||
|
||||
# When running under valgrind, we mangle '-vg' or '-vg_leak' onto the end of the
|
||||
# triple so we can check it with XFAIL and XTARGET.
|
||||
config.target_triple += lit.valgrindTriple
|
||||
|
||||
# Process jit implementation option
|
||||
jit_impl_cfg = lit.params.get('jit_impl', None)
|
||||
if jit_impl_cfg == 'mcjit':
|
||||
# When running with mcjit, mangle -mcjit into target triple
|
||||
# and add -use-mcjit flag to lli invocation
|
||||
if 'i686' in config.target_triple:
|
||||
config.target_triple += jit_impl_cfg + '-ia32'
|
||||
elif 'x86_64' in config.target_triple:
|
||||
config.target_triple += jit_impl_cfg + '-ia64'
|
||||
else:
|
||||
config.target_triple += jit_impl_cfg
|
||||
|
||||
config.substitutions.append( ('%lli', 'lli -use-mcjit') )
|
||||
else:
|
||||
config.substitutions.append( ('%lli', 'lli') )
|
||||
|
||||
# Add substitutions.
|
||||
for sub in ['link', 'shlibext', 'ocamlopt', 'llvmshlibdir']:
|
||||
config.substitutions.append(('%' + sub, site_exp[sub]))
|
||||
@ -197,13 +220,6 @@ for pattern in [r"\bbugpoint\b(?!-)", r"(?<!/|-)\bclang\b(?!-)",
|
||||
|
||||
excludes = []
|
||||
|
||||
# Provide target_triple for use in XFAIL and XTARGET.
|
||||
config.target_triple = site_exp['target_triplet']
|
||||
|
||||
# When running under valgrind, we mangle '-vg' or '-vg_leak' onto the end of the
|
||||
# triple so we can check it with XFAIL and XTARGET.
|
||||
config.target_triple += lit.valgrindTriple
|
||||
|
||||
# Provide llvm_supports_target for use in local configs.
|
||||
targets = set(site_exp["TARGETS_TO_BUILD"].split())
|
||||
def llvm_supports_target(name):
|
||||
|
@ -95,12 +95,12 @@ namespace {
|
||||
"of the executable"),
|
||||
cl::value_desc("function"),
|
||||
cl::init("main"));
|
||||
|
||||
|
||||
cl::opt<std::string>
|
||||
FakeArgv0("fake-argv0",
|
||||
cl::desc("Override the 'argv[0]' value passed into the executing"
|
||||
" program"), cl::value_desc("executable"));
|
||||
|
||||
|
||||
cl::opt<bool>
|
||||
DisableCoreFiles("disable-core-files", cl::Hidden,
|
||||
cl::desc("Disable emission of core files if possible"));
|
||||
@ -159,7 +159,7 @@ static void do_shutdown() {
|
||||
int main(int argc, char **argv, char * const *envp) {
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
|
||||
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
atexit(do_shutdown); // Call llvm_shutdown() on exit.
|
||||
|
||||
@ -174,7 +174,7 @@ int main(int argc, char **argv, char * const *envp) {
|
||||
// If the user doesn't want core files, disable them.
|
||||
if (DisableCoreFiles)
|
||||
sys::Process::PreventCoreFiles();
|
||||
|
||||
|
||||
// Load the bitcode...
|
||||
SMDiagnostic Err;
|
||||
Module *Mod = ParseIRFile(InputFile, Err, Context);
|
||||
@ -210,9 +210,11 @@ int main(int argc, char **argv, char * const *envp) {
|
||||
if (!TargetTriple.empty())
|
||||
Mod->setTargetTriple(Triple::normalize(TargetTriple));
|
||||
|
||||
// Enable MCJIT, if desired.
|
||||
if (UseMCJIT)
|
||||
// Enable MCJIT if desired.
|
||||
if (UseMCJIT && !ForceInterpreter) {
|
||||
builder.setUseMCJIT(true);
|
||||
builder.setJITMemoryManager(JITMemoryManager::CreateDefaultMemManager());
|
||||
}
|
||||
|
||||
CodeGenOpt::Level OLvl = CodeGenOpt::Default;
|
||||
switch (OptLevel) {
|
||||
@ -265,15 +267,15 @@ int main(int argc, char **argv, char * const *envp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If the program doesn't explicitly call exit, we will need the Exit
|
||||
// function later on to make an explicit call, so get the function now.
|
||||
// If the program doesn't explicitly call exit, we will need the Exit
|
||||
// function later on to make an explicit call, so get the function now.
|
||||
Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context),
|
||||
Type::getInt32Ty(Context),
|
||||
NULL);
|
||||
|
||||
|
||||
// Reset errno to zero on entry to main.
|
||||
errno = 0;
|
||||
|
||||
|
||||
// Run static constructors.
|
||||
EE->runStaticConstructorsDestructors(false);
|
||||
|
||||
@ -290,8 +292,8 @@ int main(int argc, char **argv, char * const *envp) {
|
||||
|
||||
// Run static destructors.
|
||||
EE->runStaticConstructorsDestructors(true);
|
||||
|
||||
// If the program didn't call exit explicitly, we should call it now.
|
||||
|
||||
// If the program didn't call exit explicitly, we should call it now.
|
||||
// This ensures that any atexit handlers get called correctly.
|
||||
if (Function *ExitF = dyn_cast<Function>(Exit)) {
|
||||
std::vector<GenericValue> Args;
|
||||
|
Loading…
Reference in New Issue
Block a user