Add support for big-endian
MODIFY
ir/function.h
ir/function.h
@@ -56,6 +56,8 @@ class Function final {
std::unordered_map<std::string, BasicBlock> BBs;
std::vector<BasicBlock*> BB_order;
+ bool little_endian;
+
// constants used in this function
std::vector<std::unique_ptr<Value>> constants;
std::vector<std::unique_ptr<Predicate>> predicates;
@@ -64,8 +66,8 @@ class Function final {
public:
Function() {}
- Function(Type &type, std::string &&name)
- : type(&type), name(std::move(name)) {}
+ Function(Type &type, std::string &&name, bool little_endian = true)
+ : type(&type), name(std::move(name)), little_endian(little_endian) {}
const IR::Type& getType() const { return type ? *type : Type::voidTy; }
void setType(IR::Type &t) { type = &t; }
@@ -97,6 +99,7 @@ public:
}
bool hasReturn() const;
+ bool isLittleEndian() const { return little_endian; }
void syncDataWithSrc(const Function &src);

MODIFY
ir/memory.cpp
ir/memory.cpp
@@ -376,7 +376,8 @@ static unsigned last_local_bid;
static unsigned last_nonlocal_bid;
static unsigned last_idx_ptr;
-Memory::Memory(State &state) : state(&state) {
+Memory::Memory(State &state, bool little_endian)
+ : state(&state), little_endian(little_endian) {
blocks_val = mk_val_array("blks_val");
blocks_readonly = mk_readonly_array("blks_readonly");
blocks_liveness = mk_liveness_uf();
@@ -490,8 +491,8 @@ void Memory::store(const expr &p, const StateValue &v, const Type &type,
Pointer ptr(*this, p);
ptr.is_dereferenceable(bytes.size(), align, true);
for (unsigned i = 0, e = bytes.size(); i < e; ++i) {
- // FIXME: support big-endian
- blocks_val = blocks_val.store((ptr + i).release(), bytes[i]());
+ auto ptr_i = little_endian ? (ptr + i) : (ptr + (e - i - 1));
+ blocks_val = blocks_val.store(ptr_i.release(), bytes[i]());
}
}
@@ -504,7 +505,8 @@ StateValue Memory::load(const expr &p, const Type &type, unsigned align) {
vector<Byte> loadedBytes;
for (unsigned i = 0; i < bytesize; ++i) {
- loadedBytes.emplace_back(*this, blocks_val.load((ptr + i).release()));
+ auto ptr_i = little_endian ? (ptr + i) : (ptr + (bytesize - i - 1));
+ loadedBytes.emplace_back(*this, blocks_val.load(ptr_i.release()));
}
return bytesToValue(loadedBytes, type);
}

MODIFY
ir/memory.h
ir/memory.h
@@ -103,6 +103,8 @@ class Memory {
// bits_size_t is equivalent to the size of a pointer.
unsigned bits_size_t = 64;
+ bool little_endian;
+
smt::expr blocks_val; // array: (bid, offset) -> Byte
smt::expr blocks_liveness; // array: bid -> bool
smt::expr blocks_kind; // array: bid -> uint(1bit), 1 if heap, 0 otherwise
@@ -120,7 +122,7 @@ public:
HEAP, STACK, GLOBAL, CONSTGLOBAL
};
- Memory(State &state);
+ Memory(State &state, bool little_endian);
static void resetGlobalData();
static void resetLocalBids();

MODIFY
ir/state.cpp
ir/state.cpp
@@ -14,7 +14,8 @@ using namespace std;
namespace IR {
State::State(const Function &f, bool source)
- : f(f), source(source), memory(*this), return_domain(false) {
+ : f(f), source(source), memory(*this, f.isLittleEndian()),
+ return_domain(false) {
return_val.first = f.getType().getDummyValue(false);
}

MODIFY
llvm_util/llvm2alive.cpp
llvm_util/llvm2alive.cpp
@@ -568,7 +568,7 @@ public:
if (!type)
return {};
- Function Fn(*type, f.getName());
+ Function Fn(*type, f.getName(), DL().isLittleEndian());
reset_state(Fn);
for (auto &arg : f.args()) {

ADD
tests/alive-tv/memory/bigendian-fail.src.ll
+target datalayout = "E-p:32:32:32-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-n32"
+
+define i8 @test1(i32* %p) {
+ %q = bitcast i32* %p to i8*
+ store i32 287454020, i32* %p ; 0x11223344
+ ret i8 68
+}
+
+; ERROR: Value mismatch

ADD
tests/alive-tv/memory/bigendian-fail.tgt.ll
+target datalayout = "E-p:32:32:32-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-n32"
+
+define i8 @test1(i32* %p) {
+ %q = bitcast i32* %p to i8*
+ store i32 287454020, i32* %p ; 0x11223344
+ %x = load i8, i8* %q
+ ret i8 %x
+}

ADD
tests/alive-tv/memory/bigendian.src.ll
+target datalayout = "E-p:32:32:32-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-n32"
+
+define i8 @test1(i32* %p) {
+ %q = bitcast i32* %p to i8*
+ store i32 287454020, i32* %p ; 0x11223344
+ %x = load i8, i8* %q
+ ret i8 %x
+}
+
+define i8 @test2(i32* %p) {
+ %q = bitcast i32* %p to i8*
+ store i32 287454020, i32* %p ; 0x11223344
+ %q2 = getelementptr inbounds i8, i8* %q, i64 1
+ %x = load i8, i8* %q2
+ ret i8 %x
+}
+
+define i8 @test3(i32* %p) {
+ %q = bitcast i32* %p to i8*
+ store i32 287454020, i32* %p ; 0x11223344
+ %q2 = getelementptr inbounds i8, i8* %q, i64 2
+ %x = load i8, i8* %q2
+ ret i8 %x
+}
+
+define i8 @test4(i32* %p) {
+ %q = bitcast i32* %p to i8*
+ store i32 287454020, i32* %p ; 0x11223344
+ %q2 = getelementptr inbounds i8, i8* %q, i64 3
+ %x = load i8, i8* %q2
+ ret i8 %x
+}

ADD
tests/alive-tv/memory/bigendian.tgt.ll
+target datalayout = "E-p:32:32:32-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-n32"
+
+define i8 @test1(i32* %p) {
+ %q = bitcast i32* %p to i8*
+ store i32 287454020, i32* %p ; 0x11223344
+ ret i8 17
+}
+
+define i8 @test2(i32* %p) {
+ %q = bitcast i32* %p to i8*
+ store i32 287454020, i32* %p ; 0x11223344
+ ret i8 34
+}
+
+define i8 @test3(i32* %p) {
+ %q = bitcast i32* %p to i8*
+ store i32 287454020, i32* %p ; 0x11223344
+ ret i8 51
+}
+
+define i8 @test4(i32* %p) {
+ %q = bitcast i32* %p to i8*
+ store i32 287454020, i32* %p ; 0x11223344
+ ret i8 68
+}

ADD
tests/alive-tv/memory/pre-bigendian.src.ll
+; This was excerpted from GVN/PRE/rle.ll
+; TEST-ARGS: -disable-undef-input
+target datalayout = "E-p:32:32:32-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-n32"
+
+define i8 @coerce_mustalias_pre0(i32* %P, i1 %cond) {
+ %P3 = bitcast i32* %P to i8*
+ br i1 %cond, label %T, label %F
+T:
+ store i32 42, i32* %P
+ br label %Cont
+
+F:
+ br label %Cont
+
+Cont:
+ %A = load i8, i8* %P3
+ ret i8 %A
+}

ADD
tests/alive-tv/memory/pre-bigendian.tgt.ll
+target datalayout = "E-p:32:32:32-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-n32"
+
+define i8 @coerce_mustalias_pre0(i32* %P, i1 %cond) {
+ %P3 = bitcast i32* %P to i8*
+ br i1 %cond, label %T, label %F
+
+T: ; preds = %0
+ store i32 42, i32* %P
+ br label %Cont
+
+F: ; preds = %0
+ %A.pre = load i8, i8* %P3
+ br label %Cont
+
+Cont: ; preds = %F, %T
+ %A = phi i8 [ %A.pre, %F ], [ 0, %T ]
+ ret i8 %A
+}

MODIFY
tools/alive-tv.cpp
tools/alive-tv.cpp
@@ -188,14 +188,16 @@ static bool compareFunctions(llvm::Function &F1, llvm::Function &F2,
TransformPrintOpts print_opts;
- auto Func1 = llvm2alive(F1, llvm::TargetLibraryInfoWrapperPass(targetTriple).getTLI(F1));
+ auto Func1 = llvm2alive(F1, llvm::TargetLibraryInfoWrapperPass(targetTriple)
+ .getTLI(F1));
if (!Func1) {
cerr << "Could not translate '" + (std::string)F1.getName() + "' to Alive IR\n";
++errorCount;
return true;
}
- auto Func2 = llvm2alive(F2, llvm::TargetLibraryInfoWrapperPass(targetTriple).getTLI(F2));
+ auto Func2 = llvm2alive(F2, llvm::TargetLibraryInfoWrapperPass(targetTriple)
+ .getTLI(F2));
if (!Func2) {
cerr << "Could not translate '" + (std::string)F2.getName() + "' to Alive IR\n";
++errorCount;

Add support for big-endian (#151)