Add support for vector load/store with element size not a multiple of 8
MODIFY
ir/memory.cpp
ir/memory.cpp
@@ -273,6 +273,7 @@ static vector<Byte> valueToBytes(const StateValue &val, const Type &fromType,
for (unsigned i = 0; i < bytesize; ++i)
bytes.emplace_back(p, i, val.non_poison);
} else {
+ assert(!fromType.isAggregateType() || isNonPtrVector(fromType));
StateValue bvval = fromType.toInt(*s, val);
unsigned bitsize = bvval.bits();
unsigned bytesize = divide_up(bitsize, bits_byte);
@@ -325,6 +326,7 @@ static StateValue bytesToValue(const Memory &m, const vector<Byte> &bytes,
move(non_poison) };
} else {
+ assert(!toType.isAggregateType() || isNonPtrVector(toType));
auto bitsize = toType.bits();
assert(divide_up(bitsize, bits_byte) == bytes.size());
@@ -1454,7 +1456,8 @@ unsigned Memory::getStoreByteSize(const Type &ty) {
if (ty.isPtrType())
return divide_up(bits_program_pointer, 8);
- if (auto aty = ty.getAsAggregateType()) {
+ auto aty = ty.getAsAggregateType();
+ if (aty && !isNonPtrVector(ty)) {
unsigned sz = 0;
for (unsigned i = 0; i < aty->numElementsConst(); ++i)
sz += getStoreByteSize(aty->getChild(i));
@@ -1476,7 +1479,8 @@ void Memory::store(const expr &p, const StateValue &v, const Type &type,
state->addUB(ptr.is_dereferenceable(getStoreByteSize(type), align,
!state->isInitializationPhase()));
- if (auto aty = type.getAsAggregateType()) {
+ auto aty = type.getAsAggregateType();
+ if (aty && !isNonPtrVector(type)) {
unsigned byteofs = 0;
for (unsigned i = 0, e = aty->numElementsConst(); i < e; ++i) {
auto &child = aty->getChild(i);
@@ -1512,7 +1516,8 @@ Memory::load(const expr &p, const Type &type, unsigned align) {
auto ubs = ptr.is_dereferenceable(bytecount, align, false);
StateValue ret;
- if (auto aty = type.getAsAggregateType()) {
+ auto aty = type.getAsAggregateType();
+ if (aty && !isNonPtrVector(type)) {
vector<StateValue> member_vals;
unsigned byteofs = 0;
for (unsigned i = 0, e = aty->numElementsConst(); i < e; ++i) {

MODIFY
ir/type.cpp
ir/type.cpp
@@ -720,22 +720,36 @@ StateValue AggregateType::aggregateVals(const vector<StateValue> &vals) const {
return v;
}
-StateValue AggregateType::extract(const StateValue &val, unsigned index) const {
+StateValue
+AggregateType::extract(const StateValue &val, unsigned index, bool fromInt)
+ const {
unsigned total_value = 0, total_np = 0;
for (unsigned i = 0; i < index; ++i) {
total_value += children[i]->bits();
total_np += children[i]->np_bits();
}
+
+ unsigned h_val, l_val, h_np, l_np;
+ if (fromInt && little_endian) {
+ h_val = total_value + children[index]->bits() - 1;
+ l_val = total_value;
+
+ h_np = total_np + children[index]->np_bits() - 1;
+ l_np = total_np;
+ } else {
unsigned high_val = bits() - total_value;
- unsigned h_val = high_val - 1;
- unsigned l_val = high_val - children[index]->bits();
+ h_val = high_val - 1;
+ l_val = high_val - children[index]->bits();
unsigned high_np = np_bits() - total_np;
- unsigned h_np = high_np - 1;
- unsigned l_np = high_np - children[index]->np_bits();
+ h_np = high_np - 1;
+ l_np = high_np - children[index]->np_bits();
+ }
- return children[index]->fromBV({ val.value.extract(h_val, l_val),
- val.non_poison.extract(h_np, l_np) });
+ StateValue sv(val.value.extract(h_val, l_val),
+ val.non_poison.extract(h_np, l_np));
+ return fromInt ? children[index]->fromInt(move(sv)) :
+ children[index]->fromBV(move(sv));
}
unsigned AggregateType::bits() const {
@@ -856,7 +870,10 @@ expr AggregateType::fromInt(expr v) const {
}
StateValue AggregateType::fromInt(StateValue v) const {
- UNREACHABLE();
+ vector<StateValue> child_vals;
+ for (unsigned i = 0; i < elements; ++i)
+ child_vals.emplace_back(extract(v, i, true));
+ return this->aggregateVals(child_vals);
}
pair<expr, expr>
@@ -1346,4 +1363,13 @@ bool hasPtr(const Type &t) {
}
return false;
}
+
+bool isNonPtrVector(const Type &t) {
+ auto vty = dynamic_cast<const VectorType *>(&t);
+ if (!vty || vty->numElementsConst() == 0)
+ return false;
+ auto &child = vty->getChild(0);
+ return !child.isPtrType();
+}
+
}

MODIFY
ir/type.h
ir/type.h
@@ -267,7 +267,8 @@ public:
unsigned numElementsConst() const { return elements; }
StateValue aggregateVals(const std::vector<StateValue> &vals) const;
- IR::StateValue extract(const IR::StateValue &val, unsigned index) const;
+ IR::StateValue extract(const IR::StateValue &val, unsigned index,
+ bool fromInt = false) const;
Type& getChild(unsigned index) const { return *children[index]; }
bool isPadding(unsigned i) const { return is_padding[i]; }
@@ -408,5 +409,6 @@ public:
bool hasPtr(const Type &t);
+bool isNonPtrVector(const Type &t);
}

ADD
tests/alive-tv/memory/vectors-float.srctgt.ll
+target datalayout="e"
+
+define i64 @src(<2 x float>* %p) {
+ store <2 x float> <float 1.0, float 2.0>, <2 x float>* %p
+ %p2 = bitcast <2 x float>* %p to i64*
+ %i = load i64, i64* %p2
+ ret i64 %i
+}
+
+define i64 @tgt(<2 x float>* %p) {
+ store <2 x float> <float 1.0, float 2.0>, <2 x float>* %p
+ ret i64 4611686019492741120
+}

ADD
tests/alive-tv/memory/vectors-i12.srctgt.ll
+; TEST-ARGS: -bidirectional
+target datalayout="e"
+
+define i24 @src(<2 x i12>* %p) {
+ store <2 x i12> <i12 4094, i12 2050>, <2 x i12>* %p
+ %p2 = bitcast <2 x i12>* %p to i24*
+ %v = load i24, i24* %p2
+ ret i24 %v
+}
+
+define i24 @tgt(<2 x i12>* %p) {
+ store <2 x i12> <i12 4094, i12 2050>, <2 x i12>* %p
+ ret i24 8400894
+}
+

ADD
tests/alive-tv/memory/vectors-small-bigendian-fail.srctgt.ll
+target datalayout="E"
+target triple = "powerpc64-unknown-linux-gnu"
+
+define void @src(<3 x i2>* %p) {
+ ; 00011011 = 27
+ store <3 x i2> <i2 1, i2 2, i2 3>, <3 x i2>* %p
+ ret void
+}
+
+define void @tgt(<3 x i2>* %p) {
+ store <3 x i2> <i2 1, i2 2, i2 2>, <3 x i2>* %p
+ ret void
+}
+
+; ERROR: Mismatch in memory

ADD
tests/alive-tv/memory/vectors-small-bigendian.src.ll
+target datalayout="E"
+target triple = "powerpc64-unknown-linux-gnu"
+
+define i8 @f(<3 x i2>* %p) {
+ ; 00011011 = 27
+ store <3 x i2> <i2 1, i2 2, i2 3>, <3 x i2>* %p
+ %q = load <3 x i2>, <3 x i2>* %p
+ %w = bitcast <3 x i2> %q to i6
+ %v = zext i6 %w to i8
+ ret i8 %v
+}
+
+define i8 @f2(<3 x i2>* %p) {
+ store <3 x i2> <i2 1, i2 2, i2 3>, <3 x i2>* %p
+ %p2 = bitcast <3 x i2>* %p to i8*
+ %v = load i8, i8* %p2
+ ret i8 %v
+}
+

ADD
tests/alive-tv/memory/vectors-small-bigendian.tgt.ll
+target datalayout="E"
+target triple = "powerpc64-unknown-linux-gnu"
+
+define i8 @f(<3 x i2>* %p) {
+ %p2 = bitcast <3 x i2>* %p to i8*
+ store i8 27, i8* %p2
+ ret i8 27
+}
+
+define i8 @f2(<3 x i2>* %p) {
+ %p2 = bitcast <3 x i2>* %p to i8*
+ store i8 27, i8* %p2
+ ret i8 27
+}

ADD
tests/alive-tv/memory/vectors-small-fail.srctgt.ll
+target datalayout="e"
+
+define void @src(<3 x i2>* %p) {
+ store <3 x i2> <i2 1, i2 2, i2 3>, <3 x i2>* %p
+ ret void
+}
+
+define void @tgt(<3 x i2>* %p) {
+ store <3 x i2> <i2 1, i2 2, i2 2>, <3 x i2>* %p
+ ret void
+}
+
+; ERROR: Mismatch in memory

ADD
tests/alive-tv/memory/vectors-small.src.ll
+target datalayout="e"
+
+define i8 @f(<3 x i2>* %p) {
+ ; 00111001 = 57
+ store <3 x i2> <i2 1, i2 2, i2 3>, <3 x i2>* %p
+ %q = load <3 x i2>, <3 x i2>* %p
+ %w = bitcast <3 x i2> %q to i6
+ %v = zext i6 %w to i8
+ ret i8 %v
+}
+
+define i8 @f2(<3 x i2>* %p) {
+ store <3 x i2> <i2 1, i2 2, i2 3>, <3 x i2>* %p
+ %p2 = bitcast <3 x i2>* %p to i8*
+ %v = load i8, i8* %p2
+ ret i8 %v
+}
+

ADD
tests/alive-tv/memory/vectors-small.tgt.ll
+target datalayout="e"
+
+define i8 @f(<3 x i2>* %p) {
+ %p2 = bitcast <3 x i2>* %p to i8*
+ store i8 57, i8* %p2
+ ret i8 57
+}
+
+define i8 @f2(<3 x i2>* %p) {
+ %p2 = bitcast <3 x i2>* %p to i8*
+ store i8 57, i8* %p2
+ ret i8 57
+}

Add support for vector load/store with element size not a multiple of 8 (#347)