Skip to content

Commit c103ed7

Browse files
make vscale a symbolic type parameter
- Add VScale instruction for llvm.vscale() intrinsic - Store vscale as a shared SMT variable (VectorType::getVScaleVar) - Expose vscale expr via Function::getVScaleExpr() - Bind vscale as a verification precondition in TransformVerify::exec() - Add vscale constraints in VectorType::getTypeConstraints()
1 parent 4b336d3 commit c103ed7

37 files changed

Lines changed: 524 additions & 20 deletions

ir/function.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include "ir/function.h"
55
#include "ir/instr.h"
6+
#include "ir/type.h"
7+
#include "util/config.h"
68
#include "util/errors.h"
79
#include "util/hash.h"
810
#include "util/sort.h"
@@ -168,9 +170,14 @@ expr Function::getTypeConstraints() const {
168170
t &= v.getTypeConstraints();
169171
}
170172
}
173+
171174
return t;
172175
}
173176

177+
expr Function::getVScaleExpr() const {
178+
return VectorType::getVScaleVar();
179+
}
180+
174181
void Function::rauw(const Value &what, Value &with) {
175182
for (auto bb : getBBs())
176183
bb->rauw(what, with);

ir/function.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ class Function final {
183183
bool hasReturn() const;
184184
unsigned bitsPointers() const { return bits_pointers; }
185185
unsigned bitsPtrOffset() const { return bits_ptr_offset; }
186+
smt::expr getVScaleExpr() const;
186187
bool isLittleEndian() const { return little_endian; }
187188
bool isVarArgs() const { return is_var_args; }
188189

ir/instr.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,35 @@ unique_ptr<Instr> FpBinOp::dup(Function &f, const string &suffix) const {
974974
}
975975

976976

977+
vector<Value*> VScale::operands() const {
978+
return {};
979+
}
980+
981+
bool VScale::propagatesPoison() const { return false; }
982+
983+
bool VScale::hasSideEffects() const { return false; }
984+
985+
void VScale::rauw(const Value &what, Value &with) {}
986+
987+
void VScale::print(ostream &os) const {
988+
os << getName() << " = vscale";
989+
}
990+
991+
StateValue VScale::toSMT(State &s) const {
992+
auto e = s.getFn().getVScaleExpr();
993+
return { e.zextOrTrunc(bits()), true };
994+
}
995+
996+
expr VScale::getTypeConstraints(const Function &f) const {
997+
return Value::getTypeConstraints() &&
998+
getType().enforceIntType();
999+
}
1000+
1001+
unique_ptr<Instr> VScale::dup(Function &f, const string &suffix) const {
1002+
return make_unique<VScale>(getType(), getName() + suffix);
1003+
}
1004+
1005+
9771006
vector<Value*> UnaryOp::operands() const {
9781007
return { val };
9791008
}

ir/instr.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,23 @@ class FpBinOp final : public Instr {
102102
};
103103

104104

105+
class VScale final : public Instr {
106+
public:
107+
VScale(Type &type, std::string &&name)
108+
: Instr(type, std::move(name)) {}
109+
110+
std::vector<Value*> operands() const override;
111+
bool propagatesPoison() const override;
112+
bool hasSideEffects() const override;
113+
void rauw(const Value &what, Value &with) override;
114+
void print(std::ostream &os) const override;
115+
StateValue toSMT(State &s) const override;
116+
smt::expr getTypeConstraints(const Function &f) const override;
117+
std::unique_ptr<Instr>
118+
dup(Function &f, const std::string &suffix) const override;
119+
};
120+
121+
105122
class UnaryOp final : public Instr {
106123
public:
107124
enum Op {

ir/type.cpp

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "ir/state.h"
77
#include "smt/solver.h"
88
#include "util/compiler.h"
9+
#include "util/config.h"
910
#include <array>
1011
#include <cassert>
1112
#include <numeric>
@@ -1089,12 +1090,26 @@ void ArrayType::print(ostream &os) const {
10891090
}
10901091

10911092

1092-
VectorType::VectorType(string &&name, unsigned elements, Type &elementTy)
1093-
: AggregateType(std::move(name), false) {
1094-
assert(elements != 0);
1095-
this->elements = elements;
1093+
expr VectorType::getVScaleVar() {
1094+
return expr::mkVar("vscale", var_vector_elements);
1095+
}
1096+
1097+
expr VectorType::vscale() const {
1098+
if (!scalable)
1099+
return expr::mkUInt(1, var_vector_elements);
1100+
return defined ? expr::mkUInt(vscale_value, var_vector_elements)
1101+
: getVScaleVar();
1102+
}
1103+
1104+
VectorType::VectorType(string &&name, unsigned elems, Type &elTy, bool scal)
1105+
: AggregateType(std::move(name), false), scalable(scal), min_elements(elems),
1106+
vscale_value(scal ? util::config::vscale_value : 1) {
1107+
assert(elems != 0);
1108+
if (scalable)
1109+
elems *= vscale_value;
1110+
this->elements = elems;
10961111
defined = true;
1097-
children.resize(elements, &elementTy);
1112+
children.resize(elements, &elTy);
10981113
is_padding.resize(elements, false);
10991114
}
11001115

@@ -1157,6 +1172,12 @@ expr VectorType::getTypeConstraints() const {
11571172
r &= numElements().ugt(i).implies(elementTy == *children[i]);
11581173
}
11591174

1175+
if (scalable && defined) {
1176+
r &= vscale() == expr::mkUInt(vscale_value, var_vector_elements);
1177+
} else if (scalable) {
1178+
r &= vscale().uge(expr::mkUInt(1, var_vector_elements));
1179+
}
1180+
11601181
return r;
11611182
}
11621183

@@ -1172,14 +1193,25 @@ bool VectorType::isVectorType() const {
11721193
return true;
11731194
}
11741195

1196+
void VectorType::fixup(const Model &m) {
1197+
if (!defined && scalable)
1198+
vscale_value = m.getUInt(vscale());
1199+
AggregateType::fixup(m);
1200+
}
1201+
11751202
expr VectorType::enforceVectorType(
11761203
const function<expr(const Type&)> &enforceElem) const {
11771204
return enforceElem(*children[0]);
11781205
}
11791206

11801207
void VectorType::print(ostream &os) const {
1181-
if (elements)
1182-
os << '<' << elements << " x " << *children[0] << '>';
1208+
if (!elements)
1209+
return;
1210+
os << '<';
1211+
if (scalable) {
1212+
os << "vscale" << ":" << vscale_value << " x ";
1213+
}
1214+
os << min_elements << " x " << *children[0] << '>';
11831215
}
11841216

11851217

ir/type.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include "ir/attrs.h"
77
#include "smt/expr.h"
8+
#include "util/config.h"
89

910
#include <functional>
1011
#include <memory>
@@ -335,9 +336,19 @@ class ArrayType final : public AggregateType {
335336

336337

337338
class VectorType final : public AggregateType {
339+
private:
340+
bool scalable = false;
341+
unsigned min_elements, vscale_value;
342+
338343
public:
344+
smt::expr vscale() const;
345+
static smt::expr getVScaleVar();
346+
347+
bool isScalable() const { return scalable; }
348+
unsigned getMinElements() const { return min_elements; }
349+
339350
VectorType(std::string &&name) : AggregateType(std::move(name)) {}
340-
VectorType(std::string &&name, unsigned elements, Type &elementTy);
351+
VectorType(std::string &&name, unsigned elems, Type &elemTy, bool scalable);
341352

342353
IR::StateValue extract(const IR::StateValue &vector,
343354
const smt::expr &index) const;
@@ -348,6 +359,7 @@ class VectorType final : public AggregateType {
348359
unsigned maxSubBitAccess() const override;
349360
smt::expr scalarSize() const override;
350361
bool isVectorType() const override;
362+
void fixup(const smt::Model &m) override;
351363
smt::expr enforceVectorType(
352364
const std::function<smt::expr(const Type&)> &enforceElem) const override;
353365
void print(std::ostream &os) const override;

llvm_util/cmd_args_def.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ config::debug = opt_debug;
2424
config::quiet = opt_quiet;
2525
config::max_offset_bits = opt_max_offset_in_bits;
2626
config::max_sizet_bits = opt_max_sizet_in_bits;
27+
config::vscale_value = opt_vscale;
2728

2829
if ((config::disallow_ub_exploitation = opt_disallow_ub_exploitation)) {
2930
config::disable_undef_input = true;

llvm_util/cmd_args_list.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,9 @@ llvm::cl::opt<bool> opt_disallow_ub_exploitation(
185185
llvm::cl::desc("Disallow UB exploitation by optimizations (default=allow)"),
186186
llvm::cl::init(false), llvm::cl::cat(alive_cmdargs));
187187

188+
llvm::cl::opt<unsigned> opt_vscale(LLVM_ARGS_PREFIX "vscale",
189+
llvm::cl::desc("Set vscale value for scalable vectors (default=2)"),
190+
llvm::cl::init(2), llvm::cl::value_desc("value"),
191+
llvm::cl::cat(alive_cmdargs));
192+
188193
}

llvm_util/llvm2alive.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Distributed under the MIT license that can be found in the LICENSE file.
33

44
#include "llvm_util/llvm2alive.h"
5+
#include "ir/type.h"
56
#include "ir/x86_intrinsics.h"
67
#include "llvm_util/known_fns.h"
78
#include "llvm_util/utils.h"
@@ -1224,6 +1225,12 @@ class llvm2alive_ : public llvm::InstVisitor<llvm2alive_, unique_ptr<Instr>> {
12241225
addNoundefAssumes(i, {a, b});
12251226
return make_unique<VaCopy>(*a, *b);
12261227
}
1228+
case llvm::Intrinsic::vscale: {
1229+
auto ty = llvm_type2alive(i.getType());
1230+
if (!ty)
1231+
return error(i);
1232+
return make_unique<VScale>(*ty, value_name(i));
1233+
}
12271234

12281235
// do nothing intrinsics
12291236
case llvm::Intrinsic::dbg_declare:
@@ -1335,8 +1342,17 @@ class llvm2alive_ : public llvm::InstVisitor<llvm2alive_, unique_ptr<Instr>> {
13351342
RetTy visitShuffleVectorInst(llvm::ShuffleVectorInst &i) {
13361343
PARSE_BINOP();
13371344
vector<unsigned> mask;
1338-
for (auto m : i.getShuffleMask())
1339-
mask.push_back(m);
1345+
1346+
unsigned replicate = 1;
1347+
if (i.getType()->isScalableTy()) {
1348+
replicate = config::vscale_value;
1349+
}
1350+
1351+
auto &&sm = i.getShuffleMask();
1352+
for (unsigned j = 0; j < replicate; j++) {
1353+
mask.insert(mask.end(), sm.begin(), sm.end());
1354+
}
1355+
13401356
return
13411357
make_unique<ShuffleVector>(*ty, value_name(i), *a, *b, std::move(mask));
13421358
}

llvm_util/utils.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ Type* llvm_type2alive(const llvm::Type *ty) {
203203
return cache.get();
204204
}
205205
// TODO: non-fixed sized vectors
206-
case llvm::Type::FixedVectorTyID: {
206+
case llvm::Type::FixedVectorTyID:
207+
case llvm::Type::ScalableVectorTyID: {
207208
auto &cache = type_cache[ty];
208209
if (!cache) {
209210
auto vty = cast<llvm::VectorType>(ty);
@@ -212,7 +213,7 @@ Type* llvm_type2alive(const llvm::Type *ty) {
212213
if (!ety || elems > 1024)
213214
return nullptr;
214215
cache = make_unique<VectorType>("ty_" + to_string(type_id_counter++),
215-
elems, *ety);
216+
elems, *ety, vty->isScalableTy());
216217
}
217218
return cache.get();
218219
}

0 commit comments

Comments
 (0)