Add vector support for gep
MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -1828,14 +1828,17 @@ void GEP::print(std::ostream &os) const {
}
StateValue GEP::toSMT(State &s) const {
- auto [val, non_poison] = s[*ptr];
+ auto scalar = [&](const StateValue &ptrval,
+ vector<pair<unsigned, StateValue>> &offsets)
+ -> StateValue {
+ auto non_poison = ptrval.non_poison;
+ Pointer ptr(s.getMemory(), ptrval.value);
- Pointer ptr(s.getMemory(), move(val));
if (inbounds)
non_poison &= ptr.inbounds();
- for (auto &[sz, idx] : idxs) {
- auto &[v, np] = s[*idx];
+ for (auto &[sz, idx] : offsets) {
+ auto &[v, np] = idx;
auto multiplier = expr::mkUInt(sz, bits_for_offset);
auto val = v.sextOrTrunc(bits_for_offset);
auto inc = multiplier * val;
@@ -1852,15 +1855,38 @@ StateValue GEP::toSMT(State &s) const {
non_poison &= ptr.inbounds();
}
return { ptr.release(), move(non_poison) };
+ };
+
+ if (auto ptr_aty = ptr->getType().getAsAggregateType()) {
+ vector<StateValue> vals;
+ auto &ptrval = s[*ptr];
+ for (unsigned i = 0, e = ptr_aty->numElementsConst(); i != e; ++i) {
+ vector<pair<unsigned, StateValue>> offsets;
+ for (auto &[sz, idx] : idxs) {
+ if (auto idx_aty = idx->getType().getAsAggregateType())
+ offsets.emplace_back(sz, idx_aty->extract(s[*idx], i));
+ else
+ offsets.emplace_back(sz, s[*idx]);
+ }
+ vals.emplace_back(scalar(ptr_aty->extract(ptrval, i), offsets));
+ }
+ return getType().getAsAggregateType()->aggregateVals(vals);
+ }
+ vector<pair<unsigned, StateValue>> offsets;
+ for (auto &[sz, idx] : idxs)
+ offsets.emplace_back(sz, s[*idx]);
+ return scalar(s[*ptr], offsets);
}
expr GEP::getTypeConstraints(const Function &f) const {
auto c = Value::getTypeConstraints() &&
getType() == ptr->getType() &&
- getType().enforcePtrType();
+ getType().enforcePtrOrVectorType();
for (auto &[sz, idx] : idxs) {
(void)sz;
- c &= idx->getType().enforceIntType();
+ // It is allowed to have non-vector idx with vector pointer operand
+ c &= idx->getType().enforceIntOrVectorType() &&
+ getType().enforceVectorTypeIff(idx->getType());
}
return c;
}

MODIFY
ir/type.cpp
ir/type.cpp
@@ -826,6 +826,17 @@ pair<expr, vector<expr>> AggregateType::mkUndefInput(State &s) const {
return { move(val), move(vars) };
}
+unsigned AggregateType::numPointerElements() const {
+ unsigned count = 0;
+ for (unsigned i = 0; i < elements; ++i) {
+ if (children[i]->isPtrType())
+ count++;
+ else if (auto aty = children[i]->getAsAggregateType())
+ count += aty->numPointerElements();
+ }
+ return count;
+}
+
void AggregateType::printVal(ostream &os, State &s, const expr &e) const {
UNREACHABLE();
}

MODIFY
ir/type.h
ir/type.h
@@ -282,6 +282,7 @@ public:
smt::expr mkInput(State &s, const char *name) const override;
std::pair<smt::expr, std::vector<smt::expr>>
mkUndefInput(State &s) const override;
+ unsigned numPointerElements() const;
void printVal(std::ostream &os, State &s, const smt::expr &e) const override;
const AggregateType* getAsAggregateType() const override;
};

MODIFY
llvm_util/llvm2alive.cpp
llvm_util/llvm2alive.cpp
@@ -375,6 +375,11 @@ public:
return error(i);
auto gep = make_unique<GEP>(*ty, value_name(i), *ptr, i.isInBounds());
+ auto gep_struct_ofs = [&i, this](llvm::StructType *sty, llvm::Value *ofs) {
+ llvm::Value *vals[] = { llvm::ConstantInt::getFalse(i.getContext()), ofs };
+ return this->DL().getIndexedOffsetInType(sty,
+ llvm::makeArrayRef(vals, 2));
+ };
// reference: GEPOperator::accumulateConstantOffset()
for (auto I = llvm::gep_type_begin(i), E = llvm::gep_type_end(i);
@@ -384,11 +389,35 @@ public:
return error(i);
if (auto structTy = I.getStructTypeOrNull()) {
- llvm::Value *vals[] = { llvm::ConstantInt::getFalse(i.getContext()),
- I.getOperand() };
- auto offset = DL().getIndexedOffsetInType(structTy,
- llvm::makeArrayRef(vals, 2));
- gep->addIdx(offset, *make_intconst(1, 64));
+ auto opty = I.getOperand()->getType();
+ auto ofs_ty = llvm::IntegerType::get(i.getContext(), 64);
+
+ if (auto opvty = llvm::dyn_cast<llvm::VectorType>(opty)) {
+ assert(!opvty->isScalable());
+ vector<llvm::Constant *> offsets;
+
+ for (unsigned i = 0; i < opvty->getElementCount().Min; ++i) {
+ llvm::Constant *constofs = nullptr;
+ if (auto cdv = llvm::dyn_cast<llvm::ConstantDataVector>(
+ I.getOperand())) {
+ constofs = cdv->getElementAsConstant(i);
+ } else if (auto cv = llvm::dyn_cast<llvm::ConstantAggregateZero>(
+ I.getOperand())) {
+ constofs = cv->getSequentialElement();
+ } else {
+ assert(false);
+ }
+ offsets.push_back(llvm::ConstantInt::get(ofs_ty,
+ (uint64_t)gep_struct_ofs(structTy, constofs)));
+ }
+
+ auto ofs_vector = llvm::ConstantVector::get(
+ llvm::makeArrayRef(offsets.data(), offsets.size()));
+ gep->addIdx(1, *get_operand(ofs_vector));
+ } else {
+ gep->addIdx(1, *make_intconst(
+ gep_struct_ofs(structTy, I.getOperand()), 64));
+ }
continue;
}

ADD
tests/alive-tv/memory/gep-vector.src.ll
+; TEST-ARGS: -disable-undef-input
+target datalayout = "e-m:m-p:40:64:64:32-i32:32-i16:16-i8:8-n32"
+
+define <2 x i8*> @f(<2 x i8*> %x) {
+ %y = getelementptr i8, <2 x i8*> %x, <2 x i64> <i64 0, i64 1>
+ %z = getelementptr i8, <2 x i8*> %y, <2 x i64> <i64 1, i64 0>
+ ret <2 x i8*> %z
+}
+
+; from Transforms/InstCombine/gep-custom-dl.ll
+%S = type { i32, [ 100 x i32] }
+
+define <2 x i1> @test6b(<2 x i32> %X, <2 x %S*> %P) {
+ %A = getelementptr inbounds %S, <2 x %S*> %P, i32 0, i32 1, <2 x i32> %X
+ %B = getelementptr inbounds %S, <2 x %S*> %P, i32 0, i32 0
+ %C = icmp eq <2 x i32*> %A, %B
+ ret <2 x i1> %C
+}
+

ADD
tests/alive-tv/memory/gep-vector.tgt.ll
+target datalayout = "e-m:m-p:40:64:64:32-i32:32-i16:16-i8:8-n32"
+
+define <2 x i8*> @f(<2 x i8*> %x) {
+ %y = getelementptr i8, <2 x i8*> %x, <2 x i64> <i64 1, i64 1>
+ ret <2 x i8*> %y
+}
+
+%S = type { i32, [ 100 x i32] }
+
+define <2 x i1> @test6b(<2 x i32> %X, <2 x %S*> %P) {
+ %a = icmp eq <2 x i32> %X, <i32 -1, i32 -1>
+ ret <2 x i1> %a
+}
+

MODIFY
tools/transform.cpp
tools/transform.cpp
@@ -370,11 +370,11 @@ static void calculateAndInitConstants(Transform &t) {
unsigned num_ptrinputs = 0;
const auto &inputs = t.src.getInputs();
for (auto &arg : inputs) {
- // An argument with aggregate type with pointer member isn't regarded
- // as a source of non-local pointer, because its member should be extracted
- // with extractelement / extractvalue instructions, which are also counted
- // as source of non-local blocks.
+ // An argument with aggregate type with pointer member is dealt separately
num_ptrinputs += arg.getType().isPtrType();
+
+ if (auto aty = arg.getType().getAsAggregateType())
+ num_ptrinputs += aty->numPointerElements();
}
auto returns_local = [](const Instr &inst) {

Add vector support for gep (#220)