aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/ExecutionEngine/ExecutionEngine.cpp153
-rw-r--r--test/ExecutionEngine/2007-12-14-BigEndian.ll81
-rw-r--r--test/ExecutionEngine/2007-12-14-LittleEndian.ll81
3 files changed, 256 insertions, 59 deletions
diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp
index 521e423..707ed60 100644
--- a/lib/ExecutionEngine/ExecutionEngine.cpp
+++ b/lib/ExecutionEngine/ExecutionEngine.cpp
@@ -18,6 +18,7 @@
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Config/alloca.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/Support/Debug.h"
@@ -232,6 +233,15 @@ void ExecutionEngine::runStaticConstructorsDestructors(bool isDtors) {
}
}
+/// isTargetNullPtr - Return whether the target pointer stored at Loc is null.
+static bool isTargetNullPtr(ExecutionEngine *EE, void *Loc) {
+ unsigned PtrSize = EE->getTargetData()->getPointerSize();
+ for (unsigned i = 0; i < PtrSize; ++i)
+ if (*(i + (uint8_t*)Loc))
+ return false;
+ return true;
+}
+
/// runFunctionAsMain - This is a helper function which wraps runFunction to
/// handle the common task of starting up main with the specified argc, argv,
/// and envp parameters.
@@ -281,7 +291,7 @@ int ExecutionEngine::runFunctionAsMain(Function *Fn,
GVArgs.push_back(GVArgc); // Arg #0 = argc.
if (NumArgs > 1) {
GVArgs.push_back(PTOGV(CreateArgv(this, argv))); // Arg #1 = argv.
- assert(((char **)GVTOP(GVArgs[1]))[0] &&
+ assert(!isTargetNullPtr(this, GVTOP(GVArgs[1])) &&
"argv[0] was null after CreateArgv");
if (NumArgs > 2) {
std::vector<std::string> EnvVars;
@@ -624,40 +634,44 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
return Result;
}
+/// StoreIntToMemory - Fills the StoreBytes bytes of memory starting from Dst
+/// with the integer held in IntVal.
+static void StoreIntToMemory(const APInt &IntVal, uint8_t *Dst,
+ unsigned StoreBytes) {
+ assert((IntVal.getBitWidth()+7)/8 >= StoreBytes && "Integer too small!");
+ uint8_t *Src = (uint8_t *)IntVal.getRawData();
+
+ if (sys::littleEndianHost())
+ // Little-endian host - the source is ordered from LSB to MSB. Order the
+ // destination from LSB to MSB: Do a straight copy.
+ memcpy(Dst, Src, StoreBytes);
+ else {
+ // Big-endian host - the source is an array of 64 bit words ordered from
+ // LSW to MSW. Each word is ordered from MSB to LSB. Order the destination
+ // from MSB to LSB: Reverse the word order, but not the bytes in a word.
+ while (StoreBytes > sizeof(uint64_t)) {
+ StoreBytes -= sizeof(uint64_t);
+ // May not be aligned so use memcpy.
+ memcpy(Dst + StoreBytes, Src, sizeof(uint64_t));
+ Src += sizeof(uint64_t);
+ }
+
+ memcpy(Dst, Src + sizeof(uint64_t) - StoreBytes, StoreBytes);
+ }
+}
+
/// StoreValueToMemory - Stores the data in Val of type Ty at address Ptr. Ptr
/// is the address of the memory at which to store Val, cast to GenericValue *.
/// It is not a pointer to a GenericValue containing the address at which to
/// store Val.
-///
void ExecutionEngine::StoreValueToMemory(const GenericValue &Val, GenericValue *Ptr,
const Type *Ty) {
- switch (Ty->getTypeID()) {
- case Type::IntegerTyID: {
- unsigned BitWidth = cast<IntegerType>(Ty)->getBitWidth();
- unsigned StoreBytes = (BitWidth + 7)/8;
- uint8_t *Src = (uint8_t *)Val.IntVal.getRawData();
- uint8_t *Dst = (uint8_t *)Ptr;
-
- if (sys::littleEndianHost())
- // Little-endian host - the source is ordered from LSB to MSB.
- // Order the destination from LSB to MSB: Do a straight copy.
- memcpy(Dst, Src, StoreBytes);
- else {
- // Big-endian host - the source is an array of 64 bit words ordered from
- // LSW to MSW. Each word is ordered from MSB to LSB.
- // Order the destination from MSB to LSB: Reverse the word order, but not
- // the bytes in a word.
- while (StoreBytes > sizeof(uint64_t)) {
- StoreBytes -= sizeof(uint64_t);
- // May not be aligned so use memcpy.
- memcpy(Dst + StoreBytes, Src, sizeof(uint64_t));
- Src += sizeof(uint64_t);
- }
+ const unsigned StoreBytes = getTargetData()->getTypeStoreSize(Ty);
- memcpy(Dst, Src + sizeof(uint64_t) - StoreBytes, StoreBytes);
- }
+ switch (Ty->getTypeID()) {
+ case Type::IntegerTyID:
+ StoreIntToMemory(Val.IntVal, (uint8_t*)Ptr, StoreBytes);
break;
- }
case Type::FloatTyID:
*((float*)Ptr) = Val.FloatVal;
break;
@@ -675,61 +689,82 @@ void ExecutionEngine::StoreValueToMemory(const GenericValue &Val, GenericValue *
Dest[4] = Src[3];
break;
}
- case Type::PointerTyID:
+ case Type::PointerTyID:
+ // Ensure 64 bit target pointers are fully initialized on 32 bit hosts.
+ if (StoreBytes != sizeof(PointerTy))
+ memset(Ptr, 0, StoreBytes);
+
*((PointerTy*)Ptr) = Val.PointerVal;
break;
default:
cerr << "Cannot store value of type " << *Ty << "!\n";
}
+
+ if (sys::littleEndianHost() != getTargetData()->isLittleEndian())
+ // Host and target are different endian - reverse the stored bytes.
+ std::reverse((uint8_t*)Ptr, StoreBytes + (uint8_t*)Ptr);
+}
+
+/// LoadIntFromMemory - Loads the integer stored in the LoadBytes bytes starting
+/// from Src into IntVal, which is assumed to be wide enough and to hold zero.
+static void LoadIntFromMemory(APInt &IntVal, uint8_t *Src, unsigned LoadBytes) {
+ assert((IntVal.getBitWidth()+7)/8 >= LoadBytes && "Integer too small!");
+ uint8_t *Dst = (uint8_t *)IntVal.getRawData();
+
+ if (sys::littleEndianHost())
+ // Little-endian host - the destination must be ordered from LSB to MSB.
+ // The source is ordered from LSB to MSB: Do a straight copy.
+ memcpy(Dst, Src, LoadBytes);
+ else {
+ // Big-endian - the destination is an array of 64 bit words ordered from
+ // LSW to MSW. Each word must be ordered from MSB to LSB. The source is
+ // ordered from MSB to LSB: Reverse the word order, but not the bytes in
+ // a word.
+ while (LoadBytes > sizeof(uint64_t)) {
+ LoadBytes -= sizeof(uint64_t);
+ // May not be aligned so use memcpy.
+ memcpy(Dst, Src + LoadBytes, sizeof(uint64_t));
+ Dst += sizeof(uint64_t);
+ }
+
+ memcpy(Dst + sizeof(uint64_t) - LoadBytes, Src, LoadBytes);
+ }
}
/// FIXME: document
///
-void ExecutionEngine::LoadValueFromMemory(GenericValue &Result,
+void ExecutionEngine::LoadValueFromMemory(GenericValue &Result,
GenericValue *Ptr,
const Type *Ty) {
- switch (Ty->getTypeID()) {
- case Type::IntegerTyID: {
- unsigned BitWidth = cast<IntegerType>(Ty)->getBitWidth();
- unsigned LoadBytes = (BitWidth + 7)/8;
+ const unsigned LoadBytes = getTargetData()->getTypeStoreSize(Ty);
+
+ if (sys::littleEndianHost() != getTargetData()->isLittleEndian()) {
+ // Host and target are different endian - reverse copy the stored
+ // bytes into a buffer, and load from that.
+ uint8_t *Src = (uint8_t*)Ptr;
+ uint8_t *Buf = (uint8_t*)alloca(LoadBytes);
+ std::reverse_copy(Src, Src + LoadBytes, Buf);
+ Ptr = (GenericValue*)Buf;
+ }
+ switch (Ty->getTypeID()) {
+ case Type::IntegerTyID:
// An APInt with all words initially zero.
- Result.IntVal = APInt(BitWidth, 0);
-
- uint8_t *Src = (uint8_t *)Ptr;
- uint8_t *Dst = (uint8_t *)Result.IntVal.getRawData();
-
- if (sys::littleEndianHost())
- // Little-endian host - the destination must be ordered from LSB to MSB.
- // The source is ordered from LSB to MSB: Do a straight copy.
- memcpy(Dst, Src, LoadBytes);
- else {
- // Big-endian - the destination is an array of 64 bit words ordered from
- // LSW to MSW. Each word must be ordered from MSB to LSB. The source is
- // ordered from MSB to LSB: Reverse the word order, but not the bytes in
- // a word.
- while (LoadBytes > sizeof(uint64_t)) {
- LoadBytes -= sizeof(uint64_t);
- // May not be aligned so use memcpy.
- memcpy(Dst, Src + LoadBytes, sizeof(uint64_t));
- Dst += sizeof(uint64_t);
- }
-
- memcpy(Dst + sizeof(uint64_t) - LoadBytes, Src, LoadBytes);
- }
+ Result.IntVal = APInt(cast<IntegerType>(Ty)->getBitWidth(), 0);
+ LoadIntFromMemory(Result.IntVal, (uint8_t*)Ptr, LoadBytes);
break;
- }
case Type::FloatTyID:
Result.FloatVal = *((float*)Ptr);
break;
case Type::DoubleTyID:
- Result.DoubleVal = *((double*)Ptr);
+ Result.DoubleVal = *((double*)Ptr);
break;
- case Type::PointerTyID:
+ case Type::PointerTyID:
Result.PointerVal = *((PointerTy*)Ptr);
break;
case Type::X86_FP80TyID: {
// This is endian dependent, but it will only work on x86 anyway.
+ // FIXME: Does not trap if loading a trapping NaN.
uint16_t *p = (uint16_t*)Ptr;
union {
uint16_t x[8];
diff --git a/test/ExecutionEngine/2007-12-14-BigEndian.ll b/test/ExecutionEngine/2007-12-14-BigEndian.ll
new file mode 100644
index 0000000..68059fd
--- /dev/null
+++ b/test/ExecutionEngine/2007-12-14-BigEndian.ll
@@ -0,0 +1,81 @@
+; RUN: llvm-as < %s -o - | lli -force-interpreter
+
+target datalayout = "E"
+
+define i32 @main() {
+entry:
+ %i = alloca i93
+ store i93 18364758544493064720, i93* %i
+ %i1 = load i93* %i
+ %i2 = shl i93 %i1, 32
+ %i3 = or i93 %i2, 3753679480
+ store i93 %i3, i93* %i
+ %i4 = load i93* %i
+ %C = icmp eq i93 %i3, %i4
+ br i1 %C, label %ok1, label %fail
+ok1:
+ %b = bitcast i93* %i to [12 x i8]*
+ %b0 = getelementptr [12 x i8]* %b, i32 0, i32 0
+ %v0 = load i8* %b0
+ %c0 = icmp eq i8 %v0, 30
+ br i1 %c0, label %ok2, label %fail
+ok2:
+ %b1 = getelementptr [12 x i8]* %b, i32 0, i32 1
+ %v1 = load i8* %b1
+ %c1 = icmp eq i8 %v1, 220
+ br i1 %c1, label %ok3, label %fail
+ok3:
+ %b2 = getelementptr [12 x i8]* %b, i32 0, i32 2
+ %v2 = load i8* %b2
+ %c2 = icmp eq i8 %v2, 186
+ br i1 %c2, label %ok4, label %fail
+ok4:
+ %b3 = getelementptr [12 x i8]* %b, i32 0, i32 3
+ %v3 = load i8* %b3
+ %c3 = icmp eq i8 %v3, 152
+ br i1 %c3, label %ok5, label %fail
+ok5:
+ %b4 = getelementptr [12 x i8]* %b, i32 0, i32 4
+ %v4 = load i8* %b4
+ %c4 = icmp eq i8 %v4, 118
+ br i1 %c4, label %ok6, label %fail
+ok6:
+ %b5 = getelementptr [12 x i8]* %b, i32 0, i32 5
+ %v5 = load i8* %b5
+ %c5 = icmp eq i8 %v5, 84
+ br i1 %c5, label %ok7, label %fail
+ok7:
+ %b6 = getelementptr [12 x i8]* %b, i32 0, i32 6
+ %v6 = load i8* %b6
+ %c6 = icmp eq i8 %v6, 50
+ br i1 %c6, label %ok8, label %fail
+ok8:
+ %b7 = getelementptr [12 x i8]* %b, i32 0, i32 7
+ %v7 = load i8* %b7
+ %c7 = icmp eq i8 %v7, 16
+ br i1 %c7, label %ok9, label %fail
+ok9:
+ %b8 = getelementptr [12 x i8]* %b, i32 0, i32 8
+ %v8 = load i8* %b8
+ %c8 = icmp eq i8 %v8, 223
+ br i1 %c8, label %okA, label %fail
+okA:
+ %b9 = getelementptr [12 x i8]* %b, i32 0, i32 9
+ %v9 = load i8* %b9
+ %c9 = icmp eq i8 %v9, 188
+ br i1 %c9, label %okB, label %fail
+okB:
+ %bA = getelementptr [12 x i8]* %b, i32 0, i32 10
+ %vA = load i8* %bA
+ %cA = icmp eq i8 %vA, 154
+ br i1 %cA, label %okC, label %fail
+okC:
+ %bB = getelementptr [12 x i8]* %b, i32 0, i32 11
+ %vB = load i8* %bB
+ %cB = icmp eq i8 %vB, 120
+ br i1 %cB, label %okD, label %fail
+okD:
+ ret i32 0
+fail:
+ ret i32 1
+}
diff --git a/test/ExecutionEngine/2007-12-14-LittleEndian.ll b/test/ExecutionEngine/2007-12-14-LittleEndian.ll
new file mode 100644
index 0000000..afaed51
--- /dev/null
+++ b/test/ExecutionEngine/2007-12-14-LittleEndian.ll
@@ -0,0 +1,81 @@
+; RUN: llvm-as < %s -o - | lli -force-interpreter
+
+target datalayout = "e"
+
+define i32 @main() {
+entry:
+ %i = alloca i93
+ store i93 18364758544493064720, i93* %i
+ %i1 = load i93* %i
+ %i2 = shl i93 %i1, 32
+ %i3 = or i93 %i2, 3753679480
+ store i93 %i3, i93* %i
+ %i4 = load i93* %i
+ %C = icmp eq i93 %i3, %i4
+ br i1 %C, label %ok1, label %fail
+ok1:
+ %b = bitcast i93* %i to [12 x i8]*
+ %b0 = getelementptr [12 x i8]* %b, i32 0, i32 0
+ %v0 = load i8* %b0
+ %c0 = icmp eq i8 %v0, 120
+ br i1 %c0, label %ok2, label %fail
+ok2:
+ %b1 = getelementptr [12 x i8]* %b, i32 0, i32 1
+ %v1 = load i8* %b1
+ %c1 = icmp eq i8 %v1, 154
+ br i1 %c1, label %ok3, label %fail
+ok3:
+ %b2 = getelementptr [12 x i8]* %b, i32 0, i32 2
+ %v2 = load i8* %b2
+ %c2 = icmp eq i8 %v2, 188
+ br i1 %c2, label %ok4, label %fail
+ok4:
+ %b3 = getelementptr [12 x i8]* %b, i32 0, i32 3
+ %v3 = load i8* %b3
+ %c3 = icmp eq i8 %v3, 223
+ br i1 %c3, label %ok5, label %fail
+ok5:
+ %b4 = getelementptr [12 x i8]* %b, i32 0, i32 4
+ %v4 = load i8* %b4
+ %c4 = icmp eq i8 %v4, 16
+ br i1 %c4, label %ok6, label %fail
+ok6:
+ %b5 = getelementptr [12 x i8]* %b, i32 0, i32 5
+ %v5 = load i8* %b5
+ %c5 = icmp eq i8 %v5, 50
+ br i1 %c5, label %ok7, label %fail
+ok7:
+ %b6 = getelementptr [12 x i8]* %b, i32 0, i32 6
+ %v6 = load i8* %b6
+ %c6 = icmp eq i8 %v6, 84
+ br i1 %c6, label %ok8, label %fail
+ok8:
+ %b7 = getelementptr [12 x i8]* %b, i32 0, i32 7
+ %v7 = load i8* %b7
+ %c7 = icmp eq i8 %v7, 118
+ br i1 %c7, label %ok9, label %fail
+ok9:
+ %b8 = getelementptr [12 x i8]* %b, i32 0, i32 8
+ %v8 = load i8* %b8
+ %c8 = icmp eq i8 %v8, 152
+ br i1 %c8, label %okA, label %fail
+okA:
+ %b9 = getelementptr [12 x i8]* %b, i32 0, i32 9
+ %v9 = load i8* %b9
+ %c9 = icmp eq i8 %v9, 186
+ br i1 %c9, label %okB, label %fail
+okB:
+ %bA = getelementptr [12 x i8]* %b, i32 0, i32 10
+ %vA = load i8* %bA
+ %cA = icmp eq i8 %vA, 220
+ br i1 %cA, label %okC, label %fail
+okC:
+ %bB = getelementptr [12 x i8]* %b, i32 0, i32 11
+ %vB = load i8* %bB
+ %cB = icmp eq i8 %vB, 30
+ br i1 %cB, label %okD, label %fail
+okD:
+ ret i32 0
+fail:
+ ret i32 1
+}