From 40ff81b261ff634f7dbeb41811588bc9edbfd6b7 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sun, 18 Feb 2018 02:26:24 +0100 Subject: [PATCH 01/49] Work --- CMakeLists.txt | 40 ++- include/souper/Extractor/ExprBuilder.h | 139 ++++++++ include/souper/Extractor/KLEEBuilder.h | 6 +- include/souper/Tool/CandidateMapUtils.h | 3 +- lib/Extractor/ExprBuilder.cpp | 234 +++++++++++++ lib/Extractor/KLEEBuilder.cpp | 424 ++---------------------- lib/Infer/InstSynthesis.cpp | 3 +- unittests/Extractor/ExtractorTests.cpp | 3 +- 8 files changed, 448 insertions(+), 404 deletions(-) create mode 100644 include/souper/Extractor/ExprBuilder.h create mode 100644 lib/Extractor/ExprBuilder.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b1f9f5026..d3f9d0850 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,6 +109,30 @@ find_library(HIREDIS_LIBRARY PATHS third_party/hiredis/install/lib) +find_path(Z3_INCLUDE_DIRECTORY + NAMES + z3.h + PATHS + /usr/include + /usr/local/include + /opt/local/include) +if(Z3_INCLUDE_DIRECTORY STREQUAL "Z3_INCLUDE_DIRECTORY-NOTFOUND") + message(FATAL_ERROR "Can't find folder containing z3.h") +endif() + +include_directories(${Z3_INCLUDE_DIRECTORY}) + +find_library(Z3_LIBRARY_DIRECTORY + NAMES + z3 + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib) +if(Z3_LIBRARY_DIRECTORY STREQUAL "Z3_LIBRARY_DIRECTORY-NOTFOUND") + message(FATAL_ERROR "Can't find folder containing z3 library") +endif() + set(SOUPER_CLANG_TOOL_FILES lib/ClangTool/Actions.cpp include/souper/ClangTool/Actions.h @@ -120,10 +144,12 @@ add_library(souperClangTool STATIC set(SOUPER_EXTRACTOR_FILES lib/Extractor/Candidates.cpp - lib/Extractor/KLEEBuilder.cpp +# lib/Extractor/KLEEBuilder.cpp + lib/Extractor/ExprBuilder.cpp lib/Extractor/Solver.cpp include/souper/Extractor/Candidates.h include/souper/Extractor/KLEEBuilder.h + include/souper/Extractor/ExprBuilder.h include/souper/Extractor/Solver.h ) @@ -263,14 +289,14 @@ target_link_libraries(souperKVStore ${LLVM_LIBS} ${LLVM_LDFLAGS}) target_link_libraries(souperParser souperInst ${LLVM_LIBS} ${LLVM_LDFLAGS}) target_link_libraries(souperSMTLIB2 ${LLVM_LIBS} ${LLVM_LDFLAGS}) target_link_libraries(souperTool souperExtractor souperSMTLIB2) -target_link_libraries(souperPass ${PASS_LDFLAGS} ${HIREDIS_LIBRARY}) -target_link_libraries(souperPassProfileAll ${PASS_LDFLAGS} ${HIREDIS_LIBRARY}) -target_link_libraries(souper souperExtractor souperKVStore souperParser souperSMTLIB2 souperTool kleeExpr ${HIREDIS_LIBRARY}) +target_link_libraries(souperPass ${PASS_LDFLAGS} ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) +target_link_libraries(souperPassProfileAll ${PASS_LDFLAGS} ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) +target_link_libraries(souper souperExtractor souperKVStore souperParser souperSMTLIB2 souperTool kleeExpr ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(internal-solver-test souperSMTLIB2) target_link_libraries(lexer-test souperParser) target_link_libraries(parser-test souperParser) -target_link_libraries(souper-check souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY}) -target_link_libraries(clang-souper souperClangTool souperExtractor souperKVStore souperParser souperSMTLIB2 souperTool kleeExpr ${CLANG_LIBS} ${LLVM_LIBS} ${LLVM_LDFLAGS} ${HIREDIS_LIBRARY}) +target_link_libraries(souper-check souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) +target_link_libraries(clang-souper souperClangTool souperExtractor souperKVStore souperParser souperSMTLIB2 souperTool kleeExpr ${CLANG_LIBS} ${LLVM_LIBS} ${LLVM_LDFLAGS} ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(extractor_tests souperExtractor ${GTEST_LIBS}) target_link_libraries(inst_tests souperInst ${GTEST_LIBS}) target_link_libraries(parser_tests souperParser ${GTEST_LIBS}) @@ -306,7 +332,7 @@ if(NOT GO_EXECUTABLE STREQUAL "GO_EXECUTABLE-NOTFOUND") set_target_properties(souperweb-backend PROPERTIES COMPILE_FLAGS "${LLVM_CXXFLAGS}") - target_link_libraries(souperweb-backend souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser souperInst ${HIREDIS_LIBRARY}) + target_link_libraries(souperweb-backend souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser souperInst ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) add_custom_target(souperweb ALL COMMAND ${GO_EXECUTABLE} build -o ${CMAKE_BINARY_DIR}/souperweb ${CMAKE_SOURCE_DIR}/tools/souperweb.go COMMENT "Building souperweb") diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h new file mode 100644 index 000000000..59eb7f65a --- /dev/null +++ b/include/souper/Extractor/ExprBuilder.h @@ -0,0 +1,139 @@ +// Copyright 2014 The Souper Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOUPER_EXTRACTOR_EXPRBUILDER_H +#define SOUPER_EXTRACTOR_EXPRBUILDER_H + +#include "souper/Extractor/Candidates.h" +#include "souper/Util/UniqueNameSet.h" +#include + +namespace souper { + +typedef void *SMTExpr; +typedef void *Array; + +struct CandidateExpr { + //std::vector> Arrays; + //std::vector ArrayVars; + //klee::ref E; + SMTExpr E; +}; + +const unsigned MAX_PHI_DEPTH = 25; + +typedef std::unordered_map> UBPathInstMap; +typedef std::map BlockPCPredMap; + +struct UBPath { + std::map BlockConstraints; + std::map SelectBranches; + std::vector Insts; + std::vector UBInsts; +}; + +struct BlockPCPhiPath { + std::map BlockConstraints; + std::vector Phis; + std::vector PCs; +}; + +class ExprBuilder { +public: + ExprBuilder(std::vector> &Arrays, + std::vector &ArrayVars); + virtual ~ExprBuilder(); + + virtual SMTExpr addnswUB(Inst *I) = 0; + virtual SMTExpr addnuwUB(Inst *I) = 0; + virtual SMTExpr subnswUB(Inst *I) = 0; + virtual SMTExpr subnuwUB(Inst *I) = 0; + virtual SMTExpr mulnswUB(Inst *I) = 0; + virtual SMTExpr mulnuwUB(Inst *I) = 0; + virtual SMTExpr udivUB(Inst *I) = 0; + virtual SMTExpr udivExactUB(Inst *I) = 0; + virtual SMTExpr sdivUB(Inst *I) = 0; + virtual SMTExpr sdivExactUB(Inst *I) = 0; + virtual SMTExpr shiftUB(Inst *I) = 0; + virtual SMTExpr shlnswUB(Inst *I) = 0; + virtual SMTExpr shlnuwUB(Inst *I) = 0; + virtual SMTExpr lshrExactUB(Inst *I) = 0; + virtual SMTExpr ashrExactUB(Inst *I) = 0; + virtual SMTExpr countOnes(SMTExpr E) = 0; + + virtual void recordUBInstruction(Inst *I, SMTExpr E) = 0; + SMTExpr buildAssoc(std::function F, + llvm::ArrayRef Ops); + virtual SMTExpr build(Inst *I) = 0; + virtual SMTExpr get(Inst *I) = 0; + virtual SMTExpr getInstMapping(const InstMapping &IM) = 0; + SMTExpr getZeroBitsMapping(Inst *I); + SMTExpr getOneBitsMapping(Inst *I); + SMTExpr getNonZeroBitsMapping(Inst *I); + SMTExpr getNonNegBitsMapping(Inst *I); + SMTExpr getPowerTwoBitsMapping(Inst *I); + SMTExpr getNegBitsMapping(Inst *I); + SMTExpr getSignBitsMapping(Inst *I); + std::vector getBlockPredicates(Inst *I); + virtual SMTExpr getUBInstCondition() = 0; + virtual SMTExpr getBlockPCs() = 0; + virtual void setBlockPCMap(const BlockPCs &BPCs) = 0; + virtual SMTExpr createPathPred(std::map &BlockConstraints, + Inst* PathInst, + std::map *SelectBranches) = 0; + virtual SMTExpr createUBPathInstsPred(Inst *CurrentInst, + std::vector &UBPathInsts, + std::map &BlockConstraints, + std::map *SelectBranches, + UBPathInstMap &CachedUBPathInsts) = 0; + bool getUBPaths(Inst *I, UBPath *Current, + std::vector> &Paths, + UBPathInstMap &CachedUBPathInsts, unsigned Depth); + void getBlockPCPhiPaths(Inst *I, BlockPCPhiPath *Current, + std::vector> &Paths, + UBPathInstMap &CachedPhis); + + std::map> BlockPredMap; + std::map ExprMap; + std::map UBExprMap; + std::map ZeroBitsMap; + std::map OneBitsMap; + std::map NonZeroBitsMap; + std::map NonNegBitsMap; + std::map PowerTwoBitsMap; + std::map NegBitsMap; + std::map SignBitsMap; + std::map BlockPCMap; + std::vector> &Arrays; + std::vector &ArrayVars; + std::vector UBPathInsts; + UniqueNameSet ArrayNames; + // Holding the precondition, i.e. blockpc, for the UBInst under process. + SMTExpr UBInstPrecondition; + // Indicate if the UBInst relates to BlockPC + bool IsForBlockPCUBInst; + +}; + +llvm::Optional GetCandidateExprForReplacement( + const BlockPCs &BPCs, const std::vector &PCs, + InstMapping Mapping, bool Negate); + +std::string BuildQuery(const BlockPCs &BPCs, + const std::vector &PCs, InstMapping Mapping, + std::vector *ModelVars, bool Negate=false); + +} + +#endif // SOUPER_EXTRACTOR_EXPRBUILDER_H diff --git a/include/souper/Extractor/KLEEBuilder.h b/include/souper/Extractor/KLEEBuilder.h index 9367e0f81..71f69290c 100644 --- a/include/souper/Extractor/KLEEBuilder.h +++ b/include/souper/Extractor/KLEEBuilder.h @@ -18,18 +18,21 @@ #include "klee/Expr.h" #include "klee/util/Ref.h" #include "llvm/ADT/Optional.h" -#include "souper/Extractor/Candidates.h" +#include "souper/Extractor/ExprBuilder.h" #include #include namespace souper { +class KLEEBuilder : public ExprBuilder + struct CandidateExpr { std::vector> Arrays; std::vector ArrayVars; klee::ref E; }; +#if 0 llvm::Optional GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool Negate); @@ -37,6 +40,7 @@ llvm::Optional GetCandidateExprForReplacement( std::string BuildQuery(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate=false); +#endif } diff --git a/include/souper/Tool/CandidateMapUtils.h b/include/souper/Tool/CandidateMapUtils.h index 8395f0005..533eb862f 100644 --- a/include/souper/Tool/CandidateMapUtils.h +++ b/include/souper/Tool/CandidateMapUtils.h @@ -17,7 +17,8 @@ #include "llvm/Support/raw_ostream.h" #include "souper/Extractor/Candidates.h" -#include "souper/Extractor/KLEEBuilder.h" +//#include "souper/Extractor/KLEEBuilder.h" +#include "souper/Extractor/ExprBuilder.h" #include "souper/Extractor/Solver.h" #include "souper/KVStore/KVStore.h" diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp new file mode 100644 index 000000000..6bbf78ab1 --- /dev/null +++ b/lib/Extractor/ExprBuilder.cpp @@ -0,0 +1,234 @@ +// Copyright 2014 The Souper Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "souper/Extractor/ExprBuilder.h" + +using namespace llvm; +using namespace souper; + +namespace souper { + +ExprBuilder::ExprBuilder(std::vector> &Arrays, + std::vector &ArrayVars) + : Arrays(Arrays), ArrayVars(ArrayVars), IsForBlockPCUBInst(false) {} + +SMTExpr ExprBuilder::buildAssoc( + std::function F, + llvm::ArrayRef Ops) { + SMTExpr E = get(Ops[0]); + for (Inst *I : llvm::ArrayRef(Ops.data()+1, Ops.size()-1)) { + E = F(E, get(I)); + } + return E; +} + +std::vector ExprBuilder::getBlockPredicates(Inst *I) { + assert(I->K == Inst::Phi && "not a phi inst"); + if (BlockPredMap.count(I->B)) + return BlockPredMap[I->B]; + std::vector PredExpr; + for (auto const &PredVar : I->B->PredVars) + PredExpr.push_back(build(PredVar)); + BlockPredMap[I->B] = PredExpr; + return PredExpr; +} + +bool ExprBuilder::getUBPaths(Inst *I, UBPath *Current, + std::vector> &Paths, + UBPathInstMap &CachedUBPathInsts, unsigned Depth) { + if (Depth > MAX_PHI_DEPTH) + return false; + + switch (I->K) { + default: + break; + + case Inst::AddNSW: + case Inst::AddNUW: + case Inst::AddNW: + case Inst::SubNSW: + case Inst::SubNUW: + case Inst::SubNW: + case Inst::MulNSW: + case Inst::MulNUW: + case Inst::MulNW: + case Inst::UDiv: + case Inst::SDiv: + case Inst::UDivExact: + case Inst::SDivExact: + case Inst::URem: + case Inst::SRem: + case Inst::Shl: + case Inst::ShlNSW: + case Inst::ShlNUW: + case Inst::ShlNW: + case Inst::LShr: + case Inst::LShrExact: + case Inst::AShr: + case Inst::AShrExact: + Current->UBInsts.push_back(I); + break; + } + + const std::vector &Ops = I->orderedOps(); + if (I->K == Inst::Phi) { + // Early terminate because this phi has been processed. + // We will use its cached predicates. + if (CachedUBPathInsts.count(I)) + return true; + Current->Insts.push_back(I); + // Since we treat a select instruction as a phi instruction, it's + // possible that I->B has been added already. + if (Current->BlockConstraints.count(I->B)) + return true; + std::vector Tmp = { Current }; + // Create copies of the current path + for (unsigned J = 1; J < Ops.size(); ++J) { + UBPath *New = new UBPath; + *New = *Current; + New->BlockConstraints[I->B] = J; + Paths.push_back(std::move(std::unique_ptr(New))); + Tmp.push_back(New); + } + // Original path takes the first branch + Current->BlockConstraints[I->B] = 0; + // Continue recursively + for (unsigned J = 0; J < Ops.size(); ++J) { + if (!getUBPaths(Ops[J], Tmp[J], Paths, CachedUBPathInsts, Depth + 1)) + return false; + } + } else if (I->K == Inst::Select) { + // Early terminate because this phi has been processed. + // We will use its cached predicates. + if (CachedUBPathInsts.count(I)) + return true; + Current->Insts.push_back(I); + // Current is the predicate operand branch + std::vector Tmp = { Current }; + // True branch + UBPath *True = new UBPath; + *True = *Current; + True->SelectBranches[I] = true; + Paths.push_back(std::move(std::unique_ptr(True))); + Tmp.push_back(True); + // False branch + UBPath *False = new UBPath; + *False = *Current; + False->SelectBranches[I] = false; + Paths.push_back(std::move(std::unique_ptr(False))); + Tmp.push_back(False); + // Continue recursively + for (unsigned J = 0; J < Ops.size(); ++J) { + if (!getUBPaths(Ops[J], Tmp[J], Paths, CachedUBPathInsts, Depth + 1)) + return false; + } + } else { + for (unsigned J = 0; J < Ops.size(); ++J) { + if (!getUBPaths(Ops[J], Current, Paths, CachedUBPathInsts, Depth + 1)) + return false; + } + } + return true; +} + +void ExprBuilder::getBlockPCPhiPaths( + Inst *I, BlockPCPhiPath *Current, + std::vector> &Paths, + UBPathInstMap &CachedPhis) { + + const std::vector &Ops = I->orderedOps(); + if (I->K != Inst::Phi) { + for (unsigned J = 0; J < Ops.size(); ++J) + getBlockPCPhiPaths(Ops[J], Current, Paths, CachedPhis); + return; + } + + // Early terminate because this phi has been processed. + // We will use its cached predicates. + if (CachedPhis.count(I)) + return; + Current->Phis.push_back(I); + + // Since we treat a select instruction as a phi instruction, it's + // possible that I->B has been added already. + if (Current->BlockConstraints.count(I->B)) + return; + + std::vector Tmp = { Current }; + // Create copies of the current path + for (unsigned J = 1; J < Ops.size(); ++J) { + BlockPCPhiPath *New = new BlockPCPhiPath; + *New = *Current; + New->BlockConstraints[I->B] = J; + Paths.push_back(std::move(std::unique_ptr(New))); + Tmp.push_back(New); + } + // Original path takes the first branch + Current->BlockConstraints[I->B] = 0; + + auto PCMap = BlockPCMap.find(I->B); + if (PCMap != BlockPCMap.end()) { + for (unsigned J = 0; J < Ops.size(); ++J) { + auto P = PCMap->second.find(J); + if (P != PCMap->second.end()) + Tmp[J]->PCs.push_back(P->second); + } + } + // Continue recursively + for (unsigned J = 0; J < Ops.size(); ++J) + getBlockPCPhiPaths(Ops[J], Tmp[J], Paths, CachedPhis); +} + +SMTExpr ExprBuilder::getZeroBitsMapping(Inst *I) { + return ZeroBitsMap[I]; +} + +SMTExpr ExprBuilder::getOneBitsMapping(Inst *I) { + return OneBitsMap[I]; +} + +SMTExpr ExprBuilder::getNonZeroBitsMapping(Inst *I) { + return NonZeroBitsMap[I]; +} + +SMTExpr ExprBuilder::getNonNegBitsMapping(Inst *I) { + return NonNegBitsMap[I]; +} + +SMTExpr ExprBuilder::getNegBitsMapping(Inst *I) { + return NegBitsMap[I]; +} + +SMTExpr ExprBuilder::getPowerTwoBitsMapping(Inst *I) { + return PowerTwoBitsMap[I]; +} + +SMTExpr ExprBuilder::getSignBitsMapping(Inst *I) { + return SignBitsMap[I]; +} + +//llvm::Optional GetCandidateExprForReplacement( +// const BlockPCs &BPCs, const std::vector &PCs, +// InstMapping Mapping, bool Negate) { +// return CandidateExpr(); +//} + +//std::string BuildQuery(const BlockPCs &BPCs, +// const std::vector &PCs, +// InstMapping Mapping, +// std::vector *ModelVars, bool Negate) { +// return ""; +//} + +} diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 1d5039013..8b45a4fe1 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -48,105 +48,13 @@ using namespace llvm; using namespace klee; using namespace souper; -namespace { +namespace souper { -const unsigned MAX_PHI_DEPTH = 25; +KLEEBuilder::ExprBuilder(std::vector> &Arrays, + std::vector &ArrayVars) + : Arrays(Arrays), ArrayVars(ArrayVars), IsForBlockPCUBInst(false) {} -typedef std::unordered_map>> UBPathInstMap; -typedef std::map> BlockPCPredMap; - -struct UBPath { - std::map BlockConstraints; - std::map SelectBranches; - std::vector Insts; - std::vector UBInsts; -}; - -struct BlockPCPhiPath { - std::map BlockConstraints; - std::vector Phis; - std::vector> PCs; -}; - -struct ExprBuilder { - ExprBuilder(std::vector> &Arrays, - std::vector &ArrayVars) - : Arrays(Arrays), ArrayVars(ArrayVars), IsForBlockPCUBInst(false) {} - - std::map>> BlockPredMap; - std::map> ExprMap; - std::map> UBExprMap; - std::map> ZeroBitsMap; - std::map> OneBitsMap; - std::map> NonZeroBitsMap; - std::map> NonNegBitsMap; - std::map> PowerTwoBitsMap; - std::map> NegBitsMap; - std::map> SignBitsMap; - std::map BlockPCMap; - std::vector> &Arrays; - std::vector &ArrayVars; - std::vector UBPathInsts; - UniqueNameSet ArrayNames; - // Holding the precondition, i.e. blockpc, for the UBInst under process. - ref UBInstPrecondition; - // Indicate if the UBInst relates to BlockPC - bool IsForBlockPCUBInst; - - ref makeSizedArrayRead(unsigned Width, StringRef Name, Inst *Origin); - ref addnswUB(Inst *I); - ref addnuwUB(Inst *I); - ref subnswUB(Inst *I); - ref subnuwUB(Inst *I); - ref mulnswUB(Inst *I); - ref mulnuwUB(Inst *I); - ref udivUB(Inst *I); - ref udivExactUB(Inst *I); - ref sdivUB(Inst *I); - ref sdivExactUB(Inst *I); - ref shiftUB(Inst *I); - ref shlnswUB(Inst *I); - ref shlnuwUB(Inst *I); - ref lshrExactUB(Inst *I); - ref ashrExactUB(Inst *I); - ref countOnes(ref E); - void recordUBInstruction(Inst *I, ref E); - ref buildAssoc(std::function(ref, ref)> F, - llvm::ArrayRef Ops); - ref build(Inst *I); - ref get(Inst *I); - ref getInstMapping(const InstMapping &IM); - ref getZeroBitsMapping(Inst *I); - ref getOneBitsMapping(Inst *I); - ref getNonZeroBitsMapping(Inst *I); - ref getNonNegBitsMapping(Inst *I); - ref getPowerTwoBitsMapping(Inst *I); - ref getNegBitsMapping(Inst *I); - ref getSignBitsMapping(Inst *I); - std::vector> getBlockPredicates(Inst *I); - ref getUBInstCondition(); - ref getBlockPCs(); - void setBlockPCMap(const BlockPCs &BPCs); - ref createPathPred(std::map &BlockConstraints, - Inst* PathInst, - std::map *SelectBranches); - ref createUBPathInstsPred(Inst *CurrentInst, - std::vector &UBPathInsts, - std::map &BlockConstraints, - std::map *SelectBranches, - UBPathInstMap &CachedUBPathInsts); - bool getUBPaths(Inst *I, UBPath *Current, - std::vector> &Paths, - UBPathInstMap &CachedUBPathInsts, unsigned Depth); - void getBlockPCPhiPaths(Inst *I, BlockPCPhiPath *Current, - std::vector> &Paths, - UBPathInstMap &CachedPhis); -}; - -} - -ref ExprBuilder::makeSizedArrayRead(unsigned Width, StringRef Name, - Inst *Origin) { +ref makeSizedArrayRead(unsigned Width, StringRef Name, Inst *Origin) { std::string NameStr; if (Name.empty()) NameStr = "arr"; @@ -195,7 +103,7 @@ ref ExprBuilder::makeSizedArrayRead(unsigned Width, StringRef Name, return Var; } -ref ExprBuilder::addnswUB(Inst *I) { +ref KLEEBuilder::addnswUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Add = AddExpr::create(L, R); @@ -207,7 +115,7 @@ ref ExprBuilder::addnswUB(Inst *I) { EqExpr::create(LMSB, AddMSB)); } -ref ExprBuilder::addnuwUB(Inst *I) { +ref KLEEBuilder::addnuwUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); Expr::Width Width = L->getWidth(); @@ -218,7 +126,7 @@ ref ExprBuilder::addnuwUB(Inst *I) { return Expr::createIsZero(AddMSB); } -ref ExprBuilder::subnswUB(Inst *I) { +ref KLEEBuilder::subnswUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Sub = SubExpr::create(L, R); @@ -230,7 +138,7 @@ ref ExprBuilder::subnswUB(Inst *I) { EqExpr::create(LMSB, SubMSB)); } -ref ExprBuilder::subnuwUB(Inst *I) { +ref KLEEBuilder::subnuwUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); Expr::Width Width = L->getWidth(); @@ -241,7 +149,7 @@ ref ExprBuilder::subnuwUB(Inst *I) { return Expr::createIsZero(SubMSB); } -ref ExprBuilder::mulnswUB(Inst *I) { +ref KLEEBuilder::mulnswUB(Inst *I) { const std::vector &Ops = I->orderedOps(); // The computation below has to be performed on the operands of // multiplication instruction. The instruction using mulnswUB() @@ -256,7 +164,7 @@ ref ExprBuilder::mulnswUB(Inst *I) { return EqExpr::create(Mul, LowerBitsExt); } -ref ExprBuilder::mulnuwUB(Inst *I) { +ref KLEEBuilder::mulnuwUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); Expr::Width Width = L->getWidth(); @@ -267,20 +175,20 @@ ref ExprBuilder::mulnuwUB(Inst *I) { return Expr::createIsZero(HigherBits); } -ref ExprBuilder::udivUB(Inst *I) { +ref KLEEBuilder::udivUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref R = get(Ops[1]); return NeExpr::create(R, klee::ConstantExpr::create(0, R->getWidth())); } -ref ExprBuilder::udivExactUB(Inst *I) { +ref KLEEBuilder::udivExactUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Udiv = UDivExpr::create(L, R); return EqExpr::create(L, MulExpr::create(R, Udiv)); } -ref ExprBuilder::sdivUB(Inst *I) { +ref KLEEBuilder::sdivUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref ShiftBy = klee::ConstantExpr::create(L->getWidth()-1, @@ -293,21 +201,21 @@ ref ExprBuilder::sdivUB(Inst *I) { NeExpr::create(L, IntMin), NeExpr::create(R, NegOne))); } -ref ExprBuilder::sdivExactUB(Inst *I) { +ref KLEEBuilder::sdivExactUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Sdiv = SDivExpr::create(L, R); return EqExpr::create(L, MulExpr::create(R, Sdiv)); } -ref ExprBuilder::shiftUB(Inst *I) { +ref KLEEBuilder::shiftUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Lwidth = klee::ConstantExpr::create(L->getWidth(), L->getWidth()); return UltExpr::create(R, Lwidth); } -ref ExprBuilder::shlnswUB(Inst *I) { +ref KLEEBuilder::shlnswUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = ShlExpr::create(L, R); @@ -315,7 +223,7 @@ ref ExprBuilder::shlnswUB(Inst *I) { return EqExpr::create(RShift, L); } -ref ExprBuilder::shlnuwUB(Inst *I) { +ref KLEEBuilder::shlnuwUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = ShlExpr::create(L, R); @@ -323,7 +231,7 @@ ref ExprBuilder::shlnuwUB(Inst *I) { return EqExpr::create(RShift, L); } -ref ExprBuilder::lshrExactUB(Inst *I) { +ref KLEEBuilder::lshrExactUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = LShrExpr::create(L, R); @@ -331,7 +239,7 @@ ref ExprBuilder::lshrExactUB(Inst *I) { return EqExpr::create(LShift, L); } -ref ExprBuilder::ashrExactUB(Inst *I) { +ref KLEEBuilder::ashrExactUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = AShrExpr::create(L, R); @@ -339,17 +247,7 @@ ref ExprBuilder::ashrExactUB(Inst *I) { return EqExpr::create(LShift, L); } -ref ExprBuilder::buildAssoc( - std::function(ref, ref)> F, - llvm::ArrayRef Ops) { - ref E = get(Ops[0]); - for (Inst *I : llvm::ArrayRef(Ops.data()+1, Ops.size()-1)) { - E = F(E, get(I)); - } - return E; -} - -ref ExprBuilder::countOnes(ref L) { +ref KLEEBuilder::countOnes(ref L) { Expr::Width Width = L->getWidth(); ref Count = klee::ConstantExpr::alloc(llvm::APInt(Width, 0)); for (unsigned i=0; i ExprBuilder::countOnes(ref L) { return Count; } -void ExprBuilder::recordUBInstruction(Inst *I, ref E) { +void KLEEBuilder::recordUBInstruction(Inst *I, ref E) { if (!IsForBlockPCUBInst) { UBExprMap[I] = E; } @@ -374,7 +272,7 @@ void ExprBuilder::recordUBInstruction(Inst *I, ref E) { } } -ref ExprBuilder::build(Inst *I) { +ref KLEEBuilder::build(Inst *I) { const std::vector &Ops = I->orderedOps(); switch (I->K) { case Inst::UntypedConst: @@ -650,7 +548,7 @@ ref ExprBuilder::build(Inst *I) { llvm_unreachable("unknown kind"); } -ref ExprBuilder::get(Inst *I) { +ref KLEEBuilder::get(Inst *I) { ref &E = ExprMap[I]; if (E.isNull()) { E = build(I); @@ -659,22 +557,11 @@ ref ExprBuilder::get(Inst *I) { return E; } -ref ExprBuilder::getInstMapping(const InstMapping &IM) { +ref KLEEBuilder::getInstMapping(const InstMapping &IM) { return EqExpr::create(get(IM.LHS), get(IM.RHS)); } -std::vector> ExprBuilder::getBlockPredicates(Inst *I) { - assert(I->K == Inst::Phi && "not a phi inst"); - if (BlockPredMap.count(I->B)) - return BlockPredMap[I->B]; - std::vector> PredExpr; - for (auto const &PredVar : I->B->PredVars) - PredExpr.push_back(build(PredVar)); - BlockPredMap[I->B] = PredExpr; - return PredExpr; -} - -ref ExprBuilder::createPathPred( +ref KLEEBuilder::createPathPred( std::map &BlockConstraints, Inst* PathInst, std::map *SelectBranches) { @@ -714,7 +601,7 @@ ref ExprBuilder::createPathPred( return Pred; } -ref ExprBuilder::createUBPathInstsPred( +ref KLEEBuilder::createUBPathInstsPred( Inst *CurrentInst, std::vector &PathInsts, std::map &BlockConstraints, std::map *SelectBranches, UBPathInstMap &CachedUBPathInsts) { @@ -801,7 +688,7 @@ ref ExprBuilder::createUBPathInstsPred( // These tricks basically relies on the dependency chain of instructions // generated by souper. For example, if we say %12 depends on %11, then // %12 would never appear earlier than %11. -ref ExprBuilder::getUBInstCondition() { +ref KLEEBuilder::getUBInstCondition() { // A map from a Phi instruction to all of its KLEE expressions that // encode the path and UB Inst predicates. @@ -850,105 +737,7 @@ ref ExprBuilder::getUBInstCondition() { return Result; } -bool ExprBuilder::getUBPaths(Inst *I, UBPath *Current, - std::vector> &Paths, - UBPathInstMap &CachedUBPathInsts, unsigned Depth) { - if (Depth > MAX_PHI_DEPTH) - return false; - - switch (I->K) { - default: - break; - - case Inst::AddNSW: - case Inst::AddNUW: - case Inst::AddNW: - case Inst::SubNSW: - case Inst::SubNUW: - case Inst::SubNW: - case Inst::MulNSW: - case Inst::MulNUW: - case Inst::MulNW: - case Inst::UDiv: - case Inst::SDiv: - case Inst::UDivExact: - case Inst::SDivExact: - case Inst::URem: - case Inst::SRem: - case Inst::Shl: - case Inst::ShlNSW: - case Inst::ShlNUW: - case Inst::ShlNW: - case Inst::LShr: - case Inst::LShrExact: - case Inst::AShr: - case Inst::AShrExact: - Current->UBInsts.push_back(I); - break; - } - - const std::vector &Ops = I->orderedOps(); - if (I->K == Inst::Phi) { - // Early terminate because this phi has been processed. - // We will use its cached predicates. - if (CachedUBPathInsts.count(I)) - return true; - Current->Insts.push_back(I); - // Since we treat a select instruction as a phi instruction, it's - // possible that I->B has been added already. - if (Current->BlockConstraints.count(I->B)) - return true; - std::vector Tmp = { Current }; - // Create copies of the current path - for (unsigned J = 1; J < Ops.size(); ++J) { - UBPath *New = new UBPath; - *New = *Current; - New->BlockConstraints[I->B] = J; - Paths.push_back(std::move(std::unique_ptr(New))); - Tmp.push_back(New); - } - // Original path takes the first branch - Current->BlockConstraints[I->B] = 0; - // Continue recursively - for (unsigned J = 0; J < Ops.size(); ++J) { - if (!getUBPaths(Ops[J], Tmp[J], Paths, CachedUBPathInsts, Depth + 1)) - return false; - } - } else if (I->K == Inst::Select) { - // Early terminate because this phi has been processed. - // We will use its cached predicates. - if (CachedUBPathInsts.count(I)) - return true; - Current->Insts.push_back(I); - // Current is the predicate operand branch - std::vector Tmp = { Current }; - // True branch - UBPath *True = new UBPath; - *True = *Current; - True->SelectBranches[I] = true; - Paths.push_back(std::move(std::unique_ptr(True))); - Tmp.push_back(True); - // False branch - UBPath *False = new UBPath; - *False = *Current; - False->SelectBranches[I] = false; - Paths.push_back(std::move(std::unique_ptr(False))); - Tmp.push_back(False); - // Continue recursively - for (unsigned J = 0; J < Ops.size(); ++J) { - if (!getUBPaths(Ops[J], Tmp[J], Paths, CachedUBPathInsts, Depth + 1)) - return false; - } - } else { - for (unsigned J = 0; J < Ops.size(); ++J) { - if (!getUBPaths(Ops[J], Current, Paths, CachedUBPathInsts, Depth + 1)) - return false; - } - } - return true; -} - -void ExprBuilder::setBlockPCMap(const BlockPCs &BPCs) { +void KLEEBuilder::setBlockPCMap(const BlockPCs &BPCs) { for (auto BPC : BPCs) { assert(BPC.B && "Block is NULL!"); BlockPCPredMap &PCMap = BlockPCMap[BPC.B]; @@ -980,7 +769,7 @@ void ExprBuilder::setBlockPCMap(const BlockPCs &BPCs) { // However, mixing two parts (one for UB constraints, one for BlockPCs) // may make the code less structured. If we see big performance overhead, // we may consider to combine these two parts together. -ref ExprBuilder::getBlockPCs() { +ref KLEEBuilder::getBlockPCs() { UBPathInstMap CachedPhis; ref Result = klee::ConstantExpr::create(1, Expr::Bool); @@ -1015,157 +804,6 @@ ref ExprBuilder::getBlockPCs() { return Result; } -void ExprBuilder::getBlockPCPhiPaths( - Inst *I, BlockPCPhiPath *Current, - std::vector> &Paths, - UBPathInstMap &CachedPhis) { - - const std::vector &Ops = I->orderedOps(); - if (I->K != Inst::Phi) { - for (unsigned J = 0; J < Ops.size(); ++J) - getBlockPCPhiPaths(Ops[J], Current, Paths, CachedPhis); - return; - } - - // Early terminate because this phi has been processed. - // We will use its cached predicates. - if (CachedPhis.count(I)) - return; - Current->Phis.push_back(I); - - // Since we treat a select instruction as a phi instruction, it's - // possible that I->B has been added already. - if (Current->BlockConstraints.count(I->B)) - return; - - std::vector Tmp = { Current }; - // Create copies of the current path - for (unsigned J = 1; J < Ops.size(); ++J) { - BlockPCPhiPath *New = new BlockPCPhiPath; - *New = *Current; - New->BlockConstraints[I->B] = J; - Paths.push_back(std::move(std::unique_ptr(New))); - Tmp.push_back(New); - } - // Original path takes the first branch - Current->BlockConstraints[I->B] = 0; - - auto PCMap = BlockPCMap.find(I->B); - if (PCMap != BlockPCMap.end()) { - for (unsigned J = 0; J < Ops.size(); ++J) { - auto P = PCMap->second.find(J); - if (P != PCMap->second.end()) - Tmp[J]->PCs.push_back(P->second); - } - } - // Continue recursively - for (unsigned J = 0; J < Ops.size(); ++J) - getBlockPCPhiPaths(Ops[J], Tmp[J], Paths, CachedPhis); -} - -ref ExprBuilder::getZeroBitsMapping(Inst *I) { - return ZeroBitsMap[I]; -} - -ref ExprBuilder::getOneBitsMapping(Inst *I) { - return OneBitsMap[I]; -} - -ref ExprBuilder::getNonZeroBitsMapping(Inst *I) { - return NonZeroBitsMap[I]; -} - -ref ExprBuilder::getNonNegBitsMapping(Inst *I) { - return NonNegBitsMap[I]; -} - -ref ExprBuilder::getNegBitsMapping(Inst *I) { - return NegBitsMap[I]; -} - -ref ExprBuilder::getPowerTwoBitsMapping(Inst *I) { - return PowerTwoBitsMap[I]; -} - -ref ExprBuilder::getSignBitsMapping(Inst *I) { - return SignBitsMap[I]; -} - -// Return an expression which must be proven valid for the candidate to apply. -llvm::Optional souper::GetCandidateExprForReplacement( - const BlockPCs &BPCs, const std::vector &PCs, - InstMapping Mapping, bool Negate) { - - CandidateExpr CE; - ExprBuilder EB(CE.Arrays, CE.ArrayVars); - // Build LHS - ref LHS = EB.get(Mapping.LHS); - ref Ante = klee::ConstantExpr::alloc(1, 1); - ref DemandedBits = klee::ConstantExpr::alloc(Mapping.LHS->DemandedBits); - if (!Mapping.LHS->DemandedBits.isAllOnesValue()) - LHS = AndExpr::create(LHS, DemandedBits); - for (const auto I : CE.ArrayVars) { - if (I) { - if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) { - Ante = AndExpr::create(Ante, EB.getZeroBitsMapping(I)); - Ante = AndExpr::create(Ante, EB.getOneBitsMapping(I)); - } - if (I->NonZero) - Ante = AndExpr::create(Ante, EB.getNonZeroBitsMapping(I)); - if (I->NonNegative) - Ante = AndExpr::create(Ante, EB.getNonNegBitsMapping(I)); - if (I->PowOfTwo) - Ante = AndExpr::create(Ante, EB.getPowerTwoBitsMapping(I)); - if (I->Negative) - Ante = AndExpr::create(Ante, EB.getNegBitsMapping(I)); - if (I->NumSignBits > 1) - Ante = AndExpr::create(Ante, EB.getSignBitsMapping(I)); - } - } - // Build PCs - for (const auto &PC : PCs) { - Ante = AndExpr::create(Ante, EB.getInstMapping(PC)); - } - // Build BPCs - if (BPCs.size()) { - EB.setBlockPCMap(BPCs); - Ante = AndExpr::create(Ante, EB.getBlockPCs()); - } - // Get UB constraints of LHS and (B)PCs - ref LHSPCsUB = klee::ConstantExpr::create(1, Expr::Bool); - if (ExploitUB) { - LHSPCsUB = EB.getUBInstCondition(); - if (LHSPCsUB.isNull()) - return llvm::Optional(); - } - // Build RHS - ref RHS = EB.get(Mapping.RHS); - if (!Mapping.LHS->DemandedBits.isAllOnesValue()) - RHS = AndExpr::create(RHS, DemandedBits); - // Get all UB constraints (LHS && (B)PCs && RHS) - ref UB = klee::ConstantExpr::create(1, Expr::Bool); - if (ExploitUB) { - UB = EB.getUBInstCondition(); - if (UB.isNull()) - return llvm::Optional(); - } - - ref Cons; - if (Negate) // (LHS != RHS) - Cons = NeExpr::create(LHS, RHS); - else // (LHS == RHS) - Cons = EqExpr::create(LHS, RHS); - // Cons && UB - if (Mapping.RHS->K != Inst::Const) - Cons = AndExpr::create(Cons, UB); - // (LHS UB && (B)PCs && (B)PCs UB) - Ante = AndExpr::create(Ante, LHSPCsUB); - // (LHS UB && (B)PCs && (B)PCs UB) => Cons && UB - CE.E = Expr::createImplies(Ante, Cons); - - return llvm::Optional(std::move(CE)); -} - std::string souper::BuildQuery(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, @@ -1173,7 +811,7 @@ std::string souper::BuildQuery(const BlockPCs &BPCs, std::string SMTStr; llvm::raw_string_ostream SMTSS(SMTStr); ConstraintManager Manager; - Optional OptionalCE = GetCandidateExprForReplacement(BPCs, + Optional OptionalCE = GetCandidateExprForReplacement2(BPCs, PCs, Mapping, Negate); if (!OptionalCE.hasValue()) return std::string(); diff --git a/lib/Infer/InstSynthesis.cpp b/lib/Infer/InstSynthesis.cpp index a6281ecbb..62e3efafc 100644 --- a/lib/Infer/InstSynthesis.cpp +++ b/lib/Infer/InstSynthesis.cpp @@ -14,7 +14,8 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" -#include "souper/Extractor/KLEEBuilder.h" +//#include "souper/Extractor/KLEEBuilder.h" +#include "souper/Extractor/ExprBuilder.h" #include "souper/Infer/InstSynthesis.h" #include diff --git a/unittests/Extractor/ExtractorTests.cpp b/unittests/Extractor/ExtractorTests.cpp index d26511f73..8f49f3f8b 100644 --- a/unittests/Extractor/ExtractorTests.cpp +++ b/unittests/Extractor/ExtractorTests.cpp @@ -20,7 +20,8 @@ #include "llvm/IR/Module.h" #include "llvm/Support/SourceMgr.h" #include "souper/Extractor/Candidates.h" -#include "souper/Extractor/KLEEBuilder.h" +//#include "souper/Extractor/KLEEBuilder.h" +#include "souper/Extractor/ExprBuilder.h" #include #include "gtest/gtest.h" From 784980f70e0ad8b64f6a496cc2b7cee1e538969a Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sun, 18 Feb 2018 23:16:38 +0100 Subject: [PATCH 02/49] Work --- CMakeLists.txt | 4 +- include/souper/Extractor/ExprBuilder.h | 170 +- include/souper/Extractor/KLEEBuilder.h | 47 - include/souper/Tool/CandidateMapUtils.h | 1 - include/souper/Tool/GetExprBuilderFromArgs.h | 38 + lib/Extractor/ExprBuilder.cpp | 43 +- lib/Extractor/KLEEBuilder.cpp | 1616 +++++++++--------- lib/Infer/InstSynthesis.cpp | 1 - unittests/Extractor/ExtractorTests.cpp | 1 - 9 files changed, 988 insertions(+), 933 deletions(-) delete mode 100644 include/souper/Extractor/KLEEBuilder.h create mode 100644 include/souper/Tool/GetExprBuilderFromArgs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d3f9d0850..fdd3b71f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,11 +144,10 @@ add_library(souperClangTool STATIC set(SOUPER_EXTRACTOR_FILES lib/Extractor/Candidates.cpp -# lib/Extractor/KLEEBuilder.cpp + lib/Extractor/KLEEBuilder.cpp lib/Extractor/ExprBuilder.cpp lib/Extractor/Solver.cpp include/souper/Extractor/Candidates.h - include/souper/Extractor/KLEEBuilder.h include/souper/Extractor/ExprBuilder.h include/souper/Extractor/Solver.h ) @@ -205,6 +204,7 @@ add_library(souperSMTLIB2 STATIC set(SOUPER_TOOL_FILES lib/Tool/CandidateMapUtils.cpp include/souper/Tool/CandidateMapUtils.h + include/souper/Tool/GetExprBuilderFromArgs.h include/souper/Tool/GetSolverFromArgs.h ) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 59eb7f65a..710fd9f33 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -15,84 +15,76 @@ #ifndef SOUPER_EXTRACTOR_EXPRBUILDER_H #define SOUPER_EXTRACTOR_EXPRBUILDER_H -#include "souper/Extractor/Candidates.h" +#include "klee/Expr.h" +#include "souper/Inst/Inst.h" #include "souper/Util/UniqueNameSet.h" #include -namespace souper { - -typedef void *SMTExpr; -typedef void *Array; - -struct CandidateExpr { - //std::vector> Arrays; - //std::vector ArrayVars; - //klee::ref E; - SMTExpr E; -}; - -const unsigned MAX_PHI_DEPTH = 25; - -typedef std::unordered_map> UBPathInstMap; -typedef std::map BlockPCPredMap; - -struct UBPath { - std::map BlockConstraints; - std::map SelectBranches; - std::vector Insts; - std::vector UBInsts; -}; +using namespace klee; +using namespace souper; -struct BlockPCPhiPath { - std::map BlockConstraints; - std::vector Phis; - std::vector PCs; -}; +namespace souper { class ExprBuilder { public: - ExprBuilder(std::vector> &Arrays, - std::vector &ArrayVars); - virtual ~ExprBuilder(); + const unsigned MAX_PHI_DEPTH = 25; + + typedef std::unordered_map>> UBPathInstMap; + typedef std::map> BlockPCPredMap; + + struct UBPath { + std::map BlockConstraints; + std::map SelectBranches; + std::vector Insts; + std::vector UBInsts; + }; + + struct BlockPCPhiPath { + std::map BlockConstraints; + std::vector Phis; + std::vector> PCs; + }; - virtual SMTExpr addnswUB(Inst *I) = 0; - virtual SMTExpr addnuwUB(Inst *I) = 0; - virtual SMTExpr subnswUB(Inst *I) = 0; - virtual SMTExpr subnuwUB(Inst *I) = 0; - virtual SMTExpr mulnswUB(Inst *I) = 0; - virtual SMTExpr mulnuwUB(Inst *I) = 0; - virtual SMTExpr udivUB(Inst *I) = 0; - virtual SMTExpr udivExactUB(Inst *I) = 0; - virtual SMTExpr sdivUB(Inst *I) = 0; - virtual SMTExpr sdivExactUB(Inst *I) = 0; - virtual SMTExpr shiftUB(Inst *I) = 0; - virtual SMTExpr shlnswUB(Inst *I) = 0; - virtual SMTExpr shlnuwUB(Inst *I) = 0; - virtual SMTExpr lshrExactUB(Inst *I) = 0; - virtual SMTExpr ashrExactUB(Inst *I) = 0; - virtual SMTExpr countOnes(SMTExpr E) = 0; + virtual ~ExprBuilder(); - virtual void recordUBInstruction(Inst *I, SMTExpr E) = 0; - SMTExpr buildAssoc(std::function F, + virtual ref addnswUB(Inst *I) = 0; + virtual ref addnuwUB(Inst *I) = 0; + virtual ref subnswUB(Inst *I) = 0; + virtual ref subnuwUB(Inst *I) = 0; + virtual ref mulnswUB(Inst *I) = 0; + virtual ref mulnuwUB(Inst *I) = 0; + virtual ref udivUB(Inst *I) = 0; + virtual ref udivExactUB(Inst *I) = 0; + virtual ref sdivUB(Inst *I) = 0; + virtual ref sdivExactUB(Inst *I) = 0; + virtual ref shiftUB(Inst *I) = 0; + virtual ref shlnswUB(Inst *I) = 0; + virtual ref shlnuwUB(Inst *I) = 0; + virtual ref lshrExactUB(Inst *I) = 0; + virtual ref ashrExactUB(Inst *I) = 0; + virtual ref countOnes(ref E) = 0; + + virtual void recordUBInstruction(Inst *I, ref E) = 0; + ref buildAssoc(std::function(ref, ref)> F, llvm::ArrayRef Ops); - virtual SMTExpr build(Inst *I) = 0; - virtual SMTExpr get(Inst *I) = 0; - virtual SMTExpr getInstMapping(const InstMapping &IM) = 0; - SMTExpr getZeroBitsMapping(Inst *I); - SMTExpr getOneBitsMapping(Inst *I); - SMTExpr getNonZeroBitsMapping(Inst *I); - SMTExpr getNonNegBitsMapping(Inst *I); - SMTExpr getPowerTwoBitsMapping(Inst *I); - SMTExpr getNegBitsMapping(Inst *I); - SMTExpr getSignBitsMapping(Inst *I); - std::vector getBlockPredicates(Inst *I); - virtual SMTExpr getUBInstCondition() = 0; - virtual SMTExpr getBlockPCs() = 0; + virtual ref build(Inst *I) = 0; + virtual ref get(Inst *I) = 0; + virtual ref getInstMapping(const InstMapping &IM) = 0; + ref getZeroBitsMapping(Inst *I); + ref getOneBitsMapping(Inst *I); + ref getNonZeroBitsMapping(Inst *I); + ref getNonNegBitsMapping(Inst *I); + ref getPowerTwoBitsMapping(Inst *I); + ref getNegBitsMapping(Inst *I); + ref getSignBitsMapping(Inst *I); + std::vector> getBlockPredicates(Inst *I); + virtual ref getUBInstCondition() = 0; + virtual ref getBlockPCs() = 0; virtual void setBlockPCMap(const BlockPCs &BPCs) = 0; - virtual SMTExpr createPathPred(std::map &BlockConstraints, + virtual ref createPathPred(std::map &BlockConstraints, Inst* PathInst, std::map *SelectBranches) = 0; - virtual SMTExpr createUBPathInstsPred(Inst *CurrentInst, + virtual ref createUBPathInstsPred(Inst *CurrentInst, std::vector &UBPathInsts, std::map &BlockConstraints, std::map *SelectBranches, @@ -104,35 +96,39 @@ class ExprBuilder { std::vector> &Paths, UBPathInstMap &CachedPhis); - std::map> BlockPredMap; - std::map ExprMap; - std::map UBExprMap; - std::map ZeroBitsMap; - std::map OneBitsMap; - std::map NonZeroBitsMap; - std::map NonNegBitsMap; - std::map PowerTwoBitsMap; - std::map NegBitsMap; - std::map SignBitsMap; + std::map>> BlockPredMap; + std::map> ExprMap; + std::map> UBExprMap; + std::map> ZeroBitsMap; + std::map> OneBitsMap; + std::map> NonZeroBitsMap; + std::map> NonNegBitsMap; + std::map> PowerTwoBitsMap; + std::map> NegBitsMap; + std::map> SignBitsMap; std::map BlockPCMap; - std::vector> &Arrays; - std::vector &ArrayVars; std::vector UBPathInsts; UniqueNameSet ArrayNames; // Holding the precondition, i.e. blockpc, for the UBInst under process. - SMTExpr UBInstPrecondition; + ref UBInstPrecondition; // Indicate if the UBInst relates to BlockPC - bool IsForBlockPCUBInst; - + bool IsForBlockPCUBInst = false; + + struct CandidateExpr { + std::vector> Arrays; + std::vector ArrayVars; + ref E; + }; + virtual llvm::Optional GetCandidateExprForReplacement( + const BlockPCs &BPCs, const std::vector &PCs, + InstMapping Mapping, bool Negate) = 0; + + virtual std::string BuildQuery(const BlockPCs &BPCs, + const std::vector &PCs, InstMapping Mapping, + std::vector *ModelVars, bool Negate=false) = 0; }; -llvm::Optional GetCandidateExprForReplacement( - const BlockPCs &BPCs, const std::vector &PCs, - InstMapping Mapping, bool Negate); - -std::string BuildQuery(const BlockPCs &BPCs, - const std::vector &PCs, InstMapping Mapping, - std::vector *ModelVars, bool Negate=false); +std::unique_ptr createKLEEBuilder(); } diff --git a/include/souper/Extractor/KLEEBuilder.h b/include/souper/Extractor/KLEEBuilder.h deleted file mode 100644 index 71f69290c..000000000 --- a/include/souper/Extractor/KLEEBuilder.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2014 The Souper Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOUPER_EXTRACTOR_KLEEBUILDER_H -#define SOUPER_EXTRACTOR_KLEEBUILDER_H - -#include "klee/Expr.h" -#include "klee/util/Ref.h" -#include "llvm/ADT/Optional.h" -#include "souper/Extractor/ExprBuilder.h" -#include -#include - -namespace souper { - -class KLEEBuilder : public ExprBuilder - -struct CandidateExpr { - std::vector> Arrays; - std::vector ArrayVars; - klee::ref E; -}; - -#if 0 -llvm::Optional GetCandidateExprForReplacement( - const BlockPCs &BPCs, const std::vector &PCs, - InstMapping Mapping, bool Negate); - -std::string BuildQuery(const BlockPCs &BPCs, - const std::vector &PCs, InstMapping Mapping, - std::vector *ModelVars, bool Negate=false); -#endif - -} - -#endif // SOUPER_EXTRACTOR_KLEEBUILDER_H diff --git a/include/souper/Tool/CandidateMapUtils.h b/include/souper/Tool/CandidateMapUtils.h index 533eb862f..1699d5942 100644 --- a/include/souper/Tool/CandidateMapUtils.h +++ b/include/souper/Tool/CandidateMapUtils.h @@ -17,7 +17,6 @@ #include "llvm/Support/raw_ostream.h" #include "souper/Extractor/Candidates.h" -//#include "souper/Extractor/KLEEBuilder.h" #include "souper/Extractor/ExprBuilder.h" #include "souper/Extractor/Solver.h" #include "souper/KVStore/KVStore.h" diff --git a/include/souper/Tool/GetExprBuilderFromArgs.h b/include/souper/Tool/GetExprBuilderFromArgs.h new file mode 100644 index 000000000..634c6a0ad --- /dev/null +++ b/include/souper/Tool/GetExprBuilderFromArgs.h @@ -0,0 +1,38 @@ +// Copyright 2014 The Souper Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOUPER_TOOL_GETEXPRBUILDERFROMARGS_H +#define SOUPER_TOOL_GETEXPRBUILDERFROMARGS_H + +#include "llvm/Support/CommandLine.h" +#include "souper/Extractor/ExprBuilder.h" +#include + +namespace souper { + +static llvm::cl::opt UseKLEEExprBuilder( + "use-klee-builder", llvm::cl::desc("Use KLEE Expr builder to emit SMTLIBv2"), + llvm::cl::init(true)); + +static std::unique_ptr GetExprBuilderFromArgs() { + if (UseKLEEExprBuilder) { + return createKLEEExprBuilder(); + } else { + return nullptr; + } +} + +} + +#endif // SOUPER_TOOL_GETEXPRBUILDERFROMARGS_H diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 6bbf78ab1..aeeffbf9c 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -17,27 +17,25 @@ using namespace llvm; using namespace souper; -namespace souper { +ExprBuilder::~ExprBuilder() {} -ExprBuilder::ExprBuilder(std::vector> &Arrays, - std::vector &ArrayVars) - : Arrays(Arrays), ArrayVars(ArrayVars), IsForBlockPCUBInst(false) {} +namespace souper { -SMTExpr ExprBuilder::buildAssoc( - std::function F, +ref ExprBuilder::buildAssoc( + std::function(ref, ref)> F, llvm::ArrayRef Ops) { - SMTExpr E = get(Ops[0]); + ref E = get(Ops[0]); for (Inst *I : llvm::ArrayRef(Ops.data()+1, Ops.size()-1)) { E = F(E, get(I)); } return E; } -std::vector ExprBuilder::getBlockPredicates(Inst *I) { +std::vector> ExprBuilder::getBlockPredicates(Inst *I) { assert(I->K == Inst::Phi && "not a phi inst"); if (BlockPredMap.count(I->B)) return BlockPredMap[I->B]; - std::vector PredExpr; + std::vector> PredExpr; for (auto const &PredVar : I->B->PredVars) PredExpr.push_back(build(PredVar)); BlockPredMap[I->B] = PredExpr; @@ -190,45 +188,32 @@ void ExprBuilder::getBlockPCPhiPaths( getBlockPCPhiPaths(Ops[J], Tmp[J], Paths, CachedPhis); } -SMTExpr ExprBuilder::getZeroBitsMapping(Inst *I) { +ref ExprBuilder::getZeroBitsMapping(Inst *I) { return ZeroBitsMap[I]; } -SMTExpr ExprBuilder::getOneBitsMapping(Inst *I) { +ref ExprBuilder::getOneBitsMapping(Inst *I) { return OneBitsMap[I]; } -SMTExpr ExprBuilder::getNonZeroBitsMapping(Inst *I) { +ref ExprBuilder::getNonZeroBitsMapping(Inst *I) { return NonZeroBitsMap[I]; } -SMTExpr ExprBuilder::getNonNegBitsMapping(Inst *I) { +ref ExprBuilder::getNonNegBitsMapping(Inst *I) { return NonNegBitsMap[I]; } -SMTExpr ExprBuilder::getNegBitsMapping(Inst *I) { +ref ExprBuilder::getNegBitsMapping(Inst *I) { return NegBitsMap[I]; } -SMTExpr ExprBuilder::getPowerTwoBitsMapping(Inst *I) { +ref ExprBuilder::getPowerTwoBitsMapping(Inst *I) { return PowerTwoBitsMap[I]; } -SMTExpr ExprBuilder::getSignBitsMapping(Inst *I) { +ref ExprBuilder::getSignBitsMapping(Inst *I) { return SignBitsMap[I]; } -//llvm::Optional GetCandidateExprForReplacement( -// const BlockPCs &BPCs, const std::vector &PCs, -// InstMapping Mapping, bool Negate) { -// return CandidateExpr(); -//} - -//std::string BuildQuery(const BlockPCs &BPCs, -// const std::vector &PCs, -// InstMapping Mapping, -// std::vector *ModelVars, bool Negate) { -// return ""; -//} - } diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 8b45a4fe1..6b18342f4 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "souper/Extractor/KLEEBuilder.h" - #include "klee/Expr.h" #include "klee/util/ExprPPrinter.h" #include "klee/util/ExprSMTLIBPrinter.h" @@ -27,6 +25,7 @@ #include "llvm/IR/Type.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/CommandLine.h" +#include "souper/Extractor/ExprBuilder.h" #include "souper/Inst/Inst.h" #include "souper/Util/UniqueNameSet.h" #include @@ -48,798 +47,885 @@ using namespace llvm; using namespace klee; using namespace souper; -namespace souper { +namespace { -KLEEBuilder::ExprBuilder(std::vector> &Arrays, - std::vector &ArrayVars) - : Arrays(Arrays), ArrayVars(ArrayVars), IsForBlockPCUBInst(false) {} +class KLEEBuilder : public ExprBuilder { + std::vector> &Arrays; + std::vector &ArrayVars; -ref makeSizedArrayRead(unsigned Width, StringRef Name, Inst *Origin) { - std::string NameStr; - if (Name.empty()) - NameStr = "arr"; - else if (Name[0] >= '0' && Name[0] <= '9') - NameStr = ("a" + Name).str(); - else - NameStr = Name; - Arrays.emplace_back( - new Array(ArrayNames.makeName(NameStr), 1, 0, 0, Expr::Int32, Width)); - ArrayVars.push_back(Origin); +public: + KLEEBuilder() {} + ~KLEEBuilder() {} - std::vector ZeroBits, OneBits; - UpdateList UL(Arrays.back().get(), 0); - ref Var = ReadExpr::create(UL, klee::ConstantExpr::alloc(0, Expr::Int32)); - if (Origin && Origin->K == Inst::Var) { - if (Origin->KnownZeros.getBoolValue() || Origin->KnownOnes.getBoolValue()) { - ref NotZeros = NotExpr::create(klee::ConstantExpr::alloc(Origin->KnownZeros)); - ref VarOrNotZero = OrExpr::create(Var, NotZeros); - ZeroBitsMap[Origin] = EqExpr::create(VarOrNotZero, NotZeros); - ref Ones = klee::ConstantExpr::alloc(Origin->KnownOnes); - ref VarAndOnes = AndExpr::create(Var, Ones); - OneBitsMap[Origin] = EqExpr::create(VarAndOnes, Ones); - } - if (Origin->NonZero) - NonZeroBitsMap[Origin] = NeExpr::create(Var, klee::ConstantExpr::create(0, Width)); - if (Origin->NonNegative) - NonNegBitsMap[Origin] = SleExpr::create(klee::ConstantExpr::create(0, Width), Var); - if (Origin->PowOfTwo) { - ref Zero = klee::ConstantExpr::create(0, Width); - PowerTwoBitsMap[Origin] = AndExpr::create(NeExpr::create(Var, Zero), - EqExpr::create(AndExpr::create(Var, - SubExpr::create(Var, klee::ConstantExpr::create(1, Width))), - Zero)); - } - if (Origin->Negative) - NegBitsMap[Origin] = SltExpr::create(Var, klee::ConstantExpr::create(0, Width)); - if (Origin->NumSignBits > 1) { - ref Res = AShrExpr::create(Var, klee::ConstantExpr::create(Width - Origin->NumSignBits, Width)); - ref TestOnes = AShrExpr::create(ShlExpr::create(klee::ConstantExpr::create(1, Width), - klee::ConstantExpr::create(Width - 1, Width)), - klee::ConstantExpr::create(Width - 1, Width)); - SignBitsMap[Origin] = OrExpr::create(EqExpr::create(Res, TestOnes), - EqExpr::create(Res, klee::ConstantExpr::create(0, Width))); + ref makeSizedArrayRead(unsigned Width, StringRef Name, Inst *Origin) { + std::string NameStr; + if (Name.empty()) + NameStr = "arr"; + else if (Name[0] >= '0' && Name[0] <= '9') + NameStr = ("a" + Name).str(); + else + NameStr = Name; + Arrays.emplace_back( + new Array(ArrayNames.makeName(NameStr), 1, 0, 0, Expr::Int32, Width)); + ArrayVars.push_back(Origin); + + std::vector ZeroBits, OneBits; + UpdateList UL(Arrays.back().get(), 0); + ref Var = ReadExpr::create(UL, klee::ConstantExpr::alloc(0, Expr::Int32)); + if (Origin && Origin->K == Inst::Var) { + if (Origin->KnownZeros.getBoolValue() || Origin->KnownOnes.getBoolValue()) { + ref NotZeros = NotExpr::create(klee::ConstantExpr::alloc(Origin->KnownZeros)); + ref VarOrNotZero = OrExpr::create(Var, NotZeros); + ZeroBitsMap[Origin] = EqExpr::create(VarOrNotZero, NotZeros); + ref Ones = klee::ConstantExpr::alloc(Origin->KnownOnes); + ref VarAndOnes = AndExpr::create(Var, Ones); + OneBitsMap[Origin] = EqExpr::create(VarAndOnes, Ones); + } + if (Origin->NonZero) + NonZeroBitsMap[Origin] = NeExpr::create(Var, klee::ConstantExpr::create(0, Width)); + if (Origin->NonNegative) + NonNegBitsMap[Origin] = SleExpr::create(klee::ConstantExpr::create(0, Width), Var); + if (Origin->PowOfTwo) { + ref Zero = klee::ConstantExpr::create(0, Width); + PowerTwoBitsMap[Origin] = AndExpr::create(NeExpr::create(Var, Zero), + EqExpr::create(AndExpr::create(Var, + SubExpr::create(Var, klee::ConstantExpr::create(1, Width))), + Zero)); + } + if (Origin->Negative) + NegBitsMap[Origin] = SltExpr::create(Var, klee::ConstantExpr::create(0, Width)); + if (Origin->NumSignBits > 1) { + ref Res = AShrExpr::create(Var, klee::ConstantExpr::create(Width - Origin->NumSignBits, Width)); + ref TestOnes = AShrExpr::create(ShlExpr::create(klee::ConstantExpr::create(1, Width), + klee::ConstantExpr::create(Width - 1, Width)), + klee::ConstantExpr::create(Width - 1, Width)); + SignBitsMap[Origin] = OrExpr::create(EqExpr::create(Res, TestOnes), + EqExpr::create(Res, klee::ConstantExpr::create(0, Width))); + } } - } - return Var; -} - -ref KLEEBuilder::addnswUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Add = AddExpr::create(L, R); - Expr::Width Width = L->getWidth(); - ref LMSB = ExtractExpr::create(L, Width-1, Expr::Bool); - ref RMSB = ExtractExpr::create(R, Width-1, Expr::Bool); - ref AddMSB = ExtractExpr::create(Add, Width-1, Expr::Bool); - return Expr::createImplies(EqExpr::create(LMSB, RMSB), - EqExpr::create(LMSB, AddMSB)); -} - -ref KLEEBuilder::addnuwUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - Expr::Width Width = L->getWidth(); - ref Lext = ZExtExpr::create(L, Width+1); - ref Rext = ZExtExpr::create(R, Width+1); - ref Add = AddExpr::create(Lext, Rext); - ref AddMSB = ExtractExpr::create(Add, Width, Expr::Bool); - return Expr::createIsZero(AddMSB); -} - -ref KLEEBuilder::subnswUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Sub = SubExpr::create(L, R); - Expr::Width Width = L->getWidth(); - ref LMSB = ExtractExpr::create(L, Width-1, Expr::Bool); - ref RMSB = ExtractExpr::create(R, Width-1, Expr::Bool); - ref SubMSB = ExtractExpr::create(Sub, Width-1, Expr::Bool); - return Expr::createImplies(NeExpr::create(LMSB, RMSB), - EqExpr::create(LMSB, SubMSB)); -} - -ref KLEEBuilder::subnuwUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - Expr::Width Width = L->getWidth(); - ref Lext = ZExtExpr::create(L, Width+1); - ref Rext = ZExtExpr::create(R, Width+1); - ref Sub = SubExpr::create(Lext, Rext); - ref SubMSB = ExtractExpr::create(Sub, Width, Expr::Bool); - return Expr::createIsZero(SubMSB); -} - -ref KLEEBuilder::mulnswUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - // The computation below has to be performed on the operands of - // multiplication instruction. The instruction using mulnswUB() - // can be of different width, for instance in SMulO instruction - // which is of 1-bit, but the operands width are to be used here. - Expr::Width Width = get(Ops[0])->getWidth(); - ref L = SExtExpr::create(get(Ops[0]), 2*Width); - ref R = SExtExpr::create(get(Ops[1]), 2*Width); - ref Mul = MulExpr::create(L, R); - ref LowerBits = ExtractExpr::create(Mul, 0, Width); - ref LowerBitsExt = SExtExpr::create(LowerBits, 2*Width); - return EqExpr::create(Mul, LowerBitsExt); -} - -ref KLEEBuilder::mulnuwUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - Expr::Width Width = L->getWidth(); - ref Lext = ZExtExpr::create(L, 2*Width); - ref Rext = ZExtExpr::create(R, 2*Width); - ref Mul = MulExpr::create(Lext, Rext); - ref HigherBits = ExtractExpr::create(Mul, Width, Width); - return Expr::createIsZero(HigherBits); -} - -ref KLEEBuilder::udivUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref R = get(Ops[1]); - return NeExpr::create(R, klee::ConstantExpr::create(0, R->getWidth())); -} - -ref KLEEBuilder::udivExactUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Udiv = UDivExpr::create(L, R); - return EqExpr::create(L, MulExpr::create(R, Udiv)); -} - -ref KLEEBuilder::sdivUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref ShiftBy = klee::ConstantExpr::create(L->getWidth()-1, - L->getWidth()); - ref IntMin = ShlExpr::create(klee::ConstantExpr::create( - 1, L->getWidth()), ShiftBy); - ref NegOne = AShrExpr::create(IntMin, ShiftBy); - return AndExpr::create(NeExpr::create(R, klee::ConstantExpr::create( - 0, R->getWidth())), OrExpr::create( - NeExpr::create(L, IntMin), NeExpr::create(R, NegOne))); -} - -ref KLEEBuilder::sdivExactUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Sdiv = SDivExpr::create(L, R); - return EqExpr::create(L, MulExpr::create(R, Sdiv)); -} - -ref KLEEBuilder::shiftUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Lwidth = klee::ConstantExpr::create(L->getWidth(), L->getWidth()); - return UltExpr::create(R, Lwidth); -} - -ref KLEEBuilder::shlnswUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = ShlExpr::create(L, R); - ref RShift = AShrExpr::create(Result, R); - return EqExpr::create(RShift, L); -} - -ref KLEEBuilder::shlnuwUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = ShlExpr::create(L, R); - ref RShift = LShrExpr::create(Result, R); - return EqExpr::create(RShift, L); -} - -ref KLEEBuilder::lshrExactUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = LShrExpr::create(L, R); - ref LShift = ShlExpr::create(Result, R); - return EqExpr::create(LShift, L); -} - -ref KLEEBuilder::ashrExactUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = AShrExpr::create(L, R); - ref LShift = ShlExpr::create(Result, R); - return EqExpr::create(LShift, L); -} - -ref KLEEBuilder::countOnes(ref L) { - Expr::Width Width = L->getWidth(); - ref Count = klee::ConstantExpr::alloc(llvm::APInt(Width, 0)); - for (unsigned i=0; i Bit = ExtractExpr::create(L, i, Expr::Bool); - ref BitExt = ZExtExpr::create(Bit, Width); - Count = AddExpr::create(Count, BitExt); - } - return Count; -} - -void KLEEBuilder::recordUBInstruction(Inst *I, ref E) { - if (!IsForBlockPCUBInst) { - UBExprMap[I] = E; - } - else if (!UBInstPrecondition.isNull()) { - // The current UBInst comes from BlockPC. It's possible - // that the precondition is missing at this point (e.g., - // the corresponding Phi is not part of the current - // Souper IR because the Phi is not in the equivalence class - // of the instruction. - UBExprMap[I] = Expr::createImplies(UBInstPrecondition, E); - } -} - -ref KLEEBuilder::build(Inst *I) { - const std::vector &Ops = I->orderedOps(); - switch (I->K) { - case Inst::UntypedConst: - assert(0 && "unexpected kind"); - case Inst::Const: - return klee::ConstantExpr::alloc(I->Val); - case Inst::Var: - return makeSizedArrayRead(I->Width, I->Name, I); - case Inst::Phi: { - const auto &PredExpr = getBlockPredicates(I); - ref E = get(Ops[0]); - // e.g. P2 ? (P1 ? Op1_Expr : Op2_Expr) : Op3_Expr - for (unsigned J = 1; J < Ops.size(); ++J) { - E = SelectExpr::create(PredExpr[J-1], E, get(Ops[J])); - } - UBPathInsts.push_back(I); - return E; - } - case Inst::Add: - return buildAssoc(AddExpr::create, Ops); - case Inst::AddNSW: { - ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, addnswUB(I)); - return Add; - } - case Inst::AddNUW: { - ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, addnuwUB(I)); - return Add; - } - case Inst::AddNW: { - ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(addnswUB(I), addnuwUB(I))); - return Add; - } - case Inst::Sub: - return SubExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::SubNSW: { - ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, subnswUB(I)); - return Sub; - } - case Inst::SubNUW: { - ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, subnuwUB(I)); - return Sub; - } - case Inst::SubNW: { - ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(subnswUB(I), subnuwUB(I))); - return Sub; - } - case Inst::Mul: - return buildAssoc(MulExpr::create, Ops); - case Inst::MulNSW: { - ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, mulnswUB(I)); - return Mul; - } - case Inst::MulNUW: { - ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, mulnuwUB(I)); - return Mul; - } - case Inst::MulNW: { - ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(mulnswUB(I), mulnuwUB(I))); - return Mul; - } - - // We introduce these extra checks here because KLEE invokes llvm::APInt's - // div functions , which crash upon divide-by-zero. - case Inst::UDiv: - case Inst::SDiv: - case Inst::UDivExact: - case Inst::SDivExact: - case Inst::URem: - case Inst::SRem: { // Fall-through - // If the second oprand is 0, then it definitely causes UB. - // There are quite a few cases where KLEE folds operations into zero, - // e.g., "sext i16 0 to i32", "0 + 0", "2 - 2", etc. In all cases, - // we skip building the corresponding KLEE expressions and just return - // a constant zero. - ref R = get(Ops[1]); - if (R->isZero()) { - recordUBInstruction(I, klee::ConstantExpr::create(0, 1)); - return klee::ConstantExpr::create(0, Ops[1]->Width); + return Var; + } + + ref addnswUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Add = AddExpr::create(L, R); + Expr::Width Width = L->getWidth(); + ref LMSB = ExtractExpr::create(L, Width-1, Expr::Bool); + ref RMSB = ExtractExpr::create(R, Width-1, Expr::Bool); + ref AddMSB = ExtractExpr::create(Add, Width-1, Expr::Bool); + return Expr::createImplies(EqExpr::create(LMSB, RMSB), + EqExpr::create(LMSB, AddMSB)); + } + + ref addnuwUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + Expr::Width Width = L->getWidth(); + ref Lext = ZExtExpr::create(L, Width+1); + ref Rext = ZExtExpr::create(R, Width+1); + ref Add = AddExpr::create(Lext, Rext); + ref AddMSB = ExtractExpr::create(Add, Width, Expr::Bool); + return Expr::createIsZero(AddMSB); + } + + ref subnswUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Sub = SubExpr::create(L, R); + Expr::Width Width = L->getWidth(); + ref LMSB = ExtractExpr::create(L, Width-1, Expr::Bool); + ref RMSB = ExtractExpr::create(R, Width-1, Expr::Bool); + ref SubMSB = ExtractExpr::create(Sub, Width-1, Expr::Bool); + return Expr::createImplies(NeExpr::create(LMSB, RMSB), + EqExpr::create(LMSB, SubMSB)); + } + + ref subnuwUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + Expr::Width Width = L->getWidth(); + ref Lext = ZExtExpr::create(L, Width+1); + ref Rext = ZExtExpr::create(R, Width+1); + ref Sub = SubExpr::create(Lext, Rext); + ref SubMSB = ExtractExpr::create(Sub, Width, Expr::Bool); + return Expr::createIsZero(SubMSB); + } + + ref mulnswUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + // The computation below has to be performed on the operands of + // multiplication instruction. The instruction using mulnswUB() + // can be of different width, for instance in SMulO instruction + // which is of 1-bit, but the operands width are to be used here. + Expr::Width Width = get(Ops[0])->getWidth(); + ref L = SExtExpr::create(get(Ops[0]), 2*Width); + ref R = SExtExpr::create(get(Ops[1]), 2*Width); + ref Mul = MulExpr::create(L, R); + ref LowerBits = ExtractExpr::create(Mul, 0, Width); + ref LowerBitsExt = SExtExpr::create(LowerBits, 2*Width); + return EqExpr::create(Mul, LowerBitsExt); + } + + ref mulnuwUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + Expr::Width Width = L->getWidth(); + ref Lext = ZExtExpr::create(L, 2*Width); + ref Rext = ZExtExpr::create(R, 2*Width); + ref Mul = MulExpr::create(Lext, Rext); + ref HigherBits = ExtractExpr::create(Mul, Width, Width); + return Expr::createIsZero(HigherBits); + } + + ref udivUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref R = get(Ops[1]); + return NeExpr::create(R, klee::ConstantExpr::create(0, R->getWidth())); + } + + ref udivExactUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Udiv = UDivExpr::create(L, R); + return EqExpr::create(L, MulExpr::create(R, Udiv)); + } + + ref sdivUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref ShiftBy = klee::ConstantExpr::create(L->getWidth()-1, + L->getWidth()); + ref IntMin = ShlExpr::create(klee::ConstantExpr::create( + 1, L->getWidth()), ShiftBy); + ref NegOne = AShrExpr::create(IntMin, ShiftBy); + return AndExpr::create(NeExpr::create(R, klee::ConstantExpr::create( + 0, R->getWidth())), OrExpr::create( + NeExpr::create(L, IntMin), NeExpr::create(R, NegOne))); + } + + ref sdivExactUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Sdiv = SDivExpr::create(L, R); + return EqExpr::create(L, MulExpr::create(R, Sdiv)); + } + + ref shiftUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Lwidth = klee::ConstantExpr::create(L->getWidth(), L->getWidth()); + return UltExpr::create(R, Lwidth); + } + + ref shlnswUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Result = ShlExpr::create(L, R); + ref RShift = AShrExpr::create(Result, R); + return EqExpr::create(RShift, L); + } + + ref shlnuwUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Result = ShlExpr::create(L, R); + ref RShift = LShrExpr::create(Result, R); + return EqExpr::create(RShift, L); + } + + ref lshrExactUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Result = LShrExpr::create(L, R); + ref LShift = ShlExpr::create(Result, R); + return EqExpr::create(LShift, L); + } + + ref ashrExactUB(Inst *I) { + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Result = AShrExpr::create(L, R); + ref LShift = ShlExpr::create(Result, R); + return EqExpr::create(LShift, L); + } + + ref countOnes(ref L) { + Expr::Width Width = L->getWidth(); + ref Count = klee::ConstantExpr::alloc(llvm::APInt(Width, 0)); + for (unsigned i=0; i Bit = ExtractExpr::create(L, i, Expr::Bool); + ref BitExt = ZExtExpr::create(Bit, Width); + Count = AddExpr::create(Count, BitExt); + } + return Count; + } + + void recordUBInstruction(Inst *I, ref E) { + if (!IsForBlockPCUBInst) { + UBExprMap[I] = E; } - + else if (!UBInstPrecondition.isNull()) { + // The current UBInst comes from BlockPC. It's possible + // that the precondition is missing at this point (e.g., + // the corresponding Phi is not part of the current + // Souper IR because the Phi is not in the equivalence class + // of the instruction. + UBExprMap[I] = Expr::createImplies(UBInstPrecondition, E); + } + } + + ref build(Inst *I) { + const std::vector &Ops = I->orderedOps(); switch (I->K) { + case Inst::UntypedConst: + assert(0 && "unexpected kind"); + case Inst::Const: + return klee::ConstantExpr::alloc(I->Val); + case Inst::Var: + return makeSizedArrayRead(I->Width, I->Name, I); + case Inst::Phi: { + const auto &PredExpr = getBlockPredicates(I); + ref E = get(Ops[0]); + // e.g. P2 ? (P1 ? Op1_Expr : Op2_Expr) : Op3_Expr + for (unsigned J = 1; J < Ops.size(); ++J) { + E = SelectExpr::create(PredExpr[J-1], E, get(Ops[J])); + } + UBPathInsts.push_back(I); + return E; + } + case Inst::Add: + return buildAssoc(AddExpr::create, Ops); + case Inst::AddNSW: { + ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, addnswUB(I)); + return Add; + } + case Inst::AddNUW: { + ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, addnuwUB(I)); + return Add; + } + case Inst::AddNW: { + ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, AndExpr::create(addnswUB(I), addnuwUB(I))); + return Add; + } + case Inst::Sub: + return SubExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::SubNSW: { + ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, subnswUB(I)); + return Sub; + } + case Inst::SubNUW: { + ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, subnuwUB(I)); + return Sub; + } + case Inst::SubNW: { + ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, AndExpr::create(subnswUB(I), subnuwUB(I))); + return Sub; + } + case Inst::Mul: + return buildAssoc(MulExpr::create, Ops); + case Inst::MulNSW: { + ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, mulnswUB(I)); + return Mul; + } + case Inst::MulNUW: { + ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, mulnuwUB(I)); + return Mul; + } + case Inst::MulNW: { + ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, AndExpr::create(mulnswUB(I), mulnuwUB(I))); + return Mul; + } + + // We introduce these extra checks here because KLEE invokes llvm::APInt's + // div functions , which crash upon divide-by-zero. + case Inst::UDiv: + case Inst::SDiv: + case Inst::UDivExact: + case Inst::SDivExact: + case Inst::URem: + case Inst::SRem: { // Fall-through + // If the second oprand is 0, then it definitely causes UB. + // There are quite a few cases where KLEE folds operations into zero, + // e.g., "sext i16 0 to i32", "0 + 0", "2 - 2", etc. In all cases, + // we skip building the corresponding KLEE expressions and just return + // a constant zero. + ref R = get(Ops[1]); + if (R->isZero()) { + recordUBInstruction(I, klee::ConstantExpr::create(0, 1)); + return klee::ConstantExpr::create(0, Ops[1]->Width); + } + + switch (I->K) { + default: + break; + + case Inst::UDiv: { + ref Udiv = UDivExpr::create(get(Ops[0]), R); + recordUBInstruction(I, udivUB(I)); + return Udiv; + } + case Inst::SDiv: { + ref Sdiv = SDivExpr::create(get(Ops[0]), R); + recordUBInstruction(I, sdivUB(I)); + return Sdiv; + } + case Inst::UDivExact: { + ref Udiv = UDivExpr::create(get(Ops[0]), R); + recordUBInstruction(I, AndExpr::create(udivUB(I), udivExactUB(I))); + return Udiv; + } + case Inst::SDivExact: { + ref Sdiv = SDivExpr::create(get(Ops[0]), R); + recordUBInstruction(I, AndExpr::create(sdivUB(I), sdivExactUB(I))); + return Sdiv; + } + case Inst::URem: { + ref Urem = URemExpr::create(get(Ops[0]), R); + recordUBInstruction(I, udivUB(I)); + return Urem; + } + case Inst::SRem: { + ref Srem = SRemExpr::create(get(Ops[0]), R); + recordUBInstruction(I, sdivUB(I)); + return Srem; + } + llvm_unreachable("unknown kind"); + } + } + + case Inst::And: + return buildAssoc(AndExpr::create, Ops); + case Inst::Or: + return buildAssoc(OrExpr::create, Ops); + case Inst::Xor: + return buildAssoc(XorExpr::create, Ops); + case Inst::Shl: { + ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, shiftUB(I)); + return Result; + } + case Inst::ShlNSW: { + ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, AndExpr::create(shiftUB(I), shlnswUB(I))); + return Result; + } + case Inst::ShlNUW: { + ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, AndExpr::create(shiftUB(I), shlnuwUB(I))); + return Result; + } + case Inst::ShlNW: { + ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, AndExpr::create(shiftUB(I), + AndExpr::create(shlnswUB(I), + shlnuwUB(I)))); + return Result; + } + case Inst::LShr: { + ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, shiftUB(I)); + return Result; + } + case Inst::LShrExact: { + ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, AndExpr::create(shiftUB(I), lshrExactUB(I))); + return Result; + } + case Inst::AShr: { + ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, shiftUB(I)); + return Result; + } + case Inst::AShrExact: { + ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); + recordUBInstruction(I, AndExpr::create(shiftUB(I), ashrExactUB(I))); + return Result; + } + case Inst::Select: + UBPathInsts.push_back(I); + return SelectExpr::create(get(Ops[0]), get(Ops[1]), get(Ops[2])); + case Inst::ZExt: + return ZExtExpr::create(get(Ops[0]), I->Width); + case Inst::SExt: + return SExtExpr::create(get(Ops[0]), I->Width); + case Inst::Trunc: + return ExtractExpr::create(get(Ops[0]), 0, I->Width); + case Inst::Eq: + return EqExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::Ne: + return NeExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::Ult: + return UltExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::Slt: + return SltExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::Ule: + return UleExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::Sle: + return SleExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::CtPop: + return countOnes(get(Ops[0])); + case Inst::BSwap: { + ref L = get(Ops[0]); + unsigned Width = L->getWidth(); + if (Width == 16) { + return ConcatExpr::create(ExtractExpr::create(L, 0, 8), + ExtractExpr::create(L, 8, 8)); + } + else if (Width == 32) { + return ConcatExpr::create4(ExtractExpr::create(L, 0, 8), + ExtractExpr::create(L, 8, 8), + ExtractExpr::create(L, 16, 8), + ExtractExpr::create(L, 24, 8)); + } + else if (Width == 64) { + return ConcatExpr::create8(ExtractExpr::create(L, 0, 8), + ExtractExpr::create(L, 8, 8), + ExtractExpr::create(L, 16, 8), + ExtractExpr::create(L, 24, 8), + ExtractExpr::create(L, 32, 8), + ExtractExpr::create(L, 40, 8), + ExtractExpr::create(L, 48, 8), + ExtractExpr::create(L, 56, 8)); + } + break; + } + case Inst::Cttz: { + ref L = get(Ops[0]); + unsigned Width = L->getWidth(); + ref Val = L; + for (unsigned i=0, j=0; j L = get(Ops[0]); + unsigned Width = L->getWidth(); + ref Val = L; + for (unsigned i=0, j=0; jVal.getZExtValue(); + return get(Ops[0]->Ops[Index]); + } + case Inst::SAddWithOverflow: + case Inst::UAddWithOverflow: + case Inst::SSubWithOverflow: + case Inst::USubWithOverflow: + case Inst::SMulWithOverflow: + case Inst::UMulWithOverflow: default: break; - - case Inst::UDiv: { - ref Udiv = UDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, udivUB(I)); - return Udiv; - } - case Inst::SDiv: { - ref Sdiv = SDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, sdivUB(I)); - return Sdiv; - } - case Inst::UDivExact: { - ref Udiv = UDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, AndExpr::create(udivUB(I), udivExactUB(I))); - return Udiv; - } - case Inst::SDivExact: { - ref Sdiv = SDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, AndExpr::create(sdivUB(I), sdivExactUB(I))); - return Sdiv; - } - case Inst::URem: { - ref Urem = URemExpr::create(get(Ops[0]), R); - recordUBInstruction(I, udivUB(I)); - return Urem; - } - case Inst::SRem: { - ref Srem = SRemExpr::create(get(Ops[0]), R); - recordUBInstruction(I, sdivUB(I)); - return Srem; } llvm_unreachable("unknown kind"); } + + ref get(Inst *I) { + ref &E = ExprMap[I]; + if (E.isNull()) { + E = build(I); + assert(E->getWidth() == I->Width); + } + return E; } - - case Inst::And: - return buildAssoc(AndExpr::create, Ops); - case Inst::Or: - return buildAssoc(OrExpr::create, Ops); - case Inst::Xor: - return buildAssoc(XorExpr::create, Ops); - case Inst::Shl: { - ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, shiftUB(I)); - return Result; - } - case Inst::ShlNSW: { - ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(shiftUB(I), shlnswUB(I))); - return Result; - } - case Inst::ShlNUW: { - ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(shiftUB(I), shlnuwUB(I))); - return Result; - } - case Inst::ShlNW: { - ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(shiftUB(I), - AndExpr::create(shlnswUB(I), - shlnuwUB(I)))); - return Result; - } - case Inst::LShr: { - ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, shiftUB(I)); - return Result; - } - case Inst::LShrExact: { - ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(shiftUB(I), lshrExactUB(I))); - return Result; - } - case Inst::AShr: { - ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, shiftUB(I)); - return Result; - } - case Inst::AShrExact: { - ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(shiftUB(I), ashrExactUB(I))); - return Result; - } - case Inst::Select: - UBPathInsts.push_back(I); - return SelectExpr::create(get(Ops[0]), get(Ops[1]), get(Ops[2])); - case Inst::ZExt: - return ZExtExpr::create(get(Ops[0]), I->Width); - case Inst::SExt: - return SExtExpr::create(get(Ops[0]), I->Width); - case Inst::Trunc: - return ExtractExpr::create(get(Ops[0]), 0, I->Width); - case Inst::Eq: - return EqExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::Ne: - return NeExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::Ult: - return UltExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::Slt: - return SltExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::Ule: - return UleExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::Sle: - return SleExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::CtPop: - return countOnes(get(Ops[0])); - case Inst::BSwap: { - ref L = get(Ops[0]); - unsigned Width = L->getWidth(); - if (Width == 16) { - return ConcatExpr::create(ExtractExpr::create(L, 0, 8), - ExtractExpr::create(L, 8, 8)); - } - else if (Width == 32) { - return ConcatExpr::create4(ExtractExpr::create(L, 0, 8), - ExtractExpr::create(L, 8, 8), - ExtractExpr::create(L, 16, 8), - ExtractExpr::create(L, 24, 8)); - } - else if (Width == 64) { - return ConcatExpr::create8(ExtractExpr::create(L, 0, 8), - ExtractExpr::create(L, 8, 8), - ExtractExpr::create(L, 16, 8), - ExtractExpr::create(L, 24, 8), - ExtractExpr::create(L, 32, 8), - ExtractExpr::create(L, 40, 8), - ExtractExpr::create(L, 48, 8), - ExtractExpr::create(L, 56, 8)); - } - break; - } - case Inst::Cttz: { - ref L = get(Ops[0]); - unsigned Width = L->getWidth(); - ref Val = L; - for (unsigned i=0, j=0; j L = get(Ops[0]); - unsigned Width = L->getWidth(); - ref Val = L; - for (unsigned i=0, j=0; jVal.getZExtValue(); - return get(Ops[0]->Ops[Index]); - } - case Inst::SAddWithOverflow: - case Inst::UAddWithOverflow: - case Inst::SSubWithOverflow: - case Inst::USubWithOverflow: - case Inst::SMulWithOverflow: - case Inst::UMulWithOverflow: - default: - break; - } - llvm_unreachable("unknown kind"); -} - -ref KLEEBuilder::get(Inst *I) { - ref &E = ExprMap[I]; - if (E.isNull()) { - E = build(I); - assert(E->getWidth() == I->Width); - } - return E; -} - -ref KLEEBuilder::getInstMapping(const InstMapping &IM) { - return EqExpr::create(get(IM.LHS), get(IM.RHS)); -} - -ref KLEEBuilder::createPathPred( - std::map &BlockConstraints, Inst* PathInst, - std::map *SelectBranches) { - - ref Pred = klee::ConstantExpr::alloc(1, 1); - if (PathInst->K == Inst::Phi) { - unsigned Num = BlockConstraints[PathInst->B]; - const auto &PredExpr = BlockPredMap[PathInst->B]; - // Sanity checks - assert(PredExpr.size() && "there must be path predicates for the UBs"); - assert(PredExpr.size() == PathInst->Ops.size()-1 && - "phi predicate size mismatch"); - // Add the predicate(s) - if (Num == 0) - Pred = AndExpr::create(Pred, PredExpr[0]); - else - Pred = AndExpr::create(Pred, Expr::createIsZero(PredExpr[Num-1])); - for (unsigned B = Num; B < PredExpr.size(); ++B) - Pred = AndExpr::create(Pred, PredExpr[B]); - } - else if (PathInst->K == Inst::Select) { - ref SelectPred = get(PathInst->orderedOps()[0]); - assert(SelectBranches && "NULL SelectBranches?"); - auto SI = SelectBranches->find(PathInst); - // The current path doesn't have info about this select instruction. - if (SI == SelectBranches->end()) { - return Pred; - } - if (SI->second) - Pred = AndExpr::create(Pred, SelectPred); - else - Pred = AndExpr::create(Pred, Expr::createIsZero(SelectPred)); - } - else { - assert(0 && "cannot reach here"); - } - - return Pred; -} - -ref KLEEBuilder::createUBPathInstsPred( - Inst *CurrentInst, std::vector &PathInsts, - std::map &BlockConstraints, - std::map *SelectBranches, UBPathInstMap &CachedUBPathInsts) { - ref Pred = klee::ConstantExpr::alloc(1, 1); - for (const auto &PathInst : PathInsts) { - if (PathInst->Ops.size() == 1) - continue; - ref InstPred = - createPathPred(BlockConstraints, PathInst, SelectBranches); - - UBPathInstMap::iterator PI = CachedUBPathInsts.find(PathInst); - if (PI == CachedUBPathInsts.end()) { - // It's possible that we don't have a cached instruction yet, - // e.g., the CurrentInst is a select operator. - assert(CurrentInst->K == Inst::Select && "No cached Inst?"); - CachedUBPathInsts[PathInst] = {}; - PI = CachedUBPathInsts.find(PathInst); - } - if (PI->first != CurrentInst && PI->second.size() != 0) { - // Use cached Expr along each path which has UB Insts, - // and cache the expanded Expr for the current working Phi - for (auto CE : PI->second) { - InstPred = AndExpr::create(CE, InstPred); - CachedUBPathInsts[CurrentInst].push_back(InstPred); - Pred = AndExpr::create(Pred, InstPred); + + ref getInstMapping(const InstMapping &IM) { + return EqExpr::create(get(IM.LHS), get(IM.RHS)); + } + + ref createPathPred( + std::map &BlockConstraints, Inst* PathInst, + std::map *SelectBranches) { + + ref Pred = klee::ConstantExpr::alloc(1, 1); + if (PathInst->K == Inst::Phi) { + unsigned Num = BlockConstraints[PathInst->B]; + const auto &PredExpr = BlockPredMap[PathInst->B]; + // Sanity checks + assert(PredExpr.size() && "there must be path predicates for the UBs"); + assert(PredExpr.size() == PathInst->Ops.size()-1 && + "phi predicate size mismatch"); + // Add the predicate(s) + if (Num == 0) + Pred = AndExpr::create(Pred, PredExpr[0]); + else + Pred = AndExpr::create(Pred, Expr::createIsZero(PredExpr[Num-1])); + for (unsigned B = Num; B < PredExpr.size(); ++B) + Pred = AndExpr::create(Pred, PredExpr[B]); + } + else if (PathInst->K == Inst::Select) { + ref SelectPred = get(PathInst->orderedOps()[0]); + assert(SelectBranches && "NULL SelectBranches?"); + auto SI = SelectBranches->find(PathInst); + // The current path doesn't have info about this select instruction. + if (SI == SelectBranches->end()) { + return Pred; } + if (SI->second) + Pred = AndExpr::create(Pred, SelectPred); + else + Pred = AndExpr::create(Pred, Expr::createIsZero(SelectPred)); } else { - CachedUBPathInsts[CurrentInst].push_back(InstPred); - Pred = AndExpr::create(Pred, InstPred); + assert(0 && "cannot reach here"); } - } - return Pred; -} - -// Collect UB Inst condition for each Phi instruction. -// The basic algorithm is: -// (1) for a given phi instruction, we first collect all paths that start -// from the phi. For each path, we also keep the the phi instructions -// along the path and the UB instructions associated with these phi -// instructions; -// (2) then for each path, we generate a corresponding KLEE expression -// based on the facts that we collected in step (1), including: -// * UB instructions; -// * Phi predicates; -// -// With the algorithm, it is easy to get into the path explosion problem, -// i.e., the number of paths is increased exponentially. Under some -// circumstances, e.g., the number of phis is too large, we will suffer -// with large performance overhead. In some extreme cases, we will fail -// to process some file due to the large memory footprint, i.e., `newing' -// too many UBPaths. Two tricks are used to relief the penalty of the -// path explosion problem: -// (1) caching the KLEE expresions for each processed phi, where each -// KLEE expression encodes the path that starts from one of the phi's -// values. For example, when processing a sample souper IR below -// -// %0 = block -// %1 = block -// %2:i32 = var -// %3:i32 = shl 0:i32, %2 -// %4:i32 = var -// %5:i32 = shl 0:i32, %4 -// %6 = var -// %11:i32 = phi %1, %3, %5 -// %12:i32 = phi %0, %6, %11 -// -// we first encounter phi %11. The generated KLEE expression -// for this phi encodes two paths, i.e., %3 and %5. We cache -// these two into CachedUBPathInsts. Then we move to process phi %12. -// At this point, rather than recursively re-contruct %11 (through -// %12's value), we just re-used the cached path-expressions. -// For each path-expression, we append it with %12's own predicate -// and also cache them with %12 for future use. After finishing -// %12, we will have three entries for phi %12. -// (2) The first trick increases the performance, but we still suffer -// with large memory consumption, i.e., it's easy to cache too -// many paths. The second trick is to reduce the memory footprint -// by only caching "useful" path that has UB Insts. For example, -// in the example in (1), for phi %12, we don't need to cache -// the path starting from %6, because this path doesn't have any -// UB Insts. -// -// These tricks basically relies on the dependency chain of instructions -// generated by souper. For example, if we say %12 depends on %11, then -// %12 would never appear earlier than %11. -ref KLEEBuilder::getUBInstCondition() { - - // A map from a Phi instruction to all of its KLEE expressions that - // encode the path and UB Inst predicates. - UBPathInstMap CachedUBPathInsts; - std::set UsedUBInsts; - ref Result = klee::ConstantExpr::create(1, Expr::Bool); - // For each Phi/Select instruction - for (const auto &I : UBPathInsts) { - if (CachedUBPathInsts.count(I) != 0) - continue; - // Recursively collect UB instructions - // on the block constrained Phi and Select branches - std::vector> UBPaths; - UBPath *Current = new UBPath; - UBPaths.push_back(std::move(std::unique_ptr(Current))); - if (!getUBPaths(I, Current, UBPaths, CachedUBPathInsts, 0)) - return ref(); - CachedUBPathInsts[I] = {}; - // For each found path - for (const auto &Path : UBPaths) { - if (!Path->UBInsts.size()) + + return Pred; + } + + ref createUBPathInstsPred( + Inst *CurrentInst, std::vector &PathInsts, + std::map &BlockConstraints, + std::map *SelectBranches, UBPathInstMap &CachedUBPathInsts) { + ref Pred = klee::ConstantExpr::alloc(1, 1); + for (const auto &PathInst : PathInsts) { + if (PathInst->Ops.size() == 1) continue; - // Aggregate collected UB constraints - ref Ante = klee::ConstantExpr::alloc(1, 1); - for (const auto &I : Path->UBInsts) { - auto Iter = UBExprMap.find(I); - // It's possible that the instruction I is not in the map. - // For example, it may come from a blockpc which doesn't - // have any preconditions. - if (Iter != UBExprMap.end()) - Ante = AndExpr::create(Ante, Iter->second); - UsedUBInsts.insert(I); + ref InstPred = + createPathPred(BlockConstraints, PathInst, SelectBranches); + + UBPathInstMap::iterator PI = CachedUBPathInsts.find(PathInst); + if (PI == CachedUBPathInsts.end()) { + // It's possible that we don't have a cached instruction yet, + // e.g., the CurrentInst is a select operator. + assert(CurrentInst->K == Inst::Select && "No cached Inst?"); + CachedUBPathInsts[PathInst] = {}; + PI = CachedUBPathInsts.find(PathInst); + } + if (PI->first != CurrentInst && PI->second.size() != 0) { + // Use cached Expr along each path which has UB Insts, + // and cache the expanded Expr for the current working Phi + for (auto CE : PI->second) { + InstPred = AndExpr::create(CE, InstPred); + CachedUBPathInsts[CurrentInst].push_back(InstPred); + Pred = AndExpr::create(Pred, InstPred); + } + } + else { + CachedUBPathInsts[CurrentInst].push_back(InstPred); + Pred = AndExpr::create(Pred, InstPred); } - // Create path predicate - ref Pred = - createUBPathInstsPred(I, Path->Insts, Path->BlockConstraints, - &Path->SelectBranches, CachedUBPathInsts); - // Add predicate->UB constraint - Result = AndExpr::create(Result, Expr::createImplies(Pred, Ante)); } - } - // Add the unconditional UB constraints at the top level - for (const auto &Entry: UBExprMap) - if (!UsedUBInsts.count(Entry.first)) - Result = AndExpr::create(Result, Entry.second); - return Result; -} - -void KLEEBuilder::setBlockPCMap(const BlockPCs &BPCs) { - for (auto BPC : BPCs) { - assert(BPC.B && "Block is NULL!"); - BlockPCPredMap &PCMap = BlockPCMap[BPC.B]; - auto I = PCMap.find(BPC.PredIdx); - // Relying on a class-level flag may not be a nice solution, - // but it seems hard to differentiate two cases: - // (1) UBInstExpr collected through blockpc, and; - // (2) UBInstExpr collected through pc/lhs/rhs - // For the first case, UBInst(s) is conditional, i.e., - // they rely on the fact that blockpc(s) are true. - if (I != PCMap.end()) { - UBInstPrecondition = I->second; - } - IsForBlockPCUBInst = true; - ref PE = getInstMapping(BPC.PC); - IsForBlockPCUBInst = false; - UBInstPrecondition = nullptr; - if (I == PCMap.end()) { - PCMap[BPC.PredIdx] = PE; + return Pred; + } + + // Collect UB Inst condition for each Phi instruction. + // The basic algorithm is: + // (1) for a given phi instruction, we first collect all paths that start + // from the phi. For each path, we also keep the the phi instructions + // along the path and the UB instructions associated with these phi + // instructions; + // (2) then for each path, we generate a corresponding KLEE expression + // based on the facts that we collected in step (1), including: + // * UB instructions; + // * Phi predicates; + // + // With the algorithm, it is easy to get into the path explosion problem, + // i.e., the number of paths is increased exponentially. Under some + // circumstances, e.g., the number of phis is too large, we will suffer + // with large performance overhead. In some extreme cases, we will fail + // to process some file due to the large memory footprint, i.e., `newing' + // too many UBPaths. Two tricks are used to relief the penalty of the + // path explosion problem: + // (1) caching the KLEE expresions for each processed phi, where each + // KLEE expression encodes the path that starts from one of the phi's + // values. For example, when processing a sample souper IR below + // + // %0 = block + // %1 = block + // %2:i32 = var + // %3:i32 = shl 0:i32, %2 + // %4:i32 = var + // %5:i32 = shl 0:i32, %4 + // %6 = var + // %11:i32 = phi %1, %3, %5 + // %12:i32 = phi %0, %6, %11 + // + // we first encounter phi %11. The generated KLEE expression + // for this phi encodes two paths, i.e., %3 and %5. We cache + // these two into CachedUBPathInsts. Then we move to process phi %12. + // At this point, rather than recursively re-contruct %11 (through + // %12's value), we just re-used the cached path-expressions. + // For each path-expression, we append it with %12's own predicate + // and also cache them with %12 for future use. After finishing + // %12, we will have three entries for phi %12. + // (2) The first trick increases the performance, but we still suffer + // with large memory consumption, i.e., it's easy to cache too + // many paths. The second trick is to reduce the memory footprint + // by only caching "useful" path that has UB Insts. For example, + // in the example in (1), for phi %12, we don't need to cache + // the path starting from %6, because this path doesn't have any + // UB Insts. + // + // These tricks basically relies on the dependency chain of instructions + // generated by souper. For example, if we say %12 depends on %11, then + // %12 would never appear earlier than %11. + ref getUBInstCondition() { + + // A map from a Phi instruction to all of its KLEE expressions that + // encode the path and UB Inst predicates. + UBPathInstMap CachedUBPathInsts; + std::set UsedUBInsts; + ref Result = klee::ConstantExpr::create(1, Expr::Bool); + // For each Phi/Select instruction + for (const auto &I : UBPathInsts) { + if (CachedUBPathInsts.count(I) != 0) + continue; + // Recursively collect UB instructions + // on the block constrained Phi and Select branches + std::vector> UBPaths; + UBPath *Current = new UBPath; + UBPaths.push_back(std::move(std::unique_ptr(Current))); + if (!getUBPaths(I, Current, UBPaths, CachedUBPathInsts, 0)) + return ref(); + CachedUBPathInsts[I] = {}; + // For each found path + for (const auto &Path : UBPaths) { + if (!Path->UBInsts.size()) + continue; + // Aggregate collected UB constraints + ref Ante = klee::ConstantExpr::alloc(1, 1); + for (const auto &I : Path->UBInsts) { + auto Iter = UBExprMap.find(I); + // It's possible that the instruction I is not in the map. + // For example, it may come from a blockpc which doesn't + // have any preconditions. + if (Iter != UBExprMap.end()) + Ante = AndExpr::create(Ante, Iter->second); + UsedUBInsts.insert(I); + } + // Create path predicate + ref Pred = + createUBPathInstsPred(I, Path->Insts, Path->BlockConstraints, + &Path->SelectBranches, CachedUBPathInsts); + // Add predicate->UB constraint + Result = AndExpr::create(Result, Expr::createImplies(Pred, Ante)); + } } - else { - PCMap[BPC.PredIdx] = AndExpr::create(I->second, PE); + // Add the unconditional UB constraints at the top level + for (const auto &Entry: UBExprMap) + if (!UsedUBInsts.count(Entry.first)) + Result = AndExpr::create(Result, Entry.second); + return Result; + } + + void setBlockPCMap(const BlockPCs &BPCs) { + for (auto BPC : BPCs) { + assert(BPC.B && "Block is NULL!"); + BlockPCPredMap &PCMap = BlockPCMap[BPC.B]; + auto I = PCMap.find(BPC.PredIdx); + // Relying on a class-level flag may not be a nice solution, + // but it seems hard to differentiate two cases: + // (1) UBInstExpr collected through blockpc, and; + // (2) UBInstExpr collected through pc/lhs/rhs + // For the first case, UBInst(s) is conditional, i.e., + // they rely on the fact that blockpc(s) are true. + if (I != PCMap.end()) { + UBInstPrecondition = I->second; + } + IsForBlockPCUBInst = true; + ref PE = getInstMapping(BPC.PC); + IsForBlockPCUBInst = false; + UBInstPrecondition = nullptr; + if (I == PCMap.end()) { + PCMap[BPC.PredIdx] = PE; + } + else { + PCMap[BPC.PredIdx] = AndExpr::create(I->second, PE); + } } } -} - -// Similar to the way we collect UB constraints. We could combine it with -// getUBInstCondition, because the workflow is quite similar. -// However, mixing two parts (one for UB constraints, one for BlockPCs) -// may make the code less structured. If we see big performance overhead, -// we may consider to combine these two parts together. -ref KLEEBuilder::getBlockPCs() { - - UBPathInstMap CachedPhis; - ref Result = klee::ConstantExpr::create(1, Expr::Bool); - // For each Phi instruction - for (const auto &I : UBPathInsts) { - if (CachedPhis.count(I) != 0) - continue; - // Recursively collect BlockPCs - std::vector> BlockPCPhiPaths; - BlockPCPhiPath *Current = new BlockPCPhiPath; - BlockPCPhiPaths.push_back( - std::move(std::unique_ptr(Current))); - getBlockPCPhiPaths(I, Current, BlockPCPhiPaths, CachedPhis); - CachedPhis[I] = {}; - // For each found path - for (const auto &Path : BlockPCPhiPaths) { - if (!Path->PCs.size()) + + // Similar to the way we collect UB constraints. We could combine it with + // getUBInstCondition, because the workflow is quite similar. + // However, mixing two parts (one for UB constraints, one for BlockPCs) + // may make the code less structured. If we see big performance overhead, + // we may consider to combine these two parts together. + ref getBlockPCs() { + + UBPathInstMap CachedPhis; + ref Result = klee::ConstantExpr::create(1, Expr::Bool); + // For each Phi instruction + for (const auto &I : UBPathInsts) { + if (CachedPhis.count(I) != 0) continue; - // Aggregate collected BlockPC constraints - ref Ante = klee::ConstantExpr::alloc(1, 1); - for (const auto &PC : Path->PCs) { - Ante = AndExpr::create(Ante, PC); + // Recursively collect BlockPCs + std::vector> BlockPCPhiPaths; + BlockPCPhiPath *Current = new BlockPCPhiPath; + BlockPCPhiPaths.push_back( + std::move(std::unique_ptr(Current))); + getBlockPCPhiPaths(I, Current, BlockPCPhiPaths, CachedPhis); + CachedPhis[I] = {}; + // For each found path + for (const auto &Path : BlockPCPhiPaths) { + if (!Path->PCs.size()) + continue; + // Aggregate collected BlockPC constraints + ref Ante = klee::ConstantExpr::alloc(1, 1); + for (const auto &PC : Path->PCs) { + Ante = AndExpr::create(Ante, PC); + } + // Create path predicate + ref Pred = + createUBPathInstsPred(I, Path->Phis, Path->BlockConstraints, + /*SelectBranches=*/nullptr, CachedPhis); + // Add predicate->UB constraint + Result = AndExpr::create(Result, Expr::createImplies(Pred, Ante)); } - // Create path predicate - ref Pred = - createUBPathInstsPred(I, Path->Phis, Path->BlockConstraints, - /*SelectBranches=*/nullptr, CachedPhis); - // Add predicate->UB constraint - Result = AndExpr::create(Result, Expr::createImplies(Pred, Ante)); } + return Result; } - return Result; -} - -std::string souper::BuildQuery(const BlockPCs &BPCs, - const std::vector &PCs, - InstMapping Mapping, - std::vector *ModelVars, bool Negate) { - std::string SMTStr; - llvm::raw_string_ostream SMTSS(SMTStr); - ConstraintManager Manager; - Optional OptionalCE = GetCandidateExprForReplacement2(BPCs, - PCs, Mapping, Negate); - if (!OptionalCE.hasValue()) - return std::string(); - CandidateExpr CE = std::move(OptionalCE.getValue()); - Query KQuery(Manager, CE.E); - ExprSMTLIBPrinter Printer; - Printer.setOutput(SMTSS); - Printer.setQuery(KQuery); - std::vector Arrays; - if (ModelVars) { - for (unsigned I = 0; I != CE.ArrayVars.size(); ++I) { - if (CE.ArrayVars[I]) { - Arrays.push_back(CE.Arrays[I].get()); - ModelVars->push_back(CE.ArrayVars[I]); + + // Return an expression which must be proven valid for the candidate to apply. + llvm::Optional GetCandidateExprForReplacement( + const BlockPCs &BPCs, const std::vector &PCs, + InstMapping Mapping, bool Negate) { + + CandidateExpr CE; + ExprBuilder EB(CE.Arrays, CE.ArrayVars); + // Build LHS + ref LHS = EB.get(Mapping.LHS); + ref Ante = klee::ConstantExpr::alloc(1, 1); + ref DemandedBits = klee::ConstantExpr::alloc(Mapping.LHS->DemandedBits); + if (!Mapping.LHS->DemandedBits.isAllOnesValue()) + LHS = AndExpr::create(LHS, DemandedBits); + for (const auto I : CE.ArrayVars) { + if (I) { + if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) { + Ante = AndExpr::create(Ante, EB.getZeroBitsMapping(I)); + Ante = AndExpr::create(Ante, EB.getOneBitsMapping(I)); + } + if (I->NonZero) + Ante = AndExpr::create(Ante, EB.getNonZeroBitsMapping(I)); + if (I->NonNegative) + Ante = AndExpr::create(Ante, EB.getNonNegBitsMapping(I)); + if (I->PowOfTwo) + Ante = AndExpr::create(Ante, EB.getPowerTwoBitsMapping(I)); + if (I->Negative) + Ante = AndExpr::create(Ante, EB.getNegBitsMapping(I)); + if (I->NumSignBits > 1) + Ante = AndExpr::create(Ante, EB.getSignBitsMapping(I)); } } - Printer.setArrayValuesToGet(Arrays); + // Build PCs + for (const auto &PC : PCs) { + Ante = AndExpr::create(Ante, EB.getInstMapping(PC)); + } + // Build BPCs + if (BPCs.size()) { + EB.setBlockPCMap(BPCs); + Ante = AndExpr::create(Ante, EB.getBlockPCs()); + } + // Get UB constraints of LHS and (B)PCs + ref LHSPCsUB = klee::ConstantExpr::create(1, Expr::Bool); + if (ExploitUB) { + LHSPCsUB = EB.getUBInstCondition(); + if (LHSPCsUB.isNull()) + return llvm::Optional(); + } + // Build RHS + ref RHS = EB.get(Mapping.RHS); + if (!Mapping.LHS->DemandedBits.isAllOnesValue()) + RHS = AndExpr::create(RHS, DemandedBits); + // Get all UB constraints (LHS && (B)PCs && RHS) + ref UB = klee::ConstantExpr::create(1, Expr::Bool); + if (ExploitUB) { + UB = EB.getUBInstCondition(); + if (UB.isNull()) + return llvm::Optional(); + } + + ref Cons; + if (Negate) // (LHS != RHS) + Cons = NeExpr::create(LHS, RHS); + else // (LHS == RHS) + Cons = EqExpr::create(LHS, RHS); + // Cons && UB + if (Mapping.RHS->K != Inst::Const) + Cons = AndExpr::create(Cons, UB); + // (LHS UB && (B)PCs && (B)PCs UB) + Ante = AndExpr::create(Ante, LHSPCsUB); + // (LHS UB && (B)PCs && (B)PCs UB) => Cons && UB + CE.E = Expr::createImplies(Ante, Cons); + + return llvm::Optional(std::move(CE)); + } + + std::string BuildQuery(const BlockPCs &BPCs, + const std::vector &PCs, + InstMapping Mapping, + std::vector *ModelVars, bool Negate) { + std::string SMTStr; + llvm::raw_string_ostream SMTSS(SMTStr); + ConstraintManager Manager; + Optional OptionalCE = GetCandidateExprForReplacement(BPCs, + PCs, Mapping, Negate); + if (!OptionalCE.hasValue()) + return std::string(); + CandidateExpr CE = std::move(OptionalCE.getValue()); + Query KQuery(Manager, CE.E); + ExprSMTLIBPrinter Printer; + Printer.setOutput(SMTSS); + Printer.setQuery(KQuery); + std::vector Arrays; + if (ModelVars) { + for (unsigned I = 0; I != CE.ArrayVars.size(); ++I) { + if (CE.ArrayVars[I]) { + Arrays.push_back(CE.Arrays[I].get()); + ModelVars->push_back(CE.ArrayVars[I]); + } + } + Printer.setArrayValuesToGet(Arrays); + } + Printer.generateOutput(); + + if (DumpKLEEExprs) { + SMTSS << "; KLEE expression:\n; "; + std::unique_ptr PP(ExprPPrinter::create(SMTSS)); + PP->setForceNoLineBreaks(true); + PP->scan(CE.E); + PP->print(CE.E); + SMTSS << '\n'; + } + + return SMTSS.str(); } - Printer.generateOutput(); - if (DumpKLEEExprs) { - SMTSS << "; KLEE expression:\n; "; - std::unique_ptr PP(ExprPPrinter::create(SMTSS)); - PP->setForceNoLineBreaks(true); - PP->scan(CE.E); - PP->print(CE.E); - SMTSS << '\n'; - } +}; + +} - return SMTSS.str(); +std::unique_ptr souper::createKLEEBuilder() { + return std::unique_ptr(new KLEEBuilder()); } diff --git a/lib/Infer/InstSynthesis.cpp b/lib/Infer/InstSynthesis.cpp index 62e3efafc..8e7642414 100644 --- a/lib/Infer/InstSynthesis.cpp +++ b/lib/Infer/InstSynthesis.cpp @@ -14,7 +14,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" -//#include "souper/Extractor/KLEEBuilder.h" #include "souper/Extractor/ExprBuilder.h" #include "souper/Infer/InstSynthesis.h" diff --git a/unittests/Extractor/ExtractorTests.cpp b/unittests/Extractor/ExtractorTests.cpp index 8f49f3f8b..f06b199e2 100644 --- a/unittests/Extractor/ExtractorTests.cpp +++ b/unittests/Extractor/ExtractorTests.cpp @@ -20,7 +20,6 @@ #include "llvm/IR/Module.h" #include "llvm/Support/SourceMgr.h" #include "souper/Extractor/Candidates.h" -//#include "souper/Extractor/KLEEBuilder.h" #include "souper/Extractor/ExprBuilder.h" #include #include "gtest/gtest.h" From cac3bbecd103dff9440be44659df4d09ca724488 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 19 Feb 2018 09:46:19 +0100 Subject: [PATCH 03/49] Remove --- CMakeLists.txt | 1 - include/souper/Tool/GetExprBuilderFromArgs.h | 38 -------------------- 2 files changed, 39 deletions(-) delete mode 100644 include/souper/Tool/GetExprBuilderFromArgs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fdd3b71f1..a67817a3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,7 +204,6 @@ add_library(souperSMTLIB2 STATIC set(SOUPER_TOOL_FILES lib/Tool/CandidateMapUtils.cpp include/souper/Tool/CandidateMapUtils.h - include/souper/Tool/GetExprBuilderFromArgs.h include/souper/Tool/GetSolverFromArgs.h ) diff --git a/include/souper/Tool/GetExprBuilderFromArgs.h b/include/souper/Tool/GetExprBuilderFromArgs.h deleted file mode 100644 index 634c6a0ad..000000000 --- a/include/souper/Tool/GetExprBuilderFromArgs.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 The Souper Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOUPER_TOOL_GETEXPRBUILDERFROMARGS_H -#define SOUPER_TOOL_GETEXPRBUILDERFROMARGS_H - -#include "llvm/Support/CommandLine.h" -#include "souper/Extractor/ExprBuilder.h" -#include - -namespace souper { - -static llvm::cl::opt UseKLEEExprBuilder( - "use-klee-builder", llvm::cl::desc("Use KLEE Expr builder to emit SMTLIBv2"), - llvm::cl::init(true)); - -static std::unique_ptr GetExprBuilderFromArgs() { - if (UseKLEEExprBuilder) { - return createKLEEExprBuilder(); - } else { - return nullptr; - } -} - -} - -#endif // SOUPER_TOOL_GETEXPRBUILDERFROMARGS_H From 8c63b50a1d2a2b78eadc67fbce4bddfd9e201cc3 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 19 Feb 2018 11:50:59 +0100 Subject: [PATCH 04/49] Compile --- CMakeLists.txt | 12 ++++---- include/souper/Extractor/ExprBuilder.h | 10 +++++++ lib/Extractor/ExprBuilder.cpp | 32 +++++++++++++++++++++ lib/Extractor/KLEEBuilder.cpp | 40 +++++++++++--------------- lib/Pass/Pass.cpp | 4 +-- tools/clang-souper.cpp | 2 +- tools/souper-check.cpp | 2 +- tools/souper.cpp | 2 +- tools/souperweb-backend.cpp | 2 +- 9 files changed, 71 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a67817a3d..a3e2362ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -260,9 +260,9 @@ add_executable(souper-check tools/souper-check.cpp ) -add_executable(extractor_tests - unittests/Extractor/ExtractorTests.cpp -) +#add_executable(extractor_tests +# unittests/Extractor/ExtractorTests.cpp +#) add_executable(inst_tests unittests/Inst/InstTests.cpp @@ -276,7 +276,7 @@ set_target_properties(souper internal-solver-test lexer-test parser-test souper- PROPERTIES COMPILE_FLAGS "${LLVM_CXXFLAGS}") set_target_properties(souperClangTool clang-souper PROPERTIES COMPILE_FLAGS "${CLANG_CXXFLAGS} ${LLVM_CXXFLAGS}") -set_target_properties(extractor_tests inst_tests parser_tests +set_target_properties(inst_tests parser_tests PROPERTIES COMPILE_FLAGS "${GTEST_CXXFLAGS} ${LLVM_CXXFLAGS}") target_link_libraries(kleeExpr ${LLVM_LIBS} ${LLVM_LDFLAGS}) @@ -296,7 +296,7 @@ target_link_libraries(lexer-test souperParser) target_link_libraries(parser-test souperParser) target_link_libraries(souper-check souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(clang-souper souperClangTool souperExtractor souperKVStore souperParser souperSMTLIB2 souperTool kleeExpr ${CLANG_LIBS} ${LLVM_LIBS} ${LLVM_LDFLAGS} ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) -target_link_libraries(extractor_tests souperExtractor ${GTEST_LIBS}) +#target_link_libraries(extractor_tests souperExtractor ${GTEST_LIBS}) target_link_libraries(inst_tests souperInst ${GTEST_LIBS}) target_link_libraries(parser_tests souperParser ${GTEST_LIBS}) @@ -321,7 +321,7 @@ configure_file( add_custom_target(check COMMAND ${CMAKE_BINARY_DIR}/run_lit - DEPENDS extractor_tests inst_tests parser-test parser_tests profileRuntime souper souper-check souperPass souperPassProfileAll) + DEPENDS inst_tests parser-test parser_tests profileRuntime souper souper-check souperPass souperPassProfileAll) find_program(GO_EXECUTABLE NAMES go DOC "go executable") if(NOT GO_EXECUTABLE STREQUAL "GO_EXECUTABLE-NOTFOUND") diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 710fd9f33..251b1ac02 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -27,6 +27,11 @@ namespace souper { class ExprBuilder { public: + enum Builder { + KLEE, + Z3 + }; + const unsigned MAX_PHI_DEPTH = 25; typedef std::unordered_map>> UBPathInstMap; @@ -119,6 +124,7 @@ class ExprBuilder { std::vector ArrayVars; ref E; }; + CandidateExpr CE; virtual llvm::Optional GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool Negate) = 0; @@ -128,6 +134,10 @@ class ExprBuilder { std::vector *ModelVars, bool Negate=false) = 0; }; +std::string BuildQuery(const BlockPCs &BPCs, + const std::vector &PCs, InstMapping Mapping, + std::vector *ModelVars, bool Negate=false); + std::unique_ptr createKLEEBuilder(); } diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index aeeffbf9c..d337e79a4 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "llvm/Support/CommandLine.h" #include "souper/Extractor/ExprBuilder.h" using namespace llvm; @@ -19,6 +20,16 @@ using namespace souper; ExprBuilder::~ExprBuilder() {} +static llvm::cl::opt SMTExprBuilder( + "souper-smt-expr-builder", + llvm::cl::Hidden, + llvm::cl::desc("SMT-LIBv2 expression builder (default=klee)"), + llvm::cl::values(clEnumValN(souper::ExprBuilder::KLEE, "klee", + "Use KLEE's Expr library"), + clEnumValN(souper::ExprBuilder::Z3, "z3", + "Use Z3's API")), + llvm::cl::init(souper::ExprBuilder::KLEE)); + namespace souper { ref ExprBuilder::buildAssoc( @@ -216,4 +227,25 @@ ref ExprBuilder::getSignBitsMapping(Inst *I) { return SignBitsMap[I]; } +// TODO: Fix GetCandidateExprForReplacement + +std::string BuildQuery(const BlockPCs &BPCs, + const std::vector &PCs, InstMapping Mapping, + std::vector *ModelVars, bool Negate) { + std::unique_ptr EB; + switch (SMTExprBuilder) { + case ExprBuilder::KLEE: + EB = createKLEEBuilder(); + break; + case ExprBuilder::Z3: + report_fatal_error("not supported yet"); + break; + default: + report_fatal_error("cannot reach here"); + break; + } + + return EB->BuildQuery(BPCs, PCs, Mapping, ModelVars, Negate); +} + } diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 6b18342f4..22128c636 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -50,9 +50,6 @@ using namespace souper; namespace { class KLEEBuilder : public ExprBuilder { - std::vector> &Arrays; - std::vector &ArrayVars; - public: KLEEBuilder() {} ~KLEEBuilder() {} @@ -65,12 +62,12 @@ class KLEEBuilder : public ExprBuilder { NameStr = ("a" + Name).str(); else NameStr = Name; - Arrays.emplace_back( + CE.Arrays.emplace_back( new Array(ArrayNames.makeName(NameStr), 1, 0, 0, Expr::Int32, Width)); - ArrayVars.push_back(Origin); + CE.ArrayVars.push_back(Origin); std::vector ZeroBits, OneBits; - UpdateList UL(Arrays.back().get(), 0); + UpdateList UL(CE.Arrays.back().get(), 0); ref Var = ReadExpr::create(UL, klee::ConstantExpr::alloc(0, Expr::Int32)); if (Origin && Origin->K == Inst::Var) { if (Origin->KnownZeros.getBoolValue() || Origin->KnownOnes.getBoolValue()) { @@ -811,11 +808,8 @@ class KLEEBuilder : public ExprBuilder { llvm::Optional GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool Negate) { - - CandidateExpr CE; - ExprBuilder EB(CE.Arrays, CE.ArrayVars); // Build LHS - ref LHS = EB.get(Mapping.LHS); + ref LHS = get(Mapping.LHS); ref Ante = klee::ConstantExpr::alloc(1, 1); ref DemandedBits = klee::ConstantExpr::alloc(Mapping.LHS->DemandedBits); if (!Mapping.LHS->DemandedBits.isAllOnesValue()) @@ -823,45 +817,45 @@ class KLEEBuilder : public ExprBuilder { for (const auto I : CE.ArrayVars) { if (I) { if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) { - Ante = AndExpr::create(Ante, EB.getZeroBitsMapping(I)); - Ante = AndExpr::create(Ante, EB.getOneBitsMapping(I)); + Ante = AndExpr::create(Ante, getZeroBitsMapping(I)); + Ante = AndExpr::create(Ante, getOneBitsMapping(I)); } if (I->NonZero) - Ante = AndExpr::create(Ante, EB.getNonZeroBitsMapping(I)); + Ante = AndExpr::create(Ante, getNonZeroBitsMapping(I)); if (I->NonNegative) - Ante = AndExpr::create(Ante, EB.getNonNegBitsMapping(I)); + Ante = AndExpr::create(Ante, getNonNegBitsMapping(I)); if (I->PowOfTwo) - Ante = AndExpr::create(Ante, EB.getPowerTwoBitsMapping(I)); + Ante = AndExpr::create(Ante, getPowerTwoBitsMapping(I)); if (I->Negative) - Ante = AndExpr::create(Ante, EB.getNegBitsMapping(I)); + Ante = AndExpr::create(Ante, getNegBitsMapping(I)); if (I->NumSignBits > 1) - Ante = AndExpr::create(Ante, EB.getSignBitsMapping(I)); + Ante = AndExpr::create(Ante, getSignBitsMapping(I)); } } // Build PCs for (const auto &PC : PCs) { - Ante = AndExpr::create(Ante, EB.getInstMapping(PC)); + Ante = AndExpr::create(Ante, getInstMapping(PC)); } // Build BPCs if (BPCs.size()) { - EB.setBlockPCMap(BPCs); - Ante = AndExpr::create(Ante, EB.getBlockPCs()); + setBlockPCMap(BPCs); + Ante = AndExpr::create(Ante, getBlockPCs()); } // Get UB constraints of LHS and (B)PCs ref LHSPCsUB = klee::ConstantExpr::create(1, Expr::Bool); if (ExploitUB) { - LHSPCsUB = EB.getUBInstCondition(); + LHSPCsUB = getUBInstCondition(); if (LHSPCsUB.isNull()) return llvm::Optional(); } // Build RHS - ref RHS = EB.get(Mapping.RHS); + ref RHS = get(Mapping.RHS); if (!Mapping.LHS->DemandedBits.isAllOnesValue()) RHS = AndExpr::create(RHS, DemandedBits); // Get all UB constraints (LHS && (B)PCs && RHS) ref UB = klee::ConstantExpr::create(1, Expr::Bool); if (ExploitUB) { - UB = EB.getUBInstCondition(); + UB = getUBInstCondition(); if (UB.isNull()) return llvm::Optional(); } diff --git a/lib/Pass/Pass.cpp b/lib/Pass/Pass.cpp index 40b0287a8..606093d24 100644 --- a/lib/Pass/Pass.cpp +++ b/lib/Pass/Pass.cpp @@ -130,7 +130,7 @@ struct SouperPass : public ModulePass { Constant *Repl = ConstantDataArray::getString(C, LHS, true); Constant *ReplVar = new GlobalVariable(*M, Repl->getType(), true, GlobalValue::PrivateLinkage, Repl, ""); - Constant *ReplPtr = ConstantExpr::getPointerCast(ReplVar, + Constant *ReplPtr = llvm::ConstantExpr::getPointerCast(ReplVar, PointerType::getInt8PtrTy(C)); Constant *Field = ConstantDataArray::getString(C, "dprofile " + Loc.str(), @@ -138,7 +138,7 @@ struct SouperPass : public ModulePass { Constant *FieldVar = new GlobalVariable(*M, Field->getType(), true, GlobalValue::PrivateLinkage, Field, ""); - Constant *FieldPtr = ConstantExpr::getPointerCast(FieldVar, + Constant *FieldPtr = llvm::ConstantExpr::getPointerCast(FieldVar, PointerType::getInt8PtrTy(C)); Constant *CntVar = new GlobalVariable(*M, Type::getInt64Ty(C), false, diff --git a/tools/clang-souper.cpp b/tools/clang-souper.cpp index 9d2553228..1d7ad5ebf 100644 --- a/tools/clang-souper.cpp +++ b/tools/clang-souper.cpp @@ -52,6 +52,6 @@ int main(int argc, const char **argv) { Tool.run(Factory.get()); KVStore *KV = 0; - std::unique_ptr S = GetSolverFromArgs(KV); + std::unique_ptr S = GetSolverFromArgs(KV); return SolveCandidateMap(llvm::outs(), CandMap, S.get(), IC, 0) ? 0 : 1; } diff --git a/tools/souper-check.cpp b/tools/souper-check.cpp index d364d006c..4f3fa3aba 100644 --- a/tools/souper-check.cpp +++ b/tools/souper-check.cpp @@ -176,7 +176,7 @@ int SolveInst(const MemoryBufferRef &MB, Solver *S) { int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); KVStore *KV = 0; - std::unique_ptr S = 0; + std::unique_ptr S = 0; if (!ParseOnly && !ParseLHSOnly) { S = GetSolverFromArgs(KV); if (!S) { diff --git a/tools/souper.cpp b/tools/souper.cpp index 8c014581d..42cb54e07 100644 --- a/tools/souper.cpp +++ b/tools/souper.cpp @@ -92,7 +92,7 @@ int main(int argc, char **argv) { } KVStore *KV = 0; - std::unique_ptr S = GetSolverFromArgs(KV); + std::unique_ptr S = GetSolverFromArgs(KV); InstContext IC; ExprBuilderContext EBC; diff --git a/tools/souperweb-backend.cpp b/tools/souperweb-backend.cpp index be6f0a8d3..3afc1fed8 100644 --- a/tools/souperweb-backend.cpp +++ b/tools/souperweb-backend.cpp @@ -90,7 +90,7 @@ static llvm::cl::opt Action("action", llvm::cl::init("")); int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); KVStore *KV; - std::unique_ptr S = GetSolverFromArgs(KV); + std::unique_ptr S = GetSolverFromArgs(KV); auto MB = MemoryBuffer::getSTDIN(); if (MB) { From 207df43e9079702f7c4a9bf3028958ae802d2afb Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 19 Feb 2018 16:57:53 +0100 Subject: [PATCH 05/49] Reshuffle --- include/souper/Extractor/ExprBuilder.h | 69 ++++---- lib/Extractor/KLEEBuilder.cpp | 217 +++++++++++++------------ 2 files changed, 146 insertions(+), 140 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 251b1ac02..521da1968 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -52,29 +52,8 @@ class ExprBuilder { virtual ~ExprBuilder(); - virtual ref addnswUB(Inst *I) = 0; - virtual ref addnuwUB(Inst *I) = 0; - virtual ref subnswUB(Inst *I) = 0; - virtual ref subnuwUB(Inst *I) = 0; - virtual ref mulnswUB(Inst *I) = 0; - virtual ref mulnuwUB(Inst *I) = 0; - virtual ref udivUB(Inst *I) = 0; - virtual ref udivExactUB(Inst *I) = 0; - virtual ref sdivUB(Inst *I) = 0; - virtual ref sdivExactUB(Inst *I) = 0; - virtual ref shiftUB(Inst *I) = 0; - virtual ref shlnswUB(Inst *I) = 0; - virtual ref shlnuwUB(Inst *I) = 0; - virtual ref lshrExactUB(Inst *I) = 0; - virtual ref ashrExactUB(Inst *I) = 0; - virtual ref countOnes(ref E) = 0; - - virtual void recordUBInstruction(Inst *I, ref E) = 0; ref buildAssoc(std::function(ref, ref)> F, llvm::ArrayRef Ops); - virtual ref build(Inst *I) = 0; - virtual ref get(Inst *I) = 0; - virtual ref getInstMapping(const InstMapping &IM) = 0; ref getZeroBitsMapping(Inst *I); ref getOneBitsMapping(Inst *I); ref getNonZeroBitsMapping(Inst *I); @@ -83,17 +62,6 @@ class ExprBuilder { ref getNegBitsMapping(Inst *I); ref getSignBitsMapping(Inst *I); std::vector> getBlockPredicates(Inst *I); - virtual ref getUBInstCondition() = 0; - virtual ref getBlockPCs() = 0; - virtual void setBlockPCMap(const BlockPCs &BPCs) = 0; - virtual ref createPathPred(std::map &BlockConstraints, - Inst* PathInst, - std::map *SelectBranches) = 0; - virtual ref createUBPathInstsPred(Inst *CurrentInst, - std::vector &UBPathInsts, - std::map &BlockConstraints, - std::map *SelectBranches, - UBPathInstMap &CachedUBPathInsts) = 0; bool getUBPaths(Inst *I, UBPath *Current, std::vector> &Paths, UBPathInstMap &CachedUBPathInsts, unsigned Depth); @@ -132,6 +100,43 @@ class ExprBuilder { virtual std::string BuildQuery(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate=false) = 0; + +protected: + virtual ref addnswUB(Inst *I) = 0; + virtual ref addnuwUB(Inst *I) = 0; + virtual ref subnswUB(Inst *I) = 0; + virtual ref subnuwUB(Inst *I) = 0; + virtual ref mulnswUB(Inst *I) = 0; + virtual ref mulnuwUB(Inst *I) = 0; + virtual ref udivUB(Inst *I) = 0; + virtual ref udivExactUB(Inst *I) = 0; + virtual ref sdivUB(Inst *I) = 0; + virtual ref sdivExactUB(Inst *I) = 0; + virtual ref shiftUB(Inst *I) = 0; + virtual ref shlnswUB(Inst *I) = 0; + virtual ref shlnuwUB(Inst *I) = 0; + virtual ref lshrExactUB(Inst *I) = 0; + virtual ref ashrExactUB(Inst *I) = 0; + virtual ref countOnes(ref E) = 0; + + virtual void recordUBInstruction(Inst *I, ref E) = 0; + + virtual ref build(Inst *I) = 0; + virtual ref get(Inst *I) = 0; + virtual ref getInstMapping(const InstMapping &IM) = 0; + + virtual ref getUBInstCondition() = 0; + virtual ref getBlockPCs() = 0; + virtual void setBlockPCMap(const BlockPCs &BPCs) = 0; + + virtual ref createPathPred(std::map &BlockConstraints, + Inst* PathInst, + std::map *SelectBranches) = 0; + virtual ref createUBPathInstsPred(Inst *CurrentInst, + std::vector &UBPathInsts, + std::map &BlockConstraints, + std::map *SelectBranches, + UBPathInstMap &CachedUBPathInsts) = 0; }; std::string BuildQuery(const BlockPCs &BPCs, diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 22128c636..312703e75 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -54,56 +54,48 @@ class KLEEBuilder : public ExprBuilder { KLEEBuilder() {} ~KLEEBuilder() {} - ref makeSizedArrayRead(unsigned Width, StringRef Name, Inst *Origin) { - std::string NameStr; - if (Name.empty()) - NameStr = "arr"; - else if (Name[0] >= '0' && Name[0] <= '9') - NameStr = ("a" + Name).str(); - else - NameStr = Name; - CE.Arrays.emplace_back( - new Array(ArrayNames.makeName(NameStr), 1, 0, 0, Expr::Int32, Width)); - CE.ArrayVars.push_back(Origin); - - std::vector ZeroBits, OneBits; - UpdateList UL(CE.Arrays.back().get(), 0); - ref Var = ReadExpr::create(UL, klee::ConstantExpr::alloc(0, Expr::Int32)); - if (Origin && Origin->K == Inst::Var) { - if (Origin->KnownZeros.getBoolValue() || Origin->KnownOnes.getBoolValue()) { - ref NotZeros = NotExpr::create(klee::ConstantExpr::alloc(Origin->KnownZeros)); - ref VarOrNotZero = OrExpr::create(Var, NotZeros); - ZeroBitsMap[Origin] = EqExpr::create(VarOrNotZero, NotZeros); - ref Ones = klee::ConstantExpr::alloc(Origin->KnownOnes); - ref VarAndOnes = AndExpr::create(Var, Ones); - OneBitsMap[Origin] = EqExpr::create(VarAndOnes, Ones); - } - if (Origin->NonZero) - NonZeroBitsMap[Origin] = NeExpr::create(Var, klee::ConstantExpr::create(0, Width)); - if (Origin->NonNegative) - NonNegBitsMap[Origin] = SleExpr::create(klee::ConstantExpr::create(0, Width), Var); - if (Origin->PowOfTwo) { - ref Zero = klee::ConstantExpr::create(0, Width); - PowerTwoBitsMap[Origin] = AndExpr::create(NeExpr::create(Var, Zero), - EqExpr::create(AndExpr::create(Var, - SubExpr::create(Var, klee::ConstantExpr::create(1, Width))), - Zero)); - } - if (Origin->Negative) - NegBitsMap[Origin] = SltExpr::create(Var, klee::ConstantExpr::create(0, Width)); - if (Origin->NumSignBits > 1) { - ref Res = AShrExpr::create(Var, klee::ConstantExpr::create(Width - Origin->NumSignBits, Width)); - ref TestOnes = AShrExpr::create(ShlExpr::create(klee::ConstantExpr::create(1, Width), - klee::ConstantExpr::create(Width - 1, Width)), - klee::ConstantExpr::create(Width - 1, Width)); - SignBitsMap[Origin] = OrExpr::create(EqExpr::create(Res, TestOnes), - EqExpr::create(Res, klee::ConstantExpr::create(0, Width))); + std::string BuildQuery(const BlockPCs &BPCs, + const std::vector &PCs, + InstMapping Mapping, + std::vector *ModelVars, bool Negate) override { + std::string SMTStr; + llvm::raw_string_ostream SMTSS(SMTStr); + ConstraintManager Manager; + Optional OptionalCE = GetCandidateExprForReplacement(BPCs, + PCs, Mapping, Negate); + if (!OptionalCE.hasValue()) + return std::string(); + CandidateExpr CE = std::move(OptionalCE.getValue()); + Query KQuery(Manager, CE.E); + ExprSMTLIBPrinter Printer; + Printer.setOutput(SMTSS); + Printer.setQuery(KQuery); + std::vector Arrays; + if (ModelVars) { + for (unsigned I = 0; I != CE.ArrayVars.size(); ++I) { + if (CE.ArrayVars[I]) { + Arrays.push_back(CE.Arrays[I].get()); + ModelVars->push_back(CE.ArrayVars[I]); + } } + Printer.setArrayValuesToGet(Arrays); + } + Printer.generateOutput(); + + if (DumpKLEEExprs) { + SMTSS << "; KLEE expression:\n; "; + std::unique_ptr PP(ExprPPrinter::create(SMTSS)); + PP->setForceNoLineBreaks(true); + PP->scan(CE.E); + PP->print(CE.E); + SMTSS << '\n'; } - return Var; - } - ref addnswUB(Inst *I) { + return SMTSS.str(); + } + +private: + ref addnswUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Add = AddExpr::create(L, R); @@ -115,7 +107,7 @@ class KLEEBuilder : public ExprBuilder { EqExpr::create(LMSB, AddMSB)); } - ref addnuwUB(Inst *I) { + ref addnuwUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); Expr::Width Width = L->getWidth(); @@ -126,7 +118,7 @@ class KLEEBuilder : public ExprBuilder { return Expr::createIsZero(AddMSB); } - ref subnswUB(Inst *I) { + ref subnswUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Sub = SubExpr::create(L, R); @@ -138,7 +130,7 @@ class KLEEBuilder : public ExprBuilder { EqExpr::create(LMSB, SubMSB)); } - ref subnuwUB(Inst *I) { + ref subnuwUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); Expr::Width Width = L->getWidth(); @@ -149,7 +141,7 @@ class KLEEBuilder : public ExprBuilder { return Expr::createIsZero(SubMSB); } - ref mulnswUB(Inst *I) { + ref mulnswUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); // The computation below has to be performed on the operands of // multiplication instruction. The instruction using mulnswUB() @@ -164,7 +156,7 @@ class KLEEBuilder : public ExprBuilder { return EqExpr::create(Mul, LowerBitsExt); } - ref mulnuwUB(Inst *I) { + ref mulnuwUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); Expr::Width Width = L->getWidth(); @@ -175,20 +167,20 @@ class KLEEBuilder : public ExprBuilder { return Expr::createIsZero(HigherBits); } - ref udivUB(Inst *I) { + ref udivUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref R = get(Ops[1]); return NeExpr::create(R, klee::ConstantExpr::create(0, R->getWidth())); } - ref udivExactUB(Inst *I) { + ref udivExactUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Udiv = UDivExpr::create(L, R); return EqExpr::create(L, MulExpr::create(R, Udiv)); } - ref sdivUB(Inst *I) { + ref sdivUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref ShiftBy = klee::ConstantExpr::create(L->getWidth()-1, @@ -201,21 +193,21 @@ class KLEEBuilder : public ExprBuilder { NeExpr::create(L, IntMin), NeExpr::create(R, NegOne))); } - ref sdivExactUB(Inst *I) { + ref sdivExactUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Sdiv = SDivExpr::create(L, R); return EqExpr::create(L, MulExpr::create(R, Sdiv)); } - ref shiftUB(Inst *I) { + ref shiftUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Lwidth = klee::ConstantExpr::create(L->getWidth(), L->getWidth()); return UltExpr::create(R, Lwidth); } - ref shlnswUB(Inst *I) { + ref shlnswUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = ShlExpr::create(L, R); @@ -223,7 +215,7 @@ class KLEEBuilder : public ExprBuilder { return EqExpr::create(RShift, L); } - ref shlnuwUB(Inst *I) { + ref shlnuwUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = ShlExpr::create(L, R); @@ -231,7 +223,7 @@ class KLEEBuilder : public ExprBuilder { return EqExpr::create(RShift, L); } - ref lshrExactUB(Inst *I) { + ref lshrExactUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = LShrExpr::create(L, R); @@ -239,7 +231,7 @@ class KLEEBuilder : public ExprBuilder { return EqExpr::create(LShift, L); } - ref ashrExactUB(Inst *I) { + ref ashrExactUB(Inst *I) override { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = AShrExpr::create(L, R); @@ -247,7 +239,7 @@ class KLEEBuilder : public ExprBuilder { return EqExpr::create(LShift, L); } - ref countOnes(ref L) { + ref countOnes(ref L) override { Expr::Width Width = L->getWidth(); ref Count = klee::ConstantExpr::alloc(llvm::APInt(Width, 0)); for (unsigned i=0; i E) { + void recordUBInstruction(Inst *I, ref E) override { if (!IsForBlockPCUBInst) { UBExprMap[I] = E; } @@ -272,7 +264,7 @@ class KLEEBuilder : public ExprBuilder { } } - ref build(Inst *I) { + ref build(Inst *I) override { const std::vector &Ops = I->orderedOps(); switch (I->K) { case Inst::UntypedConst: @@ -548,7 +540,7 @@ class KLEEBuilder : public ExprBuilder { llvm_unreachable("unknown kind"); } - ref get(Inst *I) { + ref get(Inst *I) override { ref &E = ExprMap[I]; if (E.isNull()) { E = build(I); @@ -557,13 +549,13 @@ class KLEEBuilder : public ExprBuilder { return E; } - ref getInstMapping(const InstMapping &IM) { + ref getInstMapping(const InstMapping &IM) override { return EqExpr::create(get(IM.LHS), get(IM.RHS)); } ref createPathPred( std::map &BlockConstraints, Inst* PathInst, - std::map *SelectBranches) { + std::map *SelectBranches) override { ref Pred = klee::ConstantExpr::alloc(1, 1); if (PathInst->K == Inst::Phi) { @@ -604,7 +596,7 @@ class KLEEBuilder : public ExprBuilder { ref createUBPathInstsPred( Inst *CurrentInst, std::vector &PathInsts, std::map &BlockConstraints, - std::map *SelectBranches, UBPathInstMap &CachedUBPathInsts) { + std::map *SelectBranches, UBPathInstMap &CachedUBPathInsts) override { ref Pred = klee::ConstantExpr::alloc(1, 1); for (const auto &PathInst : PathInsts) { if (PathInst->Ops.size() == 1) @@ -688,7 +680,7 @@ class KLEEBuilder : public ExprBuilder { // These tricks basically relies on the dependency chain of instructions // generated by souper. For example, if we say %12 depends on %11, then // %12 would never appear earlier than %11. - ref getUBInstCondition() { + ref getUBInstCondition() override { // A map from a Phi instruction to all of its KLEE expressions that // encode the path and UB Inst predicates. @@ -737,7 +729,7 @@ class KLEEBuilder : public ExprBuilder { return Result; } - void setBlockPCMap(const BlockPCs &BPCs) { + void setBlockPCMap(const BlockPCs &BPCs) override { for (auto BPC : BPCs) { assert(BPC.B && "Block is NULL!"); BlockPCPredMap &PCMap = BlockPCMap[BPC.B]; @@ -769,7 +761,7 @@ class KLEEBuilder : public ExprBuilder { // However, mixing two parts (one for UB constraints, one for BlockPCs) // may make the code less structured. If we see big performance overhead, // we may consider to combine these two parts together. - ref getBlockPCs() { + ref getBlockPCs() override { UBPathInstMap CachedPhis; ref Result = klee::ConstantExpr::create(1, Expr::Bool); @@ -807,7 +799,7 @@ class KLEEBuilder : public ExprBuilder { // Return an expression which must be proven valid for the candidate to apply. llvm::Optional GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, - InstMapping Mapping, bool Negate) { + InstMapping Mapping, bool Negate) override { // Build LHS ref LHS = get(Mapping.LHS); ref Ante = klee::ConstantExpr::alloc(1, 1); @@ -875,45 +867,54 @@ class KLEEBuilder : public ExprBuilder { return llvm::Optional(std::move(CE)); } + + ref makeSizedArrayRead(unsigned Width, StringRef Name, Inst *Origin) { + std::string NameStr; + if (Name.empty()) + NameStr = "arr"; + else if (Name[0] >= '0' && Name[0] <= '9') + NameStr = ("a" + Name).str(); + else + NameStr = Name; + CE.Arrays.emplace_back( + new Array(ArrayNames.makeName(NameStr), 1, 0, 0, Expr::Int32, Width)); + CE.ArrayVars.push_back(Origin); - std::string BuildQuery(const BlockPCs &BPCs, - const std::vector &PCs, - InstMapping Mapping, - std::vector *ModelVars, bool Negate) { - std::string SMTStr; - llvm::raw_string_ostream SMTSS(SMTStr); - ConstraintManager Manager; - Optional OptionalCE = GetCandidateExprForReplacement(BPCs, - PCs, Mapping, Negate); - if (!OptionalCE.hasValue()) - return std::string(); - CandidateExpr CE = std::move(OptionalCE.getValue()); - Query KQuery(Manager, CE.E); - ExprSMTLIBPrinter Printer; - Printer.setOutput(SMTSS); - Printer.setQuery(KQuery); - std::vector Arrays; - if (ModelVars) { - for (unsigned I = 0; I != CE.ArrayVars.size(); ++I) { - if (CE.ArrayVars[I]) { - Arrays.push_back(CE.Arrays[I].get()); - ModelVars->push_back(CE.ArrayVars[I]); - } + std::vector ZeroBits, OneBits; + UpdateList UL(CE.Arrays.back().get(), 0); + ref Var = ReadExpr::create(UL, klee::ConstantExpr::alloc(0, Expr::Int32)); + if (Origin && Origin->K == Inst::Var) { + if (Origin->KnownZeros.getBoolValue() || Origin->KnownOnes.getBoolValue()) { + ref NotZeros = NotExpr::create(klee::ConstantExpr::alloc(Origin->KnownZeros)); + ref VarOrNotZero = OrExpr::create(Var, NotZeros); + ZeroBitsMap[Origin] = EqExpr::create(VarOrNotZero, NotZeros); + ref Ones = klee::ConstantExpr::alloc(Origin->KnownOnes); + ref VarAndOnes = AndExpr::create(Var, Ones); + OneBitsMap[Origin] = EqExpr::create(VarAndOnes, Ones); + } + if (Origin->NonZero) + NonZeroBitsMap[Origin] = NeExpr::create(Var, klee::ConstantExpr::create(0, Width)); + if (Origin->NonNegative) + NonNegBitsMap[Origin] = SleExpr::create(klee::ConstantExpr::create(0, Width), Var); + if (Origin->PowOfTwo) { + ref Zero = klee::ConstantExpr::create(0, Width); + PowerTwoBitsMap[Origin] = AndExpr::create(NeExpr::create(Var, Zero), + EqExpr::create(AndExpr::create(Var, + SubExpr::create(Var, klee::ConstantExpr::create(1, Width))), + Zero)); + } + if (Origin->Negative) + NegBitsMap[Origin] = SltExpr::create(Var, klee::ConstantExpr::create(0, Width)); + if (Origin->NumSignBits > 1) { + ref Res = AShrExpr::create(Var, klee::ConstantExpr::create(Width - Origin->NumSignBits, Width)); + ref TestOnes = AShrExpr::create(ShlExpr::create(klee::ConstantExpr::create(1, Width), + klee::ConstantExpr::create(Width - 1, Width)), + klee::ConstantExpr::create(Width - 1, Width)); + SignBitsMap[Origin] = OrExpr::create(EqExpr::create(Res, TestOnes), + EqExpr::create(Res, klee::ConstantExpr::create(0, Width))); } - Printer.setArrayValuesToGet(Arrays); - } - Printer.generateOutput(); - - if (DumpKLEEExprs) { - SMTSS << "; KLEE expression:\n; "; - std::unique_ptr PP(ExprPPrinter::create(SMTSS)); - PP->setForceNoLineBreaks(true); - PP->scan(CE.E); - PP->print(CE.E); - SMTSS << '\n'; } - - return SMTSS.str(); + return Var; } }; From ec49f80454a442aaa1dca11dbcd9e1d0c61cf6fb Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 19 Feb 2018 21:29:58 +0100 Subject: [PATCH 06/49] Work --- include/souper/Extractor/ExprBuilder.h | 40 +++++++++++++++----------- include/souper/Extractor/Solver.h | 3 +- lib/Extractor/ExprBuilder.cpp | 18 ++++++------ lib/Extractor/KLEEBuilder.cpp | 28 +++++++++--------- lib/Extractor/Solver.cpp | 26 ++++++++--------- lib/Infer/InstSynthesis.cpp | 6 ++-- 6 files changed, 66 insertions(+), 55 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 521da1968..4e3f0a680 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -32,6 +32,9 @@ class ExprBuilder { Z3 }; + // Local reference + InstContext *LIC; + const unsigned MAX_PHI_DEPTH = 25; typedef std::unordered_map>> UBPathInstMap; @@ -54,13 +57,15 @@ class ExprBuilder { ref buildAssoc(std::function(ref, ref)> F, llvm::ArrayRef Ops); - ref getZeroBitsMapping(Inst *I); - ref getOneBitsMapping(Inst *I); - ref getNonZeroBitsMapping(Inst *I); - ref getNonNegBitsMapping(Inst *I); - ref getPowerTwoBitsMapping(Inst *I); - ref getNegBitsMapping(Inst *I); - ref getSignBitsMapping(Inst *I); + + Inst *getZeroBitsMapping(Inst *I); + Inst *getOneBitsMapping(Inst *I); + Inst *getNonZeroBitsMapping(Inst *I); + Inst *getNonNegBitsMapping(Inst *I); + Inst *getPowerTwoBitsMapping(Inst *I); + Inst *getNegBitsMapping(Inst *I); + Inst *getSignBitsMapping(Inst *I); + std::vector> getBlockPredicates(Inst *I); bool getUBPaths(Inst *I, UBPath *Current, std::vector> &Paths, @@ -71,14 +76,17 @@ class ExprBuilder { std::map>> BlockPredMap; std::map> ExprMap; + std::map> UBExprMap; - std::map> ZeroBitsMap; - std::map> OneBitsMap; - std::map> NonZeroBitsMap; - std::map> NonNegBitsMap; - std::map> PowerTwoBitsMap; - std::map> NegBitsMap; - std::map> SignBitsMap; + + std::map ZeroBitsMap; + std::map OneBitsMap; + std::map NonZeroBitsMap; + std::map NonNegBitsMap; + std::map PowerTwoBitsMap; + std::map NegBitsMap; + std::map SignBitsMap; + std::map BlockPCMap; std::vector UBPathInsts; UniqueNameSet ArrayNames; @@ -139,11 +147,11 @@ class ExprBuilder { UBPathInstMap &CachedUBPathInsts) = 0; }; -std::string BuildQuery(const BlockPCs &BPCs, +std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate=false); -std::unique_ptr createKLEEBuilder(); +std::unique_ptr createKLEEBuilder(InstContext &IC); } diff --git a/include/souper/Extractor/Solver.h b/include/souper/Extractor/Solver.h index df0e84e99..3eff5543a 100644 --- a/include/souper/Extractor/Solver.h +++ b/include/souper/Extractor/Solver.h @@ -33,7 +33,8 @@ class Solver { infer(const BlockPCs &BPCs, const std::vector &PCs, Inst *LHS, Inst *&RHS, InstContext &IC) = 0; virtual std::error_code - isValid(const BlockPCs &BPCs, const std::vector &PCs, + isValid(InstContext &IC, const BlockPCs &BPCs, + const std::vector &PCs, InstMapping Mapping, bool &IsValid, std::vector> *Model) = 0; virtual std::string getName() = 0; diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index d337e79a4..4c36c8269 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -199,43 +199,43 @@ void ExprBuilder::getBlockPCPhiPaths( getBlockPCPhiPaths(Ops[J], Tmp[J], Paths, CachedPhis); } -ref ExprBuilder::getZeroBitsMapping(Inst *I) { +Inst *ExprBuilder::getZeroBitsMapping(Inst *I) { return ZeroBitsMap[I]; } -ref ExprBuilder::getOneBitsMapping(Inst *I) { +Inst *ExprBuilder::getOneBitsMapping(Inst *I) { return OneBitsMap[I]; } -ref ExprBuilder::getNonZeroBitsMapping(Inst *I) { +Inst *ExprBuilder::getNonZeroBitsMapping(Inst *I) { return NonZeroBitsMap[I]; } -ref ExprBuilder::getNonNegBitsMapping(Inst *I) { +Inst *ExprBuilder::getNonNegBitsMapping(Inst *I) { return NonNegBitsMap[I]; } -ref ExprBuilder::getNegBitsMapping(Inst *I) { +Inst *ExprBuilder::getNegBitsMapping(Inst *I) { return NegBitsMap[I]; } -ref ExprBuilder::getPowerTwoBitsMapping(Inst *I) { +Inst *ExprBuilder::getPowerTwoBitsMapping(Inst *I) { return PowerTwoBitsMap[I]; } -ref ExprBuilder::getSignBitsMapping(Inst *I) { +Inst *ExprBuilder::getSignBitsMapping(Inst *I) { return SignBitsMap[I]; } // TODO: Fix GetCandidateExprForReplacement -std::string BuildQuery(const BlockPCs &BPCs, +std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate) { std::unique_ptr EB; switch (SMTExprBuilder) { case ExprBuilder::KLEE: - EB = createKLEEBuilder(); + EB = createKLEEBuilder(IC); break; case ExprBuilder::Z3: report_fatal_error("not supported yet"); diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 312703e75..c98c8d844 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -51,13 +51,15 @@ namespace { class KLEEBuilder : public ExprBuilder { public: - KLEEBuilder() {} + KLEEBuilder(InstContext &IC) { + LIC = &IC; + } ~KLEEBuilder() {} std::string BuildQuery(const BlockPCs &BPCs, - const std::vector &PCs, - InstMapping Mapping, - std::vector *ModelVars, bool Negate) override { + const std::vector &PCs, + InstMapping Mapping, + std::vector *ModelVars, bool Negate) override { std::string SMTStr; llvm::raw_string_ostream SMTSS(SMTStr); ConstraintManager Manager; @@ -809,19 +811,19 @@ class KLEEBuilder : public ExprBuilder { for (const auto I : CE.ArrayVars) { if (I) { if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) { - Ante = AndExpr::create(Ante, getZeroBitsMapping(I)); - Ante = AndExpr::create(Ante, getOneBitsMapping(I)); + Ante = AndExpr::create(Ante, get(getZeroBitsMapping(I))); + Ante = AndExpr::create(Ante, get(getOneBitsMapping(I))); } if (I->NonZero) - Ante = AndExpr::create(Ante, getNonZeroBitsMapping(I)); + Ante = AndExpr::create(Ante, get(getNonZeroBitsMapping(I))); if (I->NonNegative) - Ante = AndExpr::create(Ante, getNonNegBitsMapping(I)); + Ante = AndExpr::create(Ante, get(getNonNegBitsMapping(I))); if (I->PowOfTwo) - Ante = AndExpr::create(Ante, getPowerTwoBitsMapping(I)); + Ante = AndExpr::create(Ante, get(getPowerTwoBitsMapping(I))); if (I->Negative) - Ante = AndExpr::create(Ante, getNegBitsMapping(I)); + Ante = AndExpr::create(Ante, get(getNegBitsMapping(I))); if (I->NumSignBits > 1) - Ante = AndExpr::create(Ante, getSignBitsMapping(I)); + Ante = AndExpr::create(Ante, get(getSignBitsMapping(I))); } } // Build PCs @@ -921,6 +923,6 @@ class KLEEBuilder : public ExprBuilder { } -std::unique_ptr souper::createKLEEBuilder() { - return std::unique_ptr(new KLEEBuilder()); +std::unique_ptr souper::createKLEEBuilder(InstContext &IC) { + return std::unique_ptr(new KLEEBuilder(IC)); } diff --git a/lib/Extractor/Solver.cpp b/lib/Extractor/Solver.cpp index 3e0a7d50c..33eecd868 100644 --- a/lib/Extractor/Solver.cpp +++ b/lib/Extractor/Solver.cpp @@ -91,7 +91,7 @@ class BaseSolver : public Solver { Guesses.emplace_back(IC.getConst(APInt(LHS->Width, -1))); for (auto I : Guesses) { InstMapping Mapping(LHS, I); - std::string Query = BuildQuery(BPCs, PCs, Mapping, 0); + std::string Query = BuildQuery(IC, BPCs, PCs, Mapping, 0); if (Query.empty()) return std::make_error_code(std::errc::value_too_large); bool IsSat; @@ -110,7 +110,7 @@ class BaseSolver : public Solver { std::vector ModelVals; Inst *I = IC.createVar(LHS->Width, "constant"); InstMapping Mapping(LHS, I); - std::string Query = BuildQuery(BPCs, PCs, Mapping, &ModelInsts, /*Negate=*/true); + std::string Query = BuildQuery(IC, BPCs, PCs, Mapping, &ModelInsts, /*Negate=*/true); if (Query.empty()) return std::make_error_code(std::errc::value_too_large); bool IsSat; @@ -130,7 +130,7 @@ class BaseSolver : public Solver { assert(Const && "there must be a model for the constant"); // Check if the constant is valid for all inputs InstMapping ConstMapping(LHS, Const); - std::string Query = BuildQuery(BPCs, PCs, ConstMapping, 0); + std::string Query = BuildQuery(IC, BPCs, PCs, ConstMapping, 0); if (Query.empty()) return std::make_error_code(std::errc::value_too_large); EC = SMTSolver->isSatisfiable(Query, IsSat, 0, 0, Timeout); @@ -162,7 +162,7 @@ class BaseSolver : public Solver { } // (LHS != i_1) && (LHS != i_2) && ... && (LHS != i_n) == true InstMapping Mapping(Ante, IC.getConst(APInt(1, true))); - std::string Query = BuildQuery(BPCsCopy, PCsCopy, Mapping, 0, /*Negate=*/true); + std::string Query = BuildQuery(IC, BPCsCopy, PCsCopy, Mapping, 0, /*Negate=*/true); if (Query.empty()) return std::make_error_code(std::errc::value_too_large); bool BigQueryIsSat; @@ -175,7 +175,7 @@ class BaseSolver : public Solver { // find the nop for (auto I : Guesses) { InstMapping Mapping(LHS, I); - std::string Query = BuildQuery(BPCs, PCs, Mapping, 0); + std::string Query = BuildQuery(IC, BPCs, PCs, Mapping, 0); if (Query.empty()) continue; EC = SMTSolver->isSatisfiable(Query, SmallQueryIsSat, 0, 0, Timeout); @@ -216,7 +216,7 @@ class BaseSolver : public Solver { return EC; } - std::error_code isValid(const BlockPCs &BPCs, + std::error_code isValid(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool &IsValid, std::vector> *Model) @@ -224,7 +224,7 @@ class BaseSolver : public Solver { std::string Query; if (Model && SMTSolver->supportsModels()) { std::vector ModelInsts; - std::string Query = BuildQuery(BPCs, PCs, Mapping, &ModelInsts); + std::string Query = BuildQuery(IC, BPCs, PCs, Mapping, &ModelInsts); if (Query.empty()) return std::make_error_code(std::errc::value_too_large); bool IsSat; @@ -241,7 +241,7 @@ class BaseSolver : public Solver { } return EC; } else { - std::string Query = BuildQuery(BPCs, PCs, Mapping, 0); + std::string Query = BuildQuery(IC, BPCs, PCs, Mapping, 0); if (Query.empty()) return std::make_error_code(std::errc::value_too_large); bool IsSat; @@ -297,20 +297,20 @@ class MemCachingSolver : public Solver { } } - std::error_code isValid(const BlockPCs &BPCs, + std::error_code isValid(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool &IsValid, std::vector> *Model) override { // TODO: add caching support for models. if (Model) - return UnderlyingSolver->isValid(BPCs, PCs, Mapping, IsValid, Model); + return UnderlyingSolver->isValid(IC, BPCs, PCs, Mapping, IsValid, Model); std::string Repl = GetReplacementString(BPCs, PCs, Mapping); const auto &ent = IsValidCache.find(Repl); if (ent == IsValidCache.end()) { ++MemMissesIsValid; - std::error_code EC = UnderlyingSolver->isValid(BPCs, PCs, + std::error_code EC = UnderlyingSolver->isValid(IC, BPCs, PCs, Mapping, IsValid, 0); IsValidCache.emplace(Repl, std::make_pair(EC, IsValid)); return EC; @@ -373,14 +373,14 @@ class ExternalCachingSolver : public Solver { } } - std::error_code isValid(const BlockPCs &BPCs, + std::error_code isValid(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool &IsValid, std::vector> *Model) override { // N.B. we decided that since the important clients have moved to infer(), // we'll no longer support external caching for isValid() - return UnderlyingSolver->isValid(BPCs, PCs, Mapping, IsValid, Model); + return UnderlyingSolver->isValid(IC, BPCs, PCs, Mapping, IsValid, Model); } std::string getName() override { diff --git a/lib/Infer/InstSynthesis.cpp b/lib/Infer/InstSynthesis.cpp index 8e7642414..5bcef7690 100644 --- a/lib/Infer/InstSynthesis.cpp +++ b/lib/Infer/InstSynthesis.cpp @@ -174,7 +174,7 @@ std::error_code InstSynthesis::synthesize(SMTLIBSolver *SMTSolver, InstMapping Mapping(Query, TrueConst); // Negate the query to get a SAT model. // Don't use original BPCs/PCs, they are useless - std::string QueryStr = BuildQuery({}, LoopPCs, Mapping, + std::string QueryStr = BuildQuery(IC, {}, LoopPCs, Mapping, &ModelInsts, /*Negate=*/true); if (QueryStr.empty()) return std::make_error_code(std::errc::value_too_large); @@ -231,7 +231,7 @@ std::error_code InstSynthesis::synthesize(SMTLIBSolver *SMTSolver, ModelInsts.clear(); ModelVals.clear(); InstMapping CandMapping(LHS, Cand); - QueryStr = BuildQuery(BPCs, PCs, CandMapping, &ModelInsts, /*Negate=*/false); + QueryStr = BuildQuery(IC, BPCs, PCs, CandMapping, &ModelInsts, /*Negate=*/false); if (QueryStr.empty()) return std::make_error_code(std::errc::value_too_large); EC = SMTSolver->isSatisfiable(QueryStr, IsSat, ModelInsts.size(), @@ -1341,7 +1341,7 @@ std::error_code InstSynthesis::getInitialConcreteInputs(std::vector ModelVals; InstMapping Mapping(LHS, LIC->createVar(LHS->Width, "output")); // Negate the query to get a SAT model - std::string QueryStr = BuildQuery(*LBPCs, InputPCs, Mapping, + std::string QueryStr = BuildQuery(*LIC, *LBPCs, InputPCs, Mapping, &ModelInsts, /*Negate=*/true); if (QueryStr.empty()) return std::make_error_code(std::errc::value_too_large); From 47fe3b1795a5a31564cb4e602d1244072970fda1 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Tue, 20 Feb 2018 13:14:13 +0100 Subject: [PATCH 07/49] Foo --- include/souper/Extractor/ExprBuilder.h | 75 +++--- lib/Extractor/ExprBuilder.cpp | 292 ++++++++++++++++++++- lib/Extractor/KLEEBuilder.cpp | 337 +++---------------------- tools/souper-check.cpp | 2 +- tools/souperweb-backend.cpp | 2 +- 5 files changed, 359 insertions(+), 349 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 4e3f0a680..acdbca9a2 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -37,8 +37,8 @@ class ExprBuilder { const unsigned MAX_PHI_DEPTH = 25; - typedef std::unordered_map>> UBPathInstMap; - typedef std::map> BlockPCPredMap; + typedef std::unordered_map> UBPathInstMap; + typedef std::map BlockPCPredMap; struct UBPath { std::map BlockConstraints; @@ -50,7 +50,7 @@ class ExprBuilder { struct BlockPCPhiPath { std::map BlockConstraints; std::vector Phis; - std::vector> PCs; + std::vector PCs; }; virtual ~ExprBuilder(); @@ -58,40 +58,54 @@ class ExprBuilder { ref buildAssoc(std::function(ref, ref)> F, llvm::ArrayRef Ops); - Inst *getZeroBitsMapping(Inst *I); - Inst *getOneBitsMapping(Inst *I); - Inst *getNonZeroBitsMapping(Inst *I); - Inst *getNonNegBitsMapping(Inst *I); - Inst *getPowerTwoBitsMapping(Inst *I); - Inst *getNegBitsMapping(Inst *I); - Inst *getSignBitsMapping(Inst *I); + ref getZeroBitsMapping(Inst *I); + ref getOneBitsMapping(Inst *I); + ref getNonZeroBitsMapping(Inst *I); + ref getNonNegBitsMapping(Inst *I); + ref getPowerTwoBitsMapping(Inst *I); + ref getNegBitsMapping(Inst *I); + ref getSignBitsMapping(Inst *I); - std::vector> getBlockPredicates(Inst *I); + std::vector getBlockPredicates(Inst *I); bool getUBPaths(Inst *I, UBPath *Current, std::vector> &Paths, UBPathInstMap &CachedUBPathInsts, unsigned Depth); void getBlockPCPhiPaths(Inst *I, BlockPCPhiPath *Current, std::vector> &Paths, UBPathInstMap &CachedPhis); + Inst *createPathPred(std::map &BlockConstraints, + Inst* PathInst, + std::map *SelectBranches); + Inst *createUBPathInstsPred(Inst *CurrentInst, + std::vector &UBPathInsts, + std::map &BlockConstraints, + std::map *SelectBranches, + UBPathInstMap &CachedUBPathInsts); + + Inst *getInstMapping(const InstMapping &IM); + Inst *getUBInstCondition(); + Inst *getBlockPCs(); + void setBlockPCMap(const BlockPCs &BPCs); + void recordUBInstruction(Inst *I, Inst *E); + + std::map> BlockPredMap; - std::map>> BlockPredMap; std::map> ExprMap; + std::map UBExprMap; - std::map> UBExprMap; - - std::map ZeroBitsMap; - std::map OneBitsMap; - std::map NonZeroBitsMap; - std::map NonNegBitsMap; - std::map PowerTwoBitsMap; - std::map NegBitsMap; - std::map SignBitsMap; + std::map> ZeroBitsMap; + std::map> OneBitsMap; + std::map> NonZeroBitsMap; + std::map> NonNegBitsMap; + std::map> PowerTwoBitsMap; + std::map> NegBitsMap; + std::map> SignBitsMap; std::map BlockPCMap; std::vector UBPathInsts; UniqueNameSet ArrayNames; // Holding the precondition, i.e. blockpc, for the UBInst under process. - ref UBInstPrecondition; + Inst *UBInstPrecondition; // Indicate if the UBInst relates to BlockPC bool IsForBlockPCUBInst = false; @@ -127,24 +141,9 @@ class ExprBuilder { virtual ref ashrExactUB(Inst *I) = 0; virtual ref countOnes(ref E) = 0; - virtual void recordUBInstruction(Inst *I, ref E) = 0; - virtual ref build(Inst *I) = 0; virtual ref get(Inst *I) = 0; - virtual ref getInstMapping(const InstMapping &IM) = 0; - - virtual ref getUBInstCondition() = 0; - virtual ref getBlockPCs() = 0; - virtual void setBlockPCMap(const BlockPCs &BPCs) = 0; - - virtual ref createPathPred(std::map &BlockConstraints, - Inst* PathInst, - std::map *SelectBranches) = 0; - virtual ref createUBPathInstsPred(Inst *CurrentInst, - std::vector &UBPathInsts, - std::map &BlockConstraints, - std::map *SelectBranches, - UBPathInstMap &CachedUBPathInsts) = 0; + }; std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 4c36c8269..2493d86bf 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -42,13 +42,13 @@ ref ExprBuilder::buildAssoc( return E; } -std::vector> ExprBuilder::getBlockPredicates(Inst *I) { +std::vector ExprBuilder::getBlockPredicates(Inst *I) { assert(I->K == Inst::Phi && "not a phi inst"); if (BlockPredMap.count(I->B)) return BlockPredMap[I->B]; - std::vector> PredExpr; + std::vector PredExpr; for (auto const &PredVar : I->B->PredVars) - PredExpr.push_back(build(PredVar)); + PredExpr.push_back(PredVar); BlockPredMap[I->B] = PredExpr; return PredExpr; } @@ -199,34 +199,306 @@ void ExprBuilder::getBlockPCPhiPaths( getBlockPCPhiPaths(Ops[J], Tmp[J], Paths, CachedPhis); } -Inst *ExprBuilder::getZeroBitsMapping(Inst *I) { +Inst *ExprBuilder::createPathPred( + std::map &BlockConstraints, Inst* PathInst, + std::map *SelectBranches) { + + Inst *Pred = LIC->getConst(APInt(1, true)); + if (PathInst->K == Inst::Phi) { + unsigned Num = BlockConstraints[PathInst->B]; + const auto &PredExpr = BlockPredMap[PathInst->B]; + // Sanity checks + assert(PredExpr.size() && "there must be path predicates for the UBs"); + assert(PredExpr.size() == PathInst->Ops.size()-1 && + "phi predicate size mismatch"); + // Add the predicate(s) + if (Num == 0) + Pred = LIC->getInst(Inst::And, 1, {Pred, PredExpr[0]}); + else { + Inst *IsZero = LIC->getInst(Inst::Eq, 1, {PredExpr[Num-1], LIC->getConst(APInt(PredExpr[Num-1]->Width, 0))}); + Pred = LIC->getInst(Inst::And, 1, {Pred, IsZero}); + } + for (unsigned B = Num; B < PredExpr.size(); ++B) + Pred = LIC->getInst(Inst::And, 1, {Pred, PredExpr[B]}); + } + else if (PathInst->K == Inst::Select) { + Inst *SelectPred = PathInst->orderedOps()[0]; + assert(SelectBranches && "NULL SelectBranches?"); + auto SI = SelectBranches->find(PathInst); + // The current path doesn't have info about this select instruction. + if (SI == SelectBranches->end()) { + return Pred; + } + if (SI->second) + Pred = LIC->getInst(Inst::And, 1, {Pred, SelectPred}); + else { + Inst *IsZero = LIC->getInst(Inst::Eq, 1, {SelectPred, LIC->getConst(APInt(SelectPred->Width, 0))}); + Pred = LIC->getInst(Inst::And, 1, {Pred, IsZero}); + } + } + else { + assert(0 && "cannot reach here"); + } + + return Pred; +} + +// Collect UB Inst condition for each Phi instruction. +// The basic algorithm is: +// (1) for a given phi instruction, we first collect all paths that start +// from the phi. For each path, we also keep the the phi instructions +// along the path and the UB instructions associated with these phi +// instructions; +// (2) then for each path, we generate a corresponding KLEE expression +// based on the facts that we collected in step (1), including: +// * UB instructions; +// * Phi predicates; +// +// With the algorithm, it is easy to get into the path explosion problem, +// i.e., the number of paths is increased exponentially. Under some +// circumstances, e.g., the number of phis is too large, we will suffer +// with large performance overhead. In some extreme cases, we will fail +// to process some file due to the large memory footprint, i.e., `newing' +// too many UBPaths. Two tricks are used to relief the penalty of the +// path explosion problem: +// (1) caching the KLEE expresions for each processed phi, where each +// KLEE expression encodes the path that starts from one of the phi's +// values. For example, when processing a sample souper IR below +// +// %0 = block +// %1 = block +// %2:i32 = var +// %3:i32 = shl 0:i32, %2 +// %4:i32 = var +// %5:i32 = shl 0:i32, %4 +// %6 = var +// %11:i32 = phi %1, %3, %5 +// %12:i32 = phi %0, %6, %11 +// +// we first encounter phi %11. The generated KLEE expression +// for this phi encodes two paths, i.e., %3 and %5. We cache +// these two into CachedUBPathInsts. Then we move to process phi %12. +// At this point, rather than recursively re-contruct %11 (through +// %12's value), we just re-used the cached path-expressions. +// For each path-expression, we append it with %12's own predicate +// and also cache them with %12 for future use. After finishing +// %12, we will have three entries for phi %12. +// (2) The first trick increases the performance, but we still suffer +// with large memory consumption, i.e., it's easy to cache too +// many paths. The second trick is to reduce the memory footprint +// by only caching "useful" path that has UB Insts. For example, +// in the example in (1), for phi %12, we don't need to cache +// the path starting from %6, because this path doesn't have any +// UB Insts. +// +// These tricks basically relies on the dependency chain of instructions +// generated by souper. For example, if we say %12 depends on %11, then +// %12 would never appear earlier than %11. +Inst *ExprBuilder::getUBInstCondition() { +#if 0 + // A map from a Phi instruction to all of its KLEE expressions that + // encode the path and UB Inst predicates. + UBPathInstMap CachedUBPathInsts; + std::set UsedUBInsts; + Inst *Result = LIC->getConst(APInt(1, true)); + // For each Phi/Select instruction + for (const auto &I : UBPathInsts) { + if (CachedUBPathInsts.count(I) != 0) + continue; + // Recursively collect UB instructions + // on the block constrained Phi and Select branches + std::vector> UBPaths; + UBPath *Current = new UBPath; + UBPaths.push_back(std::move(std::unique_ptr(Current))); + if (!getUBPaths(I, Current, UBPaths, CachedUBPathInsts, 0)) + return LIC->getConst(APInt(1, true)); + CachedUBPathInsts[I] = {}; + // For each found path + for (const auto &Path : UBPaths) { + if (!Path->UBInsts.size()) + continue; + // Aggregate collected UB constraints + Inst *Ante = LIC->getConst(APInt(1, true)); + for (const auto &I : Path->UBInsts) { + auto Iter = UBExprMap.find(I); + // It's possible that the instruction I is not in the map. + // For example, it may come from a blockpc which doesn't + // have any preconditions. + if (Iter != UBExprMap.end()) + Ante = LIC->getInst(Inst::And, 1, {Ante, Iter->second}); + UsedUBInsts.insert(I); + } + // Create path predicate + Inst *Pred = + createUBPathInstsPred(I, Path->Insts, Path->BlockConstraints, + &Path->SelectBranches, CachedUBPathInsts); + // Add predicate->UB constraint + Inst *IsZero = IC.getInst(Inst::Eq, 1, {Pred, LIC->getConst(APInt(1, false))}); + Inst *Implies = IC.getInst(Inst::Or, 1, {IsZero, Ante}); + Result = LIC->getInst(Inst::And, 1, {Result, Implies}); + } + } + // Add the unconditional UB constraints at the top level + for (const auto &Entry: UBExprMap) + if (!UsedUBInsts.count(Entry.first)) + Result = LIC->getInst(Inst::And, 1, {Result, Entry.second}); + + return Result; +#endif + return LIC->getConst(APInt(1, true)); +} + +// Similar to the way we collect UB constraints. We could combine it with +// getUBInstCondition, because the workflow is quite similar. +// However, mixing two parts (one for UB constraints, one for BlockPCs) +// may make the code less structured. If we see big performance overhead, +// we may consider to combine these two parts together. +Inst *ExprBuilder::getBlockPCs() { + + UBPathInstMap CachedPhis; + Inst *Result = LIC->getConst(APInt(1, true)); + // For each Phi instruction + for (const auto &I : UBPathInsts) { + if (CachedPhis.count(I) != 0) + continue; + // Recursively collect BlockPCs + std::vector> BlockPCPhiPaths; + BlockPCPhiPath *Current = new BlockPCPhiPath; + BlockPCPhiPaths.push_back( + std::move(std::unique_ptr(Current))); + getBlockPCPhiPaths(I, Current, BlockPCPhiPaths, CachedPhis); + CachedPhis[I] = {}; + // For each found path + for (const auto &Path : BlockPCPhiPaths) { + if (!Path->PCs.size()) + continue; + // Aggregate collected BlockPC constraints + Inst *Ante = LIC->getConst(APInt(1, true)); + for (const auto &PC : Path->PCs) + Ante = LIC->getInst(Inst::And, 1, {Ante, PC}); + // Create path predicate + Inst *Pred = + createUBPathInstsPred(I, Path->Phis, Path->BlockConstraints, + /*SelectBranches=*/nullptr, CachedPhis); + // Add predicate->UB constraint + Inst *IsZero = LIC->getInst(Inst::Eq, 1, {Pred, LIC->getConst(APInt(1, false))}); + Inst *Implies = LIC->getInst(Inst::Or, 1, {IsZero, Ante}); + Result = LIC->getInst(Inst::And, 1, {Result, Implies}); + } + } + + return Result; +} + +void ExprBuilder::setBlockPCMap(const BlockPCs &BPCs) { + for (auto BPC : BPCs) { + assert(BPC.B && "Block is NULL!"); + BlockPCPredMap &PCMap = BlockPCMap[BPC.B]; + auto I = PCMap.find(BPC.PredIdx); + // Relying on a class-level flag may not be a nice solution, + // but it seems hard to differentiate two cases: + // (1) UBInstExpr collected through blockpc, and; + // (2) UBInstExpr collected through pc/lhs/rhs + // For the first case, UBInst(s) is conditional, i.e., + // they rely on the fact that blockpc(s) are true. + if (I != PCMap.end()) + UBInstPrecondition = I->second; + IsForBlockPCUBInst = true; + Inst *PE = getInstMapping(BPC.PC); + IsForBlockPCUBInst = false; + UBInstPrecondition = nullptr; + if (I == PCMap.end()) + PCMap[BPC.PredIdx] = PE; + else + PCMap[BPC.PredIdx] = LIC->getInst(Inst::And, 1, {I->second, PE}); + } +} + +Inst *ExprBuilder::createUBPathInstsPred( + Inst *CurrentInst, std::vector &PathInsts, + std::map &BlockConstraints, + std::map *SelectBranches, UBPathInstMap &CachedUBPathInsts) { + Inst *Pred = LIC->getConst(APInt(1, true)); + for (const auto &PathInst : PathInsts) { + if (PathInst->Ops.size() == 1) + continue; + Inst *InstPred = createPathPred(BlockConstraints, PathInst, SelectBranches); + + UBPathInstMap::iterator PI = CachedUBPathInsts.find(PathInst); + if (PI == CachedUBPathInsts.end()) { + // It's possible that we don't have a cached instruction yet, + // e.g., the CurrentInst is a select operator. + assert(CurrentInst->K == Inst::Select && "No cached Inst?"); + CachedUBPathInsts[PathInst] = {}; + PI = CachedUBPathInsts.find(PathInst); + } + if (PI->first != CurrentInst && PI->second.size() != 0) { + // Use cached Expr along each path which has UB Insts, + // and cache the expanded Expr for the current working Phi + for (auto CE : PI->second) { + InstPred = LIC->getInst(Inst::And, 1, {CE, InstPred}); + CachedUBPathInsts[CurrentInst].push_back(InstPred); + Pred = LIC->getInst(Inst::And, 1, {Pred, InstPred}); + } + } + else { + CachedUBPathInsts[CurrentInst].push_back(InstPred); + Pred = LIC->getInst(Inst::And, 1, {Pred, InstPred}); + } + } + + return Pred; +} + +void ExprBuilder::recordUBInstruction(Inst *I, Inst *E) { +#if 0 + if (!IsForBlockPCUBInst) { + UBExprMap[I] = E; + } + else if (!UBInstPrecondition.isNull()) { + // The current UBInst comes from BlockPC. It's possible + // that the precondition is missing at this point (e.g., + // the corresponding Phi is not part of the current + // Souper IR because the Phi is not in the equivalence class + // of the instruction. + Inst *IsZero = LIC->getInst(Inst::Eq, 1, {UBInstPrecondition, LIC->getConst(APInt(1, false))}); + UBExprMap[I] = LIC->getInst(Inst::Or, 1, {IsZero, E}); + } +#endif +} + +ref ExprBuilder::getZeroBitsMapping(Inst *I) { return ZeroBitsMap[I]; } -Inst *ExprBuilder::getOneBitsMapping(Inst *I) { +ref ExprBuilder::getOneBitsMapping(Inst *I) { return OneBitsMap[I]; } -Inst *ExprBuilder::getNonZeroBitsMapping(Inst *I) { +ref ExprBuilder::getNonZeroBitsMapping(Inst *I) { return NonZeroBitsMap[I]; } -Inst *ExprBuilder::getNonNegBitsMapping(Inst *I) { +ref ExprBuilder::getNonNegBitsMapping(Inst *I) { return NonNegBitsMap[I]; } -Inst *ExprBuilder::getNegBitsMapping(Inst *I) { +ref ExprBuilder::getNegBitsMapping(Inst *I) { return NegBitsMap[I]; } -Inst *ExprBuilder::getPowerTwoBitsMapping(Inst *I) { +ref ExprBuilder::getPowerTwoBitsMapping(Inst *I) { return PowerTwoBitsMap[I]; } -Inst *ExprBuilder::getSignBitsMapping(Inst *I) { +ref ExprBuilder::getSignBitsMapping(Inst *I) { return SignBitsMap[I]; } +Inst *ExprBuilder::getInstMapping(const InstMapping &IM) { + return LIC->getInst(Inst::Eq, 1, {IM.LHS, IM.RHS}); +} + // TODO: Fix GetCandidateExprForReplacement std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index c98c8d844..a827460be 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -252,20 +252,6 @@ class KLEEBuilder : public ExprBuilder { return Count; } - void recordUBInstruction(Inst *I, ref E) override { - if (!IsForBlockPCUBInst) { - UBExprMap[I] = E; - } - else if (!UBInstPrecondition.isNull()) { - // The current UBInst comes from BlockPC. It's possible - // that the precondition is missing at this point (e.g., - // the corresponding Phi is not part of the current - // Souper IR because the Phi is not in the equivalence class - // of the instruction. - UBExprMap[I] = Expr::createImplies(UBInstPrecondition, E); - } - } - ref build(Inst *I) override { const std::vector &Ops = I->orderedOps(); switch (I->K) { @@ -280,7 +266,7 @@ class KLEEBuilder : public ExprBuilder { ref E = get(Ops[0]); // e.g. P2 ? (P1 ? Op1_Expr : Op2_Expr) : Op3_Expr for (unsigned J = 1; J < Ops.size(); ++J) { - E = SelectExpr::create(PredExpr[J-1], E, get(Ops[J])); + E = SelectExpr::create(get(PredExpr[J-1]), E, get(Ops[J])); } UBPathInsts.push_back(I); return E; @@ -289,51 +275,51 @@ class KLEEBuilder : public ExprBuilder { return buildAssoc(AddExpr::create, Ops); case Inst::AddNSW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, addnswUB(I)); + //recordUBInstruction(I, addnswUB(I)); return Add; } case Inst::AddNUW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, addnuwUB(I)); + //recordUBInstruction(I, addnuwUB(I)); return Add; } case Inst::AddNW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(addnswUB(I), addnuwUB(I))); + //recordUBInstruction(I, AndExpr::create(addnswUB(I), addnuwUB(I))); return Add; } case Inst::Sub: return SubExpr::create(get(Ops[0]), get(Ops[1])); case Inst::SubNSW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, subnswUB(I)); + //recordUBInstruction(I, subnswUB(I)); return Sub; } case Inst::SubNUW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, subnuwUB(I)); + //recordUBInstruction(I, subnuwUB(I)); return Sub; } case Inst::SubNW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(subnswUB(I), subnuwUB(I))); + //recordUBInstruction(I, AndExpr::create(subnswUB(I), subnuwUB(I))); return Sub; } case Inst::Mul: return buildAssoc(MulExpr::create, Ops); case Inst::MulNSW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, mulnswUB(I)); + //recordUBInstruction(I, mulnswUB(I)); return Mul; } case Inst::MulNUW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, mulnuwUB(I)); + //recordUBInstruction(I, mulnuwUB(I)); return Mul; } case Inst::MulNW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(mulnswUB(I), mulnuwUB(I))); + //recordUBInstruction(I, AndExpr::create(mulnswUB(I), mulnuwUB(I))); return Mul; } @@ -352,7 +338,7 @@ class KLEEBuilder : public ExprBuilder { // a constant zero. ref R = get(Ops[1]); if (R->isZero()) { - recordUBInstruction(I, klee::ConstantExpr::create(0, 1)); + //recordUBInstruction(I, klee::ConstantExpr::create(0, 1)); return klee::ConstantExpr::create(0, Ops[1]->Width); } @@ -362,32 +348,32 @@ class KLEEBuilder : public ExprBuilder { case Inst::UDiv: { ref Udiv = UDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, udivUB(I)); + //recordUBInstruction(I, udivUB(I)); return Udiv; } case Inst::SDiv: { ref Sdiv = SDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, sdivUB(I)); + //recordUBInstruction(I, sdivUB(I)); return Sdiv; } case Inst::UDivExact: { ref Udiv = UDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, AndExpr::create(udivUB(I), udivExactUB(I))); + //recordUBInstruction(I, AndExpr::create(udivUB(I), udivExactUB(I))); return Udiv; } case Inst::SDivExact: { ref Sdiv = SDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, AndExpr::create(sdivUB(I), sdivExactUB(I))); + //recordUBInstruction(I, AndExpr::create(sdivUB(I), sdivExactUB(I))); return Sdiv; } case Inst::URem: { ref Urem = URemExpr::create(get(Ops[0]), R); - recordUBInstruction(I, udivUB(I)); + //recordUBInstruction(I, udivUB(I)); return Urem; } case Inst::SRem: { ref Srem = SRemExpr::create(get(Ops[0]), R); - recordUBInstruction(I, sdivUB(I)); + //recordUBInstruction(I, sdivUB(I)); return Srem; } llvm_unreachable("unknown kind"); @@ -402,44 +388,44 @@ class KLEEBuilder : public ExprBuilder { return buildAssoc(XorExpr::create, Ops); case Inst::Shl: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, shiftUB(I)); + //recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::ShlNSW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(shiftUB(I), shlnswUB(I))); + //recordUBInstruction(I, AndExpr::create(shiftUB(I), shlnswUB(I))); return Result; } case Inst::ShlNUW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(shiftUB(I), shlnuwUB(I))); + //recordUBInstruction(I, AndExpr::create(shiftUB(I), shlnuwUB(I))); return Result; } case Inst::ShlNW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(shiftUB(I), - AndExpr::create(shlnswUB(I), - shlnuwUB(I)))); + //recordUBInstruction(I, AndExpr::create(shiftUB(I), + // AndExpr::create(shlnswUB(I), + // shlnuwUB(I)))); return Result; } case Inst::LShr: { ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, shiftUB(I)); + //recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::LShrExact: { ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(shiftUB(I), lshrExactUB(I))); + //recordUBInstruction(I, AndExpr::create(shiftUB(I), lshrExactUB(I))); return Result; } case Inst::AShr: { ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, shiftUB(I)); + //recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::AShrExact: { ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, AndExpr::create(shiftUB(I), ashrExactUB(I))); + //recordUBInstruction(I, AndExpr::create(shiftUB(I), ashrExactUB(I))); return Result; } case Inst::Select: @@ -551,253 +537,6 @@ class KLEEBuilder : public ExprBuilder { return E; } - ref getInstMapping(const InstMapping &IM) override { - return EqExpr::create(get(IM.LHS), get(IM.RHS)); - } - - ref createPathPred( - std::map &BlockConstraints, Inst* PathInst, - std::map *SelectBranches) override { - - ref Pred = klee::ConstantExpr::alloc(1, 1); - if (PathInst->K == Inst::Phi) { - unsigned Num = BlockConstraints[PathInst->B]; - const auto &PredExpr = BlockPredMap[PathInst->B]; - // Sanity checks - assert(PredExpr.size() && "there must be path predicates for the UBs"); - assert(PredExpr.size() == PathInst->Ops.size()-1 && - "phi predicate size mismatch"); - // Add the predicate(s) - if (Num == 0) - Pred = AndExpr::create(Pred, PredExpr[0]); - else - Pred = AndExpr::create(Pred, Expr::createIsZero(PredExpr[Num-1])); - for (unsigned B = Num; B < PredExpr.size(); ++B) - Pred = AndExpr::create(Pred, PredExpr[B]); - } - else if (PathInst->K == Inst::Select) { - ref SelectPred = get(PathInst->orderedOps()[0]); - assert(SelectBranches && "NULL SelectBranches?"); - auto SI = SelectBranches->find(PathInst); - // The current path doesn't have info about this select instruction. - if (SI == SelectBranches->end()) { - return Pred; - } - if (SI->second) - Pred = AndExpr::create(Pred, SelectPred); - else - Pred = AndExpr::create(Pred, Expr::createIsZero(SelectPred)); - } - else { - assert(0 && "cannot reach here"); - } - - return Pred; - } - - ref createUBPathInstsPred( - Inst *CurrentInst, std::vector &PathInsts, - std::map &BlockConstraints, - std::map *SelectBranches, UBPathInstMap &CachedUBPathInsts) override { - ref Pred = klee::ConstantExpr::alloc(1, 1); - for (const auto &PathInst : PathInsts) { - if (PathInst->Ops.size() == 1) - continue; - ref InstPred = - createPathPred(BlockConstraints, PathInst, SelectBranches); - - UBPathInstMap::iterator PI = CachedUBPathInsts.find(PathInst); - if (PI == CachedUBPathInsts.end()) { - // It's possible that we don't have a cached instruction yet, - // e.g., the CurrentInst is a select operator. - assert(CurrentInst->K == Inst::Select && "No cached Inst?"); - CachedUBPathInsts[PathInst] = {}; - PI = CachedUBPathInsts.find(PathInst); - } - if (PI->first != CurrentInst && PI->second.size() != 0) { - // Use cached Expr along each path which has UB Insts, - // and cache the expanded Expr for the current working Phi - for (auto CE : PI->second) { - InstPred = AndExpr::create(CE, InstPred); - CachedUBPathInsts[CurrentInst].push_back(InstPred); - Pred = AndExpr::create(Pred, InstPred); - } - } - else { - CachedUBPathInsts[CurrentInst].push_back(InstPred); - Pred = AndExpr::create(Pred, InstPred); - } - } - return Pred; - } - - // Collect UB Inst condition for each Phi instruction. - // The basic algorithm is: - // (1) for a given phi instruction, we first collect all paths that start - // from the phi. For each path, we also keep the the phi instructions - // along the path and the UB instructions associated with these phi - // instructions; - // (2) then for each path, we generate a corresponding KLEE expression - // based on the facts that we collected in step (1), including: - // * UB instructions; - // * Phi predicates; - // - // With the algorithm, it is easy to get into the path explosion problem, - // i.e., the number of paths is increased exponentially. Under some - // circumstances, e.g., the number of phis is too large, we will suffer - // with large performance overhead. In some extreme cases, we will fail - // to process some file due to the large memory footprint, i.e., `newing' - // too many UBPaths. Two tricks are used to relief the penalty of the - // path explosion problem: - // (1) caching the KLEE expresions for each processed phi, where each - // KLEE expression encodes the path that starts from one of the phi's - // values. For example, when processing a sample souper IR below - // - // %0 = block - // %1 = block - // %2:i32 = var - // %3:i32 = shl 0:i32, %2 - // %4:i32 = var - // %5:i32 = shl 0:i32, %4 - // %6 = var - // %11:i32 = phi %1, %3, %5 - // %12:i32 = phi %0, %6, %11 - // - // we first encounter phi %11. The generated KLEE expression - // for this phi encodes two paths, i.e., %3 and %5. We cache - // these two into CachedUBPathInsts. Then we move to process phi %12. - // At this point, rather than recursively re-contruct %11 (through - // %12's value), we just re-used the cached path-expressions. - // For each path-expression, we append it with %12's own predicate - // and also cache them with %12 for future use. After finishing - // %12, we will have three entries for phi %12. - // (2) The first trick increases the performance, but we still suffer - // with large memory consumption, i.e., it's easy to cache too - // many paths. The second trick is to reduce the memory footprint - // by only caching "useful" path that has UB Insts. For example, - // in the example in (1), for phi %12, we don't need to cache - // the path starting from %6, because this path doesn't have any - // UB Insts. - // - // These tricks basically relies on the dependency chain of instructions - // generated by souper. For example, if we say %12 depends on %11, then - // %12 would never appear earlier than %11. - ref getUBInstCondition() override { - - // A map from a Phi instruction to all of its KLEE expressions that - // encode the path and UB Inst predicates. - UBPathInstMap CachedUBPathInsts; - std::set UsedUBInsts; - ref Result = klee::ConstantExpr::create(1, Expr::Bool); - // For each Phi/Select instruction - for (const auto &I : UBPathInsts) { - if (CachedUBPathInsts.count(I) != 0) - continue; - // Recursively collect UB instructions - // on the block constrained Phi and Select branches - std::vector> UBPaths; - UBPath *Current = new UBPath; - UBPaths.push_back(std::move(std::unique_ptr(Current))); - if (!getUBPaths(I, Current, UBPaths, CachedUBPathInsts, 0)) - return ref(); - CachedUBPathInsts[I] = {}; - // For each found path - for (const auto &Path : UBPaths) { - if (!Path->UBInsts.size()) - continue; - // Aggregate collected UB constraints - ref Ante = klee::ConstantExpr::alloc(1, 1); - for (const auto &I : Path->UBInsts) { - auto Iter = UBExprMap.find(I); - // It's possible that the instruction I is not in the map. - // For example, it may come from a blockpc which doesn't - // have any preconditions. - if (Iter != UBExprMap.end()) - Ante = AndExpr::create(Ante, Iter->second); - UsedUBInsts.insert(I); - } - // Create path predicate - ref Pred = - createUBPathInstsPred(I, Path->Insts, Path->BlockConstraints, - &Path->SelectBranches, CachedUBPathInsts); - // Add predicate->UB constraint - Result = AndExpr::create(Result, Expr::createImplies(Pred, Ante)); - } - } - // Add the unconditional UB constraints at the top level - for (const auto &Entry: UBExprMap) - if (!UsedUBInsts.count(Entry.first)) - Result = AndExpr::create(Result, Entry.second); - return Result; - } - - void setBlockPCMap(const BlockPCs &BPCs) override { - for (auto BPC : BPCs) { - assert(BPC.B && "Block is NULL!"); - BlockPCPredMap &PCMap = BlockPCMap[BPC.B]; - auto I = PCMap.find(BPC.PredIdx); - // Relying on a class-level flag may not be a nice solution, - // but it seems hard to differentiate two cases: - // (1) UBInstExpr collected through blockpc, and; - // (2) UBInstExpr collected through pc/lhs/rhs - // For the first case, UBInst(s) is conditional, i.e., - // they rely on the fact that blockpc(s) are true. - if (I != PCMap.end()) { - UBInstPrecondition = I->second; - } - IsForBlockPCUBInst = true; - ref PE = getInstMapping(BPC.PC); - IsForBlockPCUBInst = false; - UBInstPrecondition = nullptr; - if (I == PCMap.end()) { - PCMap[BPC.PredIdx] = PE; - } - else { - PCMap[BPC.PredIdx] = AndExpr::create(I->second, PE); - } - } - } - - // Similar to the way we collect UB constraints. We could combine it with - // getUBInstCondition, because the workflow is quite similar. - // However, mixing two parts (one for UB constraints, one for BlockPCs) - // may make the code less structured. If we see big performance overhead, - // we may consider to combine these two parts together. - ref getBlockPCs() override { - - UBPathInstMap CachedPhis; - ref Result = klee::ConstantExpr::create(1, Expr::Bool); - // For each Phi instruction - for (const auto &I : UBPathInsts) { - if (CachedPhis.count(I) != 0) - continue; - // Recursively collect BlockPCs - std::vector> BlockPCPhiPaths; - BlockPCPhiPath *Current = new BlockPCPhiPath; - BlockPCPhiPaths.push_back( - std::move(std::unique_ptr(Current))); - getBlockPCPhiPaths(I, Current, BlockPCPhiPaths, CachedPhis); - CachedPhis[I] = {}; - // For each found path - for (const auto &Path : BlockPCPhiPaths) { - if (!Path->PCs.size()) - continue; - // Aggregate collected BlockPC constraints - ref Ante = klee::ConstantExpr::alloc(1, 1); - for (const auto &PC : Path->PCs) { - Ante = AndExpr::create(Ante, PC); - } - // Create path predicate - ref Pred = - createUBPathInstsPred(I, Path->Phis, Path->BlockConstraints, - /*SelectBranches=*/nullptr, CachedPhis); - // Add predicate->UB constraint - Result = AndExpr::create(Result, Expr::createImplies(Pred, Ante)); - } - } - return Result; - } - // Return an expression which must be proven valid for the candidate to apply. llvm::Optional GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, @@ -811,34 +550,34 @@ class KLEEBuilder : public ExprBuilder { for (const auto I : CE.ArrayVars) { if (I) { if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) { - Ante = AndExpr::create(Ante, get(getZeroBitsMapping(I))); - Ante = AndExpr::create(Ante, get(getOneBitsMapping(I))); + Ante = AndExpr::create(Ante, getZeroBitsMapping(I)); + Ante = AndExpr::create(Ante, getOneBitsMapping(I)); } if (I->NonZero) - Ante = AndExpr::create(Ante, get(getNonZeroBitsMapping(I))); + Ante = AndExpr::create(Ante, getNonZeroBitsMapping(I)); if (I->NonNegative) - Ante = AndExpr::create(Ante, get(getNonNegBitsMapping(I))); + Ante = AndExpr::create(Ante, getNonNegBitsMapping(I)); if (I->PowOfTwo) - Ante = AndExpr::create(Ante, get(getPowerTwoBitsMapping(I))); + Ante = AndExpr::create(Ante, getPowerTwoBitsMapping(I)); if (I->Negative) - Ante = AndExpr::create(Ante, get(getNegBitsMapping(I))); + Ante = AndExpr::create(Ante, getNegBitsMapping(I)); if (I->NumSignBits > 1) - Ante = AndExpr::create(Ante, get(getSignBitsMapping(I))); + Ante = AndExpr::create(Ante, getSignBitsMapping(I)); } } // Build PCs for (const auto &PC : PCs) { - Ante = AndExpr::create(Ante, getInstMapping(PC)); + Ante = AndExpr::create(Ante, get(getInstMapping(PC))); } // Build BPCs if (BPCs.size()) { setBlockPCMap(BPCs); - Ante = AndExpr::create(Ante, getBlockPCs()); + Ante = AndExpr::create(Ante, get(getBlockPCs())); } // Get UB constraints of LHS and (B)PCs ref LHSPCsUB = klee::ConstantExpr::create(1, Expr::Bool); if (ExploitUB) { - LHSPCsUB = getUBInstCondition(); + LHSPCsUB = get(getUBInstCondition()); if (LHSPCsUB.isNull()) return llvm::Optional(); } @@ -849,7 +588,7 @@ class KLEEBuilder : public ExprBuilder { // Get all UB constraints (LHS && (B)PCs && RHS) ref UB = klee::ConstantExpr::create(1, Expr::Bool); if (ExploitUB) { - UB = getUBInstCondition(); + UB = get(getUBInstCondition()); if (UB.isNull()) return llvm::Optional(); } diff --git a/tools/souper-check.cpp b/tools/souper-check.cpp index 4f3fa3aba..e1a06c037 100644 --- a/tools/souper-check.cpp +++ b/tools/souper-check.cpp @@ -127,7 +127,7 @@ int SolveInst(const MemoryBufferRef &MB, Solver *S) { } else { bool Valid; std::vector> Models; - if (std::error_code EC = S->isValid(Rep.BPCs, Rep.PCs, + if (std::error_code EC = S->isValid(IC, Rep.BPCs, Rep.PCs, Rep.Mapping, Valid, &Models)) { llvm::errs() << EC.message() << '\n'; Ret = 1; diff --git a/tools/souperweb-backend.cpp b/tools/souperweb-backend.cpp index 3afc1fed8..f5803e9c5 100644 --- a/tools/souperweb-backend.cpp +++ b/tools/souperweb-backend.cpp @@ -61,7 +61,7 @@ void SolveInst(std::unique_ptr MB, Solver *S) { bool Valid; std::vector> Models; - if (std::error_code EC = S->isValid(Rep.BPCs, Rep.PCs, + if (std::error_code EC = S->isValid(IC, Rep.BPCs, Rep.PCs, Rep.Mapping, Valid, &Models)) { llvm::errs() << EC.message() << '\n'; return; From 8e9277f6e4401048cf052fac9047ee6f955e2c29 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Thu, 22 Feb 2018 22:52:55 +0100 Subject: [PATCH 08/49] Work --- include/souper/Extractor/ExprBuilder.h | 63 ++++------- lib/Extractor/ExprBuilder.cpp | 106 ++++++++++++++---- lib/Extractor/KLEEBuilder.cpp | 142 +++++++------------------ 3 files changed, 147 insertions(+), 164 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index acdbca9a2..f8776336f 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -55,16 +55,13 @@ class ExprBuilder { virtual ~ExprBuilder(); - ref buildAssoc(std::function(ref, ref)> F, - llvm::ArrayRef Ops); - - ref getZeroBitsMapping(Inst *I); - ref getOneBitsMapping(Inst *I); - ref getNonZeroBitsMapping(Inst *I); - ref getNonNegBitsMapping(Inst *I); - ref getPowerTwoBitsMapping(Inst *I); - ref getNegBitsMapping(Inst *I); - ref getSignBitsMapping(Inst *I); + Inst *getZeroBitsMapping(Inst *I); + Inst *getOneBitsMapping(Inst *I); + Inst *getNonZeroBitsMapping(Inst *I); + Inst *getNonNegBitsMapping(Inst *I); + Inst *getPowerTwoBitsMapping(Inst *I); + Inst *getNegBitsMapping(Inst *I); + Inst *getSignBitsMapping(Inst *I); std::vector getBlockPredicates(Inst *I); bool getUBPaths(Inst *I, UBPath *Current, @@ -90,16 +87,15 @@ class ExprBuilder { std::map> BlockPredMap; - std::map> ExprMap; std::map UBExprMap; - std::map> ZeroBitsMap; - std::map> OneBitsMap; - std::map> NonZeroBitsMap; - std::map> NonNegBitsMap; - std::map> PowerTwoBitsMap; - std::map> NegBitsMap; - std::map> SignBitsMap; + std::map ZeroBitsMap; + std::map OneBitsMap; + std::map NonZeroBitsMap; + std::map NonNegBitsMap; + std::map PowerTwoBitsMap; + std::map NegBitsMap; + std::map SignBitsMap; std::map BlockPCMap; std::vector UBPathInsts; @@ -111,39 +107,18 @@ class ExprBuilder { struct CandidateExpr { std::vector> Arrays; - std::vector ArrayVars; - ref E; + std::vector Vars; + Inst *E; }; CandidateExpr CE; - virtual llvm::Optional GetCandidateExprForReplacement( + + llvm::Optional GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, - InstMapping Mapping, bool Negate) = 0; + InstMapping Mapping, bool Negate); virtual std::string BuildQuery(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate=false) = 0; - -protected: - virtual ref addnswUB(Inst *I) = 0; - virtual ref addnuwUB(Inst *I) = 0; - virtual ref subnswUB(Inst *I) = 0; - virtual ref subnuwUB(Inst *I) = 0; - virtual ref mulnswUB(Inst *I) = 0; - virtual ref mulnuwUB(Inst *I) = 0; - virtual ref udivUB(Inst *I) = 0; - virtual ref udivExactUB(Inst *I) = 0; - virtual ref sdivUB(Inst *I) = 0; - virtual ref sdivExactUB(Inst *I) = 0; - virtual ref shiftUB(Inst *I) = 0; - virtual ref shlnswUB(Inst *I) = 0; - virtual ref shlnuwUB(Inst *I) = 0; - virtual ref lshrExactUB(Inst *I) = 0; - virtual ref ashrExactUB(Inst *I) = 0; - virtual ref countOnes(ref E) = 0; - - virtual ref build(Inst *I) = 0; - virtual ref get(Inst *I) = 0; - }; std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 2493d86bf..5b5af5d46 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -15,6 +15,11 @@ #include "llvm/Support/CommandLine.h" #include "souper/Extractor/ExprBuilder.h" +static llvm::cl::opt ExploitUB( + "souper-exploit-ub", + llvm::cl::desc("Exploit undefined behavior (default=true)"), + llvm::cl::init(true)); + using namespace llvm; using namespace souper; @@ -32,16 +37,6 @@ static llvm::cl::opt SMTExprBuilder( namespace souper { -ref ExprBuilder::buildAssoc( - std::function(ref, ref)> F, - llvm::ArrayRef Ops) { - ref E = get(Ops[0]); - for (Inst *I : llvm::ArrayRef(Ops.data()+1, Ops.size()-1)) { - E = F(E, get(I)); - } - return E; -} - std::vector ExprBuilder::getBlockPredicates(Inst *I) { assert(I->K == Inst::Phi && "not a phi inst"); if (BlockPredMap.count(I->B)) @@ -467,31 +462,31 @@ void ExprBuilder::recordUBInstruction(Inst *I, Inst *E) { #endif } -ref ExprBuilder::getZeroBitsMapping(Inst *I) { +Inst *ExprBuilder::getZeroBitsMapping(Inst *I) { return ZeroBitsMap[I]; } -ref ExprBuilder::getOneBitsMapping(Inst *I) { +Inst *ExprBuilder::getOneBitsMapping(Inst *I) { return OneBitsMap[I]; } -ref ExprBuilder::getNonZeroBitsMapping(Inst *I) { +Inst *ExprBuilder::getNonZeroBitsMapping(Inst *I) { return NonZeroBitsMap[I]; } -ref ExprBuilder::getNonNegBitsMapping(Inst *I) { +Inst *ExprBuilder::getNonNegBitsMapping(Inst *I) { return NonNegBitsMap[I]; } -ref ExprBuilder::getNegBitsMapping(Inst *I) { +Inst *ExprBuilder::getNegBitsMapping(Inst *I) { return NegBitsMap[I]; } -ref ExprBuilder::getPowerTwoBitsMapping(Inst *I) { +Inst *ExprBuilder::getPowerTwoBitsMapping(Inst *I) { return PowerTwoBitsMap[I]; } -ref ExprBuilder::getSignBitsMapping(Inst *I) { +Inst *ExprBuilder::getSignBitsMapping(Inst *I) { return SignBitsMap[I]; } @@ -499,7 +494,82 @@ Inst *ExprBuilder::getInstMapping(const InstMapping &IM) { return LIC->getInst(Inst::Eq, 1, {IM.LHS, IM.RHS}); } -// TODO: Fix GetCandidateExprForReplacement +// Return an expression which must be proven valid for the candidate to apply. +llvm::Optional ExprBuilder::GetCandidateExprForReplacement( + const BlockPCs &BPCs, const std::vector &PCs, + InstMapping Mapping, bool Negate) { + // Build LHS + Inst *LHS = Mapping.LHS; + Inst *Ante = LIC->getConst(APInt(1, true)); + llvm::APInt DemandedBits = Mapping.LHS->DemandedBits; + if (!DemandedBits.isAllOnesValue()) + LHS = LIC->getInst(Inst::And, LHS->Width, + {LHS, LIC->getConst(DemandedBits)}); + for (const auto I : CE.Vars) { + if (I) { + if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) { + Ante = LIC->getInst(Inst::And, 1, {Ante, getZeroBitsMapping(I)}); + Ante = LIC->getInst(Inst::And, 1, {Ante, getOneBitsMapping(I)}); + } + if (I->NonZero) + Ante = LIC->getInst(Inst::And, 1, {Ante, getNonZeroBitsMapping(I)}); + if (I->NonNegative) + Ante = LIC->getInst(Inst::And, 1, {Ante, getNonNegBitsMapping(I)}); + if (I->PowOfTwo) + Ante = LIC->getInst(Inst::And, 1, {Ante, getPowerTwoBitsMapping(I)}); + if (I->Negative) + Ante = LIC->getInst(Inst::And, 1, {Ante, getNegBitsMapping(I)}); + if (I->NumSignBits > 1) + Ante = LIC->getInst(Inst::And, 1, {Ante, getSignBitsMapping(I)}); + } + } + // Build PCs + for (const auto &PC : PCs) + Ante = LIC->getInst(Inst::And, 1, {Ante, getInstMapping(PC)}); + // Build BPCs + if (BPCs.size()) { + setBlockPCMap(BPCs); + Ante = LIC->getInst(Inst::And, 1, {Ante, getBlockPCs()}); + } + // Get UB constraints of LHS and (B)PCs + Inst *LHSPCsUB = LIC->getConst(APInt(1, true)); + if (ExploitUB) { + LHSPCsUB = getUBInstCondition(); + //TODO + //if (LHSPCsUB.isNull()) + // return llvm::Optional(); + } + // Build RHS + Inst *RHS = Mapping.RHS; + if (!DemandedBits.isAllOnesValue()) + RHS = LIC->getInst(Inst::And, RHS->Width, + {RHS, LIC->getConst(DemandedBits)}); + // Get all UB constraints (LHS && (B)PCs && RHS) + Inst *UB = LIC->getConst(APInt(1, true)); + if (ExploitUB) { + UB = getUBInstCondition(); + //TODO + //if (UB.isNull()) + // return llvm::Optional(); + } + + Inst *Cons; + if (Negate) // (LHS != RHS) + Cons = LIC->getInst(Inst::Ne, 1, {LHS, RHS}); + else // (LHS == RHS) + Cons = LIC->getInst(Inst::Eq, 1, {LHS, RHS}); + // Cons && UB + if (Mapping.RHS->K != Inst::Const) + Cons = LIC->getInst(Inst::And, Cons->Width, {Cons, UB}); + // (LHS UB && (B)PCs && (B)PCs UB) + Ante = LIC->getInst(Inst::And, 1, {Ante, LHSPCsUB}); + // (LHS UB && (B)PCs && (B)PCs UB) => Cons && UB + Inst *IsZero = LIC->getInst(Inst::Eq, 1, + {Ante, LIC->getConst(APInt(1, false))}); + CE.E = LIC->getInst(Inst::Or, 1, {IsZero, Cons}); + + return llvm::Optional(std::move(CE)); +} std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index a827460be..df2c90b1d 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -38,10 +38,6 @@ static llvm::cl::opt DumpKLEEExprs( "dump-klee-exprs", llvm::cl::desc("Dump KLEE expressions after SMTLIB queries"), llvm::cl::init(false)); -static llvm::cl::opt ExploitUB( - "souper-exploit-ub", - llvm::cl::desc("Exploit undefined behavior (default=true)"), - llvm::cl::init(true)); using namespace llvm; using namespace klee; @@ -56,6 +52,9 @@ class KLEEBuilder : public ExprBuilder { } ~KLEEBuilder() {} + //TODO + std::map> ExprMap; + std::string BuildQuery(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, @@ -68,16 +67,17 @@ class KLEEBuilder : public ExprBuilder { if (!OptionalCE.hasValue()) return std::string(); CandidateExpr CE = std::move(OptionalCE.getValue()); - Query KQuery(Manager, CE.E); + ref E = get(CE.E); + Query KQuery(Manager, E); ExprSMTLIBPrinter Printer; Printer.setOutput(SMTSS); Printer.setQuery(KQuery); std::vector Arrays; if (ModelVars) { - for (unsigned I = 0; I != CE.ArrayVars.size(); ++I) { - if (CE.ArrayVars[I]) { + for (unsigned I = 0; I != CE.Vars.size(); ++I) { + if (CE.Vars[I]) { Arrays.push_back(CE.Arrays[I].get()); - ModelVars->push_back(CE.ArrayVars[I]); + ModelVars->push_back(CE.Vars[I]); } } Printer.setArrayValuesToGet(Arrays); @@ -88,8 +88,8 @@ class KLEEBuilder : public ExprBuilder { SMTSS << "; KLEE expression:\n; "; std::unique_ptr PP(ExprPPrinter::create(SMTSS)); PP->setForceNoLineBreaks(true); - PP->scan(CE.E); - PP->print(CE.E); + PP->scan(E); + PP->print(E); SMTSS << '\n'; } @@ -97,7 +97,7 @@ class KLEEBuilder : public ExprBuilder { } private: - ref addnswUB(Inst *I) override { + ref addnswUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Add = AddExpr::create(L, R); @@ -109,7 +109,7 @@ class KLEEBuilder : public ExprBuilder { EqExpr::create(LMSB, AddMSB)); } - ref addnuwUB(Inst *I) override { + ref addnuwUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); Expr::Width Width = L->getWidth(); @@ -120,7 +120,7 @@ class KLEEBuilder : public ExprBuilder { return Expr::createIsZero(AddMSB); } - ref subnswUB(Inst *I) override { + ref subnswUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Sub = SubExpr::create(L, R); @@ -132,7 +132,7 @@ class KLEEBuilder : public ExprBuilder { EqExpr::create(LMSB, SubMSB)); } - ref subnuwUB(Inst *I) override { + ref subnuwUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); Expr::Width Width = L->getWidth(); @@ -143,7 +143,7 @@ class KLEEBuilder : public ExprBuilder { return Expr::createIsZero(SubMSB); } - ref mulnswUB(Inst *I) override { + ref mulnswUB(Inst *I) { const std::vector &Ops = I->orderedOps(); // The computation below has to be performed on the operands of // multiplication instruction. The instruction using mulnswUB() @@ -158,7 +158,7 @@ class KLEEBuilder : public ExprBuilder { return EqExpr::create(Mul, LowerBitsExt); } - ref mulnuwUB(Inst *I) override { + ref mulnuwUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); Expr::Width Width = L->getWidth(); @@ -169,20 +169,20 @@ class KLEEBuilder : public ExprBuilder { return Expr::createIsZero(HigherBits); } - ref udivUB(Inst *I) override { + ref udivUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref R = get(Ops[1]); return NeExpr::create(R, klee::ConstantExpr::create(0, R->getWidth())); } - ref udivExactUB(Inst *I) override { + ref udivExactUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Udiv = UDivExpr::create(L, R); return EqExpr::create(L, MulExpr::create(R, Udiv)); } - ref sdivUB(Inst *I) override { + ref sdivUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref ShiftBy = klee::ConstantExpr::create(L->getWidth()-1, @@ -195,21 +195,21 @@ class KLEEBuilder : public ExprBuilder { NeExpr::create(L, IntMin), NeExpr::create(R, NegOne))); } - ref sdivExactUB(Inst *I) override { + ref sdivExactUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Sdiv = SDivExpr::create(L, R); return EqExpr::create(L, MulExpr::create(R, Sdiv)); } - ref shiftUB(Inst *I) override { + ref shiftUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Lwidth = klee::ConstantExpr::create(L->getWidth(), L->getWidth()); return UltExpr::create(R, Lwidth); } - ref shlnswUB(Inst *I) override { + ref shlnswUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = ShlExpr::create(L, R); @@ -217,7 +217,7 @@ class KLEEBuilder : public ExprBuilder { return EqExpr::create(RShift, L); } - ref shlnuwUB(Inst *I) override { + ref shlnuwUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = ShlExpr::create(L, R); @@ -225,7 +225,7 @@ class KLEEBuilder : public ExprBuilder { return EqExpr::create(RShift, L); } - ref lshrExactUB(Inst *I) override { + ref lshrExactUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = LShrExpr::create(L, R); @@ -233,7 +233,7 @@ class KLEEBuilder : public ExprBuilder { return EqExpr::create(LShift, L); } - ref ashrExactUB(Inst *I) override { + ref ashrExactUB(Inst *I) { const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Result = AShrExpr::create(L, R); @@ -241,7 +241,7 @@ class KLEEBuilder : public ExprBuilder { return EqExpr::create(LShift, L); } - ref countOnes(ref L) override { + ref countOnes(ref L) { Expr::Width Width = L->getWidth(); ref Count = klee::ConstantExpr::alloc(llvm::APInt(Width, 0)); for (unsigned i=0; i build(Inst *I) override { + + ref buildAssoc( + std::function(ref, ref)> F, + llvm::ArrayRef Ops) { + ref E = get(Ops[0]); + for (Inst *I : llvm::ArrayRef(Ops.data()+1, Ops.size()-1)) { + E = F(E, get(I)); + } + return E; + } + + ref build(Inst *I) { const std::vector &Ops = I->orderedOps(); switch (I->K) { case Inst::UntypedConst: @@ -528,7 +538,7 @@ class KLEEBuilder : public ExprBuilder { llvm_unreachable("unknown kind"); } - ref get(Inst *I) override { + ref get(Inst *I) { ref &E = ExprMap[I]; if (E.isNull()) { E = build(I); @@ -537,78 +547,6 @@ class KLEEBuilder : public ExprBuilder { return E; } - // Return an expression which must be proven valid for the candidate to apply. - llvm::Optional GetCandidateExprForReplacement( - const BlockPCs &BPCs, const std::vector &PCs, - InstMapping Mapping, bool Negate) override { - // Build LHS - ref LHS = get(Mapping.LHS); - ref Ante = klee::ConstantExpr::alloc(1, 1); - ref DemandedBits = klee::ConstantExpr::alloc(Mapping.LHS->DemandedBits); - if (!Mapping.LHS->DemandedBits.isAllOnesValue()) - LHS = AndExpr::create(LHS, DemandedBits); - for (const auto I : CE.ArrayVars) { - if (I) { - if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) { - Ante = AndExpr::create(Ante, getZeroBitsMapping(I)); - Ante = AndExpr::create(Ante, getOneBitsMapping(I)); - } - if (I->NonZero) - Ante = AndExpr::create(Ante, getNonZeroBitsMapping(I)); - if (I->NonNegative) - Ante = AndExpr::create(Ante, getNonNegBitsMapping(I)); - if (I->PowOfTwo) - Ante = AndExpr::create(Ante, getPowerTwoBitsMapping(I)); - if (I->Negative) - Ante = AndExpr::create(Ante, getNegBitsMapping(I)); - if (I->NumSignBits > 1) - Ante = AndExpr::create(Ante, getSignBitsMapping(I)); - } - } - // Build PCs - for (const auto &PC : PCs) { - Ante = AndExpr::create(Ante, get(getInstMapping(PC))); - } - // Build BPCs - if (BPCs.size()) { - setBlockPCMap(BPCs); - Ante = AndExpr::create(Ante, get(getBlockPCs())); - } - // Get UB constraints of LHS and (B)PCs - ref LHSPCsUB = klee::ConstantExpr::create(1, Expr::Bool); - if (ExploitUB) { - LHSPCsUB = get(getUBInstCondition()); - if (LHSPCsUB.isNull()) - return llvm::Optional(); - } - // Build RHS - ref RHS = get(Mapping.RHS); - if (!Mapping.LHS->DemandedBits.isAllOnesValue()) - RHS = AndExpr::create(RHS, DemandedBits); - // Get all UB constraints (LHS && (B)PCs && RHS) - ref UB = klee::ConstantExpr::create(1, Expr::Bool); - if (ExploitUB) { - UB = get(getUBInstCondition()); - if (UB.isNull()) - return llvm::Optional(); - } - - ref Cons; - if (Negate) // (LHS != RHS) - Cons = NeExpr::create(LHS, RHS); - else // (LHS == RHS) - Cons = EqExpr::create(LHS, RHS); - // Cons && UB - if (Mapping.RHS->K != Inst::Const) - Cons = AndExpr::create(Cons, UB); - // (LHS UB && (B)PCs && (B)PCs UB) - Ante = AndExpr::create(Ante, LHSPCsUB); - // (LHS UB && (B)PCs && (B)PCs UB) => Cons && UB - CE.E = Expr::createImplies(Ante, Cons); - - return llvm::Optional(std::move(CE)); - } - ref makeSizedArrayRead(unsigned Width, StringRef Name, Inst *Origin) { std::string NameStr; if (Name.empty()) @@ -619,7 +557,7 @@ class KLEEBuilder : public ExprBuilder { NameStr = Name; CE.Arrays.emplace_back( new Array(ArrayNames.makeName(NameStr), 1, 0, 0, Expr::Int32, Width)); - CE.ArrayVars.push_back(Origin); + CE.Vars.push_back(Origin); std::vector ZeroBits, OneBits; UpdateList UL(CE.Arrays.back().get(), 0); From 5490e6620067cf62c2c07d482831acb689746e09 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Fri, 23 Feb 2018 20:47:42 +0100 Subject: [PATCH 09/49] Work --- include/souper/Extractor/ExprBuilder.h | 6 +- lib/Extractor/ExprBuilder.cpp | 82 ------------------------ lib/Extractor/KLEEBuilder.cpp | 87 +++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 87 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index f8776336f..0863749a7 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -108,13 +108,13 @@ class ExprBuilder { struct CandidateExpr { std::vector> Arrays; std::vector Vars; - Inst *E; + ref E; }; CandidateExpr CE; - llvm::Optional GetCandidateExprForReplacement( + virtual llvm::Optional GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, - InstMapping Mapping, bool Negate); + InstMapping Mapping, bool Negate) = 0; virtual std::string BuildQuery(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 5b5af5d46..dbbc0c3a9 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -15,11 +15,6 @@ #include "llvm/Support/CommandLine.h" #include "souper/Extractor/ExprBuilder.h" -static llvm::cl::opt ExploitUB( - "souper-exploit-ub", - llvm::cl::desc("Exploit undefined behavior (default=true)"), - llvm::cl::init(true)); - using namespace llvm; using namespace souper; @@ -494,83 +489,6 @@ Inst *ExprBuilder::getInstMapping(const InstMapping &IM) { return LIC->getInst(Inst::Eq, 1, {IM.LHS, IM.RHS}); } -// Return an expression which must be proven valid for the candidate to apply. -llvm::Optional ExprBuilder::GetCandidateExprForReplacement( - const BlockPCs &BPCs, const std::vector &PCs, - InstMapping Mapping, bool Negate) { - // Build LHS - Inst *LHS = Mapping.LHS; - Inst *Ante = LIC->getConst(APInt(1, true)); - llvm::APInt DemandedBits = Mapping.LHS->DemandedBits; - if (!DemandedBits.isAllOnesValue()) - LHS = LIC->getInst(Inst::And, LHS->Width, - {LHS, LIC->getConst(DemandedBits)}); - for (const auto I : CE.Vars) { - if (I) { - if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) { - Ante = LIC->getInst(Inst::And, 1, {Ante, getZeroBitsMapping(I)}); - Ante = LIC->getInst(Inst::And, 1, {Ante, getOneBitsMapping(I)}); - } - if (I->NonZero) - Ante = LIC->getInst(Inst::And, 1, {Ante, getNonZeroBitsMapping(I)}); - if (I->NonNegative) - Ante = LIC->getInst(Inst::And, 1, {Ante, getNonNegBitsMapping(I)}); - if (I->PowOfTwo) - Ante = LIC->getInst(Inst::And, 1, {Ante, getPowerTwoBitsMapping(I)}); - if (I->Negative) - Ante = LIC->getInst(Inst::And, 1, {Ante, getNegBitsMapping(I)}); - if (I->NumSignBits > 1) - Ante = LIC->getInst(Inst::And, 1, {Ante, getSignBitsMapping(I)}); - } - } - // Build PCs - for (const auto &PC : PCs) - Ante = LIC->getInst(Inst::And, 1, {Ante, getInstMapping(PC)}); - // Build BPCs - if (BPCs.size()) { - setBlockPCMap(BPCs); - Ante = LIC->getInst(Inst::And, 1, {Ante, getBlockPCs()}); - } - // Get UB constraints of LHS and (B)PCs - Inst *LHSPCsUB = LIC->getConst(APInt(1, true)); - if (ExploitUB) { - LHSPCsUB = getUBInstCondition(); - //TODO - //if (LHSPCsUB.isNull()) - // return llvm::Optional(); - } - // Build RHS - Inst *RHS = Mapping.RHS; - if (!DemandedBits.isAllOnesValue()) - RHS = LIC->getInst(Inst::And, RHS->Width, - {RHS, LIC->getConst(DemandedBits)}); - // Get all UB constraints (LHS && (B)PCs && RHS) - Inst *UB = LIC->getConst(APInt(1, true)); - if (ExploitUB) { - UB = getUBInstCondition(); - //TODO - //if (UB.isNull()) - // return llvm::Optional(); - } - - Inst *Cons; - if (Negate) // (LHS != RHS) - Cons = LIC->getInst(Inst::Ne, 1, {LHS, RHS}); - else // (LHS == RHS) - Cons = LIC->getInst(Inst::Eq, 1, {LHS, RHS}); - // Cons && UB - if (Mapping.RHS->K != Inst::Const) - Cons = LIC->getInst(Inst::And, Cons->Width, {Cons, UB}); - // (LHS UB && (B)PCs && (B)PCs UB) - Ante = LIC->getInst(Inst::And, 1, {Ante, LHSPCsUB}); - // (LHS UB && (B)PCs && (B)PCs UB) => Cons && UB - Inst *IsZero = LIC->getInst(Inst::Eq, 1, - {Ante, LIC->getConst(APInt(1, false))}); - CE.E = LIC->getInst(Inst::Or, 1, {IsZero, Cons}); - - return llvm::Optional(std::move(CE)); -} - std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate) { diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index df2c90b1d..eefa1c245 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -34,6 +34,10 @@ #include #include +static llvm::cl::opt ExploitUB( + "souper-exploit-ub", + llvm::cl::desc("Exploit undefined behavior (default=true)"), + llvm::cl::init(true)); static llvm::cl::opt DumpKLEEExprs( "dump-klee-exprs", llvm::cl::desc("Dump KLEE expressions after SMTLIB queries"), @@ -55,6 +59,83 @@ class KLEEBuilder : public ExprBuilder { //TODO std::map> ExprMap; + // Return an expression which must be proven valid for the candidate to apply. + llvm::Optional GetCandidateExprForReplacement( + const BlockPCs &BPCs, const std::vector &PCs, + InstMapping Mapping, bool Negate) override { + + // Build LHS + ref LHS = get(Mapping.LHS); + ref Ante = klee::ConstantExpr::alloc(1, 1); +#if 0 + ref DemandedBits = klee::ConstantExpr::alloc(Mapping.LHS->DemandedBits); + if (!Mapping.LHS->DemandedBits.isAllOnesValue()) + LHS = AndExpr::create(LHS, DemandedBits); + for (const auto I : CE.ArrayVars) { + if (I) { + if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) { + Ante = AndExpr::create(Ante, getZeroBitsMapping(I)); + Ante = AndExpr::create(Ante, getOneBitsMapping(I)); + } + if (I->NonZero) + Ante = AndExpr::create(Ante, getNonZeroBitsMapping(I)); + if (I->NonNegative) + Ante = AndExpr::create(Ante, getNonNegBitsMapping(I)); + if (I->PowOfTwo) + Ante = AndExpr::create(Ante, getPowerTwoBitsMapping(I)); + if (I->Negative) + Ante = AndExpr::create(Ante, getNegBitsMapping(I)); + if (I->NumSignBits > 1) + Ante = AndExpr::create(Ante, getSignBitsMapping(I)); + } + } +#endif + // Build PCs + for (const auto &PC : PCs) { + Ante = AndExpr::create(Ante, get(getInstMapping(PC))); + } + // Build BPCs + if (BPCs.size()) { + setBlockPCMap(BPCs); + Ante = AndExpr::create(Ante, get(getBlockPCs())); + } + // Get UB constraints of LHS and (B)PCs + ref LHSPCsUB = klee::ConstantExpr::create(1, Expr::Bool); + if (ExploitUB) { + LHSPCsUB = get(getUBInstCondition()); + if (LHSPCsUB.isNull()) + return llvm::Optional(); + } + // Build RHS + ref RHS = get(Mapping.RHS); +#if 0 + if (!Mapping.LHS->DemandedBits.isAllOnesValue()) + RHS = AndExpr::create(RHS, DemandedBits); +#endif + // Get all UB constraints (LHS && (B)PCs && RHS) + ref UB = klee::ConstantExpr::create(1, Expr::Bool); + if (ExploitUB) { + UB = get(getUBInstCondition()); + if (UB.isNull()) + return llvm::Optional(); + } + + ref Cons; + if (Negate) // (LHS != RHS) + Cons = NeExpr::create(LHS, RHS); + else // (LHS == RHS) + Cons = EqExpr::create(LHS, RHS); + // Cons && UB + if (Mapping.RHS->K != Inst::Const) + Cons = AndExpr::create(Cons, UB); + // (LHS UB && (B)PCs && (B)PCs UB) + Ante = AndExpr::create(Ante, LHSPCsUB); + // (LHS UB && (B)PCs && (B)PCs UB) => Cons && UB + CE.E = Expr::createImplies(Ante, Cons); + + return llvm::Optional(std::move(CE)); + } + std::string BuildQuery(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, @@ -67,7 +148,7 @@ class KLEEBuilder : public ExprBuilder { if (!OptionalCE.hasValue()) return std::string(); CandidateExpr CE = std::move(OptionalCE.getValue()); - ref E = get(CE.E); + ref E = CE.E; Query KQuery(Manager, E); ExprSMTLIBPrinter Printer; Printer.setOutput(SMTSS); @@ -559,9 +640,10 @@ class KLEEBuilder : public ExprBuilder { new Array(ArrayNames.makeName(NameStr), 1, 0, 0, Expr::Int32, Width)); CE.Vars.push_back(Origin); - std::vector ZeroBits, OneBits; UpdateList UL(CE.Arrays.back().get(), 0); ref Var = ReadExpr::create(UL, klee::ConstantExpr::alloc(0, Expr::Int32)); +#if 0 + std::vector ZeroBits, OneBits; if (Origin && Origin->K == Inst::Var) { if (Origin->KnownZeros.getBoolValue() || Origin->KnownOnes.getBoolValue()) { ref NotZeros = NotExpr::create(klee::ConstantExpr::alloc(Origin->KnownZeros)); @@ -593,6 +675,7 @@ class KLEEBuilder : public ExprBuilder { EqExpr::create(Res, klee::ConstantExpr::create(0, Width))); } } +#endif return Var; } From 37ad76e024fba749fd6f2616fa150dc528922434 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sat, 24 Feb 2018 23:10:49 +0100 Subject: [PATCH 10/49] Refactor Demanded bits condition creation --- include/souper/Extractor/ExprBuilder.h | 17 +--- lib/Extractor/ExprBuilder.cpp | 109 ++++++++++++++++++------- lib/Extractor/KLEEBuilder.cpp | 64 ++------------- 3 files changed, 88 insertions(+), 102 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 0863749a7..27274eb54 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -55,14 +55,6 @@ class ExprBuilder { virtual ~ExprBuilder(); - Inst *getZeroBitsMapping(Inst *I); - Inst *getOneBitsMapping(Inst *I); - Inst *getNonZeroBitsMapping(Inst *I); - Inst *getNonNegBitsMapping(Inst *I); - Inst *getPowerTwoBitsMapping(Inst *I); - Inst *getNegBitsMapping(Inst *I); - Inst *getSignBitsMapping(Inst *I); - std::vector getBlockPredicates(Inst *I); bool getUBPaths(Inst *I, UBPath *Current, std::vector> &Paths, @@ -81,6 +73,7 @@ class ExprBuilder { Inst *getInstMapping(const InstMapping &IM); Inst *getUBInstCondition(); + Inst *getDemandedBitsCondition(Inst *I); Inst *getBlockPCs(); void setBlockPCMap(const BlockPCs &BPCs); void recordUBInstruction(Inst *I, Inst *E); @@ -89,14 +82,6 @@ class ExprBuilder { std::map UBExprMap; - std::map ZeroBitsMap; - std::map OneBitsMap; - std::map NonZeroBitsMap; - std::map NonNegBitsMap; - std::map PowerTwoBitsMap; - std::map NegBitsMap; - std::map SignBitsMap; - std::map BlockPCMap; std::vector UBPathInsts; UniqueNameSet ArrayNames; diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index dbbc0c3a9..9b2c2cbe8 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -338,6 +338,85 @@ Inst *ExprBuilder::getUBInstCondition() { return LIC->getConst(APInt(1, true)); } +Inst *ExprBuilder::getDemandedBitsCondition(Inst *I) { + Inst *Result = LIC->getConst(APInt(1, true)); + + if (I->K != Inst::Var) + return Result; + + unsigned Width = I->Width; + Inst *Zero = LIC->getConst(APInt(Width, 0)); + Inst *One = LIC->getConst(APInt(Width, 1)); + + if (I->KnownZeros.getBoolValue()) { + //ref NotZeros = NotExpr::create(klee::ConstantExpr::alloc(Origin->KnownZeros)); + Inst *NotZeros = LIC->getInst(Inst::Xor, Width, + {LIC->getConst(I->KnownZeros), + LIC->getConst(APInt::getAllOnesValue(Width))}); + //ref VarOrNotZero = OrExpr::create(Var, NotZeros); + Inst *VarNotZero = LIC->getInst(Inst::Or, Width, {I, NotZeros}); + //ZeroBitsMap[Origin] = EqExpr::create(VarOrNotZero, NotZeros); + Inst *ZeroBits = LIC->getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); + Result = LIC->getInst(Inst::And, 1, {Result, ZeroBits}); + } + if (I->KnownOnes.getBoolValue()) { + //ref Ones = klee::ConstantExpr::alloc(Origin->KnownOnes); + //ref VarAndOnes = AndExpr::create(Var, Ones); + Inst *Ones = LIC->getConst(I->KnownOnes); + Inst *VarAndOnes = LIC->getInst(Inst::And, Width, {I, Ones}); + //OneBitsMap[Origin] = EqExpr::create(VarAndOnes, Ones); + Inst *OneBits = LIC->getInst(Inst::Eq, 1, {VarAndOnes, Ones}); + Result = LIC->getInst(Inst::And, 1, {Result, OneBits}); + } + if (I->NonZero) { + //NonZeroBitsMap[Origin] = NeExpr::create(Var, klee::ConstantExpr::create(0, Width)); + Inst *NonZeroBits = LIC->getInst(Inst::Ne, 1, {I, Zero}); + Result = LIC->getInst(Inst::And, 1, {Result, NonZeroBits}); + } + if (I->NonNegative) { + //NonNegBitsMap[Origin] = SleExpr::create(klee::ConstantExpr::create(0, Width), Var); + Inst *NonNegBits = LIC->getInst(Inst::Sle, 1, {Zero, I}); + Result = LIC->getInst(Inst::And, 1, {Result, NonNegBits}); + } + if (I->PowOfTwo) { + //ref Zero = klee::ConstantExpr::create(0, Width); + //PowerTwoBitsMap[Origin] = AndExpr::create(NeExpr::create(Var, Zero), + // EqExpr::create(AndExpr::create(Var, + // SubExpr::create(Var, klee::ConstantExpr::create(1, Width))), + // Zero)); + Inst *And = LIC->getInst(Inst::And, Width, + {I, LIC->getInst(Inst::Sub, Width, {I, One})}); + Inst *PowerTwoBits = LIC->getInst(Inst::And, 1, + {LIC->getInst(Inst::Ne, 1, {I, Zero}), + LIC->getInst(Inst::Eq, 1, {And, Zero})}); + Result = LIC->getInst(Inst::And, 1, {Result, PowerTwoBits}); + } + if (I->Negative) { + //NegBitsMap[Origin] = SltExpr::create(Var, klee::ConstantExpr::create(0, Width)); + Inst *NegBits = LIC->getInst(Inst::Slt, 1, {I, Zero}); + Result = LIC->getInst(Inst::And, 1, {Result, NegBits}); + } + if (I->NumSignBits > 1) { + //ref Res = AShrExpr::create(Var, klee::ConstantExpr::create(Width - Origin->NumSignBits, Width)); + Inst *Res = LIC->getInst(Inst::AShr, Width, + {I, LIC->getConst(APInt(Width, Width - I->NumSignBits))}); + //ref TestOnes = AShrExpr::create(ShlExpr::create(klee::ConstantExpr::create(1, Width), + // klee::ConstantExpr::create(Width - 1, Width)), + // klee::ConstantExpr::create(Width - 1, Width)); + Inst *TestOnes = LIC->getInst(Inst::AShr, Width, + {LIC->getInst(Inst::Shl, Width, {One, LIC->getConst(APInt(Width, Width-1))}), + LIC->getConst(APInt(Width, Width-1))}); + //SignBitsMap[Origin] = OrExpr::create(EqExpr::create(Res, TestOnes), + // EqExpr::create(Res, klee::ConstantExpr::create(0, Width))); + Inst *SignBits = LIC->getInst(Inst::Or, 1, + {LIC->getInst(Inst::Eq, 1, {Res, TestOnes}), + LIC->getInst(Inst::Eq, 1, {Res, Zero})}); + Result = LIC->getInst(Inst::And, 1, {Result, SignBits}); + } + + return Result; +} + // Similar to the way we collect UB constraints. We could combine it with // getUBInstCondition, because the workflow is quite similar. // However, mixing two parts (one for UB constraints, one for BlockPCs) @@ -456,37 +535,9 @@ void ExprBuilder::recordUBInstruction(Inst *I, Inst *E) { } #endif } - -Inst *ExprBuilder::getZeroBitsMapping(Inst *I) { - return ZeroBitsMap[I]; -} - -Inst *ExprBuilder::getOneBitsMapping(Inst *I) { - return OneBitsMap[I]; -} - -Inst *ExprBuilder::getNonZeroBitsMapping(Inst *I) { - return NonZeroBitsMap[I]; -} - -Inst *ExprBuilder::getNonNegBitsMapping(Inst *I) { - return NonNegBitsMap[I]; -} - -Inst *ExprBuilder::getNegBitsMapping(Inst *I) { - return NegBitsMap[I]; -} - -Inst *ExprBuilder::getPowerTwoBitsMapping(Inst *I) { - return PowerTwoBitsMap[I]; -} - -Inst *ExprBuilder::getSignBitsMapping(Inst *I) { - return SignBitsMap[I]; -} Inst *ExprBuilder::getInstMapping(const InstMapping &IM) { - return LIC->getInst(Inst::Eq, 1, {IM.LHS, IM.RHS}); + return LIC->getInst(Inst::Eq, 1, {IM.LHS, IM.RHS}); } std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index eefa1c245..2e6e4136a 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -67,29 +67,16 @@ class KLEEBuilder : public ExprBuilder { // Build LHS ref LHS = get(Mapping.LHS); ref Ante = klee::ConstantExpr::alloc(1, 1); -#if 0 + + // Get demanded bits constaints ref DemandedBits = klee::ConstantExpr::alloc(Mapping.LHS->DemandedBits); if (!Mapping.LHS->DemandedBits.isAllOnesValue()) LHS = AndExpr::create(LHS, DemandedBits); - for (const auto I : CE.ArrayVars) { - if (I) { - if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) { - Ante = AndExpr::create(Ante, getZeroBitsMapping(I)); - Ante = AndExpr::create(Ante, getOneBitsMapping(I)); - } - if (I->NonZero) - Ante = AndExpr::create(Ante, getNonZeroBitsMapping(I)); - if (I->NonNegative) - Ante = AndExpr::create(Ante, getNonNegBitsMapping(I)); - if (I->PowOfTwo) - Ante = AndExpr::create(Ante, getPowerTwoBitsMapping(I)); - if (I->Negative) - Ante = AndExpr::create(Ante, getNegBitsMapping(I)); - if (I->NumSignBits > 1) - Ante = AndExpr::create(Ante, getSignBitsMapping(I)); - } + for (const auto I : CE.Vars) { + if (I) + Ante = AndExpr::create(Ante, get(getDemandedBitsCondition(I))); } -#endif + // Build PCs for (const auto &PC : PCs) { Ante = AndExpr::create(Ante, get(getInstMapping(PC))); @@ -108,10 +95,8 @@ class KLEEBuilder : public ExprBuilder { } // Build RHS ref RHS = get(Mapping.RHS); -#if 0 if (!Mapping.LHS->DemandedBits.isAllOnesValue()) RHS = AndExpr::create(RHS, DemandedBits); -#endif // Get all UB constraints (LHS && (B)PCs && RHS) ref UB = klee::ConstantExpr::create(1, Expr::Bool); if (ExploitUB) { @@ -641,42 +626,7 @@ class KLEEBuilder : public ExprBuilder { CE.Vars.push_back(Origin); UpdateList UL(CE.Arrays.back().get(), 0); - ref Var = ReadExpr::create(UL, klee::ConstantExpr::alloc(0, Expr::Int32)); -#if 0 - std::vector ZeroBits, OneBits; - if (Origin && Origin->K == Inst::Var) { - if (Origin->KnownZeros.getBoolValue() || Origin->KnownOnes.getBoolValue()) { - ref NotZeros = NotExpr::create(klee::ConstantExpr::alloc(Origin->KnownZeros)); - ref VarOrNotZero = OrExpr::create(Var, NotZeros); - ZeroBitsMap[Origin] = EqExpr::create(VarOrNotZero, NotZeros); - ref Ones = klee::ConstantExpr::alloc(Origin->KnownOnes); - ref VarAndOnes = AndExpr::create(Var, Ones); - OneBitsMap[Origin] = EqExpr::create(VarAndOnes, Ones); - } - if (Origin->NonZero) - NonZeroBitsMap[Origin] = NeExpr::create(Var, klee::ConstantExpr::create(0, Width)); - if (Origin->NonNegative) - NonNegBitsMap[Origin] = SleExpr::create(klee::ConstantExpr::create(0, Width), Var); - if (Origin->PowOfTwo) { - ref Zero = klee::ConstantExpr::create(0, Width); - PowerTwoBitsMap[Origin] = AndExpr::create(NeExpr::create(Var, Zero), - EqExpr::create(AndExpr::create(Var, - SubExpr::create(Var, klee::ConstantExpr::create(1, Width))), - Zero)); - } - if (Origin->Negative) - NegBitsMap[Origin] = SltExpr::create(Var, klee::ConstantExpr::create(0, Width)); - if (Origin->NumSignBits > 1) { - ref Res = AShrExpr::create(Var, klee::ConstantExpr::create(Width - Origin->NumSignBits, Width)); - ref TestOnes = AShrExpr::create(ShlExpr::create(klee::ConstantExpr::create(1, Width), - klee::ConstantExpr::create(Width - 1, Width)), - klee::ConstantExpr::create(Width - 1, Width)); - SignBitsMap[Origin] = OrExpr::create(EqExpr::create(Res, TestOnes), - EqExpr::create(Res, klee::ConstantExpr::create(0, Width))); - } - } -#endif - return Var; + return ReadExpr::create(UL, klee::ConstantExpr::alloc(0, Expr::Int32)); } }; From d5d67c6457e6ad80b8172b0c561565a3950eea97 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Wed, 28 Feb 2018 22:20:42 +0100 Subject: [PATCH 11/49] Start UB refactoring --- include/souper/Extractor/ExprBuilder.h | 18 +++ lib/Extractor/ExprBuilder.cpp | 204 ++++++++++++++++++++++++- lib/Extractor/KLEEBuilder.cpp | 156 +------------------ 3 files changed, 223 insertions(+), 155 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 27274eb54..6b0d5c721 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -97,6 +97,24 @@ class ExprBuilder { }; CandidateExpr CE; + Inst *getExtractInst(Inst *I, unsigned Offset, unsigned W); + + Inst *addnswUB(Inst *I); + Inst *addnuwUB(Inst *I); + Inst *subnswUB(Inst *I); + Inst *subnuwUB(Inst *I); + Inst *mulnswUB(Inst *I); + Inst *mulnuwUB(Inst *I); + Inst *udivUB(Inst *I); + Inst *udivExactUB(Inst *I); + Inst *sdivUB(Inst *I); + Inst *sdivExactUB(Inst *I); + Inst *shiftUB(Inst *I); + Inst *shlnswUB(Inst *I); + Inst *shlnuwUB(Inst *I); + Inst *lshrExactUB(Inst *I); + Inst *ashrExactUB(Inst *I); + virtual llvm::Optional GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool Negate) = 0; diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 9b2c2cbe8..ba6b781a6 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -285,7 +285,6 @@ Inst *ExprBuilder::createPathPred( // generated by souper. For example, if we say %12 depends on %11, then // %12 would never appear earlier than %11. Inst *ExprBuilder::getUBInstCondition() { -#if 0 // A map from a Phi instruction to all of its KLEE expressions that // encode the path and UB Inst predicates. UBPathInstMap CachedUBPathInsts; @@ -323,8 +322,8 @@ Inst *ExprBuilder::getUBInstCondition() { createUBPathInstsPred(I, Path->Insts, Path->BlockConstraints, &Path->SelectBranches, CachedUBPathInsts); // Add predicate->UB constraint - Inst *IsZero = IC.getInst(Inst::Eq, 1, {Pred, LIC->getConst(APInt(1, false))}); - Inst *Implies = IC.getInst(Inst::Or, 1, {IsZero, Ante}); + Inst *IsZero = LIC->getInst(Inst::Eq, 1, {Pred, LIC->getConst(APInt(1, false))}); + Inst *Implies = LIC->getInst(Inst::Or, 1, {IsZero, Ante}); Result = LIC->getInst(Inst::And, 1, {Result, Implies}); } } @@ -334,8 +333,6 @@ Inst *ExprBuilder::getUBInstCondition() { Result = LIC->getInst(Inst::And, 1, {Result, Entry.second}); return Result; -#endif - return LIC->getConst(APInt(1, true)); } Inst *ExprBuilder::getDemandedBitsCondition(Inst *I) { @@ -540,6 +537,203 @@ Inst *ExprBuilder::getInstMapping(const InstMapping &IM) { return LIC->getInst(Inst::Eq, 1, {IM.LHS, IM.RHS}); } +Inst *ExprBuilder::getExtractInst(Inst *I, unsigned Offset, unsigned W) { + if (I->K == Inst::Const || I->K == Inst::UntypedConst) { + return LIC->getConst(APInt(I->Val.ashr(Offset)).zextOrTrunc(W)); + } else { + return NULL; + } +} + +Inst *ExprBuilder::addnswUB(Inst *I) { + #if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Add = AddExpr::create(L, R); + Expr::Width Width = L->getWidth(); + ref LMSB = ExtractExpr::create(L, Width-1, Expr::Bool); + ref RMSB = ExtractExpr::create(R, Width-1, Expr::Bool); + ref AddMSB = ExtractExpr::create(Add, Width-1, Expr::Bool); + return Expr::createImplies(EqExpr::create(LMSB, RMSB), + EqExpr::create(LMSB, AddMSB)); +#endif + return NULL; +} + +Inst *ExprBuilder::addnuwUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + Expr::Width Width = L->getWidth(); + ref Lext = ZExtExpr::create(L, Width+1); + ref Rext = ZExtExpr::create(R, Width+1); + ref Add = AddExpr::create(Lext, Rext); + ref AddMSB = ExtractExpr::create(Add, Width, Expr::Bool); + return Expr::createIsZero(AddMSB); +#endif + return NULL; +} + +Inst *ExprBuilder::subnswUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Sub = SubExpr::create(L, R); + Expr::Width Width = L->getWidth(); + ref LMSB = ExtractExpr::create(L, Width-1, Expr::Bool); + ref RMSB = ExtractExpr::create(R, Width-1, Expr::Bool); + ref SubMSB = ExtractExpr::create(Sub, Width-1, Expr::Bool); + return Expr::createImplies(NeExpr::create(LMSB, RMSB), + EqExpr::create(LMSB, SubMSB)); +#endif + return NULL; +} + +Inst *ExprBuilder::subnuwUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + Expr::Width Width = L->getWidth(); + ref Lext = ZExtExpr::create(L, Width+1); + ref Rext = ZExtExpr::create(R, Width+1); + ref Sub = SubExpr::create(Lext, Rext); + ref SubMSB = ExtractExpr::create(Sub, Width, Expr::Bool); + return Expr::createIsZero(SubMSB); +#endif + return NULL; +} + +Inst *ExprBuilder::mulnswUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + // The computation below has to be performed on the operands of + // multiplication instruction. The instruction using mulnswUB() + // can be of different width, for instance in SMulO instruction + // which is of 1-bit, but the operands width are to be used here. + Expr::Width Width = get(Ops[0])->getWidth(); + ref L = SExtExpr::create(get(Ops[0]), 2*Width); + ref R = SExtExpr::create(get(Ops[1]), 2*Width); + ref Mul = MulExpr::create(L, R); + ref LowerBits = ExtractExpr::create(Mul, 0, Width); + ref LowerBitsExt = SExtExpr::create(LowerBits, 2*Width); + return EqExpr::create(Mul, LowerBitsExt); +#endif + return NULL; +} + +Inst *ExprBuilder::mulnuwUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + Expr::Width Width = L->getWidth(); + ref Lext = ZExtExpr::create(L, 2*Width); + ref Rext = ZExtExpr::create(R, 2*Width); + ref Mul = MulExpr::create(Lext, Rext); + ref HigherBits = ExtractExpr::create(Mul, Width, Width); + return Expr::createIsZero(HigherBits); +#endif + return NULL; +} + +Inst *ExprBuilder::udivUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref R = get(Ops[1]); + return NeExpr::create(R, klee::ConstantExpr::create(0, R->getWidth())); +#endif + return NULL; +} + +Inst *ExprBuilder::udivExactUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Udiv = UDivExpr::create(L, R); + return EqExpr::create(L, MulExpr::create(R, Udiv)); +#endif + return NULL; +} + +Inst *ExprBuilder::sdivUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref ShiftBy = klee::ConstantExpr::create(L->getWidth()-1, + L->getWidth()); + ref IntMin = ShlExpr::create(klee::ConstantExpr::create( + 1, L->getWidth()), ShiftBy); + ref NegOne = AShrExpr::create(IntMin, ShiftBy); + return AndExpr::create(NeExpr::create(R, klee::ConstantExpr::create( + 0, R->getWidth())), OrExpr::create( + NeExpr::create(L, IntMin), NeExpr::create(R, NegOne))); +#endif + return NULL; +} + +Inst *ExprBuilder::sdivExactUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Sdiv = SDivExpr::create(L, R); + return EqExpr::create(L, MulExpr::create(R, Sdiv)); +#endif + return NULL; +} + +Inst *ExprBuilder::shiftUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Lwidth = klee::ConstantExpr::create(L->getWidth(), L->getWidth()); + return UltExpr::create(R, Lwidth); +#endif + return NULL; +} + +Inst *ExprBuilder::shlnswUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Result = ShlExpr::create(L, R); + ref RShift = AShrExpr::create(Result, R); + return EqExpr::create(RShift, L); +#endif + return NULL; +} + +Inst *ExprBuilder::shlnuwUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Result = ShlExpr::create(L, R); + ref RShift = LShrExpr::create(Result, R); + return EqExpr::create(RShift, L); +#endif + return NULL; +} + +Inst *ExprBuilder::lshrExactUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Result = LShrExpr::create(L, R); + ref LShift = ShlExpr::create(Result, R); + return EqExpr::create(LShift, L); +#endif + return NULL; +} + +Inst *ExprBuilder::ashrExactUB(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + ref L = get(Ops[0]), R = get(Ops[1]); + ref Result = AShrExpr::create(L, R); + ref LShift = ShlExpr::create(Result, R); + return EqExpr::create(LShift, L); +#endif + return NULL; +} + std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate) { diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 2e6e4136a..87a6db522 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -163,150 +163,6 @@ class KLEEBuilder : public ExprBuilder { } private: - ref addnswUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Add = AddExpr::create(L, R); - Expr::Width Width = L->getWidth(); - ref LMSB = ExtractExpr::create(L, Width-1, Expr::Bool); - ref RMSB = ExtractExpr::create(R, Width-1, Expr::Bool); - ref AddMSB = ExtractExpr::create(Add, Width-1, Expr::Bool); - return Expr::createImplies(EqExpr::create(LMSB, RMSB), - EqExpr::create(LMSB, AddMSB)); - } - - ref addnuwUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - Expr::Width Width = L->getWidth(); - ref Lext = ZExtExpr::create(L, Width+1); - ref Rext = ZExtExpr::create(R, Width+1); - ref Add = AddExpr::create(Lext, Rext); - ref AddMSB = ExtractExpr::create(Add, Width, Expr::Bool); - return Expr::createIsZero(AddMSB); - } - - ref subnswUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Sub = SubExpr::create(L, R); - Expr::Width Width = L->getWidth(); - ref LMSB = ExtractExpr::create(L, Width-1, Expr::Bool); - ref RMSB = ExtractExpr::create(R, Width-1, Expr::Bool); - ref SubMSB = ExtractExpr::create(Sub, Width-1, Expr::Bool); - return Expr::createImplies(NeExpr::create(LMSB, RMSB), - EqExpr::create(LMSB, SubMSB)); - } - - ref subnuwUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - Expr::Width Width = L->getWidth(); - ref Lext = ZExtExpr::create(L, Width+1); - ref Rext = ZExtExpr::create(R, Width+1); - ref Sub = SubExpr::create(Lext, Rext); - ref SubMSB = ExtractExpr::create(Sub, Width, Expr::Bool); - return Expr::createIsZero(SubMSB); - } - - ref mulnswUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - // The computation below has to be performed on the operands of - // multiplication instruction. The instruction using mulnswUB() - // can be of different width, for instance in SMulO instruction - // which is of 1-bit, but the operands width are to be used here. - Expr::Width Width = get(Ops[0])->getWidth(); - ref L = SExtExpr::create(get(Ops[0]), 2*Width); - ref R = SExtExpr::create(get(Ops[1]), 2*Width); - ref Mul = MulExpr::create(L, R); - ref LowerBits = ExtractExpr::create(Mul, 0, Width); - ref LowerBitsExt = SExtExpr::create(LowerBits, 2*Width); - return EqExpr::create(Mul, LowerBitsExt); - } - - ref mulnuwUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - Expr::Width Width = L->getWidth(); - ref Lext = ZExtExpr::create(L, 2*Width); - ref Rext = ZExtExpr::create(R, 2*Width); - ref Mul = MulExpr::create(Lext, Rext); - ref HigherBits = ExtractExpr::create(Mul, Width, Width); - return Expr::createIsZero(HigherBits); - } - - ref udivUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref R = get(Ops[1]); - return NeExpr::create(R, klee::ConstantExpr::create(0, R->getWidth())); - } - - ref udivExactUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Udiv = UDivExpr::create(L, R); - return EqExpr::create(L, MulExpr::create(R, Udiv)); - } - - ref sdivUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref ShiftBy = klee::ConstantExpr::create(L->getWidth()-1, - L->getWidth()); - ref IntMin = ShlExpr::create(klee::ConstantExpr::create( - 1, L->getWidth()), ShiftBy); - ref NegOne = AShrExpr::create(IntMin, ShiftBy); - return AndExpr::create(NeExpr::create(R, klee::ConstantExpr::create( - 0, R->getWidth())), OrExpr::create( - NeExpr::create(L, IntMin), NeExpr::create(R, NegOne))); - } - - ref sdivExactUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Sdiv = SDivExpr::create(L, R); - return EqExpr::create(L, MulExpr::create(R, Sdiv)); - } - - ref shiftUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Lwidth = klee::ConstantExpr::create(L->getWidth(), L->getWidth()); - return UltExpr::create(R, Lwidth); - } - - ref shlnswUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = ShlExpr::create(L, R); - ref RShift = AShrExpr::create(Result, R); - return EqExpr::create(RShift, L); - } - - ref shlnuwUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = ShlExpr::create(L, R); - ref RShift = LShrExpr::create(Result, R); - return EqExpr::create(RShift, L); - } - - ref lshrExactUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = LShrExpr::create(L, R); - ref LShift = ShlExpr::create(Result, R); - return EqExpr::create(LShift, L); - } - - ref ashrExactUB(Inst *I) { - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = AShrExpr::create(L, R); - ref LShift = ShlExpr::create(Result, R); - return EqExpr::create(LShift, L); - } - ref countOnes(ref L) { Expr::Width Width = L->getWidth(); ref Count = klee::ConstantExpr::alloc(llvm::APInt(Width, 0)); @@ -577,17 +433,17 @@ class KLEEBuilder : public ExprBuilder { countOnes(Val)); } case Inst::SAddO: - return XorExpr::create(addnswUB(I), klee::ConstantExpr::create(1, Expr::Bool)); + return XorExpr::create(get(addnswUB(I)), klee::ConstantExpr::create(1, Expr::Bool)); case Inst::UAddO: - return XorExpr::create(addnuwUB(I), klee::ConstantExpr::create(1, Expr::Bool)); + return XorExpr::create(get(addnuwUB(I)), klee::ConstantExpr::create(1, Expr::Bool)); case Inst::SSubO: - return XorExpr::create(subnswUB(I), klee::ConstantExpr::create(1, Expr::Bool)); + return XorExpr::create(get(subnswUB(I)), klee::ConstantExpr::create(1, Expr::Bool)); case Inst::USubO: - return XorExpr::create(subnuwUB(I), klee::ConstantExpr::create(1, Expr::Bool)); + return XorExpr::create(get(subnuwUB(I)), klee::ConstantExpr::create(1, Expr::Bool)); case Inst::SMulO: - return XorExpr::create(mulnswUB(I), klee::ConstantExpr::create(1, Expr::Bool)); + return XorExpr::create(get(mulnswUB(I)), klee::ConstantExpr::create(1, Expr::Bool)); case Inst::UMulO: - return XorExpr::create(mulnuwUB(I), klee::ConstantExpr::create(1, Expr::Bool)); + return XorExpr::create(get(mulnuwUB(I)), klee::ConstantExpr::create(1, Expr::Bool)); case Inst::ExtractValue: { unsigned Index = Ops[1]->Val.getZExtValue(); return get(Ops[0]->Ops[Index]); From dc9611e99a70d23e22ae3c50ae863518744d5f18 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 5 Mar 2018 23:12:59 +0100 Subject: [PATCH 12/49] Work on UB rewrite --- include/souper/Extractor/ExprBuilder.h | 5 +- lib/Extractor/ExprBuilder.cpp | 91 ++++++++++++++++++++++---- lib/Extractor/KLEEBuilder.cpp | 14 ++-- 3 files changed, 91 insertions(+), 19 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 6b0d5c721..de51720f0 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -86,7 +86,7 @@ class ExprBuilder { std::vector UBPathInsts; UniqueNameSet ArrayNames; // Holding the precondition, i.e. blockpc, for the UBInst under process. - Inst *UBInstPrecondition; + Inst *UBInstPrecondition = nullptr; // Indicate if the UBInst relates to BlockPC bool IsForBlockPCUBInst = false; @@ -98,11 +98,14 @@ class ExprBuilder { CandidateExpr CE; Inst *getExtractInst(Inst *I, unsigned Offset, unsigned W); + Inst *getImpliesInst(Inst *Ante, Inst *I); Inst *addnswUB(Inst *I); Inst *addnuwUB(Inst *I); + Inst *addnwUB(Inst *I); Inst *subnswUB(Inst *I); Inst *subnuwUB(Inst *I); + Inst *subnwUB(Inst *I); Inst *mulnswUB(Inst *I); Inst *mulnuwUB(Inst *I); Inst *udivUB(Inst *I); diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index ba6b781a6..22f8e9554 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -517,11 +517,10 @@ Inst *ExprBuilder::createUBPathInstsPred( } void ExprBuilder::recordUBInstruction(Inst *I, Inst *E) { -#if 0 if (!IsForBlockPCUBInst) { UBExprMap[I] = E; } - else if (!UBInstPrecondition.isNull()) { + else if (UBInstPrecondition) { // The current UBInst comes from BlockPC. It's possible // that the precondition is missing at this point (e.g., // the corresponding Phi is not part of the current @@ -530,7 +529,6 @@ void ExprBuilder::recordUBInstruction(Inst *I, Inst *E) { Inst *IsZero = LIC->getInst(Inst::Eq, 1, {UBInstPrecondition, LIC->getConst(APInt(1, false))}); UBExprMap[I] = LIC->getInst(Inst::Or, 1, {IsZero, E}); } -#endif } Inst *ExprBuilder::getInstMapping(const InstMapping &IM) { @@ -541,12 +539,25 @@ Inst *ExprBuilder::getExtractInst(Inst *I, unsigned Offset, unsigned W) { if (I->K == Inst::Const || I->K == Inst::UntypedConst) { return LIC->getConst(APInt(I->Val.ashr(Offset)).zextOrTrunc(W)); } else { - return NULL; + Inst *AShr = LIC->getInst(Inst::AShr, I->Width, + {I, LIC->getConst(APInt(I->Width, Offset))}); + if (AShr->Width < W) + return LIC->getInst(Inst::ZExt, W, {AShr}); + else if (AShr->Width > W) + return LIC->getInst(Inst::Trunc, W, {AShr}); + else + return AShr; } } +Inst *ExprBuilder::getImpliesInst(Inst *Ante, Inst *I) { + Inst *IsZero = LIC->getInst(Inst::Eq, 1, + {Ante, LIC->getConst(APInt(Ante->Width, 0))}); + return LIC->getInst(Inst::Or, 1, {IsZero, I}); +} + Inst *ExprBuilder::addnswUB(Inst *I) { - #if 0 +#if 0 const std::vector &Ops = I->orderedOps(); ref L = get(Ops[0]), R = get(Ops[1]); ref Add = AddExpr::create(L, R); @@ -557,7 +568,16 @@ Inst *ExprBuilder::addnswUB(Inst *I) { return Expr::createImplies(EqExpr::create(LMSB, RMSB), EqExpr::create(LMSB, AddMSB)); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Add = LIC->getInst(Inst::Add, Width, {L, R}); + Inst *LMSB = getExtractInst(L, Width-1, 1); + Inst *RMSB = getExtractInst(R, Width-1, 1); + Inst *AddMSB = getExtractInst(Add, Width-1, 1); + return getImpliesInst(LIC->getInst(Inst::Eq, 1, {LMSB, RMSB}), + LIC->getInst(Inst::Eq, 1, {LMSB, AddMSB})); } Inst *ExprBuilder::addnuwUB(Inst *I) { @@ -571,7 +591,22 @@ Inst *ExprBuilder::addnuwUB(Inst *I) { ref AddMSB = ExtractExpr::create(Add, Width, Expr::Bool); return Expr::createIsZero(AddMSB); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Lext = LIC->getInst(Inst::ZExt, Width+1, {L}); + Inst *Rext = LIC->getInst(Inst::ZExt, Width+1, {R}); + Inst *Add = LIC->getInst(Inst::Add, Width+1, {Lext, Rext}); + Inst *AddMSB = getExtractInst(Add, Width, 1); + return LIC->getInst(Inst::Eq, 1, {AddMSB, LIC->getConst(APInt(1, false))}); +} + +Inst *ExprBuilder::addnwUB(Inst *I) { +#if 0 + recordUBInstruction(I, AndExpr::create(addnswUB(I), addnuwUB(I))); +#endif + return LIC->getInst(Inst::And, 1, {addnswUB(I), addnuwUB(I)}); } Inst *ExprBuilder::subnswUB(Inst *I) { @@ -586,7 +621,16 @@ Inst *ExprBuilder::subnswUB(Inst *I) { return Expr::createImplies(NeExpr::create(LMSB, RMSB), EqExpr::create(LMSB, SubMSB)); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Sub = LIC->getInst(Inst::Sub, Width, {L, R}); + Inst *LMSB = getExtractInst(L, Width-1, 1); + Inst *RMSB = getExtractInst(R, Width-1, 1); + Inst *SubMSB = getExtractInst(Sub, Width-1, 1); + return getImpliesInst(LIC->getInst(Inst::Ne, 1, {LMSB, RMSB}), + LIC->getInst(Inst::Eq, 1, {LMSB, SubMSB})); } Inst *ExprBuilder::subnuwUB(Inst *I) { @@ -600,9 +644,25 @@ Inst *ExprBuilder::subnuwUB(Inst *I) { ref SubMSB = ExtractExpr::create(Sub, Width, Expr::Bool); return Expr::createIsZero(SubMSB); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Lext = LIC->getInst(Inst::ZExt, Width+1, {L}); + Inst *Rext = LIC->getInst(Inst::ZExt, Width+1, {R}); + Inst *Sub = LIC->getInst(Inst::Sub, Width+1, {Lext, Rext}); + Inst *SubMSB = getExtractInst(Sub, Width, 1); + return LIC->getInst(Inst::Eq, 1, {SubMSB, LIC->getConst(APInt(1, false))}); } +Inst *ExprBuilder::subnwUB(Inst *I) { +#if 0 + recordUBInstruction(I, AndExpr::create(subnswUB(I), subnuwUB(I))); +#endif + return LIC->getInst(Inst::And, 1, {subnswUB(I), subnuwUB(I)}); +} + + Inst *ExprBuilder::mulnswUB(Inst *I) { #if 0 const std::vector &Ops = I->orderedOps(); @@ -641,7 +701,9 @@ Inst *ExprBuilder::udivUB(Inst *I) { ref R = get(Ops[1]); return NeExpr::create(R, klee::ConstantExpr::create(0, R->getWidth())); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto R = Ops[1]; + return LIC->getInst(Inst::Ne, 1, {R, LIC->getConst(APInt(R->Width, 0))}); } Inst *ExprBuilder::udivExactUB(Inst *I) { @@ -651,7 +713,14 @@ Inst *ExprBuilder::udivExactUB(Inst *I) { ref Udiv = UDivExpr::create(L, R); return EqExpr::create(L, MulExpr::create(R, Udiv)); #endif - return NULL; + // TODO: fails + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Udiv = LIC->getInst(Inst::UDiv, Width, {L, R}); + return LIC->getInst(Inst::Eq, 1, + {L, LIC->getInst(Inst::Mul, Width, {R, Udiv})}); } Inst *ExprBuilder::sdivUB(Inst *I) { diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 87a6db522..36a4d68d8 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -207,34 +207,34 @@ class KLEEBuilder : public ExprBuilder { return buildAssoc(AddExpr::create, Ops); case Inst::AddNSW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, addnswUB(I)); + recordUBInstruction(I, addnswUB(I)); return Add; } case Inst::AddNUW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, addnuwUB(I)); + recordUBInstruction(I, addnuwUB(I)); return Add; } case Inst::AddNW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, AndExpr::create(addnswUB(I), addnuwUB(I))); + recordUBInstruction(I, addnwUB(I)); return Add; } case Inst::Sub: return SubExpr::create(get(Ops[0]), get(Ops[1])); case Inst::SubNSW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, subnswUB(I)); + recordUBInstruction(I, subnswUB(I)); return Sub; } case Inst::SubNUW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, subnuwUB(I)); + recordUBInstruction(I, subnuwUB(I)); return Sub; } case Inst::SubNW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, AndExpr::create(subnswUB(I), subnuwUB(I))); + recordUBInstruction(I, subnwUB(I)); return Sub; } case Inst::Mul: @@ -280,7 +280,7 @@ class KLEEBuilder : public ExprBuilder { case Inst::UDiv: { ref Udiv = UDivExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, udivUB(I)); + recordUBInstruction(I, udivUB(I)); return Udiv; } case Inst::SDiv: { From 00e0e5747048605f0304470e407bdb4f95e62100 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sun, 11 Mar 2018 23:51:30 +0100 Subject: [PATCH 13/49] Work --- include/souper/Extractor/ExprBuilder.h | 2 - lib/Extractor/ExprBuilder.cpp | 87 +++++++++++++++++++------- lib/Extractor/KLEEBuilder.cpp | 37 ++++++----- 3 files changed, 86 insertions(+), 40 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index de51720f0..0d1cd13ef 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -102,10 +102,8 @@ class ExprBuilder { Inst *addnswUB(Inst *I); Inst *addnuwUB(Inst *I); - Inst *addnwUB(Inst *I); Inst *subnswUB(Inst *I); Inst *subnuwUB(Inst *I); - Inst *subnwUB(Inst *I); Inst *mulnswUB(Inst *I); Inst *mulnuwUB(Inst *I); Inst *udivUB(Inst *I); diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 22f8e9554..3f946c871 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -602,13 +602,6 @@ Inst *ExprBuilder::addnuwUB(Inst *I) { return LIC->getInst(Inst::Eq, 1, {AddMSB, LIC->getConst(APInt(1, false))}); } -Inst *ExprBuilder::addnwUB(Inst *I) { -#if 0 - recordUBInstruction(I, AndExpr::create(addnswUB(I), addnuwUB(I))); -#endif - return LIC->getInst(Inst::And, 1, {addnswUB(I), addnuwUB(I)}); -} - Inst *ExprBuilder::subnswUB(Inst *I) { #if 0 const std::vector &Ops = I->orderedOps(); @@ -655,14 +648,6 @@ Inst *ExprBuilder::subnuwUB(Inst *I) { return LIC->getInst(Inst::Eq, 1, {SubMSB, LIC->getConst(APInt(1, false))}); } -Inst *ExprBuilder::subnwUB(Inst *I) { -#if 0 - recordUBInstruction(I, AndExpr::create(subnswUB(I), subnuwUB(I))); -#endif - return LIC->getInst(Inst::And, 1, {subnswUB(I), subnuwUB(I)}); -} - - Inst *ExprBuilder::mulnswUB(Inst *I) { #if 0 const std::vector &Ops = I->orderedOps(); @@ -678,7 +663,20 @@ Inst *ExprBuilder::mulnswUB(Inst *I) { ref LowerBitsExt = SExtExpr::create(LowerBits, 2*Width); return EqExpr::create(Mul, LowerBitsExt); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + // The computation below has to be performed on the operands of + // multiplication instruction. The instruction using mulnswUB() + // can be of different width, for instance in SMulO instruction + // which is of 1-bit, but the operands width are to be used here. + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + L = LIC->getInst(Inst::SExt, 2*Width, {L}); + R = LIC->getInst(Inst::SExt, 2*Width, {R}); + Inst *Mul = LIC->getInst(Inst::Mul, 2*Width, {L, R}); + Inst *LowerBits = getExtractInst(Mul, 0, Width); + Inst *LowerBitsExt = LIC->getInst(Inst::SExt, 2*Width, {LowerBits}); + return LIC->getInst(Inst::Eq, 1, {Mul, LowerBitsExt}); } Inst *ExprBuilder::mulnuwUB(Inst *I) { @@ -692,7 +690,15 @@ Inst *ExprBuilder::mulnuwUB(Inst *I) { ref HigherBits = ExtractExpr::create(Mul, Width, Width); return Expr::createIsZero(HigherBits); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Lext = LIC->getInst(Inst::ZExt, 2*Width, {L}); + Inst *Rext = LIC->getInst(Inst::ZExt, 2*Width, {R}); + Inst *Mul = LIC->getInst(Inst::Mul, 2*Width, {Lext, Rext}); + Inst *HigherBits = getExtractInst(Mul, Width, Width); + return LIC->getInst(Inst::Eq, 1, {HigherBits, LIC->getConst(APInt(Width, 0))}); } Inst *ExprBuilder::udivUB(Inst *I) { @@ -746,7 +752,13 @@ Inst *ExprBuilder::sdivExactUB(Inst *I) { ref Sdiv = SDivExpr::create(L, R); return EqExpr::create(L, MulExpr::create(R, Sdiv)); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Sdiv = LIC->getInst(Inst::SDiv, Width, {L, R}); + return LIC->getInst(Inst::Eq, 1, + {L, LIC->getInst(Inst::Mul, Width, {R, Sdiv})}); } Inst *ExprBuilder::shiftUB(Inst *I) { @@ -756,7 +768,12 @@ Inst *ExprBuilder::shiftUB(Inst *I) { ref Lwidth = klee::ConstantExpr::create(L->getWidth(), L->getWidth()); return UltExpr::create(R, Lwidth); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Lwidth = LIC->getConst(APInt(Width, Width)); + return LIC->getInst(Inst::Ult, 1, {R, Lwidth}); } Inst *ExprBuilder::shlnswUB(Inst *I) { @@ -767,7 +784,13 @@ Inst *ExprBuilder::shlnswUB(Inst *I) { ref RShift = AShrExpr::create(Result, R); return EqExpr::create(RShift, L); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Result = LIC->getInst(Inst::Shl, Width, {L, R}); + Inst *RShift = LIC->getInst(Inst::AShr, Width, {Result, R}); + return LIC->getInst(Inst::Eq, 1, {RShift, L}); } Inst *ExprBuilder::shlnuwUB(Inst *I) { @@ -778,7 +801,13 @@ Inst *ExprBuilder::shlnuwUB(Inst *I) { ref RShift = LShrExpr::create(Result, R); return EqExpr::create(RShift, L); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Result = LIC->getInst(Inst::Shl, Width, {L, R}); + Inst *RShift = LIC->getInst(Inst::LShr, Width, {Result, R}); + return LIC->getInst(Inst::Eq, 1, {RShift, L}); } Inst *ExprBuilder::lshrExactUB(Inst *I) { @@ -789,7 +818,13 @@ Inst *ExprBuilder::lshrExactUB(Inst *I) { ref LShift = ShlExpr::create(Result, R); return EqExpr::create(LShift, L); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Result = LIC->getInst(Inst::LShr, Width, {L, R}); + Inst *LShift = LIC->getInst(Inst::Shl, Width, {Result, R}); + return LIC->getInst(Inst::Eq, 1, {LShift, L}); } Inst *ExprBuilder::ashrExactUB(Inst *I) { @@ -800,7 +835,13 @@ Inst *ExprBuilder::ashrExactUB(Inst *I) { ref LShift = ShlExpr::create(Result, R); return EqExpr::create(LShift, L); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *Result = LIC->getInst(Inst::AShr, Width, {L, R}); + Inst *LShift = LIC->getInst(Inst::Shl, Width, {Result, R}); + return LIC->getInst(Inst::Eq, 1, {LShift, L}); } std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 36a4d68d8..50364deb2 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -217,7 +217,8 @@ class KLEEBuilder : public ExprBuilder { } case Inst::AddNW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, addnwUB(I)); + recordUBInstruction(I, LIC->getInst(Inst::And, 1, + {addnswUB(I), addnuwUB(I)})); return Add; } case Inst::Sub: @@ -234,24 +235,26 @@ class KLEEBuilder : public ExprBuilder { } case Inst::SubNW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, subnwUB(I)); + recordUBInstruction(I, LIC->getInst(Inst::And, 1, + {subnswUB(I), subnuwUB(I)})); return Sub; } case Inst::Mul: return buildAssoc(MulExpr::create, Ops); case Inst::MulNSW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, mulnswUB(I)); + recordUBInstruction(I, mulnswUB(I)); return Mul; } case Inst::MulNUW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, mulnuwUB(I)); + recordUBInstruction(I, mulnuwUB(I)); return Mul; } case Inst::MulNW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, AndExpr::create(mulnswUB(I), mulnuwUB(I))); + recordUBInstruction(I, LIC->getInst(Inst::And, 1, + {mulnswUB(I), mulnuwUB(I)})); return Mul; } @@ -271,6 +274,7 @@ class KLEEBuilder : public ExprBuilder { ref R = get(Ops[1]); if (R->isZero()) { //recordUBInstruction(I, klee::ConstantExpr::create(0, 1)); + recordUBInstruction(I, LIC->getConst(APInt(1, false))); return klee::ConstantExpr::create(0, Ops[1]->Width); } @@ -291,6 +295,8 @@ class KLEEBuilder : public ExprBuilder { case Inst::UDivExact: { ref Udiv = UDivExpr::create(get(Ops[0]), R); //recordUBInstruction(I, AndExpr::create(udivUB(I), udivExactUB(I))); + recordUBInstruction(I, LIC->getInst(Inst::And, 1, + {udivUB(I), udivExactUB(I)})); return Udiv; } case Inst::SDivExact: { @@ -320,44 +326,45 @@ class KLEEBuilder : public ExprBuilder { return buildAssoc(XorExpr::create, Ops); case Inst::Shl: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, shiftUB(I)); + recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::ShlNSW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, AndExpr::create(shiftUB(I), shlnswUB(I))); + recordUBInstruction(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnswUB(I)})); return Result; } case Inst::ShlNUW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, AndExpr::create(shiftUB(I), shlnuwUB(I))); + recordUBInstruction(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnuwUB(I)})); return Result; } case Inst::ShlNW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, AndExpr::create(shiftUB(I), - // AndExpr::create(shlnswUB(I), - // shlnuwUB(I)))); + recordUBInstruction(I, LIC->getInst(Inst::And, 1, + {shiftUB(I), LIC->getInst(Inst::And, 1, {shlnswUB(I), shlnuwUB(I)})})); return Result; } case Inst::LShr: { ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, shiftUB(I)); + recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::LShrExact: { ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, AndExpr::create(shiftUB(I), lshrExactUB(I))); + recordUBInstruction(I, LIC->getInst(Inst::And, 1, + {shiftUB(I), lshrExactUB(I)})); return Result; } case Inst::AShr: { ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, shiftUB(I)); + recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::AShrExact: { ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, AndExpr::create(shiftUB(I), ashrExactUB(I))); + recordUBInstruction(I, LIC->getInst(Inst::And, 1, + {shiftUB(I), ashrExactUB(I)})); return Result; } case Inst::Select: From 8975ab851f8006bf13c3923e564db04c3907db7c Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sun, 11 Mar 2018 23:52:17 +0100 Subject: [PATCH 14/49] Add failing tests --- failing-test.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 failing-test.txt diff --git a/failing-test.txt b/failing-test.txt new file mode 100644 index 000000000..7f5b04179 --- /dev/null +++ b/failing-test.txt @@ -0,0 +1,22 @@ +******************** +Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. +Testing Time: 89.09s +******************** +Failing Tests (12): + Souper :: Pass/clang-pass-profile.c + Souper :: Solver/alive/alive23.opt + Souper :: Solver/alive/alive24.opt + Souper :: Solver/alive/alive25.opt + Souper :: Solver/alive/alive27.opt + Souper :: Solver/alive/alive29.opt + Souper :: Solver/sdiv-cornercase.ll + Souper :: Tool/blockpc-invalid-3.opt + Souper :: Tool/more-knownbits2.opt + Souper :: Tool/more-knownbits25.opt + Souper :: Tool/too-many-phis.opt + Souper :: Unit/extractor_tests.ll + + Expected Passes : 332 + Expected Failures : 3 + Unexpected Failures: 12 +ninja: build stopped: subcommand failed. From 46a452012cae0486abd459d17d8ca67e6cd3313e Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 12 Mar 2018 21:56:26 +0100 Subject: [PATCH 15/49] Work --- failing-test.txt | 18 ++++-------------- lib/Extractor/ExprBuilder.cpp | 15 ++++++++++++++- lib/Extractor/KLEEBuilder.cpp | 10 ++++------ 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/failing-test.txt b/failing-test.txt index 7f5b04179..0423af483 100644 --- a/failing-test.txt +++ b/failing-test.txt @@ -1,22 +1,12 @@ ******************** Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. -Testing Time: 89.09s +Testing Time: 95.07s ******************** -Failing Tests (12): +Failing Tests (3): Souper :: Pass/clang-pass-profile.c - Souper :: Solver/alive/alive23.opt - Souper :: Solver/alive/alive24.opt - Souper :: Solver/alive/alive25.opt - Souper :: Solver/alive/alive27.opt - Souper :: Solver/alive/alive29.opt - Souper :: Solver/sdiv-cornercase.ll Souper :: Tool/blockpc-invalid-3.opt - Souper :: Tool/more-knownbits2.opt - Souper :: Tool/more-knownbits25.opt Souper :: Tool/too-many-phis.opt - Souper :: Unit/extractor_tests.ll - Expected Passes : 332 + Expected Passes : 341 Expected Failures : 3 - Unexpected Failures: 12 -ninja: build stopped: subcommand failed. + Unexpected Failures: 3 diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 3f946c871..5b79903af 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -742,7 +742,20 @@ Inst *ExprBuilder::sdivUB(Inst *I) { 0, R->getWidth())), OrExpr::create( NeExpr::create(L, IntMin), NeExpr::create(R, NegOne))); #endif - return NULL; + const std::vector &Ops = I->orderedOps(); + auto L = Ops[0]; + auto R = Ops[1]; + unsigned Width = L->Width; + Inst *ShiftBy = LIC->getConst(APInt(Width, Width-1)); + Inst *IntMin = LIC->getInst(Inst::Shl, Width, + {LIC->getConst(APInt(Width, 1)), ShiftBy}); + Inst *NegOne = LIC->getInst(Inst::AShr, Width, {IntMin, ShiftBy}); + Inst *NeExpr = LIC->getInst(Inst::Ne, 1, + {R, LIC->getConst(APInt(R->Width, 0))}); + Inst *OrExpr = LIC->getInst(Inst::Or, 1, + {LIC->getInst(Inst::Ne, 1, {L, IntMin}), + LIC->getInst(Inst::Ne, 1, {R, NegOne})}); + return LIC->getInst(Inst::And, 1, {NeExpr, OrExpr}); } Inst *ExprBuilder::sdivExactUB(Inst *I) { diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 50364deb2..950096178 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -273,7 +273,6 @@ class KLEEBuilder : public ExprBuilder { // a constant zero. ref R = get(Ops[1]); if (R->isZero()) { - //recordUBInstruction(I, klee::ConstantExpr::create(0, 1)); recordUBInstruction(I, LIC->getConst(APInt(1, false))); return klee::ConstantExpr::create(0, Ops[1]->Width); } @@ -289,29 +288,28 @@ class KLEEBuilder : public ExprBuilder { } case Inst::SDiv: { ref Sdiv = SDivExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, sdivUB(I)); + recordUBInstruction(I, sdivUB(I)); return Sdiv; } case Inst::UDivExact: { ref Udiv = UDivExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, AndExpr::create(udivUB(I), udivExactUB(I))); recordUBInstruction(I, LIC->getInst(Inst::And, 1, {udivUB(I), udivExactUB(I)})); return Udiv; } case Inst::SDivExact: { ref Sdiv = SDivExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, AndExpr::create(sdivUB(I), sdivExactUB(I))); + recordUBInstruction(I, LIC->getInst(Inst::And, 1, {sdivUB(I), sdivExactUB(I)})); return Sdiv; } case Inst::URem: { ref Urem = URemExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, udivUB(I)); + recordUBInstruction(I, udivUB(I)); return Urem; } case Inst::SRem: { ref Srem = SRemExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, sdivUB(I)); + recordUBInstruction(I, sdivUB(I)); return Srem; } llvm_unreachable("unknown kind"); From ec8c4fd23f79ffb9e66cdcc9b2f3a3d8e6961641 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 12 Mar 2018 22:08:23 +0100 Subject: [PATCH 16/49] Work, again --- lib/Extractor/ExprBuilder.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 5b79903af..2caec9246 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -719,7 +719,6 @@ Inst *ExprBuilder::udivExactUB(Inst *I) { ref Udiv = UDivExpr::create(L, R); return EqExpr::create(L, MulExpr::create(R, Udiv)); #endif - // TODO: fails const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; From 17b927301c97f44a4a3877eccac1ec77fbc56aa1 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Tue, 13 Mar 2018 22:24:47 +0100 Subject: [PATCH 17/49] Use getImpliesInst were possible --- lib/Extractor/ExprBuilder.cpp | 11 +++-------- lib/Extractor/KLEEBuilder.cpp | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 2caec9246..c66f4df8c 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -322,9 +322,7 @@ Inst *ExprBuilder::getUBInstCondition() { createUBPathInstsPred(I, Path->Insts, Path->BlockConstraints, &Path->SelectBranches, CachedUBPathInsts); // Add predicate->UB constraint - Inst *IsZero = LIC->getInst(Inst::Eq, 1, {Pred, LIC->getConst(APInt(1, false))}); - Inst *Implies = LIC->getInst(Inst::Or, 1, {IsZero, Ante}); - Result = LIC->getInst(Inst::And, 1, {Result, Implies}); + Result = LIC->getInst(Inst::And, 1, {Result, getImpliesInst(Pred, Ante)}); } } // Add the unconditional UB constraints at the top level @@ -447,9 +445,7 @@ Inst *ExprBuilder::getBlockPCs() { createUBPathInstsPred(I, Path->Phis, Path->BlockConstraints, /*SelectBranches=*/nullptr, CachedPhis); // Add predicate->UB constraint - Inst *IsZero = LIC->getInst(Inst::Eq, 1, {Pred, LIC->getConst(APInt(1, false))}); - Inst *Implies = LIC->getInst(Inst::Or, 1, {IsZero, Ante}); - Result = LIC->getInst(Inst::And, 1, {Result, Implies}); + Result = LIC->getInst(Inst::And, 1, {Result, getImpliesInst(Pred, Ante)}); } } @@ -526,8 +522,7 @@ void ExprBuilder::recordUBInstruction(Inst *I, Inst *E) { // the corresponding Phi is not part of the current // Souper IR because the Phi is not in the equivalence class // of the instruction. - Inst *IsZero = LIC->getInst(Inst::Eq, 1, {UBInstPrecondition, LIC->getConst(APInt(1, false))}); - UBExprMap[I] = LIC->getInst(Inst::Or, 1, {IsZero, E}); + UBExprMap[I] = getImpliesInst(UBInstPrecondition, E); } } diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 950096178..917b66938 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -68,7 +68,7 @@ class KLEEBuilder : public ExprBuilder { ref LHS = get(Mapping.LHS); ref Ante = klee::ConstantExpr::alloc(1, 1); - // Get demanded bits constaints + // Get demanded bits constraints ref DemandedBits = klee::ConstantExpr::alloc(Mapping.LHS->DemandedBits); if (!Mapping.LHS->DemandedBits.isAllOnesValue()) LHS = AndExpr::create(LHS, DemandedBits); From 6bdde48335ebdf19d9e5f6a271055fac2f807794 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Thu, 22 Mar 2018 21:32:09 +0100 Subject: [PATCH 18/49] Work --- include/souper/Extractor/ExprBuilder.h | 1 + lib/Extractor/ExprBuilder.cpp | 126 +++++++++++++++++++++++++ lib/Extractor/KLEEBuilder.cpp | 2 + 3 files changed, 129 insertions(+) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 0d1cd13ef..8626d184a 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -77,6 +77,7 @@ class ExprBuilder { Inst *getBlockPCs(); void setBlockPCMap(const BlockPCs &BPCs); void recordUBInstruction(Inst *I, Inst *E); + std::map getUBInstructions(Inst *Root); std::map> BlockPredMap; diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index c66f4df8c..62d0cccda 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -15,6 +15,8 @@ #include "llvm/Support/CommandLine.h" #include "souper/Extractor/ExprBuilder.h" +#include + using namespace llvm; using namespace souper; @@ -851,6 +853,130 @@ Inst *ExprBuilder::ashrExactUB(Inst *I) { return LIC->getInst(Inst::Eq, 1, {LShift, L}); } +std::map ExprBuilder::getUBInstructions(Inst *Root) { + // breadth-first search + std::map Result; + std::queue Q; + Q.push(Root); + while (!Q.empty()) { + Inst *I = Q.front(); + Q.pop(); + // Collect UB instructions + switch (I->K) { + case Inst::AddNSW: { + Result.emplace(I, addnswUB(I)); + } + case Inst::AddNUW: { + Result.emplace(I, addnuwUB(I)); + } + case Inst::AddNW: { + Result.emplace(I, LIC->getInst(Inst::And, 1, + {addnswUB(I), addnuwUB(I)})); + } + case Inst::SubNSW: { + Result.emplace(I, subnswUB(I)); + } + case Inst::SubNUW: { + Result.emplace(I, subnuwUB(I)); + } + case Inst::SubNW: { + Result.emplace(I, LIC->getInst(Inst::And, 1, + {subnswUB(I), subnuwUB(I)})); + } + case Inst::MulNSW: { + Result.emplace(I, mulnswUB(I)); + } + case Inst::MulNUW: { + Result.emplace(I, mulnuwUB(I)); + } + case Inst::MulNW: { + Result.emplace(I, LIC->getInst(Inst::And, 1, + {mulnswUB(I), mulnuwUB(I)})); + } + + case Inst::UDiv: + case Inst::SDiv: + case Inst::UDivExact: + case Inst::SDivExact: + case Inst::URem: + case Inst::SRem: { // Fall-through + // If the second oprand is 0, then it definitely causes UB. + // There are quite a few cases where KLEE folds operations into zero, + // e.g., "sext i16 0 to i32", "0 + 0", "2 - 2", etc. In all cases, + // we skip building the corresponding KLEE expressions and just return + // a constant zero. + Inst *R = I->Ops[1]; + if (R == LIC->getConst(APInt(R->Width, 0))) { + Result.emplace(I, LIC->getConst(APInt(1, false))); + return Result; + } + + switch (I->K) { + default: + break; + + case Inst::UDiv: { + Result.emplace(I, udivUB(I)); + } + case Inst::SDiv: { + Result.emplace(I, sdivUB(I)); + } + case Inst::UDivExact: { + Result.emplace(I, LIC->getInst(Inst::And, 1, + {udivUB(I), udivExactUB(I)})); + } + case Inst::SDivExact: { + Result.emplace(I, LIC->getInst(Inst::And, 1, {sdivUB(I), sdivExactUB(I)})); + } + case Inst::URem: { + Result.emplace(I, udivUB(I)); + } + case Inst::SRem: { + Result.emplace(I, sdivUB(I)); + } + llvm_unreachable("unknown kind"); + } + } + + case Inst::Shl: { + Result.emplace(I, shiftUB(I)); + } + case Inst::ShlNSW: { + Result.emplace(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnswUB(I)})); + } + case Inst::ShlNUW: { + Result.emplace(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnuwUB(I)})); + } + case Inst::ShlNW: { + Result.emplace(I, LIC->getInst(Inst::And, 1, + {shiftUB(I), LIC->getInst(Inst::And, 1, {shlnswUB(I), shlnuwUB(I)})})); + } + case Inst::LShr: { + Result.emplace(I, shiftUB(I)); + } + case Inst::LShrExact: { + Result.emplace(I, LIC->getInst(Inst::And, 1, + {shiftUB(I), lshrExactUB(I)})); + } + case Inst::AShr: { + Result.emplace(I, shiftUB(I)); + } + case Inst::AShrExact: { + Result.emplace(I, LIC->getInst(Inst::And, 1, + {shiftUB(I), ashrExactUB(I)})); + } + default: + break; + } + + for (auto Op : I->orderedOps()) + if (!Result.count(Op)) + Q.push(Op); + } + + return Result; +} + std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate) { diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 917b66938..46b354826 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -66,6 +66,8 @@ class KLEEBuilder : public ExprBuilder { // Build LHS ref LHS = get(Mapping.LHS); + if (UBExprMap.size() != getUBInstructions(Mapping.LHS).size()) + report_fatal_error("UB instruction mismatch"); ref Ante = klee::ConstantExpr::alloc(1, 1); // Get demanded bits constraints From ec0572305ec2fb88c6ca9755a0b10e405f0fb5c8 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Tue, 27 Mar 2018 22:41:45 +0200 Subject: [PATCH 19/49] Fix UB instruction gathering --- lib/Extractor/ExprBuilder.cpp | 28 ++++++++++++++++++++++++++-- lib/Extractor/KLEEBuilder.cpp | 2 -- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 62d0cccda..d7e623006 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -855,6 +855,7 @@ Inst *ExprBuilder::ashrExactUB(Inst *I) { std::map ExprBuilder::getUBInstructions(Inst *Root) { // breadth-first search + std::set Visited; std::map Result; std::queue Q; Q.push(Root); @@ -865,33 +866,42 @@ std::map ExprBuilder::getUBInstructions(Inst *Root) { switch (I->K) { case Inst::AddNSW: { Result.emplace(I, addnswUB(I)); + break; } case Inst::AddNUW: { Result.emplace(I, addnuwUB(I)); + break; } case Inst::AddNW: { Result.emplace(I, LIC->getInst(Inst::And, 1, {addnswUB(I), addnuwUB(I)})); + break; } case Inst::SubNSW: { Result.emplace(I, subnswUB(I)); + break; } case Inst::SubNUW: { Result.emplace(I, subnuwUB(I)); + break; } case Inst::SubNW: { Result.emplace(I, LIC->getInst(Inst::And, 1, {subnswUB(I), subnuwUB(I)})); + break; } case Inst::MulNSW: { Result.emplace(I, mulnswUB(I)); + break; } case Inst::MulNUW: { Result.emplace(I, mulnuwUB(I)); + break; } case Inst::MulNW: { Result.emplace(I, LIC->getInst(Inst::And, 1, {mulnswUB(I), mulnuwUB(I)})); + break; } case Inst::UDiv: @@ -917,22 +927,28 @@ std::map ExprBuilder::getUBInstructions(Inst *Root) { case Inst::UDiv: { Result.emplace(I, udivUB(I)); + break; } case Inst::SDiv: { Result.emplace(I, sdivUB(I)); + break; } case Inst::UDivExact: { Result.emplace(I, LIC->getInst(Inst::And, 1, {udivUB(I), udivExactUB(I)})); + break; } case Inst::SDivExact: { Result.emplace(I, LIC->getInst(Inst::And, 1, {sdivUB(I), sdivExactUB(I)})); + break; } case Inst::URem: { Result.emplace(I, udivUB(I)); + break; } case Inst::SRem: { Result.emplace(I, sdivUB(I)); + break; } llvm_unreachable("unknown kind"); } @@ -940,37 +956,45 @@ std::map ExprBuilder::getUBInstructions(Inst *Root) { case Inst::Shl: { Result.emplace(I, shiftUB(I)); + break; } case Inst::ShlNSW: { Result.emplace(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnswUB(I)})); + break; } case Inst::ShlNUW: { Result.emplace(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnuwUB(I)})); + break; } case Inst::ShlNW: { Result.emplace(I, LIC->getInst(Inst::And, 1, {shiftUB(I), LIC->getInst(Inst::And, 1, {shlnswUB(I), shlnuwUB(I)})})); + break; } case Inst::LShr: { Result.emplace(I, shiftUB(I)); + break; } case Inst::LShrExact: { Result.emplace(I, LIC->getInst(Inst::And, 1, {shiftUB(I), lshrExactUB(I)})); + break; } case Inst::AShr: { Result.emplace(I, shiftUB(I)); + break; } case Inst::AShrExact: { Result.emplace(I, LIC->getInst(Inst::And, 1, {shiftUB(I), ashrExactUB(I)})); + break; } default: break; } - for (auto Op : I->orderedOps()) - if (!Result.count(Op)) + if (Visited.insert(I).second) + for (auto Op : I->orderedOps()) Q.push(Op); } diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 46b354826..917b66938 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -66,8 +66,6 @@ class KLEEBuilder : public ExprBuilder { // Build LHS ref LHS = get(Mapping.LHS); - if (UBExprMap.size() != getUBInstructions(Mapping.LHS).size()) - report_fatal_error("UB instruction mismatch"); ref Ante = klee::ConstantExpr::alloc(1, 1); // Get demanded bits constraints From 693a4f5f10eb9574e1b357992f7b32bd8dcd2626 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Tue, 27 Mar 2018 22:50:35 +0200 Subject: [PATCH 20/49] Comment UB recording --- lib/Extractor/KLEEBuilder.cpp | 62 +++++++++++++++++------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 917b66938..6f8b08cd8 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -207,54 +207,54 @@ class KLEEBuilder : public ExprBuilder { return buildAssoc(AddExpr::create, Ops); case Inst::AddNSW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, addnswUB(I)); + //recordUBInstruction(I, addnswUB(I)); return Add; } case Inst::AddNUW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, addnuwUB(I)); + //recordUBInstruction(I, addnuwUB(I)); return Add; } case Inst::AddNW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, LIC->getInst(Inst::And, 1, - {addnswUB(I), addnuwUB(I)})); + //recordUBInstruction(I, LIC->getInst(Inst::And, 1, + // {addnswUB(I), addnuwUB(I)})); return Add; } case Inst::Sub: return SubExpr::create(get(Ops[0]), get(Ops[1])); case Inst::SubNSW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, subnswUB(I)); + //recordUBInstruction(I, subnswUB(I)); return Sub; } case Inst::SubNUW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, subnuwUB(I)); + //recordUBInstruction(I, subnuwUB(I)); return Sub; } case Inst::SubNW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, LIC->getInst(Inst::And, 1, - {subnswUB(I), subnuwUB(I)})); + //recordUBInstruction(I, LIC->getInst(Inst::And, 1, + // {subnswUB(I), subnuwUB(I)})); return Sub; } case Inst::Mul: return buildAssoc(MulExpr::create, Ops); case Inst::MulNSW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, mulnswUB(I)); + //recordUBInstruction(I, mulnswUB(I)); return Mul; } case Inst::MulNUW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, mulnuwUB(I)); + //recordUBInstruction(I, mulnuwUB(I)); return Mul; } case Inst::MulNW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, LIC->getInst(Inst::And, 1, - {mulnswUB(I), mulnuwUB(I)})); + //recordUBInstruction(I, LIC->getInst(Inst::And, 1, + // {mulnswUB(I), mulnuwUB(I)})); return Mul; } @@ -273,7 +273,7 @@ class KLEEBuilder : public ExprBuilder { // a constant zero. ref R = get(Ops[1]); if (R->isZero()) { - recordUBInstruction(I, LIC->getConst(APInt(1, false))); + //recordUBInstruction(I, LIC->getConst(APInt(1, false))); return klee::ConstantExpr::create(0, Ops[1]->Width); } @@ -283,33 +283,33 @@ class KLEEBuilder : public ExprBuilder { case Inst::UDiv: { ref Udiv = UDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, udivUB(I)); + //recordUBInstruction(I, udivUB(I)); return Udiv; } case Inst::SDiv: { ref Sdiv = SDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, sdivUB(I)); + //recordUBInstruction(I, sdivUB(I)); return Sdiv; } case Inst::UDivExact: { ref Udiv = UDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, LIC->getInst(Inst::And, 1, - {udivUB(I), udivExactUB(I)})); + //recordUBInstruction(I, LIC->getInst(Inst::And, 1, + // {udivUB(I), udivExactUB(I)})); return Udiv; } case Inst::SDivExact: { ref Sdiv = SDivExpr::create(get(Ops[0]), R); - recordUBInstruction(I, LIC->getInst(Inst::And, 1, {sdivUB(I), sdivExactUB(I)})); + //recordUBInstruction(I, LIC->getInst(Inst::And, 1, {sdivUB(I), sdivExactUB(I)})); return Sdiv; } case Inst::URem: { ref Urem = URemExpr::create(get(Ops[0]), R); - recordUBInstruction(I, udivUB(I)); + //recordUBInstruction(I, udivUB(I)); return Urem; } case Inst::SRem: { ref Srem = SRemExpr::create(get(Ops[0]), R); - recordUBInstruction(I, sdivUB(I)); + //recordUBInstruction(I, sdivUB(I)); return Srem; } llvm_unreachable("unknown kind"); @@ -324,45 +324,45 @@ class KLEEBuilder : public ExprBuilder { return buildAssoc(XorExpr::create, Ops); case Inst::Shl: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, shiftUB(I)); + //recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::ShlNSW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnswUB(I)})); + //recordUBInstruction(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnswUB(I)})); return Result; } case Inst::ShlNUW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnuwUB(I)})); + //recordUBInstruction(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnuwUB(I)})); return Result; } case Inst::ShlNW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, LIC->getInst(Inst::And, 1, - {shiftUB(I), LIC->getInst(Inst::And, 1, {shlnswUB(I), shlnuwUB(I)})})); + //recordUBInstruction(I, LIC->getInst(Inst::And, 1, + // {shiftUB(I), LIC->getInst(Inst::And, 1, {shlnswUB(I), shlnuwUB(I)})})); return Result; } case Inst::LShr: { ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, shiftUB(I)); + //recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::LShrExact: { ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, LIC->getInst(Inst::And, 1, - {shiftUB(I), lshrExactUB(I)})); + //recordUBInstruction(I, LIC->getInst(Inst::And, 1, + // {shiftUB(I), lshrExactUB(I)})); return Result; } case Inst::AShr: { ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, shiftUB(I)); + //recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::AShrExact: { ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - recordUBInstruction(I, LIC->getInst(Inst::And, 1, - {shiftUB(I), ashrExactUB(I)})); + //recordUBInstruction(I, LIC->getInst(Inst::And, 1, + // {shiftUB(I), ashrExactUB(I)})); return Result; } case Inst::Select: From 1eae2d3e514af962ed19535f0157d1fd76198ed7 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Tue, 27 Mar 2018 22:53:57 +0200 Subject: [PATCH 21/49] More --- include/souper/Extractor/ExprBuilder.h | 2 +- lib/Extractor/ExprBuilder.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 8626d184a..7d81091a3 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -76,7 +76,7 @@ class ExprBuilder { Inst *getDemandedBitsCondition(Inst *I); Inst *getBlockPCs(); void setBlockPCMap(const BlockPCs &BPCs); - void recordUBInstruction(Inst *I, Inst *E); + //void recordUBInstruction(Inst *I, Inst *E); std::map getUBInstructions(Inst *Root); std::map> BlockPredMap; diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index d7e623006..e8830b3d4 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -514,6 +514,7 @@ Inst *ExprBuilder::createUBPathInstsPred( return Pred; } +#if 0 void ExprBuilder::recordUBInstruction(Inst *I, Inst *E) { if (!IsForBlockPCUBInst) { UBExprMap[I] = E; @@ -527,6 +528,7 @@ void ExprBuilder::recordUBInstruction(Inst *I, Inst *E) { UBExprMap[I] = getImpliesInst(UBInstPrecondition, E); } } +#endif Inst *ExprBuilder::getInstMapping(const InstMapping &IM) { return LIC->getInst(Inst::Eq, 1, {IM.LHS, IM.RHS}); From 4b0cbf9d3e0154f034857cbe03cbefde81608a02 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Tue, 27 Mar 2018 23:50:48 +0200 Subject: [PATCH 22/49] Work --- failing-test.txt | 16 +++++----- include/souper/Extractor/ExprBuilder.h | 11 ++++--- lib/Extractor/ExprBuilder.cpp | 42 +++++++++++++++++++++++--- lib/Extractor/KLEEBuilder.cpp | 28 ++++++++--------- 4 files changed, 66 insertions(+), 31 deletions(-) diff --git a/failing-test.txt b/failing-test.txt index 0423af483..fc8c07199 100644 --- a/failing-test.txt +++ b/failing-test.txt @@ -1,12 +1,14 @@ ******************** -Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. -Testing Time: 95.07s -******************** -Failing Tests (3): +Failing Tests (4): Souper :: Pass/clang-pass-profile.c - Souper :: Tool/blockpc-invalid-3.opt + Souper :: Solver/alive-bug.ll + Souper :: Solver/bachet1.ll Souper :: Tool/too-many-phis.opt - Expected Passes : 341 + Expected Passes : 340 Expected Failures : 3 - Unexpected Failures: 3 + Unexpected Failures: 4 + +real 1m27.816s +user 3m50.009s +sys 0m15.642s diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 7d81091a3..60d60c61a 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -72,19 +72,20 @@ class ExprBuilder { UBPathInstMap &CachedUBPathInsts); Inst *getInstMapping(const InstMapping &IM); - Inst *getUBInstCondition(); + Inst *getUBInstCondition(Inst *Root); Inst *getDemandedBitsCondition(Inst *I); - Inst *getBlockPCs(); + Inst *getBlockPCs(Inst *Root); void setBlockPCMap(const BlockPCs &BPCs); //void recordUBInstruction(Inst *I, Inst *E); - std::map getUBInstructions(Inst *Root); + std::map getUBInstConstraints(Inst *Root); + std::vector getUBPathInsts(Inst *Root); std::map> BlockPredMap; - std::map UBExprMap; + //std::map UBExprMap; std::map BlockPCMap; - std::vector UBPathInsts; + //std::vector UBPathInsts; UniqueNameSet ArrayNames; // Holding the precondition, i.e. blockpc, for the UBInst under process. Inst *UBInstPrecondition = nullptr; diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index e8830b3d4..061330b17 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -286,14 +286,15 @@ Inst *ExprBuilder::createPathPred( // These tricks basically relies on the dependency chain of instructions // generated by souper. For example, if we say %12 depends on %11, then // %12 would never appear earlier than %11. -Inst *ExprBuilder::getUBInstCondition() { +Inst *ExprBuilder::getUBInstCondition(Inst *Root) { // A map from a Phi instruction to all of its KLEE expressions that // encode the path and UB Inst predicates. UBPathInstMap CachedUBPathInsts; std::set UsedUBInsts; Inst *Result = LIC->getConst(APInt(1, true)); + auto UBExprMap = getUBInstConstraints(Root); // For each Phi/Select instruction - for (const auto &I : UBPathInsts) { + for (const auto &I : getUBPathInsts(Root)) { if (CachedUBPathInsts.count(I) != 0) continue; // Recursively collect UB instructions @@ -419,12 +420,12 @@ Inst *ExprBuilder::getDemandedBitsCondition(Inst *I) { // However, mixing two parts (one for UB constraints, one for BlockPCs) // may make the code less structured. If we see big performance overhead, // we may consider to combine these two parts together. -Inst *ExprBuilder::getBlockPCs() { +Inst *ExprBuilder::getBlockPCs(Inst *Root) { UBPathInstMap CachedPhis; Inst *Result = LIC->getConst(APInt(1, true)); // For each Phi instruction - for (const auto &I : UBPathInsts) { + for (const auto &I : getUBPathInsts(Root)) { if (CachedPhis.count(I) != 0) continue; // Recursively collect BlockPCs @@ -855,7 +856,7 @@ Inst *ExprBuilder::ashrExactUB(Inst *I) { return LIC->getInst(Inst::Eq, 1, {LShift, L}); } -std::map ExprBuilder::getUBInstructions(Inst *Root) { +std::map ExprBuilder::getUBInstConstraints(Inst *Root) { // breadth-first search std::set Visited; std::map Result; @@ -1003,6 +1004,37 @@ std::map ExprBuilder::getUBInstructions(Inst *Root) { return Result; } +std::vector ExprBuilder::getUBPathInsts(Inst *Root) { + // breadth-first search + std::set Visited; + std::vector Result; + std::queue Q; + Q.push(Root); + while (!Q.empty()) { + Inst *I = Q.front(); + Q.pop(); + // Collect UB path instructions + switch (I->K) { + case Inst::Phi: { + Result.push_back(I); + break; + } + case Inst::Select: { + Result.push_back(I); + break; + } + default: + break; + } + + if (Visited.insert(I).second) + for (auto Op : I->orderedOps()) + Q.push(Op); + } + + return Result; +} + std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate) { diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 6f8b08cd8..a29293246 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -84,24 +84,24 @@ class KLEEBuilder : public ExprBuilder { // Build BPCs if (BPCs.size()) { setBlockPCMap(BPCs); - Ante = AndExpr::create(Ante, get(getBlockPCs())); + Ante = AndExpr::create(Ante, get(getBlockPCs(Mapping.LHS))); } // Get UB constraints of LHS and (B)PCs - ref LHSPCsUB = klee::ConstantExpr::create(1, Expr::Bool); + ref LHSUB = klee::ConstantExpr::create(1, Expr::Bool); if (ExploitUB) { - LHSPCsUB = get(getUBInstCondition()); - if (LHSPCsUB.isNull()) + LHSUB = get(getUBInstCondition(Mapping.LHS)); + if (LHSUB.isNull()) return llvm::Optional(); } // Build RHS ref RHS = get(Mapping.RHS); if (!Mapping.LHS->DemandedBits.isAllOnesValue()) RHS = AndExpr::create(RHS, DemandedBits); - // Get all UB constraints (LHS && (B)PCs && RHS) - ref UB = klee::ConstantExpr::create(1, Expr::Bool); + // Get UB constraints of RHS and ((B)PCs) + ref RHSUB = klee::ConstantExpr::create(1, Expr::Bool); if (ExploitUB) { - UB = get(getUBInstCondition()); - if (UB.isNull()) + RHSUB = get(getUBInstCondition(Mapping.RHS)); + if (RHSUB.isNull()) return llvm::Optional(); } @@ -110,12 +110,12 @@ class KLEEBuilder : public ExprBuilder { Cons = NeExpr::create(LHS, RHS); else // (LHS == RHS) Cons = EqExpr::create(LHS, RHS); - // Cons && UB + // Cons && RHS UB if (Mapping.RHS->K != Inst::Const) - Cons = AndExpr::create(Cons, UB); + Cons = AndExpr::create(Cons, RHSUB); // (LHS UB && (B)PCs && (B)PCs UB) - Ante = AndExpr::create(Ante, LHSPCsUB); - // (LHS UB && (B)PCs && (B)PCs UB) => Cons && UB + Ante = AndExpr::create(Ante, LHSUB); + // (LHS UB && (B)PCs && (B)PCs UB) => Cons && RHS UB CE.E = Expr::createImplies(Ante, Cons); return llvm::Optional(std::move(CE)); @@ -200,7 +200,7 @@ class KLEEBuilder : public ExprBuilder { for (unsigned J = 1; J < Ops.size(); ++J) { E = SelectExpr::create(get(PredExpr[J-1]), E, get(Ops[J])); } - UBPathInsts.push_back(I); + //UBPathInsts.push_back(I); return E; } case Inst::Add: @@ -366,7 +366,7 @@ class KLEEBuilder : public ExprBuilder { return Result; } case Inst::Select: - UBPathInsts.push_back(I); + //UBPathInsts.push_back(I); return SelectExpr::create(get(Ops[0]), get(Ops[1]), get(Ops[2])); case Inst::ZExt: return ZExtExpr::create(get(Ops[0]), I->Width); From dd6e40004f6e10f72ad72907975ad61e0b59a4b1 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Wed, 28 Mar 2018 00:05:39 +0200 Subject: [PATCH 23/49] Get UB constraints of PCs --- failing-test.txt | 15 +++++++-------- lib/Extractor/KLEEBuilder.cpp | 31 ++++++++++++++++++++++--------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/failing-test.txt b/failing-test.txt index fc8c07199..062c81a2e 100644 --- a/failing-test.txt +++ b/failing-test.txt @@ -1,14 +1,13 @@ +Testing Time: 87.60s ******************** -Failing Tests (4): +Failing Tests (2): Souper :: Pass/clang-pass-profile.c - Souper :: Solver/alive-bug.ll - Souper :: Solver/bachet1.ll Souper :: Tool/too-many-phis.opt - Expected Passes : 340 + Expected Passes : 342 Expected Failures : 3 - Unexpected Failures: 4 + Unexpected Failures: 2 -real 1m27.816s -user 3m50.009s -sys 0m15.642s +real 1m27.715s +user 4m12.942s +sys 0m15.495s diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index a29293246..af10e3679 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -63,7 +63,7 @@ class KLEEBuilder : public ExprBuilder { llvm::Optional GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool Negate) override { - + // Build LHS ref LHS = get(Mapping.LHS); ref Ante = klee::ConstantExpr::alloc(1, 1); @@ -77,27 +77,37 @@ class KLEEBuilder : public ExprBuilder { Ante = AndExpr::create(Ante, get(getDemandedBitsCondition(I))); } + // Get UB constraints of LHS + ref LHSUB = klee::ConstantExpr::create(1, Expr::Bool); + if (ExploitUB) { + LHSUB = get(getUBInstCondition(Mapping.LHS)); + if (LHSUB.isNull()) + return llvm::Optional(); + } + // Build PCs for (const auto &PC : PCs) { Ante = AndExpr::create(Ante, get(getInstMapping(PC))); + // Get UB constraints of PCs + if (ExploitUB) + LHSUB = AndExpr::create(LHSUB, get(getUBInstCondition(getInstMapping(PC)))); } + // Build BPCs if (BPCs.size()) { setBlockPCMap(BPCs); + // TODO: Get UB constraints of BPCs Ante = AndExpr::create(Ante, get(getBlockPCs(Mapping.LHS))); } - // Get UB constraints of LHS and (B)PCs - ref LHSUB = klee::ConstantExpr::create(1, Expr::Bool); - if (ExploitUB) { - LHSUB = get(getUBInstCondition(Mapping.LHS)); - if (LHSUB.isNull()) - return llvm::Optional(); - } + // Build RHS ref RHS = get(Mapping.RHS); + + // Get demanded bits constraints if (!Mapping.LHS->DemandedBits.isAllOnesValue()) RHS = AndExpr::create(RHS, DemandedBits); - // Get UB constraints of RHS and ((B)PCs) + + // Get UB constraints of RHS ref RHSUB = klee::ConstantExpr::create(1, Expr::Bool); if (ExploitUB) { RHSUB = get(getUBInstCondition(Mapping.RHS)); @@ -110,11 +120,14 @@ class KLEEBuilder : public ExprBuilder { Cons = NeExpr::create(LHS, RHS); else // (LHS == RHS) Cons = EqExpr::create(LHS, RHS); + // Cons && RHS UB if (Mapping.RHS->K != Inst::Const) Cons = AndExpr::create(Cons, RHSUB); + // (LHS UB && (B)PCs && (B)PCs UB) Ante = AndExpr::create(Ante, LHSUB); + // (LHS UB && (B)PCs && (B)PCs UB) => Cons && RHS UB CE.E = Expr::createImplies(Ante, Cons); From 71cf3d9255c4b3efdaa8e14b36c636911dfb3f86 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Wed, 28 Mar 2018 00:35:54 +0200 Subject: [PATCH 24/49] Minor --- lib/Extractor/KLEEBuilder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index af10e3679..222137875 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -125,10 +125,10 @@ class KLEEBuilder : public ExprBuilder { if (Mapping.RHS->K != Inst::Const) Cons = AndExpr::create(Cons, RHSUB); - // (LHS UB && (B)PCs && (B)PCs UB) + // (B)PCs && && LHS UB && (B)PCs UB Ante = AndExpr::create(Ante, LHSUB); - // (LHS UB && (B)PCs && (B)PCs UB) => Cons && RHS UB + // ((B)PCs && LHS UB && (B)PCs UB) => Cons && RHS UB CE.E = Expr::createImplies(Ante, Cons); return llvm::Optional(std::move(CE)); From b2737ae922b2c1f1faa5242f5ad7c3acceb24092 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Thu, 29 Mar 2018 22:16:16 +0200 Subject: [PATCH 25/49] Work --- lib/Extractor/KLEEBuilder.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 222137875..6ddc48d5d 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -72,10 +72,6 @@ class KLEEBuilder : public ExprBuilder { ref DemandedBits = klee::ConstantExpr::alloc(Mapping.LHS->DemandedBits); if (!Mapping.LHS->DemandedBits.isAllOnesValue()) LHS = AndExpr::create(LHS, DemandedBits); - for (const auto I : CE.Vars) { - if (I) - Ante = AndExpr::create(Ante, get(getDemandedBitsCondition(I))); - } // Get UB constraints of LHS ref LHSUB = klee::ConstantExpr::create(1, Expr::Bool); @@ -107,6 +103,11 @@ class KLEEBuilder : public ExprBuilder { if (!Mapping.LHS->DemandedBits.isAllOnesValue()) RHS = AndExpr::create(RHS, DemandedBits); + for (const auto I : CE.Vars) { + if (I) + Ante = AndExpr::create(Ante, get(getDemandedBitsCondition(I))); + } + // Get UB constraints of RHS ref RHSUB = klee::ConstantExpr::create(1, Expr::Bool); if (ExploitUB) { From 132ba94167d016302a46f6d3b9d645623ca8b473 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Thu, 29 Mar 2018 23:30:16 +0200 Subject: [PATCH 26/49] No need of block pcs? --- include/souper/Extractor/ExprBuilder.h | 4 ++-- lib/Extractor/ExprBuilder.cpp | 11 ----------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 60d60c61a..c5a0142f9 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -88,9 +88,9 @@ class ExprBuilder { //std::vector UBPathInsts; UniqueNameSet ArrayNames; // Holding the precondition, i.e. blockpc, for the UBInst under process. - Inst *UBInstPrecondition = nullptr; + //Inst *UBInstPrecondition = nullptr; // Indicate if the UBInst relates to BlockPC - bool IsForBlockPCUBInst = false; + //bool IsForBlockPCUBInst = false; struct CandidateExpr { std::vector> Arrays; diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 061330b17..b5dc09539 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -460,18 +460,7 @@ void ExprBuilder::setBlockPCMap(const BlockPCs &BPCs) { assert(BPC.B && "Block is NULL!"); BlockPCPredMap &PCMap = BlockPCMap[BPC.B]; auto I = PCMap.find(BPC.PredIdx); - // Relying on a class-level flag may not be a nice solution, - // but it seems hard to differentiate two cases: - // (1) UBInstExpr collected through blockpc, and; - // (2) UBInstExpr collected through pc/lhs/rhs - // For the first case, UBInst(s) is conditional, i.e., - // they rely on the fact that blockpc(s) are true. - if (I != PCMap.end()) - UBInstPrecondition = I->second; - IsForBlockPCUBInst = true; Inst *PE = getInstMapping(BPC.PC); - IsForBlockPCUBInst = false; - UBInstPrecondition = nullptr; if (I == PCMap.end()) PCMap[BPC.PredIdx] = PE; else From 8d50bdf5a058508f0fe2f73c8f52180d88226fea Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sun, 1 Apr 2018 00:35:33 +0200 Subject: [PATCH 27/49] Work --- include/souper/Extractor/ExprBuilder.h | 34 ++------ lib/Extractor/ExprBuilder.cpp | 103 ++++++++++++++++++++++- lib/Extractor/KLEEBuilder.cpp | 111 ++++--------------------- 3 files changed, 125 insertions(+), 123 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index c5a0142f9..05973edd9 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -15,12 +15,10 @@ #ifndef SOUPER_EXTRACTOR_EXPRBUILDER_H #define SOUPER_EXTRACTOR_EXPRBUILDER_H -#include "klee/Expr.h" #include "souper/Inst/Inst.h" #include "souper/Util/UniqueNameSet.h" #include -using namespace klee; using namespace souper; namespace souper { @@ -29,12 +27,10 @@ class ExprBuilder { public: enum Builder { KLEE, + // TODO Z3 }; - // Local reference - InstContext *LIC; - const unsigned MAX_PHI_DEPTH = 25; typedef std::unordered_map> UBPathInstMap; @@ -76,28 +72,16 @@ class ExprBuilder { Inst *getDemandedBitsCondition(Inst *I); Inst *getBlockPCs(Inst *Root); void setBlockPCMap(const BlockPCs &BPCs); - //void recordUBInstruction(Inst *I, Inst *E); std::map getUBInstConstraints(Inst *Root); std::vector getUBPathInsts(Inst *Root); + std::vector getVarInsts(const std::vector Insts); - std::map> BlockPredMap; - - //std::map UBExprMap; + // Local reference + InstContext *LIC; + std::map> BlockPredMap; std::map BlockPCMap; - //std::vector UBPathInsts; UniqueNameSet ArrayNames; - // Holding the precondition, i.e. blockpc, for the UBInst under process. - //Inst *UBInstPrecondition = nullptr; - // Indicate if the UBInst relates to BlockPC - //bool IsForBlockPCUBInst = false; - - struct CandidateExpr { - std::vector> Arrays; - std::vector Vars; - ref E; - }; - CandidateExpr CE; Inst *getExtractInst(Inst *I, unsigned Offset, unsigned W); Inst *getImpliesInst(Inst *Ante, Inst *I); @@ -118,10 +102,10 @@ class ExprBuilder { Inst *lshrExactUB(Inst *I); Inst *ashrExactUB(Inst *I); - virtual llvm::Optional GetCandidateExprForReplacement( - const BlockPCs &BPCs, const std::vector &PCs, - InstMapping Mapping, bool Negate) = 0; - + Inst *GetCandidateInstForReplacement( + const BlockPCs &BPCs, const std::vector &PCs, + InstMapping Mapping, bool Negate); + virtual std::string BuildQuery(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate=false) = 0; diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index b5dc09539..ca5a0324c 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -22,6 +22,10 @@ using namespace souper; ExprBuilder::~ExprBuilder() {} +static llvm::cl::opt ExploitUB( + "souper-exploit-ub", + llvm::cl::desc("Exploit undefined behavior (default=true)"), + llvm::cl::init(true)); static llvm::cl::opt SMTExprBuilder( "souper-smt-expr-builder", llvm::cl::Hidden, @@ -1024,9 +1028,104 @@ std::vector ExprBuilder::getUBPathInsts(Inst *Root) { return Result; } +std::vector ExprBuilder::getVarInsts(const std::vector Insts) { + // breadth-first search + std::set Visited; + std::vector Result; + std::queue Q; + // Populate the queue + for (const auto &I : Insts) + Q.push(I); + while (!Q.empty()) { + Inst *I = Q.front(); + Q.pop(); + if (I->K == Inst::Var) + Result.push_back(I); + if (Visited.insert(I).second) + for (auto Op : I->orderedOps()) + Q.push(Op); + } + + return Result; +} + +// Return a candidate Inst which must be proven valid for the candidate to apply. +Inst *ExprBuilder::GetCandidateInstForReplacement( + const BlockPCs &BPCs, const std::vector &PCs, + InstMapping Mapping, bool Negate) { + Inst *Result = nullptr; + + // Build LHS + Inst *LHS = Mapping.LHS; + Inst *Ante = LIC->getConst(APInt(1, true)); + + // Get demanded bits constraints + Inst *DemandedBits = LIC->getConst(LHS->DemandedBits); + if (!LHS->DemandedBits.isAllOnesValue()) + LHS = LIC->getInst(Inst::And, LHS->Width, {LHS, DemandedBits}); + + // Get UB constraints of LHS + Inst *LHSUB = LIC->getConst(APInt(1, true)); + if (ExploitUB) { + LHSUB = getUBInstCondition(Mapping.LHS); + if (LHSUB == LIC->getConst(APInt(1, false))) + return nullptr; + } + + // Build PCs + for (const auto &PC : PCs) { + Inst *Eq = getInstMapping(PC); + Ante = LIC->getInst(Inst::And, 1, {Ante, Eq}); + // Get UB constraints of PCs + if (ExploitUB) + LHSUB = LIC->getInst(Inst::And, 1, {LHSUB, getUBInstCondition(Eq)}); + } + + // Build BPCs + if (BPCs.size()) { + setBlockPCMap(BPCs); + Ante = LIC->getInst(Inst::And, 1, {Ante, getBlockPCs(Mapping.LHS)}); + } + + // Build RHS + Inst *RHS = Mapping.RHS; + + // Get demanded bits constraints + if (!Mapping.LHS->DemandedBits.isAllOnesValue()) + RHS = LIC->getInst(Inst::And, 1, {RHS, DemandedBits}); + + for (const auto &I : getVarInsts({Mapping.LHS, Mapping.RHS})) + Ante = LIC->getInst(Inst::And, 1, {Ante, getDemandedBitsCondition(I)}); + + // Get UB constraints of RHS + Inst *RHSUB = LIC->getConst(APInt(1, true)); + if (ExploitUB) { + RHSUB = getUBInstCondition(Mapping.RHS); + if (RHSUB == LIC->getConst(APInt(1, false))) + return nullptr; + } + + if (Negate) // (LHS != RHS) + Result = LIC->getInst(Inst::Ne, 1, {LHS, RHS}); + else // (LHS == RHS) + Result = LIC->getInst(Inst::Eq, 1, {LHS, RHS}); + + // Result && RHS UB + if (Mapping.RHS->K != Inst::Const) + Result = LIC->getInst(Inst::And, 1, {Result, RHSUB}); + + // (B)PCs && && LHS UB && (B)PCs UB + Ante = LIC->getInst(Inst::And, 1, {Ante, LHSUB}); + + // ((B)PCs && LHS UB && (B)PCs UB) => Result && RHS UB + Result = getImpliesInst(Ante, Result); + + return Result; +} + std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, - const std::vector &PCs, InstMapping Mapping, - std::vector *ModelVars, bool Negate) { + const std::vector &PCs, InstMapping Mapping, + std::vector *ModelVars, bool Negate) { std::unique_ptr EB; switch (SMTExprBuilder) { case ExprBuilder::KLEE: diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 6ddc48d5d..cd8ad3ec8 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -34,10 +34,6 @@ #include #include -static llvm::cl::opt ExploitUB( - "souper-exploit-ub", - llvm::cl::desc("Exploit undefined behavior (default=true)"), - llvm::cl::init(true)); static llvm::cl::opt DumpKLEEExprs( "dump-klee-exprs", llvm::cl::desc("Dump KLEE expressions after SMTLIB queries"), @@ -56,85 +52,10 @@ class KLEEBuilder : public ExprBuilder { } ~KLEEBuilder() {} - //TODO + std::vector> Arrays; + std::vector Vars; std::map> ExprMap; - // Return an expression which must be proven valid for the candidate to apply. - llvm::Optional GetCandidateExprForReplacement( - const BlockPCs &BPCs, const std::vector &PCs, - InstMapping Mapping, bool Negate) override { - - // Build LHS - ref LHS = get(Mapping.LHS); - ref Ante = klee::ConstantExpr::alloc(1, 1); - - // Get demanded bits constraints - ref DemandedBits = klee::ConstantExpr::alloc(Mapping.LHS->DemandedBits); - if (!Mapping.LHS->DemandedBits.isAllOnesValue()) - LHS = AndExpr::create(LHS, DemandedBits); - - // Get UB constraints of LHS - ref LHSUB = klee::ConstantExpr::create(1, Expr::Bool); - if (ExploitUB) { - LHSUB = get(getUBInstCondition(Mapping.LHS)); - if (LHSUB.isNull()) - return llvm::Optional(); - } - - // Build PCs - for (const auto &PC : PCs) { - Ante = AndExpr::create(Ante, get(getInstMapping(PC))); - // Get UB constraints of PCs - if (ExploitUB) - LHSUB = AndExpr::create(LHSUB, get(getUBInstCondition(getInstMapping(PC)))); - } - - // Build BPCs - if (BPCs.size()) { - setBlockPCMap(BPCs); - // TODO: Get UB constraints of BPCs - Ante = AndExpr::create(Ante, get(getBlockPCs(Mapping.LHS))); - } - - // Build RHS - ref RHS = get(Mapping.RHS); - - // Get demanded bits constraints - if (!Mapping.LHS->DemandedBits.isAllOnesValue()) - RHS = AndExpr::create(RHS, DemandedBits); - - for (const auto I : CE.Vars) { - if (I) - Ante = AndExpr::create(Ante, get(getDemandedBitsCondition(I))); - } - - // Get UB constraints of RHS - ref RHSUB = klee::ConstantExpr::create(1, Expr::Bool); - if (ExploitUB) { - RHSUB = get(getUBInstCondition(Mapping.RHS)); - if (RHSUB.isNull()) - return llvm::Optional(); - } - - ref Cons; - if (Negate) // (LHS != RHS) - Cons = NeExpr::create(LHS, RHS); - else // (LHS == RHS) - Cons = EqExpr::create(LHS, RHS); - - // Cons && RHS UB - if (Mapping.RHS->K != Inst::Const) - Cons = AndExpr::create(Cons, RHSUB); - - // (B)PCs && && LHS UB && (B)PCs UB - Ante = AndExpr::create(Ante, LHSUB); - - // ((B)PCs && LHS UB && (B)PCs UB) => Cons && RHS UB - CE.E = Expr::createImplies(Ante, Cons); - - return llvm::Optional(std::move(CE)); - } - std::string BuildQuery(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, @@ -142,25 +63,23 @@ class KLEEBuilder : public ExprBuilder { std::string SMTStr; llvm::raw_string_ostream SMTSS(SMTStr); ConstraintManager Manager; - Optional OptionalCE = GetCandidateExprForReplacement(BPCs, - PCs, Mapping, Negate); - if (!OptionalCE.hasValue()) + Inst *Candidate = GetCandidateInstForReplacement(BPCs, PCs, Mapping, Negate); + if (!Candidate) return std::string(); - CandidateExpr CE = std::move(OptionalCE.getValue()); - ref E = CE.E; + ref E = get(Candidate); Query KQuery(Manager, E); ExprSMTLIBPrinter Printer; Printer.setOutput(SMTSS); Printer.setQuery(KQuery); - std::vector Arrays; + std::vector Arr; if (ModelVars) { - for (unsigned I = 0; I != CE.Vars.size(); ++I) { - if (CE.Vars[I]) { - Arrays.push_back(CE.Arrays[I].get()); - ModelVars->push_back(CE.Vars[I]); + for (unsigned I = 0; I != Vars.size(); ++I) { + if (Vars[I]) { + Arr.push_back(Arrays[I].get()); + ModelVars->push_back(Vars[I]); } } - Printer.setArrayValuesToGet(Arrays); + Printer.setArrayValuesToGet(Arr); } Printer.generateOutput(); @@ -496,11 +415,11 @@ class KLEEBuilder : public ExprBuilder { NameStr = ("a" + Name).str(); else NameStr = Name; - CE.Arrays.emplace_back( - new Array(ArrayNames.makeName(NameStr), 1, 0, 0, Expr::Int32, Width)); - CE.Vars.push_back(Origin); + Arrays.emplace_back( + new Array(ArrayNames.makeName(NameStr), 1, 0, 0, Expr::Int32, Width)); + Vars.push_back(Origin); - UpdateList UL(CE.Arrays.back().get(), 0); + UpdateList UL(Arrays.back().get(), 0); return ReadExpr::create(UL, klee::ConstantExpr::alloc(0, Expr::Int32)); } From 28fb4b925a11d48c3859995f945f6c78e36ea932 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sun, 1 Apr 2018 23:31:22 +0200 Subject: [PATCH 28/49] Work --- include/souper/Extractor/ExprBuilder.h | 3 ++- lib/Extractor/ExprBuilder.cpp | 27 ++++++++++++++++++++++---- lib/Extractor/KLEEBuilder.cpp | 4 +++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 05973edd9..877386563 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -51,7 +51,8 @@ class ExprBuilder { virtual ~ExprBuilder(); - std::vector getBlockPredicates(Inst *I); + void setBlockPredicates(Inst *I); + void setBlockPredicateMap(Inst *Root); bool getUBPaths(Inst *I, UBPath *Current, std::vector> &Paths, UBPathInstMap &CachedUBPathInsts, unsigned Depth); diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index ca5a0324c..67288b031 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -38,15 +38,14 @@ static llvm::cl::opt SMTExprBuilder( namespace souper { -std::vector ExprBuilder::getBlockPredicates(Inst *I) { +void ExprBuilder::setBlockPredicates(Inst *I) { assert(I->K == Inst::Phi && "not a phi inst"); if (BlockPredMap.count(I->B)) - return BlockPredMap[I->B]; + return; std::vector PredExpr; for (auto const &PredVar : I->B->PredVars) PredExpr.push_back(PredVar); BlockPredMap[I->B] = PredExpr; - return PredExpr; } bool ExprBuilder::getUBPaths(Inst *I, UBPath *Current, @@ -471,7 +470,24 @@ void ExprBuilder::setBlockPCMap(const BlockPCs &BPCs) { PCMap[BPC.PredIdx] = LIC->getInst(Inst::And, 1, {I->second, PE}); } } - + +void ExprBuilder::setBlockPredicateMap(Inst *Root) { + // breadth-first search + std::set Visited; + std::queue Q; + Q.push(Root); + while (!Q.empty()) { + Inst *I = Q.front(); + Q.pop(); + if (I->K == Inst::Phi) + setBlockPredicates(I); + + if (Visited.insert(I).second) + for (auto Op : I->orderedOps()) + Q.push(Op); + } +} + Inst *ExprBuilder::createUBPathInstsPred( Inst *CurrentInst, std::vector &PathInsts, std::map &BlockConstraints, @@ -1064,6 +1080,9 @@ Inst *ExprBuilder::GetCandidateInstForReplacement( if (!LHS->DemandedBits.isAllOnesValue()) LHS = LIC->getInst(Inst::And, LHS->Width, {LHS, DemandedBits}); + // TODO + setBlockPredicateMap(Mapping.LHS); + // Get UB constraints of LHS Inst *LHSUB = LIC->getConst(APInt(1, true)); if (ExploitUB) { diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index cd8ad3ec8..433ec4f6a 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -127,7 +127,9 @@ class KLEEBuilder : public ExprBuilder { case Inst::Var: return makeSizedArrayRead(I->Width, I->Name, I); case Inst::Phi: { - const auto &PredExpr = getBlockPredicates(I); + // TODO: Move to ExprBuilder + const auto &PredExpr = BlockPredMap[I->B]; + assert(PredExpr.size() && "there must be block predicates"); ref E = get(Ops[0]); // e.g. P2 ? (P1 ? Op1_Expr : Op2_Expr) : Op3_Expr for (unsigned J = 1; J < Ops.size(); ++J) { From a5ed68cdb62d062755c664499045cfe5be1a0845 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Thu, 19 Apr 2018 23:14:59 +0200 Subject: [PATCH 29/49] Re-enable extractor tests --- CMakeLists.txt | 10 ++++----- include/souper/Extractor/ExprBuilder.h | 4 ++++ lib/Extractor/KLEEBuilder.cpp | 19 +++++++++++++++++ unittests/Extractor/ExtractorTests.cpp | 29 +++++++------------------- 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a3e2362ea..6e66ba6da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -260,9 +260,9 @@ add_executable(souper-check tools/souper-check.cpp ) -#add_executable(extractor_tests -# unittests/Extractor/ExtractorTests.cpp -#) +add_executable(extractor_tests + unittests/Extractor/ExtractorTests.cpp +) add_executable(inst_tests unittests/Inst/InstTests.cpp @@ -276,7 +276,7 @@ set_target_properties(souper internal-solver-test lexer-test parser-test souper- PROPERTIES COMPILE_FLAGS "${LLVM_CXXFLAGS}") set_target_properties(souperClangTool clang-souper PROPERTIES COMPILE_FLAGS "${CLANG_CXXFLAGS} ${LLVM_CXXFLAGS}") -set_target_properties(inst_tests parser_tests +set_target_properties(extractor_tests inst_tests parser_tests PROPERTIES COMPILE_FLAGS "${GTEST_CXXFLAGS} ${LLVM_CXXFLAGS}") target_link_libraries(kleeExpr ${LLVM_LIBS} ${LLVM_LDFLAGS}) @@ -296,7 +296,7 @@ target_link_libraries(lexer-test souperParser) target_link_libraries(parser-test souperParser) target_link_libraries(souper-check souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(clang-souper souperClangTool souperExtractor souperKVStore souperParser souperSMTLIB2 souperTool kleeExpr ${CLANG_LIBS} ${LLVM_LIBS} ${LLVM_LDFLAGS} ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) -#target_link_libraries(extractor_tests souperExtractor ${GTEST_LIBS}) +target_link_libraries(extractor_tests souperExtractor ${GTEST_LIBS}) target_link_libraries(inst_tests souperInst ${GTEST_LIBS}) target_link_libraries(parser_tests souperParser ${GTEST_LIBS}) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 877386563..d04be35dc 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -107,6 +107,10 @@ class ExprBuilder { const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool Negate); + virtual std::string GetExprStr(const BlockPCs &BPCs, + const std::vector &PCs, InstMapping Mapping, + std::vector *ModelVars, bool Negate=false) = 0; + virtual std::string BuildQuery(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate=false) = 0; diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 433ec4f6a..71de87ee2 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -56,6 +56,25 @@ class KLEEBuilder : public ExprBuilder { std::vector Vars; std::map> ExprMap; + std::string GetExprStr(const BlockPCs &BPCs, + const std::vector &PCs, + InstMapping Mapping, + std::vector *ModelVars, bool Negate) override { + Inst *Candidate = GetCandidateExprForReplacement(BPCs, PCs, Mapping, Negate); + if (!Candidate) + return std::string(); + ref E = get(Candidate); + + std::string SStr; + llvm::raw_string_ostream SS(SStr); + std::unique_ptr PP(ExprPPrinter::create(SS)); + PP->setForceNoLineBreaks(true); + PP->scan(E); + PP->print(E); + + return SS.str(); + } + std::string BuildQuery(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, diff --git a/unittests/Extractor/ExtractorTests.cpp b/unittests/Extractor/ExtractorTests.cpp index f06b199e2..111fe2130 100644 --- a/unittests/Extractor/ExtractorTests.cpp +++ b/unittests/Extractor/ExtractorTests.cpp @@ -12,9 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "klee/Expr.h" -#include "klee/util/ExprPPrinter.h" -#include "klee/util/PrintContext.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -24,7 +21,6 @@ #include #include "gtest/gtest.h" -using namespace klee; using namespace llvm; using namespace souper; @@ -36,7 +32,7 @@ struct ExtractorTest : testing::Test { InstContext IC; ExprBuilderContext EBC; FunctionCandidateSet CS; - std::vector> CandExprs; + std::vector CandExprs; bool extractFromIR(const char *IR) { SMDiagnostic Err; @@ -63,10 +59,9 @@ struct ExtractorTest : testing::Test { IC.getConst(APInt(1, true)) }; for (auto I : Guesses) { R.Mapping.RHS = I; - std::unique_ptr CE( - new CandidateExpr(GetCandidateExprForReplacement(R.BPCs, R.PCs, - R.Mapping, false).getValue())); - CandExprs.emplace_back(std::move(CE)); + std::unique_ptr EB = createKLEEBuilder(IC); + std::string Cand = EB->GetExprStr(R.BPCs, R.PCs, R.Mapping, 0); + CandExprs.emplace_back(Cand); } } } @@ -91,15 +86,7 @@ struct ExtractorTest : testing::Test { bool hasCandidateExpr(std::string Expected) { for (const auto &Cand : CandExprs) { - std::string SStr; - llvm::raw_string_ostream SS(SStr); - - std::unique_ptr PP(ExprPPrinter::create(SS)); - PP->setForceNoLineBreaks(true); - PP->scan(Cand->E); - PP->print(Cand->E); - - if (SS.str() == Expected) + if (Cand == Expected) return true; } return false; @@ -136,9 +123,9 @@ define void @f(i32 %p, i32 %q) { )m")); EXPECT_TRUE(hasCandidateExpr( - "(Or (And (Eq N0:(Extract 31 N1:(Read w32 0 p)) (Extract 31 N2:(Read w32 " - "0 q))) (Eq false (Eq N0 (Extract 31 N3:(Add w32 N1 N2))))) (Ult N1 " - "N3))")); + "(Or (And (Eq N0:(Extract 0 (AShr w32 N1:(Read w32 0 p) 31)) (Extract 0 " + "(AShr w32 N2:(Read w32 0 q) 31))) (Eq false (Eq N0 (Extract 0 (AShr w32 " + "N3:(Add w32 N1 N2) 31))))) (Ult N1 N3))")); } TEST_F(ExtractorTest, PhiCond) { From 63c912444f38af78e6fe75672cda4af1dad56867 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Thu, 19 Apr 2018 23:15:50 +0200 Subject: [PATCH 30/49] Remove ExploitUB option, always exploit UB --- include/souper/Extractor/ExprBuilder.h | 6 +- lib/Extractor/ExprBuilder.cpp | 32 +- lib/Extractor/KLEEBuilder.cpp | 2 +- test/Solver/add-nsw-no-ub.ll | 12 - test/Tool/too-many-phis.opt | 1881 ------------------------ 5 files changed, 11 insertions(+), 1922 deletions(-) delete mode 100644 test/Solver/add-nsw-no-ub.ll delete mode 100644 test/Tool/too-many-phis.opt diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index d04be35dc..51a923223 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -26,9 +26,7 @@ namespace souper { class ExprBuilder { public: enum Builder { - KLEE, - // TODO - Z3 + KLEE }; const unsigned MAX_PHI_DEPTH = 25; @@ -103,7 +101,7 @@ class ExprBuilder { Inst *lshrExactUB(Inst *I); Inst *ashrExactUB(Inst *I); - Inst *GetCandidateInstForReplacement( + Inst *GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool Negate); diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 67288b031..fc3285d88 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -22,18 +22,12 @@ using namespace souper; ExprBuilder::~ExprBuilder() {} -static llvm::cl::opt ExploitUB( - "souper-exploit-ub", - llvm::cl::desc("Exploit undefined behavior (default=true)"), - llvm::cl::init(true)); static llvm::cl::opt SMTExprBuilder( "souper-smt-expr-builder", llvm::cl::Hidden, llvm::cl::desc("SMT-LIBv2 expression builder (default=klee)"), llvm::cl::values(clEnumValN(souper::ExprBuilder::KLEE, "klee", - "Use KLEE's Expr library"), - clEnumValN(souper::ExprBuilder::Z3, "z3", - "Use Z3's API")), + "Use KLEE's Expr library")), llvm::cl::init(souper::ExprBuilder::KLEE)); namespace souper { @@ -1066,7 +1060,7 @@ std::vector ExprBuilder::getVarInsts(const std::vector Insts) { } // Return a candidate Inst which must be proven valid for the candidate to apply. -Inst *ExprBuilder::GetCandidateInstForReplacement( +Inst *ExprBuilder::GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool Negate) { Inst *Result = nullptr; @@ -1084,20 +1078,16 @@ Inst *ExprBuilder::GetCandidateInstForReplacement( setBlockPredicateMap(Mapping.LHS); // Get UB constraints of LHS - Inst *LHSUB = LIC->getConst(APInt(1, true)); - if (ExploitUB) { - LHSUB = getUBInstCondition(Mapping.LHS); - if (LHSUB == LIC->getConst(APInt(1, false))) + Inst *LHSUB = getUBInstCondition(Mapping.LHS); + if (LHSUB == LIC->getConst(APInt(1, false))) return nullptr; - } // Build PCs for (const auto &PC : PCs) { Inst *Eq = getInstMapping(PC); Ante = LIC->getInst(Inst::And, 1, {Ante, Eq}); // Get UB constraints of PCs - if (ExploitUB) - LHSUB = LIC->getInst(Inst::And, 1, {LHSUB, getUBInstCondition(Eq)}); + LHSUB = LIC->getInst(Inst::And, 1, {LHSUB, getUBInstCondition(Eq)}); } // Build BPCs @@ -1117,12 +1107,9 @@ Inst *ExprBuilder::GetCandidateInstForReplacement( Ante = LIC->getInst(Inst::And, 1, {Ante, getDemandedBitsCondition(I)}); // Get UB constraints of RHS - Inst *RHSUB = LIC->getConst(APInt(1, true)); - if (ExploitUB) { - RHSUB = getUBInstCondition(Mapping.RHS); - if (RHSUB == LIC->getConst(APInt(1, false))) - return nullptr; - } + Inst *RHSUB = getUBInstCondition(Mapping.RHS); + if (RHSUB == LIC->getConst(APInt(1, false))) + return nullptr; if (Negate) // (LHS != RHS) Result = LIC->getInst(Inst::Ne, 1, {LHS, RHS}); @@ -1150,9 +1137,6 @@ std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, case ExprBuilder::KLEE: EB = createKLEEBuilder(IC); break; - case ExprBuilder::Z3: - report_fatal_error("not supported yet"); - break; default: report_fatal_error("cannot reach here"); break; diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 71de87ee2..f8112057a 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -82,7 +82,7 @@ class KLEEBuilder : public ExprBuilder { std::string SMTStr; llvm::raw_string_ostream SMTSS(SMTStr); ConstraintManager Manager; - Inst *Candidate = GetCandidateInstForReplacement(BPCs, PCs, Mapping, Negate); + Inst *Candidate = GetCandidateExprForReplacement(BPCs, PCs, Mapping, Negate); if (!Candidate) return std::string(); ref E = get(Candidate); diff --git a/test/Solver/add-nsw-no-ub.ll b/test/Solver/add-nsw-no-ub.ll deleted file mode 100644 index 14844876b..000000000 --- a/test/Solver/add-nsw-no-ub.ll +++ /dev/null @@ -1,12 +0,0 @@ -; REQUIRES: solver - -; RUN: %llvm-as -o %t %s -; RUN: %souper %solver -souper-exploit-ub=false -check %t - -define i32 @foo(i32 %x) { -entry: - %add = add nsw i32 %x, 1 - %cmp = icmp sgt i32 %add, %x - %conv = zext i1 %cmp to i32 - ret i32 %conv -} diff --git a/test/Tool/too-many-phis.opt b/test/Tool/too-many-phis.opt deleted file mode 100644 index 4eaef74ad..000000000 --- a/test/Tool/too-many-phis.opt +++ /dev/null @@ -1,1881 +0,0 @@ -; REQUIRES: solver -; RUN: ! %souper-check %solver -print-counterexample=false %s > %t 2>&1 -; RUN: %FileCheck %s < %t -; CHECK: Value too large - -%0 = block 2 -%1:i64 = var -%2:i64 = add 12:i64, %1 -%3:i64 = shl %2, 52:i64 -%4:i64 = lshr %2, 12:i64 -%5:i64 = or %3, %4 -%6:i64 = var -%7:i64 = var -%8:i64 = add 12:i64, %7 -%9:i64 = shl %8, 52:i64 -%10:i64 = lshr %8, 12:i64 -%11:i64 = or %9, %10 -%12:i64 = var -%13:i64 = var -%14:i64 = add 12:i64, %13 -%15:i64 = shl %14, 52:i64 -%16:i64 = lshr %14, 12:i64 -%17:i64 = or %15, %16 -%18:i64 = var -%19:i64 = var -%20:i64 = add 12:i64, %19 -%21:i64 = shl %20, 52:i64 -%22:i64 = lshr %20, 12:i64 -%23:i64 = or %21, %22 -%24:i64 = var -%25:i64 = var -%26:i64 = add 12:i64, %25 -%27:i64 = shl %26, 52:i64 -%28:i64 = lshr %26, 12:i64 -%29:i64 = or %27, %28 -%30:i64 = var -%31:i64 = var -%32:i64 = add 12:i64, %31 -%33:i64 = shl %32, 52:i64 -%34:i64 = lshr %32, 12:i64 -%35:i64 = or %33, %34 -%36:i64 = var -%37:i64 = var -%38:i64 = add 12:i64, %37 -%39:i64 = shl %38, 52:i64 -%40:i64 = lshr %38, 12:i64 -%41:i64 = or %39, %40 -%42:i64 = var -%43:i64 = var -%44:i64 = add 12:i64, %43 -%45:i64 = shl %44, 52:i64 -%46:i64 = lshr %44, 12:i64 -%47:i64 = or %45, %46 -%48:i64 = var -%49:i64 = var -%50:i64 = add 12:i64, %49 -%51:i64 = shl %50, 52:i64 -%52:i64 = lshr %50, 12:i64 -%53:i64 = or %51, %52 -%54:i64 = var -%55:i64 = var -%56:i64 = add 12:i64, %55 -%57:i64 = shl %56, 52:i64 -%58:i64 = lshr %56, 12:i64 -%59:i64 = or %57, %58 -%60:i64 = var -%61:i64 = var -%62:i64 = add 12:i64, %61 -%63:i64 = shl %62, 52:i64 -%64:i64 = lshr %62, 12:i64 -%65:i64 = or %63, %64 -%66:i64 = var -%67:i64 = var -%68:i64 = add 12:i64, %67 -%69:i64 = shl %68, 52:i64 -%70:i64 = lshr %68, 12:i64 -%71:i64 = or %69, %70 -%72:i64 = var -%73:i64 = var -%74:i64 = add 12:i64, %73 -%75:i64 = shl %74, 52:i64 -%76:i64 = lshr %74, 12:i64 -%77:i64 = or %75, %76 -%78:i64 = var -%79:i64 = var -%80:i64 = add 12:i64, %79 -%81:i64 = shl %80, 52:i64 -%82:i64 = lshr %80, 12:i64 -%83:i64 = or %81, %82 -%84:i64 = var -%85:i64 = var -%86:i64 = add 12:i64, %85 -%87:i64 = shl %86, 52:i64 -%88:i64 = lshr %86, 12:i64 -%89:i64 = or %87, %88 -%90:i64 = var -%91:i64 = var -%92:i64 = add 12:i64, %91 -%93:i64 = shl %92, 52:i64 -%94:i64 = lshr %92, 12:i64 -%95:i64 = or %93, %94 -%96:i64 = var -%97:i64 = var -%98:i64 = add 12:i64, %97 -%99:i64 = shl %98, 52:i64 -%100:i64 = lshr %98, 12:i64 -%101:i64 = or %99, %100 -%102:i64 = var -%103:i64 = var -%104:i64 = add 12:i64, %103 -%105:i64 = shl %104, 52:i64 -%106:i64 = lshr %104, 12:i64 -%107:i64 = or %105, %106 -%108:i64 = var -%109:i64 = var -%110:i64 = add 12:i64, %109 -%111:i64 = shl %110, 52:i64 -%112:i64 = lshr %110, 12:i64 -%113:i64 = or %111, %112 -%114:i64 = var -%115:i64 = var -%116:i64 = add 12:i64, %115 -%117:i64 = shl %116, 52:i64 -%118:i64 = lshr %116, 12:i64 -%119:i64 = or %117, %118 -%120:i64 = var -%121:i64 = var -%122:i64 = add 12:i64, %121 -%123:i64 = shl %122, 52:i64 -%124:i64 = lshr %122, 12:i64 -%125:i64 = or %123, %124 -%126:i64 = var -%127:i64 = var -%128:i64 = add 12:i64, %127 -%129:i64 = shl %128, 52:i64 -%130:i64 = lshr %128, 12:i64 -%131:i64 = or %129, %130 -%132:i64 = var -%133:i64 = var -%134:i64 = add 12:i64, %133 -%135:i64 = shl %134, 52:i64 -%136:i64 = lshr %134, 12:i64 -%137:i64 = or %135, %136 -%138:i64 = var -%139:i64 = var -%140:i64 = add 12:i64, %139 -%141:i64 = shl %140, 52:i64 -%142:i64 = lshr %140, 12:i64 -%143:i64 = or %141, %142 -%144:i64 = var -%145:i64 = var -%146:i64 = add 12:i64, %145 -%147:i64 = shl %146, 52:i64 -%148:i64 = lshr %146, 12:i64 -%149:i64 = or %147, %148 -%150:i64 = var -%151:i64 = var -%152:i64 = add 12:i64, %151 -%153:i64 = shl %152, 52:i64 -%154:i64 = lshr %152, 12:i64 -%155:i64 = or %153, %154 -%156:i64 = var -%157:i64 = var -%158:i64 = add 12:i64, %157 -%159:i64 = shl %158, 52:i64 -%160:i64 = lshr %158, 12:i64 -%161:i64 = or %159, %160 -%162:i64 = var -%163:i64 = var -%164:i64 = add 12:i64, %163 -%165:i64 = shl %164, 52:i64 -%166:i64 = lshr %164, 12:i64 -%167:i64 = or %165, %166 -%168:i64 = var -%169:i64 = var -%170:i64 = add 12:i64, %169 -%171:i64 = shl %170, 52:i64 -%172:i64 = lshr %170, 12:i64 -%173:i64 = or %171, %172 -%174:i64 = var -%175:i64 = var -%176:i64 = add 12:i64, %175 -%177:i64 = shl %176, 52:i64 -%178:i64 = lshr %176, 12:i64 -%179:i64 = or %177, %178 -%180:i64 = var -%181:i64 = var -%182:i64 = add 12:i64, %181 -%183:i64 = shl %182, 52:i64 -%184:i64 = lshr %182, 12:i64 -%185:i64 = or %183, %184 -%186:i64 = var -%187:i64 = var -%188:i64 = add 12:i64, %187 -%189:i64 = shl %188, 52:i64 -%190:i64 = lshr %188, 12:i64 -%191:i64 = or %189, %190 -%192:i64 = var -%193:i64 = var -%194:i64 = add 12:i64, %193 -%195:i64 = shl %194, 52:i64 -%196:i64 = lshr %194, 12:i64 -%197:i64 = or %195, %196 -%198:i64 = var -%199:i64 = var -%200:i64 = add 12:i64, %199 -%201:i64 = shl %200, 52:i64 -%202:i64 = lshr %200, 12:i64 -%203:i64 = or %201, %202 -%204:i64 = var -%205:i64 = var -%206:i64 = add 12:i64, %205 -%207:i64 = shl %206, 52:i64 -%208:i64 = lshr %206, 12:i64 -%209:i64 = or %207, %208 -%210:i64 = var -%211:i64 = var -%212:i64 = add 12:i64, %211 -%213:i64 = shl %212, 52:i64 -%214:i64 = lshr %212, 12:i64 -%215:i64 = or %213, %214 -%216:i64 = var -%217:i64 = var -%218:i64 = add 12:i64, %217 -%219:i64 = shl %218, 52:i64 -%220:i64 = lshr %218, 12:i64 -%221:i64 = or %219, %220 -%222:i64 = var -%223:i64 = var -%224:i64 = add 12:i64, %223 -%225:i64 = shl %224, 52:i64 -%226:i64 = lshr %224, 12:i64 -%227:i64 = or %225, %226 -%228:i64 = var -%229:i64 = var -%230:i64 = add 12:i64, %229 -%231:i64 = shl %230, 52:i64 -%232:i64 = lshr %230, 12:i64 -%233:i64 = or %231, %232 -%234:i64 = var -%235:i64 = var -%236:i64 = add 12:i64, %235 -%237:i64 = shl %236, 52:i64 -%238:i64 = lshr %236, 12:i64 -%239:i64 = or %237, %238 -%240:i64 = var -%241:i64 = var -%242:i64 = add 12:i64, %241 -%243:i64 = shl %242, 52:i64 -%244:i64 = lshr %242, 12:i64 -%245:i64 = or %243, %244 -%246:i64 = var -%247:i64 = var -%248:i64 = add 12:i64, %247 -%249:i64 = shl %248, 52:i64 -%250:i64 = lshr %248, 12:i64 -%251:i64 = or %249, %250 -%252:i64 = var -%253:i64 = var -%254:i64 = add 12:i64, %253 -%255:i64 = shl %254, 52:i64 -%256:i64 = lshr %254, 12:i64 -%257:i64 = or %255, %256 -%258:i64 = var -%259:i64 = var -%260:i64 = add 12:i64, %259 -%261:i64 = shl %260, 52:i64 -%262:i64 = lshr %260, 12:i64 -%263:i64 = or %261, %262 -%264:i64 = var -%265:i64 = var -%266:i64 = add 12:i64, %265 -%267:i64 = shl %266, 52:i64 -%268:i64 = lshr %266, 12:i64 -%269:i64 = or %267, %268 -%270:i64 = var -%271:i64 = var -%272:i64 = add 12:i64, %271 -%273:i64 = shl %272, 52:i64 -%274:i64 = lshr %272, 12:i64 -%275:i64 = or %273, %274 -%276:i64 = var -%277:i64 = var -%278:i64 = add 12:i64, %277 -%279:i64 = shl %278, 52:i64 -%280:i64 = lshr %278, 12:i64 -%281:i64 = or %279, %280 -%282:i64 = var -%283:i64 = var -%284:i64 = add 12:i64, %283 -%285:i64 = shl %284, 52:i64 -%286:i64 = lshr %284, 12:i64 -%287:i64 = or %285, %286 -%288:i64 = var -%289:i64 = var -%290:i64 = add 12:i64, %289 -%291:i64 = shl %290, 52:i64 -%292:i64 = lshr %290, 12:i64 -%293:i64 = or %291, %292 -%294:i64 = var -%295:i64 = var -%296:i64 = add 12:i64, %295 -%297:i64 = shl %296, 52:i64 -%298:i64 = lshr %296, 12:i64 -%299:i64 = or %297, %298 -%300:i64 = var -%301:i64 = var -%302:i64 = add 12:i64, %301 -%303:i64 = shl %302, 52:i64 -%304:i64 = lshr %302, 12:i64 -%305:i64 = or %303, %304 -%306:i64 = var -%307:i64 = var -%308:i64 = add 12:i64, %307 -%309:i64 = shl %308, 52:i64 -%310:i64 = lshr %308, 12:i64 -%311:i64 = or %309, %310 -%312:i64 = var -%313:i64 = var -%314:i64 = add 12:i64, %313 -%315:i64 = shl %314, 52:i64 -%316:i64 = lshr %314, 12:i64 -%317:i64 = or %315, %316 -%318:i64 = var -%319:i64 = var -%320:i64 = add 12:i64, %319 -%321:i64 = shl %320, 52:i64 -%322:i64 = lshr %320, 12:i64 -%323:i64 = or %321, %322 -%324:i64 = var -%325:i64 = var -%326:i64 = add 12:i64, %325 -%327:i64 = shl %326, 52:i64 -%328:i64 = lshr %326, 12:i64 -%329:i64 = or %327, %328 -%330:i64 = var -%331:i64 = var -%332:i64 = add 12:i64, %331 -%333:i64 = shl %332, 52:i64 -%334:i64 = lshr %332, 12:i64 -%335:i64 = or %333, %334 -%336:i64 = var -%337:i64 = var -%338:i64 = add 12:i64, %337 -%339:i64 = shl %338, 52:i64 -%340:i64 = lshr %338, 12:i64 -%341:i64 = or %339, %340 -%342:i64 = var -%343:i64 = var -%344:i64 = add 12:i64, %343 -%345:i64 = shl %344, 52:i64 -%346:i64 = lshr %344, 12:i64 -%347:i64 = or %345, %346 -%348:i64 = var -%349:i64 = var -%350:i64 = add 12:i64, %349 -%351:i64 = shl %350, 52:i64 -%352:i64 = lshr %350, 12:i64 -%353:i64 = or %351, %352 -%354:i64 = var -%355:i64 = var -%356:i64 = add 12:i64, %355 -%357:i64 = shl %356, 52:i64 -%358:i64 = lshr %356, 12:i64 -%359:i64 = or %357, %358 -%360:i64 = var -%361:i64 = var -%362:i64 = add 12:i64, %361 -%363:i64 = shl %362, 52:i64 -%364:i64 = lshr %362, 12:i64 -%365:i64 = or %363, %364 -%366:i64 = var -%367:i64 = var -%368:i64 = add 12:i64, %367 -%369:i64 = shl %368, 52:i64 -%370:i64 = lshr %368, 12:i64 -%371:i64 = or %369, %370 -%372:i64 = var -%373:i64 = var -%374:i64 = add 12:i64, %373 -%375:i64 = shl %374, 52:i64 -%376:i64 = lshr %374, 12:i64 -%377:i64 = or %375, %376 -%378:i64 = var -%379:i64 = var -%380:i64 = add 12:i64, %379 -%381:i64 = shl %380, 52:i64 -%382:i64 = lshr %380, 12:i64 -%383:i64 = or %381, %382 -%384:i64 = var -%385:i64 = var -%386:i64 = add 12:i64, %385 -%387:i64 = shl %386, 52:i64 -%388:i64 = lshr %386, 12:i64 -%389:i64 = or %387, %388 -%390:i64 = var -%391:i64 = var -%392:i64 = add 12:i64, %391 -%393:i64 = shl %392, 52:i64 -%394:i64 = lshr %392, 12:i64 -%395:i64 = or %393, %394 -%396:i64 = var -%397:i64 = var -%398:i64 = add 12:i64, %397 -%399:i64 = shl %398, 52:i64 -%400:i64 = lshr %398, 12:i64 -%401:i64 = or %399, %400 -%402:i64 = var -%403:i64 = var -%404:i64 = add 12:i64, %403 -%405:i64 = shl %404, 52:i64 -%406:i64 = lshr %404, 12:i64 -%407:i64 = or %405, %406 -%408:i64 = var -%409:i64 = var -%410:i64 = add 12:i64, %409 -%411:i64 = shl %410, 52:i64 -%412:i64 = lshr %410, 12:i64 -%413:i64 = or %411, %412 -%414:i64 = var -%415:i64 = var -%416:i64 = add 12:i64, %415 -%417:i64 = shl %416, 52:i64 -%418:i64 = lshr %416, 12:i64 -%419:i64 = or %417, %418 -%420:i64 = var -%421:i64 = var -%422:i64 = add 12:i64, %421 -%423:i64 = shl %422, 52:i64 -%424:i64 = lshr %422, 12:i64 -%425:i64 = or %423, %424 -%426:i64 = var -%427:i64 = var -%428:i64 = add 12:i64, %427 -%429:i64 = shl %428, 52:i64 -%430:i64 = lshr %428, 12:i64 -%431:i64 = or %429, %430 -%432:i64 = var -%433:i64 = var -%434:i64 = add 12:i64, %433 -%435:i64 = shl %434, 52:i64 -%436:i64 = lshr %434, 12:i64 -%437:i64 = or %435, %436 -%438:i64 = var -%439:i64 = var -%440:i64 = add 12:i64, %439 -%441:i64 = shl %440, 52:i64 -%442:i64 = lshr %440, 12:i64 -%443:i64 = or %441, %442 -%444:i64 = var -%445:i64 = var -%446:i64 = add 12:i64, %445 -%447:i64 = shl %446, 52:i64 -%448:i64 = lshr %446, 12:i64 -%449:i64 = or %447, %448 -%450:i64 = var -%451:i64 = var -%452:i64 = add 12:i64, %451 -%453:i64 = shl %452, 52:i64 -%454:i64 = lshr %452, 12:i64 -%455:i64 = or %453, %454 -%456:i64 = var -%457:i64 = var -%458:i64 = add 12:i64, %457 -%459:i64 = shl %458, 52:i64 -%460:i64 = lshr %458, 12:i64 -%461:i64 = or %459, %460 -%462:i64 = var -%463:i64 = var -%464:i64 = add 12:i64, %463 -%465:i64 = shl %464, 52:i64 -%466:i64 = lshr %464, 12:i64 -%467:i64 = or %465, %466 -%468:i64 = var -%469:i64 = var -%470:i64 = add 12:i64, %469 -%471:i64 = shl %470, 52:i64 -%472:i64 = lshr %470, 12:i64 -%473:i64 = or %471, %472 -%474:i64 = var -%475:i64 = var -%476:i64 = add 12:i64, %475 -%477:i64 = shl %476, 52:i64 -%478:i64 = lshr %476, 12:i64 -%479:i64 = or %477, %478 -%480:i64 = var -%481:i64 = var -%482:i64 = add 12:i64, %481 -%483:i64 = shl %482, 52:i64 -%484:i64 = lshr %482, 12:i64 -%485:i64 = or %483, %484 -%486:i64 = var -%487:i64 = var -%488:i64 = add 12:i64, %487 -%489:i64 = shl %488, 52:i64 -%490:i64 = lshr %488, 12:i64 -%491:i64 = or %489, %490 -%492:i64 = var -%493:i64 = var -%494:i64 = add 12:i64, %493 -%495:i64 = shl %494, 52:i64 -%496:i64 = lshr %494, 12:i64 -%497:i64 = or %495, %496 -%498:i64 = var -%499:i64 = var -%500:i64 = add 12:i64, %499 -%501:i64 = shl %500, 52:i64 -%502:i64 = lshr %500, 12:i64 -%503:i64 = or %501, %502 -%504:i64 = var -%505:i64 = var -%506:i64 = add 12:i64, %505 -%507:i64 = shl %506, 52:i64 -%508:i64 = lshr %506, 12:i64 -%509:i64 = or %507, %508 -%510:i64 = var -%511:i64 = var -%512:i64 = add 12:i64, %511 -%513:i64 = shl %512, 52:i64 -%514:i64 = lshr %512, 12:i64 -%515:i64 = or %513, %514 -%516:i64 = var -%517:i64 = var -%518:i64 = add 12:i64, %517 -%519:i64 = shl %518, 52:i64 -%520:i64 = lshr %518, 12:i64 -%521:i64 = or %519, %520 -%522:i64 = var -%523:i64 = var -%524:i64 = add 12:i64, %523 -%525:i64 = shl %524, 52:i64 -%526:i64 = lshr %524, 12:i64 -%527:i64 = or %525, %526 -%528:i64 = var -%529:i64 = var -%530:i64 = add 12:i64, %529 -%531:i64 = shl %530, 52:i64 -%532:i64 = lshr %530, 12:i64 -%533:i64 = or %531, %532 -%534:i64 = var -%535:i64 = var -%536:i64 = add 12:i64, %535 -%537:i64 = shl %536, 52:i64 -%538:i64 = lshr %536, 12:i64 -%539:i64 = or %537, %538 -%540:i64 = var -%541:i64 = var -%542:i64 = add 12:i64, %541 -%543:i64 = shl %542, 52:i64 -%544:i64 = lshr %542, 12:i64 -%545:i64 = or %543, %544 -%546:i64 = var -%547:i64 = var -%548:i64 = add 12:i64, %547 -%549:i64 = shl %548, 52:i64 -%550:i64 = lshr %548, 12:i64 -%551:i64 = or %549, %550 -%552:i64 = var -%553:i64 = var -%554:i64 = add 12:i64, %553 -%555:i64 = shl %554, 52:i64 -%556:i64 = lshr %554, 12:i64 -%557:i64 = or %555, %556 -%558:i64 = var -%559:i64 = var -%560:i64 = add 12:i64, %559 -%561:i64 = shl %560, 52:i64 -%562:i64 = lshr %560, 12:i64 -%563:i64 = or %561, %562 -%564:i64 = var -%565:i64 = var -%566:i64 = add 12:i64, %565 -%567:i64 = shl %566, 52:i64 -%568:i64 = lshr %566, 12:i64 -%569:i64 = or %567, %568 -%570:i64 = var -%571:i64 = var -%572:i64 = add 12:i64, %571 -%573:i64 = shl %572, 52:i64 -%574:i64 = lshr %572, 12:i64 -%575:i64 = or %573, %574 -%576:i64 = var -%577:i64 = var -%578:i64 = add 12:i64, %577 -%579:i64 = shl %578, 52:i64 -%580:i64 = lshr %578, 12:i64 -%581:i64 = or %579, %580 -%582:i64 = var -%583:i64 = var -%584:i64 = add 12:i64, %583 -%585:i64 = shl %584, 52:i64 -%586:i64 = lshr %584, 12:i64 -%587:i64 = or %585, %586 -%588:i64 = var -%589:i64 = var -%590:i64 = add 12:i64, %589 -%591:i64 = shl %590, 52:i64 -%592:i64 = lshr %590, 12:i64 -%593:i64 = or %591, %592 -%594:i64 = var -%595:i64 = var -%596:i64 = add 12:i64, %595 -%597:i64 = shl %596, 52:i64 -%598:i64 = lshr %596, 12:i64 -%599:i64 = or %597, %598 -%600:i64 = var -%601:i64 = var -%602:i64 = add 12:i64, %601 -%603:i64 = shl %602, 52:i64 -%604:i64 = lshr %602, 12:i64 -%605:i64 = or %603, %604 -%606:i64 = var -%607:i64 = var -%608:i64 = add 12:i64, %607 -%609:i64 = shl %608, 52:i64 -%610:i64 = lshr %608, 12:i64 -%611:i64 = or %609, %610 -%612:i64 = var -%613:i64 = var -%614:i64 = add 12:i64, %613 -%615:i64 = shl %614, 52:i64 -%616:i64 = lshr %614, 12:i64 -%617:i64 = or %615, %616 -%618:i64 = var -%619:i64 = var -%620:i64 = add 12:i64, %619 -%621:i64 = shl %620, 52:i64 -%622:i64 = lshr %620, 12:i64 -%623:i64 = or %621, %622 -%624:i64 = var -%625:i64 = var -%626:i64 = add 12:i64, %625 -%627:i64 = shl %626, 52:i64 -%628:i64 = lshr %626, 12:i64 -%629:i64 = or %627, %628 -%630:i64 = var -%631:i64 = var -%632:i64 = add 12:i64, %631 -%633:i64 = shl %632, 52:i64 -%634:i64 = lshr %632, 12:i64 -%635:i64 = or %633, %634 -%636:i64 = var -%637:i64 = var -%638:i64 = add 12:i64, %637 -%639:i64 = shl %638, 52:i64 -%640:i64 = lshr %638, 12:i64 -%641:i64 = or %639, %640 -%642:i64 = var -%643:i64 = var -%644:i64 = add 12:i64, %643 -%645:i64 = shl %644, 52:i64 -%646:i64 = lshr %644, 12:i64 -%647:i64 = or %645, %646 -%648:i64 = var -%649:i64 = var -%650:i64 = add 12:i64, %649 -%651:i64 = shl %650, 52:i64 -%652:i64 = lshr %650, 12:i64 -%653:i64 = or %651, %652 -%654:i64 = var -%655:i64 = var -%656:i64 = xor %654, %655 -%657:i64 = xor %653, %656 -%658:i64 = mul 11376068507788127593:i64, %657 -%659:i64 = xor %658, %653 -%660:i64 = lshr %658, 47:i64 -%661:i64 = xor %659, %660 -%662:i64 = mul 11376068507788127593:i64, %661 -%663:i64 = lshr %662, 47:i64 -%664:i64 = xor %662, %663 -%665:i64 = mul 11376068507788127593:i64, %664 -%666:i64 = xor %649, %665 -%667:i64 = xor %648, %666 -%668:i64 = xor %647, %667 -%669:i64 = mul 11376068507788127593:i64, %668 -%670:i64 = xor %669, %647 -%671:i64 = lshr %669, 47:i64 -%672:i64 = xor %670, %671 -%673:i64 = mul 11376068507788127593:i64, %672 -%674:i64 = lshr %673, 47:i64 -%675:i64 = xor %673, %674 -%676:i64 = mul 11376068507788127593:i64, %675 -%677:i64 = xor %643, %676 -%678:i64 = xor %642, %677 -%679:i64 = xor %641, %678 -%680:i64 = mul 11376068507788127593:i64, %679 -%681:i64 = xor %680, %641 -%682:i64 = lshr %680, 47:i64 -%683:i64 = xor %681, %682 -%684:i64 = mul 11376068507788127593:i64, %683 -%685:i64 = lshr %684, 47:i64 -%686:i64 = xor %684, %685 -%687:i64 = mul 11376068507788127593:i64, %686 -%688:i64 = xor %637, %687 -%689:i64 = xor %636, %688 -%690:i64 = xor %635, %689 -%691:i64 = mul 11376068507788127593:i64, %690 -%692:i64 = xor %691, %635 -%693:i64 = lshr %691, 47:i64 -%694:i64 = xor %692, %693 -%695:i64 = mul 11376068507788127593:i64, %694 -%696:i64 = lshr %695, 47:i64 -%697:i64 = xor %695, %696 -%698:i64 = mul 11376068507788127593:i64, %697 -%699:i64 = xor %631, %698 -%700:i64 = xor %630, %699 -%701:i64 = xor %629, %700 -%702:i64 = mul 11376068507788127593:i64, %701 -%703:i64 = xor %702, %629 -%704:i64 = lshr %702, 47:i64 -%705:i64 = xor %703, %704 -%706:i64 = mul 11376068507788127593:i64, %705 -%707:i64 = lshr %706, 47:i64 -%708:i64 = xor %706, %707 -%709:i64 = mul 11376068507788127593:i64, %708 -%710:i64 = xor %625, %709 -%711:i64 = xor %624, %710 -%712:i64 = xor %623, %711 -%713:i64 = mul 11376068507788127593:i64, %712 -%714:i64 = xor %713, %623 -%715:i64 = lshr %713, 47:i64 -%716:i64 = xor %714, %715 -%717:i64 = mul 11376068507788127593:i64, %716 -%718:i64 = lshr %717, 47:i64 -%719:i64 = xor %717, %718 -%720:i64 = mul 11376068507788127593:i64, %719 -%721:i64 = xor %619, %720 -%722:i64 = xor %618, %721 -%723:i64 = xor %617, %722 -%724:i64 = mul 11376068507788127593:i64, %723 -%725:i64 = xor %724, %617 -%726:i64 = lshr %724, 47:i64 -%727:i64 = xor %725, %726 -%728:i64 = mul 11376068507788127593:i64, %727 -%729:i64 = lshr %728, 47:i64 -%730:i64 = xor %728, %729 -%731:i64 = mul 11376068507788127593:i64, %730 -%732:i64 = xor %613, %731 -%733:i64 = xor %612, %732 -%734:i64 = xor %611, %733 -%735:i64 = mul 11376068507788127593:i64, %734 -%736:i64 = xor %735, %611 -%737:i64 = lshr %735, 47:i64 -%738:i64 = xor %736, %737 -%739:i64 = mul 11376068507788127593:i64, %738 -%740:i64 = lshr %739, 47:i64 -%741:i64 = xor %739, %740 -%742:i64 = mul 11376068507788127593:i64, %741 -%743:i64 = xor %607, %742 -%744:i64 = xor %606, %743 -%745:i64 = xor %605, %744 -%746:i64 = mul 11376068507788127593:i64, %745 -%747:i64 = xor %746, %605 -%748:i64 = lshr %746, 47:i64 -%749:i64 = xor %747, %748 -%750:i64 = mul 11376068507788127593:i64, %749 -%751:i64 = lshr %750, 47:i64 -%752:i64 = xor %750, %751 -%753:i64 = mul 11376068507788127593:i64, %752 -%754:i64 = xor %601, %753 -%755:i64 = xor %600, %754 -%756:i64 = xor %599, %755 -%757:i64 = mul 11376068507788127593:i64, %756 -%758:i64 = xor %757, %599 -%759:i64 = lshr %757, 47:i64 -%760:i64 = xor %758, %759 -%761:i64 = mul 11376068507788127593:i64, %760 -%762:i64 = lshr %761, 47:i64 -%763:i64 = xor %761, %762 -%764:i64 = mul 11376068507788127593:i64, %763 -%765:i64 = xor %595, %764 -%766:i64 = xor %594, %765 -%767:i64 = xor %593, %766 -%768:i64 = mul 11376068507788127593:i64, %767 -%769:i64 = xor %768, %593 -%770:i64 = lshr %768, 47:i64 -%771:i64 = xor %769, %770 -%772:i64 = mul 11376068507788127593:i64, %771 -%773:i64 = lshr %772, 47:i64 -%774:i64 = xor %772, %773 -%775:i64 = mul 11376068507788127593:i64, %774 -%776:i64 = xor %589, %775 -%777:i64 = xor %588, %776 -%778:i64 = xor %587, %777 -%779:i64 = mul 11376068507788127593:i64, %778 -%780:i64 = xor %779, %587 -%781:i64 = lshr %779, 47:i64 -%782:i64 = xor %780, %781 -%783:i64 = mul 11376068507788127593:i64, %782 -%784:i64 = lshr %783, 47:i64 -%785:i64 = xor %783, %784 -%786:i64 = mul 11376068507788127593:i64, %785 -%787:i64 = xor %583, %786 -%788:i64 = xor %582, %787 -%789:i64 = xor %581, %788 -%790:i64 = mul 11376068507788127593:i64, %789 -%791:i64 = xor %790, %581 -%792:i64 = lshr %790, 47:i64 -%793:i64 = xor %791, %792 -%794:i64 = mul 11376068507788127593:i64, %793 -%795:i64 = lshr %794, 47:i64 -%796:i64 = xor %794, %795 -%797:i64 = mul 11376068507788127593:i64, %796 -%798:i64 = xor %577, %797 -%799:i64 = xor %576, %798 -%800:i64 = xor %575, %799 -%801:i64 = mul 11376068507788127593:i64, %800 -%802:i64 = xor %801, %575 -%803:i64 = lshr %801, 47:i64 -%804:i64 = xor %802, %803 -%805:i64 = mul 11376068507788127593:i64, %804 -%806:i64 = lshr %805, 47:i64 -%807:i64 = xor %805, %806 -%808:i64 = mul 11376068507788127593:i64, %807 -%809:i64 = xor %571, %808 -%810:i64 = xor %570, %809 -%811:i64 = xor %569, %810 -%812:i64 = mul 11376068507788127593:i64, %811 -%813:i64 = xor %812, %569 -%814:i64 = lshr %812, 47:i64 -%815:i64 = xor %813, %814 -%816:i64 = mul 11376068507788127593:i64, %815 -%817:i64 = lshr %816, 47:i64 -%818:i64 = xor %816, %817 -%819:i64 = mul 11376068507788127593:i64, %818 -%820:i64 = xor %565, %819 -%821:i64 = xor %564, %820 -%822:i64 = xor %563, %821 -%823:i64 = mul 11376068507788127593:i64, %822 -%824:i64 = xor %823, %563 -%825:i64 = lshr %823, 47:i64 -%826:i64 = xor %824, %825 -%827:i64 = mul 11376068507788127593:i64, %826 -%828:i64 = lshr %827, 47:i64 -%829:i64 = xor %827, %828 -%830:i64 = mul 11376068507788127593:i64, %829 -%831:i64 = xor %559, %830 -%832:i64 = xor %558, %831 -%833:i64 = xor %557, %832 -%834:i64 = mul 11376068507788127593:i64, %833 -%835:i64 = xor %834, %557 -%836:i64 = lshr %834, 47:i64 -%837:i64 = xor %835, %836 -%838:i64 = mul 11376068507788127593:i64, %837 -%839:i64 = lshr %838, 47:i64 -%840:i64 = xor %838, %839 -%841:i64 = mul 11376068507788127593:i64, %840 -%842:i64 = xor %553, %841 -%843:i64 = xor %552, %842 -%844:i64 = xor %551, %843 -%845:i64 = mul 11376068507788127593:i64, %844 -%846:i64 = xor %845, %551 -%847:i64 = lshr %845, 47:i64 -%848:i64 = xor %846, %847 -%849:i64 = mul 11376068507788127593:i64, %848 -%850:i64 = lshr %849, 47:i64 -%851:i64 = xor %849, %850 -%852:i64 = mul 11376068507788127593:i64, %851 -%853:i64 = xor %547, %852 -%854:i64 = xor %546, %853 -%855:i64 = xor %545, %854 -%856:i64 = mul 11376068507788127593:i64, %855 -%857:i64 = xor %856, %545 -%858:i64 = lshr %856, 47:i64 -%859:i64 = xor %857, %858 -%860:i64 = mul 11376068507788127593:i64, %859 -%861:i64 = lshr %860, 47:i64 -%862:i64 = xor %860, %861 -%863:i64 = mul 11376068507788127593:i64, %862 -%864:i64 = xor %541, %863 -%865:i64 = xor %540, %864 -%866:i64 = xor %539, %865 -%867:i64 = mul 11376068507788127593:i64, %866 -%868:i64 = xor %867, %539 -%869:i64 = lshr %867, 47:i64 -%870:i64 = xor %868, %869 -%871:i64 = mul 11376068507788127593:i64, %870 -%872:i64 = lshr %871, 47:i64 -%873:i64 = xor %871, %872 -%874:i64 = mul 11376068507788127593:i64, %873 -%875:i64 = xor %535, %874 -%876:i64 = xor %534, %875 -%877:i64 = xor %533, %876 -%878:i64 = mul 11376068507788127593:i64, %877 -%879:i64 = xor %878, %533 -%880:i64 = lshr %878, 47:i64 -%881:i64 = xor %879, %880 -%882:i64 = mul 11376068507788127593:i64, %881 -%883:i64 = lshr %882, 47:i64 -%884:i64 = xor %882, %883 -%885:i64 = mul 11376068507788127593:i64, %884 -%886:i64 = xor %529, %885 -%887:i64 = xor %528, %886 -%888:i64 = xor %527, %887 -%889:i64 = mul 11376068507788127593:i64, %888 -%890:i64 = xor %889, %527 -%891:i64 = lshr %889, 47:i64 -%892:i64 = xor %890, %891 -%893:i64 = mul 11376068507788127593:i64, %892 -%894:i64 = lshr %893, 47:i64 -%895:i64 = xor %893, %894 -%896:i64 = mul 11376068507788127593:i64, %895 -%897:i64 = xor %523, %896 -%898:i64 = xor %522, %897 -%899:i64 = xor %521, %898 -%900:i64 = mul 11376068507788127593:i64, %899 -%901:i64 = xor %900, %521 -%902:i64 = lshr %900, 47:i64 -%903:i64 = xor %901, %902 -%904:i64 = mul 11376068507788127593:i64, %903 -%905:i64 = lshr %904, 47:i64 -%906:i64 = xor %904, %905 -%907:i64 = mul 11376068507788127593:i64, %906 -%908:i64 = xor %517, %907 -%909:i64 = xor %516, %908 -%910:i64 = xor %515, %909 -%911:i64 = mul 11376068507788127593:i64, %910 -%912:i64 = xor %911, %515 -%913:i64 = lshr %911, 47:i64 -%914:i64 = xor %912, %913 -%915:i64 = mul 11376068507788127593:i64, %914 -%916:i64 = lshr %915, 47:i64 -%917:i64 = xor %915, %916 -%918:i64 = mul 11376068507788127593:i64, %917 -%919:i64 = xor %511, %918 -%920:i64 = xor %510, %919 -%921:i64 = xor %509, %920 -%922:i64 = mul 11376068507788127593:i64, %921 -%923:i64 = xor %922, %509 -%924:i64 = lshr %922, 47:i64 -%925:i64 = xor %923, %924 -%926:i64 = mul 11376068507788127593:i64, %925 -%927:i64 = lshr %926, 47:i64 -%928:i64 = xor %926, %927 -%929:i64 = mul 11376068507788127593:i64, %928 -%930:i64 = xor %505, %929 -%931:i64 = xor %504, %930 -%932:i64 = xor %503, %931 -%933:i64 = mul 11376068507788127593:i64, %932 -%934:i64 = xor %933, %503 -%935:i64 = lshr %933, 47:i64 -%936:i64 = xor %934, %935 -%937:i64 = mul 11376068507788127593:i64, %936 -%938:i64 = lshr %937, 47:i64 -%939:i64 = xor %937, %938 -%940:i64 = mul 11376068507788127593:i64, %939 -%941:i64 = xor %499, %940 -%942:i64 = xor %498, %941 -%943:i64 = xor %497, %942 -%944:i64 = mul 11376068507788127593:i64, %943 -%945:i64 = xor %944, %497 -%946:i64 = lshr %944, 47:i64 -%947:i64 = xor %945, %946 -%948:i64 = mul 11376068507788127593:i64, %947 -%949:i64 = lshr %948, 47:i64 -%950:i64 = xor %948, %949 -%951:i64 = mul 11376068507788127593:i64, %950 -%952:i64 = xor %493, %951 -%953:i64 = xor %492, %952 -%954:i64 = xor %491, %953 -%955:i64 = mul 11376068507788127593:i64, %954 -%956:i64 = xor %955, %491 -%957:i64 = lshr %955, 47:i64 -%958:i64 = xor %956, %957 -%959:i64 = mul 11376068507788127593:i64, %958 -%960:i64 = lshr %959, 47:i64 -%961:i64 = xor %959, %960 -%962:i64 = mul 11376068507788127593:i64, %961 -%963:i64 = xor %487, %962 -%964:i64 = xor %486, %963 -%965:i64 = xor %485, %964 -%966:i64 = mul 11376068507788127593:i64, %965 -%967:i64 = xor %966, %485 -%968:i64 = lshr %966, 47:i64 -%969:i64 = xor %967, %968 -%970:i64 = mul 11376068507788127593:i64, %969 -%971:i64 = lshr %970, 47:i64 -%972:i64 = xor %970, %971 -%973:i64 = mul 11376068507788127593:i64, %972 -%974:i64 = xor %481, %973 -%975:i64 = xor %480, %974 -%976:i64 = xor %479, %975 -%977:i64 = mul 11376068507788127593:i64, %976 -%978:i64 = xor %977, %479 -%979:i64 = lshr %977, 47:i64 -%980:i64 = xor %978, %979 -%981:i64 = mul 11376068507788127593:i64, %980 -%982:i64 = lshr %981, 47:i64 -%983:i64 = xor %981, %982 -%984:i64 = mul 11376068507788127593:i64, %983 -%985:i64 = xor %475, %984 -%986:i64 = xor %474, %985 -%987:i64 = xor %473, %986 -%988:i64 = mul 11376068507788127593:i64, %987 -%989:i64 = xor %988, %473 -%990:i64 = lshr %988, 47:i64 -%991:i64 = xor %989, %990 -%992:i64 = mul 11376068507788127593:i64, %991 -%993:i64 = lshr %992, 47:i64 -%994:i64 = xor %992, %993 -%995:i64 = mul 11376068507788127593:i64, %994 -%996:i64 = xor %469, %995 -%997:i64 = xor %468, %996 -%998:i64 = xor %467, %997 -%999:i64 = mul 11376068507788127593:i64, %998 -%1000:i64 = xor %999, %467 -%1001:i64 = lshr %999, 47:i64 -%1002:i64 = xor %1000, %1001 -%1003:i64 = mul 11376068507788127593:i64, %1002 -%1004:i64 = lshr %1003, 47:i64 -%1005:i64 = xor %1003, %1004 -%1006:i64 = mul 11376068507788127593:i64, %1005 -%1007:i64 = xor %463, %1006 -%1008:i64 = xor %462, %1007 -%1009:i64 = xor %461, %1008 -%1010:i64 = mul 11376068507788127593:i64, %1009 -%1011:i64 = xor %1010, %461 -%1012:i64 = lshr %1010, 47:i64 -%1013:i64 = xor %1011, %1012 -%1014:i64 = mul 11376068507788127593:i64, %1013 -%1015:i64 = lshr %1014, 47:i64 -%1016:i64 = xor %1014, %1015 -%1017:i64 = mul 11376068507788127593:i64, %1016 -%1018:i64 = xor %457, %1017 -%1019:i64 = xor %456, %1018 -%1020:i64 = xor %455, %1019 -%1021:i64 = mul 11376068507788127593:i64, %1020 -%1022:i64 = xor %1021, %455 -%1023:i64 = lshr %1021, 47:i64 -%1024:i64 = xor %1022, %1023 -%1025:i64 = mul 11376068507788127593:i64, %1024 -%1026:i64 = lshr %1025, 47:i64 -%1027:i64 = xor %1025, %1026 -%1028:i64 = mul 11376068507788127593:i64, %1027 -%1029:i64 = xor %451, %1028 -%1030:i64 = xor %450, %1029 -%1031:i64 = xor %449, %1030 -%1032:i64 = mul 11376068507788127593:i64, %1031 -%1033:i64 = xor %1032, %449 -%1034:i64 = lshr %1032, 47:i64 -%1035:i64 = xor %1033, %1034 -%1036:i64 = mul 11376068507788127593:i64, %1035 -%1037:i64 = lshr %1036, 47:i64 -%1038:i64 = xor %1036, %1037 -%1039:i64 = mul 11376068507788127593:i64, %1038 -%1040:i64 = xor %445, %1039 -%1041:i64 = xor %444, %1040 -%1042:i64 = xor %443, %1041 -%1043:i64 = mul 11376068507788127593:i64, %1042 -%1044:i64 = xor %1043, %443 -%1045:i64 = lshr %1043, 47:i64 -%1046:i64 = xor %1044, %1045 -%1047:i64 = mul 11376068507788127593:i64, %1046 -%1048:i64 = lshr %1047, 47:i64 -%1049:i64 = xor %1047, %1048 -%1050:i64 = mul 11376068507788127593:i64, %1049 -%1051:i64 = xor %439, %1050 -%1052:i64 = xor %438, %1051 -%1053:i64 = xor %437, %1052 -%1054:i64 = mul 11376068507788127593:i64, %1053 -%1055:i64 = xor %1054, %437 -%1056:i64 = lshr %1054, 47:i64 -%1057:i64 = xor %1055, %1056 -%1058:i64 = mul 11376068507788127593:i64, %1057 -%1059:i64 = lshr %1058, 47:i64 -%1060:i64 = xor %1058, %1059 -%1061:i64 = mul 11376068507788127593:i64, %1060 -%1062:i64 = xor %433, %1061 -%1063:i64 = xor %432, %1062 -%1064:i64 = xor %431, %1063 -%1065:i64 = mul 11376068507788127593:i64, %1064 -%1066:i64 = xor %1065, %431 -%1067:i64 = lshr %1065, 47:i64 -%1068:i64 = xor %1066, %1067 -%1069:i64 = mul 11376068507788127593:i64, %1068 -%1070:i64 = lshr %1069, 47:i64 -%1071:i64 = xor %1069, %1070 -%1072:i64 = mul 11376068507788127593:i64, %1071 -%1073:i64 = xor %427, %1072 -%1074:i64 = xor %426, %1073 -%1075:i64 = xor %425, %1074 -%1076:i64 = mul 11376068507788127593:i64, %1075 -%1077:i64 = xor %1076, %425 -%1078:i64 = lshr %1076, 47:i64 -%1079:i64 = xor %1077, %1078 -%1080:i64 = mul 11376068507788127593:i64, %1079 -%1081:i64 = lshr %1080, 47:i64 -%1082:i64 = xor %1080, %1081 -%1083:i64 = mul 11376068507788127593:i64, %1082 -%1084:i64 = xor %421, %1083 -%1085:i64 = xor %420, %1084 -%1086:i64 = xor %419, %1085 -%1087:i64 = mul 11376068507788127593:i64, %1086 -%1088:i64 = xor %1087, %419 -%1089:i64 = lshr %1087, 47:i64 -%1090:i64 = xor %1088, %1089 -%1091:i64 = mul 11376068507788127593:i64, %1090 -%1092:i64 = lshr %1091, 47:i64 -%1093:i64 = xor %1091, %1092 -%1094:i64 = mul 11376068507788127593:i64, %1093 -%1095:i64 = xor %415, %1094 -%1096:i64 = xor %414, %1095 -%1097:i64 = xor %413, %1096 -%1098:i64 = mul 11376068507788127593:i64, %1097 -%1099:i64 = xor %1098, %413 -%1100:i64 = lshr %1098, 47:i64 -%1101:i64 = xor %1099, %1100 -%1102:i64 = mul 11376068507788127593:i64, %1101 -%1103:i64 = lshr %1102, 47:i64 -%1104:i64 = xor %1102, %1103 -%1105:i64 = mul 11376068507788127593:i64, %1104 -%1106:i64 = xor %409, %1105 -%1107:i64 = xor %408, %1106 -%1108:i64 = xor %407, %1107 -%1109:i64 = mul 11376068507788127593:i64, %1108 -%1110:i64 = xor %1109, %407 -%1111:i64 = lshr %1109, 47:i64 -%1112:i64 = xor %1110, %1111 -%1113:i64 = mul 11376068507788127593:i64, %1112 -%1114:i64 = lshr %1113, 47:i64 -%1115:i64 = xor %1113, %1114 -%1116:i64 = mul 11376068507788127593:i64, %1115 -%1117:i64 = xor %403, %1116 -%1118:i64 = xor %402, %1117 -%1119:i64 = xor %401, %1118 -%1120:i64 = mul 11376068507788127593:i64, %1119 -%1121:i64 = xor %1120, %401 -%1122:i64 = lshr %1120, 47:i64 -%1123:i64 = xor %1121, %1122 -%1124:i64 = mul 11376068507788127593:i64, %1123 -%1125:i64 = lshr %1124, 47:i64 -%1126:i64 = xor %1124, %1125 -%1127:i64 = mul 11376068507788127593:i64, %1126 -%1128:i64 = xor %397, %1127 -%1129:i64 = xor %396, %1128 -%1130:i64 = xor %395, %1129 -%1131:i64 = mul 11376068507788127593:i64, %1130 -%1132:i64 = xor %1131, %395 -%1133:i64 = lshr %1131, 47:i64 -%1134:i64 = xor %1132, %1133 -%1135:i64 = mul 11376068507788127593:i64, %1134 -%1136:i64 = lshr %1135, 47:i64 -%1137:i64 = xor %1135, %1136 -%1138:i64 = mul 11376068507788127593:i64, %1137 -%1139:i64 = xor %391, %1138 -%1140:i64 = xor %390, %1139 -%1141:i64 = xor %389, %1140 -%1142:i64 = mul 11376068507788127593:i64, %1141 -%1143:i64 = xor %1142, %389 -%1144:i64 = lshr %1142, 47:i64 -%1145:i64 = xor %1143, %1144 -%1146:i64 = mul 11376068507788127593:i64, %1145 -%1147:i64 = lshr %1146, 47:i64 -%1148:i64 = xor %1146, %1147 -%1149:i64 = mul 11376068507788127593:i64, %1148 -%1150:i64 = xor %385, %1149 -%1151:i64 = xor %384, %1150 -%1152:i64 = xor %383, %1151 -%1153:i64 = mul 11376068507788127593:i64, %1152 -%1154:i64 = xor %1153, %383 -%1155:i64 = lshr %1153, 47:i64 -%1156:i64 = xor %1154, %1155 -%1157:i64 = mul 11376068507788127593:i64, %1156 -%1158:i64 = lshr %1157, 47:i64 -%1159:i64 = xor %1157, %1158 -%1160:i64 = mul 11376068507788127593:i64, %1159 -%1161:i64 = xor %379, %1160 -%1162:i64 = xor %378, %1161 -%1163:i64 = xor %377, %1162 -%1164:i64 = mul 11376068507788127593:i64, %1163 -%1165:i64 = xor %1164, %377 -%1166:i64 = lshr %1164, 47:i64 -%1167:i64 = xor %1165, %1166 -%1168:i64 = mul 11376068507788127593:i64, %1167 -%1169:i64 = lshr %1168, 47:i64 -%1170:i64 = xor %1168, %1169 -%1171:i64 = mul 11376068507788127593:i64, %1170 -%1172:i64 = xor %373, %1171 -%1173:i64 = xor %372, %1172 -%1174:i64 = xor %371, %1173 -%1175:i64 = mul 11376068507788127593:i64, %1174 -%1176:i64 = xor %1175, %371 -%1177:i64 = lshr %1175, 47:i64 -%1178:i64 = xor %1176, %1177 -%1179:i64 = mul 11376068507788127593:i64, %1178 -%1180:i64 = lshr %1179, 47:i64 -%1181:i64 = xor %1179, %1180 -%1182:i64 = mul 11376068507788127593:i64, %1181 -%1183:i64 = xor %367, %1182 -%1184:i64 = xor %366, %1183 -%1185:i64 = xor %365, %1184 -%1186:i64 = mul 11376068507788127593:i64, %1185 -%1187:i64 = xor %1186, %365 -%1188:i64 = lshr %1186, 47:i64 -%1189:i64 = xor %1187, %1188 -%1190:i64 = mul 11376068507788127593:i64, %1189 -%1191:i64 = lshr %1190, 47:i64 -%1192:i64 = xor %1190, %1191 -%1193:i64 = mul 11376068507788127593:i64, %1192 -%1194:i64 = xor %361, %1193 -%1195:i64 = xor %360, %1194 -%1196:i64 = xor %359, %1195 -%1197:i64 = mul 11376068507788127593:i64, %1196 -%1198:i64 = xor %1197, %359 -%1199:i64 = lshr %1197, 47:i64 -%1200:i64 = xor %1198, %1199 -%1201:i64 = mul 11376068507788127593:i64, %1200 -%1202:i64 = lshr %1201, 47:i64 -%1203:i64 = xor %1201, %1202 -%1204:i64 = mul 11376068507788127593:i64, %1203 -%1205:i64 = xor %355, %1204 -%1206:i64 = xor %354, %1205 -%1207:i64 = xor %353, %1206 -%1208:i64 = mul 11376068507788127593:i64, %1207 -%1209:i64 = xor %1208, %353 -%1210:i64 = lshr %1208, 47:i64 -%1211:i64 = xor %1209, %1210 -%1212:i64 = mul 11376068507788127593:i64, %1211 -%1213:i64 = lshr %1212, 47:i64 -%1214:i64 = xor %1212, %1213 -%1215:i64 = mul 11376068507788127593:i64, %1214 -%1216:i64 = xor %349, %1215 -%1217:i64 = xor %348, %1216 -%1218:i64 = xor %347, %1217 -%1219:i64 = mul 11376068507788127593:i64, %1218 -%1220:i64 = xor %1219, %347 -%1221:i64 = lshr %1219, 47:i64 -%1222:i64 = xor %1220, %1221 -%1223:i64 = mul 11376068507788127593:i64, %1222 -%1224:i64 = lshr %1223, 47:i64 -%1225:i64 = xor %1223, %1224 -%1226:i64 = mul 11376068507788127593:i64, %1225 -%1227:i64 = xor %343, %1226 -%1228:i64 = xor %342, %1227 -%1229:i64 = xor %341, %1228 -%1230:i64 = mul 11376068507788127593:i64, %1229 -%1231:i64 = xor %1230, %341 -%1232:i64 = lshr %1230, 47:i64 -%1233:i64 = xor %1231, %1232 -%1234:i64 = mul 11376068507788127593:i64, %1233 -%1235:i64 = lshr %1234, 47:i64 -%1236:i64 = xor %1234, %1235 -%1237:i64 = mul 11376068507788127593:i64, %1236 -%1238:i64 = xor %337, %1237 -%1239:i64 = xor %336, %1238 -%1240:i64 = xor %335, %1239 -%1241:i64 = mul 11376068507788127593:i64, %1240 -%1242:i64 = xor %1241, %335 -%1243:i64 = lshr %1241, 47:i64 -%1244:i64 = xor %1242, %1243 -%1245:i64 = mul 11376068507788127593:i64, %1244 -%1246:i64 = lshr %1245, 47:i64 -%1247:i64 = xor %1245, %1246 -%1248:i64 = mul 11376068507788127593:i64, %1247 -%1249:i64 = xor %331, %1248 -%1250:i64 = xor %330, %1249 -%1251:i64 = xor %329, %1250 -%1252:i64 = mul 11376068507788127593:i64, %1251 -%1253:i64 = xor %1252, %329 -%1254:i64 = lshr %1252, 47:i64 -%1255:i64 = xor %1253, %1254 -%1256:i64 = mul 11376068507788127593:i64, %1255 -%1257:i64 = lshr %1256, 47:i64 -%1258:i64 = xor %1256, %1257 -%1259:i64 = mul 11376068507788127593:i64, %1258 -%1260:i64 = xor %325, %1259 -%1261:i64 = xor %324, %1260 -%1262:i64 = xor %323, %1261 -%1263:i64 = mul 11376068507788127593:i64, %1262 -%1264:i64 = xor %1263, %323 -%1265:i64 = lshr %1263, 47:i64 -%1266:i64 = xor %1264, %1265 -%1267:i64 = mul 11376068507788127593:i64, %1266 -%1268:i64 = lshr %1267, 47:i64 -%1269:i64 = xor %1267, %1268 -%1270:i64 = mul 11376068507788127593:i64, %1269 -%1271:i64 = xor %319, %1270 -%1272:i64 = xor %318, %1271 -%1273:i64 = xor %317, %1272 -%1274:i64 = mul 11376068507788127593:i64, %1273 -%1275:i64 = xor %1274, %317 -%1276:i64 = lshr %1274, 47:i64 -%1277:i64 = xor %1275, %1276 -%1278:i64 = mul 11376068507788127593:i64, %1277 -%1279:i64 = lshr %1278, 47:i64 -%1280:i64 = xor %1278, %1279 -%1281:i64 = mul 11376068507788127593:i64, %1280 -%1282:i64 = xor %313, %1281 -%1283:i64 = xor %312, %1282 -%1284:i64 = xor %311, %1283 -%1285:i64 = mul 11376068507788127593:i64, %1284 -%1286:i64 = xor %1285, %311 -%1287:i64 = lshr %1285, 47:i64 -%1288:i64 = xor %1286, %1287 -%1289:i64 = mul 11376068507788127593:i64, %1288 -%1290:i64 = lshr %1289, 47:i64 -%1291:i64 = xor %1289, %1290 -%1292:i64 = mul 11376068507788127593:i64, %1291 -%1293:i64 = xor %307, %1292 -%1294:i64 = xor %306, %1293 -%1295:i64 = xor %305, %1294 -%1296:i64 = mul 11376068507788127593:i64, %1295 -%1297:i64 = xor %1296, %305 -%1298:i64 = lshr %1296, 47:i64 -%1299:i64 = xor %1297, %1298 -%1300:i64 = mul 11376068507788127593:i64, %1299 -%1301:i64 = lshr %1300, 47:i64 -%1302:i64 = xor %1300, %1301 -%1303:i64 = mul 11376068507788127593:i64, %1302 -%1304:i64 = xor %301, %1303 -%1305:i64 = xor %300, %1304 -%1306:i64 = xor %299, %1305 -%1307:i64 = mul 11376068507788127593:i64, %1306 -%1308:i64 = xor %1307, %299 -%1309:i64 = lshr %1307, 47:i64 -%1310:i64 = xor %1308, %1309 -%1311:i64 = mul 11376068507788127593:i64, %1310 -%1312:i64 = lshr %1311, 47:i64 -%1313:i64 = xor %1311, %1312 -%1314:i64 = mul 11376068507788127593:i64, %1313 -%1315:i64 = xor %295, %1314 -%1316:i64 = xor %294, %1315 -%1317:i64 = xor %293, %1316 -%1318:i64 = mul 11376068507788127593:i64, %1317 -%1319:i64 = xor %1318, %293 -%1320:i64 = lshr %1318, 47:i64 -%1321:i64 = xor %1319, %1320 -%1322:i64 = mul 11376068507788127593:i64, %1321 -%1323:i64 = lshr %1322, 47:i64 -%1324:i64 = xor %1322, %1323 -%1325:i64 = mul 11376068507788127593:i64, %1324 -%1326:i64 = xor %289, %1325 -%1327:i64 = xor %288, %1326 -%1328:i64 = xor %287, %1327 -%1329:i64 = mul 11376068507788127593:i64, %1328 -%1330:i64 = xor %1329, %287 -%1331:i64 = lshr %1329, 47:i64 -%1332:i64 = xor %1330, %1331 -%1333:i64 = mul 11376068507788127593:i64, %1332 -%1334:i64 = lshr %1333, 47:i64 -%1335:i64 = xor %1333, %1334 -%1336:i64 = mul 11376068507788127593:i64, %1335 -%1337:i64 = xor %283, %1336 -%1338:i64 = xor %282, %1337 -%1339:i64 = xor %281, %1338 -%1340:i64 = mul 11376068507788127593:i64, %1339 -%1341:i64 = xor %1340, %281 -%1342:i64 = lshr %1340, 47:i64 -%1343:i64 = xor %1341, %1342 -%1344:i64 = mul 11376068507788127593:i64, %1343 -%1345:i64 = lshr %1344, 47:i64 -%1346:i64 = xor %1344, %1345 -%1347:i64 = mul 11376068507788127593:i64, %1346 -%1348:i64 = xor %277, %1347 -%1349:i64 = xor %276, %1348 -%1350:i64 = xor %275, %1349 -%1351:i64 = mul 11376068507788127593:i64, %1350 -%1352:i64 = xor %1351, %275 -%1353:i64 = lshr %1351, 47:i64 -%1354:i64 = xor %1352, %1353 -%1355:i64 = mul 11376068507788127593:i64, %1354 -%1356:i64 = lshr %1355, 47:i64 -%1357:i64 = xor %1355, %1356 -%1358:i64 = mul 11376068507788127593:i64, %1357 -%1359:i64 = xor %271, %1358 -%1360:i64 = xor %270, %1359 -%1361:i64 = xor %269, %1360 -%1362:i64 = mul 11376068507788127593:i64, %1361 -%1363:i64 = xor %1362, %269 -%1364:i64 = lshr %1362, 47:i64 -%1365:i64 = xor %1363, %1364 -%1366:i64 = mul 11376068507788127593:i64, %1365 -%1367:i64 = lshr %1366, 47:i64 -%1368:i64 = xor %1366, %1367 -%1369:i64 = mul 11376068507788127593:i64, %1368 -%1370:i64 = xor %265, %1369 -%1371:i64 = xor %264, %1370 -%1372:i64 = xor %263, %1371 -%1373:i64 = mul 11376068507788127593:i64, %1372 -%1374:i64 = xor %1373, %263 -%1375:i64 = lshr %1373, 47:i64 -%1376:i64 = xor %1374, %1375 -%1377:i64 = mul 11376068507788127593:i64, %1376 -%1378:i64 = lshr %1377, 47:i64 -%1379:i64 = xor %1377, %1378 -%1380:i64 = mul 11376068507788127593:i64, %1379 -%1381:i64 = xor %259, %1380 -%1382:i64 = xor %258, %1381 -%1383:i64 = xor %257, %1382 -%1384:i64 = mul 11376068507788127593:i64, %1383 -%1385:i64 = xor %1384, %257 -%1386:i64 = lshr %1384, 47:i64 -%1387:i64 = xor %1385, %1386 -%1388:i64 = mul 11376068507788127593:i64, %1387 -%1389:i64 = lshr %1388, 47:i64 -%1390:i64 = xor %1388, %1389 -%1391:i64 = mul 11376068507788127593:i64, %1390 -%1392:i64 = xor %253, %1391 -%1393:i64 = xor %252, %1392 -%1394:i64 = xor %251, %1393 -%1395:i64 = mul 11376068507788127593:i64, %1394 -%1396:i64 = xor %1395, %251 -%1397:i64 = lshr %1395, 47:i64 -%1398:i64 = xor %1396, %1397 -%1399:i64 = mul 11376068507788127593:i64, %1398 -%1400:i64 = lshr %1399, 47:i64 -%1401:i64 = xor %1399, %1400 -%1402:i64 = mul 11376068507788127593:i64, %1401 -%1403:i64 = xor %247, %1402 -%1404:i64 = xor %246, %1403 -%1405:i64 = xor %245, %1404 -%1406:i64 = mul 11376068507788127593:i64, %1405 -%1407:i64 = xor %1406, %245 -%1408:i64 = lshr %1406, 47:i64 -%1409:i64 = xor %1407, %1408 -%1410:i64 = mul 11376068507788127593:i64, %1409 -%1411:i64 = lshr %1410, 47:i64 -%1412:i64 = xor %1410, %1411 -%1413:i64 = mul 11376068507788127593:i64, %1412 -%1414:i64 = xor %241, %1413 -%1415:i64 = xor %240, %1414 -%1416:i64 = xor %239, %1415 -%1417:i64 = mul 11376068507788127593:i64, %1416 -%1418:i64 = xor %1417, %239 -%1419:i64 = lshr %1417, 47:i64 -%1420:i64 = xor %1418, %1419 -%1421:i64 = mul 11376068507788127593:i64, %1420 -%1422:i64 = lshr %1421, 47:i64 -%1423:i64 = xor %1421, %1422 -%1424:i64 = mul 11376068507788127593:i64, %1423 -%1425:i64 = xor %235, %1424 -%1426:i64 = xor %234, %1425 -%1427:i64 = xor %233, %1426 -%1428:i64 = mul 11376068507788127593:i64, %1427 -%1429:i64 = xor %1428, %233 -%1430:i64 = lshr %1428, 47:i64 -%1431:i64 = xor %1429, %1430 -%1432:i64 = mul 11376068507788127593:i64, %1431 -%1433:i64 = lshr %1432, 47:i64 -%1434:i64 = xor %1432, %1433 -%1435:i64 = mul 11376068507788127593:i64, %1434 -%1436:i64 = xor %229, %1435 -%1437:i64 = xor %228, %1436 -%1438:i64 = xor %227, %1437 -%1439:i64 = mul 11376068507788127593:i64, %1438 -%1440:i64 = xor %1439, %227 -%1441:i64 = lshr %1439, 47:i64 -%1442:i64 = xor %1440, %1441 -%1443:i64 = mul 11376068507788127593:i64, %1442 -%1444:i64 = lshr %1443, 47:i64 -%1445:i64 = xor %1443, %1444 -%1446:i64 = mul 11376068507788127593:i64, %1445 -%1447:i64 = xor %223, %1446 -%1448:i64 = xor %222, %1447 -%1449:i64 = xor %221, %1448 -%1450:i64 = mul 11376068507788127593:i64, %1449 -%1451:i64 = xor %1450, %221 -%1452:i64 = lshr %1450, 47:i64 -%1453:i64 = xor %1451, %1452 -%1454:i64 = mul 11376068507788127593:i64, %1453 -%1455:i64 = lshr %1454, 47:i64 -%1456:i64 = xor %1454, %1455 -%1457:i64 = mul 11376068507788127593:i64, %1456 -%1458:i64 = xor %217, %1457 -%1459:i64 = xor %216, %1458 -%1460:i64 = xor %215, %1459 -%1461:i64 = mul 11376068507788127593:i64, %1460 -%1462:i64 = xor %1461, %215 -%1463:i64 = lshr %1461, 47:i64 -%1464:i64 = xor %1462, %1463 -%1465:i64 = mul 11376068507788127593:i64, %1464 -%1466:i64 = lshr %1465, 47:i64 -%1467:i64 = xor %1465, %1466 -%1468:i64 = mul 11376068507788127593:i64, %1467 -%1469:i64 = xor %211, %1468 -%1470:i64 = xor %210, %1469 -%1471:i64 = xor %209, %1470 -%1472:i64 = mul 11376068507788127593:i64, %1471 -%1473:i64 = xor %1472, %209 -%1474:i64 = lshr %1472, 47:i64 -%1475:i64 = xor %1473, %1474 -%1476:i64 = mul 11376068507788127593:i64, %1475 -%1477:i64 = lshr %1476, 47:i64 -%1478:i64 = xor %1476, %1477 -%1479:i64 = mul 11376068507788127593:i64, %1478 -%1480:i64 = xor %205, %1479 -%1481:i64 = xor %204, %1480 -%1482:i64 = xor %203, %1481 -%1483:i64 = mul 11376068507788127593:i64, %1482 -%1484:i64 = xor %1483, %203 -%1485:i64 = lshr %1483, 47:i64 -%1486:i64 = xor %1484, %1485 -%1487:i64 = mul 11376068507788127593:i64, %1486 -%1488:i64 = lshr %1487, 47:i64 -%1489:i64 = xor %1487, %1488 -%1490:i64 = mul 11376068507788127593:i64, %1489 -%1491:i64 = xor %199, %1490 -%1492:i64 = xor %198, %1491 -%1493:i64 = xor %197, %1492 -%1494:i64 = mul 11376068507788127593:i64, %1493 -%1495:i64 = xor %1494, %197 -%1496:i64 = lshr %1494, 47:i64 -%1497:i64 = xor %1495, %1496 -%1498:i64 = mul 11376068507788127593:i64, %1497 -%1499:i64 = lshr %1498, 47:i64 -%1500:i64 = xor %1498, %1499 -%1501:i64 = mul 11376068507788127593:i64, %1500 -%1502:i64 = xor %193, %1501 -%1503:i64 = xor %192, %1502 -%1504:i64 = xor %191, %1503 -%1505:i64 = mul 11376068507788127593:i64, %1504 -%1506:i64 = xor %1505, %191 -%1507:i64 = lshr %1505, 47:i64 -%1508:i64 = xor %1506, %1507 -%1509:i64 = mul 11376068507788127593:i64, %1508 -%1510:i64 = lshr %1509, 47:i64 -%1511:i64 = xor %1509, %1510 -%1512:i64 = mul 11376068507788127593:i64, %1511 -%1513:i64 = xor %187, %1512 -%1514:i64 = xor %186, %1513 -%1515:i64 = xor %185, %1514 -%1516:i64 = mul 11376068507788127593:i64, %1515 -%1517:i64 = xor %1516, %185 -%1518:i64 = lshr %1516, 47:i64 -%1519:i64 = xor %1517, %1518 -%1520:i64 = mul 11376068507788127593:i64, %1519 -%1521:i64 = lshr %1520, 47:i64 -%1522:i64 = xor %1520, %1521 -%1523:i64 = mul 11376068507788127593:i64, %1522 -%1524:i64 = xor %181, %1523 -%1525:i64 = xor %180, %1524 -%1526:i64 = xor %179, %1525 -%1527:i64 = mul 11376068507788127593:i64, %1526 -%1528:i64 = xor %1527, %179 -%1529:i64 = lshr %1527, 47:i64 -%1530:i64 = xor %1528, %1529 -%1531:i64 = mul 11376068507788127593:i64, %1530 -%1532:i64 = lshr %1531, 47:i64 -%1533:i64 = xor %1531, %1532 -%1534:i64 = mul 11376068507788127593:i64, %1533 -%1535:i64 = xor %175, %1534 -%1536:i64 = xor %174, %1535 -%1537:i64 = xor %173, %1536 -%1538:i64 = mul 11376068507788127593:i64, %1537 -%1539:i64 = xor %1538, %173 -%1540:i64 = lshr %1538, 47:i64 -%1541:i64 = xor %1539, %1540 -%1542:i64 = mul 11376068507788127593:i64, %1541 -%1543:i64 = lshr %1542, 47:i64 -%1544:i64 = xor %1542, %1543 -%1545:i64 = mul 11376068507788127593:i64, %1544 -%1546:i64 = xor %169, %1545 -%1547:i64 = xor %168, %1546 -%1548:i64 = xor %167, %1547 -%1549:i64 = mul 11376068507788127593:i64, %1548 -%1550:i64 = xor %1549, %167 -%1551:i64 = lshr %1549, 47:i64 -%1552:i64 = xor %1550, %1551 -%1553:i64 = mul 11376068507788127593:i64, %1552 -%1554:i64 = lshr %1553, 47:i64 -%1555:i64 = xor %1553, %1554 -%1556:i64 = mul 11376068507788127593:i64, %1555 -%1557:i64 = xor %163, %1556 -%1558:i64 = xor %162, %1557 -%1559:i64 = xor %161, %1558 -%1560:i64 = mul 11376068507788127593:i64, %1559 -%1561:i64 = xor %1560, %161 -%1562:i64 = lshr %1560, 47:i64 -%1563:i64 = xor %1561, %1562 -%1564:i64 = mul 11376068507788127593:i64, %1563 -%1565:i64 = lshr %1564, 47:i64 -%1566:i64 = xor %1564, %1565 -%1567:i64 = mul 11376068507788127593:i64, %1566 -%1568:i64 = xor %157, %1567 -%1569:i64 = xor %156, %1568 -%1570:i64 = xor %155, %1569 -%1571:i64 = mul 11376068507788127593:i64, %1570 -%1572:i64 = xor %1571, %155 -%1573:i64 = lshr %1571, 47:i64 -%1574:i64 = xor %1572, %1573 -%1575:i64 = mul 11376068507788127593:i64, %1574 -%1576:i64 = lshr %1575, 47:i64 -%1577:i64 = xor %1575, %1576 -%1578:i64 = mul 11376068507788127593:i64, %1577 -%1579:i64 = xor %151, %1578 -%1580:i64 = xor %150, %1579 -%1581:i64 = xor %149, %1580 -%1582:i64 = mul 11376068507788127593:i64, %1581 -%1583:i64 = xor %1582, %149 -%1584:i64 = lshr %1582, 47:i64 -%1585:i64 = xor %1583, %1584 -%1586:i64 = mul 11376068507788127593:i64, %1585 -%1587:i64 = lshr %1586, 47:i64 -%1588:i64 = xor %1586, %1587 -%1589:i64 = mul 11376068507788127593:i64, %1588 -%1590:i64 = xor %145, %1589 -%1591:i64 = xor %144, %1590 -%1592:i64 = xor %143, %1591 -%1593:i64 = mul 11376068507788127593:i64, %1592 -%1594:i64 = xor %1593, %143 -%1595:i64 = lshr %1593, 47:i64 -%1596:i64 = xor %1594, %1595 -%1597:i64 = mul 11376068507788127593:i64, %1596 -%1598:i64 = lshr %1597, 47:i64 -%1599:i64 = xor %1597, %1598 -%1600:i64 = mul 11376068507788127593:i64, %1599 -%1601:i64 = xor %139, %1600 -%1602:i64 = xor %138, %1601 -%1603:i64 = xor %137, %1602 -%1604:i64 = mul 11376068507788127593:i64, %1603 -%1605:i64 = xor %1604, %137 -%1606:i64 = lshr %1604, 47:i64 -%1607:i64 = xor %1605, %1606 -%1608:i64 = mul 11376068507788127593:i64, %1607 -%1609:i64 = lshr %1608, 47:i64 -%1610:i64 = xor %1608, %1609 -%1611:i64 = mul 11376068507788127593:i64, %1610 -%1612:i64 = xor %133, %1611 -%1613:i64 = xor %132, %1612 -%1614:i64 = xor %131, %1613 -%1615:i64 = mul 11376068507788127593:i64, %1614 -%1616:i64 = xor %1615, %131 -%1617:i64 = lshr %1615, 47:i64 -%1618:i64 = xor %1616, %1617 -%1619:i64 = mul 11376068507788127593:i64, %1618 -%1620:i64 = lshr %1619, 47:i64 -%1621:i64 = xor %1619, %1620 -%1622:i64 = mul 11376068507788127593:i64, %1621 -%1623:i64 = xor %127, %1622 -%1624:i64 = xor %126, %1623 -%1625:i64 = xor %125, %1624 -%1626:i64 = mul 11376068507788127593:i64, %1625 -%1627:i64 = xor %1626, %125 -%1628:i64 = lshr %1626, 47:i64 -%1629:i64 = xor %1627, %1628 -%1630:i64 = mul 11376068507788127593:i64, %1629 -%1631:i64 = lshr %1630, 47:i64 -%1632:i64 = xor %1630, %1631 -%1633:i64 = mul 11376068507788127593:i64, %1632 -%1634:i64 = xor %121, %1633 -%1635:i64 = xor %120, %1634 -%1636:i64 = xor %119, %1635 -%1637:i64 = mul 11376068507788127593:i64, %1636 -%1638:i64 = xor %1637, %119 -%1639:i64 = lshr %1637, 47:i64 -%1640:i64 = xor %1638, %1639 -%1641:i64 = mul 11376068507788127593:i64, %1640 -%1642:i64 = lshr %1641, 47:i64 -%1643:i64 = xor %1641, %1642 -%1644:i64 = mul 11376068507788127593:i64, %1643 -%1645:i64 = xor %115, %1644 -%1646:i64 = xor %114, %1645 -%1647:i64 = xor %113, %1646 -%1648:i64 = mul 11376068507788127593:i64, %1647 -%1649:i64 = xor %1648, %113 -%1650:i64 = lshr %1648, 47:i64 -%1651:i64 = xor %1649, %1650 -%1652:i64 = mul 11376068507788127593:i64, %1651 -%1653:i64 = lshr %1652, 47:i64 -%1654:i64 = xor %1652, %1653 -%1655:i64 = mul 11376068507788127593:i64, %1654 -%1656:i64 = xor %109, %1655 -%1657:i64 = xor %108, %1656 -%1658:i64 = xor %107, %1657 -%1659:i64 = mul 11376068507788127593:i64, %1658 -%1660:i64 = xor %1659, %107 -%1661:i64 = lshr %1659, 47:i64 -%1662:i64 = xor %1660, %1661 -%1663:i64 = mul 11376068507788127593:i64, %1662 -%1664:i64 = lshr %1663, 47:i64 -%1665:i64 = xor %1663, %1664 -%1666:i64 = mul 11376068507788127593:i64, %1665 -%1667:i64 = xor %103, %1666 -%1668:i64 = xor %102, %1667 -%1669:i64 = xor %101, %1668 -%1670:i64 = mul 11376068507788127593:i64, %1669 -%1671:i64 = xor %1670, %101 -%1672:i64 = lshr %1670, 47:i64 -%1673:i64 = xor %1671, %1672 -%1674:i64 = mul 11376068507788127593:i64, %1673 -%1675:i64 = lshr %1674, 47:i64 -%1676:i64 = xor %1674, %1675 -%1677:i64 = mul 11376068507788127593:i64, %1676 -%1678:i64 = xor %97, %1677 -%1679:i64 = xor %96, %1678 -%1680:i64 = xor %95, %1679 -%1681:i64 = mul 11376068507788127593:i64, %1680 -%1682:i64 = xor %1681, %95 -%1683:i64 = lshr %1681, 47:i64 -%1684:i64 = xor %1682, %1683 -%1685:i64 = mul 11376068507788127593:i64, %1684 -%1686:i64 = lshr %1685, 47:i64 -%1687:i64 = xor %1685, %1686 -%1688:i64 = mul 11376068507788127593:i64, %1687 -%1689:i64 = xor %91, %1688 -%1690:i64 = xor %90, %1689 -%1691:i64 = xor %89, %1690 -%1692:i64 = mul 11376068507788127593:i64, %1691 -%1693:i64 = xor %1692, %89 -%1694:i64 = lshr %1692, 47:i64 -%1695:i64 = xor %1693, %1694 -%1696:i64 = mul 11376068507788127593:i64, %1695 -%1697:i64 = lshr %1696, 47:i64 -%1698:i64 = xor %1696, %1697 -%1699:i64 = mul 11376068507788127593:i64, %1698 -%1700:i64 = xor %85, %1699 -%1701:i64 = xor %84, %1700 -%1702:i64 = xor %83, %1701 -%1703:i64 = mul 11376068507788127593:i64, %1702 -%1704:i64 = xor %1703, %83 -%1705:i64 = lshr %1703, 47:i64 -%1706:i64 = xor %1704, %1705 -%1707:i64 = mul 11376068507788127593:i64, %1706 -%1708:i64 = lshr %1707, 47:i64 -%1709:i64 = xor %1707, %1708 -%1710:i64 = mul 11376068507788127593:i64, %1709 -%1711:i64 = xor %79, %1710 -%1712:i64 = xor %78, %1711 -%1713:i64 = xor %77, %1712 -%1714:i64 = mul 11376068507788127593:i64, %1713 -%1715:i64 = xor %1714, %77 -%1716:i64 = lshr %1714, 47:i64 -%1717:i64 = xor %1715, %1716 -%1718:i64 = mul 11376068507788127593:i64, %1717 -%1719:i64 = lshr %1718, 47:i64 -%1720:i64 = xor %1718, %1719 -%1721:i64 = mul 11376068507788127593:i64, %1720 -%1722:i64 = xor %73, %1721 -%1723:i64 = xor %72, %1722 -%1724:i64 = xor %71, %1723 -%1725:i64 = mul 11376068507788127593:i64, %1724 -%1726:i64 = xor %1725, %71 -%1727:i64 = lshr %1725, 47:i64 -%1728:i64 = xor %1726, %1727 -%1729:i64 = mul 11376068507788127593:i64, %1728 -%1730:i64 = lshr %1729, 47:i64 -%1731:i64 = xor %1729, %1730 -%1732:i64 = mul 11376068507788127593:i64, %1731 -%1733:i64 = xor %67, %1732 -%1734:i64 = xor %66, %1733 -%1735:i64 = xor %65, %1734 -%1736:i64 = mul 11376068507788127593:i64, %1735 -%1737:i64 = xor %1736, %65 -%1738:i64 = lshr %1736, 47:i64 -%1739:i64 = xor %1737, %1738 -%1740:i64 = mul 11376068507788127593:i64, %1739 -%1741:i64 = lshr %1740, 47:i64 -%1742:i64 = xor %1740, %1741 -%1743:i64 = mul 11376068507788127593:i64, %1742 -%1744:i64 = xor %61, %1743 -%1745:i64 = xor %60, %1744 -%1746:i64 = xor %59, %1745 -%1747:i64 = mul 11376068507788127593:i64, %1746 -%1748:i64 = xor %1747, %59 -%1749:i64 = lshr %1747, 47:i64 -%1750:i64 = xor %1748, %1749 -%1751:i64 = mul 11376068507788127593:i64, %1750 -%1752:i64 = lshr %1751, 47:i64 -%1753:i64 = xor %1751, %1752 -%1754:i64 = mul 11376068507788127593:i64, %1753 -%1755:i64 = xor %55, %1754 -%1756:i64 = xor %54, %1755 -%1757:i64 = xor %53, %1756 -%1758:i64 = mul 11376068507788127593:i64, %1757 -%1759:i64 = xor %1758, %53 -%1760:i64 = lshr %1758, 47:i64 -%1761:i64 = xor %1759, %1760 -%1762:i64 = mul 11376068507788127593:i64, %1761 -%1763:i64 = lshr %1762, 47:i64 -%1764:i64 = xor %1762, %1763 -%1765:i64 = mul 11376068507788127593:i64, %1764 -%1766:i64 = xor %49, %1765 -%1767:i64 = xor %48, %1766 -%1768:i64 = xor %47, %1767 -%1769:i64 = mul 11376068507788127593:i64, %1768 -%1770:i64 = xor %1769, %47 -%1771:i64 = lshr %1769, 47:i64 -%1772:i64 = xor %1770, %1771 -%1773:i64 = mul 11376068507788127593:i64, %1772 -%1774:i64 = lshr %1773, 47:i64 -%1775:i64 = xor %1773, %1774 -%1776:i64 = mul 11376068507788127593:i64, %1775 -%1777:i64 = xor %43, %1776 -%1778:i64 = xor %42, %1777 -%1779:i64 = xor %41, %1778 -%1780:i64 = mul 11376068507788127593:i64, %1779 -%1781:i64 = xor %1780, %41 -%1782:i64 = lshr %1780, 47:i64 -%1783:i64 = xor %1781, %1782 -%1784:i64 = mul 11376068507788127593:i64, %1783 -%1785:i64 = lshr %1784, 47:i64 -%1786:i64 = xor %1784, %1785 -%1787:i64 = mul 11376068507788127593:i64, %1786 -%1788:i64 = xor %37, %1787 -%1789:i64 = xor %36, %1788 -%1790:i64 = xor %35, %1789 -%1791:i64 = mul 11376068507788127593:i64, %1790 -%1792:i64 = xor %1791, %35 -%1793:i64 = lshr %1791, 47:i64 -%1794:i64 = xor %1792, %1793 -%1795:i64 = mul 11376068507788127593:i64, %1794 -%1796:i64 = lshr %1795, 47:i64 -%1797:i64 = xor %1795, %1796 -%1798:i64 = mul 11376068507788127593:i64, %1797 -%1799:i64 = xor %31, %1798 -%1800:i64 = xor %30, %1799 -%1801:i64 = xor %29, %1800 -%1802:i64 = mul 11376068507788127593:i64, %1801 -%1803:i64 = xor %1802, %29 -%1804:i64 = lshr %1802, 47:i64 -%1805:i64 = xor %1803, %1804 -%1806:i64 = mul 11376068507788127593:i64, %1805 -%1807:i64 = lshr %1806, 47:i64 -%1808:i64 = xor %1806, %1807 -%1809:i64 = mul 11376068507788127593:i64, %1808 -%1810:i64 = xor %25, %1809 -%1811:i64 = xor %24, %1810 -%1812:i64 = xor %23, %1811 -%1813:i64 = mul 11376068507788127593:i64, %1812 -%1814:i64 = xor %1813, %23 -%1815:i64 = lshr %1813, 47:i64 -%1816:i64 = xor %1814, %1815 -%1817:i64 = mul 11376068507788127593:i64, %1816 -%1818:i64 = lshr %1817, 47:i64 -%1819:i64 = xor %1817, %1818 -%1820:i64 = mul 11376068507788127593:i64, %1819 -%1821:i64 = xor %19, %1820 -%1822:i64 = xor %18, %1821 -%1823:i64 = xor %17, %1822 -%1824:i64 = mul 11376068507788127593:i64, %1823 -%1825:i64 = xor %1824, %17 -%1826:i64 = lshr %1824, 47:i64 -%1827:i64 = xor %1825, %1826 -%1828:i64 = mul 11376068507788127593:i64, %1827 -%1829:i64 = lshr %1828, 47:i64 -%1830:i64 = xor %1828, %1829 -%1831:i64 = mul 11376068507788127593:i64, %1830 -%1832:i64 = xor %13, %1831 -%1833:i64 = xor %12, %1832 -%1834:i64 = xor %11, %1833 -%1835:i64 = mul 11376068507788127593:i64, %1834 -%1836:i64 = xor %1835, %11 -%1837:i64 = lshr %1835, 47:i64 -%1838:i64 = xor %1836, %1837 -%1839:i64 = mul 11376068507788127593:i64, %1838 -%1840:i64 = lshr %1839, 47:i64 -%1841:i64 = xor %1839, %1840 -%1842:i64 = mul 11376068507788127593:i64, %1841 -%1843:i64 = xor %7, %1842 -%1844:i64 = xor %6, %1843 -%1845:i64 = xor %5, %1844 -%1846:i64 = mul 11376068507788127593:i64, %1845 -%1847:i64 = xor %1846, %5 -%1848:i64 = lshr %1846, 47:i64 -%1849:i64 = xor %1847, %1848 -%1850:i64 = mul 11376068507788127593:i64, %1849 -%1851:i64 = lshr %1850, 47:i64 -%1852:i64 = xor %1850, %1851 -%1853:i64 = mul 11376068507788127593:i64, %1852 -%1854:i64 = xor %1, %1853 -%1855:i64 = var -%1856:i64 = add 16:i64, %1855 -%1857:i64 = shl %1856, 48:i64 -%1858:i64 = lshr %1856, 16:i64 -%1859:i64 = or %1857, %1858 -%1860:i64 = var -%1861:i64 = var -%1862:i64 = xor %1860, %1861 -%1863:i64 = xor %1859, %1862 -%1864:i64 = mul 11376068507788127593:i64, %1863 -%1865:i64 = xor %1864, %1859 -%1866:i64 = lshr %1864, 47:i64 -%1867:i64 = xor %1865, %1866 -%1868:i64 = mul 11376068507788127593:i64, %1867 -%1869:i64 = lshr %1868, 47:i64 -%1870:i64 = xor %1868, %1869 -%1871:i64 = mul 11376068507788127593:i64, %1870 -%1872:i64 = xor %1855, %1871 -%1873:i64 = phi %0, %1854, %1872 -%1874:i64 = var -cand %1873 %1874 From 4c0cdbf4579875113b8268a6bb2539e5163bfe56 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Thu, 19 Apr 2018 23:30:15 +0200 Subject: [PATCH 31/49] Add extractor_tests back to check --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e66ba6da..a67817a3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -321,7 +321,7 @@ configure_file( add_custom_target(check COMMAND ${CMAKE_BINARY_DIR}/run_lit - DEPENDS inst_tests parser-test parser_tests profileRuntime souper souper-check souperPass souperPassProfileAll) + DEPENDS extractor_tests inst_tests parser-test parser_tests profileRuntime souper souper-check souperPass souperPassProfileAll) find_program(GO_EXECUTABLE NAMES go DOC "go executable") if(NOT GO_EXECUTABLE STREQUAL "GO_EXECUTABLE-NOTFOUND") From 0e51008e310fd4828d0f372307ea224bb2346976 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sun, 22 Apr 2018 23:28:18 +0200 Subject: [PATCH 32/49] Fix assertions --- lib/Extractor/ExprBuilder.cpp | 5 +---- lib/Extractor/KLEEBuilder.cpp | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index fc3285d88..fc2957ddb 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -494,9 +494,6 @@ Inst *ExprBuilder::createUBPathInstsPred( UBPathInstMap::iterator PI = CachedUBPathInsts.find(PathInst); if (PI == CachedUBPathInsts.end()) { - // It's possible that we don't have a cached instruction yet, - // e.g., the CurrentInst is a select operator. - assert(CurrentInst->K == Inst::Select && "No cached Inst?"); CachedUBPathInsts[PathInst] = {}; PI = CachedUBPathInsts.find(PathInst); } @@ -1101,7 +1098,7 @@ Inst *ExprBuilder::GetCandidateExprForReplacement( // Get demanded bits constraints if (!Mapping.LHS->DemandedBits.isAllOnesValue()) - RHS = LIC->getInst(Inst::And, 1, {RHS, DemandedBits}); + RHS = LIC->getInst(Inst::And, RHS->Width, {RHS, DemandedBits}); for (const auto &I : getVarInsts({Mapping.LHS, Mapping.RHS})) Ante = LIC->getInst(Inst::And, 1, {Ante, getDemandedBitsCondition(I)}); diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index f8112057a..23ea5227a 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -148,7 +148,7 @@ class KLEEBuilder : public ExprBuilder { case Inst::Phi: { // TODO: Move to ExprBuilder const auto &PredExpr = BlockPredMap[I->B]; - assert(PredExpr.size() && "there must be block predicates"); + assert((PredExpr.size() || Ops.size() == 1) && "there must be block predicates"); ref E = get(Ops[0]); // e.g. P2 ? (P1 ? Op1_Expr : Op2_Expr) : Op3_Expr for (unsigned J = 1; J < Ops.size(); ++J) { From 4bf4c01fc68da73a80da5c33afb279b319698c64 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sun, 22 Apr 2018 23:59:36 +0200 Subject: [PATCH 33/49] Clean-up KLEEBuilder --- lib/Extractor/KLEEBuilder.cpp | 85 +++++++---------------------------- 1 file changed, 17 insertions(+), 68 deletions(-) diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 23ea5227a..85853e8f9 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -15,29 +15,8 @@ #include "klee/Expr.h" #include "klee/util/ExprPPrinter.h" #include "klee/util/ExprSMTLIBPrinter.h" -#include "klee/util/Ref.h" #include "llvm/Analysis/LoopInfo.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/GetElementPtrTypeIterator.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/Support/CommandLine.h" #include "souper/Extractor/ExprBuilder.h" -#include "souper/Inst/Inst.h" -#include "souper/Util/UniqueNameSet.h" -#include -#include -#include -#include -#include - -static llvm::cl::opt DumpKLEEExprs( - "dump-klee-exprs", - llvm::cl::desc("Dump KLEE expressions after SMTLIB queries"), - llvm::cl::init(false)); using namespace llvm; using namespace klee; @@ -45,25 +24,29 @@ using namespace souper; namespace { +static llvm::cl::opt DumpKLEEExprs( + "dump-klee-exprs", + llvm::cl::desc("Dump KLEE expressions after SMTLIB queries"), + llvm::cl::init(false)); + class KLEEBuilder : public ExprBuilder { + std::vector> Arrays; + std::map> ExprMap; + std::vector Vars; + public: KLEEBuilder(InstContext &IC) { LIC = &IC; } - ~KLEEBuilder() {} - - std::vector> Arrays; - std::vector Vars; - std::map> ExprMap; std::string GetExprStr(const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate) override { - Inst *Candidate = GetCandidateExprForReplacement(BPCs, PCs, Mapping, Negate); - if (!Candidate) + Inst *Cand = GetCandidateExprForReplacement(BPCs, PCs, Mapping, Negate); + if (!Cand) return std::string(); - ref E = get(Candidate); + ref E = get(Cand); std::string SStr; llvm::raw_string_ostream SS(SStr); @@ -82,10 +65,10 @@ class KLEEBuilder : public ExprBuilder { std::string SMTStr; llvm::raw_string_ostream SMTSS(SMTStr); ConstraintManager Manager; - Inst *Candidate = GetCandidateExprForReplacement(BPCs, PCs, Mapping, Negate); - if (!Candidate) + Inst *Cand = GetCandidateExprForReplacement(BPCs, PCs, Mapping, Negate); + if (!Cand) return std::string(); - ref E = get(Candidate); + ref E = get(Cand); Query KQuery(Manager, E); ExprSMTLIBPrinter Printer; Printer.setOutput(SMTSS); @@ -146,74 +129,60 @@ class KLEEBuilder : public ExprBuilder { case Inst::Var: return makeSizedArrayRead(I->Width, I->Name, I); case Inst::Phi: { - // TODO: Move to ExprBuilder - const auto &PredExpr = BlockPredMap[I->B]; + const auto &PredExpr = I->B->PredVars; assert((PredExpr.size() || Ops.size() == 1) && "there must be block predicates"); ref E = get(Ops[0]); // e.g. P2 ? (P1 ? Op1_Expr : Op2_Expr) : Op3_Expr for (unsigned J = 1; J < Ops.size(); ++J) { E = SelectExpr::create(get(PredExpr[J-1]), E, get(Ops[J])); } - //UBPathInsts.push_back(I); return E; } case Inst::Add: return buildAssoc(AddExpr::create, Ops); case Inst::AddNSW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, addnswUB(I)); return Add; } case Inst::AddNUW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, addnuwUB(I)); return Add; } case Inst::AddNW: { ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, LIC->getInst(Inst::And, 1, - // {addnswUB(I), addnuwUB(I)})); return Add; } case Inst::Sub: return SubExpr::create(get(Ops[0]), get(Ops[1])); case Inst::SubNSW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, subnswUB(I)); return Sub; } case Inst::SubNUW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, subnuwUB(I)); return Sub; } case Inst::SubNW: { ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, LIC->getInst(Inst::And, 1, - // {subnswUB(I), subnuwUB(I)})); return Sub; } case Inst::Mul: return buildAssoc(MulExpr::create, Ops); case Inst::MulNSW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, mulnswUB(I)); return Mul; } case Inst::MulNUW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, mulnuwUB(I)); return Mul; } case Inst::MulNW: { ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, LIC->getInst(Inst::And, 1, - // {mulnswUB(I), mulnuwUB(I)})); return Mul; } // We introduce these extra checks here because KLEE invokes llvm::APInt's - // div functions , which crash upon divide-by-zero. + // div functions, which crash upon divide-by-zero. case Inst::UDiv: case Inst::SDiv: case Inst::UDivExact: @@ -227,7 +196,6 @@ class KLEEBuilder : public ExprBuilder { // a constant zero. ref R = get(Ops[1]); if (R->isZero()) { - //recordUBInstruction(I, LIC->getConst(APInt(1, false))); return klee::ConstantExpr::create(0, Ops[1]->Width); } @@ -237,33 +205,26 @@ class KLEEBuilder : public ExprBuilder { case Inst::UDiv: { ref Udiv = UDivExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, udivUB(I)); return Udiv; } case Inst::SDiv: { ref Sdiv = SDivExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, sdivUB(I)); return Sdiv; } case Inst::UDivExact: { ref Udiv = UDivExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, LIC->getInst(Inst::And, 1, - // {udivUB(I), udivExactUB(I)})); return Udiv; } case Inst::SDivExact: { ref Sdiv = SDivExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, LIC->getInst(Inst::And, 1, {sdivUB(I), sdivExactUB(I)})); return Sdiv; } case Inst::URem: { ref Urem = URemExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, udivUB(I)); return Urem; } case Inst::SRem: { ref Srem = SRemExpr::create(get(Ops[0]), R); - //recordUBInstruction(I, sdivUB(I)); return Srem; } llvm_unreachable("unknown kind"); @@ -278,49 +239,37 @@ class KLEEBuilder : public ExprBuilder { return buildAssoc(XorExpr::create, Ops); case Inst::Shl: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::ShlNSW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnswUB(I)})); return Result; } case Inst::ShlNUW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, LIC->getInst(Inst::And, 1, {shiftUB(I), shlnuwUB(I)})); return Result; } case Inst::ShlNW: { ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, LIC->getInst(Inst::And, 1, - // {shiftUB(I), LIC->getInst(Inst::And, 1, {shlnswUB(I), shlnuwUB(I)})})); return Result; } case Inst::LShr: { ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::LShrExact: { ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, LIC->getInst(Inst::And, 1, - // {shiftUB(I), lshrExactUB(I)})); return Result; } case Inst::AShr: { ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, shiftUB(I)); return Result; } case Inst::AShrExact: { ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - //recordUBInstruction(I, LIC->getInst(Inst::And, 1, - // {shiftUB(I), ashrExactUB(I)})); return Result; } case Inst::Select: - //UBPathInsts.push_back(I); return SelectExpr::create(get(Ops[0]), get(Ops[1]), get(Ops[2])); case Inst::ZExt: return ZExtExpr::create(get(Ops[0]), I->Width); From c4fdf8bd8da3190d800dcba24d0e5d2aaad47260 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 23 Apr 2018 00:06:06 +0200 Subject: [PATCH 34/49] Remove unnecessary functions --- include/souper/Extractor/ExprBuilder.h | 1 - lib/Extractor/ExprBuilder.cpp | 32 +------------------------- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 51a923223..25dca2415 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -78,7 +78,6 @@ class ExprBuilder { // Local reference InstContext *LIC; - std::map> BlockPredMap; std::map BlockPCMap; UniqueNameSet ArrayNames; diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index fc2957ddb..a89301d14 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -32,16 +32,6 @@ static llvm::cl::opt SMTExprBuilder( namespace souper { -void ExprBuilder::setBlockPredicates(Inst *I) { - assert(I->K == Inst::Phi && "not a phi inst"); - if (BlockPredMap.count(I->B)) - return; - std::vector PredExpr; - for (auto const &PredVar : I->B->PredVars) - PredExpr.push_back(PredVar); - BlockPredMap[I->B] = PredExpr; -} - bool ExprBuilder::getUBPaths(Inst *I, UBPath *Current, std::vector> &Paths, UBPathInstMap &CachedUBPathInsts, unsigned Depth) { @@ -195,7 +185,7 @@ Inst *ExprBuilder::createPathPred( Inst *Pred = LIC->getConst(APInt(1, true)); if (PathInst->K == Inst::Phi) { unsigned Num = BlockConstraints[PathInst->B]; - const auto &PredExpr = BlockPredMap[PathInst->B]; + const auto &PredExpr = PathInst->B->PredVars; // Sanity checks assert(PredExpr.size() && "there must be path predicates for the UBs"); assert(PredExpr.size() == PathInst->Ops.size()-1 && @@ -465,23 +455,6 @@ void ExprBuilder::setBlockPCMap(const BlockPCs &BPCs) { } } -void ExprBuilder::setBlockPredicateMap(Inst *Root) { - // breadth-first search - std::set Visited; - std::queue Q; - Q.push(Root); - while (!Q.empty()) { - Inst *I = Q.front(); - Q.pop(); - if (I->K == Inst::Phi) - setBlockPredicates(I); - - if (Visited.insert(I).second) - for (auto Op : I->orderedOps()) - Q.push(Op); - } -} - Inst *ExprBuilder::createUBPathInstsPred( Inst *CurrentInst, std::vector &PathInsts, std::map &BlockConstraints, @@ -1071,9 +1044,6 @@ Inst *ExprBuilder::GetCandidateExprForReplacement( if (!LHS->DemandedBits.isAllOnesValue()) LHS = LIC->getInst(Inst::And, LHS->Width, {LHS, DemandedBits}); - // TODO - setBlockPredicateMap(Mapping.LHS); - // Get UB constraints of LHS Inst *LHSUB = getUBInstCondition(Mapping.LHS); if (LHSUB == LIC->getConst(APInt(1, false))) From 4f61f561292e1c59799b147be2cb6a955b029fbb Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 23 Apr 2018 00:57:21 +0200 Subject: [PATCH 35/49] Clean-up expression builder --- include/souper/Extractor/ExprBuilder.h | 51 +++---- lib/Extractor/ExprBuilder.cpp | 200 ++----------------------- lib/Extractor/KLEEBuilder.cpp | 1 + 3 files changed, 38 insertions(+), 214 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 25dca2415..1d84fe4d9 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -24,33 +24,42 @@ using namespace souper; namespace souper { class ExprBuilder { -public: - enum Builder { - KLEE - }; - const unsigned MAX_PHI_DEPTH = 25; - + typedef std::unordered_map> UBPathInstMap; typedef std::map BlockPCPredMap; - + struct UBPath { std::map BlockConstraints; std::map SelectBranches; std::vector Insts; std::vector UBInsts; }; - + struct BlockPCPhiPath { std::map BlockConstraints; std::vector Phis; std::vector PCs; }; - virtual ~ExprBuilder(); + std::map BlockPCMap; +public: + enum Builder { + KLEE + }; + + virtual ~ExprBuilder() {}; + + virtual std::string GetExprStr(const BlockPCs &BPCs, + const std::vector &PCs, InstMapping Mapping, + std::vector *ModelVars, bool Negate=false) = 0; + + virtual std::string BuildQuery(const BlockPCs &BPCs, + const std::vector &PCs, InstMapping Mapping, + std::vector *ModelVars, bool Negate=false) = 0; +protected: + InstContext *LIC; - void setBlockPredicates(Inst *I); - void setBlockPredicateMap(Inst *Root); bool getUBPaths(Inst *I, UBPath *Current, std::vector> &Paths, UBPathInstMap &CachedUBPathInsts, unsigned Depth); @@ -66,21 +75,14 @@ class ExprBuilder { std::map *SelectBranches, UBPathInstMap &CachedUBPathInsts); - Inst *getInstMapping(const InstMapping &IM); + void setBlockPCMap(const BlockPCs &BPCs); + Inst *getUBInstCondition(Inst *Root); Inst *getDemandedBitsCondition(Inst *I); Inst *getBlockPCs(Inst *Root); - void setBlockPCMap(const BlockPCs &BPCs); std::map getUBInstConstraints(Inst *Root); std::vector getUBPathInsts(Inst *Root); std::vector getVarInsts(const std::vector Insts); - - // Local reference - InstContext *LIC; - - std::map BlockPCMap; - UniqueNameSet ArrayNames; - Inst *getExtractInst(Inst *I, unsigned Offset, unsigned W); Inst *getImpliesInst(Inst *Ante, Inst *I); @@ -103,14 +105,6 @@ class ExprBuilder { Inst *GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool Negate); - - virtual std::string GetExprStr(const BlockPCs &BPCs, - const std::vector &PCs, InstMapping Mapping, - std::vector *ModelVars, bool Negate=false) = 0; - - virtual std::string BuildQuery(const BlockPCs &BPCs, - const std::vector &PCs, InstMapping Mapping, - std::vector *ModelVars, bool Negate=false) = 0; }; std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, @@ -118,7 +112,6 @@ std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, std::vector *ModelVars, bool Negate=false); std::unique_ptr createKLEEBuilder(InstContext &IC); - } #endif // SOUPER_EXTRACTOR_EXPRBUILDER_H diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index a89301d14..2f353e0aa 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -20,7 +20,7 @@ using namespace llvm; using namespace souper; -ExprBuilder::~ExprBuilder() {} +namespace souper { static llvm::cl::opt SMTExprBuilder( "souper-smt-expr-builder", @@ -30,8 +30,6 @@ static llvm::cl::opt SMTExprBuilder( "Use KLEE's Expr library")), llvm::cl::init(souper::ExprBuilder::KLEE)); -namespace souper { - bool ExprBuilder::getUBPaths(Inst *I, UBPath *Current, std::vector> &Paths, UBPathInstMap &CachedUBPathInsts, unsigned Depth) { @@ -228,7 +226,7 @@ Inst *ExprBuilder::createPathPred( // from the phi. For each path, we also keep the the phi instructions // along the path and the UB instructions associated with these phi // instructions; -// (2) then for each path, we generate a corresponding KLEE expression +// (2) then for each path, we generate a corresponding expression // based on the facts that we collected in step (1), including: // * UB instructions; // * Phi predicates; @@ -240,8 +238,8 @@ Inst *ExprBuilder::createPathPred( // to process some file due to the large memory footprint, i.e., `newing' // too many UBPaths. Two tricks are used to relief the penalty of the // path explosion problem: -// (1) caching the KLEE expresions for each processed phi, where each -// KLEE expression encodes the path that starts from one of the phi's +// (1) caching the expresions for each processed phi, where each +// expression encodes the path that starts from one of the phi's // values. For example, when processing a sample souper IR below // // %0 = block @@ -254,7 +252,7 @@ Inst *ExprBuilder::createPathPred( // %11:i32 = phi %1, %3, %5 // %12:i32 = phi %0, %6, %11 // -// we first encounter phi %11. The generated KLEE expression +// we first encounter phi %11. The generated expression // for this phi encodes two paths, i.e., %3 and %5. We cache // these two into CachedUBPathInsts. Then we move to process phi %12. // At this point, rather than recursively re-contruct %11 (through @@ -274,7 +272,7 @@ Inst *ExprBuilder::createPathPred( // generated by souper. For example, if we say %12 depends on %11, then // %12 would never appear earlier than %11. Inst *ExprBuilder::getUBInstCondition(Inst *Root) { - // A map from a Phi instruction to all of its KLEE expressions that + // A map from a Phi instruction to all of its expressions that // encode the path and UB Inst predicates. UBPathInstMap CachedUBPathInsts; std::set UsedUBInsts; @@ -334,41 +332,28 @@ Inst *ExprBuilder::getDemandedBitsCondition(Inst *I) { Inst *One = LIC->getConst(APInt(Width, 1)); if (I->KnownZeros.getBoolValue()) { - //ref NotZeros = NotExpr::create(klee::ConstantExpr::alloc(Origin->KnownZeros)); Inst *NotZeros = LIC->getInst(Inst::Xor, Width, {LIC->getConst(I->KnownZeros), LIC->getConst(APInt::getAllOnesValue(Width))}); - //ref VarOrNotZero = OrExpr::create(Var, NotZeros); Inst *VarNotZero = LIC->getInst(Inst::Or, Width, {I, NotZeros}); - //ZeroBitsMap[Origin] = EqExpr::create(VarOrNotZero, NotZeros); Inst *ZeroBits = LIC->getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); Result = LIC->getInst(Inst::And, 1, {Result, ZeroBits}); } if (I->KnownOnes.getBoolValue()) { - //ref Ones = klee::ConstantExpr::alloc(Origin->KnownOnes); - //ref VarAndOnes = AndExpr::create(Var, Ones); Inst *Ones = LIC->getConst(I->KnownOnes); Inst *VarAndOnes = LIC->getInst(Inst::And, Width, {I, Ones}); - //OneBitsMap[Origin] = EqExpr::create(VarAndOnes, Ones); Inst *OneBits = LIC->getInst(Inst::Eq, 1, {VarAndOnes, Ones}); Result = LIC->getInst(Inst::And, 1, {Result, OneBits}); } if (I->NonZero) { - //NonZeroBitsMap[Origin] = NeExpr::create(Var, klee::ConstantExpr::create(0, Width)); Inst *NonZeroBits = LIC->getInst(Inst::Ne, 1, {I, Zero}); Result = LIC->getInst(Inst::And, 1, {Result, NonZeroBits}); } if (I->NonNegative) { - //NonNegBitsMap[Origin] = SleExpr::create(klee::ConstantExpr::create(0, Width), Var); Inst *NonNegBits = LIC->getInst(Inst::Sle, 1, {Zero, I}); Result = LIC->getInst(Inst::And, 1, {Result, NonNegBits}); } if (I->PowOfTwo) { - //ref Zero = klee::ConstantExpr::create(0, Width); - //PowerTwoBitsMap[Origin] = AndExpr::create(NeExpr::create(Var, Zero), - // EqExpr::create(AndExpr::create(Var, - // SubExpr::create(Var, klee::ConstantExpr::create(1, Width))), - // Zero)); Inst *And = LIC->getInst(Inst::And, Width, {I, LIC->getInst(Inst::Sub, Width, {I, One})}); Inst *PowerTwoBits = LIC->getInst(Inst::And, 1, @@ -377,22 +362,15 @@ Inst *ExprBuilder::getDemandedBitsCondition(Inst *I) { Result = LIC->getInst(Inst::And, 1, {Result, PowerTwoBits}); } if (I->Negative) { - //NegBitsMap[Origin] = SltExpr::create(Var, klee::ConstantExpr::create(0, Width)); Inst *NegBits = LIC->getInst(Inst::Slt, 1, {I, Zero}); Result = LIC->getInst(Inst::And, 1, {Result, NegBits}); } if (I->NumSignBits > 1) { - //ref Res = AShrExpr::create(Var, klee::ConstantExpr::create(Width - Origin->NumSignBits, Width)); Inst *Res = LIC->getInst(Inst::AShr, Width, {I, LIC->getConst(APInt(Width, Width - I->NumSignBits))}); - //ref TestOnes = AShrExpr::create(ShlExpr::create(klee::ConstantExpr::create(1, Width), - // klee::ConstantExpr::create(Width - 1, Width)), - // klee::ConstantExpr::create(Width - 1, Width)); Inst *TestOnes = LIC->getInst(Inst::AShr, Width, {LIC->getInst(Inst::Shl, Width, {One, LIC->getConst(APInt(Width, Width-1))}), LIC->getConst(APInt(Width, Width-1))}); - //SignBitsMap[Origin] = OrExpr::create(EqExpr::create(Res, TestOnes), - // EqExpr::create(Res, klee::ConstantExpr::create(0, Width))); Inst *SignBits = LIC->getInst(Inst::Or, 1, {LIC->getInst(Inst::Eq, 1, {Res, TestOnes}), LIC->getInst(Inst::Eq, 1, {Res, Zero})}); @@ -447,7 +425,7 @@ void ExprBuilder::setBlockPCMap(const BlockPCs &BPCs) { assert(BPC.B && "Block is NULL!"); BlockPCPredMap &PCMap = BlockPCMap[BPC.B]; auto I = PCMap.find(BPC.PredIdx); - Inst *PE = getInstMapping(BPC.PC); + Inst *PE = LIC->getInst(Inst::Eq, 1, {BPC.PC.LHS, BPC.PC.RHS}); if (I == PCMap.end()) PCMap[BPC.PredIdx] = PE; else @@ -488,26 +466,6 @@ Inst *ExprBuilder::createUBPathInstsPred( return Pred; } -#if 0 -void ExprBuilder::recordUBInstruction(Inst *I, Inst *E) { - if (!IsForBlockPCUBInst) { - UBExprMap[I] = E; - } - else if (UBInstPrecondition) { - // The current UBInst comes from BlockPC. It's possible - // that the precondition is missing at this point (e.g., - // the corresponding Phi is not part of the current - // Souper IR because the Phi is not in the equivalence class - // of the instruction. - UBExprMap[I] = getImpliesInst(UBInstPrecondition, E); - } -} -#endif - -Inst *ExprBuilder::getInstMapping(const InstMapping &IM) { - return LIC->getInst(Inst::Eq, 1, {IM.LHS, IM.RHS}); -} - Inst *ExprBuilder::getExtractInst(Inst *I, unsigned Offset, unsigned W) { if (I->K == Inst::Const || I->K == Inst::UntypedConst) { return LIC->getConst(APInt(I->Val.ashr(Offset)).zextOrTrunc(W)); @@ -530,17 +488,6 @@ Inst *ExprBuilder::getImpliesInst(Inst *Ante, Inst *I) { } Inst *ExprBuilder::addnswUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Add = AddExpr::create(L, R); - Expr::Width Width = L->getWidth(); - ref LMSB = ExtractExpr::create(L, Width-1, Expr::Bool); - ref RMSB = ExtractExpr::create(R, Width-1, Expr::Bool); - ref AddMSB = ExtractExpr::create(Add, Width-1, Expr::Bool); - return Expr::createImplies(EqExpr::create(LMSB, RMSB), - EqExpr::create(LMSB, AddMSB)); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -554,16 +501,6 @@ Inst *ExprBuilder::addnswUB(Inst *I) { } Inst *ExprBuilder::addnuwUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - Expr::Width Width = L->getWidth(); - ref Lext = ZExtExpr::create(L, Width+1); - ref Rext = ZExtExpr::create(R, Width+1); - ref Add = AddExpr::create(Lext, Rext); - ref AddMSB = ExtractExpr::create(Add, Width, Expr::Bool); - return Expr::createIsZero(AddMSB); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -576,17 +513,6 @@ Inst *ExprBuilder::addnuwUB(Inst *I) { } Inst *ExprBuilder::subnswUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Sub = SubExpr::create(L, R); - Expr::Width Width = L->getWidth(); - ref LMSB = ExtractExpr::create(L, Width-1, Expr::Bool); - ref RMSB = ExtractExpr::create(R, Width-1, Expr::Bool); - ref SubMSB = ExtractExpr::create(Sub, Width-1, Expr::Bool); - return Expr::createImplies(NeExpr::create(LMSB, RMSB), - EqExpr::create(LMSB, SubMSB)); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -600,16 +526,6 @@ Inst *ExprBuilder::subnswUB(Inst *I) { } Inst *ExprBuilder::subnuwUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - Expr::Width Width = L->getWidth(); - ref Lext = ZExtExpr::create(L, Width+1); - ref Rext = ZExtExpr::create(R, Width+1); - ref Sub = SubExpr::create(Lext, Rext); - ref SubMSB = ExtractExpr::create(Sub, Width, Expr::Bool); - return Expr::createIsZero(SubMSB); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -622,20 +538,6 @@ Inst *ExprBuilder::subnuwUB(Inst *I) { } Inst *ExprBuilder::mulnswUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - // The computation below has to be performed on the operands of - // multiplication instruction. The instruction using mulnswUB() - // can be of different width, for instance in SMulO instruction - // which is of 1-bit, but the operands width are to be used here. - Expr::Width Width = get(Ops[0])->getWidth(); - ref L = SExtExpr::create(get(Ops[0]), 2*Width); - ref R = SExtExpr::create(get(Ops[1]), 2*Width); - ref Mul = MulExpr::create(L, R); - ref LowerBits = ExtractExpr::create(Mul, 0, Width); - ref LowerBitsExt = SExtExpr::create(LowerBits, 2*Width); - return EqExpr::create(Mul, LowerBitsExt); -#endif const std::vector &Ops = I->orderedOps(); // The computation below has to be performed on the operands of // multiplication instruction. The instruction using mulnswUB() @@ -653,16 +555,6 @@ Inst *ExprBuilder::mulnswUB(Inst *I) { } Inst *ExprBuilder::mulnuwUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - Expr::Width Width = L->getWidth(); - ref Lext = ZExtExpr::create(L, 2*Width); - ref Rext = ZExtExpr::create(R, 2*Width); - ref Mul = MulExpr::create(Lext, Rext); - ref HigherBits = ExtractExpr::create(Mul, Width, Width); - return Expr::createIsZero(HigherBits); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -675,23 +567,12 @@ Inst *ExprBuilder::mulnuwUB(Inst *I) { } Inst *ExprBuilder::udivUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref R = get(Ops[1]); - return NeExpr::create(R, klee::ConstantExpr::create(0, R->getWidth())); -#endif const std::vector &Ops = I->orderedOps(); auto R = Ops[1]; return LIC->getInst(Inst::Ne, 1, {R, LIC->getConst(APInt(R->Width, 0))}); } Inst *ExprBuilder::udivExactUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Udiv = UDivExpr::create(L, R); - return EqExpr::create(L, MulExpr::create(R, Udiv)); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -702,18 +583,6 @@ Inst *ExprBuilder::udivExactUB(Inst *I) { } Inst *ExprBuilder::sdivUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref ShiftBy = klee::ConstantExpr::create(L->getWidth()-1, - L->getWidth()); - ref IntMin = ShlExpr::create(klee::ConstantExpr::create( - 1, L->getWidth()), ShiftBy); - ref NegOne = AShrExpr::create(IntMin, ShiftBy); - return AndExpr::create(NeExpr::create(R, klee::ConstantExpr::create( - 0, R->getWidth())), OrExpr::create( - NeExpr::create(L, IntMin), NeExpr::create(R, NegOne))); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -731,12 +600,6 @@ Inst *ExprBuilder::sdivUB(Inst *I) { } Inst *ExprBuilder::sdivExactUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Sdiv = SDivExpr::create(L, R); - return EqExpr::create(L, MulExpr::create(R, Sdiv)); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -747,12 +610,6 @@ Inst *ExprBuilder::sdivExactUB(Inst *I) { } Inst *ExprBuilder::shiftUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Lwidth = klee::ConstantExpr::create(L->getWidth(), L->getWidth()); - return UltExpr::create(R, Lwidth); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -762,13 +619,6 @@ Inst *ExprBuilder::shiftUB(Inst *I) { } Inst *ExprBuilder::shlnswUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = ShlExpr::create(L, R); - ref RShift = AShrExpr::create(Result, R); - return EqExpr::create(RShift, L); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -779,13 +629,6 @@ Inst *ExprBuilder::shlnswUB(Inst *I) { } Inst *ExprBuilder::shlnuwUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = ShlExpr::create(L, R); - ref RShift = LShrExpr::create(Result, R); - return EqExpr::create(RShift, L); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -796,13 +639,6 @@ Inst *ExprBuilder::shlnuwUB(Inst *I) { } Inst *ExprBuilder::lshrExactUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = LShrExpr::create(L, R); - ref LShift = ShlExpr::create(Result, R); - return EqExpr::create(LShift, L); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -813,13 +649,6 @@ Inst *ExprBuilder::lshrExactUB(Inst *I) { } Inst *ExprBuilder::ashrExactUB(Inst *I) { -#if 0 - const std::vector &Ops = I->orderedOps(); - ref L = get(Ops[0]), R = get(Ops[1]); - ref Result = AShrExpr::create(L, R); - ref LShift = ShlExpr::create(Result, R); - return EqExpr::create(LShift, L); -#endif const std::vector &Ops = I->orderedOps(); auto L = Ops[0]; auto R = Ops[1]; @@ -887,9 +716,9 @@ std::map ExprBuilder::getUBInstConstraints(Inst *Root) { case Inst::URem: case Inst::SRem: { // Fall-through // If the second oprand is 0, then it definitely causes UB. - // There are quite a few cases where KLEE folds operations into zero, + // There are a few cases where an expression folds operations into zero, // e.g., "sext i16 0 to i32", "0 + 0", "2 - 2", etc. In all cases, - // we skip building the corresponding KLEE expressions and just return + // we skip building the corresponding expressions and just return // a constant zero. Inst *R = I->Ops[1]; if (R == LIC->getConst(APInt(R->Width, 0))) { @@ -1039,7 +868,7 @@ Inst *ExprBuilder::GetCandidateExprForReplacement( Inst *LHS = Mapping.LHS; Inst *Ante = LIC->getConst(APInt(1, true)); - // Get demanded bits constraints + // Get demanded bits Inst *DemandedBits = LIC->getConst(LHS->DemandedBits); if (!LHS->DemandedBits.isAllOnesValue()) LHS = LIC->getInst(Inst::And, LHS->Width, {LHS, DemandedBits}); @@ -1047,13 +876,13 @@ Inst *ExprBuilder::GetCandidateExprForReplacement( // Get UB constraints of LHS Inst *LHSUB = getUBInstCondition(Mapping.LHS); if (LHSUB == LIC->getConst(APInt(1, false))) - return nullptr; + return nullptr; // Build PCs for (const auto &PC : PCs) { - Inst *Eq = getInstMapping(PC); + Inst *Eq = LIC->getInst(Inst::Eq, 1, {PC.LHS, PC.RHS}); Ante = LIC->getInst(Inst::And, 1, {Ante, Eq}); - // Get UB constraints of PCs + // Get UB constraints of PC LHSUB = LIC->getInst(Inst::And, 1, {LHSUB, getUBInstCondition(Eq)}); } @@ -1066,10 +895,11 @@ Inst *ExprBuilder::GetCandidateExprForReplacement( // Build RHS Inst *RHS = Mapping.RHS; - // Get demanded bits constraints + // Get demanded bits if (!Mapping.LHS->DemandedBits.isAllOnesValue()) RHS = LIC->getInst(Inst::And, RHS->Width, {RHS, DemandedBits}); + // Get known bit constraints for (const auto &I : getVarInsts({Mapping.LHS, Mapping.RHS})) Ante = LIC->getInst(Inst::And, 1, {Ante, getDemandedBitsCondition(I)}); diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 85853e8f9..2f80d69bf 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -30,6 +30,7 @@ static llvm::cl::opt DumpKLEEExprs( llvm::cl::init(false)); class KLEEBuilder : public ExprBuilder { + UniqueNameSet ArrayNames; std::vector> Arrays; std::map> ExprMap; std::vector Vars; From 683fdff1fcb20949709391125b16132ce2001576 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 23 Apr 2018 01:02:22 +0200 Subject: [PATCH 36/49] Reorder --- include/souper/Extractor/ExprBuilder.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 1d84fe4d9..c56e076ef 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -24,18 +24,14 @@ using namespace souper; namespace souper { class ExprBuilder { - const unsigned MAX_PHI_DEPTH = 25; - typedef std::unordered_map> UBPathInstMap; typedef std::map BlockPCPredMap; - struct UBPath { std::map BlockConstraints; std::map SelectBranches; std::vector Insts; std::vector UBInsts; }; - struct BlockPCPhiPath { std::map BlockConstraints; std::vector Phis; @@ -43,6 +39,7 @@ class ExprBuilder { }; std::map BlockPCMap; + const unsigned MAX_PHI_DEPTH = 25; public: enum Builder { KLEE From 364e8bc2fc116149d2df1cbba0869bbac532a651 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 7 May 2018 21:25:25 +0200 Subject: [PATCH 37/49] Add z3 to build deps --- build_deps.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/build_deps.sh b/build_deps.sh index d9b0a78af..8e110b7a3 100755 --- a/build_deps.sh +++ b/build_deps.sh @@ -24,6 +24,8 @@ hiredis_commit=010756025e8cefd1bc66c6d4ed3b1648ef6f1f95 llvm_branch=tags/RELEASE_600/final klee_repo=https://github.com/rsas/klee klee_branch=pure-bv-qf-llvm-6.0-patch +z3_repo=https://github.com/Z3Prover/z3.git +z3_commit=502d0e37dd2926c1c52e33fa3ae91353d1058e25 llvm_build_type=Release if [ -n "$1" ] ; then @@ -120,3 +122,17 @@ mkdir -p $hiredisdir/install/lib (cd $hiredisdir && git checkout $hiredis_commit && make libhiredis.a && cp -r hiredis.h async.h read.h sds.h adapters install/include/hiredis && cp libhiredis.a install/lib) + +z3dir=$(pwd)/third_party/z3 + +if [ -d $z3dir/.git ] ; then + (cd $z3dir && git fetch) +else + git clone $z3_repo $z3dir +fi + +mkdir -p $z3dir/install + +(cd $z3dir && git checkout $z3_commit && +python scripts/mk_make.py --prefix=$z3dir/install && +cd build && make -j4 install) From 92a91f49c63c599676d1cede6efb163a8a166ad6 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 7 May 2018 21:36:17 +0200 Subject: [PATCH 38/49] Add Z3 to CMake --- CMakeLists.txt | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a67817a3d..619d0f169 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,27 +111,17 @@ find_library(HIREDIS_LIBRARY find_path(Z3_INCLUDE_DIRECTORY NAMES - z3.h + z3++.h PATHS - /usr/include - /usr/local/include - /opt/local/include) -if(Z3_INCLUDE_DIRECTORY STREQUAL "Z3_INCLUDE_DIRECTORY-NOTFOUND") - message(FATAL_ERROR "Can't find folder containing z3.h") -endif() + third_party/z3/install/include) include_directories(${Z3_INCLUDE_DIRECTORY}) -find_library(Z3_LIBRARY_DIRECTORY +find_library(Z3_LIBRARY NAMES z3 PATHS - /usr/lib - /usr/local/lib - /opt/local/lib) -if(Z3_LIBRARY_DIRECTORY STREQUAL "Z3_LIBRARY_DIRECTORY-NOTFOUND") - message(FATAL_ERROR "Can't find folder containing z3 library") -endif() + third_party/z3/install/lib) set(SOUPER_CLANG_TOOL_FILES lib/ClangTool/Actions.cpp From 1b704220640538d88702b471a0bebfbb4bc50bbb Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 7 May 2018 22:54:23 +0200 Subject: [PATCH 39/49] Work on Z3 backend --- CMakeLists.txt | 5 +- include/souper/Extractor/ExprBuilder.h | 4 +- lib/Extractor/ExprBuilder.cpp | 7 +- lib/Extractor/Z3Builder.cpp | 403 +++++++++++++++++++++++++ 4 files changed, 415 insertions(+), 4 deletions(-) create mode 100644 lib/Extractor/Z3Builder.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 619d0f169..3c94bafd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,9 +134,10 @@ add_library(souperClangTool STATIC set(SOUPER_EXTRACTOR_FILES lib/Extractor/Candidates.cpp - lib/Extractor/KLEEBuilder.cpp lib/Extractor/ExprBuilder.cpp + lib/Extractor/KLEEBuilder.cpp lib/Extractor/Solver.cpp + lib/Extractor/Z3Builder.cpp include/souper/Extractor/Candidates.h include/souper/Extractor/ExprBuilder.h include/souper/Extractor/Solver.h @@ -286,7 +287,7 @@ target_link_libraries(lexer-test souperParser) target_link_libraries(parser-test souperParser) target_link_libraries(souper-check souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(clang-souper souperClangTool souperExtractor souperKVStore souperParser souperSMTLIB2 souperTool kleeExpr ${CLANG_LIBS} ${LLVM_LIBS} ${LLVM_LDFLAGS} ${HIREDIS_LIBRARY} ${Z3_LIBRARY}) -target_link_libraries(extractor_tests souperExtractor ${GTEST_LIBS}) +target_link_libraries(extractor_tests souperExtractor ${GTEST_LIBS} ${Z3_LIBRARY}) target_link_libraries(inst_tests souperInst ${GTEST_LIBS}) target_link_libraries(parser_tests souperParser ${GTEST_LIBS}) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index c56e076ef..852ff82bb 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -42,7 +42,8 @@ class ExprBuilder { const unsigned MAX_PHI_DEPTH = 25; public: enum Builder { - KLEE + KLEE, + Z3 }; virtual ~ExprBuilder() {}; @@ -109,6 +110,7 @@ std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, std::vector *ModelVars, bool Negate=false); std::unique_ptr createKLEEBuilder(InstContext &IC); +std::unique_ptr createZ3Builder(InstContext &IC); } #endif // SOUPER_EXTRACTOR_EXPRBUILDER_H diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 2f353e0aa..3a0f6aa54 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -28,7 +28,9 @@ static llvm::cl::opt SMTExprBuilder( llvm::cl::desc("SMT-LIBv2 expression builder (default=klee)"), llvm::cl::values(clEnumValN(souper::ExprBuilder::KLEE, "klee", "Use KLEE's Expr library")), - llvm::cl::init(souper::ExprBuilder::KLEE)); + llvm::cl::values(clEnumValN(souper::ExprBuilder::Z3, "z3", + "Use Z3 API")), + llvm::cl::init(souper::ExprBuilder::Z3)); bool ExprBuilder::getUBPaths(Inst *I, UBPath *Current, std::vector> &Paths, @@ -934,6 +936,9 @@ std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, case ExprBuilder::KLEE: EB = createKLEEBuilder(IC); break; + case ExprBuilder::Z3: + EB = createZ3Builder(IC); + break; default: report_fatal_error("cannot reach here"); break; diff --git a/lib/Extractor/Z3Builder.cpp b/lib/Extractor/Z3Builder.cpp new file mode 100644 index 000000000..873337c64 --- /dev/null +++ b/lib/Extractor/Z3Builder.cpp @@ -0,0 +1,403 @@ +// Copyright 2018 The Souper Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "llvm/Analysis/LoopInfo.h" +#include "souper/Extractor/ExprBuilder.h" + +#include "z3++.h" + +using namespace llvm; +using namespace souper; +using namespace z3; + +namespace { + +class Z3Builder : public ExprBuilder { + context c; + UniqueNameSet ConstNames; + std::vector Consts; + std::map ExprMap; + std::vector Vars; + +public: + Z3Builder(InstContext &IC) { + LIC = &IC; + } + + std::string GetExprStr(const BlockPCs &BPCs, + const std::vector &PCs, + InstMapping Mapping, + std::vector *ModelVars, bool Negate) override { + Inst *Cand = GetCandidateExprForReplacement(BPCs, PCs, Mapping, Negate); + if (!Cand) + return std::string(); +#if 0 + ref E = get(Cand); + + std::string SStr; + llvm::raw_string_ostream SS(SStr); + std::unique_ptr PP(ExprPPrinter::create(SS)); + PP->setForceNoLineBreaks(true); + PP->scan(E); + PP->print(E); + + return SS.str(); +#endif + return std::string(); + } + + std::string BuildQuery(const BlockPCs &BPCs, + const std::vector &PCs, + InstMapping Mapping, + std::vector *ModelVars, bool Negate) override { + std::string SMTStr; + llvm::raw_string_ostream SMTSS(SMTStr); + Inst *Cand = GetCandidateExprForReplacement(BPCs, PCs, Mapping, Negate); + if (!Cand) + return std::string(); +#if 0 + ref E = get(Cand); + ConstraintManager Manager; + Query KQuery(Manager, E); + ExprSMTLIBPrinter Printer; + Printer.setOutput(SMTSS); + Printer.setQuery(KQuery); + std::vector Arr; + if (ModelVars) { + for (unsigned I = 0; I != Vars.size(); ++I) { + if (Vars[I]) { + Arr.push_back(Arrays[I].get()); + ModelVars->push_back(Vars[I]); + } + } + Printer.setArrayValuesToGet(Arr); + } + Printer.generateOutput(); + + return SMTSS.str(); +#endif + return std::string(); + } + +private: + expr countOnes(expr L) { +#if 0 + Expr::Width Width = L->getWidth(); + ref Count = klee::ConstantExpr::alloc(llvm::APInt(Width, 0)); + for (unsigned i=0; i Bit = ExtractExpr::create(L, i, Expr::Bool); + ref BitExt = ZExtExpr::create(Bit, Width); + Count = AddExpr::create(Count, BitExt); + } + return Count; +#endif + return c.bool_val(true); + } + +#if 0 + expr buildAssoc( + std::function(ref, ref)> F, + llvm::ArrayRef Ops) { + ref E = get(Ops[0]); + for (Inst *I : llvm::ArrayRef(Ops.data()+1, Ops.size()-1)) { + E = F(E, get(I)); + } + return E; + return c.bool_val(true); + } +#endif + + expr build(Inst *I) { +#if 0 + const std::vector &Ops = I->orderedOps(); + switch (I->K) { + case Inst::UntypedConst: + assert(0 && "unexpected kind"); + case Inst::Const: + return klee::ConstantExpr::alloc(I->Val); + case Inst::Var: + return makeSizedArrayRead(I->Width, I->Name, I); + case Inst::Phi: { + const auto &PredExpr = I->B->PredVars; + assert((PredExpr.size() || Ops.size() == 1) && "there must be block predicates"); + ref E = get(Ops[0]); + // e.g. P2 ? (P1 ? Op1_Expr : Op2_Expr) : Op3_Expr + for (unsigned J = 1; J < Ops.size(); ++J) { + E = SelectExpr::create(get(PredExpr[J-1]), E, get(Ops[J])); + } + return E; + } + case Inst::Add: + return buildAssoc(AddExpr::create, Ops); + case Inst::AddNSW: { + ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); + return Add; + } + case Inst::AddNUW: { + ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); + return Add; + } + case Inst::AddNW: { + ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); + return Add; + } + case Inst::Sub: + return SubExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::SubNSW: { + ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); + return Sub; + } + case Inst::SubNUW: { + ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); + return Sub; + } + case Inst::SubNW: { + ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); + return Sub; + } + case Inst::Mul: + return buildAssoc(MulExpr::create, Ops); + case Inst::MulNSW: { + ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); + return Mul; + } + case Inst::MulNUW: { + ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); + return Mul; + } + case Inst::MulNW: { + ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); + return Mul; + } + + // We introduce these extra checks here because KLEE invokes llvm::APInt's + // div functions, which crash upon divide-by-zero. + case Inst::UDiv: + case Inst::SDiv: + case Inst::UDivExact: + case Inst::SDivExact: + case Inst::URem: + case Inst::SRem: { // Fall-through + // If the second oprand is 0, then it definitely causes UB. + // There are quite a few cases where KLEE folds operations into zero, + // e.g., "sext i16 0 to i32", "0 + 0", "2 - 2", etc. In all cases, + // we skip building the corresponding KLEE expressions and just return + // a constant zero. + ref R = get(Ops[1]); + if (R->isZero()) { + return klee::ConstantExpr::create(0, Ops[1]->Width); + } + + switch (I->K) { + default: + break; + + case Inst::UDiv: { + ref Udiv = UDivExpr::create(get(Ops[0]), R); + return Udiv; + } + case Inst::SDiv: { + ref Sdiv = SDivExpr::create(get(Ops[0]), R); + return Sdiv; + } + case Inst::UDivExact: { + ref Udiv = UDivExpr::create(get(Ops[0]), R); + return Udiv; + } + case Inst::SDivExact: { + ref Sdiv = SDivExpr::create(get(Ops[0]), R); + return Sdiv; + } + case Inst::URem: { + ref Urem = URemExpr::create(get(Ops[0]), R); + return Urem; + } + case Inst::SRem: { + ref Srem = SRemExpr::create(get(Ops[0]), R); + return Srem; + } + llvm_unreachable("unknown kind"); + } + } + + case Inst::And: + return buildAssoc(AndExpr::create, Ops); + case Inst::Or: + return buildAssoc(OrExpr::create, Ops); + case Inst::Xor: + return buildAssoc(XorExpr::create, Ops); + case Inst::Shl: { + ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); + return Result; + } + case Inst::ShlNSW: { + ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); + return Result; + } + case Inst::ShlNUW: { + ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); + return Result; + } + case Inst::ShlNW: { + ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); + return Result; + } + case Inst::LShr: { + ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); + return Result; + } + case Inst::LShrExact: { + ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); + return Result; + } + case Inst::AShr: { + ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); + return Result; + } + case Inst::AShrExact: { + ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); + return Result; + } + case Inst::Select: + return SelectExpr::create(get(Ops[0]), get(Ops[1]), get(Ops[2])); + case Inst::ZExt: + return ZExtExpr::create(get(Ops[0]), I->Width); + case Inst::SExt: + return SExtExpr::create(get(Ops[0]), I->Width); + case Inst::Trunc: + return ExtractExpr::create(get(Ops[0]), 0, I->Width); + case Inst::Eq: + return EqExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::Ne: + return NeExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::Ult: + return UltExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::Slt: + return SltExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::Ule: + return UleExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::Sle: + return SleExpr::create(get(Ops[0]), get(Ops[1])); + case Inst::CtPop: + return countOnes(get(Ops[0])); + case Inst::BSwap: { + ref L = get(Ops[0]); + unsigned Width = L->getWidth(); + if (Width == 16) { + return ConcatExpr::create(ExtractExpr::create(L, 0, 8), + ExtractExpr::create(L, 8, 8)); + } + else if (Width == 32) { + return ConcatExpr::create4(ExtractExpr::create(L, 0, 8), + ExtractExpr::create(L, 8, 8), + ExtractExpr::create(L, 16, 8), + ExtractExpr::create(L, 24, 8)); + } + else if (Width == 64) { + return ConcatExpr::create8(ExtractExpr::create(L, 0, 8), + ExtractExpr::create(L, 8, 8), + ExtractExpr::create(L, 16, 8), + ExtractExpr::create(L, 24, 8), + ExtractExpr::create(L, 32, 8), + ExtractExpr::create(L, 40, 8), + ExtractExpr::create(L, 48, 8), + ExtractExpr::create(L, 56, 8)); + } + break; + } + case Inst::Cttz: { + ref L = get(Ops[0]); + unsigned Width = L->getWidth(); + ref Val = L; + for (unsigned i=0, j=0; j L = get(Ops[0]); + unsigned Width = L->getWidth(); + ref Val = L; + for (unsigned i=0, j=0; jVal.getZExtValue(); + return get(Ops[0]->Ops[Index]); + } + case Inst::SAddWithOverflow: + case Inst::UAddWithOverflow: + case Inst::SSubWithOverflow: + case Inst::USubWithOverflow: + case Inst::SMulWithOverflow: + case Inst::UMulWithOverflow: + default: + break; + } + llvm_unreachable("unknown kind"); +#endif + return c.bool_val(true); + } + + expr get(Inst *I) { + if (ExprMap.count(I)) + return ExprMap.at(I); + expr E = build(I); + assert(E.get_sort().bv_size() == I->Width); + ExprMap.insert(std::make_pair(I, E)); + return E; + } + + expr makeSizedArrayRead(unsigned Width, StringRef Name, Inst *Origin) { + std::string NameStr; + if (Name.empty()) + NameStr = "arr"; + else if (Name[0] >= '0' && Name[0] <= '9') + NameStr = ("a" + Name).str(); + else + NameStr = Name; + expr E = c.bv_const(ConstNames.makeName(NameStr).c_str(), Width); + Consts.emplace_back(E); + Vars.push_back(Origin); + + return E; + } + +}; + +} + +std::unique_ptr souper::createZ3Builder(InstContext &IC) { + return std::unique_ptr(new Z3Builder(IC)); +} From 5d8bafbf9ce5ae76656df701780c32f51988067c Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 7 May 2018 23:30:32 +0200 Subject: [PATCH 40/49] Compiling --- lib/Extractor/Z3Builder.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/Extractor/Z3Builder.cpp b/lib/Extractor/Z3Builder.cpp index 873337c64..e5529a709 100644 --- a/lib/Extractor/Z3Builder.cpp +++ b/lib/Extractor/Z3Builder.cpp @@ -105,29 +105,36 @@ class Z3Builder : public ExprBuilder { return c.bool_val(true); } -#if 0 expr buildAssoc( - std::function(ref, ref)> F, + std::function F, llvm::ArrayRef Ops) { - ref E = get(Ops[0]); + expr E = get(Ops[0]); for (Inst *I : llvm::ArrayRef(Ops.data()+1, Ops.size()-1)) { E = F(E, get(I)); } return E; - return c.bool_val(true); } -#endif expr build(Inst *I) { -#if 0 const std::vector &Ops = I->orderedOps(); switch (I->K) { case Inst::UntypedConst: assert(0 && "unexpected kind"); - case Inst::Const: - return klee::ConstantExpr::alloc(I->Val); + case Inst::Const: { + //return klee::ConstantExpr::alloc(I->Val); + if (I->Val.isNegative()) + return c.bv_val((int)(I->Val.getSExtValue()), I->Width); + else + return c.bv_val((unsigned)(I->Val.getZExtValue()), I->Width); + } case Inst::Var: - return makeSizedArrayRead(I->Width, I->Name, I); + return makeSizedConst(I->Width, I->Name, I); + // REMOVE AFTER HECiIRE + default: + break; + } + // +#if 0 case Inst::Phi: { const auto &PredExpr = I->B->PredVars; assert((PredExpr.size() || Ops.size() == 1) && "there must be block predicates"); @@ -379,7 +386,7 @@ class Z3Builder : public ExprBuilder { return E; } - expr makeSizedArrayRead(unsigned Width, StringRef Name, Inst *Origin) { + expr makeSizedConst(unsigned Width, StringRef Name, Inst *Origin) { std::string NameStr; if (Name.empty()) NameStr = "arr"; From 97c5245ce63856259bbd8332ed857f2916b2c644 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sun, 13 May 2018 11:34:28 +0200 Subject: [PATCH 41/49] Add ExprBuilder constructor --- include/souper/Extractor/ExprBuilder.h | 1 + lib/Extractor/KLEEBuilder.cpp | 4 +--- lib/Extractor/Z3Builder.cpp | 4 +--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 852ff82bb..c1e3fddc4 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -46,6 +46,7 @@ class ExprBuilder { Z3 }; + ExprBuilder(InstContext &IC) : LIC(&IC) {} virtual ~ExprBuilder() {}; virtual std::string GetExprStr(const BlockPCs &BPCs, diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 2f80d69bf..38cc97c20 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -36,9 +36,7 @@ class KLEEBuilder : public ExprBuilder { std::vector Vars; public: - KLEEBuilder(InstContext &IC) { - LIC = &IC; - } + KLEEBuilder(InstContext &IC) : ExprBuilder(IC) {} std::string GetExprStr(const BlockPCs &BPCs, const std::vector &PCs, diff --git a/lib/Extractor/Z3Builder.cpp b/lib/Extractor/Z3Builder.cpp index e5529a709..7d97ef031 100644 --- a/lib/Extractor/Z3Builder.cpp +++ b/lib/Extractor/Z3Builder.cpp @@ -31,9 +31,7 @@ class Z3Builder : public ExprBuilder { std::vector Vars; public: - Z3Builder(InstContext &IC) { - LIC = &IC; - } + Z3Builder(InstContext &IC) : ExprBuilder(IC) {} std::string GetExprStr(const BlockPCs &BPCs, const std::vector &PCs, From 398428bc555fcafdb486ac35df0b10105b867341 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sun, 13 May 2018 21:13:58 +0200 Subject: [PATCH 42/49] All KLEE functions replaced with Z3 API calls --- lib/Extractor/Z3Builder.cpp | 378 +++++++++++++++++++----------------- 1 file changed, 205 insertions(+), 173 deletions(-) diff --git a/lib/Extractor/Z3Builder.cpp b/lib/Extractor/Z3Builder.cpp index 7d97ef031..1fe97db0f 100644 --- a/lib/Extractor/Z3Builder.cpp +++ b/lib/Extractor/Z3Builder.cpp @@ -90,17 +90,14 @@ class Z3Builder : public ExprBuilder { private: expr countOnes(expr L) { -#if 0 - Expr::Width Width = L->getWidth(); - ref Count = klee::ConstantExpr::alloc(llvm::APInt(Width, 0)); - for (unsigned i=0; i Bit = ExtractExpr::create(L, i, Expr::Bool); - ref BitExt = ZExtExpr::create(Bit, Width); - Count = AddExpr::create(Count, BitExt); + unsigned Width = L.get_sort().bv_size(); + expr Count = c.bv_val(0, Width); + for (unsigned J=0; JWidth, I->Name, I); - // REMOVE AFTER HECiIRE - default: - break; - } - // -#if 0 case Inst::Phi: { const auto &PredExpr = I->B->PredVars; assert((PredExpr.size() || Ops.size() == 1) && "there must be block predicates"); - ref E = get(Ops[0]); + expr E = get(Ops[0]); // e.g. P2 ? (P1 ? Op1_Expr : Op2_Expr) : Op3_Expr for (unsigned J = 1; J < Ops.size(); ++J) { - E = SelectExpr::create(get(PredExpr[J-1]), E, get(Ops[J])); + E = ite(get(PredExpr[J-1]), E, get(Ops[J])); } return E; } - case Inst::Add: - return buildAssoc(AddExpr::create, Ops); - case Inst::AddNSW: { - ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - return Add; - } - case Inst::AddNUW: { - ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - return Add; + case Inst::Add: { + //return buildAssoc(AddExpr::create, Ops); + expr E = get(Ops[0]); + for (auto Op : Ops) { + if (Op == Ops[0]) + continue; + E = E + get(Op); + } + return E; } + case Inst::AddNSW: + case Inst::AddNUW: case Inst::AddNW: { - ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); - return Add; + //ref Add = AddExpr::create(get(Ops[0]), get(Ops[1])); + return get(Ops[0]) + get(Ops[1]); } case Inst::Sub: - return SubExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::SubNSW: { - ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - return Sub; - } - case Inst::SubNUW: { - ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - return Sub; - } + case Inst::SubNSW: + case Inst::SubNUW: case Inst::SubNW: { - ref Sub = SubExpr::create(get(Ops[0]), get(Ops[1])); - return Sub; - } - case Inst::Mul: - return buildAssoc(MulExpr::create, Ops); - case Inst::MulNSW: { - ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - return Mul; + //return SubExpr::create(get(Ops[0]), get(Ops[1])); + return get(Ops[0]) - get(Ops[1]); } - case Inst::MulNUW: { - ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - return Mul; + case Inst::Mul: { + //return buildAssoc(MulExpr::create, Ops); + expr E = get(Ops[0]); + for (auto Op : Ops) { + if (Op == Ops[0]) + continue; + E = E * get(Op); + } + return E; } + case Inst::MulNSW: + case Inst::MulNUW: case Inst::MulNW: { - ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); - return Mul; + //ref Mul = MulExpr::create(get(Ops[0]), get(Ops[1])); + return get(Ops[0]) * get(Ops[1]); } - - // We introduce these extra checks here because KLEE invokes llvm::APInt's - // div functions, which crash upon divide-by-zero. + // TODO: Handle divide-by-zero explicitly case Inst::UDiv: case Inst::SDiv: case Inst::UDivExact: @@ -195,168 +181,216 @@ class Z3Builder : public ExprBuilder { case Inst::URem: case Inst::SRem: { // Fall-through // If the second oprand is 0, then it definitely causes UB. - // There are quite a few cases where KLEE folds operations into zero, - // e.g., "sext i16 0 to i32", "0 + 0", "2 - 2", etc. In all cases, - // we skip building the corresponding KLEE expressions and just return - // a constant zero. - ref R = get(Ops[1]); - if (R->isZero()) { - return klee::ConstantExpr::create(0, Ops[1]->Width); - } + // Just return a constant zero. + if (Ops[1]->K == Inst::Const && Ops[1]->Val.isNullValue()) + return c.bv_val(0, I->Width); + + expr R = get(Ops[1]); switch (I->K) { default: break; - case Inst::UDiv: { - ref Udiv = UDivExpr::create(get(Ops[0]), R); - return Udiv; - } - case Inst::SDiv: { - ref Sdiv = SDivExpr::create(get(Ops[0]), R); - return Sdiv; - } + case Inst::UDiv: case Inst::UDivExact: { - ref Udiv = UDivExpr::create(get(Ops[0]), R); - return Udiv; + //ref Udiv = UDivExpr::create(get(Ops[0]), R); + return expr(c, Z3_mk_bvudiv(c, get(Ops[0]), get(Ops[1]))); } + case Inst::SDiv: case Inst::SDivExact: { - ref Sdiv = SDivExpr::create(get(Ops[0]), R); - return Sdiv; + //ref Sdiv = SDivExpr::create(get(Ops[0]), R); + return expr(c, Z3_mk_bvsdiv(c, get(Ops[0]), get(Ops[1]))); } case Inst::URem: { - ref Urem = URemExpr::create(get(Ops[0]), R); - return Urem; + //ref Urem = URemExpr::create(get(Ops[0]), R); + return expr(c, Z3_mk_bvurem(c, get(Ops[0]), get(Ops[1]))); } case Inst::SRem: { - ref Srem = SRemExpr::create(get(Ops[0]), R); - return Srem; + //ref Srem = SRemExpr::create(get(Ops[0]), R); + return expr(c, Z3_mk_bvsrem(c, get(Ops[0]), get(Ops[1]))); } llvm_unreachable("unknown kind"); } } - case Inst::And: - return buildAssoc(AndExpr::create, Ops); - case Inst::Or: - return buildAssoc(OrExpr::create, Ops); - case Inst::Xor: - return buildAssoc(XorExpr::create, Ops); - case Inst::Shl: { - ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - return Result; - } - case Inst::ShlNSW: { - ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - return Result; - } - case Inst::ShlNUW: { - ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - return Result; + case Inst::And: { + //return buildAssoc(AndExpr::create, Ops); + expr E = get(Ops[0]); + for (auto Op : Ops) { + if (Op == Ops[0]) + continue; + E = E & get(Op); + } + return E; } - case Inst::ShlNW: { - ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); - return Result; + case Inst::Or: { + //return buildAssoc(OrExpr::create, Ops); + expr E = get(Ops[0]); + for (auto Op : Ops) { + if (Op == Ops[0]) + continue; + E = E | get(Op); + } + return E; } - case Inst::LShr: { - ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - return Result; + case Inst::Xor: { + //return buildAssoc(XorExpr::create, Ops); + expr E = get(Ops[0]); + for (auto Op : Ops) { + if (Op == Ops[0]) + continue; + E = E ^ get(Op); + } + return E; } - case Inst::LShrExact: { - ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); - return Result; + case Inst::Shl: + case Inst::ShlNSW: + case Inst::ShlNUW: + case Inst::ShlNW: { + //ref Result = ShlExpr::create(get(Ops[0]), get(Ops[1])); + return expr(c, Z3_mk_bvshl(c, get(Ops[0]), get(Ops[1]))); } - case Inst::AShr: { - ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - return Result; + case Inst::LShr: + case Inst::LShrExact: { + //ref Result = LShrExpr::create(get(Ops[0]), get(Ops[1])); + return expr(c, Z3_mk_bvlshr(c, get(Ops[0]), get(Ops[1]))); } + case Inst::AShr: case Inst::AShrExact: { - ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); - return Result; + //ref Result = AShrExpr::create(get(Ops[0]), get(Ops[1])); + return expr(c, Z3_mk_bvashr(c, get(Ops[0]), get(Ops[1]))); + } + case Inst::Select: { + //return SelectExpr::create(get(Ops[0]), get(Ops[1]), get(Ops[2])); + return ite(get(Ops[0]), get(Ops[1]), get(Ops[2])); + } + case Inst::ZExt: { + //return ZExtExpr::create(get(Ops[0]), I->Width); + return expr(c, Z3_mk_zero_ext(c, I->Width, get(Ops[0]))); } - case Inst::Select: - return SelectExpr::create(get(Ops[0]), get(Ops[1]), get(Ops[2])); - case Inst::ZExt: - return ZExtExpr::create(get(Ops[0]), I->Width); case Inst::SExt: - return SExtExpr::create(get(Ops[0]), I->Width); - case Inst::Trunc: - return ExtractExpr::create(get(Ops[0]), 0, I->Width); - case Inst::Eq: - return EqExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::Ne: - return NeExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::Ult: - return UltExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::Slt: - return SltExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::Ule: - return UleExpr::create(get(Ops[0]), get(Ops[1])); - case Inst::Sle: - return SleExpr::create(get(Ops[0]), get(Ops[1])); + //return SExtExpr::create(get(Ops[0]), I->Width); + return expr(c, Z3_mk_sign_ext(c, I->Width, get(Ops[0]))); + case Inst::Trunc: { + //return ExtractExpr::create(get(Ops[0]), 0, I->Width); + return get(Ops[0]).extract(0, I->Width); + } + case Inst::Eq: { + //return EqExpr::create(get(Ops[0]), get(Ops[1])); + return get(Ops[0]) == get(Ops[1]); + } + case Inst::Ne: { + //return NeExpr::create(get(Ops[0]), get(Ops[1])); + return get(Ops[0]) != get(Ops[1]); + } + case Inst::Ult: { + //return UltExpr::create(get(Ops[0]), get(Ops[1])); + return expr(c, Z3_mk_bvult(c, get(Ops[0]), get(Ops[1]))); + } + case Inst::Slt: { + //return SltExpr::create(get(Ops[0]), get(Ops[1])); + return expr(c, Z3_mk_bvslt(c, get(Ops[0]), get(Ops[1]))); + } + case Inst::Ule: { + //return UleExpr::create(get(Ops[0]), get(Ops[1])); + return expr(c, Z3_mk_bvule(c, get(Ops[0]), get(Ops[1]))); + } + case Inst::Sle: { + //return SleExpr::create(get(Ops[0]), get(Ops[1])); + return expr(c, Z3_mk_bvsle(c, get(Ops[0]), get(Ops[1]))); + } case Inst::CtPop: return countOnes(get(Ops[0])); case Inst::BSwap: { - ref L = get(Ops[0]); - unsigned Width = L->getWidth(); + expr L = get(Ops[0]); + unsigned Width = L.get_sort().bv_size(); + expr_vector EV(c); if (Width == 16) { - return ConcatExpr::create(ExtractExpr::create(L, 0, 8), - ExtractExpr::create(L, 8, 8)); + //return ConcatExpr::create(ExtractExpr::create(L, 0, 8), + // ExtractExpr::create(L, 8, 8)); + EV.push_back(L.extract(c.bv_val(0, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(c.bv_val(8, Width), c.bv_val(8, Width))); } else if (Width == 32) { - return ConcatExpr::create4(ExtractExpr::create(L, 0, 8), - ExtractExpr::create(L, 8, 8), - ExtractExpr::create(L, 16, 8), - ExtractExpr::create(L, 24, 8)); + //return ConcatExpr::create4(ExtractExpr::create(L, 0, 8), + // ExtractExpr::create(L, 8, 8), + // ExtractExpr::create(L, 16, 8), + // ExtractExpr::create(L, 24, 8)); + EV.push_back(L.extract(c.bv_val(0, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(c.bv_val(8, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(c.bv_val(16, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(c.bv_val(24, Width), c.bv_val(8, Width))); } else if (Width == 64) { - return ConcatExpr::create8(ExtractExpr::create(L, 0, 8), - ExtractExpr::create(L, 8, 8), - ExtractExpr::create(L, 16, 8), - ExtractExpr::create(L, 24, 8), - ExtractExpr::create(L, 32, 8), - ExtractExpr::create(L, 40, 8), - ExtractExpr::create(L, 48, 8), - ExtractExpr::create(L, 56, 8)); + //return ConcatExpr::create8(ExtractExpr::create(L, 0, 8), + // ExtractExpr::create(L, 8, 8), + // ExtractExpr::create(L, 16, 8), + // ExtractExpr::create(L, 24, 8), + // ExtractExpr::create(L, 32, 8), + // ExtractExpr::create(L, 40, 8), + // ExtractExpr::create(L, 48, 8), + // ExtractExpr::create(L, 56, 8)); + EV.push_back(L.extract(c.bv_val(0, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(c.bv_val(8, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(c.bv_val(16, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(c.bv_val(24, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(c.bv_val(32, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(c.bv_val(40, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(c.bv_val(48, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(c.bv_val(56, Width), c.bv_val(8, Width))); } - break; + return concat(EV); } case Inst::Cttz: { - ref L = get(Ops[0]); - unsigned Width = L->getWidth(); - ref Val = L; + expr Val = get(Ops[0]); + unsigned Width = Val.get_sort().bv_size(); for (unsigned i=0, j=0; j L = get(Ops[0]); - unsigned Width = L->getWidth(); - ref Val = L; + expr Val = get(Ops[0]); + unsigned Width = Val.get_sort().bv_size(); for (unsigned i=0, j=0; jVal.getZExtValue(); return get(Ops[0]->Ops[Index]); @@ -371,8 +405,6 @@ class Z3Builder : public ExprBuilder { break; } llvm_unreachable("unknown kind"); -#endif - return c.bool_val(true); } expr get(Inst *I) { From d2aa4f210b3409e1aee47f932d54590e18255dc8 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 14 May 2018 23:09:14 +0200 Subject: [PATCH 43/49] Work --- include/souper/Extractor/ExprBuilder.h | 16 --- lib/Extractor/ExprBuilder.cpp | 152 ------------------------- lib/Extractor/KLEEBuilder.cpp | 8 -- lib/Extractor/Z3Builder.cpp | 53 +++++---- 4 files changed, 31 insertions(+), 198 deletions(-) diff --git a/include/souper/Extractor/ExprBuilder.h b/include/souper/Extractor/ExprBuilder.h index 865fb0367..ad724ea5a 100644 --- a/include/souper/Extractor/ExprBuilder.h +++ b/include/souper/Extractor/ExprBuilder.h @@ -1,8 +1,4 @@ -<<<<<<< HEAD -// Copyright 2014 The Souper Authors. All rights reserved. -======= // Copyright 2018 The Souper Authors. All rights reserved. ->>>>>>> master // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,11 +19,6 @@ #include "souper/Util/UniqueNameSet.h" #include -<<<<<<< HEAD -using namespace souper; - -======= ->>>>>>> master namespace souper { class ExprBuilder { @@ -49,12 +40,8 @@ class ExprBuilder { const unsigned MAX_PHI_DEPTH = 25; public: enum Builder { -<<<<<<< HEAD KLEE, Z3 -======= - KLEE ->>>>>>> master }; ExprBuilder(InstContext &IC) : LIC(&IC) {} @@ -122,10 +109,7 @@ std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, std::vector *ModelVars, bool Negate=false); std::unique_ptr createKLEEBuilder(InstContext &IC); -<<<<<<< HEAD std::unique_ptr createZ3Builder(InstContext &IC); -======= ->>>>>>> master } #endif // SOUPER_EXTRACTOR_EXPRBUILDER_H diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 63aa89c92..a5172a111 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -1,8 +1,4 @@ -<<<<<<< HEAD -// Copyright 2014 The Souper Authors. All rights reserved. -======= // Copyright 2018 The Souper Authors. All rights reserved. ->>>>>>> master // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,12 +17,6 @@ #include -<<<<<<< HEAD -using namespace llvm; -using namespace souper; - -======= ->>>>>>> master namespace souper { static llvm::cl::opt SMTExprBuilder( @@ -35,13 +25,9 @@ static llvm::cl::opt SMTExprBuilder( llvm::cl::desc("SMT-LIBv2 expression builder (default=klee)"), llvm::cl::values(clEnumValN(souper::ExprBuilder::KLEE, "klee", "Use KLEE's Expr library")), -<<<<<<< HEAD llvm::cl::values(clEnumValN(souper::ExprBuilder::Z3, "z3", "Use Z3 API")), llvm::cl::init(souper::ExprBuilder::Z3)); -======= - llvm::cl::init(souper::ExprBuilder::KLEE)); ->>>>>>> master bool ExprBuilder::getUBPaths(Inst *I, UBPath *Current, std::vector> &Paths, @@ -97,11 +83,7 @@ bool ExprBuilder::getUBPaths(Inst *I, UBPath *Current, UBPath *New = new UBPath; *New = *Current; New->BlockConstraints[I->B] = J; -<<<<<<< HEAD - Paths.push_back(std::move(std::unique_ptr(New))); -======= Paths.push_back(std::unique_ptr(New)); ->>>>>>> master Tmp.push_back(New); } // Original path takes the first branch @@ -197,11 +179,7 @@ Inst *ExprBuilder::createPathPred( std::map &BlockConstraints, Inst* PathInst, std::map *SelectBranches) { -<<<<<<< HEAD - Inst *Pred = LIC->getConst(APInt(1, true)); -======= Inst *Pred = LIC->getConst(llvm::APInt(1, true)); ->>>>>>> master if (PathInst->K == Inst::Phi) { unsigned Num = BlockConstraints[PathInst->B]; const auto &PredExpr = PathInst->B->PredVars; @@ -213,12 +191,8 @@ Inst *ExprBuilder::createPathPred( if (Num == 0) Pred = LIC->getInst(Inst::And, 1, {Pred, PredExpr[0]}); else { -<<<<<<< HEAD - Inst *IsZero = LIC->getInst(Inst::Eq, 1, {PredExpr[Num-1], LIC->getConst(APInt(PredExpr[Num-1]->Width, 0))}); -======= Inst *Zero = LIC->getConst(llvm::APInt(PredExpr[Num-1]->Width, 0)); Inst *IsZero = LIC->getInst(Inst::Eq, 1, {PredExpr[Num-1], Zero}); ->>>>>>> master Pred = LIC->getInst(Inst::And, 1, {Pred, IsZero}); } for (unsigned B = Num; B < PredExpr.size(); ++B) @@ -235,12 +209,8 @@ Inst *ExprBuilder::createPathPred( if (SI->second) Pred = LIC->getInst(Inst::And, 1, {Pred, SelectPred}); else { -<<<<<<< HEAD - Inst *IsZero = LIC->getInst(Inst::Eq, 1, {SelectPred, LIC->getConst(APInt(SelectPred->Width, 0))}); -======= Inst *Zero = LIC->getConst(llvm::APInt(SelectPred->Width, 0)); Inst *IsZero = LIC->getInst(Inst::Eq, 1, {SelectPred, Zero}); ->>>>>>> master Pred = LIC->getInst(Inst::And, 1, {Pred, IsZero}); } } @@ -307,11 +277,7 @@ Inst *ExprBuilder::getUBInstCondition(Inst *Root) { // encode the path and UB Inst predicates. UBPathInstMap CachedUBPathInsts; std::set UsedUBInsts; -<<<<<<< HEAD - Inst *Result = LIC->getConst(APInt(1, true)); -======= Inst *Result = LIC->getConst(llvm::APInt(1, true)); ->>>>>>> master auto UBExprMap = getUBInstConstraints(Root); // For each Phi/Select instruction for (const auto &I : getUBPathInsts(Root)) { @@ -323,22 +289,14 @@ Inst *ExprBuilder::getUBInstCondition(Inst *Root) { UBPath *Current = new UBPath; UBPaths.push_back(std::move(std::unique_ptr(Current))); if (!getUBPaths(I, Current, UBPaths, CachedUBPathInsts, 0)) -<<<<<<< HEAD - return LIC->getConst(APInt(1, true)); -======= return LIC->getConst(llvm::APInt(1, true)); ->>>>>>> master CachedUBPathInsts[I] = {}; // For each found path for (const auto &Path : UBPaths) { if (!Path->UBInsts.size()) continue; // Aggregate collected UB constraints -<<<<<<< HEAD - Inst *Ante = LIC->getConst(APInt(1, true)); -======= Inst *Ante = LIC->getConst(llvm::APInt(1, true)); ->>>>>>> master for (const auto &I : Path->UBInsts) { auto Iter = UBExprMap.find(I); // It's possible that the instruction I is not in the map. @@ -365,25 +323,12 @@ Inst *ExprBuilder::getUBInstCondition(Inst *Root) { } Inst *ExprBuilder::getDemandedBitsCondition(Inst *I) { -<<<<<<< HEAD - Inst *Result = LIC->getConst(APInt(1, true)); -======= Inst *Result = LIC->getConst(llvm::APInt(1, true)); ->>>>>>> master if (I->K != Inst::Var) return Result; unsigned Width = I->Width; -<<<<<<< HEAD - Inst *Zero = LIC->getConst(APInt(Width, 0)); - Inst *One = LIC->getConst(APInt(Width, 1)); - - if (I->KnownZeros.getBoolValue()) { - Inst *NotZeros = LIC->getInst(Inst::Xor, Width, - {LIC->getConst(I->KnownZeros), - LIC->getConst(APInt::getAllOnesValue(Width))}); -======= Inst *Zero = LIC->getConst(llvm::APInt(Width, 0)); Inst *One = LIC->getConst(llvm::APInt(Width, 1)); @@ -391,7 +336,6 @@ Inst *ExprBuilder::getDemandedBitsCondition(Inst *I) { Inst *AllOnes = LIC->getConst(llvm::APInt::getAllOnesValue(Width)); Inst *NotZeros = LIC->getInst(Inst::Xor, Width, {LIC->getConst(I->KnownZeros), AllOnes}); ->>>>>>> master Inst *VarNotZero = LIC->getInst(Inst::Or, Width, {I, NotZeros}); Inst *ZeroBits = LIC->getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); Result = LIC->getInst(Inst::And, 1, {Result, ZeroBits}); @@ -423,20 +367,12 @@ Inst *ExprBuilder::getDemandedBitsCondition(Inst *I) { Result = LIC->getInst(Inst::And, 1, {Result, NegBits}); } if (I->NumSignBits > 1) { -<<<<<<< HEAD - Inst *Res = LIC->getInst(Inst::AShr, Width, - {I, LIC->getConst(APInt(Width, Width - I->NumSignBits))}); - Inst *TestOnes = LIC->getInst(Inst::AShr, Width, - {LIC->getInst(Inst::Shl, Width, {One, LIC->getConst(APInt(Width, Width-1))}), - LIC->getConst(APInt(Width, Width-1))}); -======= Inst *Diff = LIC->getConst(llvm::APInt(Width, Width - I->NumSignBits)); Inst *Res = LIC->getInst(Inst::AShr, Width, {I, Diff}); Diff = LIC->getConst(llvm::APInt(Width, Width-1)); Inst *TestOnes = LIC->getInst(Inst::AShr, Width, {LIC->getInst(Inst::Shl, Width, {One, Diff}), LIC->getConst(llvm::APInt(Width, Width-1))}); ->>>>>>> master Inst *SignBits = LIC->getInst(Inst::Or, 1, {LIC->getInst(Inst::Eq, 1, {Res, TestOnes}), LIC->getInst(Inst::Eq, 1, {Res, Zero})}); @@ -454,11 +390,7 @@ Inst *ExprBuilder::getDemandedBitsCondition(Inst *I) { Inst *ExprBuilder::getBlockPCs(Inst *Root) { UBPathInstMap CachedPhis; -<<<<<<< HEAD - Inst *Result = LIC->getConst(APInt(1, true)); -======= Inst *Result = LIC->getConst(llvm::APInt(1, true)); ->>>>>>> master // For each Phi instruction for (const auto &I : getUBPathInsts(Root)) { if (CachedPhis.count(I) != 0) @@ -475,11 +407,7 @@ Inst *ExprBuilder::getBlockPCs(Inst *Root) { if (!Path->PCs.size()) continue; // Aggregate collected BlockPC constraints -<<<<<<< HEAD - Inst *Ante = LIC->getConst(APInt(1, true)); -======= Inst *Ante = LIC->getConst(llvm::APInt(1, true)); ->>>>>>> master for (const auto &PC : Path->PCs) Ante = LIC->getInst(Inst::And, 1, {Ante, PC}); // Create path predicate @@ -511,11 +439,7 @@ Inst *ExprBuilder::createUBPathInstsPred( Inst *CurrentInst, std::vector &PathInsts, std::map &BlockConstraints, std::map *SelectBranches, UBPathInstMap &CachedUBPathInsts) { -<<<<<<< HEAD - Inst *Pred = LIC->getConst(APInt(1, true)); -======= Inst *Pred = LIC->getConst(llvm::APInt(1, true)); ->>>>>>> master for (const auto &PathInst : PathInsts) { if (PathInst->Ops.size() == 1) continue; @@ -546,17 +470,10 @@ Inst *ExprBuilder::createUBPathInstsPred( Inst *ExprBuilder::getExtractInst(Inst *I, unsigned Offset, unsigned W) { if (I->K == Inst::Const || I->K == Inst::UntypedConst) { -<<<<<<< HEAD - return LIC->getConst(APInt(I->Val.ashr(Offset)).zextOrTrunc(W)); - } else { - Inst *AShr = LIC->getInst(Inst::AShr, I->Width, - {I, LIC->getConst(APInt(I->Width, Offset))}); -======= return LIC->getConst(llvm::APInt(I->Val.ashr(Offset)).zextOrTrunc(W)); } else { Inst *AShr = LIC->getInst(Inst::AShr, I->Width, {I, LIC->getConst(llvm::APInt(I->Width, Offset))}); ->>>>>>> master if (AShr->Width < W) return LIC->getInst(Inst::ZExt, W, {AShr}); else if (AShr->Width > W) @@ -567,13 +484,8 @@ Inst *ExprBuilder::getExtractInst(Inst *I, unsigned Offset, unsigned W) { } Inst *ExprBuilder::getImpliesInst(Inst *Ante, Inst *I) { -<<<<<<< HEAD - Inst *IsZero = LIC->getInst(Inst::Eq, 1, - {Ante, LIC->getConst(APInt(Ante->Width, 0))}); -======= Inst *Zero = LIC->getConst(llvm::APInt(Ante->Width, 0)); Inst *IsZero = LIC->getInst(Inst::Eq, 1, {Ante, Zero}); ->>>>>>> master return LIC->getInst(Inst::Or, 1, {IsZero, I}); } @@ -599,12 +511,8 @@ Inst *ExprBuilder::addnuwUB(Inst *I) { Inst *Rext = LIC->getInst(Inst::ZExt, Width+1, {R}); Inst *Add = LIC->getInst(Inst::Add, Width+1, {Lext, Rext}); Inst *AddMSB = getExtractInst(Add, Width, 1); -<<<<<<< HEAD - return LIC->getInst(Inst::Eq, 1, {AddMSB, LIC->getConst(APInt(1, false))}); -======= return LIC->getInst(Inst::Eq, 1, {AddMSB, LIC->getConst(llvm::APInt(1, false))}); ->>>>>>> master } Inst *ExprBuilder::subnswUB(Inst *I) { @@ -629,12 +537,8 @@ Inst *ExprBuilder::subnuwUB(Inst *I) { Inst *Rext = LIC->getInst(Inst::ZExt, Width+1, {R}); Inst *Sub = LIC->getInst(Inst::Sub, Width+1, {Lext, Rext}); Inst *SubMSB = getExtractInst(Sub, Width, 1); -<<<<<<< HEAD - return LIC->getInst(Inst::Eq, 1, {SubMSB, LIC->getConst(APInt(1, false))}); -======= return LIC->getInst(Inst::Eq, 1, {SubMSB, LIC->getConst(llvm::APInt(1, false))}); ->>>>>>> master } Inst *ExprBuilder::mulnswUB(Inst *I) { @@ -663,23 +567,15 @@ Inst *ExprBuilder::mulnuwUB(Inst *I) { Inst *Rext = LIC->getInst(Inst::ZExt, 2*Width, {R}); Inst *Mul = LIC->getInst(Inst::Mul, 2*Width, {Lext, Rext}); Inst *HigherBits = getExtractInst(Mul, Width, Width); -<<<<<<< HEAD - return LIC->getInst(Inst::Eq, 1, {HigherBits, LIC->getConst(APInt(Width, 0))}); -======= return LIC->getInst(Inst::Eq, 1, {HigherBits, LIC->getConst(llvm::APInt(Width, 0))}); ->>>>>>> master } Inst *ExprBuilder::udivUB(Inst *I) { const std::vector &Ops = I->orderedOps(); auto R = Ops[1]; -<<<<<<< HEAD - return LIC->getInst(Inst::Ne, 1, {R, LIC->getConst(APInt(R->Width, 0))}); -======= return LIC->getInst(Inst::Ne, 1, {R, LIC->getConst(llvm::APInt(R->Width, 0))}); ->>>>>>> master } Inst *ExprBuilder::udivExactUB(Inst *I) { @@ -697,21 +593,12 @@ Inst *ExprBuilder::sdivUB(Inst *I) { auto L = Ops[0]; auto R = Ops[1]; unsigned Width = L->Width; -<<<<<<< HEAD - Inst *ShiftBy = LIC->getConst(APInt(Width, Width-1)); - Inst *IntMin = LIC->getInst(Inst::Shl, Width, - {LIC->getConst(APInt(Width, 1)), ShiftBy}); - Inst *NegOne = LIC->getInst(Inst::AShr, Width, {IntMin, ShiftBy}); - Inst *NeExpr = LIC->getInst(Inst::Ne, 1, - {R, LIC->getConst(APInt(R->Width, 0))}); -======= Inst *ShiftBy = LIC->getConst(llvm::APInt(Width, Width-1)); Inst *IntMin = LIC->getInst(Inst::Shl, Width, {LIC->getConst(llvm::APInt(Width, 1)), ShiftBy}); Inst *NegOne = LIC->getInst(Inst::AShr, Width, {IntMin, ShiftBy}); Inst *NeExpr = LIC->getInst(Inst::Ne, 1, {R, LIC->getConst(llvm::APInt(R->Width, 0))}); ->>>>>>> master Inst *OrExpr = LIC->getInst(Inst::Or, 1, {LIC->getInst(Inst::Ne, 1, {L, IntMin}), LIC->getInst(Inst::Ne, 1, {R, NegOne})}); @@ -733,11 +620,7 @@ Inst *ExprBuilder::shiftUB(Inst *I) { auto L = Ops[0]; auto R = Ops[1]; unsigned Width = L->Width; -<<<<<<< HEAD - Inst *Lwidth = LIC->getConst(APInt(Width, Width)); -======= Inst *Lwidth = LIC->getConst(llvm::APInt(Width, Width)); ->>>>>>> master return LIC->getInst(Inst::Ult, 1, {R, Lwidth}); } @@ -844,13 +727,8 @@ std::map ExprBuilder::getUBInstConstraints(Inst *Root) { // we skip building the corresponding expressions and just return // a constant zero. Inst *R = I->Ops[1]; -<<<<<<< HEAD - if (R == LIC->getConst(APInt(R->Width, 0))) { - Result.emplace(I, LIC->getConst(APInt(1, false))); -======= if (R == LIC->getConst(llvm::APInt(R->Width, 0))) { Result.emplace(I, LIC->getConst(llvm::APInt(1, false))); ->>>>>>> master return Result; } @@ -872,12 +750,8 @@ std::map ExprBuilder::getUBInstConstraints(Inst *Root) { break; } case Inst::SDivExact: { -<<<<<<< HEAD - Result.emplace(I, LIC->getInst(Inst::And, 1, {sdivUB(I), sdivExactUB(I)})); -======= Result.emplace(I, LIC->getInst(Inst::And, 1, {sdivUB(I), sdivExactUB(I)})); ->>>>>>> master break; } case Inst::URem: { @@ -905,13 +779,8 @@ std::map ExprBuilder::getUBInstConstraints(Inst *Root) { break; } case Inst::ShlNW: { -<<<<<<< HEAD - Result.emplace(I, LIC->getInst(Inst::And, 1, - {shiftUB(I), LIC->getInst(Inst::And, 1, {shlnswUB(I), shlnuwUB(I)})})); -======= Inst *nwUB = LIC->getInst(Inst::And, 1, {shlnswUB(I), shlnuwUB(I)}); Result.emplace(I, LIC->getInst(Inst::And, 1, {shiftUB(I), nwUB})); ->>>>>>> master break; } case Inst::LShr: { @@ -996,11 +865,7 @@ std::vector ExprBuilder::getVarInsts(const std::vector Insts) { return Result; } -<<<<<<< HEAD -// Return a candidate Inst which must be proven valid for the candidate to apply. -======= // Return a candidate which must be proven valid for the candidate to apply. ->>>>>>> master Inst *ExprBuilder::GetCandidateExprForReplacement( const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool Negate) { @@ -1008,11 +873,7 @@ Inst *ExprBuilder::GetCandidateExprForReplacement( // Build LHS Inst *LHS = Mapping.LHS; -<<<<<<< HEAD - Inst *Ante = LIC->getConst(APInt(1, true)); -======= Inst *Ante = LIC->getConst(llvm::APInt(1, true)); ->>>>>>> master // Get demanded bits Inst *DemandedBits = LIC->getConst(LHS->DemandedBits); @@ -1021,11 +882,7 @@ Inst *ExprBuilder::GetCandidateExprForReplacement( // Get UB constraints of LHS Inst *LHSUB = getUBInstCondition(Mapping.LHS); -<<<<<<< HEAD - if (LHSUB == LIC->getConst(APInt(1, false))) -======= if (LHSUB == LIC->getConst(llvm::APInt(1, false))) ->>>>>>> master return nullptr; // Build PCs @@ -1055,11 +912,7 @@ Inst *ExprBuilder::GetCandidateExprForReplacement( // Get UB constraints of RHS Inst *RHSUB = getUBInstCondition(Mapping.RHS); -<<<<<<< HEAD - if (RHSUB == LIC->getConst(APInt(1, false))) -======= if (RHSUB == LIC->getConst(llvm::APInt(1, false))) ->>>>>>> master return nullptr; if (Negate) // (LHS != RHS) @@ -1088,16 +941,11 @@ std::string BuildQuery(InstContext &IC, const BlockPCs &BPCs, case ExprBuilder::KLEE: EB = createKLEEBuilder(IC); break; -<<<<<<< HEAD case ExprBuilder::Z3: EB = createZ3Builder(IC); break; - default: - report_fatal_error("cannot reach here"); -======= default: llvm::report_fatal_error("cannot reach here"); ->>>>>>> master break; } diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 967b2bdff..a87da7c1d 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -18,10 +18,6 @@ #include "llvm/Analysis/LoopInfo.h" #include "souper/Extractor/ExprBuilder.h" -<<<<<<< HEAD -using namespace llvm; -======= ->>>>>>> master using namespace klee; using namespace souper; @@ -379,11 +375,7 @@ class KLEEBuilder : public ExprBuilder { return E; } -<<<<<<< HEAD - ref makeSizedArrayRead(unsigned Width, StringRef Name, Inst *Origin) { -======= ref makeSizedArrayRead(unsigned Width, llvm::StringRef Name, Inst *Origin) { ->>>>>>> master std::string NameStr; if (Name.empty()) NameStr = "arr"; diff --git a/lib/Extractor/Z3Builder.cpp b/lib/Extractor/Z3Builder.cpp index 1fe97db0f..83e681224 100644 --- a/lib/Extractor/Z3Builder.cpp +++ b/lib/Extractor/Z3Builder.cpp @@ -25,6 +25,7 @@ namespace { class Z3Builder : public ExprBuilder { context c; + ReplacementContext Context; UniqueNameSet ConstNames; std::vector Consts; std::map ExprMap; @@ -59,13 +60,16 @@ class Z3Builder : public ExprBuilder { const std::vector &PCs, InstMapping Mapping, std::vector *ModelVars, bool Negate) override { - std::string SMTStr; - llvm::raw_string_ostream SMTSS(SMTStr); Inst *Cand = GetCandidateExprForReplacement(BPCs, PCs, Mapping, Negate); if (!Cand) return std::string(); + expr E = get(Cand); + solver s(c); + s.add(E); + llvm::outs() << s.to_smt2() << "\n"; #if 0 - ref E = get(Cand); + std::string SMTStr; + llvm::raw_string_ostream SMTSS(SMTStr); ConstraintManager Manager; Query KQuery(Manager, E); ExprSMTLIBPrinter Printer; @@ -93,7 +97,7 @@ class Z3Builder : public ExprBuilder { unsigned Width = L.get_sort().bv_size(); expr Count = c.bv_val(0, Width); for (unsigned J=0; J &Ops = I->orderedOps(); + llvm::outs() << "## getting instruction: " << Inst::getKindName(I->K) << "\n"; switch (I->K) { case Inst::UntypedConst: assert(0 && "unexpected kind"); @@ -273,15 +278,15 @@ class Z3Builder : public ExprBuilder { return expr(c, Z3_mk_sign_ext(c, I->Width, get(Ops[0]))); case Inst::Trunc: { //return ExtractExpr::create(get(Ops[0]), 0, I->Width); - return get(Ops[0]).extract(0, I->Width); + return get(Ops[0]).extract(I->Width-1, 0); } case Inst::Eq: { //return EqExpr::create(get(Ops[0]), get(Ops[1])); - return get(Ops[0]) == get(Ops[1]); + return ite(get(Ops[0]) == get(Ops[1]), c.bv_val(1, 1), c.bv_val(0, 1)); } case Inst::Ne: { //return NeExpr::create(get(Ops[0]), get(Ops[1])); - return get(Ops[0]) != get(Ops[1]); + return ite(get(Ops[0]) != get(Ops[1]), c.bv_val(1, 1), c.bv_val(0, 1)); } case Inst::Ult: { //return UltExpr::create(get(Ops[0]), get(Ops[1])); @@ -308,18 +313,18 @@ class Z3Builder : public ExprBuilder { if (Width == 16) { //return ConcatExpr::create(ExtractExpr::create(L, 0, 8), // ExtractExpr::create(L, 8, 8)); - EV.push_back(L.extract(c.bv_val(0, Width), c.bv_val(8, Width))); - EV.push_back(L.extract(c.bv_val(8, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(7, 0)); + EV.push_back(L.extract(15, 8)); } else if (Width == 32) { //return ConcatExpr::create4(ExtractExpr::create(L, 0, 8), // ExtractExpr::create(L, 8, 8), // ExtractExpr::create(L, 16, 8), // ExtractExpr::create(L, 24, 8)); - EV.push_back(L.extract(c.bv_val(0, Width), c.bv_val(8, Width))); - EV.push_back(L.extract(c.bv_val(8, Width), c.bv_val(8, Width))); - EV.push_back(L.extract(c.bv_val(16, Width), c.bv_val(8, Width))); - EV.push_back(L.extract(c.bv_val(24, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(7, 0)); + EV.push_back(L.extract(15, 8)); + EV.push_back(L.extract(23, 16)); + EV.push_back(L.extract(31, 24)); } else if (Width == 64) { //return ConcatExpr::create8(ExtractExpr::create(L, 0, 8), @@ -330,14 +335,14 @@ class Z3Builder : public ExprBuilder { // ExtractExpr::create(L, 40, 8), // ExtractExpr::create(L, 48, 8), // ExtractExpr::create(L, 56, 8)); - EV.push_back(L.extract(c.bv_val(0, Width), c.bv_val(8, Width))); - EV.push_back(L.extract(c.bv_val(8, Width), c.bv_val(8, Width))); - EV.push_back(L.extract(c.bv_val(16, Width), c.bv_val(8, Width))); - EV.push_back(L.extract(c.bv_val(24, Width), c.bv_val(8, Width))); - EV.push_back(L.extract(c.bv_val(32, Width), c.bv_val(8, Width))); - EV.push_back(L.extract(c.bv_val(40, Width), c.bv_val(8, Width))); - EV.push_back(L.extract(c.bv_val(48, Width), c.bv_val(8, Width))); - EV.push_back(L.extract(c.bv_val(56, Width), c.bv_val(8, Width))); + EV.push_back(L.extract(7, 0)); + EV.push_back(L.extract(15, 8)); + EV.push_back(L.extract(23, 16)); + EV.push_back(L.extract(31, 24)); + EV.push_back(L.extract(39, 32)); + EV.push_back(L.extract(47, 40)); + EV.push_back(L.extract(55, 48)); + EV.push_back(L.extract(63, 56)); } return concat(EV); } @@ -411,7 +416,11 @@ class Z3Builder : public ExprBuilder { if (ExprMap.count(I)) return ExprMap.at(I); expr E = build(I); - assert(E.get_sort().bv_size() == I->Width); + llvm::outs() << "@@@ sort kind for " << Inst::getKindName(I->K) << ": " << E.get_sort().sort_kind() << "\n"; + ReplacementContext Context; + PrintReplacementRHS(llvm::outs(), I, Context); + //llvm::outs() << "@@@ sort name: " << E.get_sort().name() << "\n"; + //assert(E.get_sort().bv_size() == I->Width); ExprMap.insert(std::make_pair(I, E)); return E; } From 6cc67ace71daa822e263df55f6914518ee6be3a6 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Sun, 12 Aug 2018 22:41:41 +0200 Subject: [PATCH 44/49] Work --- lib/Extractor/Z3Builder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Extractor/Z3Builder.cpp b/lib/Extractor/Z3Builder.cpp index 83e681224..71074ba95 100644 --- a/lib/Extractor/Z3Builder.cpp +++ b/lib/Extractor/Z3Builder.cpp @@ -65,7 +65,7 @@ class Z3Builder : public ExprBuilder { return std::string(); expr E = get(Cand); solver s(c); - s.add(E); + s.add(E == c.bv_val(1, E.get_sort().bv_size())); llvm::outs() << s.to_smt2() << "\n"; #if 0 std::string SMTStr; From dc85fa4fcb398b2ded549590a81b9a365f01601d Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 13 Aug 2018 06:09:54 +0200 Subject: [PATCH 45/49] First LGTM query using z3 --- lib/Extractor/Z3Builder.cpp | 52 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/lib/Extractor/Z3Builder.cpp b/lib/Extractor/Z3Builder.cpp index 71074ba95..9d21f69da 100644 --- a/lib/Extractor/Z3Builder.cpp +++ b/lib/Extractor/Z3Builder.cpp @@ -26,10 +26,9 @@ namespace { class Z3Builder : public ExprBuilder { context c; ReplacementContext Context; - UniqueNameSet ConstNames; - std::vector Consts; - std::map ExprMap; + UniqueNameSet VarNames; std::vector Vars; + std::map ExprMap; public: Z3Builder(InstContext &IC) : ExprBuilder(IC) {} @@ -64,32 +63,30 @@ class Z3Builder : public ExprBuilder { if (!Cand) return std::string(); expr E = get(Cand); + E = E.simplify(); solver s(c); - s.add(E == c.bv_val(1, E.get_sort().bv_size())); - llvm::outs() << s.to_smt2() << "\n"; -#if 0 + s.add(E == c.bv_val(0, E.get_sort().bv_size())); + // std::string SMTStr; - llvm::raw_string_ostream SMTSS(SMTStr); - ConstraintManager Manager; - Query KQuery(Manager, E); - ExprSMTLIBPrinter Printer; - Printer.setOutput(SMTSS); - Printer.setQuery(KQuery); - std::vector Arr; + SMTStr += "(set-option :produce-models true)\n"; + SMTStr += "(set-logic QF_BV )\n"; + SMTStr += s.to_smt2(); + /* + for (auto Str : Vars) { + SMTStr += "(get-value (" + Str + ") )\n"; + } + */ if (ModelVars) { - for (unsigned I = 0; I != Vars.size(); ++I) { - if (Vars[I]) { - Arr.push_back(Arrays[I].get()); - ModelVars->push_back(Vars[I]); - } + for (auto Var : Vars) { + SMTStr += "(get-value (" + Var->Name + ") )\n"; + ModelVars->push_back(Var); } - Printer.setArrayValuesToGet(Arr); } - Printer.generateOutput(); - - return SMTSS.str(); -#endif - return std::string(); + SMTStr += "(exit)\n"; + + llvm::outs() << SMTStr << "\n"; + + return SMTStr; } private: @@ -433,9 +430,10 @@ class Z3Builder : public ExprBuilder { NameStr = ("a" + Name).str(); else NameStr = Name; - expr E = c.bv_const(ConstNames.makeName(NameStr).c_str(), Width); - Consts.emplace_back(E); - Vars.push_back(Origin); + NameStr = VarNames.makeName(NameStr); + expr E = c.bv_const(NameStr.c_str(), Width); + Origin->Name = NameStr; + Vars.emplace_back(Origin); return E; } From 66edd46718430907c586cbd7d5eedad86d2bf059 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Tue, 21 Aug 2018 23:48:38 +0200 Subject: [PATCH 46/49] Work --- lib/Extractor/Z3Builder.cpp | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/lib/Extractor/Z3Builder.cpp b/lib/Extractor/Z3Builder.cpp index 9d21f69da..585935169 100644 --- a/lib/Extractor/Z3Builder.cpp +++ b/lib/Extractor/Z3Builder.cpp @@ -40,19 +40,12 @@ class Z3Builder : public ExprBuilder { Inst *Cand = GetCandidateExprForReplacement(BPCs, PCs, Mapping, Negate); if (!Cand) return std::string(); -#if 0 - ref E = get(Cand); - - std::string SStr; - llvm::raw_string_ostream SS(SStr); - std::unique_ptr PP(ExprPPrinter::create(SS)); - PP->setForceNoLineBreaks(true); - PP->scan(E); - PP->print(E); + expr E = get(Cand); + E = E.simplify(); + solver s(c); + s.add(E == c.bv_val(0, E.get_sort().bv_size())); - return SS.str(); -#endif - return std::string(); + return s.to_smt2(); } std::string BuildQuery(const BlockPCs &BPCs, @@ -63,7 +56,7 @@ class Z3Builder : public ExprBuilder { if (!Cand) return std::string(); expr E = get(Cand); - E = E.simplify(); + //E = E.simplify(); solver s(c); s.add(E == c.bv_val(0, E.get_sort().bv_size())); // @@ -71,11 +64,6 @@ class Z3Builder : public ExprBuilder { SMTStr += "(set-option :produce-models true)\n"; SMTStr += "(set-logic QF_BV )\n"; SMTStr += s.to_smt2(); - /* - for (auto Str : Vars) { - SMTStr += "(get-value (" + Str + ") )\n"; - } - */ if (ModelVars) { for (auto Var : Vars) { SMTStr += "(get-value (" + Var->Name + ") )\n"; @@ -84,7 +72,7 @@ class Z3Builder : public ExprBuilder { } SMTStr += "(exit)\n"; - llvm::outs() << SMTStr << "\n"; + //llvm::outs() << SMTStr << "\n"; return SMTStr; } @@ -113,7 +101,7 @@ class Z3Builder : public ExprBuilder { expr build(Inst *I) { const std::vector &Ops = I->orderedOps(); - llvm::outs() << "## getting instruction: " << Inst::getKindName(I->K) << "\n"; + //llvm::outs() << "## getting instruction: " << Inst::getKindName(I->K) << "\n"; switch (I->K) { case Inst::UntypedConst: assert(0 && "unexpected kind"); @@ -413,11 +401,13 @@ class Z3Builder : public ExprBuilder { if (ExprMap.count(I)) return ExprMap.at(I); expr E = build(I); +#if 0 llvm::outs() << "@@@ sort kind for " << Inst::getKindName(I->K) << ": " << E.get_sort().sort_kind() << "\n"; ReplacementContext Context; PrintReplacementRHS(llvm::outs(), I, Context); - //llvm::outs() << "@@@ sort name: " << E.get_sort().name() << "\n"; - //assert(E.get_sort().bv_size() == I->Width); + llvm::outs() << "@@@ sort name: " << E.get_sort().name() << "\n"; +#endif + assert(E.get_sort().bv_size() == I->Width); ExprMap.insert(std::make_pair(I, E)); return E; } From c45f05d89d52632ff0db03673313185c87e47af0 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Fri, 31 Aug 2018 23:54:26 +0200 Subject: [PATCH 47/49] Fix test cases --- lib/Extractor/Z3Builder.cpp | 24 ++++++++++++------------ lib/Inst/Inst.cpp | 12 ++++++------ test/lit.cfg | 2 ++ 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/Extractor/Z3Builder.cpp b/lib/Extractor/Z3Builder.cpp index 585935169..8a9c42521 100644 --- a/lib/Extractor/Z3Builder.cpp +++ b/lib/Extractor/Z3Builder.cpp @@ -82,8 +82,8 @@ class Z3Builder : public ExprBuilder { unsigned Width = L.get_sort().bv_size(); expr Count = c.bv_val(0, Width); for (unsigned J=0; JWidth); - return expr(c, Z3_mk_zero_ext(c, I->Width, get(Ops[0]))); + return zext(get(Ops[0]), I->Width-Ops[0]->Width); } case Inst::SExt: //return SExtExpr::create(get(Ops[0]), I->Width); - return expr(c, Z3_mk_sign_ext(c, I->Width, get(Ops[0]))); + return sext(get(Ops[0]), I->Width-Ops[0]->Width); case Inst::Trunc: { //return ExtractExpr::create(get(Ops[0]), 0, I->Width); return get(Ops[0]).extract(I->Width-1, 0); @@ -275,19 +275,19 @@ class Z3Builder : public ExprBuilder { } case Inst::Ult: { //return UltExpr::create(get(Ops[0]), get(Ops[1])); - return expr(c, Z3_mk_bvult(c, get(Ops[0]), get(Ops[1]))); + return ite(expr(c, Z3_mk_bvult(c, get(Ops[0]), get(Ops[1]))), c.bv_val(1, 1), c.bv_val(0, 1)); } case Inst::Slt: { //return SltExpr::create(get(Ops[0]), get(Ops[1])); - return expr(c, Z3_mk_bvslt(c, get(Ops[0]), get(Ops[1]))); + return ite(expr(c, Z3_mk_bvslt(c, get(Ops[0]), get(Ops[1]))), c.bv_val(1, 1), c.bv_val(0, 1)); } case Inst::Ule: { //return UleExpr::create(get(Ops[0]), get(Ops[1])); - return expr(c, Z3_mk_bvule(c, get(Ops[0]), get(Ops[1]))); + return ite(expr(c, Z3_mk_bvule(c, get(Ops[0]), get(Ops[1]))), c.bv_val(1, 1), c.bv_val(0, 1)); } case Inst::Sle: { //return SleExpr::create(get(Ops[0]), get(Ops[1])); - return expr(c, Z3_mk_bvsle(c, get(Ops[0]), get(Ops[1]))); + return ite(expr(c, Z3_mk_bvsle(c, get(Ops[0]), get(Ops[1]))), c.bv_val(1, 1), c.bv_val(0, 1)); } case Inst::CtPop: return countOnes(get(Ops[0])); @@ -402,10 +402,10 @@ class Z3Builder : public ExprBuilder { return ExprMap.at(I); expr E = build(I); #if 0 - llvm::outs() << "@@@ sort kind for " << Inst::getKindName(I->K) << ": " << E.get_sort().sort_kind() << "\n"; + llvm::outs() << "@@ sort kind for " << I->K << ", name: " << Inst::getKindName(I->K) << ": " << E.get_sort().sort_kind() << "\n"; ReplacementContext Context; PrintReplacementRHS(llvm::outs(), I, Context); - llvm::outs() << "@@@ sort name: " << E.get_sort().name() << "\n"; + llvm::outs() << "@@@ I->Width = " << I->Width << ", sort width = " << E.get_sort().bv_size() << "\n"; #endif assert(E.get_sort().bv_size() == I->Width); ExprMap.insert(std::make_pair(I, E)); diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index fc432f732..52b574512 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -382,24 +382,24 @@ const char *Inst::getKindName(Kind K) { return "ctlz"; case ExtractValue: return "extractvalue"; + case SAddO: case SAddWithOverflow: return "sadd.with.overflow"; + case UAddO: case UAddWithOverflow: return "uadd.with.overflow"; + case SSubO: case SSubWithOverflow: return "ssub.with.overflow"; + case USubO: case USubWithOverflow: return "usub.with.overflow"; + case SMulO: case SMulWithOverflow: return "smul.with.overflow"; + case UMulO: case UMulWithOverflow: return "umul.with.overflow"; - case SAddO: - case UAddO: - case SSubO: - case USubO: - case SMulO: - case UMulO: default: llvm_unreachable("all cases covered"); } diff --git a/test/lit.cfg b/test/lit.cfg index cf69470e7..702d1f1a8 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -44,3 +44,5 @@ if config.synthesis: llvm_profile_file = os.environ.get("LLVM_PROFILE_FILE") if llvm_profile_file: config.environment["LLVM_PROFILE_FILE"] = llvm_profile_file + +#config.available_features.add("z3") From a6b9fca0da0a9b1320e058019ed46d6792cb09ef Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Fri, 7 Sep 2018 00:06:06 +0200 Subject: [PATCH 48/49] Add Inst::Const to BV conversion --- lib/Extractor/Z3Builder.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/Extractor/Z3Builder.cpp b/lib/Extractor/Z3Builder.cpp index 8a9c42521..d06526ec6 100644 --- a/lib/Extractor/Z3Builder.cpp +++ b/lib/Extractor/Z3Builder.cpp @@ -107,10 +107,8 @@ class Z3Builder : public ExprBuilder { assert(0 && "unexpected kind"); case Inst::Const: { //return klee::ConstantExpr::alloc(I->Val); - if (I->Val.isNegative()) - return c.bv_val((int)(I->Val.getSExtValue()), I->Width); - else - return c.bv_val((unsigned)(I->Val.getZExtValue()), I->Width); + std::string ConstStr = I->Val.toString(10, true); + return c.bv_val(ConstStr.c_str(), I->Width); } case Inst::Var: return makeSizedConst(I->Width, I->Name, I); From 2819fedd7ee1f56213e4d6fdb65d5151e3f04482 Mon Sep 17 00:00:00 2001 From: Raimondas Sasnauskas Date: Mon, 11 Feb 2019 21:15:11 +0100 Subject: [PATCH 49/49] Foo --- build_deps.sh | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/build_deps.sh b/build_deps.sh index fc2568bef..d9998e3c8 100755 --- a/build_deps.sh +++ b/build_deps.sh @@ -120,17 +120,3 @@ mkdir -p $hiredisdir/install/lib (cd $hiredisdir && git checkout $hiredis_commit && make libhiredis.a && cp -r hiredis.h async.h read.h sds.h adapters install/include/hiredis && cp libhiredis.a install/lib) - -z3dir=$(pwd)/third_party/z3 - -if [ -d $z3dir/.git ] ; then - (cd $z3dir && git fetch) -else - git clone $z3_repo $z3dir -fi - -mkdir -p $z3dir/install - -(cd $z3dir && git checkout $z3_commit && -python scripts/mk_make.py --prefix=$z3dir/install && -cd build && make -j4 install)