From 2d902742edd04f691fd36d952be76c02497a9ef1 Mon Sep 17 00:00:00 2001 From: Liam Machado Date: Thu, 18 Jul 2019 12:55:12 -0600 Subject: [PATCH 01/60] Added CVC4 support --- bin/build.sh | 16 ++++++++++++++++ lib/smack/Prelude.cpp | 8 ++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/bin/build.sh b/bin/build.sh index 1d905b443..3e48cbd7e 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -23,6 +23,7 @@ # Set these flags to control various installation options INSTALL_DEPENDENCIES=1 INSTALL_Z3=1 +INSTALL_CVC4=1 BUILD_BOOGIE=1 BUILD_CORRAL=1 BUILD_SYMBOOGLIX=1 @@ -40,6 +41,7 @@ INSTALL_RUST=0 SMACK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )" ROOT="$( cd "${SMACK_DIR}" && cd .. && pwd )" Z3_DIR="${ROOT}/z3" +CVC4_DIR="${ROOT}/cvc4" BOOGIE_DIR="${ROOT}/boogie" CORRAL_DIR="${ROOT}/corral" SYMBOOGLIX_DIR="${ROOT}/symbooglix" @@ -405,6 +407,18 @@ if [ ${INSTALL_Z3} -eq 1 ] ; then fi fi +if [ ${INSTALL_CVC4} -eq 1 ] ; then + if [ ! -d "$CVC4_DIR" ] ; then + puts "Installing CVC4" + mkdir -p ${CVC4_DIR} + ${WGET} https://github.com/CVC4/CVC4/releases/download/1.7/cvc4-1.7-x86_64-linux-opt -O cvc4 + chmod +x cvc4 + mv cvc4 ${CVC4_DIR} + puts "Installed CVC4" + else + puts "CVC4 already installed" + fi +fi if [ ${BUILD_BOOGIE} -eq 1 ] ; then if ! upToDate $BOOGIE_DIR $BOOGIE_COMMIT ; then @@ -420,6 +434,7 @@ if [ ${BUILD_BOOGIE} -eq 1 ] ; then rm -rf /tmp/nuget/ msbuild Boogie.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${BOOGIE_DIR}/Binaries/z3.exe + ln -sf ${CVC4_DIR}/cvc4 ${BOOGIE_DIR}/Binaries/cvc4.exe puts "Built Boogie" else puts "Boogie already built" @@ -439,6 +454,7 @@ if [ ${BUILD_CORRAL} -eq 1 ] ; then git submodule update msbuild cba.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${CORRAL_DIR}/bin/Release/z3.exe + ln -sf ${CVC4_DIR}/cvc4 ${CORRAL_DIR}/bin/Release/cvc4.exe puts "Built Corral" else puts "Corral already built" diff --git a/lib/smack/Prelude.cpp b/lib/smack/Prelude.cpp index 6cb920185..43d69c55d 100644 --- a/lib/smack/Prelude.cpp +++ b/lib/smack/Prelude.cpp @@ -381,9 +381,9 @@ void IntOpGen::generateArithOps(std::stringstream &s) const { bvBuiltinOp, true}, {"sdiv", 2, intBuiltinOp, bvBuiltinOp, false}, {"smod", 2, intBuiltinOp, bvBuiltinOp, false}, - {"srem", 2, intBuiltinOp, bvBuiltinOp, false}, {"udiv", 2, intBuiltinOp, bvBuiltinOp, false}, - {"urem", 2, intBuiltinOp, bvBuiltinOp, false}, + {"srem", 2, uninterpretedOp, bvBuiltinOp, false}, + {"urem", 2, uninterpretedOp, bvBuiltinOp, false}, {"shl", 2, uninterpretedOp, bvBuiltinOp, false}, {"lshr", 2, uninterpretedOp, bvBuiltinOp, false}, {"ashr", 2, uninterpretedOp, bvBuiltinOp, false}, @@ -731,7 +731,7 @@ void IntOpGen::generateBvIntConvs(std::stringstream &s) const { << "\n"; if (SmackOptions::BitPrecise && !SmackOptions::BitPrecisePointers) { s << Decl::function(indexedName("$bv2uint", {ptrSize}), {{"i", bt}}, it, - nullptr, {makeBuiltinAttr("bv2int")}) + nullptr, {makeBuiltinAttr("bv2nat")}) << "\n"; const Expr *arg = Expr::id("i"); const Expr *uint = Expr::fn(indexedName("$bv2uint", {ptrSize}), arg); @@ -753,7 +753,7 @@ void IntOpGen::generateBvIntConvs(std::stringstream &s) const { << "\n"; } else s << Decl::function(indexedName("$bv2int", {ptrSize}), {{"i", bt}}, it, - nullptr, {makeBuiltinAttr("bv2int")}) + nullptr, {makeBuiltinAttr("bv2nat")}) << "\n"; s << "\n"; } From 6b4a23da73fec6ff4c3ba6d1c5bf842c469a0989 Mon Sep 17 00:00:00 2001 From: Liam Machado Date: Thu, 8 Aug 2019 17:07:00 -0600 Subject: [PATCH 02/60] Added --solver flag --- share/smack/top.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/share/smack/top.py b/share/smack/top.py index 04ebc5d9a..921552f8a 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -208,6 +208,10 @@ def arguments(): choices=['boogie', 'corral', 'symbooglix', 'svcomp'], default='corral', help='back-end verification engine') + verifier_group.add_argument('--solver', + choices=['z3', 'cvc4'], default='z3', + help='back-end SMT solver') + verifier_group.add_argument('--unroll', metavar='N', default='1', type = lambda x: int(x) if int(x) > 0 else parser.error('Unroll bound has to be positive.'), help='loop/recursion unroll bound [default: %(default)s]') @@ -460,6 +464,8 @@ def verify_bpl(args): command += ["/errorLimit:%s" % args.max_violations] if not args.modular: command += ["/loopUnroll:%d" % args.unroll] + if args.solver == 'cvc4': + command += ["/proverOpt:SOLVER=cvc4"] elif args.verifier == 'corral': command = ["corral"] @@ -471,7 +477,9 @@ def verify_bpl(args): command += ["/cex:%s" % args.max_violations] command += ["/maxStaticLoopBound:%d" % args.loop_limit] command += ["/recursionBound:%d" % args.unroll] - + if args.solver == 'cvc4': + command += ["/bopt:proverOpt:SOLVER=cvc4"] + elif args.verifier == 'symbooglix': command = ['symbooglix'] command += [args.bpl_file] From e642e4bd420896522919f4984f40be7928693760 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 31 Jul 2019 23:09:52 -0600 Subject: [PATCH 03/60] Allow optional generation of Boogie assumes from llvm.assume intrinsics LLVM has the llvm.assume intrinsic which is intended to allow a compiler to communicate facts about a program to LLVM's optimizers. These facts may be useful for verification, so this allows them to be used. Additionally, checking of assumptions is possible in order to diagnose faulty assumptions arising from source code or compiler bugs. Specifically, a new flag "--llvm-assumes" is added with three modes: - "none": This ignores the llvm.assume intrinsic and is the default mode. - "use": This enables generation of Boogie assumes from llvm.assume instructions. - "check": This enables assertion checking of the validity of assumed statements. --- .travis.yml | 1 + include/smack/SmackOptions.h | 3 +++ lib/smack/SmackInstGenerator.cpp | 23 +++++++++++++++++++++++ lib/smack/SmackOptions.cpp | 11 +++++++++++ share/smack/top.py | 5 +++++ test/special/assume.c | 12 ++++++++++++ test/special/assume2.c | 12 ++++++++++++ test/special/assume_check.c | 12 ++++++++++++ test/special/assume_check2.c | 13 +++++++++++++ test/special/assume_check_fail.c | 13 +++++++++++++ test/special/assume_fail.c | 12 ++++++++++++ 11 files changed, 117 insertions(+) create mode 100644 test/special/assume.c create mode 100644 test/special/assume2.c create mode 100644 test/special/assume_check.c create mode 100644 test/special/assume_check2.c create mode 100644 test/special/assume_check_fail.c create mode 100644 test/special/assume_fail.c diff --git a/.travis.yml b/.travis.yml index 70f6ce234..6bb28f7e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,7 @@ env: - TRAVIS_ENV="--exhaustive --folder=memory-safety" - TRAVIS_ENV="--exhaustive --folder=pthread" - TRAVIS_ENV="--exhaustive --folder=strings" + - TRAVIS_ENV="--exhaustive --folder=special" before_install: - sudo rm -rf /usr/local/clang-7.0.0 diff --git a/include/smack/SmackOptions.h b/include/smack/SmackOptions.h index 66c0f34dc..a6c210311 100644 --- a/include/smack/SmackOptions.h +++ b/include/smack/SmackOptions.h @@ -10,6 +10,8 @@ #include "smack/SmackWarnings.h" namespace smack { +enum class LLVMAssumeType { none, use, check }; + class SmackOptions { public: static const llvm::cl::list EntryPoints; @@ -28,6 +30,7 @@ class SmackOptions { static const llvm::cl::opt FloatEnabled; static const llvm::cl::opt MemorySafety; static const llvm::cl::opt IntegerOverflow; + static const llvm::cl::opt LLVMAssumes; static const llvm::cl::opt AddTiming; static bool isEntryPoint(std::string); diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index 55fcd4807..a7663d812 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -902,6 +902,28 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { }; }; + // Optionally generate a boogie assume statement from assume statements in + // LLVM. Currently this behavior is experimental and must be enabled by + // passing the -llvm-assumes flag. The default behavior of this + // function is to ignore the assume statement, specified by the "none" + // argument. If the check argument is given, an additional assertion is + // generated to check the validity of the assumption. + static const auto assume = [this](CallInst *ci) { + if (SmackOptions::LLVMAssumes != LLVMAssumeType::none) { + auto arg = rep->expr(ci->getArgOperand(0)); + auto llvmTrue = + SmackOptions::BitPrecise ? Expr::lit(1, 1) : Expr::lit(1LL); + auto chkStmt = Expr::eq(arg, llvmTrue); + if (SmackOptions::LLVMAssumes == LLVMAssumeType::check) + emit(Stmt::assert_(chkStmt)); + else + emit(Stmt::assume(chkStmt)); + } else { + // Skip assume statements + return; + } + }; + static const auto f16UpCast = conditionalModel( [this](CallInst *ci) { // translation: $f := $fpext.bvhalf.*($rmode, $bitcast.bv16.bvhalf($i)); @@ -1130,6 +1152,7 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { static const std::map> stmtMap{ + {llvm::Intrinsic::assume, assume}, {llvm::Intrinsic::bitreverse, assignBvExpr(bitreverse)}, {llvm::Intrinsic::bswap, assignBvExpr(bswap)}, {llvm::Intrinsic::convert_from_fp16, f16UpCast}, diff --git a/lib/smack/SmackOptions.cpp b/lib/smack/SmackOptions.cpp index 6c835170c..1376bede0 100644 --- a/lib/smack/SmackOptions.cpp +++ b/lib/smack/SmackOptions.cpp @@ -66,6 +66,17 @@ const llvm::cl::opt const llvm::cl::opt SmackOptions::IntegerOverflow( "integer-overflow", llvm::cl::desc("Enable integer overflow checks")); +const llvm::cl::opt SmackOptions::LLVMAssumes( + "llvm-assumes", + llvm::cl::desc( + "Optionally enable generation of Boogie assumes from LLVM assumes"), + llvm::cl::values(clEnumValN(LLVMAssumeType::none, "none", + "disable generation of assume statements"), + clEnumValN(LLVMAssumeType::use, "use", + "enable generation of assume statements"), + clEnumValN(LLVMAssumeType::check, "check", + "enable checking of assume statements"))); + bool SmackOptions::isEntryPoint(std::string name) { for (auto EP : EntryPoints) if (name == EP) diff --git a/share/smack/top.py b/share/smack/top.py index 97cb68db2..6211e2ad6 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -197,6 +197,10 @@ def arguments(): translate_group.add_argument('--integer-overflow', action='store_true', default=False, help='enable integer overflow checks') + translate_group.add_argument('--llvm-assumes', choices=['none', 'use', 'check'], default='none', + help='optionally enable generation of Boogie assume statements from LLVM assume statements ' + + '(none=no generation [default], use=generate assume statements, check=check assume statements)') + translate_group.add_argument('--float', action="store_true", default=False, help='enable bit-precise floating-point functions') @@ -347,6 +351,7 @@ def llvm_to_bpl(args): if args.no_memory_splitting: cmd += ['-no-memory-splitting'] if args.memory_safety: cmd += ['-memory-safety'] if args.integer_overflow: cmd += ['-integer-overflow'] + if args.llvm_assumes: cmd += ['-llvm-assumes=' + args.llvm_assumes] if args.float: cmd += ['-float'] if args.modular: cmd += ['-modular'] try_command(cmd, console=True) diff --git a/test/special/assume.c b/test/special/assume.c new file mode 100644 index 000000000..6e66bdbd8 --- /dev/null +++ b/test/special/assume.c @@ -0,0 +1,12 @@ +#include "smack.h" + +// @expect verified +// @flag --llvm-assumes=use + +int main(void) { + unsigned int y = 2 * (unsigned int)__VERIFIER_nondet_unsigned_short(); + // This assumption is used for verification, even though bit-precise + // is not enabled, the assertion will pass. + __builtin_assume((y & 1) == 0); + __VERIFIER_assert((y & 1) == 0); +} diff --git a/test/special/assume2.c b/test/special/assume2.c new file mode 100644 index 000000000..e4c47314a --- /dev/null +++ b/test/special/assume2.c @@ -0,0 +1,12 @@ +#include "smack.h" + +// @expect verified +// @flag --llvm-assumes=use + +int main(void) { + unsigned int y = (2 * (unsigned int)__VERIFIER_nondet_unsigned_short()) + 1; + // This assumption is used for verification, even though the assumption + // is false, the assertion will pass. + __builtin_assume((y & 1) == 0); + __VERIFIER_assert((y & 1) == 0); +} diff --git a/test/special/assume_check.c b/test/special/assume_check.c new file mode 100644 index 000000000..54d460e86 --- /dev/null +++ b/test/special/assume_check.c @@ -0,0 +1,12 @@ +#include "smack.h" + +// @expect verified +// @flag --llvm-assumes=check +// @flag --bit-precise + +int main(void) { + unsigned int y = 2 * (unsigned int)__VERIFIER_nondet_unsigned_short(); + // This assumption is checked under bit-precise and is verified. + __builtin_assume((y & 1) == 0); + __VERIFIER_assert((y & 1) == 0); +} diff --git a/test/special/assume_check2.c b/test/special/assume_check2.c new file mode 100644 index 000000000..979369b33 --- /dev/null +++ b/test/special/assume_check2.c @@ -0,0 +1,13 @@ +#include "smack.h" + +// @expect verified +// @flag --llvm-assumes=check +// @flag --bit-precise + +int main(void) { + unsigned int y = (2 * (unsigned int)__VERIFIER_nondet_unsigned_short()) + 1; + // This assumption is checked at verification time, and since bit-precise + // is enabled, and y is clearly odd, the check will pass. + __builtin_assume((y & 1) == 1); + __VERIFIER_assert((y & 1) == 1); +} diff --git a/test/special/assume_check_fail.c b/test/special/assume_check_fail.c new file mode 100644 index 000000000..1faa46507 --- /dev/null +++ b/test/special/assume_check_fail.c @@ -0,0 +1,13 @@ +#include "smack.h" + +// @expect error +// @flag --llvm-assumes=check +// @flag --bit-precise + +int main(void) { + unsigned int y = (2 * (unsigned int)__VERIFIER_nondet_unsigned_short()) + 1; + // This assumption is checked at verification time, and since bit-precise + // is enabled, and y is clearly odd, the assumption should be shown false. + __builtin_assume((y & 1) == 0); + __VERIFIER_assert((y & 1) == 0); +} diff --git a/test/special/assume_fail.c b/test/special/assume_fail.c new file mode 100644 index 000000000..b0a803faa --- /dev/null +++ b/test/special/assume_fail.c @@ -0,0 +1,12 @@ +#include "smack.h" + +// @expect error +// @flag --llvm-assumes=none + +int main(void) { + unsigned int y = 2 * (unsigned int)__VERIFIER_nondet_unsigned_short(); + // This assumption is not used, and since bit-precise is not enabled, + // verification will fail. + __builtin_assume((y & 1) == 0); + __VERIFIER_assert((y & 1) == 0); +} From 0ce767ec8763121a78eb8ce180fdea751b012a16 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Fri, 9 Aug 2019 17:01:53 -0600 Subject: [PATCH 04/60] Remove duplicate conditional AST node The CondExpr and IfThenElseExpr classes are nearly functionally identical. The issue is IfThenEseExpr's print method doesn't properly group the generated expression, leading to precedence issues in Boogie. This resolves the issue by making IfThenEsleExpr properly group its output, and removes the CondExpr class and its associated functions. Fixes #481 --- include/smack/BoogieAst.h | 20 +++---------- lib/smack/BoogieAst.cpp | 19 ++++--------- lib/smack/Prelude.cpp | 48 ++++++++++++++++---------------- lib/smack/SmackInstGenerator.cpp | 31 +++++++++++---------- lib/smack/SmackRep.cpp | 4 +-- test/basic/select.c | 2 +- test/basic/select_fail.c | 2 +- 7 files changed, 54 insertions(+), 72 deletions(-) diff --git a/include/smack/BoogieAst.h b/include/smack/BoogieAst.h index aa3c6b0aa..ffddfeac0 100644 --- a/include/smack/BoogieAst.h +++ b/include/smack/BoogieAst.h @@ -22,9 +22,9 @@ class Expr { static const Expr *forall(std::list, const Expr *e); static const Expr *and_(const Expr *l, const Expr *r); static const Expr *or_(const Expr *l, const Expr *r); - static const Expr *cond(const Expr *c, const Expr *t, const Expr *e); static const Expr *eq(const Expr *l, const Expr *r); static const Expr *lt(const Expr *l, const Expr *r); + static const Expr *ifThenElse(const Expr *c, const Expr *t, const Expr *e); static const Expr *fn(std::string f, const Expr *x); static const Expr *fn(std::string f, const Expr *x, const Expr *y); static const Expr *fn(std::string f, const Expr *x, const Expr *y, @@ -48,7 +48,6 @@ class Expr { static const Expr *sel(const Expr *b, const Expr *i); static const Expr *sel(std::string b, std::string i); static const Expr *upd(const Expr *b, const Expr *i, const Expr *v); - static const Expr *if_then_else(const Expr *c, const Expr *t, const Expr *e); static const Expr *bvExtract(const Expr *v, const Expr *upper, const Expr *lower); static const Expr *bvExtract(std::string v, unsigned upper, unsigned lower); @@ -89,17 +88,6 @@ class BinExpr : public Expr { void print(std::ostream &os) const; }; -class CondExpr : public Expr { - const Expr *cond; - const Expr *then; - const Expr *else_; - -public: - CondExpr(const Expr *c, const Expr *t, const Expr *e) - : cond(c), then(t), else_(e) {} - void print(std::ostream &os) const; -}; - class FunExpr : public Expr { std::string fun; std::list args; @@ -247,12 +235,12 @@ class VarExpr : public Expr { class IfThenElseExpr : public Expr { const Expr *cond; - const Expr *true_value; - const Expr *false_value; + const Expr *trueValue; + const Expr *falseValue; public: IfThenElseExpr(const Expr *c, const Expr *t, const Expr *e) - : cond(c), true_value(t), false_value(e) {} + : cond(c), trueValue(t), falseValue(e) {} void print(std::ostream &os) const; }; diff --git a/lib/smack/BoogieAst.cpp b/lib/smack/BoogieAst.cpp index aa1061d57..bc5a68fee 100644 --- a/lib/smack/BoogieAst.cpp +++ b/lib/smack/BoogieAst.cpp @@ -28,10 +28,6 @@ const Expr *Expr::or_(const Expr *l, const Expr *r) { return new BinExpr(BinExpr::Or, l, r); } -const Expr *Expr::cond(const Expr *c, const Expr *t, const Expr *e) { - return new CondExpr(c, t, e); -} - const Expr *Expr::eq(const Expr *l, const Expr *r) { return new BinExpr(BinExpr::Eq, l, r); } @@ -40,6 +36,10 @@ const Expr *Expr::lt(const Expr *l, const Expr *r) { return new BinExpr(BinExpr::Lt, l, r); } +const Expr *Expr::ifThenElse(const Expr *c, const Expr *t, const Expr *e) { + return new IfThenElseExpr(c, t, e); +} + const Expr *Expr::fn(std::string f, std::list args) { return new FunExpr(f, args); } @@ -115,10 +115,6 @@ const Expr *Expr::upd(const Expr *b, const Expr *i, const Expr *v) { return new UpdExpr(b, i, v); } -const Expr *Expr::if_then_else(const Expr *c, const Expr *t, const Expr *e) { - return new IfThenElseExpr(c, t, e); -} - const Expr *Expr::bvExtract(const Expr *v, const Expr *u, const Expr *l) { return new BvExtract(v, u, l); } @@ -424,10 +420,6 @@ void BinExpr::print(std::ostream &os) const { os << " " << rhs << ")"; } -void CondExpr::print(std::ostream &os) const { - os << "(if " << cond << " then " << then << " else " << else_ << ")"; -} - void FunExpr::print(std::ostream &os) const { os << fun; print_seq(os, args, "(", ", ", ")"); @@ -510,7 +502,8 @@ void CodeExpr::print(std::ostream &os) const { } void IfThenElseExpr::print(std::ostream &os) const { - os << "if " << cond << " then " << true_value << " else " << false_value; + os << "(if " << cond << " then " << trueValue << " else " << falseValue + << ")"; } void BvExtract::print(std::ostream &os) const { diff --git a/lib/smack/Prelude.cpp b/lib/smack/Prelude.cpp index 43d69c55d..c2f2d2c99 100644 --- a/lib/smack/Prelude.cpp +++ b/lib/smack/Prelude.cpp @@ -343,7 +343,7 @@ struct IntOpGen::IntArithOp : public IntOp { static const Expr *bvMinMaxExpr(unsigned size) { std::string signLetter = SIGN ? "s" : "u"; std::string pred = MIN ? "lt" : "gt"; - return Expr::if_then_else( + return Expr::ifThenElse( Expr::fn(indexedName("$" + signLetter + pred, {getBvTypeName(size), Naming::BOOL_TYPE}), makeIntVarExprs(2)), @@ -356,7 +356,7 @@ struct IntOpGen::IntArithOp : public IntOp { const Expr *a1 = makeIntVarExpr(1); const Expr *a2 = makeIntVarExpr(2); auto pred = MIN ? Expr::lt(a1, a2) : Expr::lt(a2, a1); - return Expr::if_then_else(pred, a1, a2); + return Expr::ifThenElse(pred, a1, a2); } }; @@ -465,12 +465,11 @@ struct IntOpGen::IntPred : public IntOp { Naming::BOOL_TYPE, ((IntOp::exprT)iop->func)(size)); // e.g.: function {:inline} $ule.i1(i1: i1, i2: i1) returns (i1) // { if $ule.i1.bool(i1, i2) then 1 else 0 } - auto predFunc = - inlinedOp(name, {type}, makeIntVars(2, type), getIntTypeName(1), - Expr::if_then_else( - Expr::fn(indexedName(name, {type, Naming::BOOL_TYPE}), - makeIntVarExprs(2)), - Expr::lit(1ll), Expr::lit(0ll))); + auto predFunc = inlinedOp( + name, {type}, makeIntVars(2, type), getIntTypeName(1), + Expr::ifThenElse(Expr::fn(indexedName(name, {type, Naming::BOOL_TYPE}), + makeIntVarExprs(2)), + Expr::lit(1ll), Expr::lit(0ll))); return {compFunc, predFunc}; } @@ -494,12 +493,11 @@ struct IntOpGen::IntPred : public IntOp { llvm_unreachable("no uninterpreted bv predicates"); // e.g.: function {:inline} $ule.bv1(i1: bv1, i2: bv1) returns (bv1) // { if $ule.bv1.bool(i1, i2) then 1bv1 else 0bv1 } - predFunc = - inlinedOp(name, {type}, makeIntVars(2, type), getBvTypeName(1), - Expr::if_then_else( - Expr::fn(indexedName(name, {type, Naming::BOOL_TYPE}), - makeIntVarExpr(1), makeIntVarExpr(2)), - Expr::lit(1, 1), Expr::lit(0, 1))); + predFunc = inlinedOp( + name, {type}, makeIntVars(2, type), getBvTypeName(1), + Expr::ifThenElse(Expr::fn(indexedName(name, {type, Naming::BOOL_TYPE}), + makeIntVarExpr(1), makeIntVarExpr(2)), + Expr::lit(1, 1), Expr::lit(0, 1))); return {compFunc, predFunc}; } @@ -744,11 +742,12 @@ void IntOpGen::generateBvIntConvs(std::stringstream &s) const { llvm_unreachable("Unexpected pointer bit width."); s << Decl::function( indexedName("$bv2int", {ptrSize}), {{"i", bt}}, it, - Expr::cond(Expr::fn(indexedName("$slt", {bt, Naming::BOOL_TYPE}), - {arg, Expr::lit(0ULL, ptrSize)}), - Expr::fn(indexedName("$sub", {it}), - {uint, Expr::lit(offset, 0U)}), - uint), + Expr::ifThenElse( + Expr::fn(indexedName("$slt", {bt, Naming::BOOL_TYPE}), + {arg, Expr::lit(0ULL, ptrSize)}), + Expr::fn(indexedName("$sub", {it}), + {uint, Expr::lit(offset, 0U)}), + uint), {makeInlineAttr()}) << "\n"; } else @@ -927,11 +926,12 @@ void PtrOpGen::generatePreds(std::stringstream &s) const { indexedName(pred, {Naming::PTR_TYPE}), {{"p1", Naming::PTR_TYPE}, {"p2", Naming::PTR_TYPE}}, prelude.rep.intType(1), - Expr::cond(Expr::fn(indexedName(pred, {prelude.rep.pointerType(), - Naming::BOOL_TYPE}), - {Expr::id("p1"), Expr::id("p2")}), - prelude.rep.integerLit(1LL, 1), - prelude.rep.integerLit(0LL, 1)), + Expr::ifThenElse( + Expr::fn(indexedName(pred, {prelude.rep.pointerType(), + Naming::BOOL_TYPE}), + {Expr::id("p1"), Expr::id("p2")}), + prelude.rep.integerLit(1LL, 1), + prelude.rep.integerLit(0LL, 1)), {makeInlineAttr()}) << "\n"; s << Decl::function( diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index a7663d812..89d28cf01 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -539,7 +539,8 @@ void SmackInstGenerator::visitAtomicCmpXchgInst(llvm::AtomicCmpXchgInst &i) { const Expr *cmp = rep->expr(i.getOperand(1)); const Expr *swp = rep->expr(i.getOperand(2)); emit(Stmt::assign(res, mem)); - emit(rep->store(i.getOperand(0), Expr::cond(Expr::eq(mem, cmp), swp, mem))); + emit(rep->store(i.getOperand(0), + Expr::ifThenElse(Expr::eq(mem, cmp), swp, mem))); } void SmackInstGenerator::visitAtomicRMWInst(llvm::AtomicRMWInst &i) { @@ -623,7 +624,7 @@ void SmackInstGenerator::visitSelectInst(llvm::SelectInst &i) { "Vector condition is not supported."); emit(Stmt::assign( Expr::id(x), - Expr::if_then_else(Expr::eq(c, rep->integerLit(1LL, 1)), v1, v2))); + Expr::ifThenElse(Expr::eq(c, rep->integerLit(1LL, 1)), v1, v2))); } void SmackInstGenerator::visitCallInst(llvm::CallInst &ci) { @@ -718,7 +719,7 @@ void SmackInstGenerator::visitCallInst(llvm::CallInst &ci) { // args.push_back(Expr::id(m.first)); // auto E = Expr::fn(F->getName(), args); // emit(Stmt::assign(rep->expr(&ci), - // Expr::cond(Expr::forall(binding, "int", E), + // Expr::ifThenElse(Expr::forall(binding, "int", E), // rep->integerLit(1U,1), rep->integerLit(0U,1)))); } else if (name == Naming::CONTRACT_REQUIRES || @@ -1021,7 +1022,7 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { // ... else if v[1:0] == 1 then 31bv32 else 32bv32 const Expr *body = Expr::lit(width, width); for (unsigned i = 0; i < width; ++i) { - body = Expr::if_then_else( + body = Expr::ifThenElse( Expr::eq(Expr::bvExtract(var, i + 1, i), Expr::lit(1, 1)), Expr::lit(width - i - 1, width), body); } @@ -1030,11 +1031,11 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { // argument // is zero, then the result is undefined. auto isZeroUndef = rep->expr(ci->getArgOperand(1)); - body = Expr::if_then_else( - Expr::and_(Expr::eq(isZeroUndef, Expr::lit(1, 1)), - Expr::eq(var, Expr::lit(0, width))), - rep->expr(ci), // The result is undefined - body); + body = + Expr::ifThenElse(Expr::and_(Expr::eq(isZeroUndef, Expr::lit(1, 1)), + Expr::eq(var, Expr::lit(0, width))), + rep->expr(ci), // The result is undefined + body); emit(Stmt::havoc(rep->expr(ci))); emit(Stmt::assign(rep->expr(ci), body)); }, @@ -1050,7 +1051,7 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { // ... else if v[32:31] == 1 then 31bv32 else 32bv32 const Expr *body = Expr::lit(width, width); for (unsigned i = width; i > 0; --i) { - body = Expr::if_then_else( + body = Expr::ifThenElse( Expr::eq(Expr::bvExtract(arg, i, i - 1), Expr::lit(1, 1)), Expr::lit(i - 1, width), body); } @@ -1059,11 +1060,11 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { // argument // is zero, then the result is undefined. auto isZeroUndef = rep->expr(ci->getArgOperand(1)); - body = Expr::if_then_else( - Expr::and_(Expr::eq(isZeroUndef, Expr::lit(1, 1)), - Expr::eq(arg, Expr::lit(0, width))), - rep->expr(ci), // The result is undefined - body); + body = + Expr::ifThenElse(Expr::and_(Expr::eq(isZeroUndef, Expr::lit(1, 1)), + Expr::eq(arg, Expr::lit(0, width))), + rep->expr(ci), // The result is undefined + body); emit(Stmt::havoc(rep->expr(ci))); emit(Stmt::assign(rep->expr(ci), body)); }, diff --git a/lib/smack/SmackRep.cpp b/lib/smack/SmackRep.cpp index 0067f7c57..825b1c958 100644 --- a/lib/smack/SmackRep.cpp +++ b/lib/smack/SmackRep.cpp @@ -937,8 +937,8 @@ const Expr *SmackRep::cmp(unsigned predicate, const llvm::Value *lhs, const Expr *e1 = expr(lhs, isUnsigned); const Expr *e2 = expr(rhs, isUnsigned); if (lhs->getType()->isFloatingPointTy()) - return Expr::if_then_else(Expr::fn(fn + ".bool", e1, e2), - integerLit(1ULL, 1), integerLit(0ULL, 1)); + return Expr::ifThenElse(Expr::fn(fn + ".bool", e1, e2), integerLit(1ULL, 1), + integerLit(0ULL, 1)); else return Expr::fn(fn, e1, e2); } diff --git a/test/basic/select.c b/test/basic/select.c index 9a090a8a9..6506f095f 100644 --- a/test/basic/select.c +++ b/test/basic/select.c @@ -1,7 +1,7 @@ #include "smack.h" // @expect verified -// @checkbpl grep -E ":= if.+then.+else.+" +// @checkbpl grep -E ":= \(if.+then.+else.+\)" int main(void) { int c = 2; diff --git a/test/basic/select_fail.c b/test/basic/select_fail.c index 5972bc283..55cfee492 100644 --- a/test/basic/select_fail.c +++ b/test/basic/select_fail.c @@ -1,7 +1,7 @@ #include "smack.h" // @expect error -// @checkbpl grep -E ":= if.+then.+else.+" +// @checkbpl grep -E ":= \(if.+then.+else.+\)" int main(void) { int c = 2; From f95d961cabbecbe53ea1067c06ed4434637af2ff Mon Sep 17 00:00:00 2001 From: zvonimir Date: Tue, 13 Aug 2019 10:04:04 +0200 Subject: [PATCH 05/60] Refactored CVC4 installation procedure Moved version into the versions file. --- bin/build.sh | 5 ++--- bin/versions | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/build.sh b/bin/build.sh index 7511bcc2e..ace18792f 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -411,9 +411,8 @@ if [ ${INSTALL_CVC4} -eq 1 ] ; then if [ ! -d "$CVC4_DIR" ] ; then puts "Installing CVC4" mkdir -p ${CVC4_DIR} - ${WGET} https://github.com/CVC4/CVC4/releases/download/1.7/cvc4-1.7-x86_64-linux-opt -O cvc4 - chmod +x cvc4 - mv cvc4 ${CVC4_DIR} + ${WGET} https://github.com/CVC4/CVC4/releases/download/${CVC4_VERSION}/cvc4-${CVC4_VERSION}-x86_64-linux-opt -O ${CVC4_DIR}/cvc4 + chmod +x ${CVC4_DIR}/cvc4 puts "Installed CVC4" else puts "CVC4 already installed" diff --git a/bin/versions b/bin/versions index d9e780e1d..8a0b4afe2 100644 --- a/bin/versions +++ b/bin/versions @@ -1,6 +1,7 @@ MONO_VERSION=5.0.0.100 Z3_SHORT_VERSION=4.8.5 Z3_FULL_VERSION=4.8.5 +CVC4_VERSION=1.7 BOOGIE_COMMIT=5c829b6340 CORRAL_COMMIT=c446f5e827 SYMBOOGLIX_COMMIT=7210e5d09b From b6bac0458dc16627de673ed0922fbb085f959abb Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 15 Sep 2019 11:38:34 -0700 Subject: [PATCH 06/60] Remove patched `pointer_iterator` This fix was merged upstream and released in LLVM 7.0.1. --- include/dsa/DSGraphTraits.h | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/include/dsa/DSGraphTraits.h b/include/dsa/DSGraphTraits.h index 050284a73..107cdec76 100644 --- a/include/dsa/DSGraphTraits.h +++ b/include/dsa/DSGraphTraits.h @@ -17,6 +17,7 @@ #define LLVM_ANALYSIS_DSGRAPHTRAITS_H #include "dsa/DSGraph.h" +#include "llvm/ADT/iterator.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/STLExtras.h" @@ -24,32 +25,6 @@ namespace llvm { -namespace bugfix { - -// XXX: There's a bug in llvm::pointer_iterator. The iterator_category -// parameter to iterator_adaptor_base is omitted. We can remove this once it is fixed. -// http://llvm.org/doxygen/iterator_8h_source.html#l00311 -template ())> -class pointer_iterator - : public iterator_adaptor_base, - WrappedIteratorT, - typename std::iterator_traits::iterator_category, - T> { - mutable T Ptr; - -public: - pointer_iterator() = default; - - explicit pointer_iterator(WrappedIteratorT u) - : pointer_iterator::iterator_adaptor_base(std::move(u)) {} - - T &operator*() { return Ptr = &*this->I; } - const T &operator*() const { return Ptr = &*this->I; } -}; - -} // End bugfix namespace - template class DSNodeIterator : public std::iterator { friend class DSNode; @@ -128,7 +103,7 @@ template <> struct GraphTraits { typedef DSNode::const_iterator ChildIteratorType; // nodes_iterator/begin/end - Allow iteration over all nodes in the graph - typedef bugfix::pointer_iterator nodes_iterator; + typedef pointer_iterator nodes_iterator; static nodes_iterator nodes_begin(const DSGraph *G) { return nodes_iterator(G->node_begin()); } From 01e3aa0b44e17b310b19049dc4490c68940be1c1 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sun, 22 Sep 2019 01:26:38 -0600 Subject: [PATCH 07/60] Updated url to homebrew cask Fixes #487 --- docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index e129dd08b..0db8b5a0f 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -215,6 +215,6 @@ shell in the `test` directory by executing [build.sh]: https://github.com/smackers/smack/blob/master/bin/build.sh [Xcode]: https://developer.apple.com/xcode/ [Homebrew]: http://brew.sh/ -[Homebrew Cask]: http://caskroom.io +[Homebrew Cask]: https://formulae.brew.sh/cask/ [Docker]: https://www.docker.com [Ninja]: https://ninja-build.org From db308ce6ee72637cdcb1e35730fd3a5615e67ea0 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Wed, 16 Oct 2019 20:22:35 -0600 Subject: [PATCH 08/60] Moved pthreadtypes header to its correct location It seems that this header should reside in the bits folder, which should prevent type redefinition errors from happening since it will mask the systems header. Fixes #485 --- share/smack/include/{ => bits}/pthreadtypes.h | 0 share/smack/include/pthread.h | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename share/smack/include/{ => bits}/pthreadtypes.h (100%) diff --git a/share/smack/include/pthreadtypes.h b/share/smack/include/bits/pthreadtypes.h similarity index 100% rename from share/smack/include/pthreadtypes.h rename to share/smack/include/bits/pthreadtypes.h diff --git a/share/smack/include/pthread.h b/share/smack/include/pthread.h index d93e54ce4..9c095aeb0 100644 --- a/share/smack/include/pthread.h +++ b/share/smack/include/pthread.h @@ -4,7 +4,7 @@ #ifndef PTHREAD_H #define PTHREAD_H -#include "pthreadtypes.h" +#include "bits/pthreadtypes.h" // model mutex: // 0 = unlocked, From b8201629da057f98466f70dd008f9c594d8e531a Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Tue, 22 Oct 2019 12:56:55 -0600 Subject: [PATCH 09/60] Refactored regressions into separate folders based on input language Closes #490 --- test/{ => c}/basic/ase_example.c | 0 test/{ => c}/basic/ase_example_fail.c | 0 test/{ => c}/basic/atomic_cas.c | 0 test/{ => c}/basic/atomic_cas_fail.c | 0 test/{ => c}/basic/big_numbers.c | 0 test/{ => c}/basic/big_numbers_fail.c | 0 test/{ => c}/basic/big_types.c | 0 test/{ => c}/basic/checking.c | 0 test/{ => c}/basic/checking_invert_bpl.c | 0 test/{ => c}/basic/checking_invert_out.c | 0 test/{ => c}/basic/config.yml | 0 test/{ => c}/basic/extern_func.c | 0 test/{ => c}/basic/extern_mem.c | 0 test/{ => c}/basic/extern_mem_fail.c | 0 test/{ => c}/basic/gcd.c | 0 test/{ => c}/basic/gcd_1_true.c | 0 test/{ => c}/basic/globals.c | 0 test/{ => c}/basic/globals_fail.c | 0 test/{ => c}/basic/init_funcs_example.c | 0 test/{ => c}/basic/init_funcs_example_fail.c | 0 test/{ => c}/basic/init_funcs_global.c | 0 test/{ => c}/basic/init_funcs_global_fail.c | 0 test/{ => c}/basic/jain_1_true.c | 0 test/{ => c}/basic/jain_2_true.c | 0 test/{ => c}/basic/jain_4_true.c | 0 test/{ => c}/basic/jain_5_true.c | 0 test/{ => c}/basic/limits.c | 0 test/{ => c}/basic/limits_fail.c | 0 test/{ => c}/basic/list.c | 0 test/{ => c}/basic/list_fail.c | 0 test/{ => c}/basic/lock.c | 0 test/{ => c}/basic/lock_fail.c | 0 test/{ => c}/basic/loop.c | 0 test/{ => c}/basic/loop1.c | 0 test/{ => c}/basic/loop1_fail.c | 0 test/{ => c}/basic/loop_fail.c | 0 test/{ => c}/basic/negative_numbers.c | 0 test/{ => c}/basic/negative_numbers_fail.c | 0 test/{ => c}/basic/nondet.c | 0 test/{ => c}/basic/printfs.c | 0 test/{ => c}/basic/return_label.c | 0 test/{ => c}/basic/select.c | 0 test/{ => c}/basic/select_fail.c | 0 test/{ => c}/basic/simple.c | 0 test/{ => c}/basic/simple_fail.c | 0 test/{ => c}/basic/simple_pre.c | 0 test/{ => c}/basic/simple_pre1.c | 0 test/{ => c}/basic/simple_pre1_fail.c | 0 test/{ => c}/basic/simple_pre2.c | 0 test/{ => c}/basic/simple_pre2_fail.c | 0 test/{ => c}/basic/simple_pre3.c | 0 test/{ => c}/basic/simple_pre3_fail.c | 0 test/{ => c}/basic/simple_pre4.c | 0 test/{ => c}/basic/simple_pre4_fail.c | 0 test/{ => c}/basic/simple_pre_fail.c | 0 test/{ => c}/basic/smack_code_call.c | 0 test/{ => c}/basic/smack_code_call_fail.c | 0 test/{ => c}/basic/split_aggregate_values.c | 0 test/{ => c}/basic/split_aggregate_values_fail.c | 0 test/{ => c}/basic/strings.c | 0 test/{ => c}/basic/strings1.c | 0 test/{ => c}/basic/strings1_fail.c | 0 test/{ => c}/basic/strings_fail.c | 0 test/{ => c}/basic/test_memcpy.c | 0 test/{ => c}/basic/test_memcpy_fail.c | 0 test/{ => c}/basic/timing-annotations.c | 0 test/{ => c}/basic/transform-bpl.c | 0 test/{ => c}/basic/transform-out.c | 0 test/{ => c}/basic/uninterpreted.c | 0 test/{ => c}/basic/uninterpreted_fail.c | 0 test/{ => c}/basic/vararg.c | 0 test/{ => c}/basic/vararg_fail.c | 0 test/{ => c}/bits/absolute.c | 0 test/{ => c}/bits/absolute_fail.c | 0 test/{ => c}/bits/bit_field.c | 0 test/{ => c}/bits/bit_field_fail.c | 0 test/{ => c}/bits/bit_fields.c | 0 test/{ => c}/bits/bit_fields_fail.c | 0 test/{ => c}/bits/bitreverse.c | 0 test/{ => c}/bits/bitreverse_fail.c | 0 test/{ => c}/bits/byte_swap.c | 0 test/{ => c}/bits/byte_swap_fail.c | 0 test/{ => c}/bits/config.yml | 0 test/{ => c}/bits/countlz.c | 0 test/{ => c}/bits/countlz_fail.c | 0 test/{ => c}/bits/countlz_fail2.c | 0 test/{ => c}/bits/countlz_zero_fail.c | 0 test/{ => c}/bits/countpop32.c | 0 test/{ => c}/bits/countpop32_fail.c | 0 test/{ => c}/bits/counttz.c | 0 test/{ => c}/bits/counttz_fail.c | 0 test/{ => c}/bits/counttz_fail2.c | 0 test/{ => c}/bits/interleave_bits_fail.c | 0 test/{ => c}/bits/interleave_bits_true.c | 0 test/{ => c}/bits/left_shift_negative_fail.c | 0 test/{ => c}/bits/left_shift_overflow.c | 0 test/{ => c}/bits/left_shift_overflow_fail.c | 0 test/{ => c}/bits/left_shift_unsigned.c | 0 test/{ => c}/bits/left_shift_unsigned_fail.c | 0 test/{ => c}/bits/malloc_non_alias.c | 0 test/{ => c}/bits/mm.c | 0 test/{ => c}/bits/mm_fail.c | 0 test/{ => c}/bits/num_conversion_1_fail.c | 0 test/{ => c}/bits/num_conversion_1_true.c | 0 test/{ => c}/bits/num_conversion_2_fail.c | 0 test/{ => c}/bits/num_conversion_2_true.c | 0 test/{ => c}/bits/pointers4.c | 0 test/{ => c}/bits/pointers4_fail.c | 0 test/{ => c}/bits/pointers6.c | 0 test/{ => c}/bits/pointers7.c | 0 test/{ => c}/bits/pointers7_fail.c | 0 test/{ => c}/bits/smack_code_annot.c | 0 test/{ => c}/bits/smack_code_annot_fail.c | 0 test/{ => c}/bits/sync-fetch.c | 0 test/{ => c}/bits/sync-fetch_fail.c | 0 test/{ => c}/bits/unaligned_struct.c | 0 test/{ => c}/bits/unaligned_struct_fail.c | 0 test/{ => c}/contracts/.gitignore | 0 test/{ => c}/contracts/and.c | 0 test/{ => c}/contracts/and_fail.c | 0 test/{ => c}/contracts/array.c | 0 test/{ => c}/contracts/array_fail.c | 0 test/{ => c}/contracts/config.yml | 0 test/{ => c}/contracts/failing/array_forall.c | 0 test/{ => c}/contracts/failing/array_forall_fail.c | 0 test/{ => c}/contracts/failing/forall.c | 0 test/{ => c}/contracts/failing/forall_fail.c | 0 test/{ => c}/contracts/failing/old.c | 0 test/{ => c}/contracts/failing/old_fail.c | 0 test/{ => c}/contracts/failing/result.c | 0 test/{ => c}/contracts/failing/result_fail.c | 0 test/{ => c}/contracts/invariant.c | 0 test/{ => c}/contracts/invariant_fail.c | 0 test/{ => c}/contracts/requires_const.c | 0 test/{ => c}/contracts/simple.c | 0 test/{ => c}/contracts/simple_fail.c | 0 test/{ => c}/data/array.c | 0 test/{ => c}/data/array1.c | 0 test/{ => c}/data/array1_fail.c | 0 test/{ => c}/data/array2.c | 0 test/{ => c}/data/array2_fail.c | 0 test/{ => c}/data/array3.c | 0 test/{ => c}/data/array3_fail.c | 0 test/{ => c}/data/array4.c | 0 test/{ => c}/data/array4_fail.c | 0 test/{ => c}/data/array_free.c | 0 test/{ => c}/data/array_free2.c | 0 test/{ => c}/data/array_free2_fail.c | 0 test/{ => c}/data/array_free_fail.c | 0 test/{ => c}/data/extern_func_ptr.c | 0 test/{ => c}/data/extern_func_ptr_fail.c | 0 test/{ => c}/data/extern_struct.c | 0 test/{ => c}/data/free_as_func_ptr.c | 0 test/{ => c}/data/func_ptr.c | 0 test/{ => c}/data/func_ptr1.c | 0 test/{ => c}/data/func_ptr1_fail.c | 0 test/{ => c}/data/func_ptr2.c | 0 test/{ => c}/data/func_ptr2_fail.c | 0 test/{ => c}/data/func_ptr_alias.c | 0 test/{ => c}/data/func_ptr_alias1.c | 0 test/{ => c}/data/func_ptr_alias1_fail.c | 0 test/{ => c}/data/func_ptr_alias_fail.c | 0 test/{ => c}/data/func_ptr_array.c | 0 test/{ => c}/data/func_ptr_array_fail.c | 0 test/{ => c}/data/func_ptr_fail.c | 0 test/{ => c}/data/func_ptr_vararg.c | 0 test/{ => c}/data/func_ptr_vararg_fail.c | 0 test/{ => c}/data/global_structs.c | 0 test/{ => c}/data/global_structs_fail.c | 0 test/{ => c}/data/globals_func_ptr.c | 0 test/{ => c}/data/globals_func_ptr_fail.c | 0 test/{ => c}/data/nested_struct.c | 0 test/{ => c}/data/nested_struct1.c | 0 test/{ => c}/data/nested_struct1_fail.c | 0 test/{ => c}/data/nested_struct2.c | 0 test/{ => c}/data/nested_struct2_fail.c | 0 test/{ => c}/data/nested_struct_fail.c | 0 test/{ => c}/data/nondet_pointer_fail.c | 0 test/{ => c}/data/pointers.c | 0 test/{ => c}/data/pointers1.c | 0 test/{ => c}/data/pointers1_fail.c | 0 test/{ => c}/data/pointers2.c | 0 test/{ => c}/data/pointers2_fail.c | 0 test/{ => c}/data/pointers3.c | 0 test/{ => c}/data/pointers3_fail.c | 0 test/{ => c}/data/pointers4.c | 0 test/{ => c}/data/pointers4_fail.c | 0 test/{ => c}/data/pointers5.c | 0 test/{ => c}/data/pointers5_fail.c | 0 test/{ => c}/data/pointers8.c | 0 test/{ => c}/data/pointers_fail.c | 0 test/{ => c}/data/struct_alias.c | 0 test/{ => c}/data/struct_alias_fail.c | 0 test/{ => c}/data/struct_array.c | 0 test/{ => c}/data/struct_array_fail.c | 0 test/{ => c}/data/struct_assign.c | 0 test/{ => c}/data/struct_assign_fail.c | 0 test/{ => c}/data/struct_cast.c | 0 test/{ => c}/data/struct_cast1.c | 0 test/{ => c}/data/struct_cast1_fail.c | 0 test/{ => c}/data/struct_cast_fail.c | 0 test/{ => c}/data/struct_const_return.c | 0 test/{ => c}/data/struct_const_return_fail.c | 0 test/{ => c}/data/struct_init.c | 0 test/{ => c}/data/struct_init_fail.c | 0 test/{ => c}/data/struct_return.c | 0 test/{ => c}/data/two_arrays.c | 0 test/{ => c}/data/two_arrays1.c | 0 test/{ => c}/data/two_arrays1_fail.c | 0 test/{ => c}/data/two_arrays2.c | 0 test/{ => c}/data/two_arrays3.c | 0 test/{ => c}/data/two_arrays4.c | 0 test/{ => c}/data/two_arrays5.c | 0 test/{ => c}/data/two_arrays6.c | 0 test/{ => c}/data/two_arrays6_fail.c | 0 test/{ => c}/data/two_arrays_fail.c | 0 test/{ => c}/failing/config.yml | 0 test/{ => c}/failing/exit.c | 0 test/{ => c}/failing/extern_mem2.c | 0 test/{ => c}/failing/struct_by_value.c | 0 test/{ => c}/float/bitcast.c | 0 test/{ => c}/float/bitcast_fail.c | 0 test/{ => c}/float/change_rm.c | 0 test/{ => c}/float/change_rm_fail.c | 0 test/{ => c}/float/config.yml | 0 test/{ => c}/float/double_op_fail.c | 0 test/{ => c}/float/double_ops.c | 0 test/{ => c}/float/double_to_int.c | 0 test/{ => c}/float/double_to_int_fail.c | 0 test/{ => c}/float/float_int_union.c | 0 test/{ => c}/float/float_int_union_fail.c | 0 test/{ => c}/float/float_op_fail.c | 0 test/{ => c}/float/float_ops.c | 0 test/{ => c}/float/float_ops_rm.c | 0 test/{ => c}/float/float_ops_rm_fail.c | 0 test/{ => c}/float/floats_in_memory.c | 0 test/{ => c}/float/floats_in_memory_fail.c | 0 test/{ => c}/float/floor.c | 0 test/{ => c}/float/floor_fail.c | 0 test/{ => c}/float/get_rm_invalid.c | 0 test/{ => c}/float/get_rm_invalid_fail.c | 0 test/{ => c}/float/half_intrinsics.c | 0 test/{ => c}/float/half_intrinsics_fail.c | 0 test/{ => c}/float/intrinsics.c | 0 test/{ => c}/float/intrinsics_fail.c | 0 test/{ => c}/float/llvm_intrinsic.c | 0 test/{ => c}/float/llvm_intrinsic_fail.c | 0 test/{ => c}/float/set_rm_invalid.c | 0 test/{ => c}/float/set_rm_invalid_fail.c | 0 test/{ => c}/float/simple_double.c | 0 test/{ => c}/float/simple_double_fail.c | 0 test/{ => c}/float/simple_float.c | 0 test/{ => c}/float/simple_float_fail.c | 0 test/{ => c}/float/smack_code_annot.c | 0 test/{ => c}/float/smack_code_annot_fail.c | 0 test/{ => c}/locks/.gitignore | 0 test/{ => c}/locks/config.yml | 0 test/{ => c}/locks/test_locks_10_true.c | 0 test/{ => c}/locks/test_locks_11_true.c | 0 test/{ => c}/locks/test_locks_12_true.c | 0 test/{ => c}/locks/test_locks_13_true.c | 0 test/{ => c}/locks/test_locks_14_false.c | 0 test/{ => c}/locks/test_locks_14_true.c | 0 test/{ => c}/locks/test_locks_15_false.c | 0 test/{ => c}/locks/test_locks_15_true.c | 0 test/{ => c}/locks/test_locks_5_true.c | 0 test/{ => c}/locks/test_locks_6_true.c | 0 test/{ => c}/locks/test_locks_7_true.c | 0 test/{ => c}/locks/test_locks_8_true.c | 0 test/{ => c}/locks/test_locks_9_true.c | 0 test/{ => c}/mathc/ceil.c | 0 test/{ => c}/mathc/ceil_fail.c | 0 test/{ => c}/mathc/ceilf.c | 0 test/{ => c}/mathc/ceilf_fail.c | 0 test/{ => c}/mathc/ceill.c | 0 test/{ => c}/mathc/ceill_fail.c | 0 test/{ => c}/mathc/config.yml | 0 test/{ => c}/mathc/copysign.c | 0 test/{ => c}/mathc/copysign_fail.c | 0 test/{ => c}/mathc/copysignf.c | 0 test/{ => c}/mathc/copysignf_fail.c | 0 test/{ => c}/mathc/copysignl.c | 0 test/{ => c}/mathc/copysignl_fail.c | 0 test/{ => c}/mathc/fabs.c | 0 test/{ => c}/mathc/fabs_fail.c | 0 test/{ => c}/mathc/fabsf.c | 0 test/{ => c}/mathc/fabsf_fail.c | 0 test/{ => c}/mathc/fabsl.c | 0 test/{ => c}/mathc/fabsl_fail.c | 0 test/{ => c}/mathc/fdim.c | 0 test/{ => c}/mathc/fdim_fail.c | 0 test/{ => c}/mathc/fdimf.c | 0 test/{ => c}/mathc/fdimf_fail.c | 0 test/{ => c}/mathc/fdiml.c | 0 test/{ => c}/mathc/fdiml_fail.c | 0 test/{ => c}/mathc/floor.c | 0 test/{ => c}/mathc/floor_fail.c | 0 test/{ => c}/mathc/floorf.c | 0 test/{ => c}/mathc/floorf_fail.c | 0 test/{ => c}/mathc/floorl.c | 0 test/{ => c}/mathc/floorl_fail.c | 0 test/{ => c}/mathc/fmax.c | 0 test/{ => c}/mathc/fmax_fail.c | 0 test/{ => c}/mathc/fmaxf.c | 0 test/{ => c}/mathc/fmaxf_fail.c | 0 test/{ => c}/mathc/fmaxl.c | 0 test/{ => c}/mathc/fmaxl_fail.c | 0 test/{ => c}/mathc/fmin.c | 0 test/{ => c}/mathc/fmin_fail.c | 0 test/{ => c}/mathc/fminf.c | 0 test/{ => c}/mathc/fminf_fail.c | 0 test/{ => c}/mathc/fminl.c | 0 test/{ => c}/mathc/fminl_fail.c | 0 test/{ => c}/mathc/fmod.c | 0 test/{ => c}/mathc/fmod_fail.c | 0 test/{ => c}/mathc/fmodf.c | 0 test/{ => c}/mathc/fmodf_fail.c | 0 test/{ => c}/mathc/fmodl.c | 0 test/{ => c}/mathc/fmodl_fail.c | 0 test/{ => c}/mathc/issue_198.c | 0 test/{ => c}/mathc/issue_198_fail.c | 0 test/{ => c}/mathc/issue_244.c | 0 test/{ => c}/mathc/issue_244_fail.c | 0 test/{ => c}/mathc/lrint.c | 0 test/{ => c}/mathc/lrint_fail.c | 0 test/{ => c}/mathc/lrintf.c | 0 test/{ => c}/mathc/lrintf_fail.c | 0 test/{ => c}/mathc/lrintl.c | 0 test/{ => c}/mathc/lrintl_fail.c | 0 test/{ => c}/mathc/lround.c | 0 test/{ => c}/mathc/lround_fail.c | 0 test/{ => c}/mathc/lroundf.c | 0 test/{ => c}/mathc/lroundf_fail.c | 0 test/{ => c}/mathc/lroundl.c | 0 test/{ => c}/mathc/lroundl_fail.c | 0 test/{ => c}/mathc/modf.c | 0 test/{ => c}/mathc/modf_fail.c | 0 test/{ => c}/mathc/modff.c | 0 test/{ => c}/mathc/modff_fail.c | 0 test/{ => c}/mathc/modfl.c | 0 test/{ => c}/mathc/modfl_fail.c | 0 test/{ => c}/mathc/nearbyint.c | 0 test/{ => c}/mathc/nearbyint_fail.c | 0 test/{ => c}/mathc/nearbyintf.c | 0 test/{ => c}/mathc/nearbyintf_fail.c | 0 test/{ => c}/mathc/nearbyintl.c | 0 test/{ => c}/mathc/nearbyintl_fail.c | 0 test/{ => c}/mathc/remainder.c | 0 test/{ => c}/mathc/remainder_fail.c | 0 test/{ => c}/mathc/remainderf.c | 0 test/{ => c}/mathc/remainderf_fail.c | 0 test/{ => c}/mathc/remainderl.c | 0 test/{ => c}/mathc/remainderl_fail.c | 0 test/{ => c}/mathc/rint.c | 0 test/{ => c}/mathc/rint_fail.c | 0 test/{ => c}/mathc/rintf.c | 0 test/{ => c}/mathc/rintf_fail.c | 0 test/{ => c}/mathc/rintl.c | 0 test/{ => c}/mathc/rintl_fail.c | 0 test/{ => c}/mathc/round.c | 0 test/{ => c}/mathc/round_fail.c | 0 test/{ => c}/mathc/roundf.c | 0 test/{ => c}/mathc/roundf_fail.c | 0 test/{ => c}/mathc/roundl.c | 0 test/{ => c}/mathc/roundl_fail.c | 0 test/{ => c}/mathc/sqrt.c | 0 test/{ => c}/mathc/sqrt_fail.c | 0 test/{ => c}/mathc/sqrtf.c | 0 test/{ => c}/mathc/sqrtf_fail.c | 0 test/{ => c}/mathc/sqrtl.c | 0 test/{ => c}/mathc/sqrtl_fail.c | 0 test/{ => c}/mathc/trunc.c | 0 test/{ => c}/mathc/trunc_fail.c | 0 test/{ => c}/mathc/truncf.c | 0 test/{ => c}/mathc/truncf_fail.c | 0 test/{ => c}/mathc/truncl.c | 0 test/{ => c}/mathc/truncl_fail.c | 0 test/{ => c}/memory-safety/adjacent.c | 0 test/{ => c}/memory-safety/adjacent_fail.c | 0 test/{ => c}/memory-safety/adjacent_global.c | 0 test/{ => c}/memory-safety/adjacent_global_fail.c | 0 test/{ => c}/memory-safety/array1.c | 0 test/{ => c}/memory-safety/array1_fail.c | 0 test/{ => c}/memory-safety/array2_free_fail.c | 0 test/{ => c}/memory-safety/array_free1.c | 0 test/{ => c}/memory-safety/array_free1_fail.c | 0 test/{ => c}/memory-safety/array_free1_fail1.c | 0 test/{ => c}/memory-safety/config.yml | 0 test/{ => c}/memory-safety/errno_test.c | 0 test/{ => c}/memory-safety/global_alloc.c | 0 test/{ => c}/memory-safety/global_alloc_fail_free.c | 0 test/{ => c}/memory-safety/global_and_heap_alloc.c | 0 .../memory-safety/global_and_heap_alloc_fail_free.c | 0 .../memory-safety/global_and_heap_alloc_fail_no_free.c | 0 test/{ => c}/memory-safety/malloc_nondet.c | 0 test/{ => c}/memory-safety/malloc_nondet_fail.c | 0 test/{ => c}/memory-safety/null_dereference_fail.c | 0 test/{ => c}/memory-safety/simple_double_free.c | 0 test/{ => c}/memory-safety/structure1.c | 0 test/{ => c}/memory-safety/structure1_fail.c | 0 .../ntdrivers-simplified/cdaudio_simpl1_false.cil.c | 0 .../ntdrivers-simplified/cdaudio_simpl1_true.cil.c | 0 test/{ => c}/ntdrivers-simplified/config.yml | 0 .../ntdrivers-simplified/diskperf_simpl1_true.cil.c | 0 .../ntdrivers-simplified/floppy_simpl3_false.cil.c | 0 .../{ => c}/ntdrivers-simplified/floppy_simpl3_true.cil.c | 0 .../ntdrivers-simplified/floppy_simpl4_false.cil.c | 0 .../{ => c}/ntdrivers-simplified/floppy_simpl4_true.cil.c | 0 .../ntdrivers-simplified/kbfiltr_simpl1_true.cil.c | 0 .../ntdrivers-simplified/kbfiltr_simpl2_false.cil.c | 0 .../ntdrivers-simplified/kbfiltr_simpl2_true.cil.c | 0 test/{ => c}/ntdrivers/cdaudio_true.i.cil.c | 0 test/{ => c}/ntdrivers/config.yml | 0 test/{ => c}/ntdrivers/diskperf_false.i.cil.c | 0 test/{ => c}/ntdrivers/diskperf_true.i.cil.c | 0 test/{ => c}/ntdrivers/floppy2_true.i.cil.c | 0 test/{ => c}/ntdrivers/floppy_false.i.cil.c | 0 test/{ => c}/ntdrivers/floppy_true.i.cil.c | 0 test/{ => c}/ntdrivers/kbfiltr_false.i.cil.c | 0 test/{ => c}/ntdrivers/parport_false.i.cil.c | 0 test/{ => c}/ntdrivers/parport_true.i.cil.c | 0 test/{ => c}/pthread/account.c | 0 test/{ => c}/pthread/account_fail.c | 0 test/{ => c}/pthread/cond.c | 0 test/{ => c}/pthread/cond_fail.c | 0 test/{ => c}/pthread/config.yml | 0 test/{ => c}/pthread/equal.c | 0 test/{ => c}/pthread/equal2.c | 0 test/{ => c}/pthread/join.c | 0 test/{ => c}/pthread/join_fail.c | 0 test/{ => c}/pthread/join_return.c | 0 test/{ => c}/pthread/join_return2.c | 0 test/{ => c}/pthread/join_return2_fail.c | 0 test/{ => c}/pthread/join_return_fail.c | 0 test/{ => c}/pthread/join_self.c | 0 test/{ => c}/pthread/join_self_fail.c | 0 test/{ => c}/pthread/lock.c | 0 test/{ => c}/pthread/lock2.c | 0 test/{ => c}/pthread/lock2_fail.c | 0 test/{ => c}/pthread/lock3.c | 0 test/{ => c}/pthread/lock3_fail.c | 0 test/{ => c}/pthread/lock4.c | 0 test/{ => c}/pthread/lock4_fail.c | 0 test/{ => c}/pthread/lock5.c | 0 test/{ => c}/pthread/lock5_fail.c | 0 test/{ => c}/pthread/lock_fail.c | 0 test/{ => c}/pthread/lockattr.c | 0 test/{ => c}/pthread_extras/config.yml | 0 test/{ => c}/pthread_extras/dekker_true-unreach-call.c | 0 test/{ => c}/pthread_extras/lamport_true-unreach-call.c | 0 test/{ => c}/pthread_extras/lazy01_false-unreach-call.c | 0 test/{ => c}/pthread_extras/peterson_true-unreach-call.c | 0 test/{ => c}/pthread_extras/queue_false-unreach-call.c | 0 test/{ => c}/pthread_extras/queue_ok_true-unreach-call.c | 0 .../{ => c}/pthread_extras/reorder_2_false-unreach-call.c | 0 .../{ => c}/pthread_extras/reorder_5_false-unreach-call.c | 0 test/{ => c}/pthread_extras/scull_true-unreach-call.c | 0 test/{ => c}/pthread_extras/sigma_false-unreach-call.c | 0 .../pthread_extras/sigma_false_GREAT-unreach-call.c | 0 .../{ => c}/pthread_extras/singleton_false-unreach-call.c | 0 .../pthread_extras/singleton_with-uninit-problems-true.c | 0 test/{ => c}/pthread_extras/sssc12_true-unreach-call.c | 0 test/{ => c}/pthread_extras/stack_false-unreach-call.c | 0 test/{ => c}/pthread_extras/stack_true-unreach-call.c | 0 .../pthread_extras/stateful01_false-unreach-call.c | 0 .../{ => c}/pthread_extras/stateful01_true-unreach-call.c | 0 test/{ => c}/pthread_extras/sync01_true-unreach-call.c | 0 test/{ => c}/pthread_extras/szymanski_true-unreach-call.c | 0 .../pthread_extras/time_var_mutex_true-unreach-call.c | 0 .../pthread_extras/twostage_3_false-unreach-call.c | 0 test/{ => c}/reach/.gitignore | 0 test/{ => c}/reach/break.c | 0 test/{ => c}/reach/break.expected | 0 test/{ => c}/reach/config.yml | 0 test/{ => c}/reach/continue.c | 0 test/{ => c}/reach/continue.expected | 0 test/{ => c}/reach/do.c | 0 test/{ => c}/reach/do.expected | 0 test/{ => c}/reach/for.c | 0 test/{ => c}/reach/for.expected | 0 test/{ => c}/reach/for2.c | 0 test/{ => c}/reach/for2.expected | 0 test/{ => c}/reach/func.c | 0 test/{ => c}/reach/func.expected | 0 test/{ => c}/reach/func2.c | 0 test/{ => c}/reach/func2.expected | 0 test/{ => c}/reach/func3.c | 0 test/{ => c}/reach/func3.expected | 0 test/{ => c}/reach/if.c | 0 test/{ => c}/reach/if.expected | 0 test/{ => c}/reach/if2.c | 0 test/{ => c}/reach/if2.expected | 0 test/{ => c}/reach/if3.c | 0 test/{ => c}/reach/if3.expected | 0 test/{ => c}/reach/if4.c | 0 test/{ => c}/reach/if4.expected | 0 test/{ => c}/reach/libs.c | 0 test/{ => c}/reach/libs.expected | 0 test/{ => c}/reach/regtest.py | 0 test/{ => c}/reach/return.c | 0 test/{ => c}/reach/return.expected | 0 test/{ => c}/reach/switch.c | 0 test/{ => c}/reach/switch.expected | 0 test/{ => c}/reach/switch2.c | 0 test/{ => c}/reach/switch2.expected | 0 test/{ => c}/reach/switch3.c | 0 test/{ => c}/reach/switch3.expected | 0 test/{ => c}/reach/switch4.c | 0 test/{ => c}/reach/switch4.expected | 0 test/{ => c}/reach/while.c | 0 test/{ => c}/reach/while.expected | 0 test/{ => c}/reach/while2.c | 0 test/{ => c}/reach/while2.expected | 0 test/{ => c}/reach/while3.c | 0 test/{ => c}/reach/while3.expected | 0 test/{ => c}/simd/add.c | 0 test/{ => c}/simd/add_fail.c | 0 test/{ => c}/simd/cast.c | 0 test/{ => c}/simd/cast_fail.c | 0 test/{ => c}/simd/config.yml | 0 test/{ => c}/simd/constant.c | 0 test/{ => c}/simd/constant_fail.c | 0 test/{ => c}/simd/shuffle.c | 0 test/{ => c}/simd/shuffle_fail.c | 0 test/{ => c}/special/assume.c | 0 test/{ => c}/special/assume2.c | 0 test/{ => c}/special/assume_check.c | 0 test/{ => c}/special/assume_check2.c | 0 test/{ => c}/special/assume_check_fail.c | 0 test/{ => c}/special/assume_fail.c | 0 test/{ => c}/strings/config.yml | 0 test/{ => c}/strings/strcat.c | 0 test/{ => c}/strings/strcat_fail.c | 0 test/{ => c}/strings/strcat_overflow.c | 0 test/{ => c}/strings/strchr.c | 0 test/{ => c}/strings/strchr_fail.c | 0 test/{ => c}/strings/strcmp.c | 0 test/{ => c}/strings/strcmp_fail.c | 0 test/{ => c}/strings/strcpy.c | 0 test/{ => c}/strings/strcpy_fail.c | 0 test/{ => c}/strings/strcpy_overflow.c | 0 test/{ => c}/strings/strcspn.c | 0 test/{ => c}/strings/strcspn_fail.c | 0 test/{ => c}/strings/strlen.c | 0 test/{ => c}/strings/strlen_fail.c | 0 test/{ => c}/strings/strncat.c | 0 test/{ => c}/strings/strncat_fail.c | 0 test/{ => c}/strings/strncmp.c | 0 test/{ => c}/strings/strncmp_fail.c | 0 test/{ => c}/strings/strncmp_toolong.c | 0 test/{ => c}/strings/strpbrk.c | 0 test/{ => c}/strings/strpbrk_fail.c | 0 test/{ => c}/strings/strrchr.c | 0 test/{ => c}/strings/strrchr_fail.c | 0 test/{ => c}/strings/strspn.c | 0 test/{ => c}/strings/strspn_fail.c | 0 test/{ => c}/strings/strstr.c | 0 test/{ => c}/strings/strstr_fail.c | 0 test/{ => c}/strings/strtok.c | 0 test/{ => c}/strings/strtok_fail.c | 0 test/{ => c}/timeouts/config.yml | 0 test/cplusplus/{ => basic}/config.yml | 0 test/cplusplus/{ => basic}/hello.cc | 0 test/cplusplus/{ => basic}/hello_fail.cc | 0 test/regtest.py | 8 ++++++-- 565 files changed, 6 insertions(+), 2 deletions(-) rename test/{ => c}/basic/ase_example.c (100%) rename test/{ => c}/basic/ase_example_fail.c (100%) rename test/{ => c}/basic/atomic_cas.c (100%) rename test/{ => c}/basic/atomic_cas_fail.c (100%) rename test/{ => c}/basic/big_numbers.c (100%) rename test/{ => c}/basic/big_numbers_fail.c (100%) rename test/{ => c}/basic/big_types.c (100%) rename test/{ => c}/basic/checking.c (100%) rename test/{ => c}/basic/checking_invert_bpl.c (100%) rename test/{ => c}/basic/checking_invert_out.c (100%) rename test/{ => c}/basic/config.yml (100%) rename test/{ => c}/basic/extern_func.c (100%) rename test/{ => c}/basic/extern_mem.c (100%) rename test/{ => c}/basic/extern_mem_fail.c (100%) rename test/{ => c}/basic/gcd.c (100%) rename test/{ => c}/basic/gcd_1_true.c (100%) rename test/{ => c}/basic/globals.c (100%) rename test/{ => c}/basic/globals_fail.c (100%) rename test/{ => c}/basic/init_funcs_example.c (100%) rename test/{ => c}/basic/init_funcs_example_fail.c (100%) rename test/{ => c}/basic/init_funcs_global.c (100%) rename test/{ => c}/basic/init_funcs_global_fail.c (100%) rename test/{ => c}/basic/jain_1_true.c (100%) rename test/{ => c}/basic/jain_2_true.c (100%) rename test/{ => c}/basic/jain_4_true.c (100%) rename test/{ => c}/basic/jain_5_true.c (100%) rename test/{ => c}/basic/limits.c (100%) rename test/{ => c}/basic/limits_fail.c (100%) rename test/{ => c}/basic/list.c (100%) rename test/{ => c}/basic/list_fail.c (100%) rename test/{ => c}/basic/lock.c (100%) rename test/{ => c}/basic/lock_fail.c (100%) rename test/{ => c}/basic/loop.c (100%) rename test/{ => c}/basic/loop1.c (100%) rename test/{ => c}/basic/loop1_fail.c (100%) rename test/{ => c}/basic/loop_fail.c (100%) rename test/{ => c}/basic/negative_numbers.c (100%) rename test/{ => c}/basic/negative_numbers_fail.c (100%) rename test/{ => c}/basic/nondet.c (100%) rename test/{ => c}/basic/printfs.c (100%) rename test/{ => c}/basic/return_label.c (100%) rename test/{ => c}/basic/select.c (100%) rename test/{ => c}/basic/select_fail.c (100%) rename test/{ => c}/basic/simple.c (100%) rename test/{ => c}/basic/simple_fail.c (100%) rename test/{ => c}/basic/simple_pre.c (100%) rename test/{ => c}/basic/simple_pre1.c (100%) rename test/{ => c}/basic/simple_pre1_fail.c (100%) rename test/{ => c}/basic/simple_pre2.c (100%) rename test/{ => c}/basic/simple_pre2_fail.c (100%) rename test/{ => c}/basic/simple_pre3.c (100%) rename test/{ => c}/basic/simple_pre3_fail.c (100%) rename test/{ => c}/basic/simple_pre4.c (100%) rename test/{ => c}/basic/simple_pre4_fail.c (100%) rename test/{ => c}/basic/simple_pre_fail.c (100%) rename test/{ => c}/basic/smack_code_call.c (100%) rename test/{ => c}/basic/smack_code_call_fail.c (100%) rename test/{ => c}/basic/split_aggregate_values.c (100%) rename test/{ => c}/basic/split_aggregate_values_fail.c (100%) rename test/{ => c}/basic/strings.c (100%) rename test/{ => c}/basic/strings1.c (100%) rename test/{ => c}/basic/strings1_fail.c (100%) rename test/{ => c}/basic/strings_fail.c (100%) rename test/{ => c}/basic/test_memcpy.c (100%) rename test/{ => c}/basic/test_memcpy_fail.c (100%) rename test/{ => c}/basic/timing-annotations.c (100%) rename test/{ => c}/basic/transform-bpl.c (100%) rename test/{ => c}/basic/transform-out.c (100%) rename test/{ => c}/basic/uninterpreted.c (100%) rename test/{ => c}/basic/uninterpreted_fail.c (100%) rename test/{ => c}/basic/vararg.c (100%) rename test/{ => c}/basic/vararg_fail.c (100%) rename test/{ => c}/bits/absolute.c (100%) rename test/{ => c}/bits/absolute_fail.c (100%) rename test/{ => c}/bits/bit_field.c (100%) rename test/{ => c}/bits/bit_field_fail.c (100%) rename test/{ => c}/bits/bit_fields.c (100%) rename test/{ => c}/bits/bit_fields_fail.c (100%) rename test/{ => c}/bits/bitreverse.c (100%) rename test/{ => c}/bits/bitreverse_fail.c (100%) rename test/{ => c}/bits/byte_swap.c (100%) rename test/{ => c}/bits/byte_swap_fail.c (100%) rename test/{ => c}/bits/config.yml (100%) rename test/{ => c}/bits/countlz.c (100%) rename test/{ => c}/bits/countlz_fail.c (100%) rename test/{ => c}/bits/countlz_fail2.c (100%) rename test/{ => c}/bits/countlz_zero_fail.c (100%) rename test/{ => c}/bits/countpop32.c (100%) rename test/{ => c}/bits/countpop32_fail.c (100%) rename test/{ => c}/bits/counttz.c (100%) rename test/{ => c}/bits/counttz_fail.c (100%) rename test/{ => c}/bits/counttz_fail2.c (100%) rename test/{ => c}/bits/interleave_bits_fail.c (100%) rename test/{ => c}/bits/interleave_bits_true.c (100%) rename test/{ => c}/bits/left_shift_negative_fail.c (100%) rename test/{ => c}/bits/left_shift_overflow.c (100%) rename test/{ => c}/bits/left_shift_overflow_fail.c (100%) rename test/{ => c}/bits/left_shift_unsigned.c (100%) rename test/{ => c}/bits/left_shift_unsigned_fail.c (100%) rename test/{ => c}/bits/malloc_non_alias.c (100%) rename test/{ => c}/bits/mm.c (100%) rename test/{ => c}/bits/mm_fail.c (100%) rename test/{ => c}/bits/num_conversion_1_fail.c (100%) rename test/{ => c}/bits/num_conversion_1_true.c (100%) rename test/{ => c}/bits/num_conversion_2_fail.c (100%) rename test/{ => c}/bits/num_conversion_2_true.c (100%) rename test/{ => c}/bits/pointers4.c (100%) rename test/{ => c}/bits/pointers4_fail.c (100%) rename test/{ => c}/bits/pointers6.c (100%) rename test/{ => c}/bits/pointers7.c (100%) rename test/{ => c}/bits/pointers7_fail.c (100%) rename test/{ => c}/bits/smack_code_annot.c (100%) rename test/{ => c}/bits/smack_code_annot_fail.c (100%) rename test/{ => c}/bits/sync-fetch.c (100%) rename test/{ => c}/bits/sync-fetch_fail.c (100%) rename test/{ => c}/bits/unaligned_struct.c (100%) rename test/{ => c}/bits/unaligned_struct_fail.c (100%) rename test/{ => c}/contracts/.gitignore (100%) rename test/{ => c}/contracts/and.c (100%) rename test/{ => c}/contracts/and_fail.c (100%) rename test/{ => c}/contracts/array.c (100%) rename test/{ => c}/contracts/array_fail.c (100%) rename test/{ => c}/contracts/config.yml (100%) rename test/{ => c}/contracts/failing/array_forall.c (100%) rename test/{ => c}/contracts/failing/array_forall_fail.c (100%) rename test/{ => c}/contracts/failing/forall.c (100%) rename test/{ => c}/contracts/failing/forall_fail.c (100%) rename test/{ => c}/contracts/failing/old.c (100%) rename test/{ => c}/contracts/failing/old_fail.c (100%) rename test/{ => c}/contracts/failing/result.c (100%) rename test/{ => c}/contracts/failing/result_fail.c (100%) rename test/{ => c}/contracts/invariant.c (100%) rename test/{ => c}/contracts/invariant_fail.c (100%) rename test/{ => c}/contracts/requires_const.c (100%) rename test/{ => c}/contracts/simple.c (100%) rename test/{ => c}/contracts/simple_fail.c (100%) rename test/{ => c}/data/array.c (100%) rename test/{ => c}/data/array1.c (100%) rename test/{ => c}/data/array1_fail.c (100%) rename test/{ => c}/data/array2.c (100%) rename test/{ => c}/data/array2_fail.c (100%) rename test/{ => c}/data/array3.c (100%) rename test/{ => c}/data/array3_fail.c (100%) rename test/{ => c}/data/array4.c (100%) rename test/{ => c}/data/array4_fail.c (100%) rename test/{ => c}/data/array_free.c (100%) rename test/{ => c}/data/array_free2.c (100%) rename test/{ => c}/data/array_free2_fail.c (100%) rename test/{ => c}/data/array_free_fail.c (100%) rename test/{ => c}/data/extern_func_ptr.c (100%) rename test/{ => c}/data/extern_func_ptr_fail.c (100%) rename test/{ => c}/data/extern_struct.c (100%) rename test/{ => c}/data/free_as_func_ptr.c (100%) rename test/{ => c}/data/func_ptr.c (100%) rename test/{ => c}/data/func_ptr1.c (100%) rename test/{ => c}/data/func_ptr1_fail.c (100%) rename test/{ => c}/data/func_ptr2.c (100%) rename test/{ => c}/data/func_ptr2_fail.c (100%) rename test/{ => c}/data/func_ptr_alias.c (100%) rename test/{ => c}/data/func_ptr_alias1.c (100%) rename test/{ => c}/data/func_ptr_alias1_fail.c (100%) rename test/{ => c}/data/func_ptr_alias_fail.c (100%) rename test/{ => c}/data/func_ptr_array.c (100%) rename test/{ => c}/data/func_ptr_array_fail.c (100%) rename test/{ => c}/data/func_ptr_fail.c (100%) rename test/{ => c}/data/func_ptr_vararg.c (100%) rename test/{ => c}/data/func_ptr_vararg_fail.c (100%) rename test/{ => c}/data/global_structs.c (100%) rename test/{ => c}/data/global_structs_fail.c (100%) rename test/{ => c}/data/globals_func_ptr.c (100%) rename test/{ => c}/data/globals_func_ptr_fail.c (100%) rename test/{ => c}/data/nested_struct.c (100%) rename test/{ => c}/data/nested_struct1.c (100%) rename test/{ => c}/data/nested_struct1_fail.c (100%) rename test/{ => c}/data/nested_struct2.c (100%) rename test/{ => c}/data/nested_struct2_fail.c (100%) rename test/{ => c}/data/nested_struct_fail.c (100%) rename test/{ => c}/data/nondet_pointer_fail.c (100%) rename test/{ => c}/data/pointers.c (100%) rename test/{ => c}/data/pointers1.c (100%) rename test/{ => c}/data/pointers1_fail.c (100%) rename test/{ => c}/data/pointers2.c (100%) rename test/{ => c}/data/pointers2_fail.c (100%) rename test/{ => c}/data/pointers3.c (100%) rename test/{ => c}/data/pointers3_fail.c (100%) rename test/{ => c}/data/pointers4.c (100%) rename test/{ => c}/data/pointers4_fail.c (100%) rename test/{ => c}/data/pointers5.c (100%) rename test/{ => c}/data/pointers5_fail.c (100%) rename test/{ => c}/data/pointers8.c (100%) rename test/{ => c}/data/pointers_fail.c (100%) rename test/{ => c}/data/struct_alias.c (100%) rename test/{ => c}/data/struct_alias_fail.c (100%) rename test/{ => c}/data/struct_array.c (100%) rename test/{ => c}/data/struct_array_fail.c (100%) rename test/{ => c}/data/struct_assign.c (100%) rename test/{ => c}/data/struct_assign_fail.c (100%) rename test/{ => c}/data/struct_cast.c (100%) rename test/{ => c}/data/struct_cast1.c (100%) rename test/{ => c}/data/struct_cast1_fail.c (100%) rename test/{ => c}/data/struct_cast_fail.c (100%) rename test/{ => c}/data/struct_const_return.c (100%) rename test/{ => c}/data/struct_const_return_fail.c (100%) rename test/{ => c}/data/struct_init.c (100%) rename test/{ => c}/data/struct_init_fail.c (100%) rename test/{ => c}/data/struct_return.c (100%) rename test/{ => c}/data/two_arrays.c (100%) rename test/{ => c}/data/two_arrays1.c (100%) rename test/{ => c}/data/two_arrays1_fail.c (100%) rename test/{ => c}/data/two_arrays2.c (100%) rename test/{ => c}/data/two_arrays3.c (100%) rename test/{ => c}/data/two_arrays4.c (100%) rename test/{ => c}/data/two_arrays5.c (100%) rename test/{ => c}/data/two_arrays6.c (100%) rename test/{ => c}/data/two_arrays6_fail.c (100%) rename test/{ => c}/data/two_arrays_fail.c (100%) rename test/{ => c}/failing/config.yml (100%) rename test/{ => c}/failing/exit.c (100%) rename test/{ => c}/failing/extern_mem2.c (100%) rename test/{ => c}/failing/struct_by_value.c (100%) rename test/{ => c}/float/bitcast.c (100%) rename test/{ => c}/float/bitcast_fail.c (100%) rename test/{ => c}/float/change_rm.c (100%) rename test/{ => c}/float/change_rm_fail.c (100%) rename test/{ => c}/float/config.yml (100%) rename test/{ => c}/float/double_op_fail.c (100%) rename test/{ => c}/float/double_ops.c (100%) rename test/{ => c}/float/double_to_int.c (100%) rename test/{ => c}/float/double_to_int_fail.c (100%) rename test/{ => c}/float/float_int_union.c (100%) rename test/{ => c}/float/float_int_union_fail.c (100%) rename test/{ => c}/float/float_op_fail.c (100%) rename test/{ => c}/float/float_ops.c (100%) rename test/{ => c}/float/float_ops_rm.c (100%) rename test/{ => c}/float/float_ops_rm_fail.c (100%) rename test/{ => c}/float/floats_in_memory.c (100%) rename test/{ => c}/float/floats_in_memory_fail.c (100%) rename test/{ => c}/float/floor.c (100%) rename test/{ => c}/float/floor_fail.c (100%) rename test/{ => c}/float/get_rm_invalid.c (100%) rename test/{ => c}/float/get_rm_invalid_fail.c (100%) rename test/{ => c}/float/half_intrinsics.c (100%) rename test/{ => c}/float/half_intrinsics_fail.c (100%) rename test/{ => c}/float/intrinsics.c (100%) rename test/{ => c}/float/intrinsics_fail.c (100%) rename test/{ => c}/float/llvm_intrinsic.c (100%) rename test/{ => c}/float/llvm_intrinsic_fail.c (100%) rename test/{ => c}/float/set_rm_invalid.c (100%) rename test/{ => c}/float/set_rm_invalid_fail.c (100%) rename test/{ => c}/float/simple_double.c (100%) rename test/{ => c}/float/simple_double_fail.c (100%) rename test/{ => c}/float/simple_float.c (100%) rename test/{ => c}/float/simple_float_fail.c (100%) rename test/{ => c}/float/smack_code_annot.c (100%) rename test/{ => c}/float/smack_code_annot_fail.c (100%) rename test/{ => c}/locks/.gitignore (100%) rename test/{ => c}/locks/config.yml (100%) rename test/{ => c}/locks/test_locks_10_true.c (100%) rename test/{ => c}/locks/test_locks_11_true.c (100%) rename test/{ => c}/locks/test_locks_12_true.c (100%) rename test/{ => c}/locks/test_locks_13_true.c (100%) rename test/{ => c}/locks/test_locks_14_false.c (100%) rename test/{ => c}/locks/test_locks_14_true.c (100%) rename test/{ => c}/locks/test_locks_15_false.c (100%) rename test/{ => c}/locks/test_locks_15_true.c (100%) rename test/{ => c}/locks/test_locks_5_true.c (100%) rename test/{ => c}/locks/test_locks_6_true.c (100%) rename test/{ => c}/locks/test_locks_7_true.c (100%) rename test/{ => c}/locks/test_locks_8_true.c (100%) rename test/{ => c}/locks/test_locks_9_true.c (100%) rename test/{ => c}/mathc/ceil.c (100%) rename test/{ => c}/mathc/ceil_fail.c (100%) rename test/{ => c}/mathc/ceilf.c (100%) rename test/{ => c}/mathc/ceilf_fail.c (100%) rename test/{ => c}/mathc/ceill.c (100%) rename test/{ => c}/mathc/ceill_fail.c (100%) rename test/{ => c}/mathc/config.yml (100%) rename test/{ => c}/mathc/copysign.c (100%) rename test/{ => c}/mathc/copysign_fail.c (100%) rename test/{ => c}/mathc/copysignf.c (100%) rename test/{ => c}/mathc/copysignf_fail.c (100%) rename test/{ => c}/mathc/copysignl.c (100%) rename test/{ => c}/mathc/copysignl_fail.c (100%) rename test/{ => c}/mathc/fabs.c (100%) rename test/{ => c}/mathc/fabs_fail.c (100%) rename test/{ => c}/mathc/fabsf.c (100%) rename test/{ => c}/mathc/fabsf_fail.c (100%) rename test/{ => c}/mathc/fabsl.c (100%) rename test/{ => c}/mathc/fabsl_fail.c (100%) rename test/{ => c}/mathc/fdim.c (100%) rename test/{ => c}/mathc/fdim_fail.c (100%) rename test/{ => c}/mathc/fdimf.c (100%) rename test/{ => c}/mathc/fdimf_fail.c (100%) rename test/{ => c}/mathc/fdiml.c (100%) rename test/{ => c}/mathc/fdiml_fail.c (100%) rename test/{ => c}/mathc/floor.c (100%) rename test/{ => c}/mathc/floor_fail.c (100%) rename test/{ => c}/mathc/floorf.c (100%) rename test/{ => c}/mathc/floorf_fail.c (100%) rename test/{ => c}/mathc/floorl.c (100%) rename test/{ => c}/mathc/floorl_fail.c (100%) rename test/{ => c}/mathc/fmax.c (100%) rename test/{ => c}/mathc/fmax_fail.c (100%) rename test/{ => c}/mathc/fmaxf.c (100%) rename test/{ => c}/mathc/fmaxf_fail.c (100%) rename test/{ => c}/mathc/fmaxl.c (100%) rename test/{ => c}/mathc/fmaxl_fail.c (100%) rename test/{ => c}/mathc/fmin.c (100%) rename test/{ => c}/mathc/fmin_fail.c (100%) rename test/{ => c}/mathc/fminf.c (100%) rename test/{ => c}/mathc/fminf_fail.c (100%) rename test/{ => c}/mathc/fminl.c (100%) rename test/{ => c}/mathc/fminl_fail.c (100%) rename test/{ => c}/mathc/fmod.c (100%) rename test/{ => c}/mathc/fmod_fail.c (100%) rename test/{ => c}/mathc/fmodf.c (100%) rename test/{ => c}/mathc/fmodf_fail.c (100%) rename test/{ => c}/mathc/fmodl.c (100%) rename test/{ => c}/mathc/fmodl_fail.c (100%) rename test/{ => c}/mathc/issue_198.c (100%) rename test/{ => c}/mathc/issue_198_fail.c (100%) rename test/{ => c}/mathc/issue_244.c (100%) rename test/{ => c}/mathc/issue_244_fail.c (100%) rename test/{ => c}/mathc/lrint.c (100%) rename test/{ => c}/mathc/lrint_fail.c (100%) rename test/{ => c}/mathc/lrintf.c (100%) rename test/{ => c}/mathc/lrintf_fail.c (100%) rename test/{ => c}/mathc/lrintl.c (100%) rename test/{ => c}/mathc/lrintl_fail.c (100%) rename test/{ => c}/mathc/lround.c (100%) rename test/{ => c}/mathc/lround_fail.c (100%) rename test/{ => c}/mathc/lroundf.c (100%) rename test/{ => c}/mathc/lroundf_fail.c (100%) rename test/{ => c}/mathc/lroundl.c (100%) rename test/{ => c}/mathc/lroundl_fail.c (100%) rename test/{ => c}/mathc/modf.c (100%) rename test/{ => c}/mathc/modf_fail.c (100%) rename test/{ => c}/mathc/modff.c (100%) rename test/{ => c}/mathc/modff_fail.c (100%) rename test/{ => c}/mathc/modfl.c (100%) rename test/{ => c}/mathc/modfl_fail.c (100%) rename test/{ => c}/mathc/nearbyint.c (100%) rename test/{ => c}/mathc/nearbyint_fail.c (100%) rename test/{ => c}/mathc/nearbyintf.c (100%) rename test/{ => c}/mathc/nearbyintf_fail.c (100%) rename test/{ => c}/mathc/nearbyintl.c (100%) rename test/{ => c}/mathc/nearbyintl_fail.c (100%) rename test/{ => c}/mathc/remainder.c (100%) rename test/{ => c}/mathc/remainder_fail.c (100%) rename test/{ => c}/mathc/remainderf.c (100%) rename test/{ => c}/mathc/remainderf_fail.c (100%) rename test/{ => c}/mathc/remainderl.c (100%) rename test/{ => c}/mathc/remainderl_fail.c (100%) rename test/{ => c}/mathc/rint.c (100%) rename test/{ => c}/mathc/rint_fail.c (100%) rename test/{ => c}/mathc/rintf.c (100%) rename test/{ => c}/mathc/rintf_fail.c (100%) rename test/{ => c}/mathc/rintl.c (100%) rename test/{ => c}/mathc/rintl_fail.c (100%) rename test/{ => c}/mathc/round.c (100%) rename test/{ => c}/mathc/round_fail.c (100%) rename test/{ => c}/mathc/roundf.c (100%) rename test/{ => c}/mathc/roundf_fail.c (100%) rename test/{ => c}/mathc/roundl.c (100%) rename test/{ => c}/mathc/roundl_fail.c (100%) rename test/{ => c}/mathc/sqrt.c (100%) rename test/{ => c}/mathc/sqrt_fail.c (100%) rename test/{ => c}/mathc/sqrtf.c (100%) rename test/{ => c}/mathc/sqrtf_fail.c (100%) rename test/{ => c}/mathc/sqrtl.c (100%) rename test/{ => c}/mathc/sqrtl_fail.c (100%) rename test/{ => c}/mathc/trunc.c (100%) rename test/{ => c}/mathc/trunc_fail.c (100%) rename test/{ => c}/mathc/truncf.c (100%) rename test/{ => c}/mathc/truncf_fail.c (100%) rename test/{ => c}/mathc/truncl.c (100%) rename test/{ => c}/mathc/truncl_fail.c (100%) rename test/{ => c}/memory-safety/adjacent.c (100%) rename test/{ => c}/memory-safety/adjacent_fail.c (100%) rename test/{ => c}/memory-safety/adjacent_global.c (100%) rename test/{ => c}/memory-safety/adjacent_global_fail.c (100%) rename test/{ => c}/memory-safety/array1.c (100%) rename test/{ => c}/memory-safety/array1_fail.c (100%) rename test/{ => c}/memory-safety/array2_free_fail.c (100%) rename test/{ => c}/memory-safety/array_free1.c (100%) rename test/{ => c}/memory-safety/array_free1_fail.c (100%) rename test/{ => c}/memory-safety/array_free1_fail1.c (100%) rename test/{ => c}/memory-safety/config.yml (100%) rename test/{ => c}/memory-safety/errno_test.c (100%) rename test/{ => c}/memory-safety/global_alloc.c (100%) rename test/{ => c}/memory-safety/global_alloc_fail_free.c (100%) rename test/{ => c}/memory-safety/global_and_heap_alloc.c (100%) rename test/{ => c}/memory-safety/global_and_heap_alloc_fail_free.c (100%) rename test/{ => c}/memory-safety/global_and_heap_alloc_fail_no_free.c (100%) rename test/{ => c}/memory-safety/malloc_nondet.c (100%) rename test/{ => c}/memory-safety/malloc_nondet_fail.c (100%) rename test/{ => c}/memory-safety/null_dereference_fail.c (100%) rename test/{ => c}/memory-safety/simple_double_free.c (100%) rename test/{ => c}/memory-safety/structure1.c (100%) rename test/{ => c}/memory-safety/structure1_fail.c (100%) rename test/{ => c}/ntdrivers-simplified/cdaudio_simpl1_false.cil.c (100%) rename test/{ => c}/ntdrivers-simplified/cdaudio_simpl1_true.cil.c (100%) rename test/{ => c}/ntdrivers-simplified/config.yml (100%) rename test/{ => c}/ntdrivers-simplified/diskperf_simpl1_true.cil.c (100%) rename test/{ => c}/ntdrivers-simplified/floppy_simpl3_false.cil.c (100%) rename test/{ => c}/ntdrivers-simplified/floppy_simpl3_true.cil.c (100%) rename test/{ => c}/ntdrivers-simplified/floppy_simpl4_false.cil.c (100%) rename test/{ => c}/ntdrivers-simplified/floppy_simpl4_true.cil.c (100%) rename test/{ => c}/ntdrivers-simplified/kbfiltr_simpl1_true.cil.c (100%) rename test/{ => c}/ntdrivers-simplified/kbfiltr_simpl2_false.cil.c (100%) rename test/{ => c}/ntdrivers-simplified/kbfiltr_simpl2_true.cil.c (100%) rename test/{ => c}/ntdrivers/cdaudio_true.i.cil.c (100%) rename test/{ => c}/ntdrivers/config.yml (100%) rename test/{ => c}/ntdrivers/diskperf_false.i.cil.c (100%) rename test/{ => c}/ntdrivers/diskperf_true.i.cil.c (100%) rename test/{ => c}/ntdrivers/floppy2_true.i.cil.c (100%) rename test/{ => c}/ntdrivers/floppy_false.i.cil.c (100%) rename test/{ => c}/ntdrivers/floppy_true.i.cil.c (100%) rename test/{ => c}/ntdrivers/kbfiltr_false.i.cil.c (100%) rename test/{ => c}/ntdrivers/parport_false.i.cil.c (100%) rename test/{ => c}/ntdrivers/parport_true.i.cil.c (100%) rename test/{ => c}/pthread/account.c (100%) rename test/{ => c}/pthread/account_fail.c (100%) rename test/{ => c}/pthread/cond.c (100%) rename test/{ => c}/pthread/cond_fail.c (100%) rename test/{ => c}/pthread/config.yml (100%) rename test/{ => c}/pthread/equal.c (100%) rename test/{ => c}/pthread/equal2.c (100%) rename test/{ => c}/pthread/join.c (100%) rename test/{ => c}/pthread/join_fail.c (100%) rename test/{ => c}/pthread/join_return.c (100%) rename test/{ => c}/pthread/join_return2.c (100%) rename test/{ => c}/pthread/join_return2_fail.c (100%) rename test/{ => c}/pthread/join_return_fail.c (100%) rename test/{ => c}/pthread/join_self.c (100%) rename test/{ => c}/pthread/join_self_fail.c (100%) rename test/{ => c}/pthread/lock.c (100%) rename test/{ => c}/pthread/lock2.c (100%) rename test/{ => c}/pthread/lock2_fail.c (100%) rename test/{ => c}/pthread/lock3.c (100%) rename test/{ => c}/pthread/lock3_fail.c (100%) rename test/{ => c}/pthread/lock4.c (100%) rename test/{ => c}/pthread/lock4_fail.c (100%) rename test/{ => c}/pthread/lock5.c (100%) rename test/{ => c}/pthread/lock5_fail.c (100%) rename test/{ => c}/pthread/lock_fail.c (100%) rename test/{ => c}/pthread/lockattr.c (100%) rename test/{ => c}/pthread_extras/config.yml (100%) rename test/{ => c}/pthread_extras/dekker_true-unreach-call.c (100%) rename test/{ => c}/pthread_extras/lamport_true-unreach-call.c (100%) rename test/{ => c}/pthread_extras/lazy01_false-unreach-call.c (100%) rename test/{ => c}/pthread_extras/peterson_true-unreach-call.c (100%) rename test/{ => c}/pthread_extras/queue_false-unreach-call.c (100%) rename test/{ => c}/pthread_extras/queue_ok_true-unreach-call.c (100%) rename test/{ => c}/pthread_extras/reorder_2_false-unreach-call.c (100%) rename test/{ => c}/pthread_extras/reorder_5_false-unreach-call.c (100%) rename test/{ => c}/pthread_extras/scull_true-unreach-call.c (100%) rename test/{ => c}/pthread_extras/sigma_false-unreach-call.c (100%) rename test/{ => c}/pthread_extras/sigma_false_GREAT-unreach-call.c (100%) rename test/{ => c}/pthread_extras/singleton_false-unreach-call.c (100%) rename test/{ => c}/pthread_extras/singleton_with-uninit-problems-true.c (100%) rename test/{ => c}/pthread_extras/sssc12_true-unreach-call.c (100%) rename test/{ => c}/pthread_extras/stack_false-unreach-call.c (100%) rename test/{ => c}/pthread_extras/stack_true-unreach-call.c (100%) rename test/{ => c}/pthread_extras/stateful01_false-unreach-call.c (100%) rename test/{ => c}/pthread_extras/stateful01_true-unreach-call.c (100%) rename test/{ => c}/pthread_extras/sync01_true-unreach-call.c (100%) rename test/{ => c}/pthread_extras/szymanski_true-unreach-call.c (100%) rename test/{ => c}/pthread_extras/time_var_mutex_true-unreach-call.c (100%) rename test/{ => c}/pthread_extras/twostage_3_false-unreach-call.c (100%) rename test/{ => c}/reach/.gitignore (100%) rename test/{ => c}/reach/break.c (100%) rename test/{ => c}/reach/break.expected (100%) rename test/{ => c}/reach/config.yml (100%) rename test/{ => c}/reach/continue.c (100%) rename test/{ => c}/reach/continue.expected (100%) rename test/{ => c}/reach/do.c (100%) rename test/{ => c}/reach/do.expected (100%) rename test/{ => c}/reach/for.c (100%) rename test/{ => c}/reach/for.expected (100%) rename test/{ => c}/reach/for2.c (100%) rename test/{ => c}/reach/for2.expected (100%) rename test/{ => c}/reach/func.c (100%) rename test/{ => c}/reach/func.expected (100%) rename test/{ => c}/reach/func2.c (100%) rename test/{ => c}/reach/func2.expected (100%) rename test/{ => c}/reach/func3.c (100%) rename test/{ => c}/reach/func3.expected (100%) rename test/{ => c}/reach/if.c (100%) rename test/{ => c}/reach/if.expected (100%) rename test/{ => c}/reach/if2.c (100%) rename test/{ => c}/reach/if2.expected (100%) rename test/{ => c}/reach/if3.c (100%) rename test/{ => c}/reach/if3.expected (100%) rename test/{ => c}/reach/if4.c (100%) rename test/{ => c}/reach/if4.expected (100%) rename test/{ => c}/reach/libs.c (100%) rename test/{ => c}/reach/libs.expected (100%) rename test/{ => c}/reach/regtest.py (100%) rename test/{ => c}/reach/return.c (100%) rename test/{ => c}/reach/return.expected (100%) rename test/{ => c}/reach/switch.c (100%) rename test/{ => c}/reach/switch.expected (100%) rename test/{ => c}/reach/switch2.c (100%) rename test/{ => c}/reach/switch2.expected (100%) rename test/{ => c}/reach/switch3.c (100%) rename test/{ => c}/reach/switch3.expected (100%) rename test/{ => c}/reach/switch4.c (100%) rename test/{ => c}/reach/switch4.expected (100%) rename test/{ => c}/reach/while.c (100%) rename test/{ => c}/reach/while.expected (100%) rename test/{ => c}/reach/while2.c (100%) rename test/{ => c}/reach/while2.expected (100%) rename test/{ => c}/reach/while3.c (100%) rename test/{ => c}/reach/while3.expected (100%) rename test/{ => c}/simd/add.c (100%) rename test/{ => c}/simd/add_fail.c (100%) rename test/{ => c}/simd/cast.c (100%) rename test/{ => c}/simd/cast_fail.c (100%) rename test/{ => c}/simd/config.yml (100%) rename test/{ => c}/simd/constant.c (100%) rename test/{ => c}/simd/constant_fail.c (100%) rename test/{ => c}/simd/shuffle.c (100%) rename test/{ => c}/simd/shuffle_fail.c (100%) rename test/{ => c}/special/assume.c (100%) rename test/{ => c}/special/assume2.c (100%) rename test/{ => c}/special/assume_check.c (100%) rename test/{ => c}/special/assume_check2.c (100%) rename test/{ => c}/special/assume_check_fail.c (100%) rename test/{ => c}/special/assume_fail.c (100%) rename test/{ => c}/strings/config.yml (100%) rename test/{ => c}/strings/strcat.c (100%) rename test/{ => c}/strings/strcat_fail.c (100%) rename test/{ => c}/strings/strcat_overflow.c (100%) rename test/{ => c}/strings/strchr.c (100%) rename test/{ => c}/strings/strchr_fail.c (100%) rename test/{ => c}/strings/strcmp.c (100%) rename test/{ => c}/strings/strcmp_fail.c (100%) rename test/{ => c}/strings/strcpy.c (100%) rename test/{ => c}/strings/strcpy_fail.c (100%) rename test/{ => c}/strings/strcpy_overflow.c (100%) rename test/{ => c}/strings/strcspn.c (100%) rename test/{ => c}/strings/strcspn_fail.c (100%) rename test/{ => c}/strings/strlen.c (100%) rename test/{ => c}/strings/strlen_fail.c (100%) rename test/{ => c}/strings/strncat.c (100%) rename test/{ => c}/strings/strncat_fail.c (100%) rename test/{ => c}/strings/strncmp.c (100%) rename test/{ => c}/strings/strncmp_fail.c (100%) rename test/{ => c}/strings/strncmp_toolong.c (100%) rename test/{ => c}/strings/strpbrk.c (100%) rename test/{ => c}/strings/strpbrk_fail.c (100%) rename test/{ => c}/strings/strrchr.c (100%) rename test/{ => c}/strings/strrchr_fail.c (100%) rename test/{ => c}/strings/strspn.c (100%) rename test/{ => c}/strings/strspn_fail.c (100%) rename test/{ => c}/strings/strstr.c (100%) rename test/{ => c}/strings/strstr_fail.c (100%) rename test/{ => c}/strings/strtok.c (100%) rename test/{ => c}/strings/strtok_fail.c (100%) rename test/{ => c}/timeouts/config.yml (100%) rename test/cplusplus/{ => basic}/config.yml (100%) rename test/cplusplus/{ => basic}/hello.cc (100%) rename test/cplusplus/{ => basic}/hello_fail.cc (100%) diff --git a/test/basic/ase_example.c b/test/c/basic/ase_example.c similarity index 100% rename from test/basic/ase_example.c rename to test/c/basic/ase_example.c diff --git a/test/basic/ase_example_fail.c b/test/c/basic/ase_example_fail.c similarity index 100% rename from test/basic/ase_example_fail.c rename to test/c/basic/ase_example_fail.c diff --git a/test/basic/atomic_cas.c b/test/c/basic/atomic_cas.c similarity index 100% rename from test/basic/atomic_cas.c rename to test/c/basic/atomic_cas.c diff --git a/test/basic/atomic_cas_fail.c b/test/c/basic/atomic_cas_fail.c similarity index 100% rename from test/basic/atomic_cas_fail.c rename to test/c/basic/atomic_cas_fail.c diff --git a/test/basic/big_numbers.c b/test/c/basic/big_numbers.c similarity index 100% rename from test/basic/big_numbers.c rename to test/c/basic/big_numbers.c diff --git a/test/basic/big_numbers_fail.c b/test/c/basic/big_numbers_fail.c similarity index 100% rename from test/basic/big_numbers_fail.c rename to test/c/basic/big_numbers_fail.c diff --git a/test/basic/big_types.c b/test/c/basic/big_types.c similarity index 100% rename from test/basic/big_types.c rename to test/c/basic/big_types.c diff --git a/test/basic/checking.c b/test/c/basic/checking.c similarity index 100% rename from test/basic/checking.c rename to test/c/basic/checking.c diff --git a/test/basic/checking_invert_bpl.c b/test/c/basic/checking_invert_bpl.c similarity index 100% rename from test/basic/checking_invert_bpl.c rename to test/c/basic/checking_invert_bpl.c diff --git a/test/basic/checking_invert_out.c b/test/c/basic/checking_invert_out.c similarity index 100% rename from test/basic/checking_invert_out.c rename to test/c/basic/checking_invert_out.c diff --git a/test/basic/config.yml b/test/c/basic/config.yml similarity index 100% rename from test/basic/config.yml rename to test/c/basic/config.yml diff --git a/test/basic/extern_func.c b/test/c/basic/extern_func.c similarity index 100% rename from test/basic/extern_func.c rename to test/c/basic/extern_func.c diff --git a/test/basic/extern_mem.c b/test/c/basic/extern_mem.c similarity index 100% rename from test/basic/extern_mem.c rename to test/c/basic/extern_mem.c diff --git a/test/basic/extern_mem_fail.c b/test/c/basic/extern_mem_fail.c similarity index 100% rename from test/basic/extern_mem_fail.c rename to test/c/basic/extern_mem_fail.c diff --git a/test/basic/gcd.c b/test/c/basic/gcd.c similarity index 100% rename from test/basic/gcd.c rename to test/c/basic/gcd.c diff --git a/test/basic/gcd_1_true.c b/test/c/basic/gcd_1_true.c similarity index 100% rename from test/basic/gcd_1_true.c rename to test/c/basic/gcd_1_true.c diff --git a/test/basic/globals.c b/test/c/basic/globals.c similarity index 100% rename from test/basic/globals.c rename to test/c/basic/globals.c diff --git a/test/basic/globals_fail.c b/test/c/basic/globals_fail.c similarity index 100% rename from test/basic/globals_fail.c rename to test/c/basic/globals_fail.c diff --git a/test/basic/init_funcs_example.c b/test/c/basic/init_funcs_example.c similarity index 100% rename from test/basic/init_funcs_example.c rename to test/c/basic/init_funcs_example.c diff --git a/test/basic/init_funcs_example_fail.c b/test/c/basic/init_funcs_example_fail.c similarity index 100% rename from test/basic/init_funcs_example_fail.c rename to test/c/basic/init_funcs_example_fail.c diff --git a/test/basic/init_funcs_global.c b/test/c/basic/init_funcs_global.c similarity index 100% rename from test/basic/init_funcs_global.c rename to test/c/basic/init_funcs_global.c diff --git a/test/basic/init_funcs_global_fail.c b/test/c/basic/init_funcs_global_fail.c similarity index 100% rename from test/basic/init_funcs_global_fail.c rename to test/c/basic/init_funcs_global_fail.c diff --git a/test/basic/jain_1_true.c b/test/c/basic/jain_1_true.c similarity index 100% rename from test/basic/jain_1_true.c rename to test/c/basic/jain_1_true.c diff --git a/test/basic/jain_2_true.c b/test/c/basic/jain_2_true.c similarity index 100% rename from test/basic/jain_2_true.c rename to test/c/basic/jain_2_true.c diff --git a/test/basic/jain_4_true.c b/test/c/basic/jain_4_true.c similarity index 100% rename from test/basic/jain_4_true.c rename to test/c/basic/jain_4_true.c diff --git a/test/basic/jain_5_true.c b/test/c/basic/jain_5_true.c similarity index 100% rename from test/basic/jain_5_true.c rename to test/c/basic/jain_5_true.c diff --git a/test/basic/limits.c b/test/c/basic/limits.c similarity index 100% rename from test/basic/limits.c rename to test/c/basic/limits.c diff --git a/test/basic/limits_fail.c b/test/c/basic/limits_fail.c similarity index 100% rename from test/basic/limits_fail.c rename to test/c/basic/limits_fail.c diff --git a/test/basic/list.c b/test/c/basic/list.c similarity index 100% rename from test/basic/list.c rename to test/c/basic/list.c diff --git a/test/basic/list_fail.c b/test/c/basic/list_fail.c similarity index 100% rename from test/basic/list_fail.c rename to test/c/basic/list_fail.c diff --git a/test/basic/lock.c b/test/c/basic/lock.c similarity index 100% rename from test/basic/lock.c rename to test/c/basic/lock.c diff --git a/test/basic/lock_fail.c b/test/c/basic/lock_fail.c similarity index 100% rename from test/basic/lock_fail.c rename to test/c/basic/lock_fail.c diff --git a/test/basic/loop.c b/test/c/basic/loop.c similarity index 100% rename from test/basic/loop.c rename to test/c/basic/loop.c diff --git a/test/basic/loop1.c b/test/c/basic/loop1.c similarity index 100% rename from test/basic/loop1.c rename to test/c/basic/loop1.c diff --git a/test/basic/loop1_fail.c b/test/c/basic/loop1_fail.c similarity index 100% rename from test/basic/loop1_fail.c rename to test/c/basic/loop1_fail.c diff --git a/test/basic/loop_fail.c b/test/c/basic/loop_fail.c similarity index 100% rename from test/basic/loop_fail.c rename to test/c/basic/loop_fail.c diff --git a/test/basic/negative_numbers.c b/test/c/basic/negative_numbers.c similarity index 100% rename from test/basic/negative_numbers.c rename to test/c/basic/negative_numbers.c diff --git a/test/basic/negative_numbers_fail.c b/test/c/basic/negative_numbers_fail.c similarity index 100% rename from test/basic/negative_numbers_fail.c rename to test/c/basic/negative_numbers_fail.c diff --git a/test/basic/nondet.c b/test/c/basic/nondet.c similarity index 100% rename from test/basic/nondet.c rename to test/c/basic/nondet.c diff --git a/test/basic/printfs.c b/test/c/basic/printfs.c similarity index 100% rename from test/basic/printfs.c rename to test/c/basic/printfs.c diff --git a/test/basic/return_label.c b/test/c/basic/return_label.c similarity index 100% rename from test/basic/return_label.c rename to test/c/basic/return_label.c diff --git a/test/basic/select.c b/test/c/basic/select.c similarity index 100% rename from test/basic/select.c rename to test/c/basic/select.c diff --git a/test/basic/select_fail.c b/test/c/basic/select_fail.c similarity index 100% rename from test/basic/select_fail.c rename to test/c/basic/select_fail.c diff --git a/test/basic/simple.c b/test/c/basic/simple.c similarity index 100% rename from test/basic/simple.c rename to test/c/basic/simple.c diff --git a/test/basic/simple_fail.c b/test/c/basic/simple_fail.c similarity index 100% rename from test/basic/simple_fail.c rename to test/c/basic/simple_fail.c diff --git a/test/basic/simple_pre.c b/test/c/basic/simple_pre.c similarity index 100% rename from test/basic/simple_pre.c rename to test/c/basic/simple_pre.c diff --git a/test/basic/simple_pre1.c b/test/c/basic/simple_pre1.c similarity index 100% rename from test/basic/simple_pre1.c rename to test/c/basic/simple_pre1.c diff --git a/test/basic/simple_pre1_fail.c b/test/c/basic/simple_pre1_fail.c similarity index 100% rename from test/basic/simple_pre1_fail.c rename to test/c/basic/simple_pre1_fail.c diff --git a/test/basic/simple_pre2.c b/test/c/basic/simple_pre2.c similarity index 100% rename from test/basic/simple_pre2.c rename to test/c/basic/simple_pre2.c diff --git a/test/basic/simple_pre2_fail.c b/test/c/basic/simple_pre2_fail.c similarity index 100% rename from test/basic/simple_pre2_fail.c rename to test/c/basic/simple_pre2_fail.c diff --git a/test/basic/simple_pre3.c b/test/c/basic/simple_pre3.c similarity index 100% rename from test/basic/simple_pre3.c rename to test/c/basic/simple_pre3.c diff --git a/test/basic/simple_pre3_fail.c b/test/c/basic/simple_pre3_fail.c similarity index 100% rename from test/basic/simple_pre3_fail.c rename to test/c/basic/simple_pre3_fail.c diff --git a/test/basic/simple_pre4.c b/test/c/basic/simple_pre4.c similarity index 100% rename from test/basic/simple_pre4.c rename to test/c/basic/simple_pre4.c diff --git a/test/basic/simple_pre4_fail.c b/test/c/basic/simple_pre4_fail.c similarity index 100% rename from test/basic/simple_pre4_fail.c rename to test/c/basic/simple_pre4_fail.c diff --git a/test/basic/simple_pre_fail.c b/test/c/basic/simple_pre_fail.c similarity index 100% rename from test/basic/simple_pre_fail.c rename to test/c/basic/simple_pre_fail.c diff --git a/test/basic/smack_code_call.c b/test/c/basic/smack_code_call.c similarity index 100% rename from test/basic/smack_code_call.c rename to test/c/basic/smack_code_call.c diff --git a/test/basic/smack_code_call_fail.c b/test/c/basic/smack_code_call_fail.c similarity index 100% rename from test/basic/smack_code_call_fail.c rename to test/c/basic/smack_code_call_fail.c diff --git a/test/basic/split_aggregate_values.c b/test/c/basic/split_aggregate_values.c similarity index 100% rename from test/basic/split_aggregate_values.c rename to test/c/basic/split_aggregate_values.c diff --git a/test/basic/split_aggregate_values_fail.c b/test/c/basic/split_aggregate_values_fail.c similarity index 100% rename from test/basic/split_aggregate_values_fail.c rename to test/c/basic/split_aggregate_values_fail.c diff --git a/test/basic/strings.c b/test/c/basic/strings.c similarity index 100% rename from test/basic/strings.c rename to test/c/basic/strings.c diff --git a/test/basic/strings1.c b/test/c/basic/strings1.c similarity index 100% rename from test/basic/strings1.c rename to test/c/basic/strings1.c diff --git a/test/basic/strings1_fail.c b/test/c/basic/strings1_fail.c similarity index 100% rename from test/basic/strings1_fail.c rename to test/c/basic/strings1_fail.c diff --git a/test/basic/strings_fail.c b/test/c/basic/strings_fail.c similarity index 100% rename from test/basic/strings_fail.c rename to test/c/basic/strings_fail.c diff --git a/test/basic/test_memcpy.c b/test/c/basic/test_memcpy.c similarity index 100% rename from test/basic/test_memcpy.c rename to test/c/basic/test_memcpy.c diff --git a/test/basic/test_memcpy_fail.c b/test/c/basic/test_memcpy_fail.c similarity index 100% rename from test/basic/test_memcpy_fail.c rename to test/c/basic/test_memcpy_fail.c diff --git a/test/basic/timing-annotations.c b/test/c/basic/timing-annotations.c similarity index 100% rename from test/basic/timing-annotations.c rename to test/c/basic/timing-annotations.c diff --git a/test/basic/transform-bpl.c b/test/c/basic/transform-bpl.c similarity index 100% rename from test/basic/transform-bpl.c rename to test/c/basic/transform-bpl.c diff --git a/test/basic/transform-out.c b/test/c/basic/transform-out.c similarity index 100% rename from test/basic/transform-out.c rename to test/c/basic/transform-out.c diff --git a/test/basic/uninterpreted.c b/test/c/basic/uninterpreted.c similarity index 100% rename from test/basic/uninterpreted.c rename to test/c/basic/uninterpreted.c diff --git a/test/basic/uninterpreted_fail.c b/test/c/basic/uninterpreted_fail.c similarity index 100% rename from test/basic/uninterpreted_fail.c rename to test/c/basic/uninterpreted_fail.c diff --git a/test/basic/vararg.c b/test/c/basic/vararg.c similarity index 100% rename from test/basic/vararg.c rename to test/c/basic/vararg.c diff --git a/test/basic/vararg_fail.c b/test/c/basic/vararg_fail.c similarity index 100% rename from test/basic/vararg_fail.c rename to test/c/basic/vararg_fail.c diff --git a/test/bits/absolute.c b/test/c/bits/absolute.c similarity index 100% rename from test/bits/absolute.c rename to test/c/bits/absolute.c diff --git a/test/bits/absolute_fail.c b/test/c/bits/absolute_fail.c similarity index 100% rename from test/bits/absolute_fail.c rename to test/c/bits/absolute_fail.c diff --git a/test/bits/bit_field.c b/test/c/bits/bit_field.c similarity index 100% rename from test/bits/bit_field.c rename to test/c/bits/bit_field.c diff --git a/test/bits/bit_field_fail.c b/test/c/bits/bit_field_fail.c similarity index 100% rename from test/bits/bit_field_fail.c rename to test/c/bits/bit_field_fail.c diff --git a/test/bits/bit_fields.c b/test/c/bits/bit_fields.c similarity index 100% rename from test/bits/bit_fields.c rename to test/c/bits/bit_fields.c diff --git a/test/bits/bit_fields_fail.c b/test/c/bits/bit_fields_fail.c similarity index 100% rename from test/bits/bit_fields_fail.c rename to test/c/bits/bit_fields_fail.c diff --git a/test/bits/bitreverse.c b/test/c/bits/bitreverse.c similarity index 100% rename from test/bits/bitreverse.c rename to test/c/bits/bitreverse.c diff --git a/test/bits/bitreverse_fail.c b/test/c/bits/bitreverse_fail.c similarity index 100% rename from test/bits/bitreverse_fail.c rename to test/c/bits/bitreverse_fail.c diff --git a/test/bits/byte_swap.c b/test/c/bits/byte_swap.c similarity index 100% rename from test/bits/byte_swap.c rename to test/c/bits/byte_swap.c diff --git a/test/bits/byte_swap_fail.c b/test/c/bits/byte_swap_fail.c similarity index 100% rename from test/bits/byte_swap_fail.c rename to test/c/bits/byte_swap_fail.c diff --git a/test/bits/config.yml b/test/c/bits/config.yml similarity index 100% rename from test/bits/config.yml rename to test/c/bits/config.yml diff --git a/test/bits/countlz.c b/test/c/bits/countlz.c similarity index 100% rename from test/bits/countlz.c rename to test/c/bits/countlz.c diff --git a/test/bits/countlz_fail.c b/test/c/bits/countlz_fail.c similarity index 100% rename from test/bits/countlz_fail.c rename to test/c/bits/countlz_fail.c diff --git a/test/bits/countlz_fail2.c b/test/c/bits/countlz_fail2.c similarity index 100% rename from test/bits/countlz_fail2.c rename to test/c/bits/countlz_fail2.c diff --git a/test/bits/countlz_zero_fail.c b/test/c/bits/countlz_zero_fail.c similarity index 100% rename from test/bits/countlz_zero_fail.c rename to test/c/bits/countlz_zero_fail.c diff --git a/test/bits/countpop32.c b/test/c/bits/countpop32.c similarity index 100% rename from test/bits/countpop32.c rename to test/c/bits/countpop32.c diff --git a/test/bits/countpop32_fail.c b/test/c/bits/countpop32_fail.c similarity index 100% rename from test/bits/countpop32_fail.c rename to test/c/bits/countpop32_fail.c diff --git a/test/bits/counttz.c b/test/c/bits/counttz.c similarity index 100% rename from test/bits/counttz.c rename to test/c/bits/counttz.c diff --git a/test/bits/counttz_fail.c b/test/c/bits/counttz_fail.c similarity index 100% rename from test/bits/counttz_fail.c rename to test/c/bits/counttz_fail.c diff --git a/test/bits/counttz_fail2.c b/test/c/bits/counttz_fail2.c similarity index 100% rename from test/bits/counttz_fail2.c rename to test/c/bits/counttz_fail2.c diff --git a/test/bits/interleave_bits_fail.c b/test/c/bits/interleave_bits_fail.c similarity index 100% rename from test/bits/interleave_bits_fail.c rename to test/c/bits/interleave_bits_fail.c diff --git a/test/bits/interleave_bits_true.c b/test/c/bits/interleave_bits_true.c similarity index 100% rename from test/bits/interleave_bits_true.c rename to test/c/bits/interleave_bits_true.c diff --git a/test/bits/left_shift_negative_fail.c b/test/c/bits/left_shift_negative_fail.c similarity index 100% rename from test/bits/left_shift_negative_fail.c rename to test/c/bits/left_shift_negative_fail.c diff --git a/test/bits/left_shift_overflow.c b/test/c/bits/left_shift_overflow.c similarity index 100% rename from test/bits/left_shift_overflow.c rename to test/c/bits/left_shift_overflow.c diff --git a/test/bits/left_shift_overflow_fail.c b/test/c/bits/left_shift_overflow_fail.c similarity index 100% rename from test/bits/left_shift_overflow_fail.c rename to test/c/bits/left_shift_overflow_fail.c diff --git a/test/bits/left_shift_unsigned.c b/test/c/bits/left_shift_unsigned.c similarity index 100% rename from test/bits/left_shift_unsigned.c rename to test/c/bits/left_shift_unsigned.c diff --git a/test/bits/left_shift_unsigned_fail.c b/test/c/bits/left_shift_unsigned_fail.c similarity index 100% rename from test/bits/left_shift_unsigned_fail.c rename to test/c/bits/left_shift_unsigned_fail.c diff --git a/test/bits/malloc_non_alias.c b/test/c/bits/malloc_non_alias.c similarity index 100% rename from test/bits/malloc_non_alias.c rename to test/c/bits/malloc_non_alias.c diff --git a/test/bits/mm.c b/test/c/bits/mm.c similarity index 100% rename from test/bits/mm.c rename to test/c/bits/mm.c diff --git a/test/bits/mm_fail.c b/test/c/bits/mm_fail.c similarity index 100% rename from test/bits/mm_fail.c rename to test/c/bits/mm_fail.c diff --git a/test/bits/num_conversion_1_fail.c b/test/c/bits/num_conversion_1_fail.c similarity index 100% rename from test/bits/num_conversion_1_fail.c rename to test/c/bits/num_conversion_1_fail.c diff --git a/test/bits/num_conversion_1_true.c b/test/c/bits/num_conversion_1_true.c similarity index 100% rename from test/bits/num_conversion_1_true.c rename to test/c/bits/num_conversion_1_true.c diff --git a/test/bits/num_conversion_2_fail.c b/test/c/bits/num_conversion_2_fail.c similarity index 100% rename from test/bits/num_conversion_2_fail.c rename to test/c/bits/num_conversion_2_fail.c diff --git a/test/bits/num_conversion_2_true.c b/test/c/bits/num_conversion_2_true.c similarity index 100% rename from test/bits/num_conversion_2_true.c rename to test/c/bits/num_conversion_2_true.c diff --git a/test/bits/pointers4.c b/test/c/bits/pointers4.c similarity index 100% rename from test/bits/pointers4.c rename to test/c/bits/pointers4.c diff --git a/test/bits/pointers4_fail.c b/test/c/bits/pointers4_fail.c similarity index 100% rename from test/bits/pointers4_fail.c rename to test/c/bits/pointers4_fail.c diff --git a/test/bits/pointers6.c b/test/c/bits/pointers6.c similarity index 100% rename from test/bits/pointers6.c rename to test/c/bits/pointers6.c diff --git a/test/bits/pointers7.c b/test/c/bits/pointers7.c similarity index 100% rename from test/bits/pointers7.c rename to test/c/bits/pointers7.c diff --git a/test/bits/pointers7_fail.c b/test/c/bits/pointers7_fail.c similarity index 100% rename from test/bits/pointers7_fail.c rename to test/c/bits/pointers7_fail.c diff --git a/test/bits/smack_code_annot.c b/test/c/bits/smack_code_annot.c similarity index 100% rename from test/bits/smack_code_annot.c rename to test/c/bits/smack_code_annot.c diff --git a/test/bits/smack_code_annot_fail.c b/test/c/bits/smack_code_annot_fail.c similarity index 100% rename from test/bits/smack_code_annot_fail.c rename to test/c/bits/smack_code_annot_fail.c diff --git a/test/bits/sync-fetch.c b/test/c/bits/sync-fetch.c similarity index 100% rename from test/bits/sync-fetch.c rename to test/c/bits/sync-fetch.c diff --git a/test/bits/sync-fetch_fail.c b/test/c/bits/sync-fetch_fail.c similarity index 100% rename from test/bits/sync-fetch_fail.c rename to test/c/bits/sync-fetch_fail.c diff --git a/test/bits/unaligned_struct.c b/test/c/bits/unaligned_struct.c similarity index 100% rename from test/bits/unaligned_struct.c rename to test/c/bits/unaligned_struct.c diff --git a/test/bits/unaligned_struct_fail.c b/test/c/bits/unaligned_struct_fail.c similarity index 100% rename from test/bits/unaligned_struct_fail.c rename to test/c/bits/unaligned_struct_fail.c diff --git a/test/contracts/.gitignore b/test/c/contracts/.gitignore similarity index 100% rename from test/contracts/.gitignore rename to test/c/contracts/.gitignore diff --git a/test/contracts/and.c b/test/c/contracts/and.c similarity index 100% rename from test/contracts/and.c rename to test/c/contracts/and.c diff --git a/test/contracts/and_fail.c b/test/c/contracts/and_fail.c similarity index 100% rename from test/contracts/and_fail.c rename to test/c/contracts/and_fail.c diff --git a/test/contracts/array.c b/test/c/contracts/array.c similarity index 100% rename from test/contracts/array.c rename to test/c/contracts/array.c diff --git a/test/contracts/array_fail.c b/test/c/contracts/array_fail.c similarity index 100% rename from test/contracts/array_fail.c rename to test/c/contracts/array_fail.c diff --git a/test/contracts/config.yml b/test/c/contracts/config.yml similarity index 100% rename from test/contracts/config.yml rename to test/c/contracts/config.yml diff --git a/test/contracts/failing/array_forall.c b/test/c/contracts/failing/array_forall.c similarity index 100% rename from test/contracts/failing/array_forall.c rename to test/c/contracts/failing/array_forall.c diff --git a/test/contracts/failing/array_forall_fail.c b/test/c/contracts/failing/array_forall_fail.c similarity index 100% rename from test/contracts/failing/array_forall_fail.c rename to test/c/contracts/failing/array_forall_fail.c diff --git a/test/contracts/failing/forall.c b/test/c/contracts/failing/forall.c similarity index 100% rename from test/contracts/failing/forall.c rename to test/c/contracts/failing/forall.c diff --git a/test/contracts/failing/forall_fail.c b/test/c/contracts/failing/forall_fail.c similarity index 100% rename from test/contracts/failing/forall_fail.c rename to test/c/contracts/failing/forall_fail.c diff --git a/test/contracts/failing/old.c b/test/c/contracts/failing/old.c similarity index 100% rename from test/contracts/failing/old.c rename to test/c/contracts/failing/old.c diff --git a/test/contracts/failing/old_fail.c b/test/c/contracts/failing/old_fail.c similarity index 100% rename from test/contracts/failing/old_fail.c rename to test/c/contracts/failing/old_fail.c diff --git a/test/contracts/failing/result.c b/test/c/contracts/failing/result.c similarity index 100% rename from test/contracts/failing/result.c rename to test/c/contracts/failing/result.c diff --git a/test/contracts/failing/result_fail.c b/test/c/contracts/failing/result_fail.c similarity index 100% rename from test/contracts/failing/result_fail.c rename to test/c/contracts/failing/result_fail.c diff --git a/test/contracts/invariant.c b/test/c/contracts/invariant.c similarity index 100% rename from test/contracts/invariant.c rename to test/c/contracts/invariant.c diff --git a/test/contracts/invariant_fail.c b/test/c/contracts/invariant_fail.c similarity index 100% rename from test/contracts/invariant_fail.c rename to test/c/contracts/invariant_fail.c diff --git a/test/contracts/requires_const.c b/test/c/contracts/requires_const.c similarity index 100% rename from test/contracts/requires_const.c rename to test/c/contracts/requires_const.c diff --git a/test/contracts/simple.c b/test/c/contracts/simple.c similarity index 100% rename from test/contracts/simple.c rename to test/c/contracts/simple.c diff --git a/test/contracts/simple_fail.c b/test/c/contracts/simple_fail.c similarity index 100% rename from test/contracts/simple_fail.c rename to test/c/contracts/simple_fail.c diff --git a/test/data/array.c b/test/c/data/array.c similarity index 100% rename from test/data/array.c rename to test/c/data/array.c diff --git a/test/data/array1.c b/test/c/data/array1.c similarity index 100% rename from test/data/array1.c rename to test/c/data/array1.c diff --git a/test/data/array1_fail.c b/test/c/data/array1_fail.c similarity index 100% rename from test/data/array1_fail.c rename to test/c/data/array1_fail.c diff --git a/test/data/array2.c b/test/c/data/array2.c similarity index 100% rename from test/data/array2.c rename to test/c/data/array2.c diff --git a/test/data/array2_fail.c b/test/c/data/array2_fail.c similarity index 100% rename from test/data/array2_fail.c rename to test/c/data/array2_fail.c diff --git a/test/data/array3.c b/test/c/data/array3.c similarity index 100% rename from test/data/array3.c rename to test/c/data/array3.c diff --git a/test/data/array3_fail.c b/test/c/data/array3_fail.c similarity index 100% rename from test/data/array3_fail.c rename to test/c/data/array3_fail.c diff --git a/test/data/array4.c b/test/c/data/array4.c similarity index 100% rename from test/data/array4.c rename to test/c/data/array4.c diff --git a/test/data/array4_fail.c b/test/c/data/array4_fail.c similarity index 100% rename from test/data/array4_fail.c rename to test/c/data/array4_fail.c diff --git a/test/data/array_free.c b/test/c/data/array_free.c similarity index 100% rename from test/data/array_free.c rename to test/c/data/array_free.c diff --git a/test/data/array_free2.c b/test/c/data/array_free2.c similarity index 100% rename from test/data/array_free2.c rename to test/c/data/array_free2.c diff --git a/test/data/array_free2_fail.c b/test/c/data/array_free2_fail.c similarity index 100% rename from test/data/array_free2_fail.c rename to test/c/data/array_free2_fail.c diff --git a/test/data/array_free_fail.c b/test/c/data/array_free_fail.c similarity index 100% rename from test/data/array_free_fail.c rename to test/c/data/array_free_fail.c diff --git a/test/data/extern_func_ptr.c b/test/c/data/extern_func_ptr.c similarity index 100% rename from test/data/extern_func_ptr.c rename to test/c/data/extern_func_ptr.c diff --git a/test/data/extern_func_ptr_fail.c b/test/c/data/extern_func_ptr_fail.c similarity index 100% rename from test/data/extern_func_ptr_fail.c rename to test/c/data/extern_func_ptr_fail.c diff --git a/test/data/extern_struct.c b/test/c/data/extern_struct.c similarity index 100% rename from test/data/extern_struct.c rename to test/c/data/extern_struct.c diff --git a/test/data/free_as_func_ptr.c b/test/c/data/free_as_func_ptr.c similarity index 100% rename from test/data/free_as_func_ptr.c rename to test/c/data/free_as_func_ptr.c diff --git a/test/data/func_ptr.c b/test/c/data/func_ptr.c similarity index 100% rename from test/data/func_ptr.c rename to test/c/data/func_ptr.c diff --git a/test/data/func_ptr1.c b/test/c/data/func_ptr1.c similarity index 100% rename from test/data/func_ptr1.c rename to test/c/data/func_ptr1.c diff --git a/test/data/func_ptr1_fail.c b/test/c/data/func_ptr1_fail.c similarity index 100% rename from test/data/func_ptr1_fail.c rename to test/c/data/func_ptr1_fail.c diff --git a/test/data/func_ptr2.c b/test/c/data/func_ptr2.c similarity index 100% rename from test/data/func_ptr2.c rename to test/c/data/func_ptr2.c diff --git a/test/data/func_ptr2_fail.c b/test/c/data/func_ptr2_fail.c similarity index 100% rename from test/data/func_ptr2_fail.c rename to test/c/data/func_ptr2_fail.c diff --git a/test/data/func_ptr_alias.c b/test/c/data/func_ptr_alias.c similarity index 100% rename from test/data/func_ptr_alias.c rename to test/c/data/func_ptr_alias.c diff --git a/test/data/func_ptr_alias1.c b/test/c/data/func_ptr_alias1.c similarity index 100% rename from test/data/func_ptr_alias1.c rename to test/c/data/func_ptr_alias1.c diff --git a/test/data/func_ptr_alias1_fail.c b/test/c/data/func_ptr_alias1_fail.c similarity index 100% rename from test/data/func_ptr_alias1_fail.c rename to test/c/data/func_ptr_alias1_fail.c diff --git a/test/data/func_ptr_alias_fail.c b/test/c/data/func_ptr_alias_fail.c similarity index 100% rename from test/data/func_ptr_alias_fail.c rename to test/c/data/func_ptr_alias_fail.c diff --git a/test/data/func_ptr_array.c b/test/c/data/func_ptr_array.c similarity index 100% rename from test/data/func_ptr_array.c rename to test/c/data/func_ptr_array.c diff --git a/test/data/func_ptr_array_fail.c b/test/c/data/func_ptr_array_fail.c similarity index 100% rename from test/data/func_ptr_array_fail.c rename to test/c/data/func_ptr_array_fail.c diff --git a/test/data/func_ptr_fail.c b/test/c/data/func_ptr_fail.c similarity index 100% rename from test/data/func_ptr_fail.c rename to test/c/data/func_ptr_fail.c diff --git a/test/data/func_ptr_vararg.c b/test/c/data/func_ptr_vararg.c similarity index 100% rename from test/data/func_ptr_vararg.c rename to test/c/data/func_ptr_vararg.c diff --git a/test/data/func_ptr_vararg_fail.c b/test/c/data/func_ptr_vararg_fail.c similarity index 100% rename from test/data/func_ptr_vararg_fail.c rename to test/c/data/func_ptr_vararg_fail.c diff --git a/test/data/global_structs.c b/test/c/data/global_structs.c similarity index 100% rename from test/data/global_structs.c rename to test/c/data/global_structs.c diff --git a/test/data/global_structs_fail.c b/test/c/data/global_structs_fail.c similarity index 100% rename from test/data/global_structs_fail.c rename to test/c/data/global_structs_fail.c diff --git a/test/data/globals_func_ptr.c b/test/c/data/globals_func_ptr.c similarity index 100% rename from test/data/globals_func_ptr.c rename to test/c/data/globals_func_ptr.c diff --git a/test/data/globals_func_ptr_fail.c b/test/c/data/globals_func_ptr_fail.c similarity index 100% rename from test/data/globals_func_ptr_fail.c rename to test/c/data/globals_func_ptr_fail.c diff --git a/test/data/nested_struct.c b/test/c/data/nested_struct.c similarity index 100% rename from test/data/nested_struct.c rename to test/c/data/nested_struct.c diff --git a/test/data/nested_struct1.c b/test/c/data/nested_struct1.c similarity index 100% rename from test/data/nested_struct1.c rename to test/c/data/nested_struct1.c diff --git a/test/data/nested_struct1_fail.c b/test/c/data/nested_struct1_fail.c similarity index 100% rename from test/data/nested_struct1_fail.c rename to test/c/data/nested_struct1_fail.c diff --git a/test/data/nested_struct2.c b/test/c/data/nested_struct2.c similarity index 100% rename from test/data/nested_struct2.c rename to test/c/data/nested_struct2.c diff --git a/test/data/nested_struct2_fail.c b/test/c/data/nested_struct2_fail.c similarity index 100% rename from test/data/nested_struct2_fail.c rename to test/c/data/nested_struct2_fail.c diff --git a/test/data/nested_struct_fail.c b/test/c/data/nested_struct_fail.c similarity index 100% rename from test/data/nested_struct_fail.c rename to test/c/data/nested_struct_fail.c diff --git a/test/data/nondet_pointer_fail.c b/test/c/data/nondet_pointer_fail.c similarity index 100% rename from test/data/nondet_pointer_fail.c rename to test/c/data/nondet_pointer_fail.c diff --git a/test/data/pointers.c b/test/c/data/pointers.c similarity index 100% rename from test/data/pointers.c rename to test/c/data/pointers.c diff --git a/test/data/pointers1.c b/test/c/data/pointers1.c similarity index 100% rename from test/data/pointers1.c rename to test/c/data/pointers1.c diff --git a/test/data/pointers1_fail.c b/test/c/data/pointers1_fail.c similarity index 100% rename from test/data/pointers1_fail.c rename to test/c/data/pointers1_fail.c diff --git a/test/data/pointers2.c b/test/c/data/pointers2.c similarity index 100% rename from test/data/pointers2.c rename to test/c/data/pointers2.c diff --git a/test/data/pointers2_fail.c b/test/c/data/pointers2_fail.c similarity index 100% rename from test/data/pointers2_fail.c rename to test/c/data/pointers2_fail.c diff --git a/test/data/pointers3.c b/test/c/data/pointers3.c similarity index 100% rename from test/data/pointers3.c rename to test/c/data/pointers3.c diff --git a/test/data/pointers3_fail.c b/test/c/data/pointers3_fail.c similarity index 100% rename from test/data/pointers3_fail.c rename to test/c/data/pointers3_fail.c diff --git a/test/data/pointers4.c b/test/c/data/pointers4.c similarity index 100% rename from test/data/pointers4.c rename to test/c/data/pointers4.c diff --git a/test/data/pointers4_fail.c b/test/c/data/pointers4_fail.c similarity index 100% rename from test/data/pointers4_fail.c rename to test/c/data/pointers4_fail.c diff --git a/test/data/pointers5.c b/test/c/data/pointers5.c similarity index 100% rename from test/data/pointers5.c rename to test/c/data/pointers5.c diff --git a/test/data/pointers5_fail.c b/test/c/data/pointers5_fail.c similarity index 100% rename from test/data/pointers5_fail.c rename to test/c/data/pointers5_fail.c diff --git a/test/data/pointers8.c b/test/c/data/pointers8.c similarity index 100% rename from test/data/pointers8.c rename to test/c/data/pointers8.c diff --git a/test/data/pointers_fail.c b/test/c/data/pointers_fail.c similarity index 100% rename from test/data/pointers_fail.c rename to test/c/data/pointers_fail.c diff --git a/test/data/struct_alias.c b/test/c/data/struct_alias.c similarity index 100% rename from test/data/struct_alias.c rename to test/c/data/struct_alias.c diff --git a/test/data/struct_alias_fail.c b/test/c/data/struct_alias_fail.c similarity index 100% rename from test/data/struct_alias_fail.c rename to test/c/data/struct_alias_fail.c diff --git a/test/data/struct_array.c b/test/c/data/struct_array.c similarity index 100% rename from test/data/struct_array.c rename to test/c/data/struct_array.c diff --git a/test/data/struct_array_fail.c b/test/c/data/struct_array_fail.c similarity index 100% rename from test/data/struct_array_fail.c rename to test/c/data/struct_array_fail.c diff --git a/test/data/struct_assign.c b/test/c/data/struct_assign.c similarity index 100% rename from test/data/struct_assign.c rename to test/c/data/struct_assign.c diff --git a/test/data/struct_assign_fail.c b/test/c/data/struct_assign_fail.c similarity index 100% rename from test/data/struct_assign_fail.c rename to test/c/data/struct_assign_fail.c diff --git a/test/data/struct_cast.c b/test/c/data/struct_cast.c similarity index 100% rename from test/data/struct_cast.c rename to test/c/data/struct_cast.c diff --git a/test/data/struct_cast1.c b/test/c/data/struct_cast1.c similarity index 100% rename from test/data/struct_cast1.c rename to test/c/data/struct_cast1.c diff --git a/test/data/struct_cast1_fail.c b/test/c/data/struct_cast1_fail.c similarity index 100% rename from test/data/struct_cast1_fail.c rename to test/c/data/struct_cast1_fail.c diff --git a/test/data/struct_cast_fail.c b/test/c/data/struct_cast_fail.c similarity index 100% rename from test/data/struct_cast_fail.c rename to test/c/data/struct_cast_fail.c diff --git a/test/data/struct_const_return.c b/test/c/data/struct_const_return.c similarity index 100% rename from test/data/struct_const_return.c rename to test/c/data/struct_const_return.c diff --git a/test/data/struct_const_return_fail.c b/test/c/data/struct_const_return_fail.c similarity index 100% rename from test/data/struct_const_return_fail.c rename to test/c/data/struct_const_return_fail.c diff --git a/test/data/struct_init.c b/test/c/data/struct_init.c similarity index 100% rename from test/data/struct_init.c rename to test/c/data/struct_init.c diff --git a/test/data/struct_init_fail.c b/test/c/data/struct_init_fail.c similarity index 100% rename from test/data/struct_init_fail.c rename to test/c/data/struct_init_fail.c diff --git a/test/data/struct_return.c b/test/c/data/struct_return.c similarity index 100% rename from test/data/struct_return.c rename to test/c/data/struct_return.c diff --git a/test/data/two_arrays.c b/test/c/data/two_arrays.c similarity index 100% rename from test/data/two_arrays.c rename to test/c/data/two_arrays.c diff --git a/test/data/two_arrays1.c b/test/c/data/two_arrays1.c similarity index 100% rename from test/data/two_arrays1.c rename to test/c/data/two_arrays1.c diff --git a/test/data/two_arrays1_fail.c b/test/c/data/two_arrays1_fail.c similarity index 100% rename from test/data/two_arrays1_fail.c rename to test/c/data/two_arrays1_fail.c diff --git a/test/data/two_arrays2.c b/test/c/data/two_arrays2.c similarity index 100% rename from test/data/two_arrays2.c rename to test/c/data/two_arrays2.c diff --git a/test/data/two_arrays3.c b/test/c/data/two_arrays3.c similarity index 100% rename from test/data/two_arrays3.c rename to test/c/data/two_arrays3.c diff --git a/test/data/two_arrays4.c b/test/c/data/two_arrays4.c similarity index 100% rename from test/data/two_arrays4.c rename to test/c/data/two_arrays4.c diff --git a/test/data/two_arrays5.c b/test/c/data/two_arrays5.c similarity index 100% rename from test/data/two_arrays5.c rename to test/c/data/two_arrays5.c diff --git a/test/data/two_arrays6.c b/test/c/data/two_arrays6.c similarity index 100% rename from test/data/two_arrays6.c rename to test/c/data/two_arrays6.c diff --git a/test/data/two_arrays6_fail.c b/test/c/data/two_arrays6_fail.c similarity index 100% rename from test/data/two_arrays6_fail.c rename to test/c/data/two_arrays6_fail.c diff --git a/test/data/two_arrays_fail.c b/test/c/data/two_arrays_fail.c similarity index 100% rename from test/data/two_arrays_fail.c rename to test/c/data/two_arrays_fail.c diff --git a/test/failing/config.yml b/test/c/failing/config.yml similarity index 100% rename from test/failing/config.yml rename to test/c/failing/config.yml diff --git a/test/failing/exit.c b/test/c/failing/exit.c similarity index 100% rename from test/failing/exit.c rename to test/c/failing/exit.c diff --git a/test/failing/extern_mem2.c b/test/c/failing/extern_mem2.c similarity index 100% rename from test/failing/extern_mem2.c rename to test/c/failing/extern_mem2.c diff --git a/test/failing/struct_by_value.c b/test/c/failing/struct_by_value.c similarity index 100% rename from test/failing/struct_by_value.c rename to test/c/failing/struct_by_value.c diff --git a/test/float/bitcast.c b/test/c/float/bitcast.c similarity index 100% rename from test/float/bitcast.c rename to test/c/float/bitcast.c diff --git a/test/float/bitcast_fail.c b/test/c/float/bitcast_fail.c similarity index 100% rename from test/float/bitcast_fail.c rename to test/c/float/bitcast_fail.c diff --git a/test/float/change_rm.c b/test/c/float/change_rm.c similarity index 100% rename from test/float/change_rm.c rename to test/c/float/change_rm.c diff --git a/test/float/change_rm_fail.c b/test/c/float/change_rm_fail.c similarity index 100% rename from test/float/change_rm_fail.c rename to test/c/float/change_rm_fail.c diff --git a/test/float/config.yml b/test/c/float/config.yml similarity index 100% rename from test/float/config.yml rename to test/c/float/config.yml diff --git a/test/float/double_op_fail.c b/test/c/float/double_op_fail.c similarity index 100% rename from test/float/double_op_fail.c rename to test/c/float/double_op_fail.c diff --git a/test/float/double_ops.c b/test/c/float/double_ops.c similarity index 100% rename from test/float/double_ops.c rename to test/c/float/double_ops.c diff --git a/test/float/double_to_int.c b/test/c/float/double_to_int.c similarity index 100% rename from test/float/double_to_int.c rename to test/c/float/double_to_int.c diff --git a/test/float/double_to_int_fail.c b/test/c/float/double_to_int_fail.c similarity index 100% rename from test/float/double_to_int_fail.c rename to test/c/float/double_to_int_fail.c diff --git a/test/float/float_int_union.c b/test/c/float/float_int_union.c similarity index 100% rename from test/float/float_int_union.c rename to test/c/float/float_int_union.c diff --git a/test/float/float_int_union_fail.c b/test/c/float/float_int_union_fail.c similarity index 100% rename from test/float/float_int_union_fail.c rename to test/c/float/float_int_union_fail.c diff --git a/test/float/float_op_fail.c b/test/c/float/float_op_fail.c similarity index 100% rename from test/float/float_op_fail.c rename to test/c/float/float_op_fail.c diff --git a/test/float/float_ops.c b/test/c/float/float_ops.c similarity index 100% rename from test/float/float_ops.c rename to test/c/float/float_ops.c diff --git a/test/float/float_ops_rm.c b/test/c/float/float_ops_rm.c similarity index 100% rename from test/float/float_ops_rm.c rename to test/c/float/float_ops_rm.c diff --git a/test/float/float_ops_rm_fail.c b/test/c/float/float_ops_rm_fail.c similarity index 100% rename from test/float/float_ops_rm_fail.c rename to test/c/float/float_ops_rm_fail.c diff --git a/test/float/floats_in_memory.c b/test/c/float/floats_in_memory.c similarity index 100% rename from test/float/floats_in_memory.c rename to test/c/float/floats_in_memory.c diff --git a/test/float/floats_in_memory_fail.c b/test/c/float/floats_in_memory_fail.c similarity index 100% rename from test/float/floats_in_memory_fail.c rename to test/c/float/floats_in_memory_fail.c diff --git a/test/float/floor.c b/test/c/float/floor.c similarity index 100% rename from test/float/floor.c rename to test/c/float/floor.c diff --git a/test/float/floor_fail.c b/test/c/float/floor_fail.c similarity index 100% rename from test/float/floor_fail.c rename to test/c/float/floor_fail.c diff --git a/test/float/get_rm_invalid.c b/test/c/float/get_rm_invalid.c similarity index 100% rename from test/float/get_rm_invalid.c rename to test/c/float/get_rm_invalid.c diff --git a/test/float/get_rm_invalid_fail.c b/test/c/float/get_rm_invalid_fail.c similarity index 100% rename from test/float/get_rm_invalid_fail.c rename to test/c/float/get_rm_invalid_fail.c diff --git a/test/float/half_intrinsics.c b/test/c/float/half_intrinsics.c similarity index 100% rename from test/float/half_intrinsics.c rename to test/c/float/half_intrinsics.c diff --git a/test/float/half_intrinsics_fail.c b/test/c/float/half_intrinsics_fail.c similarity index 100% rename from test/float/half_intrinsics_fail.c rename to test/c/float/half_intrinsics_fail.c diff --git a/test/float/intrinsics.c b/test/c/float/intrinsics.c similarity index 100% rename from test/float/intrinsics.c rename to test/c/float/intrinsics.c diff --git a/test/float/intrinsics_fail.c b/test/c/float/intrinsics_fail.c similarity index 100% rename from test/float/intrinsics_fail.c rename to test/c/float/intrinsics_fail.c diff --git a/test/float/llvm_intrinsic.c b/test/c/float/llvm_intrinsic.c similarity index 100% rename from test/float/llvm_intrinsic.c rename to test/c/float/llvm_intrinsic.c diff --git a/test/float/llvm_intrinsic_fail.c b/test/c/float/llvm_intrinsic_fail.c similarity index 100% rename from test/float/llvm_intrinsic_fail.c rename to test/c/float/llvm_intrinsic_fail.c diff --git a/test/float/set_rm_invalid.c b/test/c/float/set_rm_invalid.c similarity index 100% rename from test/float/set_rm_invalid.c rename to test/c/float/set_rm_invalid.c diff --git a/test/float/set_rm_invalid_fail.c b/test/c/float/set_rm_invalid_fail.c similarity index 100% rename from test/float/set_rm_invalid_fail.c rename to test/c/float/set_rm_invalid_fail.c diff --git a/test/float/simple_double.c b/test/c/float/simple_double.c similarity index 100% rename from test/float/simple_double.c rename to test/c/float/simple_double.c diff --git a/test/float/simple_double_fail.c b/test/c/float/simple_double_fail.c similarity index 100% rename from test/float/simple_double_fail.c rename to test/c/float/simple_double_fail.c diff --git a/test/float/simple_float.c b/test/c/float/simple_float.c similarity index 100% rename from test/float/simple_float.c rename to test/c/float/simple_float.c diff --git a/test/float/simple_float_fail.c b/test/c/float/simple_float_fail.c similarity index 100% rename from test/float/simple_float_fail.c rename to test/c/float/simple_float_fail.c diff --git a/test/float/smack_code_annot.c b/test/c/float/smack_code_annot.c similarity index 100% rename from test/float/smack_code_annot.c rename to test/c/float/smack_code_annot.c diff --git a/test/float/smack_code_annot_fail.c b/test/c/float/smack_code_annot_fail.c similarity index 100% rename from test/float/smack_code_annot_fail.c rename to test/c/float/smack_code_annot_fail.c diff --git a/test/locks/.gitignore b/test/c/locks/.gitignore similarity index 100% rename from test/locks/.gitignore rename to test/c/locks/.gitignore diff --git a/test/locks/config.yml b/test/c/locks/config.yml similarity index 100% rename from test/locks/config.yml rename to test/c/locks/config.yml diff --git a/test/locks/test_locks_10_true.c b/test/c/locks/test_locks_10_true.c similarity index 100% rename from test/locks/test_locks_10_true.c rename to test/c/locks/test_locks_10_true.c diff --git a/test/locks/test_locks_11_true.c b/test/c/locks/test_locks_11_true.c similarity index 100% rename from test/locks/test_locks_11_true.c rename to test/c/locks/test_locks_11_true.c diff --git a/test/locks/test_locks_12_true.c b/test/c/locks/test_locks_12_true.c similarity index 100% rename from test/locks/test_locks_12_true.c rename to test/c/locks/test_locks_12_true.c diff --git a/test/locks/test_locks_13_true.c b/test/c/locks/test_locks_13_true.c similarity index 100% rename from test/locks/test_locks_13_true.c rename to test/c/locks/test_locks_13_true.c diff --git a/test/locks/test_locks_14_false.c b/test/c/locks/test_locks_14_false.c similarity index 100% rename from test/locks/test_locks_14_false.c rename to test/c/locks/test_locks_14_false.c diff --git a/test/locks/test_locks_14_true.c b/test/c/locks/test_locks_14_true.c similarity index 100% rename from test/locks/test_locks_14_true.c rename to test/c/locks/test_locks_14_true.c diff --git a/test/locks/test_locks_15_false.c b/test/c/locks/test_locks_15_false.c similarity index 100% rename from test/locks/test_locks_15_false.c rename to test/c/locks/test_locks_15_false.c diff --git a/test/locks/test_locks_15_true.c b/test/c/locks/test_locks_15_true.c similarity index 100% rename from test/locks/test_locks_15_true.c rename to test/c/locks/test_locks_15_true.c diff --git a/test/locks/test_locks_5_true.c b/test/c/locks/test_locks_5_true.c similarity index 100% rename from test/locks/test_locks_5_true.c rename to test/c/locks/test_locks_5_true.c diff --git a/test/locks/test_locks_6_true.c b/test/c/locks/test_locks_6_true.c similarity index 100% rename from test/locks/test_locks_6_true.c rename to test/c/locks/test_locks_6_true.c diff --git a/test/locks/test_locks_7_true.c b/test/c/locks/test_locks_7_true.c similarity index 100% rename from test/locks/test_locks_7_true.c rename to test/c/locks/test_locks_7_true.c diff --git a/test/locks/test_locks_8_true.c b/test/c/locks/test_locks_8_true.c similarity index 100% rename from test/locks/test_locks_8_true.c rename to test/c/locks/test_locks_8_true.c diff --git a/test/locks/test_locks_9_true.c b/test/c/locks/test_locks_9_true.c similarity index 100% rename from test/locks/test_locks_9_true.c rename to test/c/locks/test_locks_9_true.c diff --git a/test/mathc/ceil.c b/test/c/mathc/ceil.c similarity index 100% rename from test/mathc/ceil.c rename to test/c/mathc/ceil.c diff --git a/test/mathc/ceil_fail.c b/test/c/mathc/ceil_fail.c similarity index 100% rename from test/mathc/ceil_fail.c rename to test/c/mathc/ceil_fail.c diff --git a/test/mathc/ceilf.c b/test/c/mathc/ceilf.c similarity index 100% rename from test/mathc/ceilf.c rename to test/c/mathc/ceilf.c diff --git a/test/mathc/ceilf_fail.c b/test/c/mathc/ceilf_fail.c similarity index 100% rename from test/mathc/ceilf_fail.c rename to test/c/mathc/ceilf_fail.c diff --git a/test/mathc/ceill.c b/test/c/mathc/ceill.c similarity index 100% rename from test/mathc/ceill.c rename to test/c/mathc/ceill.c diff --git a/test/mathc/ceill_fail.c b/test/c/mathc/ceill_fail.c similarity index 100% rename from test/mathc/ceill_fail.c rename to test/c/mathc/ceill_fail.c diff --git a/test/mathc/config.yml b/test/c/mathc/config.yml similarity index 100% rename from test/mathc/config.yml rename to test/c/mathc/config.yml diff --git a/test/mathc/copysign.c b/test/c/mathc/copysign.c similarity index 100% rename from test/mathc/copysign.c rename to test/c/mathc/copysign.c diff --git a/test/mathc/copysign_fail.c b/test/c/mathc/copysign_fail.c similarity index 100% rename from test/mathc/copysign_fail.c rename to test/c/mathc/copysign_fail.c diff --git a/test/mathc/copysignf.c b/test/c/mathc/copysignf.c similarity index 100% rename from test/mathc/copysignf.c rename to test/c/mathc/copysignf.c diff --git a/test/mathc/copysignf_fail.c b/test/c/mathc/copysignf_fail.c similarity index 100% rename from test/mathc/copysignf_fail.c rename to test/c/mathc/copysignf_fail.c diff --git a/test/mathc/copysignl.c b/test/c/mathc/copysignl.c similarity index 100% rename from test/mathc/copysignl.c rename to test/c/mathc/copysignl.c diff --git a/test/mathc/copysignl_fail.c b/test/c/mathc/copysignl_fail.c similarity index 100% rename from test/mathc/copysignl_fail.c rename to test/c/mathc/copysignl_fail.c diff --git a/test/mathc/fabs.c b/test/c/mathc/fabs.c similarity index 100% rename from test/mathc/fabs.c rename to test/c/mathc/fabs.c diff --git a/test/mathc/fabs_fail.c b/test/c/mathc/fabs_fail.c similarity index 100% rename from test/mathc/fabs_fail.c rename to test/c/mathc/fabs_fail.c diff --git a/test/mathc/fabsf.c b/test/c/mathc/fabsf.c similarity index 100% rename from test/mathc/fabsf.c rename to test/c/mathc/fabsf.c diff --git a/test/mathc/fabsf_fail.c b/test/c/mathc/fabsf_fail.c similarity index 100% rename from test/mathc/fabsf_fail.c rename to test/c/mathc/fabsf_fail.c diff --git a/test/mathc/fabsl.c b/test/c/mathc/fabsl.c similarity index 100% rename from test/mathc/fabsl.c rename to test/c/mathc/fabsl.c diff --git a/test/mathc/fabsl_fail.c b/test/c/mathc/fabsl_fail.c similarity index 100% rename from test/mathc/fabsl_fail.c rename to test/c/mathc/fabsl_fail.c diff --git a/test/mathc/fdim.c b/test/c/mathc/fdim.c similarity index 100% rename from test/mathc/fdim.c rename to test/c/mathc/fdim.c diff --git a/test/mathc/fdim_fail.c b/test/c/mathc/fdim_fail.c similarity index 100% rename from test/mathc/fdim_fail.c rename to test/c/mathc/fdim_fail.c diff --git a/test/mathc/fdimf.c b/test/c/mathc/fdimf.c similarity index 100% rename from test/mathc/fdimf.c rename to test/c/mathc/fdimf.c diff --git a/test/mathc/fdimf_fail.c b/test/c/mathc/fdimf_fail.c similarity index 100% rename from test/mathc/fdimf_fail.c rename to test/c/mathc/fdimf_fail.c diff --git a/test/mathc/fdiml.c b/test/c/mathc/fdiml.c similarity index 100% rename from test/mathc/fdiml.c rename to test/c/mathc/fdiml.c diff --git a/test/mathc/fdiml_fail.c b/test/c/mathc/fdiml_fail.c similarity index 100% rename from test/mathc/fdiml_fail.c rename to test/c/mathc/fdiml_fail.c diff --git a/test/mathc/floor.c b/test/c/mathc/floor.c similarity index 100% rename from test/mathc/floor.c rename to test/c/mathc/floor.c diff --git a/test/mathc/floor_fail.c b/test/c/mathc/floor_fail.c similarity index 100% rename from test/mathc/floor_fail.c rename to test/c/mathc/floor_fail.c diff --git a/test/mathc/floorf.c b/test/c/mathc/floorf.c similarity index 100% rename from test/mathc/floorf.c rename to test/c/mathc/floorf.c diff --git a/test/mathc/floorf_fail.c b/test/c/mathc/floorf_fail.c similarity index 100% rename from test/mathc/floorf_fail.c rename to test/c/mathc/floorf_fail.c diff --git a/test/mathc/floorl.c b/test/c/mathc/floorl.c similarity index 100% rename from test/mathc/floorl.c rename to test/c/mathc/floorl.c diff --git a/test/mathc/floorl_fail.c b/test/c/mathc/floorl_fail.c similarity index 100% rename from test/mathc/floorl_fail.c rename to test/c/mathc/floorl_fail.c diff --git a/test/mathc/fmax.c b/test/c/mathc/fmax.c similarity index 100% rename from test/mathc/fmax.c rename to test/c/mathc/fmax.c diff --git a/test/mathc/fmax_fail.c b/test/c/mathc/fmax_fail.c similarity index 100% rename from test/mathc/fmax_fail.c rename to test/c/mathc/fmax_fail.c diff --git a/test/mathc/fmaxf.c b/test/c/mathc/fmaxf.c similarity index 100% rename from test/mathc/fmaxf.c rename to test/c/mathc/fmaxf.c diff --git a/test/mathc/fmaxf_fail.c b/test/c/mathc/fmaxf_fail.c similarity index 100% rename from test/mathc/fmaxf_fail.c rename to test/c/mathc/fmaxf_fail.c diff --git a/test/mathc/fmaxl.c b/test/c/mathc/fmaxl.c similarity index 100% rename from test/mathc/fmaxl.c rename to test/c/mathc/fmaxl.c diff --git a/test/mathc/fmaxl_fail.c b/test/c/mathc/fmaxl_fail.c similarity index 100% rename from test/mathc/fmaxl_fail.c rename to test/c/mathc/fmaxl_fail.c diff --git a/test/mathc/fmin.c b/test/c/mathc/fmin.c similarity index 100% rename from test/mathc/fmin.c rename to test/c/mathc/fmin.c diff --git a/test/mathc/fmin_fail.c b/test/c/mathc/fmin_fail.c similarity index 100% rename from test/mathc/fmin_fail.c rename to test/c/mathc/fmin_fail.c diff --git a/test/mathc/fminf.c b/test/c/mathc/fminf.c similarity index 100% rename from test/mathc/fminf.c rename to test/c/mathc/fminf.c diff --git a/test/mathc/fminf_fail.c b/test/c/mathc/fminf_fail.c similarity index 100% rename from test/mathc/fminf_fail.c rename to test/c/mathc/fminf_fail.c diff --git a/test/mathc/fminl.c b/test/c/mathc/fminl.c similarity index 100% rename from test/mathc/fminl.c rename to test/c/mathc/fminl.c diff --git a/test/mathc/fminl_fail.c b/test/c/mathc/fminl_fail.c similarity index 100% rename from test/mathc/fminl_fail.c rename to test/c/mathc/fminl_fail.c diff --git a/test/mathc/fmod.c b/test/c/mathc/fmod.c similarity index 100% rename from test/mathc/fmod.c rename to test/c/mathc/fmod.c diff --git a/test/mathc/fmod_fail.c b/test/c/mathc/fmod_fail.c similarity index 100% rename from test/mathc/fmod_fail.c rename to test/c/mathc/fmod_fail.c diff --git a/test/mathc/fmodf.c b/test/c/mathc/fmodf.c similarity index 100% rename from test/mathc/fmodf.c rename to test/c/mathc/fmodf.c diff --git a/test/mathc/fmodf_fail.c b/test/c/mathc/fmodf_fail.c similarity index 100% rename from test/mathc/fmodf_fail.c rename to test/c/mathc/fmodf_fail.c diff --git a/test/mathc/fmodl.c b/test/c/mathc/fmodl.c similarity index 100% rename from test/mathc/fmodl.c rename to test/c/mathc/fmodl.c diff --git a/test/mathc/fmodl_fail.c b/test/c/mathc/fmodl_fail.c similarity index 100% rename from test/mathc/fmodl_fail.c rename to test/c/mathc/fmodl_fail.c diff --git a/test/mathc/issue_198.c b/test/c/mathc/issue_198.c similarity index 100% rename from test/mathc/issue_198.c rename to test/c/mathc/issue_198.c diff --git a/test/mathc/issue_198_fail.c b/test/c/mathc/issue_198_fail.c similarity index 100% rename from test/mathc/issue_198_fail.c rename to test/c/mathc/issue_198_fail.c diff --git a/test/mathc/issue_244.c b/test/c/mathc/issue_244.c similarity index 100% rename from test/mathc/issue_244.c rename to test/c/mathc/issue_244.c diff --git a/test/mathc/issue_244_fail.c b/test/c/mathc/issue_244_fail.c similarity index 100% rename from test/mathc/issue_244_fail.c rename to test/c/mathc/issue_244_fail.c diff --git a/test/mathc/lrint.c b/test/c/mathc/lrint.c similarity index 100% rename from test/mathc/lrint.c rename to test/c/mathc/lrint.c diff --git a/test/mathc/lrint_fail.c b/test/c/mathc/lrint_fail.c similarity index 100% rename from test/mathc/lrint_fail.c rename to test/c/mathc/lrint_fail.c diff --git a/test/mathc/lrintf.c b/test/c/mathc/lrintf.c similarity index 100% rename from test/mathc/lrintf.c rename to test/c/mathc/lrintf.c diff --git a/test/mathc/lrintf_fail.c b/test/c/mathc/lrintf_fail.c similarity index 100% rename from test/mathc/lrintf_fail.c rename to test/c/mathc/lrintf_fail.c diff --git a/test/mathc/lrintl.c b/test/c/mathc/lrintl.c similarity index 100% rename from test/mathc/lrintl.c rename to test/c/mathc/lrintl.c diff --git a/test/mathc/lrintl_fail.c b/test/c/mathc/lrintl_fail.c similarity index 100% rename from test/mathc/lrintl_fail.c rename to test/c/mathc/lrintl_fail.c diff --git a/test/mathc/lround.c b/test/c/mathc/lround.c similarity index 100% rename from test/mathc/lround.c rename to test/c/mathc/lround.c diff --git a/test/mathc/lround_fail.c b/test/c/mathc/lround_fail.c similarity index 100% rename from test/mathc/lround_fail.c rename to test/c/mathc/lround_fail.c diff --git a/test/mathc/lroundf.c b/test/c/mathc/lroundf.c similarity index 100% rename from test/mathc/lroundf.c rename to test/c/mathc/lroundf.c diff --git a/test/mathc/lroundf_fail.c b/test/c/mathc/lroundf_fail.c similarity index 100% rename from test/mathc/lroundf_fail.c rename to test/c/mathc/lroundf_fail.c diff --git a/test/mathc/lroundl.c b/test/c/mathc/lroundl.c similarity index 100% rename from test/mathc/lroundl.c rename to test/c/mathc/lroundl.c diff --git a/test/mathc/lroundl_fail.c b/test/c/mathc/lroundl_fail.c similarity index 100% rename from test/mathc/lroundl_fail.c rename to test/c/mathc/lroundl_fail.c diff --git a/test/mathc/modf.c b/test/c/mathc/modf.c similarity index 100% rename from test/mathc/modf.c rename to test/c/mathc/modf.c diff --git a/test/mathc/modf_fail.c b/test/c/mathc/modf_fail.c similarity index 100% rename from test/mathc/modf_fail.c rename to test/c/mathc/modf_fail.c diff --git a/test/mathc/modff.c b/test/c/mathc/modff.c similarity index 100% rename from test/mathc/modff.c rename to test/c/mathc/modff.c diff --git a/test/mathc/modff_fail.c b/test/c/mathc/modff_fail.c similarity index 100% rename from test/mathc/modff_fail.c rename to test/c/mathc/modff_fail.c diff --git a/test/mathc/modfl.c b/test/c/mathc/modfl.c similarity index 100% rename from test/mathc/modfl.c rename to test/c/mathc/modfl.c diff --git a/test/mathc/modfl_fail.c b/test/c/mathc/modfl_fail.c similarity index 100% rename from test/mathc/modfl_fail.c rename to test/c/mathc/modfl_fail.c diff --git a/test/mathc/nearbyint.c b/test/c/mathc/nearbyint.c similarity index 100% rename from test/mathc/nearbyint.c rename to test/c/mathc/nearbyint.c diff --git a/test/mathc/nearbyint_fail.c b/test/c/mathc/nearbyint_fail.c similarity index 100% rename from test/mathc/nearbyint_fail.c rename to test/c/mathc/nearbyint_fail.c diff --git a/test/mathc/nearbyintf.c b/test/c/mathc/nearbyintf.c similarity index 100% rename from test/mathc/nearbyintf.c rename to test/c/mathc/nearbyintf.c diff --git a/test/mathc/nearbyintf_fail.c b/test/c/mathc/nearbyintf_fail.c similarity index 100% rename from test/mathc/nearbyintf_fail.c rename to test/c/mathc/nearbyintf_fail.c diff --git a/test/mathc/nearbyintl.c b/test/c/mathc/nearbyintl.c similarity index 100% rename from test/mathc/nearbyintl.c rename to test/c/mathc/nearbyintl.c diff --git a/test/mathc/nearbyintl_fail.c b/test/c/mathc/nearbyintl_fail.c similarity index 100% rename from test/mathc/nearbyintl_fail.c rename to test/c/mathc/nearbyintl_fail.c diff --git a/test/mathc/remainder.c b/test/c/mathc/remainder.c similarity index 100% rename from test/mathc/remainder.c rename to test/c/mathc/remainder.c diff --git a/test/mathc/remainder_fail.c b/test/c/mathc/remainder_fail.c similarity index 100% rename from test/mathc/remainder_fail.c rename to test/c/mathc/remainder_fail.c diff --git a/test/mathc/remainderf.c b/test/c/mathc/remainderf.c similarity index 100% rename from test/mathc/remainderf.c rename to test/c/mathc/remainderf.c diff --git a/test/mathc/remainderf_fail.c b/test/c/mathc/remainderf_fail.c similarity index 100% rename from test/mathc/remainderf_fail.c rename to test/c/mathc/remainderf_fail.c diff --git a/test/mathc/remainderl.c b/test/c/mathc/remainderl.c similarity index 100% rename from test/mathc/remainderl.c rename to test/c/mathc/remainderl.c diff --git a/test/mathc/remainderl_fail.c b/test/c/mathc/remainderl_fail.c similarity index 100% rename from test/mathc/remainderl_fail.c rename to test/c/mathc/remainderl_fail.c diff --git a/test/mathc/rint.c b/test/c/mathc/rint.c similarity index 100% rename from test/mathc/rint.c rename to test/c/mathc/rint.c diff --git a/test/mathc/rint_fail.c b/test/c/mathc/rint_fail.c similarity index 100% rename from test/mathc/rint_fail.c rename to test/c/mathc/rint_fail.c diff --git a/test/mathc/rintf.c b/test/c/mathc/rintf.c similarity index 100% rename from test/mathc/rintf.c rename to test/c/mathc/rintf.c diff --git a/test/mathc/rintf_fail.c b/test/c/mathc/rintf_fail.c similarity index 100% rename from test/mathc/rintf_fail.c rename to test/c/mathc/rintf_fail.c diff --git a/test/mathc/rintl.c b/test/c/mathc/rintl.c similarity index 100% rename from test/mathc/rintl.c rename to test/c/mathc/rintl.c diff --git a/test/mathc/rintl_fail.c b/test/c/mathc/rintl_fail.c similarity index 100% rename from test/mathc/rintl_fail.c rename to test/c/mathc/rintl_fail.c diff --git a/test/mathc/round.c b/test/c/mathc/round.c similarity index 100% rename from test/mathc/round.c rename to test/c/mathc/round.c diff --git a/test/mathc/round_fail.c b/test/c/mathc/round_fail.c similarity index 100% rename from test/mathc/round_fail.c rename to test/c/mathc/round_fail.c diff --git a/test/mathc/roundf.c b/test/c/mathc/roundf.c similarity index 100% rename from test/mathc/roundf.c rename to test/c/mathc/roundf.c diff --git a/test/mathc/roundf_fail.c b/test/c/mathc/roundf_fail.c similarity index 100% rename from test/mathc/roundf_fail.c rename to test/c/mathc/roundf_fail.c diff --git a/test/mathc/roundl.c b/test/c/mathc/roundl.c similarity index 100% rename from test/mathc/roundl.c rename to test/c/mathc/roundl.c diff --git a/test/mathc/roundl_fail.c b/test/c/mathc/roundl_fail.c similarity index 100% rename from test/mathc/roundl_fail.c rename to test/c/mathc/roundl_fail.c diff --git a/test/mathc/sqrt.c b/test/c/mathc/sqrt.c similarity index 100% rename from test/mathc/sqrt.c rename to test/c/mathc/sqrt.c diff --git a/test/mathc/sqrt_fail.c b/test/c/mathc/sqrt_fail.c similarity index 100% rename from test/mathc/sqrt_fail.c rename to test/c/mathc/sqrt_fail.c diff --git a/test/mathc/sqrtf.c b/test/c/mathc/sqrtf.c similarity index 100% rename from test/mathc/sqrtf.c rename to test/c/mathc/sqrtf.c diff --git a/test/mathc/sqrtf_fail.c b/test/c/mathc/sqrtf_fail.c similarity index 100% rename from test/mathc/sqrtf_fail.c rename to test/c/mathc/sqrtf_fail.c diff --git a/test/mathc/sqrtl.c b/test/c/mathc/sqrtl.c similarity index 100% rename from test/mathc/sqrtl.c rename to test/c/mathc/sqrtl.c diff --git a/test/mathc/sqrtl_fail.c b/test/c/mathc/sqrtl_fail.c similarity index 100% rename from test/mathc/sqrtl_fail.c rename to test/c/mathc/sqrtl_fail.c diff --git a/test/mathc/trunc.c b/test/c/mathc/trunc.c similarity index 100% rename from test/mathc/trunc.c rename to test/c/mathc/trunc.c diff --git a/test/mathc/trunc_fail.c b/test/c/mathc/trunc_fail.c similarity index 100% rename from test/mathc/trunc_fail.c rename to test/c/mathc/trunc_fail.c diff --git a/test/mathc/truncf.c b/test/c/mathc/truncf.c similarity index 100% rename from test/mathc/truncf.c rename to test/c/mathc/truncf.c diff --git a/test/mathc/truncf_fail.c b/test/c/mathc/truncf_fail.c similarity index 100% rename from test/mathc/truncf_fail.c rename to test/c/mathc/truncf_fail.c diff --git a/test/mathc/truncl.c b/test/c/mathc/truncl.c similarity index 100% rename from test/mathc/truncl.c rename to test/c/mathc/truncl.c diff --git a/test/mathc/truncl_fail.c b/test/c/mathc/truncl_fail.c similarity index 100% rename from test/mathc/truncl_fail.c rename to test/c/mathc/truncl_fail.c diff --git a/test/memory-safety/adjacent.c b/test/c/memory-safety/adjacent.c similarity index 100% rename from test/memory-safety/adjacent.c rename to test/c/memory-safety/adjacent.c diff --git a/test/memory-safety/adjacent_fail.c b/test/c/memory-safety/adjacent_fail.c similarity index 100% rename from test/memory-safety/adjacent_fail.c rename to test/c/memory-safety/adjacent_fail.c diff --git a/test/memory-safety/adjacent_global.c b/test/c/memory-safety/adjacent_global.c similarity index 100% rename from test/memory-safety/adjacent_global.c rename to test/c/memory-safety/adjacent_global.c diff --git a/test/memory-safety/adjacent_global_fail.c b/test/c/memory-safety/adjacent_global_fail.c similarity index 100% rename from test/memory-safety/adjacent_global_fail.c rename to test/c/memory-safety/adjacent_global_fail.c diff --git a/test/memory-safety/array1.c b/test/c/memory-safety/array1.c similarity index 100% rename from test/memory-safety/array1.c rename to test/c/memory-safety/array1.c diff --git a/test/memory-safety/array1_fail.c b/test/c/memory-safety/array1_fail.c similarity index 100% rename from test/memory-safety/array1_fail.c rename to test/c/memory-safety/array1_fail.c diff --git a/test/memory-safety/array2_free_fail.c b/test/c/memory-safety/array2_free_fail.c similarity index 100% rename from test/memory-safety/array2_free_fail.c rename to test/c/memory-safety/array2_free_fail.c diff --git a/test/memory-safety/array_free1.c b/test/c/memory-safety/array_free1.c similarity index 100% rename from test/memory-safety/array_free1.c rename to test/c/memory-safety/array_free1.c diff --git a/test/memory-safety/array_free1_fail.c b/test/c/memory-safety/array_free1_fail.c similarity index 100% rename from test/memory-safety/array_free1_fail.c rename to test/c/memory-safety/array_free1_fail.c diff --git a/test/memory-safety/array_free1_fail1.c b/test/c/memory-safety/array_free1_fail1.c similarity index 100% rename from test/memory-safety/array_free1_fail1.c rename to test/c/memory-safety/array_free1_fail1.c diff --git a/test/memory-safety/config.yml b/test/c/memory-safety/config.yml similarity index 100% rename from test/memory-safety/config.yml rename to test/c/memory-safety/config.yml diff --git a/test/memory-safety/errno_test.c b/test/c/memory-safety/errno_test.c similarity index 100% rename from test/memory-safety/errno_test.c rename to test/c/memory-safety/errno_test.c diff --git a/test/memory-safety/global_alloc.c b/test/c/memory-safety/global_alloc.c similarity index 100% rename from test/memory-safety/global_alloc.c rename to test/c/memory-safety/global_alloc.c diff --git a/test/memory-safety/global_alloc_fail_free.c b/test/c/memory-safety/global_alloc_fail_free.c similarity index 100% rename from test/memory-safety/global_alloc_fail_free.c rename to test/c/memory-safety/global_alloc_fail_free.c diff --git a/test/memory-safety/global_and_heap_alloc.c b/test/c/memory-safety/global_and_heap_alloc.c similarity index 100% rename from test/memory-safety/global_and_heap_alloc.c rename to test/c/memory-safety/global_and_heap_alloc.c diff --git a/test/memory-safety/global_and_heap_alloc_fail_free.c b/test/c/memory-safety/global_and_heap_alloc_fail_free.c similarity index 100% rename from test/memory-safety/global_and_heap_alloc_fail_free.c rename to test/c/memory-safety/global_and_heap_alloc_fail_free.c diff --git a/test/memory-safety/global_and_heap_alloc_fail_no_free.c b/test/c/memory-safety/global_and_heap_alloc_fail_no_free.c similarity index 100% rename from test/memory-safety/global_and_heap_alloc_fail_no_free.c rename to test/c/memory-safety/global_and_heap_alloc_fail_no_free.c diff --git a/test/memory-safety/malloc_nondet.c b/test/c/memory-safety/malloc_nondet.c similarity index 100% rename from test/memory-safety/malloc_nondet.c rename to test/c/memory-safety/malloc_nondet.c diff --git a/test/memory-safety/malloc_nondet_fail.c b/test/c/memory-safety/malloc_nondet_fail.c similarity index 100% rename from test/memory-safety/malloc_nondet_fail.c rename to test/c/memory-safety/malloc_nondet_fail.c diff --git a/test/memory-safety/null_dereference_fail.c b/test/c/memory-safety/null_dereference_fail.c similarity index 100% rename from test/memory-safety/null_dereference_fail.c rename to test/c/memory-safety/null_dereference_fail.c diff --git a/test/memory-safety/simple_double_free.c b/test/c/memory-safety/simple_double_free.c similarity index 100% rename from test/memory-safety/simple_double_free.c rename to test/c/memory-safety/simple_double_free.c diff --git a/test/memory-safety/structure1.c b/test/c/memory-safety/structure1.c similarity index 100% rename from test/memory-safety/structure1.c rename to test/c/memory-safety/structure1.c diff --git a/test/memory-safety/structure1_fail.c b/test/c/memory-safety/structure1_fail.c similarity index 100% rename from test/memory-safety/structure1_fail.c rename to test/c/memory-safety/structure1_fail.c diff --git a/test/ntdrivers-simplified/cdaudio_simpl1_false.cil.c b/test/c/ntdrivers-simplified/cdaudio_simpl1_false.cil.c similarity index 100% rename from test/ntdrivers-simplified/cdaudio_simpl1_false.cil.c rename to test/c/ntdrivers-simplified/cdaudio_simpl1_false.cil.c diff --git a/test/ntdrivers-simplified/cdaudio_simpl1_true.cil.c b/test/c/ntdrivers-simplified/cdaudio_simpl1_true.cil.c similarity index 100% rename from test/ntdrivers-simplified/cdaudio_simpl1_true.cil.c rename to test/c/ntdrivers-simplified/cdaudio_simpl1_true.cil.c diff --git a/test/ntdrivers-simplified/config.yml b/test/c/ntdrivers-simplified/config.yml similarity index 100% rename from test/ntdrivers-simplified/config.yml rename to test/c/ntdrivers-simplified/config.yml diff --git a/test/ntdrivers-simplified/diskperf_simpl1_true.cil.c b/test/c/ntdrivers-simplified/diskperf_simpl1_true.cil.c similarity index 100% rename from test/ntdrivers-simplified/diskperf_simpl1_true.cil.c rename to test/c/ntdrivers-simplified/diskperf_simpl1_true.cil.c diff --git a/test/ntdrivers-simplified/floppy_simpl3_false.cil.c b/test/c/ntdrivers-simplified/floppy_simpl3_false.cil.c similarity index 100% rename from test/ntdrivers-simplified/floppy_simpl3_false.cil.c rename to test/c/ntdrivers-simplified/floppy_simpl3_false.cil.c diff --git a/test/ntdrivers-simplified/floppy_simpl3_true.cil.c b/test/c/ntdrivers-simplified/floppy_simpl3_true.cil.c similarity index 100% rename from test/ntdrivers-simplified/floppy_simpl3_true.cil.c rename to test/c/ntdrivers-simplified/floppy_simpl3_true.cil.c diff --git a/test/ntdrivers-simplified/floppy_simpl4_false.cil.c b/test/c/ntdrivers-simplified/floppy_simpl4_false.cil.c similarity index 100% rename from test/ntdrivers-simplified/floppy_simpl4_false.cil.c rename to test/c/ntdrivers-simplified/floppy_simpl4_false.cil.c diff --git a/test/ntdrivers-simplified/floppy_simpl4_true.cil.c b/test/c/ntdrivers-simplified/floppy_simpl4_true.cil.c similarity index 100% rename from test/ntdrivers-simplified/floppy_simpl4_true.cil.c rename to test/c/ntdrivers-simplified/floppy_simpl4_true.cil.c diff --git a/test/ntdrivers-simplified/kbfiltr_simpl1_true.cil.c b/test/c/ntdrivers-simplified/kbfiltr_simpl1_true.cil.c similarity index 100% rename from test/ntdrivers-simplified/kbfiltr_simpl1_true.cil.c rename to test/c/ntdrivers-simplified/kbfiltr_simpl1_true.cil.c diff --git a/test/ntdrivers-simplified/kbfiltr_simpl2_false.cil.c b/test/c/ntdrivers-simplified/kbfiltr_simpl2_false.cil.c similarity index 100% rename from test/ntdrivers-simplified/kbfiltr_simpl2_false.cil.c rename to test/c/ntdrivers-simplified/kbfiltr_simpl2_false.cil.c diff --git a/test/ntdrivers-simplified/kbfiltr_simpl2_true.cil.c b/test/c/ntdrivers-simplified/kbfiltr_simpl2_true.cil.c similarity index 100% rename from test/ntdrivers-simplified/kbfiltr_simpl2_true.cil.c rename to test/c/ntdrivers-simplified/kbfiltr_simpl2_true.cil.c diff --git a/test/ntdrivers/cdaudio_true.i.cil.c b/test/c/ntdrivers/cdaudio_true.i.cil.c similarity index 100% rename from test/ntdrivers/cdaudio_true.i.cil.c rename to test/c/ntdrivers/cdaudio_true.i.cil.c diff --git a/test/ntdrivers/config.yml b/test/c/ntdrivers/config.yml similarity index 100% rename from test/ntdrivers/config.yml rename to test/c/ntdrivers/config.yml diff --git a/test/ntdrivers/diskperf_false.i.cil.c b/test/c/ntdrivers/diskperf_false.i.cil.c similarity index 100% rename from test/ntdrivers/diskperf_false.i.cil.c rename to test/c/ntdrivers/diskperf_false.i.cil.c diff --git a/test/ntdrivers/diskperf_true.i.cil.c b/test/c/ntdrivers/diskperf_true.i.cil.c similarity index 100% rename from test/ntdrivers/diskperf_true.i.cil.c rename to test/c/ntdrivers/diskperf_true.i.cil.c diff --git a/test/ntdrivers/floppy2_true.i.cil.c b/test/c/ntdrivers/floppy2_true.i.cil.c similarity index 100% rename from test/ntdrivers/floppy2_true.i.cil.c rename to test/c/ntdrivers/floppy2_true.i.cil.c diff --git a/test/ntdrivers/floppy_false.i.cil.c b/test/c/ntdrivers/floppy_false.i.cil.c similarity index 100% rename from test/ntdrivers/floppy_false.i.cil.c rename to test/c/ntdrivers/floppy_false.i.cil.c diff --git a/test/ntdrivers/floppy_true.i.cil.c b/test/c/ntdrivers/floppy_true.i.cil.c similarity index 100% rename from test/ntdrivers/floppy_true.i.cil.c rename to test/c/ntdrivers/floppy_true.i.cil.c diff --git a/test/ntdrivers/kbfiltr_false.i.cil.c b/test/c/ntdrivers/kbfiltr_false.i.cil.c similarity index 100% rename from test/ntdrivers/kbfiltr_false.i.cil.c rename to test/c/ntdrivers/kbfiltr_false.i.cil.c diff --git a/test/ntdrivers/parport_false.i.cil.c b/test/c/ntdrivers/parport_false.i.cil.c similarity index 100% rename from test/ntdrivers/parport_false.i.cil.c rename to test/c/ntdrivers/parport_false.i.cil.c diff --git a/test/ntdrivers/parport_true.i.cil.c b/test/c/ntdrivers/parport_true.i.cil.c similarity index 100% rename from test/ntdrivers/parport_true.i.cil.c rename to test/c/ntdrivers/parport_true.i.cil.c diff --git a/test/pthread/account.c b/test/c/pthread/account.c similarity index 100% rename from test/pthread/account.c rename to test/c/pthread/account.c diff --git a/test/pthread/account_fail.c b/test/c/pthread/account_fail.c similarity index 100% rename from test/pthread/account_fail.c rename to test/c/pthread/account_fail.c diff --git a/test/pthread/cond.c b/test/c/pthread/cond.c similarity index 100% rename from test/pthread/cond.c rename to test/c/pthread/cond.c diff --git a/test/pthread/cond_fail.c b/test/c/pthread/cond_fail.c similarity index 100% rename from test/pthread/cond_fail.c rename to test/c/pthread/cond_fail.c diff --git a/test/pthread/config.yml b/test/c/pthread/config.yml similarity index 100% rename from test/pthread/config.yml rename to test/c/pthread/config.yml diff --git a/test/pthread/equal.c b/test/c/pthread/equal.c similarity index 100% rename from test/pthread/equal.c rename to test/c/pthread/equal.c diff --git a/test/pthread/equal2.c b/test/c/pthread/equal2.c similarity index 100% rename from test/pthread/equal2.c rename to test/c/pthread/equal2.c diff --git a/test/pthread/join.c b/test/c/pthread/join.c similarity index 100% rename from test/pthread/join.c rename to test/c/pthread/join.c diff --git a/test/pthread/join_fail.c b/test/c/pthread/join_fail.c similarity index 100% rename from test/pthread/join_fail.c rename to test/c/pthread/join_fail.c diff --git a/test/pthread/join_return.c b/test/c/pthread/join_return.c similarity index 100% rename from test/pthread/join_return.c rename to test/c/pthread/join_return.c diff --git a/test/pthread/join_return2.c b/test/c/pthread/join_return2.c similarity index 100% rename from test/pthread/join_return2.c rename to test/c/pthread/join_return2.c diff --git a/test/pthread/join_return2_fail.c b/test/c/pthread/join_return2_fail.c similarity index 100% rename from test/pthread/join_return2_fail.c rename to test/c/pthread/join_return2_fail.c diff --git a/test/pthread/join_return_fail.c b/test/c/pthread/join_return_fail.c similarity index 100% rename from test/pthread/join_return_fail.c rename to test/c/pthread/join_return_fail.c diff --git a/test/pthread/join_self.c b/test/c/pthread/join_self.c similarity index 100% rename from test/pthread/join_self.c rename to test/c/pthread/join_self.c diff --git a/test/pthread/join_self_fail.c b/test/c/pthread/join_self_fail.c similarity index 100% rename from test/pthread/join_self_fail.c rename to test/c/pthread/join_self_fail.c diff --git a/test/pthread/lock.c b/test/c/pthread/lock.c similarity index 100% rename from test/pthread/lock.c rename to test/c/pthread/lock.c diff --git a/test/pthread/lock2.c b/test/c/pthread/lock2.c similarity index 100% rename from test/pthread/lock2.c rename to test/c/pthread/lock2.c diff --git a/test/pthread/lock2_fail.c b/test/c/pthread/lock2_fail.c similarity index 100% rename from test/pthread/lock2_fail.c rename to test/c/pthread/lock2_fail.c diff --git a/test/pthread/lock3.c b/test/c/pthread/lock3.c similarity index 100% rename from test/pthread/lock3.c rename to test/c/pthread/lock3.c diff --git a/test/pthread/lock3_fail.c b/test/c/pthread/lock3_fail.c similarity index 100% rename from test/pthread/lock3_fail.c rename to test/c/pthread/lock3_fail.c diff --git a/test/pthread/lock4.c b/test/c/pthread/lock4.c similarity index 100% rename from test/pthread/lock4.c rename to test/c/pthread/lock4.c diff --git a/test/pthread/lock4_fail.c b/test/c/pthread/lock4_fail.c similarity index 100% rename from test/pthread/lock4_fail.c rename to test/c/pthread/lock4_fail.c diff --git a/test/pthread/lock5.c b/test/c/pthread/lock5.c similarity index 100% rename from test/pthread/lock5.c rename to test/c/pthread/lock5.c diff --git a/test/pthread/lock5_fail.c b/test/c/pthread/lock5_fail.c similarity index 100% rename from test/pthread/lock5_fail.c rename to test/c/pthread/lock5_fail.c diff --git a/test/pthread/lock_fail.c b/test/c/pthread/lock_fail.c similarity index 100% rename from test/pthread/lock_fail.c rename to test/c/pthread/lock_fail.c diff --git a/test/pthread/lockattr.c b/test/c/pthread/lockattr.c similarity index 100% rename from test/pthread/lockattr.c rename to test/c/pthread/lockattr.c diff --git a/test/pthread_extras/config.yml b/test/c/pthread_extras/config.yml similarity index 100% rename from test/pthread_extras/config.yml rename to test/c/pthread_extras/config.yml diff --git a/test/pthread_extras/dekker_true-unreach-call.c b/test/c/pthread_extras/dekker_true-unreach-call.c similarity index 100% rename from test/pthread_extras/dekker_true-unreach-call.c rename to test/c/pthread_extras/dekker_true-unreach-call.c diff --git a/test/pthread_extras/lamport_true-unreach-call.c b/test/c/pthread_extras/lamport_true-unreach-call.c similarity index 100% rename from test/pthread_extras/lamport_true-unreach-call.c rename to test/c/pthread_extras/lamport_true-unreach-call.c diff --git a/test/pthread_extras/lazy01_false-unreach-call.c b/test/c/pthread_extras/lazy01_false-unreach-call.c similarity index 100% rename from test/pthread_extras/lazy01_false-unreach-call.c rename to test/c/pthread_extras/lazy01_false-unreach-call.c diff --git a/test/pthread_extras/peterson_true-unreach-call.c b/test/c/pthread_extras/peterson_true-unreach-call.c similarity index 100% rename from test/pthread_extras/peterson_true-unreach-call.c rename to test/c/pthread_extras/peterson_true-unreach-call.c diff --git a/test/pthread_extras/queue_false-unreach-call.c b/test/c/pthread_extras/queue_false-unreach-call.c similarity index 100% rename from test/pthread_extras/queue_false-unreach-call.c rename to test/c/pthread_extras/queue_false-unreach-call.c diff --git a/test/pthread_extras/queue_ok_true-unreach-call.c b/test/c/pthread_extras/queue_ok_true-unreach-call.c similarity index 100% rename from test/pthread_extras/queue_ok_true-unreach-call.c rename to test/c/pthread_extras/queue_ok_true-unreach-call.c diff --git a/test/pthread_extras/reorder_2_false-unreach-call.c b/test/c/pthread_extras/reorder_2_false-unreach-call.c similarity index 100% rename from test/pthread_extras/reorder_2_false-unreach-call.c rename to test/c/pthread_extras/reorder_2_false-unreach-call.c diff --git a/test/pthread_extras/reorder_5_false-unreach-call.c b/test/c/pthread_extras/reorder_5_false-unreach-call.c similarity index 100% rename from test/pthread_extras/reorder_5_false-unreach-call.c rename to test/c/pthread_extras/reorder_5_false-unreach-call.c diff --git a/test/pthread_extras/scull_true-unreach-call.c b/test/c/pthread_extras/scull_true-unreach-call.c similarity index 100% rename from test/pthread_extras/scull_true-unreach-call.c rename to test/c/pthread_extras/scull_true-unreach-call.c diff --git a/test/pthread_extras/sigma_false-unreach-call.c b/test/c/pthread_extras/sigma_false-unreach-call.c similarity index 100% rename from test/pthread_extras/sigma_false-unreach-call.c rename to test/c/pthread_extras/sigma_false-unreach-call.c diff --git a/test/pthread_extras/sigma_false_GREAT-unreach-call.c b/test/c/pthread_extras/sigma_false_GREAT-unreach-call.c similarity index 100% rename from test/pthread_extras/sigma_false_GREAT-unreach-call.c rename to test/c/pthread_extras/sigma_false_GREAT-unreach-call.c diff --git a/test/pthread_extras/singleton_false-unreach-call.c b/test/c/pthread_extras/singleton_false-unreach-call.c similarity index 100% rename from test/pthread_extras/singleton_false-unreach-call.c rename to test/c/pthread_extras/singleton_false-unreach-call.c diff --git a/test/pthread_extras/singleton_with-uninit-problems-true.c b/test/c/pthread_extras/singleton_with-uninit-problems-true.c similarity index 100% rename from test/pthread_extras/singleton_with-uninit-problems-true.c rename to test/c/pthread_extras/singleton_with-uninit-problems-true.c diff --git a/test/pthread_extras/sssc12_true-unreach-call.c b/test/c/pthread_extras/sssc12_true-unreach-call.c similarity index 100% rename from test/pthread_extras/sssc12_true-unreach-call.c rename to test/c/pthread_extras/sssc12_true-unreach-call.c diff --git a/test/pthread_extras/stack_false-unreach-call.c b/test/c/pthread_extras/stack_false-unreach-call.c similarity index 100% rename from test/pthread_extras/stack_false-unreach-call.c rename to test/c/pthread_extras/stack_false-unreach-call.c diff --git a/test/pthread_extras/stack_true-unreach-call.c b/test/c/pthread_extras/stack_true-unreach-call.c similarity index 100% rename from test/pthread_extras/stack_true-unreach-call.c rename to test/c/pthread_extras/stack_true-unreach-call.c diff --git a/test/pthread_extras/stateful01_false-unreach-call.c b/test/c/pthread_extras/stateful01_false-unreach-call.c similarity index 100% rename from test/pthread_extras/stateful01_false-unreach-call.c rename to test/c/pthread_extras/stateful01_false-unreach-call.c diff --git a/test/pthread_extras/stateful01_true-unreach-call.c b/test/c/pthread_extras/stateful01_true-unreach-call.c similarity index 100% rename from test/pthread_extras/stateful01_true-unreach-call.c rename to test/c/pthread_extras/stateful01_true-unreach-call.c diff --git a/test/pthread_extras/sync01_true-unreach-call.c b/test/c/pthread_extras/sync01_true-unreach-call.c similarity index 100% rename from test/pthread_extras/sync01_true-unreach-call.c rename to test/c/pthread_extras/sync01_true-unreach-call.c diff --git a/test/pthread_extras/szymanski_true-unreach-call.c b/test/c/pthread_extras/szymanski_true-unreach-call.c similarity index 100% rename from test/pthread_extras/szymanski_true-unreach-call.c rename to test/c/pthread_extras/szymanski_true-unreach-call.c diff --git a/test/pthread_extras/time_var_mutex_true-unreach-call.c b/test/c/pthread_extras/time_var_mutex_true-unreach-call.c similarity index 100% rename from test/pthread_extras/time_var_mutex_true-unreach-call.c rename to test/c/pthread_extras/time_var_mutex_true-unreach-call.c diff --git a/test/pthread_extras/twostage_3_false-unreach-call.c b/test/c/pthread_extras/twostage_3_false-unreach-call.c similarity index 100% rename from test/pthread_extras/twostage_3_false-unreach-call.c rename to test/c/pthread_extras/twostage_3_false-unreach-call.c diff --git a/test/reach/.gitignore b/test/c/reach/.gitignore similarity index 100% rename from test/reach/.gitignore rename to test/c/reach/.gitignore diff --git a/test/reach/break.c b/test/c/reach/break.c similarity index 100% rename from test/reach/break.c rename to test/c/reach/break.c diff --git a/test/reach/break.expected b/test/c/reach/break.expected similarity index 100% rename from test/reach/break.expected rename to test/c/reach/break.expected diff --git a/test/reach/config.yml b/test/c/reach/config.yml similarity index 100% rename from test/reach/config.yml rename to test/c/reach/config.yml diff --git a/test/reach/continue.c b/test/c/reach/continue.c similarity index 100% rename from test/reach/continue.c rename to test/c/reach/continue.c diff --git a/test/reach/continue.expected b/test/c/reach/continue.expected similarity index 100% rename from test/reach/continue.expected rename to test/c/reach/continue.expected diff --git a/test/reach/do.c b/test/c/reach/do.c similarity index 100% rename from test/reach/do.c rename to test/c/reach/do.c diff --git a/test/reach/do.expected b/test/c/reach/do.expected similarity index 100% rename from test/reach/do.expected rename to test/c/reach/do.expected diff --git a/test/reach/for.c b/test/c/reach/for.c similarity index 100% rename from test/reach/for.c rename to test/c/reach/for.c diff --git a/test/reach/for.expected b/test/c/reach/for.expected similarity index 100% rename from test/reach/for.expected rename to test/c/reach/for.expected diff --git a/test/reach/for2.c b/test/c/reach/for2.c similarity index 100% rename from test/reach/for2.c rename to test/c/reach/for2.c diff --git a/test/reach/for2.expected b/test/c/reach/for2.expected similarity index 100% rename from test/reach/for2.expected rename to test/c/reach/for2.expected diff --git a/test/reach/func.c b/test/c/reach/func.c similarity index 100% rename from test/reach/func.c rename to test/c/reach/func.c diff --git a/test/reach/func.expected b/test/c/reach/func.expected similarity index 100% rename from test/reach/func.expected rename to test/c/reach/func.expected diff --git a/test/reach/func2.c b/test/c/reach/func2.c similarity index 100% rename from test/reach/func2.c rename to test/c/reach/func2.c diff --git a/test/reach/func2.expected b/test/c/reach/func2.expected similarity index 100% rename from test/reach/func2.expected rename to test/c/reach/func2.expected diff --git a/test/reach/func3.c b/test/c/reach/func3.c similarity index 100% rename from test/reach/func3.c rename to test/c/reach/func3.c diff --git a/test/reach/func3.expected b/test/c/reach/func3.expected similarity index 100% rename from test/reach/func3.expected rename to test/c/reach/func3.expected diff --git a/test/reach/if.c b/test/c/reach/if.c similarity index 100% rename from test/reach/if.c rename to test/c/reach/if.c diff --git a/test/reach/if.expected b/test/c/reach/if.expected similarity index 100% rename from test/reach/if.expected rename to test/c/reach/if.expected diff --git a/test/reach/if2.c b/test/c/reach/if2.c similarity index 100% rename from test/reach/if2.c rename to test/c/reach/if2.c diff --git a/test/reach/if2.expected b/test/c/reach/if2.expected similarity index 100% rename from test/reach/if2.expected rename to test/c/reach/if2.expected diff --git a/test/reach/if3.c b/test/c/reach/if3.c similarity index 100% rename from test/reach/if3.c rename to test/c/reach/if3.c diff --git a/test/reach/if3.expected b/test/c/reach/if3.expected similarity index 100% rename from test/reach/if3.expected rename to test/c/reach/if3.expected diff --git a/test/reach/if4.c b/test/c/reach/if4.c similarity index 100% rename from test/reach/if4.c rename to test/c/reach/if4.c diff --git a/test/reach/if4.expected b/test/c/reach/if4.expected similarity index 100% rename from test/reach/if4.expected rename to test/c/reach/if4.expected diff --git a/test/reach/libs.c b/test/c/reach/libs.c similarity index 100% rename from test/reach/libs.c rename to test/c/reach/libs.c diff --git a/test/reach/libs.expected b/test/c/reach/libs.expected similarity index 100% rename from test/reach/libs.expected rename to test/c/reach/libs.expected diff --git a/test/reach/regtest.py b/test/c/reach/regtest.py similarity index 100% rename from test/reach/regtest.py rename to test/c/reach/regtest.py diff --git a/test/reach/return.c b/test/c/reach/return.c similarity index 100% rename from test/reach/return.c rename to test/c/reach/return.c diff --git a/test/reach/return.expected b/test/c/reach/return.expected similarity index 100% rename from test/reach/return.expected rename to test/c/reach/return.expected diff --git a/test/reach/switch.c b/test/c/reach/switch.c similarity index 100% rename from test/reach/switch.c rename to test/c/reach/switch.c diff --git a/test/reach/switch.expected b/test/c/reach/switch.expected similarity index 100% rename from test/reach/switch.expected rename to test/c/reach/switch.expected diff --git a/test/reach/switch2.c b/test/c/reach/switch2.c similarity index 100% rename from test/reach/switch2.c rename to test/c/reach/switch2.c diff --git a/test/reach/switch2.expected b/test/c/reach/switch2.expected similarity index 100% rename from test/reach/switch2.expected rename to test/c/reach/switch2.expected diff --git a/test/reach/switch3.c b/test/c/reach/switch3.c similarity index 100% rename from test/reach/switch3.c rename to test/c/reach/switch3.c diff --git a/test/reach/switch3.expected b/test/c/reach/switch3.expected similarity index 100% rename from test/reach/switch3.expected rename to test/c/reach/switch3.expected diff --git a/test/reach/switch4.c b/test/c/reach/switch4.c similarity index 100% rename from test/reach/switch4.c rename to test/c/reach/switch4.c diff --git a/test/reach/switch4.expected b/test/c/reach/switch4.expected similarity index 100% rename from test/reach/switch4.expected rename to test/c/reach/switch4.expected diff --git a/test/reach/while.c b/test/c/reach/while.c similarity index 100% rename from test/reach/while.c rename to test/c/reach/while.c diff --git a/test/reach/while.expected b/test/c/reach/while.expected similarity index 100% rename from test/reach/while.expected rename to test/c/reach/while.expected diff --git a/test/reach/while2.c b/test/c/reach/while2.c similarity index 100% rename from test/reach/while2.c rename to test/c/reach/while2.c diff --git a/test/reach/while2.expected b/test/c/reach/while2.expected similarity index 100% rename from test/reach/while2.expected rename to test/c/reach/while2.expected diff --git a/test/reach/while3.c b/test/c/reach/while3.c similarity index 100% rename from test/reach/while3.c rename to test/c/reach/while3.c diff --git a/test/reach/while3.expected b/test/c/reach/while3.expected similarity index 100% rename from test/reach/while3.expected rename to test/c/reach/while3.expected diff --git a/test/simd/add.c b/test/c/simd/add.c similarity index 100% rename from test/simd/add.c rename to test/c/simd/add.c diff --git a/test/simd/add_fail.c b/test/c/simd/add_fail.c similarity index 100% rename from test/simd/add_fail.c rename to test/c/simd/add_fail.c diff --git a/test/simd/cast.c b/test/c/simd/cast.c similarity index 100% rename from test/simd/cast.c rename to test/c/simd/cast.c diff --git a/test/simd/cast_fail.c b/test/c/simd/cast_fail.c similarity index 100% rename from test/simd/cast_fail.c rename to test/c/simd/cast_fail.c diff --git a/test/simd/config.yml b/test/c/simd/config.yml similarity index 100% rename from test/simd/config.yml rename to test/c/simd/config.yml diff --git a/test/simd/constant.c b/test/c/simd/constant.c similarity index 100% rename from test/simd/constant.c rename to test/c/simd/constant.c diff --git a/test/simd/constant_fail.c b/test/c/simd/constant_fail.c similarity index 100% rename from test/simd/constant_fail.c rename to test/c/simd/constant_fail.c diff --git a/test/simd/shuffle.c b/test/c/simd/shuffle.c similarity index 100% rename from test/simd/shuffle.c rename to test/c/simd/shuffle.c diff --git a/test/simd/shuffle_fail.c b/test/c/simd/shuffle_fail.c similarity index 100% rename from test/simd/shuffle_fail.c rename to test/c/simd/shuffle_fail.c diff --git a/test/special/assume.c b/test/c/special/assume.c similarity index 100% rename from test/special/assume.c rename to test/c/special/assume.c diff --git a/test/special/assume2.c b/test/c/special/assume2.c similarity index 100% rename from test/special/assume2.c rename to test/c/special/assume2.c diff --git a/test/special/assume_check.c b/test/c/special/assume_check.c similarity index 100% rename from test/special/assume_check.c rename to test/c/special/assume_check.c diff --git a/test/special/assume_check2.c b/test/c/special/assume_check2.c similarity index 100% rename from test/special/assume_check2.c rename to test/c/special/assume_check2.c diff --git a/test/special/assume_check_fail.c b/test/c/special/assume_check_fail.c similarity index 100% rename from test/special/assume_check_fail.c rename to test/c/special/assume_check_fail.c diff --git a/test/special/assume_fail.c b/test/c/special/assume_fail.c similarity index 100% rename from test/special/assume_fail.c rename to test/c/special/assume_fail.c diff --git a/test/strings/config.yml b/test/c/strings/config.yml similarity index 100% rename from test/strings/config.yml rename to test/c/strings/config.yml diff --git a/test/strings/strcat.c b/test/c/strings/strcat.c similarity index 100% rename from test/strings/strcat.c rename to test/c/strings/strcat.c diff --git a/test/strings/strcat_fail.c b/test/c/strings/strcat_fail.c similarity index 100% rename from test/strings/strcat_fail.c rename to test/c/strings/strcat_fail.c diff --git a/test/strings/strcat_overflow.c b/test/c/strings/strcat_overflow.c similarity index 100% rename from test/strings/strcat_overflow.c rename to test/c/strings/strcat_overflow.c diff --git a/test/strings/strchr.c b/test/c/strings/strchr.c similarity index 100% rename from test/strings/strchr.c rename to test/c/strings/strchr.c diff --git a/test/strings/strchr_fail.c b/test/c/strings/strchr_fail.c similarity index 100% rename from test/strings/strchr_fail.c rename to test/c/strings/strchr_fail.c diff --git a/test/strings/strcmp.c b/test/c/strings/strcmp.c similarity index 100% rename from test/strings/strcmp.c rename to test/c/strings/strcmp.c diff --git a/test/strings/strcmp_fail.c b/test/c/strings/strcmp_fail.c similarity index 100% rename from test/strings/strcmp_fail.c rename to test/c/strings/strcmp_fail.c diff --git a/test/strings/strcpy.c b/test/c/strings/strcpy.c similarity index 100% rename from test/strings/strcpy.c rename to test/c/strings/strcpy.c diff --git a/test/strings/strcpy_fail.c b/test/c/strings/strcpy_fail.c similarity index 100% rename from test/strings/strcpy_fail.c rename to test/c/strings/strcpy_fail.c diff --git a/test/strings/strcpy_overflow.c b/test/c/strings/strcpy_overflow.c similarity index 100% rename from test/strings/strcpy_overflow.c rename to test/c/strings/strcpy_overflow.c diff --git a/test/strings/strcspn.c b/test/c/strings/strcspn.c similarity index 100% rename from test/strings/strcspn.c rename to test/c/strings/strcspn.c diff --git a/test/strings/strcspn_fail.c b/test/c/strings/strcspn_fail.c similarity index 100% rename from test/strings/strcspn_fail.c rename to test/c/strings/strcspn_fail.c diff --git a/test/strings/strlen.c b/test/c/strings/strlen.c similarity index 100% rename from test/strings/strlen.c rename to test/c/strings/strlen.c diff --git a/test/strings/strlen_fail.c b/test/c/strings/strlen_fail.c similarity index 100% rename from test/strings/strlen_fail.c rename to test/c/strings/strlen_fail.c diff --git a/test/strings/strncat.c b/test/c/strings/strncat.c similarity index 100% rename from test/strings/strncat.c rename to test/c/strings/strncat.c diff --git a/test/strings/strncat_fail.c b/test/c/strings/strncat_fail.c similarity index 100% rename from test/strings/strncat_fail.c rename to test/c/strings/strncat_fail.c diff --git a/test/strings/strncmp.c b/test/c/strings/strncmp.c similarity index 100% rename from test/strings/strncmp.c rename to test/c/strings/strncmp.c diff --git a/test/strings/strncmp_fail.c b/test/c/strings/strncmp_fail.c similarity index 100% rename from test/strings/strncmp_fail.c rename to test/c/strings/strncmp_fail.c diff --git a/test/strings/strncmp_toolong.c b/test/c/strings/strncmp_toolong.c similarity index 100% rename from test/strings/strncmp_toolong.c rename to test/c/strings/strncmp_toolong.c diff --git a/test/strings/strpbrk.c b/test/c/strings/strpbrk.c similarity index 100% rename from test/strings/strpbrk.c rename to test/c/strings/strpbrk.c diff --git a/test/strings/strpbrk_fail.c b/test/c/strings/strpbrk_fail.c similarity index 100% rename from test/strings/strpbrk_fail.c rename to test/c/strings/strpbrk_fail.c diff --git a/test/strings/strrchr.c b/test/c/strings/strrchr.c similarity index 100% rename from test/strings/strrchr.c rename to test/c/strings/strrchr.c diff --git a/test/strings/strrchr_fail.c b/test/c/strings/strrchr_fail.c similarity index 100% rename from test/strings/strrchr_fail.c rename to test/c/strings/strrchr_fail.c diff --git a/test/strings/strspn.c b/test/c/strings/strspn.c similarity index 100% rename from test/strings/strspn.c rename to test/c/strings/strspn.c diff --git a/test/strings/strspn_fail.c b/test/c/strings/strspn_fail.c similarity index 100% rename from test/strings/strspn_fail.c rename to test/c/strings/strspn_fail.c diff --git a/test/strings/strstr.c b/test/c/strings/strstr.c similarity index 100% rename from test/strings/strstr.c rename to test/c/strings/strstr.c diff --git a/test/strings/strstr_fail.c b/test/c/strings/strstr_fail.c similarity index 100% rename from test/strings/strstr_fail.c rename to test/c/strings/strstr_fail.c diff --git a/test/strings/strtok.c b/test/c/strings/strtok.c similarity index 100% rename from test/strings/strtok.c rename to test/c/strings/strtok.c diff --git a/test/strings/strtok_fail.c b/test/c/strings/strtok_fail.c similarity index 100% rename from test/strings/strtok_fail.c rename to test/c/strings/strtok_fail.c diff --git a/test/timeouts/config.yml b/test/c/timeouts/config.yml similarity index 100% rename from test/timeouts/config.yml rename to test/c/timeouts/config.yml diff --git a/test/cplusplus/config.yml b/test/cplusplus/basic/config.yml similarity index 100% rename from test/cplusplus/config.yml rename to test/cplusplus/basic/config.yml diff --git a/test/cplusplus/hello.cc b/test/cplusplus/basic/hello.cc similarity index 100% rename from test/cplusplus/hello.cc rename to test/cplusplus/basic/hello.cc diff --git a/test/cplusplus/hello_fail.cc b/test/cplusplus/basic/hello_fail.cc similarity index 100% rename from test/cplusplus/hello_fail.cc rename to test/cplusplus/basic/hello_fail.cc diff --git a/test/regtest.py b/test/regtest.py index 9562627d5..4885d0a93 100755 --- a/test/regtest.py +++ b/test/regtest.py @@ -178,7 +178,7 @@ def main(): parser.add_argument("--exhaustive", help="check all configurations on all examples", action="store_true") parser.add_argument("--all-configs", help="check all configurations per example", action="store_true") parser.add_argument("--all-examples", help="check all examples", action="store_true") - parser.add_argument("--folder", action="store", default="**", type=str, + parser.add_argument("--folder", action="store", default="**/**", type=str, help="sets the regressions folder to run") parser.add_argument("--threads", action="store", dest="n_threads", default=num_cpus, type=int, help="execute regressions using the selected number of threads in parallel") @@ -217,8 +217,12 @@ def main(): logging.info("Running regression tests...") # start processing the tests. + + files = [] + for ext in ('*.c', '*.cpp', '*.rs'): + files.extend(glob.glob(path.join("./" + args.folder + "/", ext))) results = [] - for test in sorted(glob.glob("./" + args.folder + "/*.c")): + for test in sorted(files): # get the meta data for this test meta = metadata(test) From 670b9b61041dee77a4244e55a3b3ddba89bd3269 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 31 Jul 2019 19:19:15 -0600 Subject: [PATCH 10/60] Upgrade Rust support for LLVM 8 * Install the most recent Rust compiler to support LLVM 8 * Improve entry point detection * Streamline Rust compiler installation. Closes #489 --- bin/build.sh | 3 ++- bin/versions | 2 +- lib/smack/SmackInstGenerator.cpp | 6 ++---- share/smack/frontend.py | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/bin/build.sh b/bin/build.sh index ace18792f..85f096d48 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -387,8 +387,9 @@ if [ ${INSTALL_RUST} -eq 1 ] ; then ${WGET} https://static.rust-lang.org/dist/${RUST_VERSION}/rust-nightly-x86_64-unknown-linux-gnu.tar.gz -O rust.tar.gz tar xf rust.tar.gz cd rust-nightly-x86_64-unknown-linux-gnu - sudo ./install.sh + sudo ./install.sh --without=rust-docs cd .. + rm -r rust-nightly-x86_64-unknown-linux-gnu rust.tar.gz puts "Installed Rust" fi diff --git a/bin/versions b/bin/versions index 8a0b4afe2..f266b9df7 100644 --- a/bin/versions +++ b/bin/versions @@ -8,4 +8,4 @@ SYMBOOGLIX_COMMIT=7210e5d09b LOCKPWN_COMMIT=73eddf97bd LLVM_SHORT_VERSION=8 LLVM_FULL_VERSION=8.0.1 -RUST_VERSION=2016-12-16 +RUST_VERSION=2019-07-16 diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index 89d28cf01..62120386b 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -646,10 +646,8 @@ void SmackInstGenerator::visitCallInst(llvm::CallInst &ci) { } else if (name.find(Naming::RUST_ENTRY) != std::string::npos) { // Set the entry point for Rust programs auto castExpr = ci.getArgOperand(0); - if (auto CE = dyn_cast(castExpr)) { - auto mainFunc = CE->getOperand(0); - emit(Stmt::call(mainFunc->getName(), {}, {})); - } + auto mainFunction = cast(castExpr); + emit(Stmt::call(mainFunction->getName(), {}, {})); } else if (name.find(Naming::RUST_PANIC1) != std::string::npos || name.find(Naming::RUST_PANIC2) != std::string::npos) { diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 9927fae10..222f234d8 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -220,7 +220,7 @@ def rust_frontend(input_file, args): """Generate Boogie code from Rust programming language source(s).""" compile_command = ['rustc', '-A', 'unused-imports', '-C', 'opt-level=0', '-C', 'no-prepopulate-passes', '-g', '--emit=llvm-bc', - '--cfg', 'verifier="smack"'] + '--cfg', 'verifier="smack"', '-C', 'passes=name-anon-globals'] # This links in the Rust SMACK library. This is needed due to the way rustc # finds a programs libraries. From 374445cb725302136a3f5cf9afc0cee271123bd5 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Tue, 22 Oct 2019 22:56:32 -0600 Subject: [PATCH 11/60] Updated Travis CI to match the new regressions folder structure Each input language now has a separate folder and Travis scripts did not reflect that. This is now fixed. --- .travis.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6bb28f7e1..60e0cc9cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,18 +25,18 @@ env: global: - COMPILER_NAME=clang COMPILER=clang++ CXX=clang++ CC=clang matrix: - - TRAVIS_ENV="--exhaustive --folder=basic" - - TRAVIS_ENV="--exhaustive --folder=data" - - TRAVIS_ENV="--exhaustive --folder=ntdrivers-simplified" - - TRAVIS_ENV="--exhaustive --folder=bits" - - TRAVIS_ENV="--exhaustive --folder=float" - - TRAVIS_ENV="--exhaustive --folder=locks" - - TRAVIS_ENV="--exhaustive --folder=contracts" - - TRAVIS_ENV="--exhaustive --folder=simd" - - TRAVIS_ENV="--exhaustive --folder=memory-safety" - - TRAVIS_ENV="--exhaustive --folder=pthread" - - TRAVIS_ENV="--exhaustive --folder=strings" - - TRAVIS_ENV="--exhaustive --folder=special" + - TRAVIS_ENV="--exhaustive --folder=c/basic" + - TRAVIS_ENV="--exhaustive --folder=c/data" + - TRAVIS_ENV="--exhaustive --folder=c/ntdrivers-simplified" + - TRAVIS_ENV="--exhaustive --folder=c/bits" + - TRAVIS_ENV="--exhaustive --folder=c/float" + - TRAVIS_ENV="--exhaustive --folder=c/locks" + - TRAVIS_ENV="--exhaustive --folder=c/contracts" + - TRAVIS_ENV="--exhaustive --folder=c/simd" + - TRAVIS_ENV="--exhaustive --folder=c/memory-safety" + - TRAVIS_ENV="--exhaustive --folder=c/pthread" + - TRAVIS_ENV="--exhaustive --folder=c/strings" + - TRAVIS_ENV="--exhaustive --folder=c/special" before_install: - sudo rm -rf /usr/local/clang-7.0.0 @@ -65,5 +65,5 @@ script: - clang++ --version - llvm-link --version - llvm-config --version - - ./format/run-clang-format.py -e test/basic/transform-out.c -r lib/smack include/smack share/smack/include share/smack/lib test examples + - ./format/run-clang-format.py -e test/c/basic/transform-out.c -r lib/smack include/smack share/smack/include share/smack/lib test examples - ./bin/build.sh From 428ff15122781151176c974850cf64d796665bca Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sat, 26 Oct 2019 22:32:38 -0600 Subject: [PATCH 12/60] Updated SVCOMP pthread filters to get rid of type definitions SVCOMP pthreads files define various pthreads types because of pre-processing, which clashes with our definitions. This updates those filters since SVCOMP files changed in their latest version. --- share/smack/svcomp/filters.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/share/smack/svcomp/filters.py b/share/smack/svcomp/filters.py index 1a0c8a47e..fcd7351ee 100644 --- a/share/smack/svcomp/filters.py +++ b/share/smack/svcomp/filters.py @@ -175,8 +175,10 @@ def scrub_pthreads(s): fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_mutex_s\s+{\s+int\s+__lock;\s+unsigned\s+int\s+__count;\s+int\s+__owner;\s+unsigned\s+int\s+__nusers;\s+int\s+__kind;\s+short\s+__spins;\s+short\s+__elision;\s+__pthread_list_t\s+__list;\s+# 124 "/usr/include/x86_64-linux-gnu/bits/pthreadtypes\.h" 3 4\s+}\s+__data;\s+\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+} pthread_mutex_t;') fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_mutex_s\s+{\s+int\s+__lock;\s+unsigned\s+int\s+__count;\s+int\s+__owner;\s+int\s+__kind;\s+unsigned\s+int\s+__nusers;\s+__extension__\s+union\s+{\s+struct\s+{\s+short\s+__espins;\s+short\s+__elision;\s+}\s+d;\s+__pthread_slist_t\s+__list;\s+};\s+}\s+__data;\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_mutex_t;') fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_mutex_s\s+{\s+int\s+__lock;\s+unsigned\s+int\s+__count;\s+int\s+__owner;\s+unsigned\s+int\s+__nusers;\s+int\s+__kind;\s+short\s+__spins;\s+short\s+__elision;\s+__pthread_list_t\s+__list;\s+}\s+__data;\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_mutex_t;') + fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_mutex_s\s+__data;\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_mutex_t;') #pthread_cond_t fltrs.append(r'typedef\s+union\s+{\s+struct\s+{\s+int\s+__lock;\s+unsigned\s+int\s+__futex;\s+__extension__\s+unsigned\s+long\s+long\s+int\s+__total_seq;\s+__extension__\s+unsigned\s+long\s+long\s+int\s+__wakeup_seq;\s+__extension__\s+unsigned\s+long\s+long\s+int\s+__woken_seq;\s+void\s+\*__mutex;\s+unsigned\s+int\s+__nwaiters;\s+unsigned\s+int\s+__broadcast_seq;\s+}\s+__data;\s+char\s+__size\[\d+\];\s+__extension__\s+long\s+long\s+int\s+__align;\s+}\s+pthread_cond_t;') + fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_cond_s\s+__data;\s+char\s+__size\[\d+\];\s+__extension__\s+long\s+long\s+int\s+__align;\s+}\s+pthread_cond_t;') #pthread_condattr_t fltrs.append(r'typedef\s+union\s+{\s+char\s+__size\[\d+\];\s+int\s+__align;\s+}\s+pthread_condattr_t;') fltrs.append(r'typedef\s+union\s+{\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_condattr_t;') From f8bc4d2c304fcfe0c190d0b18b8f76236aba45fb Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Fri, 25 Oct 2019 23:06:14 -0600 Subject: [PATCH 13/60] Model C integer remainder operations Fixes #496 --- lib/smack/Prelude.cpp | 44 ++++++++++++++++++++++++++++++++++-- test/c/basic/srem.c | 47 ++++++++++++++++++++++++++++++++++++++ test/c/basic/srem_fail.c | 47 ++++++++++++++++++++++++++++++++++++++ test/c/basic/urem.c | 49 ++++++++++++++++++++++++++++++++++++++++ test/c/basic/urem_fail.c | 49 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 test/c/basic/srem.c create mode 100644 test/c/basic/srem_fail.c create mode 100644 test/c/basic/urem.c create mode 100644 test/c/basic/urem_fail.c diff --git a/lib/smack/Prelude.cpp b/lib/smack/Prelude.cpp index c2f2d2c99..51a98397c 100644 --- a/lib/smack/Prelude.cpp +++ b/lib/smack/Prelude.cpp @@ -358,6 +358,44 @@ struct IntOpGen::IntArithOp : public IntOp { auto pred = MIN ? Expr::lt(a1, a2) : Expr::lt(a2, a1); return Expr::ifThenElse(pred, a1, a2); } + + // generate inlined `srem(i1, i2)` function body like + // if (mod(i1,i2) != 0 && i1 < 0) + // then mod(i1,i2) - abs(i2) else mod(i1,i2), where + // `i1` is the dividend and `i2` is the divisor + // `mod` is the Euclidean function defined in the SMT lib + // therefore its result is always positive + // the `srem` operation defined by LLVM follows the same + // definition as modern C standards + // (https://en.wikipedia.org/wiki/Modulo_operation#In_programming_languages) + // its result has the same sign as i1 because the division rounds to 0 + // therefore, the only case `mod` and `srem` differ is when i1 is negative + // and the remainder is not 0 + // for this case, the result of `srem` is the result of `mod` minus |i2| + static const Expr *sremExpr(unsigned size) { + std::string type = getIntTypeName(size); + const Expr *dividend = makeIntVarExpr(1); + const Expr *divisor = makeIntVarExpr(2); + const Expr *zero = Expr::lit((unsigned long long)0); + const Expr *mod = Expr::fn(indexedName("$smod", {type}), dividend, divisor); + const Expr *modNeZero = + Expr::fn(indexedName("$ne", {type, "bool"}), mod, zero); + const Expr *dividendLtZero = + Expr::fn(indexedName("$slt", {type, "bool"}), dividend, zero); + const Expr *negRemainder = Expr::fn( + indexedName("$sub", {type}), mod, + Expr::fn(indexedName("$smax", {type}), divisor, + Expr::fn(indexedName("$sub", {type}), zero, divisor))); + return Expr::ifThenElse(Expr::and_(modNeZero, dividendLtZero), negRemainder, + mod); + } + + // generate inlined `urem` function body like + // $smod.i32(i1,i2), where `$smod` is a wrapper to SMT's `mod` function + static const Expr *uremExpr(unsigned size) { + return Expr::fn(indexedName("$smod", {getIntTypeName(size)}), + makeIntVarExpr(1), makeIntVarExpr(2)); + } }; void IntOpGen::generateArithOps(std::stringstream &s) const { @@ -382,8 +420,10 @@ void IntOpGen::generateArithOps(std::stringstream &s) const { {"sdiv", 2, intBuiltinOp, bvBuiltinOp, false}, {"smod", 2, intBuiltinOp, bvBuiltinOp, false}, {"udiv", 2, intBuiltinOp, bvBuiltinOp, false}, - {"srem", 2, uninterpretedOp, bvBuiltinOp, false}, - {"urem", 2, uninterpretedOp, bvBuiltinOp, false}, + {"srem", 2, new InlinedOp(IntOpGen::IntArithOp::sremExpr), + bvBuiltinOp, false}, + {"urem", 2, new InlinedOp(IntOpGen::IntArithOp::uremExpr), + bvBuiltinOp, false}, {"shl", 2, uninterpretedOp, bvBuiltinOp, false}, {"lshr", 2, uninterpretedOp, bvBuiltinOp, false}, {"ashr", 2, uninterpretedOp, bvBuiltinOp, false}, diff --git a/test/c/basic/srem.c b/test/c/basic/srem.c new file mode 100644 index 000000000..355c9baa3 --- /dev/null +++ b/test/c/basic/srem.c @@ -0,0 +1,47 @@ +#include "smack.h" + +// @expect verified +// @checkbpl grep ':= \$srem' + +int main(void) { + int x; + x = 62951; + assert(x % (-37) == 14); + x = 81165; + assert(x % 34 == 7); + x = -74602; + assert(x % 47 == (-13)); + x = 82682; + assert(x % (-28) == 26); + x = 26476; + assert(x % (-19) == 9); + x = -80492; + assert(x % 5 == (-2)); + x = -44299; + assert(x % (-31) == 0); + x = 9380; + assert(x % 50 == 30); + x = 91508; + assert(x % 50 == 8); + x = 92985; + assert(x % 47 == 19); + x = -68477; + assert(x % 23 == (-6)); + x = 94126; + assert(x % 49 == 46); + x = 91440; + assert(x % (-39) == 24); + x = -2922; + assert(x % 30 == (-12)); + x = 60062; + assert(x % (-21) == 2); + x = -71622; + assert(x % (-50) == (-22)); + x = -15645; + assert(x % (-39) == (-6)); + x = 83154; + assert(x % 14 == 8); + x = 58447; + assert(x % 38 == 3); + return 0; +} diff --git a/test/c/basic/srem_fail.c b/test/c/basic/srem_fail.c new file mode 100644 index 000000000..a6b160f97 --- /dev/null +++ b/test/c/basic/srem_fail.c @@ -0,0 +1,47 @@ +#include "smack.h" + +// @expect error +// @checkbpl grep ':= \$srem' + +int main(void) { + int x; + x = 62951; + assert(x % (-37) == 14); + x = 81165; + assert(x % 34 == 7); + x = -74602; + assert(x % 47 == (-13)); + x = 82682; + assert(x % (-28) == 26); + x = 26476; + assert(x % (-19) == 9); + x = -80492; + assert(x % 5 == (-2)); + x = -44299; + assert(x % (-31) == 0); + x = 9380; + assert(x % 50 == 30); + x = 91508; + assert(x % 50 == 8); + x = 92985; + assert(x % 47 == 19); + x = -68477; + assert(x % 23 == (-6)); + x = 94126; + assert(x % 49 == 46); + x = 91440; + assert(x % (-39) == 24); + x = -2922; + assert(x % 30 != (-12)); + x = 60062; + assert(x % (-21) == 2); + x = -71622; + assert(x % (-50) == (-22)); + x = -15645; + assert(x % (-39) == (-6)); + x = 83154; + assert(x % 14 == 8); + x = 58447; + assert(x % 38 == 3); + return 0; +} diff --git a/test/c/basic/urem.c b/test/c/basic/urem.c new file mode 100644 index 000000000..74e6256ed --- /dev/null +++ b/test/c/basic/urem.c @@ -0,0 +1,49 @@ +#include "smack.h" + +// @expect verified +// @checkbpl grep ':= \$urem' + +int main(void) { + unsigned x; + x = 162951; + assert(x % 7 == 5); + x = 181165; + assert(x % 42 == 19); + x = 25398; + assert(x % 49 == 16); + x = 182682; + assert(x % 12 == 6); + x = 126476; + assert(x % 16 == 12); + x = 19508; + assert(x % 28 == 20); + x = 55701; + assert(x % 10 == 1); + x = 109380; + assert(x % 50 == 30); + x = 191508; + assert(x % 50 == 8); + x = 192985; + assert(x % 49 == 23); + x = 31523; + assert(x % 37 == 36); + x = 194126; + assert(x % 50 == 26); + x = 191440; + assert(x % 6 == 4); + x = 97078; + assert(x % 40 == 38); + x = 160062; + assert(x % 15 == 12); + x = 28378; + assert(x % 1 == 0); + x = 84355; + assert(x % 6 == 1); + x = 183154; + assert(x % 32 == 18); + x = 158447; + assert(x % 44 == 3); + x = 191905; + assert(x % 26 == 25); + return 0; +} diff --git a/test/c/basic/urem_fail.c b/test/c/basic/urem_fail.c new file mode 100644 index 000000000..dd802a908 --- /dev/null +++ b/test/c/basic/urem_fail.c @@ -0,0 +1,49 @@ +#include "smack.h" + +// @expect error +// @checkbpl grep ':= \$urem' + +int main(void) { + unsigned x; + x = 162951; + assert(x % 7 == 5); + x = 181165; + assert(x % 42 == 19); + x = 25398; + assert(x % 49 == 16); + x = 182682; + assert(x % 12 == 6); + x = 126476; + assert(x % 16 == 12); + x = 19508; + assert(x % 28 == 20); + x = 55701; + assert(x % 10 == 1); + x = 109380; + assert(x % 50 == 30); + x = 191508; + assert(x % 50 == 8); + x = 192985; + assert(x % 49 == 23); + x = 31523; + assert(x % 37 != 36); + x = 194126; + assert(x % 50 == 26); + x = 191440; + assert(x % 6 == 4); + x = 97078; + assert(x % 40 == 38); + x = 160062; + assert(x % 15 == 12); + x = 28378; + assert(x % 1 == 0); + x = 84355; + assert(x % 6 == 1); + x = 183154; + assert(x % 32 == 18); + x = 158447; + assert(x % 44 == 3); + x = 191905; + assert(x % 26 == 25); + return 0; +} From 76c39dce1d9320957336521022f12be4a0fac21b Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 23 Oct 2019 09:52:53 -0600 Subject: [PATCH 14/60] Integrate Rust regressions * regtest.py is updated to allow the selection of languages to test * Regression tests for Rust are now included in the test directory * Travis is configured to run Rust regressions automatically * Smack support for Rust is made more robust by not creating a directory in frontend.py --- .travis.yml | 9 +++- bin/build.sh | 2 +- share/smack/frontend.py | 20 ++++--- test/regtest.py | 28 ++++++++-- test/rust/basic/add_fail.rs | 11 ++++ test/rust/basic/add_overflow.rs | 12 +++++ test/rust/basic/arith.rs | 55 ++++++++++++++++++++ test/rust/basic/arith_assume.rs | 13 +++++ test/rust/basic/arith_assume2.rs | 13 +++++ test/rust/basic/arith_assume_fail.rs | 16 ++++++ test/rust/basic/div_fail.rs | 11 ++++ test/rust/basic/mod_fail.rs | 11 ++++ test/rust/basic/mul_fail.rs | 11 ++++ test/rust/basic/mul_overflow.rs | 12 +++++ test/rust/basic/sub_fail.rs | 11 ++++ test/rust/basic/sub_overflow.rs | 12 +++++ test/rust/functions/closure.rs | 24 +++++++++ test/rust/functions/closure_fail.rs | 24 +++++++++ test/rust/functions/double.rs | 15 ++++++ test/rust/functions/double_fail.rs | 15 ++++++ test/rust/generics/config.yml | 1 + test/rust/generics/generic_function.rs | 55 ++++++++++++++++++++ test/rust/generics/generic_function_fail1.rs | 55 ++++++++++++++++++++ test/rust/generics/generic_function_fail2.rs | 55 ++++++++++++++++++++ test/rust/generics/generic_function_fail3.rs | 55 ++++++++++++++++++++ test/rust/generics/generic_function_fail4.rs | 55 ++++++++++++++++++++ test/rust/generics/generic_function_fail5.rs | 55 ++++++++++++++++++++ test/rust/loops/config.yml | 1 + test/rust/loops/gauss_sum_nondet.rs | 16 ++++++ test/rust/loops/gauss_sum_nondet_fail.rs | 16 ++++++ test/rust/loops/iterator.rs | 24 +++++++++ test/rust/loops/iterator_fail.rs | 22 ++++++++ test/rust/recursion/config.yml | 1 + test/rust/recursion/fac.rs | 18 +++++++ test/rust/recursion/fac_fail.rs | 18 +++++++ test/rust/structures/option.rs | 29 +++++++++++ test/rust/structures/option_fail.rs | 29 +++++++++++ test/rust/structures/point.rs | 51 ++++++++++++++++++ test/rust/structures/point_fail.rs | 51 ++++++++++++++++++ test/rust/timeouts/fib.rs | 19 +++++++ test/rust/timeouts/fib_fail.rs | 19 +++++++ test/rust/timeouts/vec_resize.rs | 13 +++++ test/rust/timeouts/vec_resize_fail.rs | 13 +++++ test/rust/vector/config.yml | 1 + test/rust/vector/vec1.rs | 20 +++++++ test/rust/vector/vec1_fail1.rs | 20 +++++++ test/rust/vector/vec1_fail2.rs | 20 +++++++ test/rust/vector/vec1_fail3.rs | 20 +++++++ 48 files changed, 1060 insertions(+), 17 deletions(-) create mode 100644 test/rust/basic/add_fail.rs create mode 100644 test/rust/basic/add_overflow.rs create mode 100644 test/rust/basic/arith.rs create mode 100644 test/rust/basic/arith_assume.rs create mode 100644 test/rust/basic/arith_assume2.rs create mode 100644 test/rust/basic/arith_assume_fail.rs create mode 100644 test/rust/basic/div_fail.rs create mode 100644 test/rust/basic/mod_fail.rs create mode 100644 test/rust/basic/mul_fail.rs create mode 100644 test/rust/basic/mul_overflow.rs create mode 100644 test/rust/basic/sub_fail.rs create mode 100644 test/rust/basic/sub_overflow.rs create mode 100644 test/rust/functions/closure.rs create mode 100644 test/rust/functions/closure_fail.rs create mode 100644 test/rust/functions/double.rs create mode 100644 test/rust/functions/double_fail.rs create mode 100644 test/rust/generics/config.yml create mode 100644 test/rust/generics/generic_function.rs create mode 100644 test/rust/generics/generic_function_fail1.rs create mode 100644 test/rust/generics/generic_function_fail2.rs create mode 100644 test/rust/generics/generic_function_fail3.rs create mode 100644 test/rust/generics/generic_function_fail4.rs create mode 100644 test/rust/generics/generic_function_fail5.rs create mode 100644 test/rust/loops/config.yml create mode 100644 test/rust/loops/gauss_sum_nondet.rs create mode 100644 test/rust/loops/gauss_sum_nondet_fail.rs create mode 100644 test/rust/loops/iterator.rs create mode 100644 test/rust/loops/iterator_fail.rs create mode 100644 test/rust/recursion/config.yml create mode 100644 test/rust/recursion/fac.rs create mode 100644 test/rust/recursion/fac_fail.rs create mode 100644 test/rust/structures/option.rs create mode 100644 test/rust/structures/option_fail.rs create mode 100644 test/rust/structures/point.rs create mode 100644 test/rust/structures/point_fail.rs create mode 100644 test/rust/timeouts/fib.rs create mode 100644 test/rust/timeouts/fib_fail.rs create mode 100644 test/rust/timeouts/vec_resize.rs create mode 100644 test/rust/timeouts/vec_resize_fail.rs create mode 100644 test/rust/vector/config.yml create mode 100644 test/rust/vector/vec1.rs create mode 100644 test/rust/vector/vec1_fail1.rs create mode 100644 test/rust/vector/vec1_fail2.rs create mode 100644 test/rust/vector/vec1_fail3.rs diff --git a/.travis.yml b/.travis.yml index 60e0cc9cd..19371a537 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,13 @@ env: - TRAVIS_ENV="--exhaustive --folder=c/pthread" - TRAVIS_ENV="--exhaustive --folder=c/strings" - TRAVIS_ENV="--exhaustive --folder=c/special" + - TRAVIS_ENV="--exhaustive --folder=rust/basic --languages=rust" + - TRAVIS_ENV="--exhaustive --folder=rust/functions --languages=rust" + - TRAVIS_ENV="--exhaustive --folder=rust/generics --languages=rust" + - TRAVIS_ENV="--exhaustive --folder=rust/loops --languages=rust" + - TRAVIS_ENV="--exhaustive --folder=rust/recursion --languages=rust" + - TRAVIS_ENV="--exhaustive --folder=rust/structures --languages=rust" + - TRAVIS_ENV="--exhaustive --folder=rust/vector --languages=rust" before_install: - sudo rm -rf /usr/local/clang-7.0.0 @@ -66,4 +73,4 @@ script: - llvm-link --version - llvm-config --version - ./format/run-clang-format.py -e test/c/basic/transform-out.c -r lib/smack include/smack share/smack/include share/smack/lib test examples - - ./bin/build.sh + - INSTALL_RUST=1 ./bin/build.sh diff --git a/bin/build.sh b/bin/build.sh index 85f096d48..25e58384f 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -35,7 +35,7 @@ BUILD_MONO=0 # mono is typically installed from packages (see below) # Support for more programming languages INSTALL_OBJECTIVEC=0 -INSTALL_RUST=0 +INSTALL_RUST=${INSTALL_RUST:-0} # PATHS SMACK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )" diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 222f234d8..1c88add1e 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -223,19 +223,17 @@ def rust_frontend(input_file, args): '--cfg', 'verifier="smack"', '-C', 'passes=name-anon-globals'] # This links in the Rust SMACK library. This is needed due to the way rustc - # finds a programs libraries. + # finds a program's libraries. + abs_path = os.path.dirname(os.path.abspath(input_file)) + link_target = os.path.join(abs_path, "smack.rs") + link_source = os.path.join(smack_lib(), 'smack.rs') try: - abs_path = os.path.dirname(os.path.abspath(input_file)) - mod_path = os.path.join(abs_path, "smack") - if not os.path.exists(mod_path): - os.mkdir(mod_path) - link_target = os.path.join(mod_path, "mod.rs") - if not os.path.exists(link_target): - rust_macros = os.path.join(smack_lib(), 'smack.rs') - os.symlink(rust_macros, link_target) + os.symlink(link_source, link_target) except: - raise RuntimeError("Could not find or create smack module.") - + if not os.path.exists(link_source): + raise RuntimeError("Could not find or create smack module.") + # Otherwise okay + return compile_to_bc(input_file,compile_command,args) # Build libs functions here diff --git a/test/regtest.py b/test/regtest.py index 4885d0a93..fd3c2a75f 100755 --- a/test/regtest.py +++ b/test/regtest.py @@ -20,6 +20,10 @@ OVERRIDE_FIELDS = ['verifiers', 'memory', 'time-limit', 'memory-limit', 'skip'] APPEND_FIELDS = ['flags', 'checkbpl', 'checkout'] +LANGUAGES = {'c': {'*.c'}, + 'cplusplus': {'*.cpp'}, + 'rust': {'*.rs'}} + def bold(text): return '\033[1m' + text + '\033[0m' @@ -165,6 +169,20 @@ def tally_result(result): elif "UNKNOWN" in result: unknowns += 1 +def get_extensions(languages): + languages = list(languages.split(',')) + extensions = set() + for language in languages: + extensions |= LANGUAGES[language] + return extensions + +def get_tests(folder, extensions): + tests = [] + for ext in extensions: + tests.extend(glob.glob(path.join('./' + folder + '/',ext))) + tests.sort() + return tests + def main(): """ Main entry point for the test suite. @@ -186,12 +204,17 @@ def main(): help="sets the logging level (DEBUG, INFO, WARNING)") parser.add_argument("--output-log", action="store", dest="log_path", type=str, help="sets the output log path. (std out by default)") + parser.add_argument("--languages", action="store", default="c", choices=list(LANGUAGES.keys()), + help="Comma separated list of langauges to test. C[c],C++[cplusplus],Rust[rust]") args = parser.parse_args() if args.exhaustive: args.all_examples = True; args.all_configs = True; + extensions = get_extensions(args.languages) + tests = get_tests(args.folder, extensions) + # configure the logging log_format = '' log_level = logging.DEBUG @@ -218,11 +241,8 @@ def main(): # start processing the tests. - files = [] - for ext in ('*.c', '*.cpp', '*.rs'): - files.extend(glob.glob(path.join("./" + args.folder + "/", ext))) results = [] - for test in sorted(files): + for test in tests: # get the meta data for this test meta = metadata(test) diff --git a/test/rust/basic/add_fail.rs b/test/rust/basic/add_fail.rs new file mode 100644 index 000000000..3f32c4834 --- /dev/null +++ b/test/rust/basic/add_fail.rs @@ -0,0 +1,11 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect error + +fn main() { + let a = 2; + let b = 3; + assert!(a+b != 5); +} diff --git a/test/rust/basic/add_overflow.rs b/test/rust/basic/add_overflow.rs new file mode 100644 index 000000000..aa29698fe --- /dev/null +++ b/test/rust/basic/add_overflow.rs @@ -0,0 +1,12 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --integer-overflow +// @expect error + +fn main() { + let a: u8 = 128; + let b: u8 = 128; + let c = a + b; +} diff --git a/test/rust/basic/arith.rs b/test/rust/basic/arith.rs new file mode 100644 index 000000000..269e7163b --- /dev/null +++ b/test/rust/basic/arith.rs @@ -0,0 +1,55 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect verified +// @flag --bit-precise + +fn main() { + // unsigned + { + let a: u32 = 2; + let b: u32 = 3; + { + let c = a + b; + assert!(c == 5); + } + { + let c = a * b; + assert!(c == 6); + } + { + let c = b - a; + assert!(c == 1); + } + { + let c = a % b; + assert!(c == 2); + let d = b % a; + assert!(d == 1); + } + { + let c = a / b; + assert!(c == 0); + let d = b / a; + assert!(d == 1); + } + } + // signed + { + let a: i32 = -3; + let b: i32 = 5; + { + let c = a + b; + assert!(c == 2); + } + { + let c = a * b; + assert!(c == -15); + } + { + let c = b - a; + assert!(c == 8); + } + } +} diff --git a/test/rust/basic/arith_assume.rs b/test/rust/basic/arith_assume.rs new file mode 100644 index 000000000..6a2d1d381 --- /dev/null +++ b/test/rust/basic/arith_assume.rs @@ -0,0 +1,13 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect verified + +fn main() { + let a = 6i32.nondet(); + let b = 7i32.nondet(); + assume!(4 < a && a < 8); // a in [5,7] + assume!(5 < b && b < 9); // b in [6,8] + assert!(30 <= a * b && a * b <= 56); // a*b in [30,56] +} diff --git a/test/rust/basic/arith_assume2.rs b/test/rust/basic/arith_assume2.rs new file mode 100644 index 000000000..6a2d1d381 --- /dev/null +++ b/test/rust/basic/arith_assume2.rs @@ -0,0 +1,13 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect verified + +fn main() { + let a = 6i32.nondet(); + let b = 7i32.nondet(); + assume!(4 < a && a < 8); // a in [5,7] + assume!(5 < b && b < 9); // b in [6,8] + assert!(30 <= a * b && a * b <= 56); // a*b in [30,56] +} diff --git a/test/rust/basic/arith_assume_fail.rs b/test/rust/basic/arith_assume_fail.rs new file mode 100644 index 000000000..554b3e108 --- /dev/null +++ b/test/rust/basic/arith_assume_fail.rs @@ -0,0 +1,16 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect error + +fn main() { + let a = 6i32.nondet(); + let b = 7i32.nondet(); + assume!(4 < a && a < 8); // a in [5,7] + assume!(5 < b && b < 9); // b in [6,8] + let x = a * b; + assert!(!(x==30 || x==35 || x==40 || + x==36 || x==48 || x==42 || + x==49 || x==56)); // a*b != anything allowed +} diff --git a/test/rust/basic/div_fail.rs b/test/rust/basic/div_fail.rs new file mode 100644 index 000000000..812120970 --- /dev/null +++ b/test/rust/basic/div_fail.rs @@ -0,0 +1,11 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect error + +fn main() { + let a = 2; + let b = 3; + assert!(b/a != 1); +} diff --git a/test/rust/basic/mod_fail.rs b/test/rust/basic/mod_fail.rs new file mode 100644 index 000000000..89522cc79 --- /dev/null +++ b/test/rust/basic/mod_fail.rs @@ -0,0 +1,11 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect error + +fn main() { + let a = 2; + let b = 3; + assert!(b%a != 1); +} diff --git a/test/rust/basic/mul_fail.rs b/test/rust/basic/mul_fail.rs new file mode 100644 index 000000000..82638cfc4 --- /dev/null +++ b/test/rust/basic/mul_fail.rs @@ -0,0 +1,11 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect error + +fn main() { + let a = 2; + let b = 3; + assert!(b*a != 6); +} diff --git a/test/rust/basic/mul_overflow.rs b/test/rust/basic/mul_overflow.rs new file mode 100644 index 000000000..9d1c11f05 --- /dev/null +++ b/test/rust/basic/mul_overflow.rs @@ -0,0 +1,12 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --integer-overflow +// @expect error + +fn main() { + let a: u8 = 128; + let b: u8 = 2; + let c = a * b; +} diff --git a/test/rust/basic/sub_fail.rs b/test/rust/basic/sub_fail.rs new file mode 100644 index 000000000..b32beb617 --- /dev/null +++ b/test/rust/basic/sub_fail.rs @@ -0,0 +1,11 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect error + +fn main() { + let a = 2; + let b = 3; + assert!(b-a != 1); +} diff --git a/test/rust/basic/sub_overflow.rs b/test/rust/basic/sub_overflow.rs new file mode 100644 index 000000000..3128212d9 --- /dev/null +++ b/test/rust/basic/sub_overflow.rs @@ -0,0 +1,12 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --integer-overflow +// @expect error + +fn main() { + let a: u8 = 128; + let b: u8 = 129; + let c = a - b; +} diff --git a/test/rust/functions/closure.rs b/test/rust/functions/closure.rs new file mode 100644 index 000000000..f0d9b843c --- /dev/null +++ b/test/rust/functions/closure.rs @@ -0,0 +1,24 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect verified + +fn call_with_one(mut some_closure: F) -> () + where F : FnMut(i32) -> () { + + some_closure(1); +} + +fn main() { + let mut num = 5i32.nondet(); + let original_num = num; + { + let mut add_num = |x: i32| num += x; + + add_num(5); + call_with_one(&mut add_num); + } + assert_eq!(original_num + 6, num); +} diff --git a/test/rust/functions/closure_fail.rs b/test/rust/functions/closure_fail.rs new file mode 100644 index 000000000..931b8b53a --- /dev/null +++ b/test/rust/functions/closure_fail.rs @@ -0,0 +1,24 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect error + +fn call_with_one(mut some_closure: F) -> () + where F : FnMut(i32) -> () { + + some_closure(1); +} + +fn main() { + let mut num = 5i32.nondet(); + let old_num = num; + { + let mut add_num = |x: i32| num += x; + + add_num(5); + call_with_one(&mut add_num); + } + assert!(old_num + 6 != num); // Should be old_num + 6 +} diff --git a/test/rust/functions/double.rs b/test/rust/functions/double.rs new file mode 100644 index 000000000..761afe1c9 --- /dev/null +++ b/test/rust/functions/double.rs @@ -0,0 +1,15 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect verified + +fn double(a: u32) -> u32 { + a * 2 +} + +fn main() { + let a = 2u32.nondet(); + let b = double(a); + assert!(b == 2*a); +} diff --git a/test/rust/functions/double_fail.rs b/test/rust/functions/double_fail.rs new file mode 100644 index 000000000..034b36db9 --- /dev/null +++ b/test/rust/functions/double_fail.rs @@ -0,0 +1,15 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect error + +fn double(a: u32) -> u32 { + a * 2 +} + +fn main() { + let a = 2u32.nondet(); + let b = double(a); + assert!(b != 2*a); +} diff --git a/test/rust/generics/config.yml b/test/rust/generics/config.yml new file mode 100644 index 000000000..f538f2a68 --- /dev/null +++ b/test/rust/generics/config.yml @@ -0,0 +1 @@ +memory: [no-reuse-impls, no-reuse] diff --git a/test/rust/generics/generic_function.rs b/test/rust/generics/generic_function.rs new file mode 100644 index 000000000..b43cf968d --- /dev/null +++ b/test/rust/generics/generic_function.rs @@ -0,0 +1,55 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect verified + +struct Point { + pub x:T, + pub y:T +} + +struct Point3 { + pub x:T, + pub y:T, + pub z:T +} + +trait S { + fn swap_items(self)->Self; +} + +impl S for Point { + fn swap_items(self) -> Point { + Point::{x: self.y, y: self.x} + } +} + +impl S for Point3 { + fn swap_items(self) -> Point3 { + Point3::{x: self.y, y: self.z, z: self.x} + } +} + +fn swapem>(s: U) -> U { + s.swap_items() +} + +fn main() { + let x2 = 7i64.nondet(); + let y2 = 8i64.nondet(); + let x3 = 1i64.nondet(); + let y3 = 2i64.nondet(); + let z3 = 3i64.nondet(); + let p2 = Point::{x: x2, y: y2}; + let p3 = Point3::{x: x3, y: y3, z: z3}; + + let q2 = swapem(p2); + let q3 = swapem(p3); + assert!(q2.x == y2); + assert!(q2.y == x2); + assert!(q3.x == y3); + assert!(q3.y == z3); + assert!(q3.z == x3); +} diff --git a/test/rust/generics/generic_function_fail1.rs b/test/rust/generics/generic_function_fail1.rs new file mode 100644 index 000000000..c0429e31d --- /dev/null +++ b/test/rust/generics/generic_function_fail1.rs @@ -0,0 +1,55 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect error + +struct Point { + pub x:T, + pub y:T +} + +struct Point3 { + pub x:T, + pub y:T, + pub z:T +} + +trait S { + fn swap_items(self)->Self; +} + +impl S for Point { + fn swap_items(self) -> Point { + Point::{x: self.y, y: self.x} + } +} + +impl S for Point3 { + fn swap_items(self) -> Point3 { + Point3::{x: self.y, y: self.z, z: self.x} + } +} + +fn swapem>(s: U) -> U { + s.swap_items() +} + +fn main() { + let x2 = 7i64.nondet(); + let y2 = 8i64.nondet(); + let x3 = 1i64.nondet(); + let y3 = 2i64.nondet(); + let z3 = 3i64.nondet(); + let p2 = Point::{x: x2, y: y2}; + let p3 = Point3::{x: x3, y: y3, z: z3}; + + let q2 = swapem(p2); + let q3 = swapem(p3); + assert!(q2.x != y2); + assert!(q2.y == x2); + assert!(q3.x == y3); + assert!(q3.y == z3); + assert!(q3.z == x3); +} diff --git a/test/rust/generics/generic_function_fail2.rs b/test/rust/generics/generic_function_fail2.rs new file mode 100644 index 000000000..4f7684400 --- /dev/null +++ b/test/rust/generics/generic_function_fail2.rs @@ -0,0 +1,55 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect error + +struct Point { + pub x:T, + pub y:T +} + +struct Point3 { + pub x:T, + pub y:T, + pub z:T +} + +trait S { + fn swap_items(self)->Self; +} + +impl S for Point { + fn swap_items(self) -> Point { + Point::{x: self.y, y: self.x} + } +} + +impl S for Point3 { + fn swap_items(self) -> Point3 { + Point3::{x: self.y, y: self.z, z: self.x} + } +} + +fn swapem>(s: U) -> U { + s.swap_items() +} + +fn main() { + let x2 = 7i64.nondet(); + let y2 = 8i64.nondet(); + let x3 = 1i64.nondet(); + let y3 = 2i64.nondet(); + let z3 = 3i64.nondet(); + let p2 = Point::{x: x2, y: y2}; + let p3 = Point3::{x: x3, y: y3, z: z3}; + + let q2 = swapem(p2); + let q3 = swapem(p3); + assert!(q2.x == y2); + assert!(q2.y != x2); + assert!(q3.x == y3); + assert!(q3.y == z3); + assert!(q3.z == x3); +} diff --git a/test/rust/generics/generic_function_fail3.rs b/test/rust/generics/generic_function_fail3.rs new file mode 100644 index 000000000..277d837f2 --- /dev/null +++ b/test/rust/generics/generic_function_fail3.rs @@ -0,0 +1,55 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect error + +struct Point { + pub x:T, + pub y:T +} + +struct Point3 { + pub x:T, + pub y:T, + pub z:T +} + +trait S { + fn swap_items(self)->Self; +} + +impl S for Point { + fn swap_items(self) -> Point { + Point::{x: self.y, y: self.x} + } +} + +impl S for Point3 { + fn swap_items(self) -> Point3 { + Point3::{x: self.y, y: self.z, z: self.x} + } +} + +fn swapem>(s: U) -> U { + s.swap_items() +} + +fn main() { + let x2 = 7i64.nondet(); + let y2 = 8i64.nondet(); + let x3 = 1i64.nondet(); + let y3 = 2i64.nondet(); + let z3 = 3i64.nondet(); + let p2 = Point::{x: x2, y: y2}; + let p3 = Point3::{x: x3, y: y3, z: z3}; + + let q2 = swapem(p2); + let q3 = swapem(p3); + assert!(q2.x == y2); + assert!(q2.y == x2); + assert!(q3.x != y3); + assert!(q3.y == z3); + assert!(q3.z == x3); +} diff --git a/test/rust/generics/generic_function_fail4.rs b/test/rust/generics/generic_function_fail4.rs new file mode 100644 index 000000000..cfb4fa91a --- /dev/null +++ b/test/rust/generics/generic_function_fail4.rs @@ -0,0 +1,55 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect error + +struct Point { + pub x:T, + pub y:T +} + +struct Point3 { + pub x:T, + pub y:T, + pub z:T +} + +trait S { + fn swap_items(self)->Self; +} + +impl S for Point { + fn swap_items(self) -> Point { + Point::{x: self.y, y: self.x} + } +} + +impl S for Point3 { + fn swap_items(self) -> Point3 { + Point3::{x: self.y, y: self.z, z: self.x} + } +} + +fn swapem>(s: U) -> U { + s.swap_items() +} + +fn main() { + let x2 = 7i64.nondet(); + let y2 = 8i64.nondet(); + let x3 = 1i64.nondet(); + let y3 = 2i64.nondet(); + let z3 = 3i64.nondet(); + let p2 = Point::{x: x2, y: y2}; + let p3 = Point3::{x: x3, y: y3, z: z3}; + + let q2 = swapem(p2); + let q3 = swapem(p3); + assert!(q2.x == y2); + assert!(q2.y == x2); + assert!(q3.x == y3); + assert!(q3.y != z3); + assert!(q3.z == x3); +} diff --git a/test/rust/generics/generic_function_fail5.rs b/test/rust/generics/generic_function_fail5.rs new file mode 100644 index 000000000..64f5b062c --- /dev/null +++ b/test/rust/generics/generic_function_fail5.rs @@ -0,0 +1,55 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect error + +struct Point { + pub x:T, + pub y:T +} + +struct Point3 { + pub x:T, + pub y:T, + pub z:T +} + +trait S { + fn swap_items(self)->Self; +} + +impl S for Point { + fn swap_items(self) -> Point { + Point::{x: self.y, y: self.x} + } +} + +impl S for Point3 { + fn swap_items(self) -> Point3 { + Point3::{x: self.y, y: self.z, z: self.x} + } +} + +fn swapem>(s: U) -> U { + s.swap_items() +} + +fn main() { + let x2 = 7i64.nondet(); + let y2 = 8i64.nondet(); + let x3 = 1i64.nondet(); + let y3 = 2i64.nondet(); + let z3 = 3i64.nondet(); + let p2 = Point::{x: x2, y: y2}; + let p3 = Point3::{x: x3, y: y3, z: z3}; + + let q2 = swapem(p2); + let q3 = swapem(p3); + assert!(q2.x == y2); + assert!(q2.y == x2); + assert!(q3.x == y3); + assert!(q3.y == z3); + assert!(q3.z != x3); +} diff --git a/test/rust/loops/config.yml b/test/rust/loops/config.yml new file mode 100644 index 000000000..f538f2a68 --- /dev/null +++ b/test/rust/loops/config.yml @@ -0,0 +1 @@ +memory: [no-reuse-impls, no-reuse] diff --git a/test/rust/loops/gauss_sum_nondet.rs b/test/rust/loops/gauss_sum_nondet.rs new file mode 100644 index 000000000..2ff934e6b --- /dev/null +++ b/test/rust/loops/gauss_sum_nondet.rs @@ -0,0 +1,16 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting --unroll=4 +// @expect verified + +fn main() { + let mut sum = 0; + let b = 7u64.nondet(); + assume!(b < 5 && b > 1); + for i in 0..b as u64 { + sum += i; + } + assert!(2*sum == b*(b-1)); +} diff --git a/test/rust/loops/gauss_sum_nondet_fail.rs b/test/rust/loops/gauss_sum_nondet_fail.rs new file mode 100644 index 000000000..ce58d8326 --- /dev/null +++ b/test/rust/loops/gauss_sum_nondet_fail.rs @@ -0,0 +1,16 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting --unroll=10 +// @expect error + +fn main() { + let mut sum = 0; + let b = 7u64.nondet(); + assume!(b > 1); + for i in 0..b as u64 { + sum += i; + } + assert!(2*sum != b*(b-1)); +} diff --git a/test/rust/loops/iterator.rs b/test/rust/loops/iterator.rs new file mode 100644 index 000000000..e7bed0e37 --- /dev/null +++ b/test/rust/loops/iterator.rs @@ -0,0 +1,24 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting --unroll=4 +// @expect verified + +fn fac(n: u64) -> u64 { + match n { + 0 => 1, + 1 => 1, + _ => n*fac(n-1) + } +} + +fn main() { + let mut a = 1; + let n = 6u64.nondet(); + assume!(n < 5); + for i in 1..n+1 as u64 { + a *= i; + } + assert!(a == fac(n)); // a == 6! +} diff --git a/test/rust/loops/iterator_fail.rs b/test/rust/loops/iterator_fail.rs new file mode 100644 index 000000000..e160f5cc1 --- /dev/null +++ b/test/rust/loops/iterator_fail.rs @@ -0,0 +1,22 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting --unroll=10 +// @expect error + +fn fac(n: u64) -> u64 { + match n { + 0 => 1, + 1 => 1, + _ => n*fac(n-1) + } +} +fn main() { + let mut a = 1; + let n = 6u64.nondet(); + for i in 1..n+1 as u64 { + a *= i; + } + assert!(a != fac(n)); // a should equal 6! +} diff --git a/test/rust/recursion/config.yml b/test/rust/recursion/config.yml new file mode 100644 index 000000000..03dbc1e0f --- /dev/null +++ b/test/rust/recursion/config.yml @@ -0,0 +1 @@ +verifiers: [corral] \ No newline at end of file diff --git a/test/rust/recursion/fac.rs b/test/rust/recursion/fac.rs new file mode 100644 index 000000000..cbbebc0dd --- /dev/null +++ b/test/rust/recursion/fac.rs @@ -0,0 +1,18 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --unroll=10 +// @expect verified + +fn fac(n: u64, acc: u64) -> u64 { + match n { + 0 => acc, + _ => fac(n - 1, acc * n) + } +} + +fn main() { + let x = fac(5, 1); + assert!(x == 120); +} diff --git a/test/rust/recursion/fac_fail.rs b/test/rust/recursion/fac_fail.rs new file mode 100644 index 000000000..c8d9c8259 --- /dev/null +++ b/test/rust/recursion/fac_fail.rs @@ -0,0 +1,18 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --unroll=10 +// @expect error + +fn fac(n: u64, acc: u64) -> u64 { + match n { + 0 => acc, + _ => fac(n - 1, acc * n) + } +} + +fn main() { + let x = fac(5, 1); + assert!(x != 120); +} diff --git a/test/rust/structures/option.rs b/test/rust/structures/option.rs new file mode 100644 index 000000000..cbfb1e52a --- /dev/null +++ b/test/rust/structures/option.rs @@ -0,0 +1,29 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect verified + +fn safe_div(x: u64, y: u64) -> Option { + if y != 0 { + Some(x/y) + } + else { + None + } +} + +fn main() { + let x = 2u64.nondet(); + assume!(x > 0); + let a = safe_div(2*x,x); + match a { + Some(x) => assert!(x == 2), + None => assert!(false) + }; + let b = safe_div(x,0); + match b { + Some(x) => assert!(false), + None => assert!(true) + }; +} diff --git a/test/rust/structures/option_fail.rs b/test/rust/structures/option_fail.rs new file mode 100644 index 000000000..dc11d8f5b --- /dev/null +++ b/test/rust/structures/option_fail.rs @@ -0,0 +1,29 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect error + +fn safe_div(x: u64, y: u64) -> Option { + if y != 0 { + Some(x/y) + } + else { + None + } +} + +fn main() { + let x = 2u64.nondet(); + assume!(x > 0); + let a = safe_div(2*x,x); + match a { + Some(x) => assert!(x == 2), + None => assert!(false) + }; + let b = safe_div(x,0); + match b { + Some(x) => assert!(true), + None => assert!(false) // Division by zero should return None + }; +} diff --git a/test/rust/structures/point.rs b/test/rust/structures/point.rs new file mode 100644 index 000000000..34caa22ce --- /dev/null +++ b/test/rust/structures/point.rs @@ -0,0 +1,51 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect verified + +use std::ops::{Add, AddAssign}; + +#[derive(PartialEq,Clone,Copy)] +struct Point { + x: u64, + y: u64 +} + +impl Point { + pub fn new(_x: u64, _y: u64) -> Point { + Point { x: _x, y: _y } + } + pub fn get_x(self) -> u64 { + self.x + } + pub fn get_y(self) -> u64 { + self.y + } +} + +impl Add for Point { + type Output = Point; + fn add(self, other: Point) -> Point { + Point::new(self.x + other.x, self.y + other.y) + } +} + +impl AddAssign for Point { + fn add_assign(&mut self, other: Point) { + self.x += other.x; + self.y += other.y; + } +} + +fn main() { + let w = 1u64.nondet(); + let x = 2u64.nondet(); + let y = 3u64.nondet(); + let z = 4u64.nondet(); + + let a = Point::new(w, x); + let b = Point::new(y, z); + let c = a + b; + assert!(c == Point::new(w+y,x+z)); +} diff --git a/test/rust/structures/point_fail.rs b/test/rust/structures/point_fail.rs new file mode 100644 index 000000000..9a228ce66 --- /dev/null +++ b/test/rust/structures/point_fail.rs @@ -0,0 +1,51 @@ +#[macro_use] +mod smack; +use smack::*; + +// @expect error + +use std::ops::{Add, AddAssign}; + +#[derive(PartialEq,Clone,Copy)] +struct Point { + x: u64, + y: u64 +} + +impl Point { + pub fn new(_x: u64, _y: u64) -> Point { + Point { x: _x, y: _y } + } + pub fn get_x(self) -> u64 { + self.x + } + pub fn get_y(self) -> u64 { + self.y + } +} + +impl Add for Point { + type Output = Point; + fn add(self, other: Point) -> Point { + Point::new(self.x + other.x, self.y + other.y) + } +} + +impl AddAssign for Point { + fn add_assign(&mut self, other: Point) { + self.x += other.x; + self.y += other.y; + } +} + +fn main() { + let w = 1u64.nondet(); + let x = 2u64.nondet(); + let y = 3u64.nondet(); + let z = 4u64.nondet(); + + let a = Point::new(w,x); + let b = Point::new(y,z); + let c = a + b; + assert!(c != Point::new(w+y,x+z)); +} diff --git a/test/rust/timeouts/fib.rs b/test/rust/timeouts/fib.rs new file mode 100644 index 000000000..a03027636 --- /dev/null +++ b/test/rust/timeouts/fib.rs @@ -0,0 +1,19 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --unroll=10 +// @expect verified + +fn fib(x: u64) -> u64 { + match x { + 0 => 1, + 1 => 1, + _ => fib(x-1) + fib(x-2) + } +} + +fn main() { + let x = fib(6); + assert!(x == 13); +} diff --git a/test/rust/timeouts/fib_fail.rs b/test/rust/timeouts/fib_fail.rs new file mode 100644 index 000000000..9b6dee652 --- /dev/null +++ b/test/rust/timeouts/fib_fail.rs @@ -0,0 +1,19 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --unroll=10 +// @expect error + +fn fib(x: u64) -> u64 { + match x { + 0 => 1, + 1 => 1, + _ => fib(x-1) + fib(x-2) + } +} + +fn main() { + let x = fib(6); + assert!(x != 13); +} diff --git a/test/rust/timeouts/vec_resize.rs b/test/rust/timeouts/vec_resize.rs new file mode 100644 index 000000000..d91fdb001 --- /dev/null +++ b/test/rust/timeouts/vec_resize.rs @@ -0,0 +1,13 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting --unroll=3 +// @expect verified + +fn main() { + let mut v1:Vec = vec![0]; + let mut v2:Vec = vec![3]; + v1.append(&mut v2); + assert!(v1[1] == 3); +} diff --git a/test/rust/timeouts/vec_resize_fail.rs b/test/rust/timeouts/vec_resize_fail.rs new file mode 100644 index 000000000..220e805b2 --- /dev/null +++ b/test/rust/timeouts/vec_resize_fail.rs @@ -0,0 +1,13 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting --unroll=3 +// @expect error + +fn main() { + let mut v1:Vec = vec![0]; + let mut v2:Vec = vec![3]; + v1.append(&mut v2); + assert!(v1[1] != 3); +} diff --git a/test/rust/vector/config.yml b/test/rust/vector/config.yml new file mode 100644 index 000000000..f538f2a68 --- /dev/null +++ b/test/rust/vector/config.yml @@ -0,0 +1 @@ +memory: [no-reuse-impls, no-reuse] diff --git a/test/rust/vector/vec1.rs b/test/rust/vector/vec1.rs new file mode 100644 index 000000000..1f4d6a335 --- /dev/null +++ b/test/rust/vector/vec1.rs @@ -0,0 +1,20 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect verified + +fn main() { + let mut v: Vec = Vec::new(); + v.push(0); + v.push(1); + v.push(3); + assert!(v[0] == 0); + assert!(v[1] == 1); + assert!(v[2] == 3); + v[2] = v[0]+v[1]; + assert!(v[0] == 0); + assert!(v[1] == 1); + assert!(v[2] == 1); +} diff --git a/test/rust/vector/vec1_fail1.rs b/test/rust/vector/vec1_fail1.rs new file mode 100644 index 000000000..062e68426 --- /dev/null +++ b/test/rust/vector/vec1_fail1.rs @@ -0,0 +1,20 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect error + +fn main() { + let mut v: Vec = Vec::new(); + v.push(0); + v.push(1); + v.push(3); + assert!(v[0] == 0); + assert!(v[1] == 1); + assert!(v[2] == 3); + v[2] = v[0]+v[1]; + assert!(v[0] != 0); + assert!(v[1] == 1); + assert!(v[2] == 1); +} diff --git a/test/rust/vector/vec1_fail2.rs b/test/rust/vector/vec1_fail2.rs new file mode 100644 index 000000000..0d2c9c1f8 --- /dev/null +++ b/test/rust/vector/vec1_fail2.rs @@ -0,0 +1,20 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect error + +fn main() { + let mut v: Vec = Vec::new(); + v.push(0); + v.push(1); + v.push(3); + assert!(v[0] == 0); + assert!(v[1] == 1); + assert!(v[2] == 3); + v[2] = v[0]+v[1]; + assert!(v[0] == 0); + assert!(v[1] != 1); + assert!(v[2] == 1); +} diff --git a/test/rust/vector/vec1_fail3.rs b/test/rust/vector/vec1_fail3.rs new file mode 100644 index 000000000..59e2440e0 --- /dev/null +++ b/test/rust/vector/vec1_fail3.rs @@ -0,0 +1,20 @@ +#[macro_use] +mod smack; +use smack::*; + +// @flag --no-memory-splitting +// @expect error + +fn main() { + let mut v: Vec = Vec::new(); + v.push(0); + v.push(1); + v.push(3); + assert!(v[0] == 0); + assert!(v[1] == 1); + assert!(v[2] == 3); + v[2] = v[0]+v[1]; + assert!(v[0] == 0); + assert!(v[1] == 1); + assert!(v[2] != 1); +} From 62162c406861d04fcc5656edd557aefe14b426fe Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 28 Oct 2019 16:53:01 -0600 Subject: [PATCH 15/60] Inline `isExternal` Boogie encodes functions that have a body and are not inlined into quantified axioms. During this process, it adds attributes that are specific to Z3. Therefore, this commit adds the `inline` attribute to the `isExternal` function. Partially fix #500 --- lib/smack/Prelude.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/smack/Prelude.cpp b/lib/smack/Prelude.cpp index 51a98397c..c3bd83a9f 100644 --- a/lib/smack/Prelude.cpp +++ b/lib/smack/Prelude.cpp @@ -905,7 +905,8 @@ void MemDeclGen::generateAddrBoundsAndPred(std::stringstream &s) const { s << Decl::function( Naming::EXTERNAL_ADDR, makePtrVars(1), Naming::BOOL_TYPE, Expr::fn(indexedName("$slt", {Naming::PTR_TYPE, Naming::BOOL_TYPE}), - makePtrVarExpr(0), Expr::id(Naming::EXTERNS_BOTTOM))) + makePtrVarExpr(0), Expr::id(Naming::EXTERNS_BOTTOM)), + {makeInlineAttr()}) << "\n"; s << "\n"; } From c66fca0fae9233ad67448887294e93f1bc419a65 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 8 Nov 2019 09:40:06 -0700 Subject: [PATCH 16/60] Removed no memory splitting flag from Rust generics regressions This flag is not needed any more for the verification to go through as expected. --- test/rust/generics/generic_function.rs | 1 - test/rust/generics/generic_function_fail1.rs | 1 - test/rust/generics/generic_function_fail2.rs | 1 - test/rust/generics/generic_function_fail3.rs | 1 - test/rust/generics/generic_function_fail4.rs | 1 - test/rust/generics/generic_function_fail5.rs | 1 - 6 files changed, 6 deletions(-) diff --git a/test/rust/generics/generic_function.rs b/test/rust/generics/generic_function.rs index b43cf968d..0cde8c545 100644 --- a/test/rust/generics/generic_function.rs +++ b/test/rust/generics/generic_function.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect verified struct Point { diff --git a/test/rust/generics/generic_function_fail1.rs b/test/rust/generics/generic_function_fail1.rs index c0429e31d..493e3b507 100644 --- a/test/rust/generics/generic_function_fail1.rs +++ b/test/rust/generics/generic_function_fail1.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect error struct Point { diff --git a/test/rust/generics/generic_function_fail2.rs b/test/rust/generics/generic_function_fail2.rs index 4f7684400..9295c1d29 100644 --- a/test/rust/generics/generic_function_fail2.rs +++ b/test/rust/generics/generic_function_fail2.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect error struct Point { diff --git a/test/rust/generics/generic_function_fail3.rs b/test/rust/generics/generic_function_fail3.rs index 277d837f2..9a800da1e 100644 --- a/test/rust/generics/generic_function_fail3.rs +++ b/test/rust/generics/generic_function_fail3.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect error struct Point { diff --git a/test/rust/generics/generic_function_fail4.rs b/test/rust/generics/generic_function_fail4.rs index cfb4fa91a..6aad57efd 100644 --- a/test/rust/generics/generic_function_fail4.rs +++ b/test/rust/generics/generic_function_fail4.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect error struct Point { diff --git a/test/rust/generics/generic_function_fail5.rs b/test/rust/generics/generic_function_fail5.rs index 64f5b062c..7c4ec4455 100644 --- a/test/rust/generics/generic_function_fail5.rs +++ b/test/rust/generics/generic_function_fail5.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect error struct Point { From 691b231dfd6ffc00924c533164c31a6596d3b84c Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Thu, 14 Nov 2019 13:49:34 -0700 Subject: [PATCH 17/60] Fixed over-collapsing of regions when malloc is encountered In order to establish whether a pointer returned from an external function can alias program-allocated memory, we used to generate regions for return values of pointer types of all functions. We used to do that no matter how the pointers would end up being used. In the case of malloc, this would almost always lead to collapsing of regions since malloc returns a pointer of type i8, but is almost always cast into the appropriate type and then used. This fix removes this behavior and avoids collapsing of regions due to malloc. Fixes #473 --- lib/smack/Regions.cpp | 2 +- lib/smack/SmackInstGenerator.cpp | 4 ++-- test/c/basic/malloc_collapsing.c | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 test/c/basic/malloc_collapsing.c diff --git a/lib/smack/Regions.cpp b/lib/smack/Regions.cpp index c549d8bf5..e82f0260e 100644 --- a/lib/smack/Regions.cpp +++ b/lib/smack/Regions.cpp @@ -347,7 +347,7 @@ void Regions::visitCallInst(CallInst &I) { Function *F = I.getCalledFunction(); std::string name = F && F->hasName() ? F->getName().str() : ""; - if (I.getType()->isPointerTy()) + if (F && F->isDeclaration() && I.getType()->isPointerTy() && name != "malloc") idx(&I); if (name.find("__SMACK_values") != std::string::npos) { diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index 62120386b..a09efe87f 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -798,9 +798,9 @@ void SmackInstGenerator::visitCallInst(llvm::CallInst &ci) { emit(rep->call(f, ci)); } - if (f->isDeclaration() && rep->isExternal(&ci)) { + if (f->isDeclaration()) { std::string name = naming->get(*f); - if (!EXTERNAL_PROC_IGNORE.match(name)) + if (!EXTERNAL_PROC_IGNORE.match(name) && rep->isExternal(&ci)) emit(Stmt::assume(Expr::fn(Naming::EXTERNAL_ADDR, rep->expr(&ci)))); } diff --git a/test/c/basic/malloc_collapsing.c b/test/c/basic/malloc_collapsing.c new file mode 100644 index 000000000..be5ac8729 --- /dev/null +++ b/test/c/basic/malloc_collapsing.c @@ -0,0 +1,14 @@ +#include "smack.h" +#include + +// @expect verified +// @checkbpl grep "var \$M.0: \[ref\] i32;" + +int main(void) { + int *p = (int *)malloc(sizeof(int)); + *p = 2; + p = (int *)realloc(p, sizeof(int)); + *p = 1; + assert(*p != 2); + return *p; +} From aa85adab94a2933385a31787b6161cf72ee867d9 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sun, 17 Nov 2019 12:01:00 -0700 Subject: [PATCH 18/60] Upgraded to Python 3 This mostly boiled down to simple syntax updates. I also updated our installation documentation. Closes #512 --- .travis.yml | 5 +++-- bin/build.sh | 2 +- bin/smack | 2 +- bin/smack-doctor | 2 +- bin/vsmack | 4 ++-- docs/installation.md | 2 +- format/run-clang-format.py | 4 ++-- share/smack/doctor.py | 12 +++++------ share/smack/frontend.py | 18 ++++++++-------- share/smack/reach.py | 10 ++++----- share/smack/replay.py | 30 +++++++++++++------------- share/smack/svcomp/filters.py | 4 ++-- share/smack/svcomp/random_testing.py | 10 ++++----- share/smack/svcomp/toSVCOMPformat.py | 12 +++++------ share/smack/svcomp/utils.py | 28 ++++++++++++------------ share/smack/top.py | 32 +++++++++++++++------------- share/smack/utils.py | 10 ++++----- test/c/reach/regtest.py | 14 ++++++------ test/regtest.py | 9 ++++---- 19 files changed, 107 insertions(+), 103 deletions(-) diff --git a/.travis.yml b/.travis.yml index 19371a537..91ef8b88b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,8 @@ addons: packages: - git - cmake - - python-yaml - - python-psutil + - python3-yaml + - python3-psutil - unzip - libz-dev - libedit-dev @@ -66,6 +66,7 @@ install: script: - python --version + - python3 --version - $CXX --version - $CC --version - clang --version diff --git a/bin/build.sh b/bin/build.sh index 25e58384f..a84634f53 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -60,7 +60,7 @@ CONFIGURE_INSTALL_PREFIX= CMAKE_INSTALL_PREFIX= # Partial list of dependencies; the rest are added depending on the platform -DEPENDENCIES="git cmake python-yaml python-psutil unzip wget ninja-build" +DEPENDENCIES="git cmake python3-yaml python3-psutil unzip wget ninja-build" shopt -s extglob diff --git a/bin/smack b/bin/smack index bbc4e0601..e8efa74db 100755 --- a/bin/smack +++ b/bin/smack @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # This file is distributed under the MIT License. See LICENSE for details. # diff --git a/bin/smack-doctor b/bin/smack-doctor index c206adfd9..10610c495 100755 --- a/bin/smack-doctor +++ b/bin/smack-doctor @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # This file is distributed under the MIT License. See LICENSE for details. # diff --git a/bin/vsmack b/bin/vsmack index 8cbbdf037..253c3ad73 100755 --- a/bin/vsmack +++ b/bin/vsmack @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import argparse import os.path @@ -84,7 +84,7 @@ if __name__ == '__main__': raise Exception('failed to halt the box') except Exception as e: - print 'error:', e + print('error:', e) finally: pass diff --git a/docs/installation.md b/docs/installation.md index 0db8b5a0f..620e8e998 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -82,7 +82,7 @@ SMACK depends on the following projects: * [LLVM][] version [8.0.1][LLVM-8.0.1] * [Clang][] version [8.0.1][Clang-8.0.1] -* [Python][] version 2.7 or greater +* [Python][] version 3.6.8 or greater * [Ninja][] version 1.5.1 or greater * [Mono][] version 5.0.0 or greater (except on Windows) * [Z3][] or compatible SMT-format theorem prover diff --git a/format/run-clang-format.py b/format/run-clang-format.py index 3d0cca0a9..2923ee31a 100755 --- a/format/run-clang-format.py +++ b/format/run-clang-format.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """A wrapper script around clang-format, suitable for linting multiple files and to use for continuous integration. @@ -126,7 +126,7 @@ def run_clang_format_diff(args, file): # # It's not pretty, due to Python 2 & 3 compatibility. encoding_py3 = {} - if sys.version_info[0] >= 3: + if sys.version_info[0] >= 3 and sys.version_info[1] >= 6: encoding_py3['encoding'] = 'utf-8' try: diff --git a/share/smack/doctor.py b/share/smack/doctor.py index 329d26c96..ef09832a0 100755 --- a/share/smack/doctor.py +++ b/share/smack/doctor.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # This file is distributed under the MIT License. See LICENSE for details. # @@ -21,9 +21,9 @@ def check(text, condition): global count if condition: if not args.quiet: - print green("[X] " + text) + print(green("[X] " + text)) else: - print >> sys.stderr, red("[-] " + text) + print(red("[-] " + text), file=sys.stderr) count += 1 def full_path(program): @@ -88,19 +88,19 @@ def main(): count = 0 if not args.quiet: - print "Checking front-end dependencies..." + print("Checking front-end dependencies...") check_command("clang") check_command("clang++") check_command("llvm-config") check_command("llvm-link") if not args.quiet: - print "Checking back-end dependencies..." + print("Checking back-end dependencies...") check_verifier("boogie") check_verifier("corral") if not args.quiet: - print "Checking SMACK itself..." + print("Checking SMACK itself...") check_command("llvm2bpl") check_command("smack") diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 1c88add1e..046ceb943 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -1,6 +1,6 @@ import os import sys -from utils import temporary_file, try_command +from .utils import temporary_file, try_command def languages(): """A dictionary of languages per file extension.""" @@ -28,7 +28,7 @@ def frontends(): """A dictionary of front-ends per language.""" # Avoid circular import - from svcomp.utils import svcomp_frontend + from .svcomp.utils import svcomp_frontend return { 'c' : clang_frontend, @@ -72,7 +72,7 @@ def default_clang_compile_command(args, lib = False): # in order to enable optimization passes. # See: https://stackoverflow.com/a/46753969. cmd += ['-Xclang', '-disable-O0-optnone'] - cmd += map(lambda path: '-I' + path, smack_headers(args)) + cmd += ['-I' + path for path in smack_headers(args)] cmd += args.clang_options.split() cmd += ['-DMEMORY_MODEL_' + args.mem_mod.upper().replace('-','_')] if args.memory_safety: cmd += ['-DMEMORY_SAFETY'] @@ -156,7 +156,7 @@ def d_frontend(input_file, args): # note: -g and -O0 are not used here. # Right now, it works, and with these options, smack crashes. compile_command = ['ldc2', '-output-ll'] - compile_command += map(lambda path: '-I=' + path, smack_headers(args)) + compile_command += ['-I=' + path for path in smack_headers(args)] args.entry_points += ['_Dmain'] return d_compile_to_bc(input_file,compile_command,args) @@ -202,7 +202,7 @@ def json_compilation_database_frontend(input_file, args): for cc in json.load(f): if 'objects' in cc: # TODO what to do when there are multiple linkings? - bit_codes = map(lambda f: re.sub('[.]o$','.bc',f), cc['objects']) + bit_codes = [re.sub('[.]o$','.bc',f) for f in cc['objects']] try_command(['llvm-link', '-o', args.bc_file] + bit_codes) try_command(['llvm-link', '-o', args.linked_bc_file, args.bc_file] + build_libs(args)) @@ -254,7 +254,7 @@ def default_build_libs(args): libs += ['fenv.c'] compile_command = default_clang_compile_command(args, True) - for c in map(lambda c: os.path.join(smack_lib(), c), libs): + for c in [os.path.join(smack_lib(), c) for c in libs]: bc = compile_to_bc(c,compile_command,args) bitcodes.append(bc) @@ -269,7 +269,7 @@ def fortran_build_libs(args): compile_command = default_clang_compile_command(args) compile_command[0] = 'flang' - for c in map(lambda c: os.path.join(smack_lib(), c), libs): + for c in [os.path.join(smack_lib(), c) for c in libs]: bc = fortran_compile_to_bc(c,compile_command,args) bitcodes.append(bc) @@ -284,7 +284,7 @@ def cplusplus_build_libs(args): compile_command = default_clang_compile_command(args,True) compile_command[0] = 'clang++' - for c in map(lambda c: os.path.join(smack_lib(), c), libs): + for c in [os.path.join(smack_lib(), c) for c in libs]: bc = compile_to_bc(c,compile_command,args) bitcodes.append(bc) @@ -303,6 +303,6 @@ def link_bc_files(bitcodes, libs, args): try_command(['llvm-link', '-o', args.linked_bc_file, args.bc_file] + smack_libs) # import here to avoid a circular import - from top import llvm_to_bpl + from .top import llvm_to_bpl llvm_to_bpl(args) diff --git a/share/smack/reach.py b/share/smack/reach.py index 1ff4f2723..09307abe9 100755 --- a/share/smack/reach.py +++ b/share/smack/reach.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # This file is distributed under the MIT License. See LICENSE for details. # @@ -106,10 +106,10 @@ def GetCodeCoverage(verifier, bplFileName, timeLimit, unroll, contextSwitches, d result[curfile] = sorted(result[curfile], key=lambda e:e[0], reverse=False) if(smackd): - print(json.dumps(result)) + print((json.dumps(result))) else: - print '\nSMACK verifier version ' + VERSION + '\n\n' - print "Unreachable code:" + print('\nSMACK verifier version ' + VERSION + '\n\n') + print("Unreachable code:") pprint.pprint(result, width=100) def TestReachability(verifier, bplFileName, timeLimit, unroll, contextSwitches, debug, lineInfo): @@ -169,7 +169,7 @@ def main(): # remove arguments not recognized by lower scripts # not sure of a better way to do this sysArgv = sys.argv[:] - for i in reversed(range(len(sysArgv))): + for i in reversed(list(range(len(sysArgv)))): if sysArgv[i] == '--smackd': del sysArgv[i] elif sys.argv[i] == '--time-limit': diff --git a/share/smack/replay.py b/share/smack/replay.py index 3fb996920..8064eafda 100644 --- a/share/smack/replay.py +++ b/share/smack/replay.py @@ -2,7 +2,7 @@ import re import subprocess import sys -from utils import temporary_file, try_command +from .utils import temporary_file, try_command SPECIAL_NAMES = [ '__VERIFIER_assert', @@ -12,36 +12,36 @@ def replay_error_trace(verifier_output, args): if args.verifier != 'corral': - print "Replay for verifiers other than 'corral' currently unsupported; skipping replay" + print("Replay for verifiers other than 'corral' currently unsupported; skipping replay") return - print "Attempting to replay error trace." + print("Attempting to replay error trace.") missing_definitions = detect_missing_definitions(args.bc_file) if '__SMACK_code' in missing_definitions: - print "warning: inline Boogie code found; replay may fail" + print("warning: inline Boogie code found; replay may fail") arguments, return_values = extract_values(verifier_output) with open(args.replay_harness, 'w') as f: f.write(harness(arguments, return_values, missing_definitions)) - print "Generated replay harness:", args.replay_harness + print("Generated replay harness:", args.replay_harness) stubs_bc = temporary_file('stubs', '.bc', args) try_command(['clang', '-c', '-emit-llvm', '-o', stubs_bc, args.replay_harness]) try_command(['clang', '-Wl,-e,_smack_replay_main', '-o', args.replay_exe_file, args.bc_file, stubs_bc]) - print "Generated replay executable:", args.replay_exe_file + print("Generated replay executable:", args.replay_exe_file) try: if 'error reached!' in try_command(["./" + args.replay_exe_file]): - print "Error-trace replay successful." + print("Error-trace replay successful.") return True else: - print "Error-trace replay failed." + print("Error-trace replay failed.") except Exception as err: - print "Error-trace replay caught", err.message + print("Error-trace replay caught", err.message) return False @@ -67,7 +67,7 @@ def extract_values(trace): arguments = {} return_values = {} - for key, val in filter(lambda x: x, map(extract, trace.split('\n'))): + for key, val in [x for x in map(extract, trace.split('\n')) if x]: if 'smack:entry:' in key: _, _, fn = key.split(':') arguments[fn] = [] @@ -85,7 +85,7 @@ def extract_values(trace): return_values[fn].append(val) else: - print "warning: unexpected key %s" % key + print("warning: unexpected key %s" % key) return arguments, return_values @@ -128,7 +128,7 @@ def harness(arguments, return_values, missing_definitions): """ % {'fn': fn, 'vals': ", ".join(return_values[fn])}) else: - print "warning: unknown return value for %s" % fn + print("warning: unknown return value for %s" % fn) code.append("""// stub for function %(fn)s void %(fn)s() { return; @@ -136,12 +136,12 @@ def harness(arguments, return_values, missing_definitions): """ % {'fn': fn}) if len(arguments) > 1: - print "warning: multiple entrypoint argument annotations found" + print("warning: multiple entrypoint argument annotations found") elif len(arguments) < 1: - print "warning: no entrypoint argument annotations found" + print("warning: no entrypoint argument annotations found") - for fn, args in arguments.items(): + for fn, args in list(arguments.items()): code.append("""// entry point wrapper int _smack_replay_main() { %(fn)s(%(vals)s); diff --git a/share/smack/svcomp/filters.py b/share/smack/svcomp/filters.py index fcd7351ee..8e0ccda6d 100644 --- a/share/smack/svcomp/filters.py +++ b/share/smack/svcomp/filters.py @@ -213,6 +213,6 @@ def scrub_pthreads(s): if __name__ == '__main__': - print "What?" - print svcomp_filter(sys.argv[1]) + print("What?") + print(svcomp_filter(sys.argv[1])) diff --git a/share/smack/svcomp/random_testing.py b/share/smack/svcomp/random_testing.py index 169547f7f..18430c7c1 100644 --- a/share/smack/svcomp/random_testing.py +++ b/share/smack/svcomp/random_testing.py @@ -12,7 +12,7 @@ def random_test(args, result): s = fi.read() l = s.split('\n') - if not (len(l) < 20 and len(filter(lambda x: re.search(r'=\s*__VERIFIER_nondet_uint', x), l)) == 1): + if not (len(l) < 20 and len([x for x in l if re.search(r'=\s*__VERIFIER_nondet_uint', x)]) == 1): return 'abort' UMAX_INT = 2**32 - 1 @@ -47,8 +47,8 @@ def compile_and_run(f, s, n, args): rc = proc.returncode if rc: - print 'Compiling error' - print err + print('Compiling error') + print(err) return 'unknown' else: cmd = [r'./' + tmp2] @@ -59,8 +59,8 @@ def compile_and_run(f, s, n, args): if re.search(r'Assertion.*failed', err): return 'false' else: - print 'Execution error' - print err + print('Execution error') + print(err) return 'unknown' else: return 'true' diff --git a/share/smack/svcomp/toSVCOMPformat.py b/share/smack/svcomp/toSVCOMPformat.py index db3166c11..48ea39c66 100644 --- a/share/smack/svcomp/toSVCOMPformat.py +++ b/share/smack/svcomp/toSVCOMPformat.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python2 +#! /usr/bin/env python3 import xml.etree as etree import xml.etree.ElementTree as ET @@ -189,7 +189,7 @@ def smackJsonToXmlGraph(strJsonOutput, args, hasBug, status): # Add function to call stack calledFunc = str(jsonTrace["description"][len("CALL "):]).strip() if calledFunc.startswith("devirtbounce"): - print "Warning: calling function pointer dispatch procedure at line {0}".format(jsonTrace["line"]) + print("Warning: calling function pointer dispatch procedure at line {0}".format(jsonTrace["line"])) continue if isSMACKInitFunc(calledFunc): continue @@ -197,15 +197,15 @@ def smackJsonToXmlGraph(strJsonOutput, args, hasBug, status): if "RETURN from" in desc: returnedFunc = str(desc[len("RETURN from "):]).strip() if returnedFunc.startswith("devirtbounce"): - print "Warning: returning from function pointer dispatch procedure at line {0}".format(jsonTrace["line"]) + print("Warning: returning from function pointer dispatch procedure at line {0}".format(jsonTrace["line"])) continue if isSMACKInitFunc(returnedFunc): continue if returnedFunc != callStack[-1][0]: raise RuntimeError('Procedure Call/Return dismatch at line {0}. Call stack head: {1}, returning from: {2}'.format(jsonTrace["line"], callStack[-1][0], returnedFunc)) callStack.pop() - print - print + print() + print() return prettify(tree.getroot()) @@ -214,7 +214,7 @@ def smackJsonToXmlGraph(strJsonOutput, args, hasBug, status): if len(sys.argv) > 1: jsonStr = open(sys.argv[1], "r").read() - print(smackJsonToXmlGraph(jsonStr)) + print((smackJsonToXmlGraph(jsonStr))) '''print(prettify(tree.getroot())) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 2c69c5180..9b9ee9a3b 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -6,9 +6,9 @@ from shutil import copyfile import smack.top import smack.frontend -import filters -from toSVCOMPformat import smackJsonToXmlGraph -from random_testing import random_test +from . import filters +from .toSVCOMPformat import smackJsonToXmlGraph +from .random_testing import random_test def svcomp_frontend(input_file, args): """Generate Boogie code from SVCOMP-style C-language source(s).""" @@ -254,7 +254,7 @@ def verify_bpl_svcomp(args): if args.pthread and "strcpy" in bpl: heurTrace += "We are not modeling strcpy - aborting\n" if not args.quiet: - print(heurTrace + "\n") + print((heurTrace + "\n")) sys.exit(smack.top.results(args)['unknown']) # Setting good loop unroll bound based on benchmark class @@ -356,7 +356,7 @@ def verify_bpl_svcomp(args): if not args.quiet: error = smack.top.error_trace(verifier_output, args) - print error + print(error) if args.memory_safety: heurTrace += (args.prop_to_check + "has errors\n") if args.prop_to_check == 'valid-free': @@ -392,16 +392,16 @@ def verify_bpl_svcomp(args): if execution_result != 'true': heurTrace += "Oops, execution result says {0}.\n".format(execution_result) if not args.quiet: - print(heurTrace + "\n") + print((heurTrace + "\n")) sys.exit(smack.top.results(args)['unknown']) random_test_result = random_test(args, result) if random_test_result == 'false' or random_test_result == 'unknown': heurTrace += "Oops, random testing says {0}.\n".format(random_test_result) if not args.quiet: - print(heurTrace + "\n") + print((heurTrace + "\n")) sys.exit(smack.top.results(args)['unknown']) if not args.quiet: - print(heurTrace + "\n") + print((heurTrace + "\n")) if args.memory_safety: heurTrace += (args.prop_to_check + "is verified\n") if args.prop_to_check == 'valid-deref': @@ -422,7 +422,7 @@ def verify_bpl_svcomp(args): heurTrace += "Insufficient unrolls to consider 'verified'. " heurTrace += "Reporting 'timeout'.\n" if not args.quiet: - print(heurTrace + "\n") + print((heurTrace + "\n")) sys.stdout.flush() if args.memory_safety: heurTrace += (args.prop_to_check + " times out\n") @@ -444,7 +444,7 @@ def verify_bpl_svcomp(args): else: #normal inlining heurTrace += "Normal inlining returned 'unknown'. See errors above.\n" if not args.quiet: - print(heurTrace + "\n") + print((heurTrace + "\n")) if args.memory_safety and result == 'verified': heurTrace += (args.prop_to_check + " is verified\n") if args.prop_to_check == 'valid-deref': @@ -510,8 +510,8 @@ def run_binary(args): rc = proc.returncode if rc: - print 'Compiling error' - print err + print('Compiling error') + print(err) return 'unknown' else: cmd = [r'./' + tmp2] @@ -522,8 +522,8 @@ def run_binary(args): if re.search(r'Assertion.*failed', err): return 'false' else: - print 'Execution error' - print err + print('Execution error') + print(err) return 'unknown' else: return 'true' diff --git a/share/smack/top.py b/share/smack/top.py index c7d6ee3c7..764bf74e1 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -10,10 +10,10 @@ import shlex import subprocess import signal -from svcomp.utils import verify_bpl_svcomp -from utils import temporary_file, try_command, remove_temp_files -from replay import replay_error_trace -from frontend import link_bc_files, frontends, languages, extra_libs +from .svcomp.utils import verify_bpl_svcomp +from .utils import temporary_file, try_command, remove_temp_files +from .replay import replay_error_trace +from .frontend import link_bc_files, frontends, languages, extra_libs VERSION = '2.4.0' @@ -72,7 +72,7 @@ def validate_input_file(file): elif not file_extension in languages(): exit_with_error("Unexpected source file extension '%s'" % file_extension) - map(validate_input_file, files) + list(map(validate_input_file, files)) def validate_output_file(file): dir_name = os.path.dirname(os.path.abspath(file)) @@ -128,7 +128,7 @@ def arguments(): frontend_group = parser.add_argument_group('front-end options') frontend_group.add_argument('-x', '--language', metavar='LANG', - choices=frontends().keys(), default=None, + choices=list(frontends().keys()), default=None, help='Treat input files as having type LANG.') frontend_group.add_argument('-bc', '--bc-file', metavar='FILE', default=None, action=FileAction, @@ -421,13 +421,16 @@ def transform_bpl(args): old = bpl.read() bpl.seek(0) bpl.truncate() - tx = subprocess.Popen(shlex.split(args.transform_bpl), stdin=subprocess.PIPE, stdout=bpl) + tx = subprocess.Popen(shlex.split(args.transform_bpl), + stdin=subprocess.PIPE, stdout=bpl, universal_newlines=True) tx.communicate(input = old) def transform_out(args, old): out = old if args.transform_out: - tx = subprocess.Popen(shlex.split(args.transform_out), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + tx = subprocess.Popen(shlex.split(args.transform_out), + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, universal_newlines=True) out, err = tx.communicate(input = old) return out @@ -506,10 +509,10 @@ def verify_bpl(args): result = verification_result(verifier_output) if args.smackd: - print smackdOutput(verifier_output) + print(smackdOutput(verifier_output)) elif result == 'verified': - print results(args)[result] + print(results(args)[result]) else: if result == 'error' or result == 'invalid-deref' or result == 'invalid-free' or result == 'invalid-memtrack' or result == 'overflow': @@ -520,7 +523,7 @@ def verify_bpl(args): f.write(error) if not args.quiet: - print error + print(error) if args.replay: replay_error_trace(verifier_output, args) @@ -573,8 +576,7 @@ def repl(m): return re.sub('((\d+)bv\d+|(-?)0x([0-9a-fA-F]+\.[0-9a-fA-F]+)e(-?)(\d+)f(\d+)e(\d+))', repl, line.strip()) def transform(info): - return ','.join(map(reformat_assignment, filter( - lambda x: not re.search('((CALL|RETURN from)\s+(\$|__SMACK))|Done|ASSERTION', x), info.split(',')))) + return ','.join(map(reformat_assignment, [x for x in info.split(',') if not re.search('((CALL|RETURN from)\s+(\$|__SMACK))|Done|ASSERTION', x)])) def corral_error_step(step): m = re.match('([^\s]*)\s+Trace:\s+(Thread=\d+)\s+\((.*)[\)|;]', step) @@ -672,13 +674,13 @@ def main(): target_selection(args) if not args.quiet: - print "SMACK program verifier version %s" % VERSION + print("SMACK program verifier version %s" % VERSION) frontend(args) if args.no_verify: if not args.quiet: - print "SMACK generated %s" % args.bpl_file + print("SMACK generated %s" % args.bpl_file) else: verify_bpl(args) diff --git a/share/smack/utils.py b/share/smack/utils.py index d21c1f314..908b005ac 100644 --- a/share/smack/utils.py +++ b/share/smack/utils.py @@ -4,7 +4,7 @@ import subprocess import signal from threading import Timer -import top +from . import top temporary_files = [] @@ -34,10 +34,10 @@ def try_command(cmd, cwd=None, console=False, timeout=None): timer = None try: if args.debug: - print "Running %s" % " ".join(cmd) + print("Running %s" % " ".join(cmd)) proc = subprocess.Popen(cmd, cwd=cwd, preexec_fn=os.setsid, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) if timeout: timed_out = [False] @@ -49,7 +49,7 @@ def try_command(cmd, cwd=None, console=False, timeout=None): line = proc.stdout.readline() if line: output += line - print line, + print(line, end=' ') elif proc.poll() is not None: break proc.wait @@ -71,7 +71,7 @@ def try_command(cmd, cwd=None, console=False, timeout=None): return output except (RuntimeError, OSError) as err: - print >> sys.stderr, output + print(output, file=sys.stderr) sys.exit("Error invoking command:\n%s\n%s" % (" ".join(cmd), err)) finally: diff --git a/test/c/reach/regtest.py b/test/c/reach/regtest.py index fb516f534..d1b8ab39d 100755 --- a/test/c/reach/regtest.py +++ b/test/c/reach/regtest.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python2 +#! /usr/bin/env python3 import subprocess import re @@ -46,7 +46,7 @@ def runtests(): expected = ansFile.read() ansFile.close() - print "{0:>20} {1:>16}:".format(test[0], "(" + verifier + ")"), + print("{0:>20} {1:>16}:".format(test[0], "(" + verifier + ")")) # invoke smack-reach t0 = time.time() @@ -54,17 +54,17 @@ def runtests(): '--verifier=' + verifier, '--unroll=' + str(test[1]), '-o', test[0] +'.bpl', '--smackd'], - stdout=subprocess.PIPE) + stdout=subprocess.PIPE, universal_newlines=True) smackOutput = p.communicate()[0] elapsed = time.time() - t0 # check SMACK output if(json.loads(expected) == json.loads(smackOutput)): - print green('PASSED') + ' [%.2fs]' % round(elapsed, 2) + print(green('PASSED') + ' [%.2fs]' % round(elapsed, 2)) passed += 1 else: - print red('FAILED') + print(red('FAILED')) failed += 1 return passed, failed @@ -73,5 +73,5 @@ def runtests(): passed, failed = runtests() - print '\nPASSED count: ', passed - print 'FAILED count: ', failed + print('\nPASSED count: ', passed) + print('FAILED count: ', failed) diff --git a/test/regtest.py b/test/regtest.py index fd3c2a75f..d1124e21d 100755 --- a/test/regtest.py +++ b/test/regtest.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python2 +#! /usr/bin/env python3 from os import path from multiprocessing.pool import ThreadPool @@ -98,11 +98,11 @@ def metadata(file): if not m['skip']: if not 'expect' in m: - print red("WARNING: @expect MISSING IN %s" % file, None) + print(red("WARNING: @expect MISSING IN %s" % file, None)) m['expect'] = 'verified' if not m['expect'] in ['verified', 'error', 'timeout', 'unknown']: - print red("WARNING: unexpected @expect annotation '%s'" % m['expect'], None) + print(red("WARNING: unexpected @expect annotation '%s'" % m['expect'], None)) return m @@ -119,7 +119,8 @@ def process_test(cmd, test, memory, verifier, expect, checkbpl, checkout, log_fi str_result += "{0:>20} {1:>10} :".format(memory, verifier) t0 = time.time() - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + universal_newlines=True) out, err = p.communicate() elapsed = time.time() - t0 status = 0 From 6c9f8320ab2ba609305825be7f555a07df065989 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Sat, 30 Nov 2019 16:35:07 -0500 Subject: [PATCH 19/60] Run tests from any working directory. --- test/regtest.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/regtest.py b/test/regtest.py index d1124e21d..3e6a6840f 100755 --- a/test/regtest.py +++ b/test/regtest.py @@ -180,10 +180,11 @@ def get_extensions(languages): def get_tests(folder, extensions): tests = [] for ext in extensions: - tests.extend(glob.glob(path.join('./' + folder + '/',ext))) + tests_path = path.dirname(__file__) + tests.extend(glob.glob(path.join(tests_path, folder, ext))) tests.sort() return tests - + def main(): """ Main entry point for the test suite. From d55f54edb573919e924bf1f296676cb0cb1ee70d Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Mon, 9 Dec 2019 23:42:28 -0700 Subject: [PATCH 20/60] Fixed compilation warning that assert was causing Assert was causing a compilation warning since it used to expand into `__VERIFIER_assert` directly. This is not fixed by wrapping it with an if condition. Closes #515 --- share/smack/include/smack.h | 12 ++++++-- test/c/basic/select.c | 7 +++-- test/c/basic/select_fail.c | 7 +++-- test/c/ntdrivers/floppy2_true.i.cil.c | 42 +++++++++++++-------------- test/c/special/assume.c | 2 +- test/c/special/assume2.c | 2 +- test/c/special/assume_check.c | 2 +- test/c/special/assume_check2.c | 2 +- test/c/special/assume_check_fail.c | 2 +- test/c/special/assume_fail.c | 2 +- 10 files changed, 47 insertions(+), 33 deletions(-) diff --git a/share/smack/include/smack.h b/share/smack/include/smack.h index e633a01fb..e95194776 100644 --- a/share/smack/include/smack.h +++ b/share/smack/include/smack.h @@ -58,8 +58,16 @@ void __VERIFIER_assert(int); void __VERIFIER_error(void); #ifndef AVOID_NAME_CONFLICTS -#define assert(EX) __VERIFIER_assert(EX) -#define assume(EX) __VERIFIER_assume(EX) +#define assert(EX) \ + do { \ + if (!(EX)) \ + __VERIFIER_assert(0); \ + } while (0) +#define assume(EX) \ + do { \ + if (!(EX)) \ + __VERIFIER_assume(0); \ + } while (0) #endif #define S4(a, b, c, d) a b c d diff --git a/test/c/basic/select.c b/test/c/basic/select.c index 6506f095f..439fe3b9f 100644 --- a/test/c/basic/select.c +++ b/test/c/basic/select.c @@ -3,7 +3,10 @@ // @expect verified // @checkbpl grep -E ":= \(if.+then.+else.+\)" +void foo(int x) { assert(x); } + int main(void) { - int c = 2; - assert(c == 2 ? 1 : 0); + int c = __VERIFIER_nondet_int(); + assume(c == 2); + foo(c == 2 ? 1 : 0); } diff --git a/test/c/basic/select_fail.c b/test/c/basic/select_fail.c index 55cfee492..61453a8fe 100644 --- a/test/c/basic/select_fail.c +++ b/test/c/basic/select_fail.c @@ -3,7 +3,10 @@ // @expect error // @checkbpl grep -E ":= \(if.+then.+else.+\)" +void foo(int x) { assert(x); } + int main(void) { - int c = 2; - assert(c != 2 ? 1 : 0); + int c = __VERIFIER_nondet_int(); + assume(c == 2); + foo(c != 2 ? 1 : 0); } diff --git a/test/c/ntdrivers/floppy2_true.i.cil.c b/test/c/ntdrivers/floppy2_true.i.cil.c index a9268e30a..0c4227cf3 100644 --- a/test/c/ntdrivers/floppy2_true.i.cil.c +++ b/test/c/ntdrivers/floppy2_true.i.cil.c @@ -6803,7 +6803,7 @@ NTSTATUS FlQueueIrpToThread(PIRP Irp, PDISKETTE_EXTENSION DisketteExtension) { } else { { #line 949 - __VERIFIER_assert(0); + assert(0); } } { @@ -7643,7 +7643,7 @@ NTSTATUS FloppyDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) { } else { { #line 1098 - __VERIFIER_assert(0); + assert(0); } } { @@ -9322,7 +9322,7 @@ NTSTATUS FloppyDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) { } else { { #line 1534 - __VERIFIER_assert(0); + assert(0); } } { @@ -10108,7 +10108,7 @@ NTSTATUS FloppyPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) { } else { { #line 1627 - __VERIFIER_assert(0); + assert(0); } } { @@ -10291,7 +10291,7 @@ NTSTATUS FloppyPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) { } else { { #line 1673 - __VERIFIER_assert(0); + assert(0); } } { @@ -10446,7 +10446,7 @@ NTSTATUS FloppyPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) { } else { { #line 1707 - __VERIFIER_assert(0); + assert(0); } } { @@ -10593,14 +10593,14 @@ NTSTATUS FloppyPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) { if (s != 1) { { #line 1733 - __VERIFIER_assert(0); + assert(0); } } else { #line 1735 if (compRegistered != 0) { { #line 1735 - __VERIFIER_assert(0); + assert(0); } } else { #line 1737 @@ -10819,7 +10819,7 @@ NTSTATUS FloppyPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) { } else { { #line 1785 - __VERIFIER_assert(0); + assert(0); } } { @@ -10943,7 +10943,7 @@ NTSTATUS FloppyPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) { } else { { #line 1820 - __VERIFIER_assert(0); + assert(0); } } { @@ -11186,7 +11186,7 @@ NTSTATUS FloppyPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) { } else { { #line 1863 - __VERIFIER_assert(0); + assert(0); } } { @@ -11645,14 +11645,14 @@ NTSTATUS FloppyStartDevice(PDEVICE_OBJECT DeviceObject, PIRP Irp) { if (s != 1) { { #line 1904 - __VERIFIER_assert(0); + assert(0); } } else { #line 1906 if (compRegistered != 0) { { #line 1906 - __VERIFIER_assert(0); + assert(0); } } else { #line 1908 @@ -12679,7 +12679,7 @@ NTSTATUS FloppyPower(PDEVICE_OBJECT DeviceObject, PIRP Irp) { } else { { #line 2169 - __VERIFIER_assert(0); + assert(0); } } { @@ -29275,7 +29275,7 @@ NTSTATUS FloppyQueueRequest(PDISKETTE_EXTENSION DisketteExtension, PIRP Irp) { } else { { #line 6362 - __VERIFIER_assert(0); + assert(0); } } { @@ -30224,7 +30224,7 @@ int main(void) { if (status == 259L) { { #line 207 - __VERIFIER_assert(0); + assert(0); } } else { } @@ -30236,7 +30236,7 @@ int main(void) { if (status != __cil_tmp23) { { #line 209 - __VERIFIER_assert(0); + assert(0); } } else { } @@ -30870,7 +30870,7 @@ void stubMoreProcessingRequired(void) { } else { { #line 599 - __VERIFIER_assert(0); + assert(0); } } #line 602 @@ -30977,7 +30977,7 @@ NTSTATUS(__attribute__((__fastcall__)) IofCallDriver) } else { { #line 640 - __VERIFIER_assert(0); + assert(0); } } } @@ -31001,7 +31001,7 @@ void(__attribute__((__fastcall__)) IofCompleteRequest)(PIRP Irp, } else { { #line 674 - __VERIFIER_assert(0); + assert(0); } } #line 677 @@ -31153,7 +31153,7 @@ NTSTATUS KeWaitForSingleObject(PVOID Object, KWAIT_REASON WaitReason, if (s == 6) { { #line 794 - __VERIFIER_assert(0); + assert(0); } } else { } diff --git a/test/c/special/assume.c b/test/c/special/assume.c index 6e66bdbd8..883e1455a 100644 --- a/test/c/special/assume.c +++ b/test/c/special/assume.c @@ -8,5 +8,5 @@ int main(void) { // This assumption is used for verification, even though bit-precise // is not enabled, the assertion will pass. __builtin_assume((y & 1) == 0); - __VERIFIER_assert((y & 1) == 0); + assert((y & 1) == 0); } diff --git a/test/c/special/assume2.c b/test/c/special/assume2.c index e4c47314a..03b70c663 100644 --- a/test/c/special/assume2.c +++ b/test/c/special/assume2.c @@ -8,5 +8,5 @@ int main(void) { // This assumption is used for verification, even though the assumption // is false, the assertion will pass. __builtin_assume((y & 1) == 0); - __VERIFIER_assert((y & 1) == 0); + assert((y & 1) == 0); } diff --git a/test/c/special/assume_check.c b/test/c/special/assume_check.c index 54d460e86..9b8afcfa4 100644 --- a/test/c/special/assume_check.c +++ b/test/c/special/assume_check.c @@ -8,5 +8,5 @@ int main(void) { unsigned int y = 2 * (unsigned int)__VERIFIER_nondet_unsigned_short(); // This assumption is checked under bit-precise and is verified. __builtin_assume((y & 1) == 0); - __VERIFIER_assert((y & 1) == 0); + assert((y & 1) == 0); } diff --git a/test/c/special/assume_check2.c b/test/c/special/assume_check2.c index 979369b33..031b9c115 100644 --- a/test/c/special/assume_check2.c +++ b/test/c/special/assume_check2.c @@ -9,5 +9,5 @@ int main(void) { // This assumption is checked at verification time, and since bit-precise // is enabled, and y is clearly odd, the check will pass. __builtin_assume((y & 1) == 1); - __VERIFIER_assert((y & 1) == 1); + assert((y & 1) == 1); } diff --git a/test/c/special/assume_check_fail.c b/test/c/special/assume_check_fail.c index 1faa46507..3dbfacd72 100644 --- a/test/c/special/assume_check_fail.c +++ b/test/c/special/assume_check_fail.c @@ -9,5 +9,5 @@ int main(void) { // This assumption is checked at verification time, and since bit-precise // is enabled, and y is clearly odd, the assumption should be shown false. __builtin_assume((y & 1) == 0); - __VERIFIER_assert((y & 1) == 0); + assert((y & 1) == 0); } diff --git a/test/c/special/assume_fail.c b/test/c/special/assume_fail.c index b0a803faa..b775dee9c 100644 --- a/test/c/special/assume_fail.c +++ b/test/c/special/assume_fail.c @@ -8,5 +8,5 @@ int main(void) { // This assumption is not used, and since bit-precise is not enabled, // verification will fail. __builtin_assume((y & 1) == 0); - __VERIFIER_assert((y & 1) == 0); + assert((y & 1) == 0); } From e7db7eddcefaa215ac7c9fdcfe016c696ab750f6 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Tue, 10 Dec 2019 14:37:25 -0500 Subject: [PATCH 21/60] Modularizing the Boogie and Corral dependencies. --- CMakeLists.txt | 2 -- bin/build.sh | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 40f5078cc..1fc837f32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,8 +219,6 @@ INSTALL(TARGETS llvm2bpl ) INSTALL(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/bin/boogie - ${CMAKE_CURRENT_SOURCE_DIR}/bin/corral ${CMAKE_CURRENT_SOURCE_DIR}/bin/symbooglix ${CMAKE_CURRENT_SOURCE_DIR}/bin/lockpwn ${CMAKE_CURRENT_SOURCE_DIR}/bin/smack diff --git a/bin/build.sh b/bin/build.sh index a84634f53..7bb44662d 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -379,7 +379,7 @@ if [ ${INSTALL_OBJECTIVEC} -eq 1 ] ; then echo ". /usr/share/GNUstep/Makefiles/GNUstep.sh" >> ${SMACKENV} puts "Installed Objective-C" -fi +fi if [ ${INSTALL_RUST} -eq 1 ] ; then puts "Installing Rust" @@ -390,7 +390,7 @@ if [ ${INSTALL_RUST} -eq 1 ] ; then sudo ./install.sh --without=rust-docs cd .. rm -r rust-nightly-x86_64-unknown-linux-gnu rust.tar.gz - + puts "Installed Rust" fi @@ -435,6 +435,7 @@ if [ ${BUILD_BOOGIE} -eq 1 ] ; then msbuild Boogie.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${BOOGIE_DIR}/Binaries/z3.exe ln -sf ${CVC4_DIR}/cvc4 ${BOOGIE_DIR}/Binaries/cvc4.exe + ln -sf ${BOOGIE_DIR}/Binaries/boogie ${INSTALL_PREFIX}/bin/boogie puts "Built Boogie" else puts "Boogie already built" @@ -455,6 +456,7 @@ if [ ${BUILD_CORRAL} -eq 1 ] ; then msbuild cba.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${CORRAL_DIR}/bin/Release/z3.exe ln -sf ${CVC4_DIR}/cvc4 ${CORRAL_DIR}/bin/Release/cvc4.exe + ln -sf ${CORRAL_DIR}/bin/corral ${INSTALL_PREFIX}/bin/corral puts "Built Corral" else puts "Corral already built" @@ -507,8 +509,6 @@ if [ ${BUILD_SMACK} -eq 1 ] ; then sudo ninja install puts "Configuring shell environment" - echo export BOOGIE=\"mono ${BOOGIE_DIR}/Binaries/Boogie.exe\" >> ${SMACKENV} - echo export CORRAL=\"mono ${CORRAL_DIR}/bin/Release/corral.exe\" >> ${SMACKENV} echo export SYMBOOGLIX=\"mono ${SYMBOOGLIX_DIR}/src/SymbooglixDriver/bin/Release/sbx.exe\" >> ${SMACKENV} echo export LOCKPWN=\"mono ${LOCKPWN_DIR}/Binaries/lockpwn.exe\" >> ${SMACKENV} source ${SMACKENV} From 7d2a746347c72fe749c25662e4af96c6330cb3de Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Tue, 10 Dec 2019 15:25:20 -0500 Subject: [PATCH 22/60] Removing boogie and corral scripts. --- bin/boogie | 6 ------ bin/corral | 6 ------ 2 files changed, 12 deletions(-) delete mode 100755 bin/boogie delete mode 100755 bin/corral diff --git a/bin/boogie b/bin/boogie deleted file mode 100755 index 1ea15b4fb..000000000 --- a/bin/boogie +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -if [ -z "$BOOGIE" ] ; then - echo "The required BOOGIE environment variable is not set. See SMACK documentation for details." - exit 1 -fi -$BOOGIE "$@" diff --git a/bin/corral b/bin/corral deleted file mode 100755 index b26192e81..000000000 --- a/bin/corral +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -if [ -z "$CORRAL" ] ; then - echo "The required CORRAL environment variable is not set. See SMACK documentation for details." - exit 1 -fi -$CORRAL "$@" From f0cb4b36a375711ed011a08ac46071475c48cbd2 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Tue, 10 Dec 2019 17:08:03 -0500 Subject: [PATCH 23/60] Using new corral script. --- bin/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/versions b/bin/versions index f266b9df7..a1cedac00 100644 --- a/bin/versions +++ b/bin/versions @@ -3,7 +3,7 @@ Z3_SHORT_VERSION=4.8.5 Z3_FULL_VERSION=4.8.5 CVC4_VERSION=1.7 BOOGIE_COMMIT=5c829b6340 -CORRAL_COMMIT=c446f5e827 +CORRAL_COMMIT=6dc48d535f SYMBOOGLIX_COMMIT=7210e5d09b LOCKPWN_COMMIT=73eddf97bd LLVM_SHORT_VERSION=8 From 1997ca553aabec0ff8ff157a8eebdf21fa4e4dca Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Tue, 10 Dec 2019 17:11:04 -0500 Subject: [PATCH 24/60] Sudo to link Boogie and Corral scripts. --- bin/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build.sh b/bin/build.sh index 7bb44662d..c691294eb 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -435,7 +435,7 @@ if [ ${BUILD_BOOGIE} -eq 1 ] ; then msbuild Boogie.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${BOOGIE_DIR}/Binaries/z3.exe ln -sf ${CVC4_DIR}/cvc4 ${BOOGIE_DIR}/Binaries/cvc4.exe - ln -sf ${BOOGIE_DIR}/Binaries/boogie ${INSTALL_PREFIX}/bin/boogie + sudo ln -sf ${BOOGIE_DIR}/Binaries/boogie ${INSTALL_PREFIX}/bin/boogie puts "Built Boogie" else puts "Boogie already built" @@ -456,7 +456,7 @@ if [ ${BUILD_CORRAL} -eq 1 ] ; then msbuild cba.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${CORRAL_DIR}/bin/Release/z3.exe ln -sf ${CVC4_DIR}/cvc4 ${CORRAL_DIR}/bin/Release/cvc4.exe - ln -sf ${CORRAL_DIR}/bin/corral ${INSTALL_PREFIX}/bin/corral + sudo ln -sf ${CORRAL_DIR}/bin/corral ${INSTALL_PREFIX}/bin/corral puts "Built Corral" else puts "Corral already built" From abab75411b15da5489212f186b1321c01d010879 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Tue, 10 Dec 2019 19:28:35 -0500 Subject: [PATCH 25/60] Add Boogie and Corral bin to path. --- bin/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build.sh b/bin/build.sh index c691294eb..ecc7373fe 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -435,7 +435,7 @@ if [ ${BUILD_BOOGIE} -eq 1 ] ; then msbuild Boogie.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${BOOGIE_DIR}/Binaries/z3.exe ln -sf ${CVC4_DIR}/cvc4 ${BOOGIE_DIR}/Binaries/cvc4.exe - sudo ln -sf ${BOOGIE_DIR}/Binaries/boogie ${INSTALL_PREFIX}/bin/boogie + echo export PATH=\"${BOOGIE_DIR}/Binaries:\$PATH\" >> ${SMACKENV} puts "Built Boogie" else puts "Boogie already built" @@ -456,7 +456,7 @@ if [ ${BUILD_CORRAL} -eq 1 ] ; then msbuild cba.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${CORRAL_DIR}/bin/Release/z3.exe ln -sf ${CVC4_DIR}/cvc4 ${CORRAL_DIR}/bin/Release/cvc4.exe - sudo ln -sf ${CORRAL_DIR}/bin/corral ${INSTALL_PREFIX}/bin/corral + echo export PATH=\"${CORRAL_DIR}/bin:\$PATH\" >> ${SMACKENV} puts "Built Corral" else puts "Corral already built" From 4e4ddc5e0b747c17dac000d3ea9d28f53d488b03 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Tue, 10 Dec 2019 20:03:46 -0500 Subject: [PATCH 26/60] Add binaries to path independently of caching. --- bin/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build.sh b/bin/build.sh index ecc7373fe..0bd87ea95 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -435,11 +435,11 @@ if [ ${BUILD_BOOGIE} -eq 1 ] ; then msbuild Boogie.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${BOOGIE_DIR}/Binaries/z3.exe ln -sf ${CVC4_DIR}/cvc4 ${BOOGIE_DIR}/Binaries/cvc4.exe - echo export PATH=\"${BOOGIE_DIR}/Binaries:\$PATH\" >> ${SMACKENV} puts "Built Boogie" else puts "Boogie already built" fi + echo export PATH=\"${BOOGIE_DIR}/Binaries:\$PATH\" >> ${SMACKENV} fi @@ -456,11 +456,11 @@ if [ ${BUILD_CORRAL} -eq 1 ] ; then msbuild cba.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${CORRAL_DIR}/bin/Release/z3.exe ln -sf ${CVC4_DIR}/cvc4 ${CORRAL_DIR}/bin/Release/cvc4.exe - echo export PATH=\"${CORRAL_DIR}/bin:\$PATH\" >> ${SMACKENV} puts "Built Corral" else puts "Corral already built" fi + echo export PATH=\"${CORRAL_DIR}/bin:\$PATH\" >> ${SMACKENV} fi if [ ${BUILD_SYMBOOGLIX} -eq 1 ] ; then From 1e99b0589804835b86f6474d7413df67948e97c1 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Tue, 10 Dec 2019 21:16:36 -0500 Subject: [PATCH 27/60] Using corral Release build. --- bin/build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/build.sh b/bin/build.sh index 0bd87ea95..efe4281e9 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -456,6 +456,7 @@ if [ ${BUILD_CORRAL} -eq 1 ] ; then msbuild cba.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${CORRAL_DIR}/bin/Release/z3.exe ln -sf ${CVC4_DIR}/cvc4 ${CORRAL_DIR}/bin/Release/cvc4.exe + sed -i ".debug" "s/Debug/Release" ${CORRAL_DIR}/bin/corral puts "Built Corral" else puts "Corral already built" From 80f0b471a153b5827fd784a7643dd77b364dc704 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Tue, 10 Dec 2019 21:34:15 -0500 Subject: [PATCH 28/60] Linux style sed. --- bin/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build.sh b/bin/build.sh index efe4281e9..10c69018f 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -456,7 +456,7 @@ if [ ${BUILD_CORRAL} -eq 1 ] ; then msbuild cba.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${CORRAL_DIR}/bin/Release/z3.exe ln -sf ${CVC4_DIR}/cvc4 ${CORRAL_DIR}/bin/Release/cvc4.exe - sed -i ".debug" "s/Debug/Release" ${CORRAL_DIR}/bin/corral + sed -i.debug "s/Debug/Release" ${CORRAL_DIR}/bin/corral puts "Built Corral" else puts "Corral already built" From c0d29b6fa43a0bdb25967f502546a9318e600e5e Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Tue, 10 Dec 2019 21:55:24 -0500 Subject: [PATCH 29/60] Fixed Linux sed expression. --- bin/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build.sh b/bin/build.sh index 10c69018f..a1a62ef71 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -456,7 +456,7 @@ if [ ${BUILD_CORRAL} -eq 1 ] ; then msbuild cba.sln /p:Configuration=Release ln -sf ${Z3_DIR}/bin/z3 ${CORRAL_DIR}/bin/Release/z3.exe ln -sf ${CVC4_DIR}/cvc4 ${CORRAL_DIR}/bin/Release/cvc4.exe - sed -i.debug "s/Debug/Release" ${CORRAL_DIR}/bin/corral + sed -i.debug -e's/Debug/Release/' ${CORRAL_DIR}/bin/corral puts "Built Corral" else puts "Corral already built" From 1b14973126270806991c559cb35dcbf42e84b289 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Wed, 11 Dec 2019 09:20:24 -0500 Subject: [PATCH 30/60] Updated corral version. --- bin/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/versions b/bin/versions index a1cedac00..4045bd5a6 100644 --- a/bin/versions +++ b/bin/versions @@ -3,7 +3,7 @@ Z3_SHORT_VERSION=4.8.5 Z3_FULL_VERSION=4.8.5 CVC4_VERSION=1.7 BOOGIE_COMMIT=5c829b6340 -CORRAL_COMMIT=6dc48d535f +CORRAL_COMMIT=6437c41d34 SYMBOOGLIX_COMMIT=7210e5d09b LOCKPWN_COMMIT=73eddf97bd LLVM_SHORT_VERSION=8 From 686881a524fcf9a8f726e6b34b79ee123515d352 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Wed, 11 Dec 2019 12:57:08 -0500 Subject: [PATCH 31/60] Using new lockpwn script. --- CMakeLists.txt | 1 - bin/build.sh | 2 +- bin/versions | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fc837f32..19e6dded7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,7 +220,6 @@ INSTALL(TARGETS llvm2bpl INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/bin/symbooglix - ${CMAKE_CURRENT_SOURCE_DIR}/bin/lockpwn ${CMAKE_CURRENT_SOURCE_DIR}/bin/smack ${CMAKE_CURRENT_SOURCE_DIR}/bin/smack-doctor ${CMAKE_CURRENT_SOURCE_DIR}/bin/smack-svcomp-wrapper.sh diff --git a/bin/build.sh b/bin/build.sh index a1a62ef71..e713f15b3 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -498,6 +498,7 @@ if [ ${BUILD_LOCKPWN} -eq 1 ] ; then else puts "Lockpwn already built" fi + echo export PATH=\"${LOCKPWN_DIR}/Binaries:\$PATH\" >> ${SMACKENV} fi if [ ${BUILD_SMACK} -eq 1 ] ; then @@ -511,7 +512,6 @@ if [ ${BUILD_SMACK} -eq 1 ] ; then puts "Configuring shell environment" echo export SYMBOOGLIX=\"mono ${SYMBOOGLIX_DIR}/src/SymbooglixDriver/bin/Release/sbx.exe\" >> ${SMACKENV} - echo export LOCKPWN=\"mono ${LOCKPWN_DIR}/Binaries/lockpwn.exe\" >> ${SMACKENV} source ${SMACKENV} puts "The required environment variables have been set in ${SMACKENV}" puts "You should source ${SMACKENV} in your .bashrc" diff --git a/bin/versions b/bin/versions index 4045bd5a6..7480e6394 100644 --- a/bin/versions +++ b/bin/versions @@ -5,7 +5,7 @@ CVC4_VERSION=1.7 BOOGIE_COMMIT=5c829b6340 CORRAL_COMMIT=6437c41d34 SYMBOOGLIX_COMMIT=7210e5d09b -LOCKPWN_COMMIT=73eddf97bd +LOCKPWN_COMMIT=12ba58f1ec LLVM_SHORT_VERSION=8 LLVM_FULL_VERSION=8.0.1 RUST_VERSION=2019-07-16 From d357dcf15d8c341d2228c2000fef6f101047b83e Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Wed, 11 Dec 2019 16:34:55 -0500 Subject: [PATCH 32/60] Using new symbooglix script. --- CMakeLists.txt | 1 - bin/build.sh | 3 ++- bin/versions | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 19e6dded7..ca5b653c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,7 +219,6 @@ INSTALL(TARGETS llvm2bpl ) INSTALL(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/bin/symbooglix ${CMAKE_CURRENT_SOURCE_DIR}/bin/smack ${CMAKE_CURRENT_SOURCE_DIR}/bin/smack-doctor ${CMAKE_CURRENT_SOURCE_DIR}/bin/smack-svcomp-wrapper.sh diff --git a/bin/build.sh b/bin/build.sh index e713f15b3..58ee890c2 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -478,10 +478,12 @@ if [ ${BUILD_SYMBOOGLIX} -eq 1 ] ; then xbuild Symbooglix.sln /p:Configuration=Release ln -s ${Z3_DIR}/bin/z3 ${SYMBOOGLIX_DIR}/src/SymbooglixDriver/bin/Release/z3.exe ln -s ${Z3_DIR}/bin/z3 ${SYMBOOGLIX_DIR}/src/Symbooglix/bin/Release/z3.exe + sed -i.debug -e's/Debug/Release/' ${SYMBOOGLIX_DIR}/bin/symbooglix puts "Built Symbooglix" else puts "Symbooglix already built" fi + echo export PATH=\"${SYMBOOGLIX_DIR}/bin:\$PATH\" >> ${SMACKENV} fi if [ ${BUILD_LOCKPWN} -eq 1 ] ; then @@ -511,7 +513,6 @@ if [ ${BUILD_SMACK} -eq 1 ] ; then sudo ninja install puts "Configuring shell environment" - echo export SYMBOOGLIX=\"mono ${SYMBOOGLIX_DIR}/src/SymbooglixDriver/bin/Release/sbx.exe\" >> ${SMACKENV} source ${SMACKENV} puts "The required environment variables have been set in ${SMACKENV}" puts "You should source ${SMACKENV} in your .bashrc" diff --git a/bin/versions b/bin/versions index 7480e6394..7436fd763 100644 --- a/bin/versions +++ b/bin/versions @@ -4,7 +4,7 @@ Z3_FULL_VERSION=4.8.5 CVC4_VERSION=1.7 BOOGIE_COMMIT=5c829b6340 CORRAL_COMMIT=6437c41d34 -SYMBOOGLIX_COMMIT=7210e5d09b +SYMBOOGLIX_COMMIT=ccb2e7f2b3 LOCKPWN_COMMIT=12ba58f1ec LLVM_SHORT_VERSION=8 LLVM_FULL_VERSION=8.0.1 From 2229e75c13b2465300316b0bf651c17a0de3fbef Mon Sep 17 00:00:00 2001 From: ncchong Date: Thu, 12 Dec 2019 09:04:43 -0500 Subject: [PATCH 33/60] Use #define to switch types in pthread.c --- share/smack/frontend.py | 1 + share/smack/lib/pthread.c | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 046ceb943..def79535e 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -78,6 +78,7 @@ def default_clang_compile_command(args, lib = False): if args.memory_safety: cmd += ['-DMEMORY_SAFETY'] if args.integer_overflow: cmd += (['-fsanitize=signed-integer-overflow,shift'] if not lib else ['-DSIGNED_INTEGER_OVERFLOW_CHECK']) if args.float: cmd += ['-DFLOAT_ENABLED'] + if args.bit_precise: cmd += ['-DBIT_PRECISE'] if sys.stdout.isatty(): cmd += ['-fcolor-diagnostics'] return cmd diff --git a/share/smack/lib/pthread.c b/share/smack/lib/pthread.c index 3f87e68a2..4918d9d13 100644 --- a/share/smack/lib/pthread.c +++ b/share/smack/lib/pthread.c @@ -4,10 +4,16 @@ #include "pthread.h" #include "smack.h" +#if BIT_PRECISE +#define TID_TYPE "bv32" +#else +#define TID_TYPE "int" +#endif + void __SMACK_init_func_corral_primitives() { // Declare these, so bpl parsing doesn't complain - __SMACK_top_decl("procedure corral_getThreadID() returns (x:int);"); - __SMACK_top_decl("procedure corral_getChildThreadID() returns (x:int);"); + __SMACK_top_decl("procedure corral_getThreadID() returns (x:"TID_TYPE");"); + __SMACK_top_decl("procedure corral_getChildThreadID() returns (x:"TID_TYPE");"); __SMACK_top_decl("procedure corral_atomic_begin();"); __SMACK_top_decl("procedure corral_atomic_end();"); } @@ -15,14 +21,14 @@ void __SMACK_init_func_corral_primitives() { void __SMACK_init_func_thread() { // Array and possible statuses for tracking pthreads __SMACK_top_decl("//dim0=tid, dim1= idx 0 gets status, 1 gets return value"); - __SMACK_top_decl("var $pthreadStatus: [int][int]int;"); + __SMACK_top_decl("var $pthreadStatus: ["TID_TYPE"][int]int;"); __SMACK_top_decl("const unique $pthread_uninitialized: int;"); __SMACK_top_decl("const unique $pthread_initialized: int;"); __SMACK_top_decl("const unique $pthread_waiting: int;"); __SMACK_top_decl("const unique $pthread_running: int;"); __SMACK_top_decl("const unique $pthread_stopped: int;"); // Initialize this array so all threads begin as uninitialized - __SMACK_code("assume (forall i:int :: $pthreadStatus[i][0] == " + __SMACK_code("assume (forall i:"TID_TYPE" :: $pthreadStatus[i][0] == " "$pthread_uninitialized);"); } From f8cfc91e215d2920096b0d74c543a0c34c4c06b9 Mon Sep 17 00:00:00 2001 From: Nathan Chong Date: Thu, 12 Dec 2019 15:01:42 -0500 Subject: [PATCH 34/60] Cleaner: use boogie type alias for tidtype --- share/smack/lib/pthread.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/share/smack/lib/pthread.c b/share/smack/lib/pthread.c index 4918d9d13..a748c4827 100644 --- a/share/smack/lib/pthread.c +++ b/share/smack/lib/pthread.c @@ -4,16 +4,18 @@ #include "pthread.h" #include "smack.h" -#if BIT_PRECISE -#define TID_TYPE "bv32" +void __SMACK_init_tidtype() { +#ifdef BIT_PRECISE + __SMACK_top_decl("type $tidtype = bv32;"); #else -#define TID_TYPE "int" + __SMACK_top_decl("type $tidtype = i32;"); #endif +} void __SMACK_init_func_corral_primitives() { // Declare these, so bpl parsing doesn't complain - __SMACK_top_decl("procedure corral_getThreadID() returns (x:"TID_TYPE");"); - __SMACK_top_decl("procedure corral_getChildThreadID() returns (x:"TID_TYPE");"); + __SMACK_top_decl("procedure corral_getThreadID() returns (x:$tidtype);"); + __SMACK_top_decl("procedure corral_getChildThreadID() returns (x:$tidtype);"); __SMACK_top_decl("procedure corral_atomic_begin();"); __SMACK_top_decl("procedure corral_atomic_end();"); } @@ -21,14 +23,14 @@ void __SMACK_init_func_corral_primitives() { void __SMACK_init_func_thread() { // Array and possible statuses for tracking pthreads __SMACK_top_decl("//dim0=tid, dim1= idx 0 gets status, 1 gets return value"); - __SMACK_top_decl("var $pthreadStatus: ["TID_TYPE"][int]int;"); + __SMACK_top_decl("var $pthreadStatus: [$tidtype][int]int;"); __SMACK_top_decl("const unique $pthread_uninitialized: int;"); __SMACK_top_decl("const unique $pthread_initialized: int;"); __SMACK_top_decl("const unique $pthread_waiting: int;"); __SMACK_top_decl("const unique $pthread_running: int;"); __SMACK_top_decl("const unique $pthread_stopped: int;"); // Initialize this array so all threads begin as uninitialized - __SMACK_code("assume (forall i:"TID_TYPE" :: $pthreadStatus[i][0] == " + __SMACK_code("assume (forall i:$tidtype :: $pthreadStatus[i][0] == " "$pthread_uninitialized);"); } From 98436b6cae45d73bf6efe4ef2237c654558cceb6 Mon Sep 17 00:00:00 2001 From: Nathan Chong Date: Thu, 12 Dec 2019 15:23:50 -0500 Subject: [PATCH 35/60] wip: minimal pthread declarations for current work --- share/smack/include/bits/pthreadtypes.h | 4 ++++ share/smack/include/pthread.h | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/share/smack/include/bits/pthreadtypes.h b/share/smack/include/bits/pthreadtypes.h index 151cecc72..816e2cef7 100644 --- a/share/smack/include/bits/pthreadtypes.h +++ b/share/smack/include/bits/pthreadtypes.h @@ -40,4 +40,8 @@ typedef struct { typedef int pthread_condattr_t; +typedef int pthread_once_t; + +typedef int pthread_key_t + #endif diff --git a/share/smack/include/pthread.h b/share/smack/include/pthread.h index 9c095aeb0..6bcf01554 100644 --- a/share/smack/include/pthread.h +++ b/share/smack/include/pthread.h @@ -38,12 +38,16 @@ void pthread_exit(void *retval); int pthread_mutexattr_init(pthread_mutexattr_t *attr); +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); + int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); int pthread_mutex_lock(pthread_mutex_t *__mutex); +int pthread_mutex_trylock(pthread_mutex_t *mutex); + int pthread_mutex_unlock(pthread_mutex_t *__mutex); int pthread_mutex_destroy(pthread_mutex_t *__mutex); @@ -73,4 +77,14 @@ void __call_wrapper(pthread_t *__newthread, void *(*__start_routine)(void *), int pthread_create(pthread_t *__newthread, __const pthread_attr_t *__attr, void *(*__start_routine)(void *), void *__arg); +int pthread_detach(pthread_t thread); + +int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)); + +int pthread_attr_init(pthread_attr_t *attr); + +int pthread_attr_setstacksize(pthread_attr_t *attr, unsigned int stacksize); + +int pthread_attr_destroy(pthread_attr_t *attr); + #endif // PTHREAD_H From f3cf8089f8abd34349d3b8b68b49212b9c51d39a Mon Sep 17 00:00:00 2001 From: Nathan Chong Date: Mon, 16 Dec 2019 09:41:30 -0500 Subject: [PATCH 36/60] Fix syntax error in pthread typedef --- share/smack/include/bits/pthreadtypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/smack/include/bits/pthreadtypes.h b/share/smack/include/bits/pthreadtypes.h index 816e2cef7..91f7573c8 100644 --- a/share/smack/include/bits/pthreadtypes.h +++ b/share/smack/include/bits/pthreadtypes.h @@ -42,6 +42,6 @@ typedef int pthread_condattr_t; typedef int pthread_once_t; -typedef int pthread_key_t +typedef int pthread_key_t; #endif From 46ba1a8ec2c72c07f2a55223fee05dca8b57514d Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 16 Dec 2019 16:35:53 -0700 Subject: [PATCH 37/60] Fixed type errors in the svcomp scripts when using Python3 --- share/smack/svcomp/toSVCOMPformat.py | 2 +- share/smack/svcomp/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/smack/svcomp/toSVCOMPformat.py b/share/smack/svcomp/toSVCOMPformat.py index 48ea39c66..d9fe441d2 100644 --- a/share/smack/svcomp/toSVCOMPformat.py +++ b/share/smack/svcomp/toSVCOMPformat.py @@ -118,7 +118,7 @@ def buildEmptyXmlGraph(args, hasBug): programfile = os.path.abspath(args.orig_files[0]) addKey(graph, "programfile", programfile) with open(programfile, 'r') as pgf: - addKey(graph, "programhash", hashlib.sha256(pgf.read()).hexdigest()) + addKey(graph, "programhash", hashlib.sha256(pgf.read().encode('utf-8')).hexdigest()) addKey(graph, "architecture", re.search(r'-m(32|64)', args.clang_options).group(1) + 'bit') addKey(graph, "creationtime", datetime.datetime.now().replace(microsecond=0).isoformat()) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 9b9ee9a3b..370c5d764 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -479,7 +479,7 @@ def write_error_file(args, status, verifier_output): error = smack.top.error_trace(verifier_output, args) if error is not None: with open(args.error_file, 'w') as f: - f.write(error) + f.write(error.decode('utf-8')) def run_binary(args): #process the file to make it runnable From 00b611f1c65fee6d8ae206a70b327391d8a8c06b Mon Sep 17 00:00:00 2001 From: Nathan Chong Date: Tue, 17 Dec 2019 10:13:23 -0500 Subject: [PATCH 38/60] Check for NULL retval in pthread_join Fixes #528 --- share/smack/lib/pthread.c | 9 ++++++--- test/c/pthread/join_null_retval.c | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 test/c/pthread/join_null_retval.c diff --git a/share/smack/lib/pthread.c b/share/smack/lib/pthread.c index a748c4827..63026694f 100644 --- a/share/smack/lib/pthread.c +++ b/share/smack/lib/pthread.c @@ -69,10 +69,13 @@ int pthread_join(pthread_t __th, void **__thread_return) { // Get the thread's return value void *tmp_thread_return_pointer = (void *)__VERIFIER_nondet_long(); __SMACK_code("@ := $pthreadStatus[@][1];", tmp_thread_return_pointer, __th); - *__thread_return = tmp_thread_return_pointer; - // Print return pointer value to SMACK traces - void *actual_thread_return_pointer = *__thread_return; + if (__thread_return) { + *__thread_return = tmp_thread_return_pointer; + + // Print return pointer value to SMACK traces + void *actual_thread_return_pointer = *__thread_return; + } return 0; } diff --git a/test/c/pthread/join_null_retval.c b/test/c/pthread/join_null_retval.c new file mode 100644 index 000000000..950e76a52 --- /dev/null +++ b/test/c/pthread/join_null_retval.c @@ -0,0 +1,15 @@ +#include "smack.h" +#include +#include + +// @expect verified +// @flag --memory-safety + +void *t1(void *arg) { return NULL; } + +int main(void) { + pthread_t tid1; + pthread_create(&tid1, 0, t1, 0); + pthread_join(tid1, NULL); + return 0; +} From 05ee8b999d439740a6b104b166ec2150793f4c03 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Tue, 17 Dec 2019 17:34:38 -0500 Subject: [PATCH 39/60] Updated installation instructions. --- docs/installation.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 620e8e998..e30e5725d 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -169,17 +169,17 @@ prefix, add the additional flag: ```` substituting the string `PREFIX` for the desired location. -Actually running SMACK relies on the environment variables `BOOGIE` and -`CORRAL` targeting the `Boogie.exe` and `corral.exe` executables, for instance -residing in paths prefixed by `XXX` and `YYY`: -````Shell -export BOOGIE="mono /XXX/Boogie/Binaries/Boogie.exe" -export CORRAL="mono /YYY/Corral/bin/Release/corral.exe" +Actually running SMACK relies on `boogie` and `corral` being in the executable +path. For instance, if you have built Boogie and Corral from source at paths +at `$BOOGIE_SOURCE` and `$CORRAL_SOURCE`: +````bash +export PATH="$BOOGIE_SOURCE/Binaries:$PATH" +export PATH="$CORRAL_SOURCE/bin:$PATH" ```` Source the preceding lines in your shell's `.profile`, and ensure they invoke Boogie/Corral correctly. For example, running -````Shell -BOOGIE +````console +$ boogie ```` should result in ```` From c5d77fa14c0fea3081e336e7455899a501903841 Mon Sep 17 00:00:00 2001 From: zvonimir Date: Wed, 18 Dec 2019 19:22:55 -0800 Subject: [PATCH 40/60] Removed tool wrapper files that are not needed any more --- bin/lockpwn | 6 ------ bin/symbooglix | 6 ------ 2 files changed, 12 deletions(-) delete mode 100755 bin/lockpwn delete mode 100755 bin/symbooglix diff --git a/bin/lockpwn b/bin/lockpwn deleted file mode 100755 index c8cdfec33..000000000 --- a/bin/lockpwn +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -if [ -z "$LOCKPWN" ] ; then - echo "The required LOCKPWN environment variable is not set. See SMACK documentation for details." - exit 1 -fi -$LOCKPWN "$@" diff --git a/bin/symbooglix b/bin/symbooglix deleted file mode 100755 index 79c20a3cb..000000000 --- a/bin/symbooglix +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -if [ -z "$SYMBOOGLIX" ] ; then - echo "The required SYMBOOGLIX environment variable is not set. See SMACK documentation for details." - exit 1 -fi -$SYMBOOGLIX "$@" From b50064983e4b43e4e7c85ac3e426fb05ed14a7ea Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sat, 28 Dec 2019 12:25:05 -0700 Subject: [PATCH 41/60] Migrated Travis CI from travis-ci.org to travis-ci.com --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0367ec47d..912394b6d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -| **master** | [![Build Status](https://travis-ci.org/smackers/smack.svg?branch=master)](https://travis-ci.org/smackers/smack) | **develop** | [![Build Status](https://travis-ci.org/smackers/smack.svg?branch=develop)](https://travis-ci.org/smackers/smack) | +| **master** | [![Build Status](https://travis-ci.com/smackers/smack.svg?branch=master)](https://travis-ci.com/smackers/smack) | **develop** | [![Build Status](https://travis-ci.com/smackers/smack.svg?branch=develop)](https://travis-ci.com/smackers/smack) | | --- | --- | --- | --- | SMACK Logo From c306854e457be94de748575d5c5d99dcbd2998b1 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Mon, 30 Dec 2019 14:24:46 -0500 Subject: [PATCH 42/60] Appeasing OSX linker on Debug builds. * fixes #530. --- CMakeLists.txt | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca5b653c0..a3e855cce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,8 @@ if (NOT WIN32 OR MSYS OR CYGWIN) OUTPUT_STRIP_TRAILING_WHITESPACE ) + # TODO: explain why these are required. + # TODO: use string(APPEND ...) rather than string(REPLACE ...) string(REPLACE "-DNDEBUG" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") string(REPLACE "-Wno-maybe-uninitialized" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") string(REPLACE "-fuse-ld=gold" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") @@ -26,9 +28,27 @@ if (NOT WIN32 OR MSYS OR CYGWIN) string(REPLACE "-Wl," "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") string(REPLACE "-gsplit-dwarf" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") string(REGEX REPLACE "-O[0-9]" "" CMAKE_CXX_FLAGS "${LLVM_CXXFLAGS}") + + # TODO: append these one at a time; give rationale. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti -Wno-undefined-var-template") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0") + + # Apparently avoids a problem with inconsistent visibility settings from LLVM: + # + # > ld: warning: direct access in function 'llvm::_' + # > from file '/usr/local/opt/llvm@8/lib/_' + # > to global weak symbol 'llvm::_' + # > from file 'libsmackTranslator.a(_.cpp.o)' + # > means the weak symbol cannot be overridden at runtime. + # > This was likely caused by different translation units being compiled + # > with different visibility settings. + # + # Solution found on Stack Overflow: + # https://stackoverflow.com/questions/8685045/xcode-with-boost-linkerid-warning-about-visibility-settings + string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fvisibility=hidden") + + # TODO: explain why these are required. + string(APPEND CMAKE_CXX_FLAGS_DEBUG " -O0") + string(APPEND CMAKE_C_FLAGS_DEBUG " -O0") execute_process( COMMAND ${LLVM_CONFIG_EXECUTABLE} --libs From 7ae429b51c895577edb55d617924b75aa17c3060 Mon Sep 17 00:00:00 2001 From: Michael Emmi Date: Mon, 30 Dec 2019 14:27:41 -0500 Subject: [PATCH 43/60] Removed irrelevant comment. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a3e855cce..b5ba31e7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,6 @@ if (NOT WIN32 OR MSYS OR CYGWIN) ) # TODO: explain why these are required. - # TODO: use string(APPEND ...) rather than string(REPLACE ...) string(REPLACE "-DNDEBUG" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") string(REPLACE "-Wno-maybe-uninitialized" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") string(REPLACE "-fuse-ld=gold" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") From 5b478dd0838100c5216a2155a24d95c9e06ba68c Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Wed, 1 Jan 2020 13:06:54 -0700 Subject: [PATCH 44/60] Updated Travis CI to Ubuntu 18.04 (bionic) Fixed Travis CI configuration validation warnings along the way. Also added a package dependency for mono that fixes nondeterministic Travis CI failures. --- .travis.yml | 12 ++++++------ bin/build.sh | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 91ef8b88b..ccd9dc3cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: generic -dist: xenial -sudo: required +os: linux +dist: bionic compiler: clang addons: @@ -24,7 +24,7 @@ cache: env: global: - COMPILER_NAME=clang COMPILER=clang++ CXX=clang++ CC=clang - matrix: + jobs: - TRAVIS_ENV="--exhaustive --folder=c/basic" - TRAVIS_ENV="--exhaustive --folder=c/data" - TRAVIS_ENV="--exhaustive --folder=c/ntdrivers-simplified" @@ -47,15 +47,15 @@ env: before_install: - sudo rm -rf /usr/local/clang-7.0.0 - - sudo add-apt-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" - wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + - sudo add-apt-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF - sudo apt-get install -y apt-transport-https - - echo "deb https://download.mono-project.com/repo/ubuntu stable-xenial main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list + - echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list - sudo apt-get update install: - - sudo apt-get install -y clang-8 clang-format-8 llvm-8-dev mono-complete ninja-build + - sudo apt-get install -y clang-8 clang-format-8 llvm-8-dev mono-complete ca-certificates-mono ninja-build - sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-8 20 - sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-8 20 - sudo update-alternatives --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-8 20 diff --git a/bin/build.sh b/bin/build.sh index 58ee890c2..b85a2c56c 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -184,23 +184,23 @@ puts "Detected distribution: $distro" case "$distro" in linux-opensuse*) Z3_DOWNLOAD_LINK="https://github.com/Z3Prover/z3/releases/download/Z3-${Z3_SHORT_VERSION}/z3-${Z3_FULL_VERSION}-x64-debian-8.10.zip" - DEPENDENCIES+=" llvm-clang llvm-devel gcc-c++ mono-complete make" + DEPENDENCIES+=" llvm-clang llvm-devel gcc-c++ mono-complete ca-certificates-mono make" DEPENDENCIES+=" ncurses-devel zlib-devel" ;; linux-@(ubuntu|neon)-14*) Z3_DOWNLOAD_LINK="https://github.com/Z3Prover/z3/releases/download/Z3-${Z3_SHORT_VERSION}/z3-${Z3_FULL_VERSION}-x64-ubuntu-14.04.zip" - DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev mono-complete libz-dev libedit-dev" + DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev mono-complete ca-certificates-mono libz-dev libedit-dev" ;; linux-@(ubuntu|neon)-16*) Z3_DOWNLOAD_LINK="https://github.com/Z3Prover/z3/releases/download/Z3-${Z3_SHORT_VERSION}/z3-${Z3_FULL_VERSION}-x64-ubuntu-16.04.zip" - DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev mono-complete libz-dev libedit-dev" + DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev mono-complete ca-certificates-mono libz-dev libedit-dev" ;; linux-@(ubuntu|neon)-18*) Z3_DOWNLOAD_LINK="https://github.com/Z3Prover/z3/releases/download/Z3-${Z3_SHORT_VERSION}/z3-${Z3_FULL_VERSION}-x64-ubuntu-16.04.zip" - DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev mono-complete libz-dev libedit-dev" + DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev mono-complete ca-certificates-mono libz-dev libedit-dev" ;; linux-ubuntu-12*) From e818109de11a18478dbcb84ac6c53420d67cc2f2 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Thu, 6 Feb 2020 11:52:31 -0700 Subject: [PATCH 45/60] Added regressions for issue #187 --- test/c/basic/sign_cast.c | 13 +++++++++++++ test/c/basic/sign_cast_fail.c | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 test/c/basic/sign_cast.c create mode 100644 test/c/basic/sign_cast_fail.c diff --git a/test/c/basic/sign_cast.c b/test/c/basic/sign_cast.c new file mode 100644 index 000000000..b4bcc168e --- /dev/null +++ b/test/c/basic/sign_cast.c @@ -0,0 +1,13 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + unsigned x = __VERIFIER_nondet_unsigned(); + + // -n's two's complement is UNINT_MAX - (n - 1) + assume(x < UINT_MAX - 1); + assert(x < ((unsigned)-2)); + return 0; +} diff --git a/test/c/basic/sign_cast_fail.c b/test/c/basic/sign_cast_fail.c new file mode 100644 index 000000000..bce1a8c40 --- /dev/null +++ b/test/c/basic/sign_cast_fail.c @@ -0,0 +1,13 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + unsigned x = __VERIFIER_nondet_unsigned(); + + // -n's two's complement is UNINT_MAX - (n - 1) + assume(x < UINT_MAX - 1); + assert(x < ((unsigned)-3)); + return 0; +} From 7b9d5d7b3acdd8d778aedffad3715617bf3edcdf Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Thu, 6 Feb 2020 12:20:27 -0700 Subject: [PATCH 46/60] Added regressions for issue #47 --- test/c/bits/pack_struct.c | 24 ++++++++++++++++++++++++ test/c/bits/pack_struct_fail.c | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 test/c/bits/pack_struct.c create mode 100644 test/c/bits/pack_struct_fail.c diff --git a/test/c/bits/pack_struct.c b/test/c/bits/pack_struct.c new file mode 100644 index 000000000..5905eb805 --- /dev/null +++ b/test/c/bits/pack_struct.c @@ -0,0 +1,24 @@ +#include "smack.h" +#include + +// @expect verified + +struct S { + int x; + int y; +}; + +// Clang packs each argument as a 64-bit integer, +// which introduces false alarms without +// the `--bit-precise` flag +bool eq(struct S p1, struct S p2) { return p1.y == p2.y; } + +int main(void) { + struct S p; + struct S q; + + p = q; + assert(eq(p, q)); + + return 0; +} diff --git a/test/c/bits/pack_struct_fail.c b/test/c/bits/pack_struct_fail.c new file mode 100644 index 000000000..0be2ac0aa --- /dev/null +++ b/test/c/bits/pack_struct_fail.c @@ -0,0 +1,24 @@ +#include "smack.h" +#include + +// @expect error + +struct S { + int x; + int y; +}; + +// Clang packs each argument as a 64-bit integer, +// which introduces false alarms without +// the `--bit-precise` flag +bool eq(struct S p1, struct S p2) { return p1.y == p2.y; } + +int main(void) { + struct S p; + struct S q; + + p = q; + assert(!eq(p, q)); + + return 0; +} From a8e96136b48f80e8ffc89fc7e86cb2b0749b91ba Mon Sep 17 00:00:00 2001 From: Zvonimir Rakamaric Date: Wed, 12 Feb 2020 20:08:26 -0700 Subject: [PATCH 47/60] Added missing pthread header functions and types I think this now completes the pthreads header. Closes #505 --- share/smack/include/bits/pthreadtypes.h | 8 +- .../include/bits/types/struct_timespec.h | 11 ++ share/smack/include/pthread.h | 136 ++++++++++-------- share/smack/include/smack.h | 4 + share/smack/lib/pthread.c | 6 - share/smack/lib/smack.c | 8 ++ 6 files changed, 102 insertions(+), 71 deletions(-) create mode 100644 share/smack/include/bits/types/struct_timespec.h diff --git a/share/smack/include/bits/pthreadtypes.h b/share/smack/include/bits/pthreadtypes.h index 91f7573c8..50c542a44 100644 --- a/share/smack/include/bits/pthreadtypes.h +++ b/share/smack/include/bits/pthreadtypes.h @@ -39,9 +39,13 @@ typedef struct { } pthread_cond_t; typedef int pthread_condattr_t; - typedef int pthread_once_t; - typedef int pthread_key_t; +typedef int pthread_rwlock_t; +typedef int pthread_rwlockattr_t; + +struct sched_param { + int dummy; +}; #endif diff --git a/share/smack/include/bits/types/struct_timespec.h b/share/smack/include/bits/types/struct_timespec.h new file mode 100644 index 000000000..f11b7491c --- /dev/null +++ b/share/smack/include/bits/types/struct_timespec.h @@ -0,0 +1,11 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// +#ifndef STRUCT_TIMESPEC_H +#define STRUCT_TIMESPEC_H + +struct timespec { + int dummy; +}; + +#endif diff --git a/share/smack/include/pthread.h b/share/smack/include/pthread.h index 6bcf01554..aa195ae00 100644 --- a/share/smack/include/pthread.h +++ b/share/smack/include/pthread.h @@ -5,6 +5,8 @@ #define PTHREAD_H #include "bits/pthreadtypes.h" +#include "bits/types/struct_timespec.h" +#include // model mutex: // 0 = unlocked, @@ -18,73 +20,81 @@ #define PTHREAD_MUTEX_INITIALIZER \ { UNLOCKED, INITIALIZED } -// Declare corral primitive procedures -//__SMACK_INIT(corral_primitives); - -// Initialize thread status tracking variables (OS level behavior) -//__SMACK_INIT(thread); - -void __VERIFIER_atomic_begin(); - -void __VERIFIER_atomic_end(); - -pthread_t pthread_self(void); - +int pthread_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)); +int pthread_attr_destroy(pthread_attr_t *attr); +int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate); +int pthread_attr_getinheritsched(pthread_attr_t *attr, int *inheritsched); +int pthread_attr_getschedparam(pthread_attr_t *attr, struct sched_param *param); +int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy); +int pthread_attr_getscope(pthread_attr_t *attr, int *scope); +int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr); +int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize); +int pthread_attr_init(pthread_attr_t *attr); +int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); +int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched); +int pthread_attr_setschedparam(pthread_attr_t *attr, + const struct sched_param *param); +int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); +int pthread_attr_setscope(pthread_attr_t *attr, int scope); +int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr); +int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); +int pthread_cancel(pthread_t thread); +void pthread_cleanup_pop(int execute); +void pthread_cleanup_push(void (*routine)(void *), void *routine_arg); +int pthread_create(pthread_t *__newthread, __const pthread_attr_t *__attr, + void *(*__start_routine)(void *), void *__arg); +int pthread_cond_broadcast(pthread_cond_t *cond); +int pthread_cond_destroy(pthread_cond_t *cond); +int pthread_cond_init(pthread_cond_t *__cond, pthread_condattr_t *__condattr); +int pthread_cond_signal(pthread_cond_t *cond); +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime); +int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *mutex); +int pthread_condattr_destroy(pthread_condattr_t *attr); +int pthread_condattr_init(pthread_condattr_t *attr); +int pthread_detach(pthread_t thread); int pthread_equal(pthread_t t1, pthread_t t2); - -int pthread_join(pthread_t __th, void **__thread_return); - void pthread_exit(void *retval); - -int pthread_mutexattr_init(pthread_mutexattr_t *attr); - -int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); - -int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); - +void *pthread_getspecific(pthread_key_t key); +int pthread_join(pthread_t thread, void **retval); +int pthread_key_create(pthread_key_t *key, void (*routine)(void *)); +int pthread_key_delete(pthread_key_t key); +int pthread_kill(pthread_t thread, int sig); +int pthread_mutex_destroy(pthread_mutex_t *mutex); int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); - -int pthread_mutex_lock(pthread_mutex_t *__mutex); - +int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); - -int pthread_mutex_unlock(pthread_mutex_t *__mutex); - -int pthread_mutex_destroy(pthread_mutex_t *__mutex); - -int pthread_cond_init(pthread_cond_t *__cond, pthread_condattr_t *__condattr); - -int pthread_cond_wait(pthread_cond_t *__cond, pthread_mutex_t *__mutex); - -int pthread_cond_signal(pthread_cond_t *__cond); - -// NOTE: How to handle broadcast? Technically, as is, all threads have -// the opportunity to read __cond->cond before one of the other threads -// switch this value back to 0... I guess this is sufficient, but -// will this require a high number of context switches for a true -// broadcast to happen? -// -// I thought about using cond->cond = 2 to signal broadcast, but then -// how to know which thread to have switch it back to 0? - -int pthread_cond_broadcast(pthread_cond_t *__cond); - -int pthread_cond_destroy(pthread_cond_t *__cond); - -void __call_wrapper(pthread_t *__newthread, void *(*__start_routine)(void *), - void *__arg); - -int pthread_create(pthread_t *__newthread, __const pthread_attr_t *__attr, - void *(*__start_routine)(void *), void *__arg); - -int pthread_detach(pthread_t thread); - +int pthread_mutex_unlock(pthread_mutex_t *mutex); +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, + int *prioceiling); +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, + int *protocol); +int pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type); +int pthread_mutexattr_init(pthread_mutexattr_t *attr); +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, + int prioceiling); +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol); +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)); - -int pthread_attr_init(pthread_attr_t *attr); - -int pthread_attr_setstacksize(pthread_attr_t *attr, unsigned int stacksize); - -int pthread_attr_destroy(pthread_attr_t *attr); +int pthread_rwlock_destroy(pthread_rwlock_t *lock); +int pthread_rwlock_init(pthread_rwlock_t *rwlock, + const pthread_rwlockattr_t *attr); +int pthread_rwlock_rdlock(pthread_rwlock_t *lock); +int pthread_rwlock_tryrdlock(pthread_rwlock_t *lock); +int pthread_rwlock_trywrlock(pthread_rwlock_t *lock); +int pthread_rwlock_unlock(pthread_rwlock_t *lock); +int pthread_rwlock_wrlock(pthread_rwlock_t *lock); +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr); +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, + int *pshared); +int pthread_rwlockattr_init(pthread_rwlockattr_t *attr); +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared); +pthread_t pthread_self(void); +int pthread_setcancelstate(int state, int *oldstate); +int pthread_setcanceltype(int type, int *oldtype); +int pthread_setspecific(pthread_key_t key, const void *value_ptr); +void pthread_testcancel(void); #endif // PTHREAD_H diff --git a/share/smack/include/smack.h b/share/smack/include/smack.h index e95194776..30fa3d297 100644 --- a/share/smack/include/smack.h +++ b/share/smack/include/smack.h @@ -168,6 +168,10 @@ void *__VERIFIER_nondet_pointer(void); void __SMACK_decls(void); +// Concurrency helper functions +void __VERIFIER_atomic_begin(); +void __VERIFIER_atomic_end(); + #ifdef __cplusplus } #endif diff --git a/share/smack/lib/pthread.c b/share/smack/lib/pthread.c index 63026694f..f15608683 100644 --- a/share/smack/lib/pthread.c +++ b/share/smack/lib/pthread.c @@ -16,8 +16,6 @@ void __SMACK_init_func_corral_primitives() { // Declare these, so bpl parsing doesn't complain __SMACK_top_decl("procedure corral_getThreadID() returns (x:$tidtype);"); __SMACK_top_decl("procedure corral_getChildThreadID() returns (x:$tidtype);"); - __SMACK_top_decl("procedure corral_atomic_begin();"); - __SMACK_top_decl("procedure corral_atomic_end();"); } void __SMACK_init_func_thread() { @@ -34,10 +32,6 @@ void __SMACK_init_func_thread() { "$pthread_uninitialized);"); } -void __VERIFIER_atomic_begin() { __SMACK_code("call corral_atomic_begin();"); } - -void __VERIFIER_atomic_end() { __SMACK_code("call corral_atomic_end();"); } - pthread_t pthread_self(void) { int tmp_tid = __VERIFIER_nondet_int(); __SMACK_code("call @ := corral_getThreadID();", tmp_tid); diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index 23692291a..058d138dd 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -268,6 +268,10 @@ void __SMACK_decls(void) { D("var $exn: bool;"); D("var $exnv: int;"); + // Concurrency primitives + D("procedure corral_atomic_begin();"); + D("procedure corral_atomic_end();"); + D("procedure $alloc(n: ref) returns (p: ref)\n" "{\n" " call p := $$alloc(n);\n" @@ -524,3 +528,7 @@ void __SMACK_init_func_memory_model(void) { __SMACK_code("$allocatedCounter := 0;"); #endif } + +void __VERIFIER_atomic_begin() { __SMACK_code("call corral_atomic_begin();"); } + +void __VERIFIER_atomic_end() { __SMACK_code("call corral_atomic_end();"); } From c7486fe97a5937a40ce64c6d6275af36572b8dca Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Wed, 12 Feb 2020 20:14:12 -0700 Subject: [PATCH 48/60] Removed setting compiler to clang in Travis script We install clang manually from LLVM-distributed packages.. Closes #536 --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ccd9dc3cd..a8f2f259d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: generic os: linux dist: bionic -compiler: clang addons: apt: @@ -46,7 +45,6 @@ env: - TRAVIS_ENV="--exhaustive --folder=rust/vector --languages=rust" before_install: - - sudo rm -rf /usr/local/clang-7.0.0 - wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo add-apt-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF From 2263100f05522498abf90ece0c76e2720b2d096d Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Sun, 16 Feb 2020 22:35:46 -0700 Subject: [PATCH 49/60] Removed the `--bit-precise` flag in test/rust/basic/arith.rs This flag is no longer needed because of PR #478 Fixes #498 --- test/rust/basic/arith.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/rust/basic/arith.rs b/test/rust/basic/arith.rs index 269e7163b..94075f3fc 100644 --- a/test/rust/basic/arith.rs +++ b/test/rust/basic/arith.rs @@ -3,7 +3,6 @@ mod smack; use smack::*; // @expect verified -// @flag --bit-precise fn main() { // unsigned From dd4a89979fae878d22909312676aa0ecd9ac73df Mon Sep 17 00:00:00 2001 From: Nathan Chong Date: Tue, 17 Dec 2019 10:43:09 -0500 Subject: [PATCH 50/60] Tests for #525 --- test/c/pthread/regression_525_calloc.c | 34 ++++++++++++++++ test/c/pthread/regression_525_malloc.c | 43 ++++++++++++++++++++ test/c/pthread/regression_525_stackalloc.c | 46 ++++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 test/c/pthread/regression_525_calloc.c create mode 100644 test/c/pthread/regression_525_malloc.c create mode 100644 test/c/pthread/regression_525_stackalloc.c diff --git a/test/c/pthread/regression_525_calloc.c b/test/c/pthread/regression_525_calloc.c new file mode 100644 index 000000000..aa9c294fb --- /dev/null +++ b/test/c/pthread/regression_525_calloc.c @@ -0,0 +1,34 @@ +#include "smack.h" +#include +#include +#include +#include + +// @expect verified +// https://github.com/smackers/smack/issues/525 + +_Atomic(atomic_int *) x; + +void *t1(void *arg) { + atomic_store_explicit(&x, (_Atomic(int) *)calloc(1, sizeof(int)), + memory_order_relaxed); + if (atomic_load_explicit(&x, memory_order_relaxed)) { + atomic_store_explicit(x, 42, memory_order_relaxed); + } + return NULL; +} + +int main(void) { + atomic_init(&x, NULL); + pthread_t tid1; + pthread_create(&tid1, 0, t1, 0); + if (atomic_load_explicit(&x, memory_order_relaxed)) { + int r1 = atomic_load_explicit(x, memory_order_relaxed); + assert(r1 == 0 || r1 == 42); + } + pthread_join(tid1, 0); + if (x) { + free(x); + } + return 0; +} diff --git a/test/c/pthread/regression_525_malloc.c b/test/c/pthread/regression_525_malloc.c new file mode 100644 index 000000000..debc853c3 --- /dev/null +++ b/test/c/pthread/regression_525_malloc.c @@ -0,0 +1,43 @@ +#include "smack.h" +#include +#include + +// @expect verified +// https://github.com/smackers/smack/issues/525 + +pthread_t tid1; +pthread_t tid2; + +void *t1(void *arg) { + int *x = malloc(sizeof(*x)); + if (!x) + pthread_exit(NULL); + *x = 1; + pthread_exit(x); + return NULL; +} + +void *t2(void *arg) { + int *y = malloc(sizeof(*y)); + if (!y) + pthread_exit(NULL); + *y = 2; + pthread_exit(y); + return NULL; +} + +int main(void) { + pthread_create(&tid1, 0, t1, 0); + pthread_create(&tid2, 0, t2, 0); + int *tid1_retval; + int *tid2_retval; + pthread_join(tid1, (void **)&tid1_retval); + pthread_join(tid2, (void **)&tid2_retval); + assert(!tid1_retval || *tid1_retval == 1); + assert(!tid2_retval || *tid2_retval == 2); + if (tid1_retval) + free(tid1_retval); + if (tid2_retval) + free(tid2_retval); + return 0; +} diff --git a/test/c/pthread/regression_525_stackalloc.c b/test/c/pthread/regression_525_stackalloc.c new file mode 100644 index 000000000..56dc9127a --- /dev/null +++ b/test/c/pthread/regression_525_stackalloc.c @@ -0,0 +1,46 @@ +#include "smack.h" +#include +#include + +// @expect verified +// https://github.com/smackers/smack/issues/525 + +struct atomic_var { + void *value; +}; + +struct S { + struct atomic_var x; + struct atomic_var y; +}; + +struct T { + int z; +}; + +void atomic_store_ptr(struct atomic_var *var, void *p) { + __atomic_store_n(&var->value, p, __ATOMIC_SEQ_CST); +} + +void *foo(void *arg) { + struct T t = *(struct T *)arg; + return NULL; +} + +int main(void) { + struct S s; + struct T t; + pthread_t thread; + + (*(size_t *)(&s.x.value)) = 0; + s.y.value = NULL; + + if (pthread_create(&thread, NULL, foo, (void *)&t)) + return 1; + + uint64_t v = (size_t)s.x.value; + atomic_store_ptr(&s.y, NULL); + uint64_t w = (size_t)s.x.value; + assert(v == w); + return 0; +} From 33cfdad892ba183a6b8dbaca5a8819a96688a718 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Tue, 18 Feb 2020 13:33:38 -0700 Subject: [PATCH 51/60] Made memory allocation atomic Closes #525 --- share/smack/lib/smack.c | 8 ++++++++ share/smack/lib/stdlib.c | 8 +++++++- test/c/{pthread => failing}/regression_525_calloc.c | 0 test/c/pthread/regression_525_stackalloc.c | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) rename test/c/{pthread => failing}/regression_525_calloc.c (100%) diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index 058d138dd..b9c7f1d2e 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -274,7 +274,9 @@ void __SMACK_decls(void) { D("procedure $alloc(n: ref) returns (p: ref)\n" "{\n" + " call corral_atomic_begin();\n" " call p := $$alloc(n);\n" + " call corral_atomic_end();\n" "}\n"); #if MEMORY_SAFETY @@ -301,10 +303,12 @@ void __SMACK_decls(void) { D("procedure $malloc(n: ref) returns (p: ref)\n" "modifies $allocatedCounter;\n" "{\n" + " call corral_atomic_begin();\n" " if ($ne.ref.bool(n, $0.ref)) {\n" " $allocatedCounter := $allocatedCounter + 1;\n" " }\n" " call p := $$alloc(n);\n" + " call corral_atomic_end();\n" "}\n"); #if MEMORY_MODEL_NO_REUSE_IMPLS @@ -343,6 +347,7 @@ void __SMACK_decls(void) { D("procedure $free(p: ref)\n" "modifies $Alloc, $allocatedCounter;\n" "{\n" + " call corral_atomic_begin();\n" " if ($ne.ref.bool(p, $0.ref)) {\n" " assert {:valid_free} $eq.ref.bool($base(p), p);\n" " assert {:valid_free} $Alloc[p];\n" @@ -350,6 +355,7 @@ void __SMACK_decls(void) { " $Alloc[p] := false;\n" " $allocatedCounter := $allocatedCounter - 1;\n" " }\n" + " call corral_atomic_end();\n" "}\n"); #elif MEMORY_MODEL_REUSE // can reuse previously-allocated and freed addresses @@ -445,7 +451,9 @@ void __SMACK_decls(void) { #else D("procedure $malloc(n: ref) returns (p: ref)\n" "{\n" + " call corral_atomic_begin();\n" " call p := $$alloc(n);\n" + " call corral_atomic_end();\n" "}\n"); #if MEMORY_MODEL_NO_REUSE_IMPLS diff --git a/share/smack/lib/stdlib.c b/share/smack/lib/stdlib.c index 76f8be73a..eb98f7e3f 100644 --- a/share/smack/lib/stdlib.c +++ b/share/smack/lib/stdlib.c @@ -19,15 +19,21 @@ void *calloc(size_t num, size_t size) { if (__VERIFIER_nondet_int()) { ret = 0; } else { + __VERIFIER_atomic_begin(); ret = malloc(num * size); memset(ret, 0, num * size); + __VERIFIER_atomic_end(); } return ret; } void *realloc(void *ptr, size_t size) { + void *ret; + __VERIFIER_atomic_begin(); free(ptr); - return malloc(size); + ret = malloc(size); + __VERIFIER_atomic_end(); + return ret; } long int strtol(const char *nptr, char **endptr, int base) { diff --git a/test/c/pthread/regression_525_calloc.c b/test/c/failing/regression_525_calloc.c similarity index 100% rename from test/c/pthread/regression_525_calloc.c rename to test/c/failing/regression_525_calloc.c diff --git a/test/c/pthread/regression_525_stackalloc.c b/test/c/pthread/regression_525_stackalloc.c index 56dc9127a..309bf4f5c 100644 --- a/test/c/pthread/regression_525_stackalloc.c +++ b/test/c/pthread/regression_525_stackalloc.c @@ -1,5 +1,6 @@ #include "smack.h" #include +#include #include // @expect verified From 186711f8efae944528dc4e89d56440eace5919a4 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Tue, 18 Feb 2020 15:08:46 -0700 Subject: [PATCH 52/60] Renamed a regression so that it better matches its content --- .../{null_dereference_fail.c => ununallocated_dereference_fail.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/c/memory-safety/{null_dereference_fail.c => ununallocated_dereference_fail.c} (100%) diff --git a/test/c/memory-safety/null_dereference_fail.c b/test/c/memory-safety/ununallocated_dereference_fail.c similarity index 100% rename from test/c/memory-safety/null_dereference_fail.c rename to test/c/memory-safety/ununallocated_dereference_fail.c From 410aeec09383e2fb43a56661b1c6556799312a3a Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Tue, 18 Feb 2020 15:31:08 -0700 Subject: [PATCH 53/60] Added regressions for calloc We had no such regressions in our set. --- test/c/memory-safety/calloc.c | 15 +++++++++++++++ test/c/memory-safety/calloc_fail.c | 14 ++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 test/c/memory-safety/calloc.c create mode 100644 test/c/memory-safety/calloc_fail.c diff --git a/test/c/memory-safety/calloc.c b/test/c/memory-safety/calloc.c new file mode 100644 index 000000000..1758e4f08 --- /dev/null +++ b/test/c/memory-safety/calloc.c @@ -0,0 +1,15 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + int *arr = (int *)calloc(5, sizeof(int)); + int idx = __VERIFIER_nondet_int(); + assume(0 <= idx && idx < 5); + if (arr == NULL) + return 1; + assert(arr[idx] == 0); + free(arr); + return 0; +} diff --git a/test/c/memory-safety/calloc_fail.c b/test/c/memory-safety/calloc_fail.c new file mode 100644 index 000000000..2a5bdb359 --- /dev/null +++ b/test/c/memory-safety/calloc_fail.c @@ -0,0 +1,14 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + int *arr = (int *)calloc(5, sizeof(int)); + int idx = __VERIFIER_nondet_int(); + if (arr == NULL) + return 1; + assert(arr[idx] == 0); + free(arr); + return 0; +} From 10ed1710174006a5232edcafda9d616174622203 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Wed, 19 Feb 2020 08:59:57 -0700 Subject: [PATCH 54/60] Fixed the outcome of a failing regression This was just a minor mistake on my end. --- test/c/memory-safety/calloc_fail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/c/memory-safety/calloc_fail.c b/test/c/memory-safety/calloc_fail.c index 2a5bdb359..e6cdb6176 100644 --- a/test/c/memory-safety/calloc_fail.c +++ b/test/c/memory-safety/calloc_fail.c @@ -1,7 +1,7 @@ #include "smack.h" #include -// @expect verified +// @expect error int main(void) { int *arr = (int *)calloc(5, sizeof(int)); From 72abba5b1a8d07cb8843f2a93b9fe6ba2d5f1b13 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Wed, 19 Feb 2020 09:04:49 -0700 Subject: [PATCH 55/60] Added comments to clarify galloc procedure --- share/smack/lib/smack.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index b9c7f1d2e..c984ad493 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -316,6 +316,8 @@ void __SMACK_decls(void) { D("function $Size(ref) returns (ref);"); D("var $CurrAddr:ref;\n"); + // LLVM does not allocated globals explicitly. Hence, we do it in our prelude + // before the program starts using the $galloc procedure. D("procedure $galloc(base_addr: ref, size: ref)\n" "{\n" " assume $Size(base_addr) == size;\n" @@ -362,6 +364,8 @@ void __SMACK_decls(void) { D("var $Alloc: [ref] bool;"); D("var $Size: [ref] ref;\n"); + // LLVM does not allocated globals explicitly. Hence, we do it in our prelude + // before the program starts using the $galloc procedure. D("procedure $galloc(base_addr: ref, size: ref);\n" "modifies $Alloc, $Size;\n" "ensures $Size[base_addr] == size;\n" @@ -408,6 +412,8 @@ void __SMACK_decls(void) { D("function $Size(ref) returns (ref);"); D("var $CurrAddr:ref;\n"); + // LLVM does not allocated globals explicitly. Hence, we do it in our prelude + // before the program starts using the $galloc procedure. D("procedure $galloc(base_addr: ref, size: ref);\n" "modifies $Alloc;\n" "ensures $Size(base_addr) == size;\n" From d833a6fa7019ab8a1c463cec2d3cf1a12dabbc50 Mon Sep 17 00:00:00 2001 From: Shaobo <5892703+shaobo-he@users.noreply.github.com> Date: Thu, 9 Apr 2020 11:40:24 -0600 Subject: [PATCH 56/60] Replace LLVM's DSA with sea-dsa This commit replaces the old LLVM's DSA with the newer sea-dsa: * Adds sea-dsa as a submodule * Switches from LLVM's DSA to sea-dsa * Uses sea-dsa's CompleteCallGraph pass to assist indirect call resolving * Renames MemCpyd to MemOpd * Handles the case where values don't have cells * Makes sure that singletons are not in allocated nodes Closes #549 --- .gitmodules | 4 + .travis.yml | 1 + CMakeLists.txt | 115 +- bin/build.sh | 6 +- docs/installation.md | 15 +- include/assistDS/ArgCast.h | 35 - include/assistDS/DSNodeEquivs.h | 68 - include/assistDS/DataStructureCallGraph.h | 107 - include/assistDS/FuncSimplify.h | 30 - include/assistDS/FuncSpec.h | 35 - include/assistDS/GEPExprArgs.h | 34 - include/assistDS/IndCloner.h | 34 - include/assistDS/Int2PtrCmp.h | 36 - include/assistDS/LoadArgs.h | 36 - include/assistDS/SimplifyGEP.h | 32 - include/assistDS/SimplifyLoad.h | 29 - include/assistDS/StructReturnToPointer.h | 30 - include/assistDS/TypeChecks.h | 116 - include/assistDS/TypeChecksOpt.h | 52 - include/dsa/AddressTakenAnalysis.h | 47 - include/dsa/AllocatorIdentification.h | 56 - include/dsa/CallTargets.h | 74 - include/dsa/DSCallGraph.h | 210 -- include/dsa/DSGraph.h | 714 ------ include/dsa/DSGraphTraits.h | 120 - include/dsa/DSMonitor.h | 29 - include/dsa/DSNode.h | 540 ---- include/dsa/DSSupport.h | 380 --- include/dsa/DataStructure.h | 403 --- include/dsa/EntryPointAnalysis.h | 53 - include/dsa/TypeSafety.h | 90 - include/dsa/keyiterator.h | 249 -- include/dsa/stl_util.h | 54 - include/dsa/super_set.h | 43 - include/dsa/svset.h | 240 -- include/smack/DSAWrapper.h | 67 +- include/smack/Regions.h | 14 +- include/{assistDS => utils}/Devirt.h | 11 +- include/{assistDS => utils}/LICENSE.TXT | 0 include/{assistDS => utils}/MergeGEP.h | 0 .../SimplifyExtractValue.h | 0 .../{assistDS => utils}/SimplifyInsertValue.h | 0 lib/AssistDS/ArgCast.cpp | 218 -- lib/AssistDS/ArgSimplify.cpp | 173 -- lib/AssistDS/DSNodeEquivs.cpp | 289 --- lib/AssistDS/DataStructureCallGraph.cpp | 125 - lib/AssistDS/DynCount.cpp | 140 - lib/AssistDS/FuncSimplify.cpp | 72 - lib/AssistDS/FuncSpec.cpp | 121 - lib/AssistDS/GEPExprArgs.cpp | 187 -- lib/AssistDS/IndCloner.cpp | 167 -- lib/AssistDS/Int2PtrCmp.cpp | 184 -- lib/AssistDS/LICENSE.TXT | 65 - lib/AssistDS/LoadArgs.cpp | 215 -- lib/AssistDS/SVADevirt.cpp | 255 -- lib/AssistDS/SimplifyGEP.cpp | 221 -- lib/AssistDS/SimplifyLoad.cpp | 86 - lib/AssistDS/StructReturnToPointer.cpp | 184 -- lib/AssistDS/TypeChecks.cpp | 2243 ----------------- lib/AssistDS/TypeChecksOpt.cpp | 259 -- lib/DSA/AddressTakenAnalysis.cpp | 89 - lib/DSA/AllocatorIdentification.cpp | 198 -- lib/DSA/Basic.cpp | 89 - lib/DSA/BottomUpClosure.cpp | 731 ------ lib/DSA/CallTargets.cpp | 173 -- lib/DSA/CompleteBottomUp.cpp | 220 -- lib/DSA/DSCallGraph.cpp | 273 -- lib/DSA/DSGraph.cpp | 1687 ------------- lib/DSA/DSMonitor.cpp | 212 -- lib/DSA/DSTest.cpp | 709 ------ lib/DSA/DataStructure.cpp | 1558 ------------ lib/DSA/DataStructureStats.cpp | 245 -- lib/DSA/EntryPointAnalysis.cpp | 102 - lib/DSA/EquivClassGraphs.cpp | 257 -- lib/DSA/GraphChecker.cpp | 207 -- lib/DSA/LICENSE | 65 - lib/DSA/Local.cpp | 1592 ------------ lib/DSA/Printer.cpp | 415 --- lib/DSA/README | 15 - lib/DSA/SanityCheck.cpp | 140 - lib/DSA/StdLibPass.cpp | 911 ------- lib/DSA/TopDownClosure.cpp | 425 ---- lib/DSA/TypeSafety.cpp | 553 ---- lib/smack/DSAWrapper.cpp | 310 ++- lib/smack/Regions.cpp | 176 +- lib/smack/SmackInstGenerator.cpp | 1 - lib/{AssistDS => utils}/Devirt.cpp | 18 +- {include/dsa => lib/utils}/LICENSE.TXT | 0 lib/{AssistDS => utils}/MergeGEP.cpp | 2 +- .../SimplifyExtractValue.cpp | 2 +- .../SimplifyInsertValue.cpp | 2 +- sea-dsa | 1 + share/smack/top.py | 3 + test/c/{basic => failing}/atomic_cas.c | 0 test/c/{basic => failing}/atomic_cas_fail.c | 0 test/c/{basic => failing}/extern_mem_fail.c | 1 + test/c/{pthread => failing}/join_return.c | 1 + .../c/{pthread => failing}/join_return_fail.c | 0 test/c/failing/null_dereference_fail.c | 11 + .../global_and_heap_alloc_fail_no_free.c | 4 +- test/rust/functions/closure.rs | 1 - test/rust/functions/closure_fail.rs | 1 - test/rust/loops/gauss_sum_nondet.rs | 2 +- test/rust/loops/gauss_sum_nondet_fail.rs | 2 +- test/rust/loops/iterator.rs | 2 +- test/rust/loops/iterator_fail.rs | 2 +- test/rust/timeouts/vec_resize.rs | 2 +- test/rust/timeouts/vec_resize_fail.rs | 2 +- test/rust/vector/vec1.rs | 1 - test/rust/vector/vec1_fail1.rs | 1 - test/rust/vector/vec1_fail2.rs | 1 - test/rust/vector/vec1_fail3.rs | 1 - tools/llvm2bpl/llvm2bpl.cpp | 12 +- 113 files changed, 326 insertions(+), 20515 deletions(-) create mode 100644 .gitmodules delete mode 100644 include/assistDS/ArgCast.h delete mode 100644 include/assistDS/DSNodeEquivs.h delete mode 100644 include/assistDS/DataStructureCallGraph.h delete mode 100644 include/assistDS/FuncSimplify.h delete mode 100644 include/assistDS/FuncSpec.h delete mode 100644 include/assistDS/GEPExprArgs.h delete mode 100644 include/assistDS/IndCloner.h delete mode 100644 include/assistDS/Int2PtrCmp.h delete mode 100644 include/assistDS/LoadArgs.h delete mode 100644 include/assistDS/SimplifyGEP.h delete mode 100644 include/assistDS/SimplifyLoad.h delete mode 100644 include/assistDS/StructReturnToPointer.h delete mode 100644 include/assistDS/TypeChecks.h delete mode 100644 include/assistDS/TypeChecksOpt.h delete mode 100644 include/dsa/AddressTakenAnalysis.h delete mode 100644 include/dsa/AllocatorIdentification.h delete mode 100644 include/dsa/CallTargets.h delete mode 100644 include/dsa/DSCallGraph.h delete mode 100644 include/dsa/DSGraph.h delete mode 100644 include/dsa/DSGraphTraits.h delete mode 100644 include/dsa/DSMonitor.h delete mode 100644 include/dsa/DSNode.h delete mode 100644 include/dsa/DSSupport.h delete mode 100644 include/dsa/DataStructure.h delete mode 100644 include/dsa/EntryPointAnalysis.h delete mode 100644 include/dsa/TypeSafety.h delete mode 100644 include/dsa/keyiterator.h delete mode 100644 include/dsa/stl_util.h delete mode 100644 include/dsa/super_set.h delete mode 100644 include/dsa/svset.h rename include/{assistDS => utils}/Devirt.h (92%) rename include/{assistDS => utils}/LICENSE.TXT (100%) rename include/{assistDS => utils}/MergeGEP.h (100%) rename include/{assistDS => utils}/SimplifyExtractValue.h (100%) rename include/{assistDS => utils}/SimplifyInsertValue.h (100%) delete mode 100644 lib/AssistDS/ArgCast.cpp delete mode 100644 lib/AssistDS/ArgSimplify.cpp delete mode 100644 lib/AssistDS/DSNodeEquivs.cpp delete mode 100644 lib/AssistDS/DataStructureCallGraph.cpp delete mode 100644 lib/AssistDS/DynCount.cpp delete mode 100644 lib/AssistDS/FuncSimplify.cpp delete mode 100644 lib/AssistDS/FuncSpec.cpp delete mode 100644 lib/AssistDS/GEPExprArgs.cpp delete mode 100644 lib/AssistDS/IndCloner.cpp delete mode 100644 lib/AssistDS/Int2PtrCmp.cpp delete mode 100644 lib/AssistDS/LICENSE.TXT delete mode 100644 lib/AssistDS/LoadArgs.cpp delete mode 100644 lib/AssistDS/SVADevirt.cpp delete mode 100644 lib/AssistDS/SimplifyGEP.cpp delete mode 100644 lib/AssistDS/SimplifyLoad.cpp delete mode 100644 lib/AssistDS/StructReturnToPointer.cpp delete mode 100644 lib/AssistDS/TypeChecks.cpp delete mode 100644 lib/AssistDS/TypeChecksOpt.cpp delete mode 100644 lib/DSA/AddressTakenAnalysis.cpp delete mode 100644 lib/DSA/AllocatorIdentification.cpp delete mode 100644 lib/DSA/Basic.cpp delete mode 100644 lib/DSA/BottomUpClosure.cpp delete mode 100644 lib/DSA/CallTargets.cpp delete mode 100644 lib/DSA/CompleteBottomUp.cpp delete mode 100644 lib/DSA/DSCallGraph.cpp delete mode 100644 lib/DSA/DSGraph.cpp delete mode 100644 lib/DSA/DSMonitor.cpp delete mode 100644 lib/DSA/DSTest.cpp delete mode 100644 lib/DSA/DataStructure.cpp delete mode 100644 lib/DSA/DataStructureStats.cpp delete mode 100644 lib/DSA/EntryPointAnalysis.cpp delete mode 100644 lib/DSA/EquivClassGraphs.cpp delete mode 100644 lib/DSA/GraphChecker.cpp delete mode 100644 lib/DSA/LICENSE delete mode 100644 lib/DSA/Local.cpp delete mode 100644 lib/DSA/Printer.cpp delete mode 100644 lib/DSA/README delete mode 100644 lib/DSA/SanityCheck.cpp delete mode 100644 lib/DSA/StdLibPass.cpp delete mode 100644 lib/DSA/TopDownClosure.cpp delete mode 100644 lib/DSA/TypeSafety.cpp rename lib/{AssistDS => utils}/Devirt.cpp (96%) rename {include/dsa => lib/utils}/LICENSE.TXT (100%) rename lib/{AssistDS => utils}/MergeGEP.cpp (99%) rename lib/{AssistDS => utils}/SimplifyExtractValue.cpp (99%) rename lib/{AssistDS => utils}/SimplifyInsertValue.cpp (98%) create mode 160000 sea-dsa rename test/c/{basic => failing}/atomic_cas.c (100%) rename test/c/{basic => failing}/atomic_cas_fail.c (100%) rename test/c/{basic => failing}/extern_mem_fail.c (78%) rename test/c/{pthread => failing}/join_return.c (92%) rename test/c/{pthread => failing}/join_return_fail.c (100%) create mode 100644 test/c/failing/null_dereference_fail.c diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..fe7950bd7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "sea-dsa"] + path = sea-dsa + url = https://github.com/seahorn/sea-dsa.git + branch = llvm-8.0 diff --git a/.travis.yml b/.travis.yml index a8f2f259d..f8ff1c6ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ addons: - unzip - libz-dev - libedit-dev + - libboost-all-dev cache: directories: diff --git a/CMakeLists.txt b/CMakeLists.txt index b5ba31e7d..c73d88a73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ # This file is distributed under the MIT License. See LICENSE for details. # -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.4.3) project(smack) if (NOT WIN32 OR MSYS OR CYGWIN) @@ -93,87 +93,17 @@ else() endif() include_directories(include) - -add_library(assistDS STATIC - include/assistDS/ArgCast.h - include/assistDS/FuncSimplify.h - include/assistDS/Int2PtrCmp.h - include/assistDS/SimplifyExtractValue.h - include/assistDS/StructReturnToPointer.h - include/assistDS/DSNodeEquivs.h - include/assistDS/FuncSpec.h - include/assistDS/SimplifyGEP.h - include/assistDS/TypeChecks.h - include/assistDS/DataStructureCallGraph.h - include/assistDS/GEPExprArgs.h - include/assistDS/LoadArgs.h - include/assistDS/SimplifyInsertValue.h - include/assistDS/TypeChecksOpt.h - include/assistDS/Devirt.h - include/assistDS/IndCloner.h - include/assistDS/MergeGEP.h - include/assistDS/SimplifyLoad.h - lib/AssistDS/ArgCast.cpp - lib/AssistDS/Devirt.cpp - lib/AssistDS/GEPExprArgs.cpp - lib/AssistDS/LoadArgs.cpp - lib/AssistDS/SimplifyExtractValue.cpp - lib/AssistDS/StructReturnToPointer.cpp - lib/AssistDS/ArgSimplify.cpp - lib/AssistDS/DynCount.cpp - lib/AssistDS/IndCloner.cpp - lib/AssistDS/SimplifyGEP.cpp - lib/AssistDS/TypeChecks.cpp - lib/AssistDS/DSNodeEquivs.cpp - lib/AssistDS/FuncSimplify.cpp - lib/AssistDS/Int2PtrCmp.cpp - lib/AssistDS/MergeGEP.cpp - lib/AssistDS/SimplifyInsertValue.cpp - lib/AssistDS/TypeChecksOpt.cpp - lib/AssistDS/DataStructureCallGraph.cpp - lib/AssistDS/FuncSpec.cpp - lib/AssistDS/SVADevirt.cpp - lib/AssistDS/SimplifyLoad.cpp -) - -add_library(dsa STATIC - include/dsa/AddressTakenAnalysis.h - include/dsa/DSCallGraph.h - include/dsa/DSNode.h - include/dsa/EntryPointAnalysis.h - include/dsa/keyiterator.h - include/dsa/svset.h - include/dsa/AllocatorIdentification.h - include/dsa/DSGraph.h - include/dsa/DSSupport.h - include/dsa/stl_util.h - include/dsa/CallTargets.h - include/dsa/DSGraphTraits.h - include/dsa/DataStructure.h - include/dsa/TypeSafety.h - include/dsa/super_set.h - include/dsa/DSMonitor.h - lib/DSA/AddressTakenAnalysis.cpp - lib/DSA/CallTargets.cpp - lib/DSA/DSTest.cpp - lib/DSA/EquivClassGraphs.cpp - lib/DSA/StdLibPass.cpp - lib/DSA/AllocatorIdentification.cpp - lib/DSA/CompleteBottomUp.cpp - lib/DSA/DataStructure.cpp - lib/DSA/GraphChecker.cpp - lib/DSA/Printer.cpp - lib/DSA/TopDownClosure.cpp - lib/DSA/Basic.cpp - lib/DSA/DSCallGraph.cpp - lib/DSA/DataStructureStats.cpp - lib/DSA/TypeSafety.cpp - lib/DSA/BottomUpClosure.cpp - lib/DSA/DSGraph.cpp - lib/DSA/EntryPointAnalysis.cpp - lib/DSA/DSMonitor.cpp - lib/DSA/Local.cpp - lib/DSA/SanityCheck.cpp +include_directories(sea-dsa/include) + +add_library(utils STATIC + include/utils/Devirt.h + include/utils/MergeGEP.h + include/utils/SimplifyInsertValue.h + include/utils/SimplifyExtractValue.h + lib/utils/Devirt.cpp + lib/utils/MergeGEP.cpp + lib/utils/SimplifyInsertValue.cpp + lib/utils/SimplifyExtractValue.cpp ) add_library(smackTranslator STATIC @@ -230,8 +160,27 @@ add_executable(llvm2bpl tools/llvm2bpl/llvm2bpl.cpp ) +# We need to include Boost header files at least for macOS +find_package (Boost 1.55) +if (Boost_FOUND) + include_directories (${Boost_INCLUDE_DIRS}) +endif () +# We have to import LLVM's cmake definitions to build sea-dsa +# Borrowed from sea-dsa's CMakeLists.txt +find_package (LLVM 8.0.1 EXACT CONFIG) +list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") +include(AddLLVM) +include(HandleLLVMOptions) +# We need the release build of sea-dsa otherwise we'll see a lot of crashes in +# sv-comp benchmarks. +# The following solution is from: https://stackoverflow.com/questions/30985215/passing-variables-down-to-subdirectory-only +set(SMACK_BUILD_TYPE "${CMAKE_BUILD_TYPE}") +set(CMAKE_BUILD_TYPE "Release") +add_subdirectory(sea-dsa/src) +set(CMAKE_BUILD_TYPE ${SMACK_BUILD_TYPE}) + target_link_libraries(smackTranslator ${LLVM_LIBS} ${LLVM_SYSTEM_LIBS} ${LLVM_LDFLAGS}) -target_link_libraries(llvm2bpl smackTranslator assistDS dsa) +target_link_libraries(llvm2bpl smackTranslator utils SeaDsaAnalysis) INSTALL(TARGETS llvm2bpl RUNTIME DESTINATION bin diff --git a/bin/build.sh b/bin/build.sh index b85a2c56c..1fc78fc7a 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -60,7 +60,7 @@ CONFIGURE_INSTALL_PREFIX= CMAKE_INSTALL_PREFIX= # Partial list of dependencies; the rest are added depending on the platform -DEPENDENCIES="git cmake python3-yaml python3-psutil unzip wget ninja-build" +DEPENDENCIES="git cmake python3-yaml python3-psutil unzip wget ninja-build libboost-all-dev" shopt -s extglob @@ -506,6 +506,10 @@ fi if [ ${BUILD_SMACK} -eq 1 ] ; then puts "Building SMACK" + cd ${SMACK_DIR} + git submodule init + git submodule update + mkdir -p ${SMACK_DIR}/build cd ${SMACK_DIR}/build cmake ${CMAKE_INSTALL_PREFIX} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Debug .. -G Ninja diff --git a/docs/installation.md b/docs/installation.md index e30e5725d..9af8d42bf 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -82,11 +82,13 @@ SMACK depends on the following projects: * [LLVM][] version [8.0.1][LLVM-8.0.1] * [Clang][] version [8.0.1][Clang-8.0.1] +* [Boost][] version 1.55 or greater * [Python][] version 3.6.8 or greater * [Ninja][] version 1.5.1 or greater * [Mono][] version 5.0.0 or greater (except on Windows) * [Z3][] or compatible SMT-format theorem prover * [Boogie][] or [Corral][] or compatible Boogie-format verifier +* [sea-dsa][] See [here](https://github.com/smackers/smack/blob/master/bin/versions) for compatible version numbers of [Boogie][] and [Corral][]. See the appropriate @@ -153,9 +155,14 @@ installed via the Microsoft Store. ### Installing SMACK Itself -SMACK is built using [CMake][] via the following sequence of shell commands -from SMACK's root directory: -````Shell +The prerequisite step for building SMACK is to fetch its submodule +(i.e., [sea-dsa][]). Then, it is built using [CMake][]. Both steps can be done +via the following sequence of shell commands from SMACK's root directory: +```Shell +# fetch the submodule +git submodule init +git submodule update +# build SMACK mkdir build cd build cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Debug .. -G Ninja @@ -218,3 +225,5 @@ shell in the `test` directory by executing [Homebrew Cask]: https://formulae.brew.sh/cask/ [Docker]: https://www.docker.com [Ninja]: https://ninja-build.org +[sea-dsa]: https://github.com/seahorn/sea-dsa +[Boost]: http://boost.org/ diff --git a/include/assistDS/ArgCast.h b/include/assistDS/ArgCast.h deleted file mode 100644 index 4c0bf8765..000000000 --- a/include/assistDS/ArgCast.h +++ /dev/null @@ -1,35 +0,0 @@ -//===-------- ArgCast.cpp - Cast Arguments to Calls -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Convert -// call(bitcast (.., T1 arg, ...)F to(..., T2 arg, ...))(..., T2 val, ...) -// to -// val1 = bitcast T2 val to T1 -// call F (..., T1 val1, ...) -//===----------------------------------------------------------------------===// - -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" - -namespace llvm { - // - // Class: ArgCast - // - // Description: - // Implement an LLVM pass that cleans up call sites that take casted args - // - class ArgCast : public ModulePass { - public: - static char ID; - ArgCast() : ModulePass(ID) {} - virtual bool runOnModule(Module& M); - }; -} - diff --git a/include/assistDS/DSNodeEquivs.h b/include/assistDS/DSNodeEquivs.h deleted file mode 100644 index e05a542c7..000000000 --- a/include/assistDS/DSNodeEquivs.h +++ /dev/null @@ -1,68 +0,0 @@ -//===- DSNodeEquivs.h - Build DSNode equivalence classes ------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass computes equivalence classes of DSNodes across DSGraphs. -// -//===----------------------------------------------------------------------===// - -#ifndef DSNODEEQUIVS_H -#define DSNODEEQUIVS_H - -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" -#include "dsa/DSNode.h" - -#include "llvm/ADT/EquivalenceClasses.h" - -#include - -namespace llvm { - -typedef std::vector FunctionList; -typedef FunctionList::iterator FunctionList_it; - -class DSNodeEquivs : public ModulePass { -private: - EquivalenceClasses Classes; - - void buildDSNodeEquivs(Module &M); - - void addNodesFromGraph(DSGraph *G); - FunctionList getCallees(CallSite &CS); - void equivNodesThroughCallsite(CallInst *CI); - void equivNodesToGlobals(DSGraph *G); - void equivNodeMapping(DSGraph::NodeMapTy & NM); - -public: - static char ID; - - DSNodeEquivs() : ModulePass(ID) {} - - void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredTransitive(); - AU.setPreservesAll(); - } - - bool runOnModule(Module &M); - - // Returns the computed equivalence classes. Two DSNodes in the same - // equivalence class may alias. DSNodes may also alias if they have the - // Incomplete, Unknown, or External flags set (even if they are in different - // equivalence classes). - const EquivalenceClasses &getEquivalenceClasses(); - - // Returns a DSNode for the specified value. Note that two nodes may alias - // even if they have different DSNodes (because the DSNodes may belong to - // different DSGraphs). - const DSNode *getMemberForValue(const Value *V); -}; - -} - -#endif // DSNODEEQUIVS_H diff --git a/include/assistDS/DataStructureCallGraph.h b/include/assistDS/DataStructureCallGraph.h deleted file mode 100644 index ed5dcf9bf..000000000 --- a/include/assistDS/DataStructureCallGraph.h +++ /dev/null @@ -1,107 +0,0 @@ -//===- DataStructureCallGraph.h - Provide a CallGraph using DSA -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the DataStructureCallGraph implementation of the -// CallGraph analysis. Based on llvm/lib/Analysis/IPA/CallGraph.cpp. -// -//===----------------------------------------------------------------------===// - -#ifndef _DATA_STRUCTURE_CALLGRAPH_H -#define _DATA_STRUCTURE_CALLGRAPH_H - -#include "dsa/CallTargets.h" -#include "dsa/DataStructure.h" - -#include "llvm/IR/Module.h" -#include "llvm/Analysis/CallGraph.h" -#include "llvm/Support/raw_ostream.h" - -namespace llvm { - -class DataStructureCallGraph : public CallGraphWrapperPass { - // Root is root of the call graph, or the external node if a 'main' function - // couldn't be found. - CallGraphNode *Root; - - // ExternalCallingNode - This node has edges to all external functions and - // those internal functions that have their address taken. - CallGraphNode *ExternalCallingNode; - - // CallsExternalNode - This node has edges to it from all functions making - // indirect calls or calling an external function. - CallGraphNode *CallsExternalNode; - - typedef dsa::CallTargetFinder CallTargetFinderTy; - -public: - static char ID; - DataStructureCallGraph() : - Root(0), ExternalCallingNode(0), CallsExternalNode(0) { } - - virtual bool runOnModule(Module &M); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.addRequired(); - AU.setPreservesAll(); - } - - virtual void print(raw_ostream &OS, const Module *) const { - OS << "CallGraph Root is: "; - if (Function *F = getRoot()->getFunction()) - OS << F->getName() << "\n"; - else { - OS << "<>\n"; - } - - CallGraphWrapperPass::print(OS, 0); - } - - virtual void releaseMemory() { - destroy(); - } - - // getAdjustedAnalysisPointer - This method is used when a pass implements an - // analysis interface through multiple inheritance. If needed, it should - // override this to adjust the this pointer as needed for the specified pass - // info. - virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { - if (PI == CallGraphAnalysis::ID()) - return (CallGraph*)this; - return this; - } - - CallGraphNode* getExternalCallingNode() const { return ExternalCallingNode; } - CallGraphNode* getCallsExternalNode() const { return CallsExternalNode; } - - // getRoot - Return the root of the call graph, which is either main, or if - // main cannot be found, the external node. - CallGraphNode *getRoot() { return Root; } - const CallGraphNode *getRoot() const { return Root; } - -private: - // addToCallGraph - Add a function to the call graph, and link the node to all - // of the functions that it calls. - void addToCallGraph(Function *F); - - // destroy - Release memory for the call graph - virtual void destroy() { - // CallsExternalNode is not in the function map, delete it explicitly. - if (CallsExternalNode) { - // CallsExternalNode->allReferencesDropped(); FIXME FIXME FIXME FIXME - delete CallsExternalNode; - CallsExternalNode = 0; - } - CallGraphWrapperPass::releaseMemory(); - } -}; - -} - -#endif // _DATA_STRUCTURE_CALLGRAPH_H diff --git a/include/assistDS/FuncSimplify.h b/include/assistDS/FuncSimplify.h deleted file mode 100644 index ad4a93648..000000000 --- a/include/assistDS/FuncSimplify.h +++ /dev/null @@ -1,30 +0,0 @@ -//===-------- ArgCast.cpp - Cast Arguments to Calls -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" - -namespace llvm { - // - // Class: FuncSimplify - // - // Description: - // Replace all internal aliases with the - // aliasee value - // - class FuncSimplify : public ModulePass { - public: - static char ID; - FuncSimplify() : ModulePass(ID) {} - virtual bool runOnModule(Module& M); - }; -} - diff --git a/include/assistDS/FuncSpec.h b/include/assistDS/FuncSpec.h deleted file mode 100644 index 433d98c96..000000000 --- a/include/assistDS/FuncSpec.h +++ /dev/null @@ -1,35 +0,0 @@ -//===-- FuncSpec.cpp - Clone Functions With Constant Function Ptr Args ----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass clones functions that take constant function pointers as arguments -// from some call sites. It changes those call sites to call cloned functions. -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" - -namespace llvm { - // - // Class: FuncSpec - // - // Description: - // Implement an LLVM pass that clones functions which are passed - // as an argument - // - // - class FuncSpec : public ModulePass { - public: - static char ID; - FuncSpec() : ModulePass(ID) {} - virtual bool runOnModule(Module& M); - }; -} - diff --git a/include/assistDS/GEPExprArgs.h b/include/assistDS/GEPExprArgs.h deleted file mode 100644 index 201097bd5..000000000 --- a/include/assistDS/GEPExprArgs.h +++ /dev/null @@ -1,34 +0,0 @@ - -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Identify GEPs used as arguments to call sites. -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" - -namespace llvm { - // - // Class: GEPExprArgs - // - // Description: - // Implement an LLVM pass that clones functions which are passed GEPs - // as an argument - // - // - class GEPExprArgs : public ModulePass { - public: - static char ID; - GEPExprArgs() : ModulePass(ID) {} - virtual bool runOnModule(Module& M); - }; -} - diff --git a/include/assistDS/IndCloner.h b/include/assistDS/IndCloner.h deleted file mode 100644 index d99200ad6..000000000 --- a/include/assistDS/IndCloner.h +++ /dev/null @@ -1,34 +0,0 @@ -//===-- IndCloner.h - Clone Indirectly Called Functions -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This code defines a pass which clones functions which could potentially be -// used in indirect function calls. -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" - -namespace llvm { - // - // Class: IndClone - // - // Description: - // Implement an LLVM pass that clones functions which could be used for - // indirect function calls. - // - class IndClone : public ModulePass { - public: - static char ID; - IndClone() : ModulePass(ID) {} - virtual bool runOnModule(Module& M); - }; -} - diff --git a/include/assistDS/Int2PtrCmp.h b/include/assistDS/Int2PtrCmp.h deleted file mode 100644 index e9356a97c..000000000 --- a/include/assistDS/Int2PtrCmp.h +++ /dev/null @@ -1,36 +0,0 @@ -//===-- Int2PtrCmp.cpp - Merge inttoptr/ptrtoint --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Remove unnecessary inttoptr casts -// Specially ones used in just compares -// Most cases derived from InstCombine -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" - - -namespace llvm { - // - // Class: Int2PtrCmp - // - // - class Int2PtrCmp : public ModulePass { - private: - const DataLayout * TD; - public: - static char ID; - Int2PtrCmp() : ModulePass(ID) {} - virtual bool runOnModule(Module& M); - }; -} - diff --git a/include/assistDS/LoadArgs.h b/include/assistDS/LoadArgs.h deleted file mode 100644 index 760ce5c5b..000000000 --- a/include/assistDS/LoadArgs.h +++ /dev/null @@ -1,36 +0,0 @@ -//===-- LoadArgs.cpp - Promote args if they came from loads ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Identify calls, that are passed arguemtns that are LoadInsts. -// Pass the original pointer instead. Helps improve some -// context sensitivity. -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" - -namespace llvm { - // - // Class: LoadArgs - // - // Description: - // Implement an LLVM pass that clones functions which are passed loads - // as an argument - // - // - class LoadArgs : public ModulePass { - public: - static char ID; - LoadArgs() : ModulePass(ID) {} - virtual bool runOnModule(Module& M); - }; -} - diff --git a/include/assistDS/SimplifyGEP.h b/include/assistDS/SimplifyGEP.h deleted file mode 100644 index e8a48749d..000000000 --- a/include/assistDS/SimplifyGEP.h +++ /dev/null @@ -1,32 +0,0 @@ -//===--------------- SimplifyGEP.cpp - Simplify GEPs types ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Simplify GEPs with bitcasts (mostly cloned from InstCombine) -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" - -namespace llvm { - // - // Class: SimplifyGEP - // - class SimplifyGEP : public ModulePass { - private: - const DataLayout * TD; - public: - static char ID; - SimplifyGEP() : ModulePass(ID) {} - virtual bool runOnModule(Module& M); - }; -} - diff --git a/include/assistDS/SimplifyLoad.h b/include/assistDS/SimplifyLoad.h deleted file mode 100644 index 75c03f852..000000000 --- a/include/assistDS/SimplifyLoad.h +++ /dev/null @@ -1,29 +0,0 @@ -//===--------------- SimplifyLoad.cpp - Simplify load insts ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Derived from InstCombine -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" - -namespace llvm { - // - // Class: SimplifyLoad - // - class SimplifyLoad : public ModulePass { - public: - static char ID; - SimplifyLoad() : ModulePass(ID) {} - virtual bool runOnModule(Module& M); - }; -} - diff --git a/include/assistDS/StructReturnToPointer.h b/include/assistDS/StructReturnToPointer.h deleted file mode 100644 index 9cbd01a36..000000000 --- a/include/assistDS/StructReturnToPointer.h +++ /dev/null @@ -1,30 +0,0 @@ -//===-------- StructReturnToPointer.cpp ------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// For functions that return structures, -// transform them to return a pointer to the structure instead. -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" - -namespace llvm { - // - // Class: StructRet - // - class StructRet : public ModulePass { - public: - static char ID; - StructRet() : ModulePass(ID) {} - virtual bool runOnModule(Module& M); - }; -} - diff --git a/include/assistDS/TypeChecks.h b/include/assistDS/TypeChecks.h deleted file mode 100644 index cf1cf2fea..000000000 --- a/include/assistDS/TypeChecks.h +++ /dev/null @@ -1,116 +0,0 @@ -//===------------- TypeChecks.h - Insert runtime type checks --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass inserts checks to enforce type safety during runtime. -// -//===----------------------------------------------------------------------===// - -#ifndef TYPE_CHECKS_H -#define TYPE_CHECKS_H - -#include "dsa/AddressTakenAnalysis.h" - -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Function.h" -#include "llvm/Pass.h" -#include "llvm/IR/CallSite.h" -#include "llvm/IR/Dominators.h" -#include "llvm/Analysis/LoopInfo.h" - -#include -#include -#include - -namespace llvm { - -class Type; -class Value; - -class TypeChecks : public ModulePass { -private: - std::map UsedTypes; - std::map IndFunctionsMap; - std::list VAArgFunctions; - std::list ByValFunctions; - std::list AddressTakenFunctions; - std::set IndCalls; - std::set InsertedPHINodes; - std::map SelectInst_MD_Map; - std::map SelectInst_BasePtr_Map; - std::map PHINode_MD_Map; - std::map PHINode_BasePtr_Map; - std::map BitCast_MD_Map; - - // Analysis from other passes. - const DataLayout *TD; - AddressTakenAnalysis* addrAnalysis; - - unsigned int getTypeMarker(Type*); - unsigned int getTypeMarker(Value*); - Constant *getTypeMarkerConstant(Value * V); - Constant *getTypeMarkerConstant(Type* T); - unsigned int getSize(Type*); - Constant* getSizeConstant(Type*); - - bool initShadow(Module &M); - void addTypeMap(Module &M) ; - void optimizeChecks(Module &M); - void initRuntimeCheckPrototypes(Module &M); - - bool visitMain(Module &M, Function &F); - - bool visitCallInst(Module &M, CallInst &CI); - bool visitInvokeInst(Module &M, InvokeInst &CI); - bool visitCallSite(Module &M, CallSite CS); - bool visitIndirectCallSite(Module &M, Instruction *I); - - bool visitLoadInst(Module &M, LoadInst &LI); - bool visitStoreInst(Module &M, StoreInst &SI); - bool visitAllocaInst(Module &M, AllocaInst &AI); - bool visitVAArgInst(Module &M, VAArgInst &VI); - - bool visitUses(Instruction *I, Instruction *AI, Value *BCI); - - bool visitGlobal(Module &M, GlobalVariable &GV, - Constant *C, Instruction &I, SmallVector); - - bool visitInternalByValFunction(Module &M, Function &F); - bool visitExternalByValFunction(Module &M, Function &F); - bool visitByValFunction(Module &M, Function &F); - - bool visitAddressTakenFunction(Module &M, Function &F); - - - bool visitVarArgFunction(Module &M, Function &F); - bool visitInternalVarArgFunction(Module &M, Function &F); - - bool visitInputFunctionValue(Module &M, Value *V, Instruction *CI); - -public: - static char ID; - TypeChecks() : ModulePass(ID) {} - virtual bool runOnModule(Module &M); - virtual void print(raw_ostream &OS, const Module *M) const; - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.addRequired(); - AU.addRequired(); - } - - // Return the map containing all of the types used in the module. - const std::map &getTypes() const { - return UsedTypes; - } -}; - -} // End llvm namespace - -#endif diff --git a/include/assistDS/TypeChecksOpt.h b/include/assistDS/TypeChecksOpt.h deleted file mode 100644 index 0bf0e5dda..000000000 --- a/include/assistDS/TypeChecksOpt.h +++ /dev/null @@ -1,52 +0,0 @@ -//===---------- TypeChecksOpt.h - Remove safe runtime type checks ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass removes type checks that are statically proven safe -// -//===----------------------------------------------------------------------===// - -#ifndef TYPE_CHECKS_OPT_H -#define TYPE_CHECKS_OPT_H - -#include "dsa/TypeSafety.h" - -#include "llvm/Pass.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/CallSite.h" - -#include - -namespace llvm { - -class Type; -class Value; - -class TypeChecksOpt : public ModulePass { - -private: - - // Analysis from other passes. - dsa::TypeSafety *TS; - std::list toDelete; - -public: - static char ID; - TypeChecksOpt() : ModulePass(ID) {} - virtual bool runOnModule(Module &M); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired >(); - } - -}; - -} // End llvm namespace - -#endif diff --git a/include/dsa/AddressTakenAnalysis.h b/include/dsa/AddressTakenAnalysis.h deleted file mode 100644 index 4be834087..000000000 --- a/include/dsa/AddressTakenAnalysis.h +++ /dev/null @@ -1,47 +0,0 @@ -//===-- AddressTakenAnalysis.h - Identify address Taken Values-------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass helps find which functions are address taken in a module. -// Functions are considered to be address taken if they are either stored, -// or passed as arguments to functions. -// -//===----------------------------------------------------------------------===// - -#ifndef _ADDRESSTAKENANALYSIS_H -#define _ADDRESSTAKENANALYSIS_H - -#include "llvm/Pass.h" - -#include -#include - -namespace llvm { -class Function; -class Module; -class Instruction; - -class AddressTakenAnalysis : public llvm::ModulePass { - std::set addressTakenFunctions; -public: - static char ID; - AddressTakenAnalysis() : ModulePass (ID) {} - virtual ~AddressTakenAnalysis(); - - bool runOnModule(llvm::Module&); - - virtual void getAnalysisUsage(llvm::AnalysisUsage &Info) const; - - bool hasAddressTaken(llvm::Function *); - -}; - -} - -#endif /* _ADDRESSTAKENANALYSIS_H */ - diff --git a/include/dsa/AllocatorIdentification.h b/include/dsa/AllocatorIdentification.h deleted file mode 100644 index 2a35c00c9..000000000 --- a/include/dsa/AllocatorIdentification.h +++ /dev/null @@ -1,56 +0,0 @@ -//===-- AllocatorIdentification.h - Identify alloc wrappers --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Identify malloc/free wrappers. -//===----------------------------------------------------------------------===// - -#ifndef _ALLOCATORIDENTIFICATION_H -#define _ALLOCATORIDENTIFICATION_H - -#include -#include "llvm/Pass.h" -#include "llvm/IR/Value.h" - -namespace llvm { - class Function; - class Module; - class Instruction; - - class AllocIdentify : public llvm::ModulePass { - protected: - std::set allocators; - std::set deallocators; - bool flowsFrom(Value *Dest,Value *Src); - - public: - std::set::iterator alloc_begin() { - return allocators.begin(); - } - std::set::iterator alloc_end() { - return allocators.end(); - } - std::set::iterator dealloc_begin() { - return deallocators.begin(); - } - std::set::iterator dealloc_end() { - return deallocators.end(); - } - static char ID; - AllocIdentify(); - virtual ~AllocIdentify(); - bool runOnModule(llvm::Module&); - virtual void getAnalysisUsage(llvm::AnalysisUsage &Info) const; - virtual StringRef getPassName() const { - return "Allocator Identification Analysis (find malloc/free wrappers)"; - } - }; - -} - -#endif /* _ALLOCATORIDENTIFICATION_H */ - diff --git a/include/dsa/CallTargets.h b/include/dsa/CallTargets.h deleted file mode 100644 index 7130340d7..000000000 --- a/include/dsa/CallTargets.h +++ /dev/null @@ -1,74 +0,0 @@ -//=- llvm/Analysis/CallTargets.h - Resolve Indirect Call Targets --*- C++ -*-=// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass uses DSA to map targets of all calls, and reports on if it -// thinks it knows all targets of a given call. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ANALYSIS_CALLTARGETS_H -#define LLVM_ANALYSIS_CALLTARGETS_H - -#include "llvm/Pass.h" -#include "llvm/IR/CallSite.h" -#include "dsa/DataStructure.h" - -#include -#include -#include - -using namespace llvm; -namespace dsa{ - - template - class CallTargetFinder : public ModulePass { - std::map > IndMap; - std::set CompleteSites; - std::list AllSites; - - void findIndTargets(Module &M); - public: - static char ID; - CallTargetFinder() : ModulePass(ID) {} - - virtual bool runOnModule(Module &M); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const; - - virtual void print(llvm::raw_ostream &O, const Module *M) const; - - // Given a CallSite, get an iterator of callees - std::vector::iterator begin(CallSite cs){ - return IndMap[cs].begin(); - } - std::vector::iterator end(CallSite cs){ - return IndMap[cs].end(); - } - unsigned size(CallSite cs){ - return IndMap[cs].size(); - } - - // Iterate over CallSites in program - std::list::iterator cs_begin(){ - return AllSites.begin(); - } - std::list::iterator cs_end(){ - return AllSites.end(); - } - - // Do we think we have complete knowledge of this site? - // That is, do we think there are no missing callees - bool isComplete(CallSite cs) const { - return CompleteSites.find(cs) != CompleteSites.end(); - } - }; - -} - -#endif diff --git a/include/dsa/DSCallGraph.h b/include/dsa/DSCallGraph.h deleted file mode 100644 index cc4d3572a..000000000 --- a/include/dsa/DSCallGraph.h +++ /dev/null @@ -1,210 +0,0 @@ -//===- DSCallGaph.h - Build call graphs -------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Implement a detailed call graph for DSA. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DSCALLGRAPH_H -#define LLVM_DSCALLGRAPH_H - -#include "dsa/svset.h" -#include "dsa/keyiterator.h" - -#include -#include "llvm/ADT/EquivalenceClasses.h" -#include "llvm/IR/CallSite.h" - -#include -#include - -class DSCallGraph { -public: - typedef svset FuncSet; - typedef std::map ActualCalleesTy; - typedef std::map SimpleCalleesTy; - -private: - // ActualCallees contains CallSite -> set of Function mappings - ActualCalleesTy ActualCallees; - - // SimpleCallees contains Function -> set of Functions mappings - SimpleCalleesTy SimpleCallees; - - // These are used for returning empty sets when the caller has no callees - FuncSet EmptyActual; - FuncSet EmptySimple; - - // An equivalence class is exactly an SCC - llvm::EquivalenceClasses SCCs; - - // Functions we know about that aren't called - svset knownRoots; - - // Functions that might be called from an incomplete - // unresolved call site. - svset IncompleteCalleeSet; - - svset completeCS; - - // Types for SCC construction - typedef std::map TFMap; - typedef std::vector TFStack; - - // Tarjan's SCC algorithm - unsigned tarjan_rec(const llvm::Function* F, TFStack& Stack, unsigned &NextID, - TFMap& ValMap); - - void removeECFunctions(); - -public: - - DSCallGraph() {} - - typedef ActualCalleesTy::mapped_type::const_iterator callee_iterator; - typedef KeyIterator callee_key_iterator; - typedef SimpleCalleesTy::mapped_type::const_iterator flat_iterator; - typedef KeyIterator flat_key_iterator; - typedef FuncSet::const_iterator root_iterator; - typedef llvm::EquivalenceClasses::member_iterator scc_iterator; - - void insert(llvm::CallSite CS, const llvm::Function* F); - - void insureEntry(const llvm::Function* F); - - template - void insert(llvm::CallSite CS, Iterator _begin, Iterator _end) { - for (; _begin != _end; ++_begin) - insert(CS, *_begin); - } - - callee_iterator callee_begin(llvm::CallSite CS) const { - ActualCalleesTy::const_iterator ii = ActualCallees.find(CS); - if (ii == ActualCallees.end()) - return EmptyActual.end(); - return ii->second.begin(); - } - - callee_iterator callee_end(llvm::CallSite CS) const { - ActualCalleesTy::const_iterator ii = ActualCallees.find(CS); - if (ii == ActualCallees.end()) - return EmptyActual.end(); - return ii->second.end(); - } - - callee_key_iterator key_begin() const { - return callee_key_iterator(ActualCallees.begin()); - } - - callee_key_iterator key_end() const { - return callee_key_iterator(ActualCallees.end()); - } - - flat_iterator flat_callee_begin(const llvm::Function* F) const { - SimpleCalleesTy::const_iterator ii = SimpleCallees.find(F); - if (ii == SimpleCallees.end()) - return EmptySimple.end(); - return ii->second.begin(); - } - - flat_iterator flat_callee_end(const llvm::Function* F) const { - SimpleCalleesTy::const_iterator ii = SimpleCallees.find(F); - if (ii == SimpleCallees.end()) - return EmptySimple.end(); - return ii->second.end(); - } - - flat_key_iterator flat_key_begin() const { - return flat_key_iterator(SimpleCallees.begin()); - } - - flat_key_iterator flat_key_end() const { - return flat_key_iterator(SimpleCallees.end()); - } - - root_iterator root_begin() const { - return knownRoots.begin(); - } - - root_iterator root_end() const { - return knownRoots.end(); - } - - scc_iterator scc_begin(const llvm::Function* F) const { - assert(F == SCCs.getLeaderValue(F) && "Requested non-leader"); - return SCCs.member_begin(SCCs.findValue(F)); - } - - scc_iterator scc_end(const llvm::Function* F) const { - assert(F == SCCs.getLeaderValue(F) && "Requested non-leader"); - return SCCs.member_end(); - } - - const llvm::Function* sccLeader(const llvm::Function*F) const { - return SCCs.getLeaderValue(F); - } - unsigned callee_size(llvm::CallSite CS) const { - ActualCalleesTy::const_iterator ii = ActualCallees.find(CS); - if (ii == ActualCallees.end()) - return 0; - return ii->second.size(); - } - - bool called_from_incomplete_site(const llvm::Function *F) const { - return !(IncompleteCalleeSet.find(F) - == IncompleteCalleeSet.end()); - } - void callee_mark_complete(llvm::CallSite CS) { - completeCS.insert(CS); - } - - bool callee_is_complete(llvm::CallSite CS) const { - return completeCS.find(CS) != completeCS.end(); - } - - unsigned size() const { - unsigned sum = 0; - for (ActualCalleesTy::const_iterator ii = ActualCallees.begin(), - ee = ActualCallees.end(); ii != ee; ++ii) - sum += ii->second.size(); - return sum; - } - - unsigned flat_size() const { - return SimpleCallees.size(); - } - - void buildSCCs(); - - void buildRoots(); - - void buildIncompleteCalleeSet(svset callees); - - void addFullFunctionSet(llvm::CallSite CS, svset &Set) const; - // Temporary compat wrapper - void addFullFunctionList(llvm::CallSite CS, std::vector &List) const { - svset Set; - addFullFunctionSet(CS, Set); - List.insert(List.end(), Set.begin(), Set.end()); - } - - void dump() const; - - void assertSCCRoot(const llvm::Function* F) { - assert(F == SCCs.getLeaderValue(F) && "Not Leader?"); - } - - // common helper; no good reason for it to be here rather than elsewhere - static bool hasPointers(const llvm::Function* F); - static bool hasPointers(llvm::CallSite& CS); - -}; - -#endif /* LLVM_DSCALLGRAPH_H */ - diff --git a/include/dsa/DSGraph.h b/include/dsa/DSGraph.h deleted file mode 100644 index 6b0a47e87..000000000 --- a/include/dsa/DSGraph.h +++ /dev/null @@ -1,714 +0,0 @@ -//===- DSGraph.h - Represent a collection of data structures ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header defines the data structure graph (DSGraph) and the -// ReachabilityCloner class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ANALYSIS_DSGRAPH_H -#define LLVM_ANALYSIS_DSGRAPH_H - -#include "dsa/DSNode.h" -#include "dsa/DSCallGraph.h" -#include "llvm/ADT/EquivalenceClasses.h" -#include "llvm/IR/Function.h" - -#include -#include -#include - -namespace llvm { - -class DataLayout; -class GlobalValue; - -//===----------------------------------------------------------------------===// -/// DSScalarMap - An instance of this class is used to keep track of all of -/// which DSNode each scalar in a function points to. This is specialized to -/// keep track of globals with nodes in the function, and to keep track of the -/// unique DSNodeHandle being used by the scalar map. -/// -/// This class is crucial to the efficiency of DSA with some large SCC's. In -/// these cases, the cost of iterating over the scalar map dominates the cost -/// of DSA. In all of these cases, the DSA phase is really trying to identify -/// globals or unique node handles active in the function. -/// -class DSScalarMap { - typedef std::map ValueMapTy; - ValueMapTy ValueMap; - - typedef std::set GlobalSetTy; - GlobalSetTy GlobalSet; - - EquivalenceClasses &GlobalECs; -public: - DSScalarMap(EquivalenceClasses &ECs) : GlobalECs(ECs) {} - - EquivalenceClasses &getGlobalECs() const { return GlobalECs; } - - // Compatibility methods: provide an interface compatible with a map of - // Value* to DSNodeHandle's. - typedef ValueMapTy::const_iterator const_iterator; - typedef ValueMapTy::iterator iterator; - iterator begin() { return ValueMap.begin(); } - iterator end() { return ValueMap.end(); } - const_iterator begin() const { return ValueMap.begin(); } - const_iterator end() const { return ValueMap.end(); } - - const GlobalValue *getLeaderForGlobal(const GlobalValue *GV) const { - EquivalenceClasses::iterator ECI = GlobalECs.findValue(GV); - if (ECI == GlobalECs.end()) return GV; - return *GlobalECs.findLeader(ECI); - } - - - iterator find(const Value *V) { - assert(V); - iterator I = ValueMap.find(V); - if (I != ValueMap.end()) return I; - - if (const GlobalValue *GV = dyn_cast(V)) { - // If this is a global, check to see if it is equivalenced to something - // in the map. - const GlobalValue *Leader = getLeaderForGlobal(GV); - if (Leader != GV) - I = ValueMap.find((const Value*)Leader); - } - return I; - } - const_iterator find(const Value *V) const { - assert(V); - const_iterator I = ValueMap.find(V); - if (I != ValueMap.end()) return I; - - if (const GlobalValue *GV = dyn_cast(V)) { - // If this is a global, check to see if it is equivalenced to something - // in the map. - const GlobalValue *Leader = getLeaderForGlobal(GV); - if (Leader != GV) - I = ValueMap.find((const Value*)Leader); - } - return I; - } - - /// getRawEntryRef - This method can be used by clients that are aware of the - /// global value equivalence class in effect. - DSNodeHandle &getRawEntryRef(const Value *V) { - std::pair IP = - ValueMap.insert(std::make_pair(V, DSNodeHandle())); - if (IP.second) // Inserted the new entry into the map. - if (const GlobalValue *GV = dyn_cast(V)) - GlobalSet.insert(GV); - return IP.first->second; - } - - unsigned count(const Value *V) const { return ValueMap.find(V) != ValueMap.end(); } - - void erase(const Value *V) { erase(ValueMap.find(V)); } - - void eraseIfExists(const Value *V) { - iterator I = find(V); - if (I != end()) erase(I); - } - - /// replaceScalar - When an instruction needs to be modified, this method can - /// be used to update the scalar map to remove the old and insert the new. - /// - void replaceScalar(const Value *Old, const Value *New) { - iterator I = find(Old); - assert(I != end() && "Old value is not in the map!"); - ValueMap.insert(std::make_pair(New, I->second)); - erase(I); - } - - /// copyScalarIfExists - If Old exists in the scalar map, make New point to - /// whatever Old did. - void copyScalarIfExists(const Value *Old, const Value *New) { - iterator I = find(Old); - if (I != end()) - ValueMap.insert(std::make_pair(New, I->second)); - } - - /// operator[] - Return the DSNodeHandle for the specified value, creating a - /// new null handle if there is no entry yet. - DSNodeHandle &operator[](const Value *V) { - assert(V); - iterator I = ValueMap.find(V); - if (I != ValueMap.end()) - return I->second; // Return value if already exists. - - if (const GlobalValue *GV = dyn_cast(V)) - return AddGlobal(GV); - - return ValueMap.insert(std::make_pair(V, DSNodeHandle())).first->second; - } - - void erase(iterator I) { - assert(I != ValueMap.end() && "Cannot erase end!"); - if (const GlobalValue *GV = dyn_cast(I->first)) - GlobalSet.erase(GV); - ValueMap.erase(I); - } - - void clear_scalars() { - for(iterator ii = begin(); ii != end(); ) - if (isa(ii->first)) - ++ii; - else { - iterator next = ii; - ++ii; - erase(next); - } - } - - void clear() { - ValueMap.clear(); - GlobalSet.clear(); - } - - /// spliceFrom - Copy all entries from RHS, then clear RHS. - /// - void spliceFrom(DSScalarMap &RHS); - - // Access to the global set: the set of all globals currently in the - // scalar map. - typedef GlobalSetTy::const_iterator global_iterator; - global_iterator global_begin() const { return GlobalSet.begin(); } - global_iterator global_end() const { return GlobalSet.end(); } - unsigned global_size() const { return GlobalSet.size(); } - unsigned global_count(const GlobalValue *GV) const { return GlobalSet.count(GV); } -private: - DSNodeHandle &AddGlobal(const GlobalValue *GV); -}; - -//===----------------------------------------------------------------------===// -/// DSGraph - The graph that represents a function. -/// -class DSGraph { -public: - // Public data-type declarations... - typedef DSScalarMap ScalarMapTy; - typedef std::map ReturnNodesTy; - typedef std::map VANodesTy; - typedef ilist NodeListTy; - - /// NodeMapTy - This data type is used when cloning one graph into another to - /// keep track of the correspondence between the nodes in the old and new - /// graphs. - typedef std::map NodeMapTy; - - // InvNodeMapTy - This data type is used to represent the inverse of a node - // map. - typedef std::multimap InvNodeMapTy; - typedef std::list FunctionListTy; -private: - DSGraph *GlobalsGraph; // Pointer to the common graph of global objects - - // This is use to differentiate between Local and the rest of the passes. - // Local should use the FunctionCalls vector that has all the DSCallSites. - // All other passes, shoud use the Aux calls vector, as they process and - // subsequently might remove some DSCall Sites. Once those call sites - // have been resolved, we must not revisit them again. - // UseAuxCalls is false for Local. And true for the other passes. - - bool UseAuxCalls; // Should this pass use the Aux calls vector? - - NodeListTy Nodes; - ScalarMapTy ScalarMap; - - // ReturnNodes - A return value for every function merged into this graph. - // Each DSGraph may have multiple functions merged into it at any time, which - // is used for representing SCCs. - // - ReturnNodesTy ReturnNodes; - - // VANodes - Special "Variable Argument" Node for each function - // - VANodesTy VANodes; - - // FunctionCalls - This list maintains a single entry for each call - // instruction in the current graph. The first entry in the vector is the - // scalar that holds the return value for the call, the second is the function - // scalar being invoked, and the rest are pointer arguments to the function. - // This vector is built by the Local graph and is never modified after that. - // - FunctionListTy FunctionCalls; - - // AuxFunctionCalls - This vector contains call sites that have been processed - // by some mechanism. In pratice, the BU Analysis uses this vector to hold - // the _unresolved_ call sites, because it cannot modify FunctionCalls. - // - FunctionListTy AuxFunctionCalls; - - /// TD - This is the target data object for the machine this graph is - /// constructed for. - const DataLayout &TD; - - SuperSet& TypeSS; - - void operator=(const DSGraph &); // DO NOT IMPLEMENT - DSGraph(const DSGraph&); // DO NOT IMPLEMENT -public: - // Create a new, empty, DSGraph. - DSGraph(EquivalenceClasses &ECs, const DataLayout &td, - SuperSet& tss, - DSGraph *GG = 0) - :GlobalsGraph(GG), UseAuxCalls(false), - ScalarMap(ECs), TD(td), TypeSS(tss) - { } - - // Copy ctor - If you want to capture the node mapping between the source and - // destination graph, you may optionally do this by specifying a map to record - // this into. - // - // Note that a copied graph does not retain the GlobalsGraph pointer of the - // source. You need to set a new GlobalsGraph with the setGlobalsGraph - // method. - // - DSGraph( DSGraph* DSG, EquivalenceClasses &ECs, - SuperSet& tss, - unsigned CloneFlags = 0); - ~DSGraph(); - - DSGraph *getGlobalsGraph() const { return GlobalsGraph; } - void setGlobalsGraph(DSGraph *G) { GlobalsGraph = G; } - - /// getGlobalECs - Return the set of equivalence classes that the global - /// variables in the program form. - EquivalenceClasses &getGlobalECs() const { - return ScalarMap.getGlobalECs(); - } - - SuperSet& getTypeSS() const { - return TypeSS; - } - - /// getDataLayout - Return the DataLayout object for the current target. - /// - const DataLayout &getDataLayout() const { return TD; } - - /// setUseAuxCalls - If you call this method, the auxillary call vector will - /// be used instead of the standard call vector to the dot file. - /// - void setUseAuxCalls() { UseAuxCalls = true; } - bool shouldUseAuxCalls() const { return UseAuxCalls; } - - /// node_iterator/begin/end - Iterate over all of the nodes in the graph. Be - /// extremely careful with these methods because any merging of nodes could - /// cause the node to be removed from this list. This means that if you are - /// iterating over nodes and doing something that could cause _any_ node to - /// merge, your node_iterators into this graph can be invalidated. - typedef NodeListTy::iterator node_iterator; - node_iterator node_begin() { return Nodes.begin(); } - node_iterator node_end() { return Nodes.end(); } - - typedef NodeListTy::const_iterator node_const_iterator; - node_const_iterator node_begin() const { return Nodes.begin(); } - node_const_iterator node_end() const { return Nodes.end(); } - - /// getFunctionNames - Return a space separated list of the name of the - /// functions in this graph (if any) - /// - std::string getFunctionNames() const; - - /// addNode - Add a new node to the graph. - /// - void addNode(DSNode *N) { Nodes.push_back(N); } - void unlinkNode(DSNode *N) { Nodes.remove(N); } - - /// getScalarMap - Get a map that describes what the nodes the scalars in this - /// function point to... - /// - ScalarMapTy &getScalarMap() { return ScalarMap; } - const ScalarMapTy &getScalarMap() const { return ScalarMap; } - - /// getFunctionCalls - Return the list of call sites in the original local - /// graph... - /// - const FunctionListTy &getFunctionCalls() const { return FunctionCalls;} - FunctionListTy &getFunctionCalls() { return FunctionCalls;} - - /// getAuxFunctionCalls - Get the call sites as modified by whatever passes - /// have been run. - /// - FunctionListTy &getAuxFunctionCalls() { return AuxFunctionCalls; } - const FunctionListTy &getAuxFunctionCalls() const { - return AuxFunctionCalls; - } - - // addAuxFunctionCall - Add a call site to the AuxFunctionCallList - void addAuxFunctionCall(DSCallSite D) { AuxFunctionCalls.push_back(D); } - - void buildCallGraph(DSCallGraph& DCG, std::vector &GlobalFunctionList, bool filter) const; - void buildCompleteCallGraph(DSCallGraph& DCG, std::vector &GlobalFunctionList, bool filter) const; - - /// removeFunction - Specify that all call sites to the function have been - /// fully specified by a pass such as StdLibPass. - void removeFunctionCalls(Function& F); - - // Function Call iteration - typedef FunctionListTy::const_iterator fc_iterator; - fc_iterator fc_begin() const { return FunctionCalls.begin(); } - fc_iterator fc_end() const { return FunctionCalls.end(); } - - - // Aux Function Call iteration - typedef FunctionListTy::iterator afc_iterator; - afc_iterator afc_begin() { return AuxFunctionCalls.begin(); } - afc_iterator afc_end() { return AuxFunctionCalls.end(); } - typedef FunctionListTy::const_iterator afc_const_iterator; - afc_const_iterator afc_begin() const { return AuxFunctionCalls.begin(); } - afc_const_iterator afc_end() const { return AuxFunctionCalls.end(); } - - /// getNodeForValue - Given a value that is used or defined in the body of the - /// current function, return the DSNode that it points to. - /// - DSNodeHandle &getNodeForValue(const Value *V) { return ScalarMap[V]; } - - const DSNodeHandle &getNodeForValue(const Value *V) const { - ScalarMapTy::const_iterator I = ScalarMap.find(V); - assert(I != ScalarMap.end() && - "Use non-const lookup function if node may not be in the map"); - return I->second; - } - - bool hasNodeForValue(const Value* V) const { - ScalarMapTy::const_iterator I = ScalarMap.find(V); - return I != ScalarMap.end(); - } - - void eraseNodeForValue(const Value* V) { - ScalarMap.erase(V); - } - - /// retnodes_* iterator methods: expose iteration over return nodes in the - /// graph, which are also the set of functions incorporated in this graph. - typedef ReturnNodesTy::const_iterator retnodes_iterator; - retnodes_iterator retnodes_begin() const { return ReturnNodes.begin(); } - retnodes_iterator retnodes_end() const { return ReturnNodes.end(); } - - typedef VANodesTy::const_iterator vanodes_iterator; - vanodes_iterator vanodes_begin() const { return VANodes.begin(); } - vanodes_iterator vanodes_end() const { return VANodes.end(); } - - - /// getReturnNodes - Return the mapping of functions to their return nodes for - /// this graph. - /// - const ReturnNodesTy &getReturnNodes() const { return ReturnNodes; } - ReturnNodesTy &getReturnNodes() { return ReturnNodes; } - - /// getReturnNodeFor - Return the return node for the specified function. - /// - DSNodeHandle &getReturnNodeFor(const Function &F) { - ReturnNodesTy::iterator I = ReturnNodes.find(&F); - assert(I != ReturnNodes.end() && "F not in this DSGraph!"); - return I->second; - } - - const DSNodeHandle &getReturnNodeFor(const Function &F) const { - ReturnNodesTy::const_iterator I = ReturnNodes.find(&F); - assert(I != ReturnNodes.end() && "F not in this DSGraph!"); - return I->second; - } - - /// getVANodes - Return the mapping of functions to their var-arg nodes for - /// this graph. - /// - const VANodesTy &getVANodes() const { return VANodes; } - VANodesTy &getVANodes() { return VANodes; } - - /// getVANodeFor - Return the var-arg node for the specified function. - /// - DSNodeHandle &getVANodeFor(const Function &F) { - VANodesTy::iterator I = VANodes.find(&F); - assert(I != VANodes.end() && "Var-arg info for F not in this graph!"); - return I->second; - } - - const DSNodeHandle &getVANodeFor(const Function &F) const { - VANodesTy::const_iterator I = VANodes.find(&F); - assert(I != VANodes.end() && "Var-arg info for F not in this graph!"); - return I->second; - } - - DSNodeHandle& getOrCreateReturnNodeFor(const Function& F) { - return ReturnNodes[&F]; - } - - DSNodeHandle& getOrCreateVANodeFor(const Function& F) { - return VANodes[&F]; - } - - /// containsFunction - Return true if this DSGraph contains information for - /// the specified function. - bool containsFunction(const Function *F) const { - return ReturnNodes.count(F); - } - - /// getGraphSize - Return the number of nodes in this graph. - /// - unsigned getGraphSize() const { - return Nodes.size(); - } - - /// addObjectToGraph - This method can be used to add global, stack, and heap - /// objects to the graph. This can be used when updating DSGraphs due to the - /// introduction of new temporary objects. The new object is not pointed to - /// and does not point to any other objects in the graph. Note that this - /// method initializes the type of the DSNode to the declared type of the - /// object if UseDeclaredType is true, otherwise it leaves the node type as - /// void. - DSNode *addObjectToGraph(Value *Ptr, bool UseDeclaredType = true); - - - /// print - Print a dot graph to the specified ostream... - /// - void print(llvm::raw_ostream &O) const; - - /// dump - call print(cerr), for use from the debugger... - /// - void dump() const; - - /// viewGraph - Emit a dot graph, run 'dot', run gv on the postscript file, - /// then cleanup. For use from the debugger. - /// - void viewGraph() const; - - void writeGraphToFile(llvm::raw_ostream &O, const std::string &GraphName) const; - - /// maskNodeTypes - Apply a mask to all of the node types in the graph. This - /// is useful for clearing out markers like Incomplete. - /// - void maskNodeTypes(unsigned Mask) { - for (node_iterator I = node_begin(), E = node_end(); I != E; ++I) - I->maskNodeTypes(Mask); - } - void maskIncompleteMarkers() { maskNodeTypes(~DSNode::IncompleteNode); } - - // markIncompleteNodes - Traverse the graph, identifying nodes that may be - // modified by other functions that have not been resolved yet. This marks - // nodes that are reachable through three sources of "unknownness": - // Global Variables, Function Calls, and Incoming Arguments - // - // For any node that may have unknown components (because something outside - // the scope of current analysis may have modified it), the 'Incomplete' flag - // is added to the NodeType. - // - enum MarkIncompleteFlags { - MarkFormalArgs = 1, IgnoreFormalArgs = 0, - IgnoreGlobals = 2, MarkGlobalsIncomplete = 0, - MarkVAStart = 4 - }; - void markIncompleteNodes(unsigned Flags); - - // Mark nodes that have overlapping Int and Pointer types. - void computeIntPtrFlags(); - - // Mark all reachable from external as external. - enum ComputeExternalFlags { - MarkFormalsExternal = 1, DontMarkFormalsExternal = 0, - ProcessCallSites = 2, IgnoreCallSites = 0, - ResetExternal = 4, DontResetExternal = 0 - }; - void computeExternalFlags(unsigned Flags); - - // removeDeadNodes - Use a reachability analysis to eliminate subgraphs that - // are unreachable. This often occurs because the data structure doesn't - // "escape" into it's caller, and thus should be eliminated from the caller's - // graph entirely. This is only appropriate to use when inlining graphs. - // - enum RemoveDeadNodesFlags { - RemoveUnreachableGlobals = 1, KeepUnreachableGlobals = 0 - }; - void removeDeadNodes(unsigned Flags); - - /// CloneFlags enum - Bits that may be passed into the cloneInto method to - /// specify how to clone the function graph. - enum CloneFlags { - StripAllocaBit = 1 << 0, KeepAllocaBit = 0, - DontCloneCallNodes = 1 << 1, CloneCallNodes = 0, - DontCloneAuxCallNodes = 1 << 2, CloneAuxCallNodes = 0, - StripModRefBits = 1 << 3, KeepModRefBits = 0, - StripIncompleteBit = 1 << 4, KeepIncompleteBit = 0 - }; - - void updateFromGlobalGraph(); - - /// computeNodeMapping - Given roots in two different DSGraphs, traverse the - /// nodes reachable from the two graphs, computing the mapping of nodes from - /// the first to the second graph. - /// - static void computeNodeMapping(const DSNodeHandle &NH1, - const DSNodeHandle &NH2, NodeMapTy &NodeMap, - bool StrictChecking = true); - - /// computeGToGGMapping - Compute the mapping of nodes in the graph to nodes - /// in the globals graph. - void computeGToGGMapping(NodeMapTy &NodeMap); - - /// computeGGToGMapping - Compute the mapping of nodes in the global - /// graph to nodes in this graph. - void computeGGToGMapping(InvNodeMapTy &InvNodeMap); - - /// computeCalleeCallerMapping - Given a call from a function in the current - /// graph to the 'Callee' function (which lives in 'CalleeGraph'), compute the - /// mapping of nodes from the callee to nodes in the caller. - void computeCalleeCallerMapping(DSCallSite CS, const Function &Callee, - DSGraph &CalleeGraph, NodeMapTy &NodeMap); - - /// spliceFrom - Logically perform the operation of cloning the RHS graph into - /// this graph, then clearing the RHS graph. Instead of performing this as - /// two seperate operations, do it as a single, much faster, one. - /// - void spliceFrom(DSGraph* RHS); - - /// cloneInto - Clone the specified DSGraph into the current graph. - /// - /// The CloneFlags member controls various aspects of the cloning process. - /// - void cloneInto(DSGraph* G, unsigned CloneFlags = 0); - - /// getFunctionArgumentsForCall - Given a function that is currently in this - /// graph, return the DSNodeHandles that correspond to the pointer-compatible - /// function arguments. The vector is filled in with the return value (or - /// null if it is not pointer compatible), followed by all of the - /// pointer-compatible arguments. - void getFunctionArgumentsForCall(const Function *F, - std::vector &Args) const; - - /// mergeInGraph - This graph merges in the minimal number of - /// nodes from G2 into 'this' graph, merging the bindings specified by the - /// call site (in this graph) with the bindings specified by the vector in G2. - /// If the StripAlloca's argument is 'StripAllocaBit' then Alloca markers are - /// removed from nodes. - /// - void mergeInGraph(const DSCallSite &CS, std::vector &Args, - const DSGraph &G2, unsigned CloneFlags); - - /// mergeInGraph - This method is the same as the above method, but the - /// argument bindings are provided by using the formal arguments of F. - /// - void mergeInGraph(const DSCallSite &CS, const Function &F, - const DSGraph &Graph, unsigned CloneFlags); - - /// getCallSiteForArguments - Get the arguments and return value bindings for - /// the specified function in the current graph. - /// - DSCallSite getCallSiteForArguments(const Function &F) const; - - /// getDSCallSiteForCallSite - Given an LLVM CallSite object that is live in - /// the context of this graph, return the DSCallSite for it. - DSCallSite getDSCallSiteForCallSite(CallSite CS) const; - - // Methods for checking to make sure graphs are well formed... - void AssertNodeInGraph(const DSNode *N) const { - assert((!N || N->getParentGraph() == this) && - "AssertNodeInGraph: Node is not in graph!"); - } - void AssertNodeContainsGlobal(const DSNode *N, const GlobalValue *GV) const; - - void AssertCallSiteInGraph(const DSCallSite &CS) const; - void AssertCallNodesInGraph() const; - void AssertAuxCallNodesInGraph() const; - - void AssertGraphOK() const; - - /// removeTriviallyDeadNodes - After the graph has been constructed, this - /// method removes all unreachable nodes that are created because they got - /// merged with other nodes in the graph. This is used as the first step of - /// removeDeadNodes. - /// - void removeTriviallyDeadNodes(); -}; - - -/// ReachabilityCloner - This class is used to incrementally clone and merge -/// nodes from a non-changing source graph into a potentially mutating -/// destination graph. Nodes are only cloned over on demand, either in -/// responds to a merge() or getClonedNH() call. When a node is cloned over, -/// all of the nodes reachable from it are automatically brought over as well. -/// -class ReachabilityCloner { - DSGraph* Dest; - const DSGraph* Src; - - /// BitsToKeep - These bits are retained from the source node when the - /// source nodes are merged into the destination graph. - unsigned BitsToKeep; - unsigned CloneFlags; - - bool createDest; - - // NodeMap - A mapping from nodes in the source graph to the nodes that - // represent them in the destination graph. - // We cannot use a densemap here as references into it are not stable across - // insertion - typedef std::map RCNodeMap; - RCNodeMap NodeMap; - -public: - ReachabilityCloner(DSGraph* dest, const DSGraph* src, unsigned cloneFlags, - bool _createDest = true) - : Dest(dest), Src(src), CloneFlags(cloneFlags), createDest(_createDest) { - assert(Dest != Src && "Cannot clone from graph to same graph!"); - BitsToKeep = ~DSNode::DeadNode; - if (CloneFlags & DSGraph::StripAllocaBit) - BitsToKeep &= ~DSNode::AllocaNode; - if (CloneFlags & DSGraph::StripModRefBits) - BitsToKeep &= ~(DSNode::ModifiedNode | DSNode::ReadNode); - if (CloneFlags & DSGraph::StripIncompleteBit) - BitsToKeep &= ~DSNode::IncompleteNode; - } - - DSNodeHandle getClonedNH(const DSNodeHandle &SrcNH); - - void merge(const DSNodeHandle &NH, const DSNodeHandle &SrcNH); - - /// mergeCallSite - Merge the nodes reachable from the specified src call - /// site into the nodes reachable from DestCS. - /// - void mergeCallSite(DSCallSite &DestCS, const DSCallSite &SrcCS); - - DSCallSite cloneCallSite(const DSCallSite& SrcCS); - - bool clonedAnyNodes() const { return !NodeMap.empty(); } - - /// hasClonedNode - Return true if the specified node has been cloned from - /// the source graph into the destination graph. - bool hasClonedNode(const DSNode *N) { - return NodeMap.count(N); - } - - void destroy() { NodeMap.clear(); } -}; - -// -// Function: functionIsCallable() -// -// Description: -// Determine whether the specified function can be a target of the specified -// call site. We allow the user to configure what we consider to be -// uncallable at an indirect function call site. -// -// Inputs: -// CS - The call site which calls the function. -// F - The function that is potentially called by CS. -// -// Return value: -// true - The function F can be called by the call site. -// false - The function F cannot be called by the call site. -// -bool -functionIsCallable (ImmutableCallSite CS, const Function* F); - -} // End llvm namespace - -#endif diff --git a/include/dsa/DSGraphTraits.h b/include/dsa/DSGraphTraits.h deleted file mode 100644 index 107cdec76..000000000 --- a/include/dsa/DSGraphTraits.h +++ /dev/null @@ -1,120 +0,0 @@ -//===- DSGraphTraits.h - Provide generic graph interface --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides GraphTraits specializations for the DataStructure graph -// nodes, allowing datastructure graphs to be processed by generic graph -// algorithms. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ANALYSIS_DSGRAPHTRAITS_H -#define LLVM_ANALYSIS_DSGRAPHTRAITS_H - -#include "dsa/DSGraph.h" -#include "llvm/ADT/iterator.h" -#include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/STLExtras.h" - -#include - -namespace llvm { - -template -class DSNodeIterator : public std::iterator { - friend class DSNode; - - DSNode::const_edge_iterator NH; - - typedef DSNodeIterator _Self; - - DSNodeIterator(NodeTy *N) : NH(N->edge_begin()) {} // begin iterator - DSNodeIterator(NodeTy *N, bool) : NH(N->edge_end()) {} // Create end iterator - -public: -// DSNodeIterator(const DSNodeHandle &NH) -// : Node(NH.getNode()), Offset(NH.getOffset()) {} - - bool operator==(const _Self& x) const { - return NH == x.NH; - } - bool operator!=(const _Self& x) const { return !operator==(x); } - - const _Self &operator=(const _Self &I) { - NH = I.NH; - return *this; - } - - pointer operator*() const { - return NH->second.getNode(); - } - pointer operator->() const { return operator*(); } - - _Self& operator++() { // Preincrement - ++NH; - return *this; - } - _Self operator++(int) { // Postincrement - _Self tmp = *this; ++*this; return tmp; - } - - unsigned getOffset() const { return NH->first; } -}; - -// Provide iterators for DSNode... -inline DSNode::iterator DSNode::begin() { - return DSNode::iterator(this); -} -inline DSNode::iterator DSNode::end() { - return DSNode::iterator(this, false); -} -inline DSNode::const_iterator DSNode::begin() const { - return DSNode::const_iterator(this); -} -inline DSNode::const_iterator DSNode::end() const { - return DSNode::const_iterator(this, false); -} - -template <> struct GraphTraits { - typedef DSNode* NodeRef; - typedef DSNode::iterator ChildIteratorType; - - static NodeRef getEntryNode(NodeRef N) { return N; } - static ChildIteratorType child_begin(NodeRef N) { return N->begin(); } - static ChildIteratorType child_end(NodeRef N) { return N->end(); } -}; - -template <> struct GraphTraits { - typedef const DSNode* NodeRef; - typedef DSNode::const_iterator ChildIteratorType; - - static NodeRef getEntryNode(NodeRef N) { return N; } - static ChildIteratorType child_begin(NodeRef N) { return N->begin(); } - static ChildIteratorType child_end(NodeRef N) { return N->end(); } -}; - -template <> struct GraphTraits { - typedef const DSNode* NodeRef; - typedef DSNode::const_iterator ChildIteratorType; - - // nodes_iterator/begin/end - Allow iteration over all nodes in the graph - typedef pointer_iterator nodes_iterator; - static nodes_iterator nodes_begin(const DSGraph *G) { - return nodes_iterator(G->node_begin()); - } - static nodes_iterator nodes_end(const DSGraph *G) { - return nodes_iterator(G->node_end()); - } - - static ChildIteratorType child_begin(NodeRef N) { return N->begin(); } - static ChildIteratorType child_end(NodeRef N) { return N->end(); } -}; - -} // End llvm namespace - -#endif diff --git a/include/dsa/DSMonitor.h b/include/dsa/DSMonitor.h deleted file mode 100644 index 8519f95f4..000000000 --- a/include/dsa/DSMonitor.h +++ /dev/null @@ -1,29 +0,0 @@ - -#ifndef LLVM_ANALYSIS_DSMONITOR_H -#define LLVM_ANALYSIS_DSMONITOR_H - -#include "dsa/DataStructure.h" -#include "dsa/DSSupport.h" - -namespace llvm { - -class DSMonitor { - DSNodeHandle N; - std::string caption; - std::vector VS; - std::string message; - std::string location; - - void unwatch(); - -public: - DSMonitor() { } - void watch(DSNodeHandle N, std::vector VS, std::string M = ""); - void warn(); - void witness(DSNodeHandle N, std::vector VS, std::string M = ""); - void check(); -}; - -} - -#endif diff --git a/include/dsa/DSNode.h b/include/dsa/DSNode.h deleted file mode 100644 index 180cd1c20..000000000 --- a/include/dsa/DSNode.h +++ /dev/null @@ -1,540 +0,0 @@ -//===- DSNode.h - Node definition for datastructure graphs ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Data structure graph nodes and some implementation of DSNodeHandle. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ANALYSIS_DSNODE_H -#define LLVM_ANALYSIS_DSNODE_H - -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/ilist_node.h" -#include "llvm/ADT/ilist.h" -#include "llvm/Support/raw_ostream.h" -#include "dsa/svset.h" -#include "dsa/super_set.h" -#include "dsa/keyiterator.h" -#include "dsa/DSSupport.h" - -#include -#include - -namespace llvm { - -template -class DSNodeIterator; // Data structure graph traversal iterator - -//===----------------------------------------------------------------------===// -/// DSNode - Data structure node class -/// -/// This class represents an untyped memory object of Size bytes. It keeps -/// track of any pointers that have been stored into the object as well as the -/// different types represented in this object. -/// -class DSNode : public ilist_node { -public: - typedef std::map::setPtr> TyMapTy; - typedef std::map LinkMapTy; - -private: - //Sentinel - DSNode() : NumReferrers(0), Size(0), NodeType(0) {} - - /// NumReferrers - The number of DSNodeHandles pointing to this node... if - /// this is a forwarding node, then this is the number of node handles which - /// are still forwarding over us. - /// - unsigned NumReferrers; - - /// ForwardNH - This NodeHandle contain the node (and offset into the node) - /// that this node really is. When nodes get folded together, the node to be - /// eliminated has these fields filled in, otherwise ForwardNH.getNode() is - /// null. - /// - DSNodeHandle ForwardNH; - - /// Size - The current size of the node. This should be equal to the size of - /// the current type record. - /// - unsigned Size; - - /// ParentGraph - The graph this node is currently embedded into. - /// - DSGraph *ParentGraph; - - /// TyMap - Keep track of the loadable types and offsets those types are seen - // at. - TyMapTy TyMap; - - /// Links - Contains one entry for every byte in this memory - /// object. - /// - LinkMapTy Links; - - /// Globals - The list of global values that are merged into this node. - /// - svset Globals; - - void operator=(const DSNode &); // DO NOT IMPLEMENT - DSNode(const DSNode &); // DO NOT IMPLEMENT -public: - enum NodeTy { - ShadowNode = 0, // Nothing is known about this node... - AllocaNode = 1 << 0, // This node was allocated with alloca - HeapNode = 1 << 1, // This node was allocated with malloc - GlobalNode = 1 << 2, // This node was allocated by a global var decl - ExternFuncNode = 1 << 3, // This node contains external functions - ExternGlobalNode = 1 << 4, // This node contains external globals - UnknownNode = 1 << 5, // This node points to unknown allocated memory - IncompleteNode = 1 << 6, // This node may not be complete - - ModifiedNode = 1 << 7, // This node is modified in this context - ReadNode = 1 << 8, // This node is read in this context - - ArrayNode = 1 << 9, // This node is treated like an array - CollapsedNode = 1 << 10, // This node is collapsed - ExternalNode = 1 << 11, // This node comes from an external source - IntToPtrNode = 1 << 12, // This node comes from an int cast - // and is used in pointer operations - // like geps, loads, stores - PtrToIntNode = 1 << 13, // This node escapes to an int cast - // and DSA does not track it further. - VAStartNode = 1 << 14, // This node is from a vastart call - - //#ifndef NDEBUG - DeadNode = 1 << 15, // This node is dead and should not be pointed to - //#endif - - Composition = AllocaNode | HeapNode | GlobalNode | UnknownNode - }; - - /// NodeType - A union of the above bits. "Shadow" nodes do not add any flags - /// to the nodes in the data structure graph, so it is possible to have nodes - /// with a value of 0 for their NodeType. - /// -private: - unsigned short NodeType; -public: - - /// DSNode ctor - Create a node of the specified type, inserting it into the - /// specified graph. - /// - explicit DSNode(DSGraph *G); - - /// DSNode "copy ctor" - Copy the specified node, inserting it into the - /// specified graph. If NullLinks is true, then null out all of the links, - /// but keep the same number of them. This can be used for efficiency if the - /// links are just going to be clobbered anyway. - /// - DSNode(const DSNode &, DSGraph *G, bool NullLinks = false); - ~DSNode(); - - // Iterator for graph interface... Defined in DSGraphTraits.h - typedef DSNodeIterator iterator; - typedef DSNodeIterator const_iterator; - inline iterator begin(); - inline iterator end(); - inline const_iterator begin() const; - inline const_iterator end() const; - - /// type_* - Provide iterators for accessing types. Some types may be null - typedef TyMapTy::iterator type_iterator; - typedef TyMapTy::const_iterator const_type_iterator; - type_iterator type_begin() { return TyMap.begin(); } - type_iterator type_end() { return TyMap.end(); } - const_type_iterator type_begin() const { return TyMap.begin(); } - const_type_iterator type_end() const { return TyMap.end(); } - - /// edge_* - Provide iterators for accessing outgoing edges. Some outgoing - /// edges may be null. - typedef LinkMapTy::iterator edge_iterator; - typedef LinkMapTy::const_iterator const_edge_iterator; - edge_iterator edge_begin() { return Links.begin(); } - edge_iterator edge_end() { return Links.end(); } - const_edge_iterator edge_begin() const { return Links.begin(); } - const_edge_iterator edge_end() const { return Links.end(); } - - //===-------------------------------------------------- - // Accessors - - /// getSize - Return the maximum number of bytes occupied by this object... - /// - unsigned getSize() const { return Size; } - - /// hasNoReferrers - Return true if nothing is pointing to this node at all. - /// - bool hasNoReferrers() const { return getNumReferrers() == 0; } - - /// getNumReferrers - This method returns the number of referrers to the - /// current node. Note that if this node is a forwarding node, this will - /// return the number of nodes forwarding over the node! - unsigned getNumReferrers() const { return NumReferrers; } - - - DSGraph *getParentGraph() const { return ParentGraph; } - void setParentGraph(DSGraph *G) { ParentGraph = G; } - - /// getForwardNode - This method returns the node that this node is forwarded - /// to, if any. - /// - DSNode *getForwardNode() const { return ForwardNH.getNode(); } - - /// isForwarding - Return true if this node is forwarding to another. - /// - bool isForwarding() const { return !ForwardNH.isNull(); } - - /// stopForwarding - When the last reference to this forwarding node has been - /// dropped, delete the node. - /// - void stopForwarding() { - assert(isForwarding() && - "Node isn't forwarding, cannot stopForwarding()!"); - ForwardNH.setTo(0, 0); - assert(ParentGraph == 0 && - "Forwarding nodes must have been removed from graph!"); - delete this; - } - - void growSize(unsigned NSize) { - assert(NSize >= Size && "Cannot shrink"); - assert(!isCollapsedNode() && "Growing a collapsed node"); - Size = NSize; - } - - void growSizeForType(Type *Ty, unsigned Offset); - - /// hasLink - Return true if this memory object has a link in slot LinkNo - /// - bool hasLink(unsigned Offset) const { - assert(Offset < getSize() && "Link index is out of range!"); - return Links.find(Offset) != Links.end(); - } - - /// getLink - Return the link at the specified offset. - /// - DSNodeHandle &getLink(unsigned Offset) { - assert(Offset < getSize() && "Link index is out of range!"); - assert(!isForwarding() && "Link on a forwarding node"); - return Links[Offset]; - } - const DSNodeHandle &getLink(unsigned Offset) const { - assert(hasLink(Offset) && "No Link"); - assert(!isForwarding() && "Link on a forwarding node"); - return Links.find(Offset)->second; - } - - //unsigned getNumLinks() const { -// assert(!isForwarding() && "Link on a forwarding node"); -// return Links.size(); -// } - - /// mergeTypeInfo - This method merges the specified type into the current - /// node at the specified offset. This may update the current node's type - /// record if this gives more information to the node, it may do nothing to - /// the node if this information is already known, or it may merge the node - /// completely (and return true) if the information is incompatible with what - /// is already known. - /// - void mergeTypeInfo(Type *Ty, unsigned Offset); - void mergeTypeInfo(const TyMapTy::mapped_type TyIt, unsigned Offset); - void mergeTypeInfo(const DSNode* D, unsigned Offset); - - // Types records might exist without types in them - bool hasNoType() { - type_iterator ii = type_begin(), ee = type_end(); - while (ii != ee) { - if (ii->second) return false; - ++ii; - } - return true; - } - - /// markIntPtrFlags - If the node at any offset has overlapping int/ptr types - /// mark the P2I flags. - /// - void markIntPtrFlags(); - - /// foldNodeCompletely - If we determine that this node has some funny - /// behavior happening to it that we cannot represent, we fold it down to a - /// single, completely pessimistic, node. This node is represented as a - /// single byte with a single TypeEntry of "void" with isArray = true. - /// - void foldNodeCompletely(); - - /// isNodeCompletelyFolded - Return true if this node has been completely - /// folded down to something that can never be expanded, effectively losing - /// all of the field sensitivity that may be present in the node. - /// - bool isNodeCompletelyFolded() const; - - /// setLink - Set the link at the specified offset to the specified - /// NodeHandle, replacing what was there. It is uncommon to use this method, - /// instead one of the higher level methods should be used, below. - /// - void setLink(unsigned Offset, const DSNodeHandle &NH) { - assert(Offset < getSize() && "Link index is out of range!"); - Links[Offset] = NH; - } - - /// addEdgeTo - Add an edge from the current node to the specified node. This - /// can cause merging of nodes in the graph. - /// - void addEdgeTo(unsigned Offset, const DSNodeHandle &NH); - - /// mergeWith - Merge this node and the specified node, moving all links to - /// and from the argument node into the current node, deleting the node - /// argument. Offset indicates what offset the specified node is to be merged - /// into the current node. - /// - /// The specified node may be a null pointer (in which case, nothing happens). - /// - void mergeWith(const DSNodeHandle &NH, unsigned Offset); - - /// addGlobal - Add an entry for a global value to the Globals list. This - /// also marks the node with the 'G' flag if it does not already have it. - /// - void addGlobal(const GlobalValue *GV); - - void addFunction(const Function* F); - - /// removeGlobal - Remove the specified global that is explicitly in the - /// globals list. - void removeGlobal(const GlobalValue *GV); - - void mergeGlobals(const DSNode& RHS); - void clearGlobals() { Globals.clear(); } - - bool isEmptyGlobals() const { return Globals.empty(); } - unsigned numGlobals() const { return Globals.size(); } - - /// addFullGlobalSet - Compute the full set of global values that are - /// represented by this node. Unlike getGlobalsList(), this requires fair - /// amount of work to compute, so don't treat this method call as free. - void addFullGlobalsSet(svset &Set) const; - /// Same as above, keeping for compat reasons - void addFullGlobalsList(std::vector &List) const { - svset Set; - addFullGlobalsSet(Set); - List.insert(List.end(), Set.begin(), Set.end()); - } - - /// addFullFunctionSet - Identical to addFullGlobalsSet, but only return the - /// functions in the full list. - void addFullFunctionSet(svset &Set) const; - /// Same as above, keeping for compat reasons - void addFullFunctionList(std::vector &List) const { - svset Set; - addFullFunctionSet(Set); - List.insert(List.end(), Set.begin(), Set.end()); - } - /// Same as above, only doesn't include duplicates - /// (keeping both for compat with existing clients) - - /// globals_iterator/begin/end - Provide iteration methods over the global - /// value leaders set that is merged into this node. Like the getGlobalsList - /// method, these iterators do not return globals that are part of the - /// equivalence classes for globals in this node, but aren't leaders. - typedef svset::const_iterator globals_iterator; - globals_iterator globals_begin() const { return Globals.begin(); } - globals_iterator globals_end() const { return Globals.end(); } - - /// addValueList - Compute a full set of values that are represented by - /// this node. High overhead method. - void addValueList(std::vector &List) const; - - /// maskNodeTypes - Apply a mask to the node types bitfield. - /// - void maskNodeTypes(unsigned Mask) { - NodeType &= Mask; - } - - void mergeNodeFlags(unsigned RHS) { - NodeType |= RHS; - } - - /// getNodeFlags - Return all of the flags set on the node. If the DEAD flag - /// is set, hide it from the caller. - /// - unsigned getNodeFlags() const { return NodeType & ~DeadNode; } - - /// clearNodeFlags - Useful for completely resetting a node, - /// used in external recognizers - DSNode* clearNodeFlags() { NodeType = 0; return this; } - - bool isAllocaNode() const { return NodeType & AllocaNode; } - bool isHeapNode() const { return NodeType & HeapNode; } - bool isGlobalNode() const { return NodeType & GlobalNode; } - bool isExternFuncNode() const { return NodeType & ExternFuncNode; } - bool isUnknownNode() const { return NodeType & UnknownNode; } - bool isModifiedNode() const { return NodeType & ModifiedNode; } - bool isReadNode() const { return NodeType & ReadNode; } - bool isArrayNode() const { return NodeType & ArrayNode; } - bool isCollapsedNode() const { return NodeType & CollapsedNode; } - bool isIncompleteNode() const { return NodeType & IncompleteNode;} - bool isCompleteNode() const { return !isIncompleteNode(); } - bool isDeadNode() const { return NodeType & DeadNode; } - bool isExternalNode() const { return NodeType & ExternalNode; } - bool isIntToPtrNode() const { return NodeType & IntToPtrNode; } - bool isPtrToIntNode() const { return NodeType & PtrToIntNode; } - bool isVAStartNode() const { return NodeType & VAStartNode; } - - DSNode* setAllocaMarker() { NodeType |= AllocaNode; return this; } - DSNode* setHeapMarker() { NodeType |= HeapNode; return this; } - DSNode* setGlobalMarker() { NodeType |= GlobalNode; return this; } - DSNode* setExternFuncMarker() { NodeType |= ExternFuncNode; return this; } - DSNode* setExternGlobalMarker() { NodeType |= ExternGlobalNode; return this; } - DSNode* setUnknownMarker() { NodeType |= UnknownNode; return this; } - DSNode* setModifiedMarker() { NodeType |= ModifiedNode; return this; } - DSNode* setReadMarker() { NodeType |= ReadNode; return this; } - DSNode* setArrayMarker() { NodeType |= ArrayNode; return this; } - DSNode* setCollapsedMarker() { NodeType |= CollapsedNode; return this; } - DSNode* setIncompleteMarker() { NodeType |= IncompleteNode; return this; } - DSNode* setExternalMarker() { NodeType |= ExternalNode; return this; } - DSNode* setIntToPtrMarker() { NodeType |= IntToPtrNode; return this; } - DSNode* setPtrToIntMarker() { NodeType |= PtrToIntNode; return this; } - DSNode* setVAStartMarker() { NodeType |= VAStartNode; return this; } - - void makeNodeDead() { - Globals.clear(); - assert(hasNoReferrers() && "Dead node shouldn't have refs!"); - NodeType = DeadNode; - } - - /// forwardNode - Mark this node as being obsolete, and all references to it - /// should be forwarded to the specified node and offset. - /// - void forwardNode(DSNode *To, unsigned Offset); - - void cleanEdges(); - - void print(llvm::raw_ostream &O, const DSGraph *G) const; - void dump() const; - void dumpParentGraph() const; - void dumpFuncs(); - - void assertOK() const; - - void dropAllReferences() { - Links.clear(); - TyMap.clear(); - if (isForwarding()) - ForwardNH.setTo(0, 0); - } - - /// remapLinks - Change all of the Links in the current node according to the - /// specified mapping. - /// - void remapLinks(std::map &OldNodeMap); - - /// markReachableNodes - This method recursively traverses the specified - /// DSNodes, marking any nodes which are reachable. All reachable nodes it - /// adds to the set, which allows it to only traverse visited nodes once. - /// - void markReachableNodes(llvm::DenseSet &ReachableNodes) const; - - - /// checkOffsetFoldIfNeeded - Fold DSNode if the specified offset is - /// larger than its size, and the node isn't an array or forwarding. - void checkOffsetFoldIfNeeded(int Offset); -private: - friend class DSNodeHandle; - - // static mergeNodes - Helper for mergeWith() - static void MergeNodes(DSNodeHandle& CurNodeH, DSNodeHandle& NH); -}; - -//===----------------------------------------------------------------------===// -// Define inline DSNodeHandle functions that depend on the definition of DSNode -// -inline DSNode *DSNodeHandle::getNode() const { - // Disabling this assertion because it is failing on a "magic" struct - // in named (from bind). The fourth field is an array of length 0, - // presumably used to create struct instances of different sizes. - // In a variable length struct, Offset could exceed Size when getNode() - // is called before such a node is folded. In this case, the DS Analysis now - // correctly folds this node after calling getNode. - /* assert((!N || - N->isNodeCompletelyFolded() || - (N->Size == 0 && Offset == 0) || - (int(Offset) >= 0 && Offset < N->Size) || - (int(Offset) < 0 && -int(Offset) < int(N->Size)) || - N->isForwarding()) && "Node handle offset out of range!"); - */ - if (N == 0 || !N->isForwarding()) - return N; - - return HandleForwarding(); -} - -inline void DSNodeHandle::setTo(DSNode *n, unsigned NewOffset) const { - assert((!n || !n->isForwarding()) && "Cannot set node to a forwarded node!"); - if (N) getNode()->NumReferrers--; - N = n; - Offset = NewOffset; - if (N) { - N->NumReferrers++; - if (Offset >= N->Size) { - assert((Offset == 0 || N->Size == 1) && - "Pointer to non-collapsed node with invalid offset!"); - Offset = 0; - } - } - assert(!N || ((N->NodeType & DSNode::DeadNode) == 0)); - assert((!N || Offset < N->Size || (N->Size == 0 && Offset == 0) || - N->isForwarding()) && "Node handle offset out of range!"); -} - -inline bool DSNodeHandle::hasLink(unsigned Num) const { - assert(N && "DSNodeHandle does not point to a node yet!"); - return getNode()->hasLink(Num+Offset); -} - - -/// getLink - Treat this current node pointer as a pointer to a structure of -/// some sort. This method will return the pointer a mem[this+Num] -/// -inline const DSNodeHandle &DSNodeHandle::getLink(unsigned Off) const { - assert(N && "DSNodeHandle does not point to a node yet!"); - return getNode()->getLink(Offset+Off); -} -inline DSNodeHandle &DSNodeHandle::getLink(unsigned Off) { - assert(N && "DSNodeHandle does not point to a node yet!"); - return getNode()->getLink(Off+Offset); -} - -inline void DSNodeHandle::setLink(unsigned Off, const DSNodeHandle &NH) { - assert(N && "DSNodeHandle does not point to a node yet!"); - getNode()->setLink(Off+Offset, NH); -} - -/// addEdgeTo - Add an edge from the current node to the specified node. This -/// can cause merging of nodes in the graph. -/// -inline void DSNodeHandle::addEdgeTo(unsigned Off, const DSNodeHandle &NH) { - assert(N && "DSNodeHandle does not point to a node yet!"); - getNode()->addEdgeTo(Off+Offset, NH); -} - -/// mergeWith - Merge the logical node pointed to by 'this' with the node -/// pointed to by 'N'. -/// -inline void DSNodeHandle::mergeWith(const DSNodeHandle &NH) const { - if (!isNull()) - getNode()->mergeWith(NH, Offset); - else { // No node to merge with, so just point to Node - Offset = 0; - DSNode *N = NH.getNode(); - setTo(N, NH.getOffset()); - } -} - -} // End llvm namespace - -#endif diff --git a/include/dsa/DSSupport.h b/include/dsa/DSSupport.h deleted file mode 100644 index 8d58bb434..000000000 --- a/include/dsa/DSSupport.h +++ /dev/null @@ -1,380 +0,0 @@ -//===- DSSupport.h - Support for datastructure graphs -----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Support for graph nodes, call sites, and types. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ANALYSIS_DSSUPPORT_H -#define LLVM_ANALYSIS_DSSUPPORT_H - -#include -#include -#include -#include - -#include "llvm/ADT/DenseSet.h" -#include "llvm/IR/CallSite.h" - -namespace llvm { - -class Function; -class FunctionType; -class CallInst; -class Value; -class GlobalValue; -class Type; - -class DSNode; // Each node in the graph -class DSGraph; // A graph for a function -class ReachabilityCloner; - - /// isPointerType - Return true if this first class type is big enough to hold - /// a pointer. - /// - bool isPointerType(Type *Ty); - -//===----------------------------------------------------------------------===// -/// DSNodeHandle - Implement a "handle" to a data structure node that takes care -/// of all of the add/un'refing of the node to prevent the backpointers in the -/// graph from getting out of date. This class represents a "pointer" in the -/// graph, whose destination is an indexed offset into a node. -/// -/// Note: some functions that are marked as inline in DSNodeHandle are actually -/// defined in DSNode.h because they need knowledge of DSNode operation. Putting -/// them in a CPP file wouldn't help making them inlined and keeping DSNode and -/// DSNodeHandle (and friends) in one file complicates things. -/// -class DSNodeHandle { - mutable DSNode *N; - mutable unsigned Offset; - void operator==(const DSNode *N); // DISALLOW, use to promote N to nodehandle -public: - - DSNodeHandle() : N(0), Offset(0) {} - - // Allow construction, destruction, and assignment... - DSNodeHandle(DSNode *n, unsigned offs = 0) : N(0), Offset(0) { - setTo(n, offs); - } - DSNodeHandle(const DSNodeHandle &H) : N(0), Offset(0) { - DSNode *NN = H.getNode(); - setTo(NN, H.Offset); // Must read offset AFTER the getNode() - } - ~DSNodeHandle() { setTo(0, 0); } - DSNodeHandle &operator=(const DSNodeHandle &H) { - if (&H == this) return *this; // Don't set offset to 0 if self assigning. - DSNode *NN = H.getNode(); // Call getNode() before .Offset - setTo(NN, H.Offset); - return *this; - } - - bool operator<(const DSNodeHandle &H) const { // Allow sorting - return getNode() < H.getNode() || (N == H.N && Offset < H.Offset); - } - bool operator>(const DSNodeHandle &H) const { return H < *this; } - bool operator==(const DSNodeHandle &H) const { // Allow comparison - // getNode can change the offset, so we must call getNode() first. - return getNode() == H.getNode() && Offset == H.Offset; - } - bool operator!=(const DSNodeHandle &H) const { return !operator==(H); } - - inline void swap(DSNodeHandle &NH) { - std::swap(Offset, NH.Offset); - std::swap(N, NH.N); - } - - /// isNull - Check to see if getNode() == 0, without going through the trouble - /// of checking to see if we are forwarding... - /// - bool isNull() const { return N == 0; } - - // Allow explicit conversion to DSNode... - DSNode *getNode() const; // Defined inline in DSNode.h - unsigned getOffset() const { - getNode(); - assert(!isForwarding() && "This is a forwarding NH, call getNode() first!"); - return Offset; - } - - void setOffset(unsigned O) { - assert(!isForwarding() && "This is a forwarding NH, call getNode() first!"); - //assert((!N || Offset < N->Size || (N->Size == 0 && Offset == 0) || - // !N->ForwardNH.isNull()) && "Node handle offset out of range!"); - //assert((!N || O < N->Size || (N->Size == 0 && O == 0) || - // !N->ForwardNH.isNull()) && "Node handle offset out of range!"); - Offset = O; - } - - void setTo(DSNode *N, unsigned O) const; // Defined inline in DSNode.h - - void addEdgeTo(unsigned LinkNo, const DSNodeHandle &N); - void addEdgeTo(const DSNodeHandle &N) { addEdgeTo(0, N); } - - /// mergeWith - Merge the logical node pointed to by 'this' with the node - /// pointed to by 'N'. - /// - void mergeWith(const DSNodeHandle &N) const; - - /// hasLink - Return true if there is a link at the specified offset... - /// - inline bool hasLink(unsigned Num) const; - - /// getLink - Treat this current node pointer as a pointer to a structure of - /// some sort. This method will return the pointer a mem[this+Num] - /// - inline const DSNodeHandle &getLink(unsigned Num) const; - inline DSNodeHandle &getLink(unsigned Num); - - inline void setLink(unsigned Num, const DSNodeHandle &NH); -private: - DSNode *HandleForwarding() const; - - /// isForwarding - Return true if this NodeHandle is forwarding to another - /// one. - bool isForwarding() const; -}; - -} // End llvm namespace - -namespace std { - template<> - inline void swap(llvm::DSNodeHandle &NH1, llvm::DSNodeHandle &NH2) { NH1.swap(NH2); } -} - -namespace llvm { - -//===----------------------------------------------------------------------===// -/// DSCallSite - Representation of a call site via its call instruction, -/// the DSNode handle for the callee function (or function pointer), and -/// the DSNode handles for the function arguments. -/// -class DSCallSite { -public: - typedef std::set MappedSites_t; -private: - CallSite Site; // Actual call site - const Function *CalleeF; // The function called (direct call) - DSNodeHandle CalleeN; // The function node called (indirect call) - DSNodeHandle RetVal; // Returned value - DSNodeHandle VarArgVal; // Merged var-arg val - std::vector CallArgs; // The pointer arguments - MappedSites_t MappedSites; // The merged callsites - - static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src, - const std::map &NodeMap) { - if (DSNode *N = Src.getNode()) { - std::map::const_iterator I = NodeMap.find(N); - assert(I != NodeMap.end() && "Node not in mapping!"); - NH.setTo(I->second, Src.getOffset()); - } - } - - static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src, - const std::map &NodeMap) { - if (DSNode *N = Src.getNode()) { - std::map::const_iterator I = NodeMap.find(N); - assert(I != NodeMap.end() && "Node not in mapping!"); - - DSNode *NN = I->second.getNode(); // Call getNode before getOffset() - NH.setTo(NN, Src.getOffset()+I->second.getOffset()); - } - } - - static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src, - ReachabilityCloner &RC); - - - DSCallSite(); // DO NOT IMPLEMENT -public: - /// Constructor. Note - This ctor destroys the argument vector passed in. On - /// exit, the argument vector is empty. - /// - DSCallSite(CallSite CS, const DSNodeHandle &rv, const DSNodeHandle &va, - DSNode *Callee, std::vector &Args) - : Site(CS), CalleeF(0), CalleeN(Callee), RetVal(rv), VarArgVal(va) { - assert(Callee && "Null callee node specified for call site!"); - Args.swap(CallArgs); - } - DSCallSite(CallSite CS, const DSNodeHandle &rv, const DSNodeHandle &va, - const Function *Callee, std::vector &Args) - : Site(CS), CalleeF(Callee), RetVal(rv), VarArgVal(va) { - assert(Callee && "Null callee function specified for call site!"); - Args.swap(CallArgs); - } - - DSCallSite(const DSCallSite &DSCS) // Simple copy ctor - : Site(DSCS.Site), CalleeF(DSCS.CalleeF), CalleeN(DSCS.CalleeN), - RetVal(DSCS.RetVal), VarArgVal(DSCS.VarArgVal), - CallArgs(DSCS.CallArgs), MappedSites(DSCS.MappedSites) {} - - /// Mapping copy constructor - This constructor takes a preexisting call site - /// to copy plus a map that specifies how the links should be transformed. - /// This is useful when moving a call site from one graph to another. - /// - template - DSCallSite(const DSCallSite &FromCall, MapTy &NodeMap) { - Site = FromCall.Site; - InitNH(RetVal, FromCall.RetVal, NodeMap); - InitNH(CalleeN, FromCall.CalleeN, NodeMap); - InitNH(VarArgVal, FromCall.VarArgVal, NodeMap); - CalleeF = FromCall.CalleeF; - - CallArgs.resize(FromCall.CallArgs.size()); - for (unsigned i = 0, e = FromCall.CallArgs.size(); i != e; ++i) - InitNH(CallArgs[i], FromCall.CallArgs[i], NodeMap); - MappedSites = FromCall.MappedSites; - } - - const DSCallSite &operator=(const DSCallSite &RHS) { - Site = RHS.Site; - CalleeF = RHS.CalleeF; - CalleeN = RHS.CalleeN; - RetVal = RHS.RetVal; - VarArgVal = RHS.VarArgVal; - CallArgs = RHS.CallArgs; - MappedSites = RHS.MappedSites; - return *this; - } - - /// isDirectCall - Return true if this call site is a direct call of the - /// function specified by getCalleeFunc. If not, it is an indirect call to - /// the node specified by getCalleeNode. - /// - bool isDirectCall() const { return CalleeF != 0; } - bool isIndirectCall() const { return !isDirectCall(); } - - - // Accessor functions... - const Function &getCaller() const; - CallSite getCallSite() const { return Site; } - DSNodeHandle &getRetVal() { return RetVal; } - const DSNodeHandle &getRetVal() const { return RetVal; } - DSNodeHandle &getVAVal() { return VarArgVal; } - const DSNodeHandle &getVAVal() const { return VarArgVal; } - - DSNode *getCalleeNode() const { - assert(!CalleeF && CalleeN.getNode()); return CalleeN.getNode(); - } - const Function *getCalleeFunc() const { - assert(!CalleeN.getNode() && CalleeF); return CalleeF; - } - - unsigned getNumPtrArgs() const { return CallArgs.size(); } - - unsigned getNumMappedSites() const { return MappedSites.size(); } - - DSNodeHandle &getPtrArg(unsigned i) { - assert(i < CallArgs.size() && "Argument to getPtrArgNode is out of range!"); - return CallArgs[i]; - } - const DSNodeHandle &getPtrArg(unsigned i) const { - assert(i < CallArgs.size() && "Argument to getPtrArgNode is out of range!"); - return CallArgs[i]; - } - - - const MappedSites_t::iterator ms_begin() const { return MappedSites.begin(); } - const MappedSites_t::iterator ms_end() const { return MappedSites.end(); } - - void addPtrArg(const DSNodeHandle &NH) { - CallArgs.push_back(NH); - } - - void swap(DSCallSite &CS) { - if (this != &CS) { - std::swap(Site, CS.Site); - std::swap(RetVal, CS.RetVal); - std::swap(VarArgVal, CS.VarArgVal); - std::swap(CalleeN, CS.CalleeN); - std::swap(CalleeF, CS.CalleeF); - std::swap(CallArgs, CS.CallArgs); - std::swap(MappedSites, CS.MappedSites); - } - } - - /// mergeWith - Merge the return value and parameters of the these two call - /// sites. - /// - void mergeWith(DSCallSite &CS) { - getRetVal().mergeWith(CS.getRetVal()); - getVAVal().mergeWith(CS.getVAVal()); - unsigned MinArgs = getNumPtrArgs(); - if (CS.getNumPtrArgs() < MinArgs) MinArgs = CS.getNumPtrArgs(); - - for (unsigned a = 0; a != MinArgs; ++a) - getPtrArg(a).mergeWith(CS.getPtrArg(a)); - - for (unsigned a = MinArgs, e = CS.getNumPtrArgs(); a != e; ++a) - CallArgs.push_back(CS.getPtrArg(a)); - - MappedSites.insert(CS.getCallSite()); - MappedSites.insert(CS.ms_begin(), CS.ms_end()); - } - - /// markReachableNodes - This method recursively traverses the specified - /// DSNodes, marking any nodes which are reachable. All reachable nodes it - /// adds to the set, which allows it to only traverse visited nodes once. - /// - void markReachableNodes(DenseSet &Nodes) const; - - bool operator<(const DSCallSite &CS) const { - if (isDirectCall()) { // This must sort by callee first! - if (CS.isIndirectCall()) return true; - if (CalleeF < CS.CalleeF) return true; - if (CalleeF > CS.CalleeF) return false; - } else { - if (CS.isDirectCall()) return false; - if (CalleeN < CS.CalleeN) return true; - if (CalleeN > CS.CalleeN) return false; - } - if (RetVal < CS.RetVal) return true; - if (RetVal > CS.RetVal) return false; - if (VarArgVal < CS.VarArgVal) return true; - if (VarArgVal > CS.VarArgVal) return false; - return CallArgs < CS.CallArgs; - } - - bool operator==(const DSCallSite &CS) const { - return CalleeF == CS.CalleeF && CalleeN == CS.CalleeN && - RetVal == CS.RetVal && CallArgs == CS.CallArgs && - VarArgVal == CS.VarArgVal; - } - - bool operator==(DSCallSite &CS) { - return CalleeF == CS.CalleeF && CalleeN == CS.CalleeN && - RetVal == CS.RetVal && CallArgs == CS.CallArgs && - VarArgVal == CS.VarArgVal; - } - - /// FunctionTypeOfCallSite - Helper method to extract the signature of a function - /// that is called a given CallSite - /// - static const FunctionType *FunctionTypeOfCallSite(const CallSite & Site); - - /// isVarArg - Determines if the call this represents is to a variable argument - /// function - /// - bool isVarArg() const; - - /// isUnresolvable - Determines if this call has properties that would - /// prevent it from ever being resolvded. Put another way, no amount - /// additional information will make this callsite resolvable. - /// - bool isUnresolvable() const; -}; - -} // End llvm namespace - -namespace std { - template<> - inline void swap(llvm::DSCallSite &CS1, - llvm::DSCallSite &CS2) { CS1.swap(CS2); } -} -#endif diff --git a/include/dsa/DataStructure.h b/include/dsa/DataStructure.h deleted file mode 100644 index 5586417e9..000000000 --- a/include/dsa/DataStructure.h +++ /dev/null @@ -1,403 +0,0 @@ -//===- DataStructure.h - Build data structure graphs ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Implement the LLVM data structure analysis library. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ANALYSIS_DATA_STRUCTURE_H -#define LLVM_ANALYSIS_DATA_STRUCTURE_H - -#include "dsa/DSCallGraph.h" -#include "dsa/svset.h" -#include "dsa/super_set.h" -#include "dsa/AddressTakenAnalysis.h" -#include "dsa/AllocatorIdentification.h" - -#include "llvm/Pass.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/CallSite.h" -#include "llvm/ADT/EquivalenceClasses.h" -#include "llvm/ADT/DenseSet.h" - -#include - -namespace llvm { - -class Type; -class Instruction; -class GlobalValue; -class DSGraph; -class DSCallSite; -class DSNode; -class DSNodeHandle; - -FunctionPass *createDataStructureStatsPass(); -FunctionPass *createDataStructureGraphCheckerPass(); - -class DataStructures : public ModulePass { - typedef std::map DSInfoTy; - - /// DataLayout, comes in handy - const DataLayout* TD; - - /// Pass to get Graphs from - DataStructures* GraphSource; - - /// Do we clone Graphs or steal them? - bool Clone; - - /// do we reset the aux list to the func list? - bool resetAuxCalls; - - /// Were are DSGraphs stolen by another pass? - bool DSGraphsStolen; - - void buildGlobalECs(svset& ECGlobals); - - void eliminateUsesOfECGlobals(DSGraph& G, const svset &ECGlobals); - - // DSInfo, one graph for each function - DSInfoTy DSInfo; - - // Name for printing - const char* printname; - -protected: - - /// The Globals Graph contains all information on the globals - DSGraph *GlobalsGraph; - - /// GlobalECs - The equivalence classes for each global value that is merged - /// with other global values in the DSGraphs. - EquivalenceClasses GlobalECs; - - SuperSet* TypeSS; - - // Callgraph, as computed so far - DSCallGraph callgraph; - // List of all address taken functions. - // This is used as target, of indirect calls for any indirect call site with // incomplete callee node. - std::vector GlobalFunctionList; - - void init(DataStructures* D, bool clone, bool useAuxCalls, bool copyGlobalAuxCalls, bool resetAux); - void init(const DataLayout* T); - - void formGlobalECs(); - - void cloneIntoGlobals(DSGraph* G, unsigned cloneFlags); - void cloneGlobalsInto(DSGraph* G, unsigned cloneFlags); - - void restoreCorrectCallGraph(); - - void formGlobalFunctionList(); - - DataStructures(char & id, const char* name) - : ModulePass(id), TD(0), GraphSource(0), printname(name), GlobalsGraph(0) { - // For now, the graphs are owned by this pass - DSGraphsStolen = false; - } - -public: - /// print - Print out the analysis results... - /// - void print(llvm::raw_ostream &O, const Module *M) const; - void dumpCallGraph() const; - - /// handleTest - Handles various user-specified testing options. - /// Returns true iff the user specified for us to test something. - /// - bool handleTest(llvm::raw_ostream &O, const Module *M) const; - - virtual void releaseMemory(); - - virtual bool hasDSGraph(const Function &F) const { - return DSInfo.find(&F) != DSInfo.end(); - } - - /// getDSGraph - Return the data structure graph for the specified function. - /// - virtual DSGraph *getDSGraph(const Function &F) const { - std::map::const_iterator I = DSInfo.find(&F); - assert(I != DSInfo.end() && "Function not in module!"); - return I->second; - } - - void setDSGraph(const Function& F, DSGraph* G) { - DSInfo[&F] = G; - } - - DSGraph* getOrCreateGraph(const Function* F); - - DSGraph* getGlobalsGraph() const { return GlobalsGraph; } - - EquivalenceClasses &getGlobalECs() { return GlobalECs; } - - const DataLayout& getDataLayout() const { return *TD; } - - const DSCallGraph& getCallGraph() const { return callgraph; } - - SuperSet& getTypeSS() const { return *TypeSS; } - - /// deleteValue/copyValue - Interfaces to update the DSGraphs in the program. - /// These correspond to the interfaces defined in the AliasAnalysis class. - void deleteValue(Value *V); - void copyValue(Value *From, Value *To); -}; - -// BasicDataStructures - The analysis is a dummy one -- all pointers can points -// to all possible locations. -// -class BasicDataStructures : public DataStructures { -public: - static char ID; - BasicDataStructures() : DataStructures(ID, "basic.") {} - ~BasicDataStructures() { releaseMemory(); } - - virtual bool runOnModule(Module &M); - - /// getAnalysisUsage - This obviously provides a data structure graph. - /// - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - } -}; - -// LocalDataStructures - The analysis that computes the local data structure -// graphs for all of the functions in the program. -// -// FIXME: This should be a Function pass that can be USED by a Pass, and would -// be automatically preserved. Until we can do that, this is a Pass. -// -class LocalDataStructures : public DataStructures { - AddressTakenAnalysis* addrAnalysis; -public: - static char ID; - LocalDataStructures() : DataStructures(ID, "local.") {} - ~LocalDataStructures() { releaseMemory(); } - - virtual bool runOnModule(Module &M); - - /// getAnalysisUsage - This obviously provides a data structure graph. - /// - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.setPreservesAll(); - } -}; - -// StdLibDataStructures - This analysis recognizes common standard c library -// functions and generates graphs for them. -class StdLibDataStructures : public DataStructures { - void eraseCallsTo(Function* F); - void processRuntimeCheck (Module & M, std::string name, unsigned arg); - void processFunction(int x, Function *F); - AllocIdentify *AllocWrappersAnalysis; -public: - static char ID; - StdLibDataStructures() : DataStructures(ID, "stdlib.") {} - ~StdLibDataStructures() { releaseMemory(); } - - virtual bool runOnModule(Module &M); - - /// getAnalysisUsage - This obviously provides a data structure graph. - /// - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.addRequired(); - AU.setPreservesAll(); - } -}; - -/// BUDataStructures - The analysis that computes the interprocedurally closed -/// data structure graphs for all of the functions in the program. This pass -/// only performs a "Bottom Up" propagation (hence the name). -/// -class BUDataStructures : public DataStructures { -protected: - - const char* debugname; - - - // filterCallees -- Whether or not we filter out illegal callees - // from the CallGraph. This is useful while doing original BU, - // but might be undesirable in other passes such as CBU/EQBU. - bool filterCallees; -public: - static char ID; - //Child constructor (CBU) - BUDataStructures(char & CID, const char* name, const char* printname, - bool filter) - : DataStructures(CID, printname), debugname(name), filterCallees(filter) {} - //main constructor - BUDataStructures() - : DataStructures(ID, "bu."), debugname("dsa-bu"), - filterCallees(true) {} - ~BUDataStructures() { releaseMemory(); } - - virtual bool runOnModule(Module &M); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.setPreservesAll(); - } - -protected: - bool runOnModuleInternal(Module &M); - -private: - // Private typedefs - typedef std::map TarjanMap; - typedef std::vector TarjanStack; - typedef svset FuncSet; - - void postOrderInline (Module & M); - unsigned calculateGraphs (const Function *F, - TarjanStack & Stack, - unsigned & NextID, - TarjanMap & ValMap); - - void calculateGraph(DSGraph* G); - - void CloneAuxIntoGlobal(DSGraph* G); - - void getAllCallees(const DSCallSite &CS, FuncSet &Callees); - void getAllAuxCallees (DSGraph* G, FuncSet &Callees); - void applyCallsiteFilter(const DSCallSite &DCS, FuncSet &Callees); -}; - -/// CompleteBUDataStructures - This is the exact same as the bottom-up graphs, -/// but we use take a completed call graph and inline all indirect callees into -/// their callers graphs, making the result more useful for things like pool -/// allocation. -/// -class CompleteBUDataStructures : public BUDataStructures { -protected: - void buildIndirectFunctionSets (void); -public: - static char ID; - CompleteBUDataStructures(char & CID = ID, - const char* name = "dsa-cbu", - const char* printname = "cbu.") - : BUDataStructures(CID, name, printname, false) {} - ~CompleteBUDataStructures() { releaseMemory(); } - - virtual bool runOnModule(Module &M); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.setPreservesAll(); - } - -}; - -/// EquivBUDataStructures - This is the same as the complete bottom-up graphs, but -/// with functions partitioned into equivalence classes and a single merged -/// DS graph for all functions in an equivalence class. After this merging, -/// graphs are inlined bottom-up on the SCCs of the final (CBU) call graph. -/// -class EquivBUDataStructures : public CompleteBUDataStructures { - void mergeGraphsByGlobalECs(); - void verifyMerging(); - -public: - static char ID; - EquivBUDataStructures() - : CompleteBUDataStructures(ID, "dsa-eq", "eq.") {} - ~EquivBUDataStructures() { releaseMemory(); } - - virtual bool runOnModule(Module &M); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.setPreservesAll(); - } - -}; - -/// TDDataStructures - Analysis that computes new data structure graphs -/// for each function using the closed graphs for the callers computed -/// by the bottom-up pass. -/// -class TDDataStructures : public DataStructures { - svset ExternallyCallable; - - /// CallerCallEdges - For a particular graph, we keep a list of these records - /// which indicates which graphs call this function and from where. - struct CallerCallEdge { - DSGraph *CallerGraph; // The graph of the caller function. - const DSCallSite *CS; // The actual call site. - const Function *CalledFunction; // The actual function being called. - - CallerCallEdge(DSGraph *G, const DSCallSite *cs, const Function *CF) - : CallerGraph(G), CS(cs), CalledFunction(CF) {} - - bool operator<(const CallerCallEdge &RHS) const { - return CallerGraph < RHS.CallerGraph || - (CallerGraph == RHS.CallerGraph && CS < RHS.CS); - } - }; - - std::map > CallerEdges; - - - // IndCallMap - We memoize the results of indirect call inlining operations - // that have multiple targets here to avoid N*M inlining. The key to the map - // is a sorted set of callee functions, the value is the DSGraph that holds - // all of the caller graphs merged together, and the DSCallSite to merge with - // the arguments for each function. - std::map, DSGraph*> IndCallMap; - - bool useEQBU; - -public: - static char ID; - TDDataStructures(char & CID = ID, const char* printname = "td.", bool useEQ = false) - : DataStructures(CID, printname), useEQBU(useEQ) {} - ~TDDataStructures(); - - virtual bool runOnModule(Module &M); - - /// getAnalysisUsage - This obviously provides a data structure graph. - /// - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - if (useEQBU) { - AU.addRequired(); - } else { - AU.addRequired(); - AU.addPreserved(); - } - AU.setPreservesAll(); - } - -private: - void markReachableFunctionsExternallyAccessible(DSNode *N, - DenseSet &Visited); - - void InlineCallersIntoGraph(DSGraph* G); - void ComputePostOrder(const Function &F, DenseSet &Visited, - std::vector &PostOrder); -}; - -/// EQTDDataStructures - Analysis that computes new data structure graphs -/// for each function using the closed graphs for the callers computed -/// by the EQ bottom-up pass. -/// -class EQTDDataStructures : public TDDataStructures { -public: - static char ID; - EQTDDataStructures() - :TDDataStructures(ID, "eqtd.", true) - {} - ~EQTDDataStructures(); -}; - -} // End llvm namespace - -#endif diff --git a/include/dsa/EntryPointAnalysis.h b/include/dsa/EntryPointAnalysis.h deleted file mode 100644 index 1b3968ba6..000000000 --- a/include/dsa/EntryPointAnalysis.h +++ /dev/null @@ -1,53 +0,0 @@ -//===-- EntryPointAnalysis.h - Entry point Finding Pass -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a general way of finding entry points in a system. Simple programs -// will use the main version. Libraries and OS kernels can have more -// specialized versions. -// -//===----------------------------------------------------------------------===// - -#ifndef _ENTRYPOINTANALYSIS_H -#define _ENTRYPOINTANALYSIS_H - -namespace llvm { -class Function; -class Module; -} - -#include -#include "llvm/Pass.h" - -class EntryPointAnalysis : public llvm::ModulePass { - std::set names; - bool haveNames; -public: - static char ID; - EntryPointAnalysis(); - virtual ~EntryPointAnalysis(); - - /// print - Print out the analysis results... - /// - void print(llvm::raw_ostream &O, const llvm::Module *M) const; - - bool runOnModule(llvm::Module&); - - virtual void getAnalysisUsage(llvm::AnalysisUsage &Info) const; - - bool isEntryPoint(const llvm::Function* F) const; - - void findEntryPoints(const llvm::Module& M, - std::vector& dest) const; - -}; - - - -#endif /* _ENTRYPOINTANALYSIS_H */ - diff --git a/include/dsa/TypeSafety.h b/include/dsa/TypeSafety.h deleted file mode 100644 index b003434d2..000000000 --- a/include/dsa/TypeSafety.h +++ /dev/null @@ -1,90 +0,0 @@ -//===- TypeSafety.h - Find Type-Safe Pointers ---------------------*- C++ -*--// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This analysis pass determines which pointers within a program are used in -// a type-safe fashion. It uses DSA to determine type-consistency and -// abstracts the details of interpreting DSA's results. -// -//===----------------------------------------------------------------------===// - -#ifndef DSA_TYPESAFETY_H -#define DSA_TYPESAFETY_H - -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" - -#include "llvm/Pass.h" - -#include -#include - -using namespace llvm; - -namespace dsa { - -// -// Pass: TypeSafety -// -// Description: -// This pass determines which pointers within a function are type-safe. It is -// used to abstract away the interpretation of the DSNode flags and fields -// for clients. -// -// Template parameters: -// dsa - The name of the DSA Pass which this pass should use. -// -template -struct TypeSafety : public ModulePass { - typedef std::unordered_map FieldMap; - typedef std::unordered_map NodeMap; - protected: - // Methods - DSNodeHandle getDSNodeHandle (const Value * V, const Function * F); - DSNodeHandle getDSNodeHandle (const GlobalValue * V); - void findTypeSafeDSNodes (const DSGraph * Graph); - bool isTypeSafe (const DSNode * N); - bool typeFieldsOverlap (const DSNode * N); - void fieldMapUpdate(const DSNode * N); - - // Pointers to prerequisite passes - const DataLayout * TD; - dsa * dsaPass; - - // Data structures - std::set TypeSafeNodes; - NodeMap NodeInfo; - - public: - static char ID; - TypeSafety() : ModulePass(ID) {} - virtual bool runOnModule (Module & M); - - virtual StringRef getPassName() const { - return "DSA Type-Safety Analysis"; - } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.setPreservesAll(); - } - - virtual void releaseMemory () { - TypeSafeNodes.clear(); - return; - } - - // Methods for clients to use - virtual bool isTypeSafe (const Value * V, const Function * F); - virtual bool isTypeSafe (const GlobalValue * V); - virtual bool isFieldDisjoint(const Value * V, const Function *F); - virtual bool isFieldDisjoint(const GlobalValue * V, unsigned offset); -}; - -} -#endif diff --git a/include/dsa/keyiterator.h b/include/dsa/keyiterator.h deleted file mode 100644 index 7f9e04782..000000000 --- a/include/dsa/keyiterator.h +++ /dev/null @@ -1,249 +0,0 @@ -//===- keyiterator.h - Iterator over just the keys in a map -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Implement a map key iterator -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_KEYITERATOR_H -#define LLVM_KEYITERATOR_H - -#include - -//From SGI's STL - -// select1st and select2nd are extensions: they are not part of the standard. - -template -class _Select1st : public std::unary_function<_Pair, typename _Pair::first_type> { -public: - - const typename _Pair::first_type & operator()(const _Pair& __x) const { - return __x.first; - } -}; - -template -class _Select2nd : public std::unary_function<_Pair, typename _Pair::second_type> { -public: - - const typename _Pair::second_type & operator()(const _Pair& __x) const { - return __x.second; - } -}; - -template class select1st : public _Select1st<_Pair> { -}; - -template class select2nd : public _Select2nd<_Pair> { -}; - - -// ref_mapped_iterator - This is a simple iterator adapter that causes a -// function to be dereferenced whenever operator* is invoked on the iterator. -// It is assumed that the function returns a valid reference, which differs -// from llvm::mapped_iterator from which this was derived (copied) - -template -class ref_mapped_iterator { - RootIt current; - UnaryFunc Fn; -public: - typedef typename std::iterator_traits::iterator_category - iterator_category; - typedef typename std::iterator_traits::difference_type - difference_type; - typedef typename UnaryFunc::result_type value_type; - - typedef typename UnaryFunc::result_type *pointer; - typedef typename UnaryFunc::result_type& reference; - - typedef RootIt iterator_type; - typedef ref_mapped_iterator _Self; - - inline const RootIt &getCurrent() const { - return current; - } - - inline const UnaryFunc &getFunc() const { - return Fn; - } - - inline explicit ref_mapped_iterator(const RootIt &I, UnaryFunc F) - : current(I), Fn(F) { } - - inline ref_mapped_iterator(const ref_mapped_iterator &It) - : current(It.current), Fn(It.Fn) { } - - inline reference operator*() const { // All this work to do this - return Fn(*current); // little change - } - - _Self & operator++() { - ++current; - return *this; - } - - _Self & operator--() { - --current; - return *this; - } - - _Self operator++(int) { - _Self __tmp = *this; - ++current; - return __tmp; - } - - _Self operator--(int) { - _Self __tmp = *this; - --current; - return __tmp; - } - - _Self operator+(difference_type n) const { - return _Self(current + n, Fn); - } - - _Self & operator+=(difference_type n) { - current += n; - return *this; - } - - _Self operator-(difference_type n) const { - return _Self(current - n, Fn); - } - - _Self & operator-=(difference_type n) { - current -= n; - return *this; - } - - reference operator[](difference_type n) const { - return *(*this +n); - } - - inline bool operator!=(const _Self &X) const { - return !operator==(X); - } - - inline bool operator==(const _Self &X) const { - return current == X.current; - } - - inline bool operator<(const _Self &X) const { - return current < X.current; - } - - inline difference_type operator-(const _Self &X) const { - return current - X.current; - } -}; - -template -class KeyIterator -: public ref_mapped_iterator > { - typedef select1st FunTy; -public: - - KeyIterator(const Iter I) - : ref_mapped_iterator >(I, FunTy()) { } -}; - -template -class ValueIterator -: public ref_mapped_iterator > { - typedef select2nd FunTy; -public: - - ValueIterator(const Iter I) - : ref_mapped_iterator >(I, FunTy()) { } -}; - - -#if 0 - -template -class KeyIterator { - Iter I; - -public: - typedef typename Iter::difference_type difference_type; - typedef typename Iter::value_type::first_type value_type; - typedef typename Iter::value_type::first_type* pointer; - typedef typename Iter::value_type::first_type& reference; - typedef typename Iter::iterator_category iterator_category; - - KeyIterator(Iter i) : I(i) { } - - Iter base() const { - return I; - } - - reference operator*() const { - return I->first; - } - - KeyIterator operator+(difference_type n) const { - return KeyIterator(I + n); - } - - KeyIterator & operator++() { - ++I; - return *this; - } - - KeyIterator operator++(int) { - Iter OI = I; - ++I; - return KeyIterator(OI); - } - - KeyIterator & operator+=(difference_type n) { - I += n; - return *this; - } - - KeyIterator operator-(difference_type n) const { - return KeyIterator(I - n); - } - - KeyIterator & operator--() { - --I; - return *this; - } - - KeyIterator operator--(int) { - Iter OI = I; - --I; - return KeyIterator(OI); - } - - KeyIterator & operator-=(difference_type n) { - I -= n; - return *this; - } - - pointer operator->() const { - return &I->first; - } - - bool operator==(const KeyIterator& RHS) const { - return I == RHS.I; - } - - bool operator!=(const KeyIterator& RHS) const { - return I != RHS.I; - } -}; -#endif - - -#endif /* LLVM_KEYITERATOR_H */ - diff --git a/include/dsa/stl_util.h b/include/dsa/stl_util.h deleted file mode 100644 index 9366e1af4..000000000 --- a/include/dsa/stl_util.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef _DSA_STL_UTIL_H_ -#define _DSA_STL_UTIL_H_ - -#include "llvm/ADT/ilist.h" -#include -#include -#include - -namespace llvm { - -// Splicing one container into another as efficiently as we can -template -inline void splice(std::list& Dst, std::list& Src) { - Dst.splice(Dst.end(), Src); -} -template -inline void splice(ilist& Dst, ilist& Src) { - Dst.splice(Dst.end(), Src); -} - -template -static void splice(std::vector& Dst, std::vector& Src) { - if (Dst.empty()) - Dst.swap(Src); - else { - Dst.insert(Dst.end(), Src.begin(), Src.end()); - Src.clear(); - } -} - -template -inline void splice(std::map& Dst, std::map& Src) { - if (Dst.empty()) - Dst.swap(Src); - else { - Dst.insert(Src.begin(), Src.end()); - Src.clear(); - } -} - -// Efficient sort -template -inline void sort(std::vector& L) { - std::sort(L.begin(), L.end()); -} - -template -inline void sort(std::list& L) { - L.sort(); -} - -} // end namespace llvm -#endif // _DSA_STL_UTIL_H_ - diff --git a/include/dsa/super_set.h b/include/dsa/super_set.h deleted file mode 100644 index 0d1aa2915..000000000 --- a/include/dsa/super_set.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * File: super_set.h - * Author: andrew - * - * Created on March 10, 2010, 2:04 PM - */ - -#ifndef _SUPER_SET_H -#define _SUPER_SET_H - -#include "dsa/svset.h" -#include - -// Contains stable references to a set -// The sets can be grown. - -template -class SuperSet { - //std::set provides stable iterators, and that matters a lot - typedef svset InnerSetTy; - typedef std::set OuterSetTy; - OuterSetTy container; -public: - typedef const typename OuterSetTy::value_type* setPtr; - - setPtr getOrCreate(svset& S) { - if (S.empty()) return 0; - return &(*container.insert(S).first); - } - - setPtr getOrCreate(setPtr P, Ty t) { - svset s; - if (P) - s.insert(P->begin(), P->end()); - s.insert(t); - return getOrCreate(s); - } -}; - - - -#endif /* _SUPER_SET_H */ - diff --git a/include/dsa/svset.h b/include/dsa/svset.h deleted file mode 100644 index d39eea6f9..000000000 --- a/include/dsa/svset.h +++ /dev/null @@ -1,240 +0,0 @@ -#ifndef _SV_ORDERED_SET_HH_ -#define _SV_ORDERED_SET_HH_ 1 - -#include -#include -#include - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// A set implemented atop a sorted vector. -/// Iterators are not stable accross insert or delete -template< typename Key, - typename Compare = std::less, - typename Alloc = std::allocator > -class svset { - typedef std::vector internal_type; - -// Types -public: - - typedef Key key_type; - typedef Key value_type; - typedef Compare key_compare; - typedef Compare value_compare; - typedef Alloc allocator_type; - typedef typename Alloc::reference reference; - typedef typename Alloc::const_reference const_reference; - typedef typename Alloc::pointer pointer; - typedef typename Alloc::const_pointer const_pointer; - typedef typename internal_type::const_iterator const_iterator; - typedef typename internal_type::iterator iterator; - typedef typename internal_type::reverse_iterator reverse_iterator; - typedef typename internal_type::const_reverse_iterator const_reverse_iterator; - typedef typename internal_type::size_type size_type; - typedef typename internal_type::difference_type difference_type; - -private: - - internal_type container_; - - void sort_unique() { - std::sort(container_.begin(), container_.end()); - iterator i = std::unique(container_.begin(), container_.end()); - container_.erase(i, container_.end()); - } - -public: - /// Empty constructor. - svset() - : container_() { } - - /// Constructor taking a range. - template< typename Iterator > - svset(const Iterator& begin, const Iterator& end) - : container_(begin, end) { - sort_unique(); - } - - /// Copy-constructor. - svset(const svset& rhs) - : container_(rhs.container_) - {} - - /// Affectation of a sorted vector to another one. - - svset & operator=(const svset& rhs) { - if (&rhs != this) { - this->container_ = rhs.container_; - } - return *this; - } - - /// Returns the beginning of the sorted vector. - const_iterator begin() const { - return container_.begin(); - } - - /// Returns the end of the sorted vector. - const_iterator end() const { - return container_.end(); - } - - /// Returns the beginning of the sorted vector. - iterator begin() { - return container_.begin(); - } - - /// Returns the end of the sorted vector. - iterator end() { - return container_.end(); - } - - /// Returns the beginning of the sorted vector. - const_reverse_iterator rrbegin() const { - return container_.rbegin(); - } - - /// Returns the end of the sorted vector. - const_reverse_iterator rend() const { - return container_.rend(); - } - - /// Returns the beginning of the sorted vector. - reverse_iterator rbegin() { - return container_.rbegin(); - } - - /// Returns the end of the sorted vector. - reverse_iterator rend() { - return container_.rend(); - } - - bool empty() const { - return container_.empty(); - } - - size_type size() const { - return container_.size(); - } - - size_type max_size() const { - return container_.max_size(); - } - - /// Insert a value into the sorted vector. - std::pair - insert(const value_type& x) { - bool insertion = false; - iterator i = std::lower_bound(container_.begin(), container_.end(), x); - if (i == container_.end() || x < *i) { - i = container_.insert(i, x); - insertion = true; - } - return std::make_pair(i, insertion); - } - - /// Insert a value into the sorted vector. - iterator insert(iterator position, const value_type& x) { - return insert(x).first; - } - - /// Insert a range. - template < typename Iterator > - void insert(Iterator _begin, Iterator _end) { - while (_begin != _end) - container_.push_back(*_begin++); - sort_unique(); - } - - //specialized insert for another svset - void insert(const_iterator ii, const_iterator ie ) { - internal_type ctemp; - ctemp.reserve(container_.size()); - std::set_union(ii, ie, container_.begin(), container_.end(), - std::back_inserter(ctemp)); - container_.swap(ctemp); - } - - iterator erase ( iterator position ) { - return container_.erase(position); - } - - size_type erase(const key_type& x) { - iterator i = find(x); - if (i != end()) { - erase(i); - return 1; - } - return 0; - } - - iterator erase ( iterator first, iterator last ) { - return container_.erase(first, last); - } - - /// Swap the content of two sorted_vector. - void swap(svset& s) { - container_.swap(s.container_); - } - - void clear() { - container_.clear(); - } - - /// Find the key k. - - const_iterator find(const key_type& k) const { - const_iterator i = std::lower_bound(container_.begin(), container_.end(), k); - if (i != container_.end() && *i == k) return i; - return container_.end(); - } - - iterator find(const key_type& k) { - iterator i = std::lower_bound(container_.begin(), container_.end(), k); - if (i != container_.end() && *i == k) return i; - return container_.end(); - } - - bool count(const key_type& k) const { - return find(k) != end(); - } - - iterator lower_bound(const key_type& x) const { - return std::lower_bound(container_.begin(), container_.end(), x); - } - - iterator upper_bound(const key_type& x) const { - return std::upper_bound(container_.begin(), container_.end(), x); - } - - std::pair equal_range(const key_type& x) const { - return std::make_pair(lower_bound(x),upper_bound(x)); - } - - - /// Tells if this sorted vector is equal to another one. - bool operator==(const svset& rhs) const { - return container_ == rhs.container_; - } - bool operator<(const svset& rhs) const { - if (rhs.size() < size()) return false; - if (size() < rhs.size()) return true; - const_iterator ii = begin(); - const_iterator ee = end(); - const_iterator rhs_ii = rhs.begin(); - while (ii != ee) { - if (*rhs_ii < *ii) return false; - if (*ii < *rhs_ii) return true; - ++ii; - ++rhs_ii; - } - // Equal - return false; - } - -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -#endif // _SV_ORDERED_SET_HH_ diff --git a/include/smack/DSAWrapper.h b/include/smack/DSAWrapper.h index ef009069d..1e16f1c53 100644 --- a/include/smack/DSAWrapper.h +++ b/include/smack/DSAWrapper.h @@ -7,52 +7,32 @@ #ifndef DSAWRAPPER_H #define DSAWRAPPER_H -#include "llvm/Analysis/MemoryLocation.h" -#include "llvm/IR/InstVisitor.h" +#include #include -namespace llvm { -class DSNode; -class DSGraph; -class TDDataStructures; -class BUDataStructures; -class DSNodeEquivs; -} // namespace llvm - -namespace dsa { -template struct TypeSafety; -} +#include "sea_dsa/DsaAnalysis.hh" +#include "sea_dsa/Global.hh" +#include "sea_dsa/Graph.hh" namespace smack { -class MemcpyCollector : public llvm::InstVisitor { -private: - llvm::DSNodeEquivs *nodeEqs; - std::vector memcpys; - -public: - MemcpyCollector(llvm::DSNodeEquivs *neqs) : nodeEqs(neqs) {} - void visitMemCpyInst(llvm::MemCpyInst &mci); - std::vector getMemcpys() { return memcpys; } -}; - class DSAWrapper : public llvm::ModulePass { private: llvm::Module *module; - llvm::TDDataStructures *TD; - llvm::BUDataStructures *BU; - llvm::DSNodeEquivs *nodeEqs; - dsa::TypeSafety *TS; - std::vector staticInits; - std::vector memcpys; - std::unordered_set intConversions; + sea_dsa::GlobalAnalysis *SD; + // The ds graph since we're using the context-insensitive version which + // results in one graph for the whole module. + sea_dsa::Graph *DG; + std::unordered_set staticInits; + std::unordered_set memOpds; + // Mapping from the DSNodes associated with globals to the numbers of + // globals associated with them. + std::unordered_map globalRefCount; const llvm::DataLayout *dataLayout; - std::vector collectMemcpys(llvm::Module &M, - MemcpyCollector *mcc); - std::vector collectStaticInits(llvm::Module &M); - llvm::DSGraph *getGraphForValue(const llvm::Value *V); - int getOffset(const llvm::MemoryLocation *l); + void collectStaticInits(llvm::Module &M); + void collectMemOpds(llvm::Module &M); + void countGlobalRefs(); public: static char ID; @@ -61,18 +41,15 @@ class DSAWrapper : public llvm::ModulePass { virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const; virtual bool runOnModule(llvm::Module &M); - bool isMemcpyd(const llvm::DSNode *n); - bool isStaticInitd(const llvm::DSNode *n); - bool isFieldDisjoint(const llvm::Value *V, const llvm::Function *F); - bool isFieldDisjoint(const llvm::GlobalValue *V, unsigned offset); + bool isStaticInitd(const sea_dsa::Node *n); + bool isMemOpd(const sea_dsa::Node *n); bool isRead(const llvm::Value *V); - bool isAlloced(const llvm::Value *v); - bool isExternal(const llvm::Value *v); bool isSingletonGlobal(const llvm::Value *V); unsigned getPointedTypeSize(const llvm::Value *v); - int getOffset(const llvm::Value *v); - const llvm::DSNode *getNode(const llvm::Value *v); - void printDSAGraphs(const char *Filename); + unsigned getOffset(const llvm::Value *v); + const sea_dsa::Node *getNode(const llvm::Value *v); + bool isTypeSafe(const llvm::Value *v); + unsigned getNumGlobals(const sea_dsa::Node *n); }; } // namespace smack diff --git a/include/smack/Regions.h b/include/smack/Regions.h index a5b903107..efc1903b9 100644 --- a/include/smack/Regions.h +++ b/include/smack/Regions.h @@ -4,6 +4,7 @@ #ifndef REGIONS_H #define REGIONS_H +#include "sea_dsa/Graph.hh" #include "llvm/IR/InstVisitor.h" using namespace llvm; @@ -19,7 +20,7 @@ class DSAWrapper; class Region { private: LLVMContext *context; - const DSNode *representative; + const sea_dsa::Node *representative; const Type *type; unsigned offset; unsigned length; @@ -33,12 +34,10 @@ class Region { static const DataLayout *DL; static DSAWrapper *DSA; - // static DSNodeEquivs* NEQS; - static bool isSingleton(const DSNode *N, unsigned offset, unsigned length); - static bool isAllocated(const DSNode *N); - static bool bytewiseAccess(const DSNode *N); - static bool isComplicated(const DSNode *N); + static bool isSingleton(const llvm::Value *v, unsigned length); + static bool isAllocated(const sea_dsa::Node *N); + static bool isComplicated(const sea_dsa::Node *N); void init(const Value *V, unsigned length); bool isDisjoint(unsigned offset, unsigned length); @@ -89,7 +88,8 @@ class Regions : public ModulePass, public InstVisitor { void visitStoreInst(StoreInst &); void visitAtomicCmpXchgInst(AtomicCmpXchgInst &); void visitAtomicRMWInst(AtomicRMWInst &); - void visitMemIntrinsic(MemIntrinsic &); + void visitMemSetInst(MemSetInst &); + void visitMemTransferInst(MemTransferInst &); void visitCallInst(CallInst &); }; } // namespace smack diff --git a/include/assistDS/Devirt.h b/include/utils/Devirt.h similarity index 92% rename from include/assistDS/Devirt.h rename to include/utils/Devirt.h index c6d7a9d3b..1aad10057 100644 --- a/include/assistDS/Devirt.h +++ b/include/utils/Devirt.h @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -#include "dsa/CallTargets.h" #include "llvm/IR/Constants.h" #include "llvm/Transforms/IPO.h" @@ -24,6 +23,10 @@ #include "llvm/IR/InstVisitor.h" #include "llvm/IR/DataLayout.h" +#include "sea_dsa/CompleteCallGraph.hh" + +#include + using namespace llvm; namespace llvm { @@ -38,7 +41,7 @@ namespace llvm { class Devirtualize : public ModulePass, public InstVisitor { private: // Access to analysis pass which finds targets of indirect function calls - dsa::CallTargetFinder *CTF; + sea_dsa::CompleteCallGraph *CCG; // Access to the target data analysis pass const DataLayout * TD; @@ -57,12 +60,12 @@ namespace llvm { public: static char ID; - Devirtualize() : ModulePass(ID), CTF(0) {} + Devirtualize() : ModulePass(ID) {} virtual bool runOnModule(Module & M); virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired >(); + AU.addRequired(); } // Visitor methods for analyzing instructions diff --git a/include/assistDS/LICENSE.TXT b/include/utils/LICENSE.TXT similarity index 100% rename from include/assistDS/LICENSE.TXT rename to include/utils/LICENSE.TXT diff --git a/include/assistDS/MergeGEP.h b/include/utils/MergeGEP.h similarity index 100% rename from include/assistDS/MergeGEP.h rename to include/utils/MergeGEP.h diff --git a/include/assistDS/SimplifyExtractValue.h b/include/utils/SimplifyExtractValue.h similarity index 100% rename from include/assistDS/SimplifyExtractValue.h rename to include/utils/SimplifyExtractValue.h diff --git a/include/assistDS/SimplifyInsertValue.h b/include/utils/SimplifyInsertValue.h similarity index 100% rename from include/assistDS/SimplifyInsertValue.h rename to include/utils/SimplifyInsertValue.h diff --git a/lib/AssistDS/ArgCast.cpp b/lib/AssistDS/ArgCast.cpp deleted file mode 100644 index 796867b05..000000000 --- a/lib/AssistDS/ArgCast.cpp +++ /dev/null @@ -1,218 +0,0 @@ -//===-------- ArgCast.cpp - Cast Arguments to Calls -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Convert -// call(bitcast (.., T1 arg, ...)F to(..., T2 arg, ...))(..., T2 val, ...) -// to -// val1 = bitcast T2 val to T1 -// call F (..., T1 val1, ...) -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "argcast" - -#include "assistDS/ArgCast.h" -#include "llvm/IR/Attributes.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" - -#include -#include -#include - -using namespace llvm; - -// Pass statistics -STATISTIC(numChanged, "Number of Args bitcasted"); - -// -// Method: runOnModule() -// -// Description: -// Entry point for this LLVM pass. -// Search for all call sites to casted functions. -// Check if they only differ in an argument type -// Cast the argument, and call the original function -// -// Inputs: -// M - A reference to the LLVM module to transform -// -// Outputs: -// M - The transformed LLVM module. -// -// Return value: -// true - The module was modified. -// false - The module was not modified. -// -bool ArgCast::runOnModule(Module& M) { - - std::vector worklist; - for (Function &F : M) { - if (F.isInterposable()) - continue; - // Find all uses of this function - for (User *U : F.users()) { - // check if is ever casted to a different function type - ConstantExpr *CE = dyn_cast(U++); - if(!CE) - continue; - if (CE->getOpcode() != Instruction::BitCast) - continue; - if(CE->getOperand(0) != &F) - continue; - const PointerType *PTy = dyn_cast(CE->getType()); - if (!PTy) - continue; - const Type *ETy = PTy->getElementType(); - const FunctionType *FTy = dyn_cast(ETy); - if(!FTy) - continue; - // casting to a varargs funtion - // or function with same number of arguments - // possibly varying types of arguments - - if(FTy->getNumParams() != F.arg_size() && !FTy->isVarArg()) - continue; - for(Value::user_iterator uii = CE->user_begin(), - uee = CE->user_end(); uii != uee; ++uii) { - // Find all uses of the casted value, and check if it is - // used in a Call Instruction - if (CallInst* CI = dyn_cast(*uii)) { - // Check that it is the called value, and not an argument - if(CI->getCalledValue() != CE) - continue; - // Check that the number of arguments passed, and expected - // by the function are the same. - if(!F.isVarArg()) { - if(CI->getNumOperands() != F.arg_size() + 1) - continue; - } else { - if(CI->getNumOperands() < F.arg_size() + 1) - continue; - } - // If so, add to worklist - worklist.push_back(CI); - } - } - } - } - - // Proces the worklist of potential call sites to transform - while(!worklist.empty()) { - CallInst *CI = worklist.back(); - worklist.pop_back(); - // Get the called Function - Function *F = cast(CI->getCalledValue()->stripPointerCasts()); - const FunctionType *FTy = F->getFunctionType(); - - SmallVector Args; - unsigned i =0; - for(i =0; i< FTy->getNumParams(); ++i) { - Type *ArgType = CI->getOperand(i+1)->getType(); - Type *FormalType = FTy->getParamType(i); - // If the types for this argument match, just add it to the - // parameter list. No cast needs to be inserted. - if(ArgType == FormalType) { - Args.push_back(CI->getOperand(i+1)); - } - else if(ArgType->isPointerTy() && FormalType->isPointerTy()) { - CastInst *CastI = CastInst::CreatePointerCast(CI->getOperand(i+1), - FormalType, "", CI); - Args.push_back(CastI); - } else if (ArgType->isIntegerTy() && FormalType->isIntegerTy()) { - unsigned SrcBits = ArgType->getScalarSizeInBits(); - unsigned DstBits = FormalType->getScalarSizeInBits(); - if(SrcBits > DstBits) { - CastInst *CastI = CastInst::CreateIntegerCast(CI->getOperand(i+1), - FormalType, true, "", CI); - Args.push_back(CastI); - } else { - if (F->getAttributes().hasAttribute(i+1, Attribute::SExt)) { - CastInst *CastI = CastInst::CreateIntegerCast(CI->getOperand(i+1), - FormalType, true, "", CI); - Args.push_back(CastI); - } else if (F->getAttributes().hasAttribute(i+1, Attribute::ZExt)) { - CastInst *CastI = CastInst::CreateIntegerCast(CI->getOperand(i+1), - FormalType, false, "", CI); - Args.push_back(CastI); - } else { - // Use ZExt in default case. - // Derived from InstCombine. Also, the only reason this should happen - // is mismatched prototypes. - // Seen in case of integer constants which get interpreted as i32, - // even if being used as i64. - // TODO: is this correct? - CastInst *CastI = CastInst::CreateIntegerCast(CI->getOperand(i+1), - FormalType, false, "", CI); - Args.push_back(CastI); - } - } - } else { - SDEBUG(ArgType->print(smack::dbgs(), true)); - SDEBUG(FormalType->print(smack::dbgs(), true)); - break; - } - } - - // If we found an argument we could not cast, try the next instruction - if(i != FTy->getNumParams()) { - continue; - } - - if(FTy->isVarArg()) { - for(; i< CI->getNumOperands() - 1 ;i++) { - Args.push_back(CI->getOperand(i+1)); - } - } - - // else replace the call instruction - CallInst *CINew = CallInst::Create(F, Args, "", CI); - CINew->setCallingConv(CI->getCallingConv()); - CINew->setAttributes(CI->getAttributes()); - if(!CI->use_empty()) { - CastInst *RetCast; - if(CI->getType() != CINew->getType()) { - if(CI->getType()->isPointerTy() && CINew->getType()->isPointerTy()) - RetCast = CastInst::CreatePointerCast(CINew, CI->getType(), "", CI); - else if(CI->getType()->isIntOrIntVectorTy() && CINew->getType()->isIntOrIntVectorTy()) - RetCast = CastInst::CreateIntegerCast(CINew, CI->getType(), false, "", CI); - else if(CI->getType()->isIntOrIntVectorTy() && CINew->getType()->isPointerTy()) - RetCast = CastInst::CreatePointerCast(CINew, CI->getType(), "", CI); - else if(CI->getType()->isPointerTy() && CINew->getType()->isIntOrIntVectorTy()) - RetCast = new IntToPtrInst(CINew, CI->getType(), "", CI); - else { - // TODO: I'm not sure what right behavior is here, but this case should be handled. - llvm_unreachable("Unexpected type conversion in call!"); - abort(); - } - CI->replaceAllUsesWith(RetCast); - } else { - CI->replaceAllUsesWith(CINew); - } - } - - // Debug printing - SDEBUG(errs() << "ARGCAST:"); - SDEBUG(errs() << "ERASE:"); - SDEBUG(CI->print(smack::dbgs(), true)); - SDEBUG(errs() << "ARGCAST:"); - SDEBUG(errs() << "ADDED:"); - SDEBUG(CINew->print(smack::dbgs(), true)); - - CI->eraseFromParent(); - numChanged++; - } - return true; -} - -// Pass ID variable -char ArgCast::ID = 0; - -// Register the pass -static RegisterPass -X("arg-cast", "Cast Arguments"); diff --git a/lib/AssistDS/ArgSimplify.cpp b/lib/AssistDS/ArgSimplify.cpp deleted file mode 100644 index 2ddb0521a..000000000 --- a/lib/AssistDS/ArgSimplify.cpp +++ /dev/null @@ -1,173 +0,0 @@ -//===-- ArgSimplify.cpp - Special case for conditional ptr args ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "argsimpl" - -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" - -#include -#include -#include - -using namespace llvm; - -STATISTIC(numTransformable, "Number of Args changeable"); - -namespace { - - // F - Function to modify - // arg_count - The argument to function I that may be changed - // type - Declared type of the argument - - static void simplify(Function *F, unsigned arg_count, Type* type) { - - // Go through all uses of the function - for(Value::user_iterator ui = F->user_begin(), ue = F->user_end(); - ui != ue; ++ui) { - - if (Constant *C = dyn_cast(*ui)) { - if (ConstantExpr *CE = dyn_cast(C)) { - if (CE->getOpcode() == Instruction::BitCast) { - if(CE->getOperand(0) == F) { - for(Value::user_iterator uii = CE->user_begin(), uee = CE->user_end(); - uii != uee; ) { - // check if it is ever used as a call (bitcast F to ...)() - if (CallInst* CI = dyn_cast(*uii++)) { - if(CI->getCalledValue() == CE) { - // if I is ever called as a bitcasted function - if(F->getReturnType() == CI->getType()){ - // if the return types match. - if(F->arg_size() == (CI->getNumOperands()-1)){ - // and the numeber of args match too - unsigned arg_count1 = 1; - bool change = true; - for (Function::arg_iterator ii1 = F->arg_begin(), ee1 = F->arg_end(); - ii1 != ee1; ++ii1,arg_count1++) { - if(arg_count1 == (arg_count + 1)) { - if(ii1->getType() == CI->getOperand(arg_count1)->getType()){ - change = false; - break; - } - else - continue; - } - if(ii1->getType() != CI->getOperand(arg_count1)->getType()) { - change = false; - break; - } - } - // if all types match except the argument we are interested in - - if(change){ - // create a new function, to do the cast from ptr to int, - // and call the original function, with the casted value - std::vectorTP; - for(unsigned c = 1; cgetNumOperands();c++) { - TP.push_back(CI->getOperand(c)->getType()); - } - FunctionType *NewFTy = FunctionType:: - get(CI->getType(), TP, false); - - Module *M = F->getParent(); - Function *NewF = Function::Create(NewFTy, - GlobalValue::InternalLinkage, - "argbounce", - M); - std::vector fargs; - for (auto &Arg : NewF->args()) { - fargs.push_back(&Arg); - Arg.setName("arg"); - } - Value *CastedVal; - BasicBlock* entryBB = BasicBlock:: - Create (M->getContext(), "entry", NewF); - - Type *FromTy = fargs.at(arg_count)->getType(); - if(FromTy->isPointerTy()) { - CastedVal = CastInst::CreatePointerCast(fargs.at(arg_count), - type, "castd", entryBB); - } else { - CastedVal = CastInst::CreateIntegerCast(fargs.at(arg_count), - type, false, "casted", entryBB); - } - - SmallVector Args; - for (auto &Arg : NewF->args()) { - if(Arg.getArgNo() == arg_count) - Args.push_back(CastedVal); - else - Args.push_back(&Arg); - } - - CallInst * CallI = CallInst::Create(F,Args, - "", entryBB); - if(CallI->getType()->isVoidTy()) - ReturnInst::Create(M->getContext(), entryBB); - else - ReturnInst::Create(M->getContext(), CallI, entryBB); - - CI->setCalledFunction(NewF); - numTransformable++; - } - } - } - } - } - } - } - } - } - } - } - } - - class ArgSimplify : public ModulePass { - public: - static char ID; - ArgSimplify() : ModulePass(ID) {} - - bool runOnModule(Module& M) { - - for (Function &F : M) - if (!F.isDeclaration() && !F.isInterposable()) { - if(F.getName().str() == "main") - continue; - std::vector Args; - for (auto &Arg : F.args()) { - bool change = true; - for (User *U : Arg.users()) { - // check if the argument is used exclusively in ICmp Instructions - if(!isa(U)) { - change = false; - break; - } - } - // if this argument is only used in ICMP instructions, we can - // replace it. - if(change) { - simplify(&F, Arg.getArgNo(), Arg.getType()); - } - } - } - - - return true; - } - }; -} - -char ArgSimplify::ID = 0; -static RegisterPass -X("arg-simplify", "Specialize for Conditional Arguments"); diff --git a/lib/AssistDS/DSNodeEquivs.cpp b/lib/AssistDS/DSNodeEquivs.cpp deleted file mode 100644 index 8a9052ea5..000000000 --- a/lib/AssistDS/DSNodeEquivs.cpp +++ /dev/null @@ -1,289 +0,0 @@ -//===- DSNodeEquivs.cpp - Build DSNode equivalence classes ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements a pass to compute DSNode equivalence classes across -// DSGraphs. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "DSNodeEquivs" -#include "assistDS/DSNodeEquivs.h" - -#include "llvm/IR/Constants.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/InstIterator.h" -#include "llvm/ADT/SmallSet.h" -#include "smack/Debug.h" - -#include - -namespace llvm { - -char DSNodeEquivs::ID = 0; - -static RegisterPass -X("dsnodeequivs", "Compute DSNode equivalence classes"); - -// Build equivalence classes of DSNodes that are mapped between graphs. -void DSNodeEquivs::buildDSNodeEquivs(Module &M) { - TDDataStructures &TDDS = getAnalysis(); - - Module::iterator FuncIt = M.begin(), FuncItEnd = M.end(); - for (; FuncIt != FuncItEnd; ++FuncIt) { - Function &F = *FuncIt; - - if (!TDDS.hasDSGraph(F)) - continue; - - inst_iterator InstIt = inst_begin(F), InstItEnd = inst_end(F); - for (; InstIt != InstItEnd; ++InstIt) { - if (CallInst *Call = dyn_cast(&*InstIt)) { - equivNodesThroughCallsite(Call); - } - } - - DSGraph *Graph = TDDS.getDSGraph(F); - - // Ensure all nodes from this function's graph are in an equivalence class. - addNodesFromGraph(Graph); - - equivNodesToGlobals(Graph); - } - - // Ensure all nodes from the globals graph are in an equivalence class. - addNodesFromGraph(TDDS.getGlobalsGraph()); -} - -// Add nodes from the given graph into the equivalence classes. -void DSNodeEquivs::addNodesFromGraph(DSGraph *Graph) { - DSGraph::node_iterator NodeIt = Graph->node_begin(); - DSGraph::node_iterator NodeItEnd = Graph->node_end(); - for (; NodeIt != NodeItEnd; ++NodeIt) - Classes.insert(&*NodeIt); -} - -FunctionList DSNodeEquivs::getCallees(CallSite &CS) { - const Function *CalledFunc = CS.getCalledFunction(); - - // If the called function is casted from one function type to another, peer - // into the cast instruction and pull out the actual function being called. - if (ConstantExpr *CExpr = dyn_cast(CS.getCalledValue())) { - if (CExpr->getOpcode() == Instruction::BitCast && - isa(CExpr->getOperand(0))) - CalledFunc = cast(CExpr->getOperand(0)); - } - - FunctionList Callees; - - // Direct calls are simple. - if (CalledFunc) { - Callees.push_back(CalledFunc); - return Callees; - } - - // Okay, indirect call. - // Ask the DSCallGraph what this calls... - - TDDataStructures &TDDS = getAnalysis(); - const DSCallGraph &DSCG = TDDS.getCallGraph(); - - DSCallGraph::callee_iterator CalleeIt = DSCG.callee_begin(CS); - DSCallGraph::callee_iterator CalleeItEnd = DSCG.callee_end(CS); - for (; CalleeIt != CalleeItEnd; ++CalleeIt) - Callees.push_back(*CalleeIt); - - // If the callgraph doesn't give us what we want, query the DSGraph - // ourselves. - if (Callees.empty()) { - Instruction *Inst = CS.getInstruction(); - Function *Parent = Inst->getParent()->getParent(); - Value *CalledValue = CS.getCalledValue(); - DSNodeHandle &NH = TDDS.getDSGraph(*Parent)->getNodeForValue(CalledValue); - - if (!NH.isNull()) { - DSNode *Node = NH.getNode(); - Node->addFullFunctionList(Callees); - } - } - - // For debugging, dump out the callsites we are unable to get callees for. - SDEBUG( - if (Callees.empty()) { - errs() << "Failed to get callees for callsite:\n"; - CS.getInstruction()->print(smack::dbgs(), true); - }); - - return Callees; -} - -// Compute mappings through the given call site. -void DSNodeEquivs::equivNodesThroughCallsite(CallInst *CI) { - TDDataStructures &TDDS = getAnalysis(); - DSGraph &Graph = *TDDS.getDSGraph(*CI->getParent()->getParent()); - CallSite CS(CI); - FunctionList Callees = getCallees(CS); - - FunctionList_it CalleeIt = Callees.begin(), CalleeItEnd = Callees.end(); - for (; CalleeIt != CalleeItEnd; ++CalleeIt) { - const Function &Callee = **CalleeIt; - - // We can't merge through graphs that don't exist. - if (!TDDS.hasDSGraph(Callee)) - continue; - - DSGraph &CalleeGraph = *TDDS.getDSGraph(Callee); - DSGraph::NodeMapTy NodeMap; - - // Heavily lifted/inspired by PA code - - // Map arguments - Function::const_arg_iterator FArgIt = Callee.arg_begin(); - Function::const_arg_iterator FArgItEnd = Callee.arg_end(); - CallSite::arg_iterator ArgIt = CS.arg_begin(), ArgItEnd = CS.arg_end(); - for (; FArgIt != FArgItEnd && ArgIt != ArgItEnd; ++FArgIt, ++ArgIt) { - if (isa(*ArgIt)) - continue; - - DSNodeHandle &CalleeArgNH = CalleeGraph.getNodeForValue(&*FArgIt); - DSNodeHandle &CSArgNH = Graph.getNodeForValue(*ArgIt); - DSGraph::computeNodeMapping(CalleeArgNH, CSArgNH, NodeMap, false); - } - - // Map return value - if (isa(CI->getType())) { - DSNodeHandle &CalleeRetNH = CalleeGraph.getReturnNodeFor(Callee); - DSNodeHandle &CINH = Graph.getNodeForValue(CI); - DSGraph::computeNodeMapping(CalleeRetNH, CINH, NodeMap, false); - } - - // Merge information from the computed node mapping into the equivalence - // classes. - equivNodeMapping(NodeMap); - } -} - -// Compute mappings with the globals graph. -void DSNodeEquivs::equivNodesToGlobals(DSGraph *G) { - DSGraph *GlobalsGr = G->getGlobalsGraph(); - DSGraph::NodeMapTy NodeMap; - DSScalarMap &ScalarMap = GlobalsGr->getScalarMap(); - - DSScalarMap::global_iterator GlobalIt = ScalarMap.global_begin(); - DSScalarMap::global_iterator GlobalItEnd = ScalarMap.global_end(); - for (; GlobalIt != GlobalItEnd; ++GlobalIt) { - const GlobalValue *Global = *GlobalIt; - - DSNode *LocalNode = G->getNodeForValue(Global).getNode(); - - // It's quite possible this (local) graph doesn't have this global. - // If that's the case, there's nothing to do here. - if (!LocalNode) continue; - - DSNode *GlobalNode = GlobalsGr->getNodeForValue(Global).getNode(); - assert(GlobalNode && "No node for global in global scalar map?"); - - // Map the two together and all reachable from each... - NodeMap.clear(); - DSGraph::computeNodeMapping(LocalNode, GlobalNode, NodeMap, false); - - // Build EC's with this mapping. - equivNodeMapping(NodeMap); - } -} - -// Utility function to put nodes that map together into equivalence classes. -void DSNodeEquivs::equivNodeMapping(DSGraph::NodeMapTy &NodeMap) { - DSGraph::NodeMapTy::iterator NodeMapIt = NodeMap.begin(); - DSGraph::NodeMapTy::iterator NodeMapItEnd = NodeMap.end(); - for (; NodeMapIt != NodeMapItEnd; ++NodeMapIt) { - DSNodeHandle &NH = NodeMapIt->second; - if (NH.isNull()) - continue; - - const DSNode *N1 = NodeMapIt->first; - const DSNode *N2 = NH.getNode(); - - Classes.unionSets(N1, N2); - } -} - -bool DSNodeEquivs::runOnModule(Module &M) { - buildDSNodeEquivs(M); - // Does not modify module. - return false; -} - -// Returns the computed equivalence classes. -const EquivalenceClasses & -DSNodeEquivs::getEquivalenceClasses() { - return Classes; -} - -// Returns a DSNode for the specified value. -// Returns null for a node that was not found. -const DSNode *DSNodeEquivs::getMemberForValue(const Value *V) { - TDDataStructures &TDDS = getAnalysis(); - DSNodeHandle *NHForV = 0; - - if (isa(V)) { - NHForV = &TDDS.getGlobalsGraph()->getNodeForValue(V); - } else if (isa(V)) { - const Function *Parent = cast(V)->getParent()->getParent(); - NHForV = &TDDS.getDSGraph(*Parent)->getNodeForValue(V); - } else if (isa(V)) { - const Function *Parent = cast(V)->getParent(); - NHForV = &TDDS.getDSGraph(*Parent)->getNodeForValue(V); - } else { - // - // Iterate over the users to attempt to discover a DSNode that the value - // maps to. - // - std::deque WL; - SmallSet Visited; - - for (auto U : V->users()) - WL.push_back(U); - - do { - const User *TheUser = WL.front(); - WL.pop_front(); - - if (!Visited.insert(TheUser).second) - continue; - - // - // If the use is a global variable or instruction, then the value should - // be in the corresponding DSGraph. - // - // TODO: Is it possible for a value to belong to some DSGraph and never - // be relied upon by a GlobalValue or Instruction? - // - if (const Instruction *I = dyn_cast(TheUser)) { - const Function *Parent = I->getParent()->getParent(); - NHForV = &TDDS.getDSGraph(*Parent)->getNodeForValue(V); - break; - } else if (isa(TheUser)) { - NHForV = &TDDS.getGlobalsGraph()->getNodeForValue(V); - break; - } else { - // - // If this use is of some other nature, look at the users of this use. - // - for (auto U : TheUser->users()) - WL.push_back(U); - } - } while (!WL.empty()); - } - - assert(NHForV && "Unable to find node handle for given value!"); - - return NHForV->getNode(); -} - -} diff --git a/lib/AssistDS/DataStructureCallGraph.cpp b/lib/AssistDS/DataStructureCallGraph.cpp deleted file mode 100644 index ab373174f..000000000 --- a/lib/AssistDS/DataStructureCallGraph.cpp +++ /dev/null @@ -1,125 +0,0 @@ -//===- DataStructureCallGraph.cpp - Provide a CallGraph using DSA ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains the DataStructureCallGraph implementation of the -// CallGraph analysis. Based on llvm/lib/Analysis/IPA/CallGraph.cpp. -// -//===----------------------------------------------------------------------===// - -#include "assistDS/DataStructureCallGraph.h" -#include "dsa/DSGraph.h" -#include "dsa/DSNode.h" - -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/CallSite.h" -#include "llvm/IR/InstIterator.h" - -using namespace llvm; - -char DataStructureCallGraph::ID; - -namespace { - -static RegisterPass -X("dsa-cg", "DSA-based CallGraph implementation"); - -RegisterAnalysisGroup Y(X); - -} - -bool DataStructureCallGraph::runOnModule(Module &M) { - ExternalCallingNode = getOrInsertFunction(0); - CallsExternalNode = new CallGraphNode(0); - Root = 0; - - // Add every function to the call graph. - for (Function &F : M) - addToCallGraph(&F); - - // If we didn't find a main function, use the external call graph node - if (Root == 0) Root = ExternalCallingNode; - - return false; -} - -// Add a function to the call graph, and link the node to all of the functions -// that it calls. -void DataStructureCallGraph::addToCallGraph(Function *F) { - CallGraphNode *Node = getOrInsertFunction(F); - - if (!F->hasLocalLinkage()) { - ExternalCallingNode->addCalledFunction(CallSite(), Node); - - // Found the entry point? - if (F->getName() == "main") { - if (Root) // Found multiple external mains? Don't pick one. - Root = ExternalCallingNode; - else - Root = Node; // Found a main, keep track of it! - } - } - - // If this function is not defined in this translation unit, it could call - // anything. - if (F->isDeclaration() && !F->isIntrinsic()) { - Node->addCalledFunction(CallSite(), CallsExternalNode); - return; - } - - TDDataStructures &DS = getAnalysis(); - DSGraph &GG = *DS.getGlobalsGraph(); - CallTargetFinderTy &CTF = getAnalysis(); - - // Determine if the function can be called by external code by looking up - // its DSNode in the globals graph. A node marked External, Unknown, or - // Incomplete has the possibility of being called from external code. - DSNode *N = GG.getNodeForValue(F).getNode(); - - if (N && - (N->isExternalNode() || - N->isUnknownNode() || - N->isIncompleteNode())) { - ExternalCallingNode->addCalledFunction(CallSite(), Node); - } - - // Go over the instructions in the function and determine the call targets - // for each call site. - for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { - CallSite CS(&*I); - - // Only look through valid call sites that are not calls to intrinsics. - if (!CS || isa(&*I)) - continue; - - if (const Function *F = - dyn_cast(CS.getCalledValue()->stripPointerCasts())) { - // Direct call: Don't use DSA, just add the function we discovered as - // the call target. - - Node->addCalledFunction(CS, getOrInsertFunction(F)); - } else { - // Indirect call: Use CallTargetFinder to determine the set of targets to - // the indirect call site. Be conservative about incomplete call sites. - - if (!CTF.isComplete(CS)) { - // Add CallsExternalNode as a target of incomplete call sites. - Node->addCalledFunction(CS, CallsExternalNode); - } - - SmallPtrSet Targets(CTF.begin(CS), CTF.end(CS)); - - for (SmallPtrSet::const_iterator - TI = Targets.begin(), TE = Targets.end(); TI != TE; ++TI) { - Node->addCalledFunction(CS, getOrInsertFunction(*TI)); - } - } - } -} diff --git a/lib/AssistDS/DynCount.cpp b/lib/AssistDS/DynCount.cpp deleted file mode 100644 index de0e0459a..000000000 --- a/lib/AssistDS/DynCount.cpp +++ /dev/null @@ -1,140 +0,0 @@ -//===- Dyncount.cpp - Test pass for using constraints -----------*- C++ -*-===// -// -// The SAFECode Compiler -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements a test pass which helps test the generation of formulas -// and constraints. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Pass.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DataLayout.h" -#include "dsa/TypeSafety.h" - -using namespace llvm; -class Dyncount : public ModulePass { -protected: - void instrumentLoad (GlobalVariable * Counter, LoadInst * LI); - void instrumentStore (GlobalVariable * Counter, StoreInst * SI); - dsa::TypeSafety *TS; - -public: - static char ID; - Dyncount () : ModulePass (ID) { } - virtual StringRef getPassName() const { - return "Count safe/unsafe load/store"; - } - virtual bool runOnModule (Module & M); - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired >(); - } -}; - -char Dyncount::ID = 0; -static RegisterPass -X ("dyncount", "Instrument code to count number of Load/Stores"); - - -void -Dyncount::instrumentLoad (GlobalVariable * Counter, LoadInst * LI) { - // - // Generate a load, increment, and store right before the GEP. - // - LLVMContext & Context = Counter->getParent()->getContext(); - ConstantInt * One = ConstantInt::get (Type::getInt64Ty(Context), 1); - LoadInst * OldValue = new LoadInst (Counter, "count", LI); - Instruction * NewValue = BinaryOperator::Create (BinaryOperator::Add, - OldValue, - One, - "count", - LI); - new StoreInst (NewValue, Counter, LI); - return; -} -void -Dyncount::instrumentStore (GlobalVariable * Counter, StoreInst * SI) { - // - // Generate a load, increment, and store right before the GEP. - // - LLVMContext & Context = Counter->getParent()->getContext(); - ConstantInt * One = ConstantInt::get (Type::getInt64Ty(Context), 1); - LoadInst * OldValue = new LoadInst (Counter, "count", SI); - Instruction * NewValue = BinaryOperator::Create (BinaryOperator::Add, - OldValue, - One, - "count", - SI); - new StoreInst (NewValue, Counter, SI); - return; -} - -// -// Method: runOnModule() -// -// Description: -// Entry point for this pass. -// -bool -Dyncount::runOnModule (Module & M) { - // - // Create two global counters within the module. - // - TS = &getAnalysis >(); - ConstantInt * Zero = ConstantInt::get (Type::getInt64Ty(M.getContext()), 0); - GlobalVariable * Total = new GlobalVariable (M, - Type::getInt64Ty(M.getContext()), - false, - GlobalValue::InternalLinkage, - Zero, - "Total"); - GlobalVariable * Safe = new GlobalVariable (M, - Type::getInt64Ty(M.getContext()), - false, - GlobalValue::InternalLinkage, - Zero, - "Safe"); - - for (Module::iterator F = M.begin(); F != M.end(); ++F){ - for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE; I++) { - if(LoadInst *LI = dyn_cast(I)) { - instrumentLoad(Total, LI); - if(TS->isTypeSafe(LI->getOperand(0),LI->getParent()->getParent())) - instrumentLoad(Safe, LI); - - // check if safe - } else if(StoreInst *SI = dyn_cast(I)) { - instrumentStore(Total, SI); - if(TS->isTypeSafe(SI->getOperand(1),SI->getParent()->getParent())) - instrumentStore(Safe, SI); - // check if safe - } - } - } - } - - // - // Add a call to main() that will record the values on exit(). - // - Function *MainFunc = M.getFunction("main") ? M.getFunction("main") - : M.getFunction ("MAIN__"); - - BasicBlock & BB = MainFunc->getEntryBlock(); - Constant * Setup = M.getOrInsertFunction ("DYN_COUNT_setup", Type::getVoidTy(M.getContext()), Total->getType(), Safe->getType()); - std::vector args; - args.push_back (Total); - args.push_back (Safe); - CallInst::Create (Setup, args, "", BB.getFirstNonPHI()); - - - return true; -} - diff --git a/lib/AssistDS/FuncSimplify.cpp b/lib/AssistDS/FuncSimplify.cpp deleted file mode 100644 index 4640fb86c..000000000 --- a/lib/AssistDS/FuncSimplify.cpp +++ /dev/null @@ -1,72 +0,0 @@ -//===-------- FuncSimplify.cpp - Replace Global Aliases -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "func-simplify" - -#include "assistDS/FuncSimplify.h" -#include "llvm/IR/Attributes.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" - -#include -#include -#include - -using namespace llvm; - -// Pass statistics -STATISTIC(numChanged, "Number of aliases deleted"); - -// -// Method: runOnModule() -// -// Description: -// Entry point for this LLVM pass. -// Replace all internal aliases with the -// aliasee value -// -// Inputs: -// M - A reference to the LLVM module to transform -// -// Outputs: -// M - The transformed LLVM module. -// -// Return value: -// true - The module was modified. -// false - The module was not modified. -// -bool FuncSimplify::runOnModule(Module& M) { - - std::vector toDelete; - for (GlobalAlias &GA : M.aliases()) { - if(!GA.hasInternalLinkage()) - continue; - GA.replaceAllUsesWith(GA.getAliasee()); - toDelete.push_back(&GA); - } - numChanged += toDelete.size(); - - while(!toDelete.empty()) { - GlobalAlias *I = toDelete.back(); - toDelete.pop_back(); - I->eraseFromParent(); - } - - - return true; -} - -// Pass ID variable -char FuncSimplify::ID = 0; - -// Register the pass -static RegisterPass -X("func-simplify", "Delete Aliases"); diff --git a/lib/AssistDS/FuncSpec.cpp b/lib/AssistDS/FuncSpec.cpp deleted file mode 100644 index 3cbaa91ef..000000000 --- a/lib/AssistDS/FuncSpec.cpp +++ /dev/null @@ -1,121 +0,0 @@ -//===-- FuncSpec.cpp - Clone Functions With Constant Function Ptr Args ----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass clones functions that take constant function pointers as arguments -// from some call sites. It changes those call sites to call cloned functions. -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "funcspec" - -#include "assistDS/FuncSpec.h" - -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" - -#include -#include -#include - -using namespace llvm; - -// Pass statistics -STATISTIC(numCloned, "Number of Functions Cloned in FuncSpec"); -STATISTIC(numReplaced, "Number of Calls Replaced"); -// -// Method: runOnModule() -// -// Description: -// Entry point for this LLVM pass. Search for call sites, that take functions as arguments -// Clone those functions, and pass the clone. -// -// Inputs: -// M - A reference to the LLVM module to transform -// -// Outputs: -// M - The transformed LLVM module. -// -// Return value: -// true - The module was modified. -// false - The module was not modified. -// -bool FuncSpec::runOnModule(Module& M) { - std::map > > cloneSites; - std::map > >, Function* > toClone; - - for (Function &F : M) - if (!F.isDeclaration() && !F.isInterposable()) { - std::vector FPArgs; - for (auto &Arg : F.args()) { - // check if this function has a FunctionType(or a pointer to) argument - if (const PointerType* Ty = dyn_cast(Arg.getType())) { - if (isa(Ty->getElementType())) { - // Store the index of such an argument - FPArgs.push_back(Arg.getArgNo()); - SDEBUG(errs() << "Eligible: " << F.getName().str() << "\n"); - } - } else if (isa(Arg.getType())) { - // Store the index of such an argument - FPArgs.push_back(Arg.getArgNo()); - SDEBUG(errs() << "Eligible: " << F.getName().str() << "\n"); - } - } - // Now find all call sites that it is called from - for (User *U : F.users()) { - if (CallInst* CI = dyn_cast(U)) { - // Check that it is the called value (and not an argument) - if(CI->getCalledValue()->stripPointerCasts() == &F) { - std::vector > Consts; - for (unsigned x = 0; x < FPArgs.size(); ++x) - if (Constant* C = dyn_cast(U->getOperand(FPArgs.at(x) + 1))) { - // If the argument passed, at any of the locations noted earlier - // is a constant function, store the pair - Consts.push_back(std::make_pair(FPArgs.at(x), C)); - } - if (!Consts.empty()) { - // If at least one of the arguments is a constant function, - // we must clone the function. - cloneSites[CI] = Consts; - toClone[std::make_pair(&F, Consts)] = 0; - } - } - } - } - } - - numCloned += toClone.size(); - - for (std::map > >, Function* >::iterator I = toClone.begin(), E = toClone.end(); I != E; ++I) { - // Clone all the functions we need cloned - ValueToValueMapTy VMap; - Function* DirectF = CloneFunction(I->first.first, VMap); - DirectF->setName(I->first.first->getName().str() + "_SPEC"); - DirectF->setLinkage(GlobalValue::InternalLinkage); - I->first.first->getParent()->getFunctionList().push_back(DirectF); - I->second = DirectF; - } - - for (std::map > >::iterator ii = cloneSites.begin(), ee = cloneSites.end(); ii != ee; ++ii) { - // Transform the call sites, to call the clones - Function *OldCallee = cast(ii->first->getCalledValue()); - Function *NewCallee = toClone[std::make_pair(OldCallee, ii->second)]; - ii->first->setCalledFunction(NewCallee); - ++numReplaced; - } - - return true; -} - -// Pass ID variable -char FuncSpec::ID = 0; - -// Register the pass -static RegisterPass -X("funcspec", "Specialize for Function Pointers"); diff --git a/lib/AssistDS/GEPExprArgs.cpp b/lib/AssistDS/GEPExprArgs.cpp deleted file mode 100644 index 289655d05..000000000 --- a/lib/AssistDS/GEPExprArgs.cpp +++ /dev/null @@ -1,187 +0,0 @@ -//===-- GEPExprArg.cpp - Promote args if they come from GEPs -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Identify GEPs used as arguments to call sites. -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "gepexprargs" - -#include "assistDS/GEPExprArgs.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Operator.h" -#include "llvm/IR/Use.h" -#include "llvm/IR/GetElementPtrTypeIterator.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/IR/ValueMap.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" -#include -#include - -// Pass statistics -STATISTIC(numSimplified, "Number of Calls Modified"); - -using namespace llvm; - -// -// Method: runOnModule() -// -// Description: -// Entry point for this LLVM pass. -// Clone functions that take GEPs as arguments -// -// Inputs: -// M - A reference to the LLVM module to transform -// -// Outputs: -// M - The transformed LLVM module. -// -// Return value: -// true - The module was modified. -// false - The module was not modified. -// -bool GEPExprArgs::runOnModule(Module& M) { - bool changed; - do { - changed = false; - for (Module::iterator F = M.begin(); F != M.end(); ++F){ - for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;) { - CallInst *CI = dyn_cast(I++); - if(!CI) - continue; - - if(CI->hasByValArgument()) - continue; - // if the GEP calls a function, that is externally defined, - // or might be changed, ignore this call site. - Function *F = CI->getCalledFunction(); - - if (!F || (F->isDeclaration() || F->isInterposable())) - continue; - if(F->hasStructRetAttr()) - continue; - if(F->isVarArg()) - continue; - - // find the argument we must replace - Function::arg_iterator ai = F->arg_begin(), ae = F->arg_end(); - unsigned argNum = 1; - for(; argNum < CI->getNumOperands();argNum++, ++ai) { - if(ai->use_empty()) - continue; - if (isa(CI->getOperand(argNum))) - break; - } - - // if no argument was a GEP operator to be changed - if(ai == ae) - continue; - - GEPOperator *GEP = dyn_cast(CI->getOperand(argNum)); - if(!GEP->hasAllConstantIndices()) - continue; - - // Construct the new Type - // Appends the struct Type at the beginning - std::vectorTP; - TP.push_back(GEP->getPointerOperand()->getType()); - for(unsigned c = 1; c < CI->getNumOperands();c++) { - TP.push_back(CI->getOperand(c)->getType()); - } - - //return type is same as that of original instruction - FunctionType *NewFTy = FunctionType::get(CI->getType(), TP, false); - Function *NewF; - numSimplified++; - if(numSimplified > 800) - return true; - - NewF = Function::Create(NewFTy, - GlobalValue::InternalLinkage, - F->getName().str() + ".TEST", - &M); - - auto NI = NewF->arg_begin(); - NI->setName("GEParg"); - ++NI; - - ValueToValueMapTy ValueMap; - - for (auto II = F->arg_begin(); NI != NewF->arg_end(); ++II, ++NI) { - ValueMap[&*II] = &*NI; - NI->setName(II->getName()); - auto ArgAttrs = AttrBuilder(F->getAttributes().getParamAttributes(II->getArgNo() + 1)); - NI->addAttrs(ArgAttrs); - } - NewF->setAttributes(NewF->getAttributes().addAttributes( - F->getContext(), 0, F->getAttributes().getRetAttributes())); - // Perform the cloning. - SmallVector Returns; - CloneFunctionInto(NewF, F, ValueMap, false, Returns); - std::vector fargs; - for (auto &Arg : NewF->args()) { - fargs.push_back(&Arg); - } - - NewF->setAttributes(NewF->getAttributes().addAttributes( - F->getContext(), ~0, F->getAttributes().getFnAttributes())); - //Get the point to insert the GEP instr. - SmallVector Ops(CI->op_begin()+1, CI->op_end()); - Instruction *InsertPoint; - for (Instruction *insrt = &*NewF->front().begin(); - isa(InsertPoint = insrt); ++insrt) {;} - - NI = NewF->arg_begin(); - SmallVector Indices; - Indices.append(GEP->op_begin()+1, GEP->op_end()); - GetElementPtrInst *GEP_new = GetElementPtrInst::Create(nullptr, - cast(NI), - Indices, - "", InsertPoint); - fargs.at(argNum)->replaceAllUsesWith(GEP_new); - unsigned j = argNum + 1; - for(; j < CI->getNumOperands();j++) { - if(CI->getOperand(j) == GEP) - fargs.at(j)->replaceAllUsesWith(GEP_new); - } - - // Get the initial attributes of the call - AttributeList CallPAL = CI->getAttributes(); - AttributeSet RAttrs = CallPAL.getRetAttributes(); - AttributeSet FnAttrs = CallPAL.getFnAttributes(); - - SmallVector Args; - SmallVector ArgAttrs; - Args.push_back(GEP->getPointerOperand()); - ArgAttrs.push_back(AttributeSet()); - for(unsigned j =1;jgetNumOperands();j++) { - Args.push_back(CI->getOperand(j)); - ArgAttrs.push_back(CallPAL.getParamAttributes(j)); - } - - auto NewCallPAL = AttributeList::get(F->getContext(), FnAttrs, RAttrs, ArgAttrs); - CallInst *CallI = CallInst::Create(NewF,Args,"", CI); - CallI->setCallingConv(CI->getCallingConv()); - CallI->setAttributes(NewCallPAL); - CI->replaceAllUsesWith(CallI); - CI->eraseFromParent(); - changed = true; - } - } - } - } while(changed); - return true; -} - - -char GEPExprArgs::ID = 0; -static RegisterPass -X("gep-expr-arg", "Find GEP Exprs passed as args"); diff --git a/lib/AssistDS/IndCloner.cpp b/lib/AssistDS/IndCloner.cpp deleted file mode 100644 index bdc0cd5e5..000000000 --- a/lib/AssistDS/IndCloner.cpp +++ /dev/null @@ -1,167 +0,0 @@ -//===-- IndCloner.cpp - Clone Indirectly Called Functions -----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass clones functions which can be called indirectly and then updates -// direct calls to call the clone. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "indclone" - -#include "assistDS/IndCloner.h" - -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/Statistic.h" - -#include - -using namespace llvm; - -// Pass ID variable -char IndClone::ID = 0; - -// Register the Indirect Function Cloner Pass -static RegisterPass -X("indclone", "Indirect call cloning"); - -// Pass statistics -STATISTIC(numCloned, "Number of Functions Cloned in IndCloner"); -STATISTIC(numReplaced, "Number of Calls Replaced"); - -// -// Method: runOnModule() -// -// Description: -// Entry point for this LLVM pass. Search for functions which could be called -// indirectly and create clones for them which are only called by direct -// calls. -// -// Inputs: -// M - A reference to the LLVM module to transform. -// -// Outputs: -// M - The transformed LLVM module. -// -// Return value: -// true - The module was modified. -// false - The module was not modified. -// -bool -IndClone::runOnModule(Module& M) { - // Set of functions to clone - std::vector toClone; - - // - // Check all of the functions in the module. If the function could be called - // by an indirect function call, add it to our worklist of functions to - // clone. - // - for (Function &F : M) { - // Flag whether the function should be cloned - bool pleaseCloneTheFunction = false; - - // - // Only clone functions which are defined and cannot be replaced by another - // function by the linker. - // - if (!F.isDeclaration() && !F.isInterposable()) { - for (User *U : F.users()) { - if (!isa(U) && !isa(U)) { - if(!U->use_empty()) - // - // If this function is used for anything other than a direct function - // call, then we want to clone it. - // - pleaseCloneTheFunction = true; - } else { - // - // This is a call instruction, but hold up ranger! We need to make - // sure that the function isn't passed as an argument to *another* - // function. That would make the function usable in an indirect - // function call. - // - for (unsigned index = 1; index < U->getNumOperands(); ++index) { - if (U->getOperand(index)->stripPointerCasts() == &F) { - pleaseCloneTheFunction = true; - break; - } - } - } - - // - // If we've discovered that the function could be used by an indirect - // call site, schedule it for cloning. - // - if (pleaseCloneTheFunction) { - toClone.push_back(&F); - break; - } - } - } - } - - // - // Update the statistics on the number of functions we'll be cloning. - // We only update the statistic if we want to clone one or more functions; - // due to the magic of how statistics work, avoiding assignment prevents it - // from needlessly showing up. - // - if (toClone.size()) - numCloned += toClone.size(); - - // - // Go through the worklist and clone each function. After cloning a - // function, change all direct calls to use the clone instead of using the - // original function. - // - for (unsigned index = 0; index < toClone.size(); ++index) { - // - // Clone the function and give it a name indicating that it is a clone to - // be used for direct function calls. - // - Function * Original = toClone[index]; - ValueToValueMapTy VMap; - Function* DirectF = CloneFunction(Original, VMap); - DirectF->setName(Original->getName() + "_DIRECT"); - - // - // Make the clone internal; external code can use the original function. - // - DirectF->setLinkage(GlobalValue::InternalLinkage); - - // - // Link the cloned function into the set of functions belonging to the - // module. - // - Original->getParent()->getFunctionList().push_back(DirectF); - - // - // Find all uses of the function that use it as a direct call. Change - // them to use the clone. - // - for (Value::user_iterator ui = Original->user_begin(), - ue = Original->user_end(); - ui != ue; ) { - CallInst *CI = dyn_cast(*ui); - ui++; - if (CI) { - if (CI->getCalledFunction() == Original) { - ++numReplaced; - CI->setCalledFunction(DirectF); - } - } - } - } - - // - // Assume that we've cloned at least one function. - // - return true; -} - diff --git a/lib/AssistDS/Int2PtrCmp.cpp b/lib/AssistDS/Int2PtrCmp.cpp deleted file mode 100644 index f06b9267e..000000000 --- a/lib/AssistDS/Int2PtrCmp.cpp +++ /dev/null @@ -1,184 +0,0 @@ -//===-- Int2PtrCmp.cpp - Merge inttoptr/ptrtoint --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Remove unnecessary inttoptr casts -// Specially ones used in just compares -// Most cases derived from InstCombine -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "int2ptr-cmp" - -#include "assistDS/Int2PtrCmp.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" -#include "llvm/IR/PatternMatch.h" - -#include -#include -#include - -using namespace llvm; -using namespace PatternMatch; - -// -// Method: runOnModule() -// -// Description: -// Entry point for this LLVM pass. -// Remove unnecessary inttoptr instructions. -// -// Inputs: -// M - A reference to the LLVM module to transform -// -// Outputs: -// M - The transformed LLVM module. -// -// Return value: -// true - The module was modified. -// false - The module was not modified. -// -bool Int2PtrCmp::runOnModule(Module& M) { - TD = &M.getDataLayout(); - for (Module::iterator F = M.begin(); F != M.end(); ++F) { - for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;) { - // ptrtoint(inttoptr ty Y) to ty -> Y - if(PtrToIntInst *P2I = dyn_cast(I++)) { - if(IntToPtrInst *I2P = dyn_cast(P2I->getOperand(0))) { - if(I2P->getSrcTy() == P2I->getDestTy()){ - P2I->replaceAllUsesWith(I2P->getOperand(0)); - P2I->eraseFromParent(); - if(I2P->use_empty()) { - // If this is the only use of the cast delete it. - I2P->eraseFromParent(); - } - } - } - } - } - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;) { - //icmp pred inttoptr(X), null -> icmp pred X 0 - if(ICmpInst *CI = dyn_cast(I++)) { - Value *Op0 = CI->getOperand(0); - Value *Op1 = CI->getOperand(1); - if (Constant *RHSC = dyn_cast(Op1)) { - if (Instruction *LHSI = dyn_cast(Op0)){ - if(LHSI->getOpcode() == Instruction::IntToPtr) { - if (RHSC->isNullValue() && TD && - TD->getIntPtrType(RHSC->getContext(), 0) == - LHSI->getOperand(0)->getType()){ - ICmpInst *CI_new = new ICmpInst(CI, CI->getPredicate(), LHSI->getOperand(0), - Constant::getNullValue(LHSI->getOperand(0)->getType())); - - CI->replaceAllUsesWith(CI_new); - CI->eraseFromParent(); - if(LHSI->use_empty()) { - // If this is the only use of the cast delete it. - LHSI->eraseFromParent(); - } - } - } - } - } - } - } - } - } - - for (Module::iterator F = M.begin(); F != M.end(); ++F) { - for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;) { - if(ICmpInst *ICI = dyn_cast(I++)) { - Value *Op0 = ICI->getOperand(0); - Value *Op1 = ICI->getOperand(1); - if (ConstantInt *CI = dyn_cast(Op1)) { - // Since the RHS is a ConstantInt (CI), if the left hand side is an - // instruction, see if that instruction also has constants so that the - // instruction can be folded into the icmp - if (Instruction *LHSI = dyn_cast(Op0)){ - if(LHSI->getOpcode() == Instruction::Or) { - if (!ICI->isEquality() || !CI->isNullValue() || !LHSI->hasOneUse()) - break; - Value *P, *Q, *R; - if (match(LHSI, m_Or(m_PtrToInt(m_Value(P)), m_PtrToInt(m_Value(Q))))) { - // Simplify icmp eq (or (ptrtoint P), (ptrtoint Q)), 0 - // -> and (icmp eq P, null), (icmp eq Q, null). - Value *ICIP = new ICmpInst(ICI, ICI->getPredicate(), P, - Constant::getNullValue(P->getType())); - Value *ICIQ = new ICmpInst(ICI, ICI->getPredicate(), Q, - Constant::getNullValue(Q->getType())); - Instruction *Op; - if (ICI->getPredicate() == ICmpInst::ICMP_EQ) - Op = BinaryOperator::CreateAnd(ICIP, ICIQ,"",ICI); - else - Op = BinaryOperator::CreateOr(ICIP, ICIQ, "", ICI); - ICI->replaceAllUsesWith(Op); - - } else if(match(LHSI, m_Or(m_Or(m_PtrToInt(m_Value(P)), - m_PtrToInt(m_Value(Q))), - m_PtrToInt(m_Value(R))))) { - // Simplify icmp eq (or (or (ptrtoint P), (ptrtoint Q)), ptrtoint(R)), 0 - // -> and (and (icmp eq P, null), (icmp eq Q, null)), (icmp eq R, null). - Value *ICIP = new ICmpInst(ICI, ICI->getPredicate(), P, - Constant::getNullValue(P->getType())); - Value *ICIQ = new ICmpInst(ICI, ICI->getPredicate(), Q, - Constant::getNullValue(Q->getType())); - Value *ICIR = new ICmpInst(ICI, ICI->getPredicate(), R, - Constant::getNullValue(R->getType())); - Instruction *Op; - if (ICI->getPredicate() == ICmpInst::ICMP_EQ) - Op = BinaryOperator::CreateAnd(ICIP, ICIQ,"",ICI); - else - Op = BinaryOperator::CreateOr(ICIP, ICIQ, "", ICI); - - if (ICI->getPredicate() == ICmpInst::ICMP_EQ) - Op = BinaryOperator::CreateAnd(Op, ICIR,"",ICI); - else - Op = BinaryOperator::CreateOr(Op, ICIR, "", ICI); - ICI->replaceAllUsesWith(Op); - - } else if(match(LHSI, m_Or(m_PtrToInt(m_Value(Q)), m_Or( - m_PtrToInt(m_Value(P)), m_PtrToInt(m_Value(R)))))) { - // Simplify icmp eq (or (ptrtoint P), or((ptrtoint Q), ptrtoint(R))), 0 - // -> and (icmp eq P, null), (and (icmp eq Q, null), (icmp eq R, null)). - Value *ICIP = new ICmpInst(ICI, ICI->getPredicate(), P, - Constant::getNullValue(P->getType())); - Value *ICIQ = new ICmpInst(ICI, ICI->getPredicate(), Q, - Constant::getNullValue(Q->getType())); - Value *ICIR = new ICmpInst(ICI, ICI->getPredicate(), R, - Constant::getNullValue(R->getType())); - Instruction *Op; - if (ICI->getPredicate() == ICmpInst::ICMP_EQ) - Op = BinaryOperator::CreateAnd(ICIP, ICIQ,"",ICI); - else - Op = BinaryOperator::CreateOr(ICIP, ICIQ, "", ICI); - - if (ICI->getPredicate() == ICmpInst::ICMP_EQ) - Op = BinaryOperator::CreateAnd(Op, ICIR,"",ICI); - else - Op = BinaryOperator::CreateOr(Op, ICIR, "", ICI); - ICI->replaceAllUsesWith(Op); - } - } - } - } - } - } - } - } - return true; -} - -// Pass ID variable -char Int2PtrCmp::ID = 0; - -// Register the pass -static RegisterPass -X("int2ptrcmp", "Simplify inttoptr/ptrtoint insts"); diff --git a/lib/AssistDS/LICENSE.TXT b/lib/AssistDS/LICENSE.TXT deleted file mode 100644 index dba02fa23..000000000 --- a/lib/AssistDS/LICENSE.TXT +++ /dev/null @@ -1,65 +0,0 @@ -============================================================================== -LLVM Pool Allocator Release License -============================================================================== -University of Illinois/NCSA -Open Source License - -Copyright (c) 2003-2013 University of Illinois at Urbana-Champaign. -All rights reserved. - -Developed by: - - LLVM Team - - University of Illinois at Urbana-Champaign - - http://llvm.cs.uiuc.edu - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE -SOFTWARE. - -============================================================================== -Copyrights and Licenses for Third Party Software Distributed with LLVM: -============================================================================== -The Automatic Pool Allocation software contains code written by third parties. -Such software will have its own individual LICENSE.TXT file in the directory in -which it appears. This file will describe the copyrights, license, and -restrictions which apply to that code. - -The disclaimer of warranty in the University of Illinois Open Source License -applies to all code in this distribution, and nothing in any of the -other licenses gives permission to use the names of the LLVM Team or the -University of Illinois to endorse or promote products derived from this -Software. - -The following pieces of software have additional or alternate copyrights, -licenses, and/or restrictions: - -Program Directory -------- --------- -Watchdog poolalloc/tools/WatchDog - diff --git a/lib/AssistDS/LoadArgs.cpp b/lib/AssistDS/LoadArgs.cpp deleted file mode 100644 index abd464b59..000000000 --- a/lib/AssistDS/LoadArgs.cpp +++ /dev/null @@ -1,215 +0,0 @@ -//===-- LoadArgs.cpp - Promote args if they came from loads ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Identify calls, that are passed arguments that are LoadInsts. -// Pass the original pointer instead. Helps improve some -// context sensitivity. -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "ld-args" - -#include "assistDS/LoadArgs.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Use.h" -#include "llvm/IR/GetElementPtrTypeIterator.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/IR/ValueMap.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" -#include -#include -#include - -// Pass statistics -STATISTIC(numSimplified, "Number of Calls Modified"); - -using namespace llvm; - -// -// Method: runOnModule() -// -// Description: -// Entry point for this LLVM pass. -// Clone functions that take LoadInsts as arguments -// -// Inputs: -// M - A reference to the LLVM module to transform -// -// Outputs: -// M - The transformed LLVM module. -// -// Return value: -// true - The module was modified. -// false - The module was not modified. -// -bool LoadArgs::runOnModule(Module& M) { - std::map , Function* > fnCache; - bool changed; - do { - changed = false; - for (Module::iterator Func = M.begin(); Func != M.end(); ++Func) { - for (Function::iterator B = Func->begin(), FE = Func->end(); B != FE; ++B) { - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;) { - CallInst *CI = dyn_cast(I++); - if(!CI) - continue; - - if(CI->hasByValArgument()) - continue; - // if the CallInst calls a function, that is externally defined, - // or might be changed, ignore this call site. - Function *F = CI->getCalledFunction(); - if (!F || (F->isDeclaration() || F->isInterposable())) - continue; - if(F->hasStructRetAttr()) - continue; - if(F->isVarArg()) - continue; - - // find the argument we must replace - Function::arg_iterator ai = F->arg_begin(), ae = F->arg_end(); - unsigned argNum = 0; - for(; argNum < CI->getNumArgOperands();argNum++, ++ai) { - // do not care about dead arguments - if(ai->use_empty()) - continue; - if(F->getAttributes().getParamAttributes(argNum).hasAttribute(Attribute::SExt) || - F->getAttributes().getParamAttributes(argNum).hasAttribute(Attribute::ZExt)) - continue; - if (isa(CI->getArgOperand(argNum))) - break; - } - - // if no argument was a GEP operator to be changed - if(ai == ae) - continue; - - LoadInst *LI = dyn_cast(CI->getArgOperand(argNum)); - Instruction * InsertPt = &(Func->getEntryBlock().front()); - AllocaInst *NewVal = new AllocaInst( - LI->getType(), LI->getPointerAddressSpace(), "", InsertPt); - - StoreInst *Copy = new StoreInst(LI, NewVal); - Copy->insertAfter(LI); - /*if(LI->getParent() != CI->getParent()) - continue; - // Also check that there is no store after the load. - // TODO: Check if the load/store do not alias. - BasicBlock::iterator bii = LI->getParent()->begin(); - Instruction *BII = bii; - while(BII != LI) { - ++bii; - BII = bii; - } - while(BII != CI) { - if(isa(BII)) - break; - ++bii; - BII = bii; - } - if(isa(bii)){ - continue; - }*/ - - // Construct the new Type - // Appends the struct Type at the beginning - std::vectorTP; - for(unsigned c = 0; c < CI->getNumArgOperands();c++) { - if(c == argNum) - TP.push_back(LI->getPointerOperand()->getType()); - TP.push_back(CI->getArgOperand(c)->getType()); - } - - //return type is same as that of original instruction - FunctionType *NewFTy = FunctionType::get(CI->getType(), TP, false); - numSimplified++; - //if(numSimplified > 1000) - //return true; - - Function *NewF; - std::map , Function* >::iterator Test; - Test = fnCache.find(std::make_pair(F, NewFTy)); - if(Test != fnCache.end()) { - NewF = Test->second; - } else { - NewF = Function::Create(NewFTy, - GlobalValue::InternalLinkage, - F->getName().str() + ".TEST", - &M); - - fnCache[std::make_pair(F, NewFTy)] = NewF; - auto NI = NewF->arg_begin(); - - ValueToValueMapTy ValueMap; - - unsigned count = 0; - for (auto II = F->arg_begin(); NI != NewF->arg_end(); ++count, ++NI) { - if(count == argNum) { - NI->setName("LDarg"); - continue; - } - ValueMap[&*II] = &*NI; - NI->setName(II->getName()); - auto ArgAttrs = AttrBuilder(F->getAttributes().getParamAttributes(II->getArgNo() + 1)); - NI->addAttrs(ArgAttrs); - ++II; - } - // Perform the cloning. - SmallVector Returns; - CloneFunctionInto(NewF, F, ValueMap, false, Returns); - std::vector fargs; - for (auto &Arg : NewF->args()) { - fargs.push_back(&Arg); - } - - NewF->setAttributes(NewF->getAttributes().addAttributes( - F->getContext(), 0, F->getAttributes().getRetAttributes())); - NewF->setAttributes(NewF->getAttributes().addAttributes( - F->getContext(), ~0, F->getAttributes().getFnAttributes())); - //Get the point to insert the GEP instr. - Instruction *InsertPoint; - for (auto insrt = NewF->front().begin(); isa(InsertPoint = &*insrt); ++insrt) {;} - LoadInst *LI_new = new LoadInst(fargs.at(argNum), "", InsertPoint); - fargs.at(argNum+1)->replaceAllUsesWith(LI_new); - } - - // Get the initial attributes of the call - AttributeList CallPAL = CI->getAttributes(); - AttributeSet RAttrs = CallPAL.getRetAttributes(); - AttributeSet FnAttrs = CallPAL.getFnAttributes(); - - SmallVector Args; - SmallVector ArgAttrs; - for(unsigned j =0;jgetNumArgOperands();j++) { - if(j == argNum) { - Args.push_back(NewVal); - ArgAttrs.push_back(AttributeSet()); - } - Args.push_back(CI->getArgOperand(j)); - ArgAttrs.push_back(CallPAL.getParamAttributes(j)); - } - - auto NewCallPAL = AttributeList::get(F->getContext(), FnAttrs, RAttrs, ArgAttrs); - CallInst *CallI = CallInst::Create(NewF,Args,"", CI); - CallI->setCallingConv(CI->getCallingConv()); - CallI->setAttributes(NewCallPAL); - CI->replaceAllUsesWith(CallI); - CI->eraseFromParent(); - changed = true; - } - } - } - } while(changed); - return true; -} - -char LoadArgs::ID = 0; -static RegisterPass -X("ld-args", "Find Load Inst passed as args"); diff --git a/lib/AssistDS/SVADevirt.cpp b/lib/AssistDS/SVADevirt.cpp deleted file mode 100644 index 9f7db4cb6..000000000 --- a/lib/AssistDS/SVADevirt.cpp +++ /dev/null @@ -1,255 +0,0 @@ -//===- Devirt.cpp - Devirtualize using the sig match intrinsic in llva ----===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "devirt" -#include "llvm/IR/Constants.h" -#include "llvm/Transforms/IPO.h" -#include "dsa/CallTargets.h" -#include "llvm/Pass.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/ADT/Statistic.h" - -#include -#include -#include - -using namespace llvm; - -#if 0 - -// -// Function: castTo() -// -// Description: // Given an LLVM value, insert a cast instruction to make it a given type. -// -static inline Value * -castTo (Value * V, const Type * Ty, Instruction * InsertPt) { // - // Don't bother creating a cast if it's already the correct type. - // - if (V->getType() == Ty) - return V; - - // - // If it's a constant, just create a constant expression. - // - if (Constant * C = dyn_cast(V)) { - Constant * CE = ConstantExpr::getCast (C, Ty); - return CE; - } - - // - // Otherwise, insert a cast instruction. - // - return new CastInst::Create(V, Ty, "cast", InsertPt); -} - -namespace { - - static cl::opt - VirtualLimit("devirt-limit", cl::Hidden, cl::init(16), - cl::desc("Maximum number of callees to devirtualize at a call site")); - STATISTIC(FuncAdded, "Number of bounce functions added"); - STATISTIC(CSConvert, "Number of call sites converted"); - - - class Devirtualize : public ModulePass { - - - Function * IndirectFuncFail; - - std::map >, Function*> cache; - int fnum; - - // - // Method: buildBounce() - // - // Description: - // Replaces the given call site with a call to a bounce function. The - // bounce function compares the function pointer to one of the given - // target functions and calls the function directly if the pointer - // matches. - Function* buildBounce (CallSite cs, - std::vector& Targets, - Module& M) { - - Value* ptr = cs.getCalledValue(); - const FunctionType* OrigType = - cast(cast(ptr->getType())->getElementType());; - ++FuncAdded; - - std::vector< const Type *> TP(OrigType->param_begin(), OrigType->param_end()); - TP.insert(TP.begin(), ptr->getType()); - const FunctionType* NewTy = FunctionType::get(OrigType->getReturnType(), TP, false); - Function* F = new Function(NewTy, GlobalValue::InternalLinkage, "devirtbounce", &M); - std::map targets; - - F->arg_begin()->setName("funcPtr"); - std::vector fargs; - for(Function::arg_iterator ai = F->arg_begin(), ae = F->arg_end(); ai != ae; ++ai) - if (ai != F->arg_begin()) { - fargs.push_back(ai); - ai->setName("arg"); - } - - for (std::vector::iterator i = Targets.begin(), e = Targets.end(); - i != e; ++i) { - Function* FL = *i; - BasicBlock* BL = new BasicBlock(FL->getName(), F); - targets[FL] = BL; - - //Make call - Value* call = new CallInst(FL, fargs, "", BL); - - //return correctly - if (OrigType->getReturnType() == Type::VoidTy) - new ReturnInst(0, BL); - else - new ReturnInst(call, BL); - } - - // Create a set of tests that search for the correct function target - // and call it directly. If none of the target functions match, - // call pchk_ind_fail() to note the failure. - - // - // Create the failure basic block. Then, add the following: - // o the terminating instruction - // o the indirect call to the original function - // o a call to phck_ind_fail() - // - BasicBlock* tail = new BasicBlock("fail", F, &F->getEntryBlock()); - Instruction * InsertPt; -#if 0 - InsertPt = new UnreachableInst(tail); -#else - Value* p = F->arg_begin(); - Instruction * realCall = new CallInst (p, fargs, "", tail); - if (OrigType->getReturnType() == Type::VoidTy) - InsertPt = new ReturnInst(0, tail); - else - InsertPt = new ReturnInst(realCall, tail); -#endif - Value * FuncVoidPtr = castTo (p, - PointerType::get(Type::SByteTy), - realCall); - new CallInst (IndirectFuncFail, FuncVoidPtr, "", realCall); - - - // Create basic blocks for valid target functions - for (std::vector::iterator i = Targets.begin(), e = Targets.end(); - i != e; ++i) { - BasicBlock* TB = targets[*i]; - BasicBlock* newB = new BasicBlock("test." + (*i)->getName(), F, &F->getEntryBlock()); - SetCondInst* setcc = new SetCondInst(Instruction::SetEQ, *i, p, "sc", newB); - new BranchInst(TB, tail, setcc, newB); - tail = newB; - } - return F; - } - - public: - static char ID; - Devirtualize() : ModulePass(&ID) {} - - virtual bool runOnModule(Module &M) { - CallTargetFinder* CTF = &getAnalysis(); - - // Get references to functions that are needed in the module - Function* ams = M.getNamedFunction ("llva_assert_match_sig"); - if (!ams) - return false; - - IndirectFuncFail = M.getOrInsertFunction ("pchk_ind_fail", - Type::VoidTy, - PointerType::getUnqual(Type::Int8Ty)); - - std::set safecalls; - std::vector toDelete; - - for (Value::user_iterator ii = ams->user_begin(), ee = ams->user_end(); - ii != ee; ++ii) { - if (CallInst* CI = dyn_cast(*ii)) { - std::cerr << "Found safe call site in " - << CI->getParent()->getParent()->getName() << "\n"; - Value* V = CI->getOperand(1); - toDelete.push_back(CI); - do { - //V->dump(); - safecalls.insert(V); - if (CastInst* CV = dyn_cast(V)) - V = CV->getOperand(0); - else V = 0; - } while (V); - } - } - - for(std::set::iterator i = safecalls.begin(), e = safecalls.end(); - i != e; ++i) { - for (Value::user_iterator uii = (*i)->user_begin(), uie = (*i)->user_end(); - uii != uie; ++uii) { - CallSite cs = CallSite::get(*uii); - bool isSafeCall = cs.getInstruction() && - safecalls.find(cs.getCalledValue()) != safecalls.end(); - if (cs.getInstruction() && !cs.getCalledFunction() && - (isSafeCall || CTF->isComplete(cs))) { - std::vector Targets; - for (std::vector::iterator ii = CTF->begin(cs), ee = CTF->end(cs); - ii != ee; ++ii) - if (!isSafeCall || (*ii)->getType() == cs.getCalledValue()->getType()) - Targets.push_back(*ii); - - if (Targets.size() > 0) { - std::cerr << "Target count: " << Targets.size() << " in " << cs.getInstruction()->getParent()->getParent()->getName() << "\n"; - Function* NF = buildBounce(cs, Targets, M); - if (CallInst* ci = dyn_cast(cs.getInstruction())) { - ++CSConvert; - std::vector Par(ci->op_begin(), ci->op_end()); - CallInst* cn = CallInst::Create(NF, Par.begin(), Par.end(), - ci->getName() + ".dv", ci); - ci->replaceAllUsesWith(cn); - toDelete.push_back(ci); - } else if (InvokeInst* ci = dyn_cast(cs.getInstruction())) { - ++CSConvert; - std::vector Par(ci->op_begin(), ci->op_end()); - InvokeInst* cn = InvokeInst::Create(NF, ci->getNormalDest(), - ci->getUnwindDest(), - Par, ci->getName()+".dv", - ci); - ci->replaceAllUsesWith(cn); - toDelete.push_back(ci); - } - } else //Target size == 0 - std::cerr << "Call site found, but no Targets\n"; - } - } - } - - bool changed = false; - for (std::vector::iterator ii = toDelete.begin(), ee = toDelete.end(); - ii != ee; ++ii) { - changed = true; - (*ii)->eraseFromParent(); - } - return changed; - } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - } - - }; - - RegisterPass X("devirt", "Devirtualization"); - -} - -#endif diff --git a/lib/AssistDS/SimplifyGEP.cpp b/lib/AssistDS/SimplifyGEP.cpp deleted file mode 100644 index 6c5d44c5a..000000000 --- a/lib/AssistDS/SimplifyGEP.cpp +++ /dev/null @@ -1,221 +0,0 @@ -//===--------------- SimplifyGEP.cpp - Simplify GEPs types ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Simplify GEPs with bitcasts (mostly cloned from InstCombine) -// -//===----------------------------------------------------------------------===// - - -#define DEBUG_TYPE "simplify-gep" - -#include "assistDS/SimplifyGEP.h" -#include "llvm/IR/GetElementPtrTypeIterator.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Operator.h" - -#include - -using namespace llvm; - -// -// Method: preprocess() -// -// Description: -// %p = bitcast %p1 to T1 -// gep(%p) ... -// -> -// gep (bitcast %p1 to T1), ... -// -// Inputs: -// M - A reference to the LLVM module to process -// -// Outputs: -// M - The transformed LLVM module. -// -static void preprocess(Module& M) { - for (Module::iterator F = M.begin(); F != M.end(); ++F){ - for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE; I++) { - if(!(isa(I))) - continue; - GetElementPtrInst *GEP = cast(I); - if(BitCastInst *BI = dyn_cast(GEP->getOperand(0))) { - if(Constant *C = dyn_cast(BI->getOperand(0))) { - GEP->setOperand(0, ConstantExpr::getBitCast(C, BI->getType())); - } - } - } - } - } -} -// -// Method: runOnModule() -// -// Description: -// Entry point for this LLVM pass. -// Find all GEPs, and simplify them. -// -// Inputs: -// M - A reference to the LLVM module to transform -// -// Outputs: -// M - The transformed LLVM module. -// -// Return value: -// true - The module was modified. -// false - The module was not modified. -// -bool SimplifyGEP::runOnModule(Module& M) { - TD = &M.getDataLayout(); - preprocess(M); - for (Module::iterator F = M.begin(); F != M.end(); ++F){ - for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE; I++) { - if(!(isa(I))) - continue; - GetElementPtrInst *GEP = cast(I); - Value *PtrOp = GEP->getOperand(0); - Value *StrippedPtr = PtrOp->stripPointerCasts(); - // Check if the GEP base pointer is enclosed in a cast - if (StrippedPtr != PtrOp) { - const PointerType *StrippedPtrTy =cast(StrippedPtr->getType()); - bool HasZeroPointerIndex = false; - if (ConstantInt *C = dyn_cast(GEP->getOperand(1))) - HasZeroPointerIndex = C->isZero(); - // Transform: GEP (bitcast [10 x i8]* X to [0 x i8]*), i32 0, ... - // into : GEP [10 x i8]* X, i32 0, ... - // - // Likewise, transform: GEP (bitcast i8* X to [0 x i8]*), i32 0, ... - // into : GEP i8* X, ... - // - // This occurs when the program declares an array extern like "int X[];" - if (HasZeroPointerIndex) { - const PointerType *CPTy = cast(PtrOp->getType()); - if (const ArrayType *CATy = - dyn_cast(CPTy->getElementType())) { - // GEP (bitcast i8* X to [0 x i8]*), i32 0, ... ? - if (CATy->getElementType() == StrippedPtrTy->getElementType()) { - // -> GEP i8* X, ... - SmallVector Idx(GEP->idx_begin()+1, GEP->idx_end()); - GetElementPtrInst *Res = - GetElementPtrInst::Create(nullptr, StrippedPtr, Idx, GEP->getName(), GEP); - Res->setIsInBounds(GEP->isInBounds()); - GEP->replaceAllUsesWith(Res); - continue; - } - - if (const ArrayType *XATy = - dyn_cast(StrippedPtrTy->getElementType())){ - // GEP (bitcast [10 x i8]* X to [0 x i8]*), i32 0, ... ? - if (CATy->getElementType() == XATy->getElementType()) { - // -> GEP [10 x i8]* X, i32 0, ... - // At this point, we know that the cast source type is a pointer - // to an array of the same type as the destination pointer - // array. Because the array type is never stepped over (there - // is a leading zero) we can fold the cast into this GEP. - GEP->setOperand(0, StrippedPtr); - continue; - } - } - } - } else if (GEP->getNumOperands() == 2) { - // Transform things like: - // %t = getelementptr i32* bitcast ([2 x i32]* %str to i32*), i32 %V - // into: %t1 = getelementptr [2 x i32]* %str, i32 0, i32 %V; bitcast - Type *SrcElTy = StrippedPtrTy->getElementType(); - Type *ResElTy=cast(PtrOp->getType())->getElementType(); - if (TD && SrcElTy->isArrayTy() && - TD->getTypeAllocSize(cast(SrcElTy)->getElementType()) == - TD->getTypeAllocSize(ResElTy)) { - Value *Idx[2]; - Idx[0] = Constant::getNullValue(Type::getInt32Ty(GEP->getContext())); - Idx[1] = GEP->getOperand(1); - Value *NewGEP = GetElementPtrInst::Create(nullptr, StrippedPtr, Idx, - GEP->getName(), GEP); - // V and GEP are both pointer types --> BitCast - GEP->replaceAllUsesWith(new BitCastInst(NewGEP, GEP->getType(), GEP->getName(), GEP)); - continue; - } - - // Transform things like: - // getelementptr i8* bitcast ([100 x double]* X to i8*), i32 %tmp - // (where tmp = 8*tmp2) into: - // getelementptr [100 x double]* %arr, i32 0, i32 %tmp2; bitcast - - if (TD && SrcElTy->isArrayTy() && ResElTy->isIntegerTy(8)) { - uint64_t ArrayEltSize = - TD->getTypeAllocSize(cast(SrcElTy)->getElementType()); - - // Check to see if "tmp" is a scale by a multiple of ArrayEltSize. We - // allow either a mul, shift, or constant here. - Value *NewIdx = 0; - ConstantInt *Scale = 0; - if (ArrayEltSize == 1) { - NewIdx = GEP->getOperand(1); - Scale = ConstantInt::get(cast(NewIdx->getType()), 1); - } else if (ConstantInt *CI = dyn_cast(GEP->getOperand(1))) { - NewIdx = ConstantInt::get(CI->getType(), 1); - Scale = CI; - } else if (Instruction *Inst =dyn_cast(GEP->getOperand(1))){ - if (Inst->getOpcode() == Instruction::Shl && - isa(Inst->getOperand(1))) { - ConstantInt *ShAmt = cast(Inst->getOperand(1)); - uint32_t ShAmtVal = ShAmt->getLimitedValue(64); - Scale = ConstantInt::get(cast(Inst->getType()), - 1ULL << ShAmtVal); - NewIdx = Inst->getOperand(0); - } else if (Inst->getOpcode() == Instruction::Mul && - isa(Inst->getOperand(1))) { - Scale = cast(Inst->getOperand(1)); - NewIdx = Inst->getOperand(0); - } - } - - // If the index will be to exactly the right offset with the scale taken - // out, perform the transformation. Note, we don't know whether Scale is - // signed or not. We'll use unsigned version of division/modulo - // operation after making sure Scale doesn't have the sign bit set. - if (ArrayEltSize && Scale && Scale->getSExtValue() >= 0LL && - Scale->getZExtValue() % ArrayEltSize == 0) { - Scale = ConstantInt::get(Scale->getType(), - Scale->getZExtValue() / ArrayEltSize); - if (Scale->getZExtValue() != 1) { - Constant *C = ConstantExpr::getIntegerCast(Scale, NewIdx->getType(), - false /*ZExt*/); - NewIdx = BinaryOperator::Create(BinaryOperator::Mul, NewIdx, C, "idxscale"); - } - - // Insert the new GEP instruction. - Value *Idx[2]; - Idx[0] = Constant::getNullValue(Type::getInt32Ty(GEP->getContext())); - Idx[1] = NewIdx; - Value *NewGEP = GetElementPtrInst::Create(nullptr, StrippedPtr, Idx, - GEP->getName(), GEP); - GEP->replaceAllUsesWith(new BitCastInst(NewGEP, GEP->getType(), GEP->getName(), GEP)); - continue; - } - } - } - } - } - } - } - - return true; -} - -// Pass ID variable -char SimplifyGEP::ID = 0; - -// Register the pass -static RegisterPass -X("simplify-gep", "Simplify GEPs"); diff --git a/lib/AssistDS/SimplifyLoad.cpp b/lib/AssistDS/SimplifyLoad.cpp deleted file mode 100644 index d79dcbc48..000000000 --- a/lib/AssistDS/SimplifyLoad.cpp +++ /dev/null @@ -1,86 +0,0 @@ -//===--------------- SimplifyLoad.cpp - Simplify load insts ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Derived from InstCombine -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "simplifyload" - -#include "assistDS/SimplifyLoad.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" -#include "llvm/IR/PatternMatch.h" -#include "llvm/IR/DataLayout.h" - -#include -#include -#include - -using namespace llvm; - -// Pass statistic -STATISTIC(numErased, "Number of Instructions Deleted"); - -// -// Method: runOnModule() -// -// Description: -// Entry point for this LLVM pass. Search for insert/extractvalue instructions -// that can be simplified. -// -// Inputs: -// M - A reference to the LLVM module to transform. -// -// Outputs: -// M - The transformed LLVM module. -// -// Return value: -// true - The module was modified. -// false - The module was not modified. -// -bool SimplifyLoad::runOnModule(Module& M) { - // Repeat till no change - bool changed; - do { - changed = false; - for (Module::iterator F = M.begin(); F != M.end(); ++F) { - for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;) { - LoadInst *LI = dyn_cast(I++); - if(!LI) - continue; - if(LI->hasOneUse()) { - if(CastInst *CI = dyn_cast(*(LI->use_begin()))) { - if(LI->getType()->isPointerTy()) { - if(ConstantExpr *CE = dyn_cast(LI->getOperand(0))) { - if(const PointerType *PTy = dyn_cast(CE->getOperand(0)->getType())) - if(PTy->getElementType() == CI->getType()) { - LoadInst *LINew = new LoadInst(CE->getOperand(0), "", LI); - CI->replaceAllUsesWith(LINew); - } - } - } - } - } - - - } - } - } - } while(changed); - return (numErased > 0); -} - -// Pass ID variable -char SimplifyLoad::ID = 0; - -// Register the pass -static RegisterPass -X("simplify-load", "Simplify load insts"); diff --git a/lib/AssistDS/StructReturnToPointer.cpp b/lib/AssistDS/StructReturnToPointer.cpp deleted file mode 100644 index 17e1579ee..000000000 --- a/lib/AssistDS/StructReturnToPointer.cpp +++ /dev/null @@ -1,184 +0,0 @@ -//===-------- StructReturnToPointer.cpp ------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// For functions that return structures, -// transform them to return a pointer to the structure instead. -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "struct-ret" - -#include "assistDS/StructReturnToPointer.h" -#include "llvm/IR/Attributes.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/IR/ValueMap.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" - -#include -#include -#include - -using namespace llvm; - - -// -// Method: runOnModule() -// -// Description: -// Entry point for this LLVM pass. -// If a function returns a struct, make it return -// a pointer to the struct. -// -// Inputs: -// M - A reference to the LLVM module to transform -// -// Outputs: -// M - The transformed LLVM module. -// -// Return value: -// true - The module was modified. -// false - The module was not modified. -// -bool StructRet::runOnModule(Module& M) { - const llvm::DataLayout targetData(&M); - - std::vector worklist; - for (Function &F : M) - if (!F.isInterposable()) { - if(F.isDeclaration()) - continue; - if(F.hasAddressTaken()) - continue; - if(F.getReturnType()->isStructTy()) { - worklist.push_back(&F); - } - } - - while(!worklist.empty()) { - Function *F = worklist.back(); - worklist.pop_back(); - Type *NewArgType = F->getReturnType()->getPointerTo(); - - // Construct the new Type - std::vectorTP; - TP.push_back(NewArgType); - for (Function::arg_iterator ii = F->arg_begin(), ee = F->arg_end(); - ii != ee; ++ii) { - TP.push_back(ii->getType()); - } - - FunctionType *NFTy = FunctionType::get(F->getReturnType(), TP, F->isVarArg()); - - // Create the new function body and insert it into the module. - Function *NF = Function::Create(NFTy, - F->getLinkage(), - F->getName(), &M); - ValueToValueMapTy ValueMap; - auto NI = NF->arg_begin(); - NI->setName("ret"); - ++NI; - for (auto II = F->arg_begin(); II != F->arg_end(); ++II, ++NI) { - ValueMap[&*II] = &*NI; - NI->setName(II->getName()); - AttributeSet attrs = F->getAttributes().getParamAttributes(II->getArgNo() + 1); - if (attrs.hasAttributes()) { - auto AB = AttrBuilder(attrs); - NI->addAttrs(AB); - } - } - // Perform the cloning. - SmallVector Returns; - if (!F->isDeclaration()) - CloneFunctionInto(NF, F, ValueMap, false, Returns); - std::vector fargs; - for (auto &Arg : NF->args()) { - fargs.push_back(&Arg); - } - NF->setAttributes(NF->getAttributes().addAttributes( - M.getContext(), 0, F->getAttributes().getRetAttributes())); - NF->setAttributes(NF->getAttributes().addAttributes( - M.getContext(), ~0, F->getAttributes().getFnAttributes())); - - for (Function::iterator B = NF->begin(), FE = NF->end(); B != FE; ++B) { - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;) { - ReturnInst * RI = dyn_cast(I++); - if(!RI) - continue; - IRBuilder<> Builder(RI); - if (auto LI = dyn_cast(RI->getOperand(0))) { - Builder.CreateMemCpy( - fargs.at(0), - targetData.getPrefTypeAlignment(fargs.at(0)->getType()), - LI->getPointerOperand(), - targetData.getPrefTypeAlignment(LI->getType()), - targetData.getTypeStoreSize(LI->getType())); - } else if (auto CS = dyn_cast(RI->getReturnValue())) { - StructType* ST = CS->getType(); - // We could store the struct into the allocated space pointed by the first - // argument and then load it once SMACK can handle store inst of structs. - for (unsigned i = 0; i < ST->getNumElements(); ++i) { - std::vector idxs = {ConstantInt::get(Type::getInt32Ty(CS->getContext()),0), - ConstantInt::get(Type::getInt32Ty(CS->getContext()),i)}; - Builder.CreateStore(CS->getAggregateElement(i), - Builder.CreateGEP(fargs.at(0), ArrayRef(idxs))); - } - assert(RI->getNumOperands() == 1 && "Return should only have one operand"); - RI->setOperand(0, UndefValue::get(ST)); - } else - llvm_unreachable("Unexpected struct-type return value."); - } - } - - for(Value::user_iterator ui = F->user_begin(), ue = F->user_end(); - ui != ue; ) { - CallInst *CI = dyn_cast(*ui++); - if(!CI) - continue; - if(CI->getCalledFunction() != F) - continue; - if(CI->hasByValArgument()) - continue; - AllocaInst *AllocaNew = new AllocaInst(F->getReturnType(), 0, "", CI); - SmallVector Args; - SmallVector ArgAttrs; - - // Get the initial attributes of the call - AttributeList CallPAL = CI->getAttributes(); - AttributeSet RAttrs = CallPAL.getRetAttributes(); - AttributeSet FnAttrs = CallPAL.getFnAttributes(); - - Args.push_back(AllocaNew); - ArgAttrs.push_back(AttributeSet()); - for(unsigned j = 0; j < CI->getNumOperands()-1; j++) { - Args.push_back(CI->getOperand(j)); - ArgAttrs.push_back(CallPAL.getParamAttributes(j)); - } - - auto NewCallPAL = AttributeList::get(F->getContext(), FnAttrs, RAttrs, ArgAttrs); - CallInst *CallI = CallInst::Create(NF, Args, "", CI); - CallI->setCallingConv(CI->getCallingConv()); - CallI->setAttributes(NewCallPAL); - LoadInst *LI = new LoadInst(AllocaNew, "", CI); - CI->replaceAllUsesWith(LI); - CI->eraseFromParent(); - } - if(F->use_empty()) - F->eraseFromParent(); - } - return true; -} - -// Pass ID variable -char StructRet::ID = 0; - -// Register the pass -static RegisterPass -X("struct-ret", "Find struct arguments"); diff --git a/lib/AssistDS/TypeChecks.cpp b/lib/AssistDS/TypeChecks.cpp deleted file mode 100644 index 1716a6187..000000000 --- a/lib/AssistDS/TypeChecks.cpp +++ /dev/null @@ -1,2243 +0,0 @@ -//===------------ TypeChecks.cpp - Insert runtime type checks -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass inserts checks to enforce type safety during runtime. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "dsa-type-checks" -#include "assistDS/TypeChecks.h" -#include "llvm/IR/Constants.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Module.h" -#include "smack/Debug.h" -#include "llvm/IR/InstIterator.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/ADT/Statistic.h" - -#include -#include -#include - -using namespace llvm; - -char TypeChecks::ID = 0; - -static RegisterPass -TC("typechecks", "Insert runtime type checks", false, true); - -// Pass statistics -STATISTIC(numLoadChecks, "Number of Load Insts that need type checks"); -STATISTIC(numStoreChecks, "Number of Store Insts that need type checks"); -STATISTIC(numTypes, "Number of Types used in the module"); - -namespace { - static cl::opt EnablePointerTypeChecks("enable-ptr-type-checks", - cl::desc("Distinguish pointer types in loads"), - cl::Hidden, - cl::init(false)); - static cl::opt DisablePtrCmpChecks("no-ptr-cmp-checks", - cl::desc("Dont instrument cmp statements"), - cl::Hidden, - cl::init(false)); - static cl::opt TrackAllLoads("track-all-loads", - cl::desc("Check at all loads irrespective of use"), - cl::Hidden, - cl::init(false)); -} - -static int tagCounter = 0; -static Type *VoidTy = 0; -static Type *Int8Ty = 0; -static Type *Int32Ty = 0; -static Type *Int64Ty = 0; -static PointerType *VoidPtrTy = 0; - -static Type *TypeTagTy = 0; -static Type *TypeTagPtrTy = 0; - -static Constant *One = 0; -static Constant *Zero = 0; - -static Constant *RegisterArgv; -static Constant *RegisterEnvp; - -static Constant *trackGlobal; -static Constant *trackStoreInst; -static Constant *trackStringInput; -static Constant *trackArray; - -static Constant *trackInitInst; -static Constant *trackUnInitInst; - -static Constant *getTypeTag; -static Constant *checkTypeInst; - -static Constant *copyTypeInfo; -static Constant *setTypeInfo; - -static Constant *setVAInfo; -static Constant *copyVAInfo; -static Constant *checkVAArg; - -unsigned int TypeChecks::getTypeMarker(Type * Ty) { - if(!EnablePointerTypeChecks) { - if(Ty->isPointerTy()) { - Ty = VoidPtrTy; - } - } - if(UsedTypes.find(Ty) == UsedTypes.end()) - UsedTypes[Ty] = UsedTypes.size(); - - assert((UsedTypes.size() < 254) && "Too many types found. Not enough metadata bits"); - return UsedTypes[Ty]; -} - -unsigned int TypeChecks::getTypeMarker(Value *V) { - return getTypeMarker(V->getType()); -} - -unsigned int TypeChecks::getSize(Type *Ty) { - return TD->getTypeStoreSize(Ty); -} - -Constant *TypeChecks::getSizeConstant(Type *Ty) { - return (ConstantInt::get(Int64Ty, getSize(Ty))); -} - -static Constant *getTagCounter() { - return ConstantInt::get(Int32Ty, tagCounter++); -} - -Constant *TypeChecks::getTypeMarkerConstant(Value * V) { - return ConstantInt::get(TypeTagTy, getTypeMarker(V)); -} - -Constant *TypeChecks::getTypeMarkerConstant(Type *T) { - return ConstantInt::get(TypeTagTy, getTypeMarker(T)); -} - -static inline Value * -castTo (Value * V, Type * Ty, std::string Name, Instruction * InsertPt) { - // - // Don't bother creating a cast if it's already the correct type. - // - if (V->getType() == Ty) - return V; - - // - // If it's a constant, just create a constant expression. - // - if (Constant * C = dyn_cast(V)) { - Constant * CE = ConstantExpr::getZExtOrBitCast (C, Ty); - return CE; - } - - // - // Otherwise, insert a cast instruction. - // - return CastInst::CreateZExtOrBitCast (V, Ty, Name, InsertPt); -} - -bool TypeChecks::runOnModule(Module &M) { - bool modified = false; // Flags whether we modified the module. - bool transformIndirectCalls = true; - - TD = &M.getDataLayout(); - addrAnalysis = &getAnalysis(); - - // Create the necessary prototypes - VoidTy = IntegerType::getVoidTy(M.getContext()); - Int8Ty = IntegerType::getInt8Ty(M.getContext()); - Int32Ty = IntegerType::getInt32Ty(M.getContext()); - Int64Ty = IntegerType::getInt64Ty(M.getContext()); - VoidPtrTy = PointerType::getUnqual(Int8Ty); - - TypeTagTy = Int8Ty; - TypeTagPtrTy = PointerType::getUnqual(TypeTagTy); - - One = ConstantInt::get(Int64Ty, 1); - Zero = ConstantInt::get(Int64Ty, 0); - - // Add prototypes for the dynamic type checking functions - initRuntimeCheckPrototypes(M); - - UsedTypes.clear(); // Reset if run multiple times. - VAArgFunctions.clear(); - ByValFunctions.clear(); - AddressTakenFunctions.clear(); - - // Only works for whole program analysis - Function *MainF = M.getFunction("main"); - if (MainF == 0 || MainF->isDeclaration()) { - llvm_unreachable("No main function found"); - return false; - } - - // Insert the shadow initialization function. - modified |= initShadow(M); - - // Record argv/envp - modified |= visitMain(M, *MainF); - - // Recognize special cases - for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) { - Function &F = *MI; - if(F.isDeclaration()) { - if(addrAnalysis->hasAddressTaken(&F)) - transformIndirectCalls = false; - - continue; - } - - std::string name = F.getName(); - if (strncmp(name.c_str(), "tc.", 3) == 0) continue; - if (strncmp(name.c_str(), "main", 4) == 0) continue; - - // Iterate and find all byval functions - bool hasByValArg = false; - for (Function::arg_iterator I = F.arg_begin(); I != F.arg_end(); ++I) { - if (I->hasByValAttr()) { - hasByValArg = true; - break; - } - } - if(hasByValArg) { - ByValFunctions.push_back(&F); - } - - // Iterate and find all address taken functions - if(addrAnalysis->hasAddressTaken(&F)) { - AddressTakenFunctions.push_back(&F); - } - - // Iterate and find all varargs functions - if(F.isVarArg()) { - VAArgFunctions.push_back(&F); - continue; - } - } - - // Modify all byval functions - while(!ByValFunctions.empty()) { - Function *F = ByValFunctions.back(); - ByValFunctions.pop_back(); - modified |= visitByValFunction(M, *F); - } - - // Modify all the var arg functions - while(!VAArgFunctions.empty()) { - Function *F = VAArgFunctions.back(); - VAArgFunctions.pop_back(); - assert(F->isVarArg()); - modified |= visitVarArgFunction(M, *F); - } - - // Modify all the address taken functions - if(transformIndirectCalls) { - while(!AddressTakenFunctions.empty()) { - Function *F = AddressTakenFunctions.back(); - AddressTakenFunctions.pop_back(); - if(F->isVarArg()) - continue; - visitAddressTakenFunction(M, *F); - } - } - - for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) { - Function &F = *MI; - if(F.isDeclaration()) - continue; - DominatorTree & DT = getAnalysis(F).getDomTree(); - std::deque Worklist; - Worklist.push_back (DT.getRootNode()); - while(Worklist.size()) { - DomTreeNode * Node = Worklist.front(); - Worklist.pop_front(); - BasicBlock *BB = Node->getBlock(); - for (BasicBlock::iterator bi = BB->begin(); bi != BB->end(); ++bi) { - Instruction &I = *bi; - if (StoreInst *SI = dyn_cast(&I)) { - modified |= visitStoreInst(M, *SI); - } else if (LoadInst *LI = dyn_cast(&I)) { - modified |= visitLoadInst(M, *LI); - } else if (CallInst *CI = dyn_cast(&I)) { - modified |= visitCallInst(M, *CI); - } else if (InvokeInst *II = dyn_cast(&I)) { - modified |= visitInvokeInst(M, *II); - } else if (AllocaInst *AI = dyn_cast(&I)) { - modified |= visitAllocaInst(M, *AI); - } else if (VAArgInst *VI = dyn_cast(&I)) { - modified |= visitVAArgInst(M, *VI); - } - } - Worklist.insert(Worklist.end(), Node->begin(), Node->end()); - } - - // Loop over all of the instructions in the function, - // adding instrumentation where needed. - /*for (inst_iterator II = inst_begin(F), IE = inst_end(F); II != IE;++II) { - Instruction &I = *II; - if (StoreInst *SI = dyn_cast(&I)) { - modified |= visitStoreInst(M, *SI); - } else if (LoadInst *LI = dyn_cast(&I)) { - modified |= visitLoadInst(M, *LI); - } else if (CallInst *CI = dyn_cast(&I)) { - modified |= visitCallInst(M, *CI); - } else if (InvokeInst *II = dyn_cast(&I)) { - modified |= visitInvokeInst(M, *II); - } else if (AllocaInst *AI = dyn_cast(&I)) { - modified |= visitAllocaInst(M, *AI); - } else if (VAArgInst *VI = dyn_cast(&I)) { - modified |= visitVAArgInst(M, *VI); - } - }*/ - } - - // visit all the indirect call sites - if(transformIndirectCalls) { - std::set::iterator II = IndCalls.begin(); - for(; II != IndCalls.end();) { - Instruction *I = *II++; - modified |= visitIndirectCallSite(M,I); - } - } - - // visit all the uses of the address taken functions and var arg functions and modify if - // not being passed to external code - std::map::iterator FI = IndFunctionsMap.begin(), FE = IndFunctionsMap.end(); - for(;FI!=FE;++FI) { - Function *F = FI->first; - - Constant *CNew = ConstantExpr::getBitCast(FI->second, F->getType()); - - std::set toReplace; - for(Function::user_iterator User = F->user_begin(); - User != F->user_end();++User) { - toReplace.insert(*User); - } - for(std::set::iterator userI = toReplace.begin(); userI != toReplace.end(); ++userI) { - llvm::User * user = *userI; - if(Constant *C = dyn_cast(user)) { - if(!isa(C)) { - bool changeUse = true; - for(Value::user_iterator II = user->user_begin(); - II != user->user_end(); II++) { - if(CallInst *CI = dyn_cast(*II)) - if(CI->getCalledFunction()) { - if(CI->getCalledFunction()->isDeclaration()) - changeUse = false; - } - } - if(!changeUse) - continue; - std::vector ReplaceWorklist; - for (User::op_iterator use = user->op_begin(); - use != user->op_end(); - ++use) { - if (use->get() == F) { - ReplaceWorklist.push_back (use); - } - } - - if (ReplaceWorklist.size() > 0) { - C->handleOperandChange(F, CNew); - } - continue; - } - } - if(CallInst *CI = dyn_cast(user)) { - if(CI->getCalledFunction()) { - if(CI->getCalledFunction()->isDeclaration()) - continue; - } - } - user->replaceUsesOfWith(F, CNew); - } - } - - // remove redundant checks, caused due to insturmenting uses of loads - // Remove a check if it is dominated by another check for the same instruction - optimizeChecks(M); - - // add a global that contains the mapping from metadata to strings - addTypeMap(M); - - // Update stats - numTypes += UsedTypes.size(); - - return modified; -} - -void TypeChecks::initRuntimeCheckPrototypes(Module &M) { - - RegisterArgv = M.getOrInsertFunction("trackArgvType", - VoidTy, - Int32Ty, /*argc */ - VoidPtrTy->getPointerTo() /*argv*/); - - RegisterEnvp = M.getOrInsertFunction("trackEnvpType", - VoidTy, - VoidPtrTy->getPointerTo() /*envp*/); - - trackGlobal = M.getOrInsertFunction("trackGlobal", - VoidTy, - VoidPtrTy,/*ptr*/ - TypeTagTy,/*type*/ - Int64Ty,/*size*/ - Int32Ty /*tag*/); - - trackArray = M.getOrInsertFunction("trackArray", - VoidTy, - VoidPtrTy,/*ptr*/ - Int64Ty,/*size*/ - Int64Ty,/*count*/ - Int32Ty /*tag*/); - - trackInitInst = M.getOrInsertFunction("trackInitInst", - VoidTy, - VoidPtrTy,/*ptr*/ - Int64Ty,/*size*/ - Int32Ty /*tag*/); - - trackUnInitInst = M.getOrInsertFunction("trackUnInitInst", - VoidTy, - VoidPtrTy,/*ptr*/ - Int64Ty,/*size*/ - Int32Ty /*tag*/); - - trackStoreInst = M.getOrInsertFunction("trackStoreInst", - VoidTy, - VoidPtrTy,/*ptr*/ - TypeTagTy,/*type*/ - Int64Ty,/*size*/ - Int32Ty /*tag*/); - getTypeTag = M.getOrInsertFunction("getTypeTag", - VoidTy, - VoidPtrTy, /*ptr*/ - Int64Ty, /*size*/ - TypeTagPtrTy, /*dest for type tag*/ - Int32Ty /*tag*/); - checkTypeInst = M.getOrInsertFunction("checkType", - VoidTy, - TypeTagTy,/*type*/ - Int64Ty,/*size*/ - TypeTagPtrTy,/*ptr to metadata*/ - VoidPtrTy,/*ptr*/ - Int32Ty /*tag*/); - setTypeInfo = M.getOrInsertFunction("setTypeInfo", - VoidTy, - VoidPtrTy,/*dest ptr*/ - TypeTagPtrTy,/*metadata*/ - Int64Ty,/*size*/ - TypeTagTy, - VoidPtrTy, /*src ptr*/ - Int32Ty /*tag*/); - copyTypeInfo = M.getOrInsertFunction("copyTypeInfo", - VoidTy, - VoidPtrTy,/*dest ptr*/ - VoidPtrTy,/*src ptr*/ - Int64Ty,/*size*/ - Int32Ty /*tag*/); - trackStringInput = M.getOrInsertFunction("trackStringInput", - VoidTy, - VoidPtrTy, - Int32Ty); - setVAInfo = M.getOrInsertFunction("setVAInfo", - VoidTy, - VoidPtrTy,/*va_list ptr*/ - Int64Ty,/*total num of elements in va_list */ - TypeTagPtrTy,/*ptr to metadta*/ - Int32Ty /*tag*/); - copyVAInfo = M.getOrInsertFunction("copyVAInfo", - VoidTy, - VoidPtrTy,/*dst va_list*/ - VoidPtrTy,/*src va_list */ - Int32Ty /*tag*/); - checkVAArg = M.getOrInsertFunction("checkVAArgType", - VoidTy, - VoidPtrTy,/*va_list ptr*/ - TypeTagTy,/*type*/ - Int32Ty /*tag*/); - -} - -// Delete checks, if it is dominated by another check for the same value. -// We might get multiple checks on a path, if there are multiple uses of -// a load inst. - -void TypeChecks::optimizeChecks(Module &M) { - for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) { - Function &F = *MI; - if(F.isDeclaration()) - continue; - DominatorTree & DT = getAnalysis(F).getDomTree(); - std::deque Worklist; - Worklist.push_back (DT.getRootNode()); - while(Worklist.size()) { - DomTreeNode * Node = Worklist.front(); - Worklist.pop_front(); - BasicBlock *BB = Node->getBlock(); - for (BasicBlock::iterator bi = BB->begin(); bi != BB->end(); ++bi) { - CallInst *CI = dyn_cast(bi); - if(!CI) - continue; - if(CI->getCalledFunction() != checkTypeInst) - continue; - std::listtoDelete; - for(Value::user_iterator User = CI->getOperand(3)->user_begin(); User != CI->getOperand(3)->user_end(); ++User) { - CallInst *CI2 = dyn_cast(*User); - if(!CI2) - continue; - if(CI2 == CI) - continue; - // Check that they are refering to the same pointer - if(CI->getOperand(4) != CI2->getOperand(4)) - continue; - // Check that they are using the same metadata for comparison. - if(CI->getOperand(3) != CI2->getOperand(3)) - continue; - if(!DT.dominates(CI, CI2)) - continue; - // if CI, dominates CI2, delete CI2 - toDelete.push_back(CI2); - } - while(!toDelete.empty()) { - Instruction *I = toDelete.back(); - toDelete.pop_back(); - I->eraseFromParent(); - } - } - Worklist.insert(Worklist.end(), Node->begin(), Node->end()); - } - } - for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) { - Function &F = *MI; - if(F.isDeclaration()) - continue; - DominatorTree & DT = getAnalysis(F).getDomTree(); - LoopInfo & LI = getAnalysis(F).getLoopInfo(); - std::deque Worklist; - Worklist.push_back (DT.getRootNode()); - while(Worklist.size()) { - DomTreeNode * Node = Worklist.front(); - Worklist.pop_front(); - Worklist.insert(Worklist.end(), Node->begin(), Node->end()); - BasicBlock *BB = Node->getBlock(); - Loop *L = LI.getLoopFor(BB); - if(!L) - continue; - if(!L->getLoopPreheader()) - continue; - for (BasicBlock::iterator bi = BB->begin(); bi != BB->end(); ) { - CallInst *CI = dyn_cast(bi++); - if(!CI) - continue; - if(CI->getCalledFunction() != checkTypeInst) - continue; - bool hoist = true; - // The instruction is loop invariant if all of its operands are loop-invariant - for (unsigned i = 1, e = CI->getNumOperands(); i != e; ++i) - if (!L->isLoopInvariant(CI->getOperand(i))) - hoist = false; - - if(hoist) { - CI->removeFromParent(); - L->getLoopPreheader()->getInstList().insert(L->getLoopPreheader()->getTerminator()->getIterator(), CI); - } - } - } - } -} - -// add a global that has the metadata -> typeString mapping -void TypeChecks::addTypeMap(Module &M) { - - // Declare the type of the global - ArrayType* AType = ArrayType::get(VoidPtrTy, UsedTypes.size() + 1); - std::vector Values; - Values.reserve(UsedTypes.size() + 1); - - // Declare indices useful for creating a GEP - std::vector Indices; - Indices.push_back(ConstantInt::get(Int32Ty,0)); - Indices.push_back(ConstantInt::get(Int32Ty,0)); - - // Add an entry for uninitialized(Type Number = 0) - - Constant *CA = ConstantDataArray::getString(M.getContext(), - "UNINIT", true); - GlobalVariable *GV = new GlobalVariable(M, - CA->getType(), - true, - GlobalValue::ExternalLinkage, - CA, - ""); - GV->setInitializer(CA); - Constant *C = ConstantExpr::getGetElementPtr(nullptr,GV,Indices); - Values[0] = C; - - // For each used type, create a new entry. - // Also add these strings to the Values list - std::map::iterator TI = UsedTypes.begin(), - TE = UsedTypes.end(); - for(;TI!=TE; ++TI) { - std::string *type = new std::string(); - llvm::raw_string_ostream *test = new llvm::raw_string_ostream(*type); - - *test << TI->first; - //WriteTypeSymbolic(*test, TI->first, &M); - Constant *CA = ConstantDataArray::getString(M.getContext(), - test->str(), true); - GlobalVariable *GV = new GlobalVariable(M, - CA->getType(), - true, - GlobalValue::ExternalLinkage, - CA, - ""); - GV->setInitializer(CA); - Constant *C = ConstantExpr::getGetElementPtr(nullptr,GV, Indices); - Values[TI->second]= C; - } - - new GlobalVariable(M, - AType, - true, - GlobalValue::ExternalLinkage, - ConstantArray::get(AType,Values), - "typeNames" - ); -} - -// For each address taken function, create a clone -// that takes 2 extra arguments(same as a var arg function). -// Modify call sites. -bool TypeChecks::visitAddressTakenFunction(Module &M, Function &F) { - // Clone function - // 1. Create the new argument types vector - std::vector TP; - TP.push_back(Int64Ty); // for count - TP.push_back(VoidPtrTy); // for MD - for(Function::arg_iterator I = F.arg_begin(); I !=F.arg_end(); ++I) { - TP.push_back(I->getType()); - } - - // 2. Create the new function prototype - FunctionType *NewFTy = FunctionType::get(F.getReturnType(), - TP, - false); - Function *NewF = Function::Create(NewFTy, - GlobalValue::InternalLinkage, - F.getName().str() + ".mod", - &M); - - // 3. Set the mapping for the args - auto NI = NewF->arg_begin(); - ValueToValueMapTy ValueMap; - NI->setName("TotalCount"); - NI++; - NI->setName("MD"); - NI++; - for(auto II = F.arg_begin(); NI!=NewF->arg_end(); ++II, ++NI) { - // Each new argument maps to the argument in the old function - // For each of these also copy attributes - ValueMap[&*II] = &*NI; - NI->setName(II->getName()); - AttrBuilder AB{F.getAttributes().getParamAttributes(II->getArgNo()+1)}; - NI->addAttrs(AB); - } - - // 4. Copy over attributes for the function - NewF->setAttributes(NewF->getAttributes() - .addAttributes(M.getContext(), 0, F.getAttributes().getRetAttributes())); - NewF->setAttributes(NewF->getAttributes() - .addAttributes(M.getContext(), ~0, F.getAttributes().getFnAttributes())); - - // 5. Perform the cloning - SmallVectorReturns; - // TODO: Review the boolean flag here - CloneFunctionInto(NewF, &F, ValueMap, true, Returns); - // Store in the map of original -> cloned function - IndFunctionsMap[&F] = NewF; - - std::vectortoDelete; - // Find all uses of the function - for(Value::user_iterator ui = F.user_begin(), ue = F.user_end(); - ui != ue;++ui) { - if(InvokeInst *II = dyn_cast(*ui)) { - if(II->getCalledValue()->stripPointerCasts() != &F) - continue; - std::vector Args; - inst_iterator InsPt = inst_begin(II->getParent()->getParent()); - unsigned int i; - unsigned int NumArgs = II->getNumOperands() - 3; - Value *NumArgsVal = ConstantInt::get(Int32Ty, NumArgs); - AllocaInst *AI = new AllocaInst(TypeTagTy, 0, NumArgsVal, "", &*InsPt); - // set the metadata for the varargs in AI - for(i = 3; i getNumOperands(); i++) { - Value *Idx[1]; - Idx[0] = ConstantInt::get(Int32Ty, i - 3 ); - // For each vararg argument, also add its type information - GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(AI,Idx, "", II); - Constant *C = getTypeMarkerConstant(II->getOperand(i)); - new StoreInst(C, GEP, II); - } - - // As the first argument pass the number of var_arg arguments - Args.push_back(ConstantInt::get(Int64Ty, NumArgs)); - Args.push_back(AI); - for(i = 3 ;i < II->getNumOperands(); i++) { - // Add the original argument - Args.push_back(II->getOperand(i)); - } - - // Create the new call - InvokeInst *II_New = InvokeInst::Create(NewF, - II->getNormalDest(), - II->getUnwindDest(), - Args, - "", II); - II->replaceAllUsesWith(II_New); - toDelete.push_back(II); - } - // Check for call sites - else if(CallInst *CI = dyn_cast(*ui)) { - if(CI->getCalledValue()->stripPointerCasts() != &F) - continue; - std::vector Args; - unsigned int i; - unsigned int NumArgs = CI->getNumOperands() - 1; - inst_iterator InsPt = inst_begin(CI->getParent()->getParent()); - Value *NumArgsVal = ConstantInt::get(Int32Ty, NumArgs); - AllocaInst *AI = new AllocaInst(TypeTagTy, 0, NumArgsVal, "", &*InsPt); - // set the metadata for the varargs in AI - for(i = 1; i getNumOperands(); i++) { - Value *Idx[1]; - Idx[0] = ConstantInt::get(Int32Ty, i - 1 ); - // For each vararg argument, also add its type information - GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(AI,Idx, "", CI); - Constant *C = getTypeMarkerConstant(CI->getOperand(i)); - new StoreInst(C, GEP, CI); - } - - // As the first argument pass the number of var_arg arguments - Args.push_back(ConstantInt::get(Int64Ty, NumArgs)); - Args.push_back(AI); - for(i = 1 ;i < CI->getNumOperands(); i++) { - // Add the original argument - Args.push_back(CI->getOperand(i)); - } - - // Create the new call - CallInst *CI_New = CallInst::Create(NewF, Args, "", CI); - CI->replaceAllUsesWith(CI_New); - toDelete.push_back(CI); - } - } - while(!toDelete.empty()) { - Instruction *I = toDelete.back(); - toDelete.pop_back(); - I->eraseFromParent(); - } - - return true; -} - -// Transform Variable Argument functions, by also passing -// the relavant metadata info -bool TypeChecks::visitVarArgFunction(Module &M, Function &F) { - if(F.hasInternalLinkage()) { - return visitInternalVarArgFunction(M, F); - } - - // create internal clone - ValueToValueMapTy VMap; - Function *F_clone = CloneFunction(&F, VMap); - F_clone->setName(F.getName().str() + "internal"); - F.setLinkage(GlobalValue::InternalLinkage); - F.getParent()->getFunctionList().push_back(F_clone); - F.replaceAllUsesWith(F_clone); - return visitInternalVarArgFunction(M, *F_clone); -} - -// each vararg function is modified so that the first -// argument is the number of arguments passed in, -// and the second is a pointer to a metadata array, -// containing type information for each of the arguments - -// These are read and stored at the beginning of the function. - -// We keep a counter for the number of arguments accessed -// from the va_list(Counter). It is incremented and -// checked on every va_arg access. It is initialized to zero. -// It is also reset to zero on a call to va_start. - -// Similiarly we check type on every va_arg access. - -// Aside from this, this function also transforms all -// callsites of the var_arg function. - -bool TypeChecks::visitInternalVarArgFunction(Module &M, Function &F) { - - // Clone function - // 1. Create the new argument types vector - std::vector TP; - TP.push_back(Int64Ty); // for count - TP.push_back(TypeTagPtrTy); // for MD - for(Function::arg_iterator I = F.arg_begin(); I !=F.arg_end(); ++I) { - TP.push_back(I->getType()); - } - - // 2. Create the new function prototype - FunctionType *NewFTy = FunctionType::get(F.getReturnType(), - TP, - true); - Function *NewF = Function::Create(NewFTy, - GlobalValue::InternalLinkage, - F.getName().str() + ".vararg", - &M); - - // 3. Set the mapping for the args - auto NI = NewF->arg_begin(); - ValueToValueMapTy ValueMap; - NI->setName("TotalArgCount"); - NI++; - NI->setName("MD"); - NI++; - for(auto II = F.arg_begin(); NI!=NewF->arg_end(); ++II, ++NI) { - // Each new argument maps to the argument in the old function - // For each of these also copy attributes - ValueMap[&*II] = &*NI; - NI->setName(II->getName()); - AttrBuilder AB{F.getAttributes().getParamAttributes(II->getArgNo()+1)}; - NI->addAttrs(AB); - } - - // 4. Copy over attributes for the function - NewF->setAttributes(NewF->getAttributes() - .addAttributes(M.getContext(), 0, F.getAttributes().getRetAttributes())); - NewF->setAttributes(NewF->getAttributes() - .addAttributes(M.getContext(), ~0, F.getAttributes().getFnAttributes())); - - // 5. Perform the cloning - SmallVectorReturns; - // TODO: Review the boolean flag here - CloneFunctionInto(NewF, &F, ValueMap, true, Returns); - - - // Store the information - inst_iterator InsPt = inst_begin(NewF); - auto NII = NewF->arg_begin(); - // Subtract the number of initial arguments - Constant *InitialArgs = ConstantInt::get(Int64Ty, F.arg_size()); - Instruction *NewValue = BinaryOperator::Create(BinaryOperator::Sub, - &*NII, - InitialArgs, - "varargs", - &*InsPt); - NII++; - - // Increment by the number of Initial Args, so as to not read the metadata - //for those. - Value *Idx[1]; - Idx[0] = InitialArgs; - // For each vararg argument, also add its type information - GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(&*NII,Idx, "", &*InsPt); - // visit all VAStarts and initialize the counter - for (Function::iterator B = NewF->begin(), FE = NewF->end(); B != FE; ++B) { - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;I++) { - CallInst *CI = dyn_cast(I); - if(!CI) - continue; - Function *CalledF = dyn_cast(CI->getCalledFunction()); - if(!CalledF) - continue; - if(!CalledF->isIntrinsic()) - continue; - if(CalledF->getIntrinsicID() != Intrinsic::vastart) - continue; - // Reinitialize the counter - Value *BCI = castTo(CI->getArgOperand(0), VoidPtrTy, "", CI); - std::vector Args; - Args.push_back(BCI); - Args.push_back(NewValue); - Args.push_back(GEP); - Args.push_back(getTagCounter()); - CallInst::Create(setVAInfo, Args, "", CI); - } - } - - // Find all va_copy calls - for (Function::iterator B = NewF->begin(), FE = NewF->end(); B != FE; ++B) { - for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;I++) { - CallInst *CI = dyn_cast(I); - if(!CI) - continue; - Function *CalledF = dyn_cast(CI->getCalledFunction()); - if(!CalledF) - continue; - if(!CalledF->isIntrinsic()) - continue; - if(CalledF->getIntrinsicID() != Intrinsic::vacopy) - continue; - Value *BCI_Src = castTo(CI->getArgOperand(1), VoidPtrTy, "", CI); - Value *BCI_Dest = castTo(CI->getArgOperand(0), VoidPtrTy, "", CI); - std::vector Args; - Args.push_back(BCI_Dest); - Args.push_back(BCI_Src); - Args.push_back(getTagCounter()); - CallInst::Create(copyVAInfo, Args, "", CI); - } - } - - std::vectortoDelete; - // Find all uses of the function - for(Value::user_iterator ui = F.user_begin(), ue = F.user_end(); - ui != ue;ui ++) { - - // Check for call sites - if(InvokeInst *II = dyn_cast(*ui)) { - std::vector Args; - inst_iterator InsPt = inst_begin(II->getParent()->getParent()); - unsigned int i; - unsigned int NumArgs = II->getNumOperands() - 3; - Value *NumArgsVal = ConstantInt::get(Int32Ty, NumArgs); - AllocaInst *AI = new AllocaInst(TypeTagTy, 0, NumArgsVal, "", &*InsPt); - // set the metadata for the varargs in AI - for(i = 3; i getNumOperands(); i++) { - Value *Idx[1]; - Idx[0] = ConstantInt::get(Int32Ty, i - 3 ); - // For each vararg argument, also add its type information - GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(AI, Idx, "", II); - Constant *C = getTypeMarkerConstant(II->getOperand(i)); - new StoreInst(C, GEP, II); - } - - // As the first argument pass the number of var_arg arguments - Args.push_back(ConstantInt::get(Int64Ty, NumArgs)); - Args.push_back(AI); - for(i = 3 ;i < II->getNumOperands(); i++) { - // Add the original argument - Args.push_back(II->getOperand(i)); - } - - // Create the new call - InvokeInst *II_New = InvokeInst::Create(NewF, - II->getNormalDest(), - II->getUnwindDest(), - Args, - "", II); - II->replaceAllUsesWith(II_New); - toDelete.push_back(II); - } else if (CallInst *CI = dyn_cast(*ui)) { - std::vector Args; - inst_iterator InsPt = inst_begin(CI->getParent()->getParent()); - unsigned int i; - unsigned int NumArgs = CI->getNumArgOperands(); - Value *NumArgsVal = ConstantInt::get(Int32Ty, NumArgs); - AllocaInst *AI = new AllocaInst(TypeTagTy, 0, NumArgsVal, "", &*InsPt); - // set the metadata for the varargs in AI - for(i = 0; i getNumArgOperands(); i++) { - Value *Idx[1]; - Idx[0] = ConstantInt::get(Int32Ty, i); - // For each vararg argument, also add its type information - GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(AI,Idx, "", CI); - Constant *C = getTypeMarkerConstant(CI->getArgOperand(i)); - new StoreInst(C, GEP, CI); - } - - // As the first argument pass the number of var_arg arguments - Args.push_back(ConstantInt::get(Int64Ty, NumArgs)); - Args.push_back(AI); - for(i = 0 ;i < CI->getNumArgOperands(); i++) { - // Add the original argument - Args.push_back(CI->getArgOperand(i)); - } - - // Create the new call - CallInst *CI_New = CallInst::Create(NewF, Args, "", CI); - CI->replaceAllUsesWith(CI_New); - toDelete.push_back(CI); - } - } - while(!toDelete.empty()) { - Instruction *I = toDelete.back(); - toDelete.pop_back(); - I->eraseFromParent(); - } - IndFunctionsMap[&F] = NewF; - return true; -} - -bool TypeChecks::visitByValFunction(Module &M, Function &F) { - - // For internal functions - // Replace with a function with a a new function with no byval attr. - // Add an explicity copy in the function - // Also update all the call sites. - - // For external functions - // Create an internal clone (treated same as internal functions) - // Modify the original function - // To assume that the metadata for the byval arguments is TOP - - if(F.hasInternalLinkage()) { - visitInternalByValFunction(M, F); - } else { - // create internal clone - ValueToValueMapTy VMap; - Function *F_clone = CloneFunction(&F, VMap); - F_clone->setName(F.getName().str() + "internal"); - F.setLinkage(GlobalValue::InternalLinkage); - F.getParent()->getFunctionList().push_back(F_clone); - F.replaceAllUsesWith(F_clone); - visitInternalByValFunction(M, *F_clone); - visitExternalByValFunction(M, F); - } - return true; -} - -bool TypeChecks::visitInternalByValFunction(Module &M, Function &F) { - - // for every byval argument - // add an alloca, a load, and a store inst - Instruction * InsertBefore = &(F.getEntryBlock().front()); - for (auto &Arg : F.args()) { - if (!Arg.hasByValAttr()) - continue; - assert(Arg.getType()->isPointerTy()); - Type *ETy = (cast(Arg.getType()))->getElementType(); - AllocaInst *AI = new AllocaInst(ETy, 0, "", InsertBefore); - // Do this before adding the load/store pair, so that those uses are not replaced. - Arg.replaceAllUsesWith(AI); - LoadInst *LI = new LoadInst(&Arg, "", InsertBefore); - new StoreInst(LI, AI, InsertBefore); - } - - // Update the call sites - std::vectortoDelete; - for(Value::user_iterator ui = F.user_begin(), ue = F.user_end(); - ui != ue; ui++) { - // Check that F is the called value - if(InvokeInst *II = dyn_cast(*ui)) { - if(II->getCalledFunction() == &F) { - SmallVector Args; - SmallVector ArgAttrs; - - // Get the initial attributes of the call - AttributeList CallPAL = II->getAttributes(); - AttributeSet RAttrs = CallPAL.getRetAttributes(); - AttributeSet FnAttrs = CallPAL.getFnAttributes(); - - Function::arg_iterator NI = F.arg_begin(); - for(unsigned j =3;jgetNumOperands();j++, NI++) { - // Add the original argument - Args.push_back(II->getOperand(j)); - - // If there are attributes on this argument, copy them to the correct - // position in the NewCallPAL - //FIXME: copy the rest of the attributes. - if(NI->hasByValAttr()) - continue; - ArgAttrs.push_back(CallPAL.getParamAttributes(j)); - } - - // Create the substitute call - InvokeInst *CallI = InvokeInst::Create(&F, - II->getNormalDest(), - II->getUnwindDest(), - Args, - "", II); - - auto NewCallPAL = AttributeList::get(F.getContext(), FnAttrs, RAttrs, ArgAttrs); - CallI->setCallingConv(II->getCallingConv()); - CallI->setAttributes(NewCallPAL); - II->replaceAllUsesWith(CallI); - toDelete.push_back(II); - - } - } else if(CallInst *CI = dyn_cast(*ui)) { - if(CI->getCalledFunction() == &F) { - SmallVector Args; - SmallVector ArgAttrs; - - // Get the initial attributes of the call - AttributeList CallPAL = CI->getAttributes(); - AttributeSet RAttrs = CallPAL.getRetAttributes(); - AttributeSet FnAttrs = CallPAL.getFnAttributes(); - - Function::arg_iterator II = F.arg_begin(); - for(unsigned j =1;jgetNumOperands();j++, II++) { - // Add the original argument - Args.push_back(CI->getOperand(j)); - // If there are attributes on this argument, copy them to the correct - // position in the NewCallPAL - //FIXME: copy the rest of the attributes. - if(II->hasByValAttr()) - continue; - ArgAttrs.push_back(CallPAL.getParamAttributes(j)); - } - - // Create the substitute call - CallInst *CallI = CallInst::Create(&F, - Args, - "", CI); - - auto NewCallPAL = AttributeList::get(F.getContext(), FnAttrs, RAttrs, ArgAttrs); - CallI->setCallingConv(CI->getCallingConv()); - CallI->setAttributes(NewCallPAL); - CI->replaceAllUsesWith(CallI); - toDelete.push_back(CI); - } - } - } - while(!toDelete.empty()) { - Instruction *I = toDelete.back(); - toDelete.pop_back(); - I->eraseFromParent(); - } - - // remove the byval attribute from the function - for (Function::arg_iterator I = F.arg_begin(); I != F.arg_end(); ++I) { - if (I->hasByValAttr()) - I->removeAttr(Attribute::AttrKind::ByVal); - } - return true; -} - -bool TypeChecks::visitExternalByValFunction(Module &M, Function &F) { - // A list of the byval arguments that we are setting metadata for - typedef SmallVector RegisteredArgTy; - RegisteredArgTy registeredArguments; - for (auto &Arg : F.args()) { - if (Arg.hasByValAttr()) { - assert (isa(Arg.getType())); - PointerType * PT = cast(Arg.getType()); - Type * ET = PT->getElementType(); - Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET)); - Instruction * InsertPt = &(F.getEntryBlock().front()); - Value *BCI = castTo(&Arg, VoidPtrTy, "", InsertPt); - std::vector Args; - Args.push_back(BCI); - Args.push_back(AllocSize); - Args.push_back(getTagCounter()); - // Set the metadata for the byval argument to TOP/Initialized - CallInst::Create(trackInitInst, Args, "", InsertPt); - registeredArguments.push_back(&Arg); - } - } - - // Find all basic blocks which terminate the function. - std::set exitBlocks; - for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ++I) { - if (isa(*I) || isa(*I)) { - exitBlocks.insert(I->getParent()); - } - } - - // At each function exit, insert code to set the metadata as uninitialized. - for (std::set::const_iterator BI = exitBlocks.begin(), - BE = exitBlocks.end(); - BI != BE; ++BI) { - for (RegisteredArgTy::const_iterator I = registeredArguments.begin(), - E = registeredArguments.end(); - I != E; ++I) { - SmallVector args; - Instruction * Pt = &((*BI)->back()); - PointerType * PT = cast((*I)->getType()); - Type * ET = PT->getElementType(); - Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET)); - Value *BCI = castTo(*I, VoidPtrTy, "", Pt); - std::vector Args; - Args.push_back(BCI); - Args.push_back(AllocSize); - Args.push_back(getTagCounter()); - CallInst::Create(trackUnInitInst, Args, "", Pt); - } - } - return true; -} - -// Print the types found in the module. If the optional Module parameter is -// passed in, then the types are printed symbolically if possible, using the -// symbol table from the module. -void TypeChecks::print(raw_ostream &OS, const Module *M) const { - OS << "Types in use by this module:\n"; - std::map::const_iterator I = UsedTypes.begin(), - E = UsedTypes.end(); - for (; I != E; ++I) { - OS << " "; - OS << I->first; - // WriteTypeSymbolic(OS, I->first, M); - OS << " : " << I->second; - OS << '\n'; - } - - OS << "\nNumber of types: " << UsedTypes.size() << '\n'; -} - -// Initialize the shadow memory which contains the 1:1 mapping. -bool TypeChecks::initShadow(Module &M) { - // Create the call to the runtime initialization function and place it before the store instruction. - - Constant * RuntimeCtor = M.getOrInsertFunction("tc.init", VoidTy); - Constant * InitFn = M.getOrInsertFunction("shadowInit", VoidTy); - - //RuntimeCtor->setDoesNotThrow(); - //RuntimeCtor->setLinkage(GlobalValue::InternalLinkage); - - BasicBlock *BB = BasicBlock::Create(M.getContext(), "entry", cast(RuntimeCtor)); - CallInst::Create(InitFn, "", BB); - - Instruction *InsertPt = ReturnInst::Create(M.getContext(), BB); - - // record all globals - for (GlobalVariable &G : M.globals()) { - if(G.use_empty()) - continue; - if(G.getName().str() == "stderr" || - G.getName().str() == "stdout" || - G.getName().str() == "stdin" || - G.getName().str() == "optind" || - G.getName().str() == "optarg") { - // assume initialized - Value *BCI = castTo(&G, VoidPtrTy, "", InsertPt); - std::vector Args; - Args.push_back(BCI); - Args.push_back(getSizeConstant(G.getType()->getElementType())); - Args.push_back(getTagCounter()); - CallInst::Create(trackInitInst, Args, "", InsertPt); - continue; - } - if(!G.hasInitializer()) - continue; - SmallVectorindex; - index.push_back(Zero); - visitGlobal(M, G, G.getInitializer(), *InsertPt, index); - } - // - // Insert the run-time ctor into the ctor list. - // - std::vector CtorInits; - CtorInits.push_back (ConstantInt::get (Int32Ty, 65535)); - CtorInits.push_back (RuntimeCtor); - Constant * RuntimeCtorInit=ConstantStruct::getAnon(M.getContext(),CtorInits, false); - - // - // Get the current set of static global constructors and add the new ctor - // to the list. - // - std::vector CurrentCtors; - GlobalVariable * GVCtor = M.getNamedGlobal ("llvm.global_ctors"); - if (GVCtor) { - if (Constant * C = GVCtor->getInitializer()) { - for (unsigned index = 0; index < C->getNumOperands(); ++index) { - CurrentCtors.push_back (cast(C->getOperand (index))); - } - } - - // - // Rename the global variable so that we can name our global - // llvm.global_ctors. - // - GVCtor->setName ("removed"); - } - - // - // The ctor list seems to be initialized in different orders on different - // platforms, and the priority settings don't seem to work. Examine the - // module's platform string and take a best guess to the order. - // - if (M.getTargetTriple().find ("linux") == std::string::npos) - CurrentCtors.insert (CurrentCtors.begin(), RuntimeCtorInit); - else - CurrentCtors.push_back (RuntimeCtorInit); - - // - // Create a new initializer. - // - ArrayType * AT = ArrayType::get (RuntimeCtorInit-> getType(), - CurrentCtors.size()); - Constant * NewInit=ConstantArray::get (AT, CurrentCtors); - - // - // Create the new llvm.global_ctors global variable and replace all uses of - // the old global variable with the new one. - // - new GlobalVariable (M, - NewInit->getType(), - false, - GlobalValue::AppendingLinkage, - NewInit, - "llvm.global_ctors"); - - - return true; -} - - bool TypeChecks::visitMain(Module &M, Function &MainFunc) { - if(MainFunc.arg_size() < 2) - // No need to register - return false; - - auto AI = MainFunc.arg_begin(); - Value *Argc = &*AI; - Value *Argv = &*(++AI); - - Instruction *InsertPt = &*MainFunc.front().begin(); - std::vector fargs; - fargs.push_back (Argc); - fargs.push_back (Argv); - CallInst::Create (RegisterArgv, fargs, "", InsertPt); - - if(MainFunc.arg_size() < 3) - return true; - - Value *Envp = &*(++AI); - std::vector Args; - Args.push_back(Envp); - CallInst::Create(RegisterEnvp, Args, "", InsertPt); - return true; - } - -bool TypeChecks::visitGlobal(Module &M, GlobalVariable &GV, - Constant *C, Instruction &I, SmallVector Indices) { - - if(ConstantArray *CA = dyn_cast(C)) { - Type * ElementType = CA->getType()->getElementType(); - // Create the type entry for the first element - // using recursive creation till we get to the base types - Indices.push_back(ConstantInt::get(Int64Ty,0)); - visitGlobal(M, GV, CA->getOperand(0), I, Indices); - Indices.pop_back(); - GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(&GV, Indices, "", &I); - - Value *BCI = castTo(GEP, VoidPtrTy, "", &I); - - // Copy the type metadata for the first element - // over for the rest of the elements. - std::vector Args; - Args.push_back(BCI); - Args.push_back(getSizeConstant(ElementType)); - Args.push_back(ConstantInt::get(Int64Ty, CA->getNumOperands())); - Args.push_back(getTagCounter()); - CallInst::Create(trackArray, Args, "", &I); - } - else if(ConstantStruct *CS = dyn_cast(C)) { - // Create metadata for each field of the struct - // at the correct offset. - const StructLayout *SL = TD->getStructLayout(cast(CS->getType())); - for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) { - if (SL->getElementOffset(i) < SL->getSizeInBytes()) { - Constant * ConstElement = cast(CS->getOperand(i)); - Indices.push_back(ConstantInt::get(Int32Ty, i)); - visitGlobal(M, GV, ConstElement, I, Indices); - Indices.pop_back(); - } - } - } else if(ConstantAggregateZero *CAZ = dyn_cast(C)) { - // Similiar to having an initializer with all values NULL - // Must set metadata, similiar to the previous 2 cases. - Type *Ty = CAZ->getType(); - if(ArrayType * ATy = dyn_cast(Ty)) { - Type * ElementType = ATy->getElementType(); - Indices.push_back(ConstantInt::get(Int64Ty,0)); - visitGlobal(M, GV, Constant::getNullValue(ElementType), I, Indices); - Indices.pop_back(); - GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(&GV, Indices, "", &I); - - Value *BCI = castTo(GEP, VoidPtrTy, "", &I); - std::vector Args; - Args.push_back(BCI); - Args.push_back(getSizeConstant(ElementType)); - Args.push_back(ConstantInt::get(Int64Ty, ATy->getNumElements())); - Args.push_back(getTagCounter()); - CallInst::Create(trackArray, Args, "", &I); - } else if(StructType *STy = dyn_cast(Ty)) { - const StructLayout *SL = TD->getStructLayout(STy); - for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { - if (SL->getElementOffset(i) < SL->getSizeInBytes()) { - Indices.push_back(ConstantInt::get(Int32Ty, i)); - visitGlobal(M, GV, Constant::getNullValue(STy->getElementType(i)), I, Indices); - Indices.pop_back(); - } - } - } else { - // Zeroinitializer of a primitive type - GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(&GV, Indices, "", &I); - - Value *BCI = castTo(GEP, VoidPtrTy, "", &I); - std::vector Args; - Args.push_back(BCI); - Args.push_back(getTypeMarkerConstant(CAZ)); - Args.push_back(getSizeConstant(CAZ->getType())); - Args.push_back(getTagCounter()); - CallInst::Create(trackGlobal, Args, "", &I); - } - } - else { - // Primitive type value - GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(&GV, Indices, "", &I); - - Value *BCI = castTo(GEP, VoidPtrTy, "", &I); - std::vector Args; - Args.push_back(BCI); - Args.push_back(getTypeMarkerConstant(C)); - Args.push_back(getSizeConstant(C->getType())); - Args.push_back(getTagCounter()); - CallInst::Create(trackGlobal, Args, "", &I); - } - return true; -} - bool TypeChecks::visitVAArgInst(Module &M, VAArgInst &VI) { - if(!VI.getParent()->getParent()->hasInternalLinkage()) - return false; - Value *BCI = castTo(VI.getOperand(0), VoidPtrTy, "", &VI); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTypeMarkerConstant(&VI)); - Args.push_back(getTagCounter()); - CallInst::Create(checkVAArg, Args, "", &VI); - return false; - } - -// Insert code to initialize meta data to bottom -// Insert code to set objects to 0 -bool TypeChecks::visitAllocaInst(Module &M, AllocaInst &AI) { - - PointerType * PT = AI.getType(); - Type * ET = PT->getElementType(); - Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET)); - CastInst *BCI = BitCastInst::CreatePointerCast(&AI, VoidPtrTy); - BCI->insertAfter(&AI); - - Value *TotalSize; - if(!AI.isArrayAllocation()) { - TotalSize = AllocSize; - } else { - CastInst *ArraySize = CastInst::CreateSExtOrBitCast(AI.getArraySize(), Int64Ty, "", &AI); - BinaryOperator *Size = BinaryOperator::Create(Instruction::Mul, AllocSize, ArraySize, "", &AI); - TotalSize = Size; - } - - // Setting metadata to be 0(BOTTOM/Uninitialized) - - std::vector Args; - Args.push_back(BCI); - Args.push_back(TotalSize); - Args.push_back(getTagCounter()); - CallInst *CI = CallInst::Create(trackUnInitInst, Args); - CI->insertAfter(BCI); - return true; -} - -// Insert runtime checks for certain call instructions -bool TypeChecks::visitCallInst(Module &M, CallInst &CI) { - return visitCallSite(M, &CI); -} - -// Insert runtime checks for certain call instructions -bool TypeChecks::visitInvokeInst(Module &M, InvokeInst &II) { - return visitCallSite(M, &II); -} - -bool TypeChecks::visitCallSite(Module &M, CallSite CS) { - // - // Get the called value. Strip off any casts which are lossless. - // - Value *Callee = CS.getCalledValue()->stripPointerCasts(); - Instruction *I = CS.getInstruction(); - - // Special case handling of certain libc allocation functions here. - if (Function *F = dyn_cast(Callee)) { - if (F->isIntrinsic()) { - switch(F->getIntrinsicID()) { - case Intrinsic::memcpy: - case Intrinsic::memmove: - { - Value *BCI_Src = castTo(CS.getArgument(1), VoidPtrTy, "", I); - Value *BCI_Dest = castTo(CS.getArgument(0), VoidPtrTy, "", I); - std::vector Args; - Args.push_back(BCI_Dest); - Args.push_back(BCI_Src); - CastInst *Size = CastInst::CreateIntegerCast(CS.getArgument(2), Int64Ty, false, "", I); - Args.push_back(Size); - Args.push_back(getTagCounter()); - CallInst::Create(copyTypeInfo, Args, "", I); - return true; - } - - case Intrinsic::memset: - { - Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I); - std::vector Args; - Args.push_back(BCI); - CastInst *Size = CastInst::CreateIntegerCast(CS.getArgument(2), Int64Ty, false, "", I); - Args.push_back(Size); - Args.push_back(getTagCounter()); - CallInst::Create(trackInitInst, Args, "", I); - return true; - } - - default: break; - } - } else if (F->getName().str() == std::string("_ZNKSs5c_strEv")) { //c_str - std::vectorArgs; - Args.push_back(I); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - Instruction *InsertPt = I; - if (InvokeInst *II = dyn_cast(InsertPt)) { - InsertPt = &*II->getNormalDest()->begin(); - while (isa(InsertPt)) - ++InsertPt; - } else - ++InsertPt; - CI->insertBefore(InsertPt); - } else if (F->getName().str() == std::string("_ZNSsC1EPKcRKSaIcE")) { //c_str() - Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - Instruction *InsertPt = I; - if (InvokeInst *II = dyn_cast(InsertPt)) { - InsertPt = &*II->getNormalDest()->begin(); - while (isa(InsertPt)) - ++InsertPt; - } else - ++InsertPt; - CI->insertBefore(InsertPt); - } else if (F->getName().str() == std::string("accept")) { - CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(1), VoidPtrTy); - BCI->insertAfter(I); - CastInst *BCI_Size = BitCastInst::CreatePointerCast(CS.getArgument(2), VoidPtrTy); - BCI_Size->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(BCI_Size); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackaccept", VoidTy, VoidPtrTy,VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("poll")) { - CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(0), VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(CS.getArgument(1)); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackpoll", VoidTy, VoidPtrTy, Int64Ty, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("getaddrinfo")) { - CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(3), VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetaddrinfo", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("mmap")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vector Args; - Args.push_back(BCI); - Args.push_back(CS.getArgument(1)); - Args.push_back(getTagCounter()); - CallInst *CI = CallInst::Create(trackInitInst, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("__strdup")) { - CastInst *BCI_Dest = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI_Dest->insertAfter(I); - CastInst *BCI_Src = BitCastInst::CreatePointerCast(CS.getArgument(0), VoidPtrTy); - BCI_Src->insertAfter(BCI_Dest); - std::vector Args; - Args.push_back(BCI_Dest); - Args.push_back(BCI_Src); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackStrcpyInst", VoidTy, VoidPtrTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI_Src); - } else if (F->getName().str() == std::string("gettimeofday") || - F->getName().str() == std::string("time") || - F->getName().str() == std::string("times")) { - Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I); - assert (isa(CS.getArgument(0)->getType())); - PointerType * PT = cast(CS.getArgument(0)->getType()); - Type * ET = PT->getElementType(); - Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET)); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(AllocSize); - Args.push_back(getTagCounter()); - CallInst::Create(trackInitInst, Args, "", I); - } else if (F->getName().str() == std::string("getpwuid")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetpwuid", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("getpwnam")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetpwuid", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if(F->getName().str() == std::string("getopt_long")) { - Value *OptArg = M.getNamedGlobal("optarg"); - LoadInst *LI = new LoadInst(OptArg); - LI->insertAfter(I); - std::vectorArgs; - Args.push_back(LI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(LI); - } else if (F->getName().str() == std::string("getgruid") || - F->getName().str() == std::string("getgrnam") || - F->getName().str() == std::string("getpwnam") || - F->getName().str() == std::string("__errno_location")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - assert (isa(I->getType())); - PointerType * PT = cast(I->getType()); - Type * ET = PT->getElementType(); - Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET)); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(AllocSize); - Args.push_back(getTagCounter()); - CallInst *CI = CallInst::Create(trackInitInst, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("getservbyname")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetservbyname", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("gethostbyname") || - F->getName().str() == std::string("gethostbyaddr")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgethostbyname", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("gethostname")) { - CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(0), VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgethostname", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("getenv") || - F->getName().str() == std::string("strerror") || - F->getName().str() == std::string("inet_ntoa")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("getcwd")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if(F->getName().str() == std::string("crypt")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("getrusage") || - F->getName().str() == std::string("getrlimit") || - F->getName().str() == std::string("stat") || - F->getName().str() == std::string("vfsstat") || - F->getName().str() == std::string("fstat") || - F->getName().str() == std::string("lstat")) { - Value *BCI = castTo(CS.getArgument(1), VoidPtrTy, "", I); - assert (isa(CS.getArgument(1)->getType())); - PointerType * PT = cast(CS.getArgument(1)->getType()); - Type * ET = PT->getElementType(); - Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET)); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(AllocSize); - Args.push_back(getTagCounter()); - CallInst::Create(trackInitInst, Args, "", I); - } else if (F->getName().str() == std::string("sigaction")) { - Value *BCI = castTo(CS.getArgument(2), VoidPtrTy, "", I); - assert (isa(CS.getArgument(2)->getType())); - PointerType * PT = cast(CS.getArgument(2)->getType()); - Type * ET = PT->getElementType(); - Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET)); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(AllocSize); - Args.push_back(getTagCounter()); - CallInst::Create(trackInitInst, Args, "", I); - } else if (F->getName().str() == std::string("__ctype_b_loc")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackctype", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("__ctype_toupper_loc")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackctype_32", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("__ctype_tolower_loc")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackctype_32", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("strtol") || - F->getName().str() == std::string("strtod")) { - Value *BCI = castTo(CS.getArgument(1), VoidPtrTy, "", I); - PointerType *PTy = cast(CS.getArgument(1)->getType()); - Type * ElementType = PTy->getElementType(); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getSizeConstant(ElementType)); - Args.push_back(getTagCounter()); - CallInst::Create(trackInitInst, Args, "", I); - return true; - } else if (F->getName().str() == std::string("strcat") || - F->getName().str() == std::string("_ZNSspLEPKc")) { - Value *BCI_Src = castTo(CS.getArgument(1), VoidPtrTy, "", I); - Value *BCI_Dest = castTo(CS.getArgument(0), VoidPtrTy, "", I); - std::vector Args; - Args.push_back(BCI_Dest); - Args.push_back(BCI_Src); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackStrcatInst", VoidTy, VoidPtrTy, VoidPtrTy, Int32Ty); - CallInst::Create(F, Args, "", I); - } else if (F->getName().str() == std::string("strcpy")) { - std::vector Args; - Args.push_back(CS.getArgument(0)); - Args.push_back(CS.getArgument(1)); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackStrcpyInst", VoidTy, VoidPtrTy, VoidPtrTy, Int32Ty); - CallInst::Create(F, Args, "", I); - } else if (F->getName().str() == std::string("strncpy")) { - std::vectorArgs; - Args.push_back(CS.getArgument(0)); - Args.push_back(CS.getArgument(1)); - Args.push_back(CS.getArgument(2)); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackStrncpyInst", VoidTy, VoidPtrTy, VoidPtrTy, I->getOperand(3)->getType(), Int32Ty); - CallInst::Create(F, Args, "", I); - } else if (F->getName().str() == std::string("readlink")) { - std::vectorArgs; - Args.push_back(CS.getArgument(1)); - Args.push_back(I); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackReadLink", VoidTy, VoidPtrTy, I->getType(), Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(I); - } else if (F->getName().str() == std::string("pipe")) { - Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I); - std::vector Args; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackpipe", VoidTy, VoidPtrTy, Int32Ty); - CallInst::Create(F, Args, "", I); - return true; - } else if (F->getName().str() == std::string("getsockname")) { - CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(1), VoidPtrTy); - BCI->insertAfter(I); - CastInst *BCI_Size = BitCastInst::CreatePointerCast(CS.getArgument(2), VoidPtrTy); - BCI_Size->insertAfter(I); - std::vector Args; - Args.push_back(BCI); - Args.push_back(BCI_Size); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetsockname", VoidTy, VoidPtrTy, VoidPtrTy, Int32Ty); - CallInst *CI = CallInst::Create(F, Args); - CI->insertAfter(BCI); - return true; - } else if (F->getName().str() == std::string("readdir")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - PointerType *PTy = cast(I->getType()); - Type * ElementType = PTy->getElementType(); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getSizeConstant(ElementType)); - Args.push_back(getTagCounter()); - CallInst *CI = CallInst::Create(trackInitInst, Args); - CI->insertAfter(BCI); - return true; - } else if (F->getName().str() == std::string("localtime") || - F->getName().str() == std::string("gmtime")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - PointerType *PTy = cast(I->getType()); - Type * ElementType = PTy->getElementType(); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getSizeConstant(ElementType)); - Args.push_back(getTagCounter()); - CallInst *CI = CallInst::Create(trackInitInst, Args); - CI->insertAfter(BCI); - } else if (F->getName().str() == std::string("ftime") || - F->getName().str() == std::string("gettimeofday")) { - Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I); - PointerType *PTy = cast(CS.getArgument(0)->getType()); - Type * ElementType = PTy->getElementType(); - std::vector Args; - Args.push_back(BCI); - Args.push_back(getSizeConstant(ElementType)); - Args.push_back(getTagCounter()); - CallInst::Create(trackInitInst, Args, "", I); - return true; - } else if(F->getName().str() == std::string("read")) { - CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(1), VoidPtrTy); - BCI->insertAfter(I); - std::vector Args; - Args.push_back(BCI); - CastInst *Size = CastInst::CreateIntegerCast(I, Int64Ty, false); - Size->insertAfter(I); - Args.push_back(Size); - Args.push_back(getTagCounter()); - CallInst *CI = CallInst::Create(trackInitInst, Args); - CI->insertAfter(BCI); - return true; - } else if(F->getName().str() == std::string("fread")) { - CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(0), VoidPtrTy); - BCI->insertAfter(I); - std::vector Args; - Args.push_back(BCI); - CastInst *Elem = CastInst::CreateIntegerCast(I, Int64Ty, false); - BinaryOperator *Size = BinaryOperator::Create(Instruction::Mul, Elem, CS.getArgument(1)); - Elem->insertAfter(I); - Size->insertAfter(Elem); - Args.push_back(Size); - Args.push_back(getTagCounter()); - CallInst *CI = CallInst::Create(trackInitInst, Args); - CI->insertAfter(BCI); - return true; - } else if(F->getName().str() == std::string("calloc")) { - CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI->insertAfter(I); - std::vector Args; - Args.push_back(BCI); - CastInst *Size = CastInst::CreateIntegerCast(CS.getArgument(1), Int64Ty, false, "", I); - Args.push_back(Size); - Args.push_back(getTagCounter()); - CallInst *CI = CallInst::Create(trackInitInst, Args); - CI->insertAfter(BCI); - std::vector Args1; - Args1.push_back(BCI); - Args1.push_back(Size); - CastInst *Num = CastInst::CreateIntegerCast(CS.getArgument(0), Int64Ty, false, "", I); - Args1.push_back(Num); - Args1.push_back(getTagCounter()); - CallInst *CI_Arr = CallInst::Create(trackArray, Args1); - CI_Arr->insertAfter(CI); - return true; - } else if(F->getName().str() == std::string("realloc")) { - CastInst *BCI_Src = BitCastInst::CreatePointerCast(CS.getArgument(0), VoidPtrTy); - CastInst *BCI_Dest = BitCastInst::CreatePointerCast(I, VoidPtrTy); - BCI_Src->insertAfter(I); - BCI_Dest->insertAfter(BCI_Src); - std::vector Args; - Args.push_back(BCI_Dest); - Args.push_back(BCI_Src); - CastInst *Size = CastInst::CreateIntegerCast(CS.getArgument(1), Int64Ty, false, "", I); - Args.push_back(Size); - Args.push_back(getTagCounter()); - CallInst *CI = CallInst::Create(copyTypeInfo, Args); - CI->insertAfter(BCI_Dest); - return true; - } else if(F->getName().str() == std::string("fgets")) { - Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I); - std::vector Args; - Args.push_back(BCI); - CastInst *Size = CastInst::CreateIntegerCast(CS.getArgument(1), Int64Ty, false, "", I); - Args.push_back(Size); - Args.push_back(getTagCounter()); - CallInst::Create(trackInitInst, Args, "", I); - return true; - } else if(F->getName().str() == std::string("snprintf") || - F->getName().str() == std::string("vsnprintf")) { - Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty); - CallInst *CINew = CallInst::Create(F, Args); - CINew->insertAfter(I); - } else if(F->getName().str() == std::string("sprintf")) { - Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I); - std::vectorArgs; - Args.push_back(BCI); - CastInst *Size = CastInst::CreateIntegerCast(I, Int64Ty, false); - Size->insertAfter(I); - Instruction *NewValue = BinaryOperator::Create(BinaryOperator::Add, - Size, - One); - NewValue->insertAfter(Size); - Args.push_back(NewValue); - Args.push_back(getTagCounter()); - CallInst *CINew = CallInst::Create(trackInitInst, Args); - CINew->insertAfter(NewValue); - } else if(F->getName().str() == std::string("scanf")) { - unsigned i = 1; - while(i < CS.arg_size()) { - visitInputFunctionValue(M, CS.getArgument(i), I); - i++; - } - } else if(F->getName().str() == std::string("sscanf")) { - // FIXME: Need to look at the format string and check - unsigned i = 2; - while(i < CS.arg_size()) { - visitInputFunctionValue(M, CS.getArgument(i), I); - i++; - } - } else if(F->getName().str() == std::string("fscanf")) { - unsigned i = 2; - while(i < CS.arg_size()) { - visitInputFunctionValue(M, CS.getArgument(i), I); - i++; - } - } - } else { - // indirect call site - IndCalls.insert(CS.getInstruction()); - return false; - } - return false; -} - -// Add extra arguments to each indirect call site -bool TypeChecks::visitIndirectCallSite(Module &M, Instruction *I) { - // add the number of arguments as the first argument - Type* OrigType = I->getOperand(0)->getType(); - assert(OrigType->isPointerTy()); - FunctionType *FOldType = cast((cast(OrigType))->getElementType()); - std::vectorTP; - TP.push_back(Int64Ty); - TP.push_back(TypeTagPtrTy); - - for(llvm::FunctionType::param_iterator ArgI = FOldType->param_begin(); ArgI != FOldType->param_end(); ++ArgI) - TP.push_back(*ArgI); - - FunctionType *FTy = FunctionType::get(FOldType->getReturnType(), TP, FOldType->isVarArg()); - Value *Func = castTo(I->getOperand(0), FTy->getPointerTo(), "", I); - - inst_iterator InsPt = inst_begin(I->getParent()->getParent()); - CallSite CS = CallSite(I); - unsigned int NumArgs = CS.arg_size(); - Value *NumArgsVal = ConstantInt::get(Int32Ty, NumArgs); - AllocaInst *AI = new AllocaInst(TypeTagTy, 0, NumArgsVal, "", &*InsPt); - for(unsigned int i = 0; i < CS.arg_size(); i++) { - Value *Idx[1]; - Idx[0] = ConstantInt::get(Int32Ty, i-1); - GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(AI, Idx, "", I); - Constant *C = getTypeMarkerConstant(CS.getArgument(i)); - new StoreInst(C, GEP, I); - } - std::vector Args; - Args.push_back(ConstantInt::get(Int64Ty, NumArgs)); - Args.push_back(AI); - for(unsigned int i = 0; i < CS.arg_size(); i++) - Args.push_back(CS.getArgument(i)); - if(CallInst *CI = dyn_cast(I)) { - CallInst *CI_New = CallInst::Create(Func, Args, "", CI); - CI->replaceAllUsesWith(CI_New); - CI->eraseFromParent(); - } else if(InvokeInst *II = dyn_cast(I)) { - InvokeInst *INew = InvokeInst::Create(Func, - II->getNormalDest(), - II->getUnwindDest(), - Args, - "", I); - II->replaceAllUsesWith(INew); - II->eraseFromParent(); - } - return true; -} - -bool TypeChecks::visitInputFunctionValue(Module &M, Value *V, Instruction *CI) { - // Cast the pointer operand to i8* for the runtime function. - Value *BCI = castTo(V, VoidPtrTy, "", CI); - PointerType *PTy = dyn_cast(V->getType()); - if(!PTy) - return false; - - std::vector Args; - Args.push_back(BCI); - Args.push_back(getTypeMarkerConstant(PTy->getElementType())); - Args.push_back(getSizeConstant(PTy->getElementType())); - Args.push_back(getTagCounter()); - - // Create the call to the runtime check and place it before the store instruction. - CallInst::Create(trackStoreInst, Args, "", CI); - - if(PTy == VoidPtrTy) { - // TODO: This is currently a heuristic for strings. If we see a i8* in a call to - // input functions, treat as string, and get length using strlen. - std::vector Args; - Args.push_back(BCI); - Args.push_back(getTagCounter()); - CallInst *CINew = CallInst::Create(trackStringInput, Args); - CINew->insertAfter(CI); - } - - return true; -} - -// Insert runtime checks before all load instructions. -bool TypeChecks::visitLoadInst(Module &M, LoadInst &LI) { - inst_iterator InsPt = inst_begin(LI.getParent()->getParent()); - // Cast the pointer operand to i8* for the runtime function. - Value *BCI = castTo(LI.getPointerOperand(), VoidPtrTy, "", &LI); - - Value *Size = ConstantInt::get(Int32Ty, getSize(LI.getType())); - AllocaInst *AI = new AllocaInst(TypeTagTy, LI.getPointerAddressSpace(), Size, "", &*InsPt); - - std::vectorArgs1; - Args1.push_back(BCI); - Args1.push_back(getSizeConstant(LI.getType())); - Args1.push_back(AI); - Args1.push_back(getTagCounter()); - CallInst *getTypeCall = CallInst::Create(getTypeTag, Args1, "", &LI); - if(TrackAllLoads) { - std::vector Args; - Args.push_back(getTypeMarkerConstant(&LI)); - Args.push_back(getSizeConstant(LI.getType())); - Args.push_back(AI); - Args.push_back(BCI); - Args.push_back(getTagCounter()); - CallInst::Create(checkTypeInst, Args, "", &LI); - } - visitUses(&LI, AI, BCI); - - if(AI->hasOneUse()) { - // No uses needed checks - getTypeCall->eraseFromParent(); - } - - // Create the call to the runtime check and place it before the load instruction. - numLoadChecks++; - return true; -} - -// AI - metadata -// BCI - ptr -// I - instruction whose uses to instrument -bool TypeChecks::visitUses(Instruction *I, Instruction *AI, Value *BCI) { - for(Value::user_iterator II = I->user_begin(); II != I->user_end(); ++II) { - if(DisablePtrCmpChecks) { - if(isa(*II)) { - if(I->getType()->isPointerTy()) - continue; - } - } - std::vector Args; - Args.push_back(getTypeMarkerConstant(I)); - Args.push_back(getSizeConstant(I->getType())); - Args.push_back(AI); - Args.push_back(BCI); - Args.push_back(getTagCounter()); - if(StoreInst *SI = dyn_cast(*II)) { - if(SI->getOperand(0) == I) { - // Cast the pointer operand to i8* for the runtime function. - Value *BCI_Dest = castTo(SI->getPointerOperand(), VoidPtrTy, "", SI); - - std::vector Args; - Args.push_back(BCI_Dest); - Args.push_back(AI); - Args.push_back(getSizeConstant(SI->getOperand(0)->getType())); - Args.push_back(getTypeMarkerConstant(SI->getOperand(0)->getType())); - Args.push_back(BCI); - Args.push_back(getTagCounter()); - // Create the call to the runtime check and place it before the copying store instruction. - CallInst::Create(setTypeInfo, Args, "", SI); - } else { - CallInst::Create(checkTypeInst, Args, "", cast(II.getUse().getUser())); - } - } else if(SelectInst *SelI = dyn_cast(*II)) { - if(SelI->getOperand(0) == I) { - CallInst::Create(checkTypeInst, Args, "", cast(II.getUse().getUser())); - // if it is used as the condition, just insert a check - } else { - SelectInst *Prev = NULL; - SelectInst *PrevBasePtr = NULL; - if(SelectInst_MD_Map.find(SelI) != SelectInst_MD_Map.end()) { - Prev = SelectInst_MD_Map[SelI]; - PrevBasePtr = SelectInst_BasePtr_Map[SelI]; - } - SelectInst *AI_New; - SelectInst *BCI_New; - if(SelI->getTrueValue() == I) { - if(!Prev) { - AI_New = SelectInst::Create(SelI->getCondition(), AI, Constant::getNullValue(AI->getType()), "", SelI); - BCI_New = SelectInst::Create(SelI->getCondition(), BCI, Constant::getNullValue(BCI->getType()), "", SelI); - } else { - AI_New = SelectInst::Create(SelI->getCondition(), AI, Prev->getFalseValue(), "", SelI); - BCI_New = SelectInst::Create(SelI->getCondition(), BCI, Prev->getFalseValue(), "", SelI); - Prev->replaceAllUsesWith(AI_New); - PrevBasePtr->replaceAllUsesWith(BCI_New); - } - } - else { - if(!Prev) { - AI_New = SelectInst::Create(SelI->getCondition(), Constant::getNullValue(AI->getType()), AI, "", SelI); - BCI_New = SelectInst::Create(SelI->getCondition(), Constant::getNullValue(BCI->getType()), BCI, "", SelI); - } else { - AI_New = SelectInst::Create(SelI->getCondition(), Prev->getTrueValue(), AI, "", SelI); - BCI_New = SelectInst::Create(SelI->getCondition(), Prev->getTrueValue(), BCI, "", SelI); - Prev->replaceAllUsesWith(AI_New); - PrevBasePtr->replaceAllUsesWith(BCI_New); - } - } - SelectInst_MD_Map[SelI] = AI_New; - SelectInst_BasePtr_Map[SelI] = BCI_New; - if(!Prev) - visitUses(SelI, AI_New, BCI_New); - } - } else if(PHINode *PH = dyn_cast(*II)) { - PHINode *Prev = NULL; - PHINode *PrevBasePtr = NULL; - if(PHINode_MD_Map.find(PH) != PHINode_MD_Map.end()) { - Prev = PHINode_MD_Map[PH]; - PrevBasePtr = PHINode_BasePtr_Map[PH]; - } - if(InsertedPHINodes.find(PH) != InsertedPHINodes.end()) - continue; - /*if(isa(I)) { - std::string name = PH->getName(); - if (strncmp(name.c_str(), "baseptr.", 8) == 0) continue; - }*/ - PHINode *AI_New; - PHINode *BCI_New; - if(!Prev) { - AI_New = PHINode::Create(AI->getType(), - PH->getNumIncomingValues(), - PH->getName().str() + ".md", - PH); - BCI_New = PHINode::Create(BCI->getType(), - PH->getNumIncomingValues(), - PH->getName().str() + ".baseptr", - PH); - for(unsigned c = 0; c < PH->getNumIncomingValues(); c++) { - if(PH->getIncomingValue(c) == I) { - AI_New->addIncoming(AI, PH->getIncomingBlock(c)); - BCI_New->addIncoming(BCI, PH->getIncomingBlock(c)); - } - else { - AI_New->addIncoming(Constant::getNullValue(AI->getType()), PH->getIncomingBlock(c)); - BCI_New->addIncoming(Constant::getNullValue(BCI->getType()), PH->getIncomingBlock(c)); - } - } - PHINode_MD_Map[PH] = AI_New; - PHINode_BasePtr_Map[PH] = BCI_New; - InsertedPHINodes.insert(AI_New); - InsertedPHINodes.insert(BCI_New); - visitUses(PH, AI_New, BCI_New); - } - else { - for(unsigned c = 0; c < PH->getNumIncomingValues(); c++) { - if(PH->getIncomingValue(c) == I) { - Prev->setIncomingValue(c, AI); - PrevBasePtr->setIncomingValue(c, BCI); - } - } - } - } else if(BitCastInst *BI = dyn_cast(*II)) { - BitCast_MD_Map[BI] = AI; - visitUses(BI, AI, BCI); - //CallInst::Create(checkTypeInst, Args.begin(), Args.end(), "", cast(II.getUse().getUser())); - /*} else if(PtrToIntInst *P2I = dyn_cast(II)) { - visitUses(P2I, AI, BCI); - } else if(IntToPtrInst *I2P = dyn_cast(II)) { - visitUses(I2P, AI, BCI);*/ - }else { - CallInst::Create(checkTypeInst, Args, "", cast(II.getUse().getUser())); - } - } - return true; -} - -// Insert runtime checks before all store instructions. -bool TypeChecks::visitStoreInst(Module &M, StoreInst &SI) { - if(isa(SI.getOperand(0)->stripPointerCasts())) { - return false; - } - if(PHINode *PH = dyn_cast(SI.getOperand(0)->stripPointerCasts())) { - if(PHINode_MD_Map.find(PH) != PHINode_MD_Map.end()) - return false; - } - if(SelectInst *SelI = dyn_cast(SI.getOperand(0)->stripPointerCasts())) { - if(SelectInst_MD_Map.find(SelI) != SelectInst_MD_Map.end()) - return false; - } - if(BitCastInst *BI = dyn_cast(SI.getOperand(0)->stripPointerCasts())) { - if(BitCast_MD_Map.find(BI) != BitCast_MD_Map.end()) - return false; - } - // Cast the pointer operand to i8* for the runtime function. - Value *BCI = castTo(SI.getPointerOperand(), VoidPtrTy, "", &SI); - - std::vector Args; - Args.push_back(BCI); - Args.push_back(getTypeMarkerConstant(SI.getOperand(0))); // SI.getValueOperand() - Args.push_back(getSizeConstant(SI.getOperand(0)->getType())); - Args.push_back(getTagCounter()); - - // Create the call to the runtime check and place it before the store instruction. - CallInst::Create(trackStoreInst, Args, "", &SI); - numStoreChecks++; - - return true; -} diff --git a/lib/AssistDS/TypeChecksOpt.cpp b/lib/AssistDS/TypeChecksOpt.cpp deleted file mode 100644 index 490458959..000000000 --- a/lib/AssistDS/TypeChecksOpt.cpp +++ /dev/null @@ -1,259 +0,0 @@ -//===---------- TypeChecksOpt.h - Remove safe runtime type checks ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass removes type checks that are statically proven safe -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "dsa-type-checks-opt" -#include "assistDS/TypeChecksOpt.h" -#include "llvm/IR/Constants.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Module.h" -#include "smack/Debug.h" -#include "llvm/IR/InstIterator.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/ADT/Statistic.h" - -#include - -using namespace llvm; - -char TypeChecksOpt::ID = 0; - -static RegisterPass -TC("typechecks-opt", "Remove safe runtime type checks", false, true); - -// Pass statistics -STATISTIC(numSafe, "Number of statically proven safe type checks"); - -static Type *VoidTy = 0; -static Type *Int8Ty = 0; -static Type *Int32Ty = 0; -static Type *Int64Ty = 0; -static PointerType *VoidPtrTy = 0; -static Type *TypeTagTy = 0; -static Type *TypeTagPtrTy = 0; -static Constant *trackGlobal; -static Constant *trackStringInput; -static Constant *trackInitInst; -static Constant *trackUnInitInst; -static Constant *trackStoreInst; -static Constant *copyTypeInfo; -static Constant *setTypeInfo; -static Constant *checkTypeInst; -static Constant *getTypeTag; -static Constant *MallocFunc; - -bool TypeChecksOpt::runOnModule(Module &M) { - TS = &getAnalysis >(); - - // Create the necessary prototypes - VoidTy = IntegerType::getVoidTy(M.getContext()); - Int8Ty = IntegerType::getInt8Ty(M.getContext()); - Int32Ty = IntegerType::getInt32Ty(M.getContext()); - Int64Ty = IntegerType::getInt64Ty(M.getContext()); - VoidPtrTy = PointerType::getUnqual(Int8Ty); - TypeTagTy = Int8Ty; - TypeTagPtrTy = PointerType::getUnqual(TypeTagTy); - - Constant *memsetF = M.getOrInsertFunction ("llvm.memset.i64", VoidTy, - VoidPtrTy, - Int8Ty, - Int64Ty, - Int32Ty); - trackGlobal = M.getOrInsertFunction("trackGlobal", - VoidTy, - VoidPtrTy,/*ptr*/ - TypeTagTy,/*type*/ - Int64Ty,/*size*/ - Int32Ty /*tag*/); - trackInitInst = M.getOrInsertFunction("trackInitInst", - VoidTy, - VoidPtrTy,/*ptr*/ - Int64Ty,/*size*/ - Int32Ty /*tag*/); - trackUnInitInst = M.getOrInsertFunction("trackUnInitInst", - VoidTy, - VoidPtrTy,/*ptr*/ - Int64Ty,/*size*/ - Int32Ty /*tag*/); - trackStoreInst = M.getOrInsertFunction("trackStoreInst", - VoidTy, - VoidPtrTy,/*ptr*/ - TypeTagTy,/*type*/ - Int64Ty,/*size*/ - Int32Ty /*tag*/); - checkTypeInst = M.getOrInsertFunction("checkType", - VoidTy, - TypeTagTy,/*type*/ - Int64Ty,/*size*/ - TypeTagPtrTy, - VoidPtrTy,/*ptr*/ - Int32Ty /*tag*/); - copyTypeInfo = M.getOrInsertFunction("copyTypeInfo", - VoidTy, - VoidPtrTy,/*dest ptr*/ - VoidPtrTy,/*src ptr*/ - Int64Ty,/*size*/ - Int32Ty /*tag*/); - setTypeInfo = M.getOrInsertFunction("setTypeInfo", - VoidTy, - VoidPtrTy,/*dest ptr*/ - TypeTagPtrTy,/*metadata*/ - Int64Ty,/*size*/ - TypeTagTy, - VoidPtrTy, - Int32Ty /*tag*/); - trackStringInput = M.getOrInsertFunction("trackStringInput", - VoidTy, - VoidPtrTy, - Int32Ty ); - getTypeTag = M.getOrInsertFunction("getTypeTag", - VoidTy, - VoidPtrTy, /*ptr*/ - Int64Ty, /*size*/ - TypeTagPtrTy, /*dest for type tag*/ - Int32Ty /*tag*/); - MallocFunc = M.getFunction("malloc"); - - for(Value::user_iterator User = trackGlobal->user_begin(); User != trackGlobal->user_end(); ++User) { - CallInst *CI = dyn_cast(*User); - assert(CI); - if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { - std::vectorArgs; - Args.push_back(CI->getOperand(1)); - Args.push_back(CI->getOperand(3)); - Args.push_back(CI->getOperand(4)); - CallInst::Create(trackInitInst, Args, "", CI); - toDelete.push_back(CI); - } - } - - for(Value::user_iterator User = checkTypeInst->user_begin(); User != checkTypeInst->user_end(); ++User) { - CallInst *CI = dyn_cast(*User); - assert(CI); - - if(TS->isTypeSafe(CI->getOperand(4)->stripPointerCasts(), CI->getParent()->getParent())) { - toDelete.push_back(CI); - } - } - - for(Value::user_iterator User = trackStoreInst->user_begin(); User != trackStoreInst->user_end(); ++User) { - CallInst *CI = dyn_cast(*User); - assert(CI); - - if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { - toDelete.push_back(CI); - } - } - - // for alloca's if they are type known - // assume initialized with TOP - for(Value::user_iterator User = trackUnInitInst->user_begin(); User != trackUnInitInst->user_end(); ) { - CallInst *CI = dyn_cast(*(User++)); - assert(CI); - - // check if operand is an alloca inst. - if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { - CI->setCalledFunction(trackInitInst); - - if(AllocaInst *AI = dyn_cast(CI->getOperand(1)->stripPointerCasts())) { - // Initialize the allocation to NULL - std::vector Args2; - Args2.push_back(CI->getOperand(1)); - Args2.push_back(ConstantInt::get(Int8Ty, 0)); - Args2.push_back(CI->getOperand(2)); - Args2.push_back(ConstantInt::get(Int32Ty, AI->getAlignment())); - CallInst::Create(memsetF, Args2, "", CI); - } - } - } - - if(MallocFunc) { - for(Value::user_iterator User = MallocFunc->user_begin(); User != MallocFunc->user_end(); User ++) { - CallInst *CI = dyn_cast(*User); - if(!CI) - continue; - if(TS->isTypeSafe(CI, CI->getParent()->getParent())){ - CastInst *BCI = BitCastInst::CreatePointerCast(CI, VoidPtrTy); - CastInst *Size = CastInst::CreateSExtOrBitCast(CI->getOperand(1), Int64Ty); - Size->insertAfter(CI); - BCI->insertAfter(Size); - std::vectorArgs; - Args.push_back(BCI); - Args.push_back(Size); - Args.push_back(ConstantInt::get(Int32Ty, 0)); - CallInst *CINew = CallInst::Create(trackInitInst, Args); - CINew->insertAfter(BCI); - } - } - } - - // also do for mallocs/calloc/other allocators??? - // other allocators?? - - for(Value::user_iterator User = copyTypeInfo->user_begin(); User != copyTypeInfo->user_end(); ++User) { - CallInst *CI = dyn_cast(*User); - assert(CI); - - if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { - std::vector Args; - Args.push_back(CI->getOperand(1)); - Args.push_back(CI->getOperand(3)); // size - Args.push_back(CI->getOperand(4)); - CallInst::Create(trackInitInst, Args, "", CI); - toDelete.push_back(CI); - } - } - for(Value::user_iterator User = setTypeInfo->user_begin(); User != setTypeInfo->user_end(); ++User) { - CallInst *CI = dyn_cast(*User); - assert(CI); - - if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { - std::vector Args; - Args.push_back(CI->getOperand(1)); - Args.push_back(CI->getOperand(3)); // size - Args.push_back(CI->getOperand(6)); - CallInst::Create(trackInitInst, Args, "", CI); - toDelete.push_back(CI); - } - } - - for(Value::user_iterator User = getTypeTag->user_begin(); User != getTypeTag->user_end(); ++User) { - CallInst *CI = dyn_cast(*User); - assert(CI); - if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { - AllocaInst *AI = dyn_cast(CI->getOperand(3)->stripPointerCasts()); - assert(AI); - std::vectorArgs; - Args.push_back(CI->getOperand(3)); - Args.push_back(ConstantInt::get(Int8Ty, 255)); - Args.push_back(CI->getOperand(2)); - Args.push_back(ConstantInt::get(Int32Ty, AI->getAlignment())); - CallInst::Create(memsetF, Args, "", CI); - toDelete.push_back(CI); - } - } - - numSafe += toDelete.size(); - - while(!toDelete.empty()) { - Instruction *I = toDelete.back(); - toDelete.pop_back(); - I->eraseFromParent(); - } - - return (numSafe > 0); -} - - diff --git a/lib/DSA/AddressTakenAnalysis.cpp b/lib/DSA/AddressTakenAnalysis.cpp deleted file mode 100644 index 281e0c63f..000000000 --- a/lib/DSA/AddressTakenAnalysis.cpp +++ /dev/null @@ -1,89 +0,0 @@ -//===-- AddressTakenAnalysis.cpp - Address Taken Functions Finding Pass ---===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass helps find which functions are address taken in a module. -// Functions are considered to be address taken if they are either stored, -// or passed as arguments to functions. -// -// -//===----------------------------------------------------------------------===// - -#include "llvm/Pass.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Instructions.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" -#include "llvm/IR/CallSite.h" - -#include -#include - -#include "dsa/AddressTakenAnalysis.h" - -using namespace llvm; - - -AddressTakenAnalysis::~AddressTakenAnalysis() {} - -static bool isAddressTaken(Value* V) { - for (Value::const_use_iterator I = V->use_begin(), E = V->use_end(); I != E; ++I) { - User *U = I->getUser(); - if(isa(U)) - return true; - if (!isa(U) && !isa(U)) { - if(U->use_empty()) - continue; - if(isa(U)) { - if(isAddressTaken(U)) - return true; - } else { - if (Constant *C = dyn_cast(U)) { - if (ConstantExpr *CE = dyn_cast(C)) { - if (CE->getOpcode() == Instruction::BitCast) { - return isAddressTaken(CE); - } - } - } - return true; - } - - // FIXME: Can be more robust here for weak aliases that - // are never used - } else { - llvm::CallSite CS(cast(U)); - if (!CS.isCallee(&*I)) - return true; - } - } - return false; -} - -bool AddressTakenAnalysis::runOnModule(llvm::Module& M) { - for (Function &F : M) { - if(isAddressTaken(&F)) { - addressTakenFunctions.insert(&F); - } - } - - return false; -} - -bool AddressTakenAnalysis::hasAddressTaken(llvm::Function *F){ - return addressTakenFunctions.find(F) != addressTakenFunctions.end(); -} - -void AddressTakenAnalysis::getAnalysisUsage(llvm::AnalysisUsage &AU) const { - AU.setPreservesAll(); -} - -char AddressTakenAnalysis::ID; -static RegisterPass A("ata", "Identify Address Taken Functions"); diff --git a/lib/DSA/AllocatorIdentification.cpp b/lib/DSA/AllocatorIdentification.cpp deleted file mode 100644 index 220b8fc51..000000000 --- a/lib/DSA/AllocatorIdentification.cpp +++ /dev/null @@ -1,198 +0,0 @@ -//===-- AllocatorIdentification.cpp - Identify wrappers to allocators -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// A pass to identify functions that act as wrappers to malloc and other -// allocators. -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "allocator-identify" - -#include "llvm/IR/Constants.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" - -#include -#include -#include -#include - -#include "dsa/AllocatorIdentification.h" - -using namespace llvm; - -STATISTIC(numAllocators, "Number of malloc-like allocators"); -STATISTIC(numDeallocators, "Number of free-like deallocators"); - -bool AllocIdentify::flowsFrom(Value *Dest,Value *Src) { - if(Dest == Src) - return true; - if(ReturnInst *Ret = dyn_cast(Dest)) { - return flowsFrom(Ret->getReturnValue(), Src); - } - if(PHINode *PN = dyn_cast(Dest)) { - Function *F = PN->getParent()->getParent(); - LoopInfo &LI = getAnalysis(*F).getLoopInfo(); - // If this is a loop phi, ignore. - if(LI.isLoopHeader(PN->getParent())) - return false; - bool ret = true; - for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { - ret = ret && flowsFrom(PN->getIncomingValue(i), Src); - } - return ret; - } - if(BitCastInst *BI = dyn_cast(Dest)) { - return flowsFrom(BI->getOperand(0), Src); - } - if(isa(Dest)) - return true; - return false; -} - -bool isNotStored(Value *V) { - // check that V is not stored to a location that is accessible outside this fn - for(Value::user_iterator ui = V->user_begin(), ue = V->user_end(); - ui != ue; ++ui) { - if(isa(*ui)) - return false; - if(isa(*ui)) - continue; - if(isa(*ui)) - continue; - if(BitCastInst *BI = dyn_cast(*ui)) { - if(isNotStored(BI)) - continue; - else - return false; - } - if(PHINode *PN = dyn_cast(*ui)) { - if(isNotStored(PN)) - continue; - else - return false; - } - - return false; - } - return true; -} - -AllocIdentify::AllocIdentify() : ModulePass(ID) {} -AllocIdentify::~AllocIdentify() {} - -bool AllocIdentify::runOnModule(Module& M) { - - allocators.emplace("malloc"); - allocators.emplace("calloc"); - //allocators.emplace("realloc"); - //allocators.emplace("memset"); - deallocators.emplace("free"); - deallocators.emplace("cfree"); - - bool changed; - do { - changed = false; - std::set TempAllocators; - TempAllocators.insert( allocators.begin(), allocators.end()); - std::set::iterator it; - for(it = TempAllocators.begin(); it != TempAllocators.end(); ++it) { - Function* F = M.getFunction(*it); - if(!F) - continue; - for(Value::user_iterator ui = F->user_begin(), ue = F->user_end(); - ui != ue; ++ui) { - // iterate though all calls to malloc - if (CallInst* CI = dyn_cast(*ui)) { - // The function that calls malloc could be a potential allocator - Function *WrapperF = CI->getParent()->getParent(); - if(WrapperF->doesNotReturn()) - continue; - if(!(WrapperF->getReturnType()->isPointerTy())) - continue; - bool isWrapper = true; - for (Function::iterator BBI = WrapperF->begin(), E = WrapperF->end(); BBI != E; ) { - BasicBlock &BB = *BBI++; - - // Only look at return blocks. - ReturnInst *Ret = dyn_cast(BB.getTerminator()); - if (Ret == 0) continue; - - //check for ALL return values - if(flowsFrom(Ret, CI)) { - continue; - } else { - isWrapper = false; - break; - } - // if true for all return add to list of allocators - } - if(isWrapper) - isWrapper = isWrapper && isNotStored(CI); - if(isWrapper) { - changed = (allocators.find(WrapperF->getName()) == allocators.end()); - if(changed) { - ++numAllocators; - allocators.emplace(WrapperF->getName()); - SDEBUG(errs() << WrapperF->getName().str() << "\n"); - } - } - } - } - } - } while(changed); - - do { - changed = false; - std::set TempDeallocators; - TempDeallocators.insert( deallocators.begin(), deallocators.end()); - std::set::iterator it; - for(it = TempDeallocators.begin(); it != TempDeallocators.end(); ++it) { - Function* F = M.getFunction(*it); - - if(!F) - continue; - for(Value::user_iterator ui = F->user_begin(), ue = F->user_end(); - ui != ue; ++ui) { - // iterate though all calls to malloc - if (CallInst* CI = dyn_cast(*ui)) { - // The function that calls malloc could be a potential allocator - Function *WrapperF = CI->getParent()->getParent(); - - if(WrapperF->arg_size() != 1) - continue; - if(!WrapperF->arg_begin()->getType()->isPointerTy()) - continue; - Argument *arg = dyn_cast(WrapperF->arg_begin()); - if(flowsFrom(CI->getOperand(1), arg)) { - changed = (deallocators.find(WrapperF->getName()) == deallocators.end()); - if(changed) { - ++numDeallocators; - deallocators.emplace(WrapperF->getName()); - SDEBUG(errs() << WrapperF->getName().str() << "\n"); - } - } - } - } - } - } while(changed); - return false; -} -void AllocIdentify::getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.setPreservesAll(); -} - -char AllocIdentify::ID = 0; -static RegisterPass -X("alloc-identify", "Identify allocator wrapper functions"); diff --git a/lib/DSA/Basic.cpp b/lib/DSA/Basic.cpp deleted file mode 100644 index 0088aef40..000000000 --- a/lib/DSA/Basic.cpp +++ /dev/null @@ -1,89 +0,0 @@ -//===- Basic.cpp ----------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Implementation of the basic data structure analysis pass. It simply assumes -// that all pointers can points to all possible locations. -// -//===----------------------------------------------------------------------===// - -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" - -#include "llvm/IR/InstVisitor.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/InstIterator.h" -#include "llvm/IR/GetElementPtrTypeIterator.h" - -using namespace llvm; - -static RegisterPass -X("dsa-basic", "Basic Data Structure Analysis(No Analysis)"); - -char BasicDataStructures::ID = 0; - -bool BasicDataStructures::runOnModule(Module &M) { - init(&M.getDataLayout()); - - // - // Create a void pointer type. This is simply a pointer to an 8 bit value. - // - - DSNode * GVNodeInternal = new DSNode(GlobalsGraph); - DSNode * GVNodeExternal = new DSNode(GlobalsGraph); - for (Module::global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) { - if (I->isDeclaration() || (!(I->hasInternalLinkage()))) { - GlobalsGraph->getNodeForValue(&*I).mergeWith(GVNodeExternal); - } else { - GlobalsGraph->getNodeForValue(&*I).mergeWith(GVNodeInternal); - } - } - - GVNodeInternal->foldNodeCompletely(); - GVNodeInternal->maskNodeTypes(DSNode::IncompleteNode); - - GVNodeExternal->foldNodeCompletely(); - GVNodeExternal->setExternalMarker(); - - // Next step, iterate through the nodes in the globals graph, unioning - // together the globals into equivalence classes. - formGlobalECs(); - - for (Function &F : M) { - if (!F.isDeclaration()) { - DSGraph* G = new DSGraph(GlobalECs, getDataLayout(), *TypeSS, GlobalsGraph); - DSNode * Node = new DSNode(G); - - if (!F.hasInternalLinkage()) - Node->setExternalMarker(); - - // Create scalar nodes for all pointer arguments... - for (auto &Arg : F.args()) { - if (isa(Arg.getType())) { - G->getNodeForValue(&Arg).mergeWith(Node); - } - } - - for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ++I) { - G->getNodeForValue(&*I).mergeWith(Node); - } - - Node->foldNodeCompletely(); - Node->maskNodeTypes(DSNode::IncompleteNode); - - setDSGraph(F, G); - } - } - - return false; -} diff --git a/lib/DSA/BottomUpClosure.cpp b/lib/DSA/BottomUpClosure.cpp deleted file mode 100644 index 7f1281c25..000000000 --- a/lib/DSA/BottomUpClosure.cpp +++ /dev/null @@ -1,731 +0,0 @@ -//===- BottomUpClosure.cpp - Compute bottom-up interprocedural closure ----===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the BUDataStructures class, which represents the -// Bottom-Up Interprocedural closure of the data structure graph over the -// program. This is useful for applications like pool allocation, but **not** -// applications like alias analysis. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "dsa-bu" -#include "llvm/IR/Constants.h" -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" -#include "llvm/IR/Module.h" -#include "llvm/ADT/Statistic.h" -#include "smack/Debug.h" -#include "llvm/Support/FormattedStream.h" - -using namespace llvm; - -namespace { - STATISTIC (MaxSCC, "Maximum SCC Size in Call Graph"); - STATISTIC (NumInlines, "Number of graphs inlined"); - STATISTIC (NumCallEdges, "Number of 'actual' call edges"); - STATISTIC (NumIndResolved, "Number of resolved IndCalls"); - STATISTIC (NumIndUnresolved, "Number of unresolved IndCalls"); - // NumEmptyCalls = NumIndUnresolved + Number of calls to external functions - STATISTIC (NumEmptyCalls, "Number of calls we know nothing about"); - STATISTIC (NumRecalculations, "Number of DSGraph recalculations"); - STATISTIC (NumRecalculationsSkipped, "Number of DSGraph recalculations skipped"); - - RegisterPass - X("dsa-bu", "Bottom-up Data Structure Analysis"); -} - -char BUDataStructures::ID; - -// run - Calculate the bottom up data structure graphs for each function in the -// program. -// -bool BUDataStructures::runOnModule(Module &M) { - init(&getAnalysis(), true, true, false, false ); - - return runOnModuleInternal(M); -} - -// BU: -// Construct the callgraph from the local graphs -// Find SCCs -// inline bottom up -// -bool BUDataStructures::runOnModuleInternal(Module& M) { - - // - // Make sure we have a DSGraph for all declared functions in the Module. - // While we may not need them in this DSA pass, a later DSA pass may ask us - // for their DSGraphs, and we want to have them if asked. - // - for (Function &F : M) { - if (!(F.isDeclaration())){ - getOrCreateGraph(&F); - } - } - - // - // Do a post-order traversal of the SCC callgraph and do bottom-up inlining. - // - postOrderInline (M); - - // At the end of the bottom-up pass, the globals graph becomes complete. - // FIXME: This is not the right way to do this, but it is sorta better than - // nothing! In particular, externally visible globals and unresolvable call - // nodes at the end of the BU phase should make things that they point to - // incomplete in the globals graph. - // - - GlobalsGraph->removeTriviallyDeadNodes(); - GlobalsGraph->maskIncompleteMarkers(); - - // Mark external globals incomplete. - GlobalsGraph->markIncompleteNodes(DSGraph::IgnoreGlobals); - GlobalsGraph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); - GlobalsGraph->computeIntPtrFlags(); - - // - // Create equivalence classes for aliasing globals so that we only need to - // record one global per DSNode. - // - formGlobalECs(); - - // Merge the globals variables (not the calls) from the globals graph back - // into the individual function's graph so that changes made to globals during - // BU can be reflected. This is specifically needed for correct call graph - // - for (Function &F : M) { - if (!(F.isDeclaration())){ - DSGraph *Graph = getOrCreateGraph(&F); - cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes); - Graph->buildCallGraph(callgraph, GlobalFunctionList, filterCallees); - Graph->maskIncompleteMarkers(); - Graph->markIncompleteNodes(DSGraph::MarkFormalArgs | - DSGraph::IgnoreGlobals); - Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); - Graph->computeIntPtrFlags(); - } - } - - // Once the correct flags have been calculated. Update the callgraph. - for (Function &F : M) { - if (!(F.isDeclaration())){ - DSGraph *Graph = getOrCreateGraph(&F); - Graph->buildCompleteCallGraph(callgraph, - GlobalFunctionList, filterCallees); - } - } - - NumCallEdges += callgraph.size(); - - // Put the call graph in canonical form - callgraph.buildSCCs(); - callgraph.buildRoots(); - - SDEBUG(print(errs(), &M)); - return false; -} - -// -// Function: applyCallsiteFilter -// -// Description: -// Given a DSCallSite, and a list of functions, filter out the ones -// that aren't callable from the given Callsite. -// -// Does no filtering if 'filterCallees' is set to false. -// -void BUDataStructures:: -applyCallsiteFilter(const DSCallSite &DCS, FuncSet &Callees) { - - if (!filterCallees) return; - - FuncSet::iterator I = Callees.begin(); - CallSite CS = DCS.getCallSite(); - while (I != Callees.end()) { - if (functionIsCallable(CS, *I)) { - ++I; - } else { - I = Callees.erase(I); - } - } -} - -// -// Function: getAllCallees() -// -// Description: -// Given a DSCallSite, add to the list the functions that can be called by -// the call site *if* it is resolvable. Uses 'applyCallsiteFilter' to -// only add the functions that are valid targets of this callsite. -// -void BUDataStructures:: -getAllCallees(const DSCallSite &CS, FuncSet &Callees) { - // - // FIXME: Should we check for the Unknown flag on indirect call sites? - // - // Direct calls to functions that have bodies are always resolvable. - // Indirect function calls that are for a complete call site (the analysis - // knows everything about the call site) and do not target external functions - // are also resolvable. - // - if (CS.isDirectCall()) { - if (!CS.getCalleeFunc()->isDeclaration()) - Callees.insert(CS.getCalleeFunc()); - } else if (CS.getCalleeNode()->isCompleteNode()) { - // Get all callees. - if (!CS.getCalleeNode()->isExternFuncNode()) { - // Get all the callees for this callsite - FuncSet TempCallees; - CS.getCalleeNode()->addFullFunctionSet(TempCallees); - // Filter out the ones that are invalid targets with respect - // to this particular callsite. - applyCallsiteFilter(CS, TempCallees); - // Insert the remaining callees (legal ones, if we're filtering) - // into the master 'Callees' list - Callees.insert(TempCallees.begin(), TempCallees.end()); - } - } -} - -// -// Function: getAllAuxCallees() -// -// Description: -// Return a list containing all of the resolvable callees in the auxiliary -// list for the specified graph in the Callees vector. -// -// Inputs: -// G - The DSGraph for which the callers wants a list of resolvable call -// sites. -// -// Outputs: -// Callees - A list of all functions that can be called from resolvable call -// sites. This list is always cleared by this function before any -// functions are added to it. -// -void BUDataStructures:: -getAllAuxCallees (DSGraph* G, FuncSet & Callees) { - // - // Clear out the list of callees. - // - Callees.clear(); - for (DSGraph::afc_iterator I = G->afc_begin(), E = G->afc_end(); I != E; ++I) - getAllCallees(*I, Callees); -} - -// -// Method: postOrderInline() -// -// Description: -// This methods does a post order traversal of the call graph and performs -// bottom-up inlining of the DSGraphs. -// -void -BUDataStructures::postOrderInline (Module & M) { - // Variables used for Tarjan SCC-finding algorithm. These are passed into - // the recursive function used to find SCCs. - std::vector Stack; - std::map ValMap; - unsigned NextID = 1; - - - // Do post order traversal on the global ctors. Use this information to update - // the globals graph. - const char *Name = "llvm.global_ctors"; - GlobalVariable *GV = M.getNamedGlobal(Name); - if (GV && !(GV->isDeclaration()) && !(GV->hasLocalLinkage())) { - // Should be an array of '{ int, void ()* }' structs. The first value is - // the init priority, which we ignore. - ConstantArray *InitList = dyn_cast(GV->getInitializer()); - if (InitList) { - for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) - if (ConstantStruct *CS = dyn_cast(InitList->getOperand(i))) { - if (CS->getNumOperands() != 2) - break; // Not array of 2-element structs. - Constant *FP = CS->getOperand(1); - if (FP->isNullValue()) - break; // Found a null terminator, exit. - - if (ConstantExpr *CE = dyn_cast(FP)) - if (CE->isCast()) - FP = CE->getOperand(0); - Function *F = dyn_cast(FP); - if (F && !F->isDeclaration() && !ValMap.count(F)) { - calculateGraphs(F, Stack, NextID, ValMap); - CloneAuxIntoGlobal(getDSGraph(*F)); - } - } - GlobalsGraph->removeTriviallyDeadNodes(); - GlobalsGraph->maskIncompleteMarkers(); - - // Mark external globals incomplete. - GlobalsGraph->markIncompleteNodes(DSGraph::IgnoreGlobals); - GlobalsGraph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); - GlobalsGraph->computeIntPtrFlags(); - - // - // Create equivalence classes for aliasing globals so that we only need to - // record one global per DSNode. - // - formGlobalECs(); - // propogte information calculated - // from the globals graph to the other graphs. - for (Module::iterator F = M.begin(); F != M.end(); ++F) { - if (!(F->isDeclaration())){ - DSGraph *Graph = getDSGraph(*F); - cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes); - Graph->buildCallGraph(callgraph, GlobalFunctionList, filterCallees); - Graph->maskIncompleteMarkers(); - Graph->markIncompleteNodes(DSGraph::MarkFormalArgs | - DSGraph::IgnoreGlobals); - Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); - Graph->computeIntPtrFlags(); - } - } - } - } - - // - // Start the post order traversal with the main() function. If there is no - // main() function, don't worry; we'll have a separate traversal for inlining - // graphs for functions not reachable from main(). - // - Function *MainFunc = M.getFunction ("main"); - if (MainFunc && !MainFunc->isDeclaration()) { - calculateGraphs(MainFunc, Stack, NextID, ValMap); - CloneAuxIntoGlobal(getDSGraph(*MainFunc)); - } - - // - // Calculate the graphs for any functions that are unreachable from main... - // - for (Function &F : M) - if (!F.isDeclaration() && !ValMap.count(&F)) { - if (MainFunc) - SDEBUG(errs() << debugname << ": Function unreachable from main: " - << F.getName() << "\n"); - calculateGraphs(&F, Stack, NextID, ValMap); // Calculate all graphs. - CloneAuxIntoGlobal(getDSGraph(F)); - - // Mark this graph as processed. Do this by finding all functions - // in the graph that map to it, and mark them visited. - // Note that this really should be handled neatly by calculateGraphs - // itself, not here. However this catches the worst offenders. - DSGraph *G = getDSGraph(F); - for(DSGraph::retnodes_iterator RI = G->retnodes_begin(), - RE = G->retnodes_end(); RI != RE; ++RI) { - if (getDSGraph(*RI->first) == G) { - if (!ValMap.count(RI->first)) - ValMap[RI->first] = ~0U; - else - assert(ValMap[RI->first] == ~0U); - } - } - } - return; -} - -static bool hasNewCallees(svset &New, - svset &Old) { - if (New.size() > Old.size()) return true; - - svset::iterator NI = New.begin(), NE = New.end(); - - for (; NI != NE; ++NI) - if (!Old.count(*NI)) return true; - - return false; -} - -// -// Method: calculateGraphs() -// -// Description: -// Perform recursive bottom-up inlining of DSGraphs from callee to caller. -// -// Inputs: -// F - The function which should have its callees' DSGraphs merged into its -// own DSGraph. -// Stack - The stack used for Tarjan's SCC-finding algorithm. -// NextID - The nextID value used for Tarjan's SCC-finding algorithm. -// ValMap - The map used for Tarjan's SCC-finding algorithm. -// -// Return value: -// -unsigned -BUDataStructures::calculateGraphs (const Function *F, - TarjanStack & Stack, - unsigned & NextID, - TarjanMap & ValMap) { - assert(!ValMap.count(F) && "Shouldn't revisit functions!"); - unsigned Min = NextID++, MyID = Min; - ValMap[F] = Min; - Stack.push_back(F); - - // - // FIXME: This test should be generalized to be any function that we have - // already processed in the case when there isn't a main() or there are - // unreachable functions! - // - if (F->isDeclaration()) { // sprintf, fprintf, sscanf, etc... - // No callees! - Stack.pop_back(); - ValMap[F] = ~0; - return Min; - } - - // - // Get the DSGraph of the current function. Make one if one doesn't exist. - // - DSGraph* Graph = getOrCreateGraph(F); - - // - // Find all callee functions. Use the DSGraph for this (do not use the call - // graph (DSCallgraph) as we're still in the process of constructing it). - // - FuncSet CalleeFunctions; - getAllAuxCallees(Graph, CalleeFunctions); - - // - // Iterate through each call target (these are the edges out of the current - // node (i.e., the current function) in Tarjan graph parlance). Find the - // minimum assigned ID. - // - for (FuncSet::iterator I = CalleeFunctions.begin(), E = CalleeFunctions.end(); - I != E; ++I) { - const Function *Callee = *I; - unsigned M; - // - // If we have not visited this callee before, visit it now (this is the - // post-order component of the Bottom-Up algorithm). Otherwise, look up - // the assigned ID value from the Tarjan Value Map. - // - TarjanMap::iterator It = ValMap.find(Callee); - if (It == ValMap.end()) // No, visit it now. - M = calculateGraphs(Callee, Stack, NextID, ValMap); - else // Yes, get it's number. - M = It->second; - - // - // If we've found a function with a smaller ID than this funtion, record - // that ID as the minimum ID. - // - if (M < Min) Min = M; - } - - assert(ValMap[F] == MyID && "SCC construction assumption wrong!"); - - // - // If the minimum ID found is not this function's ID, then this function is - // part of a larger SCC. - // - if (Min != MyID) - return Min; - - // - // If this is a new SCC, process it now. - // - if (Stack.back() == F) { // Special case the single "SCC" case here. - SDEBUG(errs() << "Visiting single node SCC #: " << MyID << " fn: " - << F->getName() << "\n"); - Stack.pop_back(); - SDEBUG(errs() << " [BU] Calculating graph for: " << F->getName()<< "\n"); - DSGraph* G = getOrCreateGraph(F); - calculateGraph(G); - SDEBUG(errs() << " [BU] Done inlining: " << F->getName() << " [" - << G->getGraphSize() << "+" << G->getAuxFunctionCalls().size() - << "]\n"); - - if (MaxSCC < 1) MaxSCC = 1; - - // - // Should we revisit the graph? Only do it if there are now new resolvable - // callees. - FuncSet NewCallees; - getAllAuxCallees(G, NewCallees); - if (!NewCallees.empty()) { - if (hasNewCallees(NewCallees, CalleeFunctions)) { - SDEBUG(errs() << "Recalculating " << F->getName() << " due to new knowledge\n"); - ValMap.erase(F); - ++NumRecalculations; - return calculateGraphs(F, Stack, NextID, ValMap); - } - ++NumRecalculationsSkipped; - } - ValMap[F] = ~0U; - return MyID; - } else { - unsigned SCCSize = 1; - const Function *NF = Stack.back(); - if(NF != F) - ValMap[NF] = ~0U; - DSGraph* SCCGraph = getDSGraph(*NF); - - // - // First thing first: collapse all of the DSGraphs into a single graph for - // the entire SCC. Splice all of the graphs into one and discard all of - // the old graphs. - // - while (NF != F) { - Stack.pop_back(); - NF = Stack.back(); - if(NF != F) - ValMap[NF] = ~0U; - - DSGraph* NFG = getDSGraph(*NF); - - if (NFG != SCCGraph) { - // Update the Function -> DSG map. - for (DSGraph::retnodes_iterator I = NFG->retnodes_begin(), - E = NFG->retnodes_end(); I != E; ++I) - setDSGraph(*I->first, SCCGraph); - - SCCGraph->spliceFrom(NFG); - delete NFG; - ++SCCSize; - } - } - Stack.pop_back(); - - SDEBUG(errs() << "Calculating graph for SCC #: " << MyID << " of size: " - << SCCSize << "\n"); - - // Compute the Max SCC Size. - if (MaxSCC < SCCSize) - MaxSCC = SCCSize; - - // Clean up the graph before we start inlining a bunch again... - SCCGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals); - - // Now that we have one big happy family, resolve all of the call sites in - // the graph... - calculateGraph(SCCGraph); - SDEBUG(errs() << " [BU] Done inlining SCC [" << SCCGraph->getGraphSize() - << "+" << SCCGraph->getAuxFunctionCalls().size() << "]\n" - << "DONE with SCC #: " << MyID << "\n"); - FuncSet NewCallees; - getAllAuxCallees(SCCGraph, NewCallees); - if (!NewCallees.empty()) { - if (hasNewCallees(NewCallees, CalleeFunctions)) { - SDEBUG(errs() << "Recalculating SCC Graph " << F->getName() << " due to new knowledge\n"); - ValMap.erase(F); - ++NumRecalculations; - return calculateGraphs(F, Stack, NextID, ValMap); - } - ++NumRecalculationsSkipped; - } - ValMap[F] = ~0U; - return MyID; - } -} - -// -// Method: CloneAuxIntoGlobal() -// -// Description: -// This method takes the specified graph and processes each unresolved call -// site (a call site for which all targets are not yet known). For each -// unresolved call site, it adds it to the globals graph and merges -// information about the call site if the globals graph already had the call -// site in its own list of unresolved call sites. -// -void BUDataStructures::CloneAuxIntoGlobal(DSGraph* G) { - // - // If this DSGraph has no unresolved call sites, do nothing. We do enough - // work that wastes time even when the list is empty that this extra check - // is probably worth it. - // - if (G->afc_begin() == G->afc_end()) - return; - - DSGraph* GG = G->getGlobalsGraph(); - ReachabilityCloner RC(GG, G, 0); - - // - // Determine which called values are both within the local graph DSCallsites - // and the global graph DSCallsites. Note that we require that the global - // graph have a DSNode for the called value. - // - std::map CommonCallValues; - for (DSGraph::afc_iterator ii = G->afc_begin(), ee = G->afc_end(); - ii != ee; - ++ii) { - // - // If the globals graph has a DSNode for the LLVM value used in the local - // unresolved call site, then it might have a DSCallSite for it, too. - // Record this call site as a potential call site that will need to be - // merged. - // - // Otherwise, just add the call site to the globals graph. - // - Value * V = ii->getCallSite().getCalledValue(); - if (GG->hasNodeForValue(V)) { - DSCallSite & DS = *ii; - CommonCallValues[V] = &DS; - } else { - GG->addAuxFunctionCall(RC.cloneCallSite(*ii)); - } - } - - // - // Scan through all the unresolved call sites in the globals graph and see if - // the local graph has a call using the same LLVM value. If so, merge the - // call sites. - // - DSGraph::afc_iterator GGii = GG->afc_begin(); - for (; GGii != GG->afc_end(); ++GGii) { - // - // Determine if this unresolved call site is also in the local graph. - // If so, then merge it. - // - Value * CalledValue = GGii->getCallSite().getCalledValue(); - std::map::iterator v; - v = CommonCallValues.find (CalledValue); - if (v != CommonCallValues.end()) { - // - // Merge the unresolved call site into the globals graph. - // - RC.cloneCallSite(*(v->second)).mergeWith(*GGii); - - // - // Mark that this call site was merged by removing the called LLVM value - // from the set of values common to both the local and global DSGraphs. - // - CommonCallValues.erase (v); - } - } - - // - // We've now merged all DSCallSites that were known both to the local graph - // and the globals graph. Now, there are still some local call sites that - // need to be *added* to the globals graph; they are in DSCallSites remaining - // in CommonCallValues. - // - std::map::iterator v = CommonCallValues.begin (); - for (; v != CommonCallValues.end(); ++v) { - GG->addAuxFunctionCall(RC.cloneCallSite(*(v->second))); - } - - return; -} - - -// -// Description: -// Inline all graphs in the callgraph and remove callsites that are completely -// dealt with -// -void BUDataStructures::calculateGraph(DSGraph* Graph) { - SDEBUG(Graph->AssertGraphOK(); Graph->getGlobalsGraph()->AssertGraphOK()); - Graph->buildCallGraph(callgraph, GlobalFunctionList, filterCallees); - - // Move our call site list into TempFCs so that inline call sites go into the - // new call site list and doesn't invalidate our iterators! - DSGraph::FunctionListTy TempFCs; - DSGraph::FunctionListTy &AuxCallsList = Graph->getAuxFunctionCalls(); - TempFCs.swap(AuxCallsList); - - for(DSGraph::FunctionListTy::iterator I = TempFCs.begin(), E = TempFCs.end(); - I != E; ++I) { - SDEBUG(Graph->AssertGraphOK(); Graph->getGlobalsGraph()->AssertGraphOK()); - - DSCallSite &CS = *I; - - // Fast path for noop calls. Note that we don't care about merging globals - // in the callee with nodes in the caller here. - if (!CS.isIndirectCall() && CS.getRetVal().isNull() - && CS.getNumPtrArgs() == 0 && !CS.isVarArg()) { - continue; - } - - // If this callsite is unresolvable, get rid of it now. - if (CS.isUnresolvable()) { - continue; - } - - // Find all callees for this callsite, according to the DSGraph! - // Do *not* use the callgraph, because we're updating that as we go! - FuncSet CalledFuncs; - getAllCallees(CS,CalledFuncs); - - if (CalledFuncs.empty()) { - ++NumEmptyCalls; - if (CS.isIndirectCall()) - ++NumIndUnresolved; - // Remember that we could not resolve this yet! - DSGraph::FunctionListTy::iterator S = I++; - AuxCallsList.splice(AuxCallsList.end(), TempFCs, S); - continue; - } - // If we get to this point, we know the callees, and can inline. - // This means, that either it is a direct call site. Or if it is - // an indirect call site, its calleeNode is complete, and we can - // resolve this particular call site. - assert((CS.isDirectCall() || CS.getCalleeNode()->isCompleteNode()) - && "Resolving an indirect incomplete call site"); - - if (CS.isIndirectCall()) { - ++NumIndResolved; - } - - DSGraph *GI; - - for (FuncSet::iterator I = CalledFuncs.begin(), E = CalledFuncs.end(); - I != E; ++I) { - const Function *Callee = *I; - // Get the data structure graph for the called function. - - GI = getDSGraph(*Callee); // Graph to inline - SDEBUG(GI->AssertGraphOK(); GI->getGlobalsGraph()->AssertGraphOK()); - SDEBUG(errs() << " Inlining graph for " << Callee->getName() - << "[" << GI->getGraphSize() << "+" - << GI->getAuxFunctionCalls().size() << "] into '" - << Graph->getFunctionNames() << "' [" << Graph->getGraphSize() <<"+" - << Graph->getAuxFunctionCalls().size() << "]\n"); - - // - // Merge in the DSGraph of the called function. - // - // TODO: - // Why are the strip alloca bit and don't clone call nodes bit set? - // - // I believe the answer is on page 6 of the PLDI paper on DSA. The - // idea is that stack objects are invalid if they escape. - // - Graph->mergeInGraph(CS, *Callee, *GI, - DSGraph::StripAllocaBit|DSGraph::DontCloneCallNodes); - ++NumInlines; - SDEBUG(Graph->AssertGraphOK();); - } - } - TempFCs.clear(); - - // Recompute the Incomplete markers - Graph->maskIncompleteMarkers(); - Graph->markIncompleteNodes(DSGraph::MarkFormalArgs); - Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); - Graph->computeIntPtrFlags(); - - // - // Update the callgraph with the new information that we have gleaned. - // NOTE : This must be called before removeDeadNodes, so that no - // information is lost due to deletion of DSCallNodes. - Graph->buildCallGraph(callgraph, GlobalFunctionList, filterCallees); - - // Delete dead nodes. Treat globals that are unreachable but that can - // reach live nodes as live. - Graph->removeDeadNodes(DSGraph::KeepUnreachableGlobals); - - cloneIntoGlobals(Graph, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes | - DSGraph::StripAllocaBit); - //Graph->writeGraphToFile(cerr, "bu_" + F.getName()); -} diff --git a/lib/DSA/CallTargets.cpp b/lib/DSA/CallTargets.cpp deleted file mode 100644 index 4fa9fc477..000000000 --- a/lib/DSA/CallTargets.cpp +++ /dev/null @@ -1,173 +0,0 @@ -//=- lib/Analysis/IPA/CallTargets.cpp - Resolve Call Targets --*- C++ -*-=====// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass uses DSA to map targets of all calls, and reports on if it -// thinks it knows all targets of a given call. -// -// Loop over all callsites, and lookup the DSNode for that site. Pull the -// Functions from the node as callees. -// This is essentially a utility pass to simplify later passes that only depend -// on call sites and callees to operate (such as a devirtualizer). -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "call-targets" -#include "llvm/IR/Module.h" -#include "llvm/IR/Instructions.h" -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" -#include "dsa/CallTargets.h" -#include "llvm/ADT/Statistic.h" -#include "smack/Debug.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/IR/Constants.h" -#include -using namespace llvm; - -RegisterPass > X("calltarget-eqtd","Find Call Targets (uses DSA-EQTD)"); -RegisterPass > Y("calltarget-td","Find Call Targets (uses DSA-TD)"); -namespace { - STATISTIC (DirCall, "Number of direct calls"); - STATISTIC (IndCall, "Number of indirect calls"); - STATISTIC (CompleteInd, "Number of complete indirect calls"); - STATISTIC (CompleteEmpty, "Number of complete empty calls"); - -} - -namespace dsa { - -template -char CallTargetFinder::ID = 0; - - template -void CallTargetFinder::findIndTargets(Module &M) -{ - dsa* T = &getAnalysis(); - const DSCallGraph & callgraph = T->getCallGraph(); - DSGraph* G = T->getGlobalsGraph(); - DSGraph::ScalarMapTy& SM = G->getScalarMap(); - for (Function &F : M) - if (!F.isDeclaration()) - for (BasicBlock &B : F) - for (Instruction &I : B) - if (isa(&I) || isa(&I)) { - CallSite cs(&I); - AllSites.push_back(cs); - Function* CF = cs.getCalledFunction(); - - if (isa(cs.getCalledValue())) continue; - if (isa(cs.getCalledValue())) continue; - - // - // If the called function is casted from one function type to - // another, peer into the cast instruction and pull out the actual - // function being called. - // - if (!CF) - CF = dyn_cast(cs.getCalledValue()->stripPointerCasts()); - - if (!CF) { - Value * calledValue = cs.getCalledValue()->stripPointerCasts(); - if (isa(calledValue)) { - ++DirCall; - CompleteSites.insert(cs); - } else { - IndCall++; - - DSCallGraph::callee_iterator csi = callgraph.callee_begin(cs), - cse = callgraph.callee_end(cs); - while(csi != cse) { - const Function *F = *csi; - DSCallGraph::scc_iterator sccii = callgraph.scc_begin(F), - sccee = callgraph.scc_end(F); - for(;sccii != sccee; ++sccii) { - DSGraph::ScalarMapTy::const_iterator I = SM.find(SM.getLeaderForGlobal(*sccii)); - if (I != SM.end()) { - IndMap[cs].push_back (*sccii); - } - } - ++csi; - } - const Function *F1 = (cs).getInstruction()->getParent()->getParent(); - F1 = callgraph.sccLeader(&*F1); - - DSCallGraph::scc_iterator sccii = callgraph.scc_begin(F1), - sccee = callgraph.scc_end(F1); - for(;sccii != sccee; ++sccii) { - DSGraph::ScalarMapTy::const_iterator I = SM.find(SM.getLeaderForGlobal(*sccii)); - if (I != SM.end()) { - IndMap[cs].push_back (*sccii); - } - } - - DSNode* N = T->getDSGraph(*cs.getCaller()) - ->getNodeForValue(cs.getCalledValue()).getNode(); - assert (N && "CallTarget: findIndTargets: No DSNode!"); - - if (!N->isIncompleteNode() && !N->isExternalNode() && IndMap[cs].size()) { - CompleteSites.insert(cs); - ++CompleteInd; - } - if (!N->isIncompleteNode() && !N->isExternalNode() && !IndMap[cs].size()) { - ++CompleteEmpty; - SDEBUG(errs() << "Call site empty: '" - << cs.getInstruction()->getName() - << "' In '" - << cs.getInstruction()->getParent()->getParent()->getName() - << "'\n"); - } - } - } else { - ++DirCall; - IndMap[cs].push_back(CF); - CompleteSites.insert(cs); - } - } -} - - template -void CallTargetFinder::print(llvm::raw_ostream &O, const Module *M) const -{ - O << "[* = incomplete] CS: func list\n"; - for (std::map >::const_iterator ii = - IndMap.begin(), - ee = IndMap.end(); ii != ee; ++ii) { - - if (ii->first.getCalledFunction()) //only print indirect - continue; - if(isa(ii->first.getCalledValue()->stripPointerCasts())) - continue; - if (!isComplete(ii->first)) { - O << "* "; - CallSite cs = ii->first; - cs.getInstruction()->print(O, true); - O << cs.getInstruction()->getParent()->getParent()->getName().str() << " " - << cs.getInstruction()->getName().str() << " "; - } - O << ii->first.getInstruction() << ":"; - for (std::vector::const_iterator i = ii->second.begin(), - e = ii->second.end(); i != e; ++i) { - O << " " << (*i)->getName().str(); - } - O << "\n"; - } -} - - template -bool CallTargetFinder::runOnModule(Module &M) { - findIndTargets(M); - return false; -} - - template -void CallTargetFinder::getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - AU.addRequired(); -} -} diff --git a/lib/DSA/CompleteBottomUp.cpp b/lib/DSA/CompleteBottomUp.cpp deleted file mode 100644 index 17adf0cfb..000000000 --- a/lib/DSA/CompleteBottomUp.cpp +++ /dev/null @@ -1,220 +0,0 @@ -//===- CompleteBottomUp.cpp - Complete Bottom-Up Data Structure Graphs ----===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the exact same as the bottom-up graphs, but we use take a completed -// call graph and inline all indirect callees into their callers graphs, making -// the result more useful for things like pool allocation. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "dsa-cbu" -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" -#include "llvm/IR/Module.h" -#include "llvm/ADT/Statistic.h" -#include "smack/Debug.h" -#include "llvm/Support/FormattedStream.h" -using namespace llvm; - -namespace { - RegisterPass - X("dsa-cbu", "'Complete' Bottom-up Data Structure Analysis"); -} - -char CompleteBUDataStructures::ID; - -// -// Method: runOnModule() -// -// Description: -// Entry point for this pass. Calculate the bottom up data structure graphs -// for each function in the program. -// -// Return value: -// true - The module was modified. -// false - The module was not modified. -// -bool -CompleteBUDataStructures::runOnModule (Module &M) { - init(&getAnalysis(), true, true, false, true); - - - // - // Make sure we have a DSGraph for all declared functions in the Module. - // formGlobalECs assumes that DSInfo is populated with a list of - // DSgraphs for all the functions. - - for (Function &F : M) { - if (!(F.isDeclaration())){ - getOrCreateGraph(&F); - } - } - - buildIndirectFunctionSets(); - formGlobalECs(); - for (Function &F : M) { - if (!(F.isDeclaration())) { - if (DSGraph * Graph = getOrCreateGraph(&F)) { - cloneIntoGlobals(Graph, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes | - DSGraph::StripAllocaBit); - } - } - } - - for (Function &F : M) { - if (!(F.isDeclaration())) { - if (DSGraph * Graph = getOrCreateGraph(&F)) { - cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes); - } - } - } - - // - // Do bottom-up propagation. - // - bool modified = runOnModuleInternal(M); - - callgraph.buildSCCs(); - callgraph.buildRoots(); - - return modified; -} - -// -// Method: buildIndirectFunctionSets() -// -// Description: -// For every indirect call site, ensure that every function target is -// associated with a single DSNode. -// -void -CompleteBUDataStructures::buildIndirectFunctionSets (void) { - // - // Loop over all of the indirect calls in the program. If a call site can - // call multiple different functions, we need to unify all of the callees into - // the same equivalence class. - // - DSGraph* G = getGlobalsGraph(); - DSGraph::ScalarMapTy& SM = G->getScalarMap(); - - // Merge nodes in the global graph for these functions - for (DSCallGraph::callee_key_iterator ii = callgraph.key_begin(), - ee = callgraph.key_end(); ii != ee; ++ii) { - -#ifndef NDEBUG - // --Verify that for every callee of an indirect function call - // we have an entry in the GlobalsGraph - - // If any function in an SCC is a callee of an indirect function - // call, the DScallgraph contains the leader of the SCC as the - // callee of the indirect call. - // The leasder of the SCC may not have an entry in the Globals - // Graph, but at least one of the functions in the SCC - // should have an entry in the GlobalsGraph - - Value *CalledValue = (*ii).getCalledValue()->stripPointerCasts(); - - bool isIndirect = (!isa(CalledValue)); - if (isIndirect) { - DSCallGraph::callee_iterator csii = callgraph.callee_begin(*ii), - csee = callgraph.callee_end(*ii); - - for (; csii != csee; ++csii) { - // - // Declarations don't have to have entries. Functions may be - // equivalence classed already, so we have to check their equivalence - // class leader instead of the global itself. - // - const Function * F = *csii; - if (!(F->isDeclaration())){ - DSCallGraph::scc_iterator sccii = callgraph.scc_begin(F), - sccee = callgraph.scc_end(F); - bool flag = false; - for(; sccii != sccee; ++sccii) { - flag |= SM.count(SM.getLeaderForGlobal(*sccii)); - } - assert (flag && - "Indirect function callee not in globals?"); - } - } - } -#endif - - // - // Note: The code above and below is dealing with the fact that the targets - // of *direct* function calls do not show up in the Scalar Map of the - // globals graph. The above assertion simply verifies that all targets of - // indirect function calls show up in the Scalar Map of the globals graph, - // and then the code below can just check the scalar map to see if the - // call needs to be processed because it is an indirect function call. - // - // I suspect that this code is designed this way more for historical - // reasons than for simplicity. We should simplify the code is possible at - // a future date. - // - // FIXME: Given the above is a valid assertion, we could probably replace - // this code with something that *assumes* we have entries in the Scalar - // Map. However, because - // I'm not convinced that we can just *skip* direct calls in this function - // this code is careful to handle callees not existing in the globals graph - // In other words what we have here should be correct, but might be overkill - // that we can trim down later as needed. - - DSNodeHandle calleesNH; - - // When we build SCCs we remove any calls that are to functions in the - // same SCC. Hence, for every indirect call site we must assume that it - // might call functions in its function's SCC that are address taken. - const Function *F1 = (*ii).getInstruction()->getParent()->getParent(); - F1 = callgraph.sccLeader(&*F1); - - DSCallGraph::scc_iterator sccii = callgraph.scc_begin(F1), - sccee = callgraph.scc_end(F1); - for(;sccii != sccee; ++sccii) { - DSGraph::ScalarMapTy::const_iterator I = SM.find(SM.getLeaderForGlobal(*sccii)); - if (I != SM.end()) { - calleesNH.mergeWith(I->second); - } - } - - DSCallGraph::callee_iterator csi = callgraph.callee_begin(*ii), - cse = callgraph.callee_end(*ii); - - - // We get all the callees, and then for all functions in that SCC, find the - // ones that have entries in the GlobalsGraph. - - // We merge all the functions in the SCC that have entries, and then move - // on to the next callee and repeat. - - // If an SCC has functions that have entries in the GlobalsGraph, and are - // targets of an indirect function call site, they will be merged. - - // However, if an SCC has functions, that have entries in the GlobalsGraph, - // bur are not the targets of an indirect function call site, they will not - // be merged by CBU. - - // This NH starts off empty, but ends up merging them all together - - while(csi != cse) { - const Function *F = *csi; - DSCallGraph::scc_iterator sccii = callgraph.scc_begin(F), - sccee = callgraph.scc_end(F); - for(;sccii != sccee; ++sccii) { - DSGraph::ScalarMapTy::const_iterator I = SM.find(SM.getLeaderForGlobal(*sccii)); - if (I != SM.end()) { - calleesNH.mergeWith(I->second); - } - } - ++csi; - } - } -} diff --git a/lib/DSA/DSCallGraph.cpp b/lib/DSA/DSCallGraph.cpp deleted file mode 100644 index 0db83228c..000000000 --- a/lib/DSA/DSCallGraph.cpp +++ /dev/null @@ -1,273 +0,0 @@ -//===- DSCallGraph.cpp - Implement the Call Graph Support class -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Call Graph -// -//===----------------------------------------------------------------------===// - -#include "dsa/DSCallGraph.h" -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" - -#include "llvm/IR/Function.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/CommandLine.h" - -#include - -using namespace llvm; - -static bool _hasPointers(const llvm::FunctionType* T) { - if (T->isVarArg()) return true; - if (T->getReturnType()->isPointerTy()) return true; - for (unsigned x = 0; x < T->getNumParams(); ++x) - if (T->getParamType(x)->isPointerTy()) - return true; - return false; -} - -bool DSCallGraph::hasPointers(const llvm::Function* F) { - return _hasPointers(F->getFunctionType()); -} - -bool DSCallGraph::hasPointers(llvm::CallSite& CS) { - if (CS.getCalledFunction()) - return hasPointers(CS.getCalledFunction()); - - const llvm::Value* Callee = CS.getCalledValue(); - const llvm::Type* T = Callee->getType(); - if (const llvm::PointerType* PT = llvm::dyn_cast(T)) - T = PT->getElementType(); - return _hasPointers(llvm::cast(T)); -} - -unsigned DSCallGraph::tarjan_rec(const llvm::Function* F, TFStack& Stack, - unsigned &NextID, TFMap& ValMap) { - assert(!ValMap.count(F) && "Shouldn't revisit functions!"); - unsigned Min = NextID++, MyID = Min; - ValMap[F] = Min; - Stack.push_back(F); - - // The edges out of the current node are the call site targets... - for (flat_iterator ii = flat_callee_begin(F), - ee = flat_callee_end(F); ii != ee; ++ii) { - unsigned M = Min; - // Have we visited the destination function yet? - TFMap::iterator It = ValMap.find(*ii); - if (It == ValMap.end()) // No, visit it now. - M = tarjan_rec(*ii, Stack, NextID, ValMap); - else if (std::find(Stack.begin(), Stack.end(), *ii) != Stack.end()) - M = It->second; - if (M < Min) Min = M; - } - - assert(ValMap[F] == MyID && "SCC construction assumption wrong!"); - if (Min != MyID) - return Min; // This is part of a larger SCC! - - // If this is a new SCC, process it now. - if (F == Stack.back()) { - // single node case - Stack.pop_back(); - SCCs.insert(F); - } else { - // Take care that the leader is not an external function - std::vector microSCC; - const llvm::Function* NF = 0; - const llvm::Function* Leader = 0; - do { - NF = Stack.back(); - Stack.pop_back(); - microSCC.push_back(NF); - if (!Leader && !NF->isDeclaration()) Leader = NF; - } while (NF != F); - //Leader is not an extern function - //No multi-function SCC can not have a defined function, as all externs - //are treated as having no callees - assert(Leader && "No Leader?"); - SCCs.insert(Leader); - Leader = SCCs.getLeaderValue(Leader); - assert(!Leader->isDeclaration() && "extern leader"); - for (std::vector::iterator ii = microSCC.begin(), - ee = microSCC.end(); ii != ee; ++ii) { - SCCs.insert(*ii); - const llvm::Function* Temp = SCCs.getLeaderValue(*ii); - //Order Matters - SCCs.unionSets(Leader, Temp); - assert (SCCs.getLeaderValue(Leader) == Leader && "SCC construction wrong"); - assert (SCCs.getLeaderValue(Temp) == Leader && "SCC construction wrong"); - } - } - - return MyID; -} - -void DSCallGraph::buildSCCs() { - TFStack Stack; - TFMap ValMap; - unsigned NextID = 1; - - for (flat_key_iterator ii = flat_key_begin(), ee = flat_key_end(); - ii != ee; ++ii) - if (!ValMap.count(*ii)) - tarjan_rec(*ii, Stack, NextID, ValMap); - - removeECFunctions(); -} - -static void removeECs(DSCallGraph::FuncSet& F, - llvm::EquivalenceClasses& ECs) { - DSCallGraph::FuncSet result; - for (DSCallGraph::FuncSet::const_iterator ii = F.begin(), ee = F.end(); - ii != ee; ++ii) - result.insert(ECs.getLeaderValue(*ii)); - - F.swap(result); -} - -void DSCallGraph::removeECFunctions() { - //First the callers - for (SimpleCalleesTy::iterator ii = SimpleCallees.begin(), - ee = SimpleCallees.end(); ii != ee;) { - const llvm::Function* Leader = SCCs.getLeaderValue(ii->first); - if (Leader == ii->first) { - // This is the leader, leave it alone - ++ii; - } else { - //This is not the leader, merge into the leader - SimpleCallees[Leader].insert(ii->second.begin(), ii->second.end()); - SimpleCalleesTy::iterator tmpii = ii; - ++ii; - SimpleCallees.erase(tmpii); - } - } - // then the callees - for (SimpleCalleesTy::iterator ii = SimpleCallees.begin(), - ee = SimpleCallees.end(); ii != ee; ++ii) { - removeECs(ii->second, SCCs); - //and apparent self loops inside an SCC - ii->second.erase(ii->first); - } - for (ActualCalleesTy::iterator ii = ActualCallees.begin(), - ee = ActualCallees.end(); ii != ee; ++ii) - removeECs(ii->second, SCCs); -} - -void DSCallGraph::buildRoots() { - FuncSet knownCallees; - FuncSet knownCallers; - for (SimpleCalleesTy::iterator ii = SimpleCallees.begin(), - ee = SimpleCallees.end(); ii != ee; ++ii) { - knownCallees.insert(ii->second.begin(), ii->second.end()); - knownCallers.insert(ii->first); - } - knownRoots.clear(); - std::set_difference(knownCallers.begin(), knownCallers.end(), - knownCallees.begin(), knownCallees.end(), - std::inserter(knownRoots, knownRoots.begin())); -} - -void DSCallGraph::buildIncompleteCalleeSet(svset callees) { - IncompleteCalleeSet.insert(callees.begin(), callees.end()); -} - -template -void printNameOrPtr(T& Out, const llvm::Function* F) { - if (F->hasName()) - Out << F->getName(); - else - Out << F; -} - -void DSCallGraph::dump() const { - //function map - - //CallGraph map - for (SimpleCalleesTy::const_iterator ii = SimpleCallees.begin(), - ee = SimpleCallees.end(); ii != ee; ++ii) { - llvm::errs() << "CallGraph["; - printNameOrPtr(llvm::errs(), ii->first); - llvm::errs() << "]"; - for (FuncSet::const_iterator i = ii->second.begin(), - e = ii->second.end(); i != e; ++i) { - llvm::errs() << " "; - printNameOrPtr(llvm::errs(), *i); - } - llvm::errs() << "\n"; - } - - //Functions we know about that aren't called - llvm::errs() << "Roots:"; - for (FuncSet::const_iterator ii = knownRoots.begin(), ee = knownRoots.end(); - ii != ee; ++ii) { - llvm::errs() << " "; - printNameOrPtr(llvm::errs(), *ii); - } - llvm::errs() << "\n"; -} - -// -// Method: insert() -// -// Description: -// Insert a new entry into the call graph. This entry says that the specified -// call site calls the specified function. -// -// Inputs: -// CS - The call site which calls the specified function. -// F - The function which is called. This is permitted to be NULL. It is -// possible to have call sites that don't have any targets, and sometimes -// users just want to ensure that a call site has an entry within the -// call graph. -// -void -DSCallGraph::insert(llvm::CallSite CS, const llvm::Function* F) { - // - // Find the function to which the call site belongs. - // - const llvm::Function * Parent = CS.getInstruction()->getParent()->getParent(); - - // - // Determine the SCC leaders for both the calling function and the called - // function. If they don't belong to an SCC, add them as leaders. - // - SCCs.insert (Parent); - SCCs.insert (F); - const llvm::Function * ParentLeader = SCCs.getLeaderValue (Parent); - const llvm::Function * FLeader = SCCs.getLeaderValue (F); - - // - // Create an empty set for the callee; hence, all called functions get to be - // in the call graph also. This simplifies SCC formation. - // - SimpleCallees[ParentLeader]; - if (F) { - ActualCallees[CS].insert(FLeader); - SimpleCallees[ParentLeader].insert(FLeader); - } -} - -void DSCallGraph::insureEntry(const llvm::Function* F) { - SimpleCallees[F]; -} - -void DSCallGraph::addFullFunctionSet(llvm::CallSite CS, - svset &Set) const { - DSCallGraph::callee_iterator csi = callee_begin(CS), - cse = callee_end(CS); - while(csi != cse) { - const Function *F = *csi; - Set.insert(scc_begin(F), scc_end(F)); - ++csi; - } - const Function *F1 = CS.getInstruction()->getParent()->getParent(); - F1 = sccLeader(&*F1); - Set.insert(scc_begin(F1), scc_end(F1)); -} diff --git a/lib/DSA/DSGraph.cpp b/lib/DSA/DSGraph.cpp deleted file mode 100644 index f1d34fd25..000000000 --- a/lib/DSA/DSGraph.cpp +++ /dev/null @@ -1,1687 +0,0 @@ -//===- DataStructure.cpp - Implement the core data structure analysis -----===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the core data structure functionality. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "DSGraph" -#include "dsa/DSGraphTraits.h" -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" -#include "dsa/DSSupport.h" -#include "dsa/DSNode.h" -#include "dsa/stl_util.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/Support/CommandLine.h" -#include "smack/Debug.h" -#include "llvm/ADT/DepthFirstIterator.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SCCIterator.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/Timer.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/IR/Type.h" -#include "llvm/IR/GlobalAlias.h" - -#include -#include -using namespace llvm; - -#define COLLAPSE_ARRAYS_AGGRESSIVELY 0 -namespace { - STATISTIC (NumCallNodesMerged , "Number of call nodes merged"); - STATISTIC (NumDNE , "Number of nodes removed by reachability"); - STATISTIC (NumTrivialDNE , "Number of nodes trivially removed"); - STATISTIC (NumTrivialGlobalDNE , "Number of globals trivially removed"); - STATISTIC (NumFiltered , "Number of calls filtered"); - - static cl::opt noDSACallConv("dsa-no-filter-callcc", - cl::desc("Don't filter call sites based on calling convention."), - cl::Hidden, - cl::init(false)); - static cl::opt noDSACallNumArgs("dsa-no-filter-numargs", - cl::desc("Don't filter call sites based on number of arguments."), - cl::Hidden, - cl::init(false)); - static cl::opt noDSACallVA("dsa-no-filter-vararg", - cl::desc("Don't filter call sites based on vararg presense"), - cl::Hidden, - cl::init(true)); - static cl::opt noDSACallFP("dsa-no-filter-intfp", - cl::desc("Don't filter call sites based on implicit integer to FP conversion"), - cl::Hidden, - cl::init(false)); -} - -extern cl::opt TypeInferenceOptimize; - -// Determines if the DSGraph 'should' have a node for a given value. -static bool shouldHaveNodeForValue(const Value *V) { - // Peer through casts - V = V->stripPointerCasts(); - - // Only pointers get nodes - if (!isa(V->getType())) return false; - - // Undef values, even ones of pointer type, don't get nodes. - if (isa(V)) return false; - - if (isa(V)) - return false; - - // Use the Aliasee of GlobalAliases - // FIXME: This check might not be required, it's here because - // something similar is done in the Local pass. - if (const GlobalAlias *GA = dyn_cast(V)) - return shouldHaveNodeForValue(GA->getAliasee()); - - return true; -} - -/// getFunctionNames - Return a space separated list of the name of the -/// functions in this graph (if any) -std::string DSGraph::getFunctionNames() const { - switch (getReturnNodes().size()) { - case 0: return "Globals graph"; - case 1: return retnodes_begin()->first->getName(); - default: - std::string Return; - for (DSGraph::retnodes_iterator I = retnodes_begin(); - I != retnodes_end(); ++I) - Return += I->first->getName().str() + " "; - Return.erase(Return.end()-1, Return.end()); // Remove last space character - return Return; - } -} - - -DSGraph::DSGraph(DSGraph* G, EquivalenceClasses &ECs, - SuperSet& tss, - unsigned CloneFlags) - : GlobalsGraph(0), ScalarMap(ECs), TD(G->TD), TypeSS(tss) { - UseAuxCalls = false; - cloneInto(G, CloneFlags); -} - -DSGraph::~DSGraph() { - FunctionCalls.clear(); - AuxFunctionCalls.clear(); - ScalarMap.clear(); - ReturnNodes.clear(); - VANodes.clear(); - - // Drop all intra-node references, so that assertions don't fail... - for (node_iterator NI = node_begin(), E = node_end(); NI != E; ++NI) - NI->dropAllReferences(); - - // Free all of the nodes. - Nodes.clear(); -} - -// dump - Allow inspection of graph in a debugger. -void DSGraph::dump() const { print(errs()); } - -void DSGraph::removeFunctionCalls(Function& F) { - FunctionListTy::iterator Erase = FunctionCalls.end(); - for (FunctionListTy::iterator I = FunctionCalls.begin(); - I != Erase; ) { - if (I->isDirectCall() && I->getCalleeFunc() == &F) - std::swap(*I, *--Erase); - else - ++I; - } - FunctionCalls.erase(Erase, FunctionCalls.end()); - - Erase = AuxFunctionCalls.end(); - for (FunctionListTy::iterator I = AuxFunctionCalls.begin(); - I != Erase; ) { - if (I->isDirectCall() && I->getCalleeFunc() == &F) - std::swap(*I, *--Erase); - else - ++I; - } - AuxFunctionCalls.erase(Erase, AuxFunctionCalls.end()); -} - -/// addObjectToGraph - This method can be used to add global, stack, and heap -/// objects to the graph. This can be used when updating DSGraphs due to the -/// introduction of new temporary objects. The new object is not pointed to -/// and does not point to any other objects in the graph. -DSNode *DSGraph::addObjectToGraph(Value *Ptr, bool UseDeclaredType) { - assert(isa(Ptr->getType()) && "Ptr is not a pointer!"); - DSNode *N = new DSNode(this); - assert(ScalarMap[Ptr].isNull() && "Object already in this graph!"); - ScalarMap[Ptr] = N; - - if (GlobalValue *GV = dyn_cast(Ptr)) { - N->addGlobal(GV); -// } else if (isa(Ptr)) { -// N->setHeapMarker(); - } else if (isa(Ptr)) { - N->setAllocaMarker(); - } else { - llvm_unreachable("Illegal memory object input!"); - } - return N; -} - - -/// cloneInto - Clone the specified DSGraph into the current graph. The -/// translated ScalarMap for the old function is filled into the ScalarMap -/// for the graph, the translated ReturnNodes map is returned into -/// ReturnNodes, and the translated VANodes map is return into VANodes. -/// -/// The CloneFlags member controls various aspects of the cloning process. -/// -void DSGraph::cloneInto( DSGraph* G, unsigned CloneFlags) { - assert(G != this && "Cannot clone graph into itself!"); - - NodeMapTy OldNodeMap; - - // Remove alloca or mod/ref bits as specified... - unsigned BitsToClear = ((CloneFlags & StripAllocaBit)? DSNode::AllocaNode : 0) - | ((CloneFlags & StripModRefBits)? (DSNode::ModifiedNode | DSNode::ReadNode) : 0) - | ((CloneFlags & StripIncompleteBit)? DSNode::IncompleteNode : 0); - BitsToClear |= DSNode::DeadNode; // Clear dead flag... - - for (node_const_iterator I = G->node_begin(), E = G->node_end(); I != E; ++I) { - assert(!I->isForwarding() && - "Forward nodes shouldn't be in node list!"); - DSNode *New = new DSNode(*I, this); - New->maskNodeTypes(~BitsToClear); - OldNodeMap[&*I] = New; - } - - // Rewrite the links in the new nodes to point into the current graph now. - // Note that we don't loop over the node's list to do this. The problem is - // that remaping links can cause recursive merging to happen, which means - // that node_iterator's can get easily invalidated! Because of this, we - // loop over the OldNodeMap, which contains all of the new nodes as the - // .second element of the map elements. Also note that if we remap a node - // more than once, we won't break anything. - for (NodeMapTy::iterator I = OldNodeMap.begin(), E = OldNodeMap.end(); - I != E; ++I) - I->second.getNode()->remapLinks(OldNodeMap); - - // Copy the scalar map... merging all of the global nodes... - for (DSScalarMap::const_iterator I = G->ScalarMap.begin(), - E = G->ScalarMap.end(); I != E; ++I) { - DSNodeHandle &MappedNode = OldNodeMap[I->second.getNode()]; - DSNodeHandle &H = ScalarMap.getRawEntryRef(I->first); - DSNode *MappedNodeN = MappedNode.getNode(); - H.mergeWith(DSNodeHandle(MappedNodeN, - I->second.getOffset()+MappedNode.getOffset())); - } - - if (!(CloneFlags & DontCloneCallNodes)) { - // Copy the function calls list. - for (fc_iterator I = G->fc_begin(), E = G->fc_end(); I != E; ++I) - FunctionCalls.push_back(DSCallSite(*I, OldNodeMap)); - } - - if (!(CloneFlags & DontCloneAuxCallNodes)) { - // Copy the auxiliary function calls list. - for (afc_iterator I = G->afc_begin(), E = G->afc_end(); I != E; ++I) - AuxFunctionCalls.push_back(DSCallSite(*I, OldNodeMap)); - } - - // Map the return node pointers over... - for (retnodes_iterator I = G->retnodes_begin(), - E = G->retnodes_end(); I != E; ++I) { - const DSNodeHandle &Ret = I->second; - DSNodeHandle &MappedRet = OldNodeMap[Ret.getNode()]; - DSNode *MappedRetN = MappedRet.getNode(); - ReturnNodes.insert(std::make_pair(I->first, - DSNodeHandle(MappedRetN, - MappedRet.getOffset()+Ret.getOffset()))); - } - - // Map the VA node pointers over... - for (vanodes_iterator I = G->vanodes_begin(), - E = G->vanodes_end(); I != E; ++I) { - const DSNodeHandle &VarArg = I->second; - DSNodeHandle &MappedVarArg = OldNodeMap[VarArg.getNode()]; - DSNode *MappedVarArgN = MappedVarArg.getNode(); - VANodes.insert(std::make_pair(I->first, - DSNodeHandle(MappedVarArgN, - MappedVarArg.getOffset()+VarArg.getOffset()))); - } -} - -/// spliceFrom - Logically perform the operation of cloning the RHS graph into -/// this graph, then clearing the RHS graph. Instead of performing this as -/// two seperate operations, do it as a single, much faster, one. -/// -void DSGraph::spliceFrom(DSGraph* RHS) { - assert(this != RHS && "Splicing self"); - // Change all of the nodes in RHS to think we are their parent. - for (NodeListTy::iterator I = RHS->Nodes.begin(), E = RHS->Nodes.end(); - I != E; ++I) - I->setParentGraph(this); - // Take all of the nodes. - splice(Nodes, RHS->Nodes); - - // Take all of the calls. - splice(FunctionCalls, RHS->FunctionCalls); - splice(AuxFunctionCalls, RHS->AuxFunctionCalls); - - // Take all of the return nodes. - splice(ReturnNodes, RHS->ReturnNodes); - - // Same for the VA nodes - splice(VANodes, RHS->VANodes); - - // Merge the scalar map in. - ScalarMap.spliceFrom(RHS->ScalarMap); -} - -/// getFunctionArgumentsForCall - Given a function that is currently in this -/// graph, return the DSNodeHandles that correspond to the pointer-compatible -/// function arguments. The vector is filled in with the return value (or -/// null if it is not pointer compatible), a vararg node (null if not -/// applicable) followed by all of the pointer-compatible arguments. -void DSGraph::getFunctionArgumentsForCall(const Function *F, - std::vector &Args) const { - Args.push_back(getReturnNodeFor(*F)); - Args.push_back(getVANodeFor(*F)); - for (const auto &Arg : F->args()) - if (isa(Arg.getType())) { - Args.push_back(getNodeForValue(&Arg)); - assert(!Args.back().isNull() && "Pointer argument w/o scalarmap entry!?"); - } -} - -namespace { - // HackedGraphSCCFinder - This is used to find nodes that have a path from the - // node to a node cloned by the ReachabilityCloner object contained. To be - // extra obnoxious it ignores edges from nodes that are globals, and truncates - // search at RC marked nodes. This is designed as an object so that - // intermediate results can be memoized across invocations of - // PathExistsToClonedNode. - struct HackedGraphSCCFinder { - ReachabilityCloner &RC; - unsigned CurNodeId; - std::vector SCCStack; - std::map > NodeInfo; - - HackedGraphSCCFinder(ReachabilityCloner &rc) : RC(rc), CurNodeId(1) { - // Remove null pointer as a special case. - NodeInfo[0] = std::make_pair(0, false); - } - - std::pair &VisitForSCCs(const DSNode *N); - - bool PathExistsToClonedNode(const DSNode *N) { - return VisitForSCCs(N).second; - } - - bool PathExistsToClonedNode(const DSCallSite &CS) { - if (PathExistsToClonedNode(CS.getRetVal().getNode())) - return true; - if (CS.isIndirectCall() && PathExistsToClonedNode(CS.getCalleeNode())) - return true; - for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i) - if (PathExistsToClonedNode(CS.getPtrArg(i).getNode())) - return true; - if (PathExistsToClonedNode(CS.getVAVal().getNode())) - return true; - return false; - } - }; -} - -std::pair &HackedGraphSCCFinder:: -VisitForSCCs(const DSNode *N) { - std::map >::iterator - NodeInfoIt = NodeInfo.lower_bound(N); - if (NodeInfoIt != NodeInfo.end() && NodeInfoIt->first == N) - return NodeInfoIt->second; - - unsigned Min = CurNodeId++; - unsigned MyId = Min; - std::pair &ThisNodeInfo = - NodeInfo.insert(NodeInfoIt, - std::make_pair(N, std::make_pair(MyId, false)))->second; - - - // Base case: if this does reach the cloned graph portion... it does. :) - if (RC.hasClonedNode(N)) { - ThisNodeInfo.second = true; - return ThisNodeInfo; - } - // Base case: if we find a global, this doesn't reach the cloned graph - // portion. - if (N->isGlobalNode()) { - ThisNodeInfo.second = false; - return ThisNodeInfo; - } - - SCCStack.push_back(N); - - // Otherwise, check all successors. - bool AnyDirectSuccessorsReachClonedNodes = false; - for (DSNode::const_edge_iterator EI = N->edge_begin(), EE = N->edge_end(); - EI != EE; ++EI) - if (DSNode * Succ = EI->second.getNode()) { - std::pair &SuccInfo = VisitForSCCs(Succ); - if (SuccInfo.first < Min) Min = SuccInfo.first; - AnyDirectSuccessorsReachClonedNodes |= SuccInfo.second; - } - - if (Min != MyId) - return ThisNodeInfo; // Part of a large SCC. Leave self on stack. - - if (SCCStack.back() == N) { // Special case single node SCC. - SCCStack.pop_back(); - ThisNodeInfo.second = AnyDirectSuccessorsReachClonedNodes; - return ThisNodeInfo; - } - - // Find out if any direct successors of any node reach cloned nodes. - if (!AnyDirectSuccessorsReachClonedNodes) - for (unsigned i = SCCStack.size() - 1; SCCStack[i] != N; --i) - for (DSNode::const_edge_iterator EI = N->edge_begin(), EE = N->edge_end(); - EI != EE; ++EI) - if (DSNode * N = EI->second.getNode()) - if (NodeInfo[N].second) { - AnyDirectSuccessorsReachClonedNodes = true; - goto OutOfLoop; - } -OutOfLoop: - // If any successor reaches a cloned node, mark all nodes in this SCC as - // reaching the cloned node. - if (AnyDirectSuccessorsReachClonedNodes) - while (SCCStack.back() != N) { - NodeInfo[SCCStack.back()].second = true; - SCCStack.pop_back(); - } - SCCStack.pop_back(); - ThisNodeInfo.second = AnyDirectSuccessorsReachClonedNodes; - return ThisNodeInfo; -} - -/// mergeInCallFromOtherGraph - This graph merges in the minimal number of -/// nodes from G2 into 'this' graph, merging the bindings specified by the -/// call site (in this graph) with the bindings specified by the vector in G2. -/// The two DSGraphs must be different. -/// -void DSGraph::mergeInGraph(const DSCallSite &CS, - std::vector &Args, - const DSGraph &Graph, unsigned CloneFlags) { - assert((CloneFlags & DontCloneCallNodes) && - "Doesn't support copying of call nodes!"); - - // If this is not a recursive call, clone the graph into this graph... - if (&Graph == this) { - // Merge the return value with the return value of the context. - Args[0].mergeWith(CS.getRetVal()); - - // Merge var-arg node - Args[1].mergeWith(CS.getVAVal()); - - // Resolve all of the function arguments. - for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i) { - if (i == Args.size()-2) - break; - - // Add the link from the argument scalar to the provided value. - Args[i+2].mergeWith(CS.getPtrArg(i)); - } - return; - } - - // Clone the callee's graph into the current graph, keeping track of where - // scalars in the old graph _used_ to point, and of the new nodes matching - // nodes of the old graph. - ReachabilityCloner RC(this, &Graph, CloneFlags); - - // Map the return node pointer over. - if (!CS.getRetVal().isNull()) - RC.merge(CS.getRetVal(), Args[0]); - - // Map the variable arguments - if (!CS.getVAVal().isNull()) - RC.merge(CS.getVAVal(), Args[1]); - - // Map over all of the arguments. - for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i) { - if (i == Args.size()-2) - break; - - // Add the link from the argument scalar to the provided value. - RC.merge(CS.getPtrArg(i), Args[i+2]); - } - - // We generally don't want to copy global nodes or aux calls from the callee - // graph to the caller graph. However, we have to copy them if there is a - // path from the node to a node we have already copied which does not go - // through another global. Compute the set of node that can reach globals and - // aux call nodes to copy over, then do it. - std::vector AuxCallToCopy; - std::vector GlobalsToCopy; - - // NodesReachCopiedNodes - Memoize results for efficiency. Contains a - // true/false value for every visited node that reaches a copied node without - // going through a global. - HackedGraphSCCFinder SCCFinder(RC); - - if (!(CloneFlags & DontCloneAuxCallNodes)) - for (afc_const_iterator I = Graph.afc_begin(), E = Graph.afc_end(); I!=E; ++I) - if (!I->isUnresolvable() && SCCFinder.PathExistsToClonedNode(*I)) - AuxCallToCopy.push_back(&*I); - - // Copy aux calls that are needed. - // Copy these before calculating the globals to be copied, as there might be - // globals that reach the nodes cloned due to aux calls. - for (unsigned i = 0, e = AuxCallToCopy.size(); i != e; ++i) - AuxFunctionCalls.push_back(DSCallSite(*AuxCallToCopy[i], RC)); - - const DSScalarMap &GSM = Graph.getScalarMap(); - for (DSScalarMap::global_iterator GI = GSM.global_begin(), - E = GSM.global_end(); GI != E; ++GI) { - DSNode *GlobalNode = Graph.getNodeForValue(*GI).getNode(); - for (DSNode::edge_iterator EI = GlobalNode->edge_begin(), - EE = GlobalNode->edge_end(); EI != EE; ++EI) - if (SCCFinder.PathExistsToClonedNode(EI->second.getNode())) { - GlobalsToCopy.push_back(*GI); - break; - } - } - - // Copy globals that are needed. - for (unsigned i = 0, e = GlobalsToCopy.size(); i != e; ++i) - RC.getClonedNH(Graph.getNodeForValue(GlobalsToCopy[i])); -} - - - -/// mergeInGraph - The method is used for merging graphs together. If the -/// argument graph is not *this, it makes a clone of the specified graph, then -/// merges the nodes specified in the call site with the formal arguments in the -/// graph. -/// -void DSGraph::mergeInGraph(const DSCallSite &CS, const Function &F, - const DSGraph &Graph, unsigned CloneFlags) { - // Set up argument bindings. - std::vector Args; - Graph.getFunctionArgumentsForCall(&F, Args); - - mergeInGraph(CS, Args, Graph, CloneFlags); -} - -/// getCallSiteForArguments - Get the arguments and return value bindings for -/// the specified function in the current graph. -/// -DSCallSite DSGraph::getCallSiteForArguments(const Function &F) const { - std::vector Args; - - for (const auto &Arg : F.args()) - if (isa(Arg.getType())) - Args.push_back(getNodeForValue(&Arg)); - - return DSCallSite(CallSite(), getReturnNodeFor(F), getVANodeFor(F), &F, Args); -} - -/// getDSCallSiteForCallSite - Given an LLVM CallSite object that is live in -/// the context of this graph, return the DSCallSite for it. -DSCallSite DSGraph::getDSCallSiteForCallSite(CallSite CS) const { - DSNodeHandle RetVal, VarArg; - Instruction *I = CS.getInstruction(); - if (shouldHaveNodeForValue(I)) - RetVal = getNodeForValue(I); - - //FIXME: Here we trust the signature of the callsite to determine which arguments - //are var-arg and which are fixed. Apparently we can't assume this, but I'm not sure - //of a better way. For now, this assumption is known limitation. - const FunctionType *CalleeFuncType = DSCallSite::FunctionTypeOfCallSite(CS); - int NumFixedArgs = CalleeFuncType->getNumParams(); - - // Sanity check--this really, really shouldn't happen - if (!CalleeFuncType->isVarArg()) - assert(CS.arg_size() == static_cast(NumFixedArgs) && - "Too many arguments/incorrect function signature!"); - - std::vector Args; - Args.reserve(CS.arg_end()-CS.arg_begin()); - - // Calculate the arguments vector... - for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); I != E; ++I) - if (isa((*I)->getType())) { - DSNodeHandle ArgNode; // Initially empty - if (shouldHaveNodeForValue(*I)) ArgNode = getNodeForValue(*I); - if (I - CS.arg_begin() < NumFixedArgs) { - Args.push_back(ArgNode); - } else { - VarArg.mergeWith(ArgNode); - } - } - - // - // Add a new function call entry. We get the called value from the call site - // and strip pointer casts instead of asking the CallSite class to do that - // since CallSite::getCalledFunction() returns 0 if the called value is - // a bit-casted function constant. - // - if (Function *F=dyn_cast(CS.getCalledValue()->stripPointerCasts())) - return DSCallSite(CS, RetVal, VarArg, F, Args); - else - return DSCallSite(CS, RetVal, VarArg, - getNodeForValue(CS.getCalledValue()).getNode(), Args); -} - - - -// markIncompleteNodes - Mark the specified node as having contents that are not -// known with the current analysis we have performed. Because a node makes all -// of the nodes it can reach incomplete if the node itself is incomplete, we -// must recursively traverse the data structure graph, marking all reachable -// nodes as incomplete. -// -static void markIncompleteNode(DSNode *N) { - // Stop recursion if no node, or if node already marked... - if (N == 0 || N->isIncompleteNode()) return; - - // Actually mark the node - N->setIncompleteMarker(); - - // Recursively process children... - for (DSNode::edge_iterator ii = N->edge_begin(), ee = N->edge_end(); - ii != ee; ++ii) - markIncompleteNode(ii->second.getNode()); -} - -static void markIncomplete(DSCallSite &Call) { - // Then the return value is certainly incomplete! - markIncompleteNode(Call.getRetVal().getNode()); - - markIncompleteNode(Call.getVAVal().getNode()); - - // All objects pointed to by function arguments are incomplete! - for (unsigned i = 0, e = Call.getNumPtrArgs(); i != e; ++i) - markIncompleteNode(Call.getPtrArg(i).getNode()); -} - -// markIncompleteNodes - Traverse the graph, identifying nodes that may be -// modified by other functions that have not been resolved yet. This marks -// nodes that are reachable through three sources of "unknownness": -// -// Global Variables, Function Calls, and Incoming Arguments -// -// For any node that may have unknown components (because something outside the -// scope of current analysis may have modified it), the 'Incomplete' flag is -// added to the NodeType. -// -void DSGraph::markIncompleteNodes(unsigned Flags) { - // Mark any incoming arguments as incomplete. - if (Flags & DSGraph::MarkFormalArgs) { - for (ReturnNodesTy::iterator FI = ReturnNodes.begin(), E =ReturnNodes.end(); - FI != E; ++FI) { - const Function &F = *FI->first; - for (const auto &Arg : F.args()) - if (isa(Arg.getType())) - markIncompleteNode(getNodeForValue(&Arg).getNode()); - markIncompleteNode(FI->second.getNode()); - } - // Mark all vanodes as incomplete (they are also arguments) - for (vanodes_iterator I = vanodes_begin(), E = vanodes_end(); - I != E; ++I) - markIncompleteNode(I->second.getNode()); - } - - // Mark stuff passed into functions calls as being incomplete. - if (!shouldUseAuxCalls()) - for (FunctionListTy::iterator I = FunctionCalls.begin(), - E = FunctionCalls.end(); I != E; ++I) - markIncomplete(*I); - else - for (FunctionListTy::iterator I = AuxFunctionCalls.begin(), - E = AuxFunctionCalls.end(); I != E; ++I) - markIncomplete(*I); - - // Mark all global nodes as incomplete that aren't initialized and constant. - if ((Flags & DSGraph::IgnoreGlobals) == 0) - for (DSScalarMap::global_iterator I = ScalarMap.global_begin(), - E = ScalarMap.global_end(); I != E; ++I) - if (const GlobalVariable *GV = dyn_cast(*I)) { - if (!(GV->hasInitializer() && GV->isConstant())){ - markIncompleteNode(ScalarMap[GV].getNode()); - } - } - - // Mark any node with the VAStart flag as incomplete. - if (Flags & DSGraph::MarkVAStart) { - for (node_iterator i=node_begin(); i != node_end(); ++i) { - if (i->isVAStartNode()) - markIncompleteNode(&*i); - } - } -} - -// -// Function: markExternalNode() -// -// Description: -// Marks the specified node, and all that's reachable from it, as external. -// It uses 'processedNodes' to track recursion. -// -static void markExternalNode(DSNode *N, DenseSet & processedNodes) { - // Stop recursion if no node, or if node already processed - if (N == 0 || processedNodes.count(N) ) return; - - processedNodes.insert(N); - - // Actually mark the node - N->setExternalMarker(); - - // FIXME: Should we 'collapse' the node as well? - - // Recursively process children... - for (DSNode::edge_iterator ii = N->edge_begin(), ee = N->edge_end(); - ii != ee; ++ii) - markExternalNode(ii->second.getNode(), processedNodes); -} - -// markExternal --marks the specified callsite external, using 'processedNodes' to track recursion. -static void markExternal(const DSCallSite &Call, DenseSet & processedNodes) { - markExternalNode(Call.getRetVal().getNode(), processedNodes); - - markExternalNode(Call.getVAVal().getNode(), processedNodes); - - // Mark all pointer arguments... - for (unsigned i = 0, e = Call.getNumPtrArgs(); i != e; ++i) - markExternalNode(Call.getPtrArg(i).getNode(), processedNodes); -} - -// -// Method: propagateExternal() -// -// Description: -// Walk the given DSGraph and ensure that, within this graph, -// everything reachable from a node marked External is also marked External. -// -static void propagateExternal(DSGraph * G, DenseSet & processedNodes) { - DSGraph::node_iterator I = G->node_begin(), - E = G->node_end(); - for ( ; I != E; ++I ) { - if (I->isExternalNode()) - markExternalNode(&*I, processedNodes); - } -} - -// -// Method: computeIntPtrFlags() -// -// Description: -// Mark all nodes that must get P2 flags due to type overlap. -// -void DSGraph::computeIntPtrFlags() { - DSGraph::node_iterator I = node_begin(), - E = node_end(); - for ( ; I != E; ++I ) { - I->markIntPtrFlags(); - } -} - -// computeExternalFlags -- mark all reachable from external as external -void DSGraph::computeExternalFlags(unsigned Flags) { - - DenseSet processedNodes; - - // Reset if indicated - if (Flags & ResetExternal) { - maskNodeTypes(~DSNode::ExternalNode); - } - - // Make sure that everything reachable from something already external is - // also external - propagateExternal(this, processedNodes); - - // If requested, we mark all functions (their formals) in this - // graph (read: SCC) as external. - if (Flags & MarkFormalsExternal) { - for (ReturnNodesTy::iterator FI = ReturnNodes.begin(), E =ReturnNodes.end(); - FI != E; ++FI) { - const Function &F = *FI->first; - // Mark its arguments, return value (and vanode) as external. - for (const auto &Arg : F.args()) { - if(TypeInferenceOptimize) { - if(Arg.getName().str() == "argv") - continue; - } - if (isa(Arg.getType())) - markExternalNode(getNodeForValue(&Arg).getNode(), processedNodes); - } - markExternalNode(FI->second.getNode(), processedNodes); - markExternalNode(getVANodeFor(F).getNode(), processedNodes); - } - } - - // If requested, look for callsites to external functions and make - // sure that they're marked external as appropriate. - if (Flags & ProcessCallSites) { - // Get List of all callsites, resolved or not... - std::list AllCalls; - AllCalls.insert(AllCalls.begin(), fc_begin(), fc_end()); - AllCalls.insert(AllCalls.begin(), afc_begin(), afc_end()); - - // ...and use that list to find all CallSites that call external functions - // and mark them accordingly. - for (std::list::iterator I = AllCalls.begin(), - E = AllCalls.end(); I != E; ++I) { - bool shouldBeMarkedExternal = false; - - // Figure out what this callsite calls... - std::vector Functions; - if (I->isDirectCall()) - Functions.push_back(I->getCalleeFunc()); - else - I->getCalleeNode()->addFullFunctionList(Functions); - - // ...And examine each callee: - for (std::vector::iterator II = Functions.begin(), - EE = Functions.end(); - (II != EE) && !shouldBeMarkedExternal; ++II) { - - // Calls to external functions should be marked external - shouldBeMarkedExternal |= (*II)->isDeclaration(); - } - - // If this callsite can call external code, it better be the case that - // the pointer arguments and the return values are all marked external - // (and what's reachable from them) - if (shouldBeMarkedExternal) { - markExternal(*I, processedNodes); - } - } - } - - // Finally handle all external globals... - for (DSScalarMap::global_iterator I = ScalarMap.global_begin(), - E = ScalarMap.global_end(); I != E; ++I) { - if (const GlobalVariable *GV = dyn_cast(*I)) { - if(TypeInferenceOptimize) { - if(GV->getName().str() == "stderr"){ - continue; - } - if(GV->getName().str() == "stdout"){ - continue; - } - if(GV->getName().str() == "stdin"){ - continue; - } - } - // If the global is external... mark it as such! - DSNode * N = ScalarMap[GV].getNode(); - if (!(GV->hasInternalLinkage() || GV->hasPrivateLinkage()) || N->isExternalNode()) - markExternalNode(N, processedNodes); - } - } - -} - -static inline void killIfUselessEdge(DSNodeHandle &Edge) { - if (DSNode * N = Edge.getNode()) // Is there an edge? - if (N->getNumReferrers() == 1) // Does it point to a lonely node? - // No interesting info? - if ((N->getNodeFlags() & ~DSNode::IncompleteNode) == 0 - && N->hasNoType() - && !N->isNodeCompletelyFolded()) - Edge.setTo(0, 0); // Kill the edge! -} - -static void removeIdenticalCalls(DSGraph::FunctionListTy &Calls) { - // Remove trivially identical function calls - - unsigned NumDeleted = 0; - - // First, scan through killing off useless edges and trivially dead callsites - for (DSGraph::FunctionListTy::iterator I = Calls.begin(), E = Calls.end(); - I != E; ) { - DSCallSite &CS = *I; - - // If the return value or any arguments point to a void node with no - // information at all in it, and the call node is the only node to point - // to it, remove the edge to the node (killing the node). - // - killIfUselessEdge(CS.getRetVal()); - killIfUselessEdge(CS.getVAVal()); - for (unsigned a = 0, e = CS.getNumPtrArgs(); a != e; ++a) - killIfUselessEdge(CS.getPtrArg(a)); - - // If this is an indirect callsite, but the Callee DSNode isn't - // tied to from anything, remove it trivially. - if (CS.isIndirectCall()) { - DSNode *Callee = CS.getCalleeNode(); - if (Callee->getNumReferrers() == 1 && Callee->isCompleteNode() && - Callee->isEmptyGlobals()) { // No useful info? - SDEBUG(errs() << "WARNING: Useless call site found.\n"); - I = Calls.erase(I); - E = Calls.end(); - ++NumDeleted; - continue; - } - } - ++I; - } - - // Now scan for redundant indirect callsites - // First, sort by callee (using DSCallSite::operator<) - sort(Calls); - - // Then find adjacent callsites that are equivalent and handle accordingly - DSGraph::FunctionListTy::iterator I = Calls.begin(); - while((I = std::adjacent_find(I, Calls.end())) != Calls.end()) { - DSGraph::FunctionListTy::iterator Second = I; - DSCallSite &DCS1 = *I, &DCS2 = *++Second; - - if (DCS1.isIndirectCall()) { - // Merge them together (into the first one) - DCS1.mergeWith(DCS2); - } - - // Remove the second one - ++NumDeleted; - Calls.erase(Second); - - // Carry on, searching from 'I' (first one)... - } - - // Track the number of call nodes merged away... - NumCallNodesMerged += NumDeleted; - - if (NumDeleted) - SDEBUG(errs() << "Merged " << NumDeleted << " call nodes.\n"); -} -// removeTriviallyDeadNodes - After the graph has been constructed, this method -// removes all unreachable nodes that are created because they got merged with -// other nodes in the graph. These nodes will all be trivially unreachable, so -// we don't have to perform any non-trivial analysis here. -// -void DSGraph::removeTriviallyDeadNodes() { - /// NOTE: This code is disabled. This slows down DSA on 177.mesa - /// substantially! - - // Loop over all of the nodes in the graph, calling getNode on each field. - // This will cause all nodes to update their forwarding edges, causing - // forwarded nodes to be delete-able. Further, reclaim any memory used by - // useless edge or type entries - for (node_iterator NI = node_begin(), E = node_end(); NI != E; ++NI) - for (DSNode::edge_iterator ii = NI->edge_begin(), ee = NI->edge_end(); - ii != ee; ++ii) { - ii->second.getNode()->cleanEdges(); - } - - // Likewise, forward any edges from the scalar nodes. While we are at it, - // clean house a bit. - for (DSScalarMap::iterator I = ScalarMap.begin(), E = ScalarMap.end(); - I != E; ++I) - I->second.getNode(); - - bool isGlobalsGraph = !GlobalsGraph; - - for (NodeListTy::iterator NI = Nodes.begin(), E = Nodes.end(); NI != E; ) { - DSNode &Node = *NI; - - // Do not remove *any* global nodes in the globals graph. - // This is a special case because such nodes may not have I, M, R flags set. - if (Node.isGlobalNode() && isGlobalsGraph) { - ++NI; - continue; - } - - if (Node.isCompleteNode() && !Node.isModifiedNode() && !Node.isReadNode()) { - // This is a useless node if it has no mod/ref info (checked above), - // outgoing edges (which it cannot, as it is not modified in this - // context), and it has no incoming edges. If it is a global node it may - // have all of these properties and still have incoming edges, due to the - // scalar map, so we check those now. - // - if (Node.getNumReferrers() == Node.numGlobals()) { - - // Loop through and make sure all of the globals are referring directly - // to the node... - for (DSNode::globals_iterator j = Node.globals_begin(), e = Node.globals_end(); - j != e; ++j) { - getNodeForValue(*j).getNode(); - assert((getNodeForValue(*j).getNode()) == &Node && "ScalarMap doesn't match globals list!"); - } - - // Make sure NumReferrers still agrees, if so, the node is truly dead. - if (Node.getNumReferrers() == Node.numGlobals()) { - for (DSNode::globals_iterator j = Node.globals_begin(), e = Node.globals_end(); - j != e; ++j) - if (ScalarMap.find(*j) != ScalarMap.end()) - ScalarMap.erase(*j); - Node.makeNodeDead(); - ++NumTrivialGlobalDNE; - } - } - } - - if ((Node.getNodeFlags() == 0 && Node.hasNoReferrers()) - || (isGlobalsGraph && Node.hasNoReferrers() && !Node.isGlobalNode())){ - // This node is dead! - NI = Nodes.erase(NI); // Erase & remove from node list. - ++NumTrivialDNE; - } else { - ++NI; - } - } -#if 0 -#endif - removeIdenticalCalls(FunctionCalls); - removeIdenticalCalls(AuxFunctionCalls); -} - -// CanReachAliveNodes - Simple graph walker that recursively traverses the graph -// looking for a node that is marked alive. If an alive node is found, return -// true, otherwise return false. If an alive node is reachable, this node is -// marked as alive... -// -static bool CanReachAliveNodes(DSNode *N, DenseSet &Alive, - DenseSet &Visited, - bool IgnoreGlobals) { - if (N == 0) return false; - assert(N->isForwarding() == 0 && "Cannot mark a forwarded node!"); - - // If this is a global node, it will end up in the globals graph anyway, so we - // don't need to worry about it. - if (IgnoreGlobals && N->isGlobalNode()) return false; - - // If we know that this node is alive, return so! - if (Alive.count(N)) return true; - - // Otherwise, we don't think the node is alive yet, check for infinite - // recursion. - if (Visited.count(N)) return false; // Found a cycle - Visited.insert(N); // No recursion, insert into Visited... - - for (DSNode::edge_iterator I = N->edge_begin(),E = N->edge_end(); I != E; ++I) - if (CanReachAliveNodes(I->second.getNode(), Alive, Visited, IgnoreGlobals)) { - N->markReachableNodes(Alive); - return true; - } - return false; -} - -// CallSiteUsesAliveArgs - Return true if the specified call site can reach any -// alive nodes. -// -static bool CallSiteUsesAliveArgs(const DSCallSite &CS, - DenseSet &Alive, - DenseSet &Visited, - bool IgnoreGlobals) { - if (CanReachAliveNodes(CS.getRetVal().getNode(), Alive, Visited, - IgnoreGlobals)) - return true; - if (CanReachAliveNodes(CS.getVAVal().getNode(), Alive, Visited, IgnoreGlobals)) - return true; - if (CS.isIndirectCall() && - CanReachAliveNodes(CS.getCalleeNode(), Alive, Visited, IgnoreGlobals)) - return true; - for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i) - if (CanReachAliveNodes(CS.getPtrArg(i).getNode(), Alive, Visited, - IgnoreGlobals)) - return true; - return false; -} - -// removeDeadNodes - Use a more powerful reachability analysis to eliminate -// subgraphs that are unreachable. This often occurs because the data -// structure doesn't "escape" into it's caller, and thus should be eliminated -// from the caller's graph entirely. This is only appropriate to use when -// inlining graphs. -// -// This function also clones information about globals back into the globals -// graph before it deletes the nodes. -void DSGraph::removeDeadNodes(unsigned Flags) { - SDEBUG(AssertGraphOK(); if (GlobalsGraph) GlobalsGraph->AssertGraphOK()); - - // Reduce the amount of work we have to do... remove dummy nodes left over by - // merging... - removeTriviallyDeadNodes(); - - // FIXME: Merge non-trivially identical call nodes... - - // Alive - a set that holds all nodes found to be reachable/alive. - DenseSet Alive; - std::vector > GlobalNodes; - - // Copy and merge all information about globals to the GlobalsGraph if this is - // not a final pass (where unreachable globals are removed). - // - // Strip all alloca bits since we are merging information into the globals - // graph. - // Strip all incomplete bits since they are short-lived properties and they - // will be correctly computed when rematerializing nodes into the functions. - // - // This code merges information learned about the globals in 'this' graph - // back into the globals graph, before it deletes any such global nodes, - // (with some new information possibly) from 'this' current function graph. - ReachabilityCloner GGCloner(GlobalsGraph, this, DSGraph::StripAllocaBit | - DSGraph::StripIncompleteBit); - - // Mark all nodes reachable by (non-global) scalar nodes as alive... - for (DSScalarMap::iterator I = ScalarMap.begin(), E = ScalarMap.end(); - I != E; ++I) - if (isa (I->first)) { // Keep track of global nodes - assert(!I->second.isNull() && "Null global node?"); - assert(I->second.getNode()->isGlobalNode() && "Should be a global node!"); - GlobalNodes.push_back(std::make_pair(I->first, I->second.getNode())); - - // Make sure that all globals are cloned over as roots. - if (!(Flags & DSGraph::RemoveUnreachableGlobals) && GlobalsGraph) { - GGCloner.getClonedNH(I->second); - } - } else { - I->second.getNode()->markReachableNodes(Alive); - } - - // The return values are alive as well. - for (ReturnNodesTy::iterator I = ReturnNodes.begin(), E = ReturnNodes.end(); - I != E; ++I) - I->second.getNode()->markReachableNodes(Alive); - - // Mark any nodes reachable by primary calls as alive... - for (fc_iterator I = fc_begin(), E = fc_end(); I != E; ++I) - I->markReachableNodes(Alive); - - - // Now find globals and aux call nodes that are already live or reach a live - // value (which makes them live in turn), and continue till no more are found. - // - bool Iterate; - DenseSet Visited; - std::set AuxFCallsAlive; - do { - Visited.clear(); - // If any global node points to a non-global that is "alive", the global is - // "alive" as well... Remove it from the GlobalNodes list so we only have - // unreachable globals in the list. - // - Iterate = false; - if (!(Flags & DSGraph::RemoveUnreachableGlobals)) - for (unsigned i = 0; i != GlobalNodes.size(); ++i) - if (CanReachAliveNodes(GlobalNodes[i].second, Alive, Visited, - Flags & DSGraph::RemoveUnreachableGlobals)) { - std::swap(GlobalNodes[i--], GlobalNodes.back()); // Move to end to... - GlobalNodes.pop_back(); // erase efficiently - Iterate = true; - } - - // Mark only unresolvable call nodes for moving to the GlobalsGraph since - // call nodes that get resolved will be difficult to remove from that graph. - // The final unresolved call nodes must be handled specially at the end of - // the BU pass (i.e., in main or other roots of the call graph). - for (afc_iterator CI = afc_begin(), E = afc_end(); CI != E; ++CI) - if (!AuxFCallsAlive.count(&*CI) && - (CI->isIndirectCall() - || CallSiteUsesAliveArgs(*CI, Alive, Visited, - Flags & DSGraph::RemoveUnreachableGlobals))) { - CI->markReachableNodes(Alive); - AuxFCallsAlive.insert(&*CI); - Iterate = true; - } - } while (Iterate); - - // If only some of the aux calls are alive - if (AuxFCallsAlive.size() != AuxFunctionCalls.size()) { - // Move dead aux function calls to the end of the list - FunctionListTy::iterator Erase = AuxFunctionCalls.end(); - for (FunctionListTy::iterator CI = AuxFunctionCalls.begin(); CI != Erase; ) - if (AuxFCallsAlive.count(&*CI)) - ++CI; - else { - // Copy and merge global nodes and dead aux call nodes into the - // GlobalsGraph, and all nodes reachable from those nodes. Update their - // target pointers using the GGCloner. - // - if (!(Flags & DSGraph::RemoveUnreachableGlobals)) - GlobalsGraph->AuxFunctionCalls.push_back(DSCallSite(*CI, GGCloner)); - - std::swap(*CI, *--Erase); - } - AuxFunctionCalls.erase(Erase, AuxFunctionCalls.end()); - } - AuxFCallsAlive.clear(); - - // We are finally done with the GGCloner so we can destroy it. - GGCloner.destroy(); - - // At this point, any nodes which are visited, but not alive, are nodes - // which can be removed. Loop over all nodes, eliminating completely - // unreachable nodes. - // - std::vector DeadNodes; - DeadNodes.reserve(Nodes.size()); - for (NodeListTy::iterator NI = Nodes.begin(), E = Nodes.end(); NI != E;) { - DSNode *N = &*NI; - ++NI; - assert(!N->isForwarding() && "Forwarded node in nodes list?"); - - if (!Alive.count(N)) { - Nodes.remove(N); - assert(!N->isForwarding() && "Cannot remove a forwarding node!"); - DeadNodes.push_back(N); - N->dropAllReferences(); - ++NumDNE; - } - } - - // Remove all unreachable globals from the ScalarMap. - // If flag RemoveUnreachableGlobals is set, GlobalNodes has only dead nodes. - // In either case, the dead nodes will not be in the set Alive. - for (unsigned i = 0, e = GlobalNodes.size(); i != e; ++i) - if (!Alive.count(GlobalNodes[i].second)) - ScalarMap.erase(GlobalNodes[i].first); - else - assert((Flags & DSGraph::RemoveUnreachableGlobals) && "non-dead global"); - - // Delete all dead nodes now since their referrer counts are zero. - for (unsigned i = 0, e = DeadNodes.size(); i != e; ++i) - delete DeadNodes[i]; - - SDEBUG(AssertGraphOK(); GlobalsGraph->AssertGraphOK()); -} - -void DSGraph::AssertNodeContainsGlobal(const DSNode *N, const GlobalValue *GV) const { - assert(std::find(N->globals_begin(),N->globals_end(), GV) != - N->globals_end() && "Global value not in node!"); -} - -void DSGraph::AssertCallSiteInGraph(const DSCallSite &CS) const { - if (CS.isIndirectCall()) { - AssertNodeInGraph(CS.getCalleeNode()); -#if 0 - if (CS.getNumPtrArgs() && CS.getCalleeNode() == CS.getPtrArg(0).getNode() && - CS.getCalleeNode() && CS.getCalleeNode()->getGlobals().empty()) - SDEBUG(errs() << "WARNING: WEIRD CALL SITE FOUND!\n"); -#endif - } - AssertNodeInGraph(CS.getRetVal().getNode()); - AssertNodeInGraph(CS.getVAVal().getNode()); - for (unsigned j = 0, e = CS.getNumPtrArgs(); j != e; ++j) - AssertNodeInGraph(CS.getPtrArg(j).getNode()); -} - -void DSGraph::AssertCallNodesInGraph() const { - for (fc_iterator I = fc_begin(), E = fc_end(); I != E; ++I) - AssertCallSiteInGraph(*I); -} -void DSGraph::AssertAuxCallNodesInGraph() const { - for (afc_const_iterator I = afc_begin(), E = afc_end(); I != E; ++I) - AssertCallSiteInGraph(*I); -} - -void DSGraph::AssertGraphOK() const { - for (node_const_iterator NI = node_begin(), E = node_end(); NI != E; ++NI) - NI->assertOK(); - - for (ScalarMapTy::const_iterator I = ScalarMap.begin(), - E = ScalarMap.end(); I != E; ++I) { - assert(!I->second.isNull() && "Null node in scalarmap!"); - AssertNodeInGraph(I->second.getNode()); - if (const GlobalValue *GV = dyn_cast(I->first)) { - assert(I->second.getNode()->isGlobalNode() && - "Global points to node, but node isn't global?"); - AssertNodeContainsGlobal(I->second.getNode(), GV); - } - } - AssertCallNodesInGraph(); - AssertAuxCallNodesInGraph(); - - // Check that all pointer arguments to any functions in this graph have - // destinations. - for (ReturnNodesTy::const_iterator RI = ReturnNodes.begin(), - E = ReturnNodes.end(); - RI != E; ++RI) { - const Function &F = *RI->first; - for (const auto &Arg : F.args()) - if (isa(Arg.getType())) - assert(!getNodeForValue(&Arg).isNull() && - "Pointer argument must be in the scalar map!"); - if (F.isVarArg()) - assert(VANodes.find(&F) != VANodes.end() && - "VarArg function missing VANode!"); - } -} - -/// computeNodeMapping - Given roots in two different DSGraphs, traverse the -/// nodes reachable from the two graphs, computing the mapping of nodes from the -/// first to the second graph. This mapping may be many-to-one (i.e. the first -/// graph may have multiple nodes representing one node in the second graph), -/// but it will not work if there is a one-to-many or many-to-many mapping. -/// -/// Inputs: -/// @NH1 - The first root value for which a node mapping is -/// desired. This value can have a NULL DSNode. -/// @NH2 - The second root value for which a node mapping is -/// desired. This value can have a NULL DSNode. -/// @StrictChecking - Flags whether strict sanity checks should be enforced. -/// -/// Outputs: -/// @NodeMap - A mapping of DSNodes to DSNode handles providing the node -/// mapping desired by the caller. -/// -/// Notes: -/// FIXME: Why was StrictChecking not passed in the recursive calls? -/// FIXME: Why isn't StrictChecking always desired? -/// -void DSGraph::computeNodeMapping(const DSNodeHandle &NH1, - const DSNodeHandle &NH2, NodeMapTy &NodeMap, - bool StrictChecking) { - // - // Get the DSNodes associated with the root values. If either one of them is - // NULL, then we are done. - // - DSNode *N1 = NH1.getNode(), *N2 = NH2.getNode(); - if (N1 == 0 || N2 == 0) return; - - DSNodeHandle &Entry = NodeMap[N1]; - if (!Entry.isNull()) { - // Termination of recursion! - if (StrictChecking) { - assert(Entry.getNode() == N2 && "Inconsistent mapping detected!"); - assert((Entry.getOffset() == (NH2.getOffset()-NH1.getOffset()) || - Entry.getNode()->isNodeCompletelyFolded()) && - "Inconsistent mapping detected!"); - } - return; - } - - // - // Modify the entry in the node map so that the DSNode from the first - // DSNodeHandle is mapped to the second DSNodeHandle. - // - // FIXME: AA:I am not sure what the right mapping for the - // following case is. I believe we do not need to create any - // new mapping. - //assert(((signed int)(NH2.getOffset()-NH1.getOffset())>=0) && " Underflow error "); - if(NH2.getOffset() >= NH1.getOffset()) { - Entry.setTo(N2, NH2.getOffset()-NH1.getOffset()); - } - - // - // The two DSNodes that we have could be strucures with outgoing links to - // other DSNodes. Recursively map such outgoing edges together, too. - // - - // - // If the second DSNode has no outgoing edges, then stop processing. There - // is nothing more to do. - // - unsigned N2Size = N2->getSize(); - if (N2Size == 0) return; // No edges to map to. - - // - // Recursively link outgoing edges together. - // - int N2Idx = NH2.getOffset()-NH1.getOffset(); - for (unsigned i = 0, e = N1->getSize(); i < e; ++i) { - const DSNodeHandle &N1NH = N1->getLink(i); - // - // Don't call N2->getLink if not needed (avoiding crash if N2Idx is not - // aligned correctly). - // - if (!N1NH.isNull()) { - // - // Compute the offset into the second DSNode. - // - unsigned offset = 0; - if (unsigned(N2Idx)+i < N2Size) - offset = N2Idx+i; - else - offset = (unsigned(N2Idx+i) % N2Size); - - // - // Compute the node mapping for the link. - // - const DSNodeHandle &N2NH = N2->getLink(offset); - - // - // Make sure not to recurse into the same node; - // that can cause recursion that does not terminate. - // - if (N1NH.getNode() == N1 && !N2NH.isNull()) { - DSNode *N1L = N1NH.getNode(), *N2L = N2NH.getNode(); - - DSNodeHandle &Entry = NodeMap[N1L]; - if (Entry.isNull()) { - // - // Modify the entry in the node map so that the DSNode from the first - // DSNodeHandle is mapped to the second DSNodeHandle. - // - // FIXME: AA:I am not sure what the right mapping for the - // following case is. I believe we do not need to create any - // new mapping. - //assert(((signed int)(N2NH.getOffset()-N1NH.getOffset())>=0) && " Underflow error "); - if(N2NH.getOffset() >= N1NH.getOffset()) { - Entry.setTo(N2L, N2NH.getOffset()-N1NH.getOffset()); - } - } - } else { - computeNodeMapping (N1NH, N2NH, NodeMap, StrictChecking); - } - } - } -} - - -/// computeGToGGMapping - Compute the mapping of nodes in the global graph to -/// nodes in this graph. -void DSGraph::computeGToGGMapping(NodeMapTy &NodeMap) { - DSGraph &GG = *getGlobalsGraph(); - - DSScalarMap &SM = getScalarMap(); - - // - // Iterate through all values used by this function (i.e., those values in - // the local graph in the function's DSGraph). For each one, compute the - // mapping between its DSNode in the local graph and its DSNode in the - // globals graph. - // - // Note that we use variables to hold intermediate values. This allows us - // to query these values more easily in the debugger. - // - for (DSScalarMap::global_iterator I = SM.global_begin(), - E = SM.global_end(); I != E; ++I) { - // Local value in the scalar map - const Value * LocalValue = *I; - - // DSNode Handle for the value in the local graph - DSNodeHandle LocalNodeHandle = SM[LocalValue]; - - // DSNode Handle for the value in the globals graph - DSNodeHandle GlobalNodeHandle = GG.getNodeForValue(LocalValue); - - // - // Add to the node mapping the mapping between the DSNode in the local - // graph and the DSNode in the globals graph. - // - DSGraph::computeNodeMapping(LocalNodeHandle, GlobalNodeHandle, NodeMap); - } -} - -/// computeGGToGMapping - Compute the mapping of nodes in the global graph to -/// nodes in this graph. Note that any uses of this method are probably bugs, -/// unless it is known that the globals graph has been merged into this graph! -void DSGraph::computeGGToGMapping(InvNodeMapTy &InvNodeMap) { - NodeMapTy NodeMap; - computeGToGGMapping(NodeMap); - - while (!NodeMap.empty()) { - InvNodeMap.insert(std::make_pair(NodeMap.begin()->second, - NodeMap.begin()->first)); - NodeMap.erase(NodeMap.begin()); - } -} - - -/// computeCalleeCallerMapping - Given a call from a function in the current -/// graph to the 'Callee' function (which lives in 'CalleeGraph'), compute the -/// mapping of nodes from the callee to nodes in the caller. -void DSGraph::computeCalleeCallerMapping(DSCallSite CS, const Function &Callee, - DSGraph &CalleeGraph, - NodeMapTy &NodeMap) { - - DSCallSite CalleeArgs = - CalleeGraph.getCallSiteForArguments(const_cast(Callee)); - - computeNodeMapping(CalleeArgs.getRetVal(), CS.getRetVal(), NodeMap); - computeNodeMapping(CalleeArgs.getVAVal(), CS.getVAVal(), NodeMap); - - unsigned NumArgs = CS.getNumPtrArgs(); - if (NumArgs > CalleeArgs.getNumPtrArgs()) - NumArgs = CalleeArgs.getNumPtrArgs(); - - for (unsigned i = 0; i != NumArgs; ++i) - computeNodeMapping(CalleeArgs.getPtrArg(i), CS.getPtrArg(i), NodeMap); - - // Map the nodes that are pointed to by globals. - DSScalarMap &CalleeSM = CalleeGraph.getScalarMap(); - DSScalarMap &CallerSM = getScalarMap(); - - if (CalleeSM.global_size() >= CallerSM.global_size()) { - for (DSScalarMap::global_iterator GI = CallerSM.global_begin(), - E = CallerSM.global_end(); GI != E; ++GI) - if (CalleeSM.global_count(*GI)) - computeNodeMapping(CalleeSM[*GI], CallerSM[*GI], NodeMap); - } else { - for (DSScalarMap::global_iterator GI = CalleeSM.global_begin(), - E = CalleeSM.global_end(); GI != E; ++GI) - if (CallerSM.global_count(*GI)) - computeNodeMapping(CalleeSM[*GI], CallerSM[*GI], NodeMap); - } -} - -/// updateFromGlobalGraph - This function rematerializes global nodes and -/// nodes reachable from them from the globals graph into the current graph. -/// -void DSGraph::updateFromGlobalGraph() { - ReachabilityCloner RC(this, GlobalsGraph, 0); - - // Clone the non-up-to-date global nodes into this graph. - for (DSScalarMap::global_iterator I = getScalarMap().global_begin(), - E = getScalarMap().global_end(); I != E; ++I) { - DSScalarMap::iterator It = GlobalsGraph->ScalarMap.find(*I); - if (It != GlobalsGraph->ScalarMap.end()) - RC.merge(getNodeForValue(*I), It->second); - } -} - -// -// Function: functionIsCallable() -// -// Description: -// Determine whether the specified function can be a target of the specified -// call site. We allow the user to configure what we consider to be -// uncallable at an indirect function call site. -// -// Inputs: -// CS - The call site which calls the function. -// F - The function that is potentially called by CS. -// -// Return value: -// true - The function F can be called by the call site. -// false - The function F cannot be called by the call site. -// -bool -llvm::functionIsCallable (ImmutableCallSite CS, const Function* F) { - //Which targets do we choose? - //Conservative: all of them - //Pretty Safe: same calling convention, otherwise undefined behavior - //Safe on some archs: - //Safe?: vararg call only calling vararg functions - //Safe?: non-vararg call only calling non-vararg functions - //Safe?: iany/ptr can't be interchanged in args w/ float/double - //Not so safe: number of args matching - const PointerType* PT = cast(CS.getCalledValue()->getType()); - const FunctionType* FT = cast(PT->getElementType()); - - // - // If the calling convention doesn't match, then the function cannot be - // called by this call site. - // - if (!noDSACallConv && CS.getCallingConv() != F->getCallingConv()) - return false; - - // - // We will consider the byval parameter attribute to be a part of the calling - // convention. If an actual argument is marked byval while the formal - // argument is not (or vice-versa), then the function is not a valid target. - // - if (!noDSACallConv) { - Function::const_arg_iterator farg = F->arg_begin(), fend = F->arg_end(); - for (unsigned index = 0; index < CS.getNumArgOperands() && farg != fend; - ++farg, ++index) { - if (CS.isByValArgument(index) != farg->hasByValAttr()) { - return false; - } - } - } - - // - // If the caller and callee don't agree on whether the target is a vararg - // function, then the function is not a valid target. - // - if (!noDSACallVA && FT->isVarArg() != F->isVarArg()) - return false; - - // - // If calling this function from this call site would require an implicit - // integer to floating point cast (or vice-versa), then don't consider the - // function callable from this call site. - // - if (!noDSACallFP) { - unsigned ANumParams = F->getFunctionType()->getNumParams(); - unsigned PNumParams = FT->getNumParams(); - unsigned NumParams = (ANumParams < PNumParams) ? ANumParams : PNumParams; - for (unsigned index = 0; index < NumParams; ++index) { - Type * AType = F->getFunctionType()->getParamType(index); - Type * PType = FT->getParamType(index); - if ((AType->isFPOrFPVectorTy() && !PType->isFPOrFPVectorTy()) - || - (!AType->isFPOrFPVectorTy() && PType->isFPOrFPVectorTy())) - return false; - } - } - - if (!noDSACallNumArgs) { - if(CS.arg_size() < F->arg_size()) { - return false; - } - } - - // - // We've done all the checks we've cared to do. The function F can be called - // from this call site. - // - return true; -} - -// -// Method: buildCallGraph() -// -// Description: -// This method updates the given call graph with new information about targets -// of function calls that can be inferred from the unresolved call sites -// within the DSGraph. -// -// The parameter GlobalFunctionList, is a list of all the address taken -// functions in the module. This is used as the list of targets when a callee -// node is Incomplete. -// -// The parameter 'filter' determines if we should attempt to prune callees -// that are illegal to be called from the callsite. -// -void DSGraph::buildCallGraph(DSCallGraph& DCG, std::vector& GlobalFunctionList, bool filter) const { - // - // Get the list of unresolved call sites. - // - const FunctionListTy& Calls = getFunctionCalls(); - for (FunctionListTy::const_iterator ii = Calls.begin(), - ee = Calls.end(); - ii != ee; ++ii) { - // - // Direct calls are easy. We know to where they go. - // - - if (ii->isDirectCall()) { - DCG.insert(ii->getCallSite(), ii->getCalleeFunc()); - } else { - CallSite CS = ii->getCallSite(); - std::vector MaybeTargets; - - if(ii->getCalleeNode()->isIncompleteNode()) - continue; - // - // Get the list of known targets of this function. - // - ii->getCalleeNode()->addFullFunctionList(MaybeTargets); - - // - // Ensure that the call graph at least knows about (has a record of) this - // call site. - // - DCG.insert(CS, 0); - - // - // Add to the call graph only function targets that have well-defined - // behavior using LLVM semantics. - // - for (std::vector::iterator Fi = MaybeTargets.begin(), - Fe = MaybeTargets.end(); Fi != Fe; ++Fi) - if (!filter || functionIsCallable(CS, *Fi)) - DCG.insert(CS, *Fi); - else - ++NumFiltered; - for (DSCallSite::MappedSites_t::iterator I = ii->ms_begin(), - E = ii->ms_end(); I != E; ++I) { - CallSite MCS = *I; - for (std::vector::iterator Fi = MaybeTargets.begin(), - Fe = MaybeTargets.end(); Fi != Fe; ++Fi) - if (!filter || functionIsCallable(MCS, *Fi)) - DCG.insert(MCS, *Fi); - else - ++NumFiltered; - } - } - } -} - -void DSGraph::buildCompleteCallGraph(DSCallGraph& DCG, - std::vector& GlobalFunctionList, bool filter) const { - // - // Get the list of unresolved call sites. - // - const FunctionListTy& Calls = getAuxFunctionCalls(); - for (FunctionListTy::const_iterator ii = Calls.begin(), - ee = Calls.end(); - ii != ee; ++ii) { - - if (ii->isDirectCall()) continue; - CallSite CS = ii->getCallSite(); - if (DCG.callee_size(CS) != 0) continue; - std::vector MaybeTargets; - MaybeTargets.assign(GlobalFunctionList.begin(), GlobalFunctionList.end()); - - DCG.insert(CS, 0); - // - // Add to the call graph only function targets that have well-defined - // behavior using LLVM semantics. - // - for (std::vector::iterator Fi = MaybeTargets.begin(), - Fe = MaybeTargets.end(); Fi != Fe; ++Fi) - if (!filter || functionIsCallable(CS, *Fi)) - DCG.insert(CS, *Fi); - else - ++NumFiltered; - - for (DSCallSite::MappedSites_t::iterator I = ii->ms_begin(), - E = ii->ms_end(); I != E; ++I) { - CallSite MCS = *I; - for (std::vector::iterator Fi = MaybeTargets.begin(), - Fe = MaybeTargets.end(); Fi != Fe; ++Fi) { - if (!filter || functionIsCallable(MCS, *Fi)) - DCG.insert(MCS, *Fi); - else - ++NumFiltered; - } - } - } - svset callees; - callees.insert(GlobalFunctionList.begin(), GlobalFunctionList.end()); - DCG.buildIncompleteCalleeSet(callees); -} diff --git a/lib/DSA/DSMonitor.cpp b/lib/DSA/DSMonitor.cpp deleted file mode 100644 index 733d68db3..000000000 --- a/lib/DSA/DSMonitor.cpp +++ /dev/null @@ -1,212 +0,0 @@ - -#include "dsa/DSMonitor.h" -#include "dsa/DSGraph.h" -#include "llvm/IR/DebugInfo.h" -#include "llvm/Support/raw_ostream.h" -#include "smack/SmackWarnings.h" - -#include - -namespace llvm { - -// XXX duplicated from DSA/Printer.cpp XXX -static std::string getCaption(const DSNode *N, const DSGraph *G) { - std::string empty; - raw_string_ostream OS(empty); - const Module *M = 0; - - if (!G) G = N->getParentGraph(); - - // Get the module from ONE of the functions in the graph it is available. - if (G && G->retnodes_begin() != G->retnodes_end()) - M = G->retnodes_begin()->first->getParent(); - if (M == 0 && G) { - // If there is a global in the graph, we can use it to find the module. - const DSScalarMap &SM = G->getScalarMap(); - if (SM.global_begin() != SM.global_end()) - M = (*SM.global_begin())->getParent(); - } - - if (N->isNodeCompletelyFolded()) - OS << "COLLAPSED"; - else { - if (N->type_begin() != N->type_end()) - for (DSNode::TyMapTy::const_iterator ii = N->type_begin(), - ee = N->type_end(); ii != ee; ++ii) { - OS << ii->first << ": "; - if (ii->second) - for (svset::const_iterator ni = ii->second->begin(), - ne = ii->second->end(); ni != ne; ++ni) { - Type * t = *ni; - t->print (OS); - OS << ", "; - } - else - OS << "VOID"; - OS << " "; - } - else - OS << "VOID"; - if (N->isArrayNode()) - OS << " array"; - } - if (unsigned NodeType = N->getNodeFlags()) { - OS << ": "; - if (NodeType & DSNode::AllocaNode ) OS << "S"; - if (NodeType & DSNode::HeapNode ) OS << "H"; - if (NodeType & DSNode::GlobalNode ) OS << "G"; - if (NodeType & DSNode::UnknownNode ) OS << "U"; - if (NodeType & DSNode::IncompleteNode ) OS << "I"; - if (NodeType & DSNode::ModifiedNode ) OS << "M"; - if (NodeType & DSNode::ReadNode ) OS << "R"; - if (NodeType & DSNode::ExternalNode ) OS << "E"; - if (NodeType & DSNode::ExternFuncNode ) OS << "X"; - if (NodeType & DSNode::IntToPtrNode ) OS << "P"; - if (NodeType & DSNode::PtrToIntNode ) OS << "2"; - if (NodeType & DSNode::VAStartNode ) OS << "V"; - -#ifndef NDEBUG - if (NodeType & DSNode::DeadNode ) OS << ""; -#endif - OS << "\n"; - } - - //Indicate if this is a VANode for some function - for (DSGraph::vanodes_iterator I = G->vanodes_begin(), E = G->vanodes_end(); - I != E; ++I) { - DSNodeHandle VANode = I->second; - if (N == VANode.getNode()) { - OS << "(VANode for " << I->first->getName().str() << ")\n"; - } - } - - EquivalenceClasses *GlobalECs = 0; - if (G) GlobalECs = &G->getGlobalECs(); - - for (DSNode::globals_iterator i = N->globals_begin(), e = N->globals_end(); - i != e; ++i) { - (*i)->printAsOperand(OS,false,M); - - // Figure out how many globals are equivalent to this one. - if (GlobalECs) { - EquivalenceClasses::iterator I = - GlobalECs->findValue(*i); - if (I != GlobalECs->end()) { - unsigned NumMembers = - std::distance(GlobalECs->member_begin(I), GlobalECs->member_end()); - if (NumMembers != 1) OS << " + " << (NumMembers-1) << " EC"; - } - } - OS << "\n"; - } - - return OS.str(); -} - -Instruction * getInstruction(Value *V) { - std::set covered{ V }; - std::deque workList{ V }; - - while (!workList.empty()) { - V = workList.front(); - workList.pop_front(); - if (auto I = dyn_cast(V)) { - return I; - } else { - for (auto U : V->users()) { - if (covered.count(U) == 0) { - workList.push_back(U); - covered.insert(U); - } - } - } - } - - return nullptr; -} - -void DSMonitor::unwatch() { - if (!N.isNull()) - N.setTo(nullptr, 0); - caption = ""; - location = ""; -} - -void DSMonitor::watch(DSNodeHandle N, std::vector VS, std::string M) { - if (N.isNull() || N.getNode()->isCollapsedNode()) { - unwatch(); - return; - } - - this->N = N; - this->VS = VS; - this->message = M; - DSGraph *G = N.getNode()->getParentGraph(); - caption = getCaption(N.getNode(), G); - - if (!VS.empty()) { - Instruction *I = getInstruction(VS[0]); - if (I && I->getMetadata("dbg")) { - const DebugLoc DL = I->getDebugLoc(); - auto *scope = cast(DL.getScope()); - location = scope->getFilename().str() + ":" - + std::to_string(DL.getLine()) + ":" - + std::to_string(DL.getCol()); - } - } -} - -void DSMonitor::warn() { - std::string msg; - raw_string_ostream ss(msg); - - if (location != "") - ss << location << ": "; - - ss << "warning: collapsing DSA node\n"; - - if (message != "") - ss << message << "\n"; - - if (VS.empty()) { - ss << "(unknown value)" << "\n"; - - } else { - if (Instruction *I = getInstruction(VS[0])) { - if (BasicBlock *B = I->getParent()) { - if (Function *F = B->getParent()) { - if (F->hasName()) - ss << "in function:\n " << F->getName() << "\n"; - } - if (B->hasName()) - ss << "in block:\n " << I->getParent()->getName() << "\n"; - } - ss << "at instruction:\n" << *I << "\n"; - } - - for (auto V : VS) - ss << "at value:\n" << *V << "\n"; - - if (caption != "") - ss << "node:\n " << caption << "\n"; - } - ss << "\n"; - - smack::SmackWarnings::warnInfo(ss.str()); -} - -void DSMonitor::witness(DSNodeHandle N, std::vector VS, std::string M) { - if (N.isNull() || N.getNode()->isCollapsedNode()) - return; - - watch(N,VS,M); - check(); -} - -void DSMonitor::check() { - if (!N.isNull() && N.getNode()->isCollapsedNode()) - warn(); - unwatch(); -} - -} diff --git a/lib/DSA/DSTest.cpp b/lib/DSA/DSTest.cpp deleted file mode 100644 index a969fbd2e..000000000 --- a/lib/DSA/DSTest.cpp +++ /dev/null @@ -1,709 +0,0 @@ -//===- DSTest.cpp - Queries DSA results for testing -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This defines various commandline options to DSA to help in regression tests. -// These options are: -// -print-node-for-value= Print the DSNodes for the given values -// -print-only-flags Only print Flags for the given values -// -print-only-values Only print the values pointed to by the given values -// -print-only-types Only print the types for the given values -// -check-same-node= Verify the given values' nodes were merged. -// -check-not-same-node= Verify the given values' nodes weren't merged. -// -check-type=,type Verify the given nodes have the given type -// -check-callees=caller, Verify the given caller has the following callees -// -check-not-callees=caller, Verify the given caller does not have the following callees -// -verify-flags= Verify the given values match the flag specifications. -// -// In general a 'value' query on the DSA results looks like this: -// graph:value[:offset]* -// Examples: -// "value" specifies 'value' in the globals graph -// "func:value" specifies 'value' in graph for function 'func' -// "func:value:0" the node pointed to at offset 0 from the above -// "func:value:0:1" the node pointed to at offset 1 from the above -// ..etc -// We are also robust to "@value" and "@func" notation for convenience -// The -verify-flags option takes values in this format, but also followed -// by any number of 'flag specifiers' of the form '+flags' and '-flags', -// which indicate flags that the node should and shouldn't have. -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "dsgraph-test" - -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" -#include "dsa/DSNode.h" -#include "dsa/DSCallGraph.h" -#include "llvm/IR/Module.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/IR/ValueSymbolTable.h" -using namespace llvm; - -namespace { - cl::list PrintNodesForValues("print-node-for-value", - cl::CommaSeparated, cl::ReallyHidden); - cl::opt OnlyPrintFlags("print-only-flags", cl::ReallyHidden); - cl::opt OnlyPrintValues("print-only-values", cl::ReallyHidden); - cl::opt OnlyPrintTypes("print-only-types", cl::ReallyHidden); - // Test if all mentioned values are in the same node (merged) - cl::list CheckNodesSame("check-same-node", - cl::CommaSeparated, cl::ReallyHidden); - // Test if all mentioned values are in distinct nodes - cl::list CheckNodesNotSame("check-not-same-node", - cl::CommaSeparated, cl::ReallyHidden); - // For each value, verify they have (or don't have) the specified flags - cl::list VerifyFlags("verify-flags", - cl::CommaSeparated, cl::ReallyHidden); - // For each value, verify that type is as given - cl::list CheckType("check-type", - cl::CommaSeparated, cl::ReallyHidden); - // For first function, verify that it calls the other functions - cl::list CheckCallees("check-callees", - cl::CommaSeparated, cl::ReallyHidden); - // For first function, verify that it does not call the other functions - cl::list CheckNotCallees("check-not-callees", - cl::CommaSeparated, cl::ReallyHidden); -} - -typedef std::set FuncSetTy; - -/// NodeValue -- represents a particular node in a DSGraph -/// constructed from a serialized string representation of a value -/// -/// FIXME: Make this integrated into cl parsing, as mentioned: -/// http://llvm.org/docs/CommandLine.html#customparser -/// -/// FIXME: Support querying special nodes like return nodes, VANodes, etc -class NodeValue { - // Containing Function, if applicable. - Function *F; - Module *ParentM; - // Value in that graph's scalarmap that we base off of - // (note that the NH we have below could be indexed a few times - // from this value, only corresponds directly if no offsets) - Value *V; - // DSNodehandle - DSNodeHandle NH; - - // String version (that we were given) - std::string serialized; - - // Parsed list of offsets - typedef SmallVector OffsetVectorTy; - OffsetVectorTy offsets; - - NodeValue() {} - void operator=(const NodeValue&); - NodeValue(const NodeValue&); - - void initialize(const Module *M, const DataStructures *DS) { - parseValue(M); - assert(V && "Failed to parse value?"); - if (isa(V)) { - DSGraph *G = DS->getGlobalsGraph(); - assert(G->hasNodeForValue(V) && "Node not in specified graph!"); - NH = G->getNodeForValue(V); - } else { - assert(F && "No function?"); - DSGraph *G = DS->getDSGraph(*F); - assert(G->hasNodeForValue(V) && "Node not in specified graph!"); - NH = G->getNodeForValue(V); - } - // Handle offsets, if any - // For each offset in the offsets vector, follow the link at that offset - for (OffsetVectorTy::const_iterator I = offsets.begin(), E = offsets.end(); - I != E; ++I ) { - assert(!NH.isNull() && "Null NodeHandle?"); - assert(NH.hasLink(*I) && "Handle doesn't have link?"); - // Follow the offset - NH = NH.getLink(*I); - } - } - - /// stripOffsets -- strips the offsets - /// Walks backwards, stripping offsets. - /// Returns serialized without the offsets - /// - std::string stripOffsets() { - std::vector offsets_reversed; - SmallVector colonSeparated; - StringRef serializedRef = serialized; - serializedRef.split(colonSeparated,":"); - SmallVector::reverse_iterator I = colonSeparated.rbegin(), - E = colonSeparated.rend(); - for(; I != E; ++I ) { - unsigned offset; - // If this isn't an integer (offset), then bail - if (I->getAsInteger(0,offset)) - break; - offsets_reversed.push_back(offset); - } - // Okay so we built reversed list of offsets, now put things back together - - // If we have more than 2 values left, then we have something like: - // name1:name2:name3[:offset]*, which is no good. - // Also, if we have *nothing* left, something is similarly wrong. - assert(((E - I) > 0) && "Node was entirely made of offsets?"); - assert(((E - I) <= 2) && "Too many colons! (Invalid node/offset given)"); - - // Now rebuild the string, without the offsets. - std::string rebuilt = I++->str(); - for(; I != E; ++I) { - rebuilt = I->str() + ":" + rebuilt; - } - - // Reverse the offsets (since we parsed backwards) and put the result - // into the 'offsets' vector for use elsewhere. - offsets.insert(offsets.begin(), - offsets_reversed.rbegin(),offsets_reversed.rend()); - - return rebuilt; - } - - - /// parseValue -- sets value for the string we were constructed on, - /// using the provided module as the context to find the value - void parseValue(const Module *M) { - // Parse the offsets, and remove from the string - StringRef stripped = stripOffsets(); - - unsigned count = stripped.count(':'); - if (count == 0) { - // Global case - // format: "[@]value" - StringRef globalName = stripAtIfRequired(stripped); - - V = M->getNamedValue(globalName); - assert(V && "Unable to find specified global!"); - } else if (count == 1) { - // Function-specific case - // format: "[@]func:value" - - std::pair split = stripped.split(':'); - StringRef func = stripAtIfRequired(split.first); - StringRef value = split.second; - - // First, find the function - F = M->getFunction(func); - ParentM = const_cast(M); - assert(F && "Unable to find function specified!"); - - // Now we try to find the value... - // FIXME: This only works for named values, things like "%1" don't work. - // That might not be a deal breaker, but should be clear. - V = F->getValueSymbolTable()->lookup(value); - - assert(V && "Unable to find value in specified function!"); - - } else { - llvm_unreachable("Too many colons, offsets not stripped?"); - } - - assert(V && "Parsing value failed!"); - } - - /// stripAtIfRequired -- removes the leading '@' character if one exists - /// - StringRef stripAtIfRequired(StringRef v) { - if (!v.startswith("@")) - return v; - - assert(v.size() > 1 && "String too short"); - - return v.substr(1); - } -public: - /// Constructor (from string) - NodeValue(std::string & raw, const Module * M, const DataStructures *DS) - : F(NULL), V(NULL), serialized(raw) { - initialize(M,DS); - assert(V && NH.getNode() && "Parse failed!"); - } - - /// Accessors - DSNodeHandle & getNodeH() { return NH; } - DSGraph * getGraph() { return getNode()->getParentGraph(); } - // FIXME: These two (value/function) aren't used presently, and furthermore - // are a bit confusing in the context of offsets. Make this not lame. - Value * getValue() { return V; } - Function * getFunction() { return F; } - Module * getParentModule() { return ParentM; } - - /// Helper to fetch the node from the nodehandle - DSNode * getNode() { - assert(NH.getNode() && "NULL node?"); - return NH.getNode(); - } -}; - -/// printAllValuesForNode -- prints all values for a given node, without a newline -/// (meant to be a helper) -static void printAllValuesForNode(llvm::raw_ostream &O, NodeValue &NV) { - // We only consider other values that are in the graph - // containing the specified node (by design) - - // Look for values that have an equivalent NH - DSNodeHandle &NH = NV.getNodeH(); - const DSGraph::ScalarMapTy &SM = NV.getGraph()->getScalarMap(); - bool first = true; - - for (DSGraph::ScalarMapTy::const_iterator I = SM.begin(), E = SM.end(); - I != E; ++I ) - if (NH == I->second) { - //Found one! - const Value *V = I->first; - - //Print them out, separated by commas - if (!first) O << ","; - first = false; - - // Print out name, if it has one. - // FIXME: Get "%0, "%1", naming like the .ll has? - if (V->hasName()) - O << V->getName(); - else - O << ""; - } - - //FIXME: Search globals in this graph too (not just scalarMap)? -} - -// printTypesForNode --prints all the types for the given NodeValue, without a newline -// (meant to be called as a helper) -static void printTypesForNode(llvm::raw_ostream &O, NodeValue &NV) { - DSNode *N = NV.getNode(); - - if (N->isNodeCompletelyFolded()) { - O << "Folded"; - } - // Go through all the types, and just dump them. - // FIXME: Lifted from Printer.cpp, probably should be shared - bool firstType = true; - if (N->type_begin() != N->type_end()) - for (DSNode::TyMapTy::const_iterator ii = N->type_begin(), - ee = N->type_end(); ii != ee; ++ii) { - if (!firstType) O << "::"; - firstType = false; - O << ii->first << ":"; - if (ii->second) { - bool first = true; - for (svset::const_iterator ni = ii->second->begin(), - ne = ii->second->end(); ni != ne; ++ni) { - if (!first) O << "|"; - Type * t = *ni; - t->print (O); - first = false; - } - } - else - O << "VOID"; - } - else - O << "VOID"; - - if (N->isArrayNode()) - O << "Array"; -} - -FuncSetTy -getCalleesFor(const Function * caller, const DSCallGraph & cg) -{ - FuncSetTy callees; - - Function const*leader = cg.sccLeader(&*caller); - - // Add all methods in same SCC as caller... - for(DSCallGraph::scc_iterator sccii = cg.scc_begin(leader), - sccee = cg.scc_end(leader); sccii != sccee; ++sccii) - callees.insert(*sccii); - - // And all methods in the SCC's called by the caller - for(DSCallGraph::flat_iterator CI = cg.flat_callee_begin(caller); - CI != cg.flat_callee_end(caller); CI ++) { - callees.insert(*CI); - for(DSCallGraph::scc_iterator sccii = cg.scc_begin(*CI), - sccee = cg.scc_end(*CI); sccii != sccee; ++sccii) - callees.insert(*sccii); - } - - return callees; -} - -static void printCallees(FuncSetTy & Funcs, raw_ostream & O) -{ - FuncSetTy::iterator I = Funcs.begin(), - E = Funcs.end(); - if (I != E) - { - O << (*I)->getName(); - while(++I != E) - O << ", " << (*I)->getName(); - } -} - -static std::string getFlags(DSNode *N) { - std::string flags(""); - - // FIXME: This code is lifted directly from Printer.cpp - // Probably would be good to make this code shared... - // Leaving it separate for now to minimize invasiveness - if (unsigned NodeType = N->getNodeFlags()) { - if (NodeType & DSNode::AllocaNode ) flags += "S"; - if (NodeType & DSNode::HeapNode ) flags += "H"; - if (NodeType & DSNode::GlobalNode ) flags += "G"; - if (NodeType & DSNode::UnknownNode ) flags += "U"; - if (NodeType & DSNode::IncompleteNode ) flags += "I"; - if (NodeType & DSNode::ModifiedNode ) flags += "M"; - if (NodeType & DSNode::ReadNode ) flags += "R"; - if (NodeType & DSNode::ExternalNode ) flags += "E"; - if (NodeType & DSNode::ExternFuncNode ) flags += "X"; - if (NodeType & DSNode::IntToPtrNode ) flags += "P"; - if (NodeType & DSNode::PtrToIntNode ) flags += "2"; - if (NodeType & DSNode::VAStartNode ) flags += "V"; - } - - return flags; -} - -static void printFlags(llvm::raw_ostream &O, DSNode *N) { - O << getFlags(N); -} - -/// printNodes -- print the node specified by NV -/// -/// Format: -/// "flags:{value(s)}:{type(s)}" -/// -/// Additionally, the user can specify to print just one piece -static void printNode(llvm::raw_ostream &O, NodeValue &NV) { - assert( - ((!OnlyPrintFlags && !OnlyPrintValues)|| - (!OnlyPrintFlags && !OnlyPrintTypes) || - (!OnlyPrintValues && !OnlyPrintTypes)) && - "Only one \"Only\" option allowed!"); - - if (OnlyPrintFlags) { - printFlags(O,NV.getNode()); - } else if (OnlyPrintValues) { - printAllValuesForNode(O, NV); - } else if (OnlyPrintTypes) { - printTypesForNode(O, NV); - } else { - //Print all of them - printFlags(O,NV.getNode()); - O << ":{"; - printAllValuesForNode(O, NV); - O << "}:{"; - printTypesForNode(O, NV); - O << "}"; - } - - O << "\n"; -} - - -/// printNodes -- For each node the user indicated, print the node. -/// See 'printNode' for more details. -/// Returns true iff the user specified nodes to print. -/// -static bool printNodes(llvm::raw_ostream &O, const Module *M, - const DataStructures *DS) { - cl::list::iterator I = PrintNodesForValues.begin(), - E = PrintNodesForValues.end(); - if (I != E) { - for ( ; I != E; ++I ) { - // Make sense of what the user gave us - NodeValue NV(*I, M, DS); - // Print corresponding node - printNode(O, NV); - } - return true; - } - return false; -} - -/// checkIfNodesAreSame -- Verify each node that the user indicated -/// should be merged, is in fact merged. -/// Returns true iff the user specified any nodes for this option. -/// -static bool checkIfNodesAreSame(llvm::raw_ostream &O, const Module *M, - const DataStructures *DS) { - - // Verify all nodes listed in "CheckNodesSame" belong to the same node. - cl::list::iterator I = CheckNodesSame.begin(), - E = CheckNodesSame.end(); - // If the user specified that a set of values should be in the same node... - if (I != E) { - // Take the first such value as the reference to compare to the others - NodeValue NVReference(*I++, M, DS); - - // Iterate through the remaining to verify they're the same node. - for(; I != E; ++I) { - NodeValue NV(*I, M, DS); - assert(NVReference.getNodeH()==NV.getNodeH() && "Nodes don't match!"); - } - return true; - } - - return false; -} - -/// checkIfNodesAreNotSame -- Verify each node that the user indicated -/// shouldn't be merged, wasn't merged -/// Returns true iff the user specified any nodes for this option. -/// -static bool checkIfNodesAreNotSame(llvm::raw_ostream &O, const Module *M, - const DataStructures *DS) { - - // Verify all nodes listed in "CheckNodesNotSame" belong to distinct nodes. - cl::list::iterator I = CheckNodesNotSame.begin(), - E = CheckNodesNotSame.end(); - - // If the user specified that a set of values should be in separate nodes... - if (I != E) { - // Lookup all the values - unsigned count = E - I; - NodeValue ** NV = new NodeValue*[count]; - for(unsigned i = 0; I != E; ++I, ++i) - NV[i] = new NodeValue(*I, M, DS); - - //Compare all pairs to make sure they're distinct - for(unsigned i = 0; i < count; ++i) - for(unsigned j = i+1; j < count; ++j) { - assert(NV[i]->getNodeH() != NV[j]->getNodeH() && "Nodes not distinct!"); - } - - for(unsigned i = 0; i < count; ++i) - delete NV[i]; - delete [] NV; - - return true; - } - - return false; -} - -/// checkTypes -- Verify type for the given nodes. -/// Returns true iff the user specified anything for this option -/// - -static bool checkTypes(llvm::raw_ostream &O, const Module *M, - const DataStructures *DS) { - - // Verify all nodes listed in "CheckType" have the same Type - cl::list::iterator I = CheckType.begin(), - E = CheckType.end(); - // If the user specified that a set of values should be in the same node... - if (I != E) { - // last value is type string - std::string typeRef = *(--E); - //typeRef = typeRef.substr(1, typeRef.length()-2); - // Iterate through the remaining to verify they're the same node. - for(; I != E; ++I) { - NodeValue NV(*I, M, DS); - std::string *type = new std::string(); - llvm::raw_string_ostream *test= new llvm::raw_string_ostream(*type); - printTypesForNode(*test, NV); - std::string type1 = test->str(); - type1.erase(remove_if(type1.begin(), type1.end(), isspace), type1.end()); - typeRef.erase(remove_if(typeRef.begin(), typeRef.end(), isspace), typeRef.end()); - - if(type1 != typeRef) { - errs() << "ERROR: Testing for type : \t" << - typeRef << "\n"; - errs() << " But found this type :\t" << - test->str() << "\n"; - llvm_unreachable("Type verification failed!"); - } - } - return true; - } - return false; -} - -/// VerifyFlags -- Verify flag properties for the given nodes. -/// This is a common enough testing process that this was added to make it simpler. -/// Returns true iff the user specified anything for this option. -/// -/// This builds upon the node notation used elsewhere, and tacks on -/// node+flags, node-flags, node+flags-flags -/// Where +flags means 'this node should have these flags' -/// And -flags means 'this node should NOT have these flags' -/// -static bool verifyFlags(llvm::raw_ostream &O, const Module *M, - const DataStructures *DS) { - cl::list::iterator I = VerifyFlags.begin(), - E = VerifyFlags.end(); - if (I != E) { - for(; I != E; ++I) { - std::string NodeFlagOption = *I; - std::string::size_type FlagPos = NodeFlagOption.find_first_of("+-"); - if (FlagPos == std::string::npos) { - errs() << "No flags given for option \"" << NodeFlagOption << "\"!\n"; - llvm_unreachable("Invalid input!"); - } - - // Grab the part before the flag specifiers and parse that as a node - std::string NodeString = std::string(I->begin(),I->begin()+FlagPos); - NodeValue NV(NodeString, M, DS); - - // Process each of the flag specifiers (+flag, or -flag) - do { - bool shouldHaveFlag = (NodeFlagOption[FlagPos] == '+'); - - // Find the next specifier... - std::string::size_type NextPos = NodeFlagOption.find_first_of("+-",FlagPos+1); - - // Parse out the flags for this option - std::string FlagsListed; - if (NextPos != std::string::npos) - FlagsListed = std::string(I->begin()+FlagPos+1,I->begin()+NextPos); - else - FlagsListed = std::string(I->begin()+FlagPos+1,I->end()); - - // Do the checking! - std::string ActualFlags = getFlags(NV.getNode()); - for (std::string::iterator I = FlagsListed.begin(), E = FlagsListed.end(); - I != E; ++I ) { - if (shouldHaveFlag == (ActualFlags.find(*I) == std::string::npos)) - { - errs() << "ERROR: Verify flags for: \t" << - NodeFlagOption << "\n"; - errs() << " But found these flags: \t" << - ActualFlags << "\n"; - llvm_unreachable("Flag verification failed!"); - } - } - - - // Update FlagPos - FlagPos = NextPos; - } while(FlagPos != std::string::npos); - } - return true; - } - return false; -} -/// checkNotCallees -- Verify non-callees for the given function -/// Returns true iff the user specified anything for this option -/// -/// checks that the first function does not callsthe rest of the -/// functions in the list -static bool checkNotCallees(llvm::raw_ostream &O, const Module *M, - const DataStructures *DS) { - //Mangled names must be provided for C++ - cl::list::iterator I = CheckNotCallees.begin(), - E = CheckNotCallees.end(); - - // User didn't specify this option, bail. - if (I == E) return false; - - std::string &func = *(I); - Function *caller = M->getFunction(func); - assert(caller && "Function not found in module"); - - FuncSetTy notCallees; - while (++I != E) { - std::string &func = *(I); - const Function *callee = M->getFunction(func); - assert(callee && "Specified callee function not found in module!"); - notCallees.insert(callee); - } - - const DSCallGraph callgraph = DS->getCallGraph(); - FuncSetTy analysisCallees = getCalleesFor(caller, callgraph); - - if (std::includes(analysisCallees.begin(), analysisCallees.end(), - notCallees.begin(), notCallees.end())) { - FuncSetTy invalid; - std::set_intersection(analysisCallees.begin(), analysisCallees.end(), - notCallees.begin(), notCallees.end(), - std::inserter(invalid, invalid.begin())); - errs() << "ERROR: Callgraph check failed for: \t" << caller->getName() << "\n"; - errs() << " Analysis says calls: \t"; - printCallees(analysisCallees, errs()); errs() << "\n"; - errs() << " Testing to not call: \t"; - printCallees(notCallees, errs()); errs() << "\n"; - errs() << " *** Overlap: \t"; - printCallees(invalid, errs()); errs() << "\n"; - llvm_unreachable("Analysis contained the specified callees!"); - } - - return true; -} - -/// checkCallees -- Verify callees for the given function -/// Returns true iff the user specified anything for this option -/// -/// checks that the first function calls the rest of the -/// functions in the list -static bool checkCallees(llvm::raw_ostream &O, const Module *M, - const DataStructures *DS) { - - //Mangled names must be provided for C++ - cl::list::iterator I = CheckCallees.begin(), - E = CheckCallees.end(); - - // User didn't specify this option, bail. - if (I == E) return false; - - std::string &func = *(I); - Function *caller = M->getFunction(func); - assert(caller && "Function not found in module"); - - FuncSetTy expectedCallees; - while (++I != E) { - std::string &func = *(I); - const Function *callee = M->getFunction(func); - assert(callee && "Specified callee function not found in module!"); - expectedCallees.insert(callee); - } - - const DSCallGraph callgraph = DS->getCallGraph(); - FuncSetTy analysisCallees = getCalleesFor(caller, callgraph); - - if (!std::includes(analysisCallees.begin(), analysisCallees.end(), - expectedCallees.begin(), expectedCallees.end())) { - FuncSetTy missing; - std::set_difference(expectedCallees.begin(), expectedCallees.end(), - analysisCallees.begin(), analysisCallees.end(), - std::inserter(missing, missing.begin())); - errs() << "ERROR: Callgraph check failed for: \t" << caller->getName() << "\n"; - errs() << " Analysis says calls: \t"; - printCallees(analysisCallees, errs()); errs() << "\n"; - errs() << " Testing to make sure calls: \t"; - printCallees(expectedCallees, errs()); errs() << "\n"; - errs() << " *** Missing: \t"; - printCallees(missing, errs()); errs() << "\n"; - llvm_unreachable("Analysis didn't contain the specified callees!"); - } - - return true; -} - -/// handleTest -- handles any user-specified testing options. -/// returns true iff the user specified something to test. -/// -bool DataStructures::handleTest(llvm::raw_ostream &O, const Module *M) const { - - bool tested = false; - - tested |= printNodes(O,M,this); - tested |= checkIfNodesAreSame(O,M,this); - tested |= checkIfNodesAreNotSame(O,M,this); - tested |= verifyFlags(O,M,this); - tested |= checkTypes(O,M,this); - tested |= checkCallees(O,M,this); - tested |= checkNotCallees(O,M,this); - - return tested; -} - diff --git a/lib/DSA/DataStructure.cpp b/lib/DSA/DataStructure.cpp deleted file mode 100644 index 60676135e..000000000 --- a/lib/DSA/DataStructure.cpp +++ /dev/null @@ -1,1558 +0,0 @@ -//===- DataStructure.cpp - Implement the core data structure analysis -----===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the core data structure functionality. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "data-structure" -#include "dsa/DSGraphTraits.h" -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" -#include "dsa/DSSupport.h" -#include "dsa/DSNode.h" -#include "dsa/DSMonitor.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/Support/CommandLine.h" -#include "smack/Debug.h" -#include "llvm/ADT/DepthFirstIterator.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SCCIterator.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/Timer.h" -#include "llvm/Support/raw_ostream.h" - -#include -#include -using namespace llvm; - -#define COLLAPSE_ARRAYS_AGGRESSIVELY 0 -namespace { - STATISTIC (NumFolds, "Number of nodes completely folded"); - STATISTIC (NumFoldsOOBOffset, "Number of OOB offsets that caused node folding"); - STATISTIC (NumNodeAllocated , "Number of nodes allocated"); -} - -/// isForwarding - Return true if this NodeHandle is forwarding to another -/// one. -bool DSNodeHandle::isForwarding() const { - return N && N->isForwarding(); -} - -DSNode *DSNodeHandle::HandleForwarding() const { - assert(N->isForwarding() && "Can only be invoked if forwarding!"); - SDEBUG( - { //assert not looping - DSNode* NH = N; - svset seen; - while(NH && NH->isForwarding()) { - assert(seen.find(NH) == seen.end() && "Loop detected"); - seen.insert(NH); - NH = NH->ForwardNH.N; - } - } - ); - // Handle node forwarding here! - DSNode *Next = N->ForwardNH.getNode(); // Cause recursive shrinkage - Offset += N->ForwardNH.getOffset(); - - if (--N->NumReferrers == 0) { - // Removing the last referrer to the node, sever the forwarding link - N->stopForwarding(); - } - - N = Next; - N->NumReferrers++; - - if (N->getSize() <= Offset) { - assert(N->getSize() <= 1 && "Forwarded to shrunk but not collapsed node?"); - Offset = 0; - } - return N; -} - -//===----------------------------------------------------------------------===// -// DSScalarMap Implementation -//===----------------------------------------------------------------------===// - -DSNodeHandle &DSScalarMap::AddGlobal(const GlobalValue *GV) { - assert(GV); - assert(ValueMap.count(GV) == 0 && "GV already exists!"); - - // If the node doesn't exist, check to see if it's a global that is - // equated to another global in the program. - EquivalenceClasses::iterator ECI = GlobalECs.findValue(GV); - if (ECI != GlobalECs.end()) { - const GlobalValue *Leader = *GlobalECs.findLeader(ECI); - if (Leader != GV) { - GV = Leader; - iterator I = ValueMap.find(GV); - if (I != ValueMap.end()) - return I->second; - } - } - - // Okay, this is either not an equivalenced global or it is the leader, it - // will be inserted into the scalar map now. - GlobalSet.insert(GV); - - return ValueMap.insert(std::make_pair(GV, DSNodeHandle())).first->second; -} - -/// spliceFrom - Copy all entries from RHS, then clear RHS. -/// -void DSScalarMap::spliceFrom(DSScalarMap &RHS) { - // Special case if this is empty. - if (ValueMap.empty()) { - ValueMap.swap(RHS.ValueMap); - GlobalSet.swap(RHS.GlobalSet); - } else { - GlobalSet.insert(RHS.GlobalSet.begin(), RHS.GlobalSet.end()); - for (ValueMapTy::iterator I = RHS.ValueMap.begin(), E = RHS.ValueMap.end(); - I != E; ++I) - ValueMap[I->first].mergeWith(I->second); - RHS.ValueMap.clear(); - } -} - -//===----------------------------------------------------------------------===// -// DSNode Implementation -//===----------------------------------------------------------------------===// - -DSNode::DSNode(DSGraph *G) - : NumReferrers(0), Size(0), ParentGraph(G), NodeType(0) { - // Add the type entry if it is specified... - if (G) G->addNode(this); - ++NumNodeAllocated; - } - -// DSNode copy constructor... do not copy over the referrers list! -DSNode::DSNode(const DSNode &N, DSGraph *G, bool NullLinks) - : NumReferrers(0), Size(N.Size), ParentGraph(G), TyMap(N.TyMap), - Globals(N.Globals), NodeType(N.NodeType) { - if (!NullLinks) Links = N.Links; - G->addNode(this); - ++NumNodeAllocated; - } - -DSNode::~DSNode() { - dropAllReferences(); - assert(hasNoReferrers() && "Referrers to dead node exist!"); -} - -void DSNode::assertOK() const { - // assert(((Ty && Ty->getTypeID() != Type::VoidTyID) || - // ((!Ty || Ty->getTypeID() == Type::VoidTyID) && (Size == 0 || - // (NodeType & DSNode::ArrayNode)))) && - // "Node not OK!"); - - assert(ParentGraph && "Node has no parent?"); - for (globals_iterator ii = globals_begin(), ee = globals_end(); - ii != ee; ++ii) { - assert(ParentGraph->getScalarMap().global_count(*ii)); - assert(ParentGraph->getScalarMap().find(*ii)->second.getNode() == this); - } -} - -/// forwardNode - Mark this node as being obsolete, and all references to it -/// should be forwarded to the specified node and offset. -/// -void DSNode::forwardNode(DSNode *To, unsigned Offset) { - assert(this != To && "Cannot forward a node to itself!"); - assert(ForwardNH.isNull() && "Already forwarding from this node!"); - if (To->Size <= 1) Offset = 0; - assert((Offset < To->Size || (Offset == To->Size && Offset == 0)) && - "Forwarded offset is wrong!"); - ForwardNH.setTo(To, Offset); - NodeType = DeadNode; - Size = 0; - - DSNodeHandle ToNH(To,Offset); - - //Move the Links - for (LinkMapTy::iterator ii = Links.begin(), ee = Links.end(); - ii != ee; ++ii) { - if (!ii->second.isNull()) { - // Compute the offset into the current node at which to - // merge this link. In the common case, this is a linear - // relation to the offset in the original node (with - // wrapping), but if the current node gets collapsed due to - // recursive merging, we must make sure to merge in all remaining - // links at offset zero. - unsigned MergeOffset = 0; - if (ToNH.getNode()->getSize() != 1) - MergeOffset = (ii->first + Offset) % ToNH.getNode()->getSize(); - ToNH.getNode()->addEdgeTo(MergeOffset, ii->second); - } - } - Links.clear(); - - // Remove this node from the parent graph's Nodes list. - ParentGraph->unlinkNode(this); - ParentGraph = 0; -} - -// addGlobal - Add an entry for a global value to the Globals list. This also -// marks the node with the 'G' flag if it does not already have it. -// -void DSNode::addGlobal(const GlobalValue *GV) { - // First, check to make sure this is the leader if the global is in an - // equivalence class. - GV = getParentGraph()->getScalarMap().getLeaderForGlobal(GV); - - Globals.insert(GV); - setGlobalMarker(); -} - -void DSNode::addFunction(const Function* F) { - addGlobal(F); -} - -// removeGlobal - Remove the specified global that is explicitly in the globals -// list. -void DSNode::removeGlobal(const GlobalValue *GV) { - assert (Globals.count(GV) && "Global not in Node!"); - Globals.erase(GV); -} - -/// foldNodeCompletely - If we determine that this node has some funny -/// behavior happening to it that we cannot represent, we fold it down to a -/// single, completely pessimistic, node. This node is represented as a -/// single byte with a single TypeEntry of "void". -/// -void DSNode::foldNodeCompletely() { - if (isNodeCompletelyFolded()) return; // If this node is already folded... - - // llvm_unreachable("Folding is happening"); - - ++NumFolds; - - //Collapsed nodes don't really need a type - //Clear the array flag too. Node should be of type VOID - TyMap.clear(); - maskNodeTypes(~ArrayNode); - - // If this node has a size that is <= 1, we don't need to create a forwarding - // node. - if (getSize() <= 1) { - setCollapsedMarker(); - Size = 1; - assert(Links.size() <= 1 && "Size is 1, but has more links?"); - } else { - // Create the node we are going to forward to. This is required because - // some referrers may have an offset that is > 0. By forcing them to - // forward, the forwarder has the opportunity to correct the offset. - DSNode *DestNode = new DSNode(ParentGraph); - DestNode->NodeType = NodeType; - DestNode->setCollapsedMarker(); - DestNode->Size = 1; - DestNode->Globals.swap(Globals); - - // Start forwarding to the destination node... - forwardNode(DestNode, 0); - - } -} - -/// isNodeCompletelyFolded - Return true if this node has been completely -/// folded down to something that can never be expanded, effectively losing -/// all of the field sensitivity that may be present in the node. -/// -bool DSNode::isNodeCompletelyFolded() const { - return isCollapsedNode(); -} - -void DSNode::addValueList(std::vector &List) const { - DSScalarMap &SN = getParentGraph()->getScalarMap(); - for(DSScalarMap::const_iterator I = SN.begin(), E = SN.end(); I!= E; I++) { - if(SN[I->first].getNode() == this){ - //I->first->print(smack::dbgs(), true); - } - - } -} -/// addFullGlobalsSet - Compute the full set of global values that are -/// represented by this node. Unlike getGlobalsList(), this requires fair -/// amount of work to compute, so don't treat this method call as free. -void DSNode::addFullGlobalsSet(svset &Set) const { - if (globals_begin() == globals_end()) return; - - EquivalenceClasses &EC = getParentGraph()->getGlobalECs(); - - for (globals_iterator I = globals_begin(), E = globals_end(); I != E; ++I) { - EquivalenceClasses::iterator ECI = EC.findValue(*I); - if (ECI == EC.end()) - Set.insert(*I); - else - Set.insert(EC.member_begin(ECI), EC.member_end()); - } -} - -/// addFullFunctionSet - Identical to addFullGlobalsSet, but only return the -/// functions in the full list. -void DSNode::addFullFunctionSet(svset &Set) const { - if (globals_begin() == globals_end()) return; - - EquivalenceClasses &EC = getParentGraph()->getGlobalECs(); - - for (globals_iterator I = globals_begin(), E = globals_end(); I != E; ++I) { - EquivalenceClasses::iterator ECI = EC.findValue(*I); - if (ECI == EC.end()) { - if (const Function *F = dyn_cast(*I)) - Set.insert(F); - } else { - for (EquivalenceClasses::member_iterator MI = - EC.member_begin(ECI), E = EC.member_end(); MI != E; ++MI) - if (const Function *F = dyn_cast(*MI)) - Set.insert(F); - } - } -} - -void DSNode::dumpFuncs() { - std::vector List; - addFullFunctionList (List); - for (unsigned index = 0; index < List.size(); ++index) { - std::cerr << List[index]->getName().str() << std::endl; - } - return; -} - -/// markIntPtrFlags - Mark P2 flags on node, if integer and pointer types -/// overlap at any offset. -/// -void DSNode::markIntPtrFlags() { - // check if the types merged have both int and pointer at the same offset, - - const DataLayout &TD = getParentGraph()->getDataLayout(); - // check all offsets for that node. - for(unsigned offset = 0; offset < getSize() ; offset++) { - // if that Node has no Type information, skip - if(TyMap.find(offset) == TyMap.end()) - continue; - if(!TyMap[offset]) - continue; - - bool pointerTy = false; - bool integerTy = false; - unsigned intSize = 0; - unsigned ptrSize = 0; - - // Iterate through all the Types, at that offset, checking if we have - // found a pointer type/integer type - for (svset::const_iterator ni = TyMap[offset]->begin(), - ne = TyMap[offset]->end(); ni != ne; ++ni) { - if((*ni)->isPointerTy()) { - PointerType * PT = dyn_cast(*ni); - pointerTy = true; - ptrSize = TD.getPointerSize(PT->getAddressSpace()); - } - if((*ni)->isIntegerTy()) { - integerTy = true; - if (TD.getTypeStoreSize(*ni) > intSize) - intSize = TD.getTypeStoreSize(*ni); - } - } - // If this offset itself contains both pointer and integer, set the - // flags and exit. - if(pointerTy && integerTy){ - setUnknownMarker()->setIntToPtrMarker()->setPtrToIntMarker(); - return; - } - if(!pointerTy && !integerTy){ - continue; - } - - // If only either integer or pointer was found, we must see if it - // overlaps with any other pointer or integer type at an offset that - // comes later. - unsigned maxOffset = offset + (pointerTy ? ptrSize:intSize); - unsigned offset2 = offset; - while(offset2 < maxOffset && offset2 < getSize()) { - if(TyMap.find(offset2) == TyMap.end()) { - offset2++; - continue; - } - for (svset::const_iterator ni = TyMap[offset2]->begin(), - ne = TyMap[offset2]->end(); ni != ne; ++ni) { - if((*ni)->isPointerTy()) { - pointerTy = true; - } - if((*ni)->isIntegerTy()) { - integerTy = true; - } - } - // whenever we have found overlapping integer and pointer types, - // we can set the flags, and exit. - if(pointerTy && integerTy){ - setUnknownMarker()->setIntToPtrMarker()->setPtrToIntMarker(); - return; - } - offset2++; - } - } -} - -/// growSizeForType - This method increases the size of the node -/// to accomodate NewTy at the given offset. This is useful for -/// updating the size of a DSNode, without actually inferring a -/// Type. -void DSNode::growSizeForType(Type *NewTy, unsigned Offset) { - - if (!NewTy || NewTy->isVoidTy()) return; - - if (isCollapsedNode()) return; - if (isArrayNode() && getSize() > 0) { - Offset %= getSize(); - } - const DataLayout &TD = getParentGraph()->getDataLayout(); - if (Offset + TD.getTypeAllocSize(NewTy) >= getSize()) - growSize(Offset + TD.getTypeAllocSize(NewTy)); - -} - -/// mergeTypeInfo - This method merges the specified type into the current node -/// at the specified offset. This may update the current node's type record if -/// this gives more information to the node, it may do nothing to the node if -/// this information is already known, or it may merge the node completely (and -/// return true) if the information is incompatible with what is already known. -/// -/// This method returns true if the node is completely folded, otherwise false. -/// -void DSNode::mergeTypeInfo(Type *NewTy, unsigned Offset) { - if (!NewTy || NewTy->isVoidTy()) return; - if (isCollapsedNode()) return; - - growSizeForType(NewTy, Offset); - - // Clang generates loads and stores of struct types. - // %tmp12 = load %struct.demand* %retval, align 1 - - // In such cases, merge type information for each struct field - // individually(at the appropriate offset), instead of the - // struct type. - if(NewTy->isStructTy()) { - const DataLayout &TD = getParentGraph()->getDataLayout(); - StructType *STy = cast(NewTy); - const StructLayout *SL = TD.getStructLayout(cast(STy)); - unsigned count = 0; - for(Type::subtype_iterator ii = STy->element_begin(), ee = STy->element_end(); ii!= ee; ++ii, ++count) { - unsigned FieldOffset = SL->getElementOffset(count); - mergeTypeInfo(*ii, Offset + FieldOffset); - } - } else { - TyMap[Offset] = getParentGraph()->getTypeSS().getOrCreate(TyMap[Offset], NewTy); - } - - assert(TyMap[Offset]); -} - -void DSNode::mergeTypeInfo(const TyMapTy::mapped_type TyIt, unsigned Offset) { - if (isCollapsedNode()) return; - if (isArrayNode()) Offset %= getSize(); - - const DataLayout &TD = getParentGraph()->getDataLayout(); - if (!TyMap[Offset]){ - TyMap[Offset] = TyIt; - for (svset::const_iterator ni = TyMap[Offset]->begin(), - ne = TyMap[Offset]->end(); ni != ne; ++ni) { - if (Offset + TD.getTypeAllocSize(*ni) >= getSize()) - growSize(Offset + TD.getTypeAllocSize(*ni)); - } - } else if (TyIt) { - svset S(*TyMap[Offset]); - S.insert(TyIt->begin(), TyIt->end()); - TyMap[Offset] = getParentGraph()->getTypeSS().getOrCreate(S); - } - assert(TyMap[Offset]); -} - -void DSNode::mergeTypeInfo(const DSNode* DN, unsigned Offset) { - if (isCollapsedNode()) return; - - for (TyMapTy::const_iterator ii = DN->TyMap.begin(), ee = DN->TyMap.end(); - ii != ee; ++ii) - mergeTypeInfo(ii->second, ii->first + Offset); -} - -/// addEdgeTo - Add an edge from the current node to the specified node. This -/// can cause merging of nodes in the graph. -/// -void DSNode::addEdgeTo(unsigned Offset, const DSNodeHandle &NH) { - if (NH.isNull()) return; // Nothing to do - - if (isNodeCompletelyFolded()) - Offset = 0; - - DSNodeHandle &ExistingEdge = getLink(Offset); - if (!ExistingEdge.isNull()) { - // Merge the two nodes... - ExistingEdge.mergeWith(NH); - } else { // No merging to perform... - setLink(Offset, NH); // Just force a link in there... - } -} - -void DSNode::mergeGlobals(const DSNode &RHS) { - Globals.insert(RHS.Globals.begin(), RHS.Globals.end()); -} - -// MergeNodes - Helper function for DSNode::mergeWith(). -// This function does the hard work of merging two nodes, CurNodeH -// and NH after filtering out trivial cases and making sure that -// CurNodeH.offset >= NH.offset. -// -// ***WARNING*** -// Since merging may cause either node to go away, we must always -// use the node-handles to refer to the nodes. These node handles are -// automatically updated during merging, so will always provide access -// to the correct node after a merge. -// -void DSNode::MergeNodes(DSNodeHandle& CurNodeH, DSNodeHandle& NH) { - assert(CurNodeH.getOffset() >= NH.getOffset() && - "This should have been enforced in the caller."); - assert(CurNodeH.getNode()->getParentGraph()==NH.getNode()->getParentGraph() && - "Cannot merge two nodes that are not in the same graph!"); - - // Now we know that Offset >= NH.Offset, so convert it so our "Offset" (with - // respect to NH.Offset) is now zero. NOffset is the distance from the base - // of our object that N starts from. - // - unsigned NOffset = CurNodeH.getOffset()-NH.getOffset(); - unsigned NSize = NH.getNode()->getSize(); - - // If the two nodes are of different size, and the smaller node has the array - // bit set, collapse! - if (NSize != CurNodeH.getNode()->getSize()) { -#if COLLAPSE_ARRAYS_AGGRESSIVELY - if (NSize < CurNodeH.getNode()->getSize()) { - if (NH.getNode()->isArrayNode()) - NH.getNode()->foldNodeCompletely(); - } else if (CurNodeH.getNode()->isArrayNode()) { - NH.getNode()->foldNodeCompletely(); - } -#endif - } - - // If we are merging a node with a completely folded node, then both nodes are - // now completely folded. - // - if (CurNodeH.getNode()->isNodeCompletelyFolded()) { - if (!NH.getNode()->isNodeCompletelyFolded()) { - NH.getNode()->foldNodeCompletely(); - assert(NH.getNode() && NH.getOffset() == 0 && - "folding did not make offset 0?"); - NOffset = NH.getOffset(); - NSize = NH.getNode()->getSize(); - assert(NOffset == 0 && NSize == 1); - } - } else if (NH.getNode()->isNodeCompletelyFolded()) { - CurNodeH.getNode()->foldNodeCompletely(); - assert(CurNodeH.getNode() && CurNodeH.getOffset() == 0 && - "folding did not make offset 0?"); - NSize = NH.getNode()->getSize(); - NOffset = NH.getOffset(); - assert(NOffset == 0 && NSize == 1); - } - - // FIXME:Add comments. - if(NH.getNode()->isArrayNode() && !CurNodeH.getNode()->isArrayNode()) { - if(NH.getNode()->getSize() != 0 && CurNodeH.getNode()->getSize() != 0) { - if((NH.getNode()->getSize() != CurNodeH.getNode()->getSize() && - (NH.getOffset() != 0 || CurNodeH.getOffset() != 0) - && NH.getNode()->getSize() < CurNodeH.getNode()->getSize())) { - CurNodeH.getNode()->foldNodeCompletely(); - NH.getNode()->foldNodeCompletely(); - NSize = NH.getNode()->getSize(); - NOffset = NH.getOffset(); - } - } - } - if(!NH.getNode()->isArrayNode() && CurNodeH.getNode()->isArrayNode()) { - if(NH.getNode()->getSize() != 0 && CurNodeH.getNode()->getSize() != 0) { - if((NH.getNode()->getSize() != CurNodeH.getNode()->getSize() && - (NH.getOffset() != 0 || CurNodeH.getOffset() != 0) - && NH.getNode()->getSize() > CurNodeH.getNode()->getSize())) { - CurNodeH.getNode()->foldNodeCompletely(); - NH.getNode()->foldNodeCompletely(); - NSize = NH.getNode()->getSize(); - NOffset = NH.getOffset(); - } - } - } - - if (CurNodeH.getNode()->isArrayNode() && NH.getNode()->isArrayNode()) { - if(NH.getNode()->getSize() != 0 && CurNodeH.getNode()->getSize() != 0 - && (NH.getNode()->getSize() != CurNodeH.getNode()->getSize())){ - CurNodeH.getNode()->foldNodeCompletely(); - NH.getNode()->foldNodeCompletely(); - NSize = NH.getNode()->getSize(); - NOffset = NH.getOffset(); - } - } - - - DSNode *N = NH.getNode(); - if (CurNodeH.getNode() == N || N == 0) return; - assert(!CurNodeH.getNode()->isDeadNode()); - - // Merge the type entries of the two nodes together... - CurNodeH.getNode()->mergeTypeInfo(NH.getNode(), NOffset); - if (NH.getNode()->getSize() + NOffset > CurNodeH.getNode()->getSize()) - CurNodeH.getNode()->growSize(NH.getNode()->getSize() + NOffset); - assert(!CurNodeH.getNode()->isDeadNode()); - - // Merge the NodeType information. - CurNodeH.getNode()->NodeType |= N->NodeType; - - // Start forwarding to the new node! - N->forwardNode(CurNodeH.getNode(), NOffset); - assert(!CurNodeH.getNode()->isDeadNode()); - - // Make all of the outgoing links of N now be outgoing links of CurNodeH. - // - for (LinkMapTy::iterator ii = N->Links.begin(), ee = N->Links.end(); - ii != ee; ++ii) - if (ii->second.getNode()) { - // Compute the offset into the current node at which to - // merge this link. In the common case, this is a linear - // relation to the offset in the original node (with - // wrapping), but if the current node gets collapsed due to - // recursive merging, we must make sure to merge in all remaining - // links at offset zero. - unsigned MergeOffset = 0; - DSNode *CN = CurNodeH.getNode(); - if (CN->Size != 1) - MergeOffset = (ii->first + NOffset) % CN->getSize(); - CN->addEdgeTo(MergeOffset, ii->second); - } - - // Now that there are no outgoing edges, all of the Links are dead. - N->Links.clear(); - - // Merge the globals list... - CurNodeH.getNode()->mergeGlobals(*N); - - // Delete the globals from the old node... - N->Globals.clear(); -} - - -/// mergeWith - Merge this node and the specified node, moving all links to and -/// from the argument node into the current node, deleting the node argument. -/// Offset indicates what offset the specified node is to be merged into the -/// current node. -/// -/// The specified node may be a null pointer (in which case, we update it to -/// point to this node). -/// -void DSNode::mergeWith(const DSNodeHandle &NH, unsigned Offset) { - DSNode *N = NH.getNode(); - if (N == this && NH.getOffset() == Offset) - return; // Noop - - // If the RHS is a null node, make it point to this node! - if (N == 0) { - NH.mergeWith(DSNodeHandle(this, Offset)); - return; - } - - assert(!N->isDeadNode() && !isDeadNode()); - assert(!hasNoReferrers() && "Should not try to fold a useless node!"); - - if (N == this) { - // We cannot merge two pieces of the same node together, collapse the node - // completely. - SDEBUG(errs() << "Attempting to merge two chunks of the same node together!\n"); - foldNodeCompletely(); - return; - } - - // If both nodes are not at offset 0, make sure that we are merging the node - // at an later offset into the node with the zero offset. - // - if (Offset < NH.getOffset()) { - N->mergeWith(DSNodeHandle(this, Offset), NH.getOffset()); - return; - } else if (Offset == NH.getOffset() && getSize() < N->getSize()) { - // If the offsets are the same, merge the smaller node into the bigger node - N->mergeWith(DSNodeHandle(this, Offset), NH.getOffset()); - return; - } - - // Ok, now we can merge the two nodes. Use a static helper that works with - // two node handles, since "this" may get merged away at intermediate steps. - DSNodeHandle CurNodeH(this, Offset); - DSNodeHandle NHCopy(NH); - if (CurNodeH.getOffset() >= NHCopy.getOffset()) - DSNode::MergeNodes(CurNodeH, NHCopy); - else - DSNode::MergeNodes(NHCopy, CurNodeH); -} - -void DSNode::cleanEdges() { - //get rid of any type edge pointing to the null type - for (type_iterator ii = type_begin(); ii != type_end(); ) { - if (ii->second) - ++ii; - else { - type_iterator backup = ii; - ++backup; - TyMap.erase(ii); - ii = backup; - } - } - //get rid of any node edge pointing to nothing - for (edge_iterator ii = edge_begin(); ii != edge_end(); ) { - if (ii->second.isNull()) { - edge_iterator backup = ii; - ++backup; - Links.erase(ii); - ii = backup; - } else - ++ii; - } -} - -void DSNode::checkOffsetFoldIfNeeded(int Offset) { - if (!isNodeCompletelyFolded() && - (Size != 0 || Offset != 0) && - !isForwarding()) { - if ((Offset >= (int)Size) || Offset < 0) { - // Accessing offsets out of node size range - // This is seen in the "magic" struct in named (from bind), where the - // fourth field is an array of length 0, presumably used to create struct - // instances of different sizes - // More generally this happens whenever code indexes past the end - // of a struct type. We don't model this, so fold! - - // Collapse the node since its size is now variable - foldNodeCompletely(); - - ++NumFoldsOOBOffset; - } - } -} -//===----------------------------------------------------------------------===// -// ReachabilityCloner Implementation -//===----------------------------------------------------------------------===// - -DSNodeHandle ReachabilityCloner::getClonedNH(const DSNodeHandle &SrcNH) { - if (SrcNH.isNull()) return DSNodeHandle(); - const DSNode *SN = SrcNH.getNode(); - - DSNodeHandle &NH = NodeMap[SN]; - if (!NH.isNull()) { // Node already mapped? - DSNode *NHN = NH.getNode(); - unsigned NewOffset = NH.getOffset() + SrcNH.getOffset(); - if (NHN) { - NHN->checkOffsetFoldIfNeeded(NewOffset); - NHN = NH.getNode(); - } - return DSNodeHandle(NHN, NewOffset); - } - - // If SrcNH has globals and the destination graph has one of the same globals, - // merge this node with the destination node, which is much more efficient. - if (SN->globals_begin() != SN->globals_end()) { - DSScalarMap &DestSM = Dest->getScalarMap(); - for (DSNode::globals_iterator I = SN->globals_begin(),E = SN->globals_end(); - I != E; ++I) { - const GlobalValue *GV = *I; - DSScalarMap::iterator GI = DestSM.find(GV); - if (GI != DestSM.end() && !GI->second.isNull()) { - // We found one, use merge instead! - merge(GI->second, Src->getNodeForValue(GV)); - assert(!NH.isNull() && "Didn't merge node!"); - DSNode *NHN = NH.getNode(); - unsigned NewOffset = NH.getOffset() + SrcNH.getOffset(); - if (NHN) { - NHN->checkOffsetFoldIfNeeded(NewOffset); - NHN = NH.getNode(); - } - return DSNodeHandle(NHN, NewOffset); - } - } - } - - if (!createDest) return DSNodeHandle(0,0); - - DSNode *DN = new DSNode(*SN, Dest, true /* Null out all links */); - DN->maskNodeTypes(BitsToKeep); - NH = DN; - - // Next, recursively clone all outgoing links as necessary. Note that - // adding these links can cause the node to collapse itself at any time, and - // the current node may be merged with arbitrary other nodes. For this - // reason, we must always go through NH. - DN = 0; - for (DSNode::const_edge_iterator ii = SN->edge_begin(), ee = SN->edge_end(); - ii != ee; ++ii) { - const DSNodeHandle &SrcEdge = ii->second; - if (!SrcEdge.isNull()) { - const DSNodeHandle &DestEdge = getClonedNH(SrcEdge); - // Compute the offset into the current node at which to - // merge this link. In the common case, this is a linear - // relation to the offset in the original node (with - // wrapping), but if the current node gets collapsed due to - // recursive merging, we must make sure to merge in all remaining - // links at offset zero. - unsigned MergeOffset = 0; - DSNode *CN = NH.getNode(); - if (CN->getSize() != 1) - MergeOffset = (ii->first + NH.getOffset()) % CN->getSize(); - CN->addEdgeTo(MergeOffset, DestEdge); - } - } - - // If this node contains any globals, make sure they end up in the scalar - // map with the correct offset. - for (DSNode::globals_iterator I = SN->globals_begin(), E = SN->globals_end(); - I != E; ++I) { - const GlobalValue *GV = *I; - const DSNodeHandle &SrcGNH = Src->getNodeForValue(GV); - DSNodeHandle &DestGNH = NodeMap[SrcGNH.getNode()]; - assert(DestGNH.getNode() == NH.getNode() &&"Global mapping inconsistent"); - Dest->getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(), - DestGNH.getOffset()+SrcGNH.getOffset())); - } - NH.getNode()->mergeGlobals(*SN); - - DSNode* NHN = NH.getNode(); - unsigned NewOffset = NH.getOffset() + SrcNH.getOffset(); - if (NHN) { - NHN->checkOffsetFoldIfNeeded(NewOffset); - NHN = NH.getNode(); - } - return DSNodeHandle(NHN, NewOffset); -} - -void ReachabilityCloner::merge(const DSNodeHandle &NH, - const DSNodeHandle &SrcNH) { - if (SrcNH.isNull()) return; // Noop - if (NH.isNull()) { - // If there is no destination node, just clone the source and assign the - // destination node to be it. - NH.mergeWith(getClonedNH(SrcNH)); - return; - } - - // Okay, at this point, we know that we have both a destination and a source - // node that need to be merged. Check to see if the source node has already - // been cloned. - const DSNode *SN = SrcNH.getNode(); - DSNodeHandle &SCNH = NodeMap[SN]; // SourceClonedNodeHandle - if (!SCNH.isNull()) { // Node already cloned? - DSNode *SCNHN = SCNH.getNode(); - NH.mergeWith(DSNodeHandle(SCNHN, - SCNH.getOffset()+SrcNH.getOffset())); - return; // Nothing to do! - } - - // Okay, so the source node has not already been cloned. Instead of creating - // a new DSNode, only to merge it into the one we already have, try to perform - // the merge in-place. The only case we cannot handle here is when the offset - // into the existing node is less than the offset into the virtual node we are - // merging in. In this case, we have to extend the existing node, which - // requires an allocation anyway. - DSNode *DN = NH.getNode(); // Make sure the Offset is up-to-date - if (NH.getOffset() >= SrcNH.getOffset()) { - if (!DN->isNodeCompletelyFolded()) { - // Make sure the destination node is folded if the source node is folded. - if (SN->isNodeCompletelyFolded()) { - DN->foldNodeCompletely(); - DN = NH.getNode(); - } else if (SN->getSize() != DN->getSize()) { - // If the two nodes are of different size, and the smaller node has the - // array bit set, collapse! -#if COLLAPSE_ARRAYS_AGGRESSIVELY - if (SN->getSize() < DN->getSize()) { - if (SN->isArrayNode()) { - DN->foldNodeCompletely(); - DN = NH.getNode(); - } - } else if (DN->isArrayNode()) { - DN->foldNodeCompletely(); - DN = NH.getNode(); - } -#endif - } - - - // FIXME:Add comments. - if(!DN->isArrayNode() && SN->isArrayNode()) { - if(DN->getSize() != 0 && SN->getSize() != 0) { - if((DN->getSize() != SN->getSize() && - (NH.getOffset() != 0 || SrcNH.getOffset() != 0) - && DN->getSize() > SN->getSize())) { - DN->foldNodeCompletely(); - DN = NH.getNode(); - } - } - } - if(!SN->isArrayNode() && DN->isArrayNode()) { - if(DN->getSize() != 0 && SN->getSize() != 0) { - if((DN->getSize() != SN->getSize() && - (NH.getOffset() != 0 || SrcNH.getOffset() != 0) - && DN->getSize() < SN->getSize())) { - DN->foldNodeCompletely(); - DN = NH.getNode(); - } - } - } - - if (SN->isArrayNode() && DN->isArrayNode()) { - if((SN->getSize() != DN->getSize()) && (SN->getSize() != 0) - && DN->getSize() != 0) { - DN->foldNodeCompletely(); - DN = NH.getNode(); - } - } - if (!DN->isNodeCompletelyFolded() && DN->getSize() < SN->getSize()) - DN->growSize(SN->getSize()); - - - // Merge the type entries of the two nodes together... - if (!DN->isNodeCompletelyFolded()) - DN->mergeTypeInfo(SN, NH.getOffset() - SrcNH.getOffset()); - } - - assert(!DN->isDeadNode()); - - // Merge the NodeType information. - DN->mergeNodeFlags(SN->getNodeFlags() & BitsToKeep); - - // Before we start merging outgoing links and updating the scalar map, make - // sure it is known that this is the representative node for the src node. - SCNH = DSNodeHandle(DN, NH.getOffset()-SrcNH.getOffset()); - - // If the source node contains any globals, make sure they end up in the - // scalar map with the correct offset. - if (SN->globals_begin() != SN->globals_end()) { - // Update the globals in the destination node itself. - DN->mergeGlobals(*SN); - - // Update the scalar map for the graph we are merging the source node - // into. - for (DSNode::globals_iterator I = SN->globals_begin(), - E = SN->globals_end(); I != E; ++I) { - const GlobalValue *GV = *I; - const DSNodeHandle &SrcGNH = Src->getNodeForValue(GV); - DSNodeHandle &DestGNH = NodeMap[SrcGNH.getNode()]; - assert(DestGNH.getNode()==NH.getNode() &&"Global mapping inconsistent"); - Dest->getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(), - DestGNH.getOffset()+SrcGNH.getOffset())); - } - NH.getNode()->mergeGlobals(*SN); - } - } else { - // We cannot handle this case without allocating a temporary node. Fall - // back on being simple. - DSNode *NewDN = new DSNode(*SN, Dest, true /* Null out all links */); - NewDN->maskNodeTypes(BitsToKeep); - -#ifndef NDEBUG - unsigned NHOffset = NH.getOffset(); -#endif - NH.mergeWith(DSNodeHandle(NewDN, SrcNH.getOffset())); - -#ifndef NDEBUG - assert(NH.getNode() && - (NH.getOffset() > NHOffset || - (NH.getOffset() == 0 && NH.getNode()->isNodeCompletelyFolded())) && - "Merging did not adjust the offset!"); -#endif - - // Before we start merging outgoing links and updating the scalar map, make - // sure it is known that this is the representative node for the src node. - SCNH = DSNodeHandle(NH.getNode(), NH.getOffset()-SrcNH.getOffset()); - - // If the source node contained any globals, make sure to create entries - // in the scalar map for them! - for (DSNode::globals_iterator I = SN->globals_begin(), - E = SN->globals_end(); I != E; ++I) { - const GlobalValue *GV = *I; - const DSNodeHandle &SrcGNH = Src->getNodeForValue(GV); - DSNodeHandle &DestGNH = NodeMap[SrcGNH.getNode()]; - assert(DestGNH.getNode()==NH.getNode() &&"Global mapping inconsistent"); - assert(SrcGNH.getNode() == SN && "Global mapping inconsistent"); - Dest->getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(), - DestGNH.getOffset()+SrcGNH.getOffset())); - } - } - - // DOUT << "LLVA: mergeWith: " << SN << " becomes " << DN << "\n"; - - // Next, recursively merge all outgoing links as necessary. Note that - // adding these links can cause the destination node to collapse itself at - // any time, and the current node may be merged with arbitrary other nodes. - // For this reason, we must always go through NH. - DN = 0; - for (DSNode::const_edge_iterator ii = SN->edge_begin(), ee = SN->edge_end(); - ii != ee; ++ii) { - const DSNodeHandle &SrcEdge = ii->second; - if (!SrcEdge.isNull()) { - // Compute the offset into the current node at which to - // merge this link. In the common case, this is a linear - // relation to the offset in the original node (with - // wrapping), but if the current node gets collapsed due to - // recursive merging, we must make sure to merge in all remaining - // links at offset zero. - DSNode *CN = SCNH.getNode(); - unsigned MergeOffset = (ii->first+SCNH.getOffset()) % CN->getSize(); - - DSNodeHandle Tmp = CN->getLink(MergeOffset); - if (!Tmp.isNull()) { - // Perform the recursive merging. Make sure to create a temporary NH, - // because the Link can disappear in the process of recursive merging. - merge(Tmp, SrcEdge); - } else { - Tmp.mergeWith(getClonedNH(SrcEdge)); - // Merging this could cause all kinds of recursive things to happen, - // culminating in the current node being eliminated. Since this is - // possible, make sure to reaquire the link from 'CN'. - - unsigned MergeOffset = 0; - CN = SCNH.getNode(); - MergeOffset = (ii->first + SCNH.getOffset()) % CN->getSize(); - CN->getLink(MergeOffset).mergeWith(Tmp); - } - } - } -} - -/// mergeCallSite - Merge the nodes reachable from the specified src call -/// site into the nodes reachable from DestCS. -void ReachabilityCloner::mergeCallSite(DSCallSite &DestCS, - const DSCallSite &SrcCS) { - merge(DestCS.getRetVal(), SrcCS.getRetVal()); - merge(DestCS.getVAVal(), SrcCS.getVAVal()); - unsigned MinArgs = DestCS.getNumPtrArgs(); - if (SrcCS.getNumPtrArgs() < MinArgs) MinArgs = SrcCS.getNumPtrArgs(); - - for (unsigned a = 0; a != MinArgs; ++a) { - DSMonitor M; - CallSite CS = SrcCS.getCallSite(); - Function* F = CS.getCalledFunction(); - std::string name = F ? F->getName() : "(unknown)"; - unsigned b = 0; - for (unsigned i=0, j=0; i(CS.getArgument(i)->getType())) - if (j++ == a) { - b = i; - break; - } - - M.watch(DestCS.getPtrArg(a), {SrcCS.getCallSite().getArgument(b)}, - "unable to merge call-site arguments with parameters to function " - + name - ); - merge(DestCS.getPtrArg(a), SrcCS.getPtrArg(a)); - M.check(); - } - - for (unsigned a = MinArgs, e = SrcCS.getNumPtrArgs(); a != e; ++a) { - // If a call site passes more params, ignore the extra params. - // If the called function is varargs, merge the extra params, with - // the varargs node. - if(DestCS.getVAVal() != NULL) { - merge(DestCS.getVAVal(), SrcCS.getPtrArg(a)); - } - } - - for (unsigned a = MinArgs, e = DestCS.getNumPtrArgs(); a!=e; ++a) { - // If a call site passes less explicit params, than the function needs - // But passes params through a varargs node, merge those in. - if(SrcCS.getVAVal() != NULL) { - merge(DestCS.getPtrArg(a), SrcCS.getVAVal()); - } - } -} - -DSCallSite ReachabilityCloner::cloneCallSite(const DSCallSite& SrcCS) { - std::vector Args; - for(unsigned x = 0; x < SrcCS.getNumPtrArgs(); ++x) - Args.push_back(getClonedNH(SrcCS.getPtrArg(x))); - if (SrcCS.isDirectCall()) - return DSCallSite(SrcCS.getCallSite(), - getClonedNH(SrcCS.getRetVal()), - getClonedNH(SrcCS.getVAVal()), - SrcCS.getCalleeFunc(), - Args); - else { - DSNodeHandle Ret = getClonedNH(SrcCS.getRetVal()), - VA = getClonedNH(SrcCS.getVAVal()), - Callee = getClonedNH(SrcCS.getCalleeNode()); - // Resolve forwarding now as much as possible. - Ret.getNode(); VA.getNode(); - // Most importantly, ensure the node passed to DSCallSite - // is not a forwarding node: - DSNode * CalleeN = Callee.getNode(); - return DSCallSite(SrcCS.getCallSite(), Ret, VA, CalleeN, Args); - } -} - -//===----------------------------------------------------------------------===// -// DSCallSite Implementation -//===----------------------------------------------------------------------===// - -// Define here to avoid including iOther.h and BasicBlock.h in DSGraph.h -const Function &DSCallSite::getCaller() const { - return *Site.getInstruction()->getParent()->getParent(); -} - -void DSCallSite::InitNH(DSNodeHandle &NH, const DSNodeHandle &Src, - ReachabilityCloner &RC) { - NH = RC.getClonedNH(Src); -} - -/// FunctionTypeOfCallSite - Helper method to extract the signature of a function -/// that is called a given CallSite -/// -const FunctionType *DSCallSite::FunctionTypeOfCallSite(const CallSite & Site) { - Value *Callee = Site.getCalledValue(); - - // Direct call, simple - if (Function *F = dyn_cast(Callee)) - return F->getFunctionType(); - - // Indirect call, extract the type - const FunctionType *CalleeFuncType = NULL; - - const PointerType *CalleeType = dyn_cast(Callee->getType()); - if (!CalleeType) { - llvm_unreachable("Call through a non-pointer type?"); - } else { - CalleeFuncType = dyn_cast(CalleeType->getElementType()); - assert(CalleeFuncType && - "Call through pointer to non-function?"); - } - - return CalleeFuncType; -} - -/// isVarArg - Determines if the call this represents is to a variable argument -/// function -/// -bool DSCallSite::isVarArg() const { - const FunctionType *FT = FunctionTypeOfCallSite(Site); - return FT->isVarArg(); -} - -/// isUnresolvable - Determines if this call has properties that would -/// prevent it from ever being resolvded. Put another way, no amount -/// additional information will make this callsite resolvable. -/// -bool DSCallSite::isUnresolvable() const { - // Direct calls are forever unresolvable if they are calls to declarations. - if (isDirectCall()) - return getCalleeFunc()->isDeclaration(); - // Indirect calls are forever unresolvable if the call node is marked - // external. - // (Nodes can't become non-external through additional information) - return getCalleeNode()->isExternFuncNode(); -} - -/// remapLinks - Change all of the Links in the current node according to the -/// specified mapping. -/// -void DSNode::remapLinks(DSGraph::NodeMapTy &OldNodeMap) { - for (LinkMapTy::iterator ii = edge_begin(), ee = edge_end(); - ii != ee; ++ii) - if (DSNode *N = ii->second.getNode()) { - DSGraph::NodeMapTy::const_iterator ONMI = OldNodeMap.find(N); - if (ONMI != OldNodeMap.end()) { - DSNode *ONMIN = ONMI->second.getNode(); - ii->second.setTo(ONMIN, ii->second.getOffset()+ONMI->second.getOffset()); - } - } -} - -/// markReachableNodes - This method recursively traverses the specified -/// DSNodes, marking any nodes which are reachable. All reachable nodes it adds -/// to the set, which allows it to only traverse visited nodes once. -/// -void DSNode::markReachableNodes(DenseSet &ReachableNodes) const { - // warning: 'this' pointer cannot be null in well-defined C++ code; - // comparison may be assumed to always evaluate to false - // [-Wtautological-undefined-compare] - if (this == ((void*) 0)) return; - assert(!isForwarding() && "Cannot mark a forwarded node!"); - if (ReachableNodes.insert(this).second) // Is newly reachable? - for (DSNode::const_edge_iterator I = edge_begin(), E = edge_end(); - I != E; ++I) - I->second.getNode()->markReachableNodes(ReachableNodes); -} - -void DSCallSite::markReachableNodes(DenseSet &Nodes) const { - getRetVal().getNode()->markReachableNodes(Nodes); - getVAVal().getNode()->markReachableNodes(Nodes); - if (isIndirectCall()) getCalleeNode()->markReachableNodes(Nodes); - - for (unsigned i = 0, e = getNumPtrArgs(); i != e; ++i) - getPtrArg(i).getNode()->markReachableNodes(Nodes); -} - -//////////////////////////////////////////////////////////////////////////////// -//Base DataStructures impl: -//////////////////////////////////////////////////////////////////////////////// - - static const Function *getFnForValue(const Value *V) { - if (const Instruction *I = dyn_cast(V)) - return I->getParent()->getParent(); - else if (const Argument *A = dyn_cast(V)) - return A->getParent(); - else if (const BasicBlock *BB = dyn_cast(V)) - return BB->getParent(); - return 0; - } - -/// deleteValue/copyValue - Interfaces to update the DSGraphs in the program. -/// These correspond to the interfaces defined in the AliasAnalysis class. -/// FIXME: Do these update all the datastructures needed? -/// FIXME: What exactly does it mean to tell DSA to 'copy' a value? or delete it? (particularly a function) -void DataStructures::deleteValue(Value *V) { - if (const Function *F = getFnForValue(V)) { // Function local value? - // If this is a function local value, just delete it from the scalar map! - getDSGraph(*F)->getScalarMap().eraseIfExists(V); - return; - } - - if (Function *F = dyn_cast(V)) { - DSGraph *G = getDSGraph(*F); - if (G->getReturnNodes().size() == 1) { - // If this is function is part of its own SCC, just delete the graph for it - delete G; - DSInfo.erase(F); - } else { - // SCC case - - // Remove some of the graph's information about this function since it's no longer needed - G->getReturnNodes().erase(F); - G->getVANodes().erase(F); - - // Remove entry for the function, but don't delete the graph since others need it - DSInfo.erase(F); - - // FIXME: Can more be done here? Is there a good way to remove from the SCC's graph more - // of the information this function contributed? - - } - - return; - } - - assert(!isa(V) && "Do not know how to delete GV's yet!"); - - llvm_unreachable("Unrecognized value!"); - abort(); -} - -void DataStructures::copyValue(Value *From, Value *To) { - if (From == To) return; - if (const Function *F = getFnForValue(From)) { // Function local value? - // If this is a function local value, just delete it from the scalar map! - getDSGraph(*F)->getScalarMap().copyScalarIfExists(From, To); - return; - } - - if (Function *FromF = dyn_cast(From)) { - Function *ToF = cast(To); - assert(!DSInfo.count(ToF) && "New Function already exists!"); - DSGraph *G = getDSGraph(*FromF); - if (G->getReturnNodes().size() == 1) { - // Copy a single function by duplicating its dsgraph - - DSGraph *NG = new DSGraph(getDSGraph(*FromF), GlobalECs, *TypeSS); - DSInfo[ToF] = NG; - - // Change the Function* is the returnnodes map to the ToF. - DSNodeHandle Ret = NG->retnodes_begin()->second; - NG->getReturnNodes().clear(); - NG->getReturnNodes()[ToF] = Ret; - - // Change the Function* in the vanodes map to the ToF - DSNodeHandle VA = NG->vanodes_begin()->second; - NG->getVANodes().clear(); - NG->getVANodes()[ToF] = VA; - } else { - // A copy request on a function that's part of an SCC, we just map the new function to the same information - - // G is the graph for ToF as well (add it to the SCC) - setDSGraph(*ToF,G); - - // Map ToF to the same return/va nodes as FromF - G->getReturnNodes()[ToF] = G->getReturnNodes()[FromF]; - G->getVANodes()[ToF] = G->getVANodes()[FromF]; - } - - return; - } - - if (const Function *F = getFnForValue(To)) { - getDSGraph(*F)->getScalarMap().copyScalarIfExists(From, To); - return; - } - - errs() << *From; - errs() << *To; - llvm_unreachable("Do not know how to copy this yet!"); - abort(); -} - -DSGraph* DataStructures::getOrCreateGraph(const Function* F) { - assert(F && "No function"); - DSGraph *&G = DSInfo[F]; - if (!G) { - assert (F->isDeclaration() || GraphSource->hasDSGraph(*F)); - //Clone or Steal the Source Graph - DSGraph* BaseGraph = GraphSource->getDSGraph(*F); - if (Clone) { - G = new DSGraph(BaseGraph, GlobalECs, *TypeSS); - if (resetAuxCalls) - G->getAuxFunctionCalls() = G->getFunctionCalls(); - } else { - G = new DSGraph(GlobalECs, GraphSource->getDataLayout(), *TypeSS); - G->spliceFrom(BaseGraph); - if (resetAuxCalls) - G->getAuxFunctionCalls() = G->getFunctionCalls(); - } - G->setUseAuxCalls(); - G->setGlobalsGraph(GlobalsGraph); - - // Note that this graph is the graph for ALL of the function in the SCC, not - // just F. - for (DSGraph::retnodes_iterator RI = G->retnodes_begin(), - E = G->retnodes_end(); RI != E; ++RI) - if (RI->first != F) - DSInfo[RI->first] = G; - } - return G; -} - -void DataStructures::formGlobalFunctionList() { - std::vector List; - DSScalarMap &SN = GlobalsGraph->getScalarMap(); - EquivalenceClasses &EC = GlobalsGraph->getGlobalECs(); - for (DSScalarMap::global_iterator I = SN.global_begin(), E = SN.global_end(); I != E; ++I) { - EquivalenceClasses::iterator ECI = EC.findValue(*I); - if (ECI == EC.end()) { - if (const Function *F = dyn_cast(*I)) - List.push_back(F); - } else { - for (EquivalenceClasses::member_iterator MI = - EC.member_begin(ECI), ME = EC.member_end(); MI != ME; ++MI){ - if (const Function *F = dyn_cast(*MI)) - List.push_back(F); - } - } - } - GlobalFunctionList.swap(List); -} - - -void DataStructures::formGlobalECs() { - // Grow the equivalence classes for the globals to include anything that we - // now know to be aliased. - svset ECGlobals; - buildGlobalECs(ECGlobals); - if (!ECGlobals.empty()) { - SDEBUG(errs() << "Eliminating " << ECGlobals.size() << " EC Globals!\n"); - for (DSInfoTy::iterator I = DSInfo.begin(), - E = DSInfo.end(); I != E; ++I) - eliminateUsesOfECGlobals(*I->second, ECGlobals); - } -} - -/// BuildGlobalECs - Look at all of the nodes in the globals graph. If any node -/// contains multiple globals, DSA will never, ever, be able to tell the globals -/// apart. Instead of maintaining this information in all of the graphs -/// throughout the entire program, store only a single global (the "leader") in -/// the graphs, and build equivalence classes for the rest of the globals. -void DataStructures::buildGlobalECs(svset &ECGlobals) { - DSScalarMap &SM = GlobalsGraph->getScalarMap(); - EquivalenceClasses &GlobalECs = SM.getGlobalECs(); - for (DSGraph::node_iterator I = GlobalsGraph->node_begin(), - E = GlobalsGraph->node_end(); - I != E; ++I) { - if (I->numGlobals() <= 1) continue; - - // First, build up the equivalence set for this block of globals. - DSNode::globals_iterator i = I->globals_begin(); - const GlobalValue *First = *i; - if (GlobalECs.findValue(*i) != GlobalECs.end()) - First = GlobalECs.getLeaderValue(*i); - if (*i == First) ++i; - for( ; i != I->globals_end(); ++i) { - GlobalECs.unionSets(First, *i); - ECGlobals.insert(*i); - if (SM.find(*i) != SM.end()) - SM.erase(SM.find(*i)); - else - errs() << "Global missing in scalar map " << (*i)->getName() << "\n"; - } - - // Next, get the leader element. - assert(First == GlobalECs.getLeaderValue(First) && - "First did not end up being the leader?"); - - // Finally, change the global node to only contain the leader. - I->clearGlobals(); - I->addGlobal(First); - } - - SDEBUG(GlobalsGraph->AssertGraphOK()); -} - -/// EliminateUsesOfECGlobals - Once we have determined that some globals are in -/// really just equivalent to some other globals, remove the globals from the -/// specified DSGraph (if present), and merge any nodes with their leader nodes. -void DataStructures::eliminateUsesOfECGlobals(DSGraph &G, - const svset &ECGlobals) { - DSScalarMap &SM = G.getScalarMap(); - EquivalenceClasses &GlobalECs = SM.getGlobalECs(); - -#ifndef NDEBUG - bool MadeChange = false; -#endif - std::vector SMGVV(SM.global_begin(), SM.global_end()); - - for (std::vector::iterator GI = SMGVV.begin(), - E = SMGVV.end(); GI != E; ) { - const GlobalValue *GV = *GI; ++GI; - if (!ECGlobals.count(GV)) continue; - - const DSNodeHandle &GVNH = SM[GV]; - assert(!GVNH.isNull() && "Global has null NH!?"); - - // Okay, this global is in some equivalence class. Start by finding the - // leader of the class. - const GlobalValue *Leader = GlobalECs.getLeaderValue(GV); - - // If the leader isn't already in the graph, insert it into the node - // corresponding to GV. - if (!SM.global_count(Leader)) { - GVNH.getNode()->addGlobal(Leader); - SM[Leader] = GVNH; - } else { - // Otherwise, the leader is in the graph, make sure the nodes are the - // merged in the specified graph. - const DSNodeHandle &LNH = SM[Leader]; - if (LNH.getNode() != GVNH.getNode()) - LNH.mergeWith(GVNH); - } - - // Next step, remove the global from the DSNode. - GVNH.getNode()->removeGlobal(GV); - - // Finally, remove the global from the ScalarMap. - SM.erase(GV); -#ifndef NDEBUG - MadeChange = true; -#endif - } - - SDEBUG(if(MadeChange) G.AssertGraphOK()); -} - -//For Entry Points -void DataStructures::cloneGlobalsInto(DSGraph* Graph, unsigned cloneFlags) { - // If this graph contains main, copy the contents of the globals graph over. - // Note that this is *required* for correctness. If a callee contains a use - // of a global, we have to make sure to link up nodes due to global-argument - // bindings. - const DSGraph* GG = Graph->getGlobalsGraph(); - ReachabilityCloner RC(Graph, GG, cloneFlags); - - // Clone the global nodes into this graph. - for (DSScalarMap::global_iterator I = Graph->getScalarMap().global_begin(), - E = Graph->getScalarMap().global_end(); I != E; ++I) - RC.getClonedNH(GG->getNodeForValue(*I)); -} - -//For all graphs -void DataStructures::cloneIntoGlobals(DSGraph* Graph, unsigned cloneFlags) { - // When this graph is finalized, clone the globals in the graph into the - // globals graph to make sure it has everything, from all graphs. - DSScalarMap &MainSM = Graph->getScalarMap(); - ReachabilityCloner RC(GlobalsGraph, Graph, cloneFlags); - - // Clone everything reachable from globals in the function graph into the - // globals graph. - for (DSScalarMap::global_iterator I = MainSM.global_begin(), - E = MainSM.global_end(); I != E; ++I) - RC.getClonedNH(MainSM[*I]); -} - - -void DataStructures::init(DataStructures* D, bool clone, bool useAuxCalls, - bool copyGlobalAuxCalls, bool resetAux) { - assert (!GraphSource && "Already init"); - GraphSource = D; - Clone = clone; - resetAuxCalls = resetAux; - TD = D->TD; - TypeSS = D->TypeSS; - callgraph = D->callgraph; - GlobalFunctionList = D->GlobalFunctionList; - GlobalECs = D->getGlobalECs(); - GlobalsGraph = new DSGraph(D->getGlobalsGraph(), GlobalECs, *TypeSS, - copyGlobalAuxCalls? DSGraph::CloneAuxCallNodes - :DSGraph::DontCloneAuxCallNodes); - if (useAuxCalls) GlobalsGraph->setUseAuxCalls(); - - // - // Tell the other DSA pass if we're stealing its graph. - // - if (!clone) D->DSGraphsStolen = true; -} - -void DataStructures::init(const DataLayout* T) { - assert (!TD && "Already init"); - GraphSource = 0; - Clone = false; - TD = T; - TypeSS = new SuperSet(); - GlobalsGraph = new DSGraph(GlobalECs, *T, *TypeSS); -} - -// CBU has the correct call graph. All the passes that follow it -// must resotre the call graph, at the end, so that it it correct. -// This is simpler than keeping all the CBU data structures around. -// EQBU and subsequent passes must call this. -void DataStructures::restoreCorrectCallGraph(){ - callgraph = GraphSource->callgraph; -} - -void DataStructures::releaseMemory() { - // - // If the DSGraphs were stolen by another pass, free nothing. - // - if (DSGraphsStolen) return; - - std::set toDelete; - for (DSInfoTy::iterator I = DSInfo.begin(), E = DSInfo.end(); I != E; ++I) { - I->second->getReturnNodes().clear(); - toDelete.insert(I->second); - } - for (std::set::iterator I = toDelete.begin(), E = toDelete.end(); I != E; ++I) - delete *I; - - // Empty map so next time memory is released, data structures are not - // re-deleted. - DSInfo.clear(); - - delete GlobalsGraph; - GlobalsGraph = 0; -} diff --git a/lib/DSA/DataStructureStats.cpp b/lib/DSA/DataStructureStats.cpp deleted file mode 100644 index 997f24b5d..000000000 --- a/lib/DSA/DataStructureStats.cpp +++ /dev/null @@ -1,245 +0,0 @@ -//===- DataStructureStats.cpp - Various statistics for DS Graphs ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines a little pass that prints out statistics for DS Graphs. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "DSStats" -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" -#include "dsa/TypeSafety.h" - -#include "llvm/IR/Constants.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/InstVisitor.h" -#include "llvm/Pass.h" -#include "llvm/ADT/Statistic.h" -#include "smack/Debug.h" -#include "llvm/Support/FormattedStream.h" - -#include -using namespace llvm; - -namespace { - STATISTIC (TotalNumCallees, - "Total number of callee functions at all indirect call sites"); - STATISTIC (NumIndirectCalls, - "Total number of indirect call sites in the program"); - - // Typed/Untyped memory accesses: If DSA can infer that the types the loads - // and stores are accessing are correct (ie, the node has not been collapsed), - // increment the appropriate counter. - STATISTIC (NumTypedMemAccesses, - "Number of loads/stores which are fully typed"); - STATISTIC (NumUntypedMemAccesses, - "Number of loads/stores which are untyped"); - STATISTIC (NumTypeCount0Accesses, - "Number of loads/stores which are access a DSNode with 0 type"); - STATISTIC (NumTypeCount1Accesses, - "Number of loads/stores which are access a DSNode with 1 type"); - STATISTIC (NumTypeCount2Accesses, - "Number of loads/stores which are access a DSNode with 2 type"); - STATISTIC (NumTypeCount3Accesses, - "Number of loads/stores which are access a DSNode with 3 type"); - STATISTIC (NumTypeCount4Accesses, - "Number of loads/stores which are access a DSNode with >3 type"); - STATISTIC (NumIncompleteAccesses, - "Number of loads/stores which are on incomplete nodes"); - STATISTIC (NumUnknownAccesses, - "Number of loads/stores which are on unknown nodes"); - STATISTIC (NumExternalAccesses, - "Number of loads/stores which are on external nodes"); - STATISTIC (NumI2PAccesses, - "Number of loads/stores which are on inttoptr nodes"); - STATISTIC (NumFoldedAccess, - "Number of loads/stores which are on folded nodes"); - - class DSGraphStats : public FunctionPass, public InstVisitor { - void countCallees(const Function &F); - const TDDataStructures *DS; - const DataLayout *TD; - const DSGraph *TDGraph; - dsa::TypeSafety *TS; - DSNodeHandle getNodeHandleForValue(Value *V); - bool isNodeForValueUntyped(Value *V, unsigned offset, const Function *); - public: - static char ID; - DSGraphStats() : FunctionPass(ID) {} - - /// Driver functions to compute the Load/Store Dep. Graph per function. - bool runOnFunction(Function& F); - - /// getAnalysisUsage - This modify nothing, and uses the Top-Down Graph. - void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - AU.addRequired(); - AU.addRequired >(); - } - - void visitLoad(LoadInst &LI); - void visitStore(StoreInst &SI); - - /// Debugging support methods - void print(llvm::raw_ostream &O, const Module* = 0) const { } - }; - - static RegisterPass Z("dsstats", "DS Graph Statistics"); -} - -char DSGraphStats::ID; - -FunctionPass *llvm::createDataStructureStatsPass() { - return new DSGraphStats(); -} - - -static bool isIndirectCallee(Value *V) { - if (isa(V)) return false; - - if (CastInst *CI = dyn_cast(V)) - return isIndirectCallee(CI->getOperand(0)); - - if (ConstantExpr *CE = dyn_cast(V)) - if (CE->isCast()) - return isIndirectCallee(CE->getOperand(0)); - - if (GlobalAlias *GA = dyn_cast(V)) { - return isIndirectCallee(GA->getAliasee()); - } - return true; -} - - -void DSGraphStats::countCallees(const Function& F) { - const DSCallGraph callgraph = DS->getCallGraph(); - unsigned numIndirectCalls = 0, totalNumCallees = 0; - - for (DSGraph::fc_iterator I = TDGraph->fc_begin(), E = TDGraph->fc_end(); - I != E; ++I) - if (isIndirectCallee(I->getCallSite().getCalledValue())) { - // This is an indirect function call - std::vector Callees; - callgraph.addFullFunctionList(I->getCallSite(), Callees); - - if (Callees.size() > 0) { - totalNumCallees += Callees.size(); - ++numIndirectCalls; - } else { - SDEBUG(errs() << "WARNING: No callee in Function '" - << F.getName().str() << " at call: \n" - << *I->getCallSite().getInstruction()); - } - } - - TotalNumCallees += totalNumCallees; - NumIndirectCalls += numIndirectCalls; - - if (numIndirectCalls) { - SDEBUG(errs() << " In function " << F.getName() << ": " - << (totalNumCallees / (double) numIndirectCalls) - << " average callees per indirect call\n"); - } -} - -DSNodeHandle DSGraphStats::getNodeHandleForValue(Value *V) { - const DSGraph *G = TDGraph; - const DSGraph::ScalarMapTy &ScalarMap = G->getScalarMap(); - DSGraph::ScalarMapTy::const_iterator I = ScalarMap.find(V); - if (I != ScalarMap.end()) - return I->second; - - G = TDGraph->getGlobalsGraph(); - const DSGraph::ScalarMapTy &GlobalScalarMap = G->getScalarMap(); - I = GlobalScalarMap.find(V); - if (I != GlobalScalarMap.end()) - return I->second; - - return 0; -} - -bool DSGraphStats::isNodeForValueUntyped(Value *V, unsigned Offset, const Function *F) { - DSNodeHandle NH = getNodeHandleForValue(V); - if(!NH.getNode()){ - return true; - } - else { - DSNode *N = NH.getNode(); - if (N->isNodeCompletelyFolded()){ - ++NumFoldedAccess; - return true; - } - if ( N->isExternalNode()){ - ++NumExternalAccesses; - return true; - } - if ( N->isIncompleteNode()){ - ++NumIncompleteAccesses; - return true; - } - if (N->isUnknownNode()){ - ++NumUnknownAccesses; - return true; - } - if (N->isIntToPtrNode()){ - ++NumI2PAccesses; - return true; - } - // it is a complete node, now check how many types are present - int count = 0; - unsigned offset = NH.getOffset() + Offset; - if (N->type_begin() != N->type_end()) - for (DSNode::TyMapTy::const_iterator ii = N->type_begin(), - ee = N->type_end(); ii != ee; ++ii) { - if(ii->first != offset) - continue; - count += ii->second->size(); - } - - if (count ==0) - ++NumTypeCount0Accesses; - else if(count == 1) - ++NumTypeCount1Accesses; - else if(count == 2) - ++NumTypeCount2Accesses; - else if(count == 3) - ++NumTypeCount3Accesses; - else - ++NumTypeCount4Accesses; - SDEBUG(assert(TS->isTypeSafe(V,F))); - } - return false; -} - -void DSGraphStats::visitLoad(LoadInst &LI) { - if (isNodeForValueUntyped(LI.getOperand(0), 0,LI.getParent()->getParent())) { - NumUntypedMemAccesses++; - } else { - NumTypedMemAccesses++; - } -} - -void DSGraphStats::visitStore(StoreInst &SI) { - if (isNodeForValueUntyped(SI.getOperand(1), 0,SI.getParent()->getParent())) { - NumUntypedMemAccesses++; - } else { - NumTypedMemAccesses++; - } -} - -bool DSGraphStats::runOnFunction(Function& F) { - DS = &getAnalysis(); - TD = &F.getParent()->getDataLayout(); - TS = &getAnalysis >(); - TDGraph = DS->getDSGraph(F); - countCallees(F); - visit(F); - return false; -} diff --git a/lib/DSA/EntryPointAnalysis.cpp b/lib/DSA/EntryPointAnalysis.cpp deleted file mode 100644 index 07399e6b4..000000000 --- a/lib/DSA/EntryPointAnalysis.cpp +++ /dev/null @@ -1,102 +0,0 @@ -//===-- EntryPointAnalysis.cpp - Entry point Finding Pass -----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a general way of finding entry points in a system. Simple programs -// will use the main version. Libraries and OS kernels can have more -// specialized versions. This is done as an analysis group to allow more -// convinient opt invocations. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Pass.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Function.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FormattedStream.h" -#include "smack/Debug.h" - -#include -#include - -#include "dsa/EntryPointAnalysis.h" - -using namespace llvm; - -static cl::opt epaFile("epa-file", - cl::desc("File with entry point names")); //, cl::ReallyHidden); - -static void readNames(std::set& names) { - std::ifstream msf(epaFile.c_str(), std::ifstream::in); - if (!msf.good()) - errs() << "Failed to open file: " << epaFile << " (continuing anyway)\n"; - while (msf.good()) { - std::string n; - msf >> n; - if (n.size()) { - names.insert(n); -// errs() << "Read " << n << "\n"; - } - } -} - - -EntryPointAnalysis::EntryPointAnalysis() :ModulePass(ID), haveNames(false) { -} - -EntryPointAnalysis::~EntryPointAnalysis() {} - -void EntryPointAnalysis::findEntryPoints(const Module& M, - std::vector& dest) const { - for (const Function &F : M) - if (isEntryPoint(&F)) - dest.push_back(&F); -} - -void EntryPointAnalysis::print(llvm::raw_ostream& O, const Module* M) const { - std::vector d; - findEntryPoints(*M, d); - O << "EntryPoints: "; - bool prev = false; - for (std::vector::iterator ii = d.begin(), ee = d.end(); - ii != ee; ++ii) { - O << (prev ? ", " : "") << (*ii)->getName().str(); - prev = true; - } - O << "\n"; -} - -bool EntryPointAnalysis::runOnModule(llvm::Module& M) { - if (epaFile.size()) { - haveNames = true; - readNames(names); - } - return false; -} - -void EntryPointAnalysis::getAnalysisUsage(llvm::AnalysisUsage &AU) const { - AU.setPreservesAll(); -} - -bool EntryPointAnalysis::isEntryPoint(const llvm::Function* F) const { - if (haveNames) { - return !F->isDeclaration() - && F->hasExternalLinkage() - && F->hasName() - && names.find(F->getName().str()) != names.end(); - } else { - return !F->isDeclaration() - && F->hasExternalLinkage() - && F->hasName() && F->getName() == "main"; - } -} - - - -char EntryPointAnalysis::ID; -static RegisterPass A("epa", "Identify EntryPoints"); diff --git a/lib/DSA/EquivClassGraphs.cpp b/lib/DSA/EquivClassGraphs.cpp deleted file mode 100644 index dcc9dcdba..000000000 --- a/lib/DSA/EquivClassGraphs.cpp +++ /dev/null @@ -1,257 +0,0 @@ -//===- EquivClassGraphs.cpp - Merge equiv-class graphs & inline bottom-up -===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass is the same as the complete bottom-up graphs, but -// with functions partitioned into equivalence classes and a single merged -// DS graph for all functions in an equivalence class. After this merging, -// graphs are inlined bottom-up on the SCCs of the final (CBU) call graph. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "ECGraphs" -#include "dsa/DataStructure.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "dsa/DSGraph.h" -#include "llvm/IR/CallSite.h" -#include "smack/Debug.h" -#include "llvm/ADT/SCCIterator.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/ADT/EquivalenceClasses.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/FormattedStream.h" -#include -using namespace llvm; - -namespace { - RegisterPass X("dsa-eq", - "Equivalence-class Bottom-up Data Structure Analysis"); -} -char EquivBUDataStructures::ID = 0; - -// runOnModule - Calculate the bottom up data structure graphs for each function -// in the program. -// -bool EquivBUDataStructures::runOnModule(Module &M) { - init(&getAnalysis(), true, true, false, true); - - //make a list of all the DSGraphs - std::setgraphList; - for(Function &F : M) - { - if(!(F.isDeclaration())) - graphList.insert(getOrCreateGraph(&F)); - } - - //update the EQ class from indirect calls - buildIndirectFunctionSets(); - formGlobalECs(); - mergeGraphsByGlobalECs(); - - //remove all the DSGraph, that still have references - for(Function &F : M) - { - if(!(F.isDeclaration())) - graphList.erase(getOrCreateGraph(&F)); - } - // free memory for the DSGraphs, no longer in use. - for(std::set::iterator i = graphList.begin(),e = graphList.end(); - i!=e;i++) { - delete (*i); - } - SDEBUG(verifyMerging()); - - formGlobalECs(); - - for (Function &F: M) { - if (!(F.isDeclaration())) { - if (DSGraph * Graph = getOrCreateGraph(&F)) { - cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes); - } - } - } - - bool result = runOnModuleInternal(M); - - // CBU contains the correct call graph. - // Restore it, so that subsequent passes and clients can get it. - // TODO (Zvonimir): There is strong indication that EquivBUDataStructures - // in fact produces a (more) correct call graph than CBU. So restoring - // call graph here produces wrong results on a class of SVCOMP benchmarks. - // It also appears that not restoring call graph here does not introduce - // any new issues. - // restoreCorrectCallGraph(); - return result; -} - -// Verifies that all the functions in an equivalence calss have been merged. -// This is required by to be true by poolallocation. -void -EquivBUDataStructures::verifyMerging() { - - EquivalenceClasses::iterator EQSI = GlobalECs.begin(); - EquivalenceClasses::iterator EQSE = GlobalECs.end(); - for (;EQSI != EQSE; ++EQSI) { - if (!EQSI->isLeader()) continue; - EquivalenceClasses::member_iterator MI; - bool first = true; - DSGraph *firstG = 0; - for (MI = GlobalECs.member_begin(EQSI); MI != GlobalECs.member_end(); ++MI){ - if (const Function* F = dyn_cast(*MI)){ - if (F->isDeclaration()) - continue; - - if(first) { - firstG = getOrCreateGraph(F); - first = false; - } - DSGraph *G = getOrCreateGraph(F); - if( G != firstG) { - assert(G == firstG && "all functions in a Global EC do not have a merged graph"); - } - } - } - } -} - -// -// Method: mergeGraphsByGlobalECs() -// -// Description: -// Merge all graphs that are in the same equivalence class. This ensures -// that transforms like Automatic Pool Allocation only see one graph for a -// call site. -// -// After this method is executed, all functions in an equivalence class will -// have the *same* DSGraph. -// -void -EquivBUDataStructures::mergeGraphsByGlobalECs() { - // - // Merge the graphs for each equivalence class. We first scan all elements - // in the equivalence classes and look for those elements which are leaders. - // For each leader, we scan through all of its members and merge the DSGraphs - // for members which are functions. - // - - EquivalenceClasses::iterator EQSI = GlobalECs.begin(); - EquivalenceClasses::iterator EQSE = GlobalECs.end(); - for (;EQSI != EQSE; ++EQSI) { - // - // If this element is not a leader, then skip it. - // - if (!EQSI->isLeader()) continue; - DSGraph* BaseGraph = 0; - std::vector Args; - - // - // Iterate through all members of this equivalence class, looking for - // functions. - // - EquivalenceClasses::member_iterator MI; - for (MI = GlobalECs.member_begin(EQSI); MI != GlobalECs.member_end(); ++MI){ - if (const Function* F = dyn_cast(*MI)) { - // - // If the function has no body, then it has no DSGraph. - // - // FIXME: I don't believe this is correct; the stdlib pass can assign - // DSGraphs to C standard library functions. - // - if (F->isDeclaration()) - continue; - - // - // We have one of three possibilities: - // 1) This is the first function we've seen. If so, grab its DSGraph - // and the DSNodes for its arguments. - // - // 2) We have already seen this function before. Do nothing. - // - // 3) We haven't seen this function before, and it's not the first one - // we've seen. Merge its DSGraph into the DSGraph we're creating. - // - if (!BaseGraph) { - BaseGraph = getOrCreateGraph(F); - BaseGraph->getFunctionArgumentsForCall(F, Args); - } else if (BaseGraph->containsFunction(F)) { - // - // The DSGraph for this function has already been merged into the - // graph that we are creating. However, that does not mean that - // function arguments of this function have been merged with the - // function arguments of the other functions in the equivalence graph - // (or even with functions belonging to the same SCC in the call - // graph). Furthermore, it doesn't necessarily imply that the - // contained function's DSGraph is the same as the one we're - // building; it is possible (I think) for only the function's DSNodes - // and other information to have been merged in. - // - // For these reasons, we will merge the function argument DSNodes and - // set this function's DSGraph to be the same graph used for all - // other function's in this equivalence class. - // - - // - // Merge the arguments together. - // - std::vector NextArgs; - BaseGraph->getFunctionArgumentsForCall(F, NextArgs); - unsigned i = 0, e = Args.size(); - for (; i != e; ++i) { - if (i == NextArgs.size()) break; - Args[i].mergeWith(NextArgs[i]); - } - for (e = NextArgs.size(); i != e; ++i) - Args.push_back(NextArgs[i]); - - // - // Make this function use the DSGraph that we're creating for all of - // the functions in this equivalence class. - // - setDSGraph(*F, BaseGraph); - } else { - // - // Merge in the DSGraph. - // - BaseGraph->cloneInto(getOrCreateGraph(F)); - - // - // Merge the arguments together. - // - std::vector NextArgs; - BaseGraph->getFunctionArgumentsForCall(F, NextArgs); - unsigned i = 0, e = Args.size(); - for (; i != e; ++i) { - if (i == NextArgs.size()) break; - Args[i].mergeWith(NextArgs[i]); - } - for (e = NextArgs.size(); i != e; ++i) - Args.push_back(NextArgs[i]); - - // - // Make this function use the DSGraph that we're creating for all of - // the functions in this equivalence class. - // - setDSGraph(*F, BaseGraph); - } - } - } - - // - // Update the globals graph with any information that has changed due to - // graph merging. - // - if (BaseGraph) - cloneIntoGlobals(BaseGraph, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes | - DSGraph::StripAllocaBit); - } -} - diff --git a/lib/DSA/GraphChecker.cpp b/lib/DSA/GraphChecker.cpp deleted file mode 100644 index 0dafbadba..000000000 --- a/lib/DSA/GraphChecker.cpp +++ /dev/null @@ -1,207 +0,0 @@ -//===- GraphChecker.cpp - Assert that various graph properties hold -------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass is used to test DSA with regression tests. It can be used to check -// that certain graph properties hold, such as two nodes being disjoint, whether -// or not a node is collapsed, etc. These are the command line arguments that -// it supports: -// -// --dsgc-dspass={local,bu,td} - Specify what flavor of graph to check -// --dsgc-abort-if-any-collapsed - Abort if any collapsed nodes are found -// --dsgc-abort-if-collapsed= - Abort if a node pointed to by an SSA -// value with name in is collapsed -// --dsgc-check-flags= - Abort if the specified nodes have flags -// that are not specified. -// --dsgc-abort-if-merged= - Abort if any of the named SSA values -// point to the same node. -// -//===----------------------------------------------------------------------===// - -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/IR/Value.h" -#include -using namespace llvm; - -namespace { - enum DSPass { local, bu, td }; - cl::opt - DSPass("dsgc-dspass", cl::Hidden, - cl::desc("Specify which DSA pass the -datastructure-gc pass should use"), - cl::values(clEnumVal(local, "Local pass"), - clEnumVal(bu, "Bottom-up pass"), - clEnumVal(td, "Top-down pass")), - cl::init(local)); - - cl::opt - AbortIfAnyCollapsed("dsgc-abort-if-any-collapsed", cl::Hidden, - cl::desc("Abort if any collapsed nodes are found")); - cl::list - AbortIfCollapsed("dsgc-abort-if-collapsed", cl::Hidden, cl::CommaSeparated, - cl::desc("Abort if any of the named symbols is collapsed")); - cl::list - CheckFlags("dsgc-check-flags", cl::Hidden, cl::CommaSeparated, - cl::desc("Check that flags are specified for nodes")); - cl::list - AbortIfMerged("dsgc-abort-if-merged", cl::Hidden, cl::CommaSeparated, - cl::desc("Abort if any of the named symbols are merged together")); - - struct DSGC : public FunctionPass { - static char ID; - DSGC(); - bool doFinalization(Module &M); - bool runOnFunction(Function &F); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - switch (DSPass) { - case local: AU.addRequired(); break; - case bu: AU.addRequired(); break; - case td: AU.addRequired(); break; - } - AU.setPreservesAll(); - } - void print(llvm::raw_ostream &O, const Module *M) const {} - - private: - void verify(const DSGraph* G); - }; - - RegisterPass X("datastructure-gc", "DSA Graph Checking Pass"); -} - -char DSGC::ID; - -FunctionPass *llvm::createDataStructureGraphCheckerPass() { - return new DSGC(); -} - - -DSGC::DSGC() : FunctionPass(ID) { - if (!AbortIfAnyCollapsed && AbortIfCollapsed.empty() && - CheckFlags.empty() && AbortIfMerged.empty()) { - errs() << "The -datastructure-gc is useless if you don't specify any" - << " -dsgc-* options. See the -help-hidden output for a list.\n"; - abort(); - } -} - - -/// doFinalization - Verify that the globals graph is in good shape... -/// -bool DSGC::doFinalization(Module &M) { - switch (DSPass) { - case local:verify(getAnalysis().getGlobalsGraph());break; - case bu: verify(getAnalysis().getGlobalsGraph()); break; - case td: verify(getAnalysis().getGlobalsGraph()); break; - } - return false; -} - -/// runOnFunction - Get the DSGraph for this function and verify that it is ok. -/// -bool DSGC::runOnFunction(Function &F) { - switch (DSPass) { - case local: verify(getAnalysis().getDSGraph(F)); break; - case bu: verify(getAnalysis().getDSGraph(F)); break; - case td: verify(getAnalysis().getDSGraph(F)); break; - } - - return false; -} - -/// verify - This is the function which checks to make sure that all of the -/// invariants established on the command line are true. -/// -void DSGC::verify(const DSGraph* G) { - // Loop over all of the nodes, checking to see if any are collapsed... - if (AbortIfAnyCollapsed) { - for (DSGraph::node_const_iterator I = G->node_begin(), E = G->node_end(); - I != E; ++I) - if (I->isNodeCompletelyFolded()) { - errs() << "Node is collapsed: "; - I->print(errs(), G); - abort(); - } - } - - if (!AbortIfCollapsed.empty() || !CheckFlags.empty() || - !AbortIfMerged.empty()) { - // Convert from a list to a set, because we don't have cl::set's yet. FIXME - std::set AbortIfCollapsedS(AbortIfCollapsed.begin(), - AbortIfCollapsed.end()); - std::set AbortIfMergedS(AbortIfMerged.begin(), - AbortIfMerged.end()); - std::map CheckFlagsM; - - for (cl::list::iterator I = CheckFlags.begin(), - E = CheckFlags.end(); I != E; ++I) { - std::string::size_type ColonPos = I->rfind(':'); - if (ColonPos == std::string::npos) { - errs() << "Error: '" << *I - << "' is an invalid value for the --dsgc-check-flags option!\n"; - abort(); - } - - unsigned Flags = 0; - for (unsigned C = ColonPos+1; C != I->size(); ++C) - switch ((*I)[C]) { - case 'S': Flags |= DSNode::AllocaNode; break; - case 'H': Flags |= DSNode::HeapNode; break; - case 'G': Flags |= DSNode::GlobalNode; break; - case 'U': Flags |= DSNode::UnknownNode; break; - case 'I': Flags |= DSNode::IncompleteNode; break; - case 'M': Flags |= DSNode::ModifiedNode; break; - case 'R': Flags |= DSNode::ReadNode; break; - case 'A': Flags |= DSNode::ArrayNode; break; - default: errs() << "Invalid DSNode flag!\n"; abort(); - } - CheckFlagsM[std::string(I->begin(), I->begin()+ColonPos)] = Flags; - } - - // Now we loop over all of the scalars, checking to see if any are collapsed - // that are not supposed to be, or if any are merged together. - const DSGraph::ScalarMapTy &SM = G->getScalarMap(); - std::map AbortIfMergedNodes; - - for (DSGraph::ScalarMapTy::const_iterator I = SM.begin(), E = SM.end(); - I != E; ++I) - if (I->first->hasName() && I->second.getNode()) { - const std::string &Name = I->first->getName(); - DSNode *N = I->second.getNode(); - - // Verify it is not collapsed if it is not supposed to be... - if (N->isNodeCompletelyFolded() && AbortIfCollapsedS.count(Name)) { - errs() << "Node for value '%" << Name << "' is collapsed: "; - N->print(errs(), G); - abort(); - } - - if (CheckFlagsM.count(Name) && CheckFlagsM[Name] != N->getNodeFlags()) { - errs() << "Node flags are not as expected for node: " << Name - << " (" << CheckFlagsM[Name] << ":" <getNodeFlags() - << ")\n"; - N->print(errs(), G); - abort(); - } - - // Verify that it is not merged if it is not supposed to be... - if (AbortIfMergedS.count(Name)) { - if (AbortIfMergedNodes.count(N)) { - errs() << "Nodes for values '%" << Name << "' and '%" - << AbortIfMergedNodes[N] << "' is merged: "; - N->print(errs(), G); - abort(); - } - AbortIfMergedNodes[N] = Name; - } - } - } -} diff --git a/lib/DSA/LICENSE b/lib/DSA/LICENSE deleted file mode 100644 index dba02fa23..000000000 --- a/lib/DSA/LICENSE +++ /dev/null @@ -1,65 +0,0 @@ -============================================================================== -LLVM Pool Allocator Release License -============================================================================== -University of Illinois/NCSA -Open Source License - -Copyright (c) 2003-2013 University of Illinois at Urbana-Champaign. -All rights reserved. - -Developed by: - - LLVM Team - - University of Illinois at Urbana-Champaign - - http://llvm.cs.uiuc.edu - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE -SOFTWARE. - -============================================================================== -Copyrights and Licenses for Third Party Software Distributed with LLVM: -============================================================================== -The Automatic Pool Allocation software contains code written by third parties. -Such software will have its own individual LICENSE.TXT file in the directory in -which it appears. This file will describe the copyrights, license, and -restrictions which apply to that code. - -The disclaimer of warranty in the University of Illinois Open Source License -applies to all code in this distribution, and nothing in any of the -other licenses gives permission to use the names of the LLVM Team or the -University of Illinois to endorse or promote products derived from this -Software. - -The following pieces of software have additional or alternate copyrights, -licenses, and/or restrictions: - -Program Directory -------- --------- -Watchdog poolalloc/tools/WatchDog - diff --git a/lib/DSA/Local.cpp b/lib/DSA/Local.cpp deleted file mode 100644 index 06f372e16..000000000 --- a/lib/DSA/Local.cpp +++ /dev/null @@ -1,1592 +0,0 @@ -//===- Local.cpp - Compute a local data structure graph for a function ----===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Compute the local version of the data structure graph for a function. The -// external interface to this file is the DSGraph constructor. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "dsa-local" - -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" -#include "dsa/DSMonitor.h" - -#include "llvm/ADT/Statistic.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/Triple.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/InlineAsm.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Use.h" -#include "llvm/Support/CommandLine.h" -#include "smack/Debug.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/IR/GetElementPtrTypeIterator.h" -#include "llvm/IR/InstVisitor.h" -#include "llvm/Support/Timer.h" - -#include - -// FIXME: This should eventually be a FunctionPass that is automatically -// aggregated into a Pass. -// -#include "llvm/IR/Module.h" - -using namespace llvm; - -namespace { -STATISTIC(NumDirectCall, "Number of direct calls added"); -STATISTIC(NumIndirectCall, "Number of indirect calls added"); -STATISTIC(NumAsmCall, "Number of asm calls collapsed/seen"); -STATISTIC(NumIntrinsicCall, "Number of intrinsics called"); -STATISTIC(NumBoringIntToPtr, "Number of inttoptr used only in cmp"); -//STATISTIC(NumSimpleIntToPtr, "Number of inttoptr from ptrtoint"); -STATISTIC(NumIgnoredInst, "Number of instructions ignored"); - -RegisterPass -X("dsa-local", "Local Data Structure Analysis"); - -cl::opt hasMagicSections("dsa-magic-sections", - cl::desc("File with section to global mapping")); //, cl::ReallyHidden); -} -cl::opt TypeInferenceOptimize("enable-type-inference-opts", - cl::desc("Enable Type Inference Optimizations added to DSA."), - cl::Hidden, - cl::init(false)); - -namespace { - //===--------------------------------------------------------------------===// - // GraphBuilder Class - //===--------------------------------------------------------------------===// - // - /// This class is the builder class that constructs the local data structure - /// graph by performing a single pass over the function in question. - /// - class GraphBuilder : InstVisitor { - DSGraph &G; - Function* FB; - LocalDataStructures* DS; - const DataLayout& TD; - DSNode *VAArray; - DSMonitor M; - - //////////////////////////////////////////////////////////////////////////// - // Helper functions used to implement the visitation functions... - - void MergeConstantInitIntoNode(DSNodeHandle &NH, Type* Ty, Constant *C); - - /// createNode - Create a new DSNode, ensuring that it is properly added to - /// the graph. - /// - DSNode *createNode() - { - DSNode* ret = new DSNode(&G); - assert(ret->getParentGraph() && "No parent?"); - return ret; - } - - /// setDestTo - Set the ScalarMap entry for the specified value to point to - /// the specified destination. If the Value already points to a node, make - /// sure to merge the two destinations together. - /// - void setDestTo(Value &V, const DSNodeHandle &NH); - - /// getValueDest - Return the DSNode that the actual value points to. - /// - DSNodeHandle getValueDest(Value* V); - - /// getLink - This method is used to return the specified link in the - /// specified node if one exists. If a link does not already exist (it's - /// null), then we create a new node, link it, then return it. - /// - DSNodeHandle &getLink(const DSNodeHandle &Node, unsigned Link = 0); - - //////////////////////////////////////////////////////////////////////////// - // Visitor functions, used to handle each instruction type we encounter... - friend class InstVisitor; - - void visitAllocaInst(AllocaInst &AI) - { setDestTo(AI, createNode()->setAllocaMarker()); } - - //the simple ones - void visitPHINode(PHINode &PN); - void visitSelectInst(SelectInst &SI); - void visitLoadInst(LoadInst &LI); - void visitStoreInst(StoreInst &SI); - void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I); - void visitAtomicRMWInst(AtomicRMWInst &I); - void visitReturnInst(ReturnInst &RI); - void visitVAArgInst(VAArgInst &I); - void visitIntToPtrInst(IntToPtrInst &I); - void visitPtrToIntInst(PtrToIntInst &I); - void visitBitCastInst(BitCastInst &I); - void visitCmpInst(CmpInst &I); - void visitInsertValueInst(InsertValueInst& I); - void visitExtractValueInst(ExtractValueInst& I); - - //the nasty ones - void visitGetElementPtrInst(User &GEP); - void visitCallInst(CallInst &CI); - void visitInvokeInst(InvokeInst &II); - void visitInstruction(Instruction &I); - - bool visitIntrinsic(CallSite CS, Function* F); - void visitCallSite(CallSite CS); - void visitVAStart(CallSite CS); - void visitVAStartNode(DSNode* N); - - public: - GraphBuilder(Function &f, DSGraph &g, LocalDataStructures& DSi) - : G(g), FB(&f), DS(&DSi), TD(g.getDataLayout()), VAArray(0) { - - SDEBUG(errs() << "[local] Building graph for function: " - << f.getName() << "\n"); - - // Create scalar nodes for all pointer arguments... - for (auto &Arg : f.args()) { - if (isa(Arg.getType())) { - // WD: Why do we set the external marker so early in the analysis? - // Functions we have definitions for, but are externally reachable have no external contexts - // that we'd want to BU external information into (since those contexts are by definition - // ones we don't have code for). Shouldn't this just be set in TD? -#if 0 - DSNode * Node = getValueDest(I).getNode(); - - if (!f.hasInternalLinkage() || !f.hasPrivateLinkage()) - Node->setExternalMarker(); -#else - getValueDest(&Arg).getNode(); -#endif - - } - } - - // Create an entry for the return, which tracks which functions are in - // the graph - g.getOrCreateReturnNodeFor(f); - - // Create a node to handle information about variable arguments - g.getOrCreateVANodeFor(f); - - visit(f); // Single pass over the function - - // If there are any constant globals referenced in this function, merge - // their initializers into the local graph from the globals graph. - // This resolves indirect calls in some common cases - // Only merge info for nodes that already exist in the local pass - // otherwise leaf functions could contain less collapsing than the globals - // graph - if (g.getScalarMap().global_begin() != g.getScalarMap().global_end()) { - ReachabilityCloner RC(&g, g.getGlobalsGraph(), 0); - for (DSScalarMap::global_iterator I = g.getScalarMap().global_begin(), - E = g.getScalarMap().global_end(); I != E; ++I) { - if (const GlobalVariable * GV = dyn_cast (*I)) - if (GV->isConstant()) - RC.merge(g.getNodeForValue(GV), g.getGlobalsGraph()->getNodeForValue(GV)); - } - } - - g.markIncompleteNodes(DSGraph::MarkFormalArgs); - - // Compute sources of external - unsigned EFlags = 0 - | DSGraph::DontMarkFormalsExternal - | DSGraph::ProcessCallSites; - - g.computeExternalFlags(EFlags); - g.computeIntPtrFlags(); - - // Remove any nodes made dead due to merging... - g.removeDeadNodes(DSGraph::KeepUnreachableGlobals); - } - - // GraphBuilder ctor for working on the globals graph - explicit GraphBuilder(DSGraph& g, LocalDataStructures& DSi) - :G(g), FB(0), TD(g.getDataLayout()), VAArray(0) - {} - - void mergeInGlobalInitializer(GlobalVariable *GV); - void mergeExternalGlobal(GlobalVariable* GV); - void mergeFunction(Function* F) { getValueDest(F); } - }; - - /// Traverse the whole DSGraph, and propagate the unknown flags through all - /// out edges. - static void propagateUnknownFlag(DSGraph * G) { - std::vector workList; - DenseSet visited; - for (DSGraph::node_iterator I = G->node_begin(), E = G->node_end(); I != E; ++I) - if (I->isUnknownNode()) - workList.push_back(&*I); - - while (!workList.empty()) { - DSNode * N = workList.back(); - workList.pop_back(); - if (visited.count(N) != 0) continue; - visited.insert(N); - N->setUnknownMarker(); - for (DSNode::edge_iterator I = N->edge_begin(), E = N->edge_end(); I != E; ++I) - if (!I->second.isNull()) - workList.push_back(I->second.getNode()); - } - } -} - -//===----------------------------------------------------------------------===// -// Helper method implementations... -// - - -/// -/// getValueDest - Return the DSNode that the actual value points to. -/// -DSNodeHandle GraphBuilder::getValueDest(Value* V) { - if (isa(V) && cast(V)->isNullValue()) - return 0; // Null doesn't point to anything, don't add to ScalarMap! - - DSNodeHandle &NH = G.getNodeForValue(V); - if (!NH.isNull()) - return NH; // Already have a node? Just return it... - - // Otherwise we need to create a new node to point to. - // Check first for constant expressions that must be traversed to - // extract the actual value. - DSNode* N; - if (Function * F = dyn_cast (V)) { - // Create a new global node for this function. - N = createNode(); - N->addFunction(F); - if (F->isDeclaration()) - N->setExternFuncMarker(); - } else if (GlobalValue * GV = dyn_cast (V)) { - // Create a new global node for this global variable. - N = createNode(); - N->addGlobal(GV); - if (GV->isDeclaration()) - N->setExternGlobalMarker(); - } else if (Constant *C = dyn_cast(V)) { - if (ConstantExpr *CE = dyn_cast(C)) { - if (CE->isCast()) { - if (isa(CE->getOperand(0)->getType())) - NH = getValueDest(CE->getOperand(0)); - else - NH = createNode()->setUnknownMarker(); - } else if (CE->getOpcode() == Instruction::GetElementPtr) { - visitGetElementPtrInst(*CE); - assert(G.hasNodeForValue(CE) && "GEP didn't get processed right?"); - NH = G.getNodeForValue(CE); - } else { - // This returns a conservative unknown node for any unhandled ConstExpr - NH = createNode()->setUnknownMarker(); - } - if (NH.isNull()) { // (getelementptr null, X) returns null - G.eraseNodeForValue(V); - return 0; - } - return NH; - } else if (isa(C)) { - G.eraseNodeForValue(V); - return 0; - } else if (isa(C)) { - // XXX: Need more investigation - // According to Andrew, DSA is broken on global aliasing, since it does - // not handle the aliases of parameters correctly. Here is only a quick - // fix for some special cases. - NH = getValueDest(cast(C)->getAliasee()); - return NH; - } else if (isa(C)) { - // - // FIXME: This may not be quite right; we should probably add a - // BlockAddress flag to the DSNode instead of using the unknown flag. - // - N = createNode(); - N->setUnknownMarker(); - } else if (isa(C) || isa(C) || - isa(C) || isa(C) || - isa(C)) { - // Treat these the same way we treat global initializers - N = createNode(); - NH.mergeWith(N); - MergeConstantInitIntoNode(NH, C->getType(), C); - } else { - errs() << "Unknown constant: " << *C << "\n"; - llvm_unreachable("Unknown constant type!"); - } - N = createNode(); // just create a shadow node - } else { - // Otherwise just create a shadow node - N = createNode(); - } - - NH.setTo(N, 0); // Remember that we are pointing to it... - return NH; -} - - -/// getLink - This method is used to return the specified link in the -/// specified node if one exists. If a link does not already exist (it's -/// null), then we create a new node, link it, then return it. We must -/// specify the type of the Node field we are accessing so that we know what -/// type should be linked to if we need to create a new node. -/// -DSNodeHandle &GraphBuilder::getLink(const DSNodeHandle &node, unsigned LinkNo) { - DSNodeHandle &Node = const_cast(node); - DSNodeHandle &Link = Node.getLink(LinkNo); - if (Link.isNull()) { - // If the link hasn't been created yet, make and return a new shadow node - Link = createNode(); - } - return Link; -} - - -/// setDestTo - Set the ScalarMap entry for the specified value to point to the -/// specified destination. If the Value already points to a node, make sure to -/// merge the two destinations together. -/// -void GraphBuilder::setDestTo(Value &V, const DSNodeHandle &NH) { - G.getNodeForValue(&V).mergeWith(NH); -} - - -//===----------------------------------------------------------------------===// -// Specific instruction type handler implementations... -// - -// PHINode - Make the scalar for the PHI node point to all of the things the -// incoming values point to... which effectively causes them to be merged. -// -void GraphBuilder::visitPHINode(PHINode &PN) { - SDEBUG(errs() << "[local] visiting phi node: " << PN.getName() << "\n"); - - if (!isa(PN.getType())) return; // Only pointer PHIs - - DSNodeHandle &PNDest = G.getNodeForValue(&PN); - for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) - PNDest.mergeWith(getValueDest(PN.getIncomingValue(i))); -} - -void GraphBuilder::visitSelectInst(SelectInst &SI) { - if (!isa(SI.getType())) - return; // Only pointer Selects - - DSNodeHandle &Dest = G.getNodeForValue(&SI); - DSNodeHandle S1 = getValueDest(SI.getOperand(1)); - DSNodeHandle S2 = getValueDest(SI.getOperand(2)); - Dest.mergeWith(S1); - Dest.mergeWith(S2); -} - -void GraphBuilder::visitLoadInst(LoadInst &LI) { - SDEBUG(errs() << "[local] visiting load: " << LI << "\n"); - // - // Create a DSNode for the pointer dereferenced by the load. If the DSNode - // is NULL, do nothing more (this can occur if the load is loading from a - // NULL pointer constant (bugpoint can generate such code). - // - DSNodeHandle Ptr = getValueDest(LI.getPointerOperand()); - if (Ptr.isNull()) return; // Load from null - - // Make that the node is read from... - Ptr.getNode()->setReadMarker(); - - // Ensure a typerecord exists... - Ptr.getNode()->growSizeForType(LI.getType(), Ptr.getOffset()); - - if (isa(LI.getType())) - setDestTo(LI, getLink(Ptr)); - - // check that it is the inserted value - if(TypeInferenceOptimize) - if(LI.hasOneUse()) - if(StoreInst *SI = dyn_cast(*(LI.use_begin()))) - if(SI->getOperand(0) == &LI) { - ++NumIgnoredInst; - return; - } - Ptr.getNode()->mergeTypeInfo(LI.getType(), Ptr.getOffset()); -} - -void GraphBuilder::visitStoreInst(StoreInst &SI) { - SDEBUG(errs() << "[local] visiting store: " << SI << "\n"); - Type *StoredTy = SI.getOperand(0)->getType(); - DSNodeHandle Dest = getValueDest(SI.getOperand(1)); - if (Dest.isNull()) return; - - // Mark that the node is written to... - Dest.getNode()->setModifiedMarker(); - - // Ensure a type-record exists... - Dest.getNode()->growSizeForType(StoredTy, Dest.getOffset()); - - // Avoid adding edges from null, or processing non-"pointer" stores - if (isa(StoredTy)) - Dest.addEdgeTo(getValueDest(SI.getOperand(0))); - - if(TypeInferenceOptimize) - if(SI.getOperand(0)->hasOneUse()) - if(isa(SI.getOperand(0))){ - ++NumIgnoredInst; - return; - } - Dest.getNode()->mergeTypeInfo(StoredTy, Dest.getOffset()); -} - -void GraphBuilder::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { - SDEBUG(errs() << "[local] visiting atomic cmpxchg: " << I << "\n"); - if (isa(I.getType())) { - visitInstruction (I); - return; - } - - // - // Create a DSNode for the dereferenced pointer . If the DSNode is NULL, do - // nothing more (this can occur if the pointer is a NULL constant; bugpoint - // can generate such code). - // - DSNodeHandle Ptr = getValueDest(I.getPointerOperand()); - if (Ptr.isNull()) return; - - // - // Make that the memory object is read and written. - // - Ptr.getNode()->setReadMarker(); - Ptr.getNode()->setModifiedMarker(); - - // - // If the result of the compare-and-swap is a pointer, then we need to do - // a few things: - // o Merge the compare and swap values (which are pointers) with the result - // o Merge the DSNode of the pointer *within* the memory object with the - // DSNode of the compare, swap, and result DSNode. - // - if (isa(I.getType())) { - // - // Get the DSNodeHandle of the memory object returned from the load. Make - // it the DSNodeHandle of the instruction's result. - // - DSNodeHandle FieldPtr = getLink (Ptr); - setDestTo(I, getLink(Ptr)); - - // - // Merge the result, compare, and swap values of the instruction. - // - FieldPtr.mergeWith (getValueDest (I.getCompareOperand())); - FieldPtr.mergeWith (getValueDest (I.getNewValOperand())); - } - - // - // Modify the DSNode so that it has the loaded/written type at the - // appropriate offset. - // - Ptr.getNode()->growSizeForType(I.getType(), Ptr.getOffset()); - Ptr.getNode()->mergeTypeInfo(I.getType(), Ptr.getOffset()); - return; -} - -void GraphBuilder::visitAtomicRMWInst(AtomicRMWInst &I) { - SDEBUG(errs() << "[local] visiting atomic RMW: " << I << "\n"); - // - // Create a DSNode for the dereferenced pointer . If the DSNode is NULL, do - // nothing more (this can occur if the pointer is a NULL constant; bugpoint - // can generate such code). - // - DSNodeHandle Ptr = getValueDest(I.getPointerOperand()); - if (Ptr.isNull()) return; - - // - // Make that the memory object is read and written. - // - Ptr.getNode()->setReadMarker(); - Ptr.getNode()->setModifiedMarker(); - - // - // Modify the DSNode so that it has the loaded/written type at the - // appropriate offset. - // - Ptr.getNode()->growSizeForType(I.getType(), Ptr.getOffset()); - Ptr.getNode()->mergeTypeInfo(I.getType(), Ptr.getOffset()); - return; -} - -void GraphBuilder::visitReturnInst(ReturnInst &RI) { - SDEBUG(errs() << "[local] visiting return: " << RI << "\n"); - if (RI.getNumOperands() && isa(RI.getOperand(0)->getType())) - G.getOrCreateReturnNodeFor(*FB).mergeWith(getValueDest(RI.getOperand(0))); -} - -void GraphBuilder::visitVAArgInst(VAArgInst &I) { - SDEBUG(errs() << "[local] visiting vaarg: " << I << "\n"); - Module *M = FB->getParent(); - Triple TargetTriple(M->getTargetTriple()); - Triple::ArchType Arch = TargetTriple.getArch(); - switch(Arch) { - case Triple::x86_64: { - // On x86_64, we have va_list as a struct {i32, i32, i8*, i8* } - // The first i8* is where arguments generally go, but the second i8* can - // be used also to pass arguments by register. - // We model this by having both the i8*'s point to an array of pointers - // to the arguments. - DSNodeHandle Ptr = G.getVANodeFor(*FB); - DSNodeHandle Dest = getValueDest(&I); - if (Ptr.isNull()) return; - - // Make that the node is read and written - Ptr.getNode()->setReadMarker()->setModifiedMarker(); - - // Not updating type info, as it is already a collapsed node - - if (isa(I.getType())) - Dest.mergeWith(Ptr); - return; - } - - default: { - llvm_unreachable("What frontend generates this?"); - DSNodeHandle Ptr = getValueDest(I.getOperand(0)); - - //FIXME: also updates the argument - if (Ptr.isNull()) return; - - // Make that the node is read and written - Ptr.getNode()->setReadMarker()->setModifiedMarker(); - - // Ensure a type record exists. - DSNode *PtrN = Ptr.getNode(); - PtrN->mergeTypeInfo(I.getType(), Ptr.getOffset()); - - if (isa(I.getType())) - setDestTo(I, getLink(Ptr)); - } - } -} - -void GraphBuilder::visitIntToPtrInst(IntToPtrInst &I) { - SDEBUG(errs() << "[local] visiting inttoptr: " << I << "\n"); - DSNode *N = createNode(); - if(I.hasOneUse()) { - if(isa(*(I.use_begin()))) { - NumBoringIntToPtr++; - return; - } - } - N->setIntToPtrMarker(); - N->setUnknownMarker(); - setDestTo(I, N); -} - -void GraphBuilder::visitPtrToIntInst(PtrToIntInst& I) { - SDEBUG(errs() << "[local] visiting ptrtoint: " << I << "\n"); - DSNode* N = getValueDest(I.getOperand(0)).getNode(); - if(I.hasOneUse()) { - if(isa(*(I.use_begin()))) { - NumBoringIntToPtr++; - return; - } - } - if(I.hasOneUse()) { - Value *V = dyn_cast(*(I.use_begin())); - DenseSet Seen; - while(V && V->hasOneUse() && - Seen.insert(V).second) { - if(isa(V)) - break; - if(isa(V)) - break; - if(isa(V)) - break; - V = dyn_cast(*(V->use_begin())); - } - if(isa(V)){ - NumBoringIntToPtr++; - return; - } - } - if(N) - N->setPtrToIntMarker(); -} - - -void GraphBuilder::visitBitCastInst(BitCastInst &I) { - SDEBUG(errs() << "[local] visiting bitcast: " << I << "\n"); - if (!isa(I.getType())) return; // Only pointers - DSNodeHandle Ptr = getValueDest(I.getOperand(0)); - if (Ptr.isNull()) return; - setDestTo(I, Ptr); -} - -void GraphBuilder::visitCmpInst(CmpInst &I) { - SDEBUG(errs() << "[local] visiting compare: " << I << "\n"); - //Address can escape through cmps -} - -unsigned getValueOffset(Type *Ty, ArrayRef Idxs, - const DataLayout &TD) { - unsigned Offset = 0; - for (ArrayRef::iterator I = Idxs.begin(), E = Idxs.end(); I != E; - ++I) { - // Lifted from DataLayout.cpp's getIndexedOffset. - // We can't use that because it insists on only allowing pointer types. - if (StructType *STy = dyn_cast(Ty)) { - unsigned FieldNo = *I; - - // Get structure layout information... - const StructLayout *Layout = TD.getStructLayout(STy); - - // Add in the offset, as calculated by the structure layout info... - Offset += Layout->getElementOffset(FieldNo); - - // Update Ty to refer to current element - Ty = STy->getElementType(FieldNo); - } else { - // Update Ty to refer to current element - Ty = cast(Ty)->getElementType(); - - // Get the array index and the size of each array element. - int64_t arrayIdx = *I; - Offset += (uint64_t)arrayIdx * TD.getTypeAllocSize(Ty); - } - } - return Offset; -} - -void GraphBuilder::visitInsertValueInst(InsertValueInst& I) { - SDEBUG(errs() << "[local] visiting insertvalue: " << I << "\n"); - setDestTo(I, createNode()->setAllocaMarker()); - - Type *StoredTy = I.getInsertedValueOperand()->getType(); - DSNodeHandle Dest = getValueDest(&I); - Dest.mergeWith(getValueDest(I.getAggregateOperand())); - - // Mark that the node is written to... - Dest.getNode()->setModifiedMarker(); - Type* STy = I.getAggregateOperand()->getType(); - - unsigned Offset = getValueOffset(STy, I.getIndices(), TD); - - // Ensure a type-record exists... - Dest.getNode()->mergeTypeInfo(StoredTy, Offset); - - // Avoid adding edges from null, or processing non-"pointer" stores - if (isa(StoredTy)) - Dest.addEdgeTo(getValueDest(I.getInsertedValueOperand())); -} - -void GraphBuilder::visitExtractValueInst(ExtractValueInst& I) { - SDEBUG(errs() << "[local] visiting extractvalue: " << I << "\n"); - DSNodeHandle Ptr = getValueDest(I.getAggregateOperand()); - - // Make that the node is read from... - Ptr.getNode()->setReadMarker(); - Type* STy = I.getAggregateOperand()->getType(); - - unsigned Offset = getValueOffset(STy, I.getIndices(), TD); - - // Ensure a typerecord exists... - Ptr.getNode()->mergeTypeInfo(I.getType(), Offset); - - if (isa(I.getType())) - setDestTo(I, getLink(Ptr)); -} - -void GraphBuilder::visitGetElementPtrInst(User &GEP) { - SDEBUG(errs() << "[local] visiting GEP: " << GEP << "\n"); - // - // Ensure that the indexed pointer has a DSNode. - // - DSNodeHandle NodeH = getValueDest(GEP.getOperand(0)); - if (NodeH.isNull()) - NodeH = createNode(); - - // - // There are a few quick and easy cases to handle. If the DSNode of the - // indexed pointer is already folded, then we know that the result of the - // GEP will have the same offset into the same DSNode - // as the indexed pointer. - // - - if (!NodeH.isNull() && - NodeH.getNode()->isNodeCompletelyFolded()) { - setDestTo(GEP, NodeH); - return; - } - - // - // Okay, no easy way out. Calculate the offset into the object being - // indexed. - // - - int Offset = 0; - - // FIXME: I am not sure if the code below is completely correct (especially - // if we start doing fancy analysis on non-constant array indices). - // What if the array is indexed using a larger index than its declared - // size? Does the LLVM verifier catch such issues? - // - - // - // Determine the offset (in bytes) between the result of the GEP and the - // GEP's pointer operand. - // - // Note: All of these subscripts are indexing INTO the elements we have... - // - // FIXME: We can do better for array indexing. First, if the array index is - // constant, we can determine how much farther we're moving the - // pointer. Second, we can try to use the results of other analysis - // passes (e.g., ScalarEvolution) to find min/max values to do less - // conservative type-folding. - // - for (gep_type_iterator I = gep_type_begin(GEP), E = gep_type_end(GEP); - I != E; ++I) { - - if (StructType *STy = I.getStructTypeOrNull()) { - // indexing into a structure - // next index must be a constant - const ConstantInt* CUI = cast(I.getOperand()); - int FieldNo = CUI->getSExtValue(); - // increment the offset by the actual byte offset being accessed - - unsigned requiredSize = TD.getTypeAllocSize(STy) + NodeH.getOffset() + Offset; - - // - // Grow the DSNode size as needed. - // - if (!NodeH.getNode()->isArrayNode() || NodeH.getNode()->getSize() <= 0){ - if (requiredSize > NodeH.getNode()->getSize()) - NodeH.getNode()->growSize(requiredSize); - } - - Offset += (unsigned)TD.getStructLayout(STy)->getElementOffset(FieldNo); - if (TypeInferenceOptimize) { - if (ArrayType* AT = dyn_cast(STy->getTypeAtIndex(FieldNo))) { - NodeH.getNode()->mergeTypeInfo(AT, NodeH.getOffset() + Offset); - if ((++I) == E) { - break; - } - - // Check if we are still indexing into an array. - // We only record the topmost array type of any nested array. - // Keep skipping indexes till we reach a non-array type. - // J is the type of the next index. - // Uncomment the line below to get all the nested types. - gep_type_iterator J = I; - while ((++J).isSequential()) { - // NodeH.getNode()->mergeTypeInfo(AT1, NodeH.getOffset() + Offset); - if((++I) == E) { - break; - } - J = I; - } - if ((I) == E) { - break; - } - } - } - } else { - Type *CurTy = I.getIndexedType(); - if (I.isBoundedSequential()) { - // indexing into an array. - NodeH.getNode()->setArrayMarker(); - - // - // Ensure that the DSNode's size is large enough to contain one - // element of the type to which the pointer points. - // - if (!isa(CurTy) && NodeH.getNode()->getSize() <= 0) { - NodeH.getNode()->growSize(TD.getTypeAllocSize(CurTy)); - } else if(isa(CurTy) && NodeH.getNode()->getSize() <= 0){ - Type *ETy = (cast(CurTy))->getElementType(); - while(isa(ETy)) { - ETy = (cast(ETy))->getElementType(); - } - NodeH.getNode()->growSize(TD.getTypeAllocSize(ETy)); - } - - // Find if the DSNode belongs to the array - // If not fold. - if((NodeH.getOffset() || Offset != 0) - || (!isa(CurTy) - && (NodeH.getNode()->getSize() != TD.getTypeAllocSize(CurTy)))) { - - M.witness(NodeH, {&GEP, I.getOperand()}, - "node does not belong to array" - ); - - SDEBUG( - errs() << "[local] FOLDING FOR ARRAY ACCESS" << "\n"; - errs() << "[local] type: " << *CurTy << "\n"; - errs() << "[local] offset: " << Offset - << " (" << NodeH.getOffset() << ")\n"; - errs() << "[local] size: " << TD.getTypeAllocSize(CurTy) - << " (" << NodeH.getNode()->getSize() << ")\n"; - errs() << "[local] value: " << GEP << "\n"; - errs() << "[local] index: " << *I.getOperand() << "\n"; - ); - NodeH.getNode()->foldNodeCompletely(); - NodeH.getNode(); - Offset = 0; - break; - } - } else { - // Pointer type - - // - // Some LLVM transforms lower structure indexing into byte-level - // indexing. Try to recognize forms of that here. - // - Type * Int8Type = Type::getInt8Ty(CurTy->getContext()); - ConstantInt * IS = dyn_cast(I.getOperand()); - if (IS && - (NodeH.getOffset() == 0) && - (!(NodeH.getNode()->isArrayNode())) && - (CurTy == Int8Type)) { - // Calculate the offset of the field - Offset += IS->getSExtValue() * TD.getTypeAllocSize (Int8Type); - - // - // Grow the DSNode size as needed. - // - unsigned requiredSize = Offset + TD.getTypeAllocSize (Int8Type); - if (NodeH.getNode()->getSize() <= requiredSize){ - NodeH.getNode()->growSize (requiredSize); - } - - // Add in the offset calculated... - NodeH.setOffset(NodeH.getOffset()+Offset); - - // Check the offset - DSNode *N = NodeH.getNode(); - if (N) N->checkOffsetFoldIfNeeded(NodeH.getOffset()); - - // NodeH is now the pointer we want to GEP to be... - setDestTo(GEP, NodeH); - return; - } - - // - // Unless we're advancing the pointer by zero bytes via array indexing, - // fold the node (i.e., mark it type-unknown) and indicate that we're - // indexing zero bytes into the object (because all fields are aliased). - // - // Note that we break out of the loop if we fold the node. Once - // something is folded, all values within it are considered to alias. - // - if (!isa(I.getOperand()) || - !cast(I.getOperand())->isNullValue()) { - - // - // Treat the memory object (DSNode) as an array. - // - NodeH.getNode()->setArrayMarker(); - - // - // Ensure that the DSNode's size is large enough to contain one - // element of the type to which the pointer points. - // - if (!isa(CurTy) && NodeH.getNode()->getSize() <= 0){ - NodeH.getNode()->growSize(TD.getTypeAllocSize(CurTy)); - } else if (isa(CurTy) && NodeH.getNode()->getSize() <= 0){ - Type *ETy = (cast(CurTy))->getElementType(); - while (isa(ETy)) { - ETy = (cast(ETy))->getElementType(); - } - NodeH.getNode()->growSize(TD.getTypeAllocSize(ETy)); - } - - // - // Fold the DSNode if we're indexing into it in a type-incompatible - // manner. That can occur if: - // 1) The DSNode represents a pointer into the object at a non-zero - // offset. - // 2) The offset of the pointer is already non-zero. - // 3) The size of the array element does not match the size into which - // the pointer indexing is indexing. - // - if (NodeH.getOffset() || Offset != 0 || - (!isa(CurTy) && - (NodeH.getNode()->getSize() != TD.getTypeAllocSize(CurTy)))) { - - M.witness(NodeH, {&GEP, I.getOperand()}, - "type-incompatible access into node" - ); - - SDEBUG( - errs() << "[local] FOLDING FOR POINTER ACCESS" << "\n"; - errs() << "[local] type: " << *CurTy << "\n"; - errs() << "[local] offset: " << Offset - << " (" << NodeH.getOffset() << ")\n"; - errs() << "[local] size: " << TD.getTypeAllocSize(CurTy) - << " (" << NodeH.getNode()->getSize() << ")\n"; - errs() << "[local] value: " << GEP << "\n"; - errs() << "[local] index: " << *I.getOperand() << "\n"; - ); - NodeH.getNode()->foldNodeCompletely(); - NodeH.getNode(); - Offset = 0; - break; - } - } - } - } - } - - // Add in the offset calculated... - NodeH.setOffset(NodeH.getOffset()+Offset); - - // Check the offset - DSNode *N = NodeH.getNode(); - if (N) N->checkOffsetFoldIfNeeded(NodeH.getOffset()); - - // NodeH is now the pointer we want to GEP to be... - setDestTo(GEP, NodeH); -} - - -void GraphBuilder::visitCallInst(CallInst &CI) { - SDEBUG(errs() << "[local] visiting call: " << CI << "\n"); - visitCallSite(&CI); -} - -void GraphBuilder::visitInvokeInst(InvokeInst &II) { - SDEBUG(errs() << "[local] visiting invoke: " << II << "\n"); - visitCallSite(&II); -} - -void GraphBuilder::visitVAStart(CallSite CS) { - SDEBUG(errs() << "[local] visiting VA start: " - << CS.getCalledValue()->getName() << "\n"); - - // Build out DSNodes for the va_list depending on the target arch - // And assosiate the right node with the VANode for this function - // so it can be merged with the right arguments from callsites - - DSNodeHandle RetNH = getValueDest(CS.getArgument(0)); - - if (DSNode *N = RetNH.getNode()) - visitVAStartNode(N); -} - -void GraphBuilder::visitVAStartNode(DSNode* N) { - assert(N && "Null node as argument"); - assert(FB && "No function for this graph?"); - Module *M = FB->getParent(); - assert(M && "No module for function"); - Triple TargetTriple(M->getTargetTriple()); - Triple::ArchType Arch = TargetTriple.getArch(); - - // Fetch the VANode associated with the func containing the call to va_start - DSNodeHandle & VANH = G.getVANodeFor(*FB); - // Make sure this NodeHandle has a node to go with it - if (VANH.isNull()) VANH.mergeWith(createNode()); - - // Create a dsnode for an array of pointers to the VAInfo for this func - // We create one such array for each function analyzed, as all - // calls to va_start will populate their argument with the same data. - if (!VAArray) VAArray = createNode(); - VAArray->setArrayMarker(); - VAArray->foldNodeCompletely(); - VAArray->setLink(0,VANH); - - //VAStart modifies its argument - N->setModifiedMarker(); - - // For the architectures we support, build dsnodes that match - // how we know va_list is used. - switch (Arch) { - case Triple::x86: - // On x86, we have: - // va_list as a pointer to an array of pointers to the variable arguments - if (N->getSize() < 1) - N->growSize(1); - N->setLink(0, VAArray); - break; - case Triple::x86_64: - // On x86_64, we have va_list as a struct {i32, i32, i8*, i8* } - // The first i8* is where arguments generally go, but the second i8* can - // be used also to pass arguments by register. - // We model this by having both the i8*'s point to an array of pointers - // to the arguments. - if (N->getSize() < 24) - N->growSize(24); //sizeof the va_list struct mentioned above - N->setLink(8,VAArray); //first i8* - N->setLink(16,VAArray); //second i8* - - break; - default: - // FIXME: For now we abort if we don't know how to handle this arch - // Either add support for other architectures, or at least mark the - // nodes unknown/incomplete or whichever results in the correct - // conservative behavior in the general case - llvm_unreachable("VAstart not supported on this architecture!"); - //XXX: This might be good enough in those cases that we don't know - //what the arch does - N->setIncompleteMarker()->setUnknownMarker()->foldNodeCompletely(); - } - - // XXX: We used to set the alloca marker for the DSNode passed to va_start. - // Seems to me that you could allocate the va_list on the heap, so ignoring - // for now. - N->setModifiedMarker()->setVAStartMarker(); -} - -/// -/// Method: visitIntrinsic() -/// -/// Description: -/// Generate correct DSNodes for calls to LLVM intrinsic functions. -/// -/// Inputs: -/// CS - The CallSite representing the call or invoke to the intrinsic. -/// F - A pointer to the function called by the call site. -/// -/// Return value: -/// true - This intrinsic is properly handled by this method. -/// false - This intrinsic is not recognized by DSA. -/// -bool GraphBuilder::visitIntrinsic(CallSite CS, Function *F) { - SDEBUG(errs() << "[local] visiting intrinsic: " << F->getName() << "\n"); - - ++NumIntrinsicCall; - - // - // If this is a debug intrinsic, then don't do any special processing. - // - if (isa(CS.getInstruction())) - return true; - - switch (F->getIntrinsicID()) { - case Intrinsic::vastart: { - visitVAStart(CS); - return true; - } - case Intrinsic::vacopy: { - // Simply merge the two arguments to va_copy. - // This results in loss of precision on the temporaries used to manipulate - // the va_list, and so isn't a big deal. In theory we would build a - // separate graph for this (like the one created in visitVAStartNode) - // and only merge the node containing the variable arguments themselves. - DSNodeHandle destNH = getValueDest(CS.getArgument(0)); - DSNodeHandle srcNH = getValueDest(CS.getArgument(1)); - destNH.mergeWith(srcNH); - return true; - } - case Intrinsic::stacksave: { - DSNode * Node = createNode(); - Node->setAllocaMarker()->setIncompleteMarker()->setUnknownMarker(); - Node->foldNodeCompletely(); - setDestTo (*(CS.getInstruction()), Node); - return true; - } - case Intrinsic::stackrestore: - getValueDest(CS.getInstruction()).getNode()->setAllocaMarker() - ->setIncompleteMarker() - ->setUnknownMarker() - ->foldNodeCompletely(); - return true; - case Intrinsic::vaend: - // TODO: What to do here? - return true; - case Intrinsic::memcpy: - case Intrinsic::memmove: { - // Merge the first & second arguments, and mark the memory read and - // modified. - DSNodeHandle RetNH = getValueDest(CS.getArgument(0)); - RetNH.mergeWith(getValueDest(CS.getArgument(1))); - if (DSNode *N = RetNH.getNode()) - N->setModifiedMarker()->setReadMarker(); - return true; - } - case Intrinsic::memset: - // Mark the memory modified. - if (DSNode *N = getValueDest(CS.getArgument(0)).getNode()) - N->setModifiedMarker(); - return true; - - // TODO: Add support for the new EH system -#if 0 - case Intrinsic::eh_exception: { - DSNode * Node = createNode(); - Node->setIncompleteMarker(); - Node->foldNodeCompletely(); - setDestTo (*(CS.getInstruction()), Node); - return true; - } - - case Intrinsic::eh_selector: { - for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); - I != E; ++I) { - if (isa((*I)->getType())) { - DSNodeHandle Ptr = getValueDest(*I); - if(Ptr.getNode()) { - Ptr.getNode()->setReadMarker(); - Ptr.getNode()->setIncompleteMarker(); - } - } - } - return true; - } -#endif - - case Intrinsic::eh_typeid_for: { - DSNodeHandle Ptr = getValueDest(CS.getArgument(0)); - Ptr.getNode()->setReadMarker(); - Ptr.getNode()->setIncompleteMarker(); - return true; - } - - case Intrinsic::prefetch: - return true; - - case Intrinsic::objectsize: - return true; - - // - // The return address/frame address aliases with the stack, - // is type-unknown, and should - // have the unknown flag set since we don't know where it goes. - // - case Intrinsic::returnaddress: - case Intrinsic::frameaddress: { - DSNode * Node = createNode(); - Node->setAllocaMarker()->setIncompleteMarker()->setUnknownMarker(); - Node->foldNodeCompletely(); - setDestTo (*(CS.getInstruction()), Node); - return true; - } - - // Process lifetime intrinsics - case Intrinsic::lifetime_start: - case Intrinsic::lifetime_end: - case Intrinsic::invariant_start: - case Intrinsic::invariant_end: - return true; - - default: { - //ignore pointer free intrinsics - if (!isa(F->getReturnType())) { - bool hasPtr = false; - for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end(); - I != E && !hasPtr; ++I) - if (isa(I->getType())) - hasPtr = true; - if (!hasPtr) - return true; - } - - SDEBUG(errs() << "[dsa:local] Unhandled intrinsic: " << F->getName() << "\n"); - llvm_unreachable("Unhandled intrinsic"); - return false; - } - } -} - -void GraphBuilder::visitCallSite(CallSite CS) { - // - // Get the called value. Strip off any casts which are lossless. - // - Value *Callee = CS.getCalledValue()->stripPointerCasts(); - - // Special case handling of certain libc allocation functions here. - if (Function *F = dyn_cast(Callee)) - if (F->isIntrinsic() && visitIntrinsic(CS, F)) - return; - - //Can't do much about inline asm (yet!) - if (isa (Callee)) { - ++NumAsmCall; - DSNodeHandle RetVal; - Instruction *I = CS.getInstruction(); - if (isa (I->getType())) - RetVal = getValueDest(I); - - // Calculate the arguments vector... - for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); I != E; ++I) - if (isa ((*I)->getType())) - RetVal.mergeWith(getValueDest(*I)); - if (!RetVal.isNull()) { - - M.witness(RetVal, {I}, - "inline asm call" - ); - - RetVal.getNode()->foldNodeCompletely(); - } - return; - } - - // Set up the return value... - DSNodeHandle RetVal; - Instruction *I = CS.getInstruction(); - if (isa(I->getType())) - RetVal = getValueDest(I); - - DSNode *CalleeNode = 0; - if (!isa(Callee)) { - CalleeNode = getValueDest(Callee).getNode(); - if (CalleeNode == 0) { - SDEBUG(errs() << "WARNING: Program is calling through a null pointer?\n" << *I); - return; // Calling a null pointer? - } - } - - // NOTE: This code is identical to 'DSGraph::getDSCallSiteForCallSite', - // the reason it's duplicated is because this calls getValueDest instead - // of getNodeForValue to get the DSNodes for the arguments. Since we're in - // local it's possible that we need to create a DSNode for the argument, as - // opposed to getNodeForValue which simply retrieves the existing node. - - - //Get the FunctionType for the called function - const FunctionType *CalleeFuncType = DSCallSite::FunctionTypeOfCallSite(CS); - int NumFixedArgs = CalleeFuncType->getNumParams(); - - // Sanity check--this really, really shouldn't happen - if (!CalleeFuncType->isVarArg()) - assert(CS.arg_size() == static_cast(NumFixedArgs) && - "Too many arguments/incorrect function signature!"); - - std::vector Args; - Args.reserve(CS.arg_size()); - DSNodeHandle VarArgNH; - - // Calculate the arguments vector... - // Add all fixed pointer arguments, then merge the rest together - for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); - I != E; ++I) - if (isa((*I)->getType())) { - DSNodeHandle ArgNode = getValueDest(*I); - if (I - CS.arg_begin() < NumFixedArgs) { - Args.push_back(ArgNode); - } else { - VarArgNH.mergeWith(ArgNode); - } - } - - // Add a new function call entry... - if (CalleeNode) { - ++NumIndirectCall; - G.getFunctionCalls().push_back(DSCallSite(CS, RetVal, VarArgNH, CalleeNode, - Args)); - } else { - ++NumDirectCall; - G.getFunctionCalls().push_back(DSCallSite(CS, RetVal, VarArgNH, - cast(Callee), - Args)); - } - - -} - -// visitInstruction - For all other instruction types, if we have any arguments -// that are of pointer type, make them have unknown composition bits, and merge -// the nodes together. -void GraphBuilder::visitInstruction(Instruction &Inst) { - SDEBUG(errs() << "[local] visiting instruction: " << Inst << "\n"); - DSNodeHandle CurNode; - if (isa(Inst.getType())) - CurNode = getValueDest(&Inst); - for (User::op_iterator I = Inst.op_begin(), E = Inst.op_end(); I != E; ++I) - if (isa((*I)->getType())) - CurNode.mergeWith(getValueDest(*I)); - - if (DSNode *N = CurNode.getNode()) - N->setUnknownMarker(); -} - - - -//===----------------------------------------------------------------------===// -// LocalDataStructures Implementation -//===----------------------------------------------------------------------===// - -// -// Function: MergeConstantInitIntoNode() -// -// Description: -// Merge the specified constant into the specified DSNode. -// -void -GraphBuilder::MergeConstantInitIntoNode(DSNodeHandle &NH, - Type* Ty, - Constant *C) { - // - // Ensure a type-record exists... - // - DSNode *NHN = NH.getNode(); - //NHN->mergeTypeInfo(Ty, NH.getOffset()); - - // - // If we've found something of pointer type, create or find its DSNode and - // make a link from the specified DSNode to the new DSNode describing the - // pointer we've just found. - // - if (isa(Ty)) { - NHN->mergeTypeInfo(Ty, NH.getOffset()); - NH.addEdgeTo(getValueDest(C)); - return; - } - - // - // If the type of the object (array element, structure field, etc.) is an - // integer or floating point type, then just ignore it. It has no DSNode. - // - if (Ty->isIntOrIntVectorTy() || Ty->isFPOrFPVectorTy()) return; - - // - // Handle aggregate constants. - // - if (ConstantArray *CA = dyn_cast(C)) { - // - // For an array, we don't worry about different elements pointing to - // different objects; we essentially pretend that all array elements alias. - // - Type * ElementType = cast(Ty)->getElementType(); - for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) { - Constant * ConstElement = cast(CA->getOperand(i)); - MergeConstantInitIntoNode(NH, ElementType, ConstElement); - } - } else if (ConstantStruct *CS = dyn_cast(C)) { - // - // For a structure, we need to merge each element of the constant structure - // into the specified DSNode. However, we must also handle structures that - // end with a zero-length array ([0 x sbyte]); this is a common C idiom - // that continues to plague the world. - // - //NHN->mergeTypeInfo(Ty, NH.getOffset()); - - const StructLayout *SL = TD.getStructLayout(cast(Ty)); - - for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) { - DSNode *NHN = NH.getNode(); - if (SL->getElementOffset(i) < SL->getSizeInBytes()) { - // - // Get the type and constant value of this particular element of the - // constant structure. - // - Type * ElementType = cast(Ty)->getElementType(i); - Constant * ConstElement = cast(CS->getOperand(i)); - - // - // Get the offset (in bytes) into the memory object that we're - // analyzing. - // - unsigned offset = NH.getOffset()+(unsigned)SL->getElementOffset(i); - NHN->mergeTypeInfo(ElementType, offset); - // - // Create a new DSNodeHandle. This DSNodeHandle will point to the same - // DSNode as the one we're constructing for our caller; however, it - // will point into a different offset into that DSNode. - // - DSNodeHandle NewNH (NHN, offset); - assert ((NHN->isNodeCompletelyFolded() || (NewNH.getOffset() == offset)) - && "Need to resize DSNode!"); - - // - // Recursively merge in this element of the constant struture into the - // DSNode. - // - MergeConstantInitIntoNode(NewNH, ElementType, ConstElement); - } else if (SL->getElementOffset(i) == SL->getSizeInBytes()) { - // - // If this is one of those cute structures that ends with a zero-length - // array, just fold the DSNode now and get it over with. - // - SDEBUG(errs() << "Zero size element at end of struct\n" ); - - M.witness(NHN, {CS}, - "zero size element at end of struct" - ); - - NHN->foldNodeCompletely(); - } else { - llvm_unreachable("type was smaller than offsets of struct layout indicate"); - } - } - } else if (isa(C) || isa(C)) { - // - // Undefined values and NULL pointers have no DSNodes, so they do nothing. - // - } else if (isa(C)) { - // - // ConstantDataSequential's are arrays of integers or floats, so they - // have no DSNodes. Nothing to do here. - // - } else { - llvm_unreachable("Unknown constant type!"); - } -} - -void GraphBuilder::mergeInGlobalInitializer(GlobalVariable *GV) { - // Ensure that the global variable is not external - assert(!GV->isDeclaration() && "Cannot merge in external global!"); - - // - // Get a node handle to the global node and merge the initializer into it. - // - DSNodeHandle NH = getValueDest(GV); - - // - // Ensure that the DSNode is large enough to hold the new constant that we'll - // be adding to it. - // - Type * ElementType = GV->getType()->getElementType(); - while(ArrayType *ATy = dyn_cast(ElementType)) { - ElementType = ATy->getElementType(); - } - if(!NH.getNode()->isNodeCompletelyFolded()) { - unsigned requiredSize = TD.getTypeAllocSize(ElementType) + NH.getOffset(); - if (NH.getNode()->getSize() < requiredSize){ - NH.getNode()->growSize (requiredSize); - } - } - - // - // Do the actual merging in of the constant initializer. - // - MergeConstantInitIntoNode(NH, GV->getType()->getElementType(), GV->getInitializer()); - -} - -void GraphBuilder::mergeExternalGlobal(GlobalVariable *GV) { - // Get a node handle to the global node and merge the initializer into it. - DSNodeHandle NH = getValueDest(GV); -} - -// some evil programs use sections as linker generated arrays -// read a description of this behavior in and apply it -// format: numglobals section globals... -// terminates when numglobals == 0 -void handleMagicSections(DSGraph* GlobalsGraph, Module& M) { - std::ifstream msf(hasMagicSections.c_str(), std::ifstream::in); - if (msf.good()) { - //no checking happens here - unsigned count = 0; - msf >> count; - while (count) { - std::string section; - msf >> section; - svset inSection; - for (Function &F : M) - if (F.hasSection() && F.getSection() == section) - inSection.insert(&F); - for (GlobalVariable &GV : M.globals()) - if (GV.hasSection() && GV.getSection() == section) - inSection.insert(&GV); - - for (unsigned x = 0; x < count; ++x) { - std::string global; - msf >> global; - Value* V = M.getNamedValue(global); - if (V) { - DSNodeHandle& DHV = GlobalsGraph->getNodeForValue(V); - for (svset::iterator SI = inSection.begin(), - SE = inSection.end(); SI != SE; ++SI) { - SDEBUG(errs() << "Merging " << V->getName().str() << " with " - << (*SI)->getName().str() << "\n"); - GlobalsGraph->getNodeForValue(*SI).mergeWith(DHV); - } - } - } - msf >> count; - } - } else { - errs() << "Failed to open magic sections file:" << hasMagicSections << - "\n"; - } -} - -char LocalDataStructures::ID; - -bool LocalDataStructures::runOnModule(Module &M) { - init(&M.getDataLayout()); - addrAnalysis = &getAnalysis(); - - // First step, build the globals graph. - { - GraphBuilder GGB(*GlobalsGraph, *this); - - // Add initializers for all of the globals to the globals graph. - for (GlobalVariable &GV : M.globals()) - if (!(GV.hasSection() && std::string(GV.getSection()) == "llvm.metadata")) { - if (GV.isDeclaration()) - GGB.mergeExternalGlobal(&GV); - else - GGB.mergeInGlobalInitializer(&GV); - } - // Add Functions to the globals graph. - for (Function &F : M) { - if(addrAnalysis->hasAddressTaken(&F)) { - GGB.mergeFunction(&F); - } - } - } - - if (hasMagicSections.size()) - handleMagicSections(GlobalsGraph, M); - - // Next step, iterate through the nodes in the globals graph, unioning - // together the globals into equivalence classes. - formGlobalECs(); - - // Iterate through the address taken functions in the globals graph, - // collecting them in a list, to be used as target for call sites that - // cant be resolved. - formGlobalFunctionList(); - GlobalsGraph->maskIncompleteMarkers(); - - // Calculate all of the graphs... - for (Function &F : M) - if (!F.isDeclaration()) { - DSGraph* G = new DSGraph(GlobalECs, getDataLayout(), *TypeSS, GlobalsGraph); - setDSGraph(F, G); - GraphBuilder GGB(F, *G, *this); - G->getAuxFunctionCalls() = G->getFunctionCalls(); - propagateUnknownFlag(G); - callgraph.insureEntry(&F); - G->buildCallGraph(callgraph, GlobalFunctionList, true); - G->maskIncompleteMarkers(); - G->markIncompleteNodes(DSGraph::MarkFormalArgs - |DSGraph::IgnoreGlobals); - cloneIntoGlobals(G, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes | - DSGraph::StripAllocaBit); - formGlobalECs(); - SDEBUG(G->AssertGraphOK()); - } - - //GlobalsGraph->removeTriviallyDeadNodes(); - GlobalsGraph->markIncompleteNodes(DSGraph::MarkFormalArgs - |DSGraph::IgnoreGlobals); - GlobalsGraph->computeExternalFlags(DSGraph::ProcessCallSites); - - // Now that we've computed all of the graphs, and merged all of the info into - // the globals graph, see if we have further constrained the globals in the - // program if so, update GlobalECs and remove the extraneous globals from the - // program. - formGlobalECs(); - - propagateUnknownFlag(GlobalsGraph); - for (Function &F : M) - if (!F.isDeclaration()) { - DSGraph *Graph = getOrCreateGraph(&F); - Graph->maskIncompleteMarkers(); - cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes); - Graph->markIncompleteNodes(DSGraph::MarkFormalArgs - |DSGraph::IgnoreGlobals); - } - - SDEBUG(print(errs(), &M)); - return false; -} diff --git a/lib/DSA/Printer.cpp b/lib/DSA/Printer.cpp deleted file mode 100644 index 1220888e9..000000000 --- a/lib/DSA/Printer.cpp +++ /dev/null @@ -1,415 +0,0 @@ -//===- Printer.cpp - Code for printing data structure graphs nicely -------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the 'dot' graph printer. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "dsgraph-printer" - -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" -#include "dsa/DSGraphTraits.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Constants.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/GraphWriter.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Config/llvm-config.h" -#include "llvm/Support/FormattedStream.h" -#include -using namespace llvm; - -// OnlyPrintMain - The DataStructure printer exposes this option to allow -// printing of only the graph for "main". -// -namespace { - cl::list OnlyPrint("dsa-only-print", cl::ReallyHidden); - cl::opt DontPrintGraphs("dont-print-ds", cl::ReallyHidden); - cl::opt LimitPrint("dsa-limit-print", cl::Hidden); - STATISTIC (MaxGraphSize , "Maximum graph size"); - STATISTIC (NumFoldedNodes , "Number of folded nodes (in final graph)"); -} - -void DSNode::dump() const { print(errs(), 0); } -void DSNode::dumpParentGraph() const { getParentGraph()->dump(); } - -static std::string getCaption(const DSNode *N, const DSGraph *G) { - std::string empty; - raw_string_ostream OS(empty); - const Module *M = 0; - - if (!G) G = N->getParentGraph(); - - // Get the module from ONE of the functions in the graph it is available. - if (G && G->retnodes_begin() != G->retnodes_end()) - M = G->retnodes_begin()->first->getParent(); - if (M == 0 && G) { - // If there is a global in the graph, we can use it to find the module. - const DSScalarMap &SM = G->getScalarMap(); - if (SM.global_begin() != SM.global_end()) - M = (*SM.global_begin())->getParent(); - } - - if (N->isNodeCompletelyFolded()) - OS << "COLLAPSED"; - else { - if (N->type_begin() != N->type_end()) - for (DSNode::TyMapTy::const_iterator ii = N->type_begin(), - ee = N->type_end(); ii != ee; ++ii) { - OS << ii->first << ": "; - if (ii->second) - for (svset::const_iterator ni = ii->second->begin(), - ne = ii->second->end(); ni != ne; ++ni) { - Type * t = *ni; - t->print (OS); - OS << ", "; - } - else - OS << "VOID"; - OS << " "; - } - else - OS << "VOID"; - if (N->isArrayNode()) - OS << " array"; - } - if (unsigned NodeType = N->getNodeFlags()) { - OS << ": "; - if (NodeType & DSNode::AllocaNode ) OS << "S"; - if (NodeType & DSNode::HeapNode ) OS << "H"; - if (NodeType & DSNode::GlobalNode ) OS << "G"; - if (NodeType & DSNode::UnknownNode ) OS << "U"; - if (NodeType & DSNode::IncompleteNode ) OS << "I"; - if (NodeType & DSNode::ModifiedNode ) OS << "M"; - if (NodeType & DSNode::ReadNode ) OS << "R"; - if (NodeType & DSNode::ExternalNode ) OS << "E"; - if (NodeType & DSNode::ExternFuncNode ) OS << "X"; - if (NodeType & DSNode::IntToPtrNode ) OS << "P"; - if (NodeType & DSNode::PtrToIntNode ) OS << "2"; - if (NodeType & DSNode::VAStartNode ) OS << "V"; - -#ifndef NDEBUG - if (NodeType & DSNode::DeadNode ) OS << ""; -#endif - OS << "\n"; - } - - //Indicate if this is a VANode for some function - for (DSGraph::vanodes_iterator I = G->vanodes_begin(), E = G->vanodes_end(); - I != E; ++I) { - DSNodeHandle VANode = I->second; - if (N == VANode.getNode()) { - OS << "(VANode for " << I->first->getName().str() << ")\n"; - } - } - - EquivalenceClasses *GlobalECs = 0; - if (G) GlobalECs = &G->getGlobalECs(); - - for (DSNode::globals_iterator i = N->globals_begin(), e = N->globals_end(); - i != e; ++i) { - (*i)->printAsOperand(OS,false,M); - - // Figure out how many globals are equivalent to this one. - if (GlobalECs) { - EquivalenceClasses::iterator I = - GlobalECs->findValue(*i); - if (I != GlobalECs->end()) { - unsigned NumMembers = - std::distance(GlobalECs->member_begin(I), GlobalECs->member_end()); - if (NumMembers != 1) OS << " + " << (NumMembers-1) << " EC"; - } - } - OS << "\n"; - } - - return OS.str(); -} - -namespace llvm { -template<> -struct DOTGraphTraits : public DefaultDOTGraphTraits { - DOTGraphTraits(bool& b) {} - DOTGraphTraits() {} - static std::string getGraphName(const DSGraph *G) { - switch (G->getReturnNodes().size()) { - case 0: return G->getFunctionNames(); - case 1: return "Function " + G->getFunctionNames(); - default: return "Functions: " + G->getFunctionNames(); - } - } - - static std::string - getNodeLabel(const DSNode* Node, const DSGraph *Graph) { - return getCaption(Node, Graph); - } - - static std::string getNodeAttributes(const DSNode *N, const DSGraph *Graph) { - return "shape=Mrecord"; - } - - static bool edgeTargetsEdgeSource(const void *Node, - DSNode::const_iterator I) { - if (I.getOffset() < I->getSize()) { - if (I->hasLink (I.getOffset())) { - unsigned O = I->getLink(I.getOffset()).getOffset(); - return O != 0; - } else { - return false; - } - } else { - return false; - } - } - - static std::string getEdgeSourceLabel(const void* Node, - DSNode::const_iterator I) { - std::string S; - llvm::raw_string_ostream O(S); - O << I.getOffset(); - return O.str(); - } - - static DSNode::const_iterator getEdgeTarget(const DSNode *Node, - DSNode::const_iterator I) { - unsigned O = I->getLink(I.getOffset()).getOffset(); - unsigned LinkNo = O; - const DSNode *N = *I; - DSNode::const_iterator R = N->begin(); - for (; LinkNo; --LinkNo) - ++R; - return R; - } - - - /// addCustomGraphFeatures - Use this graph writing hook to emit call nodes - /// and the return node. - /// - static void addCustomGraphFeatures(const DSGraph *G, - GraphWriter &GW) { - const Module *CurMod = 0; - if (G->retnodes_begin() != G->retnodes_end()) - CurMod = G->retnodes_begin()->first->getParent(); - else { - // If there is a global in the graph, we can use it to find the module. - const DSScalarMap &SM = G->getScalarMap(); - if (SM.global_begin() != SM.global_end()) - CurMod = (*SM.global_begin())->getParent(); - } - - - if (!LimitPrint) { - // Add scalar nodes to the graph... - const DSGraph::ScalarMapTy &VM = G->getScalarMap(); - for (DSGraph::ScalarMapTy::const_iterator I = VM.begin(); - I != VM.end(); ++I) - if (!isa(I->first)) { - std::string OS_str; - llvm::raw_string_ostream OS(OS_str); - I->first->printAsOperand(OS, false, CurMod); - GW.emitSimpleNode(I->first, "", OS.str()); - - // Add edge from return node to real destination - DSNode *DestNode = I->second.getNode(); - int EdgeDest = I->second.getOffset(); - if (EdgeDest == 0) EdgeDest = -1; - GW.emitEdge(I->first, -1, DestNode, - EdgeDest, "arrowtail=tee,color=gray63"); - } - } - - - // Output the returned value pointer... - for (DSGraph::retnodes_iterator I = G->retnodes_begin(), - E = G->retnodes_end(); I != E; ++I) - if (I->second.getNode()) { - std::string Label; - if (G->getReturnNodes().size() == 1) - Label = "returning"; - else - Label = I->first->getName().str() + " ret node"; - // Output the return node... - GW.emitSimpleNode(const_cast(I->first), "plaintext=circle", Label); - - // Add edge from return node to real destination - DSNode *RetNode = I->second.getNode(); - int RetEdgeDest = I->second.getOffset(); - if (RetEdgeDest == 0) RetEdgeDest = -1; - GW.emitEdge(const_cast(I->first), -1, RetNode, - RetEdgeDest, "arrowtail=tee,color=gray63"); - } - - // Output all of the call nodes... - const DSGraph::FunctionListTy &FCs = - G->shouldUseAuxCalls() ? G->getAuxFunctionCalls() - : G->getFunctionCalls(); - for (DSGraph::FunctionListTy::const_iterator I = FCs.begin(), E = FCs.end(); - I != E; ++I) { - const DSCallSite &Call = *I; - std::vector EdgeSourceCaptions(Call.getNumPtrArgs()+2); - EdgeSourceCaptions[0] = "r"; - if (Call.isDirectCall()) - EdgeSourceCaptions[1] = Call.getCalleeFunc()->getName(); - else - EdgeSourceCaptions[1] = "f"; - - GW.emitSimpleNode(&Call, "shape=record", "call", Call.getNumPtrArgs()+2, - &EdgeSourceCaptions); - - if (DSNode *N = Call.getRetVal().getNode()) { - int EdgeDest = Call.getRetVal().getOffset(); - if (EdgeDest == 0) EdgeDest = -1; - GW.emitEdge(&Call, 0, N, EdgeDest, "color=gray63,tailclip=false"); - } - - // FIXME: visualize the VANode? - - // Print out the callee... - if (Call.isIndirectCall()) { - DSNode *N = Call.getCalleeNode(); - assert(N && "Null call site callee node!"); - GW.emitEdge(&Call, 1, N, -1, "color=gray63,tailclip=false"); - } - - for (unsigned j = 0, e = Call.getNumPtrArgs(); j != e; ++j) - if (DSNode *N = Call.getPtrArg(j).getNode()) { - int EdgeDest = Call.getPtrArg(j).getOffset(); - if (EdgeDest == 0) EdgeDest = -1; - GW.emitEdge(&Call, j+2, N, EdgeDest, "color=gray63,tailclip=false"); - } - } - } -}; -} // end namespace llvm - -void DSNode::print(llvm::raw_ostream &O, const DSGraph *G) const { - GraphWriter W(O, G, false); - W.writeNode(this); -} - -void DSGraph::print(llvm::raw_ostream &O) const { - WriteGraph(O, this); -} - -void DSGraph::writeGraphToFile(llvm::raw_ostream &O, - const std::string &GraphName) const { - std::string Filename = GraphName + ".dot"; - O << "Writing '" << Filename << "'..."; - if (!DontPrintGraphs) { - std::error_code EC; - llvm::raw_fd_ostream F(Filename.c_str(), EC, sys::fs::F_None); - - if (EC) { - O << " error opening file for writing! " << EC.message() << "\n"; - return; - } - - print(F); - } else { - O << "(disabled by command-line flag)"; - } - unsigned NumCalls = shouldUseAuxCalls() ? - getAuxFunctionCalls().size() : getFunctionCalls().size(); - O << " [" << getGraphSize() << "+" << NumCalls << "]\n"; -} - -/// viewGraph - Emit a dot graph, run 'dot', run gv on the postscript file, -/// then cleanup. For use from the debugger. -/// -void DSGraph::viewGraph() const { - ViewGraph(this, "ds.tempgraph"); -} - - -template -static void printCollection(const Collection &C, llvm::raw_ostream &O, - const Module *M, const std::string &Prefix) { - if (M == 0) { - O << "Null Module pointer, cannot continue!\n"; - return; - } - - unsigned TotalNumNodes = 0, TotalCallNodes = 0; - for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) - if (C.hasDSGraph(*I)) { - DSGraph* Gr = C.getDSGraph((const Function&)*I); - unsigned NumCalls = Gr->shouldUseAuxCalls() ? - Gr->getAuxFunctionCalls().size() : Gr->getFunctionCalls().size(); - bool IsDuplicateGraph = false; - - //if no only print options, print everything - bool doPrint = OnlyPrint.begin() == OnlyPrint.end(); - //otherwise check the name - if (!doPrint) - doPrint = OnlyPrint.end() != - std::find(OnlyPrint.begin(), OnlyPrint.end(), I->getName().str()); - - if (doPrint) { - const Function *SCCFn = Gr->retnodes_begin()->first; - if (&*I == SCCFn) { - Gr->writeGraphToFile(O, Prefix+I->getName().str()); - } else { - IsDuplicateGraph = true; // Don't double count node/call nodes. - O << "Didn't write '" << Prefix+I->getName().str() - << ".dot' - Graph already emitted to '" << Prefix+SCCFn->getName().str() - << "\n"; - } - } else { - const Function *SCCFn = Gr->retnodes_begin()->first; - if (&*I == SCCFn) { - //O << "Skipped Writing '" << Prefix+I->getName().str() << ".dot'... [" - // << Gr->getGraphSize() << "+" << NumCalls << "]\n"; - } else { - IsDuplicateGraph = true; // Don't double count node/call nodes. - } - } - - if (!IsDuplicateGraph) { - unsigned GraphSize = Gr->getGraphSize(); - if (MaxGraphSize < GraphSize) MaxGraphSize = GraphSize; - - TotalNumNodes += Gr->getGraphSize(); - TotalCallNodes += NumCalls; - for (DSGraph::node_iterator NI = Gr->node_begin(), E = Gr->node_end(); - NI != E; ++NI) - if (NI->isNodeCompletelyFolded()) - ++NumFoldedNodes; - } - } - - DSGraph* GG = C.getGlobalsGraph(); - TotalNumNodes += GG->getGraphSize(); - TotalCallNodes += GG->getFunctionCalls().size(); - GG->writeGraphToFile(O, Prefix + "GlobalsGraph"); - - O << "\nGraphs contain [" << TotalNumNodes << "+" << TotalCallNodes - << "] nodes total\n"; -} - - -void DataStructures::dumpCallGraph() const { - for (DSCallGraph::flat_key_iterator ki = callgraph.flat_key_begin(), - ke = callgraph.flat_key_end(); ki != ke; ++ki) { - errs() << (*ki)->getName() << ": ["; - for (DSCallGraph::flat_iterator cbi = callgraph.flat_callee_begin(*ki), - cbe = callgraph.flat_callee_end(*ki); cbi != cbe; ++cbi) - errs() << (*cbi)->getName() << " "; - errs() << "]\n"; - } -} - -// print - Print out the analysis results... -void DataStructures::print(llvm::raw_ostream &O, const Module *M) const { - if (handleTest(O, M)) return; - - printCollection(*this, O, M, printname); - //dumpCallGraph(); -} diff --git a/lib/DSA/README b/lib/DSA/README deleted file mode 100644 index 48cb2355b..000000000 --- a/lib/DSA/README +++ /dev/null @@ -1,15 +0,0 @@ -DSA is changed since PLDI07 in (at least) the following ways: - -1) DSA tracks types per offset. -2) DSA does not assume that all clients will want to collapse a node if types - conflict. Many clients don't care that an offset is used as an int or a - double, they just care about the points-to result. - -In Progress: - -1) DSA handles multiple entry points in a module. -2) Optional assumption that only legal targets are called at indirect call sites -3) Positional arguments, rather than pointer relative arguments. This handles - the case where pointer and ints are assumed compatible and function pointers - containing them are cast freely. - diff --git a/lib/DSA/SanityCheck.cpp b/lib/DSA/SanityCheck.cpp deleted file mode 100644 index 2f187a39b..000000000 --- a/lib/DSA/SanityCheck.cpp +++ /dev/null @@ -1,140 +0,0 @@ -//===- SanityCheck.cpp - Check sanity and consistency of DSA results ------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Perform a sanity check on the DSA results. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "dsa-check" - -#include "dsa/DataStructure.h" -#include "dsa/DSGraph.h" - -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" - -using namespace llvm; - -// -// Class: CheckSanity -// -// Description: -// This is an LLVM pass that will request DSA results and then do some sanity -// checks on the DSA results. -// -class SanityCheck : public ModulePass { - public: - static char ID; - SanityCheck() : ModulePass (ID) { - dsaPass = 0; - } - virtual bool runOnModule(Module &M); - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.setPreservesAll(); - } - - protected: - void checkLoad (LoadInst & LI); - - // The DSA pass which is to be sanitized - DataStructures * dsaPass; -}; - -// Sanity Check Pass ID -char SanityCheck::ID = 0; - -static RegisterPass -X("dsa-check", "Check consistency of Data Structure Analysis"); - -// -// Method: checkLoad() -// -// Description: -// This method ensures that the DSNode associated with the result of a load -// instruction is linked from the DSNode associated with the pointer -// dereferenced by the load. -// -void -SanityCheck::checkLoad (LoadInst & LI) { - // - // Get the DSA Graph for the function in which the load instruction lives. - // - Function * F = LI.getParent()->getParent(); - DSGraph * G = dsaPass->getDSGraph (*F); - - // - // Get the DSNode information for both the result of the load instruction - // and its pointer operand. If the result of the load has no DSNode, then - // nothing needs to be done. - // - DSNode* ResultNode = G->getNodeForValue (&LI).getNode(); - DSNode* PtrNode = G->getNodeForValue (LI.getPointerOperand()).getNode(); - if (!ResultNode) { - return; - } - assert (PtrNode && "Load operand has no DSNode!\n"); - - // - // Scan through the links of the DSNode of the load's pointer operand; we - // need to determine the offset into the memory object from which the result - // of the load is loaded. - // - DSNode::LinkMapTy::iterator linki = PtrNode->edge_begin(); -#ifndef NDEBUG - bool found = false; -#endif - for (; linki != PtrNode->edge_end(); ++linki) { - DSNodeHandle & LinkNode = linki->second; - if (LinkNode.getNode() == ResultNode) { -#ifndef NDEBUG - found = true; -#endif - } - } - - assert (found && "Can't find link for load result!\n"); - return; -} - -// -// Method: runOnModule() -// -// Description: -// This method is the entry point for the sanity checking pass. -// -// Inputs: -// M - The LLVM module which should be analyzed for sanity and consistency. -// -// Return value: -// false - The Module has not been modified (this pass should never modify the -// Module). -// -bool -SanityCheck::runOnModule(Module & M) { - // - // Get a reference to the DSA pass to check. - // - dsaPass = &getAnalysis(); - - // - // Scan through all instructions in the module and sanity check the load - // instructions. - // - for (Module::iterator F = M.begin(); F != M.end(); ++F) { - for (Function::iterator BB = F->begin(); BB != F->end(); ++BB) { - for (BasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) { - if (LoadInst * LI = dyn_cast(I)) - checkLoad (*LI); - } - } - } - - return false; -} diff --git a/lib/DSA/StdLibPass.cpp b/lib/DSA/StdLibPass.cpp deleted file mode 100644 index f5b7726c3..000000000 --- a/lib/DSA/StdLibPass.cpp +++ /dev/null @@ -1,911 +0,0 @@ -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Recognize common standard c library functions and generate graphs for them -// FIXME: Move table to separate analysis pass, so that even the Local Pass -// may query it. -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "stdlib-pass" -#include "llvm/ADT/Statistic.h" -#include "dsa/DataStructure.h" -#include "dsa/AllocatorIdentification.h" -#include "dsa/DSGraph.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/IR/GetElementPtrTypeIterator.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/Support/CommandLine.h" -#include "smack/Debug.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/Timer.h" -#include -#include "llvm/IR/Module.h" - -using namespace llvm; - -static RegisterPass -X("dsa-stdlib", "Standard Library Local Data Structure Analysis"); - -STATISTIC(NumNodesFoldedInStdLib, "Number of nodes folded in std lib"); - -char StdLibDataStructures::ID; - -#define numOps 10 -namespace { - static cl::opt noStdLibFold("dsa-stdlib-no-fold", - cl::desc("Don't fold nodes in std-lib."), - cl::Hidden, - cl::init(false)); - static cl::opt DisableStdLib("disable-dsa-stdlib", - cl::desc("Don't use DSA's stdlib pass."), - cl::Hidden, - cl::init(false)); -} - -// -// Structure: libAction -// -// Description: -// Describe how the DSGraph of a function should be built. Note that for the -// boolean arrays of arity numOps, the first element is a flag describing the -// return value, and the remaining elements are flags describing the -// function's arguments. -// -struct libAction { - // The return value/arguments that should be marked read. - bool read[numOps]; - - // The return value/arguments that should be marked modified. - bool write[numOps]; - - // The return value/arguments that should be marked as heap. - bool heap[numOps]; - - // Flags whether the return value should be merged with all arguments. - bool mergeNodes[numOps]; - - // Flags whether the return value and arguments should be folded. - bool collapse; -}; - -#define NRET_NARGS {0,0,0,0,0,0,0,0,0,0} -#define YRET_NARGS {1,0,0,0,0,0,0,0,0,0} -#define NRET_YARGS {0,1,1,1,1,1,1,1,1,1} -#define YRET_YARGS {1,1,1,1,1,1,1,1,1,1} -#define NRET_NYARGS {0,0,1,1,1,1,1,1,1,1} -#define YRET_NYARGS {1,0,1,1,1,1,1,1,1,1} -#define NRET_YNARGS {0,1,0,0,0,0,0,0,0,0} -#define YRET_YNARGS {1,1,0,0,0,0,0,0,0,0} -#define YRET_NNYARGS {1,0,0,1,1,1,1,1,1,1} -#define YRET_YNYARGS {1,1,0,1,1,1,1,1,1,1} -#define NRET_NNYARGS {0,0,0,1,1,1,1,1,1,1} -#define YRET_NNYNARGS {1,0,0,1,0,0,0,0,0,0} -#define NRET_NNNYARGS {0,0,0,0,1,1,1,1,1,1} - -const struct { - const char* name; - libAction action; -} recFuncs[] = { - {"stat", {NRET_YNARGS, NRET_NYARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fstat", {NRET_YNARGS, NRET_NYARGS, NRET_NARGS, NRET_NARGS, false}}, - {"lstat", {NRET_YNARGS, NRET_NYARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"getenv", {NRET_YNARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"getrusage", {NRET_YNARGS, YRET_NYARGS, NRET_NARGS, NRET_NARGS, false}}, - {"getrlimit", {NRET_YNARGS, YRET_NYARGS, NRET_NARGS, NRET_NARGS, false}}, - {"setrlimit", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"getcwd", {NRET_NYARGS, YRET_YNARGS, NRET_NARGS, YRET_YNARGS, false}}, - - {"select", {NRET_YARGS, YRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - {"_setjmp", {NRET_YARGS, YRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - {"longjmp", {NRET_YARGS, NRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"remove", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"rename", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"unlink", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fileno", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"create", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"write", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"read", {NRET_YARGS, YRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - {"truncate", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"open", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"chdir", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"mkdir", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"rmdir", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"chmod", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fchmod", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"kill", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pipe", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"execl", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"execlp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"execle", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"execv", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"execvp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"time", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"times", {NRET_YARGS, YRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - {"ctime", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"asctime", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"utime", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"localtime", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"gmtime", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"ftime", {NRET_YARGS, NRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - - // printf not strictly true, %n could cause a write - {"printf", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fprintf", {NRET_YARGS, NRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fprintf", {NRET_YARGS, NRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - {"sprintf", {NRET_YARGS, NRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - {"snprintf", {NRET_YARGS, NRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - {"vsnprintf", {NRET_YARGS, YRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - {"sscanf", {NRET_YARGS, YRET_NYARGS, NRET_NARGS, NRET_NARGS, false}}, - {"scanf", {NRET_YARGS, YRET_NYARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fscanf", {NRET_YARGS, YRET_NYARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"calloc", {NRET_NARGS, YRET_NARGS, YRET_NARGS, NRET_NARGS, false}}, - {"malloc", {NRET_NARGS, YRET_NARGS, YRET_NARGS, NRET_NARGS, false}}, - {"valloc", {NRET_NARGS, YRET_NARGS, YRET_NARGS, NRET_NARGS, false}}, - {"realloc", {NRET_NARGS, YRET_NARGS, YRET_YNARGS, YRET_YNARGS,false}}, - {"free", {NRET_NARGS, NRET_NARGS, NRET_YNARGS, NRET_NARGS, false}}, - - {"strdup", {NRET_YARGS, YRET_NARGS, YRET_NARGS, YRET_YARGS, false}}, - {"__strdup", {NRET_YARGS, YRET_NARGS, YRET_NARGS, YRET_YARGS, false}}, - {"wcsdup", {NRET_YARGS, YRET_NARGS, YRET_NARGS, YRET_YARGS, false}}, - - {"strlen", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"wcslen", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"atoi", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"atof", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"atol", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"atoll", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"atoq", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"memcmp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"strcmp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"wcscmp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"strncmp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"wcsncmp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"strcasecmp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"wcscasecmp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"strncasecmp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"wcsncasecmp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"strcat", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YARGS, true}}, - {"strncat", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YARGS, true}}, - - {"strcpy", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YARGS, true}}, - {"stpcpy", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YARGS, true}}, - {"wcscpy", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YARGS, true}}, - {"strncpy", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YARGS, true}}, - {"wcsncpy", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YARGS, true}}, - {"memcpy", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YARGS, true}}, - {"memccpy", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YARGS, true}}, - {"wmemccpy", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YARGS, true}}, - {"memmove", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YARGS, true}}, - - {"bcopy", {NRET_YARGS, NRET_YARGS, NRET_NARGS, NRET_YARGS, true}}, - {"bcmp", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, true}}, - - {"strerror", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, true}}, - {"clearerr", {NRET_YARGS, NRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - {"strstr", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"wcsstr", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"strspn", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, true}}, - {"wcsspn", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, true}}, - {"strcspn", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, true}}, - {"wcscspn", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, true}}, - {"strtok", {NRET_YARGS, YRET_YARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"strpbrk", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"wcspbrk", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - - {"strchr", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"wcschr", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"strrchr", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"wcsrchr", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"strchrnul", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"wcschrnul", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - - {"memchr", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"wmemchr", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"memrchr", {NRET_YARGS, YRET_NARGS, NRET_NARGS, YRET_YNARGS, true}}, - - {"memalign", {NRET_NARGS, YRET_NARGS, YRET_NARGS, NRET_NARGS, false}}, - //{"posix_memalign", {NRET_YARGS, YRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"perror", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"feof", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fflush", {NRET_YARGS, NRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fpurge", {NRET_YARGS, NRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fclose", {NRET_YARGS, NRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fopen", {NRET_YARGS, YRET_NARGS, YRET_NARGS, NRET_NARGS, false}}, - {"ftell", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fseek", {NRET_YARGS, NRET_YARGS, NRET_NARGS, NRET_NARGS, true}}, - {"rewind", {NRET_YARGS, NRET_YARGS, NRET_NARGS, NRET_NARGS, true}}, - {"ferror", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fwrite", {NRET_YARGS, NRET_NYARGS,NRET_NARGS, NRET_NARGS, false}}, - {"fread", {NRET_NYARGS, NRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fdopen", {NRET_YARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"__errno_location", {NRET_NARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"puts", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"gets", {NRET_NARGS, YRET_YARGS, NRET_NARGS, YRET_YNARGS, false}}, - {"fgets", {NRET_NYARGS, YRET_YNARGS, NRET_NARGS, YRET_YNARGS, false}}, - {"getc", {NRET_YNARGS, YRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - {"ungetc", {NRET_YNARGS, YRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - {"_IO_getc", {NRET_YNARGS, YRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fgetc", {NRET_YNARGS, YRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - {"putc", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"_IO_putc", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"putchar", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fputs", {NRET_YARGS, NRET_NYARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fputc", {NRET_YARGS, NRET_NYARGS, NRET_NARGS, NRET_NARGS, false}}, - - - // SAFECode Intrinsics - {"pool_init_logfile",{NRET_YNARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheck", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheckui", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheckstr", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheckstrui", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fastlscheck", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheckalign", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheckalignui", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheck_free", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheck_freeui", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"funccheck", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"funccheckui", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"poolcheck_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheckui_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheckstr_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheckstrui_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"fastlscheck_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheckalign_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheckalignui_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheck_free_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"poolcheck_freeui_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"funccheck_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"funccheckui_debug",{NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"pool_register_stack", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_unregister_stack", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_register_global", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_unregister_global", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_register", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_unregister", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_argvregister", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - {"pool_register_stack_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_unregister_stack_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_register_global_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_unregister_global_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_register_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_unregister_debug", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - // CIF Intrinsics - {"__if_pool_get_label", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"__if_pool_set_label", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - // CStdLib Runtime Wrapper Functions - {"pool_strncpy", {NRET_NNYARGS, YRET_NNYARGS, NRET_NARGS, YRET_NNYARGS, true}}, - {"pool_strcpy", {NRET_NNYARGS, YRET_NNYARGS, NRET_NARGS, YRET_NNYARGS, true}}, - {"pool_stpcpy", {NRET_NNYARGS, YRET_NNYARGS, NRET_NARGS, YRET_NNYARGS, true}}, - // strchr and index have same functionality - {"pool_strchr", {NRET_NYARGS, YRET_NARGS, NRET_NARGS, YRET_NYARGS, true}}, - {"pool_index", {NRET_NYARGS, YRET_NARGS, NRET_NARGS, YRET_NYARGS, true}}, - // strrchr and rindex have same functionality - {"pool_strrchr", {NRET_NYARGS, YRET_NARGS, NRET_NARGS, YRET_NYARGS, true}}, - {"pool_rindex", {NRET_NYARGS, YRET_NARGS, NRET_NARGS, YRET_NYARGS, true}}, - {"pool_strcat", {NRET_NNYARGS, YRET_NNYARGS, NRET_NARGS, YRET_NNYARGS, true}}, - {"pool_strncat", {NRET_NNYARGS, YRET_NNYARGS, NRET_NARGS, YRET_NNYARGS, true}}, - {"pool_strstr", {NRET_NNYARGS, YRET_NARGS, NRET_NARGS, YRET_NNYNARGS, true}}, - {"pool_strcasestr", {NRET_NNYARGS, YRET_NARGS, NRET_NARGS, YRET_NNYNARGS, true}}, - {"pool_strpbrk", {NRET_NNYARGS, YRET_NARGS, NRET_NARGS, YRET_NNYNARGS, true}}, - {"pool_strspn", {NRET_NYARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, true}}, - {"pool_strcspn", {NRET_NYARGS, YRET_NARGS, NRET_NARGS, NRET_NARGS, true}}, - {"pool_memccpy", {NRET_NNYARGS, YRET_NNYARGS, NRET_NARGS, YRET_NNYARGS, true}}, - {"pool_memchr", {NRET_NYARGS, YRET_NARGS, NRET_NARGS, YRET_NYARGS, true}}, - {"pool_strcmp", {NRET_NNYARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_strncmp", {NRET_NNYARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_strlen", {NRET_NYARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_strnlen", {NRET_NYARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_memcmp", {NRET_NNYARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_strcasecmp", {NRET_NNYARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_strncasecmp",{NRET_NNYARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_bcopy", {NRET_NNYARGS, NRET_NNNYARGS, NRET_NARGS, NRET_NNYARGS, true}}, - {"pool_bcmp", {NRET_NNYARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_read", {NRET_NARGS, NRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_recv", {NRET_NARGS, NRET_YARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_write", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_send", {NRET_YARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_readlink", {NRET_YNARGS, NRET_NYARGS, NRET_NARGS, NRET_NARGS, true}}, - {"pool_realpath", {NRET_YNARGS, NRET_NYARGS, NRET_NARGS, NRET_NARGS, true}}, - {"pool_getcwd", {NRET_YARGS, NRET_NYARGS, NRET_NARGS, YRET_NYARGS, false}}, - - // format string intrinsics and functions - {"sc.fsparameter", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"sc.fscallinfo", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"sc.fscallinfo_debug",{NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_printf", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_fprintf", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_sprintf", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_snprintf", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_err", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_errx", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_warn", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_warnx", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_syslog", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_scanf", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_fscanf", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool_sscanf", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool___printf_chk", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool___fprintf_chk", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool___sprintf_chk", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"pool___snprintf_chk", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - - // Important C I/O functions - {"pool_fgets", {NRET_NNYARGS, YRET_YNYARGS, NRET_NARGS, YRET_YNARGS, true}}, - {"pool_fgets_debug",{NRET_NNYARGS, YRET_YNYARGS, NRET_NARGS, YRET_YNARGS, true}}, - - // Type Checks - {"trackArgvType", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackEnvpType", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackGlobal", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackArray", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackStoreInst", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackStringInput", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"compareTypeAndNumber", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"compareVAArgType", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"getTypeTag", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"checkType", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackInitInst", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackUnInitInst", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"copyTypeInfo", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"setTypeInfo", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"setVAInfo", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"copyVAInfo", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackctype", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackctype_32", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackStrcpyInst", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackStrcnpyInst", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackStrcatInst", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackgetcwd", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackgetpwuid", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackgethostname", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackgethostbyname", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackgetservbyname", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackgetaddrinfo", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackgetsockname", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackaccept", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackpoll", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackpipe", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - {"trackReadLink", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - -#if 0 - {"wait", {false, false, false, false, true, false, false, false, false}}, -#endif - - // C++ functions, as mangled on linux gcc 4.2 - // operator new(unsigned long) - {"_Znwm", {NRET_NARGS, YRET_NARGS, YRET_NARGS, NRET_NARGS, false}}, - // operator new[](unsigned long) - {"_Znam", {NRET_NARGS, YRET_NARGS, YRET_NARGS, NRET_NARGS, false}}, - // operator new(unsigned int) - {"_Znwj", {NRET_NARGS, YRET_NARGS, YRET_NARGS, NRET_NARGS, false}}, - // operator new[](unsigned int) - {"_Znaj", {NRET_NARGS, YRET_NARGS, YRET_NARGS, NRET_NARGS, false}}, - // operator delete(void*) - {"_ZdlPv", {NRET_NARGS, NRET_NARGS, NRET_YNARGS,NRET_NARGS, false}}, - // operator delete[](void*) - {"_ZdaPv", {NRET_NARGS, NRET_NARGS, NRET_YNARGS, NRET_NARGS, false}}, - // flush - {"_ZNSo5flushEv", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - // << operator - {"_ZNSolsEd", {NRET_YARGS, NRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - // << operator - {"_ZNSolsEPFRSoS_E", {NRET_YARGS, NRET_YNARGS, NRET_NARGS, NRET_NARGS, false}}, - //endl - {"_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_", {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, - // Added by Jingyue - {"strtoll", {NRET_YARGS, NRET_NYARGS, NRET_NYARGS, NRET_YARGS, false}}, - // Terminate the list of special functions recognized by this pass - {0, {NRET_NARGS, NRET_NARGS, NRET_NARGS, NRET_NARGS, false}}, -}; - -/* - Functions to add - freopen - strftime - strtoul - strtol - strtoll - ctype family - setbuf - setvbuf - __strpbrk_c3 - open64/fopen64/lseek64 - */ - -// -// Method: eraseCallsTo() -// -// Description: -// This method removes the specified function from DSCallsites within the -// specified function. We do not do anything with call sites that call this -// function indirectly (for which there is not much point as we do not yet -// know the targets of indirect function calls). -// -void -StdLibDataStructures::eraseCallsTo(Function* F) { - typedef std::pair RemovalPair; - DenseSet ToRemove; - for (Value::user_iterator ii = F->user_begin(), ee = F->user_end(); - ii != ee; ++ii) - if (CallInst* CI = dyn_cast(*ii)){ - if (CI->getCalledValue() == F) { - DSGraph* Graph = getDSGraph(*CI->getParent()->getParent()); - //delete the call - SDEBUG(errs() << "Removing " << F->getName().str() << " from " - << CI->getParent()->getParent()->getName().str() << "\n"); - ToRemove.insert(std::make_pair(Graph, F)); - } - }else if (InvokeInst* CI = dyn_cast(*ii)){ - if (CI->getCalledValue() == F) { - DSGraph* Graph = getDSGraph(*CI->getParent()->getParent()); - //delete the call - SDEBUG(errs() << "Removing " << F->getName().str() << " from " - << CI->getParent()->getParent()->getName().str() << "\n"); - ToRemove.insert(std::make_pair(Graph, F)); - } - } else if(ConstantExpr *CE = dyn_cast(*ii)) { - if(CE->isCast()) { - for (Value::user_iterator ci = CE->user_begin(), ce = CE->user_end(); - ci != ce; ++ci) { - if (CallInst* CI = dyn_cast(*ci)){ - if(CI->getCalledValue() == CE) { - DSGraph* Graph = getDSGraph(*CI->getParent()->getParent()); - //delete the call - SDEBUG(errs() << "Removing " << F->getName().str() << " from " - << CI->getParent()->getParent()->getName().str() << "\n"); - ToRemove.insert(std::make_pair(Graph, F)); - } - } - } - } - } - - for(DenseSet::iterator I = ToRemove.begin(), E = ToRemove.end(); - I != E; ++I) - I->first->removeFunctionCalls(*I->second); -} - -// -// Function: processRuntimeCheck() -// -// Description: -// Modify a run-time check so that its return value has the same DSNode as the -// checked pointer. -// -// Inputs: -// M - The module in which calls to the function live. -// name - The name of the function for which direct calls should be processed. -// arg - The argument index that contains the pointer which the run-time -// check returns. -// -void -StdLibDataStructures::processRuntimeCheck (Module & M, - std::string name, - unsigned arg) { - // - // Get a pointer to the function. - // - Function* F = M.getFunction (name); - - // - // If the function doesn't exist, then there is no work to do. - // - if (!F) return; - - // - // Scan through all direct calls to the function (there should only be direct - // calls) and process each one. - // - for (Value::user_iterator ii = F->user_begin(), ee = F->user_end(); - ii != ee; ++ii) { - if (CallInst* CI = dyn_cast(*ii)) { - if (CI->getCalledValue() == F) { - DSGraph* Graph = getDSGraph(*CI->getParent()->getParent()); - DSNodeHandle & RetNode = Graph->getNodeForValue(CI); - DSNodeHandle & ArgNode = Graph->getNodeForValue(CI->getArgOperand(arg)); - RetNode.mergeWith(ArgNode); - } - } - } - - // - // Erase the DSCallSites for this function. This should prevent other DSA - // passes from making the DSNodes passed to/returned from the function - // from becoming Incomplete or External. - // - eraseCallsTo (F); - return; -} - -bool -StdLibDataStructures::runOnModule (Module &M) { - // - // Get the results from the local pass. - // - init (&getAnalysis(), true, true, false, false); - AllocWrappersAnalysis = &getAnalysis(); - - // - // Fetch the DSGraphs for all defined functions within the module. - // - for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) - if (!I->isDeclaration()) - getOrCreateGraph(&*I); - - // - // Erase direct calls to functions that don't return a pointer and are marked - // with the readnone annotation. - // - for (Function &F : M) - if (F.isDeclaration() && F.doesNotAccessMemory() && - !isa(F.getReturnType())) - eraseCallsTo(&F); - - // - // Erase direct calls to external functions that are not varargs, do not - // return a pointer, and do not take pointers. - // - for (Function &F : M) - if (F.isDeclaration() && !F.isVarArg() && - !isa(F.getReturnType())) { - bool hasPtr = false; - for (auto &Arg : F.args()) - if (isa(Arg.getType())) { - hasPtr = true; - break; - } - if (!hasPtr) - eraseCallsTo(&F); - } - - if(!DisableStdLib) { - - // - // Scan through the function summaries and process functions by summary. - // - for (int x = 0; recFuncs[x].name; ++x) - if (Function* F = M.getFunction(recFuncs[x].name)) - if (F->isDeclaration()) { - processFunction(x, F); - } - - std::set::iterator ai = AllocWrappersAnalysis->alloc_begin(); - std::set::iterator ae = AllocWrappersAnalysis->alloc_end(); - int x; - for (x = 0; recFuncs[x].name; ++x) { - if(recFuncs[x].name == std::string("malloc")) - break; - } - - for(;ai != ae; ++ai) { - if(Function* F = M.getFunction(*ai)) - processFunction(x, F); - } - - ai = AllocWrappersAnalysis->dealloc_begin(); - ae = AllocWrappersAnalysis->dealloc_end(); - for (x = 0; recFuncs[x].name; ++x) { - if(recFuncs[x].name == std::string("free")) - break; - } - - for(;ai != ae; ++ai) { - if(Function* F = M.getFunction(*ai)) - processFunction(x, F); - } - - // - // Merge return values and checked pointer values for SAFECode run-time - // checks. - // - processRuntimeCheck (M, "boundscheck", 2); - processRuntimeCheck (M, "boundscheckui", 2); - processRuntimeCheck (M, "exactcheck2", 1); - - processRuntimeCheck (M, "boundscheck_debug", 2); - processRuntimeCheck (M, "boundscheckui_debug", 2); - processRuntimeCheck (M, "exactcheck2_debug", 1); - - processRuntimeCheck (M, "pchk_getActualValue", 1); - } - - // - // In the Local DSA Pass, we marked nodes passed to/returned from 'StdLib' - // functions as External because, at that point, they were. However, they no - // longer are necessarily External, and we need to update accordingly. - // - GlobalsGraph->maskIncompleteMarkers(); - - GlobalsGraph->computeExternalFlags(DSGraph::ResetExternal); - for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) - if (!I->isDeclaration()) { - DSGraph * G = getDSGraph(*I); - unsigned EFlags = 0 - | DSGraph::ResetExternal - | DSGraph::DontMarkFormalsExternal - | DSGraph::ProcessCallSites; - G->maskIncompleteMarkers(); - G->markIncompleteNodes(DSGraph::MarkFormalArgs - |DSGraph::IgnoreGlobals); - G->computeExternalFlags(EFlags); - SDEBUG(G->AssertGraphOK()); - } - GlobalsGraph->markIncompleteNodes(DSGraph::MarkFormalArgs - |DSGraph::IgnoreGlobals); - GlobalsGraph->computeExternalFlags(DSGraph::ProcessCallSites); - SDEBUG(GlobalsGraph->AssertGraphOK()); - for (Function &F : M) - if (!F.isDeclaration()) { - DSGraph *Graph = getOrCreateGraph(&F); - Graph->maskIncompleteMarkers(); - cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes); - Graph->markIncompleteNodes(DSGraph::MarkFormalArgs - |DSGraph::IgnoreGlobals); - } - - return false; -} - - -void StdLibDataStructures::processFunction(int x, Function *F) { - for (Value::user_iterator ii = F->user_begin(), ee = F->user_end(); - ii != ee; ++ii) - - if (CallInst* CI = dyn_cast(*ii)){ - if (CI->getCalledValue() == F) { - DSGraph* Graph = getDSGraph(*CI->getParent()->getParent()); - - // - // Set the read, write, and heap markers on the return value - // as appropriate. - // - if(isa((CI)->getType())){ - if(Graph->hasNodeForValue(CI)){ - if (recFuncs[x].action.read[0]) - Graph->getNodeForValue(CI).getNode()->setReadMarker(); - if (recFuncs[x].action.write[0]) - Graph->getNodeForValue(CI).getNode()->setModifiedMarker(); - if (recFuncs[x].action.heap[0]) - Graph->getNodeForValue(CI).getNode()->setHeapMarker(); - } - } - - // - // Set the read, write, and heap markers on the actual arguments - // as appropriate. - // - for (unsigned y = 0; y < CI->getNumArgOperands(); ++y) - if (isa(CI->getArgOperand(y)->getType())){ - if (Graph->hasNodeForValue(CI->getArgOperand(y))){ - if (recFuncs[x].action.read[y + 1]) - Graph->getNodeForValue(CI->getArgOperand(y)).getNode()->setReadMarker(); - if (recFuncs[x].action.write[y + 1]) - Graph->getNodeForValue(CI->getArgOperand(y)).getNode()->setModifiedMarker(); - if (recFuncs[x].action.heap[y + 1]) - Graph->getNodeForValue(CI->getArgOperand(y)).getNode()->setHeapMarker(); - } - } - - // - // Merge the DSNoes for return values and parameters as - // appropriate. - // - std::vector toMerge; - if (recFuncs[x].action.mergeNodes[0]) - if (isa(CI->getType())) - if (Graph->hasNodeForValue(CI)) - toMerge.push_back(Graph->getNodeForValue(CI)); - for (unsigned y = 0; y < CI->getNumArgOperands(); ++y) - if (recFuncs[x].action.mergeNodes[y + 1]) - if (isa(CI->getArgOperand(y)->getType())) - if (Graph->hasNodeForValue(CI->getArgOperand(y))) - toMerge.push_back(Graph->getNodeForValue(CI->getArgOperand(y))); - for (unsigned y = 1; y < toMerge.size(); ++y) - toMerge[0].mergeWith(toMerge[y]); - - // - // Collapse (fold) the DSNode of the return value and the actual - // arguments if directed to do so. - // - if (!noStdLibFold && recFuncs[x].action.collapse) { - if (isa(CI->getType())){ - if (Graph->hasNodeForValue(CI)) - Graph->getNodeForValue(CI).getNode()->foldNodeCompletely(); - NumNodesFoldedInStdLib++; - } - for (unsigned y = 0; y < CI->getNumArgOperands(); ++y){ - if (isa(CI->getArgOperand(y)->getType())){ - if (Graph->hasNodeForValue(CI->getArgOperand(y))){ - Graph->getNodeForValue(CI->getArgOperand(y)).getNode()->foldNodeCompletely(); - NumNodesFoldedInStdLib++; - } - } - } - } - } - } else if (InvokeInst* CI = dyn_cast(*ii)){ - if (CI->getCalledValue() == F) { - DSGraph* Graph = getDSGraph(*CI->getParent()->getParent()); - - // - // Set the read, write, and heap markers on the return value - // as appropriate. - // - if(isa((CI)->getType())){ - if(Graph->hasNodeForValue(CI)){ - if (recFuncs[x].action.read[0]) - Graph->getNodeForValue(CI).getNode()->setReadMarker(); - if (recFuncs[x].action.write[0]) - Graph->getNodeForValue(CI).getNode()->setModifiedMarker(); - if (recFuncs[x].action.heap[0]) - Graph->getNodeForValue(CI).getNode()->setHeapMarker(); - } - } - - // - // Set the read, write, and heap markers on the actual arguments - // as appropriate. - // - for (unsigned y = 0; y < CI->getNumArgOperands(); ++y) - if (isa(CI->getArgOperand(y)->getType())){ - if (Graph->hasNodeForValue(CI->getArgOperand(y))){ - if (recFuncs[x].action.read[y + 1]) - Graph->getNodeForValue(CI->getArgOperand(y)).getNode()->setReadMarker(); - if (recFuncs[x].action.write[y + 1]) - Graph->getNodeForValue(CI->getArgOperand(y)).getNode()->setModifiedMarker(); - if (recFuncs[x].action.heap[y + 1]) - Graph->getNodeForValue(CI->getArgOperand(y)).getNode()->setHeapMarker(); - } - } - - // - // Merge the DSNoes for return values and parameters as - // appropriate. - // - std::vector toMerge; - if (recFuncs[x].action.mergeNodes[0]) - if (isa(CI->getType())) - if (Graph->hasNodeForValue(CI)) - toMerge.push_back(Graph->getNodeForValue(CI)); - for (unsigned y = 0; y < CI->getNumArgOperands(); ++y) - if (recFuncs[x].action.mergeNodes[y + 1]) - if (isa(CI->getArgOperand(y)->getType())) - if (Graph->hasNodeForValue(CI->getArgOperand(y))) - toMerge.push_back(Graph->getNodeForValue(CI->getArgOperand(y))); - for (unsigned y = 1; y < toMerge.size(); ++y) - toMerge[0].mergeWith(toMerge[y]); - - // - // Collapse (fold) the DSNode of the return value and the actual - // arguments if directed to do so. - // - if (!noStdLibFold && recFuncs[x].action.collapse) { - if (isa(CI->getType())){ - if (Graph->hasNodeForValue(CI)) - Graph->getNodeForValue(CI).getNode()->foldNodeCompletely(); - NumNodesFoldedInStdLib++; - } - for (unsigned y = 0; y < CI->getNumArgOperands(); ++y){ - if (isa(CI->getArgOperand(y)->getType())){ - if (Graph->hasNodeForValue(CI->getArgOperand(y))){ - Graph->getNodeForValue(CI->getArgOperand(y)).getNode()->foldNodeCompletely(); - NumNodesFoldedInStdLib++; - } - } - } - } - } - } else if(ConstantExpr *CE = dyn_cast(*ii)) { - if(CE->isCast()) - for (Value::user_iterator ci = CE->user_begin(), ce = CE->user_end(); - ci != ce; ++ci) { - - if (CallInst* CI = dyn_cast(*ci)){ - if (CI->getCalledValue() == CE) { - DSGraph* Graph = getDSGraph(*CI->getParent()->getParent()); - - // - // Set the read, write, and heap markers on the return value - // as appropriate. - // - if(isa((CI)->getType())){ - if(Graph->hasNodeForValue(CI)){ - if (recFuncs[x].action.read[0]) - Graph->getNodeForValue(CI).getNode()->setReadMarker(); - if (recFuncs[x].action.write[0]) - Graph->getNodeForValue(CI).getNode()->setModifiedMarker(); - if (recFuncs[x].action.heap[0]) - Graph->getNodeForValue(CI).getNode()->setHeapMarker(); - } - } - - // - // Set the read, write, and heap markers on the actual arguments - // as appropriate. - // - for (unsigned y = 0; y < CI->getNumArgOperands(); ++y) - if (recFuncs[x].action.read[y + 1]){ - if (isa(CI->getArgOperand(y)->getType())){ - if (Graph->hasNodeForValue(CI->getArgOperand(y))) - Graph->getNodeForValue(CI->getArgOperand(y)).getNode()->setReadMarker(); - if (Graph->hasNodeForValue(CI->getArgOperand(y))) - Graph->getNodeForValue(CI->getArgOperand(y)).getNode()->setModifiedMarker(); - if (Graph->hasNodeForValue(CI->getArgOperand(y))) - Graph->getNodeForValue(CI->getArgOperand(y)).getNode()->setHeapMarker(); - } - } - - // - // Merge the DSNoes for return values and parameters as - // appropriate. - // - std::vector toMerge; - if (recFuncs[x].action.mergeNodes[0]) - if (isa(CI->getType())) - if (Graph->hasNodeForValue(CI)) - toMerge.push_back(Graph->getNodeForValue(CI)); - for (unsigned y = 0; y < CI->getNumArgOperands(); ++y) - if (recFuncs[x].action.mergeNodes[y + 1]) - if (isa(CI->getArgOperand(y)->getType())) - if (Graph->hasNodeForValue(CI->getArgOperand(y))) - toMerge.push_back(Graph->getNodeForValue(CI->getArgOperand(y))); - for (unsigned y = 1; y < toMerge.size(); ++y) - toMerge[0].mergeWith(toMerge[y]); - - // - // Collapse (fold) the DSNode of the return value and the actual - // arguments if directed to do so. - // - if (!noStdLibFold && recFuncs[x].action.collapse) { - if (isa(CI->getType())){ - if (Graph->hasNodeForValue(CI)) - Graph->getNodeForValue(CI).getNode()->foldNodeCompletely(); - NumNodesFoldedInStdLib++; - } - for (unsigned y = 0; y < CI->getNumArgOperands(); ++y) - if (isa(CI->getArgOperand(y)->getType())){ - if (Graph->hasNodeForValue(CI->getArgOperand(y))){ - DSNode * Node=Graph->getNodeForValue(CI->getArgOperand(y)).getNode(); - Node->foldNodeCompletely(); - NumNodesFoldedInStdLib++; - } - } - } - } - } - } - } - - // - // Pretend that this call site does not call this function anymore. - // - eraseCallsTo(F); -} diff --git a/lib/DSA/TopDownClosure.cpp b/lib/DSA/TopDownClosure.cpp deleted file mode 100644 index 3e50bb6e5..000000000 --- a/lib/DSA/TopDownClosure.cpp +++ /dev/null @@ -1,425 +0,0 @@ -//===- TopDownClosure.cpp - Compute the top-down interprocedure closure ---===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the TDDataStructures class, which represents the -// Top-down Interprocedural closure of the data structure graph over the -// program. This is useful (but not strictly necessary?) for applications -// like pointer analysis. -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "td_dsa" - -#include "dsa/DataStructure.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/DerivedTypes.h" -#include "dsa/DSGraph.h" -#include "smack/Debug.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/Timer.h" -#include "llvm/ADT/Statistic.h" -using namespace llvm; - -#define TIME_REGION(VARNAME, DESC) - -namespace { - RegisterPass // Register the pass - Y("dsa-td", "Top-down Data Structure Analysis"); - - RegisterPass // Register the pass - Z("dsa-eqtd", "EQ Top-down Data Structure Analysis"); - - STATISTIC (NumTDInlines, "Number of graphs inlined"); -} - -char TDDataStructures::ID; -char EQTDDataStructures::ID; - -TDDataStructures::~TDDataStructures() { - releaseMemory(); -} - -EQTDDataStructures::~EQTDDataStructures() { - releaseMemory(); -} - -void TDDataStructures::markReachableFunctionsExternallyAccessible(DSNode *N, - DenseSet &Visited) { - if (!N || Visited.count(N)) return; - Visited.insert(N); - - // Handle this node - { - N->addFullFunctionSet(ExternallyCallable); - } - - for (DSNode::edge_iterator ii = N->edge_begin(), - ee = N->edge_end(); ii != ee; ++ii) - if (!ii->second.isNull()) { - DSNodeHandle &NH = ii->second; - DSNode * NN = NH.getNode(); - NN->addFullFunctionSet(ExternallyCallable); - markReachableFunctionsExternallyAccessible(NN, Visited); - } -} - - -// run - Calculate the top down data structure graphs for each function in the -// program. -// -bool TDDataStructures::runOnModule(Module &M) { - - init(useEQBU ? &getAnalysis() - : &getAnalysis(), - true, true, true, false); - // Figure out which functions must not mark their arguments complete because - // they are accessible outside this compilation unit. Currently, these - // arguments are functions which are reachable by incomplete or external - // nodes in the globals graph. - const DSScalarMap &GGSM = GlobalsGraph->getScalarMap(); - DenseSet Visited; - for (DSScalarMap::global_iterator I=GGSM.global_begin(), E=GGSM.global_end(); - I != E; ++I) { - DSNode *N = GGSM.find(*I)->second.getNode(); - if (N->isIncompleteNode() || N->isExternalNode()) - markReachableFunctionsExternallyAccessible(N, Visited); - } - - // Loop over unresolved call nodes. Any functions passed into (but not - // returned!) from unresolvable call nodes may be invoked outside of the - // current module. - for (DSGraph::afc_iterator I = GlobalsGraph->afc_begin(), - E = GlobalsGraph->afc_end(); I != E; ++I) - for (unsigned arg = 0, e = I->getNumPtrArgs(); arg != e; ++arg) - markReachableFunctionsExternallyAccessible(I->getPtrArg(arg).getNode(), - Visited); - Visited.clear(); - - // Clear Aux of Globals Graph to be refilled in later by post-TD unresolved - // functions - GlobalsGraph->getAuxFunctionCalls().clear(); - - // Functions without internal linkage are definitely externally callable! - for (Function &F : M) - if (!F.isDeclaration() && !F.hasInternalLinkage() && !F.hasPrivateLinkage()) - ExternallyCallable.insert(&F); - - // Debug code to print the functions that are externally callable -#if 0 - for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) - if (ExternallyCallable.count(I)) { - errs() << "ExternallyCallable: " << I->getNameStr() << "\n"; - } -#endif - - // We want to traverse the call graph in reverse post-order. To do this, we - // calculate a post-order traversal, then reverse it. - DenseSet VisitedGraph; - std::vector PostOrder; - -{TIME_REGION(XXX, "td:Compute postorder"); - - // Calculate top-down from main... - if (Function *F = M.getFunction("main")) - ComputePostOrder(*F, VisitedGraph, PostOrder); - - // Next calculate the graphs for each unreachable function... - for (Function &F : M) - if (!F.isDeclaration()) - ComputePostOrder(F, VisitedGraph, PostOrder); - - VisitedGraph.clear(); // Release memory! -} - -{TIME_REGION(XXX, "td:Inline stuff"); - - // Visit each of the graphs in reverse post-order now! - while (!PostOrder.empty()) { - InlineCallersIntoGraph(PostOrder.back()); - PostOrder.pop_back(); - } -} - - // Free the IndCallMap. - while (!IndCallMap.empty()) { - delete IndCallMap.begin()->second; - IndCallMap.erase(IndCallMap.begin()); - } - - formGlobalECs(); - - ExternallyCallable.clear(); - GlobalsGraph->removeTriviallyDeadNodes(); - GlobalsGraph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); - GlobalsGraph->computeIntPtrFlags(); - - // Make sure each graph has updated external information about globals - // in the globals graph. - VisitedGraph.clear(); - for (Function &F : M) { - if (!(F.isDeclaration())){ - DSGraph *Graph = getOrCreateGraph(&F); - if (!VisitedGraph.insert(Graph).second) continue; - - cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes); - - Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); - Graph->computeIntPtrFlags(); - // Clean up uninteresting nodes - Graph->removeDeadNodes(0); - - } - } - - // CBU contains the correct call graph. - // Restore it, so that subsequent passes and clients can get it. - restoreCorrectCallGraph(); - SDEBUG(print(errs(), &M)); - return false; -} - - -void TDDataStructures::ComputePostOrder(const Function &F, - DenseSet &Visited, - std::vector &PostOrder) { - if (F.isDeclaration()) return; - DSGraph* G = getOrCreateGraph(&F); - if (!Visited.insert(G).second) return; - - // Recursively traverse all of the callee graphs. - svset Callees; - - // Go through all of the callsites in this graph and find all callees - // Here we're trying to capture all possible callees so that we can ensure - // each function has all possible callers inlined into it. - for (DSGraph::fc_iterator CI = G->fc_begin(), E = G->fc_end(); - CI != E; ++CI) { - // Direct calls are easy, no reason to look at DSCallGraph - // or anything to do with SCC's - if (CI->isDirectCall()) { - ComputePostOrder(*CI->getCalleeFunc(), Visited, PostOrder); - } - else { - // Otherwise, ask the DSCallGraph for the full set of possible - // callees for this callsite. - // This includes all members of the SCC's of those callees, - // and well as others in F's SCC, since we must assume - // any indirect call might be intra-SCC. - callgraph.addFullFunctionSet(CI->getCallSite(), Callees); - } - } - - for (svset::iterator I = Callees.begin(), - E = Callees.end(); I != E; ++I) - ComputePostOrder(**I, Visited, PostOrder); - - PostOrder.push_back(G); -} - -/// InlineCallersIntoGraph - Inline all of the callers of the specified DS graph -/// into it, then recompute completeness of nodes in the resultant graph. -void TDDataStructures::InlineCallersIntoGraph(DSGraph* DSG) { - // Inline caller graphs into this graph. First step, get the list of call - // sites that call into this graph. - std::vector EdgesFromCaller; - std::map >::iterator - CEI = CallerEdges.find(DSG); - if (CEI != CallerEdges.end()) { - std::swap(CEI->second, EdgesFromCaller); - CallerEdges.erase(CEI); - } - - // Sort the caller sites to provide a by-caller-graph ordering. - std::sort(EdgesFromCaller.begin(), EdgesFromCaller.end()); - - - // Merge information from the globals graph into this graph. FIXME: This is - // stupid. Instead of us cloning information from the GG into this graph, - // then having RemoveDeadNodes clone it back, we should do all of this as a - // post-pass over all of the graphs. We need to take cloning out of - // removeDeadNodes and gut removeDeadNodes at the same time first though. :( - cloneGlobalsInto(DSG, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes); - - SDEBUG(errs() << "[TD] Inlining callers into '" - << DSG->getFunctionNames() << "'\n"); - - DSG->maskIncompleteMarkers(); - // Iteratively inline caller graphs into this graph. - while (!EdgesFromCaller.empty()) { - DSGraph* CallerGraph = EdgesFromCaller.back().CallerGraph; - - // Iterate through all of the call sites of this graph, cloning and merging - // any nodes required by the call. - ReachabilityCloner RC(DSG, CallerGraph, - DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes); - - // Inline all call sites from this caller graph. - do { - const DSCallSite &CS = *EdgesFromCaller.back().CS; - const Function &CF = *EdgesFromCaller.back().CalledFunction; - SDEBUG(errs() << " [TD] Inlining graph into Fn '" - << CF.getName().str() << "' from "); - if (CallerGraph->getReturnNodes().empty()) { - SDEBUG(errs() << "SYNTHESIZED INDIRECT GRAPH"); - } else { - SDEBUG(errs() << "Fn '" << CS.getCallSite().getInstruction()-> - getParent()->getParent()->getName().str() << "'"); - } - SDEBUG(errs() << ": " << CF.getFunctionType()->getNumParams() - << " args\n"); - - // Get the formal argument and return nodes for the called function and - // merge them with the cloned subgraph. - DSCallSite T1 = DSG->getCallSiteForArguments(CF); - RC.mergeCallSite(T1, CS); - ++NumTDInlines; - - EdgesFromCaller.pop_back(); - } while (!EdgesFromCaller.empty() && - EdgesFromCaller.back().CallerGraph == CallerGraph); - } - - - - // Next, now that this graph is finalized, we need to recompute the - // incompleteness markers for this graph and remove unreachable nodes. - - // If any of the functions is externally callable, treat everything in its - // SCC as externally callable. - bool isExternallyCallable = false; - for (DSGraph::retnodes_iterator I = DSG->retnodes_begin(), - E = DSG->retnodes_end(); I != E; ++I) - if (ExternallyCallable.count(I->first)) { - isExternallyCallable = true; - break; - } - - // Recompute the Incomplete markers. Depends on whether args are complete - unsigned IncFlags = DSGraph::IgnoreFormalArgs; - IncFlags |= DSGraph::IgnoreGlobals | DSGraph::MarkVAStart; - DSG->markIncompleteNodes(IncFlags); - - // If this graph contains functions that are externally callable, now is the time to mark - // their arguments and return values as external. At this point TD is inlining all caller information, - // and that means External callers too. - unsigned ExtFlags - = isExternallyCallable ? DSGraph::MarkFormalsExternal : DSGraph::DontMarkFormalsExternal; - DSG->computeExternalFlags(ExtFlags); - DSG->computeIntPtrFlags(); - - cloneIntoGlobals(DSG, DSGraph::DontCloneCallNodes | - DSGraph::DontCloneAuxCallNodes); - // - // Delete dead nodes. Treat globals that are unreachable as dead also. - // - // FIXME: - // Do not delete unreachable globals as the comment describes. For its - // alignment checks on the results of load instructions, SAFECode must be - // able to find the DSNode of both the result of the load as well as the - // pointer dereferenced by the load. If we remove unreachable globals, then - // if the dereferenced pointer is a global, its DSNode will not reachable - // from the local graph's scalar map, and chaos ensues. - // - // So, for now, just remove dead nodes but leave the globals alone. - // - DSG->removeDeadNodes(0); - - // We are done with computing the current TD Graph! Finally, before we can - // finish processing this function, we figure out which functions it calls and - // records these call graph edges, so that we have them when we process the - // callee graphs. - if (DSG->fc_begin() == DSG->fc_end()) return; - - // Loop over all the call sites and all the callees at each call site, and add - // edges to the CallerEdges structure for each callee. - for (DSGraph::fc_iterator CI = DSG->fc_begin(), E = DSG->fc_end(); - CI != E; ++CI) { - - // Handle direct calls efficiently. - if (CI->isDirectCall()) { - if (!CI->getCalleeFunc()->isDeclaration() && - !DSG->getReturnNodes().count(CI->getCalleeFunc())) - CallerEdges[getOrCreateGraph(CI->getCalleeFunc())] - .push_back(CallerCallEdge(DSG, &*CI, CI->getCalleeFunc())); - continue; - } - - svset AllCallees; - std::vector Callees; - - // Get the list of callees - callgraph.addFullFunctionSet(CI->getCallSite(), AllCallees); - - // Filter all non-declarations, and calls within this DSGraph - for (svset::iterator I = AllCallees.begin(), - E = AllCallees.end(); I != E; ++I) { - const Function *F = *I; - if (!F->isDeclaration() && getDSGraph(**I) != DSG) - Callees.push_back(F); - } - AllCallees.clear(); - - // If there is exactly one callee from this call site, remember the edge in - // CallerEdges. - if (Callees.size() == 1) { - const Function * Callee = Callees[0]; - CallerEdges[getOrCreateGraph(Callee)] - .push_back(CallerCallEdge(DSG, &*CI, Callee)); - } - if (Callees.size() <= 1) continue; - - // Otherwise, there are multiple callees from this call site, so it must be - // an indirect call. Chances are that there will be other call sites with - // this set of targets. If so, we don't want to do M*N inlining operations, - // so we build up a new, private, graph that represents the calls of all - // calls to this set of functions. - - std::map, DSGraph*>::iterator IndCallRecI = - IndCallMap.lower_bound(Callees); - - // If we already have this graph, recycle it. - if (IndCallRecI != IndCallMap.end() && IndCallRecI->first == Callees) { - SDEBUG(errs() << " [TD] *** Reuse of indcall graph for " << Callees.size() - << " callees!\n"); - DSGraph * IndCallGraph = IndCallRecI->second; - assert(IndCallGraph->getFunctionCalls().size() == 1); - - // Merge the call into the CS already in the IndCallGraph - ReachabilityCloner RC(IndCallGraph, DSG, 0); - RC.mergeCallSite(IndCallGraph->getFunctionCalls().front(), *CI); - } else { - // Otherwise, create a new DSGraph to represent this. - DSGraph* IndCallGraph = new DSGraph(DSG->getGlobalECs(), - DSG->getDataLayout(), *TypeSS); - - // Clone over the call into the new DSGraph - ReachabilityCloner RC(IndCallGraph, DSG, 0); - DSCallSite ClonedCS = RC.cloneCallSite(*CI); - - // Add the cloned CS to the graph, as if it were an original call. - IndCallGraph->getFunctionCalls().push_back(ClonedCS); - - // Save this graph for use later, should we need it. - IndCallRecI = IndCallMap.insert(IndCallRecI, - std::make_pair(Callees, IndCallGraph)); - - // Additionally, make sure that each of the callees inlines this graph - // exactly once. - DSCallSite *NCS = &IndCallGraph->getFunctionCalls().front(); - for (unsigned i = 0, e = Callees.size(); i != e; ++i) { - DSGraph* CalleeGraph = getDSGraph(*Callees[i]); - if (CalleeGraph != DSG) - CallerEdges[CalleeGraph].push_back(CallerCallEdge(IndCallGraph, NCS, - Callees[i])); - } - } - } -} diff --git a/lib/DSA/TypeSafety.cpp b/lib/DSA/TypeSafety.cpp deleted file mode 100644 index 128365479..000000000 --- a/lib/DSA/TypeSafety.cpp +++ /dev/null @@ -1,553 +0,0 @@ -//===- TypeSafety.cpp - Find type-safe pointers --------------------------- --// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass implements code that determines if memory objects are used in -// a type-consistent fashion. It is built using DSA and essentially abstracts -// away the details of interpreting DSNodes. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "type-safety" - -#include "dsa/TypeSafety.h" - -#include "llvm/IR/Module.h" -#include "llvm/IR/DerivedTypes.h" -#include "smack/Debug.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/ADT/Statistic.h" - -static RegisterPass > -X ("typesafety-eqtd", "Find type-safe pointers"); -static RegisterPass > -Y ("typesafety-td", "Find type-safe pointers"); - -// Pass Statistics -namespace { - //STATISTIC (TypeSafeNodes, "Type-safe DSNodes"); -} -extern cl::opt TypeInferenceOptimize; - -namespace dsa { - -template -char TypeSafety::ID = 0; - -// Method: getDSNodeHandle() -// -// Description: -// This method looks up the DSNodeHandle for a given LLVM globalvalue. -// The value is looked up in the globals graph -// -// Return value: -// A DSNodeHandle for the value is returned. This DSNodeHandle is from -// the GlobalsGraph. Note that the DSNodeHandle may represent a NULL DSNode. -// -template DSNodeHandle -TypeSafety::getDSNodeHandle(const GlobalValue *V) { - DSNodeHandle DSH; - const DSGraph * GlobalsGraph = dsaPass->getGlobalsGraph (); - if(GlobalsGraph->hasNodeForValue(V)) { - DSH = GlobalsGraph->getNodeForValue(V); - } - // - // Try looking up this DSNode value in the globals graph. Note that - // globals are put into equivalence classes; we may need to first find the - // equivalence class to which our global belongs, find the global that - // represents all globals in that equivalence class, and then look up the - // DSNode Handle for *that* global. - // - if (DSH.isNull()) { - // - // DSA does not currently handle global aliases. - // - if (!isa(V)) { - // - // We have to dig into the globalEC of the DSGraph to find the DSNode. - // - const GlobalValue * GV = dyn_cast(V); - const GlobalValue * Leader; - Leader = GlobalsGraph->getGlobalECs().getLeaderValue(GV); - DSH = GlobalsGraph->getNodeForValue(Leader); - } - } - return DSH; -} - -// Method: getDSNodeHandle() -// -// Description: -// This method looks up the DSNodeHandle for a given LLVM value. The context -// of the value is the specified function, although if it is a global value, -// the DSNodeHandle may exist within the global DSGraph. -// -// Return value: -// A DSNodeHandle for the value is returned. This DSNodeHandle could either -// be in the function's DSGraph or from the GlobalsGraph. Note that the -// DSNodeHandle may represent a NULL DSNode. -// -template DSNodeHandle -TypeSafety::getDSNodeHandle (const Value * V, const Function * F) { - // - // Ensure that the function has a DSGraph - // - assert (dsaPass->hasDSGraph(*F) && "No DSGraph for function!\n"); - - // - // Lookup the DSNode for the value in the function's DSGraph. - // - const DSGraph * TDG = dsaPass->getDSGraph(*F); - - DSNodeHandle DSH; - if(TDG->hasNodeForValue(V)) - DSH = TDG->getNodeForValue(V); - - // - // If the value wasn't found in the function's DSGraph, then maybe we can - // find the value in the globals graph. - // - if ((DSH.isNull()) && (isa(V))) { - // - // Try looking up this DSNode value in the globals graph. Note that - // globals are put into equivalence classes; we may need to first find the - // equivalence class to which our global belongs, find the global that - // represents all globals in that equivalence class, and then look up the - // DSNode Handle for *that* global. - // - DSH = getDSNodeHandle(cast(V)); - } - return DSH; -} - -template bool -TypeSafety::isTypeSafe (const Value * V, const Function * F) { - // - // Get the DSNode for the specified value. - // - DSNodeHandle DH = getDSNodeHandle (V, F); - - // - // If there is no DSNode, claim that it is not type safe. - // - if (DH.isNull()) { - return false; - } - - // - // See if the DSNode is one that we think is type-safe. - // - if (TypeSafeNodes.count (DH.getNode())) - return true; - - return false; -} - -template bool -TypeSafety::isFieldDisjoint (const Value * V, const Function * F) { - // - // Get the DSNode for the specified value. - // - DSNodeHandle DH = getDSNodeHandle (V, F); - DSNode *node = DH.getNode(); - unsigned offset = DH.getOffset(); - SDEBUG(errs() << " check fields overlap at: " << offset << "\n"); - - // - // If there is no DSNode, claim that it is not type safe. - // - if (DH.isNull()) { - return false; - } - // - // If the DSNode is completely folded, then we know for sure that it is not - // type-safe. - // - if (node->isNodeCompletelyFolded()) - return false; - - // - // If the memory object represented by this DSNode can be manipulated by - // external code or DSA has otherwise not finished analyzing all operations - // on it, declare it type-unsafe. - // - if (node->isExternalNode() || node->isIncompleteNode()) - return false; - - // - // If the pointer to the memory object came from some source not understood - // by DSA or somehow came from/escapes to the realm of integers, declare it - // type-unsafe. - // - if (node->isUnknownNode() || node->isIntToPtrNode() || node->isPtrToIntNode()) { - return false; - } - - return !((NodeInfo[node])[offset]); -} - -// -// TODO -// -template bool -TypeSafety::isFieldDisjoint (const GlobalValue * V, unsigned offset) { - // - // Get the DSNode for the specified value. - // - DSNodeHandle DH = getDSNodeHandle (V); - DSNode *node = DH.getNode(); - //unsigned offset = DH.getOffset(); - SDEBUG(errs() << " check fields overlap at: " << offset << "\n"); - - // - // If there is no DSNode, claim that it is not type safe. - // - if (DH.isNull()) { - return false; - } - // - // If the DSNode is completely folded, then we know for sure that it is not - // type-safe. - // - if (node->isNodeCompletelyFolded()) - return false; - - // - // If the memory object represented by this DSNode can be manipulated by - // external code or DSA has otherwise not finished analyzing all operations - // on it, declare it type-unsafe. - // - if (node->isExternalNode() || node->isIncompleteNode()) - return false; - - // - // If the pointer to the memory object came from some source not understood - // by DSA or somehow came from/escapes to the realm of integers, declare it - // type-unsafe. - // - if (node->isUnknownNode() || node->isIntToPtrNode() || node->isPtrToIntNode()) { - return false; - } - - return !((NodeInfo[node])[offset]); -} - -template bool -TypeSafety::isTypeSafe(const GlobalValue *V) { - // - // Get the DSNode for the specified value. - // - DSNodeHandle DH = getDSNodeHandle(V); - - // - // If there is no DSNode, claim that it is not typesafe. - // - if (DH.isNull()) - return false; - - // - // See if the DSNode is one that we think is type-safe. - // - if (TypeSafeNodes.count (DH.getNode())) - return true; - - return false; -} - -// -// Method: fieldMapUpdate() -// -// Description: -// Update the fieldmap -// -template void -TypeSafety::fieldMapUpdate (const DSNode * N) { - FieldMap fmap; - // - // There are no overlapping fields if the DSNode has no fields. - // - if (N->type_begin() == N->type_end()) - return; - - // - // Iterate through the DSNode to see if the previous fields overlaps with the - // current field. - // - DSNode::const_type_iterator tn = N->type_begin(); - while (true) { - // - // If this is the last field, then we are done updating. - // - if (tn == N->type_end()) { - break; - } - // - // Get the information about the current field. - // - unsigned offset = tn->first; - SuperSet::setPtr TypeSet = tn->second; - - - // - // If there are multiple types in the current field, then the field is type-unsafe. - // - if (TypeSet) { - svset::const_iterator tb = TypeSet->begin(); - if (++tb != TypeSet->end()) { - fmap[offset] = true; - SDEBUG(errs() << "Multiple fields at " << offset << "\n"); - } - } - - for (DSNode::const_type_iterator ti = ++tn; ti != N->type_end(); ++ti) { - - // - // Get the offset of the next field. - // - unsigned next_offset = ti->first; - assert((next_offset >= offset) && "next offset should be larger than offset."); - - // - // Check to see if any of the types in the current field extend into the - // next field. - // - if (TypeSet) { - bool overlaps = false; - for (svset::const_iterator ni = TypeSet->begin(), - ne = TypeSet->end(); ni != ne; ++ni) { - unsigned field_length = TD->getTypeStoreSize (*ni); - if ((offset + field_length) > next_offset) { - if(TypeInferenceOptimize) { - if(const ArrayType *AT = dyn_cast(*ni)) { - Type *ElemTy = AT->getElementType(); - while(ArrayType *AT1 = dyn_cast(ElemTy)) - ElemTy = AT1->getElementType(); - if(next_offset < (TD->getTypeStoreSize(ElemTy) + offset)) { - assert(isa(ElemTy) && "Array Not of Struct Type??"); - //overlaps = false; - //fmap[next_offset] = false; - continue; - } - } - } - fmap[offset] = true; - fmap[next_offset] = true; - overlaps = true; - if(overlaps) { - SDEBUG(errs() << "Found overlap at " << offset << " with " << next_offset << "\n"); - break; - } - } - } - if (!overlaps) - break; - } - } - - if (fmap.find(offset) == fmap.end()) - fmap[offset] = false; - } - - // - // Return the result. - // - NodeInfo[N] = fmap; - return; -} - -// -// Method: typeFieldsOverlap() -// -// Description: -// Determine if any of the type fields can overlap within the DSNode. -// -// Notes: -// o) We take advantage of the fact that a std::map keeps its elements sorted -// by key. -// -template bool -TypeSafety::typeFieldsOverlap (const DSNode * N) { - // - // There are no overlapping fields if the DSNode has no fields. - // - if (N->type_begin() == N->type_end()) - return false; - - // - // Iterate through the DSNode to see if the previous fields overlaps with the - // current field. - // - DSNode::const_type_iterator tn = N->type_begin(); - bool overlaps = false; - while (!overlaps) { - // - // Get the information about the current field. - // - unsigned offset = tn->first; - SuperSet::setPtr TypeSet = tn->second; - - // - // If there are multiple types in the current field, then the node is type-unsafe. - // - if (TypeSet) { - svset::const_iterator tb = TypeSet->begin(); - if (++tb != TypeSet->end()) { - overlaps = true; - break; - } - } - // - // If this is the last field, then we are done searching. - // - if ((++tn) == N->type_end()) { - break; - } - - // - // Get the offset of the next field. - // - unsigned next_offset = tn->first; - - // - // Check to see if any of the types in the current field extend into the - // next field. - // - if (TypeSet) { - for (svset::const_iterator ni = TypeSet->begin(), - ne = TypeSet->end(); ni != ne; ++ni) { - unsigned field_length = TD->getTypeStoreSize (*ni); - if ((offset + field_length) > next_offset) { - overlaps = true; - if(TypeInferenceOptimize) { - if(const ArrayType *AT = dyn_cast(*ni)) { - Type *ElemTy = AT->getElementType(); - while(ArrayType *AT1 = dyn_cast(ElemTy)) - ElemTy = AT1->getElementType(); - if(next_offset < (TD->getTypeStoreSize(ElemTy) + offset)) { - assert(isa(ElemTy) && "Array Not of Struct Type??"); - overlaps = false; - } - } - } - if(overlaps) { - SDEBUG(errs() << " Found overlap at " << offset << " with " << next_offset << "\n"); - break; - } - } - } - } - } - - // - // Return the result. - // - return overlaps; -} - -// -// Method: isTypeSafe() -// -// Description: -// Determine whether a DSNode represents a piece of memory that is accessed -// in a type-safe fasion. -// -// Inputs: -// N - A pointer to a DSNode representing the memory object. -// -// Return value: -// true - The memory object is used in a type-safe fasion. -// false - The memory object *may* be used in a type-unsafe fasion. -// -template bool -TypeSafety::isTypeSafe (const DSNode * N) { - // - // If the DSNode is completely folded, then we know for sure that it is not - // type-safe. - // - if (N->isNodeCompletelyFolded()) - return false; - - // - // If the memory object represented by this DSNode can be manipulated by - // external code or DSA has otherwise not finished analyzing all operations - // on it, declare it type-unsafe. - // - if (N->isExternalNode() || N->isIncompleteNode()) - return false; - - // - // If the pointer to the memory object came from some source not understood - // by DSA or somehow came from/escapes to the realm of integers, declare it - // type-unsafe. - // - if (N->isUnknownNode() || N->isIntToPtrNode() || N->isPtrToIntNode()) { - return false; - } - - // - // Scan through all of the fields within the DSNode and see if any overlap. - // If they do, then the DSNode is not type-safe. - // - if (typeFieldsOverlap (N)) - return false; - - // - // We have run out of reasons for this DSNode to be type-unsafe. Declare it - // type-safe. - // - return true; -} - -// -// Method: findTypeSafeDSNodes() -// -// Description: -// Find and record all type-safe DSNodes. -// -// Inputs: -// Graph - The DSGraph for which we should search for type-safe nodes. -// -// Side-effects: -// Class level data structures are updated to record which DSNodes are -// type-safe. -// -template void -TypeSafety::findTypeSafeDSNodes (const DSGraph * Graph) { - DSGraph::node_const_iterator N = Graph->node_begin(); - DSGraph::node_const_iterator NE = Graph->node_end(); - for (; N != NE; ++N) { - if (isTypeSafe (&*N)) { - TypeSafeNodes.insert (&*N); - } - fieldMapUpdate(&*N); - } -} - -template bool -TypeSafety::runOnModule(Module & M) { - // - // Get access to prerequisite passes. - // - TD = &M.getDataLayout(); - dsaPass = &getAnalysis(); - - // - // For every DSGraph, find which DSNodes are type-safe. - // - findTypeSafeDSNodes (dsaPass->getGlobalsGraph()); - for (Module::iterator F = M.begin(); F != M.end(); ++F) { - if (dsaPass->hasDSGraph (*F)) { - findTypeSafeDSNodes (dsaPass->getDSGraph (*F)); - } - } - - return false; -} - -} diff --git a/lib/smack/DSAWrapper.cpp b/lib/smack/DSAWrapper.cpp index a419fb8bf..32be24a5d 100644 --- a/lib/smack/DSAWrapper.cpp +++ b/lib/smack/DSAWrapper.cpp @@ -5,12 +5,16 @@ // the University of Illinois Open Source License. See LICENSE for details. // #include "smack/DSAWrapper.h" -#include "assistDS/DSNodeEquivs.h" -#include "dsa/DSGraph.h" -#include "dsa/DataStructure.h" -#include "dsa/TypeSafety.h" +#include "smack/Debug.h" +#include "smack/SmackOptions.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/IntrinsicInst.h" + #include "llvm/Support/FileSystem.h" +#include +#include + #define DEBUG_TYPE "dsa-wrapper" namespace smack { @@ -22,185 +26,73 @@ RegisterPass DSAWrapperPass("dsa-wrapper", "SMACK Data Structure Graph Based Alias Analysis Wrapper"); -void MemcpyCollector::visitMemCpyInst(llvm::MemCpyInst &mci) { - const llvm::EquivalenceClasses &eqs = - nodeEqs->getEquivalenceClasses(); - const llvm::DSNode *n1 = - eqs.getLeaderValue(nodeEqs->getMemberForValue(mci.getOperand(0))); - const llvm::DSNode *n2 = - eqs.getLeaderValue(nodeEqs->getMemberForValue(mci.getOperand(1))); - - bool f1 = false, f2 = false; - for (unsigned i = 0; i < memcpys.size() && (!f1 || !f2); i++) { - f1 = f1 || memcpys[i] == n1; - f2 = f2 || memcpys[i] == n2; - } - - if (!f1) - memcpys.push_back(eqs.getLeaderValue(n1)); - if (!f2) - memcpys.push_back(eqs.getLeaderValue(n2)); -} - void DSAWrapper::getAnalysisUsage(llvm::AnalysisUsage &AU) const { AU.setPreservesAll(); - AU.addRequiredTransitive(); - AU.addRequiredTransitive(); - AU.addRequiredTransitive(); - AU.addRequired>(); + AU.addRequiredTransitive(); } bool DSAWrapper::runOnModule(llvm::Module &M) { dataLayout = &M.getDataLayout(); - TD = &getAnalysis(); - BU = &getAnalysis(); - nodeEqs = &getAnalysis(); - TS = &getAnalysis>(); - memcpys = collectMemcpys(M, new MemcpyCollector(nodeEqs)); - staticInits = collectStaticInits(M); + SD = &getAnalysis().getDsaAnalysis(); + assert(SD->kind() == sea_dsa::GlobalAnalysisKind::CONTEXT_INSENSITIVE && + "Currently we only want the context-insensitive sea-dsa."); + DG = &SD->getGraph(*M.begin()); + // Print the graph in dot format when debugging + SDEBUG(DG->writeGraph("main.mem.dot")); + collectStaticInits(M); + collectMemOpds(M); + countGlobalRefs(); module = &M; return false; } -std::vector -DSAWrapper::collectMemcpys(llvm::Module &M, MemcpyCollector *mcc) { - - for (llvm::Module::iterator func = M.begin(), e = M.end(); func != e; - ++func) { - - for (llvm::Function::iterator block = func->begin(); block != func->end(); - ++block) { - - mcc->visit(*block); - } - } - return mcc->getMemcpys(); -} - -std::vector -DSAWrapper::collectStaticInits(llvm::Module &M) { - std::vector sis; +void DSAWrapper::collectStaticInits(llvm::Module &M) { for (GlobalVariable &GV : M.globals()) { if (GV.hasInitializer()) { if (auto *N = getNode(&GV)) { - sis.push_back(N); + assert(N && "Global values should have nodes."); + staticInits.insert(N); } } } - return sis; } -DSGraph *DSAWrapper::getGraphForValue(const Value *V) { - if (const Instruction *I = dyn_cast(V)) - return TD->getDSGraph(*I->getParent()->getParent()); - else if (const Argument *A = dyn_cast(V)) - return TD->getDSGraph(*A->getParent()); - else if (const BasicBlock *BB = dyn_cast(V)) - return TD->getDSGraph(*BB->getParent()); - else if (isa(V)) - return TD->getGlobalsGraph(); - - // XXX I know this looks bad, but it works for now - for (auto U : V->users()) { - return getGraphForValue(U); +void DSAWrapper::collectMemOpds(llvm::Module &M) { + for (auto &f : M) { + for (inst_iterator I = inst_begin(&f), E = inst_end(&f); I != E; ++I) { + if (MemCpyInst *memcpyInst = dyn_cast(&*I)) { + memOpds.insert(getNode(memcpyInst->getSource())); + memOpds.insert(getNode(memcpyInst->getDest())); + } else if (MemSetInst *memsetInst = dyn_cast(&*I)) + memOpds.insert(getNode(memsetInst->getDest())); + } } - - llvm_unreachable("Unexpected value."); } -int DSAWrapper::getOffset(const MemoryLocation *l) { - const DSGraph::ScalarMapTy &S = getGraphForValue(l->Ptr)->getScalarMap(); - DSGraph::ScalarMapTy::const_iterator I = S.find((const Value *)l->Ptr); - if (I == S.end()) - return 0; - if (I->second.getNode() && I->second.getNode()->isCollapsedNode()) - return -1; - unsigned offset = I->second.getOffset(); - assert(offset <= INT_MAX && "Cannot handle large offsets"); - return (int)offset; -} - -bool DSAWrapper::isMemcpyd(const llvm::DSNode *n) { - const llvm::EquivalenceClasses &eqs = - nodeEqs->getEquivalenceClasses(); - const llvm::DSNode *nn = eqs.getLeaderValue(n); - for (unsigned i = 0; i < memcpys.size(); i++) - if (memcpys[i] == nn) - return true; - return false; -} - -bool DSAWrapper::isStaticInitd(const llvm::DSNode *n) { - const llvm::EquivalenceClasses &eqs = - nodeEqs->getEquivalenceClasses(); - const llvm::DSNode *nn = eqs.getLeaderValue(n); - for (unsigned i = 0; i < staticInits.size(); i++) - if (staticInits[i] == nn) - return true; - return false; +void DSAWrapper::countGlobalRefs() { + for (auto &g : DG->globals()) { + auto &cellRef = g.second; + auto *node = cellRef->getNode(); + assert(node && "Global values should have DSNodes."); + if (!globalRefCount.count(node)) + globalRefCount[node] = 1; + else + globalRefCount[node]++; + } } -bool DSAWrapper::isFieldDisjoint(const llvm::Value *V, - const llvm::Function *F) { - return TS->isFieldDisjoint(V, F); +bool DSAWrapper::isStaticInitd(const sea_dsa::Node *n) { + return staticInits.count(n) > 0; } -bool DSAWrapper::isFieldDisjoint(const GlobalValue *V, unsigned offset) { - return TS->isFieldDisjoint(V, offset); +bool DSAWrapper::isMemOpd(const sea_dsa::Node *n) { + return memOpds.count(n) > 0; } bool DSAWrapper::isRead(const Value *V) { - const DSNode *N = getNode(V); - return N && (N->isReadNode()); -} - -bool DSAWrapper::isAlloced(const Value *v) { - const DSNode *N = getNode(v); - return N && (N->isHeapNode() || N->isAllocaNode()); -} - -bool DSAWrapper::isExternal(const Value *v) { - const DSNode *N = getNode(v); - return N && N->isExternalNode(); -} - -bool DSAWrapper::isSingletonGlobal(const Value *V) { - const DSNode *N = getNode(V); - if (!N || !N->isGlobalNode() || N->numGlobals() > 1) - return false; - - // Ensure this node has a unique scalar type... (?) - DSNode::const_type_iterator TSi = N->type_begin(); - if (TSi == N->type_end()) - return false; - svset::const_iterator Ti = TSi->second->begin(); - if (Ti == TSi->second->end()) - return false; - const Type *T = *Ti; - while (T->isPointerTy()) - T = T->getPointerElementType(); - if (!T->isSingleValueType()) - return false; - ++Ti; - if (Ti != TSi->second->end()) - return false; - ++TSi; - if (TSi != N->type_end()) - return false; - - // Ensure this node is in its own class... (?) - const EquivalenceClasses &Cs = - nodeEqs->getEquivalenceClasses(); - EquivalenceClasses::iterator C = Cs.findValue(N); - assert(C != Cs.end() && "Did not find value."); - EquivalenceClasses::member_iterator I = Cs.member_begin(C); - if (I == Cs.member_end()) - return false; - ++I; - if (I != Cs.member_end()) - return false; - - return true; + auto node = getNode(V); + assert(node && "Global values should have nodes."); + return node->isRead(); } unsigned DSAWrapper::getPointedTypeSize(const Value *v) { @@ -214,24 +106,104 @@ unsigned DSAWrapper::getPointedTypeSize(const Value *v) { llvm_unreachable("Type should be pointer."); } -int DSAWrapper::getOffset(const Value *v) { - return getOffset(new MemoryLocation(v)); +unsigned DSAWrapper::getOffset(const Value *v) { + if (!DG->hasCell(*v)) + return 0; + return DG->getCell(*v).getOffset(); +} + +const sea_dsa::Node *DSAWrapper::getNode(const Value *v) { + // For sea-dsa, a node is obtained by getting the cell first. + // It's possible that a value doesn't have a cell, e.g., undef. + if (!DG->hasCell(*v)) + return nullptr; + auto node = DG->getCell(*v).getNode(); + assert(node && "Values should have nodes if they have cells."); + return node; } -// TODO: Should this return the node or its leader? -const DSNode *DSAWrapper::getNode(const Value *v) { - const llvm::EquivalenceClasses &eqs = - nodeEqs->getEquivalenceClasses(); - auto *N = nodeEqs->getMemberForValue(v); - return N ? eqs.getLeaderValue(N) : nullptr; +bool DSAWrapper::isTypeSafe(const Value *v) { + typedef std::unordered_map FieldMap; + typedef std::unordered_map NodeMap; + static NodeMap nodeMap; + + auto node = getNode(v); + + if (node->isOffsetCollapsed() || node->isExternal() || node->isIncomplete() || + node->isUnknown() || node->isIntToPtr() || node->isPtrToInt()) + // We consider it type-unsafe to be safe for these cases + return false; + + if (!nodeMap.count(node)) { + // Iterate all the fields of a node to find out + // the type-safety of each field. Then, we cache the results. + FieldMap fieldMap; + auto &types = node->types(); + std::set offsets; + + for (auto &t : types) + offsets.insert(t.first); + + auto offsetIterator = offsets.begin(); + + while (true) { + if (offsetIterator == offsets.end()) + // We have reached the last field and exit the loop + break; + + unsigned offset = *offsetIterator; + + auto &typeSet = types.find(offset)->second; + + auto ti = typeSet.begin(); + if (++ti != typeSet.end()) + // If there are multiple access types, then it's trivially type-unsafe. + fieldMap[offset] = false; + + // Get the maximum length + unsigned fieldLength = 0; + for (auto &t : typeSet) { + // TODO: fix the const_cast + unsigned length = + dataLayout->getTypeStoreSize(const_cast(t)); + if (length > fieldLength) + fieldLength = length; + } + + // Check if the current field overlaps with the next *fields* + for (auto oi = ++offsetIterator; oi != offsets.end(); ++oi) { + unsigned next_offset = *oi; + if (offset + fieldLength > next_offset) { + // Overlaps; mark the current field and the next unsafe + fieldMap[offset] = false; + fieldMap[next_offset] = false; + } else + // If the current field doesn't overlap with the next one, + // it certainly won't overlap with the rest. + break; + } + + if (!fieldMap.count(offset)) + fieldMap[offset] = true; + } + + nodeMap[node] = fieldMap; + } + + auto offset = getOffset(v); + if (nodeMap[node].count(offset)) + return nodeMap[node][offset]; + else + // Chances to hit this branch are when we visit memcpy/memset + // pointer operands. + return false; } -void DSAWrapper::printDSAGraphs(const char *Filename) { - std::error_code EC; - llvm::raw_fd_ostream F(Filename, EC, sys::fs::OpenFlags::F_None); - TD->print(F, module); - BU->print(F, module); - TS->print(F, module); +unsigned DSAWrapper::getNumGlobals(const sea_dsa::Node *n) { + if (globalRefCount.count(n)) + return globalRefCount[n]; + else + return 0; } } // namespace smack diff --git a/lib/smack/Regions.cpp b/lib/smack/Regions.cpp index e82f0260e..3d58c15eb 100644 --- a/lib/smack/Regions.cpp +++ b/lib/smack/Regions.cpp @@ -2,11 +2,6 @@ // This file is distributed under the MIT License. See LICENSE for details. // #include "smack/Regions.h" -#include "assistDS/DSNodeEquivs.h" -#include "dsa/DSGraph.h" -#include "dsa/DSNode.h" -#include "dsa/DataStructure.h" -#include "dsa/TypeSafety.h" #include "smack/DSAWrapper.h" #include "smack/Debug.h" #include "smack/SmackOptions.h" @@ -18,111 +13,27 @@ namespace smack { const DataLayout *Region::DL = nullptr; DSAWrapper *Region::DSA = nullptr; -// DSNodeEquivs* Region::NEQS = nullptr; - -namespace { -const Function *getFunction(const Value *V) { - if (const Instruction *I = dyn_cast(V)) - return I->getParent()->getParent(); - else if (const Argument *A = dyn_cast(V)) - return A->getParent(); - else if (const BasicBlock *BB = dyn_cast(V)) - return BB->getParent(); - - // XXX I know this looks bad, but it works for now - for (auto U : V->users()) - return getFunction(U); - - llvm_unreachable("Unexpected value."); -} - -bool isFieldDisjoint(DSAWrapper *DSA, const Value *V, unsigned offset) { - if (const GlobalValue *G = dyn_cast(V)) - return DSA->isFieldDisjoint(G, offset); - else - return DSA->isFieldDisjoint(V, getFunction(V)); -} -} // namespace void Region::init(Module &M, Pass &P) { DL = &M.getDataLayout(); DSA = &P.getAnalysis(); } -namespace { -unsigned numGlobals(const DSNode *N) { - unsigned count = 0; - - // shamelessly ripped from getCaption(..) in lib/DSA/Printer.cpp - EquivalenceClasses *GlobalECs = 0; - const DSGraph *G = N->getParentGraph(); - if (G) - GlobalECs = &G->getGlobalECs(); - - for (auto i = N->globals_begin(), e = N->globals_end(); i != e; ++i) { - count += 1; - - if (GlobalECs) { - // Figure out how many globals are equivalent to this one. - auto I = GlobalECs->findValue(*i); - if (I != GlobalECs->end()) { - count += - std::distance(GlobalECs->member_begin(I), GlobalECs->member_end()) - - 1; - } - } - } +bool Region::isSingleton(const Value *v, unsigned length) { + // TODO can we do something for non-global nodes? + auto node = DSA->getNode(v); - return count; -} -} // namespace - -bool Region::isSingleton(const DSNode *N, unsigned offset, unsigned length) { - if (N->isGlobalNode() && numGlobals(N) == 1 && !N->isArrayNode() && - !N->isAllocaNode() && !N->isHeapNode() && !N->isExternalNode() && - !N->isUnknownNode()) { - - // TODO can we do something for non-global nodes? - - // TODO don’t need to know if there are other members of this class, right? - // assert(NEQS && "Missing DS node equivalence information."); - // auto &Cs = NEQS->getEquivalenceClasses(); - // auto C = Cs.findValue(representative); - // assert(C != Cs.end() && "No equivalence class found."); - // assert(Cs.member_begin(C) != Cs.member_end() && "Found empty class."); - // if (++(Cs.member_begin(C)) != Cs.member_end()) return false; - - assert(DL && "Missing data layout information."); - - for (auto I = N->type_begin(), E = N->type_end(); I != E; ++I) { - if (I->first < offset) - continue; - if (I->first > offset) - break; - if (I->second->begin() == I->second->end()) - break; - if ((++(I->second->begin())) != I->second->end()) - break; - Type *T = *I->second->begin(); - if (!T->isSized()) - break; - if (DL->getTypeAllocSize(T) != length) - break; - if (!T->isSingleValueType()) - break; - return true; - } - } - return false; + return !isAllocated(node) && DSA->getNumGlobals(node) == 1 && + !node->isArray() && DSA->isTypeSafe(v) && !DSA->isMemOpd(node); } -bool Region::isAllocated(const DSNode *N) { - return N->isHeapNode() || N->isAllocaNode(); +bool Region::isAllocated(const sea_dsa::Node *N) { + return N->isHeap() || N->isAlloca(); } -bool Region::isComplicated(const DSNode *N) { - return N->isIntToPtrNode() || N->isPtrToIntNode() || N->isExternalNode() || - N->isUnknownNode(); +bool Region::isComplicated(const sea_dsa::Node *N) { + return N->isIntToPtr() || N->isPtrToInt() || N->isExternal() || + N->isUnknown(); } void Region::init(const Value *V, unsigned length) { @@ -133,25 +44,17 @@ void Region::init(const Value *V, unsigned length) { representative = (DSA && !dyn_cast(V)) ? DSA->getNode(V) : nullptr; this->type = T; - int offset = DSA ? DSA->getOffset(V) : 0; - if (offset < 0) { - this->offset = 0; - this->length = -1U; - } else { - this->offset = offset; - this->length = length; - } + this->offset = DSA ? DSA->getOffset(V) : 0; + this->length = length; - singleton = - DL && representative && isSingleton(representative, offset, length); + singleton = DL && representative && isSingleton(V, length); allocated = !representative || isAllocated(representative); bytewise = DSA && SmackOptions::BitPrecise && (SmackOptions::NoByteAccessInference || - !isFieldDisjoint(DSA, V, offset) || - DSA->isMemcpyd(representative) || T->isIntegerTy(8)); - incomplete = !representative || representative->isIncompleteNode(); + (!representative || !DSA->isTypeSafe(V)) || T->isIntegerTy(8)); + incomplete = !representative || representative->isIncomplete(); complicated = !representative || isComplicated(representative); - collapsed = !representative || representative->isCollapsedNode(); + collapsed = !representative || representative->isOffsetCollapsed(); } Region::Region(const Value *V) { @@ -196,13 +99,17 @@ void Region::print(raw_ostream &O) { else O << "*"; O << ">[" << offset << "," << (offset + length) << "]{"; - if (isSingleton()) + if (singleton) O << "S"; if (bytewise) O << "B"; if (complicated) O << "C"; - if (isAllocated()) + if (incomplete) + O << "I"; + if (collapsed) + O << "L"; + if (allocated) O << "A"; O << "}"; } @@ -212,17 +119,25 @@ RegisterPass RegionsPass("smack-regions", "SMACK Memory Regions Pass"); void Regions::getAnalysisUsage(llvm::AnalysisUsage &AU) const { AU.setPreservesAll(); - if (!SmackOptions::NoMemoryRegionSplitting) { - AU.addRequiredTransitive(); - AU.addRequiredTransitive(); - AU.addRequiredTransitive(); - AU.addRequiredTransitive(); - AU.addRequiredTransitive>(); + if (!SmackOptions::NoMemoryRegionSplitting) AU.addRequired(); - } } bool Regions::runOnModule(Module &M) { + // Shaobo: my understanding of how this class works: + // First, a bunch of instructions involving pointers are visited (via + // Regions::idx). During a visit on an instruction, a region is created + // (Region::init) for the pointer operand. Note that a region is always + // created for a pointer when it's visited, regardless of whether it alias + // with the existing ones. A region can be roughly seen as a tuple of (cell, + // length) or (node, offset, length) since a cell is essentially a tuple of + // (node, offset). After a region is created, we will merge it to the existing + // ones if it overlaps with the them. So after this pass, we will get a bunch + // of regions which are mutually exclusive to each other. + // After that, SmackRep will call Regions::idx to get the region for a pointer + // operand, which repeats the aforementioned process. Note that we don't have + // fancy caching, so a region is created and merged everytime Regions::idx + // is called. if (!SmackOptions::NoMemoryRegionSplitting) { Region::init(M, *this); visit(M); @@ -332,7 +247,18 @@ void Regions::visitAtomicRMWInst(AtomicRMWInst &I) { idx(I.getPointerOperand()); } -void Regions::visitMemIntrinsic(MemIntrinsic &I) { +void Regions::visitMemSetInst(MemSetInst &I) { + unsigned length; + + if (auto CI = dyn_cast(I.getLength())) + length = CI->getZExtValue(); + else + length = std::numeric_limits::max(); + + idx(I.getDest(), length); +} + +void Regions::visitMemTransferInst(MemTransferInst &I) { unsigned length; if (auto CI = dyn_cast(I.getLength())) @@ -340,6 +266,10 @@ void Regions::visitMemIntrinsic(MemIntrinsic &I) { else length = std::numeric_limits::max(); + // We need to visit the source location otherwise + // extra merges will happen in the translation phrase, + // resulting in ``hanging'' regions. + idx(I.getSource(), length); idx(I.getDest(), length); } diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index a09efe87f..cf9d14645 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -16,7 +16,6 @@ #include "llvm/Support/GraphWriter.h" #include -#include "dsa/DSNode.h" #include "llvm/Support/raw_ostream.h" #include diff --git a/lib/AssistDS/Devirt.cpp b/lib/utils/Devirt.cpp similarity index 96% rename from lib/AssistDS/Devirt.cpp rename to lib/utils/Devirt.cpp index 3fe33086e..a4b7c907f 100644 --- a/lib/AssistDS/Devirt.cpp +++ b/lib/utils/Devirt.cpp @@ -9,7 +9,7 @@ #define DEBUG_TYPE "devirt" -#include "assistDS/Devirt.h" +#include "utils/Devirt.h" #include "smack/Debug.h" #include "llvm/Support/CommandLine.h" @@ -374,16 +374,12 @@ Devirtualize::makeDirectCall (CallSite & CS) { std::vector Targets; - if (CTF->size(CS) && CTF->isComplete(CS)) { - // TODO should we allow non-matching targets? - // TODO non-matching targets leads to crashes in bounce creation - // TODO formerly, all call-target-finder tarets were included: - // Targets.insert (Targets.begin(), CTF->begin(CS), CTF->end(CS)); - // TODO presently we filter out unmatching targets: - for (auto F = CTF->begin(CS); F != CTF->end(CS); ++F) + // TODO should we allow non-matching targets? + // TODO non-matching targets leads to crashes in bounce creation + if (CCG->isComplete(CS)) { + for (auto F = CCG->begin(CS); F != CCG->end(CS); ++F) if (match(CS, **F)) Targets.push_back(*F); - } else { for (auto &F : *CS.getInstruction()->getParent()->getParent()->getParent()) if (F.hasAddressTaken() && match(CS, F)) @@ -472,7 +468,7 @@ Devirtualize::visitCallSite (CallSite &CS) { // Second, we will only transform those call sites which are complete (i.e., // for which we know all of the call targets). // - if (SKIP_INCOMPLETE_NODES && !CTF->isComplete(CS)) + if (SKIP_INCOMPLETE_NODES && !CCG->isComplete(CS)) return; // @@ -495,7 +491,7 @@ Devirtualize::runOnModule (Module & M) { // // Get the targets of indirect function calls. // - CTF = &getAnalysis >(); + CCG = &getAnalysis(); // // Get information on the target system. diff --git a/include/dsa/LICENSE.TXT b/lib/utils/LICENSE.TXT similarity index 100% rename from include/dsa/LICENSE.TXT rename to lib/utils/LICENSE.TXT diff --git a/lib/AssistDS/MergeGEP.cpp b/lib/utils/MergeGEP.cpp similarity index 99% rename from lib/AssistDS/MergeGEP.cpp rename to lib/utils/MergeGEP.cpp index 9d9e7cdf9..77d1e0fa0 100644 --- a/lib/AssistDS/MergeGEP.cpp +++ b/lib/utils/MergeGEP.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "merge-gep" -#include "assistDS/MergeGEP.h" +#include "utils/MergeGEP.h" #include "llvm/Pass.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" diff --git a/lib/AssistDS/SimplifyExtractValue.cpp b/lib/utils/SimplifyExtractValue.cpp similarity index 99% rename from lib/AssistDS/SimplifyExtractValue.cpp rename to lib/utils/SimplifyExtractValue.cpp index e645fae6f..8cf04ecf9 100644 --- a/lib/AssistDS/SimplifyExtractValue.cpp +++ b/lib/utils/SimplifyExtractValue.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "simplifyev" -#include "assistDS/SimplifyExtractValue.h" +#include "utils/SimplifyExtractValue.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/ArrayRef.h" diff --git a/lib/AssistDS/SimplifyInsertValue.cpp b/lib/utils/SimplifyInsertValue.cpp similarity index 98% rename from lib/AssistDS/SimplifyInsertValue.cpp rename to lib/utils/SimplifyInsertValue.cpp index 7bf59dd91..9614b64b5 100644 --- a/lib/AssistDS/SimplifyInsertValue.cpp +++ b/lib/utils/SimplifyInsertValue.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "simplify-iv" -#include "assistDS/SimplifyInsertValue.h" +#include "utils/SimplifyInsertValue.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/FormattedStream.h" diff --git a/sea-dsa b/sea-dsa new file mode 160000 index 000000000..855c78b30 --- /dev/null +++ b/sea-dsa @@ -0,0 +1 @@ +Subproject commit 855c78b304f275a5ed2f527d35ea4a53a7070338 diff --git a/share/smack/top.py b/share/smack/top.py index 764bf74e1..52e72b567 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -339,6 +339,9 @@ def llvm_to_bpl(args): cmd = ['llvm2bpl', args.linked_bc_file, '-bpl', args.bpl_file] cmd += ['-warn-type', args.warn] + cmd += ['-sea-dsa=ci'] + # This flag can lead to unsoundness in Rust regressions. + #cmd += ['-sea-dsa-type-aware'] if sys.stdout.isatty(): cmd += ['-colored-warnings'] cmd += ['-source-loc-syms'] for ep in args.entry_points: diff --git a/test/c/basic/atomic_cas.c b/test/c/failing/atomic_cas.c similarity index 100% rename from test/c/basic/atomic_cas.c rename to test/c/failing/atomic_cas.c diff --git a/test/c/basic/atomic_cas_fail.c b/test/c/failing/atomic_cas_fail.c similarity index 100% rename from test/c/basic/atomic_cas_fail.c rename to test/c/failing/atomic_cas_fail.c diff --git a/test/c/basic/extern_mem_fail.c b/test/c/failing/extern_mem_fail.c similarity index 78% rename from test/c/basic/extern_mem_fail.c rename to test/c/failing/extern_mem_fail.c index b2fb4d566..d432dc7f2 100644 --- a/test/c/basic/extern_mem_fail.c +++ b/test/c/failing/extern_mem_fail.c @@ -3,6 +3,7 @@ // @expect error +// see: https://github.com/smackers/smack/issues/553 void foo(int *); int *bar(); diff --git a/test/c/pthread/join_return.c b/test/c/failing/join_return.c similarity index 92% rename from test/c/pthread/join_return.c rename to test/c/failing/join_return.c index d5c7b812b..9e811a092 100644 --- a/test/c/pthread/join_return.c +++ b/test/c/failing/join_return.c @@ -8,6 +8,7 @@ // @expect verified +// see: https://github.com/smackers/smack/issues/555 int x = 1; typedef struct pair { diff --git a/test/c/pthread/join_return_fail.c b/test/c/failing/join_return_fail.c similarity index 100% rename from test/c/pthread/join_return_fail.c rename to test/c/failing/join_return_fail.c diff --git a/test/c/failing/null_dereference_fail.c b/test/c/failing/null_dereference_fail.c new file mode 100644 index 000000000..8e3f49232 --- /dev/null +++ b/test/c/failing/null_dereference_fail.c @@ -0,0 +1,11 @@ +#include "smack.h" +#include + +// @expect error + +// see: https://github.com/smackers/smack/issues/554 +int main(void) { + int *a; + int b = a[0]; + return b; +} diff --git a/test/c/memory-safety/global_and_heap_alloc_fail_no_free.c b/test/c/memory-safety/global_and_heap_alloc_fail_no_free.c index a4b18b6b0..6de2153d6 100644 --- a/test/c/memory-safety/global_and_heap_alloc_fail_no_free.c +++ b/test/c/memory-safety/global_and_heap_alloc_fail_no_free.c @@ -9,5 +9,7 @@ int main(void) { int *a = &x; int *b = malloc(4); int c = a[0]; - return c; + // We have to use `b` otherwise the call to malloc will be removed. + // This is only observable after sea-dsa is used. + return *b; } diff --git a/test/rust/functions/closure.rs b/test/rust/functions/closure.rs index f0d9b843c..e20a855db 100644 --- a/test/rust/functions/closure.rs +++ b/test/rust/functions/closure.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect verified fn call_with_one(mut some_closure: F) -> () diff --git a/test/rust/functions/closure_fail.rs b/test/rust/functions/closure_fail.rs index 931b8b53a..40ca9948e 100644 --- a/test/rust/functions/closure_fail.rs +++ b/test/rust/functions/closure_fail.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect error fn call_with_one(mut some_closure: F) -> () diff --git a/test/rust/loops/gauss_sum_nondet.rs b/test/rust/loops/gauss_sum_nondet.rs index 2ff934e6b..fee9cf404 100644 --- a/test/rust/loops/gauss_sum_nondet.rs +++ b/test/rust/loops/gauss_sum_nondet.rs @@ -2,7 +2,7 @@ mod smack; use smack::*; -// @flag --no-memory-splitting --unroll=4 +// @flag --unroll=4 // @expect verified fn main() { diff --git a/test/rust/loops/gauss_sum_nondet_fail.rs b/test/rust/loops/gauss_sum_nondet_fail.rs index ce58d8326..47c79428a 100644 --- a/test/rust/loops/gauss_sum_nondet_fail.rs +++ b/test/rust/loops/gauss_sum_nondet_fail.rs @@ -2,7 +2,7 @@ mod smack; use smack::*; -// @flag --no-memory-splitting --unroll=10 +// @flag --unroll=10 // @expect error fn main() { diff --git a/test/rust/loops/iterator.rs b/test/rust/loops/iterator.rs index e7bed0e37..20dad0d14 100644 --- a/test/rust/loops/iterator.rs +++ b/test/rust/loops/iterator.rs @@ -2,7 +2,7 @@ mod smack; use smack::*; -// @flag --no-memory-splitting --unroll=4 +// @flag --unroll=4 // @expect verified fn fac(n: u64) -> u64 { diff --git a/test/rust/loops/iterator_fail.rs b/test/rust/loops/iterator_fail.rs index e160f5cc1..2f740e534 100644 --- a/test/rust/loops/iterator_fail.rs +++ b/test/rust/loops/iterator_fail.rs @@ -2,7 +2,7 @@ mod smack; use smack::*; -// @flag --no-memory-splitting --unroll=10 +// @flag --unroll=10 // @expect error fn fac(n: u64) -> u64 { diff --git a/test/rust/timeouts/vec_resize.rs b/test/rust/timeouts/vec_resize.rs index d91fdb001..c6a5ccc22 100644 --- a/test/rust/timeouts/vec_resize.rs +++ b/test/rust/timeouts/vec_resize.rs @@ -2,7 +2,7 @@ mod smack; use smack::*; -// @flag --no-memory-splitting --unroll=3 +// @flag --unroll=3 // @expect verified fn main() { diff --git a/test/rust/timeouts/vec_resize_fail.rs b/test/rust/timeouts/vec_resize_fail.rs index 220e805b2..7dad2eadd 100644 --- a/test/rust/timeouts/vec_resize_fail.rs +++ b/test/rust/timeouts/vec_resize_fail.rs @@ -2,7 +2,7 @@ mod smack; use smack::*; -// @flag --no-memory-splitting --unroll=3 +// @flag --unroll=3 // @expect error fn main() { diff --git a/test/rust/vector/vec1.rs b/test/rust/vector/vec1.rs index 1f4d6a335..eca63922b 100644 --- a/test/rust/vector/vec1.rs +++ b/test/rust/vector/vec1.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect verified fn main() { diff --git a/test/rust/vector/vec1_fail1.rs b/test/rust/vector/vec1_fail1.rs index 062e68426..de2d5fdd1 100644 --- a/test/rust/vector/vec1_fail1.rs +++ b/test/rust/vector/vec1_fail1.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect error fn main() { diff --git a/test/rust/vector/vec1_fail2.rs b/test/rust/vector/vec1_fail2.rs index 0d2c9c1f8..79e642f58 100644 --- a/test/rust/vector/vec1_fail2.rs +++ b/test/rust/vector/vec1_fail2.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect error fn main() { diff --git a/test/rust/vector/vec1_fail3.rs b/test/rust/vector/vec1_fail3.rs index 59e2440e0..dbf298842 100644 --- a/test/rust/vector/vec1_fail3.rs +++ b/test/rust/vector/vec1_fail3.rs @@ -2,7 +2,6 @@ mod smack; use smack::*; -// @flag --no-memory-splitting // @expect error fn main() { diff --git a/tools/llvm2bpl/llvm2bpl.cpp b/tools/llvm2bpl/llvm2bpl.cpp index 41b97c056..f16935d41 100644 --- a/tools/llvm2bpl/llvm2bpl.cpp +++ b/tools/llvm2bpl/llvm2bpl.cpp @@ -24,11 +24,10 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" -#include "assistDS/Devirt.h" -#include "assistDS/MergeGEP.h" -#include "assistDS/SimplifyExtractValue.h" -#include "assistDS/SimplifyInsertValue.h" -#include "assistDS/StructReturnToPointer.h" +#include "utils/Devirt.h" +#include "utils/MergeGEP.h" +#include "utils/SimplifyExtractValue.h" +#include "utils/SimplifyInsertValue.h" #include "smack/AddTiming.h" #include "smack/BplFilePrinter.h" #include "smack/CodifyStaticInits.h" @@ -153,7 +152,8 @@ int main(int argc, char **argv) { pass_manager.add(llvm::createLowerSwitchPass()); // pass_manager.add(llvm::createCFGSimplificationPass()); - pass_manager.add(llvm::createInternalizePass()); + // Shaobo: sea-dsa is inconsistent with the pass below. + //pass_manager.add(llvm::createInternalizePass()); pass_manager.add(llvm::createPromoteMemoryToRegisterPass()); if (StaticUnroll) { From 20f4db69af21d7bf5b44a8537f83ccf9287d6ce7 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Thu, 9 Apr 2020 15:54:16 -0600 Subject: [PATCH 57/60] Moved failing regressions due to #550 to the failing folder --- test/c/{ntdrivers => failing}/floppy_false.i.cil.c | 1 + test/c/{ntdrivers => failing}/floppy_true.i.cil.c | 1 + test/c/{ntdrivers => failing}/parport_false.i.cil.c | 1 + test/c/{ntdrivers => failing}/parport_true.i.cil.c | 1 + test/c/{pthread => failing}/regression_525_malloc.c | 1 + ...reference_fail.c => unallocated_dereference_fail.c} | 0 test/c/memory-safety/ununallocated_dereference_fail.c | 10 ---------- 7 files changed, 5 insertions(+), 10 deletions(-) rename test/c/{ntdrivers => failing}/floppy_false.i.cil.c (99%) rename test/c/{ntdrivers => failing}/floppy_true.i.cil.c (99%) rename test/c/{ntdrivers => failing}/parport_false.i.cil.c (99%) rename test/c/{ntdrivers => failing}/parport_true.i.cil.c (99%) rename test/c/{pthread => failing}/regression_525_malloc.c (94%) rename test/c/failing/{null_dereference_fail.c => unallocated_dereference_fail.c} (100%) delete mode 100644 test/c/memory-safety/ununallocated_dereference_fail.c diff --git a/test/c/ntdrivers/floppy_false.i.cil.c b/test/c/failing/floppy_false.i.cil.c similarity index 99% rename from test/c/ntdrivers/floppy_false.i.cil.c rename to test/c/failing/floppy_false.i.cil.c index de2af3864..9d57493ea 100644 --- a/test/c/ntdrivers/floppy_false.i.cil.c +++ b/test/c/failing/floppy_false.i.cil.c @@ -2,6 +2,7 @@ // @expect error +// see: https://github.com/smackers/smack/issues/554 extern char __VERIFIER_nondet_char(void); extern int __VERIFIER_nondet_int(void); extern long __VERIFIER_nondet_long(void); diff --git a/test/c/ntdrivers/floppy_true.i.cil.c b/test/c/failing/floppy_true.i.cil.c similarity index 99% rename from test/c/ntdrivers/floppy_true.i.cil.c rename to test/c/failing/floppy_true.i.cil.c index d548c4135..67388109c 100644 --- a/test/c/ntdrivers/floppy_true.i.cil.c +++ b/test/c/failing/floppy_true.i.cil.c @@ -2,6 +2,7 @@ // @expect verified +// see: https://github.com/smackers/smack/issues/554 extern char __VERIFIER_nondet_char(void); extern int __VERIFIER_nondet_int(void); extern long __VERIFIER_nondet_long(void); diff --git a/test/c/ntdrivers/parport_false.i.cil.c b/test/c/failing/parport_false.i.cil.c similarity index 99% rename from test/c/ntdrivers/parport_false.i.cil.c rename to test/c/failing/parport_false.i.cil.c index 8f6290522..e6dda6b9f 100644 --- a/test/c/ntdrivers/parport_false.i.cil.c +++ b/test/c/failing/parport_false.i.cil.c @@ -2,6 +2,7 @@ // @expect error +// see: https://github.com/smackers/smack/issues/554 extern char __VERIFIER_nondet_char(void); extern int __VERIFIER_nondet_int(void); extern long __VERIFIER_nondet_long(void); diff --git a/test/c/ntdrivers/parport_true.i.cil.c b/test/c/failing/parport_true.i.cil.c similarity index 99% rename from test/c/ntdrivers/parport_true.i.cil.c rename to test/c/failing/parport_true.i.cil.c index 36921913e..1606668e4 100644 --- a/test/c/ntdrivers/parport_true.i.cil.c +++ b/test/c/failing/parport_true.i.cil.c @@ -2,6 +2,7 @@ // @expect verified +// see: https://github.com/smackers/smack/issues/554 extern char __VERIFIER_nondet_char(void); extern int __VERIFIER_nondet_int(void); extern long __VERIFIER_nondet_long(void); diff --git a/test/c/pthread/regression_525_malloc.c b/test/c/failing/regression_525_malloc.c similarity index 94% rename from test/c/pthread/regression_525_malloc.c rename to test/c/failing/regression_525_malloc.c index debc853c3..a11c59dc2 100644 --- a/test/c/pthread/regression_525_malloc.c +++ b/test/c/failing/regression_525_malloc.c @@ -3,6 +3,7 @@ #include // @expect verified +// see: https://github.com/smackers/smack/issues/555 // https://github.com/smackers/smack/issues/525 pthread_t tid1; diff --git a/test/c/failing/null_dereference_fail.c b/test/c/failing/unallocated_dereference_fail.c similarity index 100% rename from test/c/failing/null_dereference_fail.c rename to test/c/failing/unallocated_dereference_fail.c diff --git a/test/c/memory-safety/ununallocated_dereference_fail.c b/test/c/memory-safety/ununallocated_dereference_fail.c deleted file mode 100644 index 3b4ceaad5..000000000 --- a/test/c/memory-safety/ununallocated_dereference_fail.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "smack.h" -#include - -// @expect error - -int main(void) { - int *a; - int b = a[0]; - return b; -} From 05f0deb046094f269ae56b1ca5cd05ea449c4e21 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Thu, 9 Apr 2020 16:06:59 -0600 Subject: [PATCH 58/60] Fixed the implementation of the `fdiml` function The type of variable `val` should be `long double`. Fixes #558 --- share/smack/lib/math.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/smack/lib/math.c b/share/smack/lib/math.c index 248cf3da7..303a06567 100644 --- a/share/smack/lib/math.c +++ b/share/smack/lib/math.c @@ -354,7 +354,7 @@ long double fdiml(long double x, long double y) { if (__isnanl(x) || __isnanl(y)) { return nanl(0); } - double val = __VERIFIER_nondet_long_double(); + long double val = __VERIFIER_nondet_long_double(); __SMACK_code("@ := $fsub.bvlongdouble($rmode, @, @);", val, x, y); return fmaxl(0.0l, val); } From 17f423096bba395f8496299f556a8cede6b0ce62 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Thu, 9 Apr 2020 16:18:03 -0600 Subject: [PATCH 59/60] Moved previously timedout Rust benchmarks to the right folders --- test/rust/{timeouts => recursion}/fib.rs | 0 test/rust/{timeouts => recursion}/fib_fail.rs | 0 test/rust/{timeouts => vector}/vec_resize.rs | 0 test/rust/{timeouts => vector}/vec_resize_fail.rs | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename test/rust/{timeouts => recursion}/fib.rs (100%) rename test/rust/{timeouts => recursion}/fib_fail.rs (100%) rename test/rust/{timeouts => vector}/vec_resize.rs (100%) rename test/rust/{timeouts => vector}/vec_resize_fail.rs (100%) diff --git a/test/rust/timeouts/fib.rs b/test/rust/recursion/fib.rs similarity index 100% rename from test/rust/timeouts/fib.rs rename to test/rust/recursion/fib.rs diff --git a/test/rust/timeouts/fib_fail.rs b/test/rust/recursion/fib_fail.rs similarity index 100% rename from test/rust/timeouts/fib_fail.rs rename to test/rust/recursion/fib_fail.rs diff --git a/test/rust/timeouts/vec_resize.rs b/test/rust/vector/vec_resize.rs similarity index 100% rename from test/rust/timeouts/vec_resize.rs rename to test/rust/vector/vec_resize.rs diff --git a/test/rust/timeouts/vec_resize_fail.rs b/test/rust/vector/vec_resize_fail.rs similarity index 100% rename from test/rust/timeouts/vec_resize_fail.rs rename to test/rust/vector/vec_resize_fail.rs From ad345481911c539c3c26bbfab9c8af3b8a3e8d6d Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 10 Apr 2020 10:27:20 -0600 Subject: [PATCH 60/60] Bumped version number to 2.4.1 --- Doxyfile | 2 +- share/smack/reach.py | 2 +- share/smack/top.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doxyfile b/Doxyfile index f77267f29..8f750c35f 100644 --- a/Doxyfile +++ b/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = smack -PROJECT_NUMBER = 2.4.0 +PROJECT_NUMBER = 2.4.1 PROJECT_BRIEF = "A bounded software verifier." PROJECT_LOGO = OUTPUT_DIRECTORY = docs diff --git a/share/smack/reach.py b/share/smack/reach.py index 09307abe9..750667ea5 100755 --- a/share/smack/reach.py +++ b/share/smack/reach.py @@ -11,7 +11,7 @@ from smackgen import * from smackverify import * -VERSION = '2.4.0' +VERSION = '2.4.1' def reachParser(): parser = argparse.ArgumentParser(add_help=False, parents=[verifyParser()]) diff --git a/share/smack/top.py b/share/smack/top.py index 52e72b567..021437c0e 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -15,7 +15,7 @@ from .replay import replay_error_trace from .frontend import link_bc_files, frontends, languages, extra_libs -VERSION = '2.4.0' +VERSION = '2.4.1' def results(args): """A dictionary of the result output messages."""