summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>2013-05-03 14:15:35 +0000
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>2013-05-03 14:15:35 +0000
commit6fc2ad62e23673ef829c9c4bbf62743d30928a5b (patch)
tree5d02f72b50273a8b69b172ca35b9e9db79e203d2
parent3ea50a69d75a541624a04ce957cc9eef3de639fc (diff)
downloadllvm-6fc2ad62e23673ef829c9c4bbf62743d30928a5b.tar.gz
llvm-6fc2ad62e23673ef829c9c4bbf62743d30928a5b.tar.bz2
llvm-6fc2ad62e23673ef829c9c4bbf62743d30928a5b.tar.xz
[SystemZ] Add MCJIT support
Another step towards reinstating the SystemZ backend. I'll commit the configure changes separately (TARGET_HAS_JIT etc.), then commit a patch to enable the MCJIT tests on SystemZ. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181015 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp13
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp86
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h5
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h9
4 files changed, 113 insertions, 0 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
index 7b32db7f0e..14c0cd8368 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
@@ -234,6 +234,12 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
Check(Section.isReadOnlyData(IsReadOnly));
Check(Section.getSize(DataSize));
Check(Section.getName(Name));
+ if (StubSize > 0) {
+ unsigned StubAlignment = getStubAlignment();
+ unsigned EndAlignment = (DataSize | Alignment) & -(DataSize | Alignment);
+ if (StubAlignment > EndAlignment)
+ StubBufSize += StubAlignment - EndAlignment;
+ }
unsigned Allocate;
unsigned SectionID = Sections.size();
@@ -371,6 +377,13 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) {
writeInt32BE(Addr+40, 0x4E800420); // bctr
return Addr;
+ } else if (Arch == Triple::systemz) {
+ writeInt16BE(Addr, 0xC418); // lgrl %r1,.+8
+ writeInt16BE(Addr+2, 0x0000);
+ writeInt16BE(Addr+4, 0x0004);
+ writeInt16BE(Addr+6, 0x07F1); // brc 15,%r1
+ // 8-byte address stored at Addr + 8
+ return Addr;
}
return Addr;
}
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
index c5bad8e416..7b8dd30cb8 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
@@ -560,6 +560,42 @@ void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section,
}
}
+void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section,
+ uint64_t Offset,
+ uint64_t Value,
+ uint32_t Type,
+ int64_t Addend) {
+ uint8_t *LocalAddress = Section.Address + Offset;
+ switch (Type) {
+ default:
+ llvm_unreachable("Relocation type not implemented yet!");
+ break;
+ case ELF::R_390_PC16DBL:
+ case ELF::R_390_PLT16DBL: {
+ int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset);
+ assert(int16_t(Delta / 2) * 2 == Delta && "R_390_PC16DBL overflow");
+ writeInt16BE(LocalAddress, Delta / 2);
+ break;
+ }
+ case ELF::R_390_PC32DBL:
+ case ELF::R_390_PLT32DBL: {
+ int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset);
+ assert(int32_t(Delta / 2) * 2 == Delta && "R_390_PC32DBL overflow");
+ writeInt32BE(LocalAddress, Delta / 2);
+ break;
+ }
+ case ELF::R_390_PC32: {
+ int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset);
+ assert(int32_t(Delta) == Delta && "R_390_PC32 overflow");
+ writeInt32BE(LocalAddress, Delta);
+ break;
+ }
+ case ELF::R_390_64:
+ writeInt64BE(LocalAddress, Value + Addend);
+ break;
+ }
+}
+
void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE,
uint64_t Value) {
const SectionEntry &Section = Sections[RE.SectionID];
@@ -595,6 +631,9 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
case Triple::ppc64:
resolvePPC64Relocation(Section, Offset, Value, Type, Addend);
break;
+ case Triple::systemz:
+ resolveSystemZRelocation(Section, Offset, Value, Type, Addend);
+ break;
default: llvm_unreachable("Unsupported CPU type!");
}
}
@@ -839,6 +878,53 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
else
addRelocationForSection(RE, Value.SectionID);
}
+ } else if (Arch == Triple::systemz &&
+ (RelType == ELF::R_390_PLT32DBL ||
+ RelType == ELF::R_390_GOTENT)) {
+ // Create function stubs for both PLT and GOT references, regardless of
+ // whether the GOT reference is to data or code. The stub contains the
+ // full address of the symbol, as needed by GOT references, and the
+ // executable part only adds an overhead of 8 bytes.
+ //
+ // We could try to conserve space by allocating the code and data
+ // parts of the stub separately. However, as things stand, we allocate
+ // a stub for every relocation, so using a GOT in JIT code should be
+ // no less space efficient than using an explicit constant pool.
+ DEBUG(dbgs() << "\t\tThis is a SystemZ indirect relocation.");
+ SectionEntry &Section = Sections[SectionID];
+
+ // Look for an existing stub.
+ StubMap::const_iterator i = Stubs.find(Value);
+ uintptr_t StubAddress;
+ if (i != Stubs.end()) {
+ StubAddress = uintptr_t(Section.Address) + i->second;
+ DEBUG(dbgs() << " Stub function found\n");
+ } else {
+ // Create a new stub function.
+ DEBUG(dbgs() << " Create a new stub function\n");
+
+ uintptr_t BaseAddress = uintptr_t(Section.Address);
+ uintptr_t StubAlignment = getStubAlignment();
+ StubAddress = (BaseAddress + Section.StubOffset +
+ StubAlignment - 1) & -StubAlignment;
+ unsigned StubOffset = StubAddress - BaseAddress;
+
+ Stubs[Value] = StubOffset;
+ createStubFunction((uint8_t *)StubAddress);
+ RelocationEntry RE(SectionID, StubOffset + 8,
+ ELF::R_390_64, Value.Addend - Addend);
+ if (Value.SymbolName)
+ addRelocationForSymbol(RE, Value.SymbolName);
+ else
+ addRelocationForSection(RE, Value.SectionID);
+ Section.StubOffset = StubOffset + getMaxStubSize();
+ }
+
+ if (RelType == ELF::R_390_GOTENT)
+ resolveRelocation(Section, Offset, StubAddress + 8,
+ ELF::R_390_PC32DBL, Addend);
+ else
+ resolveRelocation(Section, Offset, StubAddress, RelType, Addend);
} else {
RelocationEntry RE(SectionID, Offset, RelType, Value.Addend);
if (Value.SymbolName)
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
index 102b1c6b59..12e3122b4c 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
@@ -67,6 +67,11 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
uint32_t Type,
int64_t Addend);
+ void resolveSystemZRelocation(const SectionEntry &Section,
+ uint64_t Offset,
+ uint64_t Value,
+ uint32_t Type,
+ int64_t Addend);
uint64_t findPPC64TOC() const;
void findOPDEntrySection(ObjectImage &Obj,
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
index 51873b1f4b..9d767a067c 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
@@ -172,10 +172,19 @@ protected:
return 16;
else if (Arch == Triple::ppc64)
return 44;
+ else if (Arch == Triple::systemz)
+ return 16;
else
return 0;
}
+ inline unsigned getStubAlignment() {
+ if (Arch == Triple::systemz)
+ return 8;
+ else
+ return 1;
+ }
+
bool HasError;
std::string ErrorStr;