From 63c8fc3e869575c0452e7142e53b2eb231605db0 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 1 Dec 2020 15:29:32 -0700 Subject: [PATCH 001/165] Generalization tool --- CMakeLists.txt | 7 +- include/souper/Extractor/Solver.h | 10 +- include/souper/Infer/Preconditions.h | 2 +- lib/Extractor/Solver.cpp | 66 +++++------ lib/Infer/Preconditions.cpp | 9 +- test/Generalize/fixit.opt | 42 +++++++ test/Generalize/leaf.opt | 22 ++++ tools/generalize.cpp | 163 +++++++++++++++++++++++++++ tools/souper-check.cpp | 29 ++++- 9 files changed, 305 insertions(+), 45 deletions(-) create mode 100644 test/Generalize/fixit.opt create mode 100644 test/Generalize/leaf.opt create mode 100644 tools/generalize.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f2d81d8c6..52aa752e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -295,6 +295,10 @@ add_executable(souper-check tools/souper-check.cpp ) +add_executable(generalize + tools/generalize.cpp +) + add_executable(souper-interpret tools/souper-interpret.cpp ) @@ -362,7 +366,7 @@ configure_file( ) foreach(target souper internal-solver-test lexer-test parser-test souper-check count-insts - souper2llvm souper-interpret + souper2llvm souper-interpret generalize souperExtractor souperInfer souperInst souperKVStore souperParser souperSMTLIB2 souperTool souperPass souperPassProfileAll kleeExpr souperCodegen) @@ -400,6 +404,7 @@ 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} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) +target_link_libraries(generalize souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(souper-interpret souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(clang-souper souperClangTool souperExtractor souperKVStore souperParser souperSMTLIB2 souperTool kleeExpr ${CLANG_LIBS} ${LLVM_LIBS} ${LLVM_LDFLAGS} ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(count-insts souperParser) diff --git a/include/souper/Extractor/Solver.h b/include/souper/Extractor/Solver.h index a9648cfe1..11488e186 100644 --- a/include/souper/Extractor/Solver.h +++ b/include/souper/Extractor/Solver.h @@ -44,6 +44,12 @@ class Solver { InstMapping Mapping, bool &IsValid, std::vector> *Model) = 0; + virtual std::error_code + isSatisfiable(llvm::StringRef Query, bool &Result, + unsigned NumModels, + std::vector *Models, + unsigned Timeout = 0) = 0; + virtual std::string getName() = 0; virtual @@ -90,8 +96,8 @@ class Solver { virtual std::error_code abstractPrecondition(const BlockPCs &BPCs, const std::vector &PCs, - InstMapping &Mapping, InstContext &IC, - bool &FoundWeakest) = 0; + InstMapping &Mapping, InstContext &IC, bool &FoundWeakest, + std::vector> &Results) = 0; }; std::unique_ptr createBaseSolver( diff --git a/include/souper/Infer/Preconditions.h b/include/souper/Infer/Preconditions.h index 7aabc735c..c5970d0b7 100644 --- a/include/souper/Infer/Preconditions.h +++ b/include/souper/Infer/Preconditions.h @@ -9,7 +9,7 @@ class SMTLIBSolver; class Solver; std::vector> inferAbstractKBPreconditions(SynthesisContext &SC, Inst *RHS, - SMTLIBSolver *SMTSolver, Solver *S, bool &FoundWeakest); + Solver *S, bool &FoundWeakest); } #endif // SOUPER_PRECONDITIONS_H diff --git a/lib/Extractor/Solver.cpp b/lib/Extractor/Solver.cpp index d4d940799..2fd9b64d5 100644 --- a/lib/Extractor/Solver.cpp +++ b/lib/Extractor/Solver.cpp @@ -265,39 +265,12 @@ class BaseSolver : public Solver { std::error_code abstractPrecondition(const BlockPCs &BPCs, const std::vector &PCs, - InstMapping &Mapping, InstContext &IC, - bool &FoundWeakest) override { + InstMapping &Mapping, InstContext &IC, bool &FoundWeakest, + std::vector> &Results) override { SynthesisContext SC{IC, SMTSolver.get(), Mapping.LHS, /*LHSUB*/nullptr, PCs, BPCs, /*CheckAllGuesses=*/false, Timeout}; - std::vector> Results = - inferAbstractKBPreconditions(SC, Mapping.RHS, SMTSolver.get(), this, FoundWeakest); - - ReplacementContext RC; - auto LHSStr = RC.printInst(Mapping.LHS, llvm::outs(), true); - llvm::outs() << "infer " << LHSStr << "\n"; - auto RHSStr = RC.printInst(Mapping.RHS, llvm::outs(), true); - llvm::outs() << "result " << RHSStr << "\n"; - for (size_t i = 0; i < Results.size(); ++i) { - for (auto It = Results[i].begin(); It != Results[i].end(); ++It) { - auto &&P = *It; - std::string dummy; - llvm::raw_string_ostream str(dummy); - auto VarStr = RC.printInst(P.first, str, false); - llvm::outs() << VarStr << " -> " << Inst::getKnownBitsString(P.second.Zero, P.second.One); - - auto Next = It; - Next++; - if (Next != Results[i].end()) { - llvm::outs() << " (and) "; - } - } - if (i == Results.size() - 1) { - llvm::outs() << "\n"; - } else { - llvm::outs() << "\n(or)\n"; - } - } + Results = inferAbstractKBPreconditions(SC, Mapping.RHS, this, FoundWeakest); return {}; } @@ -461,6 +434,13 @@ class BaseSolver : public Solver { return EC; } + std::error_code isSatisfiable(llvm::StringRef Query, bool &Result, + unsigned NumModels, + std::vector *Models, + unsigned Timeout = 0) override { + return SMTSolver->isSatisfiable(Query, Result, NumModels, Models, Timeout); + } + std::error_code isValid(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool &IsValid, @@ -717,6 +697,13 @@ class MemCachingSolver : public Solver { } } + std::error_code isSatisfiable(llvm::StringRef Query, bool &Result, + unsigned NumModels, + std::vector *Models, + unsigned Timeout = 0) override { + return UnderlyingSolver->isSatisfiable(Query, Result, NumModels, Models, Timeout); + } + std::string getName() override { return UnderlyingSolver->getName() + " + internal cache"; } @@ -745,9 +732,9 @@ class MemCachingSolver : public Solver { std::error_code abstractPrecondition(const BlockPCs &BPCs, const std::vector &PCs, - InstMapping &Mapping, InstContext &IC, - bool &FoundWeakest) override { - return UnderlyingSolver->abstractPrecondition(BPCs, PCs, Mapping, IC, FoundWeakest); + InstMapping &Mapping, InstContext &IC, bool &FoundWeakest, + std::vector> &Results) override { + return UnderlyingSolver->abstractPrecondition(BPCs, PCs, Mapping, IC, FoundWeakest, Results); } std::error_code knownBits(const BlockPCs &BPCs, @@ -847,6 +834,13 @@ class ExternalCachingSolver : public Solver { return UnderlyingSolver->constantRange(BPCs, PCs, LHS, IC); } + std::error_code isSatisfiable(llvm::StringRef Query, bool &Result, + unsigned NumModels, + std::vector *Models, + unsigned Timeout = 0) override { + return UnderlyingSolver->isSatisfiable(Query, Result, NumModels, Models, Timeout); + } + std::error_code isValid(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool &IsValid, @@ -885,9 +879,9 @@ class ExternalCachingSolver : public Solver { std::error_code abstractPrecondition(const BlockPCs &BPCs, const std::vector &PCs, - InstMapping &Mapping, InstContext &IC, - bool &FoundWeakest) override { - return UnderlyingSolver->abstractPrecondition(BPCs, PCs, Mapping, IC, FoundWeakest); + InstMapping &Mapping, InstContext &IC, bool &FoundWeakest, + std::vector> &Results) override { + return UnderlyingSolver->abstractPrecondition(BPCs, PCs, Mapping, IC, FoundWeakest, Results); } std::error_code knownBits(const BlockPCs &BPCs, diff --git a/lib/Infer/Preconditions.cpp b/lib/Infer/Preconditions.cpp index 3df2bedc2..2fae19e1b 100644 --- a/lib/Infer/Preconditions.cpp +++ b/lib/Infer/Preconditions.cpp @@ -7,7 +7,7 @@ using llvm::APInt; namespace souper { std::vector> inferAbstractKBPreconditions(SynthesisContext &SC, Inst *RHS, - SMTLIBSolver *SMTSolver, Solver *S, bool &FoundWeakest) { + Solver *S, bool &FoundWeakest) { InstMapping Mapping(SC.LHS, RHS); bool Valid; if (DebugLevel >= 3) { @@ -20,7 +20,10 @@ std::vector> } std::vector PCCopy = SC.PCs; if (Valid) { - llvm::outs() << "Already valid.\n"; + FoundWeakest = true; + if (DebugLevel > 1) { + llvm::errs() << "Already valid.\n"; + } return {}; } @@ -97,7 +100,7 @@ std::vector> &ModelInsts, Precondition, true); - SMTSolver->isSatisfiable(Query, FoundWeakest, ModelInsts.size(), + S->isSatisfiable(Query, FoundWeakest, ModelInsts.size(), &ModelVals, SC.Timeout); std::map Known; diff --git a/test/Generalize/fixit.opt b/test/Generalize/fixit.opt new file mode 100644 index 000000000..782c10e56 --- /dev/null +++ b/test/Generalize/fixit.opt @@ -0,0 +1,42 @@ +; REQUIRES: solver, synthesis +; RUN: %generalize -fixit %s | %souper-check > %t +; RUN: %FileCheck %s < %t + +%x:i8 = var +%y:i8 = var +%z = add %x, %y +%t = add %z, 42 +%u = sub %t, %y +infer %u +%v = add %x, 42 +result %v +;CHECK: LGTM + +%x:i8 = var +%y:i8 = var +%t = add %x, 42 +%u = sub %t, %y +infer %u +%v = add %x, 42 +result %v +;CHECK: LGTM + +%x:i8 = var +%y:i8 = var +%t = and %x, 137 +%u = xor %t, %y +infer %u +%v = or %x, %y +result %v +;CHECK: LGTM +;CHECK-NEXT: LGTM + +%x:i8 = var +%y:i8 = var +%t = or %x, 42 +%u = and %t, %y +infer %u +%v = and %x, %y +result %v +;CHECK: LGTM +;CHECK-NEXT: LGTM diff --git a/test/Generalize/leaf.opt b/test/Generalize/leaf.opt new file mode 100644 index 000000000..c3ac27865 --- /dev/null +++ b/test/Generalize/leaf.opt @@ -0,0 +1,22 @@ +; REQUIRES: solver, synthesis +; RUN: %generalize -remove-leaf %s | %souper-check > %t +; RUN: %FileCheck %s < %t + +%x:i8 = var +%y:i8 = var +%masked = and %x, 3 +%and = and %masked, %y +%foo = lshr %and, 2 +infer %and +result 0:i8 +; CHECK: LGTM +; CHECK: LGTM + +%x:i8 = var +%y:i8 = var +%a = and %x, 15 +%b = and %y, 240 +%foo = or %a, %b +infer %foo +result 0:i8 +; CHECK: LGTM diff --git a/tools/generalize.cpp b/tools/generalize.cpp new file mode 100644 index 000000000..865125c6f --- /dev/null +++ b/tools/generalize.cpp @@ -0,0 +1,163 @@ +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/KnownBits.h" + +#include "souper/Infer/Preconditions.h" + +#include "souper/Inst/InstGraph.h" +#include "souper/Parser/Parser.h" +#include "souper/Tool/GetSolver.h" +#include "souper/Util/DfaUtils.h" + +using namespace llvm; +using namespace souper; + +unsigned DebugLevel; + +static cl::opt +DebugFlagParser("souper-debug-level", + cl::desc("Control the verbose level of debug output (default=1). " + "The larger the number is, the more fine-grained debug " + "information will be printed."), + cl::location(DebugLevel), cl::init(1)); + +static cl::opt +InputFilename(cl::Positional, cl::desc(""), + cl::init("-")); + +static llvm::cl::opt RemoveLeaf("remove-leaf", + llvm::cl::desc("Try to generalize a valid optimization by replacing" + "the use of a once-used variable with a new variable" + "(default=false)"), + llvm::cl::init(false)); + +static llvm::cl::opt FixIt("fixit", + llvm::cl::desc("Given an invalid optimization, generate a valid one." + "(default=false)"), + llvm::cl::init(false)); + +void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { + bool FoundWP = false; + std::vector> Results; + S->abstractPrecondition(Input.BPCs, Input.PCs, Input.Mapping, IC, FoundWP, Results); + + if (FoundWP && Results.empty()) { + Input.print(llvm::outs(), true); + } else { + for (auto &&Result : Results) { // Each result is a disjunction + for (auto Pair: Result) { + Pair.first->KnownOnes = Pair.second.One; + Pair.first->KnownZeros = Pair.second.Zero; + } + Input.print(llvm::outs(), true); + } + } +} + +// TODO: Return modified instructions instead of just printing out +void RemoveLeafAndGeneralize(InstContext &IC, + Solver *S, ParsedReplacement Input) { + + if (DebugLevel > 1) { + llvm::errs() << "Attempting to generalize by removing leaf.\n"; + } + // TODO: Do not generalize by removing leaf if LHS has one inst. + + std::map> Uses; + + std::vector Stack{Input.Mapping.LHS, Input.Mapping.RHS}; + // TODO: Find uses in PCs/BPCs + + std::set Visited; + while (!Stack.empty()) { + auto Current = Stack.back(); + Stack.pop_back(); + Visited.insert(Current); + + for (auto Op : Current->Ops) { + if (Op->K == Inst::Var) { + Uses[Op].insert(Current); + // Intentionally skips root + } + if (Visited.find(Op) == Visited.end()) { + Stack.push_back(Op); + } + } + } + + // Find a variable with one use; + Inst *UsedOnce = nullptr; + for (auto P : Uses) { + if (P.second.size() == 1) { + UsedOnce = P.first; + break; + } + } + + if (!UsedOnce) { + llvm::outs() << "Failed. No var with one use."; + return; + } else { + Inst *User = *Uses[UsedOnce].begin(); + Inst *NewVar = IC.createVar(User->Width, "newvar"); + + std::map ICache; + ICache[User] = NewVar; + + std::map BCache; + std::map CMap; + + Input.Mapping.LHS = getInstCopy(Input.Mapping.LHS, IC, ICache, + BCache, &CMap, false); + + Input.Mapping.RHS = getInstCopy(Input.Mapping.RHS, IC, ICache, + BCache, &CMap, false); + + // TODO: Replace PCs/BPCs + } + + Generalize(IC, S, Input); +} + +int main(int argc, char **argv) { + cl::ParseCommandLineOptions(argc, argv); + KVStore *KV = 0; + + std::unique_ptr S = 0; + S = GetSolver(KV); + + auto MB = MemoryBuffer::getFileOrSTDIN(InputFilename); + if (!MB) { + llvm::errs() << MB.getError().message() << '\n'; + return 1; + } + + InstContext IC; + std::string ErrStr; + + auto &&Data = (*MB)->getMemBufferRef(); + auto Inputs = ParseReplacements(IC, Data.getBufferIdentifier(), + Data.getBuffer(), ErrStr); + + if (!ErrStr.empty()) { + llvm::errs() << ErrStr << '\n'; + return 1; + } + + // TODO: Write default action which chooses what to do based on input structure + + for (auto &&Input: Inputs) { + if (FixIt) { + // TODO: Verify that inputs are valid optimizations + Generalize(IC, S.get(), Input); + } + if (RemoveLeaf) { + RemoveLeafAndGeneralize(IC, S.get(), Input); + } + // if (EviscerateRoot) {...} + // if (SymbolizeConstant) {...} + // if (LiberateWidth) {...} + } + + return 0; +} diff --git a/tools/souper-check.cpp b/tools/souper-check.cpp index f45adffec..9f310d220 100644 --- a/tools/souper-check.cpp +++ b/tools/souper-check.cpp @@ -325,11 +325,36 @@ int SolveInst(const MemoryBufferRef &MB, Solver *S) { } } else if (InferAP) { bool FoundWeakest = false; - S->abstractPrecondition(Rep.BPCs, Rep.PCs, Rep.Mapping, IC, FoundWeakest); + std::vector> Results; + S->abstractPrecondition(Rep.BPCs, Rep.PCs, Rep.Mapping, IC, FoundWeakest, Results); if (!FoundWeakest) { llvm::outs() << "Failed to find WP.\n"; } - + ReplacementContext RC; + auto LHSStr = RC.printInst(Rep.Mapping.LHS, llvm::outs(), true); + llvm::outs() << "infer " << LHSStr << "\n"; + auto RHSStr = RC.printInst(Rep.Mapping.RHS, llvm::outs(), true); + llvm::outs() << "result " << RHSStr << "\n"; + for (size_t i = 0; i < Results.size(); ++i) { + for (auto It = Results[i].begin(); It != Results[i].end(); ++It) { + auto &&P = *It; + std::string dummy; + llvm::raw_string_ostream str(dummy); + auto VarStr = RC.printInst(P.first, str, false); + llvm::outs() << VarStr << " -> " << Inst::getKnownBitsString(P.second.Zero, P.second.One); + + auto Next = It; + Next++; + if (Next != Results[i].end()) { + llvm::outs() << " (and) "; + } + } + if (i == Results.size() - 1) { + llvm::outs() << "\n"; + } else { + llvm::outs() << "\n(or)\n"; + } + } } else { bool Valid; std::vector> Models; From b06aef9ed7dbded9afa3e26fffb90b0004e1d75f Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 1 Dec 2020 21:11:02 -0700 Subject: [PATCH 002/165] Generalize constants --- include/souper/Infer/EnumerativeSynthesis.h | 6 + lib/Infer/EnumerativeSynthesis.cpp | 45 ++++++- test/Generalize/symbolize.opt | 11 ++ tools/generalize.cpp | 128 +++++++++++++++++++- 4 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 test/Generalize/symbolize.opt diff --git a/include/souper/Infer/EnumerativeSynthesis.h b/include/souper/Infer/EnumerativeSynthesis.h index c15b15d14..84f8ad659 100644 --- a/include/souper/Infer/EnumerativeSynthesis.h +++ b/include/souper/Infer/EnumerativeSynthesis.h @@ -30,6 +30,8 @@ namespace souper { class EnumerativeSynthesis { public: + EnumerativeSynthesis(); + // Synthesize an instruction from the specification in LHS std::error_code synthesize(SMTLIBSolver *SMTSolver, const BlockPCs &BPCs, @@ -38,6 +40,10 @@ class EnumerativeSynthesis { bool CheckAllGuesses, InstContext &IC, unsigned Timeout); + std::vector + generateExprs(InstContext &IC, size_t CountLimit, + std::vector Vars, size_t Width); + }; } diff --git a/lib/Infer/EnumerativeSynthesis.cpp b/lib/Infer/EnumerativeSynthesis.cpp index 66bce8352..4ee94d45f 100644 --- a/lib/Infer/EnumerativeSynthesis.cpp +++ b/lib/Infer/EnumerativeSynthesis.cpp @@ -33,8 +33,8 @@ extern unsigned DebugLevel; using namespace souper; using namespace llvm; -static const std::vector UnaryOperators = { - Inst::CtPop, Inst::BSwap, Inst::BitReverse, Inst::Cttz, Inst::Ctlz, Inst::Freeze +static std::vector UnaryOperators = { + Inst::CtPop, Inst::BSwap, Inst::BitReverse, Inst::Cttz, Inst::Ctlz }; static const std::vector BinaryOperators = { @@ -91,6 +91,9 @@ namespace { static cl::opt IgnoreCost("souper-enumerative-synthesis-ignore-cost", cl::desc("Ignore cost of RHSes -- just generate them. (default=false)"), cl::init(false)); + static cl::opt SynFreeze("souper-synthesize-freeze", + cl::desc("Generate Freeze (default=true)"), + cl::init(true)); static cl::opt MaxLHSCands("souper-max-lhs-cands", cl::desc("Gather at most this many values from a LHS to use as synthesis inputs (default=8)"), cl::init(8)); @@ -881,3 +884,41 @@ EnumerativeSynthesis::synthesize(SMTLIBSolver *SMTSolver, return EC; } + +EnumerativeSynthesis::EnumerativeSynthesis() { + if (SynFreeze) { + UnaryOperators.push_back(Inst::Freeze); + } +} + +std::vector +EnumerativeSynthesis::generateExprs(InstContext &IC, size_t CountLimit, + std::vector Vars, size_t Width) { + MaxNumInstructions = CountLimit; + + std::set Visited; + std::vector PruneFuncs = { [&Visited](Inst *I, std::vector &ReservedInsts) { + return CountPrune(I, ReservedInsts, Visited); + }}; + auto PruneCallback = MkPruneFunc(PruneFuncs); + + std::vector Guesses; + + int TooExpensive = CountLimit + 1; + + for (auto I : Vars) { + if (I->Width == Width) + addGuess(I, Width, IC, TooExpensive, Guesses, TooExpensive); + } + + auto Generate = [&Guesses](Inst *Guess) { + Guesses.push_back(Guess); + return true; + }; + + getGuesses(Vars, Width, TooExpensive, IC, nullptr, + nullptr, TooExpensive, PruneCallback, Generate); + + return Guesses; +} + diff --git a/test/Generalize/symbolize.opt b/test/Generalize/symbolize.opt new file mode 100644 index 000000000..7c52b493a --- /dev/null +++ b/test/Generalize/symbolize.opt @@ -0,0 +1,11 @@ +; REQUIRES: solver, synthesis +; RUN: %generalize -symbolize --souper-synthesize-freeze=false --generalization-num-results=2 %s | %souper-check > %t +; RUN: %FileCheck %s < %t + +%x:i8 = var +%foo = add %x, 2 +%bar = sub %foo, %x +infer %bar +result 2:i8 +;CHECK: LGTM +;CHECK: LGTM diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 865125c6f..92393e101 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -3,7 +3,7 @@ #include "llvm/Support/KnownBits.h" #include "souper/Infer/Preconditions.h" - +#include "souper/Infer/EnumerativeSynthesis.h" #include "souper/Inst/InstGraph.h" #include "souper/Parser/Parser.h" #include "souper/Tool/GetSolver.h" @@ -31,11 +31,21 @@ static llvm::cl::opt RemoveLeaf("remove-leaf", "(default=false)"), llvm::cl::init(false)); +static llvm::cl::opt SymbolizeConstant("symbolize", + llvm::cl::desc("Try to replace a concrete constant with a symbolic constant." + "(default=false)"), + llvm::cl::init(false)); + static llvm::cl::opt FixIt("fixit", llvm::cl::desc("Given an invalid optimization, generate a valid one." "(default=false)"), llvm::cl::init(false)); +static cl::opt NumResults("generalization-num-results", + cl::desc("Number of Generalization Results"), + cl::init(5)); + + void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { bool FoundWP = false; std::vector> Results; @@ -54,10 +64,120 @@ void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { } } +void SymbolizeAndGeneralize(InstContext &IC, + Solver *S, ParsedReplacement Input) { + std::vector LHSConsts, RHSConsts; + auto Pred = [](Inst *I) {return I->K == Inst::Const;}; + findInsts(Input.Mapping.LHS, LHSConsts, Pred); + findInsts(Input.Mapping.RHS, RHSConsts, Pred); + + if (LHSConsts.size() != 1 || RHSConsts.size() != 1) { + return; + // TODO: Relax this restriction later + } + + // Replace LHSConst[0] with a new variable and RHSConst[0] + // with a synthesized function. + + auto FakeConst = IC.createVar(LHSConsts[0]->Width, "fakeconst"); + + // Does it makes sense for the expression to depend on other variables? + // If yes, expand the third argument to include inputs + EnumerativeSynthesis ES; + auto Guesses = ES.generateExprs(IC, 2, {FakeConst}, + RHSConsts[0]->Width); + + // Discarding guesses with symbolic constants + // Find a way to avoid this + // Here is the problem that needs to be solved for this: + // Given f and g\C, find N and P such that P -> (f == c\N) + // Weakest possible P is desirable. + + std::vector Filtered; + for (auto Guess : Guesses) { + std::set ConstSet; + std::map ResultConstMap; + souper::getConstants(Guess, ConstSet); + if (ConstSet.empty()) { + Filtered.push_back(Guess); + } + } + std::swap(Guesses, Filtered); + + std::vector>> + Preconditions; + + std::map InstCache{{LHSConsts[0], FakeConst}}; + std::map BlockCache; + std::map ConstMap; + auto LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, + BlockCache, &ConstMap, false); + for (auto &Guess : Guesses) { + std::map InstCache{{RHSConsts[0], Guess}}; + auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, + BlockCache, &ConstMap, false); + std::vector> Results; + bool FoundWP = false; + InstMapping Mapping(LHS, RHS); + S->abstractPrecondition(Input.BPCs, Input.PCs, Mapping, IC, FoundWP, Results); + + Preconditions.push_back(Results); + if (!FoundWP) { + Guess = nullptr; // TODO: Better failure indicator + } else { + Guess = RHS; + } + } + + std::vector Idx; + std::vector Utility; + for (size_t i = 0; i < Guesses.size(); ++i) { + Idx.push_back(i); + } + for (size_t i = 0; i < Preconditions.size(); ++i) { + Utility.push_back(0); + if (!Guesses[i]) continue; + if (Preconditions[i].empty()) { + Utility[i] = 1000; // High magic number + } + + for (auto V : Preconditions[i]) { + for (auto P : V) { + auto W = P.second.getBitWidth(); + Utility[i] += (W - P.second.Zero.countPopulation()); + Utility[i] += (W - P.second.One.countPopulation()); + } + } + } + + std::sort(Idx.begin(), Idx.end(), [&Utility](size_t a, size_t b) { + return Utility[a] > Utility[b]; + }); + for (size_t i = 0; i < std::min(Idx.size(), NumResults.getValue()); ++i) { + if (Preconditions[Idx[i]].empty()) { + ReplacementContext RC; + auto LHSStr = RC.printInst(LHS, llvm::outs(), true); + llvm::outs() << "infer " << LHSStr << "\n"; + auto RHSStr = RC.printInst(Guesses[Idx[i]], llvm::outs(), true); + llvm::outs() << "result " << RHSStr << "\n\n"; + } + for (auto Results : Preconditions[Idx[i]]) { + for (auto Pair : Results) { + Pair.first->KnownOnes = Pair.second.One; + Pair.first->KnownZeros = Pair.second.Zero; + } + ReplacementContext RC; + auto LHSStr = RC.printInst(LHS, llvm::outs(), true); + llvm::outs() << "infer " << LHSStr << "\n"; + auto RHSStr = RC.printInst(Guesses[Idx[i]], llvm::outs(), true); + llvm::outs() << "result " << RHSStr << "\n\n"; + } + } +} + // TODO: Return modified instructions instead of just printing out void RemoveLeafAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input) { - if (DebugLevel > 1) { llvm::errs() << "Attempting to generalize by removing leaf.\n"; } @@ -155,7 +275,9 @@ int main(int argc, char **argv) { RemoveLeafAndGeneralize(IC, S.get(), Input); } // if (EviscerateRoot) {...} - // if (SymbolizeConstant) {...} + if (SymbolizeConstant) { + SymbolizeAndGeneralize(IC, S.get(), Input); + } // if (LiberateWidth) {...} } From f589d86059280a9be0e7df60de6611087581628c Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 2 Dec 2020 09:48:34 -0700 Subject: [PATCH 003/165] Symbolize multiple LHS consts --- test/Generalize/symbolize.opt | 10 ++++++++++ tools/generalize.cpp | 19 +++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/test/Generalize/symbolize.opt b/test/Generalize/symbolize.opt index 7c52b493a..99d9277dc 100644 --- a/test/Generalize/symbolize.opt +++ b/test/Generalize/symbolize.opt @@ -9,3 +9,13 @@ infer %bar result 2:i8 ;CHECK: LGTM ;CHECK: LGTM + +%x:i8 = var +%foo = add %x, 42 +%bar = sub %foo, 31 +infer %bar +%xip = add %x, 11 +result %xip +;CHECK: LGTM +;CHECK: LGTM +;CHECK: LGTM diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 92393e101..473426486 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -71,7 +71,7 @@ void SymbolizeAndGeneralize(InstContext &IC, findInsts(Input.Mapping.LHS, LHSConsts, Pred); findInsts(Input.Mapping.RHS, RHSConsts, Pred); - if (LHSConsts.size() != 1 || RHSConsts.size() != 1) { + if (RHSConsts.size() != 1) { return; // TODO: Relax this restriction later } @@ -79,12 +79,18 @@ void SymbolizeAndGeneralize(InstContext &IC, // Replace LHSConst[0] with a new variable and RHSConst[0] // with a synthesized function. - auto FakeConst = IC.createVar(LHSConsts[0]->Width, "fakeconst"); + std::map InstCache; + std::vector FakeConsts; + for (size_t i = 0; i < LHSConsts.size(); ++i) { + FakeConsts.push_back( + IC.createVar(LHSConsts[i]->Width, "fakeconst_" + std::to_string(i))); + InstCache[LHSConsts[i]] = FakeConsts[i]; + } // Does it makes sense for the expression to depend on other variables? // If yes, expand the third argument to include inputs EnumerativeSynthesis ES; - auto Guesses = ES.generateExprs(IC, 2, {FakeConst}, + auto Guesses = ES.generateExprs(IC, 1, FakeConsts, RHSConsts[0]->Width); // Discarding guesses with symbolic constants @@ -107,14 +113,15 @@ void SymbolizeAndGeneralize(InstContext &IC, std::vector>> Preconditions; - std::map InstCache{{LHSConsts[0], FakeConst}}; std::map BlockCache; std::map ConstMap; auto LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, false); for (auto &Guess : Guesses) { - std::map InstCache{{RHSConsts[0], Guess}}; - auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, + std::map InstCacheCopy = InstCache; + InstCacheCopy[RHSConsts[0]] = Guess; + + auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, BlockCache, &ConstMap, false); std::vector> Results; bool FoundWP = false; From 8b3b40938c7782179d494e23653f86b585678495 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 5 Jan 2021 11:56:24 -0700 Subject: [PATCH 004/165] temp commit --- lib/Infer/Preconditions.cpp | 27 ++++++++- tools/generalize.cpp | 116 ++++++++++++++++++++++++++---------- 2 files changed, 108 insertions(+), 35 deletions(-) diff --git a/lib/Infer/Preconditions.cpp b/lib/Infer/Preconditions.cpp index 2fae19e1b..e5118342e 100644 --- a/lib/Infer/Preconditions.cpp +++ b/lib/Infer/Preconditions.cpp @@ -4,6 +4,11 @@ #include using llvm::APInt; +static llvm::cl::opt FixItNoVar("fixit-no-restrict-vars", + llvm::cl::desc("Do not restrict input variables, only constants." + "(default=false)"), + llvm::cl::init(false)); + namespace souper { std::vector> inferAbstractKBPreconditions(SynthesisContext &SC, Inst *RHS, @@ -34,6 +39,15 @@ std::vector> std::vector Vars; findVars(Mapping.LHS, Vars); + std::set FilteredVars; + + for (auto Var : Vars) { + std::string NamePrefix = Var->Name; + NamePrefix.resize(4); + if (!FixItNoVar || Var->K != Inst::Var || NamePrefix == "fake") { + FilteredVars.insert(Var); + } + } std::map OriginalState; @@ -95,6 +109,7 @@ std::vector> } } + // Find one input for which the given transformation is valid Models.clear(); std::string Query = BuildQuery(SC.IC, SC.BPCs, PCCopy, Mapping, &ModelInsts, Precondition, true); @@ -107,11 +122,18 @@ std::vector> if (FoundWeakest) { for (unsigned J = 0; J < ModelInsts.size(); ++J) { llvm::KnownBits KBCurrent(ModelInsts[J]->Width); - Known[ModelInsts[J]].One = ModelVals[J]; + if (FilteredVars.find(ModelInsts[J]) != FilteredVars.end()) { + Known[ModelInsts[J]].One = ModelVals[J]; + Known[ModelInsts[J]].Zero = ~ModelVals[J]; + } else { + auto Zero = llvm::APInt(ModelInsts[J]->Width, 0); + Known[ModelInsts[J]].One = Zero; + Known[ModelInsts[J]].Zero = Zero; + } + if (DebugLevel >= 3) { llvm::outs() << "Starting with : " << ModelVals[J] << "\n"; } - Known[ModelInsts[J]].Zero = ~ModelVals[J]; } } else { if (Results.empty()) { @@ -125,6 +147,7 @@ std::vector> break; } } + for (unsigned J = 0; J < Vars.size(); ++J) { Vars[J]->KnownZeros = Known[Vars[J]].Zero; Vars[J]->KnownOnes = Known[Vars[J]].One; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 473426486..ef51d3528 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -4,6 +4,7 @@ #include "souper/Infer/Preconditions.h" #include "souper/Infer/EnumerativeSynthesis.h" +#include "souper/Infer/ConstantSynthesis.h" #include "souper/Inst/InstGraph.h" #include "souper/Parser/Parser.h" #include "souper/Tool/GetSolver.h" @@ -36,6 +37,15 @@ static llvm::cl::opt SymbolizeConstant("symbolize", "(default=false)"), llvm::cl::init(false)); +static llvm::cl::opt SymbolizeNumInsts("symbolize-num-insts", + llvm::cl::desc("Number of instructions to synthesize" + "(default=1)"), + llvm::cl::init(1)); + +static llvm::cl::opt SymbolizeNoDFP("symbolize-no-dataflow", + llvm::cl::desc("Do not generate optimizations with dataflow preconditions."), + llvm::cl::init(false)); + static llvm::cl::opt FixIt("fixit", llvm::cl::desc("Given an invalid optimization, generate a valid one." "(default=false)"), @@ -64,21 +74,9 @@ void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { } } -void SymbolizeAndGeneralize(InstContext &IC, - Solver *S, ParsedReplacement Input) { - std::vector LHSConsts, RHSConsts; - auto Pred = [](Inst *I) {return I->K == Inst::Const;}; - findInsts(Input.Mapping.LHS, LHSConsts, Pred); - findInsts(Input.Mapping.RHS, RHSConsts, Pred); - - if (RHSConsts.size() != 1) { - return; - // TODO: Relax this restriction later - } - - // Replace LHSConst[0] with a new variable and RHSConst[0] - // with a synthesized function. - +void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, + std::vector LHSConsts, + std::vector RHSConsts) { std::map InstCache; std::vector FakeConsts; for (size_t i = 0; i < LHSConsts.size(); ++i) { @@ -90,26 +88,9 @@ void SymbolizeAndGeneralize(InstContext &IC, // Does it makes sense for the expression to depend on other variables? // If yes, expand the third argument to include inputs EnumerativeSynthesis ES; - auto Guesses = ES.generateExprs(IC, 1, FakeConsts, + auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, FakeConsts, RHSConsts[0]->Width); - // Discarding guesses with symbolic constants - // Find a way to avoid this - // Here is the problem that needs to be solved for this: - // Given f and g\C, find N and P such that P -> (f == c\N) - // Weakest possible P is desirable. - - std::vector Filtered; - for (auto Guess : Guesses) { - std::set ConstSet; - std::map ResultConstMap; - souper::getConstants(Guess, ConstSet); - if (ConstSet.empty()) { - Filtered.push_back(Guess); - } - } - std::swap(Guesses, Filtered); - std::vector>> Preconditions; @@ -117,12 +98,51 @@ void SymbolizeAndGeneralize(InstContext &IC, std::map ConstMap; auto LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, false); + + std::vector WithoutConsts; + + for (auto &Guess : Guesses) { + std::set ConstSet; + std::map ResultConstMap; + souper::getConstants(Guess, ConstSet); + if (!ConstSet.empty()) { + std::map InstCacheCopy = InstCache; + InstCacheCopy[RHSConsts[0]] = Guess; + auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, + BlockCache, &ConstMap, false); + ConstantSynthesis CS; + auto SMTSolver = GetUnderlyingSolver(); + auto EC = CS.synthesize(SMTSolver.get(), Input.BPCs, Input.PCs, + InstMapping (LHS, RHS), ConstSet, + ResultConstMap, IC, /*MaxTries=*/30, 10, + /*AvoidNops=*/true); + if (!ResultConstMap.empty()) { + std::map InstCache; + std::map BlockCache; + RHS = getInstCopy(RHS, IC, InstCache, BlockCache, &ResultConstMap, false); + ReplacementContext RC; + auto LHSStr = RC.printInst(LHS, llvm::outs(), true); + llvm::outs() << "infer " << LHSStr << "\n"; + auto RHSStr = RC.printInst(RHS, llvm::outs(), true); + llvm::outs() << "result " << RHSStr << "\n\n"; + } else { + if (DebugLevel > 2) { + llvm::errs() << "Costant Synthesis ((no Dataflow Preconditions)) failed. \n"; + } + } + } else { + WithoutConsts.push_back(Guess); + } + } + std::swap(WithoutConsts, Guesses); + return; for (auto &Guess : Guesses) { std::map InstCacheCopy = InstCache; InstCacheCopy[RHSConsts[0]] = Guess; auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, BlockCache, &ConstMap, false); + std::vector> Results; bool FoundWP = false; InstMapping Mapping(LHS, RHS); @@ -168,6 +188,9 @@ void SymbolizeAndGeneralize(InstContext &IC, auto RHSStr = RC.printInst(Guesses[Idx[i]], llvm::outs(), true); llvm::outs() << "result " << RHSStr << "\n\n"; } + if (SymbolizeNoDFP) { + continue; // Do not print results with dataflow preconditions + } for (auto Results : Preconditions[Idx[i]]) { for (auto Pair : Results) { Pair.first->KnownOnes = Pair.second.One; @@ -182,6 +205,33 @@ void SymbolizeAndGeneralize(InstContext &IC, } } +void SymbolizeAndGeneralize(InstContext &IC, + Solver *S, ParsedReplacement Input) { + std::vector LHSConsts, RHSConsts; + auto Pred = [](Inst *I) {return I->K == Inst::Const;}; + findInsts(Input.Mapping.LHS, LHSConsts, Pred); + findInsts(Input.Mapping.RHS, RHSConsts, Pred); + + // Find RHS Consts not in LHS + std::vector RHSNewConsts; + for (auto Var : RHSConsts) { + if (std::find(LHSConsts.begin(), + LHSConsts.end(), Var) == LHSConsts.end()) { + RHSNewConsts.push_back(Var); + } + } + std::swap(RHSConsts, RHSNewConsts); + + // One at a time + for (auto LHSConst : LHSConsts) { + SymbolizeAndGeneralize(IC, S, Input, {LHSConst}, RHSConsts); + } + // TODO: Two at a time, etc. Is this replaceable by DFP? + + // All at once + SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts); +} + // TODO: Return modified instructions instead of just printing out void RemoveLeafAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input) { From 0b4d2a1ef29040fd44f3a920c26dfc89f536eb54 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 7 Jan 2021 16:14:46 -0700 Subject: [PATCH 005/165] temp commit --- CMakeLists.txt | 2 +- lib/Infer/Preconditions.cpp | 16 +++++++++------- tools/generalize.cpp | 14 ++------------ 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 52aa752e0..3e33a26a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ endif() if (NOT LLVM_BUILD_TYPE) set(LLVM_BUILD_TYPE ${CMAKE_BUILD_TYPE}) endif() -set(LLVM_CONFIG_EXECUTABLE ${CMAKE_SOURCE_DIR}/third_party/llvm-${LLVM_BUILD_TYPE}-install/bin/llvm-config) +set(LLVM_CONFIG_EXECUTABLE ${CMAKE_SOURCE_DIR}/third_party/llvm-Release-install/bin/llvm-config) if(NOT EXISTS ${LLVM_CONFIG_EXECUTABLE}) message(FATAL_ERROR "llvm-config could not be found!") endif() diff --git a/lib/Infer/Preconditions.cpp b/lib/Infer/Preconditions.cpp index e5118342e..38d855200 100644 --- a/lib/Infer/Preconditions.cpp +++ b/lib/Infer/Preconditions.cpp @@ -41,13 +41,13 @@ std::vector> findVars(Mapping.LHS, Vars); std::set FilteredVars; - for (auto Var : Vars) { - std::string NamePrefix = Var->Name; - NamePrefix.resize(4); - if (!FixItNoVar || Var->K != Inst::Var || NamePrefix == "fake") { - FilteredVars.insert(Var); - } + for (auto Var : Vars) { + std::string NamePrefix = Var->Name; + NamePrefix.resize(4); + if (!FixItNoVar || Var->K != Inst::Var || NamePrefix == "fake") { + FilteredVars.insert(Var); } + } std::map OriginalState; @@ -137,7 +137,9 @@ std::vector> } } else { if (Results.empty()) { - llvm::outs() << "Transformation is not valid for any input.\n"; + if (DebugLevel >= 3) { + llvm::outs() << "Transformation is not valid for any input.\n"; + } return {}; } else { FoundWeakest = true; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index ef51d3528..c21a6c56e 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -135,7 +135,7 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, } } std::swap(WithoutConsts, Guesses); - return; + for (auto &Guess : Guesses) { std::map InstCacheCopy = InstCache; InstCacheCopy[RHSConsts[0]] = Guess; @@ -181,7 +181,7 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, return Utility[a] > Utility[b]; }); for (size_t i = 0; i < std::min(Idx.size(), NumResults.getValue()); ++i) { - if (Preconditions[Idx[i]].empty()) { + if (Preconditions[Idx[i]].empty() && Guesses[Idx[i]]) { ReplacementContext RC; auto LHSStr = RC.printInst(LHS, llvm::outs(), true); llvm::outs() << "infer " << LHSStr << "\n"; @@ -212,16 +212,6 @@ void SymbolizeAndGeneralize(InstContext &IC, findInsts(Input.Mapping.LHS, LHSConsts, Pred); findInsts(Input.Mapping.RHS, RHSConsts, Pred); - // Find RHS Consts not in LHS - std::vector RHSNewConsts; - for (auto Var : RHSConsts) { - if (std::find(LHSConsts.begin(), - LHSConsts.end(), Var) == LHSConsts.end()) { - RHSNewConsts.push_back(Var); - } - } - std::swap(RHSConsts, RHSNewConsts); - // One at a time for (auto LHSConst : LHSConsts) { SymbolizeAndGeneralize(IC, S, Input, {LHSConst}, RHSConsts); From 25fe3f18d3228a3e9f6cf63003e5fce2b7ee9ad5 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 7 Jan 2021 18:43:42 -0700 Subject: [PATCH 006/165] temp commit --- tools/generalize.cpp | 54 +++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index c21a6c56e..826906995 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -76,7 +76,8 @@ void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::vector LHSConsts, - std::vector RHSConsts) { + std::vector RHSConsts, + CandidateMap &Results) { std::map InstCache; std::vector FakeConsts; for (size_t i = 0; i < LHSConsts.size(); ++i) { @@ -120,11 +121,9 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::map InstCache; std::map BlockCache; RHS = getInstCopy(RHS, IC, InstCache, BlockCache, &ResultConstMap, false); - ReplacementContext RC; - auto LHSStr = RC.printInst(LHS, llvm::outs(), true); - llvm::outs() << "infer " << LHSStr << "\n"; - auto RHSStr = RC.printInst(RHS, llvm::outs(), true); - llvm::outs() << "result " << RHSStr << "\n\n"; + + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHS, RHS))); + } else { if (DebugLevel > 2) { llvm::errs() << "Costant Synthesis ((no Dataflow Preconditions)) failed. \n"; @@ -180,27 +179,22 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::sort(Idx.begin(), Idx.end(), [&Utility](size_t a, size_t b) { return Utility[a] > Utility[b]; }); - for (size_t i = 0; i < std::min(Idx.size(), NumResults.getValue()); ++i) { + + for (size_t i = 0; i < Idx.size(); ++i) { if (Preconditions[Idx[i]].empty() && Guesses[Idx[i]]) { - ReplacementContext RC; - auto LHSStr = RC.printInst(LHS, llvm::outs(), true); - llvm::outs() << "infer " << LHSStr << "\n"; - auto RHSStr = RC.printInst(Guesses[Idx[i]], llvm::outs(), true); - llvm::outs() << "result " << RHSStr << "\n\n"; + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHS, Guesses[Idx[i]]))); } - if (SymbolizeNoDFP) { - continue; // Do not print results with dataflow preconditions - } - for (auto Results : Preconditions[Idx[i]]) { - for (auto Pair : Results) { - Pair.first->KnownOnes = Pair.second.One; - Pair.first->KnownZeros = Pair.second.Zero; + } + + if (!SymbolizeNoDFP) { + for (size_t i = 0; i < std::min(Idx.size(), NumResults.getValue()); ++i) { + for (auto Computed : Preconditions[Idx[i]]) { + for (auto Pair : Computed) { + Pair.first->KnownOnes = Pair.second.One; + Pair.first->KnownZeros = Pair.second.Zero; + } + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHS, Guesses[Idx[i]]))); } - ReplacementContext RC; - auto LHSStr = RC.printInst(LHS, llvm::outs(), true); - llvm::outs() << "infer " << LHSStr << "\n"; - auto RHSStr = RC.printInst(Guesses[Idx[i]], llvm::outs(), true); - llvm::outs() << "result " << RHSStr << "\n\n"; } } } @@ -212,14 +206,22 @@ void SymbolizeAndGeneralize(InstContext &IC, findInsts(Input.Mapping.LHS, LHSConsts, Pred); findInsts(Input.Mapping.RHS, RHSConsts, Pred); + CandidateMap Results; + // One at a time for (auto LHSConst : LHSConsts) { - SymbolizeAndGeneralize(IC, S, Input, {LHSConst}, RHSConsts); + SymbolizeAndGeneralize(IC, S, Input, {LHSConst}, RHSConsts, Results); } // TODO: Two at a time, etc. Is this replaceable by DFP? // All at once - SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts); + SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); + + // TODO: Move sorting here + for (auto &&Result : Results) { + Result.print(llvm::outs(), true); + llvm::outs() << "\n"; + } } // TODO: Return modified instructions instead of just printing out From 8b3aea420f8d68c5b0d76bb2c2ec04f01ab5e359 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 13 Jan 2021 11:29:38 -0700 Subject: [PATCH 007/165] temp --- lib/Infer/Preconditions.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/Infer/Preconditions.cpp b/lib/Infer/Preconditions.cpp index 38d855200..991f1d96a 100644 --- a/lib/Infer/Preconditions.cpp +++ b/lib/Infer/Preconditions.cpp @@ -87,25 +87,35 @@ std::vector> V->KnownOnes = OriginalState[V].OriginalOne; V->KnownZeros = OriginalState[V].OriginalZero; } - + Inst *NewPre = nullptr; for (size_t i = 0; i < Vars.size(); ++i) { auto &I = Vars[i]; auto W = I->Width; - auto Zero = SC.IC.getConst(llvm::APInt(W, 0)); +// auto Zero = SC.IC.getConst(llvm::APInt(W, 0)); auto AllOnes = SC.IC.getConst(llvm::APInt::getAllOnesValue(W)); - auto A = SC.IC.getInst(Inst::And, W, {I, SC.IC.getConst(KB[I].One)}); + auto KnownOne = SC.IC.getConst(KB[I].One); + auto KnownZero = SC.IC.getConst(KB[I].Zero); + auto A = SC.IC.getInst(Inst::And, W, {I, KnownOne}); auto B = SC.IC.getInst(Inst::And, W, {SC.IC.getInst(Inst::Xor, W, {I, AllOnes}), - SC.IC.getConst(KB[I].Zero)}); + KnownZero}); - auto New = SC.IC.getInst(Inst::And, 1, - {SC.IC.getInst(Inst::Eq, 1, {A, Zero}), - SC.IC.getInst(Inst::Eq, 1, {B, Zero})}); + auto VarConstraint = SC.IC.getInst(Inst::Or, 1, + {SC.IC.getInst(Inst::Ne, 1, {A, KnownOne}), + SC.IC.getInst(Inst::Ne, 1, {B, KnownZero})}); - // Do not find an input belonging to a derived abstract set. - Precondition = SC.IC.getInst(Inst::And, 1, {Precondition, New}); + if (NewPre) { + NewPre = SC.IC.getInst(Inst::Or, 1, {NewPre, VarConstraint}); + } else { + NewPre = VarConstraint; + } + + } + // Do not find an input belonging to a derived abstract set. + if (NewPre) { + Precondition = SC.IC.getInst(Inst::And, 1, {Precondition, NewPre}); } } From ab9a314a6a078a75639e1a2d775a475ee56f1965 Mon Sep 17 00:00:00 2001 From: Martin Monperrus Date: Wed, 28 Apr 2021 18:02:59 +0000 Subject: [PATCH 008/165] doc: add link to arxiv paper (#811) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ef7743c95..261ac3b06 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ Souper is a superoptimizer for LLVM IR. It uses an SMT solver to help identify missing peephole optimizations in LLVM's midend optimizers. +The architecture and concepts of Souper are described in [Souper: A synthesizing superoptimizer](https://arxiv.org/pdf/1711.04422.pdf). + # Requirements Souper should work on any reasonably modern Linux or OS X machine. From 934244831211dde570d05c1c1dda55c264df68dc Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 28 Apr 2021 11:03:24 -0700 Subject: [PATCH 009/165] Misc fixes to make Souper work better with SPEC 2017 (#813) --- build_deps.sh | 2 +- include/souper/Inst/Inst.h | 2 +- lib/Infer/EnumerativeSynthesis.cpp | 4 ++-- lib/Inst/Inst.cpp | 12 ++++++++---- lib/Pass/Pass.cpp | 21 ++++++++++++++++++++- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/build_deps.sh b/build_deps.sh index efec652ec..bbbaed4ed 100755 --- a/build_deps.sh +++ b/build_deps.sh @@ -75,7 +75,7 @@ mkdir -p $llvm_srcdir mkdir -p $llvm_builddir -cmake_flags="-DCMAKE_INSTALL_PREFIX=$llvm_installdir -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_FORCE_ENABLE_STATS=ON -DCMAKE_BUILD_TYPE=$llvm_build_type -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_ENABLE_PROJECTS=\'llvm;clang;compiler-rt\'" +cmake_flags="-DCMAKE_INSTALL_PREFIX=$llvm_installdir -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_FORCE_ENABLE_STATS=ON -DCMAKE_BUILD_TYPE=$llvm_build_type -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_ENABLE_PROJECTS=\'llvm;clang;openmp;compiler-rt\'" if [ -n "`which ninja`" ] ; then (cd $llvm_builddir && cmake ${llvm_srcdir}/llvm -G Ninja $cmake_flags -DCMAKE_CXX_FLAGS="-DDISABLE_WRONG_OPTIMIZATIONS_DEFAULT_VALUE=true -DDISABLE_PEEPHOLES_DEFAULT_VALUE=false" "$@") diff --git a/include/souper/Inst/Inst.h b/include/souper/Inst/Inst.h index b854c570d..7c268677c 100644 --- a/include/souper/Inst/Inst.h +++ b/include/souper/Inst/Inst.h @@ -315,7 +315,7 @@ Inst *getInstCopy(Inst *I, InstContext &IC, std::map &InstCache, std::map &BlockCache, std::map *ConstMap, - bool CloneVars); + bool CloneVars, bool CloneBlocks = true); Inst *instJoin(Inst *I, Inst *Reserved, Inst *NewInst, std::map &InstCache, InstContext &IC); diff --git a/lib/Infer/EnumerativeSynthesis.cpp b/lib/Infer/EnumerativeSynthesis.cpp index 4ee94d45f..4d9d9f67b 100644 --- a/lib/Infer/EnumerativeSynthesis.cpp +++ b/lib/Infer/EnumerativeSynthesis.cpp @@ -725,7 +725,7 @@ std::error_code synthesizeWithKLEE(SynthesisContext &SC, std::vector &RH if (!ResultConstMap.empty()) { std::map InstCache; std::map BlockCache; - RHS = getInstCopy(I, SC.IC, InstCache, BlockCache, &ResultConstMap, false); + RHS = getInstCopy(I, SC.IC, InstCache, BlockCache, &ResultConstMap, false, false); } else { continue; } @@ -761,7 +761,7 @@ std::error_code synthesizeWithKLEE(SynthesisContext &SC, std::vector &RH } std::map InstCache; std::map BlockCache; - auto newRHS = getInstCopy(I, SC.IC, InstCache, BlockCache, &ZeroConstMap, false); + auto newRHS = getInstCopy(I, SC.IC, InstCache, BlockCache, &ZeroConstMap, false, false); if (isTransformationValid(SC.LHS, newRHS, SC.PCs, SC.BPCs, SC.IC)) RHS = newRHS; } diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index 5ee10945d..7d4316edd 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -1172,7 +1172,7 @@ Inst *souper::getInstCopy(Inst *I, InstContext &IC, std::map &InstCache, std::map &BlockCache, std::map *ConstMap, - bool CloneVars) { + bool CloneVars, bool CloneBlocks) { if (InstCache.count(I)) return InstCache.at(I); @@ -1209,9 +1209,13 @@ Inst *souper::getInstCopy(Inst *I, InstContext &IC, } } else if (I->K == Inst::Phi) { if (!BlockCache.count(I->B)) { - auto BlockCopy = IC.createBlock(I->B->Preds); - BlockCache[I->B] = BlockCopy; - Copy = IC.getPhi(BlockCopy, Ops, I->DemandedBits); + if (CloneBlocks) { + auto BlockCopy = IC.createBlock(I->B->Preds); + BlockCache[I->B] = BlockCopy; + Copy = IC.getPhi(BlockCopy, Ops, I->DemandedBits); + } else { + Copy = IC.getPhi(I->B, Ops, I->DemandedBits); + } } else { Copy = IC.getPhi(BlockCache.at(I->B), Ops, I->DemandedBits); } diff --git a/lib/Pass/Pass.cpp b/lib/Pass/Pass.cpp index 997f5299e..121a0bbfa 100644 --- a/lib/Pass/Pass.cpp +++ b/lib/Pass/Pass.cpp @@ -18,8 +18,10 @@ #include "llvm/Analysis/DemandedBits.h" #include "llvm/Analysis/LazyValueInfo.h" #include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/CodeGen/UnreachableBlockElim.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" @@ -33,6 +35,7 @@ #include "llvm/IR/Verifier.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Scalar/ADCE.h" #include "llvm/Transforms/Scalar/DCE.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -233,6 +236,17 @@ struct SouperPass : public ModulePass { if (!TLI) report_fatal_error("getTLI() failed"); + // Run UnreachableBlockElim and ADCE locally + // TODO: In the long run, switch this tool to the new pass manager. + FunctionPassManager FM; + FunctionAnalysisManager FAM; + FAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + FAM.registerPass([&] { return DominatorTreeAnalysis(); }); + FAM.registerPass([&] { return PostDominatorTreeAnalysis(); }); + FM.addPass(UnreachableBlockElimPass()); + FM.addPass(ADCEPass()); + FM.run(*F, FAM); + FunctionCandidateSet CS = ExtractCandidatesFromPass(F, LI, DB, LVI, SE, TLI, IC, EBC); if (DebugLevel > 3) @@ -277,7 +291,12 @@ struct SouperPass : public ModulePass { EC == std::errc::value_too_large) { continue; } else { - report_fatal_error("Unable to query solver: " + EC.message() + "\n"); + llvm::errs() << "[FIXME: Crash commented out]\nUnable to query solver: " + EC.message() + "\n"; + continue; + // TODO: This is a temporary workaround to suppress a protocol error which is encountered + // once in SPEC 2017. This workaround does not have a negative effect other than maybe + // missing one potential transformation. + //report_fatal_error("Unable to query solver: " + EC.message() + "\n"); } } if (RHSs.empty()) From 30806dd344f310d6a2fbe32e1b5a2cceb0c2f31d Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sat, 1 May 2021 18:55:59 -0700 Subject: [PATCH 010/165] Keep up with alive2 API (#814) --- CMakeLists.txt | 35 +++++++++-- build_deps.sh | 2 +- lib/Infer/AliveDriver.cpp | 118 ++++++++------------------------------ 3 files changed, 54 insertions(+), 101 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e33a26a2..e7a6c6bce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,10 +84,10 @@ set(GTEST_CXXFLAGS "-DGTEST_HAS_RTTI=0") set(GTEST_INCLUDEDIR "${LLVM_SRC}/utils/unittest/googletest/include") set(GTEST_LIBS "-lgtest_main -lgtest") -set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS} -std=c++17") +set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS} -std=c++20") if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++17") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++20") set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS} -fvisibility-inlines-hidden") set(PASS_LDFLAGS "-Wl,-undefined,dynamic_lookup") endif() @@ -129,11 +129,32 @@ find_library(HIREDIS_LIBRARY third_party/hiredis-install/lib NO_DEFAULT_PATH) -find_library(ALIVE_LIBRARY alive2 PATHS "${ALIVE_BUILDDIR}" NO_DEFAULT_PATH) -if (ALIVE_LIBRARY) - message(STATUS "Alive2: ${ALIVE_LIBRARY}") +find_library(ALIVE_IR ir PATHS "${ALIVE_BUILDDIR}" NO_DEFAULT_PATH) +if (ALIVE_IR) + message(STATUS "Alive2 IR") else() - message(SEND_ERROR "Alive2 not found") + message(SEND_ERROR "Alive2 libir.a not found") +endif() + +find_library(ALIVE_SMT smt PATHS "${ALIVE_BUILDDIR}" NO_DEFAULT_PATH) +if (ALIVE_SMT) + message(STATUS "Alive2 SMT") +else() + message(SEND_ERROR "Alive2 libsmt.a not found") +endif() + +find_library(ALIVE_TOOLS tools PATHS "${ALIVE_BUILDDIR}" NO_DEFAULT_PATH) +if (ALIVE_TOOLS) + message(STATUS "Alive2 TOOLS") +else() + message(SEND_ERROR "Alive2 libtools.a not found") +endif() + +find_library(ALIVE_UTIL util PATHS "${ALIVE_BUILDDIR}" NO_DEFAULT_PATH) +if (ALIVE_UTIL) + message(STATUS "Alive2 UTIL") +else() + message(SEND_ERROR "Alive2 libutil.a not found") endif() set(Z3 "${CMAKE_SOURCE_DIR}/third_party/z3-install/bin/z3") @@ -147,6 +168,8 @@ else() message(SEND_ERROR "Z3 shared lib not found") endif() +set(ALIVE_LIBRARY ${ALIVE_IR} ${ALIVE_SMT} ${ALIVE_TOOLS} ${ALIVE_UTIL} ${Z3_LIBRARY}) + set(SOUPER_CLANG_TOOL_FILES lib/ClangTool/Actions.cpp include/souper/ClangTool/Actions.h diff --git a/build_deps.sh b/build_deps.sh index bbbaed4ed..e8b3826a0 100755 --- a/build_deps.sh +++ b/build_deps.sh @@ -28,7 +28,7 @@ llvm_repo=https://github.com/regehr/llvm-project.git llvm_commit=disable-peepholes-v04 klee_repo=https://github.com/rsas/klee klee_branch=pure-bv-qf-llvm-7.0 -alive_commit=v1 +alive_commit=v2 alive_repo=https://github.com/manasij7479/alive2.git z3_repo=https://github.com/Z3Prover/z3.git z3_commit=z3-4.8.9 diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index f4a360e0f..7001df8ba 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -238,7 +238,7 @@ performCegisFirstQuery(tools::Transform &t, std::set Vars; std::map SMTConsts; - for (auto &[Var, Val, Pred] : TgtState.getValues()) { + for (auto &[Var, Val] : TgtState.getValues()) { auto &Name = Var->getName(); if (startsWith("%reservedconst", Name)) { SMTConsts[Name] = Val.first.value; @@ -248,107 +248,37 @@ performCegisFirstQuery(tools::Transform &t, if (SkipAliveSolver) return SynthesisResult; - // TODO: implement synthesis with refinement - smt::Solver::check({{(Sv.first.value == Tv.first.value) && (TriedExpr), - [&](const smt::Result &R) { - - // no more guesses, stop immediately - if (R.isUnsat()) { - if (DebugLevel > 3) - llvm::errs()<<"No more new possible guesses\n"; - return; - } else if (R.isSat()) { - auto &&Model = R.getModel(); - smt::expr TriedAnte(false); - - for (auto &[name, expr] : SMTConsts) { - TriedAnte |= (expr != smt::expr::mkUInt(Model.getInt(expr), expr.bits())); - } - TriedExpr &= TriedAnte; - - for (auto &[name, expr] : SMTConsts) { - auto *I = SouperConsts[name]; - SynthesisResult[I] = llvm::APInt(I->Width, Model.getInt(expr)); - } - } - }}}); + auto R = smt::check_expr((Sv.first.value == Tv.first.value) && (TriedExpr)); + // no more guesses, stop immediately + if (R.isUnsat()) { + if (DebugLevel > 3) + llvm::errs()<<"No more new possible guesses\n"; + return {}; + } else if (R.isSat()) { + auto &&Model = R.getModel(); + smt::expr TriedAnte(false); + + for (auto &[name, expr] : SMTConsts) { + TriedAnte |= (expr != smt::expr::mkUInt(Model.getInt(expr), expr.bits())); + } + TriedExpr &= TriedAnte; + for (auto &[name, expr] : SMTConsts) { + auto *I = SouperConsts[name]; + SynthesisResult[I] = llvm::APInt(I->Width, Model.getInt(expr)); + } + } return SynthesisResult; } std::map synthesizeConstantUsingSolver(tools::Transform &t, std::map &SouperConsts) { + // Removed because implementation was bit-rotting. + // The combination of the options requiring this is + // not currently used. + llvm::errs() << "Direct solver based constant synthesis through alive unimplemented."; return {}; - - IR::State SrcState(t.src, true), tgt_state(t.tgt, false); - util::sym_exec(SrcState); - util::sym_exec(tgt_state); - - util::Errors Errs; - - auto &&SrcRet = SrcState.returnVal(); - auto &&TgtRet = tgt_state.returnVal(); - - auto QVars = SrcState.getQuantVars(); - QVars.insert(SrcRet.second.begin(), SrcRet.second.end()); - - auto ErrF = [&](const smt::Result &r, bool print_var, const char *msg) { -// tools::error(Errs, SrcState, tgt_state, r, print_var, nullptr, -// SrcRet.first, TgtRet.first, msg,false); - //FIXME: temporarily disabled, find a way to pass a Type to tools::error - std::cerr << msg << "\n"; - tools::TransformPrintOpts Opts; - Opts.print_fn_header = true; - t.print(std::cerr, Opts); - }; - - std::set Vars; - std::map SMTConsts; - - for (auto &[var, val, Pred] : SrcState.getValues()) { - auto &name = var->getName(); - if (startsWith("%var", name)) { - auto app = val.first.value.isApp(); - assert(app); - Vars.insert(Z3_get_app_arg(smt::ctx(), app, 1)); - } - } - for (auto &[var, val, Pred] : tgt_state.getValues()) { - auto &name = var->getName(); - if (startsWith("%reserved", name)) { - auto app = val.first.value.isApp(); - assert(app); - SMTConsts[name] = (Z3_get_app_arg(smt::ctx(), app, 1)); - } - } - - auto SimpleConstExistsCheck = - smt::expr::mkForAll(Vars, SrcRet.first.value == TgtRet.first.value); - - std::map SynthesisResult; - - if (SkipAliveSolver) - return SynthesisResult; - - smt::Solver::check({{preprocess(t, QVars, SrcRet.second, - std::move(SimpleConstExistsCheck)), - [&] (const smt::Result &R) { - if (R.isUnsat()) { - ErrF(R, true, "Value mismatch"); - } else if (R.isSat()) { - auto &&Model = R.getModel(); - for (auto &[name, expr] : SMTConsts) { - auto *I = SouperConsts[name]; - SynthesisResult[I] = llvm::APInt(I->Width, Model.getInt(expr)); - } - return; - } else { - ErrF(R, true, "Unknown/Invalid Result, investigate."); - } - }}}); - - return SynthesisResult; } souper::AliveDriver::AliveDriver(Inst *LHS_, Inst *PreCondition_, InstContext &IC_, From 1494a8b895c3b0b2a07212a23c692806ea2369ff Mon Sep 17 00:00:00 2001 From: John Regehr Date: Sun, 2 May 2021 14:38:47 -0600 Subject: [PATCH 011/165] update to llvm 12, update to latest Z3, fixup fragile tests (#815) --- build_deps.sh | 5 +++-- docs/Doxyfile.in | 7 ------- .../{argument-order-XFAIL.opt => argument-order.opt} | 0 test/Codegen/inst-bitreverse.opt | 5 +++-- test/Codegen/inst-bswap.opt | 4 ++-- test/Codegen/inst-ctlz.opt | 4 ++-- test/Codegen/inst-ctpop.opt | 4 ++-- test/Codegen/inst-cttz.opt | 4 ++-- test/Codegen/inst-fshl.opt | 4 ++-- test/Codegen/inst-fshr.opt | 4 ++-- ...IL.opt => inst-sadd_with_overflow-extract-overflow.opt} | 4 ++-- ...l-XFAIL.opt => inst-sadd_with_overflow-extract-val.opt} | 4 ++-- ...with_overflow-XFAIL.opt => inst-sadd_with_overflow.opt} | 4 ++-- ...IL.opt => inst-smul_with_overflow-extract-overflow.opt} | 4 ++-- ...l-XFAIL.opt => inst-smul_with_overflow-extract-val.opt} | 5 ----- ...with_overflow-XFAIL.opt => inst-smul_with_overflow.opt} | 4 ++-- ...IL.opt => inst-ssub_with_overflow-extract-overflow.opt} | 5 ----- ...l-XFAIL.opt => inst-ssub_with_overflow-extract-val.opt} | 5 ----- ...with_overflow-XFAIL.opt => inst-ssub_with_overflow.opt} | 5 ----- ...IL.opt => inst-uadd_with_overflow-extract-overflow.opt} | 5 ----- ...l-XFAIL.opt => inst-uadd_with_overflow-extract-val.opt} | 5 ----- ...with_overflow-XFAIL.opt => inst-uadd_with_overflow.opt} | 5 ----- ...IL.opt => inst-umul_with_overflow-extract-overflow.opt} | 5 ----- ...l-XFAIL.opt => inst-umul_with_overflow-extract-val.opt} | 5 ----- ...with_overflow-XFAIL.opt => inst-umul_with_overflow.opt} | 5 ----- ...IL.opt => inst-usub_with_overflow-extract-overflow.opt} | 5 ----- ...l-XFAIL.opt => inst-usub_with_overflow-extract-val.opt} | 5 ----- ...with_overflow-XFAIL.opt => inst-usub_with_overflow.opt} | 5 ----- .../{return-named-arg-XFAIL.opt => return-named-arg.opt} | 0 29 files changed, 28 insertions(+), 98 deletions(-) rename test/Codegen/{argument-order-XFAIL.opt => argument-order.opt} (100%) rename test/Codegen/{inst-sadd_with_overflow-extract-overflow-XFAIL.opt => inst-sadd_with_overflow-extract-overflow.opt} (73%) rename test/Codegen/{inst-sadd_with_overflow-extract-val-XFAIL.opt => inst-sadd_with_overflow-extract-val.opt} (73%) rename test/Codegen/{inst-sadd_with_overflow-XFAIL.opt => inst-sadd_with_overflow.opt} (71%) rename test/Codegen/{inst-smul_with_overflow-extract-overflow-XFAIL.opt => inst-smul_with_overflow-extract-overflow.opt} (73%) rename test/Codegen/{inst-smul_with_overflow-extract-val-XFAIL.opt => inst-smul_with_overflow-extract-val.opt} (66%) rename test/Codegen/{inst-smul_with_overflow-XFAIL.opt => inst-smul_with_overflow.opt} (71%) rename test/Codegen/{inst-ssub_with_overflow-extract-overflow-XFAIL.opt => inst-ssub_with_overflow-extract-overflow.opt} (66%) rename test/Codegen/{inst-ssub_with_overflow-extract-val-XFAIL.opt => inst-ssub_with_overflow-extract-val.opt} (66%) rename test/Codegen/{inst-ssub_with_overflow-XFAIL.opt => inst-ssub_with_overflow.opt} (62%) rename test/Codegen/{inst-uadd_with_overflow-extract-overflow-XFAIL.opt => inst-uadd_with_overflow-extract-overflow.opt} (66%) rename test/Codegen/{inst-uadd_with_overflow-extract-val-XFAIL.opt => inst-uadd_with_overflow-extract-val.opt} (66%) rename test/Codegen/{inst-uadd_with_overflow-XFAIL.opt => inst-uadd_with_overflow.opt} (62%) rename test/Codegen/{inst-umul_with_overflow-extract-overflow-XFAIL.opt => inst-umul_with_overflow-extract-overflow.opt} (66%) rename test/Codegen/{inst-umul_with_overflow-extract-val-XFAIL.opt => inst-umul_with_overflow-extract-val.opt} (66%) rename test/Codegen/{inst-umul_with_overflow-XFAIL.opt => inst-umul_with_overflow.opt} (62%) rename test/Codegen/{inst-usub_with_overflow-extract-overflow-XFAIL.opt => inst-usub_with_overflow-extract-overflow.opt} (66%) rename test/Codegen/{inst-usub_with_overflow-extract-val-XFAIL.opt => inst-usub_with_overflow-extract-val.opt} (66%) rename test/Codegen/{inst-usub_with_overflow-XFAIL.opt => inst-usub_with_overflow.opt} (62%) rename test/Codegen/{return-named-arg-XFAIL.opt => return-named-arg.opt} (100%) diff --git a/build_deps.sh b/build_deps.sh index e8b3826a0..74705e3a3 100755 --- a/build_deps.sh +++ b/build_deps.sh @@ -25,13 +25,14 @@ ncpus=$(command nproc 2>/dev/null || command sysctl -n hw.ncpu 2>/dev/null || ec hiredis_commit=685030652cd98c5414ce554ff5b356dfe8437870 llvm_repo=https://github.com/regehr/llvm-project.git # llvm_commit specifies the git branch or hash to checkout to -llvm_commit=disable-peepholes-v04 +llvm_commit=disable-peepholes-v05 klee_repo=https://github.com/rsas/klee klee_branch=pure-bv-qf-llvm-7.0 alive_commit=v2 alive_repo=https://github.com/manasij7479/alive2.git z3_repo=https://github.com/Z3Prover/z3.git -z3_commit=z3-4.8.9 +#z3_commit=z3-4.8.10 +z3_commit=323e0e62705d31edc0ce06c6b4378c45c6b6184d llvm_build_type=Release if [ -n "$1" ] ; then diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 7ad3b1d6c..7ba7f5095 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -1119,13 +1119,6 @@ VERBATIM_HEADERS = YES ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored diff --git a/test/Codegen/argument-order-XFAIL.opt b/test/Codegen/argument-order.opt similarity index 100% rename from test/Codegen/argument-order-XFAIL.opt rename to test/Codegen/argument-order.opt diff --git a/test/Codegen/inst-bitreverse.opt b/test/Codegen/inst-bitreverse.opt index 71e2387ed..8ab07c0e1 100644 --- a/test/Codegen/inst-bitreverse.opt +++ b/test/Codegen/inst-bitreverse.opt @@ -10,7 +10,8 @@ result %1 ; CHECK-NEXT: ret i8 %1 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn ; CHECK-NEXT: declare i8 @llvm.bitreverse.i8(i8) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } + diff --git a/test/Codegen/inst-bswap.opt b/test/Codegen/inst-bswap.opt index 23d6dbc76..4446a6482 100644 --- a/test/Codegen/inst-bswap.opt +++ b/test/Codegen/inst-bswap.opt @@ -10,7 +10,7 @@ result %1 ; CHECK-NEXT: ret i16 %1 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn ; CHECK-NEXT: declare i16 @llvm.bswap.i16(i16) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; CHECK: attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-ctlz.opt b/test/Codegen/inst-ctlz.opt index fbef3443b..91009c007 100644 --- a/test/Codegen/inst-ctlz.opt +++ b/test/Codegen/inst-ctlz.opt @@ -10,7 +10,7 @@ result %1 ; CHECK-NEXT: ret i8 %1 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn ; CHECK-NEXT: declare i8 @llvm.ctlz.i8(i8, i1 immarg) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; CHECK: attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-ctpop.opt b/test/Codegen/inst-ctpop.opt index 221a0a138..a4b1fabac 100644 --- a/test/Codegen/inst-ctpop.opt +++ b/test/Codegen/inst-ctpop.opt @@ -10,7 +10,7 @@ result %1 ; CHECK-NEXT: ret i8 %1 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn ; CHECK-NEXT: declare i8 @llvm.ctpop.i8(i8) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; CHECK: attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-cttz.opt b/test/Codegen/inst-cttz.opt index e10fd102a..29c02bed7 100644 --- a/test/Codegen/inst-cttz.opt +++ b/test/Codegen/inst-cttz.opt @@ -10,7 +10,7 @@ result %1 ; CHECK-NEXT: ret i8 %1 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn ; CHECK-NEXT: declare i8 @llvm.cttz.i8(i8, i1 immarg) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; CHECK: attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-fshl.opt b/test/Codegen/inst-fshl.opt index c68e4247c..7c7932a30 100644 --- a/test/Codegen/inst-fshl.opt +++ b/test/Codegen/inst-fshl.opt @@ -12,7 +12,7 @@ result %3 ; CHECK-NEXT: ret i8 %3 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn ; CHECK-NEXT: declare i8 @llvm.fshl.i8(i8, i8, i8) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; CHECK: attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-fshr.opt b/test/Codegen/inst-fshr.opt index e1b718c62..795d869c0 100644 --- a/test/Codegen/inst-fshr.opt +++ b/test/Codegen/inst-fshr.opt @@ -12,7 +12,7 @@ result %3 ; CHECK-NEXT: ret i8 %3 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn ; CHECK-NEXT: declare i8 @llvm.fshr.i8(i8, i8, i8) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; CHECK: attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-sadd_with_overflow-extract-overflow-XFAIL.opt b/test/Codegen/inst-sadd_with_overflow-extract-overflow.opt similarity index 73% rename from test/Codegen/inst-sadd_with_overflow-extract-overflow-XFAIL.opt rename to test/Codegen/inst-sadd_with_overflow-extract-overflow.opt index 41d0855d8..8a1eb4601 100644 --- a/test/Codegen/inst-sadd_with_overflow-extract-overflow-XFAIL.opt +++ b/test/Codegen/inst-sadd_with_overflow-extract-overflow.opt @@ -14,7 +14,7 @@ result %3 ; CHECK-NEXT: ret i1 %4 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn ; CHECK-NEXT: declare { i8, i1 } @llvm.sadd.with.overflow.i8(i8, i8) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; CHECK: attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-sadd_with_overflow-extract-val-XFAIL.opt b/test/Codegen/inst-sadd_with_overflow-extract-val.opt similarity index 73% rename from test/Codegen/inst-sadd_with_overflow-extract-val-XFAIL.opt rename to test/Codegen/inst-sadd_with_overflow-extract-val.opt index 29459432a..4a71cc90b 100644 --- a/test/Codegen/inst-sadd_with_overflow-extract-val-XFAIL.opt +++ b/test/Codegen/inst-sadd_with_overflow-extract-val.opt @@ -14,7 +14,7 @@ result %3 ; CHECK-NEXT: ret i8 %4 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn ; CHECK-NEXT: declare { i8, i1 } @llvm.sadd.with.overflow.i8(i8, i8) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; CHECK: attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-sadd_with_overflow-XFAIL.opt b/test/Codegen/inst-sadd_with_overflow.opt similarity index 71% rename from test/Codegen/inst-sadd_with_overflow-XFAIL.opt rename to test/Codegen/inst-sadd_with_overflow.opt index 7b594b304..d519597a4 100644 --- a/test/Codegen/inst-sadd_with_overflow-XFAIL.opt +++ b/test/Codegen/inst-sadd_with_overflow.opt @@ -12,7 +12,7 @@ result %2 ; CHECK-NEXT: ret { i8, i1 } %3 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willretur ; CHECK-NEXT: declare { i8, i1 } @llvm.sadd.with.overflow.i8(i8, i8) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; CHECK: attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-smul_with_overflow-extract-overflow-XFAIL.opt b/test/Codegen/inst-smul_with_overflow-extract-overflow.opt similarity index 73% rename from test/Codegen/inst-smul_with_overflow-extract-overflow-XFAIL.opt rename to test/Codegen/inst-smul_with_overflow-extract-overflow.opt index c3e63ddc9..cde076cb9 100644 --- a/test/Codegen/inst-smul_with_overflow-extract-overflow-XFAIL.opt +++ b/test/Codegen/inst-smul_with_overflow-extract-overflow.opt @@ -14,7 +14,7 @@ result %3 ; CHECK-NEXT: ret i1 %4 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn ; CHECK-NEXT: declare { i8, i1 } @llvm.smul.with.overflow.i8(i8, i8) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; CHECK: attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-smul_with_overflow-extract-val-XFAIL.opt b/test/Codegen/inst-smul_with_overflow-extract-val.opt similarity index 66% rename from test/Codegen/inst-smul_with_overflow-extract-val-XFAIL.opt rename to test/Codegen/inst-smul_with_overflow-extract-val.opt index 6e64a426d..70929eddb 100644 --- a/test/Codegen/inst-smul_with_overflow-extract-val-XFAIL.opt +++ b/test/Codegen/inst-smul_with_overflow-extract-val.opt @@ -13,8 +13,3 @@ result %3 ; CHECK-NEXT: %4 = extractvalue { i8, i1 } %3, 0 ; CHECK-NEXT: ret i8 %4 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.smul.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-smul_with_overflow-XFAIL.opt b/test/Codegen/inst-smul_with_overflow.opt similarity index 71% rename from test/Codegen/inst-smul_with_overflow-XFAIL.opt rename to test/Codegen/inst-smul_with_overflow.opt index 8462dc034..5dec61884 100644 --- a/test/Codegen/inst-smul_with_overflow-XFAIL.opt +++ b/test/Codegen/inst-smul_with_overflow.opt @@ -12,7 +12,7 @@ result %2 ; CHECK-NEXT: ret { i8, i1 } %3 ; CHECK-NEXT: } -; CHECK: ; Function Attrs: nounwind readnone speculatable +; CHECK: ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn ; CHECK-NEXT: declare { i8, i1 } @llvm.smul.with.overflow.i8(i8, i8) #0 -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } +; CHECK: attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-ssub_with_overflow-extract-overflow-XFAIL.opt b/test/Codegen/inst-ssub_with_overflow-extract-overflow.opt similarity index 66% rename from test/Codegen/inst-ssub_with_overflow-extract-overflow-XFAIL.opt rename to test/Codegen/inst-ssub_with_overflow-extract-overflow.opt index 2096c817c..ba8234f8d 100644 --- a/test/Codegen/inst-ssub_with_overflow-extract-overflow-XFAIL.opt +++ b/test/Codegen/inst-ssub_with_overflow-extract-overflow.opt @@ -13,8 +13,3 @@ result %3 ; CHECK-NEXT: %4 = extractvalue { i8, i1 } %3, 1 ; CHECK-NEXT: ret i1 %4 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-ssub_with_overflow-extract-val-XFAIL.opt b/test/Codegen/inst-ssub_with_overflow-extract-val.opt similarity index 66% rename from test/Codegen/inst-ssub_with_overflow-extract-val-XFAIL.opt rename to test/Codegen/inst-ssub_with_overflow-extract-val.opt index b1d9345d7..faaef7f90 100644 --- a/test/Codegen/inst-ssub_with_overflow-extract-val-XFAIL.opt +++ b/test/Codegen/inst-ssub_with_overflow-extract-val.opt @@ -13,8 +13,3 @@ result %3 ; CHECK-NEXT: %4 = extractvalue { i8, i1 } %3, 0 ; CHECK-NEXT: ret i8 %4 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-ssub_with_overflow-XFAIL.opt b/test/Codegen/inst-ssub_with_overflow.opt similarity index 62% rename from test/Codegen/inst-ssub_with_overflow-XFAIL.opt rename to test/Codegen/inst-ssub_with_overflow.opt index 10b1432e1..dbffff03c 100644 --- a/test/Codegen/inst-ssub_with_overflow-XFAIL.opt +++ b/test/Codegen/inst-ssub_with_overflow.opt @@ -11,8 +11,3 @@ result %2 ; CHECK-NEXT: %3 = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %0, i8 %1) ; CHECK-NEXT: ret { i8, i1 } %3 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-uadd_with_overflow-extract-overflow-XFAIL.opt b/test/Codegen/inst-uadd_with_overflow-extract-overflow.opt similarity index 66% rename from test/Codegen/inst-uadd_with_overflow-extract-overflow-XFAIL.opt rename to test/Codegen/inst-uadd_with_overflow-extract-overflow.opt index f7fa211f5..8c353d122 100644 --- a/test/Codegen/inst-uadd_with_overflow-extract-overflow-XFAIL.opt +++ b/test/Codegen/inst-uadd_with_overflow-extract-overflow.opt @@ -13,8 +13,3 @@ result %3 ; CHECK-NEXT: %4 = extractvalue { i8, i1 } %3, 1 ; CHECK-NEXT: ret i1 %4 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.uadd.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-uadd_with_overflow-extract-val-XFAIL.opt b/test/Codegen/inst-uadd_with_overflow-extract-val.opt similarity index 66% rename from test/Codegen/inst-uadd_with_overflow-extract-val-XFAIL.opt rename to test/Codegen/inst-uadd_with_overflow-extract-val.opt index 3a93ca85a..5f1fec59e 100644 --- a/test/Codegen/inst-uadd_with_overflow-extract-val-XFAIL.opt +++ b/test/Codegen/inst-uadd_with_overflow-extract-val.opt @@ -13,8 +13,3 @@ result %3 ; CHECK-NEXT: %4 = extractvalue { i8, i1 } %3, 0 ; CHECK-NEXT: ret i8 %4 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.uadd.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-uadd_with_overflow-XFAIL.opt b/test/Codegen/inst-uadd_with_overflow.opt similarity index 62% rename from test/Codegen/inst-uadd_with_overflow-XFAIL.opt rename to test/Codegen/inst-uadd_with_overflow.opt index 5fcf26938..3385f136b 100644 --- a/test/Codegen/inst-uadd_with_overflow-XFAIL.opt +++ b/test/Codegen/inst-uadd_with_overflow.opt @@ -11,8 +11,3 @@ result %2 ; CHECK-NEXT: %3 = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %0, i8 %1) ; CHECK-NEXT: ret { i8, i1 } %3 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.uadd.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-umul_with_overflow-extract-overflow-XFAIL.opt b/test/Codegen/inst-umul_with_overflow-extract-overflow.opt similarity index 66% rename from test/Codegen/inst-umul_with_overflow-extract-overflow-XFAIL.opt rename to test/Codegen/inst-umul_with_overflow-extract-overflow.opt index 11ef0ded5..5855f89e9 100644 --- a/test/Codegen/inst-umul_with_overflow-extract-overflow-XFAIL.opt +++ b/test/Codegen/inst-umul_with_overflow-extract-overflow.opt @@ -13,8 +13,3 @@ result %3 ; CHECK-NEXT: %4 = extractvalue { i8, i1 } %3, 1 ; CHECK-NEXT: ret i1 %4 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.umul.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-umul_with_overflow-extract-val-XFAIL.opt b/test/Codegen/inst-umul_with_overflow-extract-val.opt similarity index 66% rename from test/Codegen/inst-umul_with_overflow-extract-val-XFAIL.opt rename to test/Codegen/inst-umul_with_overflow-extract-val.opt index 3a29ca915..c181e5d2b 100644 --- a/test/Codegen/inst-umul_with_overflow-extract-val-XFAIL.opt +++ b/test/Codegen/inst-umul_with_overflow-extract-val.opt @@ -13,8 +13,3 @@ result %3 ; CHECK-NEXT: %4 = extractvalue { i8, i1 } %3, 0 ; CHECK-NEXT: ret i8 %4 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.umul.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-umul_with_overflow-XFAIL.opt b/test/Codegen/inst-umul_with_overflow.opt similarity index 62% rename from test/Codegen/inst-umul_with_overflow-XFAIL.opt rename to test/Codegen/inst-umul_with_overflow.opt index c2502efd5..c16e22326 100644 --- a/test/Codegen/inst-umul_with_overflow-XFAIL.opt +++ b/test/Codegen/inst-umul_with_overflow.opt @@ -11,8 +11,3 @@ result %2 ; CHECK-NEXT: %3 = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %0, i8 %1) ; CHECK-NEXT: ret { i8, i1 } %3 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.umul.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-usub_with_overflow-extract-overflow-XFAIL.opt b/test/Codegen/inst-usub_with_overflow-extract-overflow.opt similarity index 66% rename from test/Codegen/inst-usub_with_overflow-extract-overflow-XFAIL.opt rename to test/Codegen/inst-usub_with_overflow-extract-overflow.opt index 3ac11e5de..f56c94012 100644 --- a/test/Codegen/inst-usub_with_overflow-extract-overflow-XFAIL.opt +++ b/test/Codegen/inst-usub_with_overflow-extract-overflow.opt @@ -13,8 +13,3 @@ result %3 ; CHECK-NEXT: %4 = extractvalue { i8, i1 } %3, 1 ; CHECK-NEXT: ret i1 %4 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.usub.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-usub_with_overflow-extract-val-XFAIL.opt b/test/Codegen/inst-usub_with_overflow-extract-val.opt similarity index 66% rename from test/Codegen/inst-usub_with_overflow-extract-val-XFAIL.opt rename to test/Codegen/inst-usub_with_overflow-extract-val.opt index 1de03c099..85e244d41 100644 --- a/test/Codegen/inst-usub_with_overflow-extract-val-XFAIL.opt +++ b/test/Codegen/inst-usub_with_overflow-extract-val.opt @@ -13,8 +13,3 @@ result %3 ; CHECK-NEXT: %4 = extractvalue { i8, i1 } %3, 0 ; CHECK-NEXT: ret i8 %4 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.usub.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/inst-usub_with_overflow-XFAIL.opt b/test/Codegen/inst-usub_with_overflow.opt similarity index 62% rename from test/Codegen/inst-usub_with_overflow-XFAIL.opt rename to test/Codegen/inst-usub_with_overflow.opt index 8da3dafd2..a4a225d28 100644 --- a/test/Codegen/inst-usub_with_overflow-XFAIL.opt +++ b/test/Codegen/inst-usub_with_overflow.opt @@ -11,8 +11,3 @@ result %2 ; CHECK-NEXT: %3 = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %0, i8 %1) ; CHECK-NEXT: ret { i8, i1 } %3 ; CHECK-NEXT: } - -; CHECK: ; Function Attrs: nounwind readnone speculatable -; CHECK-NEXT: declare { i8, i1 } @llvm.usub.with.overflow.i8(i8, i8) #0 - -; CHECK: attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/test/Codegen/return-named-arg-XFAIL.opt b/test/Codegen/return-named-arg.opt similarity index 100% rename from test/Codegen/return-named-arg-XFAIL.opt rename to test/Codegen/return-named-arg.opt From 02a10f27c46171a2ccc3492aab2e19f57c3cc96c Mon Sep 17 00:00:00 2001 From: John Regehr Date: Sun, 2 May 2021 15:03:43 -0600 Subject: [PATCH 012/165] Remove references to master (#816) * update to llvm 12, update to latest Z3, fixup fragile tests * remove references to master branch --- clone_and_test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clone_and_test.sh b/clone_and_test.sh index a2fb96f47..225b3881f 100755 --- a/clone_and_test.sh +++ b/clone_and_test.sh @@ -14,8 +14,8 @@ echo "TRAVIS_EVENT_TYPE set to push"; fi if [ -z ${TRAVIS_BRANCH} ]; then -TRAVIS_BRANCH="master"; -echo "TRAVIS_BRANCH set to master"; +TRAVIS_BRANCH="main"; +echo "TRAVIS_BRANCH set to main"; fi # check if this is a pull request or a push From 7eabcbf5a4c49c60fc23fc5601467c76afe522e9 Mon Sep 17 00:00:00 2001 From: John Regehr Date: Mon, 3 May 2021 14:43:53 -0600 Subject: [PATCH 013/165] use llvm-mca as a cost model -- this implements that, but the work is unfinished and it isn't used anywhere, still work to do (#816) --- CMakeLists.txt | 38 +++-- include/souper/Codegen/Codegen.h | 17 +++ include/souper/Inst/Inst.h | 2 + lib/Codegen/Codegen.cpp | 58 ++++++++ lib/Codegen/MachineCost.cpp | 173 +++++++++++++++++++++++ lib/Extractor/Solver.cpp | 26 +++- lib/Infer/EnumerativeSynthesis.cpp | 4 +- lib/Inst/Inst.cpp | 16 ++- test/Codegen/argument-order.opt | 6 +- test/Codegen/return-const-unused-arg.opt | 2 +- test/LLVM/clang1.c | 19 +++ test/LLVM/clang2.c | 19 +++ test/Unit/codegen_tests.ll | 1 + tools/souper2llvm.cpp | 49 +------ unittests/Codegen/CodegenTests.cpp | 55 +++++++ 15 files changed, 411 insertions(+), 74 deletions(-) create mode 100644 lib/Codegen/MachineCost.cpp create mode 100644 test/LLVM/clang1.c create mode 100644 test/LLVM/clang2.c create mode 100644 test/Unit/codegen_tests.ll create mode 100644 unittests/Codegen/CodegenTests.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e7a6c6bce..8a56f292b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,6 +262,16 @@ add_library(souperTool STATIC ${SOUPER_TOOL_FILES} ) +set(SOUPER_CODEGEN_FILES + lib/Codegen/Codegen.cpp + lib/Codegen/MachineCost.cpp + include/souper/Codegen/Codegen.h +) + +add_library(souperCodegen STATIC + ${SOUPER_CODEGEN_FILES} +) + set(SOUPER_SOURCES ${SOUPER_EXTRACTOR_FILES} ${SOUPER_INST_FILES} @@ -269,12 +279,8 @@ set(SOUPER_SOURCES ${SOUPER_PARSER_FILES} ${SOUPER_SMTLIB2_FILES} ${SOUPER_TOOL_FILES} - ${SOUPER_INFER_FILES}) - -set(SOUPER_CODEGEN_FILES - lib/Codegen/Codegen.cpp - include/souper/Codegen/Codegen.h -) + ${SOUPER_INFER_FILES} + ${SOUPER_CODEGEN_FILES}) add_library(souperPass SHARED ${KLEE_EXPR_FILES} @@ -288,10 +294,6 @@ add_library(souperPassProfileAll SHARED lib/Pass/Pass.cpp ) -add_library(souperCodegen SHARED - ${SOUPER_CODEGEN_FILES} -) - target_compile_definitions(souperPassProfileAll PRIVATE DYNAMIC_PROFILE_ALL=1) add_executable(clang-souper @@ -346,6 +348,10 @@ add_executable(parser_tests unittests/Parser/ParserTests.cpp ) +add_executable(codegen_tests + unittests/Codegen/CodegenTests.cpp +) + add_executable(interpreter_tests unittests/Interpreter/InterpreterInfra.cpp unittests/Interpreter/InterpreterTests.cpp) @@ -400,7 +406,7 @@ foreach(target souperClangTool clang-souper) set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${CLANG_CXXFLAGS} ${LLVM_CXXFLAGS}") target_include_directories(${target} PRIVATE "${LLVM_INCLUDEDIR}" ${CLANG_INCLUDEDIR}) endforeach() -foreach(target extractor_tests inst_tests parser_tests interpreter_tests bulk_tests) +foreach(target extractor_tests inst_tests parser_tests interpreter_tests bulk_tests codegen_tests) set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${GTEST_CXXFLAGS} ${LLVM_CXXFLAGS}") target_include_directories(${target} PRIVATE "${LLVM_INCLUDEDIR}" "${GTEST_INCLUDEDIR}") endforeach() @@ -408,18 +414,19 @@ endforeach() # static target_link_libraries(kleeExpr ${LLVM_LIBS} ${LLVM_LDFLAGS}) target_link_libraries(souperClangTool souperExtractor souperTool ${CLANG_LIBS} ${LLVM_LIBS} ${LLVM_LDFLAGS}) -target_link_libraries(souperExtractor souperParser souperKVStore souperInfer souperInst kleeExpr) +target_link_libraries(souperExtractor souperParser souperKVStore souperInfer souperInst kleeExpr souperCodegen) target_link_libraries(souperInfer souperExtractor ${LLVM_LIBS} ${LLVM_LDFLAGS} ${Z3_LIBRARY}) target_link_libraries(souperInst ${LLVM_LIBS} ${LLVM_LDFLAGS}) target_link_libraries(souperKVStore ${HIREDIS_LIBRARY} ${LLVM_LIBS} ${LLVM_LDFLAGS}) target_link_libraries(souperParser souperInst ${LLVM_LIBS} ${LLVM_LDFLAGS} ${ALIVE_LIBRARY}) target_link_libraries(souperSMTLIB2 ${LLVM_LIBS} ${LLVM_LDFLAGS}) target_link_libraries(souperTool souperExtractor souperSMTLIB2) +target_link_libraries(souperCodegen ${LLVM_LIBS} ${LLVM_LDFLAGS}) # dynamic target_link_libraries(souperCodegen ${PASS_LDFLAGS}) -target_link_libraries(souperPass souperCodegen ${PASS_LDFLAGS} ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) -target_link_libraries(souperPassProfileAll souperCodegen ${PASS_LDFLAGS} ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) +target_link_libraries(souperPass ${PASS_LDFLAGS} ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) +target_link_libraries(souperPassProfileAll ${PASS_LDFLAGS} ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) # executables target_link_libraries(souper souperExtractor souperKVStore souperParser souperSMTLIB2 souperTool kleeExpr ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) @@ -435,6 +442,7 @@ target_link_libraries(souper2llvm souperParser souperCodegen) target_link_libraries(extractor_tests souperExtractor souperParser ${GTEST_LIBS} ${ALIVE_LIBRARY}) target_link_libraries(inst_tests souperInfer souperPass souperInst souperExtractor ${GTEST_LIBS} ${ALIVE_LIBRARY}) target_link_libraries(parser_tests souperParser ${GTEST_LIBS} ${ALIVE_LIBRARY}) +target_link_libraries(codegen_tests souperCodegen souperInst ${GTEST_LIBS} ${ALIVE_LIBRARY}) target_link_libraries(interpreter_tests souperInfer souperInst ${GTEST_LIBS} ${ALIVE_LIBRARY}) target_link_libraries(bulk_tests souperInfer souperInst ${GTEST_LIBS} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) @@ -464,7 +472,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 souper-interpret souperPass souper2llvm souperPassProfileAll count-insts interpreter_tests bulk_tests + DEPENDS extractor_tests inst_tests parser-test parser_tests profileRuntime souper souper-check souper-interpret souperPass souper2llvm souperPassProfileAll count-insts interpreter_tests bulk_tests codegen_tests USES_TERMINAL) # we want assertions even in release mode! diff --git a/include/souper/Codegen/Codegen.h b/include/souper/Codegen/Codegen.h index ed8a88d18..b6fe6534b 100644 --- a/include/souper/Codegen/Codegen.h +++ b/include/souper/Codegen/Codegen.h @@ -16,13 +16,17 @@ #define SOUPER_CODEGEN_CODEGEN_H #include "souper/Inst/Inst.h" +#include "souper/Parser/Parser.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Value.h" +#include "llvm/IR/Verifier.h" #include +#include "llvm/Support/MemoryBuffer.h" + namespace souper { class Codegen { @@ -47,6 +51,19 @@ class Codegen { llvm::Value *getValue(Inst *I); }; +// If there are no errors, the function returns false. If an error is found, +// a message describing the error is written to OS (if non-null) and true is +// returned. +bool genModule(InstContext &IC, Inst *I, llvm::Module &Module); + +struct BackendCost { + std::vector C; +}; + +void getBackendCost(InstContext &IC, Inst *I, BackendCost &BC); + +bool compareCosts(const BackendCost &C1, const BackendCost &C2); + } // namespace souper #endif // SOUPER_CODEGEN_CODEGEN_H diff --git a/include/souper/Inst/Inst.h b/include/souper/Inst/Inst.h index 7c268677c..c64c90251 100644 --- a/include/souper/Inst/Inst.h +++ b/include/souper/Inst/Inst.h @@ -269,6 +269,7 @@ class InstContext { llvm::APInt DemandedBits, bool Available); std::vector getVariables() const; + std::vector getVariablesFor(Inst *Root) const; }; struct SynthesisContext { @@ -283,6 +284,7 @@ struct SynthesisContext { }; int cost(Inst *I, bool IgnoreDepsWithExternalUses = false); +int backendCost(Inst *I, bool IgnoreDepsWithExternalUses = false); int countHelper(Inst *I, std::set &Visited); int instCount(Inst *I); int benefit(Inst *LHS, Inst *RHS); diff --git a/lib/Codegen/Codegen.cpp b/lib/Codegen/Codegen.cpp index 75fa3e52f..de0d5622a 100644 --- a/lib/Codegen/Codegen.cpp +++ b/lib/Codegen/Codegen.cpp @@ -321,4 +321,62 @@ llvm::Value *Codegen::getValue(Inst *I) { Inst::getKindName(I->K) + " in Codegen::getValue()"); } +static std::vector +GetInputArgumentTypes(const InstContext &IC, llvm::LLVMContext &Context, Inst *Root) { + const std::vector AllVariables = IC.getVariablesFor(Root); + + std::vector ArgTypes; + ArgTypes.reserve(AllVariables.size()); + for (const Inst *const Var : AllVariables) { + llvm::errs() << "arg with width " << Var->Width << " and number " << Var->Number << "\n"; + ArgTypes.emplace_back(Type::getIntNTy(Context, Var->Width)); + } + + return ArgTypes; +} + +static std::map GetArgsMapping(const InstContext &IC, + Function *F, Inst *Root) { + std::map Args; + + const std::vector AllVariables = IC.getVariablesFor(Root); + for (auto zz : llvm::zip(AllVariables, F->args())) + Args[std::get<0>(zz)] = &(std::get<1>(zz)); + + return Args; +}; + +/// If there are no errors, the function returns false. If an error is found, +/// a message describing the error is written to OS (if non-null) and true is +/// returned. +bool genModule(InstContext &IC, souper::Inst *I, llvm::Module &Module) { + llvm::LLVMContext &Context = Module.getContext(); + const std::vector ArgTypes = GetInputArgumentTypes(IC, Context, I); + const auto FT = llvm::FunctionType::get( + /*Result=*/Codegen::GetInstReturnType(Context, I), + /*Params=*/ArgTypes, /*isVarArg=*/false); + + Function *F = Function::Create(FT, Function::ExternalLinkage, "fun", &Module); + + const std::map Args = GetArgsMapping(IC, F, I); + + BasicBlock *BB = BasicBlock::Create(Context, "entry", F); + + llvm::IRBuilder<> Builder(Context); + Builder.SetInsertPoint(BB); + + Value *RetVal = Codegen(Context, &Module, Builder, /*DT*/ nullptr, + /*ReplacedInst*/ nullptr, Args) + .getValue(I); + + Builder.CreateRet(RetVal); + + // Validate the generated code, checking for consistency. + if (verifyFunction(*F, &llvm::errs())) + return true; + if (verifyModule(Module, &llvm::errs())) + return true; + return false; +} + } // namespace souper diff --git a/lib/Codegen/MachineCost.cpp b/lib/Codegen/MachineCost.cpp new file mode 100644 index 000000000..b394e988f --- /dev/null +++ b/lib/Codegen/MachineCost.cpp @@ -0,0 +1,173 @@ +// 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/Codegen/Codegen.h" +#include "souper/Inst/Inst.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Value.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Support/SmallVectorMemoryBuffer.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include + +#define DEBUG_TYPE "souper" + +using namespace llvm; + +namespace souper { + +void optimizeModule(llvm::Module &M) { + llvm::LoopAnalysisManager LAM; + llvm::FunctionAnalysisManager FAM; + llvm::CGSCCAnalysisManager CGAM; + llvm::ModuleAnalysisManager MAM; + + llvm::PassBuilder PB; + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + llvm::FunctionPassManager FPM = + PB.buildFunctionSimplificationPipeline(llvm::PassBuilder::OptimizationLevel::O2, + ThinOrFullLTOPhase::None); + llvm::ModulePassManager MPM; + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + MPM.run(M, MAM); +} + +long getCodeSize(Module &M, TargetMachine *TM) { + M.setDataLayout(TM->createDataLayout()); + SmallVector DotO; + raw_svector_ostream dest(DotO); + + legacy::PassManager pass; + if (TM->addPassesToEmitFile(pass, dest, nullptr, CGFT_ObjectFile)) { + errs() << "Target machine can't emit a file of this type"; + report_fatal_error("oops"); + } + pass.run(M); + + SmallVectorMemoryBuffer Buf(std::move(DotO)); + auto ObjOrErr = object::ObjectFile::createObjectFile(Buf); + if (!ObjOrErr) + report_fatal_error("createObjectFile() failed"); + object::ObjectFile *OF = ObjOrErr.get().get(); + auto SecList = OF->sections(); + long Size = 0; + for (auto &S : SecList) { + if (S.isText()) + Size += S.getSize(); + } + if (Size > 0) + return Size; + else + report_fatal_error("no text segment found"); +} + +struct TargetInfo { + std::string Trip, CPU; +}; + +std::vector Targets { + { "x86_64", "skylake" }, + { "aarch64", "apple-a12" }, +}; + +bool Init = false; + +void getBackendCost(InstContext &IC, souper::Inst *I, BackendCost &BC) { + // TODO is this better than just forcing all clients of this code to + // do the init themselves? + if (!Init) { + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmParsers(); + InitializeAllAsmPrinters(); + Init = true; + } + + llvm::LLVMContext C; + llvm::Module M("", C); + if (genModule(IC, I, M)) + llvm::report_fatal_error("codegen error in getBackendCost()"); + + optimizeModule(M); + + llvm::errs() << M; + + BackendCost Cost; + for (auto &T : Targets) { + std::string Error; + auto Target = TargetRegistry::lookupTarget(T.Trip, Error); + if (!Target) { + errs() << Error; + report_fatal_error("can't lookup target"); + } + + auto Features = ""; + TargetOptions Opt; + auto RM = Optional(); + auto TM = Target->createTargetMachine(T.Trip, T.CPU, Features, Opt, RM); + + Cost.C.push_back(getCodeSize(M, TM)); + } + + llvm::errs() << "cost vector: "; + for (auto I : Cost.C) { + llvm::errs() << I << " "; + } + llvm::errs() << "\n"; +} + +int threeWayCompare(int A, int B) { + if (A < B) + return -1; + if (A > B) + return 1; + return 0; +} + +// "The value returned indicates whether the element passed as first +// argument is considered to go before the second" +bool compareCosts(const BackendCost &C1, const BackendCost &C2) { + assert(C1.C.size() == C2.C.size()); + + int Count = 0; + for (int i = 0; i < C1.C.size(); ++i) + Count += threeWayCompare(C1.C[i], C2.C[i]); + if (Count < 0) + return true; + if (Count > 0) + return false; + + // break ties using souper cost? + // break final ties how? we want a canonical winner for all cases + // FIXME -- not finished + return false; +} + +} // namespace souper diff --git a/lib/Extractor/Solver.cpp b/lib/Extractor/Solver.cpp index 2fd9b64d5..cd9ea2ed2 100644 --- a/lib/Extractor/Solver.cpp +++ b/lib/Extractor/Solver.cpp @@ -21,6 +21,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" +#include "souper/Codegen/Codegen.h" #include "souper/Extractor/Solver.h" #include "souper/Infer/AliveDriver.h" #include "souper/Infer/ConstantSynthesis.h" @@ -376,10 +377,10 @@ class BaseSolver : public Solver { return std::error_code(); } - std::error_code infer(const BlockPCs &BPCs, - const std::vector &PCs, - Inst *LHS, std::vector &RHSs, - bool AllowMultipleRHSs, InstContext &IC) override { + std::error_code inferHelper(const BlockPCs &BPCs, + const std::vector &PCs, + Inst *LHS, std::vector &RHSs, + bool AllowMultipleRHSs, InstContext &IC) { std::error_code EC; // FIXME -- it's a bit messy to have this custom logic here @@ -441,6 +442,23 @@ class BaseSolver : public Solver { return SMTSolver->isSatisfiable(Query, Result, NumModels, Models, Timeout); } + std::error_code infer(const BlockPCs &BPCs, + const std::vector &PCs, + Inst *LHS, std::vector &RHSs, + bool AllowMultipleRHSs, InstContext &IC) override { + auto EC = inferHelper(BPCs, PCs, LHS, RHSs, AllowMultipleRHSs, IC); + if (RHSs.size() <= 1) + return EC; + + for (auto &RHS : RHSs) { + BackendCost BC; + getBackendCost(IC, RHS, BC); + // FIXME sort the list + } + + return EC; + } + std::error_code isValid(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, bool &IsValid, diff --git a/lib/Infer/EnumerativeSynthesis.cpp b/lib/Infer/EnumerativeSynthesis.cpp index 4d9d9f67b..483d867a2 100644 --- a/lib/Infer/EnumerativeSynthesis.cpp +++ b/lib/Infer/EnumerativeSynthesis.cpp @@ -645,9 +645,9 @@ std::error_code synthesizeWithAlive(SynthesisContext &SC, std::vector &R } assert (RHS); RHSs.emplace_back(RHS); - if (!SC.CheckAllGuesses) { + if (!SC.CheckAllGuesses) return EC; - } + if (DebugLevel > 3) { llvm::outs() << "; result " << RHSs.size() << ":\n"; ReplacementContext RC; diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index 7d4316edd..712ad3b2b 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -787,6 +787,21 @@ std::vector InstContext::getVariables() const { return AllVariables; }; +std::vector InstContext::getVariablesFor(Inst *I) const { + std::vector AllVariables; + findVars(I, AllVariables); + + std::sort(AllVariables.begin(), AllVariables.end(), + [](const Inst *LHS, const Inst *RHS) { + if (LHS->Width == RHS->Width) + return LHS->Number < RHS->Number; + else + return LHS->Width < RHS->Width; + }); + + return AllVariables; +}; + bool Inst::isCommutative(Inst::Kind K) { switch (K) { case Add: @@ -956,7 +971,6 @@ int souper::cost(Inst *I, bool IgnoreDepsWithExternalUses) { return costHelper(I, I, Visited, IgnoreDepsWithExternalUses); } - int souper::countHelper(Inst *I, std::set &Visited) { if (!Visited.insert(I).second) return 0; diff --git a/test/Codegen/argument-order.opt b/test/Codegen/argument-order.opt index c11b5c7ba..8a5b616a6 100644 --- a/test/Codegen/argument-order.opt +++ b/test/Codegen/argument-order.opt @@ -10,10 +10,10 @@ result %4 ; CHECK: ; ModuleID = 'souper.ll' ; CHECK-NEXT: source_filename = "souper.ll" -; CHECK: define i8 @fun(i16 %0, i4 %1) { +; CHECK: define i8 @fun(i4 %0, i16 %1) { ; CHECK-NEXT: entry: -; CHECK-NEXT: %2 = zext i4 %1 to i8 -; CHECK-NEXT: %3 = trunc i16 %0 to i8 +; CHECK-NEXT: %2 = zext i4 %0 to i8 +; CHECK-NEXT: %3 = trunc i16 %1 to i8 ; CHECK-NEXT: %4 = and i8 %2, %3 ; CHECK-NEXT: ret i8 %4 ; CHECK-NEXT: } diff --git a/test/Codegen/return-const-unused-arg.opt b/test/Codegen/return-const-unused-arg.opt index a32a7fddf..1cb431eae 100644 --- a/test/Codegen/return-const-unused-arg.opt +++ b/test/Codegen/return-const-unused-arg.opt @@ -6,7 +6,7 @@ result 42:i8 ; CHECK: ; ModuleID = 'souper.ll' ; CHECK-NEXT: source_filename = "souper.ll" -; CHECK: define i8 @fun(i8 %0) { +; CHECK: define i8 @fun() { ; CHECK-NEXT: entry: ; CHECK-NEXT: ret i8 42 ; CHECK-NEXT: } diff --git a/test/LLVM/clang1.c b/test/LLVM/clang1.c new file mode 100644 index 000000000..257b159c0 --- /dev/null +++ b/test/LLVM/clang1.c @@ -0,0 +1,19 @@ +// REQUIRES: solver + +// RUN: %clang -O2 -S -o - %s -emit-llvm | %FileCheck -check-prefix=TEST1 %s +// TEST1: %or = or i32 %b, %a + +// RUN: %clang -O2 -S -o - %s -emit-llvm -mllvm -disable-all-peepholes | %FileCheck -check-prefix=TEST2 %s +// TEST2: %xor = xor i32 %a, %b +// TEST2-NEXT: %or = or i32 %xor, %a + +// RUN: SOUPER_SOLVER=%solver SOUPER_NO_INFER=1 SOUPER_NO_EXTERNAL_CACHE=1 %sclang -O2 -S -o - %s -emit-llvm | %FileCheck -check-prefix=TEST3 %s +// TEST3: %or = or i32 %b, %a + +// RUN: LLVM_DISABLE_PEEPHOLES=1 SOUPER_SOLVER=%solver SOUPER_NO_INFER=1 SOUPER_NO_EXTERNAL_CACHE=1 %sclang -O2 -S -o - %s -emit-llvm | %FileCheck -check-prefix=TEST4 %s +// TEST4: %xor = xor i32 %a, %b +// TEST4-NEXT: %or = or i32 %xor, %a + +unsigned foo(unsigned a, unsigned b) { + return (a ^ b) | a; +} diff --git a/test/LLVM/clang2.c b/test/LLVM/clang2.c new file mode 100644 index 000000000..8525e8546 --- /dev/null +++ b/test/LLVM/clang2.c @@ -0,0 +1,19 @@ +// REQUIRES: solver + +// RUN: %clang -O2 -S -o - %s -emit-llvm | %FileCheck -check-prefix=TEST1 %s +// TEST1: and i64 %x, 1 + +// RUN: %clang -O2 -S -o - %s -emit-llvm -mllvm -disable-all-peepholes | %FileCheck -check-prefix=TEST2 %s +// TEST2: shl i64 %x, 63 +// TEST2-NEXT: lshr i64 %shl, 63 + +// RUN: SOUPER_SOLVER=%solver SOUPER_NO_INFER=1 SOUPER_NO_EXTERNAL_CACHE=1 %sclang -O2 -S -o - %s -emit-llvm | %FileCheck -check-prefix=TEST3 %s +// TEST3: and i64 %x, 1 + +// RUN: LLVM_DISABLE_PEEPHOLES=1 SOUPER_SOLVER=%solver SOUPER_NO_INFER=1 SOUPER_NO_EXTERNAL_CACHE=1 %sclang -O2 -S -o - %s -emit-llvm | %FileCheck -check-prefix=TEST4 %s +// TEST4: shl i64 %x, 63 +// TEST4-NEXT: lshr i64 %shl, 63 + +unsigned long foo(unsigned long x) { + return ((x << 63) >> 63) + 1; +} diff --git a/test/Unit/codegen_tests.ll b/test/Unit/codegen_tests.ll new file mode 100644 index 000000000..26dcc6a4b --- /dev/null +++ b/test/Unit/codegen_tests.ll @@ -0,0 +1 @@ +; RUN: %builddir/codegen_tests diff --git a/tools/souper2llvm.cpp b/tools/souper2llvm.cpp index acac0017e..9e2ba3e31 100644 --- a/tools/souper2llvm.cpp +++ b/tools/souper2llvm.cpp @@ -41,29 +41,6 @@ static cl::opt OutputFilename( "o", cl::desc(""), cl::init("-")); -static std::vector -GetInputArgumentTypes(const InstContext &IC, llvm::LLVMContext &Context) { - const std::vector AllVariables = IC.getVariables(); - - std::vector ArgTypes; - ArgTypes.reserve(AllVariables.size()); - for (const Inst *const Var : AllVariables) - ArgTypes.emplace_back(Type::getIntNTy(Context, Var->Width)); - - return ArgTypes; -} - -static std::map GetArgsMapping(const InstContext &IC, - Function *F) { - std::map Args; - - const std::vector AllVariables = IC.getVariables(); - for (auto zz : llvm::zip(AllVariables, F->args())) - Args[std::get<0>(zz)] = &(std::get<1>(zz)); - - return Args; -}; - int Work(const MemoryBufferRef &MB) { InstContext IC; ReplacementContext RC; @@ -79,31 +56,7 @@ int Work(const MemoryBufferRef &MB) { llvm::LLVMContext Context; llvm::Module Module("souper.ll", Context); - - const std::vector ArgTypes = GetInputArgumentTypes(IC, Context); - const auto FT = llvm::FunctionType::get( - /*Result=*/Codegen::GetInstReturnType(Context, RepRHS.Mapping.RHS), - /*Params=*/ArgTypes, /*isVarArg=*/false); - - Function *F = Function::Create(FT, Function::ExternalLinkage, "fun", &Module); - - const std::map Args = GetArgsMapping(IC, F); - - BasicBlock *BB = BasicBlock::Create(Context, "entry", F); - - llvm::IRBuilder<> Builder(Context); - Builder.SetInsertPoint(BB); - - Value *RetVal = Codegen(Context, &Module, Builder, /*DT*/ nullptr, - /*ReplacedInst*/ nullptr, Args) - .getValue(RepRHS.Mapping.RHS); - - Builder.CreateRet(RetVal); - - // Validate the generated code, checking for consistency. - if (verifyFunction(*F, &llvm::errs())) - return 1; - if (verifyModule(Module, &llvm::errs())) + if (genModule(IC, RepRHS.Mapping.RHS, Module)) return 1; std::error_code EC; diff --git a/unittests/Codegen/CodegenTests.cpp b/unittests/Codegen/CodegenTests.cpp new file mode 100644 index 000000000..6039512b5 --- /dev/null +++ b/unittests/Codegen/CodegenTests.cpp @@ -0,0 +1,55 @@ +// 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 "llvm/Support/raw_ostream.h" +#include "souper/Codegen/Codegen.h" +#include "gtest/gtest.h" + +unsigned DebugLevel; + +using namespace souper; + +const BackendCost C5a { .C = { 1, 2, 3, 4, 5 }}; +const BackendCost C5b { .C = { 0, 0, 0, 0, 0 }}; +const BackendCost C5c { .C = { 1, 2, 3, 4, 4 }}; +const BackendCost C5d { .C = { 1, 2, 3, 4, 6 }}; + +TEST(CodegenTest, Compare) { + const struct { + BackendCost L, R; + } Tests[] = { + { C5b, C5a }, + { C5b, C5c }, + { C5b, C5d }, + }; + + for (const auto &T : Tests) { + EXPECT_EQ(compareCosts(T.L, T.R), true); + EXPECT_EQ(compareCosts(T.R, T.L), false); + } +} + +TEST(CodegenTest, Sort) { + const struct { + std::vector Costs; + BackendCost Best; + } Tests[] = { + { { C5a, C5b, C5c, C5d }, C5b }, + }; + + for (const auto &T : Tests) { + //std::sort(T.Costs.begin(), T.Costs.end(), compareCosts); + //EXPECT_EQ(T.WantError, ErrStr); + } +} From a1fb8922f6310444d3d0bd3b3d6208df0a1a48f4 Mon Sep 17 00:00:00 2001 From: John Regehr Date: Mon, 3 May 2021 22:05:26 -0600 Subject: [PATCH 014/165] remove go stuff (#818) --- CMakeLists.txt | 15 - Dockerfile | 8 +- README.md | 5 - clone_and_test.sh | 1 - tools/souperweb-backend.cpp | 107 ------ tools/souperweb.go | 682 ------------------------------------ 6 files changed, 2 insertions(+), 816 deletions(-) delete mode 100644 tools/souperweb-backend.cpp delete mode 100644 tools/souperweb.go diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a56f292b..b82457566 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -478,21 +478,6 @@ add_custom_target(check # we want assertions even in release mode! string(REPLACE "-DNDEBUG" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") -find_program(GO_EXECUTABLE NAMES go DOC "go executable") -if(NOT GO_EXECUTABLE STREQUAL "GO_EXECUTABLE-NOTFOUND") - add_executable(souperweb-backend - tools/souperweb-backend.cpp - ) - set_target_properties(souperweb-backend - PROPERTIES COMPILE_FLAGS "${LLVM_CXXFLAGS}") - target_include_directories(souperweb-backend PRIVATE "${LLVM_INCLUDEDIR}") - - target_link_libraries(souperweb-backend souperTool souperExtractor souperPass souperKVStore souperSMTLIB2 souperParser souperInst ${HIREDIS_LIBRARY}) - - add_custom_target(souperweb ALL COMMAND ${GO_EXECUTABLE} build -o ${CMAKE_BINARY_DIR}/souperweb ${CMAKE_SOURCE_DIR}/tools/souperweb.go - COMMENT "Building souperweb") -endif() - add_library(profileRuntime STATIC runtime/souperPassProfile.c) diff --git a/Dockerfile b/Dockerfile index b1c911694..b4e22666d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ run set -x; \ && apt-get autoremove -y -qq \ && apt-get remove -y -qq clang llvm llvm-runtime \ && apt-get install libgmp10 \ - && echo 'ca-certificates valgrind libc6-dev libgmp-dev cmake ninja-build make autoconf automake libtool golang-go python subversion re2c git clang' > /usr/src/build-deps \ + && echo 'ca-certificates valgrind libc6-dev libgmp-dev cmake ninja-build make autoconf automake libtool python subversion re2c git clang' > /usr/src/build-deps \ && apt-get install -y $(cat /usr/src/build-deps) --no-install-recommends \ && git clone https://github.com/antirez/redis /usr/src/redis @@ -17,9 +17,6 @@ run export CC=clang CXX=clang++ \ && make -j10 \ && make install -run export GOPATH=/usr/src/go \ - && go get github.com/gomodule/redigo/redis - add build_deps.sh /usr/src/souper/build_deps.sh add clone_and_test.sh /usr/src/souper/clone_and_test.sh @@ -41,8 +38,7 @@ add tools /usr/src/souper/tools add utils /usr/src/souper/utils add unittests /usr/src/souper/unittests -run export GOPATH=/usr/src/go \ - && export LD_LIBRARY_PATH=/usr/src/souper/third_party/z3-install/lib:$LD_LIBRARY_PATH \ +run export LD_LIBRARY_PATH=/usr/src/souper/third_party/z3-install/lib:$LD_LIBRARY_PATH \ && mkdir -p /usr/src/souper-build \ && cd /usr/src/souper-build \ && CC=/usr/src/souper/third_party/llvm-Release-install/bin/clang CXX=/usr/src/souper/third_party/llvm-Release-install/bin/clang++ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DTEST_SYNTHESIS=ON ../souper \ diff --git a/README.md b/README.md index 261ac3b06..1c22f6328 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,6 @@ http://llvm.org/docs/GettingStarted.html#getting-a-modern-host-c-toolchain You will also need CMake to build Souper and its dependencies. -If you have Go installed, you will also need the Redigo Redis client: -``` -$ go get github.com/gomodule/redigo/redis -``` - # Building Souper 1. Download and build dependencies: diff --git a/clone_and_test.sh b/clone_and_test.sh index 225b3881f..d8bcbaae8 100755 --- a/clone_and_test.sh +++ b/clone_and_test.sh @@ -32,7 +32,6 @@ else ln -s /usr/src/souper/third_party; fi -export GOPATH=/usr/src/go Z3=/usr/bin/z3 SRCDIR="$PWD" diff --git a/tools/souperweb-backend.cpp b/tools/souperweb-backend.cpp deleted file mode 100644 index 72c409f5b..000000000 --- a/tools/souperweb-backend.cpp +++ /dev/null @@ -1,107 +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. - -#include "llvm/AsmParser/Parser.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include "souper/Extractor/Solver.h" -#include "souper/SMTLIB2/Solver.h" -#include "souper/Parser/Parser.h" -#include "souper/Tool/CandidateMapUtils.h" -#include "souper/Tool/GetSolver.h" - -using namespace llvm; -using namespace souper; - -unsigned DebugLevel; - -extern "C" int boolector_main(int argc, char **argv); - -LLVMContext Context; - -void SolveIR(std::unique_ptr MB, Solver *S) { - SMDiagnostic Err; - if (std::unique_ptr M = - parseAssembly(MB->getMemBufferRef(), Err, Context)) { - InstContext IC; - ExprBuilderContext EBC; - CandidateMap CandMap; - - AddModuleToCandidateMap(IC, EBC, CandMap, M.get()); - - SolveCandidateMap(llvm::outs(), CandMap, S, IC, 0); - } else { - Err.print(0, llvm::errs(), false); - } -} - -void SolveInst(std::unique_ptr MB, Solver *S) { - InstContext IC; - std::string ErrStr; - - ParsedReplacement Rep = - ParseReplacement(IC, "", MB->getBuffer(), ErrStr); - if (!ErrStr.empty()) { - llvm::errs() << ErrStr << '\n'; - return; - } - - bool Valid; - std::vector> Models; - if (std::error_code EC = S->isValid(IC, Rep.BPCs, Rep.PCs, - Rep.Mapping, Valid, &Models)) { - llvm::errs() << EC.message() << '\n'; - return; - } - - if (Valid) { - llvm::outs() << "LGTM\n"; - } else { - llvm::outs() << "Invalid"; - if (!Models.empty()) { - llvm::outs() << ", e.g.\n\n"; - std::sort(Models.begin(), Models.end(), - [](const std::pair &A, - const std::pair &B) { - return A.first->Name < B.first->Name; - }); - for (const auto &M : Models) { - llvm::outs() << '%' << M.first->Name << " = " << M.second << '\n'; - } - } - } -} - -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 = GetSolver(KV); - - auto MB = MemoryBuffer::getSTDIN(); - if (MB) { - if (Action == "ir") { - SolveIR(std::move(*MB), S.get()); - } else { - SolveInst(std::move(*MB), S.get()); - } - } else { - llvm::errs() << MB.getError().message() << '\n'; - } -} diff --git a/tools/souperweb.go b/tools/souperweb.go deleted file mode 100644 index dc39b2064..000000000 --- a/tools/souperweb.go +++ /dev/null @@ -1,682 +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. - -package main - -import ( - "bytes" - "crypto/sha1" - "encoding/json" - "html" - "io" - "math/rand" - "net" - "net/http" - "os" - "os/exec" - "regexp" - "sort" - "strings" - "syscall" - "text/template" - "time" - "fmt" - - "github.com/gomodule/redigo/redis" -) - -type solverQuery struct { - IsIR bool - Req string -} - -type solverReq struct { - solverQuery - dest io.Writer - result chan<- solverResp -} - -type solverResp struct { - result string - err error -} - -type solveHTMLResp struct { - HTML string - Key string -} - -type friendlyError struct { - msg string - err error -} - -func (e friendlyError) Error() string { - s := e.msg - if e.err != nil { - s += " (" + e.err.Error() + ")" - } - return s -} - -type rateReq struct { - ip string - ok chan<- bool -} - -type context struct { - homepage *template.Template - solverch chan solverReq - ratech chan rateReq - pool redis.Pool -} - -func (ctx *context) init() { - ctx.solverch = make(chan solverReq) - ctx.ratech = make(chan rateReq) - ctx.pool = redis.Pool{ - MaxIdle: 3, - IdleTimeout: 240 * time.Second, - Dial: func() (redis.Conn, error) { - return redis.Dial("tcp", "127.0.0.1:6379") - }, - TestOnBorrow: func(c redis.Conn, t time.Time) error { - _, err := c.Do("PING") - return err - }, - } - - go ctx.solverWorker() - go ctx.solverWorker() - go ctx.rateWorker() - - ctx.homepage = ctx.buildHomePage() -} - -func randFromQuery(query string) *rand.Rand { - hash := sha1.Sum([]byte(query)) - var hash8 int64 - for i, h := range hash[0:8] { - hash8 |= int64(h) << (8 * uint(i)) - } - source := rand.NewSource(hash8) - return rand.New(source) -} - -// avoid English words and transcription errors by excluding 01AEIOU -const keyChars = "23456789BCDFGHJKLMNPQRSTVWXYZ" - -func keyFromRand(r *rand.Rand) string { - var key string - for i := 0; i != 6; i++ { - key += string(keyChars[r.Int31n(int32(len(keyChars)))]) - } - return key -} - -var keyRE = regexp.MustCompile("^[" + keyChars + "]{6}$") - -func isKey(k string) bool { - return keyRE.MatchString(k) -} - -func (ctx *context) lookupByKey(conn redis.Conn, key string) (solverQuery, error) { - _, err := conn.Do("SELECT", 0) - if err != nil { - return solverQuery{}, err - } - - jsonquery, err := redis.Bytes(conn.Do("GET", key)) - if err != nil { - return solverQuery{}, friendlyError{"Invalid key", err} - } - - var query solverQuery - err = json.Unmarshal(jsonquery, &query) - return query, err -} - -func (ctx *context) getKey(conn redis.Conn, query solverQuery) (string, error) { - json, err := json.Marshal(query) - if err != nil { - return "", err - } - - rand := randFromQuery(query.Req) - - _, err = conn.Do("SELECT", 0) - if err != nil { - return "", err - } - - for { - _, err := conn.Do("WATCH", "key:"+string(json)) - if err != nil { - return "", err - } - - key, err := redis.String(conn.Do("GET", "key:"+string(json))) - if err != nil && err != redis.ErrNil { - return "", err - } - if key != "" { - _, err := conn.Do("UNWATCH") - if err != nil { - return "", err - } - return key, nil - } - - _, err = conn.Do("WATCH", key) - if err != nil { - return "", err - } - - key = keyFromRand(rand) - len, err := redis.Int(conn.Do("STRLEN", key)) - if len != 0 { - _, err := conn.Do("UNWATCH") - if err != nil { - return "", err - } - continue - } - - _, err = conn.Do("MULTI") - if err != nil { - return "", err - } - - _, err = conn.Do("SET", key, json) - if err != nil { - return "", err - } - - _, err = conn.Do("SET", "key:"+string(json), key) - if err != nil { - return "", err - } - - exec, err := conn.Do("EXEC") - if err != nil { - return "", err - } - if exec == nil { - continue - } - - return key, nil - } -} - -func (ctx *context) solverWorker() { - conn := ctx.pool.Get() - defer conn.Close() - - for r := range ctx.solverch { - var arg string - if r.IsIR { - arg = "-action=ir" - } else { - arg = "-action=inst" - } - cmd := exec.Command(os.Args[0]+"-backend", arg, os.Args[1]) - - cmd.Stdin = strings.NewReader(r.Req) - - var outb, errb bytes.Buffer - cmd.Stdout = &outb - cmd.Stderr = &errb - - var sys syscall.SysProcAttr - sys.Setpgid = true - cmd.SysProcAttr = &sys - - err := cmd.Start() - if err != nil { - os.Stdout.Write([]byte("Error invoking solver: " + err.Error() + "\n")) - r.result <- solverResp{"", friendlyError{"Error invoking solver", err}} - continue - } - - timeout := false - timer := time.AfterFunc(10*time.Second, func() { - syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) - timeout = true - }) - - err = cmd.Wait() - timer.Stop() - if timeout { - os.Stdout.Write([]byte("Solver timeout\n")) - r.result <- solverResp{"", friendlyError{"Solver timeout", nil}} - } else if err != nil { - r.result <- solverResp{"", friendlyError{"Error invoking solver", err}} - } else if errb.Len() != 0 { - r.result <- solverResp{"", friendlyError{errb.String(), nil}} - } else { - r.result <- solverResp{outb.String(), nil} - } - } -} - -func (ctx *context) rateWorker() { - visits := make(map[string][3]int64) - - daily := make(chan bool) - go func() { - for { - time.Sleep(86400 * time.Second) - daily <- true - } - }() - - for { - select { - case r := <-ctx.ratech: - now := time.Now().Unix() - vs := visits[r.ip] - ok := vs[2] <= now-10 - vs[0], vs[1], vs[2] = now, vs[0], vs[1] - visits[r.ip] = vs - r.ok <- ok - - case <-daily: - visits = make(map[string][3]int64) - } - } -} - -func (ctx *context) buildHomePage() *template.Template { - conn := ctx.pool.Get() - defer conn.Close() - - examples := map[string]solverQuery{ - "addnsw (IR)": {true, `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 -} -`}, - "addnsw (inst)": {false, `%x:i32 = var -%add = addnsw %x, 1 -%cmp = slt %x, %add -cand %cmp 1 -`}, - "instcombine1": {false, `%a:i1 = var -%b:i32 = var -%ax:i32 = zext %a -%c = add %ax, %b - -%b1 = add %b, 1 -%c2 = select %a, %b1, %b - -cand %c %c2 -`}, - "simple": {false, `%a:i32 = var -%aa = add %a, %a -%2a = mul %a, 2 -cand %aa %2a -`}, - "simple-pc": {false, `%x:i32 = var -%2lx = slt 2, %x -pc %2lx 1 -%1lx = slt 1, %x -cand %1lx 1 -`}, - "simple-pc-invalid": {false, `%x:i32 = var -%2lx = slt 2, %x -pc %2lx 1 -%3lx = slt 3, %x -cand %3lx 1 -`}, - } - - exampleNames := make([]string, len(examples)) - i := 0 - for name, _ := range examples { - exampleNames[i] = name - i++ - } - sort.Strings(exampleNames) - - var b bytes.Buffer - b.WriteString(` - - - - - - -

souperweb

-Enter Souper instructions or LLVM IR into the box below and hit Submit.
-`) - - b.WriteString(` -
-Souper inst -LLVM IR
- - - - - -
-
-
-Examples:
-`) - for _, n := range exampleNames { - key, err := ctx.getKey(conn, examples[n]) - if err != nil { - panic(err.Error()) - } - b.WriteString(``) - b.WriteString(n) - b.WriteString(`
`) - } - b.WriteString(` -
- -
- -
{{.resp.HTML}}
- - -`) - return template.Must(template.New("homepage").Parse(b.String())) -} - -func (ctx *context) rootHandler(w http.ResponseWriter, r *http.Request) { - if len(r.URL.Path) > 1 { - key := r.URL.Path[1:] - isjson := false - if strings.HasSuffix(key, "/json") { - key = key[:len(key)-5] - isjson = true - } - - if !isKey(key) { - w.WriteHeader(http.StatusNotFound) - w.Write([]byte("Not Found\n")) - return - } - - conn := ctx.pool.Get() - defer conn.Close() - - query, resp := ctx.buildLookupResp(conn, key, r) - if isjson { - json, _ := json.Marshal(map[string]interface{}{"query": query, "resp": resp}) - w.Write(json) - } else { - ctx.writeHomePage(w, query, resp) - } - } else { - ctx.writeHomePage(w, solverQuery{}, solveHTMLResp{}) - } -} - -func (ctx *context) getErrorResp(err error) (resp solveHTMLResp) { - var w bytes.Buffer - w.Write([]byte(`
`))
-	if ferr, ok := err.(friendlyError); ok {
-		if ferr.err != nil {
-			os.Stdout.Write([]byte(ferr.err.Error() + "\n"))
-		}
-		w.Write([]byte(html.EscapeString(ferr.msg)))
-	} else {
-		os.Stdout.Write([]byte(err.Error() + "\n"))
-		w.Write([]byte("Internal error"))
-	}
-	w.Write([]byte(`
`)) - resp.HTML = w.String() - return resp -} - -func (ctx *context) solve(conn redis.Conn, w io.Writer, query solverQuery, r *http.Request) error { - _, err := conn.Do("SELECT", 1) - if err != nil { - return err - } - - json, err := json.Marshal(query) - if err != nil { - return err - } - - result, err := redis.String(conn.Do("GET", json)) - if err != nil && err != redis.ErrNil { - return err - } - if err != redis.ErrNil { - w.Write([]byte("
"))
-		w.Write([]byte(html.EscapeString(result)))
-		w.Write([]byte("
")) - return nil - } - - os.Stdout.WriteString(time.Now().String() + " " + r.RemoteAddr + "\n") - - ch := make(chan bool) - - host, _, err := net.SplitHostPort(r.RemoteAddr) - if err != nil { - return err - } - - ctx.ratech <- rateReq{host, ch} - - if <-ch { - respch := make(chan solverResp) - ctx.solverch <- solverReq{query, w, respch} - resp := <-respch - - if resp.err != nil { - return resp.err - } - - _, err := conn.Do("SET", json, resp.result) - if err != nil { - return err - } - - w.Write([]byte("
"))
-		w.Write([]byte(html.EscapeString(resp.result)))
-		w.Write([]byte("
")) - - return nil - } else { - return friendlyError{"Rate limit exceeded", nil} - } - - return nil -} - -func (ctx *context) buildLookupResp(conn redis.Conn, key string, r *http.Request) (solverQuery, solveHTMLResp) { - query, err := ctx.lookupByKey(conn, key) - if err != nil { - return solverQuery{}, ctx.getErrorResp(err) - } - - var html bytes.Buffer - err = ctx.solve(conn, &html, query, r) - if err != nil { - return query, ctx.getErrorResp(err) - } - - var resp solveHTMLResp - resp.HTML = html.String() - resp.Key = key - return query, resp -} - -func (ctx *context) buildSolveResp(conn redis.Conn, query solverQuery, r *http.Request) solveHTMLResp { - var html bytes.Buffer - err := ctx.solve(conn, &html, query, r) - if err != nil { - return ctx.getErrorResp(err) - } - - key, err := ctx.getKey(conn, query) - if err != nil { - return ctx.getErrorResp(err) - } - - var resp solveHTMLResp - resp.HTML = html.String() - resp.Key = key - return resp -} - -func (ctx *context) solveHandler(w http.ResponseWriter, r *http.Request) { - conn := ctx.pool.Get() - defer conn.Close() - - r.ParseForm() - - typeForm := r.Form["type"] - if len(typeForm) == 0 { - return - } - - dataForm := r.Form["data"] - if len(dataForm) == 0 { - return - } - - data := strings.Replace(dataForm[0], "\r\n", "\n", -1) - query := solverQuery{typeForm[0] == "ir", data} - - resp := ctx.buildSolveResp(conn, query, r) - - if strings.HasSuffix(r.URL.Path, "/json") { - json, _ := json.Marshal(resp) - w.Write(json) - } else if resp.Key != "" { - http.Redirect(w, r, "/"+resp.Key, http.StatusFound) - } else { - ctx.writeHomePage(w, query, resp) - } -} - -func (ctx *context) writeHomePage(w io.Writer, query solverQuery, resp solveHTMLResp) { - ctx.homepage.Execute(w, map[string]interface{}{"query": query, "resp": resp}) -} - -func main() { - var ctx context - ctx.init() - - http.HandleFunc("/", ctx.rootHandler) - http.HandleFunc("/solve", ctx.solveHandler) - http.HandleFunc("/solve/json", ctx.solveHandler) - - fmt.Println("Listening on port :8080") - http.ListenAndServe(":8080", nil) -} From 3a7aa1a107746f43c9b586c8bd1c524c9b117583 Mon Sep 17 00:00:00 2001 From: Zhengyang Liu <2017989+zhengyang92@users.noreply.github.com> Date: Tue, 4 May 2021 14:58:22 -0700 Subject: [PATCH 015/165] GCC compiled Souper failed to synthsize constants for some range synthesis tests within 30 Tries, Use MaxTries=60 for those tests (#819) --- test/Dataflow/precision-multiple.ll | 2 +- test/Dataflow/precision-multiple.opt | 2 +- test/Dataflow/precision-range-1.ll | 2 +- test/Dataflow/precision-range-1.opt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Dataflow/precision-multiple.ll b/test/Dataflow/precision-multiple.ll index ad249eba9..f4ad5c725 100644 --- a/test/Dataflow/precision-multiple.ll +++ b/test/Dataflow/precision-multiple.ll @@ -1,7 +1,7 @@ ; RUN: %llvm-as -o %t %s -; RUN: %souper -infer-range -infer-non-zero %t > %t2 || true +; RUN: %souper -infer-range -infer-non-zero -souper-max-constant-synthesis-tries=60 %t > %t2 || true ; RUN: %FileCheck %s < %t2 define i8 @foo(i8 %x1, i64 %_phiinput) { diff --git a/test/Dataflow/precision-multiple.opt b/test/Dataflow/precision-multiple.opt index fdfac5c10..c792ae97d 100644 --- a/test/Dataflow/precision-multiple.opt +++ b/test/Dataflow/precision-multiple.opt @@ -1,5 +1,5 @@ -; RUN: %souper-check -infer-range -infer-non-zero %s | %FileCheck %s +; RUN: %souper-check -infer-range -infer-non-zero -souper-max-constant-synthesis-tries=60 %s | %FileCheck %s ; CHECK: nonZero from souper: true ; CHECK: range from souper: [1,0) diff --git a/test/Dataflow/precision-range-1.ll b/test/Dataflow/precision-range-1.ll index c285fb3b9..748aaab5c 100644 --- a/test/Dataflow/precision-range-1.ll +++ b/test/Dataflow/precision-range-1.ll @@ -1,7 +1,7 @@ ; RUN: %llvm-as -o %t %s -; RUN: %souper -infer-range %t > %t2 || true +; RUN: %souper -infer-range -souper-max-constant-synthesis-tries=60 %t > %t2 || true ; RUN: %FileCheck %s < %t2 define i8 @foo(i8 %x1, i64 %_phiinput) { diff --git a/test/Dataflow/precision-range-1.opt b/test/Dataflow/precision-range-1.opt index 5a97d2525..9f09ebaea 100644 --- a/test/Dataflow/precision-range-1.opt +++ b/test/Dataflow/precision-range-1.opt @@ -1,5 +1,5 @@ -; RUN: %souper-check -infer-range %s | %FileCheck %s +; RUN: %souper-check -infer-range -souper-max-constant-synthesis-tries=60 %s | %FileCheck %s ; CHECK: range from souper: [1,0) From 28c88d882e8b19a43e36698102a8bda0a478eb61 Mon Sep 17 00:00:00 2001 From: Zhengyang Liu <2017989+zhengyang92@users.noreply.github.com> Date: Wed, 5 May 2021 08:24:50 -0700 Subject: [PATCH 016/165] cleanup dockerfile (#820) --- CMakeLists.txt | 2 +- Dockerfile | 59 ++++++++++------------- build_docker.sh | 2 +- test/Infer/syn-double-insts/syn-ctpop.opt | 13 ++--- 4 files changed, 32 insertions(+), 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b82457566..03fd4ac49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE ) -set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS} -fno-exceptions -fno-rtti") +set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS} -fno-exceptions -fno-rtti -Wno-deprecated-enum-enum-conversion") execute_process( COMMAND ${LLVM_CONFIG_EXECUTABLE} --libs diff --git a/Dockerfile b/Dockerfile index b4e22666d..362194091 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,31 +1,24 @@ from ubuntu:20.04 run set -x; \ - echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections \ - && apt-get update -y -qq \ - && apt-get dist-upgrade -y -qq \ - && apt-get autoremove -y -qq \ - && apt-get remove -y -qq clang llvm llvm-runtime \ - && apt-get install libgmp10 \ - && echo 'ca-certificates valgrind libc6-dev libgmp-dev cmake ninja-build make autoconf automake libtool python subversion re2c git clang' > /usr/src/build-deps \ - && apt-get install -y $(cat /usr/src/build-deps) --no-install-recommends \ - && git clone https://github.com/antirez/redis /usr/src/redis - -run export CC=clang CXX=clang++ \ - && cd /usr/src/redis \ - && git checkout 5.0.3 \ - && make -j10 \ - && make install + echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections \ + && apt-get update -y -qq \ + && apt-get dist-upgrade -y -qq \ + && apt-get autoremove -y -qq \ + && apt-get remove -y -qq clang llvm llvm-runtime \ + && apt-get install libgmp10 \ + && echo 'ca-certificates valgrind libc6-dev libgmp-dev cmake ninja-build make autoconf automake libtool python python3 subversion re2c git clang libstdc++-10-dev redis' > /usr/src/build-deps \ + && apt-get install -y $(cat /usr/src/build-deps) --no-install-recommends add build_deps.sh /usr/src/souper/build_deps.sh add clone_and_test.sh /usr/src/souper/clone_and_test.sh run export CC=clang CXX=clang++ \ - && cd /usr/src/souper \ -# && ./build_deps.sh Debug \ -# && rm -r third_party/llvm-Debug-build \ - && ./build_deps.sh Release \ - && rm -r third_party/llvm-Release-build + && cd /usr/src/souper \ +# && ./build_deps.sh Debug \ +# && rm -r third_party/llvm-Debug-build \ + && ./build_deps.sh Release \ + && rm -r third_party/llvm-Release-build add CMakeLists.txt /usr/src/souper/CMakeLists.txt @@ -39,17 +32,15 @@ add utils /usr/src/souper/utils add unittests /usr/src/souper/unittests run export LD_LIBRARY_PATH=/usr/src/souper/third_party/z3-install/lib:$LD_LIBRARY_PATH \ - && mkdir -p /usr/src/souper-build \ - && cd /usr/src/souper-build \ - && CC=/usr/src/souper/third_party/llvm-Release-install/bin/clang CXX=/usr/src/souper/third_party/llvm-Release-install/bin/clang++ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DTEST_SYNTHESIS=ON ../souper \ - && ninja souperweb souperweb-backend \ - && ninja check \ - && cp souperweb souperweb-backend /usr/local/bin \ - && cd .. \ - && rm -rf /usr/src/souper-build \ - && strip /usr/local/bin/* \ - && groupadd -r souper \ - && useradd -m -r -g souper souper \ - && mkdir /data \ - && chown souper:souper /data \ - && rm -rf /usr/local/include /usr/local/lib/*.a /usr/local/lib/*.la + && mkdir -p /usr/src/souper-build \ + && cd /usr/src/souper-build \ + && CC=/usr/src/souper/third_party/llvm-Release-install/bin/clang CXX=/usr/src/souper/third_party/llvm-Release-install/bin/clang++ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DTEST_SYNTHESIS=ON ../souper \ + && ninja \ + && ninja check \ + && cd .. \ + && rm -rf /usr/src/souper-build \ + && groupadd -r souper \ + && useradd -m -r -g souper souper \ + && mkdir /data \ + && chown souper:souper /data \ + && rm -rf /usr/local/include /usr/local/lib/*.a /usr/local/lib/*.la diff --git a/build_docker.sh b/build_docker.sh index f0012d7c4..02da70cb6 100755 --- a/build_docker.sh +++ b/build_docker.sh @@ -2,7 +2,7 @@ # docker system prune -a -tar cz Dockerfile build_deps.sh clone_and_test.sh CMakeLists.txt docs include lib patches runtime scripts test tools utils unittests | docker build -t souperweb - +tar cz Dockerfile build_deps.sh clone_and_test.sh CMakeLists.txt docs include lib runtime test tools utils unittests | docker build -t souperweb - container=$(/usr/bin/docker run -d souperweb true) docker export $container | docker import - souperweb_squashed docker build -t souperweb_final - < Dockerfile.metadata diff --git a/test/Infer/syn-double-insts/syn-ctpop.opt b/test/Infer/syn-double-insts/syn-ctpop.opt index 3762bf0cc..eb1cf8dd5 100644 --- a/test/Infer/syn-double-insts/syn-ctpop.opt +++ b/test/Infer/syn-double-insts/syn-ctpop.opt @@ -2,15 +2,12 @@ ; RUN: %souper-check -infer-rhs -souper-enumerative-synthesis-max-instructions=2 %s > %t1 ; RUN: %FileCheck %s < %t1 -; synthesis ctpop - -; Need 2min~ +; enumerator stress test %0:i8 = var %1:i8 = add %0, 1:i8 %2:i8 = add %1, 3:i8 -%3:i8 = add %2, 5:i8 -%4:i8 = ctpop %3 -infer %4 -; CHECK: %5:i8 = add 9:i8, %0 -; CHECK: %6:i8 = ctpop %5 +%3:i8 = ctpop %2 +infer %3 +; CHECK: %4:i8 = add 4:i8, %0 +; CHECK: %5:i8 = ctpop %4 From 08bd23c2d467189a116815b4b1092fb4b3e7b4e6 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 19 May 2021 09:41:59 -0700 Subject: [PATCH 017/165] Switch to using assume for encoding PCs (#822) --- lib/Infer/AliveDriver.cpp | 4 +--- test/Solver/alive-pc.opt | 13 +++++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 test/Solver/alive-pc.opt diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index 7001df8ba..5ed4f9211 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -463,9 +463,7 @@ bool souper::AliveDriver::translateRoot(const souper::Inst *I, const Inst *PC, FunctionBuilder Builder(F); if (PC) { - auto Zero = Builder.val(getType(I->Width), llvm::APInt(I->Width, 0)); - ExprCache[I] = Builder.select(getType(I->Width), "%ifpc", - ExprCache[PC], ExprCache[I], Zero); + Builder.assume(ExprCache[PC]); } Builder.ret(getType(I->Width), ExprCache[I]); F.setType(getType(I->Width)); diff --git a/test/Solver/alive-pc.opt b/test/Solver/alive-pc.opt new file mode 100644 index 000000000..e529d3ecd --- /dev/null +++ b/test/Solver/alive-pc.opt @@ -0,0 +1,13 @@ +; RUN: %souper-check -souper-use-alive %s > %t 2>&1 +; RUN: %FileCheck %s < %t + +%0:i64 = var +%1:i64 = udiv 6148914691236517204:i64, %0 +%2:i64 = var +%3:i1 = ule %1, %2 +pc %3 0:i1 +%4:i64 = udiv %2, 2:i64 +infer %4 +%5:i64 = ashr %2, 1:i64 +result %5 +;CHECK: LGTM From 081d878eafd66d8fbab74c6e6def062a06187a41 Mon Sep 17 00:00:00 2001 From: John Regehr Date: Wed, 19 May 2021 12:52:02 -0600 Subject: [PATCH 018/165] fix issue 821 (#823) --- lib/Extractor/Candidates.cpp | 2 +- lib/Pass/Pass.cpp | 2 +- test/Pass/issue-821.ll | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 test/Pass/issue-821.ll diff --git a/lib/Extractor/Candidates.cpp b/lib/Extractor/Candidates.cpp index 4c98f4de5..ced018a8b 100644 --- a/lib/Extractor/Candidates.cpp +++ b/lib/Extractor/Candidates.cpp @@ -1022,7 +1022,7 @@ void ExtractExprCandidates(Function &F, const LoopInfo *LI, DemandedBits *DB, In->HarvestFrom = nullptr; EB.markExternalUses(In); BCS->Replacements.emplace_back(&I, InstMapping(In, 0)); - assert(EB.get(&I)->hasOrigin(&I)); + assert(EB.get(&I)->K == Inst::Const || EB.get(&I)->hasOrigin(&I)); } if (!BCS->Replacements.empty()) { std::unordered_set VisitedBlocks; diff --git a/lib/Pass/Pass.cpp b/lib/Pass/Pass.cpp index 121a0bbfa..4686d5f20 100644 --- a/lib/Pass/Pass.cpp +++ b/lib/Pass/Pass.cpp @@ -305,7 +305,7 @@ struct SouperPass : public ModulePass { Cand.Mapping.RHS = RHSs.front(); Instruction *I = Cand.Origin; - assert(Cand.Mapping.LHS->hasOrigin(I)); + assert(Cand.Mapping.LHS->K == Inst::Const || Cand.Mapping.LHS->hasOrigin(I)); IRBuilder<> Builder(I); Value *NewVal = getValue(Cand.Mapping.RHS, I, EBC, DT, diff --git a/test/Pass/issue-821.ll b/test/Pass/issue-821.ll new file mode 100644 index 000000000..ae592e158 --- /dev/null +++ b/test/Pass/issue-821.ll @@ -0,0 +1,22 @@ +; RUN: %opt -load %pass -souper -S -o - %s 2>&1 | %FileCheck %s + +; CHECK-NOT: ptrtoint +; CHECK-NOT: trunc +; CHECK-NOT: shl +; CHECK: store + +; ModuleID = 'foo.ll' +source_filename = "sqlite3.c" +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.15.0" + +define internal fastcc void @yy_reduce() unnamed_addr { +sw.bb115: + %sub.ptr.rhs.cast139 = ptrtoint i8* undef to i64 + %sub.ptr.sub140 = sub i64 undef, %sub.ptr.rhs.cast139 + %conv141 = trunc i64 %sub.ptr.sub140 to i32 + %bf.value145 = and i32 %conv141, 2147483647 + %bf.shl146 = shl i32 %bf.value145, 1 + store i32 %bf.shl146, i32* undef, align 8 + ret void +} From e888ac146519c249e1ef8c1183958d68febfd792 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 19 May 2021 14:46:51 -0700 Subject: [PATCH 019/165] Increase alive2 solver timeout to a minute (#826) --- lib/Infer/AliveDriver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index 5ed4f9211..dac070fde 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -284,6 +284,7 @@ synthesizeConstantUsingSolver(tools::Transform &t, souper::AliveDriver::AliveDriver(Inst *LHS_, Inst *PreCondition_, InstContext &IC_, std::vector ExtraInputs) : LHS(LHS_), PreCondition(PreCondition_), IC(IC_) { + smt::set_query_timeout(std::to_string(60000)); // milliseconds IsLHS = true; InstNumbers = 101; //FIXME: Magic number. 101 is chosen arbitrarily. From 8220bdf3fe87c4f39aa424b85a76689902b22377 Mon Sep 17 00:00:00 2001 From: John Regehr Date: Wed, 19 May 2021 15:47:00 -0600 Subject: [PATCH 020/165] a few random cleanups (#825) --- build_deps.sh | 4 ++-- include/souper/Tool/GetSolver.h.in | 3 ++- lib/Infer/AliveDriver.cpp | 7 +++--- tools/souper-check.cpp | 6 ++--- utils/cache_infer.in | 36 +++++++++++++++++++++++++----- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/build_deps.sh b/build_deps.sh index 74705e3a3..56f06925e 100755 --- a/build_deps.sh +++ b/build_deps.sh @@ -21,8 +21,8 @@ fi ncpus=$(command nproc 2>/dev/null || command sysctl -n hw.ncpu 2>/dev/null || echo 8) -# hiredis version 0.14.0 -hiredis_commit=685030652cd98c5414ce554ff5b356dfe8437870 +# hiredis latest as of May 7 2021 +hiredis_commit=667dbf536524ba3f28c1d964793db1055c5a64f2 llvm_repo=https://github.com/regehr/llvm-project.git # llvm_commit specifies the git branch or hash to checkout to llvm_commit=disable-peepholes-v05 diff --git a/include/souper/Tool/GetSolver.h.in b/include/souper/Tool/GetSolver.h.in index 8d98ae492..a2f7b9d3e 100644 --- a/include/souper/Tool/GetSolver.h.in +++ b/include/souper/Tool/GetSolver.h.in @@ -62,7 +62,8 @@ static std::unique_ptr GetUnderlyingSolver() { static std::unique_ptr GetSolver(KVStore *&KV) { std::unique_ptr US = GetUnderlyingSolver(); - if (!US) return NULL; + if (!US) + return NULL; std::unique_ptr S = createBaseSolver (std::move(US), SolverTimeout); if (ExternalCache) { KV = new KVStore; diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index dac070fde..48e4e73c8 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -438,15 +438,16 @@ bool souper::AliveDriver::verify (Inst *RHS, Inst *RHSAssumptions) { return false; if (auto errs = tv.verify()) { - if (DebugLevel >= 1) { + if (DebugLevel >= 2) { std::ostringstream os; os << errs << "\n"; llvm::errs() << os.str(); + llvm::errs() << "RHS rejected by Alive2\n"; } return false; // TODO: Encode errs into ErrorCode } else { - if (DebugLevel > 2) - llvm::errs() << "RHS proved valid.\n"; + if (DebugLevel >= 2) + llvm::errs() << "RHS verified by Alive2\n"; return true; } } diff --git a/tools/souper-check.cpp b/tools/souper-check.cpp index 9f310d220..0e2c62a3c 100644 --- a/tools/souper-check.cpp +++ b/tools/souper-check.cpp @@ -254,11 +254,11 @@ int SolveInst(const MemoryBufferRef &MB, Solver *S) { } if (CheckAllGuesses) { - for (unsigned RI = 0 ; RI < RHSs.size() ; RI++) { - llvm::outs()<<"; result " << (RI + 1) <<":\n"; + for (unsigned RI = 0 ; RI < RHSs.size(); RI++) { + llvm::outs() << "; result " << (RI + 1) << ":\n"; ReplacementContext RC; PrintReplacementRHS(llvm::outs(), RHSs[RI], RC); - llvm::outs()<<"\n"; + llvm::outs() << "\n"; } } else { if (PrintRepl) { diff --git a/utils/cache_infer.in b/utils/cache_infer.in index 452b53b27..a424c07d7 100755 --- a/utils/cache_infer.in +++ b/utils/cache_infer.in @@ -33,8 +33,10 @@ my $RAM_LIMIT = 4 * 1024 * 1024 * 1024; sub usage() { print <<"END"; Options: - -n number of CPUs to use (default=$NPROCS) - -tag add this tag to cache entries, and skip entries with it + -n number of CPUs to use (default=$NPROCS) + -tag add this tag to cache entries, and skip entries with it + -separate-files put each souper invocation's output into its own output file + -souper-debug-level pass this integer debug level to Souper -verbose END exit -1; @@ -42,18 +44,26 @@ END my $tag = "x"; my $VERBOSE = 0; +my $SAVE_TEMPS; +my $SOUPER_DEBUG = -1; GetOptions( "n=i" => \$NPROCS, "tag=s" => \$tag, "verbose" => \$VERBOSE, + "separate-files" => \$SAVE_TEMPS, + "souper-debug-level=i" => \$SOUPER_DEBUG, ) or usage(); my $OPTS = ""; +$OPTS .= "-souper-external-cache "; $OPTS .= "-souper-double-check "; $OPTS .= "-souper-dataflow-pruning "; $OPTS .= "-souper-enumerative-synthesis-max-instructions=1 "; +if ($SOUPER_DEBUG != -1) { + $OPTS .= "-souper-debug-level=${SOUPER_DEBUG} "; +} my $check = "@CMAKE_BINARY_DIR@/souper-check -solver-timeout=15"; @@ -70,11 +80,22 @@ sub infer($) { print STDERR "$cmd\n"; $fh->flush(); open(my $foo, '>>', 'fail.txt'); - open INF, "$cmd < $tmpfn |" or print $foo "$k\n";; + my $INF; + my $OFN = "tmp_$$.log"; + if ($SAVE_TEMPS) { + system "$cmd < $tmpfn > $OFN 2>&1"; + open my $OF, ">>$OFN" or die; + print $OF "\n\n$cmd\n\n"; + print $OF "$k\n\n"; + close $OF; + open $INF, "<$OFN" or die; + } else { + open $INF, "$cmd < $tmpfn |" or print $foo "$k\n"; + } my $ok = 0; my $failed = 0; my $output = ""; - while (my $line = ) { + while (my $line = <$INF>) { if ($line =~ /Failed/) { $failed = 1; next; @@ -85,7 +106,7 @@ sub infer($) { } $output .= $line; } - close INF; + close $INF; close $fh; unlink $tmpfn; # exit 1 unless $ok || $failed; @@ -93,7 +114,10 @@ sub infer($) { $red->ping || die "no server?"; $red->hset($k, "cache-infer-tag" => $tag); exit 1 unless $ok; + + ## FIXME -- we should have souper-check do this $red->hset($k, "result" => $output); + exit 0; } @@ -127,7 +151,7 @@ sub reset_status($) { sub status() { print "."; $status_cnt++; - my $pct = int(100.0*$status_cnt/$status_total); + my $pct = int(100.0 * $status_cnt/$status_total); if ($pct > $status_opct) { $status_opct = $pct; print "$pct %\n"; From 1af29166cd70aa802bca98d3f0611d24f05d1678 Mon Sep 17 00:00:00 2001 From: John Regehr Date: Thu, 20 May 2021 09:07:35 -0600 Subject: [PATCH 021/165] oops, didn't notice a problem caused by hiredis bump (#828) --- build_deps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_deps.sh b/build_deps.sh index 56f06925e..f52f88ff8 100755 --- a/build_deps.sh +++ b/build_deps.sh @@ -115,5 +115,5 @@ mkdir -p $hiredis_installdir/include/hiredis mkdir -p $hiredis_installdir/lib (cd $hiredis_srcdir && git checkout $hiredis_commit && make libhiredis.a && - cp -r hiredis.h async.h read.h sds.h adapters ${hiredis_installdir}/include/hiredis && + cp -r alloc.h hiredis.h async.h read.h sds.h adapters ${hiredis_installdir}/include/hiredis && cp libhiredis.a ${hiredis_installdir}/lib) From 0bb88f25fa083fd914dca682d6c195d554ae43e5 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 20 May 2021 08:12:19 -0700 Subject: [PATCH 022/165] Make constant shrinking optional, defaulting to false (#827) --- lib/Infer/EnumerativeSynthesis.cpp | 32 +++++++++++++++++------------- test/Solver/div-by-zero1.ll | 2 +- test/Solver/div-by-zero2.ll | 2 +- test/Solver/div-by-zero3.ll | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/lib/Infer/EnumerativeSynthesis.cpp b/lib/Infer/EnumerativeSynthesis.cpp index 483d867a2..0f91acc86 100644 --- a/lib/Infer/EnumerativeSynthesis.cpp +++ b/lib/Infer/EnumerativeSynthesis.cpp @@ -103,6 +103,9 @@ namespace { static cl::opt OnlyInferIN("souper-only-infer-iN", cl::desc("Only infer integer constants (default=false)"), cl::init(false)); + static cl::opt TryShrinkConsts("souper-shrink-consts", + cl::desc("Try to shrink constants (defaults=false)"), + cl::init(false)); } // TODO @@ -750,22 +753,23 @@ std::error_code synthesizeWithKLEE(SynthesisContext &SC, std::vector &RH RHS = nullptr; } } - - // FIXME shrink constants properly, this is a placeholder where we - // just see if we can replace every constant with zero - if (RHS && !ResultConstMap.empty() && DoubleCheckWithAlive) { - std::map ZeroConstMap; - for (auto it : ResultConstMap) { - auto I = it.first; - ZeroConstMap[I] = llvm::APInt(I->Width, 0); + if (TryShrinkConsts) { + // FIXME shrink constants properly, this is a placeholder where we + // just see if we can replace every constant with zero + // TODO(manasij) : Implement binary search, involve alive only when we find a solution + if (RHS && !ResultConstMap.empty() && DoubleCheckWithAlive) { + std::map ZeroConstMap; + for (auto it : ResultConstMap) { + auto I = it.first; + ZeroConstMap[I] = llvm::APInt(I->Width, 0); + } + std::map InstCache; + std::map BlockCache; + auto newRHS = getInstCopy(I, SC.IC, InstCache, BlockCache, &ZeroConstMap, false, false); + if (isTransformationValid(SC.LHS, newRHS, SC.PCs, SC.BPCs, SC.IC)) + RHS = newRHS; } - std::map InstCache; - std::map BlockCache; - auto newRHS = getInstCopy(I, SC.IC, InstCache, BlockCache, &ZeroConstMap, false, false); - if (isTransformationValid(SC.LHS, newRHS, SC.PCs, SC.BPCs, SC.IC)) - RHS = newRHS; } - if (RHS) { RHSs.emplace_back(RHS); if (!SC.CheckAllGuesses) diff --git a/test/Solver/div-by-zero1.ll b/test/Solver/div-by-zero1.ll index 33e5237ea..1aa56e8a6 100644 --- a/test/Solver/div-by-zero1.ll +++ b/test/Solver/div-by-zero1.ll @@ -1,7 +1,7 @@ ; RUN: %llvm-as -o %t %s -; RUN: %souper -check -souper-only-infer-iN -souper-double-check %t +; RUN: %souper -check -souper-only-infer-iN -souper-double-check -souper-shrink-consts=true %t define void @fn1() { entry: diff --git a/test/Solver/div-by-zero2.ll b/test/Solver/div-by-zero2.ll index d3227a627..538857194 100644 --- a/test/Solver/div-by-zero2.ll +++ b/test/Solver/div-by-zero2.ll @@ -1,7 +1,7 @@ ; RUN: %llvm-as -o %t %s -; RUN: %souper -check -souper-only-infer-i1 -souper-double-check %t +; RUN: %souper -check -souper-only-infer-i1 -souper-double-check -souper-shrink-consts=true %t define void @fn1() { entry: diff --git a/test/Solver/div-by-zero3.ll b/test/Solver/div-by-zero3.ll index 57f2aacb1..3c59b6573 100644 --- a/test/Solver/div-by-zero3.ll +++ b/test/Solver/div-by-zero3.ll @@ -1,7 +1,7 @@ ; RUN: %llvm-as -o %t %s -; RUN: %souper -check -souper-only-infer-i1 -souper-double-check %t +; RUN: %souper -check -souper-only-infer-i1 -souper-double-check -souper-shrink-consts=true %t define void @fn1() { entry: From ac139a23694817bb50ffcb80d4e74f536d9c9429 Mon Sep 17 00:00:00 2001 From: John Regehr Date: Tue, 25 May 2021 16:39:55 -0600 Subject: [PATCH 023/165] new verison of patched LLVM 12 and Z3 (#829) --- build_deps.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build_deps.sh b/build_deps.sh index f52f88ff8..4b4ff9ba3 100755 --- a/build_deps.sh +++ b/build_deps.sh @@ -25,14 +25,14 @@ ncpus=$(command nproc 2>/dev/null || command sysctl -n hw.ncpu 2>/dev/null || ec hiredis_commit=667dbf536524ba3f28c1d964793db1055c5a64f2 llvm_repo=https://github.com/regehr/llvm-project.git # llvm_commit specifies the git branch or hash to checkout to -llvm_commit=disable-peepholes-v05 +llvm_commit=disable-peepholes-llvm12-v02 klee_repo=https://github.com/rsas/klee klee_branch=pure-bv-qf-llvm-7.0 alive_commit=v2 alive_repo=https://github.com/manasij7479/alive2.git z3_repo=https://github.com/Z3Prover/z3.git -#z3_commit=z3-4.8.10 -z3_commit=323e0e62705d31edc0ce06c6b4378c45c6b6184d +# latest as of May 25 2021 +z3_commit=322531e95cb7da59b4596000ffbc92d792433f17 llvm_build_type=Release if [ -n "$1" ] ; then From 73ca4ad685297f9f0e44fe6af48e253df3fd8047 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 25 May 2021 18:07:11 -0700 Subject: [PATCH 024/165] Mask out not-demanded bits for concrete interpreter (#830) --- lib/Infer/Pruning.cpp | 7 ++++++- test/Infer/pruning/dontprune.opt | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test/Infer/pruning/dontprune.opt diff --git a/lib/Infer/Pruning.cpp b/lib/Infer/Pruning.cpp index b5e55ff7c..ba560cc39 100644 --- a/lib/Infer/Pruning.cpp +++ b/lib/Infer/Pruning.cpp @@ -414,7 +414,12 @@ bool PruningManager::isInfeasible(souper::Inst *RHS, } else { auto RHSV = ConcreteInterpreters[I].evaluateInst(RHS); if (RHSV.hasValue()) { - if (Val != RHSV.getValue()) { + auto RVal = RHSV.getValue(); + if (SC.LHS->DemandedBits != 0) { + Val &= SC.LHS->DemandedBits; + RVal &= SC.LHS->DemandedBits; + } + if (Val != RVal) { if (StatsLevel > 2) { llvm::errs() << " RHS value = " << RHSV.getValue() << "\n"; llvm::errs() << " pruned using concrete interpreter!\n"; diff --git a/test/Infer/pruning/dontprune.opt b/test/Infer/pruning/dontprune.opt new file mode 100644 index 000000000..c2010064f --- /dev/null +++ b/test/Infer/pruning/dontprune.opt @@ -0,0 +1,18 @@ +; REQUIRES: synthesis + +; RUN: %souper-check -try-dataflow-pruning %s > %t +; RUN: %FileCheck %s < %t + +; CHECK: Pruning failed + +%0 = block 2 +%1:i64 = var +%2:i64 = lshr %1, 16:i64 +%3:i64 = var +%4:i64 = lshr %3, 16:i64 +%5:i64 = phi %0, %2, %4 +%6:i16 = trunc %5 +%7:i32 = zext %6 +infer %7 (demandedBits=00000000000000001111111100000000) +%8:i32 = trunc %5 +result %8 From 6cc0615c16cd6c200d50b70aec799584c8071aee Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 1 Dec 2020 15:29:32 -0700 Subject: [PATCH 025/165] Generalization tool --- lib/Extractor/Solver.cpp | 6 ++++++ tools/generalize.cpp | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/lib/Extractor/Solver.cpp b/lib/Extractor/Solver.cpp index cd9ea2ed2..96ad1c920 100644 --- a/lib/Extractor/Solver.cpp +++ b/lib/Extractor/Solver.cpp @@ -458,6 +458,12 @@ class BaseSolver : public Solver { return EC; } + std::error_code isSatisfiable(llvm::StringRef Query, bool &Result, + unsigned NumModels, + std::vector *Models, + unsigned Timeout = 0) override { + return SMTSolver->isSatisfiable(Query, Result, NumModels, Models, Timeout); + } std::error_code isValid(InstContext &IC, const BlockPCs &BPCs, const std::vector &PCs, diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 826906995..b495ff9be 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -32,6 +32,7 @@ static llvm::cl::opt RemoveLeaf("remove-leaf", "(default=false)"), llvm::cl::init(false)); +<<<<<<< HEAD static llvm::cl::opt SymbolizeConstant("symbolize", llvm::cl::desc("Try to replace a concrete constant with a symbolic constant." "(default=false)"), @@ -46,16 +47,21 @@ static llvm::cl::opt SymbolizeNoDFP("symbolize-no-dataflow", llvm::cl::desc("Do not generate optimizations with dataflow preconditions."), llvm::cl::init(false)); +======= +>>>>>>> 04440f0 (Generalization tool) static llvm::cl::opt FixIt("fixit", llvm::cl::desc("Given an invalid optimization, generate a valid one." "(default=false)"), llvm::cl::init(false)); +<<<<<<< HEAD static cl::opt NumResults("generalization-num-results", cl::desc("Number of Generalization Results"), cl::init(5)); +======= +>>>>>>> 04440f0 (Generalization tool) void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { bool FoundWP = false; std::vector> Results; @@ -74,6 +80,7 @@ void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { } } +<<<<<<< HEAD void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::vector LHSConsts, std::vector RHSConsts, @@ -227,6 +234,12 @@ void SymbolizeAndGeneralize(InstContext &IC, // TODO: Return modified instructions instead of just printing out void RemoveLeafAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input) { +======= +// TODO: Return modified instructions instead of just printing out +void RemoveLeafAndGeneralize(InstContext &IC, + Solver *S, ParsedReplacement Input) { + +>>>>>>> 04440f0 (Generalization tool) if (DebugLevel > 1) { llvm::errs() << "Attempting to generalize by removing leaf.\n"; } @@ -324,9 +337,13 @@ int main(int argc, char **argv) { RemoveLeafAndGeneralize(IC, S.get(), Input); } // if (EviscerateRoot) {...} +<<<<<<< HEAD if (SymbolizeConstant) { SymbolizeAndGeneralize(IC, S.get(), Input); } +======= + // if (SymbolizeConstant) {...} +>>>>>>> 04440f0 (Generalization tool) // if (LiberateWidth) {...} } From a098f3cf969c904b68efa6bc4a456465ccb92c30 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 26 May 2021 12:03:21 -0500 Subject: [PATCH 026/165] temp --- tools/generalize.cpp | 79 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index b495ff9be..6a8cd1bb9 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -47,21 +47,20 @@ static llvm::cl::opt SymbolizeNoDFP("symbolize-no-dataflow", llvm::cl::desc("Do not generate optimizations with dataflow preconditions."), llvm::cl::init(false)); -======= ->>>>>>> 04440f0 (Generalization tool) static llvm::cl::opt FixIt("fixit", llvm::cl::desc("Given an invalid optimization, generate a valid one." "(default=false)"), llvm::cl::init(false)); -<<<<<<< HEAD +static llvm::cl::opt GeneralizeWidth("generalize-width", + llvm::cl::desc("Given a valid optimization, generalize bitwidth." + "(default=false)"), + llvm::cl::init(false)); + static cl::opt NumResults("generalization-num-results", cl::desc("Number of Generalization Results"), cl::init(5)); - -======= ->>>>>>> 04440f0 (Generalization tool) void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { bool FoundWP = false; std::vector> Results; @@ -231,15 +230,61 @@ void SymbolizeAndGeneralize(InstContext &IC, } } +size_t InferWidth(Inst::Kind K, const std::vector &Ops) { + switch (K) { + case Inst::And: + case Inst::Or: + case Inst::Xor: + case Inst::Sub: + case Inst::Mul: + case Inst::Add: return Ops[0]->Width; + case Inst::Slt: + case Inst::Sle: + case Inst::Ult: + case Inst::Ule: return 1; + default: llvm_unreachable((std::string("Unimplemented ") + Inst::getKindName(K)).c_str()); + } +} + +Inst *CloneInst(InstContext &IC, Inst *I, std::map &WidthMap) { + if (I->K == Inst::Var) { + return IC.createVar(WidthMap[I], I->Name); // TODO other attributes + } else if (I->K == Inst::Const) { + llvm_unreachable("Const"); + } else { + std::vector Ops; + for (auto Op : I->Ops) { + Ops.push_back(CloneInst(IC, Op, WidthMap)); + } + return IC.getInst(I->K, InferWidth(I->K, Ops), Ops); + } +} + +void GeneralizeBitWidth(InstContext &IC, Solver *S, + ParsedReplacement Input) { + auto Vars = IC.getVariablesFor(Input.Mapping.LHS); + + assert(Vars.size() == 1 && "Multiple variables unimplemented."); + + std::map WidthMap; + + for (int i = 1; i < 64; ++i) { + WidthMap[Vars[0]] = i; + auto LHS = CloneInst(IC, Input.Mapping.LHS, WidthMap); + auto RHS = CloneInst(IC, Input.Mapping.RHS, WidthMap); + + ReplacementContext RC; + auto str = RC.printInst(LHS, llvm::outs(), true); + llvm::outs() << "infer " << str << "\n"; + str = RC.printInst(RHS, llvm::outs(), true); + llvm::outs() << "result " << str << "\n\n"; + } + +} + // TODO: Return modified instructions instead of just printing out void RemoveLeafAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input) { -======= -// TODO: Return modified instructions instead of just printing out -void RemoveLeafAndGeneralize(InstContext &IC, - Solver *S, ParsedReplacement Input) { - ->>>>>>> 04440f0 (Generalization tool) if (DebugLevel > 1) { llvm::errs() << "Attempting to generalize by removing leaf.\n"; } @@ -336,15 +381,13 @@ int main(int argc, char **argv) { if (RemoveLeaf) { RemoveLeafAndGeneralize(IC, S.get(), Input); } - // if (EviscerateRoot) {...} -<<<<<<< HEAD if (SymbolizeConstant) { SymbolizeAndGeneralize(IC, S.get(), Input); } -======= - // if (SymbolizeConstant) {...} ->>>>>>> 04440f0 (Generalization tool) - // if (LiberateWidth) {...} + + if (GeneralizeWidth) { + GeneralizeBitWidth(IC, S.get(), Input); + } } return 0; From 4b785dbd2ace8229a19506e476a874a18fa3b251 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 15 Sep 2021 11:46:43 -0600 Subject: [PATCH 027/165] foo --- lib/Extractor/Solver.cpp | 7 ------- tools/generalize.cpp | 3 +-- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/Extractor/Solver.cpp b/lib/Extractor/Solver.cpp index 96ad1c920..c40529bc1 100644 --- a/lib/Extractor/Solver.cpp +++ b/lib/Extractor/Solver.cpp @@ -435,13 +435,6 @@ class BaseSolver : public Solver { return EC; } - std::error_code isSatisfiable(llvm::StringRef Query, bool &Result, - unsigned NumModels, - std::vector *Models, - unsigned Timeout = 0) override { - return SMTSolver->isSatisfiable(Query, Result, NumModels, Models, Timeout); - } - std::error_code infer(const BlockPCs &BPCs, const std::vector &PCs, Inst *LHS, std::vector &RHSs, diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 6a8cd1bb9..b70637b40 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -32,7 +32,6 @@ static llvm::cl::opt RemoveLeaf("remove-leaf", "(default=false)"), llvm::cl::init(false)); -<<<<<<< HEAD static llvm::cl::opt SymbolizeConstant("symbolize", llvm::cl::desc("Try to replace a concrete constant with a symbolic constant." "(default=false)"), @@ -79,7 +78,7 @@ void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { } } -<<<<<<< HEAD + void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::vector LHSConsts, std::vector RHSConsts, From 829ac756a40f070163e0073f6133cdb1c70b42b2 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 27 Sep 2021 13:53:17 -0600 Subject: [PATCH 028/165] foo --- tools/generalize.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index b70637b40..1e570a1e9 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -149,9 +149,10 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::vector> Results; bool FoundWP = false; - InstMapping Mapping(LHS, RHS); - S->abstractPrecondition(Input.BPCs, Input.PCs, Mapping, IC, FoundWP, Results); - + if (!SymbolizeNoDFP) { + InstMapping Mapping(LHS, RHS); + S->abstractPrecondition(Input.BPCs, Input.PCs, Mapping, IC, FoundWP, Results); + } Preconditions.push_back(Results); if (!FoundWP) { Guess = nullptr; // TODO: Better failure indicator @@ -191,17 +192,17 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, } } - if (!SymbolizeNoDFP) { - for (size_t i = 0; i < std::min(Idx.size(), NumResults.getValue()); ++i) { - for (auto Computed : Preconditions[Idx[i]]) { - for (auto Pair : Computed) { - Pair.first->KnownOnes = Pair.second.One; - Pair.first->KnownZeros = Pair.second.Zero; - } - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHS, Guesses[Idx[i]]))); - } - } - } + // if (!SymbolizeNoDFP) { + // for (size_t i = 0; i < std::min(Idx.size(), NumResults.getValue()); ++i) { + // for (auto Computed : Preconditions[Idx[i]]) { + // for (auto Pair : Computed) { + // Pair.first->KnownOnes = Pair.second.One; + // Pair.first->KnownZeros = Pair.second.Zero; + // } + // Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHS, Guesses[Idx[i]]))); + // } + // } + // } } void SymbolizeAndGeneralize(InstContext &IC, From 2beedf613019ca82a3ef9bf6a68f04267f1e0f66 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 22 Oct 2021 13:40:56 -0600 Subject: [PATCH 029/165] foo --- include/souper/Extractor/Solver.h | 3 ++- include/souper/Infer/Preconditions.h | 10 ++++++++++ lib/Extractor/Solver.cpp | 18 +++++++++++------ lib/Infer/Preconditions.cpp | 30 ++++++++++++++++++++++++++++ tools/generalize.cpp | 27 ++++++++++++++++--------- tools/souper-check.cpp | 13 ++++++------ 6 files changed, 79 insertions(+), 22 deletions(-) diff --git a/include/souper/Extractor/Solver.h b/include/souper/Extractor/Solver.h index 11488e186..3044dbd5a 100644 --- a/include/souper/Extractor/Solver.h +++ b/include/souper/Extractor/Solver.h @@ -97,7 +97,8 @@ class Solver { std::error_code abstractPrecondition(const BlockPCs &BPCs, const std::vector &PCs, InstMapping &Mapping, InstContext &IC, bool &FoundWeakest, - std::vector> &Results) = 0; + std::vector> &KBResults, + std::vector> &CRResults) = 0; }; std::unique_ptr createBaseSolver( diff --git a/include/souper/Infer/Preconditions.h b/include/souper/Infer/Preconditions.h index c5970d0b7..aecfff26e 100644 --- a/include/souper/Infer/Preconditions.h +++ b/include/souper/Infer/Preconditions.h @@ -3,13 +3,23 @@ #include "souper/Inst/Inst.h" #include "llvm/Support/KnownBits.h" +#include "llvm/IR/ConstantRange.h" extern unsigned DebugLevel; namespace souper { class SMTLIBSolver; class Solver; + +std::pair>, +std::vector>> +inferAbstractPreconditions(SynthesisContext &SC, Inst *RHS, + Solver *S, bool &FoundWeakest); + std::vector> inferAbstractKBPreconditions(SynthesisContext &SC, Inst *RHS, Solver *S, bool &FoundWeakest); +std::vector> + inferAbstractCRPreconditions(SynthesisContext &SC, Inst *RHS, + Solver *S, bool &FoundWeakest); } #endif // SOUPER_PRECONDITIONS_H diff --git a/lib/Extractor/Solver.cpp b/lib/Extractor/Solver.cpp index c40529bc1..e250eacb4 100644 --- a/lib/Extractor/Solver.cpp +++ b/lib/Extractor/Solver.cpp @@ -267,11 +267,13 @@ class BaseSolver : public Solver { std::error_code abstractPrecondition(const BlockPCs &BPCs, const std::vector &PCs, InstMapping &Mapping, InstContext &IC, bool &FoundWeakest, - std::vector> &Results) override { + std::vector> &KBResults, + std::vector> &CRResults) override { SynthesisContext SC{IC, SMTSolver.get(), Mapping.LHS, /*LHSUB*/nullptr, PCs, BPCs, /*CheckAllGuesses=*/false, Timeout}; - Results = inferAbstractKBPreconditions(SC, Mapping.RHS, this, FoundWeakest); + std::tie(KBResults, CRResults) = + inferAbstractPreconditions(SC, Mapping.RHS, this, FoundWeakest); return {}; } @@ -750,8 +752,10 @@ class MemCachingSolver : public Solver { std::error_code abstractPrecondition(const BlockPCs &BPCs, const std::vector &PCs, InstMapping &Mapping, InstContext &IC, bool &FoundWeakest, - std::vector> &Results) override { - return UnderlyingSolver->abstractPrecondition(BPCs, PCs, Mapping, IC, FoundWeakest, Results); + std::vector> &KBResults, + std::vector> &CRResults) override { + return UnderlyingSolver->abstractPrecondition(BPCs, PCs, Mapping, IC, FoundWeakest, + KBResults, CRResults); } std::error_code knownBits(const BlockPCs &BPCs, @@ -897,8 +901,10 @@ class ExternalCachingSolver : public Solver { std::error_code abstractPrecondition(const BlockPCs &BPCs, const std::vector &PCs, InstMapping &Mapping, InstContext &IC, bool &FoundWeakest, - std::vector> &Results) override { - return UnderlyingSolver->abstractPrecondition(BPCs, PCs, Mapping, IC, FoundWeakest, Results); + std::vector> &KBResults, + std::vector> &CRResults) override { + return UnderlyingSolver->abstractPrecondition(BPCs, PCs, Mapping, IC, FoundWeakest, + KBResults, CRResults); } std::error_code knownBits(const BlockPCs &BPCs, diff --git a/lib/Infer/Preconditions.cpp b/lib/Infer/Preconditions.cpp index 991f1d96a..b07821719 100644 --- a/lib/Infer/Preconditions.cpp +++ b/lib/Infer/Preconditions.cpp @@ -9,7 +9,37 @@ static llvm::cl::opt FixItNoVar("fixit-no-restrict-vars", "(default=false)"), llvm::cl::init(false)); +static llvm::cl::opt GenCR("gencr", + llvm::cl::desc("Generate a CR precondition." + "(default=false)"), + llvm::cl::init(false)); + +static llvm::cl::opt GenKB("genkb", + llvm::cl::desc("Generate a KB precondition." + "(default=true)"), +llvm::cl::init(true)); + + namespace souper { + +std::pair>, +std::vector>> +inferAbstractPreconditions(SynthesisContext &SC, Inst *RHS, + Solver *S, bool &FoundWeakest) { + + std::vector> CRResults; + std::vector> KBResults; + if (GenKB) KBResults = inferAbstractKBPreconditions(SC, RHS, S, FoundWeakest); + if (GenCR) CRResults = inferAbstractCRPreconditions(SC, RHS, S, FoundWeakest); + return std::make_pair(KBResults, CRResults); +} + +std::vector> + inferAbstractCRPreconditions(SynthesisContext &SC, Inst *RHS, + Solver *S, bool &FoundWeakest) { + return {}; +} + std::vector> inferAbstractKBPreconditions(SynthesisContext &SC, Inst *RHS, Solver *S, bool &FoundWeakest) { diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 1e570a1e9..3cdfdfb97 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -62,19 +62,27 @@ static cl::opt NumResults("generalization-num-results", void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { bool FoundWP = false; - std::vector> Results; - S->abstractPrecondition(Input.BPCs, Input.PCs, Input.Mapping, IC, FoundWP, Results); + std::vector> KBResults; + std::vector> CRResults; + S->abstractPrecondition(Input.BPCs, Input.PCs, Input.Mapping, IC, FoundWP, KBResults, CRResults); - if (FoundWP && Results.empty()) { + if (FoundWP && KBResults.empty() && CRResults.empty()) { Input.print(llvm::outs(), true); - } else { - for (auto &&Result : Results) { // Each result is a disjunction - for (auto Pair: Result) { + } else if (!KBResults.empty()) { + for (auto &&Result : KBResults) { // Each result is a disjunction + for (auto &Pair: Result) { Pair.first->KnownOnes = Pair.second.One; Pair.first->KnownZeros = Pair.second.Zero; } Input.print(llvm::outs(), true); } + } else if (!CRResults.empty()) { + for (auto &&Result : CRResults) { // Each result is a disjunction + for (auto &Pair: Result) { + Pair.first->Range = Pair.second; + } + Input.print(llvm::outs(), true); + } } } @@ -147,13 +155,14 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, BlockCache, &ConstMap, false); - std::vector> Results; + std::vector> KBResults; + std::vector> CRResults; bool FoundWP = false; if (!SymbolizeNoDFP) { InstMapping Mapping(LHS, RHS); - S->abstractPrecondition(Input.BPCs, Input.PCs, Mapping, IC, FoundWP, Results); + S->abstractPrecondition(Input.BPCs, Input.PCs, Mapping, IC, FoundWP, KBResults, CRResults); } - Preconditions.push_back(Results); + Preconditions.push_back(KBResults); if (!FoundWP) { Guess = nullptr; // TODO: Better failure indicator } else { diff --git a/tools/souper-check.cpp b/tools/souper-check.cpp index 0e2c62a3c..3efc3e416 100644 --- a/tools/souper-check.cpp +++ b/tools/souper-check.cpp @@ -325,8 +325,9 @@ int SolveInst(const MemoryBufferRef &MB, Solver *S) { } } else if (InferAP) { bool FoundWeakest = false; - std::vector> Results; - S->abstractPrecondition(Rep.BPCs, Rep.PCs, Rep.Mapping, IC, FoundWeakest, Results); + std::vector> KBResults; + std::vector> CRResults; + S->abstractPrecondition(Rep.BPCs, Rep.PCs, Rep.Mapping, IC, FoundWeakest, KBResults, CRResults); if (!FoundWeakest) { llvm::outs() << "Failed to find WP.\n"; } @@ -335,8 +336,8 @@ int SolveInst(const MemoryBufferRef &MB, Solver *S) { llvm::outs() << "infer " << LHSStr << "\n"; auto RHSStr = RC.printInst(Rep.Mapping.RHS, llvm::outs(), true); llvm::outs() << "result " << RHSStr << "\n"; - for (size_t i = 0; i < Results.size(); ++i) { - for (auto It = Results[i].begin(); It != Results[i].end(); ++It) { + for (size_t i = 0; i < KBResults.size(); ++i) { + for (auto It = KBResults[i].begin(); It != KBResults[i].end(); ++It) { auto &&P = *It; std::string dummy; llvm::raw_string_ostream str(dummy); @@ -345,11 +346,11 @@ int SolveInst(const MemoryBufferRef &MB, Solver *S) { auto Next = It; Next++; - if (Next != Results[i].end()) { + if (Next != KBResults[i].end()) { llvm::outs() << " (and) "; } } - if (i == Results.size() - 1) { + if (i == KBResults.size() - 1) { llvm::outs() << "\n"; } else { llvm::outs() << "\n(or)\n"; From ef23122d52e8ded390b2711122ba18ba765c4b3c Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 26 Oct 2021 15:22:19 -0600 Subject: [PATCH 030/165] foo --- lib/Infer/Preconditions.cpp | 132 +++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/lib/Infer/Preconditions.cpp b/lib/Infer/Preconditions.cpp index b07821719..ef9151a4d 100644 --- a/lib/Infer/Preconditions.cpp +++ b/lib/Infer/Preconditions.cpp @@ -37,6 +37,136 @@ inferAbstractPreconditions(SynthesisContext &SC, Inst *RHS, std::vector> inferAbstractCRPreconditions(SynthesisContext &SC, Inst *RHS, Solver *S, bool &FoundWeakest) { + + InstMapping Mapping(SC.LHS, RHS); + bool Valid; + if (DebugLevel >= 3) { + PrintReplacement(llvm::outs(), SC.BPCs, SC.PCs, Mapping); + } + std::vector> Models; + + if (std::error_code EC = S->isValid(SC.IC, SC.BPCs, SC.PCs, Mapping, Valid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + std::vector PCCopy = SC.PCs; + if (Valid) { + FoundWeakest = true; + if (DebugLevel > 1) { + llvm::errs() << "Already valid.\n"; + } + return {}; + } + + std::vector Vars; + findVars(Mapping.LHS, Vars); + std::set FilteredVars; + + for (auto Var : Vars) { + std::string NamePrefix = Var->Name; + NamePrefix.resize(4); + if (!FixItNoVar || Var->K != Inst::Var || NamePrefix == "fake") { + FilteredVars.insert(Var); + } + } + + // std::map OriginalState; + + // for (auto V : Vars) { + // OriginalState[V] = V->Range; + // } + + std::vector> Results; + Inst *Precondition = SC.IC.getConst(llvm::APInt(1, true)); + + std::vector> ValidInputs; + // unlike for known bits, this is not guaranteed to terminate quickly. + size_t Iterations = 0; + while (true) { + if (Iterations >= 10000) { + break; + // TODO adjust this threshold + } else { + Iterations++; + } + + std::vector ModelInsts; + std::vector ModelVals; + + if (!ValidInputs.empty()) { + auto LastInputSet = ValidInputs.back(); + // for (auto V : Vars) { + // V->KnownOnes = OriginalState[V].OriginalOne; + // V->KnownZeros = OriginalState[V].OriginalZero; + // } + Inst *NewPre = nullptr; + for (size_t i = 0; i < Vars.size(); ++i) { + auto &I = Vars[i]; + auto W = I->Width; +// auto Zero = SC.IC.getConst(llvm::APInt(W, 0)); + + auto VarConstraint = SC.IC.getInst(Inst::Ne, 1, {I, SC.IC.getConst(LastInputSet[I])}); + + if (NewPre) { + NewPre = SC.IC.getInst(Inst::Or, 1, {NewPre, VarConstraint}); + } else { + NewPre = VarConstraint; + } + + } + + // Do not find an input belonging to a derived abstract set. + if (NewPre) { + Precondition = SC.IC.getInst(Inst::And, 1, {Precondition, NewPre}); + } + } + + // Find one input for which the given transformation is valid + Models.clear(); + std::string Query = BuildQuery(SC.IC, SC.BPCs, PCCopy, Mapping, + &ModelInsts, Precondition, true); + + + S->isSatisfiable(Query, FoundWeakest, ModelInsts.size(), + &ModelVals, SC.Timeout); + + std::map CurrentCE; + if (FoundWeakest) { + for (unsigned J = 0; J < ModelInsts.size(); ++J) { + if (FilteredVars.find(ModelInsts[J]) != FilteredVars.end()) { + CurrentCE[ModelInsts[J]] = ModelVals[J]; + } else { + auto Zero = llvm::APInt(ModelInsts[J]->Width, 0); + CurrentCE[ModelInsts[J]] = Zero; + } + + if (DebugLevel >= 3) { + llvm::outs() << "Starting with : " << ModelVals[J] << "\n"; + } + } + ValidInputs.push_back(CurrentCE); + } else { + if (ValidInputs.empty()) { + if (DebugLevel >= 3) { + llvm::outs() << "Transformation is not valid for any input.\n"; + } + return {}; + } else { + FoundWeakest = true; + if (DebugLevel >= 3) { + llvm::outs() << "Exhausted search space.\n"; + } + break; + } + } + + // Widen CurrentCE into the largest possible CR which maintains validity + // How to do this?? + + + + + } + return {}; } @@ -89,7 +219,7 @@ std::vector> std::vector> Results; Inst *Precondition = SC.IC.getConst(llvm::APInt(1, true)); - while (true) { // guaranteed to terminate + while (true) { // guaranteed to terminate in O(Width) if (!Results.empty()) { bool foundNonTop = false;; for (auto R : Results) { From 1b216ff1c8e6e896c501181356144f5f42888597 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 6 Oct 2021 11:06:57 -0600 Subject: [PATCH 031/165] foo --- tools/generalize.cpp | 170 +++++++++++++++++++++++++++++++------------ 1 file changed, 125 insertions(+), 45 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 3cdfdfb97..17ac0b8c5 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -26,9 +26,13 @@ static cl::opt InputFilename(cl::Positional, cl::desc(""), cl::init("-")); -static llvm::cl::opt RemoveLeaf("remove-leaf", - llvm::cl::desc("Try to generalize a valid optimization by replacing" - "the use of a once-used variable with a new variable" +static llvm::cl::opt Reduce("reduce", + llvm::cl::desc("Try to reduce the number of instructions by replacing instructions with variables." + "(default=false)"), + llvm::cl::init(false)); + +static llvm::cl::opt ReducePrintAll("reduce-all-results", + llvm::cl::desc("Print all reduced results." "(default=false)"), llvm::cl::init(false)); @@ -291,68 +295,144 @@ void GeneralizeBitWidth(InstContext &IC, Solver *S, } -// TODO: Return modified instructions instead of just printing out -void RemoveLeafAndGeneralize(InstContext &IC, - Solver *S, ParsedReplacement Input) { - if (DebugLevel > 1) { - llvm::errs() << "Attempting to generalize by removing leaf.\n"; +void collectInsts(Inst *I, std::unordered_set &Results) { + std::vector Stack{I}; + while (!Stack.empty()) { + auto Current = Stack.back(); + Stack.pop_back(); + + Results.insert(Current); + + for (auto Child : Current->Ops) { + if (Results.find(Child) == Results.end()) { + Stack.push_back(Child); + } + } + } +} +void ReduceRec(InstContext &IC, + Solver *S, ParsedReplacement Input_, std::vector &Results, std::unordered_set &DNR) { + auto Str = Input_.getString(false); + if (DNR.find(Str) != DNR.end()) { + return; + } else { + DNR.insert(Str); } - // TODO: Do not generalize by removing leaf if LHS has one inst. - std::map> Uses; + static int varnum = 0; // persistent state, maybe 'oop' away at some point. - std::vector Stack{Input.Mapping.LHS, Input.Mapping.RHS}; - // TODO: Find uses in PCs/BPCs + std::unordered_set Insts; + collectInsts(Input_.Mapping.LHS, Insts); + collectInsts(Input_.Mapping.RHS, Insts); - std::set Visited; - while (!Stack.empty()) { - auto Current = Stack.back(); - Stack.pop_back(); - Visited.insert(Current); - - for (auto Op : Current->Ops) { - if (Op->K == Inst::Var) { - Uses[Op].insert(Current); - // Intentionally skips root - } - if (Visited.find(Op) == Visited.end()) { - Stack.push_back(Op); - } - } + for (auto &&PC : Input_.PCs) { + collectInsts(PC.LHS, Insts); + collectInsts(PC.RHS, Insts); } - // Find a variable with one use; - Inst *UsedOnce = nullptr; - for (auto P : Uses) { - if (P.second.size() == 1) { - UsedOnce = P.first; - break; - } + for (auto &&BPC : Input_.BPCs) { + collectInsts(BPC.PC.LHS, Insts); + collectInsts(BPC.PC.RHS, Insts); } - if (!UsedOnce) { - llvm::outs() << "Failed. No var with one use."; - return; - } else { - Inst *User = *Uses[UsedOnce].begin(); - Inst *NewVar = IC.createVar(User->Width, "newvar"); + if (Insts.size() <= 1) { + return; // Base case + } + + // Remove at least one instruction and call recursively for valid opts + for (auto I : Insts) { + ParsedReplacement Input = Input_; + + if (I == Input.Mapping.LHS || I == Input.Mapping.RHS || I->K == Inst::Var || I->K == Inst::Const) { + continue; + } + + // Try to replace I with a new Var. + Inst *NewVar = IC.createVar(I->Width, "newvar" + std::to_string(varnum++)); std::map ICache; - ICache[User] = NewVar; + ICache[I] = NewVar; std::map BCache; std::map CMap; + ParsedReplacement NewInst = Input; + Input.Mapping.LHS = getInstCopy(Input.Mapping.LHS, IC, ICache, BCache, &CMap, false); Input.Mapping.RHS = getInstCopy(Input.Mapping.RHS, IC, ICache, BCache, &CMap, false); - // TODO: Replace PCs/BPCs + for (auto &M : Input.PCs) { + M.LHS = getInstCopy(M.LHS, IC, ICache, BCache, &CMap, false); + M.RHS = getInstCopy(M.RHS, IC, ICache, BCache, &CMap, false); + } + for (auto &BPC : Input.BPCs) { + BPC.PC.LHS = getInstCopy(BPC.PC.LHS, IC, ICache, BCache, &CMap, false); + BPC.PC.RHS = getInstCopy(BPC.PC.RHS, IC, ICache, BCache, &CMap, false); + } + + std::vector> Models; + bool Valid; + if (std::error_code EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, Valid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + + if (Valid) { + Results.push_back(Input); + ReduceRec(IC, S, Input, Results, DNR); + } else { + if (DebugLevel >= 2) { + llvm::outs() << "Invalid attempt.\n"; + Input.print(llvm::outs(), true); + } + } + } +} + +void ReduceAndGeneralize(InstContext &IC, + Solver *S, ParsedReplacement Input) { + std::vector> Models; + bool Valid; + if (std::error_code EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, Valid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + if (!Valid) { + llvm::errs() << "Invalid Input.\n"; + return; } - Generalize(IC, S, Input); + std::vector Results; + std::unordered_set DoNotRepeat; + ReduceRec(IC, S, Input, Results, DoNotRepeat); + + if (!Results.empty()) { + std::set DedupedResults; + for (auto &&Result : Results) { + DedupedResults.insert(Result.getString(false)); + } + + std::vector SortedResults(DedupedResults.begin(), DedupedResults.end()); + std::sort(SortedResults.begin(), SortedResults.end(), [](auto a, auto b){return a.length() < b.length();}); + + for (auto &&S : SortedResults) { + if (DebugLevel > 2) { + llvm::outs() << "\n\nResult:\n"; + } + llvm::outs() << S << '\n'; + if (!ReducePrintAll) { + break; + } + } + } else { + if (DebugLevel > 2) { + llvm::errs() << "Failed to Generalize.\n"; + } + } + if (DebugLevel > 2) { + llvm::outs() << "Number of Results: " << Results.size() << ".\n"; + } } int main(int argc, char **argv) { @@ -387,8 +467,8 @@ int main(int argc, char **argv) { // TODO: Verify that inputs are valid optimizations Generalize(IC, S.get(), Input); } - if (RemoveLeaf) { - RemoveLeafAndGeneralize(IC, S.get(), Input); + if (Reduce) { + ReduceAndGeneralize(IC, S.get(), Input); } if (SymbolizeConstant) { SymbolizeAndGeneralize(IC, S.get(), Input); From e41801ee22d2be029377ac5746a5c1d35f8a59bf Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 3 Nov 2021 16:43:04 -0600 Subject: [PATCH 032/165] foo --- tools/generalize.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 17ac0b8c5..1f7af55d3 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -426,6 +426,7 @@ void ReduceAndGeneralize(InstContext &IC, } } } else { + Input.print(llvm::outs(), true); if (DebugLevel > 2) { llvm::errs() << "Failed to Generalize.\n"; } From 5fa37a1eebcf6114fb9305e279418c738bdf34d3 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 19 Nov 2021 15:52:25 -0700 Subject: [PATCH 033/165] foo --- tools/generalize.cpp | 83 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 1f7af55d3..53f1bfebf 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -310,9 +310,27 @@ void collectInsts(Inst *I, std::unordered_set &Results) { } } } + void ReduceRec(InstContext &IC, Solver *S, ParsedReplacement Input_, std::vector &Results, std::unordered_set &DNR) { - auto Str = Input_.getString(false); + + ReplacementContext RC; + std::string Str; + llvm::raw_string_ostream SStr(Str); + RC.printInst(Input_.Mapping.LHS, SStr, false); + + Inst *Ante = IC.getConst(llvm::APInt(1, true)); + for (auto PC : Input_.PCs ) { + Inst *Eq = IC.getInst(Inst::Eq, 1, {PC.LHS, PC.RHS}); + Ante = IC.getInst(Inst::And, 1, {Ante, Eq}); + } + + RC.printInst(Ante, SStr, false); + SStr.flush(); + +// llvm::errs() << Str << "\n"; + +// auto Str = Input_.getString(false); if (DNR.find(Str) != DNR.end()) { return; } else { @@ -320,20 +338,21 @@ void ReduceRec(InstContext &IC, } static int varnum = 0; // persistent state, maybe 'oop' away at some point. + static int numSolverCalls = 0; std::unordered_set Insts; collectInsts(Input_.Mapping.LHS, Insts); collectInsts(Input_.Mapping.RHS, Insts); - for (auto &&PC : Input_.PCs) { - collectInsts(PC.LHS, Insts); - collectInsts(PC.RHS, Insts); - } +// for (auto &&PC : Input_.PCs) { +// collectInsts(PC.LHS, Insts); +// collectInsts(PC.RHS, Insts); +// } - for (auto &&BPC : Input_.BPCs) { - collectInsts(BPC.PC.LHS, Insts); - collectInsts(BPC.PC.RHS, Insts); - } +// for (auto &&BPC : Input_.BPCs) { +// collectInsts(BPC.PC.LHS, Insts); +// collectInsts(BPC.PC.RHS, Insts); +// } if (Insts.size() <= 1) { return; // Base case @@ -343,7 +362,13 @@ void ReduceRec(InstContext &IC, for (auto I : Insts) { ParsedReplacement Input = Input_; - if (I == Input.Mapping.LHS || I == Input.Mapping.RHS || I->K == Inst::Var || I->K == Inst::Const) { + if (I == Input.Mapping.LHS || I == Input.Mapping.RHS || I->K == Inst::Var || I->K == Inst::Const || + I->K == Inst::UMulWithOverflow || I->K == Inst::UMulO || + I->K == Inst::SMulWithOverflow || I->K == Inst::SMulO || + I->K == Inst::UAddWithOverflow || I->K == Inst::UAddO || + I->K == Inst::SAddWithOverflow || I->K == Inst::SAddO || + I->K == Inst::USubWithOverflow || I->K == Inst::USubO || + I->K == Inst::SSubWithOverflow || I->K == Inst::SSubO) { continue; } @@ -378,6 +403,8 @@ void ReduceRec(InstContext &IC, if (std::error_code EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, Valid, &Models)) { llvm::errs() << EC.message() << '\n'; } + numSolverCalls++; + llvm::errs() << "Solver Calls: " << numSolverCalls << "\n"; if (Valid) { Results.push_back(Input); @@ -391,6 +418,41 @@ void ReduceRec(InstContext &IC, } } +// Assumes Input is valid +ParsedReplacement ReducePCs(InstContext &IC, + Solver *S, ParsedReplacement Input) { + + std::set UnnecessaryPCs; + for (size_t i =0; i < Input.PCs.size(); ++i) { + std::vector PCsExceptOne; + for (size_t j = 0; j < Input.PCs.size(); ++j) { + if (i != j) { + PCsExceptOne.push_back(Input.PCs[i]); + } + } + + std::vector> Models; + bool Valid; + if (std::error_code EC = S->isValid(IC, Input.BPCs, PCsExceptOne, Input.Mapping, Valid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + if (Valid) { + UnnecessaryPCs.insert(i); + } + } + + std::vector NecessaryPCs; + for (size_t i =0; i < Input.PCs.size(); ++i) { + if (UnnecessaryPCs.find(i) == UnnecessaryPCs.end()) { + NecessaryPCs.push_back(Input.PCs[i]); + } + } + + auto Result = Input; + Result.PCs = NecessaryPCs; + return Result; +} + void ReduceAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input) { std::vector> Models; @@ -405,6 +467,7 @@ void ReduceAndGeneralize(InstContext &IC, std::vector Results; std::unordered_set DoNotRepeat; + Input = ReducePCs(IC, S, Input); ReduceRec(IC, S, Input, Results, DoNotRepeat); if (!Results.empty()) { From b5de91142c481c5fb76fdadfecab4860768b297e Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 30 Nov 2021 18:37:30 -0700 Subject: [PATCH 034/165] foo --- tools/generalize.cpp | 438 ++++++++++++++++++++++++++++--------------- 1 file changed, 286 insertions(+), 152 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 53f1bfebf..f1297c46d 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -119,33 +119,72 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::vector WithoutConsts; + auto TryConstSynth = [&](Inst *Guess, std::set &ConstSet) { + std::map ResultConstMap; + std::map InstCacheCopy/* = InstCache*/; + InstCacheCopy[RHSConsts[0]] = Guess; + auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, + BlockCache, &ConstMap, false); + ConstantSynthesis CS; + auto SMTSolver = GetUnderlyingSolver(); + auto EC = CS.synthesize(SMTSolver.get(), Input.BPCs, Input.PCs, + InstMapping (LHS, RHS), ConstSet, + ResultConstMap, IC, /*MaxTries=*/30, 10, + /*AvoidNops=*/true); + if (!ResultConstMap.empty()) { + std::map InstCache; + std::map BlockCache; + auto LHSCopy = getInstCopy(LHS, IC, InstCache, BlockCache, &ResultConstMap, true); + RHS = getInstCopy(RHS, IC, InstCache, BlockCache, &ResultConstMap, true); + + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHSCopy, RHS))); + return true; + } else { + if (DebugLevel > 2) { + llvm::errs() << "Constant Synthesis ((no Dataflow Preconditions)) failed. \n"; + } + } + return false; + }; + + for (auto &Guess : Guesses) { std::set ConstSet; - std::map ResultConstMap; souper::getConstants(Guess, ConstSet); if (!ConstSet.empty()) { - std::map InstCacheCopy = InstCache; - InstCacheCopy[RHSConsts[0]] = Guess; - auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, - BlockCache, &ConstMap, false); - ConstantSynthesis CS; - auto SMTSolver = GetUnderlyingSolver(); - auto EC = CS.synthesize(SMTSolver.get(), Input.BPCs, Input.PCs, - InstMapping (LHS, RHS), ConstSet, - ResultConstMap, IC, /*MaxTries=*/30, 10, - /*AvoidNops=*/true); - if (!ResultConstMap.empty()) { - std::map InstCache; - std::map BlockCache; - RHS = getInstCopy(RHS, IC, InstCache, BlockCache, &ResultConstMap, false); - - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHS, RHS))); + bool Success = TryConstSynth(Guess, ConstSet); +// llvm::errs() << "Succ:" << Success << "\n"; + if (!Success) { + FakeConsts[0]->PowOfTwo = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->PowOfTwo = false; + } +// llvm::errs() << "Succ:" << Success << "\n"; - } else { - if (DebugLevel > 2) { - llvm::errs() << "Costant Synthesis ((no Dataflow Preconditions)) failed. \n"; - } + + + if (!Success) { + FakeConsts[0]->NonZero = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->NonZero = false; + } +// llvm::errs() << "Succ:" << Success << "\n"; + + if (!Success) { + FakeConsts[0]->NonNegative = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->NonNegative = false; + } +// llvm::errs() << "Succ:" << Success << "\n"; + + if (!Success) { + FakeConsts[0]->Negative = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->Negative = false; } +// llvm::errs() << "Succ:" << Success << "\n"; + (void)Success; + } else { WithoutConsts.push_back(Guess); } @@ -153,57 +192,89 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::swap(WithoutConsts, Guesses); for (auto &Guess : Guesses) { - std::map InstCacheCopy = InstCache; + std::map InstCacheCopy/* = InstCache*/; InstCacheCopy[RHSConsts[0]] = Guess; +// { +// llvm::errs() << "GUESS:\n"; +// ReplacementContext RC; +// RC.printInst(Guess, llvm::errs(), true); +// } + auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, BlockCache, &ConstMap, false); - std::vector> KBResults; - std::vector> CRResults; - bool FoundWP = false; - if (!SymbolizeNoDFP) { - InstMapping Mapping(LHS, RHS); - S->abstractPrecondition(Input.BPCs, Input.PCs, Mapping, IC, FoundWP, KBResults, CRResults); - } - Preconditions.push_back(KBResults); - if (!FoundWP) { - Guess = nullptr; // TODO: Better failure indicator - } else { - Guess = RHS; - } - } +// { +// llvm::errs() << "JoinedGUESS:\n"; +// ReplacementContext RC; +// RC.printInst(RHS, llvm::errs(), true); +// } + + InstMapping Mapping(LHS, RHS); + if (SymbolizeNoDFP) { + bool IsValid; + auto CheckAndSave = [&](){ + std::vector> Models; + if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Mapping, IsValid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + if (IsValid) { + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Mapping)); + } + }; + CheckAndSave(); + if (!IsValid) { + FakeConsts[0]->PowOfTwo = true; + CheckAndSave(); + FakeConsts[0]->PowOfTwo = false; + } - std::vector Idx; - std::vector Utility; - for (size_t i = 0; i < Guesses.size(); ++i) { - Idx.push_back(i); - } - for (size_t i = 0; i < Preconditions.size(); ++i) { - Utility.push_back(0); - if (!Guesses[i]) continue; - if (Preconditions[i].empty()) { - Utility[i] = 1000; // High magic number - } - for (auto V : Preconditions[i]) { - for (auto P : V) { - auto W = P.second.getBitWidth(); - Utility[i] += (W - P.second.Zero.countPopulation()); - Utility[i] += (W - P.second.One.countPopulation()); - } + + } else { +// std::vector> KBResults; +// std::vector> CRResults; +// bool FoundWP = false; +// S->abstractPrecondition(Input.BPCs, Input.PCs, Mapping, IC, FoundWP, KBResults, CRResults); +// Preconditions.push_back(KBResults); +// if (!FoundWP) { +// Guess = nullptr; // TODO: Better failure indicator +// } else { +// Guess = RHS; +// } } } - std::sort(Idx.begin(), Idx.end(), [&Utility](size_t a, size_t b) { - return Utility[a] > Utility[b]; - }); +// std::vector Idx; +// std::vector Utility; +// for (size_t i = 0; i < Guesses.size(); ++i) { +// Idx.push_back(i); +// } +// for (size_t i = 0; i < Preconditions.size(); ++i) { +// Utility.push_back(0); +// if (!Guesses[i]) continue; +// if (Preconditions[i].empty()) { +// Utility[i] = 1000; // High magic number +// } + +// for (auto V : Preconditions[i]) { +// for (auto P : V) { +// auto W = P.second.getBitWidth(); +// Utility[i] += (W - P.second.Zero.countPopulation()); +// Utility[i] += (W - P.second.One.countPopulation()); +// } +// } +// } + +// std::sort(Idx.begin(), Idx.end(), [&Utility](size_t a, size_t b) { +// return Utility[a] > Utility[b]; +// }); - for (size_t i = 0; i < Idx.size(); ++i) { - if (Preconditions[Idx[i]].empty() && Guesses[Idx[i]]) { - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHS, Guesses[Idx[i]]))); - } - } +// for (size_t i = 0; i < Idx.size(); ++i) { +// if (Preconditions[Idx[i]].empty() && Guesses[Idx[i]]) { +// Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHS, Guesses[Idx[i]]))); +// } +// } // if (!SymbolizeNoDFP) { // for (size_t i = 0; i < std::min(Idx.size(), NumResults.getValue()); ++i) { @@ -234,7 +305,7 @@ void SymbolizeAndGeneralize(InstContext &IC, // TODO: Two at a time, etc. Is this replaceable by DFP? // All at once - SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); +// SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); // TODO: Move sorting here for (auto &&Result : Results) { @@ -295,7 +366,7 @@ void GeneralizeBitWidth(InstContext &IC, Solver *S, } -void collectInsts(Inst *I, std::unordered_set &Results) { +void collectInsts(Inst *I, std::set &Results) { std::vector Stack{I}; while (!Stack.empty()) { auto Current = Stack.back(); @@ -311,57 +382,89 @@ void collectInsts(Inst *I, std::unordered_set &Results) { } } -void ReduceRec(InstContext &IC, - Solver *S, ParsedReplacement Input_, std::vector &Results, std::unordered_set &DNR) { - - ReplacementContext RC; - std::string Str; - llvm::raw_string_ostream SStr(Str); - RC.printInst(Input_.Mapping.LHS, SStr, false); - - Inst *Ante = IC.getConst(llvm::APInt(1, true)); - for (auto PC : Input_.PCs ) { - Inst *Eq = IC.getInst(Inst::Eq, 1, {PC.LHS, PC.RHS}); - Ante = IC.getInst(Inst::And, 1, {Ante, Eq}); - } - - RC.printInst(Ante, SStr, false); - SStr.flush(); - -// llvm::errs() << Str << "\n"; - -// auto Str = Input_.getString(false); - if (DNR.find(Str) != DNR.end()) { - return; - } else { - DNR.insert(Str); +class Reducer { +public: + Reducer(InstContext &IC_, Solver *S_) : IC(IC_), S(S_), varnum(0), numSolverCalls(0) {} + + ParsedReplacement ReduceGreedy(ParsedReplacement Input) { + std::set Insts; + collectInsts(Input.Mapping.LHS, Insts); + // TODO: topological sort, to reduce number of solver calls + // Try to remove one instruction at a time + int failcount = 0; + std::set Visited; + do { + auto It = Insts.begin(); + auto I = *It; + Insts.erase(It); + if (Visited.find(I) != Visited.end()) { + continue; + } + Visited.insert(I); + if (!safeToRemove(I, Input)) { + continue; + } + auto Copy = Input; + Eliminate(Input, I); + if (!Verify(Input)) { + Input = Copy; + failcount++; + if (failcount >= Insts.size()) { + break; + } + continue; + } + Insts.clear(); + collectInsts(Input.Mapping.LHS, Insts); + } while (!Insts.empty()); + return Input; } - static int varnum = 0; // persistent state, maybe 'oop' away at some point. - static int numSolverCalls = 0; + // Assumes Input is valid + ParsedReplacement ReducePCs(ParsedReplacement Input) { - std::unordered_set Insts; - collectInsts(Input_.Mapping.LHS, Insts); - collectInsts(Input_.Mapping.RHS, Insts); + std::set UnnecessaryPCs; + for (size_t i =0; i < Input.PCs.size(); ++i) { + std::vector PCsExceptOne; + for (size_t j = 0; j < Input.PCs.size(); ++j) { + if (i != j) { + PCsExceptOne.push_back(Input.PCs[i]); + } + } -// for (auto &&PC : Input_.PCs) { -// collectInsts(PC.LHS, Insts); -// collectInsts(PC.RHS, Insts); -// } + std::vector> Models; + bool Valid; + if (std::error_code EC = S->isValid(IC, Input.BPCs, PCsExceptOne, Input.Mapping, Valid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + if (Valid) { + UnnecessaryPCs.insert(i); + } + } -// for (auto &&BPC : Input_.BPCs) { -// collectInsts(BPC.PC.LHS, Insts); -// collectInsts(BPC.PC.RHS, Insts); -// } + std::vector NecessaryPCs; + for (size_t i =0; i < Input.PCs.size(); ++i) { + if (UnnecessaryPCs.find(i) == UnnecessaryPCs.end()) { + NecessaryPCs.push_back(Input.PCs[i]); + } + } - if (Insts.size() <= 1) { - return; // Base case + auto Result = Input; + Result.PCs = NecessaryPCs; + return Result; } - // Remove at least one instruction and call recursively for valid opts - for (auto I : Insts) { - ParsedReplacement Input = Input_; + bool Verify(ParsedReplacement &Input) { + std::vector> Models; + bool Valid; + if (std::error_code EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, Valid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + numSolverCalls++; + return Valid; + } + bool safeToRemove(Inst *I, ParsedReplacement &Input) { if (I == Input.Mapping.LHS || I == Input.Mapping.RHS || I->K == Inst::Var || I->K == Inst::Const || I->K == Inst::UMulWithOverflow || I->K == Inst::UMulO || I->K == Inst::SMulWithOverflow || I->K == Inst::SMulO || @@ -369,9 +472,12 @@ void ReduceRec(InstContext &IC, I->K == Inst::SAddWithOverflow || I->K == Inst::SAddO || I->K == Inst::USubWithOverflow || I->K == Inst::USubO || I->K == Inst::SSubWithOverflow || I->K == Inst::SSubO) { - continue; + return false; } + return true; + } + void Eliminate(ParsedReplacement &Input, Inst *I) { // Try to replace I with a new Var. Inst *NewVar = IC.createVar(I->Width, "newvar" + std::to_string(varnum++)); @@ -397,61 +503,83 @@ void ReduceRec(InstContext &IC, BPC.PC.LHS = getInstCopy(BPC.PC.LHS, IC, ICache, BCache, &CMap, false); BPC.PC.RHS = getInstCopy(BPC.PC.RHS, IC, ICache, BCache, &CMap, false); } + } - std::vector> Models; - bool Valid; - if (std::error_code EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, Valid, &Models)) { - llvm::errs() << EC.message() << '\n'; + void ReduceRec(ParsedReplacement Input_, std::vector &Results) { + + // Try to remove subsets of instructions recursively, and store all valid results + ReplacementContext RC; + std::string Str; + llvm::raw_string_ostream SStr(Str); + RC.printInst(Input_.Mapping.LHS, SStr, false); + + Inst *Ante = IC.getConst(llvm::APInt(1, true)); + for (auto PC : Input_.PCs ) { + Inst *Eq = IC.getInst(Inst::Eq, 1, {PC.LHS, PC.RHS}); + Ante = IC.getInst(Inst::And, 1, {Ante, Eq}); } - numSolverCalls++; - llvm::errs() << "Solver Calls: " << numSolverCalls << "\n"; - if (Valid) { - Results.push_back(Input); - ReduceRec(IC, S, Input, Results, DNR); + RC.printInst(Ante, SStr, false); + SStr.flush(); + + // llvm::errs() << Str << "\n"; + + // auto Str = Input_.getString(false); + if (DNR.find(Str) != DNR.end()) { + return; } else { - if (DebugLevel >= 2) { - llvm::outs() << "Invalid attempt.\n"; - Input.print(llvm::outs(), true); - } + DNR.insert(Str); } - } -} -// Assumes Input is valid -ParsedReplacement ReducePCs(InstContext &IC, - Solver *S, ParsedReplacement Input) { + std::set Insts; + collectInsts(Input_.Mapping.LHS, Insts); + collectInsts(Input_.Mapping.RHS, Insts); - std::set UnnecessaryPCs; - for (size_t i =0; i < Input.PCs.size(); ++i) { - std::vector PCsExceptOne; - for (size_t j = 0; j < Input.PCs.size(); ++j) { - if (i != j) { - PCsExceptOne.push_back(Input.PCs[i]); - } - } + // for (auto &&PC : Input_.PCs) { + // collectInsts(PC.LHS, Insts); + // collectInsts(PC.RHS, Insts); + // } - std::vector> Models; - bool Valid; - if (std::error_code EC = S->isValid(IC, Input.BPCs, PCsExceptOne, Input.Mapping, Valid, &Models)) { - llvm::errs() << EC.message() << '\n'; - } - if (Valid) { - UnnecessaryPCs.insert(i); + // for (auto &&BPC : Input_.BPCs) { + // collectInsts(BPC.PC.LHS, Insts); + // collectInsts(BPC.PC.RHS, Insts); + // } + + if (Insts.size() <= 1) { + return; // Base case } - } - std::vector NecessaryPCs; - for (size_t i =0; i < Input.PCs.size(); ++i) { - if (UnnecessaryPCs.find(i) == UnnecessaryPCs.end()) { - NecessaryPCs.push_back(Input.PCs[i]); + // Remove at least one instruction and call recursively for valid opts + for (auto I : Insts) { + ParsedReplacement Input = Input_; + + if (!safeToRemove(I, Input)) { + continue; + } + + Eliminate(Input, I); + + if (Verify(Input)) { + Results.push_back(Input); + ReduceRec(Input, Results); + } else { + if (DebugLevel >= 2) { + llvm::outs() << "Invalid attempt.\n"; + Input.print(llvm::outs(), true); + } + } } } - - auto Result = Input; - Result.PCs = NecessaryPCs; - return Result; -} + void Stats() { + llvm::outs() << "Solver Calls: " << numSolverCalls << "\n"; + } +private: + InstContext &IC; + Solver *S; + int varnum; + int numSolverCalls; + std::unordered_set DNR; +}; void ReduceAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input) { @@ -465,11 +593,17 @@ void ReduceAndGeneralize(InstContext &IC, return; } + Reducer R(IC, S); + std::vector Results; - std::unordered_set DoNotRepeat; - Input = ReducePCs(IC, S, Input); - ReduceRec(IC, S, Input, Results, DoNotRepeat); + Input = R.ReducePCs(Input); + Input = R.ReduceGreedy(Input); + + +// Results.push_back(Input); + R.ReduceRec(Input, Results); + R.Stats(); if (!Results.empty()) { std::set DedupedResults; for (auto &&Result : Results) { From e3a37b463d83d6f20368309ce585d7eb5c2f159b Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 30 Nov 2021 20:08:24 -0700 Subject: [PATCH 035/165] foo --- tools/generalize.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index f1297c46d..48e9efcbe 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -161,8 +161,6 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, } // llvm::errs() << "Succ:" << Success << "\n"; - - if (!Success) { FakeConsts[0]->NonZero = true; Success = TryConstSynth(Guess, ConstSet); @@ -298,14 +296,14 @@ void SymbolizeAndGeneralize(InstContext &IC, CandidateMap Results; - // One at a time +// // One at a time for (auto LHSConst : LHSConsts) { SymbolizeAndGeneralize(IC, S, Input, {LHSConst}, RHSConsts, Results); } // TODO: Two at a time, etc. Is this replaceable by DFP? - // All at once -// SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); +// All at once + SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); // TODO: Move sorting here for (auto &&Result : Results) { @@ -603,7 +601,9 @@ void ReduceAndGeneralize(InstContext &IC, // Results.push_back(Input); R.ReduceRec(Input, Results); - R.Stats(); + if (DebugLevel > 3) { + R.Stats(); + } if (!Results.empty()) { std::set DedupedResults; for (auto &&Result : Results) { From a3e247cb9e6cb47c04785f4723c0d2915ba7e39f Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 2 Dec 2021 09:36:09 -0700 Subject: [PATCH 036/165] foo --- lib/Inst/Inst.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index 712ad3b2b..7832ad51b 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -168,7 +168,12 @@ std::string ReplacementContext::printInstImpl(Inst *I, llvm::raw_ostream &Out, } } - std::string InstName = std::to_string(InstNames.size() + BlockNames.size()); + std::string InstName; + if (printNames && !I->Name.empty()) { + InstName = I->Name; + } else { + InstName = std::to_string(InstNames.size() + BlockNames.size()); + } assert(InstNames.find(I) == InstNames.end()); assert(NameToBlock.find(InstName) == NameToBlock.end()); setInst(InstName, I); From 4c0b0989074581c4cca4fe58cd87cb0b169663e5 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 6 Dec 2021 20:37:32 -0700 Subject: [PATCH 037/165] foo --- tools/generalize.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 48e9efcbe..8edca2ae4 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -294,6 +294,11 @@ void SymbolizeAndGeneralize(InstContext &IC, findInsts(Input.Mapping.LHS, LHSConsts, Pred); findInsts(Input.Mapping.RHS, RHSConsts, Pred); + if (RHSConsts.empty()) { + return; + // TODO: Possible to just generalize LHS consts with preconditions? + } + CandidateMap Results; // // One at a time From 9545924dad6937c3ac9cd02cfdf6963ca9343357 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 3 Dec 2020 18:29:33 -0700 Subject: [PATCH 038/165] souper-combine pass template --- tools/pass-generator/CMakeLists.txt | 14 +++++ tools/pass-generator/src/CMakeLists.txt | 1 + tools/pass-generator/src/template.cpp | 69 +++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 tools/pass-generator/CMakeLists.txt create mode 100644 tools/pass-generator/src/CMakeLists.txt create mode 100644 tools/pass-generator/src/template.cpp diff --git a/tools/pass-generator/CMakeLists.txt b/tools/pass-generator/CMakeLists.txt new file mode 100644 index 000000000..e5e4c0390 --- /dev/null +++ b/tools/pass-generator/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.7) +project(souper-combine) + +find_package(LLVM 11.0 REQUIRED CONFIG) +list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") +include(HandleLLVMOptions) +include(AddLLVM) + +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + +add_definitions(${LLVM_DEFINITIONS}) +include_directories(${LLVM_INCLUDE_DIRS}) + +add_subdirectory(src) diff --git a/tools/pass-generator/src/CMakeLists.txt b/tools/pass-generator/src/CMakeLists.txt new file mode 100644 index 000000000..c2c67d52d --- /dev/null +++ b/tools/pass-generator/src/CMakeLists.txt @@ -0,0 +1 @@ +add_llvm_library(SouperCombine MODULE template.cpp) diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp new file mode 100644 index 000000000..6027c5807 --- /dev/null +++ b/tools/pass-generator/src/template.cpp @@ -0,0 +1,69 @@ +#include "llvm/Pass.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/PatternMatch.h" +#include "llvm/Transforms/InstCombine/InstCombineWorklist.h" + +using namespace llvm; +using namespace llvm::PatternMatch; + +namespace { + +Value *getReplacement(llvm::Instruction *I, llvm::IRBuilder<> *B) { +// Generate one block like the following for each +// optimization derived by souper + llvm::Value *a; + if (match(I, m_Add(m_Value(a), m_Value(a)))) { + return B->CreateShl(I->getOperand(0), 1); + } + +//#include "generated.cpp.inc" + + return nullptr; +} + +struct SouperCombine : public FunctionPass { + static char ID; + SouperCombine() : FunctionPass(ID), Builder(TheContext) { + } + + bool runOnFunction(Function &F) override { + W.reserve(F.getInstructionCount()); + for (auto &BB : F) { + for (auto &&I : BB) { + W.push(&I); + } + } + return run(); + } + + bool processInst(Instruction *I) { + Builder.SetInsertPoint(I); + if (auto V = getReplacement(I, &Builder)) { + replace(I, V); + return true; + } + return false; + } + void replace(Instruction *I, Value *V) { + W.pushUsersToWorkList(*I); + I->replaceAllUsesWith(V); + } + bool run() { + bool Changed = false; + while (auto I = W.removeOne()) { + Changed = processInst(I) || Changed; + } + return Changed; + } + + InstCombineWorklist W; + + LLVMContext TheContext; + llvm::IRBuilder<> Builder; +}; +} + +char SouperCombine::ID = 0; +static RegisterPass X("souper-combine", "Souper Combine", + false /* Only looks at CFG */, + false /* Analysis Pass */); From a4341e20c854397f8b47af94cdebb36ad273587d Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 17 Dec 2021 01:38:14 -0700 Subject: [PATCH 039/165] foo --- CMakeLists.txt | 7 +- tools/matcher-gen.cpp | 421 ++++++++++++++++++++++++++ tools/pass-generator/CMakeLists.txt | 2 +- tools/pass-generator/src/template.cpp | 34 ++- 4 files changed, 449 insertions(+), 15 deletions(-) create mode 100644 tools/matcher-gen.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 03fd4ac49..30a579fff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -324,6 +324,10 @@ add_executable(generalize tools/generalize.cpp ) +add_executable(matcher-gen + tools/matcher-gen.cpp +) + add_executable(souper-interpret tools/souper-interpret.cpp ) @@ -395,7 +399,7 @@ configure_file( ) foreach(target souper internal-solver-test lexer-test parser-test souper-check count-insts - souper2llvm souper-interpret generalize + souper2llvm souper-interpret generalize matcher-gen souperExtractor souperInfer souperInst souperKVStore souperParser souperSMTLIB2 souperTool souperPass souperPassProfileAll kleeExpr souperCodegen) @@ -435,6 +439,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} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(generalize souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) +target_link_libraries(matcher-gen souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(souper-interpret souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(clang-souper souperClangTool souperExtractor souperKVStore souperParser souperSMTLIB2 souperTool kleeExpr ${CLANG_LIBS} ${LLVM_LIBS} ${LLVM_LDFLAGS} ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(count-insts souperParser) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp new file mode 100644 index 000000000..e2cc256d4 --- /dev/null +++ b/tools/matcher-gen.cpp @@ -0,0 +1,421 @@ +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/KnownBits.h" + +#include "souper/Infer/Preconditions.h" +#include "souper/Infer/EnumerativeSynthesis.h" +#include "souper/Infer/ConstantSynthesis.h" +#include "souper/Inst/InstGraph.h" +#include "souper/Parser/Parser.h" +#include "souper/Tool/GetSolver.h" +#include "souper/Util/DfaUtils.h" + +using namespace llvm; +using namespace souper; + +unsigned DebugLevel; + +static cl::opt +DebugFlagParser("souper-debug-level", + cl::desc("Control the verbose level of debug output (default=1). " + "The larger the number is, the more fine-grained debug " + "information will be printed."), + cl::location(DebugLevel), cl::init(1)); + +static cl::opt +InputFilename(cl::Positional, cl::desc(""), + cl::init("-")); + +static llvm::cl::opt Reduce("reduce", + llvm::cl::desc("Try to reduce the number of instructions by replacing instructions with variables." + "(default=false)"), + llvm::cl::init(false)); + +static const std::map MatchOps = { + {Inst::Add, "m_Add("}, {Inst::Sub, "m_Sub("}, + {Inst::Mul, "m_Mul("}, + + {Inst::Shl, "m_Shl("}, {Inst::LShr, "m_LShr("}, + {Inst::AShr, "m_AShr("}, + + {Inst::AddNSW, "m_NSWAdd("}, {Inst::SubNSW, "m_NSWSub("}, + {Inst::MulNSW, "m_NSWMul("}, {Inst::ShlNSW, "m_NSWShl("}, + + {Inst::AddNUW, "m_NUWAdd("}, {Inst::SubNUW, "m_NUWSub("}, + {Inst::MulNUW, "m_NUWMul("}, {Inst::ShlNUW, "m_NUWShl("}, + + {Inst::SDiv, "m_SDiv("}, {Inst::UDiv, "m_UDiv("}, + {Inst::SRem, "m_SRem("}, {Inst::URem, "m_URem("}, + + + {Inst::And, "m_And("}, {Inst::Or, "m_Or("}, + {Inst::Xor, "m_Xor("}, + + {Inst::Eq, "m_Cmp("}, + {Inst::Ne, "m_Cmp("}, + {Inst::Ule, "m_Cmp("}, + {Inst::Ult, "m_Cmp("}, + {Inst::Sle, "m_Cmp("}, + {Inst::Slt, "m_Cmp("}, + + {Inst::SExt, "m_SExt("}, + {Inst::ZExt, "m_ZExt("}, + {Inst::Trunc, "m_Trunc("}, + {Inst::Select, "m_Select("}, +}; + +static const std::map CreateOps = { + {Inst::Shl, "CreateShl("}, {Inst::AShr, "CreateAShr("}, {Inst::LShr, "CreateLShr("}, + {Inst::Add, "CreateAdd("}, {Inst::Mul, "CreateMul("}, {Inst::Sub, "CreateSub("}, + {Inst::SDiv, "CreateSDiv("}, {Inst::UDiv, "CreateUDiv("}, {Inst::SRem, "CreateSRem("}, + {Inst::URem, "CreateURem("}, + {Inst::Or, "CreateOr("}, {Inst::And, "CreateAnd("}, {Inst::Xor, "CreateXor("}, + + {Inst::Eq, "CreateCmp(ICmpInst::ICMP_EQ, "}, + {Inst::Ne, "CreateCmp(ICmpInst::ICMP_NE, "}, + {Inst::Ule, "CreateCmp(ICmpInst::ICMP_ULE, "}, + {Inst::Ult, "CreateCmp(ICmpInst::ICMP_ULT, "}, + {Inst::Sle, "CreateCmp(ICmpInst::ICMP_SLE, "}, + {Inst::Slt, "CreateCmp(ICmpInst::ICMP_SLT, "}, + +// {Inst::Trunc, "CreateTrunc("}, +// {Inst::SExt, "CreateSExt("}, +// {Inst::ZExt, "CreateZExt("}, + // TODO have to create dest type + + {Inst::Select, "CreateSelect("}, + + {Inst::Const, "dummy"}, +}; + +static const std::map PredNames = { + {Inst::Eq, "ICmpInst::ICMP_EQ"}, + {Inst::Ne, "ICmpInst::ICMP_NE"}, + {Inst::Ule, "ICmpInst::ICMP_ULE"}, + {Inst::Ult, "ICmpInst::ICMP_ULT"}, + {Inst::Sle, "ICmpInst::ICMP_SLE"}, + {Inst::Slt, "ICmpInst::ICMP_SLT"}, +}; + +struct SymbolTable : public std::map> { + std::vector> Eqs; + std::map Preds; + + void RegisterPred(Inst *I) { + if (PredNames.find(I->K) == PredNames.end()) { + return; + } + auto Name = "P" + std::to_string(Preds.size()); + Preds[I] = Name; + Eqs.push_back(std::make_pair(Name, PredNames.at(I->K))); + } + template + void PrintPreds(Stream &Out) { + if (Preds.empty()) { + return; + } + Out << "ICmpInst::Predicate "; + bool first = true; + for (auto &&P : Preds) { + if (first) { + first = false; + } else { + Out << ", "; + } + Out << P.second; + } + Out << ";\n"; + } + void GenVarEqConstraints() { + for (auto &&S : *this) { + if (S.second.size() > 1) { + for (int i = 1; i < S.second.size(); ++i) { + Eqs.push_back(std::make_pair(S.second[0], S.second[i])); + } + } + } + } + template + void PrintEqPre(Stream &Out) { + if (Eqs.empty()) { + return; + } + Out << "if ("; + bool first = true; + for (auto &&P : Eqs) { + if (first) { + first = false; + } else { + Out << " && "; + } + Out << P.first << " == " << P.second; + } + Out << ") {\n"; + } + template + void PrintEqPost(Stream &Out) { + if (Eqs.empty()) { + return; + } + Out << "\n}\n"; + } +}; + + +//TODO: Enforce bitwidth +template +bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { + auto It = MatchOps.find(I->K); + if (It == MatchOps.end()) { + llvm::errs() << "\nUnimplemented matcher:" << Inst::getKindName(I->K) << "\n"; + return false; + } + auto Op = It->second; + + Out << Op; + + if (PredNames.find(I->K) != PredNames.end()) { + Out << Syms.Preds[I] << ", "; + } + + bool first = true; + for (auto Child : I->Ops) { + if (first) { + first = false; + } else { + Out << ", "; + } + if (Child->K == Inst::Const) { + Out << "m_SpecificInt(" << Child->Val << ")"; + } else if (Child->K == Inst::Var) { + Out << "m_Value(" << Syms[Child].back() << ")"; + Syms[Child].pop_back(); + } else { + if (!GenLHSMatcher(Child, Out, Syms)) { + return false; + } + } + + } + Out << ")"; + return true; +} + +template +bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms) { + auto It = CreateOps.find(I->K); + if (It == CreateOps.end()) { + llvm::errs() << "\nUnimplemented creator:" << Inst::getKindName(I->K) << "\n"; + return false; + } + auto Op = It->second; + + Out << Op; + bool first = true; + for (auto Child : I->Ops) { + if (first) { + first = false; + } else { + Out << ", "; + } + if (Syms.find(Child) != Syms.end()) { + Out << Syms[Child][0]; + } else { + if (!GenRHSCreator(Child, Out, Syms)) { + return false; + } + } + + } + Out << ")"; + + return true; +} + +template +bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { + std::map> Paths; + + std::set Consts; + + + Paths[Root] = {}; // root has an empty path + std::vector Stack{Root}; + + int varnum = 0; + while (!Stack.empty()) { + auto I = Stack.back(); + Stack.pop_back(); + Syms.RegisterPred(I); + if (I->K == Inst::Var) { + Syms[I].push_back("x" + std::to_string(varnum++)); + } + if (I->K == Inst::Const) { + Consts.insert(I); + } + for (int i = 0; i < I->Ops.size(); ++i) { + Paths[I->Ops[i]] = Paths[I]; // Child inherits parent's path + Paths[I->Ops[i]].push_back(i); + Stack.push_back(I->Ops[i]); // Souper exprs are DAGs + } + } + + + std::set LHSRefs; + std::set Visited; + std::set ConstRefs; + Stack.push_back(RHS); + while (!Stack.empty()) { + auto I = Stack.back(); + Stack.pop_back(); + Visited.insert(I); + if (I->K == Inst::Const) { + Consts.insert(I); + ConstRefs.insert(I); + } + if (Paths.find(I) != Paths.end()) { + LHSRefs.insert(I); + } else { + for (auto Child : I->Ops) { + if (Visited.find(Child) == Visited.end()) { + Stack.push_back(Child); + } + } + } + } + + if (!Syms.empty()) { + Out << "llvm::Value "; + bool first = true; + for (auto &&S : Syms) { + for (auto &&Name : S.second) { + if (first) { + first = false; + } else { + Out << ", "; + } + Out << "*" << Name; + } + } + Out << ";\n"; + } + + varnum = 0; + for (auto &&P : Paths) { + if (P.first == Root || P.first->K == Inst::Var + || LHSRefs.find(P.first) == LHSRefs.end()) { + continue; + } + std::string Name = "I"; + for (auto idx : P.second) { + auto NewName = "y" + std::to_string(varnum++); + Out << "auto " << NewName << " = cast(" << Name; + Out << ")->getOperand(" << idx << ");\n"; + std::swap(Name, NewName); + } + Syms[P.first].push_back(Name); + } + Syms[Root].push_back("I"); + + varnum = 0; + for (auto C : Consts) { + if (ConstRefs.find(C) == ConstRefs.end()) { + continue; + } + auto Name = "C" + std::to_string(varnum++); + Out << "auto " << Name << " = ConstantInt::get(TheContext, APInt(" + << C->Val.getBitWidth() <<", " + << C->Val << "));\n"; + Syms[C].push_back(Name); + } + Syms.PrintPreds(Out); + return true; +} + +template +bool GenMatcher(ParsedReplacement Input, Stream &Out) { + SymbolTable Syms; + Out << "{\n"; + + if (!InitSymbolTable(Input.Mapping.LHS, Input.Mapping.RHS, Out, Syms)) { + return false; + } + + Out << "if (match(I, "; + + SymbolTable SymsCopy = Syms; + if (!GenLHSMatcher(Input.Mapping.LHS, Out, SymsCopy)) { + return false; + } + Out << ")) {\n"; + + Syms.GenVarEqConstraints(); + Syms.PrintEqPre(Out); + + if (Syms.find(Input.Mapping.RHS) != Syms.end()) { + Out << " return " << Syms[Input.Mapping.RHS][0] << ";"; + } else if (Input.Mapping.RHS->K == Inst::Const) { + Out << " APInt Result(" + << Input.Mapping.RHS->Width <<", " + << Input.Mapping.RHS->Val << ");\n"; + Out << " return ConstantInt::get(TheContext, Result);"; + } else { + Out << " return B->"; + if (!GenRHSCreator(Input.Mapping.RHS, Out, Syms)) { + return false; + } + Out << ";"; + } + Out << "\n}\n}\n"; + + Syms.PrintEqPost(Out); + + return true; +} + + + +int main(int argc, char **argv) { + cl::ParseCommandLineOptions(argc, argv); + KVStore *KV = 0; + + std::unique_ptr S = 0; + S = GetSolver(KV); + + auto MB = MemoryBuffer::getFileOrSTDIN(InputFilename); + if (!MB) { + llvm::errs() << MB.getError().message() << '\n'; + return 1; + } + + InstContext IC; + std::string ErrStr; + + auto &&Data = (*MB)->getMemBufferRef(); + auto Inputs = ParseReplacements(IC, Data.getBufferIdentifier(), + Data.getBuffer(), ErrStr); + + if (!ErrStr.empty()) { + llvm::errs() << ErrStr << '\n'; + return 1; + } + + for (auto &&Input: Inputs) { + // ignores PCs for now. + + if (DebugLevel > 3) { + Input.print(llvm::outs(), true); + } + std::string Str; + llvm::raw_string_ostream Out(Str); + if (GenMatcher(Input, Out)) { + llvm::outs() << Str << "\n"; + llvm::outs().flush(); + } else { + llvm::errs() << "Failed to generate matcher.\n\n\n"; + llvm::errs().flush(); + } + } + + return 0; +} diff --git a/tools/pass-generator/CMakeLists.txt b/tools/pass-generator/CMakeLists.txt index e5e4c0390..8df5f73eb 100644 --- a/tools/pass-generator/CMakeLists.txt +++ b/tools/pass-generator/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.7) project(souper-combine) -find_package(LLVM 11.0 REQUIRED CONFIG) +find_package(LLVM 12.0 REQUIRED CONFIG) list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") include(HandleLLVMOptions) include(AddLLVM) diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 6027c5807..8a3165b68 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -1,6 +1,14 @@ #include "llvm/Pass.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/PatternMatch.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" #include "llvm/Transforms/InstCombine/InstCombineWorklist.h" using namespace llvm; @@ -8,19 +16,6 @@ using namespace llvm::PatternMatch; namespace { -Value *getReplacement(llvm::Instruction *I, llvm::IRBuilder<> *B) { -// Generate one block like the following for each -// optimization derived by souper - llvm::Value *a; - if (match(I, m_Add(m_Value(a), m_Value(a)))) { - return B->CreateShl(I->getOperand(0), 1); - } - -//#include "generated.cpp.inc" - - return nullptr; -} - struct SouperCombine : public FunctionPass { static char ID; SouperCombine() : FunctionPass(ID), Builder(TheContext) { @@ -56,6 +51,19 @@ struct SouperCombine : public FunctionPass { return Changed; } + Value *getReplacement(llvm::Instruction *I, llvm::IRBuilder<> *B) { + // Generate one block like the following for each + // optimization derived by souper + llvm::Value *a; + if (match(I, m_Add(m_Value(a), m_Value(a)))) { + return B->CreateShl(I->getOperand(0), 1); + } + + #include "gen.cpp.inc" + + return nullptr; + } + InstCombineWorklist W; LLVMContext TheContext; From 52a85501e63407a8324db0dfdec77aaf5198f9c6 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 21 Dec 2021 23:27:35 -0700 Subject: [PATCH 040/165] foo --- tools/matcher-gen.cpp | 96 ++++++++++++++++++++++----- tools/pass-generator/src/template.cpp | 22 +++++- 2 files changed, 101 insertions(+), 17 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index e2cc256d4..c2d92c59e 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -26,8 +26,8 @@ static cl::opt InputFilename(cl::Positional, cl::desc(""), cl::init("-")); -static llvm::cl::opt Reduce("reduce", - llvm::cl::desc("Try to reduce the number of instructions by replacing instructions with variables." +static llvm::cl::opt IgnorePCs("ignore-pcs", + llvm::cl::desc("Ignore inputs which have souper path conditions." "(default=false)"), llvm::cl::init(false)); @@ -100,6 +100,7 @@ static const std::map PredNames = { struct SymbolTable : public std::map> { std::vector> Eqs; std::map Preds; + std::vector Vars; void RegisterPred(Inst *I) { if (PredNames.find(I->K) == PredNames.end()) { @@ -157,6 +158,42 @@ struct SymbolTable : public std::map> { if (Eqs.empty()) { return; } + Out << "}\n"; + } + + template + void PrintWidthPre(Inst *LHS, Stream &Out) { + findVars(LHS, Vars); + if (Vars.empty()) { + return; + } + Out << "if (util::check_width({"; + bool first = true; + for (auto V : Vars) { + if (first) { + first = false; + } else { + Out << ", "; + } + Out << this->at(V)[0]; + } + Out << "}, {"; + first = true; + for (auto V : Vars) { + if (first) { + first = false; + } else { + Out << ", "; + } + Out << V->Width; + } + Out << "})) {\n"; + } + template + void PrintWidthPost(Stream &Out) { + if (Vars.empty()) { + return; + } Out << "\n}\n"; } }; @@ -232,6 +269,21 @@ bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms) { return true; } +template +void printPath(Stream &Out, const Container& C) { + Out << "{"; + bool first = true; + for (auto c : C) { + if (first) { + first = false; + } else { + Out << ", "; + } + Out << c; + } + Out << "}"; +} + template bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { std::map> Paths; @@ -306,13 +358,19 @@ bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { || LHSRefs.find(P.first) == LHSRefs.end()) { continue; } - std::string Name = "I"; - for (auto idx : P.second) { - auto NewName = "y" + std::to_string(varnum++); - Out << "auto " << NewName << " = cast(" << Name; - Out << ")->getOperand(" << idx << ");\n"; - std::swap(Name, NewName); - } +// std::string Name = "I"; +// for (auto idx : P.second) { +// auto NewName = "y" + std::to_string(varnum++); +// Out << "auto " << NewName << " = cast(" << Name; +// Out << ")->getOperand(" << idx << ");\n"; +// std::swap(Name, NewName); +// } +// Syms[P.first].push_back(Name); + + auto Name = "y" + std::to_string(varnum++); + Out << "auto " << Name << " = util::node(I, "; + printPath(Out, P.second); + Out << ");\n"; Syms[P.first].push_back(Name); } Syms[Root].push_back("I"); @@ -323,9 +381,9 @@ bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { continue; } auto Name = "C" + std::to_string(varnum++); - Out << "auto " << Name << " = ConstantInt::get(TheContext, APInt(" + Out << "auto " << Name << " = C(" << C->Val.getBitWidth() <<", " - << C->Val << "));\n"; + << C->Val << ");\n"; Syms[C].push_back(Name); } Syms.PrintPreds(Out); @@ -351,6 +409,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out) { Syms.GenVarEqConstraints(); Syms.PrintEqPre(Out); + Syms.PrintWidthPre(Input.Mapping.LHS, Out); if (Syms.find(Input.Mapping.RHS) != Syms.end()) { Out << " return " << Syms[Input.Mapping.RHS][0] << ";"; @@ -366,8 +425,9 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out) { } Out << ";"; } - Out << "\n}\n}\n"; + Out << "\n}\n}"; + Syms.PrintWidthPost(Out); Syms.PrintEqPost(Out); return true; @@ -400,15 +460,19 @@ int main(int argc, char **argv) { return 1; } + size_t optnumber = 0; for (auto &&Input: Inputs) { - // ignores PCs for now. - - if (DebugLevel > 3) { - Input.print(llvm::outs(), true); + if (IgnorePCs && !Input.PCs.empty()) { + continue; } + std::string Str; llvm::raw_string_ostream Out(Str); if (GenMatcher(Input, Out)) { + auto current = optnumber++; + llvm::outs() << "/* Opt : " << current << "\n"; + Input.print(llvm::outs(), true); + llvm::outs() << "*/\n"; llvm::outs() << Str << "\n"; llvm::outs().flush(); } else { diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 8a3165b68..56165e13f 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -15,7 +15,23 @@ using namespace llvm; using namespace llvm::PatternMatch; namespace { - +namespace util { + Value *node(Instruction *I, const std::vector &Path) { + Value *Current = I; + for (auto &&P : Path) { + Current = cast(Current)->getOperand(P); + } + return Current; + } + bool check_width(std::vector V, std::vector W) { + for (size_t i = 0; i < V.size(); ++i) { + if (V[i]->getType()->getScalarSizeInBits() != W[i]) { + return false; + } + } + return true; + } +} struct SouperCombine : public FunctionPass { static char ID; SouperCombine() : FunctionPass(ID), Builder(TheContext) { @@ -51,6 +67,10 @@ struct SouperCombine : public FunctionPass { return Changed; } + Value *C(size_t Width, size_t Value) { + return ConstantInt::get(TheContext, APInt(Width, Value)); + } + Value *getReplacement(llvm::Instruction *I, llvm::IRBuilder<> *B) { // Generate one block like the following for each // optimization derived by souper From ea1ad8fdf58c3da6e13052e42eb7ff8e3a3f3143 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 10 Jan 2022 08:43:44 -0700 Subject: [PATCH 041/165] foo --- tools/matcher-gen.cpp | 6 ++--- tools/pass-generator/src/template.cpp | 35 +++++++++++++++++++-------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index c2d92c59e..5dff2e210 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -391,7 +391,7 @@ bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { } template -bool GenMatcher(ParsedReplacement Input, Stream &Out) { +bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { SymbolTable Syms; Out << "{\n"; @@ -410,7 +410,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out) { Syms.GenVarEqConstraints(); Syms.PrintEqPre(Out); Syms.PrintWidthPre(Input.Mapping.LHS, Out); - + Out << " St.hit(" << OptID << ");\n"; if (Syms.find(Input.Mapping.RHS) != Syms.end()) { Out << " return " << Syms[Input.Mapping.RHS][0] << ";"; } else if (Input.Mapping.RHS->K == Inst::Const) { @@ -468,7 +468,7 @@ int main(int argc, char **argv) { std::string Str; llvm::raw_string_ostream Out(Str); - if (GenMatcher(Input, Out)) { + if (GenMatcher(Input, Out, optnumber)) { auto current = optnumber++; llvm::outs() << "/* Opt : " << current << "\n"; Input.print(llvm::outs(), true); diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 56165e13f..5945bf3be 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -31,6 +31,25 @@ namespace util { } return true; } + + struct Stats { + void hit(size_t opt) { + Hits[opt]++; + } + std::map Hits; + void print() { + std::vector> Copy(Hits.size(), std::make_pair(0, 0)); + std::copy(Hits.begin(), Hits.end(), Copy.begin()); + std::sort(Copy.begin(), Copy.end(), + [](auto &A, auto &B) {return A.second > B.second;}); + llvm::outs() << "Hits begin:\n"; + for (auto &&P : Copy) { + llvm::outs() << "OptID " << P.first << " matched " << P.second << " time(s).\n"; + } + llvm::outs() << "Hits end.\n"; + } + }; + } struct SouperCombine : public FunctionPass { static char ID; @@ -64,6 +83,9 @@ struct SouperCombine : public FunctionPass { while (auto I = W.removeOne()) { Changed = processInst(I) || Changed; } + + St.print(); + return Changed; } @@ -72,20 +94,13 @@ struct SouperCombine : public FunctionPass { } Value *getReplacement(llvm::Instruction *I, llvm::IRBuilder<> *B) { - // Generate one block like the following for each - // optimization derived by souper - llvm::Value *a; - if (match(I, m_Add(m_Value(a), m_Value(a)))) { - return B->CreateShl(I->getOperand(0), 1); - } - - #include "gen.cpp.inc" - + // Autogenerated transforms +#include "gen.cpp.inc" return nullptr; } InstCombineWorklist W; - + util::Stats St; LLVMContext TheContext; llvm::IRBuilder<> Builder; }; From 3d928922e029e071a395dcff3b627929bd1e50ac Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 12 Jan 2022 03:09:44 -0700 Subject: [PATCH 042/165] foo --- tools/matcher-gen.cpp | 3 +++ tools/pass-generator/src/template.cpp | 39 ++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 5dff2e210..fca4586bf 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -264,6 +264,9 @@ bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms) { } } + if (I->K == Inst::Trunc || I->K == Inst::SExt || I->K == Inst::ZExt) { + Out << ", T(" << I->Width << ")"; + } Out << ")"; return true; diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 5945bf3be..3a1377072 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -9,6 +9,9 @@ #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" +#include "llvm/InitializePasses.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/InstCombine/InstCombineWorklist.h" using namespace llvm; @@ -99,6 +102,10 @@ struct SouperCombine : public FunctionPass { return nullptr; } + llvm::Type *T(size_t W) { + return llvm::Type::getIntNTy(TheContext, W); + } + InstCombineWorklist W; util::Stats St; LLVMContext TheContext; @@ -107,6 +114,32 @@ struct SouperCombine : public FunctionPass { } char SouperCombine::ID = 0; -static RegisterPass X("souper-combine", "Souper Combine", - false /* Only looks at CFG */, - false /* Analysis Pass */); +namespace llvm { +void initializeSouperCombinePass(llvm::PassRegistry &); +} + +INITIALIZE_PASS_BEGIN(SouperCombine, "souper", "Souper super-optimizer pass", + false, false) +INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) +INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(DemandedBitsWrapperPass) +INITIALIZE_PASS_DEPENDENCY(LazyValueInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass) +INITIALIZE_PASS_END(SouperCombine, "souper-combine", "Souper super-optimizer pass", false, + false) + +static struct Register { + Register() { + initializeSouperCombinePass(*llvm::PassRegistry::getPassRegistry()); + } +} X; + +static void registerSouperCombine( + const llvm::PassManagerBuilder &Builder, llvm::legacy::PassManagerBase &PM) { + PM.add(new SouperCombine); +} + +static llvm::RegisterStandardPasses +RegisterSouperOptimizer(llvm::PassManagerBuilder::EP_Peephole, + registerSouperCombine); From b4461eca8de47b502788715f2d7a38b43ab01d69 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 12 Jan 2022 03:22:59 -0700 Subject: [PATCH 043/165] foo --- tools/pass-generator/src/template.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 3a1377072..fef539a93 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -22,7 +22,15 @@ namespace util { Value *node(Instruction *I, const std::vector &Path) { Value *Current = I; for (auto &&P : Path) { - Current = cast(Current)->getOperand(P); + if (Instruction *CI = dyn_cast(Current)) { + if (CI->getNumOperands() > P) { + Current = CI->getOperand(P); + } else { + return nullptr; + } + } else { + return nullptr; + } } return Current; } From ae03d160c0bc4a27b8c98d80208107522cb2c032 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 7 Jun 2022 23:14:40 -0600 Subject: [PATCH 044/165] foo --- tools/matcher-gen.cpp | 18 ++++++++++-------- tools/pass-generator/CMakeLists.txt | 2 +- tools/pass-generator/src/template.cpp | 11 +++++++---- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index fca4586bf..27fc8a6ee 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -32,14 +32,14 @@ static llvm::cl::opt IgnorePCs("ignore-pcs", llvm::cl::init(false)); static const std::map MatchOps = { - {Inst::Add, "m_Add("}, {Inst::Sub, "m_Sub("}, - {Inst::Mul, "m_Mul("}, + {Inst::Add, "m_c_Add("}, {Inst::Sub, "m_c_Sub("}, + {Inst::Mul, "m_c_Mul("}, {Inst::Shl, "m_Shl("}, {Inst::LShr, "m_LShr("}, {Inst::AShr, "m_AShr("}, - {Inst::AddNSW, "m_NSWAdd("}, {Inst::SubNSW, "m_NSWSub("}, - {Inst::MulNSW, "m_NSWMul("}, {Inst::ShlNSW, "m_NSWShl("}, + {Inst::AddNSW, "m_NSWAdd("}, {Inst::SubNSW, "m_NSWSub("}, // add _c_ too? + {Inst::MulNSW, "m_NSWMul("}, {Inst::ShlNSW, "m_NSWShl("}, // Also, figure out what to do about NW. {Inst::AddNUW, "m_NUWAdd("}, {Inst::SubNUW, "m_NUWSub("}, {Inst::MulNUW, "m_NUWMul("}, {Inst::ShlNUW, "m_NUWShl("}, @@ -48,8 +48,8 @@ static const std::map MatchOps = { {Inst::SRem, "m_SRem("}, {Inst::URem, "m_URem("}, - {Inst::And, "m_And("}, {Inst::Or, "m_Or("}, - {Inst::Xor, "m_Xor("}, + {Inst::And, "m_c_And("}, {Inst::Or, "m_c_Or("}, + {Inst::Xor, "m_c_Xor("}, {Inst::Eq, "m_Cmp("}, {Inst::Ne, "m_Cmp("}, @@ -149,7 +149,8 @@ struct SymbolTable : public std::map> { } else { Out << " && "; } - Out << P.first << " == " << P.second; + Out << "(!util::nc(" << P.first << ',' << P.second << " ) " + << "|| " << P.first << " == " << P.second << ")"; } Out << ") {\n"; } @@ -223,7 +224,8 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { Out << ", "; } if (Child->K == Inst::Const) { - Out << "m_SpecificInt(" << Child->Val << ")"; + auto Str = Child->Val.toString(10, false); + Out << "m_SpecificInt(" << Str << ")"; } else if (Child->K == Inst::Var) { Out << "m_Value(" << Syms[Child].back() << ")"; Syms[Child].pop_back(); diff --git a/tools/pass-generator/CMakeLists.txt b/tools/pass-generator/CMakeLists.txt index 8df5f73eb..d4e5a67fd 100644 --- a/tools/pass-generator/CMakeLists.txt +++ b/tools/pass-generator/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.7) project(souper-combine) -find_package(LLVM 12.0 REQUIRED CONFIG) +find_package(LLVM 13.0 REQUIRED CONFIG) list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") include(HandleLLVMOptions) include(AddLLVM) diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index fef539a93..b214367d9 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -53,14 +53,17 @@ namespace util { std::copy(Hits.begin(), Hits.end(), Copy.begin()); std::sort(Copy.begin(), Copy.end(), [](auto &A, auto &B) {return A.second > B.second;}); - llvm::outs() << "Hits begin:\n"; + llvm::errs() << "Hits begin:\n"; for (auto &&P : Copy) { - llvm::outs() << "OptID " << P.first << " matched " << P.second << " time(s).\n"; + llvm::errs() << "OptID " << P.first << " matched " << P.second << " time(s).\n"; } - llvm::outs() << "Hits end.\n"; + llvm::errs() << "Hits end.\n"; } }; - + bool nc(llvm::Value *a, llvm::Value *b) { + if (llvm::isa(a) || llvm::isa(b)) return false; + return true; + } } struct SouperCombine : public FunctionPass { static char ID; From d7e63c869885d67d81123b765789422559eebbc4 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 16 Jan 2022 22:02:07 -0700 Subject: [PATCH 045/165] foo --- tools/generalize.cpp | 97 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 8edca2ae4..54e5c4bc5 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -457,6 +457,99 @@ class Reducer { return Result; } + // Assumes Input is valid + ParsedReplacement WeakenKB(ParsedReplacement Input) { + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); + for (auto &&V : Vars) { + auto OriZero = V->KnownZeros; + auto OriOne = V->KnownOnes; + if (OriZero == 0 && OriOne == 0) { + continue; // this var doesn't have a knownbits condition + } + if (OriZero.getBitWidth() != V->Width || OriOne.getBitWidth() != V->Width) { + continue; // this var doesn't have a well formed knownbits condition + } + + // Try to remove KB + V->KnownOnes = llvm::APInt(V->Width, 0); + V->KnownZeros = llvm::APInt(V->Width, 0); + if (Verify(Input)) { + continue; // Removed KB from this var + } + V->KnownOnes = OriOne; + V->KnownZeros = OriZero; + + // Try resetting bitwise KB + + for (size_t i = 0; i < V->Width; ++i) { + auto Ones = V->KnownOnes; + if (Ones[i]) { + V->KnownOnes.setBitVal(i, false); + if (!Verify(Input)) { + V->KnownOnes = Ones; + } + } + auto Zeros = V->KnownZeros; + if (Zeros[i]) { + V->KnownZeros.setBitVal(i, false); + if (!Verify(Input)) { + V->KnownZeros = Zeros; + } + } + } + } + return Input; + } + + // Assumes Input is valid + ParsedReplacement WeakenCR(ParsedReplacement Input) { + // Just try to remove CR for now. + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); + + for (auto &&V : Vars) { + auto Ori = V->Range; + if (V->Range.isFullSet()) { + continue; + } + V->Range = llvm::ConstantRange(V->Width, true); + if (!Verify(Input)) { + V->Range = Ori; + } + // TODO: Try Widening Range + } + + return Input; + } + + // Assumes Input is valid + ParsedReplacement WeakenDB(ParsedReplacement Input) { + auto Ori = Input.Mapping.LHS->DemandedBits; + auto Width = Input.Mapping.LHS->Width; + if (Ori.getBitWidth() != Width || Ori.isAllOnesValue()) { + return Input; + } + // Try replacing with all ones. + Input.Mapping.LHS->DemandedBits.setAllBits(); + if (Verify(Input)) { + return Input; + } + Input.Mapping.LHS->DemandedBits = Ori; + + for (size_t i = 0; i < Width; ++i) { + auto Last = Input.Mapping.LHS->DemandedBits; + if (!Last[i]) { + Input.Mapping.LHS->DemandedBits.setBitVal(i, true); + if (!Verify(Input)) { + Input.Mapping.LHS->DemandedBits = Last; + } + } + } + + return Input; + } + bool Verify(ParsedReplacement &Input) { std::vector> Models; bool Valid; @@ -601,7 +694,9 @@ void ReduceAndGeneralize(InstContext &IC, std::vector Results; Input = R.ReducePCs(Input); Input = R.ReduceGreedy(Input); - + Input = R.WeakenKB(Input); + Input = R.WeakenCR(Input); + Input = R.WeakenDB(Input); // Results.push_back(Input); From b4e4ce4c3454d3d791d8d96ffb44435b00d4b7ea Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 14 Feb 2022 12:01:25 -0700 Subject: [PATCH 046/165] foo --- include/souper/Inst/Inst.h | 1 + lib/Extractor/KLEEBuilder.cpp | 14 ++++ lib/Infer/EnumerativeSynthesis.cpp | 6 ++ lib/Inst/Inst.cpp | 3 + lib/Parser/Parser.cpp | 1 + tools/generalize.cpp | 119 +++++++++++++++++++++-------- 6 files changed, 112 insertions(+), 32 deletions(-) diff --git a/include/souper/Inst/Inst.h b/include/souper/Inst/Inst.h index c64c90251..af12c59f8 100644 --- a/include/souper/Inst/Inst.h +++ b/include/souper/Inst/Inst.h @@ -100,6 +100,7 @@ struct Inst : llvm::FoldingSetNode { BSwap, Cttz, Ctlz, + LogB, BitReverse, FShl, FShr, diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index a94fb2e84..460298e63 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -340,6 +340,20 @@ class KLEEBuilder : public ExprBuilder { return SubExpr::create(klee::ConstantExpr::create(Width, Width), countOnes(Val)); } + case Inst::LogB: { + ref L = get(Ops[0]); + unsigned Width = L->getWidth(); + ref Val = L; + for (unsigned i=0, j=0; jWidth; diff --git a/lib/Infer/EnumerativeSynthesis.cpp b/lib/Infer/EnumerativeSynthesis.cpp index 0f91acc86..a57701030 100644 --- a/lib/Infer/EnumerativeSynthesis.cpp +++ b/lib/Infer/EnumerativeSynthesis.cpp @@ -94,6 +94,9 @@ namespace { static cl::opt SynFreeze("souper-synthesize-freeze", cl::desc("Generate Freeze (default=true)"), cl::init(true)); + static cl::opt SynLog("souper-synthesize-log", + cl::desc("Generate LogB (default=false)"), + cl::init(false)); static cl::opt MaxLHSCands("souper-max-lhs-cands", cl::desc("Gather at most this many values from a LHS to use as synthesis inputs (default=8)"), cl::init(8)); @@ -893,6 +896,9 @@ EnumerativeSynthesis::EnumerativeSynthesis() { if (SynFreeze) { UnaryOperators.push_back(Inst::Freeze); } + if (SynLog) { + UnaryOperators.push_back(Inst::LogB); + } } std::vector diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index 7832ad51b..936a74b5a 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -423,6 +423,8 @@ const char *Inst::getKindName(Kind K) { return "cttz"; case Ctlz: return "ctlz"; + case LogB: + return "logb"; case FShl: return "fshl"; case FShr: @@ -517,6 +519,7 @@ Inst::Kind Inst::getKind(std::string Name) { .Case("bitreverse", Inst::BitReverse) .Case("cttz", Inst::Cttz) .Case("ctlz", Inst::Ctlz) + .Case("logb", Inst::LogB) .Case("fshl", Inst::FShl) .Case("fshr", Inst::FShr) .Case("sadd.with.overflow", Inst::SAddWithOverflow) diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp index f53e5791f..caafaf2ef 100644 --- a/lib/Parser/Parser.cpp +++ b/lib/Parser/Parser.cpp @@ -590,6 +590,7 @@ bool Parser::typeCheckInst(Inst::Kind IK, unsigned &Width, case Inst::BitReverse: case Inst::Cttz: case Inst::Ctlz: + case Inst::LogB: case Inst::Freeze: MaxOps = MinOps = 1; break; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 54e5c4bc5..b67f8aad2 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -31,6 +31,12 @@ static llvm::cl::opt Reduce("reduce", "(default=false)"), llvm::cl::init(false)); +static llvm::cl::opt ReduceKBIFY("reduce-kbify", + llvm::cl::desc("Try to reduce the number of instructions by introducing known bits constraints." + "(default=false)"), + llvm::cl::init(false)); + + static llvm::cl::opt ReducePrintAll("reduce-all-results", llvm::cl::desc("Print all reduced results." "(default=false)"), @@ -152,38 +158,41 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::set ConstSet; souper::getConstants(Guess, ConstSet); if (!ConstSet.empty()) { - bool Success = TryConstSynth(Guess, ConstSet); -// llvm::errs() << "Succ:" << Success << "\n"; - if (!Success) { - FakeConsts[0]->PowOfTwo = true; - Success = TryConstSynth(Guess, ConstSet); - FakeConsts[0]->PowOfTwo = false; - } -// llvm::errs() << "Succ:" << Success << "\n"; +// bool Success = TryConstSynth(Guess, ConstSet); +//// llvm::errs() << "Succ:" << Success << "\n"; +// if (!Success) { +// FakeConsts[0]->PowOfTwo = true; +// Success = TryConstSynth(Guess, ConstSet); +// FakeConsts[0]->PowOfTwo = false; +// } +//// llvm::errs() << "Succ:" << Success << "\n"; - if (!Success) { - FakeConsts[0]->NonZero = true; - Success = TryConstSynth(Guess, ConstSet); - FakeConsts[0]->NonZero = false; - } -// llvm::errs() << "Succ:" << Success << "\n"; +// if (!Success) { +// FakeConsts[0]->NonZero = true; +// Success = TryConstSynth(Guess, ConstSet); +// FakeConsts[0]->NonZero = false; +// } +//// llvm::errs() << "Succ:" << Success << "\n"; - if (!Success) { - FakeConsts[0]->NonNegative = true; - Success = TryConstSynth(Guess, ConstSet); - FakeConsts[0]->NonNegative = false; - } -// llvm::errs() << "Succ:" << Success << "\n"; +// if (!Success) { +// FakeConsts[0]->NonNegative = true; +// Success = TryConstSynth(Guess, ConstSet); +// FakeConsts[0]->NonNegative = false; +// } +//// llvm::errs() << "Succ:" << Success << "\n"; - if (!Success) { - FakeConsts[0]->Negative = true; - Success = TryConstSynth(Guess, ConstSet); - FakeConsts[0]->Negative = false; - } -// llvm::errs() << "Succ:" << Success << "\n"; - (void)Success; +// if (!Success) { +// FakeConsts[0]->Negative = true; +// Success = TryConstSynth(Guess, ConstSet); +// FakeConsts[0]->Negative = false; +// } +//// llvm::errs() << "Succ:" << Success << "\n"; +// (void)Success; } else { +// llvm::errs() << "P\n"; +// ReplacementContext RC; +// RC.printInst(Guess, llvm::errs(), true); WithoutConsts.push_back(Guess); } } @@ -202,6 +211,8 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, BlockCache, &ConstMap, false); + + // { // llvm::errs() << "JoinedGUESS:\n"; // ReplacementContext RC; @@ -209,7 +220,7 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, // } InstMapping Mapping(LHS, RHS); - if (SymbolizeNoDFP) { + if (true /*remove when the other branch exists*/ || SymbolizeNoDFP) { bool IsValid; auto CheckAndSave = [&](){ std::vector> Models; @@ -217,7 +228,13 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, llvm::errs() << EC.message() << '\n'; } if (IsValid) { - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Mapping)); + InstMapping Clone; + std::map InstCache; + std::map BlockCache; + std::map ConstMap; + Clone.LHS = getInstCopy(Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); + Clone.RHS = getInstCopy(Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Clone)); } }; CheckAndSave(); @@ -227,8 +244,6 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, FakeConsts[0]->PowOfTwo = false; } - - } else { // std::vector> KBResults; // std::vector> CRResults; @@ -308,7 +323,7 @@ void SymbolizeAndGeneralize(InstContext &IC, // TODO: Two at a time, etc. Is this replaceable by DFP? // All at once - SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); +// SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); // TODO: Move sorting here for (auto &&Result : Results) { @@ -423,6 +438,42 @@ class Reducer { return Input; } + + ParsedReplacement ReduceGreedyKBIFY(ParsedReplacement Input) { + std::set Insts; + collectInsts(Input.Mapping.LHS, Insts); + // TODO: topological sort, to reduce number of solver calls + // Try to remove one instruction at a time + int failcount = 0; + std::set Visited; + do { + auto It = Insts.begin(); + auto I = *It; + Insts.erase(It); + if (Visited.find(I) != Visited.end()) { + continue; + } + Visited.insert(I); + if (!safeToRemove(I, Input)) { + continue; + } + auto Copy = Input; + Eliminate(Input, I); + if (!Verify(Input)) { + Input = Copy; + failcount++; + if (failcount >= Insts.size()) { + break; + } + continue; + } + Insts.clear(); + collectInsts(Input.Mapping.LHS, Insts); + } while (!Insts.empty()); + return Input; + } + + // Assumes Input is valid ParsedReplacement ReducePCs(ParsedReplacement Input) { @@ -698,6 +749,10 @@ void ReduceAndGeneralize(InstContext &IC, Input = R.WeakenCR(Input); Input = R.WeakenDB(Input); +// if (ReduceKBIFY) { +// Input = R.ReduceKBIFY(Input); +// } + // Results.push_back(Input); R.ReduceRec(Input, Results); From 44889b0a6a511c7459ae3a270d4e746264221369 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 17 Feb 2022 13:38:42 -0700 Subject: [PATCH 047/165] foo --- include/souper/Extractor/Solver.h | 2 + lib/Extractor/Solver.cpp | 21 ++- lib/Infer/ConstantSynthesis.cpp | 4 +- tools/generalize.cpp | 210 +++++++++++++++++++++--------- tools/souper-check.cpp | 13 +- 5 files changed, 181 insertions(+), 69 deletions(-) diff --git a/include/souper/Extractor/Solver.h b/include/souper/Extractor/Solver.h index 3044dbd5a..8299b0a40 100644 --- a/include/souper/Extractor/Solver.h +++ b/include/souper/Extractor/Solver.h @@ -50,6 +50,8 @@ class Solver { std::vector *Models, unsigned Timeout = 0) = 0; + virtual SMTLIBSolver *getSMTLIBSolver() = 0; + virtual std::string getName() = 0; virtual diff --git a/lib/Extractor/Solver.cpp b/lib/Extractor/Solver.cpp index e250eacb4..cf557bf25 100644 --- a/lib/Extractor/Solver.cpp +++ b/lib/Extractor/Solver.cpp @@ -453,6 +453,11 @@ class BaseSolver : public Solver { return EC; } + + SMTLIBSolver *getSMTLIBSolver() override { + return SMTSolver.get(); + } + std::error_code isSatisfiable(llvm::StringRef Query, bool &Result, unsigned NumModels, std::vector *Models, @@ -511,13 +516,12 @@ class BaseSolver : public Solver { // case LHS to evaluate to UB std::vector Inputs; findVars(LHS, Inputs); - PruningManager Pruner(SC, Inputs, DebugLevel); - Pruner.init(); - ConstantSynthesis CS{&Pruner}; +// PruningManager Pruner(SC, Inputs, DebugLevel); +// Pruner.init(); + ConstantSynthesis CS{nullptr}; std::error_code EC = CS.synthesize(SMTSolver.get(), BPCs, PCs, InstMapping(LHS, RHS), ConstSet, ResultMap, IC, MaxConstantSynthesisTries, Timeout, /*AvoidNops=*/false); - if (EC || ResultMap.empty()) return EC; @@ -676,6 +680,11 @@ class MemCachingSolver : public Solver { return ent->second.first; } } + + SMTLIBSolver *getSMTLIBSolver() override { + return UnderlyingSolver->getSMTLIBSolver(); + } + std::error_code inferConst(const BlockPCs &BPCs, const std::vector &PCs, Inst *LHS, Inst *&RHS, @@ -848,6 +857,10 @@ class ExternalCachingSolver : public Solver { } } + SMTLIBSolver *getSMTLIBSolver() override { + return UnderlyingSolver->getSMTLIBSolver(); + } + llvm::ConstantRange constantRange(const BlockPCs &BPCs, const std::vector &PCs, Inst *LHS, diff --git a/lib/Infer/ConstantSynthesis.cpp b/lib/Infer/ConstantSynthesis.cpp index 67046464a..11c82bcfa 100644 --- a/lib/Infer/ConstantSynthesis.cpp +++ b/lib/Infer/ConstantSynthesis.cpp @@ -345,6 +345,7 @@ ConstantSynthesis::synthesize(SMTLIBSolver *SMTSolver, auto ConstConstraints = TrueConst; std::set Visited; + visitConstants(Mapping.LHS, Visited, ConstConstraints, ConstSet, IC, AvoidNops); visitConstants(Mapping.RHS, Visited, ConstConstraints, ConstSet, IC, AvoidNops); for (int I = 0; I < MaxTries; ++I) { @@ -409,6 +410,7 @@ ConstantSynthesis::synthesize(SMTLIBSolver *SMTSolver, std::map InstCache; std::map BlockCache; Inst *RHSCopy = getInstCopy(Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, false); + Inst *LHSCopy = getInstCopy(Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, false); std::vector Blocks = getBlocksFromPhis(Mapping.LHS); for (auto Block : Blocks) { @@ -426,7 +428,7 @@ ConstantSynthesis::synthesize(SMTLIBSolver *SMTSolver, std::vector ModelInstsSecondQuery; std::vector ModelValsSecondQuery; - Query = BuildQuery(IC, BPCs, PCs, InstMapping(Mapping.LHS, RHSCopy), + Query = BuildQuery(IC, BPCs, PCs, InstMapping(LHSCopy, RHSCopy), &ModelInstsSecondQuery, 0); if (Query.empty()) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index b67f8aad2..be052c94a 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -34,7 +34,7 @@ static llvm::cl::opt Reduce("reduce", static llvm::cl::opt ReduceKBIFY("reduce-kbify", llvm::cl::desc("Try to reduce the number of instructions by introducing known bits constraints." "(default=false)"), - llvm::cl::init(false)); + llvm::cl::init(true)); static llvm::cl::opt ReducePrintAll("reduce-all-results", @@ -56,6 +56,14 @@ static llvm::cl::opt SymbolizeNoDFP("symbolize-no-dataflow", llvm::cl::desc("Do not generate optimizations with dataflow preconditions."), llvm::cl::init(false)); +static llvm::cl::opt SymbolizeSimpleDF("symbolize-simple-dataflow", + llvm::cl::desc("Generate simple dataflow facts supported by LLVM."), + llvm::cl::init(false)); + +static llvm::cl::opt SymbolizeConstSynthesis("symbolize-constant-synthesis", + llvm::cl::desc("Allow concrete constants in the generated code."), + llvm::cl::init(false)); + static llvm::cl::opt FixIt("fixit", llvm::cl::desc("Given an invalid optimization, generate a valid one." "(default=false)"), @@ -158,41 +166,42 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::set ConstSet; souper::getConstants(Guess, ConstSet); if (!ConstSet.empty()) { -// bool Success = TryConstSynth(Guess, ConstSet); -//// llvm::errs() << "Succ:" << Success << "\n"; -// if (!Success) { -// FakeConsts[0]->PowOfTwo = true; -// Success = TryConstSynth(Guess, ConstSet); -// FakeConsts[0]->PowOfTwo = false; -// } -//// llvm::errs() << "Succ:" << Success << "\n"; + if (SymbolizeConstSynthesis) { + bool Success = TryConstSynth(Guess, ConstSet); + // llvm::errs() << "Succ:" << Success << "\n"; + if (SymbolizeSimpleDF) { + if (!Success) { + FakeConsts[0]->PowOfTwo = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->PowOfTwo = false; + } + // llvm::errs() << "Succ:" << Success << "\n"; -// if (!Success) { -// FakeConsts[0]->NonZero = true; -// Success = TryConstSynth(Guess, ConstSet); -// FakeConsts[0]->NonZero = false; -// } -//// llvm::errs() << "Succ:" << Success << "\n"; + if (!Success) { + FakeConsts[0]->NonZero = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->NonZero = false; + } + // llvm::errs() << "Succ:" << Success << "\n"; -// if (!Success) { -// FakeConsts[0]->NonNegative = true; -// Success = TryConstSynth(Guess, ConstSet); -// FakeConsts[0]->NonNegative = false; -// } -//// llvm::errs() << "Succ:" << Success << "\n"; + if (!Success) { + FakeConsts[0]->NonNegative = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->NonNegative = false; + } + // llvm::errs() << "Succ:" << Success << "\n"; -// if (!Success) { -// FakeConsts[0]->Negative = true; -// Success = TryConstSynth(Guess, ConstSet); -// FakeConsts[0]->Negative = false; -// } -//// llvm::errs() << "Succ:" << Success << "\n"; -// (void)Success; + if (!Success) { + FakeConsts[0]->Negative = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->Negative = false; + } + // llvm::errs() << "Succ:" << Success << "\n"; + (void)Success; + } + } } else { -// llvm::errs() << "P\n"; -// ReplacementContext RC; -// RC.printInst(Guess, llvm::errs(), true); WithoutConsts.push_back(Guess); } } @@ -202,22 +211,24 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::map InstCacheCopy/* = InstCache*/; InstCacheCopy[RHSConsts[0]] = Guess; -// { -// llvm::errs() << "GUESS:\n"; -// ReplacementContext RC; -// RC.printInst(Guess, llvm::errs(), true); -// } + auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, BlockCache, &ConstMap, false); - -// { -// llvm::errs() << "JoinedGUESS:\n"; -// ReplacementContext RC; -// RC.printInst(RHS, llvm::errs(), true); -// } + if (DebugLevel > 4) { + { + llvm::errs() << "GUESS:\n"; + ReplacementContext RC; + RC.printInst(Guess, llvm::errs(), true); + } + { + llvm::errs() << "JoinedGUESS:\n"; + ReplacementContext RC; + RC.printInst(RHS, llvm::errs(), true); + } + } InstMapping Mapping(LHS, RHS); if (true /*remove when the other branch exists*/ || SymbolizeNoDFP) { @@ -238,10 +249,27 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, } }; CheckAndSave(); - if (!IsValid) { - FakeConsts[0]->PowOfTwo = true; - CheckAndSave(); - FakeConsts[0]->PowOfTwo = false; + if (SymbolizeSimpleDF) { + if (!IsValid) { + FakeConsts[0]->PowOfTwo = true; + CheckAndSave(); + FakeConsts[0]->PowOfTwo = false; + } + if (!IsValid) { + FakeConsts[0]->NonZero = true; + CheckAndSave(); + FakeConsts[0]->NonZero = false; + } + if (!IsValid) { + FakeConsts[0]->NonNegative = true; + CheckAndSave(); + FakeConsts[0]->NonNegative = false; + } + if (!IsValid) { + FakeConsts[0]->Negative = true; + CheckAndSave(); + FakeConsts[0]->Negative = false; + } } } else { @@ -317,13 +345,15 @@ void SymbolizeAndGeneralize(InstContext &IC, CandidateMap Results; // // One at a time - for (auto LHSConst : LHSConsts) { - SymbolizeAndGeneralize(IC, S, Input, {LHSConst}, RHSConsts, Results); - } - // TODO: Two at a time, etc. Is this replaceable by DFP? +// for (auto LHSConst : LHSConsts) { +// SymbolizeAndGeneralize(IC, S, Input, {LHSConst}, RHSConsts, Results); +// } + + // TODO: Why does one at a time get solutions that all at once doesn't? + // All at once -// SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); + SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); // TODO: Move sorting here for (auto &&Result : Results) { @@ -438,7 +468,6 @@ class Reducer { return Input; } - ParsedReplacement ReduceGreedyKBIFY(ParsedReplacement Input) { std::set Insts; collectInsts(Input.Mapping.LHS, Insts); @@ -454,18 +483,78 @@ class Reducer { continue; } Visited.insert(I); - if (!safeToRemove(I, Input)) { + if (!safeToRemove(I, Input) || I->Width == 1 /*1 bit KB doesn't make sense*/) { continue; } auto Copy = Input; - Eliminate(Input, I); - if (!Verify(Input)) { + auto NewVar = Eliminate(Input, I); + + // Input won't verify because ReduceGreedy has been called before this. + + // Try to replace NewVar with a symbolic constant and do constant synthesis. + Inst *C = IC.createSynthesisConstant(NewVar->Width, 0); + std::map InstCache = {{NewVar, C}}; + std::map BlockCache; + std::map ConstMap; + + InstMapping Rep; + Rep.LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, false, false); + Rep.RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, false, false); + + ConstantSynthesis CS; + std::set ConstSet{C}; + +// llvm::errs() << "Constant synthesis problem: \n"; +// Input.print(llvm::errs(), true); +// llvm::errs() << "....end.... \n"; + + if (auto EC = CS.synthesize(S->getSMTLIBSolver(), Input.BPCs, Input.PCs, + Rep, ConstSet, ConstMap, IC, 30, 60, false)) { + llvm::errs() << "Constant Synthesis internal error : " << EC.message(); + } + + if (ConstMap.empty()) { +// if (DebugLevel > 3) { + llvm::errs() << "Constant Synthesis failed, moving on.\n"; +// } Input = Copy; failcount++; if (failcount >= Insts.size()) { break; } - continue; + } else { + InstCache.clear(); + InstCache[C] = NewVar; + + NewVar->KnownOnes = ConstMap[C]; + NewVar->KnownZeros = ~ConstMap[C]; + + // Give up if can't be weakened 'too much' + const size_t WeakeningThreshold = NewVar->Width/2; + size_t BitsWeakened = 0; + + for (size_t i = 0; i < NewVar->Width; ++i) { + auto SaveZero = NewVar->KnownZeros; + auto SaveOne = NewVar->KnownOnes; + + NewVar->KnownZeros.clearBit(i); + NewVar->KnownOnes.clearBit(i); + + if (!Verify(Input)) { + NewVar->KnownZeros = SaveZero; + NewVar->KnownOnes = SaveOne; + } else { + BitsWeakened++; + } + } + if (BitsWeakened < WeakeningThreshold) { + Input = Copy; + failcount++; + if (failcount >= Insts.size()) { + break; + } + } + } Insts.clear(); collectInsts(Input.Mapping.LHS, Insts); @@ -624,7 +713,7 @@ class Reducer { return true; } - void Eliminate(ParsedReplacement &Input, Inst *I) { + Inst *Eliminate(ParsedReplacement &Input, Inst *I) { // Try to replace I with a new Var. Inst *NewVar = IC.createVar(I->Width, "newvar" + std::to_string(varnum++)); @@ -650,6 +739,7 @@ class Reducer { BPC.PC.LHS = getInstCopy(BPC.PC.LHS, IC, ICache, BCache, &CMap, false); BPC.PC.RHS = getInstCopy(BPC.PC.RHS, IC, ICache, BCache, &CMap, false); } + return NewVar; } void ReduceRec(ParsedReplacement Input_, std::vector &Results) { @@ -749,9 +839,9 @@ void ReduceAndGeneralize(InstContext &IC, Input = R.WeakenCR(Input); Input = R.WeakenDB(Input); -// if (ReduceKBIFY) { -// Input = R.ReduceKBIFY(Input); -// } + if (ReduceKBIFY) { + Input = R.ReduceGreedyKBIFY(Input); + } // Results.push_back(Input); diff --git a/tools/souper-check.cpp b/tools/souper-check.cpp index 3efc3e416..47cb883bb 100644 --- a/tools/souper-check.cpp +++ b/tools/souper-check.cpp @@ -289,6 +289,7 @@ int SolveInst(const MemoryBufferRef &MB, Solver *S) { std::set ConstSet; souper::getConstants(Rep.Mapping.RHS, ConstSet); + souper::getConstants(Rep.Mapping.LHS, ConstSet); if (ConstSet.empty()) { llvm::outs() << "; No reservedconst found in RHS\n"; } else { @@ -301,13 +302,17 @@ int SolveInst(const MemoryBufferRef &MB, Solver *S) { } if (!ResultConstMap.empty()) { - ReplacementContext Context; - llvm::outs() << "; RHS inferred successfully\n"; - PrintReplacementRHS(llvm::outs(), Rep.Mapping.RHS, Context); + std::map InstCache; + std::map BlockCache; + Rep.Mapping.LHS = + getInstCopy(Rep.Mapping.LHS, IC, InstCache, BlockCache, &ResultConstMap, false, false); + Rep.Mapping.RHS = + getInstCopy(Rep.Mapping.RHS, IC, InstCache, BlockCache, &ResultConstMap, false, false); + Rep.print(llvm::outs(), true); ++Success; } else { ++Fail; - llvm::outs() << "; Failed to infer RHS\n"; + llvm::outs() << "; Failed to synthesize constant(s)\n"; } } } else if (TryDataflowPruning) { From a77319ca7ec0c10f6eb53a47c23500bd3d93912d Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sat, 19 Feb 2022 10:03:06 -0700 Subject: [PATCH 048/165] foo --- include/souper/Inst/Inst.h | 1 + lib/Extractor/KLEEBuilder.cpp | 5 +++++ lib/Inst/Inst.cpp | 3 +++ lib/Parser/Parser.cpp | 1 + 4 files changed, 10 insertions(+) diff --git a/include/souper/Inst/Inst.h b/include/souper/Inst/Inst.h index af12c59f8..e1ec8c3ee 100644 --- a/include/souper/Inst/Inst.h +++ b/include/souper/Inst/Inst.h @@ -101,6 +101,7 @@ struct Inst : llvm::FoldingSetNode { Cttz, Ctlz, LogB, + BitWidth, BitReverse, FShl, FShr, diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index 460298e63..fbbea5ee7 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -354,6 +354,11 @@ class KLEEBuilder : public ExprBuilder { auto Ctlz = SubExpr::create(W, countOnes(Val)); return SubExpr::create(SubExpr::create(W, Ctlz), One); } + case Inst::BitWidth: { + ref L = get(Ops[0]); + unsigned Width = L->getWidth(); + return klee::ConstantExpr::create(Width, Width); + } case Inst::FShl: case Inst::FShr: { unsigned IWidth = I->Width; diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index 936a74b5a..cb1d3d656 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -425,6 +425,8 @@ const char *Inst::getKindName(Kind K) { return "ctlz"; case LogB: return "logb"; + case BitWidth: + return "width"; case FShl: return "fshl"; case FShr: @@ -520,6 +522,7 @@ Inst::Kind Inst::getKind(std::string Name) { .Case("cttz", Inst::Cttz) .Case("ctlz", Inst::Ctlz) .Case("logb", Inst::LogB) + .Case("width", Inst::BitWidth) .Case("fshl", Inst::FShl) .Case("fshr", Inst::FShr) .Case("sadd.with.overflow", Inst::SAddWithOverflow) diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp index caafaf2ef..e2b91fabb 100644 --- a/lib/Parser/Parser.cpp +++ b/lib/Parser/Parser.cpp @@ -591,6 +591,7 @@ bool Parser::typeCheckInst(Inst::Kind IK, unsigned &Width, case Inst::Cttz: case Inst::Ctlz: case Inst::LogB: + case Inst::BitWidth: case Inst::Freeze: MaxOps = MinOps = 1; break; From 7f9d726cff4db481143fec46d6a5b174c91bcb79 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 22 Feb 2022 16:55:29 -0700 Subject: [PATCH 049/165] foo --- tools/generalize.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index be052c94a..de68c3242 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -47,6 +47,11 @@ static llvm::cl::opt SymbolizeConstant("symbolize", "(default=false)"), llvm::cl::init(false)); +static llvm::cl::opt SymbolizeWidth("symbolize-width", + llvm::cl::desc("Try to replace a concrete constant with a function of bitwidth." + "(default=false)"), + llvm::cl::init(false)); + static llvm::cl::opt SymbolizeNumInsts("symbolize-num-insts", llvm::cl::desc("Number of instructions to synthesize" "(default=1)"), @@ -117,10 +122,24 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, InstCache[LHSConsts[i]] = FakeConsts[i]; } + auto Components = FakeConsts; // Does it makes sense for the expression to depend on other variables? // If yes, expand the third argument to include inputs + if (SymbolizeWidth) { + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); + for (auto &&V : Vars) { + auto Width = IC.getInst(Inst::BitWidth, FakeConsts[0]->Width, {V}); + Components.push_back(Width); + Components.push_back(IC.getInst(Inst::LogB, FakeConsts[0]->Width, {Width})); + // auto IntMax = 1 << Width - 1 + // TODO other comps, like INT_MAX + // Dedup widths which can not be different + } + } + EnumerativeSynthesis ES; - auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, FakeConsts, + auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, RHSConsts[0]->Width); std::vector>> From aa52e367a58110fd959483a753efbeb6e38b65b1 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 22 Feb 2022 18:32:54 -0700 Subject: [PATCH 050/165] foo --- lib/Inst/Inst.cpp | 3 +++ tools/generalize.cpp | 21 +++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index cb1d3d656..4370ba1a4 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -116,6 +116,9 @@ std::string ReplacementContext::printInst(Inst *I, llvm::raw_ostream &Out, std::string ReplacementContext::printInstImpl(Inst *I, llvm::raw_ostream &Out, bool printNames, Inst *OrigI) { + if (printNames && I->Name.length() != 0 && std::isdigit(I->Name[0])) { + I->Name = "v" + I->Name; + } std::string Str; llvm::raw_string_ostream SS(Str); diff --git a/tools/generalize.cpp b/tools/generalize.cpp index de68c3242..73f260ece 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -118,7 +118,7 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::vector FakeConsts; for (size_t i = 0; i < LHSConsts.size(); ++i) { FakeConsts.push_back( - IC.createVar(LHSConsts[i]->Width, "fakeconst_" + std::to_string(i))); + IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i))); InstCache[LHSConsts[i]] = FakeConsts[i]; } @@ -364,9 +364,9 @@ void SymbolizeAndGeneralize(InstContext &IC, CandidateMap Results; // // One at a time -// for (auto LHSConst : LHSConsts) { -// SymbolizeAndGeneralize(IC, S, Input, {LHSConst}, RHSConsts, Results); -// } + for (auto LHSConst : LHSConsts) { + SymbolizeAndGeneralize(IC, S, Input, {LHSConst}, RHSConsts, Results); + } // TODO: Why does one at a time get solutions that all at once doesn't? @@ -375,9 +375,18 @@ void SymbolizeAndGeneralize(InstContext &IC, SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); // TODO: Move sorting here + std::set ResultStrs; for (auto &&Result : Results) { - Result.print(llvm::outs(), true); - llvm::outs() << "\n"; + std::string str; + llvm::raw_string_ostream ostr(str); + Result.print(ostr, true); + ResultStrs.insert(str); + } + for (auto &&Str : ResultStrs) { + llvm::outs() << Str << "\n"; + } + if (Results.empty()) { + Input.print(llvm::outs(), true); } } From 3cbb0d6e1382b9672f807710a2e1ca2a97a71323 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 22 Feb 2022 18:36:28 -0700 Subject: [PATCH 051/165] foo --- tools/generalize.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 73f260ece..ef8980424 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -374,6 +374,10 @@ void SymbolizeAndGeneralize(InstContext &IC, // All at once SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); + llvm::outs() << "Input:\n"; + Input.print(llvm::outs(), true); + llvm::outs() << "\nResults:\n"; + // TODO: Move sorting here std::set ResultStrs; for (auto &&Result : Results) { @@ -382,12 +386,10 @@ void SymbolizeAndGeneralize(InstContext &IC, Result.print(ostr, true); ResultStrs.insert(str); } + for (auto &&Str : ResultStrs) { llvm::outs() << Str << "\n"; } - if (Results.empty()) { - Input.print(llvm::outs(), true); - } } size_t InferWidth(Inst::Kind K, const std::vector &Ops) { From 3eba869dc74343f209c538ffbf69d8ccc0b24264 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 24 Feb 2022 17:25:46 -0700 Subject: [PATCH 052/165] foo --- include/souper/Infer/SynthUtils.h | 74 +++++++++++++++++++++++++++++++ tools/generalize.cpp | 2 + 2 files changed, 76 insertions(+) create mode 100644 include/souper/Infer/SynthUtils.h diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h new file mode 100644 index 000000000..56a3b8355 --- /dev/null +++ b/include/souper/Infer/SynthUtils.h @@ -0,0 +1,74 @@ +#ifndef SOUPER_SYNTH_UTILS_H +#define SOUPER_SYNTH_UTILS_H + +#include "souper/Inst/Inst.h" +#include "souper/Infer/EnumerativeSynthesis.h" + +namespace souper { + +class Builder { +public: + Builder(Inst *I_, InstContext *IC_) : I(I_), IC(IC_) {} + + Inst *operator()() { + assert(I); + return I; + } + +#define BINOP(K) \ + template Builder K(T t) { \ + auto L = I; auto R = i(t, *this); \ + return Builder(IC->getInst(Inst::K, L->Width, {L, R}), IC); \ + } \ + + BINOP(Add) BINOP(Sub) +#undef BINOP + +#define BINOPW(K) \ + template Builder K(T t) { \ + auto L = I; auto R = i(t, *this); \ + return Builder(IC->getInst(Inst::K, 1, {L, R}), IC); \ + } \ + BINOPW(Slt) BINOPW(Ult) +#undef BINOPW + +private: + Inst *I = nullptr; + InstContext *IC = nullptr; + + Inst *i(Builder A, Inst *I) { + assert(A.I); + return A.I; + } + + template + Inst *i(N Number, Builder B) { + return B.IC->getConst(llvm::APInt(B.I->Width, Number)); + } + + template<> + Inst *i(Inst *I, Builder B) { + assert(I); + return I; + } + + template<> + Inst *i(Builder A, Builder B) { + assert(A.I); + return A.I; + } + + template<> + Inst *i(std::string Number, Builder B) { + return B.IC->getConst(llvm::APInt(B.I->Width, Number, 10)); + } + + template<> + Inst *i(llvm::APInt Number, Builder B) { + return B.IC->getConst(Number); + } +}; + +} + +#endif diff --git a/tools/generalize.cpp b/tools/generalize.cpp index ef8980424..2c0ed7845 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -5,6 +5,7 @@ #include "souper/Infer/Preconditions.h" #include "souper/Infer/EnumerativeSynthesis.h" #include "souper/Infer/ConstantSynthesis.h" +#include "souper/Infer/SynthUtils.h" #include "souper/Inst/InstGraph.h" #include "souper/Parser/Parser.h" #include "souper/Tool/GetSolver.h" @@ -114,6 +115,7 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::vector LHSConsts, std::vector RHSConsts, CandidateMap &Results) { + std::map InstCache; std::vector FakeConsts; for (size_t i = 0; i < LHSConsts.size(); ++i) { From 0e6cfe77e65d4d7abfe37f3874c713d4678d57c7 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 24 Feb 2022 17:49:07 -0700 Subject: [PATCH 053/165] foo --- include/souper/Infer/SynthUtils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 56a3b8355..2d7b5d96b 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -21,7 +21,7 @@ class Builder { return Builder(IC->getInst(Inst::K, L->Width, {L, R}), IC); \ } \ - BINOP(Add) BINOP(Sub) + BINOP(Add) BINOP(Sub) BINOP(And) #undef BINOP #define BINOPW(K) \ @@ -29,7 +29,7 @@ class Builder { auto L = I; auto R = i(t, *this); \ return Builder(IC->getInst(Inst::K, 1, {L, R}), IC); \ } \ - BINOPW(Slt) BINOPW(Ult) + BINOPW(Slt) BINOPW(Ult) BINOPW(Eq) #undef BINOPW private: From 3d6c39d2defe35e667c59a4f04e074dce2bee523 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 15 Mar 2022 13:27:38 +0530 Subject: [PATCH 054/165] foo --- include/souper/Infer/SynthUtils.h | 18 +++---- tools/generalize.cpp | 78 ++++++++++++++++++++++++------- 2 files changed, 69 insertions(+), 27 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 2d7b5d96b..f8812c03f 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -8,7 +8,7 @@ namespace souper { class Builder { public: - Builder(Inst *I_, InstContext *IC_) : I(I_), IC(IC_) {} + Builder(Inst *I_, InstContext &IC_) : I(I_), IC(IC_) {} Inst *operator()() { assert(I); @@ -18,8 +18,8 @@ class Builder { #define BINOP(K) \ template Builder K(T t) { \ auto L = I; auto R = i(t, *this); \ - return Builder(IC->getInst(Inst::K, L->Width, {L, R}), IC); \ - } \ + return Builder(IC.getInst(Inst::K, L->Width, {L, R}), IC); \ + } BINOP(Add) BINOP(Sub) BINOP(And) #undef BINOP @@ -27,14 +27,14 @@ class Builder { #define BINOPW(K) \ template Builder K(T t) { \ auto L = I; auto R = i(t, *this); \ - return Builder(IC->getInst(Inst::K, 1, {L, R}), IC); \ - } \ + return Builder(IC.getInst(Inst::K, 1, {L, R}), IC); \ + } BINOPW(Slt) BINOPW(Ult) BINOPW(Eq) #undef BINOPW private: Inst *I = nullptr; - InstContext *IC = nullptr; + InstContext &IC; Inst *i(Builder A, Inst *I) { assert(A.I); @@ -43,7 +43,7 @@ class Builder { template Inst *i(N Number, Builder B) { - return B.IC->getConst(llvm::APInt(B.I->Width, Number)); + return B.IC.getConst(llvm::APInt(B.I->Width, Number)); } template<> @@ -60,12 +60,12 @@ class Builder { template<> Inst *i(std::string Number, Builder B) { - return B.IC->getConst(llvm::APInt(B.I->Width, Number, 10)); + return B.IC.getConst(llvm::APInt(B.I->Width, Number, 10)); } template<> Inst *i(llvm::APInt Number, Builder B) { - return B.IC->getConst(Number); + return B.IC.getConst(Number); } }; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 2c0ed7845..e1f855f38 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -75,8 +75,18 @@ static llvm::cl::opt FixIt("fixit", "(default=false)"), llvm::cl::init(false)); -static llvm::cl::opt GeneralizeWidth("generalize-width", - llvm::cl::desc("Given a valid optimization, generalize bitwidth." +static llvm::cl::opt GeneralizeWidth("all-widths", + llvm::cl::desc("Given a valid optimization, output all bitwidths." + "(default=false)"), + llvm::cl::init(false)); + +static llvm::cl::opt GeneralizeWidthVerify("all-widths-verify", + llvm::cl::desc("Verify for all bitwidths" + "(default=false)"), + llvm::cl::init(false)); + +static llvm::cl::opt MinimizeWidth("minimize-width", + llvm::cl::desc("Find valid version with minimal width" "(default=false)"), llvm::cl::init(false)); @@ -396,6 +406,8 @@ void SymbolizeAndGeneralize(InstContext &IC, size_t InferWidth(Inst::Kind K, const std::vector &Ops) { switch (K) { + case Inst::LShr: + case Inst::Shl: case Inst::And: case Inst::Or: case Inst::Xor: @@ -410,15 +422,18 @@ size_t InferWidth(Inst::Kind K, const std::vector &Ops) { } } -Inst *CloneInst(InstContext &IC, Inst *I, std::map &WidthMap) { +Inst *CloneInst(InstContext &IC, Inst *I, std::map &Vars) { if (I->K == Inst::Var) { - return IC.createVar(WidthMap[I], I->Name); // TODO other attributes + return Vars[I]; } else if (I->K == Inst::Const) { - llvm_unreachable("Const"); + // llvm_unreachable("Const"); + auto Goal = Vars.begin()->second->Width; // TODO Infer. + auto NewVal = I->Val.isSignBitSet() ? I->Val.sextOrTrunc(Goal) : I->Val.zextOrTrunc(Goal); + return IC.getConst(NewVal); } else { std::vector Ops; for (auto Op : I->Ops) { - Ops.push_back(CloneInst(IC, Op, WidthMap)); + Ops.push_back(CloneInst(IC, Op, Vars)); } return IC.getInst(I->K, InferWidth(I->K, Ops), Ops); } @@ -430,18 +445,44 @@ void GeneralizeBitWidth(InstContext &IC, Solver *S, assert(Vars.size() == 1 && "Multiple variables unimplemented."); - std::map WidthMap; + for (int i = 1; i <= 64; ++i) { + std::map Reps; + Reps[Vars[0]] = IC.createVar(i, Vars[0]->Name); - for (int i = 1; i < 64; ++i) { - WidthMap[Vars[0]] = i; - auto LHS = CloneInst(IC, Input.Mapping.LHS, WidthMap); - auto RHS = CloneInst(IC, Input.Mapping.RHS, WidthMap); + auto LHS = CloneInst(IC, Input.Mapping.LHS, Reps); + auto RHS = CloneInst(IC, Input.Mapping.RHS, Reps); - ReplacementContext RC; - auto str = RC.printInst(LHS, llvm::outs(), true); - llvm::outs() << "infer " << str << "\n"; - str = RC.printInst(RHS, llvm::outs(), true); - llvm::outs() << "result " << str << "\n\n"; + if (!GeneralizeWidthVerify && !MinimizeWidth) { + ReplacementContext RC; + auto str = RC.printInst(LHS, llvm::outs(), true); + llvm::outs() << "infer " << str << "\n"; + str = RC.printInst(RHS, llvm::outs(), true); + llvm::outs() << "result " << str << "\n\n"; + } else { + bool Valid; + InstMapping M(LHS, RHS); + std::vector> Models; + if (std::error_code EC = S->isValid(IC, {}, {}, M, Valid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + + if (Valid) { + if (MinimizeWidth) { + ReplacementContext RC; + auto str = RC.printInst(LHS, llvm::outs(), true); + llvm::outs() << "infer " << str << "\n"; + str = RC.printInst(RHS, llvm::outs(), true); + llvm::outs() << "result " << str << "\n\n"; + break; + } + llvm::outs () << "valid " << i << "\n"; + } else { + if (!MinimizeWidth) { + llvm::outs () << "invalid " << i << "\n"; + } + } + + } } } @@ -784,8 +825,9 @@ class Reducer { Inst *Ante = IC.getConst(llvm::APInt(1, true)); for (auto PC : Input_.PCs ) { - Inst *Eq = IC.getInst(Inst::Eq, 1, {PC.LHS, PC.RHS}); - Ante = IC.getInst(Inst::And, 1, {Ante, Eq}); + // Inst *Eq = IC.getInst(Inst::Eq, 1, {PC.LHS, PC.RHS}); + // Ante = IC.getInst(Inst::And, 1, {Ante, Eq}); + Ante = Builder(PC.LHS, IC).Eq(PC.RHS).And(Ante)(); } RC.printInst(Ante, SStr, false); From 6a014f706fc6db218d5506c71f19e31b4e8e0d00 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 24 Mar 2022 08:05:32 -0600 Subject: [PATCH 055/165] foo --- tools/generalize.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index e1f855f38..7190548a1 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -66,6 +66,10 @@ static llvm::cl::opt SymbolizeSimpleDF("symbolize-simple-dataflow", llvm::cl::desc("Generate simple dataflow facts supported by LLVM."), llvm::cl::init(false)); +static llvm::cl::opt SymbolizeKBDF("symbolize-infer-kb", + llvm::cl::desc("Generate KB constraints for symbolic constants."), + llvm::cl::init(false)); + static llvm::cl::opt SymbolizeConstSynthesis("symbolize-constant-synthesis", llvm::cl::desc("Allow concrete constants in the generated code."), llvm::cl::init(false)); @@ -302,6 +306,9 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, FakeConsts[0]->Negative = false; } } + if (SymbolizeKBDF) { + + } } else { // std::vector> KBResults; @@ -541,6 +548,91 @@ class Reducer { return Input; } + // Eventually replace the functions in Preconditions{.h/.cpp} with this. + // Does not produce exhaustive result. TODO Have an option to wrap in a cegis loop. + std::map inferKBPrecondition(ParsedReplacement Input, std::vector Targets) { + assert(Targets.size() == 1 && "Multiple targets unimplemented"); + std::map Result; + std::set SymConsts; + std::map InstCache; + std::map BlockCache; + std::map ConstMap; + size_t ConstID = 0; + for (auto V : Targets) { + auto C = IC.createSynthesisConstant(V->Width, ConstID++); + InstCache[V] = C; + SymConsts.insert(C); + } + auto Copy = Input; + InstMapping Rep; + Rep.LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, false, false); + Rep.RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, false, false); + + ConstantSynthesis CS; + +// llvm::errs() << "Constant synthesis problem: \n"; +// Input.print(llvm::errs(), true); +// llvm::errs() << "....end.... \n"; + + if (auto EC = CS.synthesize(S->getSMTLIBSolver(), Input.BPCs, Input.PCs, + Rep, SymConsts, ConstMap, IC, 30, 60, false)) { + llvm::errs() << "Constant Synthesis internal error : " << EC.message(); + } + + if (ConstMap.empty()) { +// if (DebugLevel > 3) { + llvm::errs() << "Constant Synthesis failed, moving on.\n"; +// } + Input = Copy; +// failcount++; +// if (failcount >= Insts.size()) { +// break; +// } + } else { + InstCache.clear(); + + // TODO: Generalize before allowing multiple targets + auto NewVar = Targets[0]; + auto C = InstCache[NewVar]; + + InstCache[C] = NewVar; + + NewVar->KnownOnes = ConstMap[C]; + NewVar->KnownZeros = ~ConstMap[C]; + + // Give up if can't be weakened 'too much' + const size_t WeakeningThreshold = NewVar->Width/2; + size_t BitsWeakened = 0; + + for (size_t i = 0; i < NewVar->Width; ++i) { + auto SaveZero = NewVar->KnownZeros; + auto SaveOne = NewVar->KnownOnes; + + NewVar->KnownZeros.clearBit(i); + NewVar->KnownOnes.clearBit(i); + + if (!Verify(Input)) { + NewVar->KnownZeros = SaveZero; + NewVar->KnownOnes = SaveOne; + } else { + BitsWeakened++; + } + } + if (BitsWeakened < WeakeningThreshold) { + Input = Copy; +// failcount++; +// if (failcount >= Insts.size()) { +// break; +// } + } + + } + + // CONT FROM HERE. DUMP RESULTS INTO MAP + + return Result; + } + ParsedReplacement ReduceGreedyKBIFY(ParsedReplacement Input) { std::set Insts; collectInsts(Input.Mapping.LHS, Insts); @@ -631,6 +723,7 @@ class Reducer { } Insts.clear(); collectInsts(Input.Mapping.LHS, Insts); + // ^ Can this be skipped? } while (!Insts.empty()); return Input; } From bd586e1d04d5238845538d9f1045d3dc04758280 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 24 Mar 2022 08:05:55 -0600 Subject: [PATCH 056/165] foo --- include/souper/Infer/SynthUtils.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index f8812c03f..de5468528 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -70,5 +70,4 @@ class Builder { }; } - #endif From 610e23bf999c975bb3b46c1bda9ed1aee27b58a2 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 4 Apr 2022 22:56:38 -0600 Subject: [PATCH 057/165] foo --- tools/generalize.cpp | 316 +++++++++++++++++++++++-------------------- 1 file changed, 168 insertions(+), 148 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 7190548a1..dda2502c1 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -124,26 +124,38 @@ void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { } } +void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement Input, + std::vector LHSConsts, + std::vector RHSConsts, + CandidateMap &Results) { + +} void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, std::vector LHSConsts, std::vector RHSConsts, CandidateMap &Results) { + // FIXME Very fragile. Maybe rewrite + + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); + std::map InstCache; std::vector FakeConsts; for (size_t i = 0; i < LHSConsts.size(); ++i) { FakeConsts.push_back( IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i))); InstCache[LHSConsts[i]] = FakeConsts[i]; + if (SymbolizeWidth) { + FakeConsts.push_back(IC.getInst(Inst::BitWidth, LHSConsts[i]->Width, {Vars[0]})); + } } auto Components = FakeConsts; // Does it makes sense for the expression to depend on other variables? // If yes, expand the third argument to include inputs if (SymbolizeWidth) { - std::vector Vars; - findVars(Input.Mapping.LHS, Vars); for (auto &&V : Vars) { auto Width = IC.getInst(Inst::BitWidth, FakeConsts[0]->Width, {V}); Components.push_back(Width); @@ -154,175 +166,183 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, } } - EnumerativeSynthesis ES; - auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, - RHSConsts[0]->Width); + std::vector Targets; + for (auto C : LHSConsts) { + Targets.push_back(C); + } + for (auto C : RHSConsts) { + Targets.push_back(C); + } - std::vector>> - Preconditions; + for (auto T : Targets) { - std::map BlockCache; - std::map ConstMap; - auto LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, - BlockCache, &ConstMap, false); + EnumerativeSynthesis ES; + auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, + T->Width); - std::vector WithoutConsts; + std::vector>> + Preconditions; - auto TryConstSynth = [&](Inst *Guess, std::set &ConstSet) { - std::map ResultConstMap; - std::map InstCacheCopy/* = InstCache*/; - InstCacheCopy[RHSConsts[0]] = Guess; - auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, + std::map BlockCache; + std::map ConstMap; + auto LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, false); - ConstantSynthesis CS; - auto SMTSolver = GetUnderlyingSolver(); - auto EC = CS.synthesize(SMTSolver.get(), Input.BPCs, Input.PCs, - InstMapping (LHS, RHS), ConstSet, - ResultConstMap, IC, /*MaxTries=*/30, 10, - /*AvoidNops=*/true); - if (!ResultConstMap.empty()) { - std::map InstCache; - std::map BlockCache; - auto LHSCopy = getInstCopy(LHS, IC, InstCache, BlockCache, &ResultConstMap, true); - RHS = getInstCopy(RHS, IC, InstCache, BlockCache, &ResultConstMap, true); - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHSCopy, RHS))); - return true; - } else { - if (DebugLevel > 2) { - llvm::errs() << "Constant Synthesis ((no Dataflow Preconditions)) failed. \n"; + std::vector WithoutConsts; + + auto TryConstSynth = [&](Inst *Guess, std::set &ConstSet) { + std::map ResultConstMap; + std::map InstCacheCopy/* = InstCache*/; + InstCacheCopy[T] = Guess; + auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, + BlockCache, &ConstMap, false); + ConstantSynthesis CS; + auto SMTSolver = GetUnderlyingSolver(); + auto EC = CS.synthesize(SMTSolver.get(), Input.BPCs, Input.PCs, + InstMapping (LHS, RHS), ConstSet, + ResultConstMap, IC, /*MaxTries=*/30, 10, + /*AvoidNops=*/true); + if (!ResultConstMap.empty()) { + std::map InstCache; + std::map BlockCache; + auto LHSCopy = getInstCopy(LHS, IC, InstCache, BlockCache, &ResultConstMap, true); + RHS = getInstCopy(RHS, IC, InstCache, BlockCache, &ResultConstMap, true); + + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHSCopy, RHS))); + return true; + } else { + if (DebugLevel > 2) { + llvm::errs() << "Constant Synthesis ((no Dataflow Preconditions)) failed. \n"; + } + } + return false; + }; + + + for (auto &Guess : Guesses) { + std::set ConstSet; + souper::getConstants(Guess, ConstSet); + if (!ConstSet.empty()) { + if (SymbolizeConstSynthesis) { + bool Success = TryConstSynth(Guess, ConstSet); + // llvm::errs() << "Succ:" << Success << "\n"; + if (SymbolizeSimpleDF) { + if (!Success) { + FakeConsts[0]->PowOfTwo = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->PowOfTwo = false; + } + // llvm::errs() << "Succ:" << Success << "\n"; + + if (!Success) { + FakeConsts[0]->NonZero = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->NonZero = false; + } + // llvm::errs() << "Succ:" << Success << "\n"; + + if (!Success) { + FakeConsts[0]->NonNegative = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->NonNegative = false; + } + // llvm::errs() << "Succ:" << Success << "\n"; + + if (!Success) { + FakeConsts[0]->Negative = true; + Success = TryConstSynth(Guess, ConstSet); + FakeConsts[0]->Negative = false; + } + // llvm::errs() << "Succ:" << Success << "\n"; + (void)Success; + } + } + + } else { + WithoutConsts.push_back(Guess); } } - return false; - }; + std::swap(WithoutConsts, Guesses); + + for (auto &Guess : Guesses) { + std::map InstCacheCopy/* = InstCache*/; + InstCacheCopy[T] = Guess; - for (auto &Guess : Guesses) { - std::set ConstSet; - souper::getConstants(Guess, ConstSet); - if (!ConstSet.empty()) { - if (SymbolizeConstSynthesis) { - bool Success = TryConstSynth(Guess, ConstSet); - // llvm::errs() << "Succ:" << Success << "\n"; + + auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, + BlockCache, &ConstMap, false); + + + if (DebugLevel > 4) { + { + llvm::errs() << "GUESS:\n"; + ReplacementContext RC; + RC.printInst(Guess, llvm::errs(), true); + } + { + llvm::errs() << "JoinedGUESS:\n"; + ReplacementContext RC; + RC.printInst(RHS, llvm::errs(), true); + } + } + + InstMapping Mapping(LHS, RHS); + if (true /*remove when the other branch exists*/ || SymbolizeNoDFP) { + bool IsValid; + auto CheckAndSave = [&](){ + std::vector> Models; + if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Mapping, IsValid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + if (IsValid) { + InstMapping Clone; + std::map InstCache; + std::map BlockCache; + std::map ConstMap; + Clone.LHS = getInstCopy(Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); + Clone.RHS = getInstCopy(Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Clone)); + } + }; + CheckAndSave(); if (SymbolizeSimpleDF) { - if (!Success) { + if (!IsValid) { FakeConsts[0]->PowOfTwo = true; - Success = TryConstSynth(Guess, ConstSet); + CheckAndSave(); FakeConsts[0]->PowOfTwo = false; } - // llvm::errs() << "Succ:" << Success << "\n"; - - if (!Success) { + if (!IsValid) { FakeConsts[0]->NonZero = true; - Success = TryConstSynth(Guess, ConstSet); + CheckAndSave(); FakeConsts[0]->NonZero = false; } - // llvm::errs() << "Succ:" << Success << "\n"; - - if (!Success) { + if (!IsValid) { FakeConsts[0]->NonNegative = true; - Success = TryConstSynth(Guess, ConstSet); + CheckAndSave(); FakeConsts[0]->NonNegative = false; } - // llvm::errs() << "Succ:" << Success << "\n"; - - if (!Success) { + if (!IsValid) { FakeConsts[0]->Negative = true; - Success = TryConstSynth(Guess, ConstSet); + CheckAndSave(); FakeConsts[0]->Negative = false; } - // llvm::errs() << "Succ:" << Success << "\n"; - (void)Success; - } - } - - } else { - WithoutConsts.push_back(Guess); - } - } - std::swap(WithoutConsts, Guesses); - - for (auto &Guess : Guesses) { - std::map InstCacheCopy/* = InstCache*/; - InstCacheCopy[RHSConsts[0]] = Guess; - - - - auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, - BlockCache, &ConstMap, false); - - - if (DebugLevel > 4) { - { - llvm::errs() << "GUESS:\n"; - ReplacementContext RC; - RC.printInst(Guess, llvm::errs(), true); - } - { - llvm::errs() << "JoinedGUESS:\n"; - ReplacementContext RC; - RC.printInst(RHS, llvm::errs(), true); - } - } - - InstMapping Mapping(LHS, RHS); - if (true /*remove when the other branch exists*/ || SymbolizeNoDFP) { - bool IsValid; - auto CheckAndSave = [&](){ - std::vector> Models; - if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Mapping, IsValid, &Models)) { - llvm::errs() << EC.message() << '\n'; - } - if (IsValid) { - InstMapping Clone; - std::map InstCache; - std::map BlockCache; - std::map ConstMap; - Clone.LHS = getInstCopy(Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); - Clone.RHS = getInstCopy(Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Clone)); - } - }; - CheckAndSave(); - if (SymbolizeSimpleDF) { - if (!IsValid) { - FakeConsts[0]->PowOfTwo = true; - CheckAndSave(); - FakeConsts[0]->PowOfTwo = false; - } - if (!IsValid) { - FakeConsts[0]->NonZero = true; - CheckAndSave(); - FakeConsts[0]->NonZero = false; - } - if (!IsValid) { - FakeConsts[0]->NonNegative = true; - CheckAndSave(); - FakeConsts[0]->NonNegative = false; - } - if (!IsValid) { - FakeConsts[0]->Negative = true; - CheckAndSave(); - FakeConsts[0]->Negative = false; } - } - if (SymbolizeKBDF) { + } else { + // std::vector> KBResults; + // std::vector> CRResults; + // bool FoundWP = false; + // S->abstractPrecondition(Input.BPCs, Input.PCs, Mapping, IC, FoundWP, KBResults, CRResults); + // Preconditions.push_back(KBResults); + // if (!FoundWP) { + // Guess = nullptr; // TODO: Better failure indicator + // } else { + // Guess = RHS; + // } } - - } else { -// std::vector> KBResults; -// std::vector> CRResults; -// bool FoundWP = false; -// S->abstractPrecondition(Input.BPCs, Input.PCs, Mapping, IC, FoundWP, KBResults, CRResults); -// Preconditions.push_back(KBResults); -// if (!FoundWP) { -// Guess = nullptr; // TODO: Better failure indicator -// } else { -// Guess = RHS; -// } - } } +} // std::vector Idx; // std::vector Utility; @@ -375,10 +395,10 @@ void SymbolizeAndGeneralize(InstContext &IC, findInsts(Input.Mapping.LHS, LHSConsts, Pred); findInsts(Input.Mapping.RHS, RHSConsts, Pred); - if (RHSConsts.empty()) { - return; - // TODO: Possible to just generalize LHS consts with preconditions? - } + // if (RHSConsts.empty()) { + // return; + // // TODO: Possible to just generalize LHS consts with preconditions? + // } CandidateMap Results; From 344d87d729fc573d8d5b0438f0a91ebb911199da Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 5 Apr 2022 16:13:11 -0600 Subject: [PATCH 058/165] foo --- tools/generalize.cpp | 153 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 2 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index dda2502c1..cc9567dbc 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -5,6 +5,7 @@ #include "souper/Infer/Preconditions.h" #include "souper/Infer/EnumerativeSynthesis.h" #include "souper/Infer/ConstantSynthesis.h" +#include "souper/Infer/Interpreter.h" #include "souper/Infer/SynthUtils.h" #include "souper/Inst/InstGraph.h" #include "souper/Parser/Parser.h" @@ -124,11 +125,159 @@ void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { } } + +// This can probably be done more efficiently, but likely not the bottleneck anywhere +std::vector> GetCombinations(std::vector Counts) { + if (Counts.size() == 1) { + std::vector> Result; + for (int i = 0; i < Counts[0]; ++i) { + Result.push_back({i}); + } + return Result; + } + + auto Last = Counts.back(); + Counts.pop_back(); + auto Partial = GetCombinations(Counts); + + std::vector> Result; + for (int i = 0; i < Last; ++i) { + for (auto Copy : Partial) { + Copy.push_back(i); + Result.push_back(Copy); + } + } + return Result; +} + +// TODO separate function for bitwidth +// why? + +// TODO Document options void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement Input, std::vector LHSConsts, std::vector RHSConsts, CandidateMap &Results) { + llvm::outs() << "HERE\n"; + + // The goal of this function is to convert concrete constants into expressions + // And synthesize preconditions when appropriate + + // std::vector Vars; + // findVars(Input.Mapping.LHS, Vars); + + std::vector Components; + + std::map InstCache; + ValueCache VC; + // Create a symbolic const for each LHS const + for (size_t i = 0; i < LHSConsts.size(); ++i) { + auto C = IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i)); + Components.push_back(C); + InstCache[LHSConsts[i]] = C; + VC[C] = EvalValue(LHSConsts[i]->Val); + } + + if (!SymbolizeConstSynthesis) { + std::set ConcreteConsts; // for deduplication + for (auto C : LHSConsts) { + ConcreteConsts.insert(C); + ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 0))); + ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 1))); + ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, -1))); + ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 2))); + } + for (auto C : RHSConsts) { + ConcreteConsts.insert(C); + } + for (auto C : ConcreteConsts) { + Components.push_back(C); + } + } + + // TODO Derive relations between LHSConsts and use them as preconditions + + // Must consider all targets at once + // Test phase before verification + // Is it possible to pre-generate the set of all possible constants? No. + // Some? definitely. + + std::vector> Candidates; + + ConcreteInterpreter CI(VC); + for (auto &&Target : RHSConsts) { + Candidates.push_back({}); + EnumerativeSynthesis ES; + auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, + Target->Width); + // TODO : Memoize expressions by width + + for (auto &&Guess : Guesses) { + std::set ConstSet; + souper::getConstants(Guess, ConstSet); + if (!ConstSet.empty()) { + continue; + // TODO: Fake constant synthesis based on algebra + // We have ConcreteLHS = f(ConcreteRHS, SymbolicConst) + // Solve equation to find SymbolicConst + // TODO: Proper constant synthesis + } + auto Val = CI.evaluateInst(Guess); + if (Val.hasValue() && Val.getValue() == Target->Val) { + Candidates.back().push_back(Guess); + } + } + } + + + std::vector Counts; + for (auto &&Cand : Candidates) { + Counts.push_back(Cand.size()); + } + + // Generate all combination of candidates + std::vector> Combinations = GetCombinations(Counts); + + for (auto &&Comb : Combinations) { + auto InstCacheCopy = InstCache; + for (int i = 0; i < RHSConsts.size(); ++i) { + InstCacheCopy[RHSConsts[i]] = Candidates[i][Comb[i]]; + } + + std::map BlockCache; + std::map ConstMap; + auto LHS = getInstCopy(Input.Mapping.LHS, IC, InstCacheCopy, + BlockCache, &ConstMap, false); + auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, + BlockCache, &ConstMap, false); + + InstMapping Mapping(LHS, RHS); + + bool IsValid = false; + auto CheckAndSave = [&](){ + std::vector> Models; + if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Mapping, IsValid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + if (IsValid) { + InstMapping Clone; + std::map InstCache; + std::map BlockCache; + std::map ConstMap; + Clone.LHS = getInstCopy(Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); + Clone.RHS = getInstCopy(Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Clone)); + } + }; + + CheckAndSave(); + + // TODO With preconditions + + } + + } void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, @@ -404,14 +553,14 @@ void SymbolizeAndGeneralize(InstContext &IC, // // One at a time for (auto LHSConst : LHSConsts) { - SymbolizeAndGeneralize(IC, S, Input, {LHSConst}, RHSConsts, Results); + SymbolizeAndGeneralizeRewrite(IC, S, Input, {LHSConst}, RHSConsts, Results); } // TODO: Why does one at a time get solutions that all at once doesn't? // All at once - SymbolizeAndGeneralize(IC, S, Input, LHSConsts, RHSConsts, Results); + SymbolizeAndGeneralizeRewrite(IC, S, Input, LHSConsts, RHSConsts, Results); llvm::outs() << "Input:\n"; Input.print(llvm::outs(), true); From 16f1bdb327899d69e2db6119f9b6db3a4508b6b2 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 10 May 2020 01:06:39 -0600 Subject: [PATCH 059/165] Fix improveMustDemandedBits --- lib/Infer/Pruning.cpp | 52 ++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/lib/Infer/Pruning.cpp b/lib/Infer/Pruning.cpp index ba560cc39..7dce33f22 100644 --- a/lib/Infer/Pruning.cpp +++ b/lib/Infer/Pruning.cpp @@ -686,28 +686,38 @@ bool PruningManager::isInputValid(ValueCache &Cache) { void PruningManager::improveMustDemandedBits(InputVarInfo &IVI) { for (size_t i = 0; i < InputVals.size(); ++i) { - for (size_t j = 0; j < InputVals.size(); ++j) { - for (auto &Pair : IVI) { - auto Var = Pair.first; - auto &I1 = InputVals[i][Var]; - auto &I2 = InputVals[j][Var]; - if (I1.hasValue() && I1.hasValue() && - I1.getValue() != I2.getValue()) { - auto &MDB = Pair.second; - for (size_t k = 0; k < Var->Width; ++k) { - if (!MDB[k] && I1.getValue()[k] != I2.getValue()[k]) { - auto V1 = ConcreteInterpreters[i].evaluateInst(SC.LHS); - auto V2 = ConcreteInterpreters[j].evaluateInst(SC.LHS); - if (V1.hasValue() && V2.hasValue() && - V1.getValue() != V2.getValue()) { - MDB.setBit(k); - // If two input values of a variable differing in the - // k'th bit can produce differing outputs, the k'th - // is required/must demanded/important. - } - } - } + auto VC = InputVals[i]; + for (auto &Pair : IVI) { + auto Var = Pair.first; + + for (size_t k = 0; k < Var->Width; ++k) { + llvm::APInt Val = VC[Var].getValue(); + auto Val2 = Val; + if (Val[k]) { + Val2.clearBit(k); + } else { + Val2.setBit(k); } + + ValueCache VC2 = VC; + VC2[Var] = EvalValue(Val2); + auto &MDB = Pair.second; + if (!isInputValid(VC2) || MDB[k]) { + continue; + } + + auto V1 = ConcreteInterpreters[i].evaluateInst(SC.LHS); + auto V2 = ConcreteInterpreter(SC.LHS, VC2).evaluateInst(SC.LHS); + + if (V1.hasValue() && V2.hasValue() && + V1.getValue() != V2.getValue()) { + MDB.setBit(k); + // If two input values of a variable differing in the + // k'th bit BUT EQUAL IN ALL OTHER BITS can produce + // differing outputs, the k'th is required/must + // demanded/important. + } + } } } From d677ba95231fa5a96abf493fa79865cb352e39b2 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 5 Apr 2022 21:47:24 -0600 Subject: [PATCH 060/165] foo --- include/souper/Infer/SynthUtils.h | 25 ++++++ lib/Infer/Pruning.cpp | 4 +- tools/generalize.cpp | 122 ++++++++++++++++++++++-------- 3 files changed, 116 insertions(+), 35 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index de5468528..9b07b0356 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -69,5 +69,30 @@ class Builder { } }; +Inst *Replace(Inst *R, InstContext &IC, std::map &M) { + std::map BlockCache; + std::map ConstMap; + return getInstCopy(R, IC, M, BlockCache, &ConstMap, false); +} + +Inst *Clone(Inst *R, InstContext &IC) { + std::map BlockCache; + std::map ConstMap; + std::map InstCache; + return getInstCopy(R, IC, InstCache, BlockCache, &ConstMap, true, false); +} + +InstMapping Clone(InstMapping In, InstContext &IC) { + std::map BlockCache; + std::map ConstMap; + std::map InstCache; + InstMapping Out; + Out.LHS = getInstCopy(In.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); + Out.RHS = getInstCopy(In.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); + return Out; +} + + + } #endif diff --git a/lib/Infer/Pruning.cpp b/lib/Infer/Pruning.cpp index 7dce33f22..3ccb455c7 100644 --- a/lib/Infer/Pruning.cpp +++ b/lib/Infer/Pruning.cpp @@ -37,7 +37,7 @@ namespace { static llvm::cl::opt EnableFB("souper-dataflow-pruning-fb", llvm::cl::desc("Prune with forced-bits analysis (default=true)"), - llvm::cl::init(true)); + llvm::cl::init(false)); static llvm::cl::opt EnableRB("souper-dataflow-pruning-rb", llvm::cl::desc("Prune with required-bits analysis (default=true)"), @@ -45,7 +45,7 @@ namespace { static llvm::cl::opt EnableBB("souper-dataflow-pruning-bb", llvm::cl::desc("Prune with bivalent-bits analysis (default=true)"), - llvm::cl::init(true)); + llvm::cl::init(false)); } namespace souper { diff --git a/tools/generalize.cpp b/tools/generalize.cpp index cc9567dbc..9a9ccc22f 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -5,7 +5,7 @@ #include "souper/Infer/Preconditions.h" #include "souper/Infer/EnumerativeSynthesis.h" #include "souper/Infer/ConstantSynthesis.h" -#include "souper/Infer/Interpreter.h" +#include "souper/Infer/Pruning.h" #include "souper/Infer/SynthUtils.h" #include "souper/Inst/InstGraph.h" #include "souper/Parser/Parser.h" @@ -158,32 +158,29 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement std::vector LHSConsts, std::vector RHSConsts, CandidateMap &Results) { - - llvm::outs() << "HERE\n"; - // The goal of this function is to convert concrete constants into expressions // And synthesize preconditions when appropriate // std::vector Vars; // findVars(Input.Mapping.LHS, Vars); - std::vector Components; + std::vector SymCS; std::map InstCache; ValueCache VC; // Create a symbolic const for each LHS const for (size_t i = 0; i < LHSConsts.size(); ++i) { auto C = IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i)); - Components.push_back(C); + SymCS.push_back(C); InstCache[LHSConsts[i]] = C; VC[C] = EvalValue(LHSConsts[i]->Val); } + std::vector Components; if (!SymbolizeConstSynthesis) { std::set ConcreteConsts; // for deduplication for (auto C : LHSConsts) { ConcreteConsts.insert(C); - ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 0))); ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 1))); ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, -1))); ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 2))); @@ -196,6 +193,11 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement } } + for (auto SymC : SymCS) { + Components.push_back(SymC); + } + + // TODO Derive relations between LHSConsts and use them as preconditions // Must consider all targets at once @@ -217,15 +219,32 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement std::set ConstSet; souper::getConstants(Guess, ConstSet); if (!ConstSet.empty()) { - continue; + if (SymbolizeConstSynthesis) { + auto SMTLIBSolver = GetUnderlyingSolver(); + SynthesisContext SC{IC, SMTLIBSolver.get(), Target, nullptr, {}, {}, false, 10}; + PruningManager Pruner(SC, SymCS, DebugLevel); + Pruner.init(); + if (!Pruner.isInfeasible(Guess, DebugLevel)) { + Candidates.back().push_back(Guess); +// llvm::errs() << "NOT PRUNED\n"; + } +// else { +// ReplacementContext RC; +// RC.printInst(Guess, llvm::errs(), true); +// llvm::errs() << "\n PRUNED\n"; +// } + } +// continue; +// Candidates.back().push_back(Guess); // TODO: Fake constant synthesis based on algebra // We have ConcreteLHS = f(ConcreteRHS, SymbolicConst) // Solve equation to find SymbolicConst // TODO: Proper constant synthesis - } - auto Val = CI.evaluateInst(Guess); - if (Val.hasValue() && Val.getValue() == Target->Val) { - Candidates.back().push_back(Guess); + } else { + auto Val = CI.evaluateInst(Guess); + if (Val.hasValue() && Val.getValue() == Target->Val) { + Candidates.back().push_back(Guess); + } } } } @@ -245,35 +264,73 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement InstCacheCopy[RHSConsts[i]] = Candidates[i][Comb[i]]; } - std::map BlockCache; - std::map ConstMap; - auto LHS = getInstCopy(Input.Mapping.LHS, IC, InstCacheCopy, - BlockCache, &ConstMap, false); - auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, - BlockCache, &ConstMap, false); + auto LHS = Replace(Input.Mapping.LHS, IC, InstCacheCopy); + auto RHS = Replace(Input.Mapping.RHS, IC, InstCacheCopy); InstMapping Mapping(LHS, RHS); bool IsValid = false; - auto CheckAndSave = [&](){ + auto CheckAndSave = [&]() { + + std::set ConstSet; + souper::getConstants(Mapping.RHS, ConstSet); + if (!ConstSet.empty()) { + std::map ResultConstMap; + ConstantSynthesis CS; + auto SMTSolver = GetUnderlyingSolver(); + auto EC = CS.synthesize(SMTSolver.get(), Input.BPCs, Input.PCs, + InstMapping (LHS, RHS), ConstSet, + ResultConstMap, IC, /*MaxTries=*/30, 10, + /*AvoidNops=*/true); + if (!ResultConstMap.empty()) { + std::map InstCache; + std::map BlockCache; + auto LHSCopy = getInstCopy(LHS, IC, InstCache, BlockCache, &ResultConstMap, true); + RHS = getInstCopy(RHS, IC, InstCache, BlockCache, &ResultConstMap, true); + + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHSCopy, RHS))); + } else { + if (DebugLevel > 2) { + llvm::errs() << "Constant Synthesis ((no Dataflow Preconditions)) failed. \n"; + } + } + return; + } std::vector> Models; if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Mapping, IsValid, &Models)) { llvm::errs() << EC.message() << '\n'; } if (IsValid) { - InstMapping Clone; - std::map InstCache; - std::map BlockCache; - std::map ConstMap; - Clone.LHS = getInstCopy(Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); - Clone.RHS = getInstCopy(Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Clone)); + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Clone(Mapping, IC))); } }; CheckAndSave(); - // TODO With preconditions + // TODO Make preconditions consistent + if (SymbolizeSimpleDF) { + if (!IsValid) { + Components[0]->PowOfTwo = true; + CheckAndSave(); + Components[0]->PowOfTwo = false; + } + if (!IsValid) { + Components[0]->NonZero = true; + CheckAndSave(); + Components[0]->NonZero = false; + } + if (!IsValid) { + Components[0]->NonNegative = true; + CheckAndSave(); + Components[0]->NonNegative = false; + } + if (!IsValid) { + Components[0]->Negative = true; + CheckAndSave(); + Components[0]->Negative = false; + } + } + // Is there a better way of doing this? } @@ -324,7 +381,6 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, } for (auto T : Targets) { - EnumerativeSynthesis ES; auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, T->Width); @@ -439,7 +495,7 @@ void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, InstMapping Mapping(LHS, RHS); if (true /*remove when the other branch exists*/ || SymbolizeNoDFP) { bool IsValid; - auto CheckAndSave = [&](){ + auto CheckAndSave = [&]() { std::vector> Models; if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Mapping, IsValid, &Models)) { llvm::errs() << EC.message() << '\n'; @@ -551,15 +607,15 @@ void SymbolizeAndGeneralize(InstContext &IC, CandidateMap Results; -// // One at a time + // One at a time for (auto LHSConst : LHSConsts) { SymbolizeAndGeneralizeRewrite(IC, S, Input, {LHSConst}, RHSConsts, Results); } - // TODO: Why does one at a time get solutions that all at once doesn't? - + // All subsets? + // TODO: Is it possible to encode this logically. -// All at once + // All at once SymbolizeAndGeneralizeRewrite(IC, S, Input, LHSConsts, RHSConsts, Results); llvm::outs() << "Input:\n"; From c3ffe7e99620993ab19b54895d183475a3ef26dc Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 5 Apr 2022 22:28:01 -0600 Subject: [PATCH 061/165] foo --- include/souper/Infer/SynthUtils.h | 43 ++++++++++++++++++++++++++- tools/generalize.cpp | 48 ++++++------------------------- 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 9b07b0356..dd2343bb4 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -3,6 +3,9 @@ #include "souper/Inst/Inst.h" #include "souper/Infer/EnumerativeSynthesis.h" +#include "souper/Infer/ConstantSynthesis.h" +#include "souper/Parser/Parser.h" +#include "souper/Tool/GetSolver.h" namespace souper { @@ -92,7 +95,45 @@ InstMapping Clone(InstMapping In, InstContext &IC) { return Out; } - +// Also Synthesizes given constants +// Returns clone if verified, nullptrs if not +InstMapping Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { + std::set ConstSet; + souper::getConstants(Input.Mapping.RHS, ConstSet); + if (!ConstSet.empty()) { + std::map ResultConstMap; + ConstantSynthesis CS; + auto SMTSolver = GetUnderlyingSolver(); + auto EC = CS.synthesize(SMTSolver.get(), Input.BPCs, Input.PCs, + Input.Mapping, ConstSet, + ResultConstMap, IC, /*MaxTries=*/30, 10, + /*AvoidNops=*/true); + if (!ResultConstMap.empty()) { + std::map InstCache; + std::map BlockCache; + auto LHSCopy = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ResultConstMap, true); + auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, BlockCache, &ResultConstMap, true); + return InstMapping(LHSCopy, RHS); +// Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHSCopy, RHS))); + } else { + if (DebugLevel > 2) { + llvm::errs() << "Constant Synthesis ((no Dataflow Preconditions)) failed. \n"; + } + } + return InstMapping(nullptr, nullptr); + } + std::vector> Models; + bool IsValid; + if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, IsValid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + if (IsValid) { +// Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Clone(Mapping, IC))); + return Clone(Input.Mapping, IC); + } else { + return InstMapping(nullptr, nullptr); + } +} } #endif diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 9a9ccc22f..493980428 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -158,11 +158,6 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement std::vector LHSConsts, std::vector RHSConsts, CandidateMap &Results) { - // The goal of this function is to convert concrete constants into expressions - // And synthesize preconditions when appropriate - - // std::vector Vars; - // findVars(Input.Mapping.LHS, Vars); std::vector SymCS; @@ -197,7 +192,6 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement Components.push_back(SymC); } - // TODO Derive relations between LHSConsts and use them as preconditions // Must consider all targets at once @@ -249,7 +243,6 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement } } - std::vector Counts; for (auto &&Cand : Candidates) { Counts.push_back(Cand.size()); @@ -268,40 +261,14 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement auto RHS = Replace(Input.Mapping.RHS, IC, InstCacheCopy); InstMapping Mapping(LHS, RHS); - + auto Copy = Input; + Copy.Mapping = Mapping; bool IsValid = false; - auto CheckAndSave = [&]() { - std::set ConstSet; - souper::getConstants(Mapping.RHS, ConstSet); - if (!ConstSet.empty()) { - std::map ResultConstMap; - ConstantSynthesis CS; - auto SMTSolver = GetUnderlyingSolver(); - auto EC = CS.synthesize(SMTSolver.get(), Input.BPCs, Input.PCs, - InstMapping (LHS, RHS), ConstSet, - ResultConstMap, IC, /*MaxTries=*/30, 10, - /*AvoidNops=*/true); - if (!ResultConstMap.empty()) { - std::map InstCache; - std::map BlockCache; - auto LHSCopy = getInstCopy(LHS, IC, InstCache, BlockCache, &ResultConstMap, true); - RHS = getInstCopy(RHS, IC, InstCache, BlockCache, &ResultConstMap, true); - - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHSCopy, RHS))); - } else { - if (DebugLevel > 2) { - llvm::errs() << "Constant Synthesis ((no Dataflow Preconditions)) failed. \n"; - } - } - return; - } - std::vector> Models; - if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Mapping, IsValid, &Models)) { - llvm::errs() << EC.message() << '\n'; - } - if (IsValid) { - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Clone(Mapping, IC))); + auto CheckAndSave = [&] () { + auto Result = Verify(Copy, IC, S); + if (Result.LHS && Result.RHS) { + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Result)); } }; @@ -330,7 +297,8 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement Components[0]->Negative = false; } } - // Is there a better way of doing this? + // TODO Is there a better way of doing this? + // TODO Other kinds of preconditions? } From ad0edad792126d829062869ac741b88f3c3ac4db Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 19 Apr 2022 17:58:47 -0600 Subject: [PATCH 062/165] foo --- include/souper/Infer/SynthUtils.h | 4 +- lib/Infer/Interpreter.cpp | 4 ++ lib/Inst/Inst.cpp | 4 +- tools/generalize.cpp | 95 +++++++++++++++++++++++-------- 4 files changed, 79 insertions(+), 28 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index dd2343bb4..4856b273b 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -24,7 +24,7 @@ class Builder { return Builder(IC.getInst(Inst::K, L->Width, {L, R}), IC); \ } - BINOP(Add) BINOP(Sub) BINOP(And) + BINOP(Add) BINOP(Sub) BINOP(And) BINOP(Xor) #undef BINOP #define BINOPW(K) \ @@ -46,7 +46,7 @@ class Builder { template Inst *i(N Number, Builder B) { - return B.IC.getConst(llvm::APInt(B.I->Width, Number)); + return B.IC.getConst(llvm::APInt(B.I->Width, Number, false)); } template<> diff --git a/lib/Infer/Interpreter.cpp b/lib/Infer/Interpreter.cpp index b3e3c3f82..a5b902470 100644 --- a/lib/Infer/Interpreter.cpp +++ b/lib/Infer/Interpreter.cpp @@ -444,6 +444,10 @@ namespace souper { return Args[0]; } + case Inst::LogB: { + return {llvm::APInt(Inst->Width, ARG0.logBase2())}; + } + default: llvm::report_fatal_error("unimplemented instruction kind " + std::string(Inst::getKindName(Inst->K)) + diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index 4370ba1a4..a00fb4a5f 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -1225,12 +1225,13 @@ Inst *souper::getInstCopy(Inst *I, InstContext &IC, } } if (!Copy) { - if (CloneVars && I->SynthesisConstID == 0) + if (CloneVars && I->SynthesisConstID == 0) { Copy = IC.createVar(I->Width, I->Name, I->Range, I->KnownZeros, I->KnownOnes, I->NonZero, I->NonNegative, I->PowOfTwo, I->Negative, I->NumSignBits, I->DemandedBits, I->SynthesisConstID); + } else { Copy = I; } @@ -1254,6 +1255,7 @@ Inst *souper::getInstCopy(Inst *I, InstContext &IC, } assert(Copy); InstCache[I] = Copy; + Copy->Name = I->Name; return Copy; } diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 493980428..8cbef77bd 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -75,6 +75,10 @@ static llvm::cl::opt SymbolizeConstSynthesis("symbolize-constant-synthesis llvm::cl::desc("Allow concrete constants in the generated code."), llvm::cl::init(false)); +static llvm::cl::opt SymbolizeHackersDelight("symbolize-bit-hacks", + llvm::cl::desc("Include bit hacks in the components."), + llvm::cl::init(true)); + static llvm::cl::opt FixIt("fixit", llvm::cl::desc("Given an invalid optimization, generate a valid one." "(default=false)"), @@ -188,6 +192,26 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement } } + if (true) { + for (auto C : SymCS) { + // // Minus One + // Components.push_back(IC.getInst(Inst::Sub, + // C->Width, {C, IC.getConst(llvm::APInt(C->Width, 1))})); + // // Flip bits + // Components.push_back(IC.getInst(Inst::Xor, + // C->Width, {C, IC.getConst(llvm::APInt(C->Width, -1))})); + + // Custom test + // auto M1 = IC.getConst(llvm::APInt(C->Width, -1)); + // auto Test = Builder(C, IC).Add(M1).Xor(M1).And(M1); + // Components.push_back(Test()); + auto M0 = IC.getConst(llvm::APInt(C->Width, 0)); + auto Test = Builder(M0, IC).Sub(C); + Components.push_back(Test()); + } + + } + for (auto SymC : SymCS) { Components.push_back(SymC); } @@ -204,9 +228,12 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement ConcreteInterpreter CI(VC); for (auto &&Target : RHSConsts) { Candidates.push_back({}); - EnumerativeSynthesis ES; - auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, - Target->Width); + // EnumerativeSynthesis ES; + // auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, + // Target->Width); + + auto Guesses = Components; + // TODO : Memoize expressions by width for (auto &&Guess : Guesses) { @@ -235,10 +262,24 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement // Solve equation to find SymbolicConst // TODO: Proper constant synthesis } else { - auto Val = CI.evaluateInst(Guess); - if (Val.hasValue() && Val.getValue() == Target->Val) { + // Candidates.back().push_back(Guess); + // auto Val = CI.evaluateInst(Guess); + // if (!Val.hasValue()) { Candidates.back().push_back(Guess); - } + // llvm::outs() << "CI Fail\n"; + // Somehow interpreter failed, full verification desirable + // } else { + // if (Val.hasValue() && Val.getValue() == Target->Val) { + // Candidates.back().push_back(Guess); + // } else { + // if (DebugLevel > 4) { + // llvm::outs() << "\nDiscarded by ConcreteInterpreter:\n"; + // llvm::outs() << Val.getValue() << '\t' << Target->Val << '\n'; + // ReplacementContext RC; + // RC.printInst(Guess, llvm::errs(), true); + // } + // } + // } } } } @@ -253,8 +294,10 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement for (auto &&Comb : Combinations) { auto InstCacheCopy = InstCache; + int SymExprCount = 0; for (int i = 0; i < RHSConsts.size(); ++i) { InstCacheCopy[RHSConsts[i]] = Candidates[i][Comb[i]]; + Candidates[i][Comb[i]]->Name = std::string("constexpr_") + std::to_string(SymExprCount++); } auto LHS = Replace(Input.Mapping.LHS, IC, InstCacheCopy); @@ -276,25 +319,27 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement // TODO Make preconditions consistent if (SymbolizeSimpleDF) { - if (!IsValid) { - Components[0]->PowOfTwo = true; - CheckAndSave(); - Components[0]->PowOfTwo = false; - } - if (!IsValid) { - Components[0]->NonZero = true; - CheckAndSave(); - Components[0]->NonZero = false; - } - if (!IsValid) { - Components[0]->NonNegative = true; - CheckAndSave(); - Components[0]->NonNegative = false; - } - if (!IsValid) { - Components[0]->Negative = true; - CheckAndSave(); - Components[0]->Negative = false; + for (auto &&C : SymCS) { + if (!IsValid) { + C->PowOfTwo = true; + CheckAndSave(); + C->PowOfTwo = false; + } + // if (!IsValid) { + // C->NonZero = true; + // CheckAndSave(); + // C->NonZero = false; + // } + // if (!IsValid) { + // C->NonNegative = true; + // CheckAndSave(); + // C->NonNegative = false; + // } + // if (!IsValid) { + // C->Negative = true; + // CheckAndSave(); + // C->Negative = false; + // } } } // TODO Is there a better way of doing this? From c41874048c5f05d25b279555d6532860117e9fae Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 21 Apr 2022 18:29:47 -0600 Subject: [PATCH 063/165] foo --- tools/generalize.cpp | 154 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 130 insertions(+), 24 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 8cbef77bd..468d5fb61 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -103,6 +103,10 @@ static cl::opt NumResults("generalization-num-results", cl::desc("Number of Generalization Results"), cl::init(5)); +static cl::opt Everything("everything", + cl::desc("Run everything, output one result."), + cl::init(false)); + void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { bool FoundWP = false; std::vector> KBResults; @@ -154,6 +158,80 @@ std::vector> GetCombinations(std::vector Counts) { return Result; } +void SymbolizeWidthNew(InstContext &IC, Solver *S, ParsedReplacement Input, + CandidateMap &Results) { + std::vector Consts; + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); + + auto Pred = [](Inst *I) {return I->K == Inst::Const;}; + findInsts(Input.Mapping.LHS, Consts, Pred); + findInsts(Input.Mapping.RHS, Consts, Pred); + + for (auto &&C : Consts) { + std::vector Components; + Components.push_back(IC.getInst(Inst::BitWidth, C->Width, {Vars[0]})); + + EnumerativeSynthesis ES; + auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, + C->Width); + + for (auto &&G : Guesses) { + std::map InstCache; + InstCache[C] = G; + int SymExprCount = 0; + + + auto LHS = Replace(Input.Mapping.LHS, IC, InstCache); + auto RHS = Replace(Input.Mapping.RHS, IC, InstCache); + + InstMapping Mapping(LHS, RHS); + auto Copy = Input; + Copy.Mapping = Mapping; + bool IsValid = false; + + auto CheckAndSave = [&] () { + auto Result = Verify(Copy, IC, S); + if (Result.LHS && Result.RHS) { + Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Result)); + } + }; + + CheckAndSave(); + + // TODO Make preconditions consistent + // if (SymbolizeSimpleDF) { + // for (auto &&C : SymCS) { + // if (!IsValid) { + // C->PowOfTwo = true; + // CheckAndSave(); + // C->PowOfTwo = false; + // } + // if (!IsValid) { + // C->NonZero = true; + // CheckAndSave(); + // C->NonZero = false; + // } + // if (!IsValid) { + // C->NonNegative = true; + // CheckAndSave(); + // C->NonNegative = false; + // } + // if (!IsValid) { + // C->Negative = true; + // CheckAndSave(); + // C->Negative = false; + // } + // } + // } + // TODO Is there a better way of doing this? + // TODO Other kinds of preconditions? + + } + + } +} + // TODO separate function for bitwidth // why? @@ -228,11 +306,11 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement ConcreteInterpreter CI(VC); for (auto &&Target : RHSConsts) { Candidates.push_back({}); - // EnumerativeSynthesis ES; - // auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, - // Target->Width); + EnumerativeSynthesis ES; + auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, + Target->Width); - auto Guesses = Components; + // auto Guesses = Components; // TODO : Memoize expressions by width @@ -818,9 +896,9 @@ class Reducer { } if (ConstMap.empty()) { -// if (DebugLevel > 3) { + if (DebugLevel > 3) { llvm::errs() << "Constant Synthesis failed, moving on.\n"; -// } + } Input = Copy; // failcount++; // if (failcount >= Insts.size()) { @@ -917,9 +995,9 @@ class Reducer { } if (ConstMap.empty()) { -// if (DebugLevel > 3) { + if (DebugLevel > 3) { llvm::errs() << "Constant Synthesis failed, moving on.\n"; -// } + } Input = Copy; failcount++; if (failcount >= Insts.size()) { @@ -1223,7 +1301,7 @@ class Reducer { std::unordered_set DNR; }; -void ReduceAndGeneralize(InstContext &IC, +std::vector ReduceAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input) { std::vector> Models; bool Valid; @@ -1232,7 +1310,7 @@ void ReduceAndGeneralize(InstContext &IC, } if (!Valid) { llvm::errs() << "Invalid Input.\n"; - return; + return {}; } Reducer R(IC, S); @@ -1263,23 +1341,29 @@ void ReduceAndGeneralize(InstContext &IC, std::vector SortedResults(DedupedResults.begin(), DedupedResults.end()); std::sort(SortedResults.begin(), SortedResults.end(), [](auto a, auto b){return a.length() < b.length();}); - for (auto &&S : SortedResults) { - if (DebugLevel > 2) { - llvm::outs() << "\n\nResult:\n"; + if (!Everything) { + for (auto &&S : SortedResults) { + if (DebugLevel > 2) { + llvm::outs() << "\n\nResult:\n"; + } + llvm::outs() << S << '\n'; + if (!ReducePrintAll) { + break; + } } - llvm::outs() << S << '\n'; - if (!ReducePrintAll) { - break; + if (DebugLevel > 2) { + llvm::outs() << "Number of Results: " < 2) { - llvm::errs() << "Failed to Generalize.\n"; + if (!Everything) { + Input.print(llvm::outs(), true); + if (DebugLevel > 2) { + llvm::errs() << "Failed to Generalize.\n"; + } } - } - if (DebugLevel > 2) { - llvm::outs() << "Number of Results: " << Results.size() << ".\n"; + return {}; } } @@ -1311,6 +1395,22 @@ int main(int argc, char **argv) { // TODO: Write default action which chooses what to do based on input structure for (auto &&Input: Inputs) { + if (Everything) { + auto Reduced = ReduceAndGeneralize(IC, S.get(), Input); + + ParsedReplacement Rep; + + if (Reduced.empty()) { + Rep = Input; + } else { + auto MB = llvm::MemoryBuffer::getMemBuffer(Reduced[0]); + Rep = ParseReplacements(IC, MB->getMemBufferRef().getBufferIdentifier(), + Data.getBuffer(), ErrStr)[0]; + } + + Rep.print(llvm::outs(), true); + + } if (FixIt) { // TODO: Verify that inputs are valid optimizations Generalize(IC, S.get(), Input); @@ -1322,8 +1422,14 @@ int main(int argc, char **argv) { SymbolizeAndGeneralize(IC, S.get(), Input); } - if (GeneralizeWidth) { - GeneralizeBitWidth(IC, S.get(), Input); + if (SymbolizeWidth) { + CandidateMap Results; + SymbolizeWidthNew(IC, S.get(), Input, Results); + + for (auto Result : Results) { + Result.print(llvm::outs()); + llvm::outs() << "\n"; + } } } From 31d1f79a8d08ee8e48f322d2695f652f8d543d37 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 9 May 2022 15:52:37 -0600 Subject: [PATCH 064/165] Fix faulty clone --- include/souper/Infer/SynthUtils.h | 32 ++++++++--- lib/Infer/AliveDriver.cpp | 88 ++++++++++++++++--------------- tools/generalize.cpp | 35 +++++++----- 3 files changed, 92 insertions(+), 63 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 4856b273b..ca62d3e74 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -95,9 +95,22 @@ InstMapping Clone(InstMapping In, InstContext &IC) { return Out; } +ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { + std::map BlockCache; + std::map ConstMap; + std::map InstCache; + In.Mapping.LHS = getInstCopy(In.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); + In.Mapping.RHS = getInstCopy(In.Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); + for (auto &PC : In.PCs) { + PC.LHS = getInstCopy(PC.LHS, IC, InstCache, BlockCache, &ConstMap, false, false); + PC.RHS = getInstCopy(PC.RHS, IC, InstCache, BlockCache, &ConstMap, false, false); + } + return In; +} + // Also Synthesizes given constants // Returns clone if verified, nullptrs if not -InstMapping Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { +ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { std::set ConstSet; souper::getConstants(Input.Mapping.RHS, ConstSet); if (!ConstSet.empty()) { @@ -113,14 +126,19 @@ InstMapping Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { std::map BlockCache; auto LHSCopy = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ResultConstMap, true); auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, BlockCache, &ResultConstMap, true); - return InstMapping(LHSCopy, RHS); -// Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHSCopy, RHS))); + Input.Mapping = InstMapping(LHSCopy, RHS); + for (auto &PC : Input.PCs) { + PC.LHS = getInstCopy(PC.LHS, IC, InstCache, BlockCache, &ResultConstMap, true); + PC.RHS = getInstCopy(PC.RHS, IC, InstCache, BlockCache, &ResultConstMap, true); + } + return Input; } else { if (DebugLevel > 2) { llvm::errs() << "Constant Synthesis ((no Dataflow Preconditions)) failed. \n"; } } - return InstMapping(nullptr, nullptr); + Input.Mapping = InstMapping(nullptr, nullptr); + return Input; } std::vector> Models; bool IsValid; @@ -129,9 +147,11 @@ InstMapping Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { } if (IsValid) { // Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Clone(Mapping, IC))); - return Clone(Input.Mapping, IC); + Input = Clone(Input, IC); + return Input; } else { - return InstMapping(nullptr, nullptr); + Input.Mapping = InstMapping(nullptr, nullptr); + return Input; } } diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index 48e4e73c8..303142394 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -225,50 +225,52 @@ std::map performCegisFirstQuery(tools::Transform &t, std::map &SouperConsts, smt::expr &TriedExpr) { - IR::State SrcState(t.src, true); - IR::State TgtState(t.tgt, false); - util::sym_exec(SrcState); - util::sym_exec(TgtState); - - auto &&Sv = SrcState.returnVal(); - auto &&Tv = TgtState.returnVal(); - - std::map SynthesisResult; - SynthesisResult.clear(); - - std::set Vars; - std::map SMTConsts; - for (auto &[Var, Val] : TgtState.getValues()) { - auto &Name = Var->getName(); - if (startsWith("%reservedconst", Name)) { - SMTConsts[Name] = Val.first.value; - } - } - - if (SkipAliveSolver) - return SynthesisResult; - - auto R = smt::check_expr((Sv.first.value == Tv.first.value) && (TriedExpr)); - // no more guesses, stop immediately - if (R.isUnsat()) { - if (DebugLevel > 3) - llvm::errs()<<"No more new possible guesses\n"; + llvm::errs() << "Constant synthesis through alive unimplemented."; return {}; - } else if (R.isSat()) { - auto &&Model = R.getModel(); - smt::expr TriedAnte(false); - - for (auto &[name, expr] : SMTConsts) { - TriedAnte |= (expr != smt::expr::mkUInt(Model.getInt(expr), expr.bits())); - } - TriedExpr &= TriedAnte; - - for (auto &[name, expr] : SMTConsts) { - auto *I = SouperConsts[name]; - SynthesisResult[I] = llvm::APInt(I->Width, Model.getInt(expr)); - } - } - return SynthesisResult; +// IR::State SrcState(t.src, true); +// IR::State TgtState(t.tgt, false); +// util::sym_exec(SrcState); +// util::sym_exec(TgtState); +// +// auto &&Sv = SrcState.returnVal(); +// auto &&Tv = TgtState.returnVal(); + +// std::map SynthesisResult; +// SynthesisResult.clear(); +// +// std::set Vars; +// std::map SMTConsts; +// for (auto &[Var, Val] : TgtState.getValues()) { +// auto &Name = Var->getName(); +// if (startsWith("%reservedconst", Name)) { +// SMTConsts[Name] = Val.first.value; +// } +// } +// +// if (SkipAliveSolver) +// return SynthesisResult; +// +// auto R = smt::check_expr((Sv.first.value == Tv.first.value) && (TriedExpr)); +// // no more guesses, stop immediately +// if (R.isUnsat()) { +// if (DebugLevel > 3) +// llvm::errs()<<"No more new possible guesses\n"; +// return {}; +// } else if (R.isSat()) { +// auto &&Model = R.getModel(); +// smt::expr TriedAnte(false); +// +// for (auto &[name, expr] : SMTConsts) { +// TriedAnte |= (expr != smt::expr::mkUInt(Model.getInt(expr), expr.bits())); +// } +// TriedExpr &= TriedAnte; +// +// for (auto &[name, expr] : SMTConsts) { +// auto *I = SouperConsts[name]; +// SynthesisResult[I] = llvm::APInt(I->Width, Model.getInt(expr)); +// } +// } +// return SynthesisResult; } std::map diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 468d5fb61..bab52c06e 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -192,8 +192,10 @@ void SymbolizeWidthNew(InstContext &IC, Solver *S, ParsedReplacement Input, auto CheckAndSave = [&] () { auto Result = Verify(Copy, IC, S); - if (Result.LHS && Result.RHS) { - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Result)); + if (Result.Mapping.LHS && Result.Mapping.RHS) { + CandidateReplacement Rep(nullptr, Result.Mapping); + Rep.PCs = Result.PCs; + Results.push_back(Rep); } }; @@ -273,19 +275,19 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement if (true) { for (auto C : SymCS) { // // Minus One - // Components.push_back(IC.getInst(Inst::Sub, - // C->Width, {C, IC.getConst(llvm::APInt(C->Width, 1))})); - // // Flip bits - // Components.push_back(IC.getInst(Inst::Xor, - // C->Width, {C, IC.getConst(llvm::APInt(C->Width, -1))})); + Components.push_back(IC.getInst(Inst::Sub, + C->Width, {C, IC.getConst(llvm::APInt(C->Width, 1))})); + // Flip bits + Components.push_back(IC.getInst(Inst::Xor, + C->Width, {C, IC.getConst(llvm::APInt(C->Width, -1))})); // Custom test // auto M1 = IC.getConst(llvm::APInt(C->Width, -1)); // auto Test = Builder(C, IC).Add(M1).Xor(M1).And(M1); // Components.push_back(Test()); - auto M0 = IC.getConst(llvm::APInt(C->Width, 0)); - auto Test = Builder(M0, IC).Sub(C); - Components.push_back(Test()); +// auto M0 = IC.getConst(llvm::APInt(C->Width, 0)); +// auto Test = Builder(M0, IC).Sub(C); +// Components.push_back(Test()); } } @@ -370,12 +372,14 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement // Generate all combination of candidates std::vector> Combinations = GetCombinations(Counts); + int SymExprCount = 0; for (auto &&Comb : Combinations) { auto InstCacheCopy = InstCache; - int SymExprCount = 0; for (int i = 0; i < RHSConsts.size(); ++i) { InstCacheCopy[RHSConsts[i]] = Candidates[i][Comb[i]]; - Candidates[i][Comb[i]]->Name = std::string("constexpr_") + std::to_string(SymExprCount++); + if (Candidates[i][Comb[i]]->K != Inst::Var) { + Candidates[i][Comb[i]]->Name = std::string("constexpr_") + std::to_string(SymExprCount++); + } } auto LHS = Replace(Input.Mapping.LHS, IC, InstCacheCopy); @@ -388,8 +392,11 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement auto CheckAndSave = [&] () { auto Result = Verify(Copy, IC, S); - if (Result.LHS && Result.RHS) { - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Result)); + + if (Result.Mapping.LHS && Result.Mapping.RHS) { + CandidateReplacement Rep(nullptr, Result.Mapping); + Rep.PCs = Result.PCs; + Results.push_back(Rep); } }; From 8867113de20e0068b2bdfe3b202cfe88cbc2d522 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 7 Jun 2022 23:16:51 -0600 Subject: [PATCH 065/165] foo --- include/souper/Infer/SynthUtils.h | 18 ++++++++- include/souper/Inst/Inst.h | 2 + lib/Extractor/ExprBuilder.cpp | 15 ++++++++ lib/Inst/Inst.cpp | 10 +++++ tools/generalize.cpp | 62 ++++++++++++++++++++++++++----- 5 files changed, 95 insertions(+), 12 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index ca62d3e74..edb0e914e 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -99,18 +99,33 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { std::map BlockCache; std::map ConstMap; std::map InstCache; + std::vector RHSVars; + findVars(In.Mapping.RHS, RHSVars); In.Mapping.LHS = getInstCopy(In.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); In.Mapping.RHS = getInstCopy(In.Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); for (auto &PC : In.PCs) { PC.LHS = getInstCopy(PC.LHS, IC, InstCache, BlockCache, &ConstMap, false, false); PC.RHS = getInstCopy(PC.RHS, IC, InstCache, BlockCache, &ConstMap, false, false); } + + for (auto &V : RHSVars) { + if (V->SymOneOf) { + InstCache[V->SymOneOf]->SymKnownOnes = InstCache[V]; + } + if (V->SymZeroOf) { + InstCache[V->SymZeroOf]->SymKnownZeros = InstCache[V]; + } + } + return In; } + + // Also Synthesizes given constants // Returns clone if verified, nullptrs if not ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { + Input = Clone(Input, IC); std::set ConstSet; souper::getConstants(Input.Mapping.RHS, ConstSet); if (!ConstSet.empty()) { @@ -146,12 +161,11 @@ ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { llvm::errs() << EC.message() << '\n'; } if (IsValid) { -// Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Clone(Mapping, IC))); - Input = Clone(Input, IC); return Input; } else { Input.Mapping = InstMapping(nullptr, nullptr); return Input; + // TODO: Better vailure indication? } } diff --git a/include/souper/Inst/Inst.h b/include/souper/Inst/Inst.h index e1ec8c3ee..ee1cae397 100644 --- a/include/souper/Inst/Inst.h +++ b/include/souper/Inst/Inst.h @@ -174,6 +174,8 @@ struct Inst : llvm::FoldingSetNode { static int getCost(Kind K); llvm::APInt KnownZeros; llvm::APInt KnownOnes; + Inst *SymKnownZeros = nullptr, *SymKnownOnes = nullptr; + Inst *SymZeroOf = nullptr, *SymOneOf = nullptr; bool NonZero; bool NonNegative; bool PowOfTwo; diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index facf92826..2287a226a 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -344,6 +344,21 @@ Inst *ExprBuilder::getDataflowConditions(Inst *I) { Inst *OneBits = LIC->getInst(Inst::Eq, 1, {VarAndOnes, Ones}); Result = LIC->getInst(Inst::And, 1, {Result, OneBits}); } + + if (I->SymKnownZeros) { + Inst *AllOnes = LIC->getConst(llvm::APInt::getAllOnesValue(Width)); + Inst *NotZeros = LIC->getInst(Inst::Xor, Width, + {I->SymKnownZeros, AllOnes}); + 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}); + } + if (I->SymKnownOnes) { + Inst *VarAndOnes = LIC->getInst(Inst::And, Width, {I, I->SymKnownOnes}); + Inst *OneBits = LIC->getInst(Inst::Eq, 1, {VarAndOnes, I->SymKnownOnes}); + Result = LIC->getInst(Inst::And, 1, {Result, OneBits}); + } + if (I->NonZero) { Inst *NonZeroBits = LIC->getInst(Inst::Ne, 1, {I, Zero}); Result = LIC->getInst(Inst::And, 1, {Result, NonZeroBits}); diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index a00fb4a5f..23550f502 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -197,6 +197,12 @@ std::string ReplacementContext::printInstImpl(Inst *I, llvm::raw_ostream &Out, if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) Out << " (knownBits=" << Inst::getKnownBitsString(I->KnownZeros, I->KnownOnes) << ")"; + if (I->SymKnownZeros) { + Out << "(knownZeros=%" << I->SymKnownZeros->Name << ")"; + } + if (I->SymKnownOnes) { + Out << "(knownOnes=%" << I->SymKnownOnes->Name << ")"; + } if (I->NonNegative) Out << " (nonNegative)"; if (I->Negative) @@ -1256,6 +1262,10 @@ Inst *souper::getInstCopy(Inst *I, InstContext &IC, assert(Copy); InstCache[I] = Copy; Copy->Name = I->Name; + Copy->SymKnownOnes = I->SymKnownOnes; + Copy->SymKnownZeros = I->SymKnownZeros; + Copy->SymOneOf = I->SymOneOf; + Copy->SymZeroOf = I->SymZeroOf; return Copy; } diff --git a/tools/generalize.cpp b/tools/generalize.cpp index bab52c06e..ab78afc53 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1,3 +1,5 @@ +#define _LIBCPP_DISABLE_DEPRECATION_WARNINGS + #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/KnownBits.h" @@ -107,6 +109,10 @@ static cl::opt Everything("everything", cl::desc("Run everything, output one result."), cl::init(false)); +static cl::opt SymbolicDF("symbolic-df", + cl::desc("Generalize with symbolic dataflow facts."), + cl::init(false)); + void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { bool FoundWP = false; std::vector> KBResults; @@ -234,16 +240,37 @@ void SymbolizeWidthNew(InstContext &IC, Solver *S, ParsedReplacement Input, } } -// TODO separate function for bitwidth -// why? +void ReplaceConstsSimple(InstContext &IC, Solver *S, + ParsedReplacement Input, + std::vector LHSConsts, + std::vector RHSConsts, + CandidateMap &Results) { + // FIXME Start from here + // Try replacing each constant with a width independent + // expr or a kb expr +} + +// FIXME Other interesting things to try +// Symbolic KB in preconditions +// Symbolic KB with extra constraints. +// Simple relational conditions for symcs +// Relations between symcs // TODO Document options void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement Input, std::vector LHSConsts, std::vector RHSConsts, CandidateMap &Results) { + + if (RHSConsts.empty()) { + // FIXME: Support generalizing LHS Consts too. + return; + } std::vector SymCS; + std::vector Vars; + std::vector SymDFVars; + findVars(Input.Mapping.LHS, Vars); std::map InstCache; ValueCache VC; @@ -271,8 +298,23 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement Components.push_back(C); } } - + if (true) { + for (size_t i = 0; i < Vars.size(); ++i) { + SymDFVars.push_back(IC.createVar(Vars[i]->Width, "symk_one_" + std::to_string(i))); + SymDFVars.back()->SymOneOf = Vars[i]; +// Vars[i]->SymKnownOnes = SymDFVars.back(); + Components.push_back(SymDFVars.back()); + + SymDFVars.push_back(IC.createVar(Vars[i]->Width, "symk_zero_" + std::to_string(i))); + SymDFVars.back()->SymZeroOf = Vars[i]; +// Vars[i]->SymKnownZeros = SymDFVars.back(); + Components.push_back(SymDFVars.back()); + } + } + + + if (SymbolizeConstant) { for (auto C : SymCS) { // // Minus One Components.push_back(IC.getInst(Inst::Sub, @@ -323,12 +365,12 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement if (SymbolizeConstSynthesis) { auto SMTLIBSolver = GetUnderlyingSolver(); SynthesisContext SC{IC, SMTLIBSolver.get(), Target, nullptr, {}, {}, false, 10}; - PruningManager Pruner(SC, SymCS, DebugLevel); - Pruner.init(); - if (!Pruner.isInfeasible(Guess, DebugLevel)) { +// PruningManager Pruner(SC, SymCS, DebugLevel); +// Pruner.init(); +// if (!Pruner.isInfeasible(Guess, DebugLevel)) { Candidates.back().push_back(Guess); // llvm::errs() << "NOT PRUNED\n"; - } +// } // else { // ReplacementContext RC; // RC.printInst(Guess, llvm::errs(), true); @@ -372,8 +414,8 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement // Generate all combination of candidates std::vector> Combinations = GetCombinations(Counts); - int SymExprCount = 0; for (auto &&Comb : Combinations) { + int SymExprCount = 0; auto InstCacheCopy = InstCache; for (int i = 0; i < RHSConsts.size(); ++i) { InstCacheCopy[RHSConsts[i]] = Candidates[i][Comb[i]]; @@ -716,9 +758,9 @@ void SymbolizeAndGeneralize(InstContext &IC, // All at once SymbolizeAndGeneralizeRewrite(IC, S, Input, LHSConsts, RHSConsts, Results); - llvm::outs() << "Input:\n"; + llvm::outs() << ";Input:\n"; Input.print(llvm::outs(), true); - llvm::outs() << "\nResults:\n"; + llvm::outs() << "\n;Results:\n"; // TODO: Move sorting here std::set ResultStrs; From 6235802cae41c2ae5fd9b3f204e2da5c36257d3c Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 8 Jun 2022 19:57:26 -0600 Subject: [PATCH 066/165] foo --- tools/matcher-gen.cpp | 166 +++++++++++++++++--------- tools/pass-generator/src/template.cpp | 62 ++++++---- 2 files changed, 151 insertions(+), 77 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 27fc8a6ee..6499c6eb1 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -31,8 +31,13 @@ static llvm::cl::opt IgnorePCs("ignore-pcs", "(default=false)"), llvm::cl::init(false)); +static llvm::cl::opt IgnoreDF("ignore-df", + llvm::cl::desc("Ignore inputs with dataflow constraints." + "(default=false)"), + llvm::cl::init(false)); + static const std::map MatchOps = { - {Inst::Add, "m_c_Add("}, {Inst::Sub, "m_c_Sub("}, + {Inst::Add, "m_c_Add("}, {Inst::Sub, "m_Sub("}, {Inst::Mul, "m_c_Mul("}, {Inst::Shl, "m_Shl("}, {Inst::LShr, "m_LShr("}, @@ -71,6 +76,9 @@ static const std::map CreateOps = { {Inst::URem, "CreateURem("}, {Inst::Or, "CreateOr("}, {Inst::And, "CreateAnd("}, {Inst::Xor, "CreateXor("}, + // FakeOps + {Inst::LogB, "CreateLogB("}, + {Inst::Eq, "CreateCmp(ICmpInst::ICMP_EQ, "}, {Inst::Ne, "CreateCmp(ICmpInst::ICMP_NE, "}, {Inst::Ule, "CreateCmp(ICmpInst::ICMP_ULE, "}, @@ -97,8 +105,53 @@ static const std::map PredNames = { {Inst::Slt, "ICmpInst::ICMP_SLT"}, }; +struct Constraint { + virtual std::string print() = 0; +}; + +struct VarEq : public Constraint { + VarEq(std::string LHS_, std::string RHS_) : LHS(LHS_), RHS(RHS_) {} + std::string LHS; + std::string RHS; + std::string print() override { + return LHS + " == " + RHS; + } +}; + +struct PredEq : public Constraint { + PredEq(std::string P_, std::string K_) : P(P_), K(K_) {} + std::string P; + std::string K; + std::string print() override { + return P + " == " + K; + } +}; + +struct WidthEq : public Constraint { + WidthEq(std::string Name_, size_t W_) : Name(Name_) , W(W_){} + std::string Name; + size_t W; + std::string print() override { + return "util::check_width(" + Name + ',' + std::to_string(W) + ")"; + } +}; + +// Enforce that `Name` is a constant and a power of 2 +struct CPow2 : public Constraint { + CPow2(std::string Name_) : Name(Name_) {} + std::string print() override { + return "util::cpow2(" + Name + ")"; + } + std::string Name; +}; + +//struct VarKB : public Constraint { + +//}; + struct SymbolTable : public std::map> { - std::vector> Eqs; + std::vector Constraints; + std::map Preds; std::vector Vars; @@ -108,7 +161,7 @@ struct SymbolTable : public std::map> { } auto Name = "P" + std::to_string(Preds.size()); Preds[I] = Name; - Eqs.push_back(std::make_pair(Name, PredNames.at(I->K))); + Constraints.push_back(new PredEq(Name, PredNames.at(I->K))); } template void PrintPreds(Stream &Out) { @@ -131,76 +184,53 @@ struct SymbolTable : public std::map> { for (auto &&S : *this) { if (S.second.size() > 1) { for (int i = 1; i < S.second.size(); ++i) { - Eqs.push_back(std::make_pair(S.second[0], S.second[i])); + Constraints.push_back(new VarEq(S.second[0], S.second[i])); } } } } - template - void PrintEqPre(Stream &Out) { - if (Eqs.empty()) { - return; - } - Out << "if ("; - bool first = true; - for (auto &&P : Eqs) { - if (first) { - first = false; - } else { - Out << " && "; + + void GenVarPropConstraints(Inst *LHS) { + std::vector Vars; + findVars(LHS, Vars); + + for (auto V : Vars) { + auto Name = this->at(V)[0]; + Constraints.push_back(new WidthEq(Name, V->Width)); + if (V->Name.starts_with("symconst_")) { + if (V->PowOfTwo) { + Constraints.push_back(new CPow2(Name)); + } } - Out << "(!util::nc(" << P.first << ',' << P.second << " ) " - << "|| " << P.first << " == " << P.second << ")"; - } - Out << ") {\n"; - } - template - void PrintEqPost(Stream &Out) { - if (Eqs.empty()) { - return; } - Out << "}\n"; } template - void PrintWidthPre(Inst *LHS, Stream &Out) { - findVars(LHS, Vars); - if (Vars.empty()) { + void PrintConstraintsPre(Stream &Out) { + if (Constraints.empty()) { return; } - Out << "if (util::check_width({"; + Out << "if ("; bool first = true; - for (auto V : Vars) { + for (auto &&C : Constraints) { if (first) { first = false; } else { - Out << ", "; - } - Out << this->at(V)[0]; - } - Out << "}, {"; - first = true; - for (auto V : Vars) { - if (first) { - first = false; - } else { - Out << ", "; + Out << " && "; } - Out << V->Width; + Out << C->print(); } - Out << "})) {\n"; + Out << ") {\n"; } template - void PrintWidthPost(Stream &Out) { - if (Vars.empty()) { + void PrintConstraintsPost(Stream &Out) { + if (Constraints.empty()) { return; } - Out << "\n}\n"; + Out << "}\n"; } }; - -//TODO: Enforce bitwidth template bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { auto It = MatchOps.find(I->K); @@ -249,7 +279,7 @@ bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms) { } auto Op = It->second; - Out << Op; + Out << "B->" << Op; bool first = true; for (auto Child : I->Ops) { if (first) { @@ -388,7 +418,7 @@ bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { auto Name = "C" + std::to_string(varnum++); Out << "auto " << Name << " = C(" << C->Val.getBitWidth() <<", " - << C->Val << ");\n"; + << C->Val << ", B);\n"; Syms[C].push_back(Name); } Syms.PrintPreds(Out); @@ -413,8 +443,8 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { Out << ")) {\n"; Syms.GenVarEqConstraints(); - Syms.PrintEqPre(Out); - Syms.PrintWidthPre(Input.Mapping.LHS, Out); + Syms.GenVarPropConstraints(Input.Mapping.LHS); + Syms.PrintConstraintsPre(Out); Out << " St.hit(" << OptID << ");\n"; if (Syms.find(Input.Mapping.RHS) != Syms.end()) { Out << " return " << Syms[Input.Mapping.RHS][0] << ";"; @@ -424,7 +454,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { << Input.Mapping.RHS->Val << ");\n"; Out << " return ConstantInt::get(TheContext, Result);"; } else { - Out << " return B->"; + Out << " return "; if (!GenRHSCreator(Input.Mapping.RHS, Out, Syms)) { return false; } @@ -432,8 +462,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { } Out << "\n}\n}"; - Syms.PrintWidthPost(Out); - Syms.PrintEqPost(Out); + Syms.PrintConstraintsPost(Out); return true; } @@ -470,6 +499,31 @@ int main(int argc, char **argv) { if (IgnorePCs && !Input.PCs.empty()) { continue; } + if (IgnoreDF) { + if (Input.Mapping.LHS->DemandedBits.getBitWidth() + == Input.Mapping.LHS->Width && !Input.Mapping.LHS->DemandedBits.isAllOnesValue()) { + continue; + } + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); + findVars(Input.Mapping.RHS, Vars); + bool found = false; + for (auto V : Vars) { + if (V->KnownOnes.getBitWidth() == V->Width && V->KnownOnes != 0) { + found = true; + break; + } + + if (V->KnownZeros.getBitWidth() == V->Width && V->KnownZeros != 0) { + found = true; + break; + } +// if (!V->Range.isFullSet() || !V->Range.isEmptySet()) { +// continue; +// } + } + if (found) continue; + } std::string Str; llvm::raw_string_ostream Out(Str); diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index b214367d9..a83011a2e 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -9,6 +9,7 @@ #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" +#include "llvm/IR/NoFolder.h" #include "llvm/InitializePasses.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" @@ -18,6 +19,22 @@ using namespace llvm; using namespace llvm::PatternMatch; namespace { + +class IRBuilder : public llvm::IRBuilder { +public: + IRBuilder(llvm::LLVMContext &C) : llvm::IRBuilder(C) {} + + // Implement Souper instructions which do not have an LLVM counterpart. + llvm::Value *CreateLogB(llvm::Value *V) { + if (ConstantInt *Con = llvm::dyn_cast(V)) { + auto Result = Con->getValue().logBase2(); + return ConstantInt::get(Con->getType(), Result); + } else { + llvm_unreachable("Panic, has to be guarded in advance!"); + } + } +}; + namespace util { Value *node(Instruction *I, const std::vector &Path) { Value *Current = I; @@ -34,13 +51,18 @@ namespace util { } return Current; } - bool check_width(std::vector V, std::vector W) { - for (size_t i = 0; i < V.size(); ++i) { - if (V[i]->getType()->getScalarSizeInBits() != W[i]) { - return false; + + bool check_width(llvm::Value *V, size_t W) { + return V->getType()->getScalarSizeInBits() == W; + } + + bool cpow2(llvm::Value *V) { + if (ConstantInt *Con = llvm::dyn_cast(V)) { + if (Con->getValue().isPowerOf2()) { + return true; } } - return true; + return false; } struct Stats { @@ -67,7 +89,7 @@ namespace util { } struct SouperCombine : public FunctionPass { static char ID; - SouperCombine() : FunctionPass(ID), Builder(TheContext) { + SouperCombine() : FunctionPass(ID) { } bool runOnFunction(Function &F) override { @@ -77,50 +99,48 @@ struct SouperCombine : public FunctionPass { W.push(&I); } } - return run(); + IRBuilder Builder(F.getContext()); + llvm::errs() << "Before:\n" << F; + auto r = run(Builder); + llvm::errs() << "After:\n" << F; + return r; } - bool processInst(Instruction *I) { + bool processInst(Instruction *I, IRBuilder &Builder) { Builder.SetInsertPoint(I); if (auto V = getReplacement(I, &Builder)) { - replace(I, V); + replace(I, V, Builder); return true; } return false; } - void replace(Instruction *I, Value *V) { + void replace(Instruction *I, Value *V, IRBuilder &Builder) { W.pushUsersToWorkList(*I); I->replaceAllUsesWith(V); } - bool run() { + bool run(IRBuilder &Builder) { bool Changed = false; while (auto I = W.removeOne()) { - Changed = processInst(I) || Changed; + Changed = processInst(I, Builder) || Changed; } St.print(); return Changed; } - - Value *C(size_t Width, size_t Value) { - return ConstantInt::get(TheContext, APInt(Width, Value)); - } - Value *getReplacement(llvm::Instruction *I, llvm::IRBuilder<> *B) { + Value *getReplacement(llvm::Instruction *I, IRBuilder *B) { // Autogenerated transforms #include "gen.cpp.inc" return nullptr; } - llvm::Type *T(size_t W) { - return llvm::Type::getIntNTy(TheContext, W); + Value *C(size_t Width, size_t Value, IRBuilder *B) { + return B->getIntN(Width, Value); } InstCombineWorklist W; util::Stats St; - LLVMContext TheContext; - llvm::IRBuilder<> Builder; }; } From ef657404602ffab9265fdddc5c30a27d4a4ed36e Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 23 Jun 2022 01:37:56 -0600 Subject: [PATCH 067/165] foo --- tools/generalize.cpp | 3 ++- tools/matcher-gen.cpp | 25 +++++++++++------- tools/pass-generator/src/template.cpp | 38 ++++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index ab78afc53..4e83f4b23 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1370,11 +1370,12 @@ std::vector ReduceAndGeneralize(InstContext &IC, Input = R.WeakenKB(Input); Input = R.WeakenCR(Input); Input = R.WeakenDB(Input); - if (ReduceKBIFY) { Input = R.ReduceGreedyKBIFY(Input); } + Input = R.ReducePCs(Input); + // Results.push_back(Input); R.ReduceRec(Input, Results); diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 6499c6eb1..286c2d1a5 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -29,7 +29,7 @@ InputFilename(cl::Positional, cl::desc(""), static llvm::cl::opt IgnorePCs("ignore-pcs", llvm::cl::desc("Ignore inputs which have souper path conditions." "(default=false)"), - llvm::cl::init(false)); + llvm::cl::init(true)); static llvm::cl::opt IgnoreDF("ignore-df", llvm::cl::desc("Ignore inputs with dataflow constraints." @@ -44,10 +44,11 @@ static const std::map MatchOps = { {Inst::AShr, "m_AShr("}, {Inst::AddNSW, "m_NSWAdd("}, {Inst::SubNSW, "m_NSWSub("}, // add _c_ too? - {Inst::MulNSW, "m_NSWMul("}, {Inst::ShlNSW, "m_NSWShl("}, // Also, figure out what to do about NW. - + {Inst::MulNSW, "m_NSWMul("}, {Inst::ShlNSW, "m_NSWShl("}, {Inst::AddNUW, "m_NUWAdd("}, {Inst::SubNUW, "m_NUWSub("}, {Inst::MulNUW, "m_NUWMul("}, {Inst::ShlNUW, "m_NUWShl("}, + {Inst::AddNW, "m_NWAdd("}, {Inst::SubNW, "m_NWSub("}, + {Inst::MulNW, "m_NWMul("}, {Inst::ShlNW, "m_NWShl("}, {Inst::SDiv, "m_SDiv("}, {Inst::UDiv, "m_UDiv("}, {Inst::SRem, "m_SRem("}, {Inst::URem, "m_URem("}, @@ -86,13 +87,16 @@ static const std::map CreateOps = { {Inst::Sle, "CreateCmp(ICmpInst::ICMP_SLE, "}, {Inst::Slt, "CreateCmp(ICmpInst::ICMP_SLT, "}, -// {Inst::Trunc, "CreateTrunc("}, -// {Inst::SExt, "CreateSExt("}, -// {Inst::ZExt, "CreateZExt("}, - // TODO have to create dest type + {Inst::Trunc, "CreateTrunc("}, + {Inst::SExt, "CreateSExt("}, + {Inst::ZExt, "CreateZExt("}, {Inst::Select, "CreateSelect("}, + {Inst::FShl, "CreateFShl("}, + {Inst::FShr, "CreateFShr("}, + {Inst::BSwap, "CreateBSwap("}, + {Inst::Const, "dummy"}, }; @@ -157,7 +161,10 @@ struct SymbolTable : public std::map> { void RegisterPred(Inst *I) { if (PredNames.find(I->K) == PredNames.end()) { - return; + return; // not a predicate + } + if (Preds.find(I) != Preds.end()) { + return; // already registered } auto Name = "P" + std::to_string(Preds.size()); Preds[I] = Name; @@ -297,7 +304,7 @@ bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms) { } if (I->K == Inst::Trunc || I->K == Inst::SExt || I->K == Inst::ZExt) { - Out << ", T(" << I->Width << ")"; + Out << ", T(" << I->Width << ", B)"; } Out << ")"; diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index a83011a2e..88349b84c 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -20,11 +20,12 @@ using namespace llvm::PatternMatch; namespace { +// Custom Creators + class IRBuilder : public llvm::IRBuilder { public: IRBuilder(llvm::LLVMContext &C) : llvm::IRBuilder(C) {} - // Implement Souper instructions which do not have an LLVM counterpart. llvm::Value *CreateLogB(llvm::Value *V) { if (ConstantInt *Con = llvm::dyn_cast(V)) { auto Result = Con->getValue().logBase2(); @@ -33,8 +34,39 @@ class IRBuilder : public llvm::IRBuilder { llvm_unreachable("Panic, has to be guarded in advance!"); } } + + // TODO Verify that these work, the mangling argument is weird + llvm::Value *CreateFShl(llvm::Value *A, llvm::Value *B, llvm::Value *C) { + return CreateIntrinsic(Intrinsic::fshl, {A->getType()}, {A, B, C}); + } + llvm::Value *CreateFShr(llvm::Value *A, llvm::Value *B, llvm::Value *C) { + return CreateIntrinsic(Intrinsic::fshr, {A->getType()}, {A, B, C}); + } + llvm::Value *CreateBSwap(llvm::Value *A) { + return CreateIntrinsic(Intrinsic::bswap, {A->getType()}, {A}); + } }; + +// Custom Matchers + +static constexpr auto NWFlag = OverflowingBinaryOperator::NoSignedWrap + | OverflowingBinaryOperator::NoUnsignedWrap; +#define NWT(OP) OverflowingBinaryOp_match +#define NWM(OP) \ +template NWT(OP) \ +m_NW##OP(const LHS &L, const RHS &R) { \ + return NWT(OP)(L, R); \ +} + +NWM(Add) +NWM(Sub) +NWM(Mul) +NWM(Shl) + +#undef NWM +#undef NWT + namespace util { Value *node(Instruction *I, const std::vector &Path) { Value *Current = I; @@ -139,6 +171,10 @@ struct SouperCombine : public FunctionPass { return B->getIntN(Width, Value); } + Type *T(size_t W, IRBuilder *B) { + return B->getIntNTy(W); + } + InstCombineWorklist W; util::Stats St; }; From a9e4d2c51b84f7609ea2e6fb77a11540970790e3 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 23 Jun 2022 13:15:25 -0600 Subject: [PATCH 068/165] foo --- tools/matcher-gen.cpp | 46 ++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 286c2d1a5..6681af1a5 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -158,6 +158,7 @@ struct SymbolTable : public std::map> { std::map Preds; std::vector Vars; + std::set Consts, ConstRefs; void RegisterPred(Inst *I) { if (PredNames.find(I->K) == PredNames.end()) { @@ -236,6 +237,21 @@ struct SymbolTable : public std::map> { } Out << "}\n"; } + + template + void PrintConstDecls(Stream &Out) { + size_t varnum = 0; + for (auto C : ConstRefs) { + if (Consts.find(C) != Consts.end()) { + continue; + } + auto Name = "C" + std::to_string(varnum++); + Out << "auto " << Name << " = C(" + << C->Val.getBitWidth() <<", " + << C->Val << ", B);\n"; + (*this)[C].push_back(Name); + } + } }; template @@ -364,7 +380,7 @@ bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { Stack.pop_back(); Visited.insert(I); if (I->K == Inst::Const) { - Consts.insert(I); +// Consts.insert(I); ConstRefs.insert(I); } if (Paths.find(I) != Paths.end()) { @@ -417,18 +433,10 @@ bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { } Syms[Root].push_back("I"); - varnum = 0; - for (auto C : Consts) { - if (ConstRefs.find(C) == ConstRefs.end()) { - continue; - } - auto Name = "C" + std::to_string(varnum++); - Out << "auto " << Name << " = C(" - << C->Val.getBitWidth() <<", " - << C->Val << ", B);\n"; - Syms[C].push_back(Name); - } Syms.PrintPreds(Out); + + Syms.Consts = Consts; + Syms.ConstRefs = ConstRefs; return true; } @@ -452,7 +460,21 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { Syms.GenVarEqConstraints(); Syms.GenVarPropConstraints(Input.Mapping.LHS); Syms.PrintConstraintsPre(Out); + Syms.PrintConstDecls(Out); Out << " St.hit(" << OptID << ");\n"; + +// size_t varnum = 0; +// for (auto C : SymsCopy.ConstRefs) { +// if (SymsCopy.Consts.find(C) != SymsCopy.Consts.end()) { +// continue; +// } +// auto Name = "C" + std::to_string(varnum++); +// Out << "auto " << Name << " = C(" +// << C->Val.getBitWidth() <<", " +// << C->Val << ", B);\n"; +// Syms[C].push_back(Name); +// } + if (Syms.find(Input.Mapping.RHS) != Syms.end()) { Out << " return " << Syms[Input.Mapping.RHS][0] << ";"; } else if (Input.Mapping.RHS->K == Inst::Const) { From 87ee1135b0d7b7054c70bf72afef5a9c89cea9dc Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 28 Jun 2022 16:56:07 -0600 Subject: [PATCH 069/165] foo --- tools/generalize.cpp | 1 + tools/matcher-gen.cpp | 5 ++- tools/pass-generator/src/template.cpp | 56 +++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 4e83f4b23..63d5b84c7 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -899,6 +899,7 @@ class Reducer { } auto Copy = Input; Eliminate(Input, I); + if (!Verify(Input)) { Input = Copy; failcount++; diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 6681af1a5..622d32cc1 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -68,6 +68,7 @@ static const std::map MatchOps = { {Inst::ZExt, "m_ZExt("}, {Inst::Trunc, "m_Trunc("}, {Inst::Select, "m_Select("}, + {Inst::Phi, "m_Phi("}, }; static const std::map CreateOps = { @@ -191,7 +192,7 @@ struct SymbolTable : public std::map> { void GenVarEqConstraints() { for (auto &&S : *this) { if (S.second.size() > 1) { - for (int i = 1; i < S.second.size(); ++i) { + for (size_t i = 1; i < S.second.size(); ++i) { Constraints.push_back(new VarEq(S.second[0], S.second[i])); } } @@ -246,7 +247,7 @@ struct SymbolTable : public std::map> { continue; } auto Name = "C" + std::to_string(varnum++); - Out << "auto " << Name << " = C(" + Out << " auto " << Name << " = C(" << C->Val.getBitWidth() <<", " << C->Val << ", B);\n"; (*this)[C].push_back(Name); diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 88349b84c..eaaf4a10e 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -12,6 +12,7 @@ #include "llvm/IR/NoFolder.h" #include "llvm/InitializePasses.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/InstCombine/InstCombineWorklist.h" @@ -67,6 +68,41 @@ NWM(Shl) #undef NWM #undef NWT +template +struct phi_match { + phi_match(Args... args) : Matchers{args...} {}; + std::tuple Matchers; + + bool check(const Value *V) { + if (auto Phi = dyn_cast(V)) { + // Every Phi Argument has to match with at least one matcher + for (size_t i =0; i < Phi->getNumOperands(); ++i) { + bool Matched = false; + std::apply([&](auto &&... args){ + ((Matched |= args.match(Phi->getOperand(i))), ...); + }, Matchers); + + if (!Matched) { + return false; + } + } + return true; + } + return false; + } + + template bool match(I *V) { + return check(V); + } +}; + +// TODO Test semantics, it compiles and runs. +template +phi_match m_Phi(Args... args) { + return phi_match(args...); +} + + namespace util { Value *node(Instruction *I, const std::vector &Path) { Value *Current = I; @@ -97,6 +133,26 @@ namespace util { return false; } +// bool ckb(llvm::Value *V) { +// // TODO +// return false; +// } + +// bool ccr(llvm::Value *V) { +// // TODO +// return false; +// } + +// bool vkb(llvm::Value *V, IRBuilder *I) { +// I->getContext().get +// computeKnownBits() +// } + +// bool vcr(llvm::Value *V) { + +// } + + struct Stats { void hit(size_t opt) { Hits[opt]++; From 469546fa504ebfcc046b2d8481b9134922b34c99 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 28 Jun 2022 17:08:23 -0600 Subject: [PATCH 070/165] foo --- tools/matcher-gen.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 622d32cc1..9e7032700 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -281,6 +281,9 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { auto Str = Child->Val.toString(10, false); Out << "m_SpecificInt(" << Str << ")"; } else if (Child->K == Inst::Var) { + + // FIXME What about Symbolic constants? + Out << "m_Value(" << Syms[Child].back() << ")"; Syms[Child].pop_back(); } else { From 44ef0bb9dddb6370dfbeb3a7e8919d0aaba18bad Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 29 Jun 2022 15:10:17 -0600 Subject: [PATCH 071/165] foo --- tools/matcher-gen.cpp | 1 + tools/pass-generator/src/template.cpp | 54 ++++++++++++++++++++------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 9e7032700..51f742a76 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -283,6 +283,7 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { } else if (Child->K == Inst::Var) { // FIXME What about Symbolic constants? + // How about matching const exprs? Out << "m_Value(" << Syms[Child].back() << ")"; Syms[Child].pop_back(); diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index eaaf4a10e..cd0cb8a30 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -2,6 +2,7 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/Constant.h" +#include "llvm/IR/ConstantRange.h" #include "llvm/IR/Constants.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" @@ -15,6 +16,7 @@ #include "llvm/Analysis/ValueTracking.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/InstCombine/InstCombineWorklist.h" +#include "llvm/Support/KnownBits.h" using namespace llvm; using namespace llvm::PatternMatch; @@ -133,24 +135,48 @@ namespace util { return false; } -// bool ckb(llvm::Value *V) { -// // TODO -// return false; -// } + bool IsKBSubset(KnownBits Small, KnownBits Big) { + // FIXME Think about this carefully. + // It can't just be conflict. -// bool ccr(llvm::Value *V) { -// // TODO -// return false; -// } + return false; + } -// bool vkb(llvm::Value *V, IRBuilder *I) { -// I->getContext().get -// computeKnownBits() -// } + bool IsCRSubset(ConstantRange Small, ConstantRange Big) { + return Big.contains(Small); + } -// bool vcr(llvm::Value *V) { + bool ckb(llvm::Value *V, llvm::KnownBits Overapprox) { + if (ConstantInt *Con = llvm::dyn_cast(V)) { + auto Val = Con->getUniqueInteger(); + llvm::KnownBits KB(V->getType()->getIntegerBitWidth()); + KB.One = Val; + KB.Zero = ~Val; + return IsKBSubset(KB, Overapprox); + } + return false; + } -// } + bool ccr(llvm::Value *V,llvm::ConstantRange R) { + if (ConstantInt *Con = llvm::dyn_cast(V)) { + return R.contains(Con->getUniqueInteger()); + } + return false; + } + + bool vkb(llvm::Value *V, llvm::KnownBits OverApprox) { + auto Analyzed = llvm::KnownBits(V->getType()->getIntegerBitWidth()); + if (Instruction *I = llvm::dyn_cast(V)) { + DataLayout DL(I->getParent()->getParent()->getParent()); + computeKnownBits(V, Analyzed, DL, 4); + } + return IsKBSubset(Analyzed, OverApprox); + } + + bool vcr(llvm::Value *V, llvm::ConstantRange R) { + // FIXME obtain result from range analysis pass + return false; + } struct Stats { From bfc06fd93b79452f7f3f5be642ae9f272a133bb4 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 30 Jun 2022 15:45:22 -0600 Subject: [PATCH 072/165] foo --- tools/generalize.cpp | 57 +++++++++++++++++++++++++++++++++++++++---- tools/matcher-gen.cpp | 2 ++ 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 63d5b84c7..60df33baa 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1004,7 +1004,7 @@ class Reducer { collectInsts(Input.Mapping.LHS, Insts); // TODO: topological sort, to reduce number of solver calls // Try to remove one instruction at a time - int failcount = 0; + size_t failcount = 0; std::set Visited; do { auto It = Insts.begin(); @@ -1094,6 +1094,55 @@ class Reducer { return Input; } + ParsedReplacement ReduceRedundantPhis(ParsedReplacement Input) { + std::set Insts; + std::vector Phis; + + auto Collect = [&] () { + Insts.clear(); + Phis.clear(); + collectInsts(Input.Mapping.LHS, Insts); + collectInsts(Input.Mapping.RHS, Insts); + for (auto &&I : Insts) { + if (I->K == Inst::Phi) { + Phis.push_back(I); + } + } + }; + Collect(); + + size_t NumPhis = Phis.size(); + while (NumPhis --) { + std::map ICache; + for (auto &&I : Phis) { + if (I->Ops.size() == 1) { + ICache[I] = I->Ops[0]; + } else if (I->Ops.size() > 1) { + bool allEq = true; + for (size_t i = 0; i < I->Ops.size(); ++i) { + if (I->Ops[i] != I->Ops[0]) { + allEq = false; + break; + } + } + if (allEq) { + ICache[I] = I->Ops[0]; + } + } + } + + Input.Mapping.LHS = Replace(Input.Mapping.LHS, IC, ICache); + Input.Mapping.RHS = Replace(Input.Mapping.RHS, IC, ICache); + for (auto &PC : Input.PCs) { + PC.LHS = Replace(PC.LHS, IC, ICache); + PC.RHS = Replace(PC.RHS, IC, ICache); + } + if (NumPhis) { + Collect(); + } + } + return Input; + } // Assumes Input is valid ParsedReplacement ReducePCs(ParsedReplacement Input) { @@ -1367,6 +1416,7 @@ std::vector ReduceAndGeneralize(InstContext &IC, std::vector Results; Input = R.ReducePCs(Input); + Input = R.ReduceRedundantPhis(Input); Input = R.ReduceGreedy(Input); Input = R.WeakenKB(Input); Input = R.WeakenCR(Input); @@ -1374,12 +1424,9 @@ std::vector ReduceAndGeneralize(InstContext &IC, if (ReduceKBIFY) { Input = R.ReduceGreedyKBIFY(Input); } - Input = R.ReducePCs(Input); - -// Results.push_back(Input); - R.ReduceRec(Input, Results); + if (DebugLevel > 3) { R.Stats(); } diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 51f742a76..c18b23c30 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -569,7 +569,9 @@ int main(int argc, char **argv) { llvm::outs() << Str << "\n"; llvm::outs().flush(); } else { + Input.print(llvm::errs(), true); llvm::errs() << "Failed to generate matcher.\n\n\n"; + llvm::errs().flush(); } } From e05249ee3f5be4f88bf4f27da8af6c28a4012abc Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 30 Jun 2022 16:27:41 -0600 Subject: [PATCH 073/165] foo --- utils/cache_to_dir.py | 16 ++++++++++++++++ utils/magic.sh | 14 ++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 utils/cache_to_dir.py create mode 100755 utils/magic.sh diff --git a/utils/cache_to_dir.py b/utils/cache_to_dir.py new file mode 100644 index 000000000..3c7fe858b --- /dev/null +++ b/utils/cache_to_dir.py @@ -0,0 +1,16 @@ +import redis +import sys +r = redis.Redis() +n = 0 +dir = sys.argv[1] +for key in r.keys(): + try: + val = r.hgetall(key)[b'rhs'] + if val != b"": + s = key.decode('utf-8') + val.decode('utf-8') + f = open(dir + "/" + str(n) + '.opt', "w") + n = n + 1 + f.write(s) + f.close() + except KeyError: + pass diff --git a/utils/magic.sh b/utils/magic.sh new file mode 100755 index 000000000..37e14a578 --- /dev/null +++ b/utils/magic.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Last argument is assumed to be a file with multiple inputs +# separated by empty lines + +mkdir -p /tmp/scratch/ +rm -f /tmp/scratch/* + +infile=${@: -1} +cmd=${*%${!#}} + +csplit --quiet --prefix=/tmp/scratch/opt --suffix-format=%02d.txt --suppress-matched $infile /^$/ {*} + +for i in `ls -v /tmp/scratch/*`; do echo $cmd $i "&& echo";done > /tmp/cmdfile.txt +parallel --will-cite -k < /tmp/cmdfile.txt From 567d7e7d02791b8f1a7d7d1c36415e1ef17c9722 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 7 Jul 2022 01:12:05 -0600 Subject: [PATCH 074/165] foo --- tools/pass-generator/CMakeLists.txt | 2 +- tools/pass-generator/src/template.cpp | 15 ++++++++++++--- utils/magic.sh | 6 +++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/tools/pass-generator/CMakeLists.txt b/tools/pass-generator/CMakeLists.txt index d4e5a67fd..ddd3a8821 100644 --- a/tools/pass-generator/CMakeLists.txt +++ b/tools/pass-generator/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.7) project(souper-combine) -find_package(LLVM 13.0 REQUIRED CONFIG) +find_package(LLVM 14.0 REQUIRED CONFIG) list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") include(HandleLLVMOptions) include(AddLLVM) diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index cd0cb8a30..1240d6296 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -1,3 +1,5 @@ +#define DEBUG_TYPE "" + #include "llvm/Pass.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/PatternMatch.h" @@ -15,9 +17,12 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" -#include "llvm/Transforms/InstCombine/InstCombineWorklist.h" +#include "llvm/Support/Debug.h" +#include "llvm/Transforms/Utils/InstructionWorklist.h" #include "llvm/Support/KnownBits.h" +#include + using namespace llvm; using namespace llvm::PatternMatch; @@ -104,7 +109,6 @@ phi_match m_Phi(Args... args) { return phi_match(args...); } - namespace util { Value *node(Instruction *I, const std::vector &Path) { Value *Current = I; @@ -126,6 +130,11 @@ namespace util { return V->getType()->getScalarSizeInBits() == W; } + template + bool check_related(Out Result, FT F, Args... args) { + return Result == F(args...); + } + bool cpow2(llvm::Value *V) { if (ConstantInt *Con = llvm::dyn_cast(V)) { if (Con->getValue().isPowerOf2()) { @@ -257,7 +266,7 @@ struct SouperCombine : public FunctionPass { return B->getIntNTy(W); } - InstCombineWorklist W; + InstructionWorklist W; util::Stats St; }; } diff --git a/utils/magic.sh b/utils/magic.sh index 37e14a578..fbd920614 100755 --- a/utils/magic.sh +++ b/utils/magic.sh @@ -5,10 +5,10 @@ mkdir -p /tmp/scratch/ rm -f /tmp/scratch/* -infile=${@: -1} -cmd=${*%${!#}} +infile=${@: -1} # Last argument +cmd=${*%${!#}} # All but the last argument -csplit --quiet --prefix=/tmp/scratch/opt --suffix-format=%02d.txt --suppress-matched $infile /^$/ {*} +csplit --quiet --prefix=/tmp/scratch/opt --suffix-format=%02d.txt $infile '/^result/ +1' '/^cand/ +1' '{*}' for i in `ls -v /tmp/scratch/*`; do echo $cmd $i "&& echo";done > /tmp/cmdfile.txt parallel --will-cite -k < /tmp/cmdfile.txt From 5cae24b19ad2b0f42af4931db3e1ab3497f798fd Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 20 Jul 2022 12:42:00 -0600 Subject: [PATCH 075/165] foo --- tools/generalize.cpp | 380 ++++---------------------- tools/pass-generator/src/template.cpp | 28 +- 2 files changed, 75 insertions(+), 333 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 60df33baa..a82fe4ba6 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -283,37 +283,41 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement } std::vector Components; - if (!SymbolizeConstSynthesis) { - std::set ConcreteConsts; // for deduplication - for (auto C : LHSConsts) { - ConcreteConsts.insert(C); - ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 1))); - ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, -1))); - ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 2))); - } - for (auto C : RHSConsts) { - ConcreteConsts.insert(C); - } - for (auto C : ConcreteConsts) { - Components.push_back(C); - } - } +// if (!SymbolizeConstSynthesis) { +// std::set ConcreteConsts; // for deduplication + +// for (auto C : LHSConsts) { +// ConcreteConsts.insert(C); +// ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 1))); +// ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, -1))); +// ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 2))); +// ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 31))); +// } +// for (auto C : RHSConsts) { +// ConcreteConsts.insert(C); +// } +// for (auto C : ConcreteConsts) { +// Components.push_back(C); +// } +// } - if (true) { - for (size_t i = 0; i < Vars.size(); ++i) { - SymDFVars.push_back(IC.createVar(Vars[i]->Width, "symk_one_" + std::to_string(i))); - SymDFVars.back()->SymOneOf = Vars[i]; -// Vars[i]->SymKnownOnes = SymDFVars.back(); - Components.push_back(SymDFVars.back()); - - SymDFVars.push_back(IC.createVar(Vars[i]->Width, "symk_zero_" + std::to_string(i))); - SymDFVars.back()->SymZeroOf = Vars[i]; -// Vars[i]->SymKnownZeros = SymDFVars.back(); - Components.push_back(SymDFVars.back()); - } - } +// // Symbolic known bits +// if (false) { +// for (size_t i = 0; i < Vars.size(); ++i) { +// SymDFVars.push_back(IC.createVar(Vars[i]->Width, "symk_one_" + std::to_string(i))); +// SymDFVars.back()->SymOneOf = Vars[i]; +//// Vars[i]->SymKnownOnes = SymDFVars.back(); +// Components.push_back(SymDFVars.back()); + +// SymDFVars.push_back(IC.createVar(Vars[i]->Width, "symk_zero_" + std::to_string(i))); +// SymDFVars.back()->SymZeroOf = Vars[i]; +//// Vars[i]->SymKnownZeros = SymDFVars.back(); +// Components.push_back(SymDFVars.back()); +// } +// } + // Put custom components here if (SymbolizeConstant) { for (auto C : SymCS) { // // Minus One @@ -353,55 +357,15 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement EnumerativeSynthesis ES; auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, Target->Width); - - // auto Guesses = Components; - - // TODO : Memoize expressions by width - for (auto &&Guess : Guesses) { std::set ConstSet; souper::getConstants(Guess, ConstSet); if (!ConstSet.empty()) { if (SymbolizeConstSynthesis) { - auto SMTLIBSolver = GetUnderlyingSolver(); - SynthesisContext SC{IC, SMTLIBSolver.get(), Target, nullptr, {}, {}, false, 10}; -// PruningManager Pruner(SC, SymCS, DebugLevel); -// Pruner.init(); -// if (!Pruner.isInfeasible(Guess, DebugLevel)) { Candidates.back().push_back(Guess); -// llvm::errs() << "NOT PRUNED\n"; -// } -// else { -// ReplacementContext RC; -// RC.printInst(Guess, llvm::errs(), true); -// llvm::errs() << "\n PRUNED\n"; -// } } -// continue; -// Candidates.back().push_back(Guess); - // TODO: Fake constant synthesis based on algebra - // We have ConcreteLHS = f(ConcreteRHS, SymbolicConst) - // Solve equation to find SymbolicConst - // TODO: Proper constant synthesis } else { - // Candidates.back().push_back(Guess); - // auto Val = CI.evaluateInst(Guess); - // if (!Val.hasValue()) { Candidates.back().push_back(Guess); - // llvm::outs() << "CI Fail\n"; - // Somehow interpreter failed, full verification desirable - // } else { - // if (Val.hasValue() && Val.getValue() == Target->Val) { - // Candidates.back().push_back(Guess); - // } else { - // if (DebugLevel > 4) { - // llvm::outs() << "\nDiscarded by ConcreteInterpreter:\n"; - // llvm::outs() << Val.getValue() << '\t' << Target->Val << '\n'; - // ReplacementContext RC; - // RC.printInst(Guess, llvm::errs(), true); - // } - // } - // } } } } @@ -439,12 +403,15 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement CandidateReplacement Rep(nullptr, Result.Mapping); Rep.PCs = Result.PCs; Results.push_back(Rep); + IsValid = true; + } else { + IsValid = false; } }; CheckAndSave(); - // TODO Make preconditions consistent + // TODO Make preconditions consistent with inputs if (SymbolizeSimpleDF) { for (auto &&C : SymCS) { if (!IsValid) { @@ -469,268 +436,7 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement // } } } - // TODO Is there a better way of doing this? - // TODO Other kinds of preconditions? - } - - -} - -void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input, - std::vector LHSConsts, - std::vector RHSConsts, - CandidateMap &Results) { - - // FIXME Very fragile. Maybe rewrite - - std::vector Vars; - findVars(Input.Mapping.LHS, Vars); - - std::map InstCache; - std::vector FakeConsts; - for (size_t i = 0; i < LHSConsts.size(); ++i) { - FakeConsts.push_back( - IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i))); - InstCache[LHSConsts[i]] = FakeConsts[i]; - if (SymbolizeWidth) { - FakeConsts.push_back(IC.getInst(Inst::BitWidth, LHSConsts[i]->Width, {Vars[0]})); - } - } - - auto Components = FakeConsts; - // Does it makes sense for the expression to depend on other variables? - // If yes, expand the third argument to include inputs - if (SymbolizeWidth) { - for (auto &&V : Vars) { - auto Width = IC.getInst(Inst::BitWidth, FakeConsts[0]->Width, {V}); - Components.push_back(Width); - Components.push_back(IC.getInst(Inst::LogB, FakeConsts[0]->Width, {Width})); - // auto IntMax = 1 << Width - 1 - // TODO other comps, like INT_MAX - // Dedup widths which can not be different - } - } - - std::vector Targets; - for (auto C : LHSConsts) { - Targets.push_back(C); - } - for (auto C : RHSConsts) { - Targets.push_back(C); - } - - for (auto T : Targets) { - EnumerativeSynthesis ES; - auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, - T->Width); - - std::vector>> - Preconditions; - - std::map BlockCache; - std::map ConstMap; - auto LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, - BlockCache, &ConstMap, false); - - std::vector WithoutConsts; - - auto TryConstSynth = [&](Inst *Guess, std::set &ConstSet) { - std::map ResultConstMap; - std::map InstCacheCopy/* = InstCache*/; - InstCacheCopy[T] = Guess; - auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, - BlockCache, &ConstMap, false); - ConstantSynthesis CS; - auto SMTSolver = GetUnderlyingSolver(); - auto EC = CS.synthesize(SMTSolver.get(), Input.BPCs, Input.PCs, - InstMapping (LHS, RHS), ConstSet, - ResultConstMap, IC, /*MaxTries=*/30, 10, - /*AvoidNops=*/true); - if (!ResultConstMap.empty()) { - std::map InstCache; - std::map BlockCache; - auto LHSCopy = getInstCopy(LHS, IC, InstCache, BlockCache, &ResultConstMap, true); - RHS = getInstCopy(RHS, IC, InstCache, BlockCache, &ResultConstMap, true); - - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHSCopy, RHS))); - return true; - } else { - if (DebugLevel > 2) { - llvm::errs() << "Constant Synthesis ((no Dataflow Preconditions)) failed. \n"; - } - } - return false; - }; - - - for (auto &Guess : Guesses) { - std::set ConstSet; - souper::getConstants(Guess, ConstSet); - if (!ConstSet.empty()) { - if (SymbolizeConstSynthesis) { - bool Success = TryConstSynth(Guess, ConstSet); - // llvm::errs() << "Succ:" << Success << "\n"; - if (SymbolizeSimpleDF) { - if (!Success) { - FakeConsts[0]->PowOfTwo = true; - Success = TryConstSynth(Guess, ConstSet); - FakeConsts[0]->PowOfTwo = false; - } - // llvm::errs() << "Succ:" << Success << "\n"; - - if (!Success) { - FakeConsts[0]->NonZero = true; - Success = TryConstSynth(Guess, ConstSet); - FakeConsts[0]->NonZero = false; - } - // llvm::errs() << "Succ:" << Success << "\n"; - - if (!Success) { - FakeConsts[0]->NonNegative = true; - Success = TryConstSynth(Guess, ConstSet); - FakeConsts[0]->NonNegative = false; - } - // llvm::errs() << "Succ:" << Success << "\n"; - - if (!Success) { - FakeConsts[0]->Negative = true; - Success = TryConstSynth(Guess, ConstSet); - FakeConsts[0]->Negative = false; - } - // llvm::errs() << "Succ:" << Success << "\n"; - (void)Success; - } - } - - } else { - WithoutConsts.push_back(Guess); - } - } - std::swap(WithoutConsts, Guesses); - - for (auto &Guess : Guesses) { - std::map InstCacheCopy/* = InstCache*/; - InstCacheCopy[T] = Guess; - - - - auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCacheCopy, - BlockCache, &ConstMap, false); - - - if (DebugLevel > 4) { - { - llvm::errs() << "GUESS:\n"; - ReplacementContext RC; - RC.printInst(Guess, llvm::errs(), true); - } - { - llvm::errs() << "JoinedGUESS:\n"; - ReplacementContext RC; - RC.printInst(RHS, llvm::errs(), true); - } - } - - InstMapping Mapping(LHS, RHS); - if (true /*remove when the other branch exists*/ || SymbolizeNoDFP) { - bool IsValid; - auto CheckAndSave = [&]() { - std::vector> Models; - if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Mapping, IsValid, &Models)) { - llvm::errs() << EC.message() << '\n'; - } - if (IsValid) { - InstMapping Clone; - std::map InstCache; - std::map BlockCache; - std::map ConstMap; - Clone.LHS = getInstCopy(Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); - Clone.RHS = getInstCopy(Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); - Results.push_back(CandidateReplacement(/*Origin=*/nullptr, Clone)); - } - }; - CheckAndSave(); - if (SymbolizeSimpleDF) { - if (!IsValid) { - FakeConsts[0]->PowOfTwo = true; - CheckAndSave(); - FakeConsts[0]->PowOfTwo = false; - } - if (!IsValid) { - FakeConsts[0]->NonZero = true; - CheckAndSave(); - FakeConsts[0]->NonZero = false; - } - if (!IsValid) { - FakeConsts[0]->NonNegative = true; - CheckAndSave(); - FakeConsts[0]->NonNegative = false; - } - if (!IsValid) { - FakeConsts[0]->Negative = true; - CheckAndSave(); - FakeConsts[0]->Negative = false; - } - } - - } else { - // std::vector> KBResults; - // std::vector> CRResults; - // bool FoundWP = false; - // S->abstractPrecondition(Input.BPCs, Input.PCs, Mapping, IC, FoundWP, KBResults, CRResults); - // Preconditions.push_back(KBResults); - // if (!FoundWP) { - // Guess = nullptr; // TODO: Better failure indicator - // } else { - // Guess = RHS; - // } - } - } -} - -// std::vector Idx; -// std::vector Utility; -// for (size_t i = 0; i < Guesses.size(); ++i) { -// Idx.push_back(i); -// } -// for (size_t i = 0; i < Preconditions.size(); ++i) { -// Utility.push_back(0); -// if (!Guesses[i]) continue; -// if (Preconditions[i].empty()) { -// Utility[i] = 1000; // High magic number -// } - -// for (auto V : Preconditions[i]) { -// for (auto P : V) { -// auto W = P.second.getBitWidth(); -// Utility[i] += (W - P.second.Zero.countPopulation()); -// Utility[i] += (W - P.second.One.countPopulation()); -// } -// } -// } - -// std::sort(Idx.begin(), Idx.end(), [&Utility](size_t a, size_t b) { -// return Utility[a] > Utility[b]; -// }); - -// for (size_t i = 0; i < Idx.size(); ++i) { -// if (Preconditions[Idx[i]].empty() && Guesses[Idx[i]]) { -// Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHS, Guesses[Idx[i]]))); -// } -// } - - // if (!SymbolizeNoDFP) { - // for (size_t i = 0; i < std::min(Idx.size(), NumResults.getValue()); ++i) { - // for (auto Computed : Preconditions[Idx[i]]) { - // for (auto Pair : Computed) { - // Pair.first->KnownOnes = Pair.second.One; - // Pair.first->KnownZeros = Pair.second.Zero; - // } - // Results.push_back(CandidateReplacement(/*Origin=*/nullptr, InstMapping(LHS, Guesses[Idx[i]]))); - // } - // } - // } } void SymbolizeAndGeneralize(InstContext &IC, @@ -762,8 +468,16 @@ void SymbolizeAndGeneralize(InstContext &IC, Input.print(llvm::outs(), true); llvm::outs() << "\n;Results:\n"; - // TODO: Move sorting here - std::set ResultStrs; + auto cmp = [](const std::string &a, const std::string &b) { + if (a.length() < b.length()) { + return true; + } else if (a.length() == b.length()) { + return a < b; + } else { + return false; + } + }; + std::set ResultStrs(cmp); for (auto &&Result : Results) { std::string str; llvm::raw_string_ostream ostr(str); @@ -771,7 +485,9 @@ void SymbolizeAndGeneralize(InstContext &IC, ResultStrs.insert(str); } + int n = 5; for (auto &&Str : ResultStrs) { + if (!n--) break; llvm::outs() << Str << "\n"; } } diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 1240d6296..170248fa2 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -109,6 +109,27 @@ phi_match m_Phi(Args... args) { return phi_match(args...); } +struct bind_apint { + APInt &VR; + + bind_apint(APInt &V) : VR(V) {} + + template bool match(ITy *V) { + if (const auto *CV = dyn_cast(V)) { + VR = CV->getValue(); + return true; + } else { + return false; + } + return false; + } +}; + +// Tested, matches APInts +inline bind_apint m_APInt(APInt &V) { return bind_apint(V); } + +// TODO: Match (arbitrarily) constrained APInts + namespace util { Value *node(Instruction *I, const std::vector &Path) { Value *Current = I; @@ -252,7 +273,7 @@ struct SouperCombine : public FunctionPass { return Changed; } - Value *getReplacement(llvm::Instruction *I, IRBuilder *B) { + Value *getReplacement(llvm::Instruction *I, IRBuilder *B) { // Autogenerated transforms #include "gen.cpp.inc" return nullptr; @@ -262,6 +283,11 @@ struct SouperCombine : public FunctionPass { return B->getIntN(Width, Value); } + Value *C(llvm::APInt Value, IRBuilder *B) { + return B->getIntN(Value.getBitWidth(), Value.getLimitedValue()); + // FIXME: Figure out how to make a value from a full APInt. + } + Type *T(size_t W, IRBuilder *B) { return B->getIntNTy(W); } From 3240b5222034a93656f78e85e6f8b52066f050e7 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 21 Jul 2022 01:16:18 -0600 Subject: [PATCH 076/165] foo --- include/souper/Infer/SynthUtils.h | 13 +++- tools/generalize.cpp | 110 +++++++++++++++++++++--------- 2 files changed, 88 insertions(+), 35 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index edb0e914e..c541886ac 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -120,8 +120,6 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { return In; } - - // Also Synthesizes given constants // Returns clone if verified, nullptrs if not ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { @@ -165,9 +163,18 @@ ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { } else { Input.Mapping = InstMapping(nullptr, nullptr); return Input; - // TODO: Better vailure indication? + // TODO: Better failure indication? } } +std::map findValidInput(ParsedReplacement Input, InstContext &IC, + Solver *S, std::vector> &BlockList) { + // FIXME Continue from here +} + +std::vector> findValidInputs(ParsedReplacement Input, InstContext &IC, Solver *S, size_t Count = 1) { + +} + } #endif diff --git a/tools/generalize.cpp b/tools/generalize.cpp index a82fe4ba6..d970b81a1 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -250,6 +250,51 @@ void ReplaceConstsSimple(InstContext &IC, Solver *S, // expr or a kb expr } +bool InferPreconditionsAndVerify(ParsedReplacement Input, CandidateMap &Results, + const std::vector &SymCS, InstContext &IC, Solver *S) { + + auto Result = Verify(Input, IC, S); + if (Result.Mapping.LHS && Result.Mapping.RHS) { + CandidateReplacement Rep(nullptr, Result.Mapping); + Rep.PCs = Result.PCs; + Results.push_back(Rep); + return true; + } + + if (SymbolizeSimpleDF) { + for (auto &&C : SymCS) { + C->PowOfTwo = true; + + // Abstract away the following logic + auto Result = Verify(Input, IC, S); + if (Result.Mapping.LHS && Result.Mapping.RHS) { + CandidateReplacement Rep(nullptr, Result.Mapping); + Rep.PCs = Result.PCs; + Results.push_back(Rep); + return true; + } + + C->PowOfTwo = false; + +// C->NonZero = true; +// CheckAndSave(); +// C->NonZero = false; +// C->NonNegative = true; +// CheckAndSave(); +// C->NonNegative = false; +// C->Negative = true; +// CheckAndSave(); +// C->Negative = false; + } + } + // TODO Is there a better way of doing this? + // TODO Other kinds of preconditions? + + + return false; +} + + // FIXME Other interesting things to try // Symbolic KB in preconditions // Symbolic KB with extra constraints. @@ -257,7 +302,7 @@ void ReplaceConstsSimple(InstContext &IC, Solver *S, // Relations between symcs // TODO Document options -void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement Input, +void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement Input, std::vector LHSConsts, std::vector RHSConsts, CandidateMap &Results) { @@ -335,7 +380,6 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement // auto Test = Builder(M0, IC).Sub(C); // Components.push_back(Test()); } - } for (auto SymC : SymCS) { @@ -408,34 +452,36 @@ void SymbolizeAndGeneralizeRewrite(InstContext &IC, Solver *S, ParsedReplacement IsValid = false; } }; - - CheckAndSave(); - - // TODO Make preconditions consistent with inputs - if (SymbolizeSimpleDF) { - for (auto &&C : SymCS) { - if (!IsValid) { - C->PowOfTwo = true; - CheckAndSave(); - C->PowOfTwo = false; - } - // if (!IsValid) { - // C->NonZero = true; - // CheckAndSave(); - // C->NonZero = false; - // } - // if (!IsValid) { - // C->NonNegative = true; - // CheckAndSave(); - // C->NonNegative = false; - // } - // if (!IsValid) { - // C->Negative = true; - // CheckAndSave(); - // C->Negative = false; - // } - } - } + + InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); + +// CheckAndSave(); +// +// // TODO Make preconditions consistent with inputs +// if (SymbolizeSimpleDF) { +// for (auto &&C : SymCS) { +// if (!IsValid) { +// C->PowOfTwo = true; +// CheckAndSave(); +// C->PowOfTwo = false; +// } +// // if (!IsValid) { +// // C->NonZero = true; +// // CheckAndSave(); +// // C->NonZero = false; +// // } +// // if (!IsValid) { +// // C->NonNegative = true; +// // CheckAndSave(); +// // C->NonNegative = false; +// // } +// // if (!IsValid) { +// // C->Negative = true; +// // CheckAndSave(); +// // C->Negative = false; +// // } +// } +// } } } @@ -455,14 +501,14 @@ void SymbolizeAndGeneralize(InstContext &IC, // One at a time for (auto LHSConst : LHSConsts) { - SymbolizeAndGeneralizeRewrite(IC, S, Input, {LHSConst}, RHSConsts, Results); + SymbolizeAndGeneralizeImpl(IC, S, Input, {LHSConst}, RHSConsts, Results); } // All subsets? // TODO: Is it possible to encode this logically. // All at once - SymbolizeAndGeneralizeRewrite(IC, S, Input, LHSConsts, RHSConsts, Results); + SymbolizeAndGeneralizeImpl(IC, S, Input, LHSConsts, RHSConsts, Results); llvm::outs() << ";Input:\n"; Input.print(llvm::outs(), true); From 9a9d9686bc5c90216830c27f9e9ab16f00e3e4a7 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 28 Jul 2022 12:14:22 -0600 Subject: [PATCH 077/165] foo --- CMakeLists.txt | 17 +- include/souper/Generalize/Reducer.h | 62 +++ include/souper/Infer/SynthUtils.h | 117 +---- lib/Generalize/Reducer.cpp | 527 ++++++++++++++++++++++ lib/Infer/ConstantSynthesis.cpp | 3 +- lib/Infer/SynthUtils.cpp | 174 ++++++++ tools/generalize.cpp | 662 ++++------------------------ 7 files changed, 892 insertions(+), 670 deletions(-) create mode 100644 include/souper/Generalize/Reducer.h create mode 100644 lib/Generalize/Reducer.cpp create mode 100644 lib/Infer/SynthUtils.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 30a579fff..55d946ef1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,12 +218,23 @@ set(SOUPER_INFER_FILES include/souper/Infer/Interpreter.h lib/Infer/Preconditions.cpp include/souper/Infer/Preconditions.h + lib/Infer/SynthUtils.cpp + include/souper/Infer/SynthUtils.h ) add_library(souperInfer STATIC ${SOUPER_INFER_FILES} ) +set(SOUPER_GENERALIZE_FILES + lib/Generalize/Reducer.cpp + include/souper/Generalize/Reducer.h +) + +add_library(souperGeneralize STATIC + ${SOUPER_GENERALIZE_FILES} +) + set(SOUPER_INST_FILES lib/Inst/Inst.cpp include/souper/Inst/Inst.h @@ -280,6 +291,7 @@ set(SOUPER_SOURCES ${SOUPER_SMTLIB2_FILES} ${SOUPER_TOOL_FILES} ${SOUPER_INFER_FILES} + ${SOUPER_GENERALIZE_FILES} ${SOUPER_CODEGEN_FILES}) add_library(souperPass SHARED @@ -400,7 +412,7 @@ configure_file( foreach(target souper internal-solver-test lexer-test parser-test souper-check count-insts souper2llvm souper-interpret generalize matcher-gen - souperExtractor souperInfer souperInst souperKVStore souperParser + souperExtractor souperInfer souperGeneralize souperInst souperKVStore souperParser souperSMTLIB2 souperTool souperPass souperPassProfileAll kleeExpr souperCodegen) set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${LLVM_CXXFLAGS}") @@ -420,6 +432,7 @@ target_link_libraries(kleeExpr ${LLVM_LIBS} ${LLVM_LDFLAGS}) target_link_libraries(souperClangTool souperExtractor souperTool ${CLANG_LIBS} ${LLVM_LIBS} ${LLVM_LDFLAGS}) target_link_libraries(souperExtractor souperParser souperKVStore souperInfer souperInst kleeExpr souperCodegen) target_link_libraries(souperInfer souperExtractor ${LLVM_LIBS} ${LLVM_LDFLAGS} ${Z3_LIBRARY}) +target_link_libraries(souperGeneralize souperInfer ${LLVM_LIBS} ${LLVM_LDFLAGS} ${Z3_LIBRARY}) target_link_libraries(souperInst ${LLVM_LIBS} ${LLVM_LDFLAGS}) target_link_libraries(souperKVStore ${HIREDIS_LIBRARY} ${LLVM_LIBS} ${LLVM_LDFLAGS}) target_link_libraries(souperParser souperInst ${LLVM_LIBS} ${LLVM_LDFLAGS} ${ALIVE_LIBRARY}) @@ -438,7 +451,7 @@ 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} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) -target_link_libraries(generalize souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) +target_link_libraries(generalize souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser souperInfer souperGeneralize ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(matcher-gen souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(souper-interpret souperTool souperExtractor souperKVStore souperSMTLIB2 souperParser ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) target_link_libraries(clang-souper souperClangTool souperExtractor souperKVStore souperParser souperSMTLIB2 souperTool kleeExpr ${CLANG_LIBS} ${LLVM_LIBS} ${LLVM_LDFLAGS} ${HIREDIS_LIBRARY} ${ALIVE_LIBRARY} ${Z3_LIBRARY}) diff --git a/include/souper/Generalize/Reducer.h b/include/souper/Generalize/Reducer.h new file mode 100644 index 000000000..2263d16bb --- /dev/null +++ b/include/souper/Generalize/Reducer.h @@ -0,0 +1,62 @@ +#ifndef SOUPER_GENERALIZE_REDUCER_H +#define SOUPER_GENERALIZE_REDUCER_H + +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/KnownBits.h" +#include "souper/Parser/Parser.h" +#include "souper/Infer/EnumerativeSynthesis.h" +#include "souper/Infer/ConstantSynthesis.h" +#include "souper/Infer/Pruning.h" +#include "souper/Infer/SynthUtils.h" + +namespace souper { + +class Reducer { +public: + Reducer(InstContext &IC_, Solver *S_) : IC(IC_), S(S_), varnum(0), numSolverCalls(0) {} + + ParsedReplacement ReduceGreedy(ParsedReplacement Input); + + // Eventually replace the functions in Preconditions{.h/.cpp} with this. + // Does not produce exhaustive result. TODO Have an option to wrap in a cegis loop. + bool inferKBPrecondition(ParsedReplacement &Input, std::vector Targets); + + ParsedReplacement ReduceGreedyKBIFY(ParsedReplacement Input); + + ParsedReplacement ReduceRedundantPhis(ParsedReplacement Input); + + // Assumes Input is valid + ParsedReplacement ReducePCs(ParsedReplacement Input); + + // Assumes Input is valid + ParsedReplacement WeakenKB(ParsedReplacement Input); + + // Assumes Input is valid + ParsedReplacement WeakenCR(ParsedReplacement Input); + + // Assumes Input is valid + ParsedReplacement WeakenDB(ParsedReplacement Input); + + bool VerifyInput(ParsedReplacement &Input); + + bool safeToRemove(Inst *I, ParsedReplacement &Input); + + Inst *Eliminate(ParsedReplacement &Input, Inst *I); + + void ReduceRec(ParsedReplacement Input_, std::vector &Results); + void Stats() { + llvm::outs() << "Solver Calls: " << numSolverCalls << "\n"; + } +private: + InstContext &IC; + Solver *S; + int varnum; + int numSolverCalls; + std::unordered_set DNR; +}; + +} + +#endif + diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index c541886ac..8ed44c7a0 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -5,13 +5,21 @@ #include "souper/Infer/EnumerativeSynthesis.h" #include "souper/Infer/ConstantSynthesis.h" #include "souper/Parser/Parser.h" -#include "souper/Tool/GetSolver.h" namespace souper { +// TODO: Lazy construction instead of eager. +// eg: Instead of Builder(I, IC).Add(1)() +// we could do Builder(I).Add(1)(IC) class Builder { public: Builder(Inst *I_, InstContext &IC_) : I(I_), IC(IC_) {} + Builder(InstContext &IC_, llvm::APInt Value) : IC(IC_) { + I = IC.getConst(Value); + } + Builder(Inst *I_, InstContext &IC_, uint64_t Value) : IC(IC_) { + I = IC.getConst(llvm::APInt(I_->Width, Value)); + } Inst *operator()() { assert(I); @@ -32,7 +40,7 @@ class Builder { auto L = I; auto R = i(t, *this); \ return Builder(IC.getInst(Inst::K, 1, {L, R}), IC); \ } - BINOPW(Slt) BINOPW(Ult) BINOPW(Eq) + BINOPW(Slt) BINOPW(Ult) BINOPW(Eq) BINOPW(Ne) #undef BINOPW private: @@ -72,109 +80,24 @@ class Builder { } }; -Inst *Replace(Inst *R, InstContext &IC, std::map &M) { - std::map BlockCache; - std::map ConstMap; - return getInstCopy(R, IC, M, BlockCache, &ConstMap, false); -} - -Inst *Clone(Inst *R, InstContext &IC) { - std::map BlockCache; - std::map ConstMap; - std::map InstCache; - return getInstCopy(R, IC, InstCache, BlockCache, &ConstMap, true, false); -} +Inst *Replace(Inst *R, InstContext &IC, std::map &M); +ParsedReplacement Replace(ParsedReplacement I, InstContext &IC, + std::map &M); -InstMapping Clone(InstMapping In, InstContext &IC) { - std::map BlockCache; - std::map ConstMap; - std::map InstCache; - InstMapping Out; - Out.LHS = getInstCopy(In.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); - Out.RHS = getInstCopy(In.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); - return Out; -} +Inst *Clone(Inst *R, InstContext &IC); -ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { - std::map BlockCache; - std::map ConstMap; - std::map InstCache; - std::vector RHSVars; - findVars(In.Mapping.RHS, RHSVars); - In.Mapping.LHS = getInstCopy(In.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); - In.Mapping.RHS = getInstCopy(In.Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); - for (auto &PC : In.PCs) { - PC.LHS = getInstCopy(PC.LHS, IC, InstCache, BlockCache, &ConstMap, false, false); - PC.RHS = getInstCopy(PC.RHS, IC, InstCache, BlockCache, &ConstMap, false, false); - } +InstMapping Clone(InstMapping In, InstContext &IC); - for (auto &V : RHSVars) { - if (V->SymOneOf) { - InstCache[V->SymOneOf]->SymKnownOnes = InstCache[V]; - } - if (V->SymZeroOf) { - InstCache[V->SymZeroOf]->SymKnownZeros = InstCache[V]; - } - } - - return In; -} +ParsedReplacement Clone(ParsedReplacement In, InstContext &IC); // Also Synthesizes given constants // Returns clone if verified, nullptrs if not -ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { - Input = Clone(Input, IC); - std::set ConstSet; - souper::getConstants(Input.Mapping.RHS, ConstSet); - if (!ConstSet.empty()) { - std::map ResultConstMap; - ConstantSynthesis CS; - auto SMTSolver = GetUnderlyingSolver(); - auto EC = CS.synthesize(SMTSolver.get(), Input.BPCs, Input.PCs, - Input.Mapping, ConstSet, - ResultConstMap, IC, /*MaxTries=*/30, 10, - /*AvoidNops=*/true); - if (!ResultConstMap.empty()) { - std::map InstCache; - std::map BlockCache; - auto LHSCopy = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ResultConstMap, true); - auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, BlockCache, &ResultConstMap, true); - Input.Mapping = InstMapping(LHSCopy, RHS); - for (auto &PC : Input.PCs) { - PC.LHS = getInstCopy(PC.LHS, IC, InstCache, BlockCache, &ResultConstMap, true); - PC.RHS = getInstCopy(PC.RHS, IC, InstCache, BlockCache, &ResultConstMap, true); - } - return Input; - } else { - if (DebugLevel > 2) { - llvm::errs() << "Constant Synthesis ((no Dataflow Preconditions)) failed. \n"; - } - } - Input.Mapping = InstMapping(nullptr, nullptr); - return Input; - } - std::vector> Models; - bool IsValid; - if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, IsValid, &Models)) { - llvm::errs() << EC.message() << '\n'; - } - if (IsValid) { - return Input; - } else { - Input.Mapping = InstMapping(nullptr, nullptr); - return Input; - // TODO: Better failure indication? - } -} +ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S); -std::map findValidInput(ParsedReplacement Input, InstContext &IC, - Solver *S, std::vector> &BlockList) { - // FIXME Continue from here -} -std::vector> findValidInputs(ParsedReplacement Input, InstContext &IC, Solver *S, size_t Count = 1) { - -} +std::map findOneConstSet(ParsedReplacement Input, const std::set &SymCS, InstContext &IC, Solver *S); + +std::vector> findValidConsts(ParsedReplacement Input, const std::set &Insts, InstContext &IC, Solver *S, size_t MaxCount); } #endif diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp new file mode 100644 index 000000000..3d284f76c --- /dev/null +++ b/lib/Generalize/Reducer.cpp @@ -0,0 +1,527 @@ +#include "llvm/Support/KnownBits.h" +#include "souper/Generalize/Reducer.h" +#include "souper/Infer/SynthUtils.h" + +#define _LIBCPP_DISABLE_DEPRECATION_WARNINGS + +namespace souper { + +void collectInsts(Inst *I, std::set &Results) { + std::vector Stack{I}; + while (!Stack.empty()) { + auto Current = Stack.back(); + Stack.pop_back(); + + Results.insert(Current); + + for (auto Child : Current->Ops) { + if (Results.find(Child) == Results.end()) { + Stack.push_back(Child); + } + } + } +} + +ParsedReplacement Reducer::ReduceGreedy(ParsedReplacement Input) { + std::set Insts; + collectInsts(Input.Mapping.LHS, Insts); + // TODO: topological sort, to reduce number of solver calls + // Try to remove one instruction at a time + int failcount = 0; + std::set Visited; + do { + auto It = Insts.begin(); + auto I = *It; + Insts.erase(It); + if (Visited.find(I) != Visited.end()) { + continue; + } + Visited.insert(I); + if (!safeToRemove(I, Input)) { + continue; + } + auto Copy = Input; + Eliminate(Input, I); + + if (!VerifyInput(Input)) { + Input = Copy; + failcount++; + if (failcount >= Insts.size()) { + break; + } + continue; + } + Insts.clear(); + collectInsts(Input.Mapping.LHS, Insts); + } while (!Insts.empty()); + return Input; +} + +// Eventually replace the functions in Preconditions{.h/.cpp} with this. +// Does not produce exhaustive result. TODO Have an option to wrap in a cegis loop. +bool Reducer::inferKBPrecondition(ParsedReplacement &Input, std::vector Targets) { + assert(Targets.size() == 1 && "Multiple targets unimplemented"); + std::map Result; + std::set SymConsts; + std::map InstCache; + std::map BlockCache; + std::map ConstMap; + size_t ConstID = 0; + for (auto V : Targets) { + auto C = IC.createSynthesisConstant(V->Width, ConstID++); + InstCache[V] = C; + SymConsts.insert(C); + } + auto Copy = Input; + InstMapping Rep; + Rep.LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, false, false); + Rep.RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, false, false); + + ConstantSynthesis CS; + +// llvm::errs() << "Constant synthesis problem: \n"; +// Input.print(llvm::errs(), true); +// llvm::errs() << "....end.... \n"; + + if (auto EC = CS.synthesize(S->getSMTLIBSolver(), Input.BPCs, Input.PCs, + Rep, SymConsts, ConstMap, IC, 30, 60, false)) { + llvm::errs() << "Constant Synthesis internal error : " << EC.message(); + } + + if (ConstMap.empty()) { + if (DebugLevel > 3) { + llvm::errs() << "Constant Synthesis failed, moving on.\n"; + } + Input = Copy; + } else { + InstCache.clear(); + + // TODO: Generalize before allowing multiple targets + auto NewVar = Targets[0]; + auto C = InstCache[NewVar]; + + InstCache[C] = NewVar; + + NewVar->KnownOnes = ConstMap[C]; + NewVar->KnownZeros = ~ConstMap[C]; + + // Give up if can't be weakened 'too much' + const size_t WeakeningThreshold = NewVar->Width/2; + size_t BitsWeakened = 0; + + for (size_t i = 0; i < NewVar->Width; ++i) { + auto SaveZero = NewVar->KnownZeros; + auto SaveOne = NewVar->KnownOnes; + + NewVar->KnownZeros.clearBit(i); + NewVar->KnownOnes.clearBit(i); + + if (!VerifyInput(Input)) { + NewVar->KnownZeros = SaveZero; + NewVar->KnownOnes = SaveOne; + } else { + BitsWeakened++; + } + } + if (BitsWeakened < WeakeningThreshold) { + Input = Copy; // Reset to old state + return false; + } else { + return true; + } + } + return false; +} + +ParsedReplacement Reducer::ReduceGreedyKBIFY(ParsedReplacement Input) { + std::set Insts; + collectInsts(Input.Mapping.LHS, Insts); + // TODO: topological sort, to reduce number of solver calls + // Try to remove one instruction at a time + size_t failcount = 0; + std::set Visited; + do { + auto It = Insts.begin(); + auto I = *It; + Insts.erase(It); + if (Visited.find(I) != Visited.end()) { + continue; + } + Visited.insert(I); + if (!safeToRemove(I, Input) || I->Width == 1 /*1 bit KB doesn't make sense*/) { + continue; + } + auto Copy = Input; + auto NewVar = Eliminate(Input, I); + + // Input won't verify because ReduceGreedy has been called before this. + + // Try to replace NewVar with a symbolic constant and do constant synthesis. + Inst *C = IC.createSynthesisConstant(NewVar->Width, 0); + std::map InstCache = {{NewVar, C}}; + std::map BlockCache; + std::map ConstMap; + + InstMapping Rep; + Rep.LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, false, false); + Rep.RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, false, false); + + ConstantSynthesis CS; + std::set ConstSet{C}; + +// llvm::errs() << "Constant synthesis problem: \n"; +// Input.print(llvm::errs(), true); +// llvm::errs() << "....end.... \n"; + + if (auto EC = CS.synthesize(S->getSMTLIBSolver(), Input.BPCs, Input.PCs, + Rep, ConstSet, ConstMap, IC, 30, 60, false)) { + llvm::errs() << "Constant Synthesis internal error : " << EC.message(); + } + + if (ConstMap.empty()) { + if (DebugLevel > 3) { + llvm::errs() << "Constant Synthesis failed, moving on.\n"; + } + Input = Copy; + failcount++; + if (failcount >= Insts.size()) { + break; + } + } else { + InstCache.clear(); + InstCache[C] = NewVar; + + NewVar->KnownOnes = ConstMap[C]; + NewVar->KnownZeros = ~ConstMap[C]; + + // Give up if can't be weakened 'too much' + const size_t WeakeningThreshold = NewVar->Width/2; + size_t BitsWeakened = 0; + + for (size_t i = 0; i < NewVar->Width; ++i) { + auto SaveZero = NewVar->KnownZeros; + auto SaveOne = NewVar->KnownOnes; + + NewVar->KnownZeros.clearBit(i); + NewVar->KnownOnes.clearBit(i); + + if (!VerifyInput(Input)) { + NewVar->KnownZeros = SaveZero; + NewVar->KnownOnes = SaveOne; + } else { + BitsWeakened++; + } + } + if (BitsWeakened < WeakeningThreshold) { + Input = Copy; + failcount++; + if (failcount >= Insts.size()) { + break; + } + } + } + Insts.clear(); + collectInsts(Input.Mapping.LHS, Insts); + // ^ Can this be skipped? + } while (!Insts.empty()); + return Input; +} + +ParsedReplacement Reducer::ReduceRedundantPhis(ParsedReplacement Input) { + std::set Insts; + std::vector Phis; + + auto Collect = [&] () { + Insts.clear(); + Phis.clear(); + collectInsts(Input.Mapping.LHS, Insts); + collectInsts(Input.Mapping.RHS, Insts); + for (auto &&I : Insts) { + if (I->K == Inst::Phi) { + Phis.push_back(I); + } + } + }; + Collect(); + + size_t NumPhis = Phis.size(); + while (NumPhis --) { + std::map ICache; + for (auto &&I : Phis) { + if (I->Ops.size() == 1) { + ICache[I] = I->Ops[0]; + } else if (I->Ops.size() > 1) { + bool allEq = true; + for (size_t i = 0; i < I->Ops.size(); ++i) { + if (I->Ops[i] != I->Ops[0]) { + allEq = false; + break; + } + } + if (allEq) { + ICache[I] = I->Ops[0]; + } + } + } + + Input.Mapping.LHS = Replace(Input.Mapping.LHS, IC, ICache); + Input.Mapping.RHS = Replace(Input.Mapping.RHS, IC, ICache); + for (auto &PC : Input.PCs) { + PC.LHS = Replace(PC.LHS, IC, ICache); + PC.RHS = Replace(PC.RHS, IC, ICache); + } + if (NumPhis) { + Collect(); + } + } + return Input; +} + +// Assumes Input is valid +ParsedReplacement Reducer::ReducePCs(ParsedReplacement Input) { + + std::set UnnecessaryPCs; + for (size_t i =0; i < Input.PCs.size(); ++i) { + std::vector PCsExceptOne; + for (size_t j = 0; j < Input.PCs.size(); ++j) { + if (i != j) { + PCsExceptOne.push_back(Input.PCs[i]); + } + } + + std::vector> Models; + bool Valid; + if (std::error_code EC = S->isValid(IC, Input.BPCs, PCsExceptOne, Input.Mapping, Valid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + if (Valid) { + UnnecessaryPCs.insert(i); + } + } + + std::vector NecessaryPCs; + for (size_t i =0; i < Input.PCs.size(); ++i) { + if (UnnecessaryPCs.find(i) == UnnecessaryPCs.end()) { + NecessaryPCs.push_back(Input.PCs[i]); + } + } + + auto Result = Input; + Result.PCs = NecessaryPCs; + return Result; +} + +// Assumes Input is valid +ParsedReplacement Reducer::WeakenKB(ParsedReplacement Input) { + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); + for (auto &&V : Vars) { + auto OriZero = V->KnownZeros; + auto OriOne = V->KnownOnes; + if (OriZero == 0 && OriOne == 0) { + continue; // this var doesn't have a knownbits condition + } + if (OriZero.getBitWidth() != V->Width || OriOne.getBitWidth() != V->Width) { + continue; // this var doesn't have a well formed knownbits condition + } + + // Try to remove KB + V->KnownOnes = llvm::APInt(V->Width, 0); + V->KnownZeros = llvm::APInt(V->Width, 0); + if (VerifyInput(Input)) { + continue; // Removed KB from this var + } + V->KnownOnes = OriOne; + V->KnownZeros = OriZero; + + // Try resetting bitwise KB + + for (size_t i = 0; i < V->Width; ++i) { + auto Ones = V->KnownOnes; + if (Ones[i]) { + V->KnownOnes.setBitVal(i, false); + if (!VerifyInput(Input)) { + V->KnownOnes = Ones; + } + } + auto Zeros = V->KnownZeros; + if (Zeros[i]) { + V->KnownZeros.setBitVal(i, false); + if (!VerifyInput(Input)) { + V->KnownZeros = Zeros; + } + } + } + } + return Input; +} + +// Assumes Input is valid +ParsedReplacement Reducer::WeakenCR(ParsedReplacement Input) { + // Just try to remove CR for now. + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); + + for (auto &&V : Vars) { + auto Ori = V->Range; + if (V->Range.isFullSet()) { + continue; + } + V->Range = llvm::ConstantRange(V->Width, true); + if (!VerifyInput(Input)) { + V->Range = Ori; + } + // TODO: Try Widening Range + } + + return Input; +} + +// Assumes Input is valid +ParsedReplacement Reducer::WeakenDB(ParsedReplacement Input) { + auto Ori = Input.Mapping.LHS->DemandedBits; + auto Width = Input.Mapping.LHS->Width; + if (Ori.getBitWidth() != Width || Ori.isAllOnesValue()) { + return Input; + } + // Try replacing with all ones. + Input.Mapping.LHS->DemandedBits.setAllBits(); + if (VerifyInput(Input)) { + return Input; + } + Input.Mapping.LHS->DemandedBits = Ori; + + for (size_t i = 0; i < Width; ++i) { + auto Last = Input.Mapping.LHS->DemandedBits; + if (!Last[i]) { + Input.Mapping.LHS->DemandedBits.setBitVal(i, true); + if (!VerifyInput(Input)) { + Input.Mapping.LHS->DemandedBits = Last; + } + } + } + + return Input; +} + +bool Reducer::VerifyInput(ParsedReplacement &Input) { + std::vector> Models; + bool Valid; + if (std::error_code EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, Valid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + numSolverCalls++; + return Valid; +} + +bool Reducer::safeToRemove(Inst *I, ParsedReplacement &Input) { + if (I == Input.Mapping.LHS || I == Input.Mapping.RHS || I->K == Inst::Var || I->K == Inst::Const || + I->K == Inst::UMulWithOverflow || I->K == Inst::UMulO || + I->K == Inst::SMulWithOverflow || I->K == Inst::SMulO || + I->K == Inst::UAddWithOverflow || I->K == Inst::UAddO || + I->K == Inst::SAddWithOverflow || I->K == Inst::SAddO || + I->K == Inst::USubWithOverflow || I->K == Inst::USubO || + I->K == Inst::SSubWithOverflow || I->K == Inst::SSubO) { + return false; + } + return true; +} + +Inst *Reducer::Eliminate(ParsedReplacement &Input, Inst *I) { + // Try to replace I with a new Var. + Inst *NewVar = IC.createVar(I->Width, "newvar" + std::to_string(varnum++)); + + std::map ICache; + ICache[I] = NewVar; + + std::map BCache; + std::map CMap; + + ParsedReplacement NewInst = Input; + + Input.Mapping.LHS = getInstCopy(Input.Mapping.LHS, IC, ICache, + BCache, &CMap, false); + + Input.Mapping.RHS = getInstCopy(Input.Mapping.RHS, IC, ICache, + BCache, &CMap, false); + + for (auto &M : Input.PCs) { + M.LHS = getInstCopy(M.LHS, IC, ICache, BCache, &CMap, false); + M.RHS = getInstCopy(M.RHS, IC, ICache, BCache, &CMap, false); + } + for (auto &BPC : Input.BPCs) { + BPC.PC.LHS = getInstCopy(BPC.PC.LHS, IC, ICache, BCache, &CMap, false); + BPC.PC.RHS = getInstCopy(BPC.PC.RHS, IC, ICache, BCache, &CMap, false); + } + return NewVar; +} + +void Reducer::ReduceRec(ParsedReplacement Input_, std::vector &Results) { + + // Try to remove subsets of instructions recursively, and store all valid results + ReplacementContext RC; + std::string Str; + llvm::raw_string_ostream SStr(Str); + RC.printInst(Input_.Mapping.LHS, SStr, false); + + Inst *Ante = IC.getConst(llvm::APInt(1, true)); + for (auto PC : Input_.PCs ) { + // Inst *Eq = IC.getInst(Inst::Eq, 1, {PC.LHS, PC.RHS}); + // Ante = IC.getInst(Inst::And, 1, {Ante, Eq}); + Ante = Builder(PC.LHS, IC).Eq(PC.RHS).And(Ante)(); + } + + RC.printInst(Ante, SStr, false); + SStr.flush(); + +// llvm::errs() << Str << "\n"; + +// auto Str = Input_.getString(false); + if (DNR.find(Str) != DNR.end()) { + return; + } else { + DNR.insert(Str); + } + + std::set Insts; + collectInsts(Input_.Mapping.LHS, Insts); + collectInsts(Input_.Mapping.RHS, Insts); + +// for (auto &&PC : Input_.PCs) { +// collectInsts(PC.LHS, Insts); +// collectInsts(PC.RHS, Insts); +// } + +// for (auto &&BPC : Input_.BPCs) { +// collectInsts(BPC.PC.LHS, Insts); +// collectInsts(BPC.PC.RHS, Insts); +// } + + if (Insts.size() <= 1) { + return; // Base case + } + + // Remove at least one instruction and call recursively for valid opts + for (auto I : Insts) { + ParsedReplacement Input = Input_; + + if (!safeToRemove(I, Input)) { + continue; + } + + Eliminate(Input, I); + + if (VerifyInput(Input)) { + Results.push_back(Input); + ReduceRec(Input, Results); + } else { + if (DebugLevel >= 2) { + llvm::outs() << "Invalid attempt.\n"; + Input.print(llvm::outs(), true); + } + } + } +} + + +} diff --git a/lib/Infer/ConstantSynthesis.cpp b/lib/Infer/ConstantSynthesis.cpp index 11c82bcfa..bfd1ae831 100644 --- a/lib/Infer/ConstantSynthesis.cpp +++ b/lib/Infer/ConstantSynthesis.cpp @@ -231,6 +231,8 @@ Inst *getConstConstraint(Inst::Kind K, unsigned OpNum, Inst *C, IC.getInst(Inst::Ne, 1, { IC.getConst(llvm::APInt::getSignedMinValue(C->Width)), C }) }); + case Inst::LogB: + case Inst::Freeze: case Inst::Eq: case Inst::Ne: case Inst::SAddO: @@ -242,7 +244,6 @@ Inst *getConstConstraint(Inst::Kind K, unsigned OpNum, Inst *C, case Inst::Select: // handled elsewhere: 2nd and 3rd arguments can't be same constant // no constraint return IC.getConst(llvm::APInt(1, true)); - default: llvm::report_fatal_error("unmatched: " + (std::string)Inst::getKindName(K)); } diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp new file mode 100644 index 000000000..52fc0f873 --- /dev/null +++ b/lib/Infer/SynthUtils.cpp @@ -0,0 +1,174 @@ +#include "souper/Infer/SynthUtils.h" + +namespace souper { + +Inst *Replace(Inst *R, InstContext &IC, std::map &M) { + std::map BlockCache; + std::map ConstMap; + return getInstCopy(R, IC, M, BlockCache, &ConstMap, false); +} + +ParsedReplacement Replace(ParsedReplacement I, InstContext &IC, + std::map &M) { + std::map BlockCache; + std::map ConstMap; + + I.Mapping.LHS = getInstCopy(I.Mapping.LHS, IC, M, BlockCache, &ConstMap, false); + I.Mapping.RHS = getInstCopy(I.Mapping.RHS, IC, M, BlockCache, &ConstMap, false); + + for (auto &PC : I.PCs) { + PC.LHS = getInstCopy(PC.LHS, IC, M, BlockCache, &ConstMap, false, false); + PC.RHS = getInstCopy(PC.RHS, IC, M, BlockCache, &ConstMap, false, false); + } + + return I; +} + +Inst *Clone(Inst *R, InstContext &IC) { + std::map BlockCache; + std::map ConstMap; + std::map InstCache; + return getInstCopy(R, IC, InstCache, BlockCache, &ConstMap, true, false); +} + +InstMapping Clone(InstMapping In, InstContext &IC) { + std::map BlockCache; + std::map ConstMap; + std::map InstCache; + InstMapping Out; + Out.LHS = getInstCopy(In.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); + Out.RHS = getInstCopy(In.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); + return Out; +} + +ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { + std::map BlockCache; + std::map ConstMap; + std::map InstCache; + std::vector RHSVars; + findVars(In.Mapping.RHS, RHSVars); + In.Mapping.LHS = getInstCopy(In.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, true, false); + In.Mapping.RHS = getInstCopy(In.Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, true, false); + for (auto &PC : In.PCs) { + PC.LHS = getInstCopy(PC.LHS, IC, InstCache, BlockCache, &ConstMap, false, false); + PC.RHS = getInstCopy(PC.RHS, IC, InstCache, BlockCache, &ConstMap, false, false); + } + + for (auto &V : RHSVars) { + if (V->SymOneOf) { + InstCache[V->SymOneOf]->SymKnownOnes = InstCache[V]; + } + if (V->SymZeroOf) { + InstCache[V->SymZeroOf]->SymKnownZeros = InstCache[V]; + } + } + + return In; +} + +//std::map ConstantSynthesis + +// Also Synthesizes given constants +// Returns clone if verified, nullptrs if not +ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { + Input = Clone(Input, IC); + std::set ConstSet; + souper::getConstants(Input.Mapping.RHS, ConstSet); + if (!ConstSet.empty()) { + std::map ResultConstMap; + ConstantSynthesis CS; + auto SMTSolver = S->getSMTLIBSolver(); + + auto EC = CS.synthesize(SMTSolver, Input.BPCs, Input.PCs, + Input.Mapping, ConstSet, + ResultConstMap, IC, /*MaxTries=*/30, 10, + /*AvoidNops=*/true); + if (!ResultConstMap.empty()) { + std::map InstCache; + std::map BlockCache; + auto LHSCopy = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ResultConstMap, true); + auto RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, BlockCache, &ResultConstMap, true); + Input.Mapping = InstMapping(LHSCopy, RHS); + for (auto &PC : Input.PCs) { + PC.LHS = getInstCopy(PC.LHS, IC, InstCache, BlockCache, &ResultConstMap, true); + PC.RHS = getInstCopy(PC.RHS, IC, InstCache, BlockCache, &ResultConstMap, true); + } + return Input; + } else { + if (DebugLevel > 2) { + llvm::errs() << "Constant Synthesis ((no Dataflow Preconditions)) failed. \n"; + } + } + Input.Mapping = InstMapping(nullptr, nullptr); + return Input; + } + std::vector> Models; + bool IsValid; + if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, IsValid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + if (IsValid) { + return Input; + } else { + Input.Mapping = InstMapping(nullptr, nullptr); + return Input; + // TODO: Better failure indication? + } +} + +std::map findOneConstSet(ParsedReplacement Input, const std::set &SymCS, InstContext &IC, Solver *S) { + + std::map InstCache; + + std::set SynthCS; + + size_t cid = 0; + for (auto C : SymCS) { + InstCache[C] = IC.createSynthesisConstant(C->Width, cid++); + SynthCS.insert(InstCache[C]); + } + Input = Replace(Input, IC, InstCache); + + std::map ResultConstMap; + ConstantSynthesis CS; + auto EC = CS.synthesize(S->getSMTLIBSolver(), Input.BPCs, Input.PCs, + Input.Mapping, SynthCS, + ResultConstMap, IC, /*MaxTries=*/30, 10, + /*AvoidNops=*/true); + + std::map Result; + if (!ResultConstMap.empty()) { + for (auto C : SymCS) { + Result[C] = ResultConstMap[InstCache[C]]; + } + } + + return Result; + +} + +std::vector> findValidConsts(ParsedReplacement Input, const std::set &Insts, InstContext &IC, Solver *S, size_t MaxCount = 1) { + + // FIXME: Ignores Count + std::vector> Results; + + Inst *T = IC.getConst(llvm::APInt(1, 1)); // true + Inst *F = IC.getConst(llvm::APInt(1, 0)); // false + + while (MaxCount-- ) { + auto &&Result = findOneConstSet(Input, Insts, IC, S); + if (Result.empty()) { + break; + } else { + Results.push_back(Result); + for (auto I : Result) { + Input.PCs.push_back({Builder(I.first, IC).Ne(I.second)(), T}); + } + } + } + + return Results; +} + + +} diff --git a/tools/generalize.cpp b/tools/generalize.cpp index d970b81a1..cd2f05552 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -11,6 +11,7 @@ #include "souper/Infer/SynthUtils.h" #include "souper/Inst/InstGraph.h" #include "souper/Parser/Parser.h" +#include "souper/Generalize/Reducer.h" #include "souper/Tool/GetSolver.h" #include "souper/Util/DfaUtils.h" @@ -250,46 +251,93 @@ void ReplaceConstsSimple(InstContext &IC, Solver *S, // expr or a kb expr } +template +bool All(const C &c, F f) { + for (auto &&m : c) { + if (!f(m)) { + return false; + } + } + return true; +} + + + bool InferPreconditionsAndVerify(ParsedReplacement Input, CandidateMap &Results, - const std::vector &SymCS, InstContext &IC, Solver *S) { + std::vector> &SymCS, InstContext &IC, Solver *S) { + + auto SOLVE = [&]() { + auto Result = Verify(Input, IC, S); + if (Result.Mapping.LHS && Result.Mapping.RHS) { + CandidateReplacement Rep(nullptr, Result.Mapping); + Rep.PCs = Result.PCs; + Results.push_back(Rep); + return true; + } else { + return false; + } + }; - auto Result = Verify(Input, IC, S); - if (Result.Mapping.LHS && Result.Mapping.RHS) { - CandidateReplacement Rep(nullptr, Result.Mapping); - Rep.PCs = Result.PCs; - Results.push_back(Rep); - return true; + if (SOLVE()) return true; + + std::vector Insts; + findVars(Input.Mapping.LHS, Insts); + + std::set ModelInsts; + for (auto I : SymCS) { + ModelInsts.insert(I.first); + } + + + + std::vector> Inputs; + Inputs.push_back({}); + for (auto &&P : SymCS) { + Inputs.back()[P.first] = P.second; } - if (SymbolizeSimpleDF) { - for (auto &&C : SymCS) { - C->PowOfTwo = true; - - // Abstract away the following logic - auto Result = Verify(Input, IC, S); - if (Result.Mapping.LHS && Result.Mapping.RHS) { - CandidateReplacement Rep(nullptr, Result.Mapping); - Rep.PCs = Result.PCs; - Results.push_back(Rep); - return true; - } - - C->PowOfTwo = false; - -// C->NonZero = true; -// CheckAndSave(); -// C->NonZero = false; -// C->NonNegative = true; -// CheckAndSave(); -// C->NonNegative = false; -// C->Negative = true; -// CheckAndSave(); -// C->Negative = false; - } + // TODO Is this worth using? + bool SynthNewConsts = false; + if (SynthNewConsts) { + for (auto &&I : findValidConsts(Input, ModelInsts, IC, S, 5)) { + Inputs.push_back(I); + } + } + + std::map> CVals; + + for (auto &&I : Inputs) { + for (auto &&P: I) { + CVals[P.first].push_back(P.second); + } + } + + if (Inputs.empty()) { + if (DebugLevel > 4) + llvm::errs() << "Could not find valid concrete constants.\n"; + return false; + } + + if (SymbolizeSimpleDF) { + +#define DF(Fact, Check) \ +if (All(CVals[C], [](auto Val) { return Check;})) { \ +C->Fact = true; if (SOLVE()) return true; C->Fact = false;}; + + for (auto &&P : SymCS) { + auto C = P.first; + DF(PowOfTwo, Val.isPowerOf2()) + DF(NonZero, Val != 0); + DF(NonNegative, Val.uge(0)); + DF(Negative, Val.slt(0)); } - // TODO Is there a better way of doing this? - // TODO Other kinds of preconditions? +#undef DF + } + if (SymbolizeKBDF) { +// Reducer R(IC, S); + + } return false; } @@ -312,22 +360,23 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In return; } - std::vector SymCS; + std::vector> SymCS; std::vector Vars; std::vector SymDFVars; findVars(Input.Mapping.LHS, Vars); - + std::map InstCache; ValueCache VC; // Create a symbolic const for each LHS const for (size_t i = 0; i < LHSConsts.size(); ++i) { auto C = IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i)); - SymCS.push_back(C); + SymCS.push_back({C, LHSConsts[i]->Val}); InstCache[LHSConsts[i]] = C; VC[C] = EvalValue(LHSConsts[i]->Val); } std::vector Components; + // if (!SymbolizeConstSynthesis) { // std::set ConcreteConsts; // for deduplication @@ -365,13 +414,11 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In // Put custom components here if (SymbolizeConstant) { for (auto C : SymCS) { - // // Minus One - Components.push_back(IC.getInst(Inst::Sub, - C->Width, {C, IC.getConst(llvm::APInt(C->Width, 1))})); - // Flip bits - Components.push_back(IC.getInst(Inst::Xor, - C->Width, {C, IC.getConst(llvm::APInt(C->Width, -1))})); - + // Minus One + Components.push_back(Builder(C.first, IC).Sub(1)()); + // Flip bits + Components.push_back(Builder(C.first, IC).Xor(-1)()); + // Custom test // auto M1 = IC.getConst(llvm::APInt(C->Width, -1)); // auto Test = Builder(C, IC).Add(M1).Xor(M1).And(M1); @@ -383,7 +430,7 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In } for (auto SymC : SymCS) { - Components.push_back(SymC); + Components.push_back(SymC.first); } // TODO Derive relations between LHSConsts and use them as preconditions @@ -637,531 +684,6 @@ void collectInsts(Inst *I, std::set &Results) { } } -class Reducer { -public: - Reducer(InstContext &IC_, Solver *S_) : IC(IC_), S(S_), varnum(0), numSolverCalls(0) {} - - ParsedReplacement ReduceGreedy(ParsedReplacement Input) { - std::set Insts; - collectInsts(Input.Mapping.LHS, Insts); - // TODO: topological sort, to reduce number of solver calls - // Try to remove one instruction at a time - int failcount = 0; - std::set Visited; - do { - auto It = Insts.begin(); - auto I = *It; - Insts.erase(It); - if (Visited.find(I) != Visited.end()) { - continue; - } - Visited.insert(I); - if (!safeToRemove(I, Input)) { - continue; - } - auto Copy = Input; - Eliminate(Input, I); - - if (!Verify(Input)) { - Input = Copy; - failcount++; - if (failcount >= Insts.size()) { - break; - } - continue; - } - Insts.clear(); - collectInsts(Input.Mapping.LHS, Insts); - } while (!Insts.empty()); - return Input; - } - - // Eventually replace the functions in Preconditions{.h/.cpp} with this. - // Does not produce exhaustive result. TODO Have an option to wrap in a cegis loop. - std::map inferKBPrecondition(ParsedReplacement Input, std::vector Targets) { - assert(Targets.size() == 1 && "Multiple targets unimplemented"); - std::map Result; - std::set SymConsts; - std::map InstCache; - std::map BlockCache; - std::map ConstMap; - size_t ConstID = 0; - for (auto V : Targets) { - auto C = IC.createSynthesisConstant(V->Width, ConstID++); - InstCache[V] = C; - SymConsts.insert(C); - } - auto Copy = Input; - InstMapping Rep; - Rep.LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, false, false); - Rep.RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, false, false); - - ConstantSynthesis CS; - -// llvm::errs() << "Constant synthesis problem: \n"; -// Input.print(llvm::errs(), true); -// llvm::errs() << "....end.... \n"; - - if (auto EC = CS.synthesize(S->getSMTLIBSolver(), Input.BPCs, Input.PCs, - Rep, SymConsts, ConstMap, IC, 30, 60, false)) { - llvm::errs() << "Constant Synthesis internal error : " << EC.message(); - } - - if (ConstMap.empty()) { - if (DebugLevel > 3) { - llvm::errs() << "Constant Synthesis failed, moving on.\n"; - } - Input = Copy; -// failcount++; -// if (failcount >= Insts.size()) { -// break; -// } - } else { - InstCache.clear(); - - // TODO: Generalize before allowing multiple targets - auto NewVar = Targets[0]; - auto C = InstCache[NewVar]; - - InstCache[C] = NewVar; - - NewVar->KnownOnes = ConstMap[C]; - NewVar->KnownZeros = ~ConstMap[C]; - - // Give up if can't be weakened 'too much' - const size_t WeakeningThreshold = NewVar->Width/2; - size_t BitsWeakened = 0; - - for (size_t i = 0; i < NewVar->Width; ++i) { - auto SaveZero = NewVar->KnownZeros; - auto SaveOne = NewVar->KnownOnes; - - NewVar->KnownZeros.clearBit(i); - NewVar->KnownOnes.clearBit(i); - - if (!Verify(Input)) { - NewVar->KnownZeros = SaveZero; - NewVar->KnownOnes = SaveOne; - } else { - BitsWeakened++; - } - } - if (BitsWeakened < WeakeningThreshold) { - Input = Copy; -// failcount++; -// if (failcount >= Insts.size()) { -// break; -// } - } - - } - - // CONT FROM HERE. DUMP RESULTS INTO MAP - - return Result; - } - - ParsedReplacement ReduceGreedyKBIFY(ParsedReplacement Input) { - std::set Insts; - collectInsts(Input.Mapping.LHS, Insts); - // TODO: topological sort, to reduce number of solver calls - // Try to remove one instruction at a time - size_t failcount = 0; - std::set Visited; - do { - auto It = Insts.begin(); - auto I = *It; - Insts.erase(It); - if (Visited.find(I) != Visited.end()) { - continue; - } - Visited.insert(I); - if (!safeToRemove(I, Input) || I->Width == 1 /*1 bit KB doesn't make sense*/) { - continue; - } - auto Copy = Input; - auto NewVar = Eliminate(Input, I); - - // Input won't verify because ReduceGreedy has been called before this. - - // Try to replace NewVar with a symbolic constant and do constant synthesis. - Inst *C = IC.createSynthesisConstant(NewVar->Width, 0); - std::map InstCache = {{NewVar, C}}; - std::map BlockCache; - std::map ConstMap; - - InstMapping Rep; - Rep.LHS = getInstCopy(Input.Mapping.LHS, IC, InstCache, BlockCache, &ConstMap, false, false); - Rep.RHS = getInstCopy(Input.Mapping.RHS, IC, InstCache, BlockCache, &ConstMap, false, false); - - ConstantSynthesis CS; - std::set ConstSet{C}; - -// llvm::errs() << "Constant synthesis problem: \n"; -// Input.print(llvm::errs(), true); -// llvm::errs() << "....end.... \n"; - - if (auto EC = CS.synthesize(S->getSMTLIBSolver(), Input.BPCs, Input.PCs, - Rep, ConstSet, ConstMap, IC, 30, 60, false)) { - llvm::errs() << "Constant Synthesis internal error : " << EC.message(); - } - - if (ConstMap.empty()) { - if (DebugLevel > 3) { - llvm::errs() << "Constant Synthesis failed, moving on.\n"; - } - Input = Copy; - failcount++; - if (failcount >= Insts.size()) { - break; - } - } else { - InstCache.clear(); - InstCache[C] = NewVar; - - NewVar->KnownOnes = ConstMap[C]; - NewVar->KnownZeros = ~ConstMap[C]; - - // Give up if can't be weakened 'too much' - const size_t WeakeningThreshold = NewVar->Width/2; - size_t BitsWeakened = 0; - - for (size_t i = 0; i < NewVar->Width; ++i) { - auto SaveZero = NewVar->KnownZeros; - auto SaveOne = NewVar->KnownOnes; - - NewVar->KnownZeros.clearBit(i); - NewVar->KnownOnes.clearBit(i); - - if (!Verify(Input)) { - NewVar->KnownZeros = SaveZero; - NewVar->KnownOnes = SaveOne; - } else { - BitsWeakened++; - } - } - if (BitsWeakened < WeakeningThreshold) { - Input = Copy; - failcount++; - if (failcount >= Insts.size()) { - break; - } - } - - } - Insts.clear(); - collectInsts(Input.Mapping.LHS, Insts); - // ^ Can this be skipped? - } while (!Insts.empty()); - return Input; - } - - ParsedReplacement ReduceRedundantPhis(ParsedReplacement Input) { - std::set Insts; - std::vector Phis; - - auto Collect = [&] () { - Insts.clear(); - Phis.clear(); - collectInsts(Input.Mapping.LHS, Insts); - collectInsts(Input.Mapping.RHS, Insts); - for (auto &&I : Insts) { - if (I->K == Inst::Phi) { - Phis.push_back(I); - } - } - }; - Collect(); - - size_t NumPhis = Phis.size(); - while (NumPhis --) { - std::map ICache; - for (auto &&I : Phis) { - if (I->Ops.size() == 1) { - ICache[I] = I->Ops[0]; - } else if (I->Ops.size() > 1) { - bool allEq = true; - for (size_t i = 0; i < I->Ops.size(); ++i) { - if (I->Ops[i] != I->Ops[0]) { - allEq = false; - break; - } - } - if (allEq) { - ICache[I] = I->Ops[0]; - } - } - } - - Input.Mapping.LHS = Replace(Input.Mapping.LHS, IC, ICache); - Input.Mapping.RHS = Replace(Input.Mapping.RHS, IC, ICache); - for (auto &PC : Input.PCs) { - PC.LHS = Replace(PC.LHS, IC, ICache); - PC.RHS = Replace(PC.RHS, IC, ICache); - } - if (NumPhis) { - Collect(); - } - } - return Input; - } - - // Assumes Input is valid - ParsedReplacement ReducePCs(ParsedReplacement Input) { - - std::set UnnecessaryPCs; - for (size_t i =0; i < Input.PCs.size(); ++i) { - std::vector PCsExceptOne; - for (size_t j = 0; j < Input.PCs.size(); ++j) { - if (i != j) { - PCsExceptOne.push_back(Input.PCs[i]); - } - } - - std::vector> Models; - bool Valid; - if (std::error_code EC = S->isValid(IC, Input.BPCs, PCsExceptOne, Input.Mapping, Valid, &Models)) { - llvm::errs() << EC.message() << '\n'; - } - if (Valid) { - UnnecessaryPCs.insert(i); - } - } - - std::vector NecessaryPCs; - for (size_t i =0; i < Input.PCs.size(); ++i) { - if (UnnecessaryPCs.find(i) == UnnecessaryPCs.end()) { - NecessaryPCs.push_back(Input.PCs[i]); - } - } - - auto Result = Input; - Result.PCs = NecessaryPCs; - return Result; - } - - // Assumes Input is valid - ParsedReplacement WeakenKB(ParsedReplacement Input) { - std::vector Vars; - findVars(Input.Mapping.LHS, Vars); - for (auto &&V : Vars) { - auto OriZero = V->KnownZeros; - auto OriOne = V->KnownOnes; - if (OriZero == 0 && OriOne == 0) { - continue; // this var doesn't have a knownbits condition - } - if (OriZero.getBitWidth() != V->Width || OriOne.getBitWidth() != V->Width) { - continue; // this var doesn't have a well formed knownbits condition - } - - // Try to remove KB - V->KnownOnes = llvm::APInt(V->Width, 0); - V->KnownZeros = llvm::APInt(V->Width, 0); - if (Verify(Input)) { - continue; // Removed KB from this var - } - V->KnownOnes = OriOne; - V->KnownZeros = OriZero; - - // Try resetting bitwise KB - - for (size_t i = 0; i < V->Width; ++i) { - auto Ones = V->KnownOnes; - if (Ones[i]) { - V->KnownOnes.setBitVal(i, false); - if (!Verify(Input)) { - V->KnownOnes = Ones; - } - } - auto Zeros = V->KnownZeros; - if (Zeros[i]) { - V->KnownZeros.setBitVal(i, false); - if (!Verify(Input)) { - V->KnownZeros = Zeros; - } - } - } - } - return Input; - } - - // Assumes Input is valid - ParsedReplacement WeakenCR(ParsedReplacement Input) { - // Just try to remove CR for now. - std::vector Vars; - findVars(Input.Mapping.LHS, Vars); - - for (auto &&V : Vars) { - auto Ori = V->Range; - if (V->Range.isFullSet()) { - continue; - } - V->Range = llvm::ConstantRange(V->Width, true); - if (!Verify(Input)) { - V->Range = Ori; - } - // TODO: Try Widening Range - } - - return Input; - } - - // Assumes Input is valid - ParsedReplacement WeakenDB(ParsedReplacement Input) { - auto Ori = Input.Mapping.LHS->DemandedBits; - auto Width = Input.Mapping.LHS->Width; - if (Ori.getBitWidth() != Width || Ori.isAllOnesValue()) { - return Input; - } - // Try replacing with all ones. - Input.Mapping.LHS->DemandedBits.setAllBits(); - if (Verify(Input)) { - return Input; - } - Input.Mapping.LHS->DemandedBits = Ori; - - for (size_t i = 0; i < Width; ++i) { - auto Last = Input.Mapping.LHS->DemandedBits; - if (!Last[i]) { - Input.Mapping.LHS->DemandedBits.setBitVal(i, true); - if (!Verify(Input)) { - Input.Mapping.LHS->DemandedBits = Last; - } - } - } - - return Input; - } - - bool Verify(ParsedReplacement &Input) { - std::vector> Models; - bool Valid; - if (std::error_code EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, Valid, &Models)) { - llvm::errs() << EC.message() << '\n'; - } - numSolverCalls++; - return Valid; - } - - bool safeToRemove(Inst *I, ParsedReplacement &Input) { - if (I == Input.Mapping.LHS || I == Input.Mapping.RHS || I->K == Inst::Var || I->K == Inst::Const || - I->K == Inst::UMulWithOverflow || I->K == Inst::UMulO || - I->K == Inst::SMulWithOverflow || I->K == Inst::SMulO || - I->K == Inst::UAddWithOverflow || I->K == Inst::UAddO || - I->K == Inst::SAddWithOverflow || I->K == Inst::SAddO || - I->K == Inst::USubWithOverflow || I->K == Inst::USubO || - I->K == Inst::SSubWithOverflow || I->K == Inst::SSubO) { - return false; - } - return true; - } - - Inst *Eliminate(ParsedReplacement &Input, Inst *I) { - // Try to replace I with a new Var. - Inst *NewVar = IC.createVar(I->Width, "newvar" + std::to_string(varnum++)); - - std::map ICache; - ICache[I] = NewVar; - - std::map BCache; - std::map CMap; - - ParsedReplacement NewInst = Input; - - Input.Mapping.LHS = getInstCopy(Input.Mapping.LHS, IC, ICache, - BCache, &CMap, false); - - Input.Mapping.RHS = getInstCopy(Input.Mapping.RHS, IC, ICache, - BCache, &CMap, false); - - for (auto &M : Input.PCs) { - M.LHS = getInstCopy(M.LHS, IC, ICache, BCache, &CMap, false); - M.RHS = getInstCopy(M.RHS, IC, ICache, BCache, &CMap, false); - } - for (auto &BPC : Input.BPCs) { - BPC.PC.LHS = getInstCopy(BPC.PC.LHS, IC, ICache, BCache, &CMap, false); - BPC.PC.RHS = getInstCopy(BPC.PC.RHS, IC, ICache, BCache, &CMap, false); - } - return NewVar; - } - - void ReduceRec(ParsedReplacement Input_, std::vector &Results) { - - // Try to remove subsets of instructions recursively, and store all valid results - ReplacementContext RC; - std::string Str; - llvm::raw_string_ostream SStr(Str); - RC.printInst(Input_.Mapping.LHS, SStr, false); - - Inst *Ante = IC.getConst(llvm::APInt(1, true)); - for (auto PC : Input_.PCs ) { - // Inst *Eq = IC.getInst(Inst::Eq, 1, {PC.LHS, PC.RHS}); - // Ante = IC.getInst(Inst::And, 1, {Ante, Eq}); - Ante = Builder(PC.LHS, IC).Eq(PC.RHS).And(Ante)(); - } - - RC.printInst(Ante, SStr, false); - SStr.flush(); - - // llvm::errs() << Str << "\n"; - - // auto Str = Input_.getString(false); - if (DNR.find(Str) != DNR.end()) { - return; - } else { - DNR.insert(Str); - } - - std::set Insts; - collectInsts(Input_.Mapping.LHS, Insts); - collectInsts(Input_.Mapping.RHS, Insts); - - // for (auto &&PC : Input_.PCs) { - // collectInsts(PC.LHS, Insts); - // collectInsts(PC.RHS, Insts); - // } - - // for (auto &&BPC : Input_.BPCs) { - // collectInsts(BPC.PC.LHS, Insts); - // collectInsts(BPC.PC.RHS, Insts); - // } - - if (Insts.size() <= 1) { - return; // Base case - } - - // Remove at least one instruction and call recursively for valid opts - for (auto I : Insts) { - ParsedReplacement Input = Input_; - - if (!safeToRemove(I, Input)) { - continue; - } - - Eliminate(Input, I); - - if (Verify(Input)) { - Results.push_back(Input); - ReduceRec(Input, Results); - } else { - if (DebugLevel >= 2) { - llvm::outs() << "Invalid attempt.\n"; - Input.print(llvm::outs(), true); - } - } - } - } - void Stats() { - llvm::outs() << "Solver Calls: " << numSolverCalls << "\n"; - } -private: - InstContext &IC; - Solver *S; - int varnum; - int numSolverCalls; - std::unordered_set DNR; -}; - std::vector ReduceAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input) { std::vector> Models; From 24ff6d98cc4e82576149d49c09732593dd4a1fd1 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 28 Jul 2022 15:28:43 -0600 Subject: [PATCH 078/165] foo --- tools/generalize.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index cd2f05552..c3788b986 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -68,15 +68,15 @@ static llvm::cl::opt SymbolizeNoDFP("symbolize-no-dataflow", static llvm::cl::opt SymbolizeSimpleDF("symbolize-simple-dataflow", llvm::cl::desc("Generate simple dataflow facts supported by LLVM."), - llvm::cl::init(false)); + llvm::cl::init(true)); static llvm::cl::opt SymbolizeKBDF("symbolize-infer-kb", llvm::cl::desc("Generate KB constraints for symbolic constants."), - llvm::cl::init(false)); + llvm::cl::init(true)); static llvm::cl::opt SymbolizeConstSynthesis("symbolize-constant-synthesis", llvm::cl::desc("Allow concrete constants in the generated code."), - llvm::cl::init(false)); + llvm::cl::init(true)); static llvm::cl::opt SymbolizeHackersDelight("symbolize-bit-hacks", llvm::cl::desc("Include bit hacks in the components."), @@ -449,6 +449,7 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, Target->Width); for (auto &&Guess : Guesses) { + llvm::errs() << "HERE.\n"; std::set ConstSet; souper::getConstants(Guess, ConstSet); if (!ConstSet.empty()) { @@ -546,10 +547,10 @@ void SymbolizeAndGeneralize(InstContext &IC, CandidateMap Results; - // One at a time - for (auto LHSConst : LHSConsts) { - SymbolizeAndGeneralizeImpl(IC, S, Input, {LHSConst}, RHSConsts, Results); - } +// // One at a time +// for (auto LHSConst : LHSConsts) { +// SymbolizeAndGeneralizeImpl(IC, S, Input, {LHSConst}, RHSConsts, Results); +// } // All subsets? // TODO: Is it possible to encode this logically. @@ -561,6 +562,11 @@ void SymbolizeAndGeneralize(InstContext &IC, Input.print(llvm::outs(), true); llvm::outs() << "\n;Results:\n"; + // TODO : Improve sorting. + // Here are some ideas + // Prioritize results with more symbolic constants + // If same number of symbolic constants - prefer lower number of runtime instructions + auto cmp = [](const std::string &a, const std::string &b) { if (a.length() < b.length()) { return true; @@ -580,7 +586,7 @@ void SymbolizeAndGeneralize(InstContext &IC, int n = 5; for (auto &&Str : ResultStrs) { - if (!n--) break; +// if (!n--) break; llvm::outs() << Str << "\n"; } } From 45b50af6e9916a02d536b520c2d613bfa151d4e6 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 29 Jul 2022 21:43:01 -0600 Subject: [PATCH 079/165] foo --- tools/generalize.cpp | 53 +++++--------------------------------------- 1 file changed, 6 insertions(+), 47 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index c3788b986..cfeb5fdb7 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -449,12 +449,11 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, Target->Width); for (auto &&Guess : Guesses) { - llvm::errs() << "HERE.\n"; std::set ConstSet; souper::getConstants(Guess, ConstSet); if (!ConstSet.empty()) { if (SymbolizeConstSynthesis) { - Candidates.back().push_back(Guess); + Candidates.back().push_back(Guess); } } else { Candidates.back().push_back(Guess); @@ -472,64 +471,24 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In for (auto &&Comb : Combinations) { int SymExprCount = 0; - auto InstCacheCopy = InstCache; + auto InstCacheRHS = InstCache; for (int i = 0; i < RHSConsts.size(); ++i) { - InstCacheCopy[RHSConsts[i]] = Candidates[i][Comb[i]]; + InstCacheRHS[RHSConsts[i]] = Candidates[i][Comb[i]]; if (Candidates[i][Comb[i]]->K != Inst::Var) { Candidates[i][Comb[i]]->Name = std::string("constexpr_") + std::to_string(SymExprCount++); } } - auto LHS = Replace(Input.Mapping.LHS, IC, InstCacheCopy); - auto RHS = Replace(Input.Mapping.RHS, IC, InstCacheCopy); + auto LHS = Replace(Input.Mapping.LHS, IC, InstCache); + auto RHS = Replace(Input.Mapping.RHS, IC, InstCacheRHS); InstMapping Mapping(LHS, RHS); auto Copy = Input; Copy.Mapping = Mapping; bool IsValid = false; - - auto CheckAndSave = [&] () { - auto Result = Verify(Copy, IC, S); - - if (Result.Mapping.LHS && Result.Mapping.RHS) { - CandidateReplacement Rep(nullptr, Result.Mapping); - Rep.PCs = Result.PCs; - Results.push_back(Rep); - IsValid = true; - } else { - IsValid = false; - } - }; + static int n = 0; InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); - -// CheckAndSave(); -// -// // TODO Make preconditions consistent with inputs -// if (SymbolizeSimpleDF) { -// for (auto &&C : SymCS) { -// if (!IsValid) { -// C->PowOfTwo = true; -// CheckAndSave(); -// C->PowOfTwo = false; -// } -// // if (!IsValid) { -// // C->NonZero = true; -// // CheckAndSave(); -// // C->NonZero = false; -// // } -// // if (!IsValid) { -// // C->NonNegative = true; -// // CheckAndSave(); -// // C->NonNegative = false; -// // } -// // if (!IsValid) { -// // C->Negative = true; -// // CheckAndSave(); -// // C->Negative = false; -// // } -// } -// } } } From 1b79eaaad5f305290c58a35b27cdb12a5e9b38ea Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 29 Jul 2022 23:07:30 -0600 Subject: [PATCH 080/165] foo --- tools/generalize.cpp | 72 ++++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index cfeb5fdb7..99ef86ed5 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -356,7 +356,7 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In CandidateMap &Results) { if (RHSConsts.empty()) { - // FIXME: Support generalizing LHS Consts too. + // Handled in another function return; } @@ -367,6 +367,7 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In std::map InstCache; ValueCache VC; + // Create a symbolic const for each LHS const for (size_t i = 0; i < LHSConsts.size(); ++i) { auto C = IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i)); @@ -433,13 +434,6 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In Components.push_back(SymC.first); } - // TODO Derive relations between LHSConsts and use them as preconditions - - // Must consider all targets at once - // Test phase before verification - // Is it possible to pre-generate the set of all possible constants? No. - // Some? definitely. - std::vector> Candidates; ConcreteInterpreter CI(VC); @@ -487,11 +481,47 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In Copy.Mapping = Mapping; bool IsValid = false; - static int n = 0; InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); } } +// This is a simpler version of +void SymbolizeAndGeneralizeOnlyLHS(InstContext &IC, + Solver *S, + ParsedReplacement Input, + const std::vector &LHSConsts, + CandidateMap &Results) { + if (LHSConsts.empty()) { + return; // What are we even doing here? + } + + std::vector> SymCS; + std::vector Vars; + std::vector SymDFVars; + findVars(Input.Mapping.LHS, Vars); + + std::map InstCache; + ValueCache VC; + + // Create a symbolic const for each LHS const + for (size_t i = 0; i < LHSConsts.size(); ++i) { + auto C = IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i)); + SymCS.push_back({C, LHSConsts[i]->Val}); + InstCache[LHSConsts[i]] = C; + VC[C] = EvalValue(LHSConsts[i]->Val); + } + + auto LHS = Replace(Input.Mapping.LHS, IC, InstCache); + auto RHS = Replace(Input.Mapping.RHS, IC, InstCache); + + InstMapping Mapping(LHS, RHS); + auto Copy = Input; + Copy.Mapping = Mapping; + bool IsValid = false; + + InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); +} + void SymbolizeAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input) { std::vector LHSConsts, RHSConsts; @@ -499,17 +529,16 @@ void SymbolizeAndGeneralize(InstContext &IC, findInsts(Input.Mapping.LHS, LHSConsts, Pred); findInsts(Input.Mapping.RHS, RHSConsts, Pred); - // if (RHSConsts.empty()) { - // return; - // // TODO: Possible to just generalize LHS consts with preconditions? - // } - CandidateMap Results; + + if (RHSConsts.empty()) { + return SymbolizeAndGeneralizeOnlyLHS(IC, S, Input, LHSConsts, Results); + } -// // One at a time -// for (auto LHSConst : LHSConsts) { -// SymbolizeAndGeneralizeImpl(IC, S, Input, {LHSConst}, RHSConsts, Results); -// } + // One at a time + for (auto LHSConst : LHSConsts) { + SymbolizeAndGeneralizeImpl(IC, S, Input, {LHSConst}, RHSConsts, Results); + } // All subsets? // TODO: Is it possible to encode this logically. @@ -779,6 +808,11 @@ int main(int argc, char **argv) { } } } - return 0; } + +// TODO List +// Derive relations between LHSConsts and use them as preconditions +// Test phase before verification +// Is it possible to pre-generate the set of all possible constants? No. +// Some? definitely. From 2abddb96a12719b2277b85ca2325d799ddb3ba17 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 1 Aug 2022 18:41:28 -0600 Subject: [PATCH 081/165] foo --- lib/Infer/SynthUtils.cpp | 4 ++-- tools/generalize.cpp | 13 ++++++++++++- tools/matcher-gen.cpp | 9 +++++++-- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index 52fc0f873..32dca93b4 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -1,4 +1,5 @@ #include "souper/Infer/SynthUtils.h" +#include "souper/Infer/Pruning.h" namespace souper { @@ -70,7 +71,7 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { // Also Synthesizes given constants // Returns clone if verified, nullptrs if not -ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { +ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { Input = Clone(Input, IC); std::set ConstSet; souper::getConstants(Input.Mapping.RHS, ConstSet); @@ -170,5 +171,4 @@ std::vector> findValidConsts(ParsedReplacement Inp return Results; } - } diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 99ef86ed5..dbf6ceb26 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -460,6 +460,13 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In Counts.push_back(Cand.size()); } +// SynthesisContext SC{IC, S->getSMTLIBSolver(), Input.Mapping.LHS, nullptr, Input.PCs, Input.BPCs, false, 10}; + auto LHS = Replace(Input.Mapping.LHS, IC, InstCache); +// std::vector NewVars; +// findVars(LHS, NewVars); + +// PruningManager Pr(SC, Vars, 0); + // Generate all combination of candidates std::vector> Combinations = GetCombinations(Counts); @@ -473,7 +480,6 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In } } - auto LHS = Replace(Input.Mapping.LHS, IC, InstCache); auto RHS = Replace(Input.Mapping.RHS, IC, InstCacheRHS); InstMapping Mapping(LHS, RHS); @@ -481,7 +487,12 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In Copy.Mapping = Mapping; bool IsValid = false; + //if (Pr.isInfeasible(RHS, 0)) { +// llvm::errs() << "PRUNED\n"; // Figure out why this never succeeds :( + //} else { + //llvm::errs() << "NP"; InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); + //} } } diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index c18b23c30..e303f7eea 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -281,11 +281,16 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { auto Str = Child->Val.toString(10, false); Out << "m_SpecificInt(" << Str << ")"; } else if (Child->K == Inst::Var) { - + if (Child->Name.starts_with("symconst")) { + Out << "m_Constant()"; + } else if (Child->Name.starts_with("constexpr")) { + llvm::errs() << "FOUND A CONSTEXPR\n"; + } else { // FIXME What about Symbolic constants? // How about matching const exprs? - Out << "m_Value(" << Syms[Child].back() << ")"; + Out << "m_Value(" << Syms[Child].back() << ")"; + } Syms[Child].pop_back(); } else { if (!GenLHSMatcher(Child, Out, Syms)) { From fd6705bb45851773949e2ac3d991712154bb8026 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 2 Aug 2022 16:10:02 -0600 Subject: [PATCH 082/165] foo --- tools/generalize.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index dbf6ceb26..ac2f6169c 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -505,7 +505,6 @@ void SymbolizeAndGeneralizeOnlyLHS(InstContext &IC, if (LHSConsts.empty()) { return; // What are we even doing here? } - std::vector> SymCS; std::vector Vars; std::vector SymDFVars; @@ -529,7 +528,7 @@ void SymbolizeAndGeneralizeOnlyLHS(InstContext &IC, auto Copy = Input; Copy.Mapping = Mapping; bool IsValid = false; - + InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); } @@ -543,20 +542,19 @@ void SymbolizeAndGeneralize(InstContext &IC, CandidateMap Results; if (RHSConsts.empty()) { - return SymbolizeAndGeneralizeOnlyLHS(IC, S, Input, LHSConsts, Results); - } - - // One at a time - for (auto LHSConst : LHSConsts) { - SymbolizeAndGeneralizeImpl(IC, S, Input, {LHSConst}, RHSConsts, Results); - } - - // All subsets? - // TODO: Is it possible to encode this logically. + SymbolizeAndGeneralizeOnlyLHS(IC, S, Input, LHSConsts, Results); + } else { + // One at a time + for (auto LHSConst : LHSConsts) { + SymbolizeAndGeneralizeImpl(IC, S, Input, {LHSConst}, RHSConsts, Results); + } - // All at once - SymbolizeAndGeneralizeImpl(IC, S, Input, LHSConsts, RHSConsts, Results); + // All subsets? + // TODO: Is it possible to encode this logically. + // All at once + SymbolizeAndGeneralizeImpl(IC, S, Input, LHSConsts, RHSConsts, Results); + } llvm::outs() << ";Input:\n"; Input.print(llvm::outs(), true); llvm::outs() << "\n;Results:\n"; From f34f0cfc9d2d53731e076ce5d0f96f91b7ad8409 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 4 Aug 2022 11:16:53 -0600 Subject: [PATCH 083/165] foo --- include/souper/Infer/SynthUtils.h | 4 +- tools/generalize.cpp | 101 ++++++++++++++++++++++-------- 2 files changed, 79 insertions(+), 26 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 8ed44c7a0..2447b5168 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -32,7 +32,9 @@ class Builder { return Builder(IC.getInst(Inst::K, L->Width, {L, R}), IC); \ } - BINOP(Add) BINOP(Sub) BINOP(And) BINOP(Xor) + BINOP(Add) BINOP(Sub) BINOP(Mul) + BINOP(And) BINOP(Xor) BINOP(Or) + BINOP(Shl) BINOP(LShr) #undef BINOP #define BINOPW(K) \ diff --git a/tools/generalize.cpp b/tools/generalize.cpp index ac2f6169c..4eefef03f 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -342,6 +342,31 @@ C->Fact = true; if (SOLVE()) return true; C->Fact = false;}; return false; } +std::vector InferPotentialRelations(const std::vector> &CMap, InstContext &IC) { + std::vector Results; + // Generate a set of pairwise relations + for (auto &&[XI, XC] : CMap) { + for (auto &&[YI, YC] : CMap) { + if (XI == YI) continue; + // Add C +// auto Diff = XC - YC; +// Results.push_back(Builder(XI, IC).Sub(Diff).Eq(YI)()); + // Mul C + if (XC.urem(YC) == 0) { + auto Fact = XC.udiv(YC); + Results.push_back(Builder(YI, IC).Mul(Fact).Eq(XI)()); + } + if (YC.urem(XC) == 0) { + auto Fact = YC.udiv(XC); + Results.push_back(Builder(XI, IC).Mul(Fact).Eq(YI)()); + } + + // TODO LT/GT + } + } + + return Results; +}; // FIXME Other interesting things to try // Symbolic KB in preconditions @@ -376,25 +401,9 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In VC[C] = EvalValue(LHSConsts[i]->Val); } - std::vector Components; - -// if (!SymbolizeConstSynthesis) { -// std::set ConcreteConsts; // for deduplication + auto Relations = InferPotentialRelations(SymCS, IC); -// for (auto C : LHSConsts) { -// ConcreteConsts.insert(C); -// ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 1))); -// ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, -1))); -// ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 2))); -// ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 31))); -// } -// for (auto C : RHSConsts) { -// ConcreteConsts.insert(C); -// } -// for (auto C : ConcreteConsts) { -// Components.push_back(C); -// } -// } + std::vector Components; // // Symbolic known bits // if (false) { @@ -414,11 +423,14 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In // Put custom components here if (SymbolizeConstant) { - for (auto C : SymCS) { + for (auto &&C : SymCS) { // Minus One - Components.push_back(Builder(C.first, IC).Sub(1)()); +// Components.push_back(Builder(C.first, IC).Sub(1)()); // Flip bits - Components.push_back(Builder(C.first, IC).Xor(-1)()); +// Components.push_back(Builder(C.first, IC).Xor(-1)()); + + // Shiftmask +// Components.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C.first->Width)).Shl(C.first)()); // Custom test // auto M1 = IC.getConst(llvm::APInt(C->Width, -1)); @@ -430,7 +442,27 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In } } - for (auto SymC : SymCS) { + std::set ConcreteConsts; // for deduplication + + if (!SymbolizeConstSynthesis) { + for (auto C : LHSConsts) { +// ConcreteConsts.insert(C); +// ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 1))); + ConcreteConsts.insert(IC.getConst(llvm::APInt::getAllOnesValue(C->Width))); + } +// for (auto C : RHSConsts) { +// ConcreteConsts.insert(C); +// } +// for (auto C : ConcreteConsts) { +// Components.push_back(C); +// } + } + + for (auto &&ConC : ConcreteConsts) { + Components.push_back(ConC); + } + + for (auto &&SymC : SymCS) { Components.push_back(SymC.first); } @@ -443,6 +475,11 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, Target->Width); for (auto &&Guess : Guesses) { + + if (ConcreteConsts.find(Guess) != ConcreteConsts.end()) { + continue; + } + std::set ConstSet; souper::getConstants(Guess, ConstSet); if (!ConstSet.empty()) { @@ -471,7 +508,7 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In std::vector> Combinations = GetCombinations(Counts); for (auto &&Comb : Combinations) { - int SymExprCount = 0; + static int SymExprCount = 0; auto InstCacheRHS = InstCache; for (int i = 0; i < RHSConsts.size(); ++i) { InstCacheRHS[RHSConsts[i]] = Candidates[i][Comb[i]]; @@ -491,7 +528,14 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In // llvm::errs() << "PRUNED\n"; // Figure out why this never succeeds :( //} else { //llvm::errs() << "NP"; - InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); + if (!InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S)) { + for (auto R : Relations) { + Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); + Copy.PCs.pop_back(); + } + } + //} } } @@ -529,7 +573,14 @@ void SymbolizeAndGeneralizeOnlyLHS(InstContext &IC, Copy.Mapping = Mapping; bool IsValid = false; - InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); + if (!InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S)) { + auto Relations = InferPotentialRelations(SymCS, IC); + for (auto R : Relations) { + Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); + Copy.PCs.pop_back(); + } + } } void SymbolizeAndGeneralize(InstContext &IC, From bbcae4deae0bfc0d17c6be2a604a89533e82deca Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 4 Aug 2022 15:23:25 -0600 Subject: [PATCH 084/165] foo --- include/souper/Infer/SynthUtils.h | 3 ++- lib/Infer/SynthUtils.cpp | 2 ++ tools/generalize.cpp | 37 +++++++++++++++++++++---------- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 2447b5168..ae6fec41b 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -42,7 +42,8 @@ class Builder { auto L = I; auto R = i(t, *this); \ return Builder(IC.getInst(Inst::K, 1, {L, R}), IC); \ } - BINOPW(Slt) BINOPW(Ult) BINOPW(Eq) BINOPW(Ne) + BINOPW(Slt) BINOPW(Ult) BINOPW(Sle) BINOPW(Ule) + BINOPW(Eq) BINOPW(Ne) #undef BINOPW private: diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index 32dca93b4..927a36cab 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -111,6 +111,8 @@ ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { if (IsValid) { return Input; } else { + static int C = 0; + llvm::errs() << "C " << C++ << '\n'; Input.Mapping = InstMapping(nullptr, nullptr); return Input; // TODO: Better failure indication? diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 4eefef03f..2cf12c246 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -52,6 +52,11 @@ static llvm::cl::opt SymbolizeConstant("symbolize", "(default=false)"), llvm::cl::init(false)); +static llvm::cl::opt FindConstantRelations("relational", + llvm::cl::desc("Find constant relations." + "(default=false)"), + llvm::cl::init(false)); + static llvm::cl::opt SymbolizeWidth("symbolize-width", llvm::cl::desc("Try to replace a concrete constant with a function of bitwidth." "(default=false)"), @@ -342,8 +347,13 @@ C->Fact = true; if (SOLVE()) return true; C->Fact = false;}; return false; } -std::vector InferPotentialRelations(const std::vector> &CMap, InstContext &IC) { +std::vector InferPotentialRelations( + const std::vector> &CMap, + InstContext &IC, const ParsedReplacement &Input) { std::vector Results; + if (!FindConstantRelations) { + return Results; + } // Generate a set of pairwise relations for (auto &&[XI, XC] : CMap) { for (auto &&[YI, YC] : CMap) { @@ -352,16 +362,24 @@ std::vector InferPotentialRelations(const std::vectorWidth == 1) { + // need both signed and unsigned? + // What about s/t/e/ versions? + if (XC.slt(YC)) Results.push_back(Builder(XI, IC).Slt(YI)()); + if (XC.ult(YC)) Results.push_back(Builder(XI, IC).Ult(YI)()); + if (YC.slt(XC)) Results.push_back(Builder(YI, IC).Slt(XI)()); + if (YC.ult(XC)) Results.push_back(Builder(YI, IC).Ult(XI)()); + } } } @@ -371,8 +389,6 @@ std::vector InferPotentialRelations(const std::vectorVal); } - auto Relations = InferPotentialRelations(SymCS, IC); - + auto Relations = InferPotentialRelations(SymCS, IC, Input); std::vector Components; // // Symbolic known bits @@ -522,7 +537,6 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In InstMapping Mapping(LHS, RHS); auto Copy = Input; Copy.Mapping = Mapping; - bool IsValid = false; //if (Pr.isInfeasible(RHS, 0)) { // llvm::errs() << "PRUNED\n"; // Figure out why this never succeeds :( @@ -571,10 +585,9 @@ void SymbolizeAndGeneralizeOnlyLHS(InstContext &IC, InstMapping Mapping(LHS, RHS); auto Copy = Input; Copy.Mapping = Mapping; - bool IsValid = false; if (!InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S)) { - auto Relations = InferPotentialRelations(SymCS, IC); + auto Relations = InferPotentialRelations(SymCS, IC, Input); for (auto R : Relations) { Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); @@ -604,7 +617,7 @@ void SymbolizeAndGeneralize(InstContext &IC, // TODO: Is it possible to encode this logically. // All at once - SymbolizeAndGeneralizeImpl(IC, S, Input, LHSConsts, RHSConsts, Results); +// SymbolizeAndGeneralizeImpl(IC, S, Input, LHSConsts, RHSConsts, Results); } llvm::outs() << ";Input:\n"; Input.print(llvm::outs(), true); From 18d2f509bb540513a94b1f5508af6214cf28a5c8 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 7 Sep 2022 12:55:29 -0600 Subject: [PATCH 085/165] foo --- include/souper/Infer/SynthUtils.h | 8 +++++++ lib/Infer/Pruning.cpp | 2 +- lib/Infer/SynthUtils.cpp | 21 +++++++++++++++++-- tools/generalize.cpp | 35 +++++++++++++++++++------------ utils/cache_to_dir.py | 2 +- 5 files changed, 51 insertions(+), 17 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index ae6fec41b..a381438af 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -46,6 +46,14 @@ class Builder { BINOPW(Eq) BINOPW(Ne) #undef BINOPW +#define UNOP(K) \ + Builder K() { \ + auto L = I; \ + return Builder(IC.getInst(Inst::K, L->Width, {L}), IC); \ + } + UNOP(LogB) +#undef UNOP + private: Inst *I = nullptr; InstContext &IC; diff --git a/lib/Infer/Pruning.cpp b/lib/Infer/Pruning.cpp index 3ccb455c7..e7b00165b 100644 --- a/lib/Infer/Pruning.cpp +++ b/lib/Infer/Pruning.cpp @@ -294,7 +294,7 @@ bool PruningManager::isInfeasible(souper::Inst *RHS, if (C.hasValue()) { auto Val = C.getValue(); if (StatsLevel > 2) - llvm::errs() << " LHS value = " << Val << "\n"; + llvm::errs() << " LHS value = " << Val <<" - " < 2) diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index 927a36cab..11c84d67a 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -71,7 +71,24 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { // Also Synthesizes given constants // Returns clone if verified, nullptrs if not -ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { +ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { + SynthesisContext SC{IC, S->getSMTLIBSolver(), Input.Mapping.LHS, nullptr, + Input.PCs,Input.BPCs, false, 15}; + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); + + // TODO figure out why prunning isn't working + +// PruningManager Pruner(SC, Vars, 5); + +// Input.print(llvm::errs(), true); + +// if (Pruner.isInfeasibleWithSolver(Input.Mapping.RHS, 5)) { +// llvm::errs() << "FOOOO\n"; +// } else { +// llvm::errs() << "BAAAR\n"; +// } + Input = Clone(Input, IC); std::set ConstSet; souper::getConstants(Input.Mapping.RHS, ConstSet); @@ -112,7 +129,7 @@ ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { return Input; } else { static int C = 0; - llvm::errs() << "C " << C++ << '\n'; +// llvm::errs() << "C " << C++ << '\n'; Input.Mapping = InstMapping(nullptr, nullptr); return Input; // TODO: Better failure indication? diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 2cf12c246..00f55ddcb 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -55,7 +55,7 @@ static llvm::cl::opt SymbolizeConstant("symbolize", static llvm::cl::opt FindConstantRelations("relational", llvm::cl::desc("Find constant relations." "(default=false)"), - llvm::cl::init(false)); + llvm::cl::init(true)); static llvm::cl::opt SymbolizeWidth("symbolize-width", llvm::cl::desc("Try to replace a concrete constant with a function of bitwidth." @@ -81,7 +81,7 @@ static llvm::cl::opt SymbolizeKBDF("symbolize-infer-kb", static llvm::cl::opt SymbolizeConstSynthesis("symbolize-constant-synthesis", llvm::cl::desc("Allow concrete constants in the generated code."), - llvm::cl::init(true)); + llvm::cl::init(false)); static llvm::cl::opt SymbolizeHackersDelight("symbolize-bit-hacks", llvm::cl::desc("Include bit hacks in the components."), @@ -109,7 +109,7 @@ static llvm::cl::opt MinimizeWidth("minimize-width", static cl::opt NumResults("generalization-num-results", cl::desc("Number of Generalization Results"), - cl::init(5)); + cl::init(1)); static cl::opt Everything("everything", cl::desc("Run everything, output one result."), @@ -436,9 +436,12 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In // } - // Put custom components here + // Put custom components here if (SymbolizeConstant) { for (auto &&C : SymCS) { + if (Everything) { + Components.push_back(Builder(C.first, IC).LogB()()); + } // Minus One // Components.push_back(Builder(C.first, IC).Sub(1)()); // Flip bits @@ -617,12 +620,13 @@ void SymbolizeAndGeneralize(InstContext &IC, // TODO: Is it possible to encode this logically. // All at once -// SymbolizeAndGeneralizeImpl(IC, S, Input, LHSConsts, RHSConsts, Results); + SymbolizeAndGeneralizeImpl(IC, S, Input, LHSConsts, RHSConsts, Results); + } + if (!Everything) { + llvm::outs() << ";Input:\n"; + Input.print(llvm::outs(), true); + llvm::outs() << "\n;Results:\n"; } - llvm::outs() << ";Input:\n"; - Input.print(llvm::outs(), true); - llvm::outs() << "\n;Results:\n"; - // TODO : Improve sorting. // Here are some ideas // Prioritize results with more symbolic constants @@ -646,9 +650,15 @@ void SymbolizeAndGeneralize(InstContext &IC, } int n = 5; - for (auto &&Str : ResultStrs) { + for (auto &&Str : ResultStrs) { // if (!n--) break; llvm::outs() << Str << "\n"; + if (Everything) { + break; + } + } + if (ResultStrs.empty()) { + Input.print(llvm::outs(), true); } } @@ -856,9 +866,8 @@ int main(int argc, char **argv) { Rep = ParseReplacements(IC, MB->getMemBufferRef().getBufferIdentifier(), Data.getBuffer(), ErrStr)[0]; } - - Rep.print(llvm::outs(), true); - + SymbolizeAndGeneralize(IC, S.get(), Rep); + continue; } if (FixIt) { // TODO: Verify that inputs are valid optimizations diff --git a/utils/cache_to_dir.py b/utils/cache_to_dir.py index 3c7fe858b..9ed7ea2c6 100644 --- a/utils/cache_to_dir.py +++ b/utils/cache_to_dir.py @@ -5,7 +5,7 @@ dir = sys.argv[1] for key in r.keys(): try: - val = r.hgetall(key)[b'rhs'] + val = r.hgetall(key)[b'result'] if val != b"": s = key.decode('utf-8') + val.decode('utf-8') f = open(dir + "/" + str(n) + '.opt', "w") From 5cd76823b451e74b7c57e60b785e1ff45d81929d Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 7 Sep 2022 23:19:05 -0600 Subject: [PATCH 086/165] foo --- tools/matcher-gen.cpp | 10 ++- tools/pass-generator/CMakeLists.txt | 2 + tools/pass-generator/src/template.cpp | 87 ++++++++++++++++++++++----- 3 files changed, 82 insertions(+), 17 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index e303f7eea..e84dc10d2 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -34,7 +34,7 @@ static llvm::cl::opt IgnorePCs("ignore-pcs", static llvm::cl::opt IgnoreDF("ignore-df", llvm::cl::desc("Ignore inputs with dataflow constraints." "(default=false)"), - llvm::cl::init(false)); + llvm::cl::init(true)); static const std::map MatchOps = { {Inst::Add, "m_c_Add("}, {Inst::Sub, "m_Sub("}, @@ -262,10 +262,15 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { llvm::errs() << "\nUnimplemented matcher:" << Inst::getKindName(I->K) << "\n"; return false; } + auto Op = It->second; Out << Op; + if (I->K == Inst::SExt || I->K == Inst::ZExt || I->K == Inst::Trunc) { + Out << I->Width << ", "; + } + if (PredNames.find(I->K) != PredNames.end()) { Out << Syms.Preds[I] << ", "; } @@ -538,6 +543,9 @@ int main(int argc, char **argv) { if (IgnorePCs && !Input.PCs.empty()) { continue; } + if (Input.Mapping.LHS == Input.Mapping.RHS) { + continue; + } if (IgnoreDF) { if (Input.Mapping.LHS->DemandedBits.getBitWidth() == Input.Mapping.LHS->Width && !Input.Mapping.LHS->DemandedBits.isAllOnesValue()) { diff --git a/tools/pass-generator/CMakeLists.txt b/tools/pass-generator/CMakeLists.txt index ddd3a8821..ebb7dd798 100644 --- a/tools/pass-generator/CMakeLists.txt +++ b/tools/pass-generator/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.7) project(souper-combine) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") + find_package(LLVM 14.0 REQUIRED CONFIG) list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") include(HandleLLVMOptions) diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 170248fa2..378303b40 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -1,11 +1,10 @@ -#define DEBUG_TYPE "" - #include "llvm/Pass.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/Constant.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" @@ -18,6 +17,7 @@ #include "llvm/Analysis/ValueTracking.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Support/Debug.h" +#define DEBUG_TYPE "" #include "llvm/Transforms/Utils/InstructionWorklist.h" #include "llvm/Support/KnownBits.h" @@ -80,16 +80,30 @@ struct phi_match { phi_match(Args... args) : Matchers{args...} {}; std::tuple Matchers; + bool match_nth(size_t n, Value *V) { + switch (n) { + case 0 : return std::get<0>(Matchers).match(V); + case 1 : return std::get<1>(Matchers).match(V); + // case 2 : return std::get<2>(Matchers).match(V); + // case 3 : return std::get<3>(Matchers).match(V); + // case 4 : return std::get<4>(Matchers).match(V); + default: return false; + // TODO Add more if needed. + } + } + bool check(const Value *V) { if (auto Phi = dyn_cast(V)) { - // Every Phi Argument has to match with at least one matcher for (size_t i =0; i < Phi->getNumOperands(); ++i) { - bool Matched = false; - std::apply([&](auto &&... args){ - ((Matched |= args.match(Phi->getOperand(i))), ...); - }, Matchers); - - if (!Matched) { + // bool Matched = false; + // std::apply([&](auto &&... args){ + // ((Matched |= args.match(Phi->getOperand(i))), ...); + // }, Matchers); + + // if (!Matched) { + // return false; + // } + if (!match_nth(i, Phi->getOperand(i))) { return false; } } @@ -130,6 +144,39 @@ inline bind_apint m_APInt(APInt &V) { return bind_apint(V); } // TODO: Match (arbitrarily) constrained APInts + +template struct CastClass_match_width { + size_t Width; + Op_t Op; + + CastClass_match_width(size_t W, const Op_t &OpMatch) : Width(W), Op(OpMatch) {} + + template bool match(OpTy *V) { + if (V->getType()->getScalarSizeInBits() != Width) { + return false; + } + if (auto *O = dyn_cast(V)) + return O->getOpcode() == Opcode && Op.match(O->getOperand(0)); + return false; + } +}; + +template +inline CastClass_match_width m_ZExt(size_t W, const OpTy &Op) { + return CastClass_match_width(W, Op); +} + +template +inline CastClass_match_width m_SExt(size_t W, const OpTy &Op) { + return CastClass_match_width(W, Op); +} + +template +inline CastClass_match_width m_Trunc(size_t W, const OpTy &Op) { + return CastClass_match_width(W, Op); +} + +// Utility functions to use in the DSL namespace util { Value *node(Instruction *I, const std::vector &Path) { Value *Current = I; @@ -235,8 +282,12 @@ struct SouperCombine : public FunctionPass { static char ID; SouperCombine() : FunctionPass(ID) { } + ~SouperCombine() { + St.print(); + } bool runOnFunction(Function &F) override { + DT = new DominatorTree(F); W.reserve(F.getInstructionCount()); for (auto &BB : F) { for (auto &&I : BB) { @@ -244,9 +295,9 @@ struct SouperCombine : public FunctionPass { } } IRBuilder Builder(F.getContext()); - llvm::errs() << "Before:\n" << F; + // llvm::errs() << "Before:\n" << F; auto r = run(Builder); - llvm::errs() << "After:\n" << F; + // llvm::errs() << "After:\n" << F; return r; } @@ -268,14 +319,17 @@ struct SouperCombine : public FunctionPass { Changed = processInst(I, Builder) || Changed; } - St.print(); - return Changed; } - Value *getReplacement(llvm::Instruction *I, IRBuilder *B) { + Value *getReplacement(llvm::Instruction *I, IRBuilder *B) { + if (!I->hasOneUse()) { + return nullptr; + } + // Autogenerated transforms -#include "gen.cpp.inc" + #include "gen.cpp.inc" + return nullptr; } @@ -294,6 +348,7 @@ struct SouperCombine : public FunctionPass { InstructionWorklist W; util::Stats St; + DominatorTree *DT; }; } @@ -302,7 +357,7 @@ namespace llvm { void initializeSouperCombinePass(llvm::PassRegistry &); } -INITIALIZE_PASS_BEGIN(SouperCombine, "souper", "Souper super-optimizer pass", +INITIALIZE_PASS_BEGIN(SouperCombine, "souper-combine", "Souper super-optimizer pass", false, false) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) From 7a3c8a6e1b7daa9b3b4e1165dc96b5b7e826f43b Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 13 Sep 2022 16:03:54 -0600 Subject: [PATCH 087/165] foo --- tools/matcher-gen.cpp | 237 +++++++++++++++++--------- tools/pass-generator/src/template.cpp | 95 ++++++++++- 2 files changed, 250 insertions(+), 82 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index e84dc10d2..3d92f32d4 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -141,6 +141,15 @@ struct WidthEq : public Constraint { } }; +struct DomCheck : public Constraint { + DomCheck(std::string Name_) : Name(Name_) {} + std::string Name; + + std::string print() override { + return "util::dc(DT, I, " + Name + ")"; + } +}; + // Enforce that `Name` is a constant and a power of 2 struct CPow2 : public Constraint { CPow2(std::string Name_) : Name(Name_) {} @@ -161,6 +170,8 @@ struct SymbolTable : public std::map> { std::vector Vars; std::set Consts, ConstRefs; + std::set Used; + void RegisterPred(Inst *I) { if (PredNames.find(I->K) == PredNames.end()) { return; // not a predicate @@ -172,6 +183,7 @@ struct SymbolTable : public std::map> { Preds[I] = Name; Constraints.push_back(new PredEq(Name, PredNames.at(I->K))); } + template void PrintPreds(Stream &Out) { if (Preds.empty()) { @@ -198,6 +210,24 @@ struct SymbolTable : public std::map> { } } } + + void GenDomConstraints(Inst *RHS) { + static std::set Visited; + Visited.insert(RHS); + for (auto Op : RHS->Ops) { + if (Op->K == Inst::Const) { + continue; + // TODO: Find other cases + } + auto It = find(Op); + if (It != end()) { + if (Visited.find(Op) == Visited.end()) { + Constraints.push_back(new DomCheck(It->second[0])); + GenDomConstraints(Op); + } + } + } + } void GenVarPropConstraints(Inst *LHS) { std::vector Vars; @@ -239,24 +269,34 @@ struct SymbolTable : public std::map> { Out << "}\n"; } + // Consts = consts found in LHS + // ConstRefs = consts found in RHS template void PrintConstDecls(Stream &Out) { size_t varnum = 0; - for (auto C : ConstRefs) { - if (Consts.find(C) != Consts.end()) { - continue; - } + + auto Print = [&](SymbolTable &Syms, Inst *C){ auto Name = "C" + std::to_string(varnum++); Out << " auto " << Name << " = C(" << C->Val.getBitWidth() <<", " << C->Val << ", B);\n"; - (*this)[C].push_back(Name); + Syms[C].push_back(Name); + }; + + for (auto C : ConstRefs) { + if (Consts.find(C) == Consts.end()) { + Print(*this, C); + } } } }; template bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { + if (I->K != souper::Inst::Var && Syms.Used.find(I) != Syms.Used.end()) { + Out << "&" << Syms[I].back() << " <<= "; + } + auto It = MatchOps.find(I->K); if (It == MatchOps.end()) { llvm::errs() << "\nUnimplemented matcher:" << Inst::getKindName(I->K) << "\n"; @@ -282,18 +322,21 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { } else { Out << ", "; } + if (Child->K == Inst::Const) { + if (Child->K != souper::Inst::Var && Syms.Used.find(Child) != Syms.Used.end()) { + Out << "&" << Syms[Child].back() << " <<= "; + } auto Str = Child->Val.toString(10, false); - Out << "m_SpecificInt(" << Str << ")"; + Out << "m_SpecificInt( " << Child->Width << ", " << Str << ")"; } else if (Child->K == Inst::Var) { if (Child->Name.starts_with("symconst")) { - Out << "m_Constant()"; + Out << "m_Constant(&" << Syms[Child].back() << ")"; } else if (Child->Name.starts_with("constexpr")) { llvm::errs() << "FOUND A CONSTEXPR\n"; } else { // FIXME What about Symbolic constants? // How about matching const exprs? - Out << "m_Value(" << Syms[Child].back() << ")"; } Syms[Child].pop_back(); @@ -342,71 +385,54 @@ bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms) { return true; } -template -void printPath(Stream &Out, const Container& C) { - Out << "{"; - bool first = true; - for (auto c : C) { - if (first) { - first = false; - } else { - Out << ", "; - } - Out << c; - } - Out << "}"; -} - template bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { - std::map> Paths; - - std::set Consts; + std::set LHSInsts; - - Paths[Root] = {}; // root has an empty path +// Paths[Root] = {}; // root has an empty path std::vector Stack{Root}; - +// int varnum = 0; while (!Stack.empty()) { auto I = Stack.back(); Stack.pop_back(); Syms.RegisterPred(I); + LHSInsts.insert(I); if (I->K == Inst::Var) { Syms[I].push_back("x" + std::to_string(varnum++)); } if (I->K == Inst::Const) { - Consts.insert(I); + Syms.Consts.insert(I); } for (int i = 0; i < I->Ops.size(); ++i) { - Paths[I->Ops[i]] = Paths[I]; // Child inherits parent's path - Paths[I->Ops[i]].push_back(i); +// Paths[I->Ops[i]] = Paths[I]; // Child inherits parent's path +// Paths[I->Ops[i]].push_back(i); Stack.push_back(I->Ops[i]); // Souper exprs are DAGs } } - std::set LHSRefs; std::set Visited; - std::set ConstRefs; Stack.push_back(RHS); while (!Stack.empty()) { auto I = Stack.back(); Stack.pop_back(); Visited.insert(I); if (I->K == Inst::Const) { -// Consts.insert(I); - ConstRefs.insert(I); + Syms.ConstRefs.insert(I); } - if (Paths.find(I) != Paths.end()) { - LHSRefs.insert(I); - } else { - for (auto Child : I->Ops) { - if (Visited.find(Child) == Visited.end()) { - Stack.push_back(Child); - } + + if (LHSInsts.find(I) != LHSInsts.end()) { + if (Syms.Used.insert(I).second && Syms.find(I) == Syms.end()) { + Syms[I].push_back("x" + std::to_string(varnum++)); } } + for (auto Child : I->Ops) { + if (Visited.find(Child) == Visited.end()) { + Stack.push_back(Child); + } + } + } if (!Syms.empty()) { @@ -425,33 +451,29 @@ bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { Out << ";\n"; } - varnum = 0; - for (auto &&P : Paths) { - if (P.first == Root || P.first->K == Inst::Var - || LHSRefs.find(P.first) == LHSRefs.end()) { - continue; - } -// std::string Name = "I"; -// for (auto idx : P.second) { -// auto NewName = "y" + std::to_string(varnum++); -// Out << "auto " << NewName << " = cast(" << Name; -// Out << ")->getOperand(" << idx << ");\n"; -// std::swap(Name, NewName); +// varnum = 0; +// for (auto &&P : Paths) { +// if (P.first == Root || P.first->K == Inst::Var +// || LHSRefs.find(P.first) == LHSRefs.end()) { +// continue; // } +//// std::string Name = "I"; +//// for (auto idx : P.second) { +//// auto NewName = "y" + std::to_string(varnum++); +//// Out << "auto " << NewName << " = cast(" << Name; +//// Out << ")->getOperand(" << idx << ");\n"; +//// std::swap(Name, NewName); +//// } +//// Syms[P.first].push_back(Name); +// +// auto Name = "y" + std::to_string(varnum++); +// Out << "auto " << Name << " = util::node(I, "; +// printPath(Out, P.second); +// Out << ");\n"; // Syms[P.first].push_back(Name); - - auto Name = "y" + std::to_string(varnum++); - Out << "auto " << Name << " = util::node(I, "; - printPath(Out, P.second); - Out << ");\n"; - Syms[P.first].push_back(Name); - } +// } Syms[Root].push_back("I"); - Syms.PrintPreds(Out); - - Syms.Consts = Consts; - Syms.ConstRefs = ConstRefs; return true; } @@ -474,21 +496,12 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { Syms.GenVarEqConstraints(); Syms.GenVarPropConstraints(Input.Mapping.LHS); + Syms.GenDomConstraints(Input.Mapping.RHS); Syms.PrintConstraintsPre(Out); - Syms.PrintConstDecls(Out); + Out << " St.hit(" << OptID << ");\n"; -// size_t varnum = 0; -// for (auto C : SymsCopy.ConstRefs) { -// if (SymsCopy.Consts.find(C) != SymsCopy.Consts.end()) { -// continue; -// } -// auto Name = "C" + std::to_string(varnum++); -// Out << "auto " << Name << " = C(" -// << C->Val.getBitWidth() <<", " -// << C->Val << ", B);\n"; -// Syms[C].push_back(Name); -// } + Syms.PrintConstDecls(Out); if (Syms.find(Input.Mapping.RHS) != Syms.end()) { Out << " return " << Syms[Input.Mapping.RHS][0] << ";"; @@ -511,7 +524,58 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { return true; } +std::string getLLVMInstKindName(Inst::Kind K) { + StringRef str = MatchOps.find(K)->second; + str.consume_front("m_"); + str.consume_back("("); +// str.consume_front("NSW"); +// str.consume_front("NUW"); +// str.consume_front("NW"); + return str.str(); +} +void genDispatchCode(const std::set &Kinds) { + llvm::outs() << "bool matchAll = true;\n"; + llvm::outs() << "auto CI = dyn_cast(I);"; + // TODO Handle NSW/etc + for (auto K : Kinds) { + switch(K) { + case Inst::Add: + llvm::outs() << "if (I->getOpcodeName() == \"add\") {matchAll = false;goto add_;}"; + break; + case Inst::Sub: + llvm::outs() << "if (I->getOpcodeName() == \"sub\") {matchAll = false;goto sub_;}"; + break; + case Inst::Mul: + llvm::outs() << "if (I->getOpcodeName() == \"mul\") {matchAll = false;goto mul_;}"; + break; + case Inst::And: + llvm::outs() << "if (I->getOpcodeName() == \"and\") {matchAll = false;goto and_;}"; + break; + case Inst::Or: + llvm::outs() << "if (I->getOpcodeName() == \"or\") {matchAll = false;goto or_;}"; + break; + case Inst::Xor: + llvm::outs() << "if (I->getOpcodeName() == \"xor\") {matchAll = false;goto xor_;}"; + break; + + case Inst::Eq: + llvm::outs() << "if (I->getOpcodeName() == \"icmp\" &&" + << "CI->getPredicate() == CmpInst::ICMP_EQ) " + << "{matchAll = false;goto eq_;}"; + break; + case Inst::Ne: + llvm::outs() << "if (I->getOpcodeName() == \"icmp\" &&" + << "CI->getPredicate() == CmpInst::ICMP_NE) " + << "{matchAll = false;goto ne_;}"; + break; + + + + default: break; + } + } +} int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); @@ -533,13 +597,29 @@ int main(int argc, char **argv) { auto Inputs = ParseReplacements(IC, Data.getBufferIdentifier(), Data.getBuffer(), ErrStr); + std::set Kinds; + std::sort(Inputs.begin(), Inputs.end(), + [&Kinds](const ParsedReplacement& A, const ParsedReplacement &B) { + Kinds.insert(A.Mapping.LHS->K); + Kinds.insert(B.Mapping.LHS->K); + return A.Mapping.LHS->K < B.Mapping.LHS->K; + }); + if (!ErrStr.empty()) { llvm::errs() << ErrStr << '\n'; return 1; } size_t optnumber = 0; +// genDispatchCode(Kinds); + Inst::Kind Last = Inst::Kind::None; + for (auto &&Input: Inputs) { +// if (Input.Mapping.LHS->K != Last) { +// llvm::outs() << "if (!matchAll) goto end;\n"; +// Last = Input.Mapping.LHS->K; +// llvm::outs() << Inst::getKindName(Last) << "_" << ":\n"; +// } if (IgnorePCs && !Input.PCs.empty()) { continue; } @@ -588,6 +668,7 @@ int main(int argc, char **argv) { llvm::errs().flush(); } } +// llvm::outs() << "end:\n"; return 0; } diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 378303b40..9c41e9d05 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -26,6 +26,11 @@ using namespace llvm; using namespace llvm::PatternMatch; +// TODO Match trees +// TODO Make the commutative operations work +// This is critical because commutative operations +// sometimes have the arguments inverted for canonicalization + namespace { // Custom Creators @@ -79,7 +84,7 @@ template struct phi_match { phi_match(Args... args) : Matchers{args...} {}; std::tuple Matchers; - + bool match_nth(size_t n, Value *V) { switch (n) { case 0 : return std::get<0>(Matchers).match(V); @@ -139,6 +144,39 @@ struct bind_apint { } }; +struct width_specific_intval : public specific_intval { + size_t Width; + width_specific_intval(llvm::APInt V, size_t W) : specific_intval(V), Width(W) {} + + template bool match(ITy *V) { + if (V->getType()->getScalarSizeInBits() != Width) { + return false; + } + return specific_intval::match(V); + } +}; + +// FIXME Widths beyond 64 +inline width_specific_intval m_SpecificInt(size_t W, uint64_t V) { + return width_specific_intval(APInt(64, V), W); +} + +struct constant_matcher { + llvm::Value** Captured; + constant_matcher(llvm::Value** C) : Captured(C) {} + template bool match(OpTy *V) { + if (isa(V)) { + *Captured = dyn_cast(V); + return *Captured != nullptr; + } + return false; + } +}; + +inline constant_matcher m_Constant(Value **V) { + return constant_matcher(V); +} + // Tested, matches APInts inline bind_apint m_APInt(APInt &V) { return bind_apint(V); } @@ -161,6 +199,40 @@ template struct CastClass_match_width { } }; +template +struct Capture { + Value **Captured; + Matcher M; + + template + explicit Capture(Value **V, CArgs ...C) : Captured(V), M(C...) {} + + template bool match(OpTy *V) { + if (M.match(V)) { + *Captured = dyn_cast(V); + if (!*Captured) { + llvm::errs() << "Capture failed.\n"; + return false; + } + return true; + } else { + *Captured = nullptr; + return false; + } + } +}; + +template +Capture Cap(Value **V, Matcher &&M) { + return Capture(V, M); +} + +// Equivalent to the Cap function +template +Capture operator<<=(Value **V, Matcher &&M) { + return Capture(V, M); +} + template inline CastClass_match_width m_ZExt(size_t W, const OpTy &Op) { return CastClass_match_width(W, Op); @@ -194,6 +266,16 @@ namespace util { return Current; } + bool dc(llvm::DominatorTree *DT, llvm::Instruction *I, llvm::Value *V) { + if (auto Def = dyn_cast(V)) { + if (I->getParent() == Def->getParent()) { + return true; + } + return DT->dominates(Def, I->getParent()); + } + return true; + } + bool check_width(llvm::Value *V, size_t W) { return V->getType()->getScalarSizeInBits() == W; } @@ -260,17 +342,23 @@ namespace util { void hit(size_t opt) { Hits[opt]++; } +// void dcmiss(size_t opt) { +// DCMiss[opt]++; +// } std::map Hits; +// std::map DCMiss; void print() { std::vector> Copy(Hits.size(), std::make_pair(0, 0)); std::copy(Hits.begin(), Hits.end(), Copy.begin()); std::sort(Copy.begin(), Copy.end(), [](auto &A, auto &B) {return A.second > B.second;}); llvm::errs() << "Hits begin:\n"; + size_t sum = 0; for (auto &&P : Copy) { + sum += P.second; llvm::errs() << "OptID " << P.first << " matched " << P.second << " time(s).\n"; } - llvm::errs() << "Hits end.\n"; + llvm::errs() << "Hits end. Total = " << sum << ".\n"; } }; bool nc(llvm::Value *a, llvm::Value *b) { @@ -288,6 +376,7 @@ struct SouperCombine : public FunctionPass { bool runOnFunction(Function &F) override { DT = new DominatorTree(F); + W.reserve(F.getInstructionCount()); for (auto &BB : F) { for (auto &&I : BB) { @@ -318,7 +407,6 @@ struct SouperCombine : public FunctionPass { while (auto I = W.removeOne()) { Changed = processInst(I, Builder) || Changed; } - return Changed; } @@ -326,7 +414,6 @@ struct SouperCombine : public FunctionPass { if (!I->hasOneUse()) { return nullptr; } - // Autogenerated transforms #include "gen.cpp.inc" From 4ca8672c3d337d9c5ab7f690303940d9f97474e0 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 21 Sep 2022 14:02:20 -0600 Subject: [PATCH 088/165] foo --- include/souper/Generalize/Reducer.h | 5 +- lib/Generalize/Reducer.cpp | 32 ++++ tools/generalize.cpp | 3 +- tools/matcher-gen.cpp | 190 +++++++++++++++------- tools/pass-generator/scripts/bisection.py | 46 ++++++ tools/pass-generator/src/template.cpp | 58 +++++-- 6 files changed, 254 insertions(+), 80 deletions(-) create mode 100644 tools/pass-generator/scripts/bisection.py diff --git a/include/souper/Generalize/Reducer.h b/include/souper/Generalize/Reducer.h index 2263d16bb..b36ff7ca9 100644 --- a/include/souper/Generalize/Reducer.h +++ b/include/souper/Generalize/Reducer.h @@ -29,15 +29,14 @@ class Reducer { // Assumes Input is valid ParsedReplacement ReducePCs(ParsedReplacement Input); - // Assumes Input is valid ParsedReplacement WeakenKB(ParsedReplacement Input); - // Assumes Input is valid ParsedReplacement WeakenCR(ParsedReplacement Input); - // Assumes Input is valid ParsedReplacement WeakenDB(ParsedReplacement Input); + ParsedReplacement WeakenOther(ParsedReplacement Input); + bool VerifyInput(ParsedReplacement &Input); bool safeToRemove(Inst *I, ParsedReplacement &Input); diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index 3d284f76c..f31c8a2aa 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -404,6 +404,38 @@ ParsedReplacement Reducer::WeakenDB(ParsedReplacement Input) { return Input; } +// Assumes Input is valid +ParsedReplacement Reducer::WeakenOther(ParsedReplacement Input) { + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); + + for (auto &&V : Vars) { +#define WEAKEN(X) \ +if (V->X) { \ + V->X = false; \ + if (!VerifyInput(Input)) {\ + V->X = true;}} + + WEAKEN(NonZero) + WEAKEN(NonNegative) + WEAKEN(PowOfTwo) + WEAKEN(Negative) + +#undef WEAKEN + + while (V->NumSignBits) { + V->NumSignBits--; + if (!VerifyInput(Input)) { + V->NumSignBits++; + break; + } + } + + } + + return Input; +} + bool Reducer::VerifyInput(ParsedReplacement &Input) { std::vector> Models; bool Valid; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 00f55ddcb..9b156f8a1 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -266,8 +266,6 @@ bool All(const C &c, F f) { return true; } - - bool InferPreconditionsAndVerify(ParsedReplacement Input, CandidateMap &Results, std::vector> &SymCS, InstContext &IC, Solver *S) { @@ -782,6 +780,7 @@ std::vector ReduceAndGeneralize(InstContext &IC, Input = R.WeakenKB(Input); Input = R.WeakenCR(Input); Input = R.WeakenDB(Input); + Input = R.WeakenOther(Input); if (ReduceKBIFY) { Input = R.ReduceGreedyKBIFY(Input); } diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 3d92f32d4..8ba3bf029 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -10,6 +10,8 @@ #include "souper/Tool/GetSolver.h" #include "souper/Util/DfaUtils.h" +#include + using namespace llvm; using namespace souper; @@ -36,6 +38,12 @@ static llvm::cl::opt IgnoreDF("ignore-df", "(default=false)"), llvm::cl::init(true)); +static llvm::cl::opt ListFile("listfile", + llvm::cl::desc("List of optimization indexes to include.\n" + "(default=empty-string)"), + llvm::cl::init("")); + + static const std::map MatchOps = { {Inst::Add, "m_c_Add("}, {Inst::Sub, "m_Sub("}, {Inst::Mul, "m_c_Mul("}, @@ -57,12 +65,12 @@ static const std::map MatchOps = { {Inst::And, "m_c_And("}, {Inst::Or, "m_c_Or("}, {Inst::Xor, "m_c_Xor("}, - {Inst::Eq, "m_Cmp("}, - {Inst::Ne, "m_Cmp("}, - {Inst::Ule, "m_Cmp("}, - {Inst::Ult, "m_Cmp("}, - {Inst::Sle, "m_Cmp("}, - {Inst::Slt, "m_Cmp("}, + {Inst::Eq, "m_c_ICmp("}, + {Inst::Ne, "m_c_ICmp("}, + {Inst::Ule, "m_ICmp("}, + {Inst::Ult, "m_ICmp("}, + {Inst::Sle, "m_ICmp("}, + {Inst::Slt, "m_ICmp("}, {Inst::SExt, "m_SExt("}, {Inst::ZExt, "m_ZExt("}, @@ -150,13 +158,13 @@ struct DomCheck : public Constraint { } }; -// Enforce that `Name` is a constant and a power of 2 -struct CPow2 : public Constraint { - CPow2(std::string Name_) : Name(Name_) {} +struct VC : public Constraint { + VC(std::string Cons_, std::string Name_) : Cons(Cons_), Name(Name_) {} std::string print() override { - return "util::cpow2(" + Name + ")"; + return "util::" + Cons + "(" + Name + ")"; } std::string Name; + std::string Cons; }; //struct VarKB : public Constraint { @@ -236,11 +244,19 @@ struct SymbolTable : public std::map> { for (auto V : Vars) { auto Name = this->at(V)[0]; Constraints.push_back(new WidthEq(Name, V->Width)); - if (V->Name.starts_with("symconst_")) { - if (V->PowOfTwo) { - Constraints.push_back(new CPow2(Name)); - } + if (V->PowOfTwo) { + Constraints.push_back(new VC("pow2", Name)); + } + if (V->NonZero) { + Constraints.push_back(new VC("nz", Name)); + } + if (V->NonNegative) { + Constraints.push_back(new VC("nn", Name)); + } + if (V->Negative) { + Constraints.push_back(new VC("neg", Name)); } + } } @@ -337,6 +353,7 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { } else { // FIXME What about Symbolic constants? // How about matching const exprs? + Out << "m_Value(" << Syms[Child].back() << ")"; } Syms[Child].pop_back(); @@ -534,47 +551,9 @@ std::string getLLVMInstKindName(Inst::Kind K) { return str.str(); } -void genDispatchCode(const std::set &Kinds) { - llvm::outs() << "bool matchAll = true;\n"; - llvm::outs() << "auto CI = dyn_cast(I);"; - // TODO Handle NSW/etc - for (auto K : Kinds) { - switch(K) { - case Inst::Add: - llvm::outs() << "if (I->getOpcodeName() == \"add\") {matchAll = false;goto add_;}"; - break; - case Inst::Sub: - llvm::outs() << "if (I->getOpcodeName() == \"sub\") {matchAll = false;goto sub_;}"; - break; - case Inst::Mul: - llvm::outs() << "if (I->getOpcodeName() == \"mul\") {matchAll = false;goto mul_;}"; - break; - case Inst::And: - llvm::outs() << "if (I->getOpcodeName() == \"and\") {matchAll = false;goto and_;}"; - break; - case Inst::Or: - llvm::outs() << "if (I->getOpcodeName() == \"or\") {matchAll = false;goto or_;}"; - break; - case Inst::Xor: - llvm::outs() << "if (I->getOpcodeName() == \"xor\") {matchAll = false;goto xor_;}"; - break; - - case Inst::Eq: - llvm::outs() << "if (I->getOpcodeName() == \"icmp\" &&" - << "CI->getPredicate() == CmpInst::ICMP_EQ) " - << "{matchAll = false;goto eq_;}"; - break; - case Inst::Ne: - llvm::outs() << "if (I->getOpcodeName() == \"icmp\" &&" - << "CI->getPredicate() == CmpInst::ICMP_NE) " - << "{matchAll = false;goto ne_;}"; - break; - - - - default: break; - } - } +int profitability(const ParsedReplacement &Input) { + return souper::cost(Input.Mapping.LHS) - + souper::cost(Input.Mapping.RHS); } int main(int argc, char **argv) { @@ -584,6 +563,15 @@ int main(int argc, char **argv) { std::unique_ptr S = 0; S = GetSolver(KV); + std::unordered_set optnumbers; + if (ListFile != "") { + std::ifstream in(ListFile); + size_t num; + while (in >> num) { + optnumbers.insert(num); + } + } + auto MB = MemoryBuffer::getFileOrSTDIN(InputFilename); if (!MB) { llvm::errs() << MB.getError().message() << '\n'; @@ -602,6 +590,14 @@ int main(int argc, char **argv) { [&Kinds](const ParsedReplacement& A, const ParsedReplacement &B) { Kinds.insert(A.Mapping.LHS->K); Kinds.insert(B.Mapping.LHS->K); + +// if (A.Mapping.LHS->K < B.Mapping.LHS->K) { +// return true; +// } else if (A.Mapping.LHS->K == B.Mapping.LHS->K) { +// return profitability(A) > profitability(B); +// } else { +// return false; +// } return A.Mapping.LHS->K < B.Mapping.LHS->K; }); @@ -614,12 +610,9 @@ int main(int argc, char **argv) { // genDispatchCode(Kinds); Inst::Kind Last = Inst::Kind::None; + bool first = true; + for (auto &&Input: Inputs) { -// if (Input.Mapping.LHS->K != Last) { -// llvm::outs() << "if (!matchAll) goto end;\n"; -// Last = Input.Mapping.LHS->K; -// llvm::outs() << Inst::getKindName(Last) << "_" << ":\n"; -// } if (IgnorePCs && !Input.PCs.empty()) { continue; } @@ -652,10 +645,86 @@ int main(int argc, char **argv) { if (found) continue; } + if (Input.Mapping.LHS->K != Last) { + if (!first) { + llvm::outs() << "}\n"; + } + first = false; + llvm::outs() << "if ("; + switch (Input.Mapping.LHS->K) { + case Inst::AddNW: + case Inst::AddNUW: + case Inst::AddNSW: + case Inst::Add: llvm::outs() + << "I->getOpcode() == Instruction::Add"; break; + + case Inst::SubNW: + case Inst::SubNUW: + case Inst::SubNSW: + case Inst::Sub: llvm::outs() + << "I->getOpcode() == Instruction::Sub"; break; + + case Inst::MulNW: + case Inst::MulNUW: + case Inst::MulNSW: + case Inst::Mul: llvm::outs() + << "I->getOpcode() == Instruction::Mul"; break; + + case Inst::ShlNW: + case Inst::ShlNUW: + case Inst::ShlNSW: + case Inst::Shl: llvm::outs() + << "I->getOpcode() == Instruction::Shl"; break; + + case Inst::And: llvm::outs() + << "I->getOpcode() == Instruction::And"; break; + case Inst::Or: llvm::outs() + << "I->getOpcode() == Instruction::Or"; break; + case Inst::Xor: llvm::outs() + << "I->getOpcode() == Instruction::Xor"; break; + case Inst::SRem: llvm::outs() + << "I->getOpcode() == Instruction::SRem"; break; + case Inst::URem: llvm::outs() + << "I->getOpcode() == Instruction::URem"; break; + case Inst::SDiv: llvm::outs() + << "I->getOpcode() == Instruction::SDiv"; break; + case Inst::UDiv: llvm::outs() + << "I->getOpcode() == Instruction::UDiv"; break; + case Inst::ZExt: llvm::outs() + << "I->getOpcode() == Instruction::ZExt"; break; + case Inst::SExt: llvm::outs() + << "I->getOpcode() == Instruction::SExt"; break; + case Inst::Trunc: llvm::outs() + << "I->getOpcode() == Instruction::Trunc"; break; + case Inst::Select: llvm::outs() + << "I->getOpcode() == Instruction::Select"; break; + case Inst::Phi: llvm::outs() + << "isa(I)"; break; + case Inst::Eq: + case Inst::Ne: + case Inst::Ult: + case Inst::Slt: + case Inst::Ule: + case Inst::Sle: llvm::outs() + << "I->getOpcode() == Instruction::ICmp"; break; + + default: llvm::outs() << "true"; + } + llvm::outs() << ") {\n"; + } + Last = Input.Mapping.LHS->K; + std::string Str; llvm::raw_string_ostream Out(Str); if (GenMatcher(Input, Out, optnumber)) { auto current = optnumber++; + if (!optnumbers.empty() + && optnumbers.find(current) == optnumbers.end()) { + Out.flush(); + Str.clear(); + llvm::errs() << "Opt " << current << " skipped on demand.\n"; + continue; + } llvm::outs() << "/* Opt : " << current << "\n"; Input.print(llvm::outs(), true); llvm::outs() << "*/\n"; @@ -668,6 +737,7 @@ int main(int argc, char **argv) { llvm::errs().flush(); } } + llvm::outs() << "}\n"; // llvm::outs() << "end:\n"; return 0; diff --git a/tools/pass-generator/scripts/bisection.py b/tools/pass-generator/scripts/bisection.py new file mode 100644 index 000000000..8111d498f --- /dev/null +++ b/tools/pass-generator/scripts/bisection.py @@ -0,0 +1,46 @@ +import sys +import re +import os + +def split_on_empty_lines(s): + blank_line_regex = r"(?:\r?\n){2,}" + return re.split(blank_line_regex, s.strip()) + +def split_list(a_list): + half = len(a_list)//2 + return a_list[:half], a_list[half:] + +# Return true if the command crashes +def call(opts, cmd): + if len(opts) == 0: + return False + open("/tmp/scratch.inc", 'w+').write('\n'.join(opts)) + print("HERE: ", cmd + " /tmp/scratch.inc") + return os.system(cmd + " /tmp/scratch.inc > /dev/null") != 0 + +# Find a small range of optimizations which causes cmd to crash +def bsearch(opts, cmd): + if len(opts) == 1: + return opts + elif len(opts) == 0: + return () + else: + left, right = split_list(opts) + if call(left, cmd) == True: + return bsearch(left, cmd) + elif call(right, cmd) == True: + return bsearch(right, cmd) + else: + print("Rangefinder failed, find combinations") + return opts + +def main(): + # First argument is the autogenerated matcher file + # Second argument is a file with the command to run whatever you want to run with the matchers as input + all = split_on_empty_lines(open(sys.argv[1]).read()) + cmd = sys.argv[2] + print('\n'.join(bsearch(all, cmd))) + return 0 + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 9c41e9d05..48e49c009 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -285,7 +285,7 @@ namespace util { return Result == F(args...); } - bool cpow2(llvm::Value *V) { + bool pow2(llvm::Value *V) { if (ConstantInt *Con = llvm::dyn_cast(V)) { if (Con->getValue().isPowerOf2()) { return true; @@ -305,23 +305,23 @@ namespace util { return Big.contains(Small); } - bool ckb(llvm::Value *V, llvm::KnownBits Overapprox) { - if (ConstantInt *Con = llvm::dyn_cast(V)) { - auto Val = Con->getUniqueInteger(); - llvm::KnownBits KB(V->getType()->getIntegerBitWidth()); - KB.One = Val; - KB.Zero = ~Val; - return IsKBSubset(KB, Overapprox); - } - return false; + bool ckb(llvm::Value *V, llvm::KnownBits Overapprox) { + if (ConstantInt *Con = llvm::dyn_cast(V)) { + auto Val = Con->getUniqueInteger(); + llvm::KnownBits KB(V->getType()->getIntegerBitWidth()); + KB.One = Val; + KB.Zero = ~Val; + return IsKBSubset(KB, Overapprox); } + return false; + } - bool ccr(llvm::Value *V,llvm::ConstantRange R) { - if (ConstantInt *Con = llvm::dyn_cast(V)) { - return R.contains(Con->getUniqueInteger()); - } - return false; + bool ccr(llvm::Value *V,llvm::ConstantRange R) { + if (ConstantInt *Con = llvm::dyn_cast(V)) { + return R.contains(Con->getUniqueInteger()); } + return false; + } bool vkb(llvm::Value *V, llvm::KnownBits OverApprox) { auto Analyzed = llvm::KnownBits(V->getType()->getIntegerBitWidth()); @@ -337,6 +337,29 @@ namespace util { return false; } + bool nz(llvm::Value *V) { + if (ConstantInt *Con = llvm::dyn_cast(V)) { + return !Con->getValue().isZero(); + } +// llvm::errs() << "NZ called on NC.\n"; + return false; + } + + bool nn(llvm::Value *V) { + if (ConstantInt *Con = llvm::dyn_cast(V)) { + return Con->getValue().isNonNegative(); + } +// llvm::errs() << "NN called on NC.\n"; + return false; + } + + bool neg(llvm::Value *V) { + if (ConstantInt *Con = llvm::dyn_cast(V)) { + return Con->getValue().isNegative(); + } +// llvm::errs() << "Neg called on NC.\n"; + return false; + } struct Stats { void hit(size_t opt) { @@ -414,6 +437,11 @@ struct SouperCombine : public FunctionPass { if (!I->hasOneUse()) { return nullptr; } + + // Interestingly commenting out ^this block + // slightly improves results. + // Implying this situation can be improved further + // Autogenerated transforms #include "gen.cpp.inc" From 31a6cf9795349bac8b90a2de5889e39c32512c34 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 21 Sep 2022 16:35:00 -0600 Subject: [PATCH 089/165] foo --- lib/Generalize/Reducer.cpp | 14 ++++++++++++++ tools/generalize.cpp | 10 +++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index f31c8a2aa..42ae84abc 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -30,6 +30,11 @@ ParsedReplacement Reducer::ReduceGreedy(ParsedReplacement Input) { int failcount = 0; std::set Visited; do { + + if (souper::cost(Input.Mapping.LHS) - souper::cost(Input.Mapping.LHS) <= 1) { + break; + } + auto It = Insts.begin(); auto I = *It; Insts.erase(It); @@ -141,6 +146,11 @@ ParsedReplacement Reducer::ReduceGreedyKBIFY(ParsedReplacement Input) { size_t failcount = 0; std::set Visited; do { + + if (souper::cost(Input.Mapping.LHS) - souper::cost(Input.Mapping.LHS) <= 1) { + break; + } + auto It = Insts.begin(); auto I = *It; Insts.erase(It); @@ -490,6 +500,10 @@ Inst *Reducer::Eliminate(ParsedReplacement &Input, Inst *I) { void Reducer::ReduceRec(ParsedReplacement Input_, std::vector &Results) { + if (souper::cost(Input_.Mapping.LHS) - souper::cost(Input_.Mapping.LHS) <= 1) { + return; + } + // Try to remove subsets of instructions recursively, and store all valid results ReplacementContext RC; std::string Str; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 9b156f8a1..629a7972c 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -50,7 +50,7 @@ static llvm::cl::opt ReducePrintAll("reduce-all-results", static llvm::cl::opt SymbolizeConstant("symbolize", llvm::cl::desc("Try to replace a concrete constant with a symbolic constant." "(default=false)"), - llvm::cl::init(false)); + llvm::cl::init(true)); static llvm::cl::opt FindConstantRelations("relational", llvm::cl::desc("Find constant relations." @@ -81,7 +81,7 @@ static llvm::cl::opt SymbolizeKBDF("symbolize-infer-kb", static llvm::cl::opt SymbolizeConstSynthesis("symbolize-constant-synthesis", llvm::cl::desc("Allow concrete constants in the generated code."), - llvm::cl::init(false)); + llvm::cl::init(true)); static llvm::cl::opt SymbolizeHackersDelight("symbolize-bit-hacks", llvm::cl::desc("Include bit hacks in the components."), @@ -113,7 +113,7 @@ static cl::opt NumResults("generalization-num-results", static cl::opt Everything("everything", cl::desc("Run everything, output one result."), - cl::init(false)); + cl::init(true)); static cl::opt SymbolicDF("symbolic-df", cl::desc("Generalize with symbolic dataflow facts."), @@ -435,7 +435,7 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In // Put custom components here - if (SymbolizeConstant) { + if (SymbolizeConstant || Everything) { for (auto &&C : SymCS) { if (Everything) { Components.push_back(Builder(C.first, IC).LogB()()); @@ -555,7 +555,7 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In } } -// This is a simpler version of +// This is a simpler version of the above void SymbolizeAndGeneralizeOnlyLHS(InstContext &IC, Solver *S, ParsedReplacement Input, From e3643dcd5a09ac109200c8a50e02d1fef9322119 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 20 Oct 2022 18:09:31 -0600 Subject: [PATCH 090/165] foo --- lib/Generalize/Reducer.cpp | 1 + tools/generalize.cpp | 133 +++++++++++++++++++++++++++++++++++-- 2 files changed, 130 insertions(+), 4 deletions(-) diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index 42ae84abc..e91e11c68 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -30,6 +30,7 @@ ParsedReplacement Reducer::ReduceGreedy(ParsedReplacement Input) { int failcount = 0; std::set Visited; do { + // TODO : implement reduction properly if (souper::cost(Input.Mapping.LHS) - souper::cost(Input.Mapping.LHS) <= 1) { break; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 629a7972c..78fafac33 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -113,8 +113,16 @@ static cl::opt NumResults("generalization-num-results", static cl::opt Everything("everything", cl::desc("Run everything, output one result."), + cl::init(false)); + +static cl::opt Basic("basic", + cl::desc("Run all fast techniques, no synthesis^2."), cl::init(true)); +static cl::opt Advanced("advanced", + cl::desc("Just run more advanced stuff. Assume -basic."), + cl::init(false)); + static cl::opt SymbolicDF("symbolic-df", cl::desc("Generalize with symbolic dataflow facts."), cl::init(false)); @@ -660,6 +668,107 @@ void SymbolizeAndGeneralize(InstContext &IC, } } +std::set findConcreteConsts(Inst *I) { + std::vector Results; + std::set Ret; + auto Pred = [](Inst *I) {return I->K == Inst::Const;}; + findInsts(I, Results, Pred); + for (auto R : Results) { + Ret.insert(R); + } + return Ret; +} + +// Assuming the input has leaves pruned and preconditions weakened +ParsedReplacement SuccessiveSymbolize(InstContext &IC, + Solver *S, ParsedReplacement Input) { + + // Print first successful result and exit, no result sorting. + + // Prelude + + auto LHSConsts = findConcreteConsts(Input.Mapping.LHS); + auto RHSConsts = findConcreteConsts(Input.Mapping.RHS); + + ParsedReplacement Result = Input; + + std::map SymConstMap; + int i = 1; + for (auto I : LHSConsts) { + SymConstMap[I] = IC.createVar(I->Width, "symconst_" + + std::to_string(i++)); + } + + for (auto I : RHSConsts) { + if (SymConstMap.find(I) != SymConstMap.end()) { + continue; + } + SymConstMap[I] = IC.createVar(I->Width, "symconst_" + + std::to_string(i++)); + } + + // Step 1 : Just direct symbolize for common consts, no constraints + + std::map CommonConsts; + for (auto C : RHSConsts) { + if (LHSConsts.find(C) != LHSConsts.end()) { + CommonConsts[C] = SymConstMap[C]; + } + } + + Result = Replace(Result, IC, CommonConsts); + + auto Clone = Verify(Result, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + + // Step 1.5 : Direct symbolize, simple rel constraints. + + std::set RHSFresh; // RHSConsts - LHSConsts + + for (auto C : RHSConsts) { + if (LHSConsts.find(C) == LHSConsts.end()) { + RHSFresh.insert(C); + } + } + + + + + // Step 2 : Symbolize LHS Consts with KB, CR, Rel constraints. + + // Step 3 : Simple RHS constant exprs + + // Step 3.5: Simple RHS exprs with constraints + + // Step 4 : Synthesized RHS exprs, no constant synthesis + + // Step 4.1 : Synthesized RHS exprs, with synthesize + weakened KB. CR? + + // Step 4.5 : Synthesized RHS constant exprs, no constant synthesis, rel preconditions + + // Step 5 : Synthesized RHS constant exprs with specific consts + + return Input; +} + +ParsedReplacement SuccessiveSymbolizeAdvanced(InstContext &IC, + Solver *S, + ParsedReplacement Input) { + // Step 90 : Symbolic dataflow for LHS + preconditions + + // Step 100 : Symbolic dataflow vars in RHS const exprs + + // Step 101 : Permuted exprs for RHS consts + + // Step 110 : Synthesized RHS constant exprs with constant synthesis. + // ^ This would get stuck fairly often. + + return Input; +} + + size_t InferWidth(Inst::Kind K, const std::vector &Ops) { switch (K) { case Inst::LShr: @@ -799,7 +908,7 @@ std::vector ReduceAndGeneralize(InstContext &IC, std::vector SortedResults(DedupedResults.begin(), DedupedResults.end()); std::sort(SortedResults.begin(), SortedResults.end(), [](auto a, auto b){return a.length() < b.length();}); - if (!Everything) { + if (!Everything && !Basic && !Advanced) { for (auto &&S : SortedResults) { if (DebugLevel > 2) { llvm::outs() << "\n\nResult:\n"; @@ -815,7 +924,7 @@ std::vector ReduceAndGeneralize(InstContext &IC, } return SortedResults; } else { - if (!Everything) { + if (!Everything && !Basic && !Advanced) { Input.print(llvm::outs(), true); if (DebugLevel > 2) { llvm::errs() << "Failed to Generalize.\n"; @@ -853,8 +962,9 @@ int main(int argc, char **argv) { // TODO: Write default action which chooses what to do based on input structure for (auto &&Input: Inputs) { - if (Everything) { + if (Basic) { auto Reduced = ReduceAndGeneralize(IC, S.get(), Input); + // TODO make sure this doesn't destroy the optimization ParsedReplacement Rep; @@ -865,9 +975,24 @@ int main(int argc, char **argv) { Rep = ParseReplacements(IC, MB->getMemBufferRef().getBufferIdentifier(), Data.getBuffer(), ErrStr)[0]; } - SymbolizeAndGeneralize(IC, S.get(), Rep); + +// SymbolizeAndGeneralize(IC, S.get(), Rep); + + auto Result = SuccessiveSymbolize(IC, S.get(), Rep); + + Result.print(llvm::outs(), true); + llvm::outs() << "\n"; + continue; } + + if (Advanced) { + auto Result = SuccessiveSymbolize(IC, S.get(), Input); + Result.print(llvm::outs()); + llvm::outs() << "\n"; + continue; + } + if (FixIt) { // TODO: Verify that inputs are valid optimizations Generalize(IC, S.get(), Input); From fb9ee5a2ce4ef7369705078f0be1bd0a8f744719 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 21 Oct 2022 14:39:50 -0600 Subject: [PATCH 091/165] foo --- include/souper/Infer/SynthUtils.h | 2 +- tools/generalize.cpp | 168 +++++++++++++++++++++++++++--- 2 files changed, 157 insertions(+), 13 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index a381438af..e63033f11 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -34,7 +34,7 @@ class Builder { BINOP(Add) BINOP(Sub) BINOP(Mul) BINOP(And) BINOP(Xor) BINOP(Or) - BINOP(Shl) BINOP(LShr) + BINOP(Shl) BINOP(LShr) BINOP(UDiv) #undef BINOP #define BINOPW(K) \ diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 78fafac33..fc89b8905 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -679,6 +679,83 @@ std::set findConcreteConsts(Inst *I) { return Ret; } +ParsedReplacement +FirstValidCombination(ParsedReplacement Input, + const std::vector &Targets, + const std::vector> &Candidates, + std::map InstCache, + InstContext &IC, Solver *S) { + std::vector Counts; + for (auto &&Cand : Candidates) { + Counts.push_back(Cand.size()); + } + + auto Combinations = GetCombinations(Counts); + + for (auto &&Comb : Combinations) { + static int SymExprCount = 0; + auto InstCacheRHS = InstCache; + for (int i = 0; i < Targets.size(); ++i) { + InstCacheRHS[Targets[i]] = Candidates[i][Comb[i]]; + if (Candidates[i][Comb[i]]->K != Inst::Var) { + Candidates[i][Comb[i]]->Name = std::string("constexpr_") + std::to_string(SymExprCount++); + } + } + + auto Copy = Replace(Input, IC, InstCacheRHS); + +// Copy.print(llvm::errs(), true); + + auto Clone = Verify(Copy, IC, S); + + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } + + Input.Mapping.LHS = nullptr; + Input.Mapping.RHS = nullptr; + return Input; +} + +std::vector> +InferSimpleConstExprs(std::vector RHS, std::set + LHS, std::map SMap, + InstContext &IC) { + std::vector> Result; + + for (auto &&RC : RHS) { + auto RV = RC->Val; + Result.push_back({}); + for (auto &&LC : LHS) { + auto LV = LC->Val; + + // TODO: Check width constraints + + // RC = LC + (RV - LV) + Result.back().push_back(Builder(SMap[LC], IC).Add(RV - LV)()); + + // RC = (RV + LV) - LC + Result.back().push_back(Builder(IC, RV + LV).Sub(SMap[LC])()); + + + // RC = LC * (RV / LV) only if no remainder + if (RV.urem(LV) == 0) { + Result.back().push_back(Builder(SMap[LC], IC).Mul(RV.udiv(LV))()); + } + + // RC = LC / (RV * LV) only if no remainder + if (RV.urem(LV) == 0) { + Result.back().push_back(Builder(SMap[LC], IC).UDiv(RV * LV)()); + } + + // TODO: Masks + } + } + + return Result; +} + // Assuming the input has leaves pruned and preconditions weakened ParsedReplacement SuccessiveSymbolize(InstContext &IC, Solver *S, ParsedReplacement Input) { @@ -693,10 +770,15 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, ParsedReplacement Result = Input; std::map SymConstMap; + + std::map InstCache; + int i = 1; for (auto I : LHSConsts) { SymConstMap[I] = IC.createVar(I->Width, "symconst_" + std::to_string(i++)); + + InstCache[I] = SymConstMap[I]; } for (auto I : RHSConsts) { @@ -707,6 +789,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, std::to_string(i++)); } + llvm::errs() << "POST Prelude.\n"; // Step 1 : Just direct symbolize for common consts, no constraints std::map CommonConsts; @@ -716,39 +799,100 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } } - Result = Replace(Result, IC, CommonConsts); + if (!CommonConsts.empty()) { + Result = Replace(Result, IC, CommonConsts); - auto Clone = Verify(Result, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; + auto Clone = Verify(Result, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } } - // Step 1.5 : Direct symbolize, simple rel constraints. + llvm::errs() << "POST 1.\n"; - std::set RHSFresh; // RHSConsts - LHSConsts + // Step 1.5 : Direct symbolize, simple rel constraints on LHS - for (auto C : RHSConsts) { - if (LHSConsts.find(C) == LHSConsts.end()) { - RHSFresh.insert(C); + std::vector> CMap; + + for (auto &&C : LHSConsts) { + CMap.push_back({SymConstMap[C], C->Val}); + } + + auto Relations = InferPotentialRelations(CMap, IC, Input); + + std::map JustLHSSymConstMap; + + for (auto &&C : LHSConsts) { + JustLHSSymConstMap[C] = SymConstMap[C]; + } + + // Maybe call InferPreconditionsAndVerify instead of Verify? + // TODO: Are these matched yet? + auto Copy = Replace(Input, IC, JustLHSSymConstMap); + for (auto &&R : Relations) { + Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + auto Clone = Verify(Copy, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } + Copy.PCs.pop_back(); } - + llvm::errs() << "POST 1.5\n"; + + // Step 2 : Symbolize LHS Consts with KB, CR, SimpleDF constrains + + Copy = Replace(Input, IC, JustLHSSymConstMap); + // TODO: write precondition inference for a given set of variables. + // TODO: Do this today!! - // Step 2 : Symbolize LHS Consts with KB, CR, Rel constraints. + llvm::errs() << "POST 2\n"; // Step 3 : Simple RHS constant exprs + std::vector RHSFresh; // RHSConsts - LHSConsts + + for (auto C : RHSConsts) { + if (LHSConsts.find(C) == LHSConsts.end()) { + RHSFresh.push_back(C); + } + } + + std::vector> Candidates = + InferSimpleConstExprs(RHSFresh, LHSConsts, SymConstMap, IC); + + auto Clone = FirstValidCombination(Input, RHSFresh, Candidates, + InstCache, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + + llvm::errs() << "POST 3\n"; + // Step 3.5: Simple RHS exprs with constraints + for (auto &&R : Relations) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + + auto Clone = FirstValidCombination(Input, RHSFresh, Candidates, + InstCache, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + + Input.PCs.pop_back(); + } + + llvm::errs() << "POST 3\n"; + // Step 4 : Synthesized RHS exprs, no constant synthesis + // Step 4.1 : Synthesized RHS exprs, with synthesize + weakened KB. CR? // Step 4.5 : Synthesized RHS constant exprs, no constant synthesis, rel preconditions - // Step 5 : Synthesized RHS constant exprs with specific consts return Input; } From cede61d0c876616bcb9809b27d4ab81f6dbbc5a0 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 21 Oct 2022 21:56:23 -0600 Subject: [PATCH 092/165] foo --- lib/Generalize/Reducer.cpp | 15 +-- tools/generalize.cpp | 213 +++++++++++++++++++++++++++++++------ utils/magic.sh | 4 +- utils/parallel.sh | 19 ++++ 4 files changed, 212 insertions(+), 39 deletions(-) create mode 100755 utils/parallel.sh diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index e91e11c68..9b773ec9b 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -30,12 +30,6 @@ ParsedReplacement Reducer::ReduceGreedy(ParsedReplacement Input) { int failcount = 0; std::set Visited; do { - // TODO : implement reduction properly - - if (souper::cost(Input.Mapping.LHS) - souper::cost(Input.Mapping.LHS) <= 1) { - break; - } - auto It = Insts.begin(); auto I = *It; Insts.erase(It); @@ -49,6 +43,15 @@ ParsedReplacement Reducer::ReduceGreedy(ParsedReplacement Input) { auto Copy = Input; Eliminate(Input, I); + if (souper::cost(Input.Mapping.LHS) - souper::cost(Input.Mapping.LHS) <= 1) { + Input = Copy; + failcount++; + if (failcount >= Insts.size()) { + break; + } + continue; + } + if (!VerifyInput(Input)) { Input = Copy; failcount++; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index fc89b8905..0bfd0fb32 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -115,9 +115,13 @@ static cl::opt Everything("everything", cl::desc("Run everything, output one result."), cl::init(false)); +static cl::opt JustReduce("just-reduce", + cl::desc("JustReduce"), + cl::init(false)); + static cl::opt Basic("basic", cl::desc("Run all fast techniques, no synthesis^2."), - cl::init(true)); + cl::init(false)); static cl::opt Advanced("advanced", cl::desc("Just run more advanced stuff. Assume -basic."), @@ -679,12 +683,64 @@ std::set findConcreteConsts(Inst *I) { return Ret; } +ParsedReplacement SimplePreconditionsAndVerifyGreedy( + ParsedReplacement Input, InstContext &IC, + Solver *S, std::map SymCS) { + ParsedReplacement Clone; + Clone.Mapping.LHS = nullptr; + Clone.Mapping.RHS = nullptr; + + auto SOLVE = [&]() -> bool { + Clone = Verify(Input, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return true; + } else { + return false; + } + }; + + std::vector Insts; + findVars(Input.Mapping.LHS, Insts); + + std::vector> Inputs; + Inputs.push_back({}); + for (auto &&P : SymCS) { + Inputs.back()[P.first] = P.second; + } + + std::map> CVals; + + for (auto &&I : Inputs) { + for (auto &&P: I) { + CVals[P.first].push_back(P.second); + } + } + + +#define DF(Fact, Check) \ +if (All(CVals[C], [](auto Val) { return Check;})) { \ +C->Fact = true; if (SOLVE()) return Clone; C->Fact = false;}; + + for (auto &&P : SymCS) { + auto C = P.first; + DF(PowOfTwo, Val.isPowerOf2()) + DF(NonZero, Val != 0); + DF(NonNegative, Val.uge(0)); + DF(Negative, Val.slt(0)); + } +#undef DF + + return Clone; +} + + ParsedReplacement FirstValidCombination(ParsedReplacement Input, const std::vector &Targets, const std::vector> &Candidates, std::map InstCache, - InstContext &IC, Solver *S) { + InstContext &IC, Solver *S, + std::map SymCS, bool SDF = false) { std::vector Counts; for (auto &&Cand : Candidates) { Counts.push_back(Cand.size()); @@ -711,6 +767,13 @@ FirstValidCombination(ParsedReplacement Input, if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } + + if (SDF) { + Clone = SimplePreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); + } + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } } Input.Mapping.LHS = nullptr; @@ -728,8 +791,10 @@ InferSimpleConstExprs(std::vector RHS, std::set auto RV = RC->Val; Result.push_back({}); for (auto &&LC : LHS) { + if (LC->Width != RC->Width) { + continue; + } auto LV = LC->Val; - // TODO: Check width constraints // RC = LC + (RV - LV) @@ -749,6 +814,11 @@ InferSimpleConstExprs(std::vector RHS, std::set Result.back().push_back(Builder(SMap[LC], IC).UDiv(RV * LV)()); } + // RC = logb(LC) if logb(LV) = RV && LV is a power of 2. + if (LV.isPowerOf2() && LV.logBase2() == RV) { + Result.back().push_back(Builder(SMap[LC], IC).LogB()()); + } + // TODO: Masks } } @@ -756,6 +826,38 @@ InferSimpleConstExprs(std::vector RHS, std::set return Result; } +std::vector> Enumerate(std::vector RHSConsts, + std::set LHSConsts, InstContext &IC) { + std::vector> Candidates; + + std::vector Components; + for (auto &&C : LHSConsts) { + Components.push_back(C); + } + + // TODO: Custom components + + for (auto &&Target : RHSConsts) { + Candidates.push_back({}); + EnumerativeSynthesis ES; + auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, + Target->Width); + for (auto &&Guess : Guesses) { + std::set ConstSet; + souper::getConstants(Guess, ConstSet); + if (!ConstSet.empty()) { + if (SymbolizeConstSynthesis) { + Candidates.back().push_back(Guess); + } + } else { + Candidates.back().push_back(Guess); + } + } + } + + return Candidates; +} + // Assuming the input has leaves pruned and preconditions weakened ParsedReplacement SuccessiveSymbolize(InstContext &IC, Solver *S, ParsedReplacement Input) { @@ -773,12 +875,15 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, std::map InstCache; + std::map SymCS; + int i = 1; for (auto I : LHSConsts) { SymConstMap[I] = IC.createVar(I->Width, "symconst_" + std::to_string(i++)); InstCache[I] = SymConstMap[I]; + SymCS[SymConstMap[I]] = I->Val; } for (auto I : RHSConsts) { @@ -787,9 +892,11 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } SymConstMap[I] = IC.createVar(I->Width, "symconst_" + std::to_string(i++)); + InstCache[I] = SymConstMap[I]; + SymCS[SymConstMap[I]] = I->Val; } - llvm::errs() << "POST Prelude.\n"; +// llvm::errs() << "POST Prelude.\n"; // Step 1 : Just direct symbolize for common consts, no constraints std::map CommonConsts; @@ -806,9 +913,15 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } + + Clone = SimplePreconditionsAndVerifyGreedy(Result, IC, S, SymCS); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } - llvm::errs() << "POST 1.\n"; +// llvm::errs() << "POST 1.\n"; // Step 1.5 : Direct symbolize, simple rel constraints on LHS @@ -838,7 +951,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Copy.PCs.pop_back(); } - llvm::errs() << "POST 1.5\n"; +// llvm::errs() << "POST 1.5\n"; // Step 2 : Symbolize LHS Consts with KB, CR, SimpleDF constrains @@ -847,7 +960,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // TODO: write precondition inference for a given set of variables. // TODO: Do this today!! - llvm::errs() << "POST 2\n"; +// llvm::errs() << "POST 2\n"; // Step 3 : Simple RHS constant exprs @@ -859,16 +972,18 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } } + if (!RHSFresh.empty()) { + std::vector> Candidates = InferSimpleConstExprs(RHSFresh, LHSConsts, SymConstMap, IC); auto Clone = FirstValidCombination(Input, RHSFresh, Candidates, - InstCache, IC, S); + InstCache, IC, S, SymCS, true); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } - llvm::errs() << "POST 3\n"; +// llvm::errs() << "POST 3\n"; // Step 3.5: Simple RHS exprs with constraints @@ -876,7 +991,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); auto Clone = FirstValidCombination(Input, RHSFresh, Candidates, - InstCache, IC, S); + InstCache, IC, S, SymCS, false); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } @@ -884,16 +999,38 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Input.PCs.pop_back(); } - llvm::errs() << "POST 3\n"; +// llvm::errs() << "POST 3\n"; // Step 4 : Synthesized RHS exprs, no constant synthesis - - // Step 4.1 : Synthesized RHS exprs, with synthesize + weakened KB. CR? + Candidates = Enumerate(RHSFresh, LHSConsts, IC); - // Step 4.5 : Synthesized RHS constant exprs, no constant synthesis, rel preconditions + Clone = FirstValidCombination(Input, RHSFresh, Candidates, + InstCache, IC, S, SymCS, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + + Clone = FirstValidCombination(Input, RHSFresh, Candidates, + InstCache, IC, S, SymCS, true); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + // Step 4.1 : Synthesized RHS exprs, weakened KB. CR? + // TODO + // Step 4.5 : Synthesized RHS constant exprs, no constant synthesis, rel preconditions + for (auto &&R : Relations) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + + auto Clone = FirstValidCombination(Input, RHSFresh, Candidates, + InstCache, IC, S, SymCS, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } + } return Input; } @@ -1012,6 +1149,23 @@ void collectInsts(Inst *I, std::set &Results) { } } +ParsedReplacement ReduceBasic(InstContext &IC, + Solver *S, ParsedReplacement Input) { + Reducer R(IC, S); + Input = R.ReducePCs(Input); + Input = R.ReduceRedundantPhis(Input); + Input = R.ReduceGreedy(Input); + Input = R.WeakenKB(Input); + Input = R.WeakenCR(Input); + Input = R.WeakenDB(Input); + Input = R.WeakenOther(Input); + if (ReduceKBIFY) { + Input = R.ReduceGreedyKBIFY(Input); + } + Input = R.ReducePCs(Input); + return Input; +} + std::vector ReduceAndGeneralize(InstContext &IC, Solver *S, ParsedReplacement Input) { std::vector> Models; @@ -1038,11 +1192,17 @@ std::vector ReduceAndGeneralize(InstContext &IC, Input = R.ReduceGreedyKBIFY(Input); } Input = R.ReducePCs(Input); + + llvm::outs() << "HERE5\n"; + Input.print(llvm::outs(), true); + return {Input.getString(true)}; + R.ReduceRec(Input, Results); if (DebugLevel > 3) { R.Stats(); } +// llvm::errs() << "HERE0: " << Results.size(); if (!Results.empty()) { std::set DedupedResults; for (auto &&Result : Results) { @@ -1052,6 +1212,11 @@ std::vector ReduceAndGeneralize(InstContext &IC, std::vector SortedResults(DedupedResults.begin(), DedupedResults.end()); std::sort(SortedResults.begin(), SortedResults.end(), [](auto a, auto b){return a.length() < b.length();}); + if (Basic) { +// llvm::errs() << "HERE: " << SortedResults.size(); + return SortedResults; + } + if (!Everything && !Basic && !Advanced) { for (auto &&S : SortedResults) { if (DebugLevel > 2) { @@ -1107,26 +1272,12 @@ int main(int argc, char **argv) { for (auto &&Input: Inputs) { if (Basic) { - auto Reduced = ReduceAndGeneralize(IC, S.get(), Input); - // TODO make sure this doesn't destroy the optimization - - ParsedReplacement Rep; - - if (Reduced.empty()) { - Rep = Input; - } else { - auto MB = llvm::MemoryBuffer::getMemBuffer(Reduced[0]); - Rep = ParseReplacements(IC, MB->getMemBufferRef().getBufferIdentifier(), - Data.getBuffer(), ErrStr)[0]; + ParsedReplacement Result = ReduceBasic(IC, S.get(), Input); + if (!JustReduce) { + Result = SuccessiveSymbolize(IC, S.get(), Result); } - -// SymbolizeAndGeneralize(IC, S.get(), Rep); - - auto Result = SuccessiveSymbolize(IC, S.get(), Rep); - Result.print(llvm::outs(), true); llvm::outs() << "\n"; - continue; } diff --git a/utils/magic.sh b/utils/magic.sh index fbd920614..9166d671c 100755 --- a/utils/magic.sh +++ b/utils/magic.sh @@ -8,7 +8,7 @@ rm -f /tmp/scratch/* infile=${@: -1} # Last argument cmd=${*%${!#}} # All but the last argument -csplit --quiet --prefix=/tmp/scratch/opt --suffix-format=%02d.txt $infile '/^result/ +1' '/^cand/ +1' '{*}' +csplit --quiet --prefix=/tmp/scratch/opt --suffix-format=%02d.txt $infile '/^cand/ +1' '{*}' -for i in `ls -v /tmp/scratch/*`; do echo $cmd $i "&& echo";done > /tmp/cmdfile.txt +for i in `ls -v /tmp/scratch/*`; do echo "echo \";$i \"&&" $cmd $i "&& echo";done > /tmp/cmdfile.txt parallel --will-cite -k < /tmp/cmdfile.txt diff --git a/utils/parallel.sh b/utils/parallel.sh new file mode 100755 index 000000000..20a702c00 --- /dev/null +++ b/utils/parallel.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Last argument is assumed to be a dir with multiple inputs + +indir=${@: -1} # Last argument +cmd=${*%${!#}} # All but the last argument + +mkdir -p "${indir}r" + +rm "${indir}r"/* +cp "${indir}"/* "${indir}r" + +mkdir -p "${indir}t" +rm "${indir}t"/* + +for i in `ls -v $indir/*`; do echo "timeout 300" $cmd $i " > " ${indir}t/`basename $i` " && cp " ${indir}t/`basename $i` ${indir}r/ ;done > /tmp/cmdfile.txt + +# for i in `ls -v $indir/*`; do echo "timeout 300" $cmd $i " > " ${indir}r/`basename $i`;done > /tmp/cmdfile.txt + +#parallel --will-cite -k < /tmp/cmdfile.txt From 73cbeaf83f2da5daf5f7775122fab9e7a303a46f Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sat, 22 Oct 2022 09:47:55 -0600 Subject: [PATCH 093/165] foo --- include/souper/Generalize/Reducer.h | 4 + lib/Generalize/Reducer.cpp | 123 +++++++++++++++++++++++++- tools/generalize.cpp | 131 ++++++++++++++++++++++------ 3 files changed, 228 insertions(+), 30 deletions(-) diff --git a/include/souper/Generalize/Reducer.h b/include/souper/Generalize/Reducer.h index b36ff7ca9..2a8027c04 100644 --- a/include/souper/Generalize/Reducer.h +++ b/include/souper/Generalize/Reducer.h @@ -18,6 +18,10 @@ class Reducer { ParsedReplacement ReduceGreedy(ParsedReplacement Input); + ParsedReplacement ReducePairsGreedy(ParsedReplacement Input); + + ParsedReplacement ReduceTriplesGreedy(ParsedReplacement Input); + // Eventually replace the functions in Preconditions{.h/.cpp} with this. // Does not produce exhaustive result. TODO Have an option to wrap in a cegis loop. bool inferKBPrecondition(ParsedReplacement &Input, std::vector Targets); diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index 9b773ec9b..eef066402 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -22,6 +22,126 @@ void collectInsts(Inst *I, std::set &Results) { } } +void collectInstsToDepth(Inst *I, size_t Depth, std::set &Results) { + std::vector Stack{I}; + std::map DepthMap; + DepthMap[I] = 0; + while (!Stack.empty()) { + auto Current = Stack.back(); + Stack.pop_back(); + + if (DepthMap[Current] > Depth) { + continue; + } + Results.insert(Current); + + for (auto Child : Current->Ops) { + DepthMap[Child] = DepthMap[Current] + 1; + if (Results.find(Child) == Results.end()) { + Stack.push_back(Child); + } + } + } +} + +ParsedReplacement Reducer::ReducePairsGreedy(ParsedReplacement Input) { + size_t Depth = 4, Passes = 5; + bool Changed = false; + while (Passes-- ) { + // Try to remove two instructions at a time + std::set Insts; + + collectInstsToDepth(Input.Mapping.LHS, Depth, Insts); + + for (auto &&I : Insts) { + if (!safeToRemove(I, Input)) { + continue; + } + for (auto &&J : Insts) { + if (I != J) { + if (!safeToRemove(J, Input)) { + continue; + } + + auto Copy = Input; + Eliminate(Input, I); + Eliminate(Input, J); + + if (souper::cost(Input.Mapping.LHS) <= souper::cost(Input.Mapping.RHS)) { + Input = Copy; + continue; + } + + if (!VerifyInput(Input)) { + Input = Copy; + continue; + } + Changed = true; + + } + } + } + if (!Changed) { + break; + } + } + + return Input; +} + +ParsedReplacement Reducer::ReduceTriplesGreedy(ParsedReplacement Input) { + size_t Depth = 4, Passes = 2; + bool Changed = false; + while (Passes-- ) { + // Try to remove two instructions at a time + std::set Insts; + + collectInstsToDepth(Input.Mapping.LHS, Depth, Insts); + + for (auto &&I : Insts) { + if (!safeToRemove(I, Input)) { + continue; + } + for (auto &&J : Insts) { + if (I != J) { + if (!safeToRemove(J, Input)) { + continue; + } + + for (auto &&K : Insts) { + if (!safeToRemove(K, Input)) { + continue; + } + if (I != K && J != K) { + + auto Copy = Input; + Eliminate(Input, I); + Eliminate(Input, J); + Eliminate(Input, K); + + if (souper::cost(Input.Mapping.LHS) <= souper::cost(Input.Mapping.RHS)) { + Input = Copy; + continue; + } + + if (!VerifyInput(Input)) { + Input = Copy; + continue; + } + Changed = true; + } + } + } + } + } + if (!Changed) { + break; + } + } + + return Input; +} + ParsedReplacement Reducer::ReduceGreedy(ParsedReplacement Input) { std::set Insts; collectInsts(Input.Mapping.LHS, Insts); @@ -43,7 +163,7 @@ ParsedReplacement Reducer::ReduceGreedy(ParsedReplacement Input) { auto Copy = Input; Eliminate(Input, I); - if (souper::cost(Input.Mapping.LHS) - souper::cost(Input.Mapping.LHS) <= 1) { + if (souper::cost(Input.Mapping.LHS) <= souper::cost(Input.Mapping.RHS)) { Input = Copy; failcount++; if (failcount >= Insts.size()) { @@ -444,7 +564,6 @@ if (V->X) { \ break; } } - } return Input; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 0bfd0fb32..2735645ce 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -683,9 +683,73 @@ std::set findConcreteConsts(Inst *I) { return Ret; } +ParsedReplacement DFPreconditionsAndVerifyGreedy( + ParsedReplacement Input, InstContext &IC, Solver *S, + std::map SymCS) { + + std::map> Restore; + + + size_t BitsWeakened = 0; + + auto Clone = souper::Clone(Input, IC); + + for (auto &&C : SymCS) { + Restore[C.first] = {C.first->KnownZeros, C.first->KnownOnes}; + C.first->KnownZeros = ~C.second; + C.first->KnownOnes = C.second; + } + + ParsedReplacement Ret; + auto SOLVE = [&]() -> bool { + Ret = Verify(Input, IC, S); + if (Ret.Mapping.LHS && Ret.Mapping.RHS) { + return true; + } else { + return false; + } + }; + + for (auto &&C : SymCS) { + for (size_t i = 0; i < C.first->Width; ++i) { + llvm::APInt OriZ = C.first->KnownZeros; + llvm::APInt OriO = C.first->KnownOnes; + + if (OriO[i] == 0 && OriZ[i] == 0) { + continue; + } + + if (OriO[i] == 1) C.first->KnownOnes.clearBit(i); + if (OriZ[i] == 1) C.first->KnownZeros.clearBit(i); + + if (!SOLVE()) { + C.first->KnownZeros = OriZ; + C.first->KnownOnes = OriO; + } else { + BitsWeakened++; + } + } + } + + if (BitsWeakened >= 32) { // compute better threshold somehow + return Input; + } else { + for (auto &&P : Restore) { + P.first->KnownZeros = P.second.first; + P.first->KnownOnes = P.second.second; + } + Clone.Mapping.LHS = nullptr; + Clone.Mapping.RHS = nullptr; + return Clone; + } + +} + ParsedReplacement SimplePreconditionsAndVerifyGreedy( ParsedReplacement Input, InstContext &IC, Solver *S, std::map SymCS) { + // Assume Input is not valid + ParsedReplacement Clone; Clone.Mapping.LHS = nullptr; Clone.Mapping.RHS = nullptr; @@ -716,10 +780,10 @@ ParsedReplacement SimplePreconditionsAndVerifyGreedy( } } - #define DF(Fact, Check) \ if (All(CVals[C], [](auto Val) { return Check;})) { \ -C->Fact = true; if (SOLVE()) return Clone; C->Fact = false;}; +C->Fact = true; auto s = SOLVE(); C->Fact = false; \ +if(s) return Clone;}; for (auto &&P : SymCS) { auto C = P.first; @@ -740,7 +804,9 @@ FirstValidCombination(ParsedReplacement Input, const std::vector> &Candidates, std::map InstCache, InstContext &IC, Solver *S, - std::map SymCS, bool SDF = false) { + std::map SymCS, + bool SDF = false, + bool DFF = false) { std::vector Counts; for (auto &&Cand : Candidates) { Counts.push_back(Cand.size()); @@ -770,9 +836,16 @@ FirstValidCombination(ParsedReplacement Input, if (SDF) { Clone = SimplePreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } } - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; + + if (DFF) { + Clone = DFPreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } } } @@ -805,12 +878,12 @@ InferSimpleConstExprs(std::vector RHS, std::set // RC = LC * (RV / LV) only if no remainder - if (RV.urem(LV) == 0) { + if (LV != 0 && RV.urem(LV) == 0) { Result.back().push_back(Builder(SMap[LC], IC).Mul(RV.udiv(LV))()); } // RC = LC / (RV * LV) only if no remainder - if (RV.urem(LV) == 0) { + if (LV != 0 && RV!= 0 && RV.urem(LV) == 0) { Result.back().push_back(Builder(SMap[LC], IC).UDiv(RV * LV)()); } @@ -893,7 +966,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, SymConstMap[I] = IC.createVar(I->Width, "symconst_" + std::to_string(i++)); InstCache[I] = SymConstMap[I]; - SymCS[SymConstMap[I]] = I->Val; +// SymCS[SymConstMap[I]] = I->Val; } // llvm::errs() << "POST Prelude.\n"; @@ -919,6 +992,11 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Clone; } + Clone = DFPreconditionsAndVerifyGreedy(Result, IC, S, SymCS); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } // llvm::errs() << "POST 1.\n"; @@ -954,11 +1032,21 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // llvm::errs() << "POST 1.5\n"; // Step 2 : Symbolize LHS Consts with KB, CR, SimpleDF constrains + { + auto Copy = Replace(Input, IC, JustLHSSymConstMap); + + auto Clone = SimplePreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + + Clone = DFPreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } - Copy = Replace(Input, IC, JustLHSSymConstMap); - // TODO: write precondition inference for a given set of variables. - // TODO: Do this today!! // llvm::errs() << "POST 2\n"; @@ -978,7 +1066,8 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, InferSimpleConstExprs(RHSFresh, LHSConsts, SymConstMap, IC); auto Clone = FirstValidCombination(Input, RHSFresh, Candidates, - InstCache, IC, S, SymCS, true); + InstCache, IC, S, SymCS, + true, true); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } @@ -1133,28 +1222,14 @@ void GeneralizeBitWidth(InstContext &IC, Solver *S, } -void collectInsts(Inst *I, std::set &Results) { - std::vector Stack{I}; - while (!Stack.empty()) { - auto Current = Stack.back(); - Stack.pop_back(); - - Results.insert(Current); - - for (auto Child : Current->Ops) { - if (Results.find(Child) == Results.end()) { - Stack.push_back(Child); - } - } - } -} - ParsedReplacement ReduceBasic(InstContext &IC, Solver *S, ParsedReplacement Input) { Reducer R(IC, S); Input = R.ReducePCs(Input); Input = R.ReduceRedundantPhis(Input); Input = R.ReduceGreedy(Input); + Input = R.ReducePairsGreedy(Input); + Input = R.ReduceTriplesGreedy(Input); Input = R.WeakenKB(Input); Input = R.WeakenCR(Input); Input = R.WeakenDB(Input); From 2d2f64fe1fa132c0477a0857a0fede773b3ee723 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sat, 22 Oct 2022 14:43:29 -0600 Subject: [PATCH 094/165] foo --- tools/generalize.cpp | 4 +-- tools/souper-check.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 2735645ce..db6a241b5 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -864,10 +864,10 @@ InferSimpleConstExprs(std::vector RHS, std::set auto RV = RC->Val; Result.push_back({}); for (auto &&LC : LHS) { - if (LC->Width != RC->Width) { + auto LV = LC->Val; + if (LC->Width != RC->Width || LV.getBitWidth() != RV.getBitWidth()) { continue; } - auto LV = LC->Val; // TODO: Check width constraints // RC = LC + (RV - LV) diff --git a/tools/souper-check.cpp b/tools/souper-check.cpp index 47cb883bb..4b92e050b 100644 --- a/tools/souper-check.cpp +++ b/tools/souper-check.cpp @@ -88,6 +88,69 @@ static cl::opt CheckAllGuesses("souper-check-all-guesses", cl::desc("Continue even after a valid RHS is found. (default=false)"), cl::init(false)); +static cl::opt Hash("hash", + cl::desc("Hash a trasnformation."), + cl::init(false)); + + +size_t HashInt(size_t x) { + x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); + x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb); + x = x ^ (x >> 31); + return x; +} + +size_t HashInst(Inst *I, std::map &M, std::set &SeenVars) { + if (M.find(I) != M.end()) { + return M[I]; + } + + size_t Result = 0; + +// if (I->Name != "") { +// Result ^= std::hash()(I->Name); +// } + + Result ^= std::hash()(I->K); + + if (I->K == Inst::Var) { + SeenVars.insert(I); + Result ^= HashInt(SeenVars.size()); + // TODO: DF attributes + M[I] = Result; + } + + if (I->K == Inst::Const) { + Result ^= HashInt(I->Val.getLimitedValue()); + } + + for (size_t i = 0; i < I->Ops.size(); ++i) { + size_t Weight = Inst::isCommutative(I->K) ? 0 : HashInt(i); + + Result ^= (Weight ^ HashInst(I->Ops[i], M, SeenVars)); + } + + M[I] = Result; + return Result; +} + +size_t HashRep(ParsedReplacement Rep) { + std::map M; + std::set SeenVars; + auto Result = HashInst(Rep.Mapping.LHS, M, SeenVars); + Result ^= HashInst(Rep.Mapping.RHS, M, SeenVars); + + // Is this needed? + Result ^= Rep.Mapping.LHS->Width; + + for (auto PC : Rep.PCs) { + Result ^= HashInst(PC.LHS, M, SeenVars); + Result ^= HashInst(PC.RHS, M, SeenVars); + } + + return Result; +} + int SolveInst(const MemoryBufferRef &MB, Solver *S) { InstContext IC; std::string ErrStr; @@ -121,6 +184,11 @@ int SolveInst(const MemoryBufferRef &MB, Solver *S) { int Ret = 0; int Success = 0, Fail = 0, Error = 0; for (auto Rep : Reps) { + if (Hash) { + llvm::outs() << HashRep(Rep) << '\n'; + continue; + } + if (isInferDFA()) { if (InferNeg) { bool Negative; From 1cd3900ec32cb319df9aba3dadd1d84811a030b0 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sat, 22 Oct 2022 14:53:17 -0600 Subject: [PATCH 095/165] foo --- tools/souper-check.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/souper-check.cpp b/tools/souper-check.cpp index 4b92e050b..329ef5128 100644 --- a/tools/souper-check.cpp +++ b/tools/souper-check.cpp @@ -111,7 +111,7 @@ size_t HashInst(Inst *I, std::map &M, std::set &SeenVars // Result ^= std::hash()(I->Name); // } - Result ^= std::hash()(I->K); + Result ^= HashInt(I->K); if (I->K == Inst::Var) { SeenVars.insert(I); From 37f5d27ca8fe91fb7821428e39e96c3ec83d060d Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sat, 22 Oct 2022 18:01:37 -0600 Subject: [PATCH 096/165] foo --- tools/generalize.cpp | 10 ++- tools/matcher-gen.cpp | 116 ++++++++++++++++++++++++-- tools/pass-generator/src/template.cpp | 5 ++ tools/souper-check.cpp | 2 +- 4 files changed, 122 insertions(+), 11 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index db6a241b5..f464e131e 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -750,6 +750,14 @@ ParsedReplacement SimplePreconditionsAndVerifyGreedy( Solver *S, std::map SymCS) { // Assume Input is not valid + std::map NonBools; + for (auto &&C : SymCS) { + if (C.first->Width != 1) { + NonBools.insert(C); + } + } + std::swap(SymCS, NonBools); + ParsedReplacement Clone; Clone.Mapping.LHS = nullptr; Clone.Mapping.RHS = nullptr; @@ -797,7 +805,6 @@ if(s) return Clone;}; return Clone; } - ParsedReplacement FirstValidCombination(ParsedReplacement Input, const std::vector &Targets, @@ -1047,7 +1054,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } - // llvm::errs() << "POST 2\n"; // Step 3 : Simple RHS constant exprs diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 8ba3bf029..ecc993e26 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -1,14 +1,9 @@ #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/GraphWriter.h" -#include "llvm/Support/KnownBits.h" #include "souper/Infer/Preconditions.h" #include "souper/Infer/EnumerativeSynthesis.h" -#include "souper/Infer/ConstantSynthesis.h" -#include "souper/Inst/InstGraph.h" #include "souper/Parser/Parser.h" #include "souper/Tool/GetSolver.h" -#include "souper/Util/DfaUtils.h" #include @@ -31,7 +26,7 @@ InputFilename(cl::Positional, cl::desc(""), static llvm::cl::opt IgnorePCs("ignore-pcs", llvm::cl::desc("Ignore inputs which have souper path conditions." "(default=false)"), - llvm::cl::init(true)); + llvm::cl::init(false)); static llvm::cl::opt IgnoreDF("ignore-df", llvm::cl::desc("Ignore inputs with dataflow constraints." @@ -167,6 +162,14 @@ struct VC : public Constraint { std::string Cons; }; +struct PC : public Constraint { + PC(std::string LHS, std::string RHS) : L(LHS), R(RHS) {} + std::string print() override { + return "(" + L + " == " + R + ")"; + } + std::string L, R; +}; + //struct VarKB : public Constraint { //}; @@ -218,6 +221,81 @@ struct SymbolTable : public std::map> { } } } + + // Try to translate Souper expressions to APInt operations. + std::pair Translate(souper::Inst *I) { + std::vector> Children; + + for (auto Op : I ->Ops) { + Children.push_back(Translate(Op)); + if (!Children.back().second) { + return {"", false}; + } + } + + auto MET = [&](auto Str) { + return Children[0].first + "." + Str + "(" + Children[1].first + ")"; + }; + + auto OP = [&](auto Str) { + return Children[0].first + " " + Str + " " + Children[1].first; + }; + + switch (I->K) { + case Inst::Var : return {"util::V(" + at(I)[0] + ")", true}; + case Inst::Const : return {I->Val.toString(10, false), true}; + + case Inst::AddNW : + case Inst::AddNUW : + case Inst::AddNSW : + case Inst::Add : return {OP("+"), true}; + + case Inst::SubNW : + case Inst::SubNUW : + case Inst::SubNSW : + case Inst::Sub : return {OP("-"), true}; + + case Inst::MulNW : + case Inst::MulNUW : + case Inst::MulNSW : + case Inst::Mul : return {OP("*"), true}; + + case Inst::Shl : return {MET("shl"), true}; + case Inst::LShr : return {MET("lshr"), true}; + case Inst::AShr : return {MET("ashr"), true}; + + case Inst::And : return {OP("&"), true}; + case Inst::Or : return {OP("|"), true}; + case Inst::Xor : return {OP("^"), true}; + + case Inst::URem : return {MET("urem"), true}; + case Inst::SRem : return {MET("srem"), true}; + case Inst::UDiv : return {MET("udiv"), true}; + case Inst::SDiv : return {MET("sdiv"), true}; + + case Inst::Slt : return {MET("slt"), true}; + case Inst::Sle : return {MET("sle"), true}; + case Inst::Ult : return {MET("ult"), true}; + case Inst::Ule : return {MET("ule"), true}; + case Inst::Eq : return {MET("eq"), true}; + case Inst::Ne : return {MET("ne"), true}; + + default: return {"", false}; + } + + } + + bool GenPCConstraints(std::vector PCs) { + for (auto M : PCs) { + auto L = Translate(M.LHS); + auto R = Translate(M.RHS); + if (!L.second || !R.second) { + return false; + } + Constraints.push_back(new PC(L.first, R.first)); + } + return true; + } void GenDomConstraints(Inst *RHS) { static std::set Visited; @@ -511,6 +589,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { } Out << ")) {\n"; + if (!Syms.GenPCConstraints(Input.PCs)) return false; Syms.GenVarEqConstraints(); Syms.GenVarPropConstraints(Input.Mapping.LHS); Syms.GenDomConstraints(Input.Mapping.RHS); @@ -556,6 +635,22 @@ int profitability(const ParsedReplacement &Input) { souper::cost(Input.Mapping.RHS); } +bool PCHasVar(const ParsedReplacement &Input) { + std::vector Vars; + for (auto &&PC : Input.PCs) { + findVars(PC.LHS, Vars); + findVars(PC.RHS, Vars); + } + + for (auto &&V : Vars) { + if (!V->Name.starts_with("sym")) { + return true; + } + } + + return false; +} + int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); KVStore *KV = 0; @@ -611,11 +706,13 @@ int main(int argc, char **argv) { Inst::Kind Last = Inst::Kind::None; bool first = true; + bool outputs = false; for (auto &&Input: Inputs) { - if (IgnorePCs && !Input.PCs.empty()) { + if (PCHasVar(Input)) { continue; } + if (Input.Mapping.LHS == Input.Mapping.RHS) { continue; } @@ -730,6 +827,7 @@ int main(int argc, char **argv) { llvm::outs() << "*/\n"; llvm::outs() << Str << "\n"; llvm::outs().flush(); + outputs= true; } else { Input.print(llvm::errs(), true); llvm::errs() << "Failed to generate matcher.\n\n\n"; @@ -737,7 +835,9 @@ int main(int argc, char **argv) { llvm::errs().flush(); } } - llvm::outs() << "}\n"; + if (outputs) { + llvm::outs() << "}\n"; + } // llvm::outs() << "end:\n"; return 0; diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 48e49c009..21c587072 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -388,7 +388,12 @@ namespace util { if (llvm::isa(a) || llvm::isa(b)) return false; return true; } + + llvm::APInt V(llvm::Value *V) { + return llvm::dyn_cast(V)->getValue(); + } } + struct SouperCombine : public FunctionPass { static char ID; SouperCombine() : FunctionPass(ID) { diff --git a/tools/souper-check.cpp b/tools/souper-check.cpp index 329ef5128..cae73848d 100644 --- a/tools/souper-check.cpp +++ b/tools/souper-check.cpp @@ -141,7 +141,7 @@ size_t HashRep(ParsedReplacement Rep) { Result ^= HashInst(Rep.Mapping.RHS, M, SeenVars); // Is this needed? - Result ^= Rep.Mapping.LHS->Width; + Result ^= HashInt(Rep.Mapping.LHS->Width); for (auto PC : Rep.PCs) { Result ^= HashInst(PC.LHS, M, SeenVars); From fe69f410dd34bd4dacaf6118aa5c6b62e1d07274 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sat, 22 Oct 2022 20:08:28 -0600 Subject: [PATCH 097/165] foo --- tools/souper-check.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/souper-check.cpp b/tools/souper-check.cpp index cae73848d..663d19eed 100644 --- a/tools/souper-check.cpp +++ b/tools/souper-check.cpp @@ -127,7 +127,7 @@ size_t HashInst(Inst *I, std::map &M, std::set &SeenVars for (size_t i = 0; i < I->Ops.size(); ++i) { size_t Weight = Inst::isCommutative(I->K) ? 0 : HashInt(i); - Result ^= (Weight ^ HashInst(I->Ops[i], M, SeenVars)); + Result ^= (Weight + HashInst(I->Ops[i], M, SeenVars)); } M[I] = Result; @@ -138,7 +138,8 @@ size_t HashRep(ParsedReplacement Rep) { std::map M; std::set SeenVars; auto Result = HashInst(Rep.Mapping.LHS, M, SeenVars); - Result ^= HashInst(Rep.Mapping.RHS, M, SeenVars); + Result ^= 7* HashInst(Rep.Mapping.RHS, M, SeenVars); + // Just ^ produces weird conflicts for very different trees // Is this needed? Result ^= HashInt(Rep.Mapping.LHS->Width); From af0b4672458aa6a54e1f58d5d0061e0a32a265ad Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 23 Oct 2022 20:22:31 -0600 Subject: [PATCH 098/165] foo --- lib/Extractor/Solver.cpp | 2 +- lib/Inst/Inst.cpp | 2 +- tools/generalize.cpp | 268 ++++++++++++++++++++++++++++----------- 3 files changed, 198 insertions(+), 74 deletions(-) diff --git a/lib/Extractor/Solver.cpp b/lib/Extractor/Solver.cpp index cf557bf25..435eb9135 100644 --- a/lib/Extractor/Solver.cpp +++ b/lib/Extractor/Solver.cpp @@ -433,7 +433,7 @@ class BaseSolver : public Solver { return EC; } - RHSs.clear(); +// RHSs.clear(); return EC; } diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index 23550f502..63979d8b4 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -1159,7 +1159,7 @@ void souper::findInsts(Inst *Root, std::vector &Insts, std::function &Visited, std::set &ConstSet) { - if (I->K == Inst::Var && I->SynthesisConstID != 0) { + if (I->K == Inst::Var && (I->SynthesisConstID != 0 || I->Name.starts_with("reserved"))) { ConstSet.insert(I); } else { if (Visited.insert(I).second) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index f464e131e..a9336ece6 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -81,7 +81,7 @@ static llvm::cl::opt SymbolizeKBDF("symbolize-infer-kb", static llvm::cl::opt SymbolizeConstSynthesis("symbolize-constant-synthesis", llvm::cl::desc("Allow concrete constants in the generated code."), - llvm::cl::init(true)); + llvm::cl::init(false)); static llvm::cl::opt SymbolizeHackersDelight("symbolize-bit-hacks", llvm::cl::desc("Include bit hacks in the components."), @@ -749,7 +749,6 @@ ParsedReplacement SimplePreconditionsAndVerifyGreedy( ParsedReplacement Input, InstContext &IC, Solver *S, std::map SymCS) { // Assume Input is not valid - std::map NonBools; for (auto &&C : SymCS) { if (C.first->Width != 1) { @@ -795,9 +794,9 @@ if(s) return Clone;}; for (auto &&P : SymCS) { auto C = P.first; - DF(PowOfTwo, Val.isPowerOf2()) - DF(NonZero, Val != 0); + DF(PowOfTwo, Val.isPowerOf2()); DF(NonNegative, Val.uge(0)); + DF(NonZero, Val != 0); DF(Negative, Val.slt(0)); } #undef DF @@ -812,8 +811,9 @@ FirstValidCombination(ParsedReplacement Input, std::map InstCache, InstContext &IC, Solver *S, std::map SymCS, - bool SDF = false, - bool DFF = false) { + bool GEN, + bool SDF, + bool DFF) { std::vector Counts; for (auto &&Cand : Candidates) { Counts.push_back(Cand.size()); @@ -821,39 +821,88 @@ FirstValidCombination(ParsedReplacement Input, auto Combinations = GetCombinations(Counts); + size_t IterLimit = 2000; + size_t CurIter = 0; + for (auto &&Comb : Combinations) { + if (CurIter >= IterLimit) { + break; + } else { + CurIter++; + } + static int SymExprCount = 0; auto InstCacheRHS = InstCache; + + std::vector VarsFound; + for (int i = 0; i < Targets.size(); ++i) { InstCacheRHS[Targets[i]] = Candidates[i][Comb[i]]; + findVars(Candidates[i][Comb[i]], VarsFound); if (Candidates[i][Comb[i]]->K != Inst::Var) { Candidates[i][Comb[i]]->Name = std::string("constexpr_") + std::to_string(SymExprCount++); } } - auto Copy = Replace(Input, IC, InstCacheRHS); - -// Copy.print(llvm::errs(), true); + std::set SymsInCurrent; + for (auto &&V : VarsFound) { + if (V->Name.starts_with("sym")) { + SymsInCurrent.insert(V); + } + } - auto Clone = Verify(Copy, IC, S); + std::map ReverseMap; - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; + for (auto &&[C, Val] : SymCS) { + if (SymsInCurrent.find(C) == SymsInCurrent.end()) { + ReverseMap[C] = Builder(IC, Val)(); + } } - if (SDF) { - Clone = SimplePreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; + auto Clone = Input; + Clone.Mapping.LHS = nullptr; + Clone.Mapping.RHS = nullptr; + + auto SOLVE = [&](ParsedReplacement P) -> bool { +// P.print(llvm::errs(), true); +// llvm::errs() << "\n"; + + if (GEN) { + Clone = Verify(P, IC, S); + + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return true; + } } - } - if (DFF) { - Clone = DFPreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; + if (DFF) { + Clone = DFPreconditionsAndVerifyGreedy(P, IC, S, SymCS); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return true; + } + } + + if (SDF) { + Clone = SimplePreconditionsAndVerifyGreedy(P, IC, S, SymCS); + + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return true; + } } + + return false; + }; + + auto Copy = Replace(Input, IC, InstCacheRHS); + if (SOLVE(Copy)) { + return Clone; } + + Copy = Replace(Copy, IC, ReverseMap); + if (SOLVE(Copy)) { + return Clone; + } + } Input.Mapping.LHS = nullptr; @@ -907,12 +956,16 @@ InferSimpleConstExprs(std::vector RHS, std::set } std::vector> Enumerate(std::vector RHSConsts, - std::set LHSConsts, InstContext &IC) { + std::set LHSConsts, InstContext &IC, + size_t NumInsts = 1) { std::vector> Candidates; std::vector Components; for (auto &&C : LHSConsts) { Components.push_back(C); + Components.push_back(Builder(C, IC).Sub(1)()); + Components.push_back(Builder(C, IC).Xor(-1)()); + Components.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C->Width)).Shl(C)()); } // TODO: Custom components @@ -920,7 +973,7 @@ std::vector> Enumerate(std::vector RHSConsts, for (auto &&Target : RHSConsts) { Candidates.push_back({}); EnumerativeSynthesis ES; - auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, + auto Guesses = ES.generateExprs(IC, NumInsts, Components, Target->Width); for (auto &&Guess : Guesses) { std::set ConstSet; @@ -930,7 +983,7 @@ std::vector> Enumerate(std::vector RHSConsts, Candidates.back().push_back(Guess); } } else { - Candidates.back().push_back(Guess); + Candidates.back().push_back(Guess); } } } @@ -946,6 +999,14 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Prelude + auto Fresh = Clone(Input, IC); + + auto Refresh = [&] (auto Msg) { + Input = Fresh; + llvm::errs() << "POST " << Msg << "\n"; + return Fresh; + }; + auto LHSConsts = findConcreteConsts(Input.Mapping.LHS); auto RHSConsts = findConcreteConsts(Input.Mapping.RHS); @@ -976,7 +1037,15 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // SymCS[SymConstMap[I]] = I->Val; } -// llvm::errs() << "POST Prelude.\n"; + std::vector RHSFresh; // RHSConsts - LHSConsts + + for (auto C : RHSConsts) { + if (LHSConsts.find(C) == LHSConsts.end()) { + RHSFresh.push_back(C); + } + } + + Refresh("Prelude"); // Step 1 : Just direct symbolize for common consts, no constraints std::map CommonConsts; @@ -1006,7 +1075,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } -// llvm::errs() << "POST 1.\n"; + Refresh(1); // Step 1.5 : Direct symbolize, simple rel constraints on LHS @@ -1025,7 +1094,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } // Maybe call InferPreconditionsAndVerify instead of Verify? - // TODO: Are these matched yet? + auto Copy = Replace(Input, IC, JustLHSSymConstMap); for (auto &&R : Relations) { Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); @@ -1036,10 +1105,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Copy.PCs.pop_back(); } -// llvm::errs() << "POST 1.5\n"; + Refresh(1.5); // Step 2 : Symbolize LHS Consts with KB, CR, SimpleDF constrains - { + if (RHSFresh.empty()) { auto Copy = Replace(Input, IC, JustLHSSymConstMap); auto Clone = SimplePreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); @@ -1047,83 +1116,138 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Clone; } + Refresh(1.51); + Clone = DFPreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } } - - -// llvm::errs() << "POST 2\n"; + Refresh(2); // Step 3 : Simple RHS constant exprs - std::vector RHSFresh; // RHSConsts - LHSConsts + if (!RHSFresh.empty()) { - for (auto C : RHSConsts) { - if (LHSConsts.find(C) == LHSConsts.end()) { - RHSFresh.push_back(C); + std::vector> SimpleCandidates = + InferSimpleConstExprs(RHSFresh, LHSConsts, SymConstMap, IC); + + if (!SimpleCandidates.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, + InstCache, IC, S, SymCS, + true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } } - if (!RHSFresh.empty()) { + Refresh(3); - std::vector> Candidates = - InferSimpleConstExprs(RHSFresh, LHSConsts, SymConstMap, IC); + // Step 4 : Enumerated expressions - auto Clone = FirstValidCombination(Input, RHSFresh, Candidates, - InstCache, IC, S, SymCS, - true, true); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; + std::set Components; + for (auto C : LHSConsts) { + Components.insert(SymConstMap[C]); } -// llvm::errs() << "POST 3\n"; + auto EnumeratedCandidates = Enumerate(RHSFresh, Components, IC); - // Step 3.5: Simple RHS exprs with constraints + if (!EnumeratedCandidates.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + Refresh(4); - for (auto &&R : Relations) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + // Enumerated Expressions with some relational constraints + if (CMap.size() == 2) { + for (auto &&R : Relations) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } + } + Refresh(4.5); + } + + // Step 4.75 : Enumerate 2 instructions when single RHS Constant. + if (RHSFresh.size() == 1) { + auto EnumeratedCandidates = Enumerate(RHSFresh, Components, IC, 2); - auto Clone = FirstValidCombination(Input, RHSFresh, Candidates, - InstCache, IC, S, SymCS, false); + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, false, false); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } + Refresh(4.75); - Input.PCs.pop_back(); + // Enumerated Expressions with some relational constraints + if (CMap.size() == 2) { + for (auto &&R : Relations) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } + Refresh(4.76); + } } -// llvm::errs() << "POST 3\n"; - // Step 4 : Synthesized RHS exprs, no constant synthesis - Candidates = Enumerate(RHSFresh, LHSConsts, IC); + // Step 5 : Simple exprs with constraints - Clone = FirstValidCombination(Input, RHSFresh, Candidates, - InstCache, IC, S, SymCS, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } + if (!SimpleCandidates.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, + InstCache, IC, S, SymCS, false, true, true); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + Refresh(5); - Clone = FirstValidCombination(Input, RHSFresh, Candidates, - InstCache, IC, S, SymCS, true); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } + for (auto &&R : Relations) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - // Step 4.1 : Synthesized RHS exprs, weakened KB. CR? - // TODO + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, + InstCache, IC, S, SymCS, true, true, true); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } - // Step 4.5 : Synthesized RHS constant exprs, no constant synthesis, rel preconditions - for (auto &&R : Relations) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + Input.PCs.pop_back(); + } + Refresh(5.1); + } + + // Step 6 : Enumerated exprs with constraints - auto Clone = FirstValidCombination(Input, RHSFresh, Candidates, - InstCache, IC, S, SymCS, false); + if (!EnumeratedCandidates.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, true, true); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } + + Refresh(6); + + for (auto &&R : Relations) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, false, true, true); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } + Refresh(6.1); } } return Input; @@ -1274,7 +1398,7 @@ std::vector ReduceAndGeneralize(InstContext &IC, } Input = R.ReducePCs(Input); - llvm::outs() << "HERE5\n"; +// llvm::outs() << "HERE5\n"; Input.print(llvm::outs(), true); return {Input.getString(true)}; From e17e17a91cef9670b62aa78652012693344259df Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 24 Oct 2022 20:09:26 -0600 Subject: [PATCH 099/165] foo --- include/souper/Generalize/Reducer.h | 2 + lib/Generalize/Reducer.cpp | 112 ++++++++++++++++++++++++++ tools/generalize.cpp | 1 + tools/matcher-gen.cpp | 44 ++++++++-- tools/pass-generator/src/template.cpp | 54 ++++++++----- 5 files changed, 188 insertions(+), 25 deletions(-) diff --git a/include/souper/Generalize/Reducer.h b/include/souper/Generalize/Reducer.h index 2a8027c04..a228aa2e2 100644 --- a/include/souper/Generalize/Reducer.h +++ b/include/souper/Generalize/Reducer.h @@ -41,6 +41,8 @@ class Reducer { ParsedReplacement WeakenOther(ParsedReplacement Input); + ParsedReplacement ReducePCsToDF(ParsedReplacement Input); + bool VerifyInput(ParsedReplacement &Input); bool safeToRemove(Inst *I, ParsedReplacement &Input); diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index eef066402..7d1661a13 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -411,6 +411,118 @@ ParsedReplacement Reducer::ReduceRedundantPhis(ParsedReplacement Input) { return Input; } +size_t WeakenSingleKB(ParsedReplacement Input, InstContext &IC, Solver *S, + Inst *Target, std::optional Val) { + size_t BitsWeakened = 0; + + if (Target->Width <= 8) return 0; // hack + + if (!Val.has_value()) { + // Synthesize a value + Inst *C = IC.createVar(Target->Width, "reservedconst_1"); + C->SynthesisConstID = 1; + std::map InstCache = {{Target, C}}; + + auto Copy = Input; + + auto Rep = Replace(Input, IC, InstCache); + + std::set ConstSet{C}; + + std::map ConstMap; + ConstantSynthesis CS; + +// Rep.print(llvm::errs(), true); + + if (auto EC = CS.synthesize(S->getSMTLIBSolver(), Rep.BPCs, + Rep.PCs, Rep.Mapping, ConstSet, ConstMap, IC, 30, 60, false)) { + llvm::errs() << "Constant Synthesis internal error : " << EC.message(); + } + + if (!ConstMap.empty()) { + Val = ConstMap[C]; + } + + } + + if (!Val.has_value()) { + return 0; // No bits weakened + } + + ParsedReplacement Ret; + auto SOLVE = [&]() -> bool { + Ret = Verify(Input, IC, S); + if (Ret.Mapping.LHS && Ret.Mapping.RHS) { + return true; + } else { + return false; + } + }; + + llvm::APInt RestoreZero = Target->KnownZeros; + llvm::APInt RestoreOne = Target->KnownOnes; + + Target->KnownOnes = Val.value(); + Target->KnownZeros = ~Val.value(); + + for (size_t i = 0; i < Target->Width; ++i) { + llvm::APInt OriZ = Target->KnownZeros; + llvm::APInt OriO = Target->KnownOnes; + + if (OriO[i] == 0 && OriZ[i] == 0) { + continue; + } + + if (OriO[i] == 1) Target->KnownOnes.clearBit(i); + if (OriZ[i] == 1) Target->KnownZeros.clearBit(i); + + if (!SOLVE()) { + Target->KnownZeros = OriZ; + Target->KnownOnes = OriO; + } else { + BitsWeakened++; + } + } + + if (BitsWeakened < Target->Width / 2) { + Target->KnownOnes = RestoreOne; + Target->KnownZeros = RestoreZero; + BitsWeakened = 0; + } + + return BitsWeakened; +} + +ParsedReplacement Reducer::ReducePCsToDF(ParsedReplacement Input) { + std::vector FoundVars; + for (auto &&PC : Input.PCs) { + findVars(PC.LHS, FoundVars); + findVars(PC.RHS, FoundVars); + } + std::set Vars; + for (auto &&V : FoundVars) { + if (!V->Name.starts_with("sym") && !V->Name.starts_with("const")) { + Vars.insert(V); + } + } + + auto Backup = Input.PCs; + Input.PCs.clear(); + + bool Succ = false; + + for (auto &&V : Vars) { + auto BitsWeakened = WeakenSingleKB(Input, IC, S, V, {}); + Succ |= (BitsWeakened != 0); + } + + if (!Succ) { + Input.PCs = Backup; + } + + return Input; +} + // Assumes Input is valid ParsedReplacement Reducer::ReducePCs(ParsedReplacement Input) { diff --git a/tools/generalize.cpp b/tools/generalize.cpp index a9336ece6..37707d449 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1368,6 +1368,7 @@ ParsedReplacement ReduceBasic(InstContext &IC, Input = R.ReduceGreedyKBIFY(Input); } Input = R.ReducePCs(Input); + Input = R.ReducePCsToDF(Input); return Input; } diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index ecc993e26..53bef0734 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -31,7 +31,7 @@ static llvm::cl::opt IgnorePCs("ignore-pcs", static llvm::cl::opt IgnoreDF("ignore-df", llvm::cl::desc("Ignore inputs with dataflow constraints." "(default=false)"), - llvm::cl::init(true)); + llvm::cl::init(false)); static llvm::cl::opt ListFile("listfile", llvm::cl::desc("List of optimization indexes to include.\n" @@ -170,6 +170,14 @@ struct PC : public Constraint { std::string L, R; }; +struct DB : public Constraint { + DB(std::string Val_) : Val(Val_) {} + std::string print() override { + return "util::vdb(DB, I, \"" + Val + "\")"; + } + std::string Val; +}; + //struct VarKB : public Constraint { //}; @@ -243,7 +251,8 @@ struct SymbolTable : public std::map> { switch (I->K) { case Inst::Var : return {"util::V(" + at(I)[0] + ")", true}; - case Inst::Const : return {I->Val.toString(10, false), true}; + case Inst::Const : return {"util::V(" + std::to_string(I->Width) + + ", " + I->Val.toString(10, false) + ")", true}; case Inst::AddNW : case Inst::AddNUW : @@ -315,6 +324,16 @@ struct SymbolTable : public std::map> { } } + void GenDFConstraints(Inst *LHS) { + if (LHS->DemandedBits.getBitWidth() + == LHS->Width && !LHS->DemandedBits.isAllOnesValue()) { + Constraints.push_back(new DB(LHS->DemandedBits.toString(2, false))); + } + + // TODO KB and CR + + } + void GenVarPropConstraints(Inst *LHS) { std::vector Vars; findVars(LHS, Vars); @@ -593,6 +612,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { Syms.GenVarEqConstraints(); Syms.GenVarPropConstraints(Input.Mapping.LHS); Syms.GenDomConstraints(Input.Mapping.RHS); + Syms.GenDFConstraints(Input.Mapping.LHS); Syms.PrintConstraintsPre(Out); Out << " St.hit(" << OptID << ");\n"; @@ -709,16 +729,25 @@ int main(int argc, char **argv) { bool outputs = false; for (auto &&Input: Inputs) { + auto SKIP = [&] (auto Msg) { + Input.print(llvm::errs(), true); + llvm::errs() << Msg << "\n\n\n"; + llvm::errs().flush(); + }; + if (PCHasVar(Input)) { + SKIP("SKIP PC has var."); continue; } if (Input.Mapping.LHS == Input.Mapping.RHS) { + SKIP("SKIP LHS = RHS."); continue; } if (IgnoreDF) { if (Input.Mapping.LHS->DemandedBits.getBitWidth() == Input.Mapping.LHS->Width && !Input.Mapping.LHS->DemandedBits.isAllOnesValue()) { + continue; } std::vector Vars; @@ -739,7 +768,10 @@ int main(int argc, char **argv) { // continue; // } } - if (found) continue; + if (found) { + SKIP("SKIP Unsupported DF."); + continue; + } } if (Input.Mapping.LHS->K != Last) { @@ -820,6 +852,7 @@ int main(int argc, char **argv) { Out.flush(); Str.clear(); llvm::errs() << "Opt " << current << " skipped on demand.\n"; + SKIP("SKIP Filtered."); continue; } llvm::outs() << "/* Opt : " << current << "\n"; @@ -829,10 +862,7 @@ int main(int argc, char **argv) { llvm::outs().flush(); outputs= true; } else { - Input.print(llvm::errs(), true); - llvm::errs() << "Failed to generate matcher.\n\n\n"; - - llvm::errs().flush(); + SKIP("SKIP Failed to generate matcher."); } } if (outputs) { diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 21c587072..ff8cea1d2 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -15,6 +15,8 @@ #include "llvm/InitializePasses.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/Analysis/ValueTracking.h" +#include "llvm/Analysis/DemandedBits.h" +#include "llvm/Analysis/AssumptionCache.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Support/Debug.h" #define DEBUG_TYPE "" @@ -84,30 +86,30 @@ template struct phi_match { phi_match(Args... args) : Matchers{args...} {}; std::tuple Matchers; + + // cpp weirdness for accessing specific tuple element in runtime + template + void runtime_get(Func func, Tuple& tup, size_t idx) { + if (N == idx) { + std::invoke(func, std::get(tup)); + return; + } + + if constexpr (N + 1 < std::tuple_size_v) { + return runtime_get(func, tup, idx); + } + } bool match_nth(size_t n, Value *V) { - switch (n) { - case 0 : return std::get<0>(Matchers).match(V); - case 1 : return std::get<1>(Matchers).match(V); - // case 2 : return std::get<2>(Matchers).match(V); - // case 3 : return std::get<3>(Matchers).match(V); - // case 4 : return std::get<4>(Matchers).match(V); - default: return false; - // TODO Add more if needed. - } + bool Ret = false; + auto F = [&](auto M) {Ret = M.match(V);}; + runtime_get(F, Matchers, n); + return Ret; } bool check(const Value *V) { if (auto Phi = dyn_cast(V)) { for (size_t i =0; i < Phi->getNumOperands(); ++i) { - // bool Matched = false; - // std::apply([&](auto &&... args){ - // ((Matched |= args.match(Phi->getOperand(i))), ...); - // }, Matchers); - - // if (!Matched) { - // return false; - // } if (!match_nth(i, Phi->getOperand(i))) { return false; } @@ -122,7 +124,6 @@ struct phi_match { } }; -// TODO Test semantics, it compiles and runs. template phi_match m_Phi(Args... args) { return phi_match(args...); @@ -337,6 +338,15 @@ namespace util { return false; } + bool vdb(llvm::DemandedBits *DB, llvm::Instruction *I, std::string DBUnderApprox) { + llvm::APInt V = llvm::APInt(I->getType()->getIntegerBitWidth(), DBUnderApprox, 2); + auto ComputedDB = DB->getDemandedBits(I); + + // 0 in DBUnderApprox implies 0 in ComputedDB + return (V | ~ComputedDB) != 0; + // TODO Carefully think about this. + } + bool nz(llvm::Value *V) { if (ConstantInt *Con = llvm::dyn_cast(V)) { return !Con->getValue().isZero(); @@ -392,6 +402,9 @@ namespace util { llvm::APInt V(llvm::Value *V) { return llvm::dyn_cast(V)->getValue(); } + llvm::APInt V(size_t Width, size_t Val) { + return llvm::APInt(Width, Val); + } } struct SouperCombine : public FunctionPass { @@ -403,7 +416,9 @@ struct SouperCombine : public FunctionPass { } bool runOnFunction(Function &F) override { + AssumptionCache AC(F); DT = new DominatorTree(F); + DB = new DemandedBits(F, AC, *DT); W.reserve(F.getInstructionCount()); for (auto &BB : F) { @@ -415,6 +430,8 @@ struct SouperCombine : public FunctionPass { // llvm::errs() << "Before:\n" << F; auto r = run(Builder); // llvm::errs() << "After:\n" << F; + delete DB; + delete DT; return r; } @@ -469,6 +486,7 @@ struct SouperCombine : public FunctionPass { InstructionWorklist W; util::Stats St; DominatorTree *DT; + DemandedBits *DB; }; } From 73a67f906fdc6cdd0418a6a44c998e1526f8ec93 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 24 Oct 2022 23:52:53 -0600 Subject: [PATCH 100/165] foo --- tools/generalize.cpp | 2 +- tools/matcher-gen.cpp | 1 + tools/pass-generator/src/template.cpp | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 37707d449..1607714c2 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1003,7 +1003,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Refresh = [&] (auto Msg) { Input = Fresh; - llvm::errs() << "POST " << Msg << "\n"; +// llvm::errs() << "POST " << Msg << "\n"; return Fresh; }; diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 53bef0734..4b85540ae 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -840,6 +840,7 @@ int main(int argc, char **argv) { default: llvm::outs() << "true"; } llvm::outs() << ") {\n"; + outputs = true; } Last = Input.Mapping.LHS->K; diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index ff8cea1d2..f712ce99d 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -456,9 +456,9 @@ struct SouperCombine : public FunctionPass { } Value *getReplacement(llvm::Instruction *I, IRBuilder *B) { - if (!I->hasOneUse()) { - return nullptr; - } +// if (!I->hasOneUse()) { +// return nullptr; +// } // Interestingly commenting out ^this block // slightly improves results. From 51ef4fd0a85efdcc811aa211cae408094a0ae4f0 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 24 Oct 2022 23:57:48 -0600 Subject: [PATCH 101/165] foo --- utils/cache_to_dir.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/utils/cache_to_dir.py b/utils/cache_to_dir.py index 9ed7ea2c6..70cd30d8a 100644 --- a/utils/cache_to_dir.py +++ b/utils/cache_to_dir.py @@ -3,6 +3,7 @@ r = redis.Redis() n = 0 dir = sys.argv[1] +fails = 0 for key in r.keys(): try: val = r.hgetall(key)[b'result'] @@ -13,4 +14,7 @@ f.write(s) f.close() except KeyError: - pass + fails = fails + 1 + +print("Number of failures = ", fails) + From 0efd8c62e508c50491f12f6daf72c050033c6d28 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 26 Oct 2022 01:52:46 -0600 Subject: [PATCH 102/165] foo --- tools/generalize.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 1607714c2..5962ca6a3 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -991,6 +991,28 @@ std::vector> Enumerate(std::vector RHSConsts, return Candidates; } +void findDangerousConstants(Inst *I, std::set &Results) { + std::set Visited; + std::vector Stack{I}; + while (!Stack.empty()) { + auto Cur = Stack.back(); + Stack.pop_back(); + Visited.insert(Cur); + if (Visited.find(Cur) == Visited.end()) { + continue; + } + for (auto Child : Cur->Ops) { + if (Cur->K == Inst::ExtractValue) { + if (Child->K == Inst::Const) { + // Constant operands of ExtractValue instructions + Results.insert(Child); + } + } + Stack.push_back(Child); + } + } +} + // Assuming the input has leaves pruned and preconditions weakened ParsedReplacement SuccessiveSymbolize(InstContext &IC, Solver *S, ParsedReplacement Input) { @@ -1010,6 +1032,16 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto LHSConsts = findConcreteConsts(Input.Mapping.LHS); auto RHSConsts = findConcreteConsts(Input.Mapping.RHS); + std::set ConstsBlackList; + findDangerousConstants(Input.Mapping.LHS, ConstsBlackList); + findDangerousConstants(Input.Mapping.RHS, ConstsBlackList); + + for (auto &&C : ConstsBlackList) { + LHSConsts.erase(C); + RHSConsts.erase(C); + } + + ParsedReplacement Result = Input; std::map SymConstMap; From 0d45d566e5b8d5ca1e4a0d7a4ee97d8e94b34ff0 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 26 Oct 2022 02:00:04 -0600 Subject: [PATCH 103/165] foo --- tools/generalize.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 5962ca6a3..3d9e4770e 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -367,7 +367,9 @@ std::vector InferPotentialRelations( // Generate a set of pairwise relations for (auto &&[XI, XC] : CMap) { for (auto &&[YI, YC] : CMap) { - if (XI == YI) continue; + if (XI == YI || XC.getBitWidth() != YC.getBitWidth()) { + continue; + } // Add C // auto Diff = XC - YC; // Results.push_back(Builder(XI, IC).Sub(Diff).Eq(YI)()); From 11b616f31dfae5b3538db1ccf1770253f81731a2 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 26 Oct 2022 02:08:31 -0600 Subject: [PATCH 104/165] foo --- lib/Generalize/Reducer.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index 7d1661a13..c9f68784e 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -44,6 +44,10 @@ void collectInstsToDepth(Inst *I, size_t Depth, std::set &Results) { } } +bool IsReductionCostEffective(Inst *LHS, Inst *RHS) { + return souper::instCount(RHS) < souper::instCount(LHS); +} + ParsedReplacement Reducer::ReducePairsGreedy(ParsedReplacement Input) { size_t Depth = 4, Passes = 5; bool Changed = false; @@ -67,7 +71,7 @@ ParsedReplacement Reducer::ReducePairsGreedy(ParsedReplacement Input) { Eliminate(Input, I); Eliminate(Input, J); - if (souper::cost(Input.Mapping.LHS) <= souper::cost(Input.Mapping.RHS)) { + if (!IsReductionCostEffective(Input.Mapping.LHS, Input.Mapping.RHS)) { Input = Copy; continue; } @@ -119,7 +123,7 @@ ParsedReplacement Reducer::ReduceTriplesGreedy(ParsedReplacement Input) { Eliminate(Input, J); Eliminate(Input, K); - if (souper::cost(Input.Mapping.LHS) <= souper::cost(Input.Mapping.RHS)) { + if (!IsReductionCostEffective(Input.Mapping.LHS, Input.Mapping.RHS)) { Input = Copy; continue; } @@ -163,7 +167,7 @@ ParsedReplacement Reducer::ReduceGreedy(ParsedReplacement Input) { auto Copy = Input; Eliminate(Input, I); - if (souper::cost(Input.Mapping.LHS) <= souper::cost(Input.Mapping.RHS)) { + if (!IsReductionCostEffective(Input.Mapping.LHS, Input.Mapping.RHS)) { Input = Copy; failcount++; if (failcount >= Insts.size()) { From 1930c3b6a46b6fe4b793f179ef4c0db95c07e272 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 26 Oct 2022 10:54:32 -0600 Subject: [PATCH 105/165] foo --- lib/Generalize/Reducer.cpp | 2 +- tools/generalize.cpp | 89 ++++++++++++++++++++------------------ 2 files changed, 48 insertions(+), 43 deletions(-) diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index c9f68784e..f35aa861f 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -45,7 +45,7 @@ void collectInstsToDepth(Inst *I, size_t Depth, std::set &Results) { } bool IsReductionCostEffective(Inst *LHS, Inst *RHS) { - return souper::instCount(RHS) < souper::instCount(LHS); + return souper::cost(RHS) < souper::cost(LHS); } ParsedReplacement Reducer::ReducePairsGreedy(ParsedReplacement Input) { diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 3d9e4770e..690d12df0 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1017,17 +1017,18 @@ void findDangerousConstants(Inst *I, std::set &Results) { // Assuming the input has leaves pruned and preconditions weakened ParsedReplacement SuccessiveSymbolize(InstContext &IC, - Solver *S, ParsedReplacement Input) { + Solver *S, ParsedReplacement Input, bool &Changed) { // Print first successful result and exit, no result sorting. // Prelude auto Fresh = Clone(Input, IC); - + Changed = true; auto Refresh = [&] (auto Msg) { Input = Fresh; // llvm::errs() << "POST " << Msg << "\n"; + Changed = false; return Fresh; }; @@ -1109,7 +1110,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } - Refresh(1); + Refresh("Direct Symbolize for common consts"); // Step 1.5 : Direct symbolize, simple rel constraints on LHS @@ -1127,8 +1128,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, JustLHSSymConstMap[C] = SymConstMap[C]; } - // Maybe call InferPreconditionsAndVerify instead of Verify? - auto Copy = Replace(Input, IC, JustLHSSymConstMap); for (auto &&R : Relations) { Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); @@ -1139,7 +1138,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Copy.PCs.pop_back(); } - Refresh(1.5); + Refresh("Direct + simple rel constraints"); // Step 2 : Symbolize LHS Consts with KB, CR, SimpleDF constrains if (RHSFresh.empty()) { @@ -1150,32 +1149,14 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Clone; } - Refresh(1.51); + Refresh("LHS Constraints"); Clone = DFPreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } } - Refresh(2); - - // Step 3 : Simple RHS constant exprs - - if (!RHSFresh.empty()) { - - std::vector> SimpleCandidates = - InferSimpleConstExprs(RHSFresh, LHSConsts, SymConstMap, IC); - - if (!SimpleCandidates.empty()) { - auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, - InstCache, IC, S, SymCS, - true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - } - - Refresh(3); + Refresh("All LHS Constraints"); // Step 4 : Enumerated expressions @@ -1192,7 +1173,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } - Refresh(4); + Refresh("Enumerated cands, no constraints"); // Enumerated Expressions with some relational constraints if (CMap.size() == 2) { @@ -1206,9 +1187,27 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } } } - Refresh(4.5); + Refresh("Some constraints for enumerated cands."); + } + + // Step 3 : Simple RHS constant exprs + + if (!RHSFresh.empty()) { + + std::vector> SimpleCandidates = + InferSimpleConstExprs(RHSFresh, LHSConsts, SymConstMap, IC); + + if (!SimpleCandidates.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, + InstCache, IC, S, SymCS, + true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } } + Refresh("Simple cands with constants"); + // Step 4.75 : Enumerate 2 instructions when single RHS Constant. if (RHSFresh.size() == 1) { auto EnumeratedCandidates = Enumerate(RHSFresh, Components, IC, 2); @@ -1218,7 +1217,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } - Refresh(4.75); + Refresh("Enumerated 2 insts"); // Enumerated Expressions with some relational constraints if (CMap.size() == 2) { @@ -1231,7 +1230,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Clone; } } - Refresh(4.76); + Refresh("Enumerated 2 insts some constraints"); } } @@ -1245,7 +1244,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } - Refresh(5); + Refresh("Simple cands with constraints"); for (auto &&R : Relations) { Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); @@ -1258,7 +1257,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Input.PCs.pop_back(); } - Refresh(5.1); + Refresh("Simple cands with constraints and relations"); } // Step 6 : Enumerated exprs with constraints @@ -1270,20 +1269,21 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Clone; } - Refresh(6); + Refresh("Enumerated exprs with constraints"); for (auto &&R : Relations) { Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, - InstCache, IC, S, SymCS, false, true, true); + InstCache, IC, S, SymCS, true, true, true); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } } - Refresh(6.1); + Refresh("Enumerated exprs with constraints and relations"); } } + Refresh("END"); return Input; } @@ -1514,19 +1514,24 @@ int main(int argc, char **argv) { if (Basic) { ParsedReplacement Result = ReduceBasic(IC, S.get(), Input); if (!JustReduce) { - Result = SuccessiveSymbolize(IC, S.get(), Result); + bool Changed = false; + size_t MaxTries = 4; + do { + Result = ReduceBasic(IC, S.get(), Input); + Result = SuccessiveSymbolize(IC, S.get(), Result, Changed); + } while (MaxTries-- && Changed); } Result.print(llvm::outs(), true); llvm::outs() << "\n"; continue; } - if (Advanced) { - auto Result = SuccessiveSymbolize(IC, S.get(), Input); - Result.print(llvm::outs()); - llvm::outs() << "\n"; - continue; - } +// if (Advanced) { +// auto Result = SuccessiveSymbolize(IC, S.get(), Input); +// Result.print(llvm::outs()); +// llvm::outs() << "\n"; +// continue; +// } if (FixIt) { // TODO: Verify that inputs are valid optimizations From e74d1bfdd8a903693a753f9df9a3144e1c44f272 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 26 Oct 2022 10:56:11 -0600 Subject: [PATCH 106/165] foo --- lib/Generalize/Reducer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index f35aa861f..c9f68784e 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -45,7 +45,7 @@ void collectInstsToDepth(Inst *I, size_t Depth, std::set &Results) { } bool IsReductionCostEffective(Inst *LHS, Inst *RHS) { - return souper::cost(RHS) < souper::cost(LHS); + return souper::instCount(RHS) < souper::instCount(LHS); } ParsedReplacement Reducer::ReducePairsGreedy(ParsedReplacement Input) { From c16f3299ea339b4782cafccdaab05ccb347514d5 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 26 Oct 2022 10:58:51 -0600 Subject: [PATCH 107/165] foo --- tools/generalize.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 690d12df0..85be60e52 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1024,11 +1024,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Prelude auto Fresh = Clone(Input, IC); - Changed = true; auto Refresh = [&] (auto Msg) { Input = Fresh; // llvm::errs() << "POST " << Msg << "\n"; - Changed = false; + Changed = true; return Fresh; }; @@ -1283,6 +1282,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Enumerated exprs with constraints and relations"); } } + Changed = false; Refresh("END"); return Input; } From 41582bb110856ecc277282d40afdcac6a3f7157e Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 26 Oct 2022 16:43:17 -0600 Subject: [PATCH 108/165] foo --- tools/generalize.cpp | 7 ++++--- tools/matcher-gen.cpp | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 85be60e52..29eaf666f 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1282,8 +1282,8 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Enumerated exprs with constraints and relations"); } } - Changed = false; Refresh("END"); + Changed = false; return Input; } @@ -1515,11 +1515,12 @@ int main(int argc, char **argv) { ParsedReplacement Result = ReduceBasic(IC, S.get(), Input); if (!JustReduce) { bool Changed = false; - size_t MaxTries = 4; + size_t MaxTries = 2; do { Result = ReduceBasic(IC, S.get(), Input); Result = SuccessiveSymbolize(IC, S.get(), Result, Changed); - } while (MaxTries-- && Changed); +// Result.print(llvm::errs(), true); + } while (--MaxTries && Changed); } Result.print(llvm::outs(), true); llvm::outs() << "\n"; diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 4b85540ae..88d8a1a37 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -203,6 +203,13 @@ struct SymbolTable : public std::map> { Constraints.push_back(new PredEq(Name, PredNames.at(I->K))); } + bool exists(Inst *I) { + if (find(I) == end()) { + return false; + } + return !at(I).empty(); + } + template void PrintPreds(Stream &Out) { if (Preds.empty()) { @@ -250,8 +257,12 @@ struct SymbolTable : public std::map> { }; switch (I->K) { - case Inst::Var : return {"util::V(" + at(I)[0] + ")", true}; - case Inst::Const : return {"util::V(" + std::to_string(I->Width) + case Inst::Var : if (exists(I)) { + return {"util::V(" + at(I)[0] + ")", true}; + } else { + return {"", false}; + } + case Inst::Const : return {"util::V(" + std::to_string(I->Width) + ", " + I->Val.toString(10, false) + ")", true}; case Inst::AddNW : @@ -608,11 +619,13 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { } Out << ")) {\n"; - if (!Syms.GenPCConstraints(Input.PCs)) return false; + Input.print(llvm::errs(), true); + Syms.GenVarEqConstraints(); Syms.GenVarPropConstraints(Input.Mapping.LHS); Syms.GenDomConstraints(Input.Mapping.RHS); Syms.GenDFConstraints(Input.Mapping.LHS); + if (!Syms.GenPCConstraints(Input.PCs)) return false; Syms.PrintConstraintsPre(Out); Out << " St.hit(" << OptID << ");\n"; From 7759e2a41fb4c455656e34a77c8f33582c07fc58 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 28 Oct 2022 18:07:30 -0600 Subject: [PATCH 109/165] foo --- tools/matcher-gen.cpp | 140 +++++++++++++++++++++--- tools/pass-generator/src/template.cpp | 148 ++++++++++++++++++++------ 2 files changed, 240 insertions(+), 48 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 88d8a1a37..bbefb744c 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -178,9 +178,29 @@ struct DB : public Constraint { std::string Val; }; -//struct VarKB : public Constraint { +struct K0 : public Constraint { + K0(std::string Name_, std::string Val_) : Name(Name_), Val(Val_) {} + std::string print() override { + return "util::k0(" + Name + ", \"" + Val + "\")"; + } + std::string Name, Val; +}; + +struct K1 : public Constraint { + K1(std::string Name_, std::string Val_) : Name(Name_), Val(Val_) {} + std::string print() override { + return "util::k1(" + Name + ", \"" + Val + "\")"; + } + std::string Name, Val; +}; -//}; +struct CR : public Constraint { + CR(std::string Name_, std::string L_, std::string H_) : Name(Name_), L(L_), H(H_) {} + std::string print() override { + return "util::cr(" + Name + ", \"" + L + "\", \"" + H + "\")"; + } + std::string Name, L, H; +}; struct SymbolTable : public std::map> { std::vector Constraints; @@ -252,6 +272,8 @@ struct SymbolTable : public std::map> { return Children[0].first + "." + Str + "(" + Children[1].first + ")"; }; +// auto B = [] + auto OP = [&](auto Str) { return Children[0].first + " " + Str + " " + Children[1].first; }; @@ -341,17 +363,42 @@ struct SymbolTable : public std::map> { Constraints.push_back(new DB(LHS->DemandedBits.toString(2, false))); } - // TODO KB and CR + std::vector Vars; + findVars(LHS, Vars); + + std::set VarSet; + for (auto &&V : Vars) { + VarSet.insert(V); + } + + for (auto &&V : VarSet) { + auto Name = this->at(V)[0]; + if (V->KnownOnes.getBitWidth() == V->Width && + V->KnownOnes != 0) { + Constraints.push_back(new K1(Name, V->KnownOnes.toString(2, false))); + } + if (V->KnownZeros.getBitWidth() == V->Width && + V->KnownZeros != 0) { + Constraints.push_back(new K0(Name, V->KnownZeros.toString(2, false))); + } + if (!V->Range.isFullSet()) { + Constraints.push_back(new CR(Name, V->Range.getLower().toString(10, false), V->Range.getUpper().toString(10, false))); + } + } } - void GenVarPropConstraints(Inst *LHS) { + void GenVarPropConstraints(Inst *LHS, bool WidthIndependent) { std::vector Vars; findVars(LHS, Vars); for (auto V : Vars) { auto Name = this->at(V)[0]; - Constraints.push_back(new WidthEq(Name, V->Width)); + + if (!WidthIndependent) { + Constraints.push_back(new WidthEq(Name, V->Width)); + } + if (V->PowOfTwo) { Constraints.push_back(new VC("pow2", Name)); } @@ -401,9 +448,15 @@ struct SymbolTable : public std::map> { auto Print = [&](SymbolTable &Syms, Inst *C){ auto Name = "C" + std::to_string(varnum++); - Out << " auto " << Name << " = C(" - << C->Val.getBitWidth() <<", " - << C->Val << ", B);\n"; + if (C->Width < 64) { + Out << " auto " << Name << " = C(" + << C->Val.getBitWidth() <<", " + << C->Val << ", B);\n"; + } else { + Out << " auto " << Name << " = C(" + << "APInt(" << C->Val.getBitWidth() << ", " + << "\"" << C->Val.toString(10, false) << "\", 10), B);\n"; + } Syms[C].push_back(Name); }; @@ -452,16 +505,14 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { Out << "&" << Syms[Child].back() << " <<= "; } auto Str = Child->Val.toString(10, false); - Out << "m_SpecificInt( " << Child->Width << ", " << Str << ")"; + Out << "m_SpecificInt( " << Child->Width << ", \"" << Str << "\")"; } else if (Child->K == Inst::Var) { if (Child->Name.starts_with("symconst")) { Out << "m_Constant(&" << Syms[Child].back() << ")"; } else if (Child->Name.starts_with("constexpr")) { llvm::errs() << "FOUND A CONSTEXPR\n"; + return false; } else { - // FIXME What about Symbolic constants? - // How about matching const exprs? - Out << "m_Value(" << Syms[Child].back() << ")"; } Syms[Child].pop_back(); @@ -603,15 +654,17 @@ bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { } template -bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { +bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIndependent) { SymbolTable Syms; Out << "{\n"; if (!InitSymbolTable(Input.Mapping.LHS, Input.Mapping.RHS, Out, Syms)) { return false; } +// Out << " llvm::errs() << \"NOW \" << " << OptID << "<< \"\\n\";\n"; - Out << "if (match(I, "; + auto F = "util::filter(F, " + std::to_string(OptID) + ") && "; + Out << "if (" << F << "match(I, "; SymbolTable SymsCopy = Syms; if (!GenLHSMatcher(Input.Mapping.LHS, Out, SymsCopy)) { @@ -619,10 +672,10 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID) { } Out << ")) {\n"; - Input.print(llvm::errs(), true); +// Input.print(llvm::errs(), true); Syms.GenVarEqConstraints(); - Syms.GenVarPropConstraints(Input.Mapping.LHS); + Syms.GenVarPropConstraints(Input.Mapping.LHS, WidthIndependent); Syms.GenDomConstraints(Input.Mapping.RHS); Syms.GenDFConstraints(Input.Mapping.LHS); if (!Syms.GenPCConstraints(Input.PCs)) return false; @@ -684,6 +737,54 @@ bool PCHasVar(const ParsedReplacement &Input) { return false; } +bool IsWidthIndependent(InstContext &IC, + Solver *S, ParsedReplacement Input) { + + if (Input.Mapping.LHS->Width == 1) { + return false; + } + + + + std::vector Consts; + auto Pred = [](Inst *I) {return I->K == Inst::Const;}; + findInsts(Input.Mapping.LHS, Consts, Pred); + findInsts(Input.Mapping.RHS, Consts, Pred); + for (auto M : Input.PCs) { + findInsts(M.LHS, Consts, Pred); + findInsts(M.RHS, Consts, Pred); + } + + std::vector WidthChanges; + auto WPred = [](Inst *I) {return I->K == Inst::Trunc || I->K == Inst::SExt + || I->K == Inst::ZExt;}; + + findInsts(Input.Mapping.LHS, WidthChanges, WPred); + findInsts(Input.Mapping.RHS, WidthChanges, WPred); + for (auto M : Input.PCs) { + findInsts(M.LHS, WidthChanges, WPred); + findInsts(M.RHS, WidthChanges, WPred); + } + + if (!WidthChanges.empty()) { + return false; + // TODO This is too conservative. + // Figure out where this is allowed in a width independent manner. + } + + // False if non zero const + for (auto &&C : Consts) { + if (C->K == Inst::Const && C->Val != 0) { + return false; + } + } + + // TODO Set up constant sytnthesis problem to see if subexpressions + // simplify to non zero consts + + return true; +} + int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); KVStore *KV = 0; @@ -741,6 +842,7 @@ int main(int argc, char **argv) { bool first = true; bool outputs = false; + for (auto &&Input: Inputs) { auto SKIP = [&] (auto Msg) { Input.print(llvm::errs(), true); @@ -859,7 +961,8 @@ int main(int argc, char **argv) { std::string Str; llvm::raw_string_ostream Out(Str); - if (GenMatcher(Input, Out, optnumber)) { + + if (GenMatcher(Input, Out, optnumber, IsWidthIndependent(IC, S.get(), Input))) { auto current = optnumber++; if (!optnumbers.empty() && optnumbers.find(current) == optnumbers.end()) { @@ -872,7 +975,9 @@ int main(int argc, char **argv) { llvm::outs() << "/* Opt : " << current << "\n"; Input.print(llvm::outs(), true); llvm::outs() << "*/\n"; + llvm::outs() << Str << "\n"; + llvm::outs().flush(); outputs= true; } else { @@ -882,6 +987,7 @@ int main(int argc, char **argv) { if (outputs) { llvm::outs() << "}\n"; } + // llvm::outs() << "end:\n"; return 0; diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index f712ce99d..78606ce86 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -22,12 +22,28 @@ #define DEBUG_TYPE "" #include "llvm/Transforms/Utils/InstructionWorklist.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Support/CommandLine.h" #include +#include using namespace llvm; using namespace llvm::PatternMatch; +static llvm::cl::opt ListFile("listfile", + llvm::cl::desc("List of optimization indexes to include.\n" + "(default=empty-string)"), + llvm::cl::init("")); + +static llvm::cl::opt Low("low", + llvm::cl::desc("Low"), + llvm::cl::init(-1)); + +static llvm::cl::opt High("high", + llvm::cl::desc("High"), + llvm::cl::init(-1)); + + // TODO Match trees // TODO Make the commutative operations work // This is critical because commutative operations @@ -162,6 +178,10 @@ inline width_specific_intval m_SpecificInt(size_t W, uint64_t V) { return width_specific_intval(APInt(64, V), W); } +inline width_specific_intval m_SpecificInt(size_t W, std::string S) { + return width_specific_intval(APInt(W, S, 10), W); +} + struct constant_matcher { llvm::Value** Captured; constant_matcher(llvm::Value** C) : Captured(C) {} @@ -278,7 +298,11 @@ namespace util { } bool check_width(llvm::Value *V, size_t W) { - return V->getType()->getScalarSizeInBits() == W; + if (V->getType()) { + return V->getType()->getScalarSizeInBits() == W; + } else { + return false; + } } template @@ -295,46 +319,79 @@ namespace util { return false; } - bool IsKBSubset(KnownBits Small, KnownBits Big) { - // FIXME Think about this carefully. - // It can't just be conflict. + bool KnownBitImplies(llvm::APInt Big, llvm::APInt Small) { - return false; - } - - bool IsCRSubset(ConstantRange Small, ConstantRange Big) { - return Big.contains(Small); - } + if (Big.getBitWidth() != Small.getBitWidth()) { + return false; + } - bool ckb(llvm::Value *V, llvm::KnownBits Overapprox) { +// auto P = [](llvm::APInt A, auto S) { +// llvm::SmallVector Foo; +// A.toString(Foo, 2, false); +// llvm::errs() << "\n" << Foo << " <--" << S << "\n"; +// }; +// +// auto Val = (~Big | Small); +// +// P(Big, "BIG"); +// P(Small, "SMALL"); +// P(~Big, "FLIP"); +// +// P(Small, "OR"); +// P(~Big | Small, "RES"); + + return (~Big | Small).isAllOnes(); + } + + bool k0(llvm::Value *V, std::string Val) { + auto W = V->getType()->getIntegerBitWidth(); + llvm::APInt Value(W, Val, 2); if (ConstantInt *Con = llvm::dyn_cast(V)) { - auto Val = Con->getUniqueInteger(); - llvm::KnownBits KB(V->getType()->getIntegerBitWidth()); - KB.One = Val; - KB.Zero = ~Val; - return IsKBSubset(KB, Overapprox); + auto X = Con->getUniqueInteger(); + return KnownBitImplies(Value, ~X); } - return false; - } + auto Analyzed = llvm::KnownBits(W); + if (Instruction *I = llvm::dyn_cast(V)) { + DataLayout DL(I->getParent()->getParent()->getParent()); + computeKnownBits(V, Analyzed, DL, 4); - bool ccr(llvm::Value *V,llvm::ConstantRange R) { - if (ConstantInt *Con = llvm::dyn_cast(V)) { - return R.contains(Con->getUniqueInteger()); + llvm::SmallVector Result; + Analyzed.Zero.toString(Result, 2, false); + + auto b = KnownBitImplies(Value, Analyzed.Zero); +// llvm::errs() << "HERE: " << Result << ' ' << Val +// << ' ' << b << "\n\n"; + return b; } return false; } - bool vkb(llvm::Value *V, llvm::KnownBits OverApprox) { - auto Analyzed = llvm::KnownBits(V->getType()->getIntegerBitWidth()); + bool k1(llvm::Value *V, std::string Val) { + auto W = V->getType()->getIntegerBitWidth(); + llvm::APInt Value(W, Val, 2); + if (ConstantInt *Con = llvm::dyn_cast(V)) { + auto X = Con->getUniqueInteger(); + return KnownBitImplies(Value, X); + } + auto Analyzed = llvm::KnownBits(W); if (Instruction *I = llvm::dyn_cast(V)) { DataLayout DL(I->getParent()->getParent()->getParent()); computeKnownBits(V, Analyzed, DL, 4); + return KnownBitImplies(Value, Analyzed.One); } - return IsKBSubset(Analyzed, OverApprox); + return false; } - bool vcr(llvm::Value *V, llvm::ConstantRange R) { + bool cr(llvm::Value *V, std::string L, std::string H) { + auto W = V->getType()->getIntegerBitWidth(); + llvm::ConstantRange R(llvm::APInt(W, L, 10), llvm::APInt(W, H, 10)); + if (ConstantInt *Con = llvm::dyn_cast(V)) { + return R.contains(Con->getUniqueInteger()); + } // FIXME obtain result from range analysis pass +// if (Instruction *I = llvm::dyn_cast(V)) { +// +// } return false; } @@ -343,8 +400,7 @@ namespace util { auto ComputedDB = DB->getDemandedBits(I); // 0 in DBUnderApprox implies 0 in ComputedDB - return (V | ~ComputedDB) != 0; - // TODO Carefully think about this. + return (V | ~ComputedDB).isAllOnes(); } bool nz(llvm::Value *V) { @@ -371,6 +427,16 @@ namespace util { return false; } + bool filter(const std::set &F, size_t id) { + if (Low != -1 && High != -1) { + llvm::errs() << Low << " " << id << " " << High << " " << (Low <= id && id < High) << "\n"; + return Low <= id && id < High; + } + if (F.empty()) return true; + return F.find(id) != F.end(); +// return true; + } + struct Stats { void hit(size_t opt) { Hits[opt]++; @@ -410,6 +476,13 @@ namespace util { struct SouperCombine : public FunctionPass { static char ID; SouperCombine() : FunctionPass(ID) { + if (ListFile != "") { + std::ifstream in(ListFile); + size_t num; + while (in >> num) { + F.insert(num); + } + } } ~SouperCombine() { St.print(); @@ -423,7 +496,13 @@ struct SouperCombine : public FunctionPass { W.reserve(F.getInstructionCount()); for (auto &BB : F) { for (auto &&I : BB) { - W.push(&I); + if (I.getNumOperands() && + !isa(&I) && + !isa(&I) && + !isa(&I) && + !isa(&I)) { + W.push(&I); + } } } IRBuilder Builder(F.getContext()); @@ -437,10 +516,14 @@ struct SouperCombine : public FunctionPass { bool processInst(Instruction *I, IRBuilder &Builder) { Builder.SetInsertPoint(I); +// llvm::errs() << "HERE0\n"; if (auto V = getReplacement(I, &Builder)) { +// llvm::errs() << "HERE1\n"; replace(I, V, Builder); +// llvm::errs() << "BAR\n"; return true; } +// llvm::errs() << "HERE2\n"; return false; } void replace(Instruction *I, Value *V, IRBuilder &Builder) { @@ -450,6 +533,8 @@ struct SouperCombine : public FunctionPass { bool run(IRBuilder &Builder) { bool Changed = false; while (auto I = W.removeOne()) { +// llvm::errs() << "FOO\n"; +// I->print(llvm::errs()); Changed = processInst(I, Builder) || Changed; } return Changed; @@ -459,7 +544,7 @@ struct SouperCombine : public FunctionPass { // if (!I->hasOneUse()) { // return nullptr; // } - +// llvm::errs() << "\nHERE REPL\n"; // Interestingly commenting out ^this block // slightly improves results. // Implying this situation can be improved further @@ -475,8 +560,8 @@ struct SouperCombine : public FunctionPass { } Value *C(llvm::APInt Value, IRBuilder *B) { - return B->getIntN(Value.getBitWidth(), Value.getLimitedValue()); - // FIXME: Figure out how to make a value from a full APInt. + return ConstantInt::get(B->getIntNTy(Value.getBitWidth()), Value); +// return B->getIntN(Value.getBitWidth(), Value.getLimitedValue()); } Type *T(size_t W, IRBuilder *B) { @@ -487,6 +572,7 @@ struct SouperCombine : public FunctionPass { util::Stats St; DominatorTree *DT; DemandedBits *DB; + std::set F; }; } From 77fb1de41b64d5cfb430f931e9664bc71c5773a3 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sat, 29 Oct 2022 14:07:40 -0600 Subject: [PATCH 110/165] foo --- lib/Pass/Pass.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/Pass/Pass.cpp b/lib/Pass/Pass.cpp index 4686d5f20..785f07c63 100644 --- a/lib/Pass/Pass.cpp +++ b/lib/Pass/Pass.cpp @@ -200,6 +200,29 @@ struct SouperPass : public ModulePass { .getValue(I); } + bool hasNewPhi(InstMapping Cand) { + auto PhiCheck = [](Inst *I) {return I->K == Inst::Phi;}; + std::vector Insts; + + findInsts(Cand.LHS, Insts, PhiCheck); + + std::set LHSPhis; + for (auto &I : Insts) { + LHSPhis.insert(I); + } + Insts.clear(); + + findInsts(Cand.RHS, Insts, PhiCheck); + + for (auto &&I : Insts) { + if (LHSPhis.find(I) == LHSPhis.end()) { + return true; + } + } + + return false; + } + bool runOnFunction(Function *F) { std::string FunctionName; if (F->hasLocalLinkage()) { @@ -304,6 +327,10 @@ struct SouperPass : public ModulePass { Cand.Mapping.RHS = RHSs.front(); + if (hasNewPhi(Cand.Mapping)) { + continue; + } + Instruction *I = Cand.Origin; assert(Cand.Mapping.LHS->K == Inst::Const || Cand.Mapping.LHS->hasOrigin(I)); IRBuilder<> Builder(I); From de6f256974188430b1323107791879eed600b451 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 30 Oct 2022 13:08:06 -0600 Subject: [PATCH 111/165] foo --- lib/Generalize/Reducer.cpp | 179 ++++++++++++++++++++++---- tools/pass-generator/src/template.cpp | 30 +++-- 2 files changed, 175 insertions(+), 34 deletions(-) diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index c9f68784e..5d3932939 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -1,4 +1,5 @@ #include "llvm/Support/KnownBits.h" +#include "llvm/IR/ConstantRange.h" #include "souper/Generalize/Reducer.h" #include "souper/Infer/SynthUtils.h" @@ -414,6 +415,102 @@ ParsedReplacement Reducer::ReduceRedundantPhis(ParsedReplacement Input) { } return Input; } +size_t WeakenSingleCR(ParsedReplacement Input, InstContext &IC, Solver *S, + Inst *Target, std::optional Val) { + if (Target->Width <= 8) return 0; // hack + if (!Val.has_value()) { + // Synthesize a value + Inst *C = IC.createVar(Target->Width, "reservedconst_1"); + C->SynthesisConstID = 1; + std::map InstCache = {{Target, C}}; + + auto Copy = Input; + + auto Rep = Replace(Input, IC, InstCache); + + std::set ConstSet{C}; + + std::map ConstMap; + ConstantSynthesis CS; + +// Rep.print(llvm::errs(), true); + + if (auto EC = CS.synthesize(S->getSMTLIBSolver(), Rep.BPCs, + Rep.PCs, Rep.Mapping, ConstSet, ConstMap, IC, 30, 60, false)) { + llvm::errs() << "Constant Synthesis internal error : " << EC.message(); + } + + if (!ConstMap.empty()) { + Val = ConstMap[C]; + } + } + + if (!Val.has_value()) { + return 0; // fail + } + + ParsedReplacement Ret; + auto SOLVE = [&]() -> bool { + Ret = Verify(Input, IC, S); + if (Ret.Mapping.LHS && Ret.Mapping.RHS) { + return true; + } else { + return false; + } + }; + + auto Restore = Target->Range; + + // Binary search to extend upper and lower boundaries + llvm::ConstantRange R(Val.value()); + +// llvm::errs() << "R " << R << " " << Val.value() <<"\n"; + + auto Full = R.getFull(R.getBitWidth()); + + auto L = R.getLower(); + auto U = R.getUpper(); + + size_t inc = 1; + while (inc && U.ult(Full.getUpper())) { + auto Backup = Target->Range; + auto Attempt = U + inc; + Target->Range = llvm::ConstantRange(L, Attempt); + if (SOLVE()) { + U = Attempt; +// llvm::errs() << "U " << Attempt << '\n'; + inc *= 2; + } else { + inc /= 2; + Target->Range = Backup; + } + } + + size_t dec = 1; + while (dec && L.ult(0)) { + auto Backup = Target->Range; + auto Attempt = L - dec; + Target->Range = llvm::ConstantRange(Attempt, U); + if (SOLVE()) { + L = Attempt; +// llvm::errs() << "L " << Attempt << '\n'; + dec *= 2; + } else { + dec /= 2; + Target->Range = Backup; + } + } + +// llvm::errs() << "HERE " << L << " " << U << "\n"; + + if ((U - L).sgt(1 << (Target->Width - 2))) { // Heuristic + return (U - L).getLimitedValue(); + } else { + Target->Range = Restore; + return 0; + }; + +} size_t WeakenSingleKB(ParsedReplacement Input, InstContext &IC, Solver *S, Inst *Target, std::optional Val) { @@ -446,7 +543,6 @@ size_t WeakenSingleKB(ParsedReplacement Input, InstContext &IC, Solver *S, if (!ConstMap.empty()) { Val = ConstMap[C]; } - } if (!Val.has_value()) { @@ -516,8 +612,15 @@ ParsedReplacement Reducer::ReducePCsToDF(ParsedReplacement Input) { bool Succ = false; for (auto &&V : Vars) { - auto BitsWeakened = WeakenSingleKB(Input, IC, S, V, {}); - Succ |= (BitsWeakened != 0); + auto RangeSize = WeakenSingleCR(Input, IC, S, V, {}); + Succ |= (RangeSize > 0); + } + + if (!Succ) { + for (auto &&V : Vars) { + auto BitsWeakened = WeakenSingleKB(Input, IC, S, V, {}); + Succ |= (BitsWeakened != 0); + } } if (!Succ) { @@ -530,35 +633,22 @@ ParsedReplacement Reducer::ReducePCsToDF(ParsedReplacement Input) { // Assumes Input is valid ParsedReplacement Reducer::ReducePCs(ParsedReplacement Input) { - std::set UnnecessaryPCs; - for (size_t i =0; i < Input.PCs.size(); ++i) { - std::vector PCsExceptOne; + for (size_t i = 0; i < Input.PCs.size(); ++i) { + auto Result = Input; + Result.PCs.clear(); for (size_t j = 0; j < Input.PCs.size(); ++j) { if (i != j) { - PCsExceptOne.push_back(Input.PCs[i]); + Result.PCs.push_back(Input.PCs[j]); } } - std::vector> Models; - bool Valid; - if (std::error_code EC = S->isValid(IC, Input.BPCs, PCsExceptOne, Input.Mapping, Valid, &Models)) { - llvm::errs() << EC.message() << '\n'; - } - if (Valid) { - UnnecessaryPCs.insert(i); - } - } - - std::vector NecessaryPCs; - for (size_t i =0; i < Input.PCs.size(); ++i) { - if (UnnecessaryPCs.find(i) == UnnecessaryPCs.end()) { - NecessaryPCs.push_back(Input.PCs[i]); + auto Clone = Verify(Result, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return ReducePCs(Result); } } - auto Result = Input; - Result.PCs = NecessaryPCs; - return Result; + return Input; } // Assumes Input is valid @@ -608,7 +698,6 @@ ParsedReplacement Reducer::WeakenKB(ParsedReplacement Input) { // Assumes Input is valid ParsedReplacement Reducer::WeakenCR(ParsedReplacement Input) { - // Just try to remove CR for now. std::vector Vars; findVars(Input.Mapping.LHS, Vars); @@ -621,7 +710,45 @@ ParsedReplacement Reducer::WeakenCR(ParsedReplacement Input) { if (!VerifyInput(Input)) { V->Range = Ori; } - // TODO: Try Widening Range + + auto R = V->Range; + + if (!R.isWrappedSet()) { + auto Full = R.getFull(R.getBitWidth()); + + auto L = R.getLower(); + auto U = R.getUpper(); + + size_t inc = 1; + while (inc && U.ult(Full.getUpper())) { + auto Backup = V->Range; + auto Attempt = U + inc; + V->Range = llvm::ConstantRange(L, Attempt); + if (VerifyInput(Input)) { + U = Attempt; + // llvm::errs() << "U " << Attempt << '\n'; + inc *= 2; + } else { + inc /= 2; + V->Range = Backup; + } + } + + size_t dec = 1; + while (dec && L.ult(0)) { + auto Backup = V->Range; + auto Attempt = L - dec; + V->Range = llvm::ConstantRange(Attempt, U); + if (VerifyInput(Input)) { + L = Attempt; + // llvm::errs() << "L " << Attempt << '\n'; + dec *= 2; + } else { + dec /= 2; + V->Range = Backup; + } + } + } } return Input; diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 78606ce86..067349888 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -16,6 +16,7 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/DemandedBits.h" +#include "llvm/Analysis/LazyValueInfo.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Support/Debug.h" @@ -388,11 +389,8 @@ namespace util { if (ConstantInt *Con = llvm::dyn_cast(V)) { return R.contains(Con->getUniqueInteger()); } - // FIXME obtain result from range analysis pass -// if (Instruction *I = llvm::dyn_cast(V)) { -// -// } - return false; + auto CR = computeConstantRange(V, true); + return R.contains(CR); } bool vdb(llvm::DemandedBits *DB, llvm::Instruction *I, std::string DBUnderApprox) { @@ -488,11 +486,26 @@ struct SouperCombine : public FunctionPass { St.print(); } + virtual void getAnalysisUsage(AnalysisUsage &Info) const override { +// Info.addRequired(); + Info.addRequired(); + Info.addRequired(); + Info.addRequired(); +// Info.addRequired(); +// Info.addRequired(); + } + + bool runOnFunction(Function &F) override { AssumptionCache AC(F); + DT = new DominatorTree(F); DB = new DemandedBits(F, AC, *DT); - +//// LVI = +// auto DL = new DataLayout(F.getParent()); +// auto TLI = new TargetLibraryInfo(); +// new LazyValueInfo + W.reserve(F.getInstructionCount()); for (auto &BB : F) { for (auto &&I : BB) { @@ -509,8 +522,8 @@ struct SouperCombine : public FunctionPass { // llvm::errs() << "Before:\n" << F; auto r = run(Builder); // llvm::errs() << "After:\n" << F; - delete DB; - delete DT; +// delete DB; +// delete DT; return r; } @@ -572,6 +585,7 @@ struct SouperCombine : public FunctionPass { util::Stats St; DominatorTree *DT; DemandedBits *DB; + LazyValueInfo *LVI; std::set F; }; } From a92a8b75f9b237450f0694e9e3e43327b2bc5a57 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 1 Nov 2022 00:22:34 -0600 Subject: [PATCH 112/165] foo --- include/souper/Infer/SynthUtils.h | 4 +- tools/generalize.cpp | 323 +++++++++++++++++++++++------- 2 files changed, 259 insertions(+), 68 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index e63033f11..fa8f68b7b 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -35,6 +35,7 @@ class Builder { BINOP(Add) BINOP(Sub) BINOP(Mul) BINOP(And) BINOP(Xor) BINOP(Or) BINOP(Shl) BINOP(LShr) BINOP(UDiv) + BINOP(SDiv) #undef BINOP #define BINOPW(K) \ @@ -51,7 +52,8 @@ class Builder { auto L = I; \ return Builder(IC.getInst(Inst::K, L->Width, {L}), IC); \ } - UNOP(LogB) + UNOP(LogB) UNOP(BitReverse) UNOP(BSwap) + #undef UNOP private: diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 29eaf666f..929e0ca12 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -912,49 +912,213 @@ FirstValidCombination(ParsedReplacement Input, return Input; } -std::vector> -InferSimpleConstExprs(std::vector RHS, std::set - LHS, std::map SMap, - InstContext &IC) { - std::vector> Result; - - for (auto &&RC : RHS) { - auto RV = RC->Val; - Result.push_back({}); - for (auto &&LC : LHS) { - auto LV = LC->Val; - if (LC->Width != RC->Width || LV.getBitWidth() != RV.getBitWidth()) { - continue; + +std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, + std::map SMap, InstContext &IC, size_t Threshold, bool ConstMode) { + + std::vector Results; + + // Just symbolic or Concrete constant + + for (auto C : LHSConsts) { + if (!ConstMode) { + if (C->Width == Target.getBitWidth() && C->Val == Target) { + Results.push_back(SMap[C]); } - // TODO: Check width constraints + } else { + if (C->Width == Target.getBitWidth()) { + Results.push_back(Builder(IC, Target)()); + } + } + } + + if (!Threshold) { + return Results; + } + + // Recursive formulation - // RC = LC + (RV - LV) - Result.back().push_back(Builder(SMap[LC], IC).Add(RV - LV)()); + for (auto C : LHSConsts) { + if (C->Width != Target.getBitWidth()) { + continue; + } - // RC = (RV + LV) - LC - Result.back().push_back(Builder(IC, RV + LV).Sub(SMap[LC])()); + // Binary operators + // C + X == Target + for (auto X : IOSynthesize(Target - C->Val, LHSConsts, SMap, IC, + Threshold - 1, ConstMode)) { + Results.push_back(Builder(SMap[C], IC).Add(X)()); + } - // RC = LC * (RV / LV) only if no remainder - if (LV != 0 && RV.urem(LV) == 0) { - Result.back().push_back(Builder(SMap[LC], IC).Mul(RV.udiv(LV))()); + // C - X == Target + for (auto X : IOSynthesize(C->Val - Target, LHSConsts, SMap, IC, + Threshold - 1, ConstMode)) { + Results.push_back(Builder(SMap[C], IC).Sub(X)()); + } + + // X - C == Target + for (auto X : IOSynthesize(Target + C->Val, LHSConsts, SMap, IC, + Threshold - 1, ConstMode)) { + Results.push_back(Builder(X, IC).Sub(SMap[C])()); + } + + // C * X == Target + if (C->Val.isNegative() || Target.isNegative()) { + if (C->Val != 0 && Target.srem(C->Val) == 0) { + for (auto X : IOSynthesize(Target.sdiv(C->Val), LHSConsts, SMap, + IC, Threshold - 1, ConstMode)) { + Results.push_back(Builder(X, IC).Mul(SMap[C])()); + } } + } else { + if (C->Val != 0 && Target.urem(C->Val) == 0) { + for (auto X : IOSynthesize(Target.udiv(C->Val), LHSConsts, SMap, + IC, Threshold - 1, ConstMode)) { + Results.push_back(Builder(X, IC).Mul(SMap[C])()); + } + } + } - // RC = LC / (RV * LV) only if no remainder - if (LV != 0 && RV!= 0 && RV.urem(LV) == 0) { - Result.back().push_back(Builder(SMap[LC], IC).UDiv(RV * LV)()); + // C / X == Target + if (C->Val.isNegative() || Target.isNegative()) { + if (Target != 0 && C->Val.srem(Target) == 0) { + for (auto X : IOSynthesize(C->Val.sdiv(Target), LHSConsts, SMap, + IC, Threshold - 1, ConstMode)) { + Results.push_back(Builder(SMap[C], IC).SDiv(X)()); + } + } + } else { + if (Target != 0 && C->Val.urem(Target) == 0) { + for (auto X : IOSynthesize(C->Val.udiv(Target), LHSConsts, SMap, + IC, Threshold - 1, ConstMode)) { + Results.push_back(Builder(SMap[C], IC).UDiv(X)()); + } } + } + + // X / C == Target - // RC = logb(LC) if logb(LV) = RV && LV is a power of 2. - if (LV.isPowerOf2() && LV.logBase2() == RV) { - Result.back().push_back(Builder(SMap[LC], IC).LogB()()); + if (C->Val.isNegative() || Target.isNegative()) { + if (C->Val != 0 && Target.srem(C->Val) == 0) { + for (auto X : IOSynthesize(C->Val * Target, LHSConsts, SMap, + IC, Threshold - 1, ConstMode)) { + Results.push_back(Builder(X, IC).SDiv(SMap[C])()); + } } + } else { + if (C->Val != 0 && Target.urem(C->Val) == 0) { + for (auto X : IOSynthesize(C->Val * Target, LHSConsts, SMap, + IC, Threshold - 1, ConstMode)) { + Results.push_back(Builder(X, IC).UDiv(SMap[C])()); + } + } + } - // TODO: Masks + // Shifts? + + // Unary operators (no recursion required) + if (Target == C->Val.logBase2()) { + Results.push_back(Builder(SMap[C], IC).LogB()()); + } + if (Target == C->Val.reverseBits()) { + Results.push_back(Builder(SMap[C], IC).BitReverse()()); + } + // TODO Add others + + if (Threshold == 1) { + for (auto C2 : LHSConsts) { + if (C == C2 || C->Width != C2->Width) { + continue; + } + if ((C->Val & C2->Val) == Target) { + Results.push_back(Builder(SMap[C], IC).And(SMap[C2])()); + } + if ((C->Val | C2->Val) == Target) { + Results.push_back(Builder(SMap[C], IC).Or(SMap[C2])()); + } + if ((C->Val ^ C2->Val) == Target) { + Results.push_back(Builder(SMap[C], IC).Xor(SMap[C2])()); + } + } } } - return Result; + return Results; +} + +//std::vector> +//InferSimpleConstExprs(std::vector RHS, std::set +// LHS, std::map SMap, +// InstContext &IC) { +// std::vector> Result; +// +// for (auto &&RC : RHS) { +// auto RV = RC->Val; +// Result.push_back({}); +// for (auto &&LC : LHS) { +// auto LV = LC->Val; +// if (LC->Width != RC->Width || LV.getBitWidth() != RV.getBitWidth()) { +// continue; +// } +// // TODO: Check width constraints +// +// // RC = LC + (RV - LV) +// Result.back().push_back(Builder(SMap[LC], IC).Add(RV - LV)()); +// +// // RC = (RV + LV) - LC +// Result.back().push_back(Builder(IC, RV + LV).Sub(SMap[LC])()); +// +// +// // RC = LC * (RV / LV) only if no remainder +// if (LV != 0 && RV.urem(LV) == 0) { +// Result.back().push_back(Builder(SMap[LC], IC).Mul(RV.udiv(LV))()); +// } +// +// // RC = LC / (RV * LV) only if no remainder +// if (LV != 0 && RV!= 0 && RV.urem(LV) == 0) { +// Result.back().push_back(Builder(SMap[LC], IC).UDiv(RV * LV)()); +// } +// +// // RC = logb(LC) if logb(LV) = RV && LV is a power of 2. +// if (LV.isPowerOf2() && LV.logBase2() == RV) { +// Result.back().push_back(Builder(SMap[LC], IC).LogB()()); +// } +// +// // TODO: Masks +// } +// } +// +// return Result; +//} + +std::vector> +InferSpecialConstExprsAllSym(std::vector RHS, std::set + LHS, std::map SMap, + InstContext &IC) { + std::vector> Results; + for (auto R : RHS) { + Results.push_back(IOSynthesize(R->Val, LHS, SMap, IC, 3, false)); + } + return Results; +} + +std::vector> +InferSpecialConstExprsWithConcretes(std::vector RHS, std::set + LHS, std::map SMap, + InstContext &IC) { + std::vector> Results; + for (auto R : RHS) { + auto Cands = IOSynthesize(R->Val, LHS, SMap, IC, 3, true); + std::vector Filtered; + for (auto Cand : Cands) { + if (Cand->K != Inst::Const) { + Filtered.push_back(Cand); + } + } + Results.push_back(Filtered); + } + return Results; } std::vector> Enumerate(std::vector RHSConsts, @@ -1157,6 +1321,26 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } Refresh("All LHS Constraints"); + + // Step 3 : Special RHS constant exprs, no constants + + if (!RHSFresh.empty()) { + + std::vector> SimpleCandidates = + InferSpecialConstExprsAllSym(RHSFresh, LHSConsts, SymConstMap, IC); + + if (!SimpleCandidates.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, + InstCache, IC, S, SymCS, + true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } + + Refresh("Special expressions, no constants"); + + // Step 4 : Enumerated expressions std::set Components; @@ -1186,32 +1370,15 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } } } - Refresh("Some constraints for enumerated cands."); + Refresh("Relational constraints for enumerated cands."); } - // Step 3 : Simple RHS constant exprs - - if (!RHSFresh.empty()) { - - std::vector> SimpleCandidates = - InferSimpleConstExprs(RHSFresh, LHSConsts, SymConstMap, IC); - - if (!SimpleCandidates.empty()) { - auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, - InstCache, IC, S, SymCS, - true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - } - - Refresh("Simple cands with constants"); // Step 4.75 : Enumerate 2 instructions when single RHS Constant. if (RHSFresh.size() == 1) { - auto EnumeratedCandidates = Enumerate(RHSFresh, Components, IC, 2); + auto EnumeratedCandidatesTwoInsts = Enumerate(RHSFresh, Components, IC, 2); - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, InstCache, IC, S, SymCS, true, false, false); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; @@ -1223,7 +1390,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, for (auto &&R : Relations) { Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, InstCache, IC, S, SymCS, true, false, false); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; @@ -1233,7 +1400,21 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } } + // Step 4.8 : Special RHS constant exprs, with constants + std::vector> SimpleCandidatesWithConsts = + InferSpecialConstExprsWithConcretes(RHSFresh, LHSConsts, SymConstMap, IC); + + if (!SimpleCandidatesWithConsts.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, + InstCache, IC, S, SymCS, + true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } + + Refresh("Special expressions, with constants"); // Step 5 : Simple exprs with constraints @@ -1259,6 +1440,30 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Simple cands with constraints and relations"); } + // Step 5.5 : Simple exprs with constraints + + if (!SimpleCandidatesWithConsts.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, + InstCache, IC, S, SymCS, false, true, true); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + Refresh("Simple cands+consts with constraints"); + + for (auto &&R : Relations) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, + InstCache, IC, S, SymCS, true, true, true); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + + Input.PCs.pop_back(); + } + Refresh("Simple cands+consts with constraints and relations"); + } + // Step 6 : Enumerated exprs with constraints if (!EnumeratedCandidates.empty()) { @@ -1287,22 +1492,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Input; } -ParsedReplacement SuccessiveSymbolizeAdvanced(InstContext &IC, - Solver *S, - ParsedReplacement Input) { - // Step 90 : Symbolic dataflow for LHS + preconditions - - // Step 100 : Symbolic dataflow vars in RHS const exprs - - // Step 101 : Permuted exprs for RHS consts - - // Step 110 : Synthesized RHS constant exprs with constant synthesis. - // ^ This would get stuck fairly often. - - return Input; -} - - size_t InferWidth(Inst::Kind K, const std::vector &Ops) { switch (K) { case Inst::LShr: @@ -1515,7 +1704,7 @@ int main(int argc, char **argv) { ParsedReplacement Result = ReduceBasic(IC, S.get(), Input); if (!JustReduce) { bool Changed = false; - size_t MaxTries = 2; + size_t MaxTries = 1; // Increase this if we even run with 10/100x timeout. do { Result = ReduceBasic(IC, S.get(), Input); Result = SuccessiveSymbolize(IC, S.get(), Result, Changed); From 24d3c11f70d0f646b8f1c9c92fa0d30ab5925afd Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 1 Nov 2022 00:25:15 -0600 Subject: [PATCH 113/165] foo --- tools/pass-generator/src/template.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 067349888..d1a3df611 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -1,4 +1,5 @@ #include "llvm/Pass.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/Constant.h" @@ -299,7 +300,7 @@ namespace util { } bool check_width(llvm::Value *V, size_t W) { - if (V->getType()) { + if (V && V->getType() && V->getType()->isIntegerTy()) { return V->getType()->getScalarSizeInBits() == W; } else { return false; @@ -345,7 +346,11 @@ namespace util { } bool k0(llvm::Value *V, std::string Val) { + if (!V || !V->getType() || !V->getType()->isIntegerTy() ) { + return false; + } auto W = V->getType()->getIntegerBitWidth(); + llvm::APInt Value(W, Val, 2); if (ConstantInt *Con = llvm::dyn_cast(V)) { auto X = Con->getUniqueInteger(); @@ -368,6 +373,9 @@ namespace util { } bool k1(llvm::Value *V, std::string Val) { + if (!V || !V->getType() || !V->getType()->isIntegerTy()) { + return false; + } auto W = V->getType()->getIntegerBitWidth(); llvm::APInt Value(W, Val, 2); if (ConstantInt *Con = llvm::dyn_cast(V)) { @@ -384,6 +392,9 @@ namespace util { } bool cr(llvm::Value *V, std::string L, std::string H) { + if (!V || !V->getType() || !V->getType()->isIntegerTy()) { + return false; + } auto W = V->getType()->getIntegerBitWidth(); llvm::ConstantRange R(llvm::APInt(W, L, 10), llvm::APInt(W, H, 10)); if (ConstantInt *Con = llvm::dyn_cast(V)) { @@ -397,6 +408,9 @@ namespace util { llvm::APInt V = llvm::APInt(I->getType()->getIntegerBitWidth(), DBUnderApprox, 2); auto ComputedDB = DB->getDemandedBits(I); +// llvm::errs() << DBUnderApprox << ' ' << llvm::toString(ComputedDB, 2, false) << ' ' +// << (V | ~ComputedDB).isAllOnes() << "\n"; + // 0 in DBUnderApprox implies 0 in ComputedDB return (V | ~ComputedDB).isAllOnes(); } From 4cd1609d8aebbc7c6ad38d631e49568326b61c98 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 1 Nov 2022 01:43:38 -0600 Subject: [PATCH 114/165] foo --- lib/Generalize/Reducer.cpp | 22 +++++++++- tools/generalize.cpp | 82 +++++++++++++++++--------------------- 2 files changed, 56 insertions(+), 48 deletions(-) diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index 5d3932939..6d6208a7d 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -386,6 +386,7 @@ ParsedReplacement Reducer::ReduceRedundantPhis(ParsedReplacement Input) { size_t NumPhis = Phis.size(); while (NumPhis --) { std::map ICache; + bool Done = false; for (auto &&I : Phis) { if (I->Ops.size() == 1) { ICache[I] = I->Ops[0]; @@ -399,10 +400,18 @@ ParsedReplacement Reducer::ReduceRedundantPhis(ParsedReplacement Input) { } if (allEq) { ICache[I] = I->Ops[0]; + } else { + Done = true; } + } else { + Done = true; } } + if (Done || instCount(Input.Mapping.LHS) - instCount(Input.Mapping.RHS) <= 1) { + break; + } + Input.Mapping.LHS = Replace(Input.Mapping.LHS, IC, ICache); Input.Mapping.RHS = Replace(Input.Mapping.RHS, IC, ICache); for (auto &PC : Input.PCs) { @@ -472,9 +481,15 @@ size_t WeakenSingleCR(ParsedReplacement Input, InstContext &IC, Solver *S, auto U = R.getUpper(); size_t inc = 1; - while (inc && U.ult(Full.getUpper())) { + while (inc && U.slt(Full.getUpper())) { + +// llvm::errs() << "L " << L << " " << "U " << U << " inc " << inc <<"\n"; + auto Backup = Target->Range; auto Attempt = U + inc; + if (Attempt.sge(Full.getUpper())) { + Attempt = Full.getLower(); + } Target->Range = llvm::ConstantRange(L, Attempt); if (SOLVE()) { U = Attempt; @@ -490,6 +505,9 @@ size_t WeakenSingleCR(ParsedReplacement Input, InstContext &IC, Solver *S, while (dec && L.ult(0)) { auto Backup = Target->Range; auto Attempt = L - dec; + if (Attempt.sle(Full.getLower())) { + Attempt = Full.getLower(); + } Target->Range = llvm::ConstantRange(Attempt, U); if (SOLVE()) { L = Attempt; @@ -516,7 +534,7 @@ size_t WeakenSingleKB(ParsedReplacement Input, InstContext &IC, Solver *S, Inst *Target, std::optional Val) { size_t BitsWeakened = 0; - if (Target->Width <= 8) return 0; // hack + if (Target->Width < 8) return 0; // hack if (!Val.has_value()) { // Synthesize a value diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 929e0ca12..98ffd52f0 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -691,12 +691,12 @@ ParsedReplacement DFPreconditionsAndVerifyGreedy( std::map> Restore; - size_t BitsWeakened = 0; auto Clone = souper::Clone(Input, IC); for (auto &&C : SymCS) { + if (C.first->Width < 8) continue; Restore[C.first] = {C.first->KnownZeros, C.first->KnownOnes}; C.first->KnownZeros = ~C.second; C.first->KnownOnes = C.second; @@ -713,6 +713,7 @@ ParsedReplacement DFPreconditionsAndVerifyGreedy( }; for (auto &&C : SymCS) { + if (C.first->Width < 8) continue; for (size_t i = 0; i < C.first->Width; ++i) { llvm::APInt OriZ = C.first->KnownZeros; llvm::APInt OriO = C.first->KnownOnes; @@ -1047,51 +1048,6 @@ std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, return Results; } -//std::vector> -//InferSimpleConstExprs(std::vector RHS, std::set -// LHS, std::map SMap, -// InstContext &IC) { -// std::vector> Result; -// -// for (auto &&RC : RHS) { -// auto RV = RC->Val; -// Result.push_back({}); -// for (auto &&LC : LHS) { -// auto LV = LC->Val; -// if (LC->Width != RC->Width || LV.getBitWidth() != RV.getBitWidth()) { -// continue; -// } -// // TODO: Check width constraints -// -// // RC = LC + (RV - LV) -// Result.back().push_back(Builder(SMap[LC], IC).Add(RV - LV)()); -// -// // RC = (RV + LV) - LC -// Result.back().push_back(Builder(IC, RV + LV).Sub(SMap[LC])()); -// -// -// // RC = LC * (RV / LV) only if no remainder -// if (LV != 0 && RV.urem(LV) == 0) { -// Result.back().push_back(Builder(SMap[LC], IC).Mul(RV.udiv(LV))()); -// } -// -// // RC = LC / (RV * LV) only if no remainder -// if (LV != 0 && RV!= 0 && RV.urem(LV) == 0) { -// Result.back().push_back(Builder(SMap[LC], IC).UDiv(RV * LV)()); -// } -// -// // RC = logb(LC) if logb(LV) = RV && LV is a power of 2. -// if (LV.isPowerOf2() && LV.logBase2() == RV) { -// Result.back().push_back(Builder(SMap[LC], IC).LogB()()); -// } -// -// // TODO: Masks -// } -// } -// -// return Result; -//} - std::vector> InferSpecialConstExprsAllSym(std::vector RHS, std::set LHS, std::map SMap, @@ -1486,6 +1442,40 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } Refresh("Enumerated exprs with constraints and relations"); } + +// std::vector SymDFVars; +// std::set LHSConstsAndSymDF; + +// auto Clone = souper::Clone(Input, IC); +// std::vector Vars; +// findVars(Clone.Mapping.LHS, Vars); + + +// std::set Visited; +// for (size_t i = 0; i < Vars.size(); ++i) { +// if (Visited.find(Vars[i]) != Visited.end()/* || Vars[i]->Width == 7*/) { +// continue; +// } +// if (Vars[i]->KnownOnes.getBitWidth() != Vars[i]->Width || +// Vars[i]->KnownZeros.getBitWidth() != Vars[i]->Width) { +// continue; +// } + +// SymDFVars.push_back(IC.createVar(Vars[i]->Width, "skb_one_" + std::to_string(i))); +// SymDFVars.back()->SymOneOf = Vars[i]; +// Vars[i]->SymKnownOnes = SymDFVars.back(); +// LHSConstsAndSymDF.insert(SymDFVars.back()); +// Vars[i]->KnownOnes = llvm::APInt(); + +// SymDFVars.push_back(IC.createVar(Vars[i]->Width, "skb_zero_" + std::to_string(i))); +// SymDFVars.back()->SymZeroOf = Vars[i]; +// Vars[i]->SymKnownZeros = SymDFVars.back(); +// LHSConstsAndSymDF.insert(SymDFVars.back()); +// Vars[i]->KnownZeros = llvm::APInt(); +// } + + +// Refresh("Symbolic known bits"); } Refresh("END"); Changed = false; From 98cf7bd694db6b2e4bf657d55322fa098fc7a3bc Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 1 Nov 2022 01:56:59 -0600 Subject: [PATCH 115/165] foo --- lib/Generalize/Reducer.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index 6d6208a7d..dc9146cf0 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -502,7 +502,8 @@ size_t WeakenSingleCR(ParsedReplacement Input, InstContext &IC, Solver *S, } size_t dec = 1; - while (dec && L.ult(0)) { + while (dec && L.slt(0)) { +// llvm::errs() << "L " << L << " " << "U " << U << " inc " << dec <<"\n"; auto Backup = Target->Range; auto Attempt = L - dec; if (Attempt.sle(Full.getLower())) { @@ -738,9 +739,14 @@ ParsedReplacement Reducer::WeakenCR(ParsedReplacement Input) { auto U = R.getUpper(); size_t inc = 1; - while (inc && U.ult(Full.getUpper())) { + while (inc && U.slt(Full.getUpper())) { auto Backup = V->Range; auto Attempt = U + inc; + + if (Attempt.sge(Full.getUpper())) { + Attempt = Full.getLower(); + } + V->Range = llvm::ConstantRange(L, Attempt); if (VerifyInput(Input)) { U = Attempt; @@ -753,9 +759,12 @@ ParsedReplacement Reducer::WeakenCR(ParsedReplacement Input) { } size_t dec = 1; - while (dec && L.ult(0)) { + while (dec && L.slt(0)) { auto Backup = V->Range; auto Attempt = L - dec; + if (Attempt.sle(Full.getLower())) { + Attempt = Full.getLower(); + } V->Range = llvm::ConstantRange(Attempt, U); if (VerifyInput(Input)) { L = Attempt; From 40e0182cc8efbbbb3201f6b128b2042a4917253b Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 1 Nov 2022 22:07:41 -0600 Subject: [PATCH 116/165] foo --- lib/Generalize/Reducer.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index dc9146cf0..f6124d673 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -386,7 +386,7 @@ ParsedReplacement Reducer::ReduceRedundantPhis(ParsedReplacement Input) { size_t NumPhis = Phis.size(); while (NumPhis --) { std::map ICache; - bool Done = false; +// bool Done = false; for (auto &&I : Phis) { if (I->Ops.size() == 1) { ICache[I] = I->Ops[0]; @@ -401,16 +401,16 @@ ParsedReplacement Reducer::ReduceRedundantPhis(ParsedReplacement Input) { if (allEq) { ICache[I] = I->Ops[0]; } else { - Done = true; +// Done = true; } } else { - Done = true; +// Done = true; } } - if (Done || instCount(Input.Mapping.LHS) - instCount(Input.Mapping.RHS) <= 1) { - break; - } +// if (Done || instCount(Input.Mapping.LHS) - instCount(Input.Mapping.RHS) <= 1) { +// break; +// } Input.Mapping.LHS = Replace(Input.Mapping.LHS, IC, ICache); Input.Mapping.RHS = Replace(Input.Mapping.RHS, IC, ICache); From c1c6d561e4de14ad82ab9d7440bcc515f118619f Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 2 Nov 2022 15:26:55 -0600 Subject: [PATCH 117/165] foo --- lib/Generalize/Reducer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index f6124d673..6f1926005 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -46,7 +46,7 @@ void collectInstsToDepth(Inst *I, size_t Depth, std::set &Results) { } bool IsReductionCostEffective(Inst *LHS, Inst *RHS) { - return souper::instCount(RHS) < souper::instCount(LHS); + return souper::cost(RHS) < souper::cost(LHS); } ParsedReplacement Reducer::ReducePairsGreedy(ParsedReplacement Input) { @@ -411,6 +411,9 @@ ParsedReplacement Reducer::ReduceRedundantPhis(ParsedReplacement Input) { // if (Done || instCount(Input.Mapping.LHS) - instCount(Input.Mapping.RHS) <= 1) { // break; // } + if (souper::cost(Input.Mapping.LHS) <= souper::cost(Input.Mapping.RHS)) { + break; + } Input.Mapping.LHS = Replace(Input.Mapping.LHS, IC, ICache); Input.Mapping.RHS = Replace(Input.Mapping.RHS, IC, ICache); From bccba9cabe2488578ada9fcc4b97c1896a4e000b Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 4 Nov 2022 11:22:03 -0600 Subject: [PATCH 118/165] foo --- tools/matcher-gen.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index bbefb744c..98a034946 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -469,9 +469,11 @@ struct SymbolTable : public std::map> { }; template -bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms) { - if (I->K != souper::Inst::Var && Syms.Used.find(I) != Syms.Used.end()) { - Out << "&" << Syms[I].back() << " <<= "; +bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms, bool IsRoot = false) { + if (!IsRoot) { + if (I->K != souper::Inst::Var && Syms.Used.find(I) != Syms.Used.end()) { + Out << "&" << Syms[I].back() << " <<= "; + } } auto It = MatchOps.find(I->K); @@ -667,7 +669,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn Out << "if (" << F << "match(I, "; SymbolTable SymsCopy = Syms; - if (!GenLHSMatcher(Input.Mapping.LHS, Out, SymsCopy)) { + if (!GenLHSMatcher(Input.Mapping.LHS, Out, SymsCopy, /*IsRoot = */true)) { return false; } Out << ")) {\n"; From b6fc1d4cd6bf36a6dc2b8cdfe3750171d54c514b Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 4 Nov 2022 11:35:18 -0600 Subject: [PATCH 119/165] foo --- tools/matcher-gen.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 98a034946..4479894d8 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -284,8 +284,9 @@ struct SymbolTable : public std::map> { } else { return {"", false}; } - case Inst::Const : return {"util::V(" + std::to_string(I->Width) - + ", " + I->Val.toString(10, false) + ")", true}; + case Inst::Const : + return {"util::V(" + std::to_string(I->Width) + + ", \"" + I->Val.toString(10, false) + "\")", true}; case Inst::AddNW : case Inst::AddNUW : From 46ae8ffcf0570450d28a952dfb6c23b6f92f8762 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 4 Nov 2022 23:57:42 -0600 Subject: [PATCH 120/165] foo --- tools/generalize.cpp | 71 ++++++++++++++++++--------- tools/pass-generator/src/template.cpp | 3 ++ 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 98ffd52f0..ae4b96861 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -765,6 +765,7 @@ ParsedReplacement SimplePreconditionsAndVerifyGreedy( Clone.Mapping.RHS = nullptr; auto SOLVE = [&]() -> bool { +// Input.print(llvm::errs(), true); Clone = Verify(Input, IC, S); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return true; @@ -1027,6 +1028,21 @@ std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, } // TODO Add others + // bit flip + llvm::APInt D = C->Val; + D.flipAllBits(); +// llvm::errs() << "HERE: " << Target << ' ' << C->Val << ' ' << D << "\n"; + if (Target == D) { + Results.push_back(Builder(SMap[C], IC).Xor(llvm::APInt::getAllOnesValue(C->Width))()); + } + + // neg + D = C->Val; + D.negate(); + if (Target == D) { + Results.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C->Width)).Sub(SMap[C])()); + } + if (Threshold == 1) { for (auto C2 : LHSConsts) { if (C == C2 || C->Width != C2->Width) { @@ -1085,13 +1101,12 @@ std::vector> Enumerate(std::vector RHSConsts, std::vector Components; for (auto &&C : LHSConsts) { Components.push_back(C); + Components.push_back(Builder(C, IC).LogB()()); Components.push_back(Builder(C, IC).Sub(1)()); Components.push_back(Builder(C, IC).Xor(-1)()); Components.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C->Width)).Shl(C)()); } - // TODO: Custom components - for (auto &&Target : RHSConsts) { Candidates.push_back({}); EnumerativeSynthesis ES; @@ -1120,6 +1135,12 @@ void findDangerousConstants(Inst *I, std::set &Results) { auto Cur = Stack.back(); Stack.pop_back(); Visited.insert(Cur); + + if (Cur->K == Inst::Const && Cur->Val == 0) { + // Don't try to 'generalize' zero! + Results.insert(Cur); + } + if (Visited.find(Cur) == Visited.end()) { continue; } @@ -1146,7 +1167,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Fresh = Clone(Input, IC); auto Refresh = [&] (auto Msg) { Input = Fresh; -// llvm::errs() << "POST " << Msg << "\n"; + llvm::errs() << "POST " << Msg << "\n"; Changed = true; return Fresh; }; @@ -1372,6 +1393,29 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Special expressions, with constants"); + // Enumerated exprs with constraints + + if (!EnumeratedCandidates.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, true, true); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + + Refresh("Enumerated exprs with constraints"); + + for (auto &&R : Relations) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, true, true); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } + Refresh("Enumerated exprs with constraints and relations"); + } + // Step 5 : Simple exprs with constraints if (!SimpleCandidates.empty()) { @@ -1420,28 +1464,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Simple cands+consts with constraints and relations"); } - // Step 6 : Enumerated exprs with constraints - if (!EnumeratedCandidates.empty()) { - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, - InstCache, IC, S, SymCS, true, true, true); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - - Refresh("Enumerated exprs with constraints"); - - for (auto &&R : Relations) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, - InstCache, IC, S, SymCS, true, true, true); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - } - Refresh("Enumerated exprs with constraints and relations"); - } // std::vector SymDFVars; // std::set LHSConstsAndSymDF; diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index d1a3df611..64c0d60c0 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -483,6 +483,9 @@ namespace util { llvm::APInt V(size_t Width, size_t Val) { return llvm::APInt(Width, Val); } + llvm::APInt V(size_t Width, std::string Val) { + return llvm::APInt(Width, Val, 2); + } } struct SouperCombine : public FunctionPass { From b2acfeefa0f1470d9c221c259a3111874b5dc167 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 4 Nov 2022 23:58:00 -0600 Subject: [PATCH 121/165] foo --- tools/generalize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index ae4b96861..42985d8d9 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1167,7 +1167,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Fresh = Clone(Input, IC); auto Refresh = [&] (auto Msg) { Input = Fresh; - llvm::errs() << "POST " << Msg << "\n"; +// llvm::errs() << "POST " << Msg << "\n"; Changed = true; return Fresh; }; From e526624502a121445f96ae4352748fb44e3e002b Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 6 Nov 2022 02:08:16 -0700 Subject: [PATCH 122/165] foo --- include/souper/Infer/SynthUtils.h | 2 +- tools/generalize.cpp | 129 ++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index fa8f68b7b..1c0cacb7f 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -52,7 +52,7 @@ class Builder { auto L = I; \ return Builder(IC.getInst(Inst::K, L->Width, {L}), IC); \ } - UNOP(LogB) UNOP(BitReverse) UNOP(BSwap) + UNOP(LogB) UNOP(BitReverse) UNOP(BSwap) UNOP(Cttz) UNOP(Ctlz) #undef UNOP diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 42985d8d9..98f6b2bd7 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -808,6 +808,127 @@ if(s) return Clone;}; return Clone; } +ParsedReplacement SymKBPreconditionsAndVerifyGreedy( + ParsedReplacement Input, InstContext &IC, + Solver *S, std::map SymCS) { + + std::map SymKMap; + static size_t i = 0; + for (auto &&C : SymCS) { + SymKMap[IC.createVar(C.first->Width, "symconst_k0_" + std::to_string(i++))] = C.first; + SymKMap[IC.createVar(C.first->Width, "symconst_k1_" + std::to_string(i++))] = C.first; + // Only discriminant for these two are in Name + } + + auto KPC = [&](Inst *SymK) -> InstMapping { + // true : Constraint for known zero + // false : Constraint for known one + + InstMapping Result; + Result.RHS = IC.getConst(llvm::APInt(1, 1)); + + auto I = SymKMap[SymK]; + auto Width = I->Width; + + auto K0 = SymK->Name.starts_with("symconst_k0_"); + + if (K0) { + Inst *AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(Width)); + Inst *NotZeros = IC.getInst(Inst::Xor, Width, {SymK, AllOnes}); + Inst *VarNotZero = IC.getInst(Inst::Or, Width, {I, NotZeros}); + Inst *ZeroBits = IC.getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); + Result.LHS = ZeroBits; + } else { + Inst *VarAndOnes = IC.getInst(Inst::And, Width, {I, SymK}); + Inst *OneBits = IC.getInst(Inst::Eq, 1, {VarAndOnes, SymK}); + Result.LHS = OneBits; + } + + return Result; + }; + + + // Pairwise expressions, all boolean + + for (auto &&P1 : SymKMap) { + for (auto &&P2 : SymKMap) { + if (P1.first == P2.first || P1.first->Width != P2.first->Width) { + continue; + } + + auto X = P1.first; + auto Y = P2.first; + + auto W = P1.first->Width; + + std::vector Exprs; + + auto TrueVal = IC.getConst(llvm::APInt(1, 1)); + + // bit flip x == ~y + Exprs.push_back(Builder(X, IC).Xor(Y).Eq(llvm::APInt::getAllOnesValue(X->Width))()); + + // cttz(val) + ctlz(val) >= Width + auto XV = X; + if (X->Name.starts_with("symconst_k0_")) { + XV = Builder(X, IC).Xor(llvm::APInt::getAllOnesValue(W))(); + } + auto YV = Y; + if (Y->Name.starts_with("symconst_k0_")) { + YV = Builder(Y, IC).Xor(llvm::APInt::getAllOnesValue(W))(); + } + Exprs.push_back(Builder(IC, llvm::APInt(W, W)).Ule( + Builder(XV, IC).Cttz().Add( + Builder(YV, IC).Ctlz()())())()); + + + std::vector Components{X, Y, XV, YV}; + Components.push_back(IC.getConst(llvm::APInt::getAllOnesValue(W))); + + EnumerativeSynthesis ES; + auto Guesses = ES.generateExprs(IC, 2, Components, 1); + for (auto &&Guess : Guesses) { + std::set ConstSet; + souper::getConstants(Guess, ConstSet); + if (!ConstSet.empty()) { + if (SymbolizeConstSynthesis) { + Exprs.push_back(Guess); + } + } else { + Exprs.push_back(Guess); + } + } + + + for (auto &&E : Exprs) { + + auto Backup = Input.PCs; + + InstMapping M(E, TrueVal); + + Input.PCs.push_back(M); + Input.PCs.push_back(KPC(X)); + Input.PCs.push_back(KPC(Y)); + +// Input.print(llvm::errs(), true); +// llvm::errs() << "\n"; + + auto Clone = Verify(Input, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + + Input.PCs = Backup; + } + } + } + + Input.Mapping.LHS = nullptr; + Input.Mapping.RHS = nullptr; + //TODO Better failure indicator + return Input; +} + ParsedReplacement FirstValidCombination(ParsedReplacement Input, const std::vector &Targets, @@ -1243,6 +1364,13 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Clone; } + if (Advanced) { + Clone = SymKBPreconditionsAndVerifyGreedy(Result, IC, S, SymCS); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } + Clone = DFPreconditionsAndVerifyGreedy(Result, IC, S, SymCS); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; @@ -1295,6 +1423,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } + } Refresh("All LHS Constraints"); From 5da5ad96c58b9464e22b47bbb1b0673ab0add2e6 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 7 Nov 2022 12:50:02 -0700 Subject: [PATCH 123/165] foo --- tools/generalize.cpp | 53 ++++++++++++++++----------- tools/matcher-gen.cpp | 18 ++++++--- tools/pass-generator/src/template.cpp | 12 +++++- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 98f6b2bd7..49a80be59 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1144,6 +1144,7 @@ std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, if (Target == C->Val.logBase2()) { Results.push_back(Builder(SMap[C], IC).LogB()()); } + if (Target == C->Val.reverseBits()) { Results.push_back(Builder(SMap[C], IC).BitReverse()()); } @@ -1152,11 +1153,14 @@ std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, // bit flip llvm::APInt D = C->Val; D.flipAllBits(); -// llvm::errs() << "HERE: " << Target << ' ' << C->Val << ' ' << D << "\n"; if (Target == D) { Results.push_back(Builder(SMap[C], IC).Xor(llvm::APInt::getAllOnesValue(C->Width))()); } + if (Target == D + 1) { + Results.push_back(Builder(SMap[C], IC).Xor(llvm::APInt::getAllOnesValue(C->Width)).Add(1)()); + } + // neg D = C->Val; D.negate(); @@ -1288,7 +1292,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Fresh = Clone(Input, IC); auto Refresh = [&] (auto Msg) { Input = Fresh; -// llvm::errs() << "POST " << Msg << "\n"; +// llvm::errs() << "POST " << Msg << "\n"; Changed = true; return Fresh; }; @@ -1481,8 +1485,9 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Step 4.75 : Enumerate 2 instructions when single RHS Constant. + std::vector> EnumeratedCandidatesTwoInsts; if (RHSFresh.size() == 1) { - auto EnumeratedCandidatesTwoInsts = Enumerate(RHSFresh, Components, IC, 2); + EnumeratedCandidatesTwoInsts = Enumerate(RHSFresh, Components, IC, 2); auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, InstCache, IC, S, SymCS, true, false, false); @@ -1490,7 +1495,19 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Clone; } Refresh("Enumerated 2 insts"); + } + + if (!EnumeratedCandidates.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, true, true); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + Refresh("Enumerated exprs with constraints"); + } + + if (RHSFresh.size() == 1) { // Enumerated Expressions with some relational constraints if (CMap.size() == 2) { for (auto &&R : Relations) { @@ -1506,33 +1523,25 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } } - // Step 4.8 : Special RHS constant exprs, with constants + // Step 4.8 : Special RHS constant exprs, with constants - std::vector> SimpleCandidatesWithConsts = - InferSpecialConstExprsWithConcretes(RHSFresh, LHSConsts, SymConstMap, IC); + std::vector> SimpleCandidatesWithConsts = + InferSpecialConstExprsWithConcretes(RHSFresh, LHSConsts, SymConstMap, IC); - if (!SimpleCandidatesWithConsts.empty()) { - auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, - InstCache, IC, S, SymCS, - true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } + if (!SimpleCandidatesWithConsts.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, + InstCache, IC, S, SymCS, + true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } + } - Refresh("Special expressions, with constants"); + Refresh("Special expressions, with constants"); // Enumerated exprs with constraints if (!EnumeratedCandidates.empty()) { - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, - InstCache, IC, S, SymCS, true, true, true); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - - Refresh("Enumerated exprs with constraints"); - for (auto &&R : Relations) { Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 4479894d8..2082a7cc0 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -656,11 +656,22 @@ bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { return true; } +int profitability(const ParsedReplacement &Input) { + return souper::cost(Input.Mapping.LHS) - + souper::cost(Input.Mapping.RHS); +} + template bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIndependent) { SymbolTable Syms; Out << "{\n"; + int prof = profitability(Input); + size_t LHSSize = souper::instCount(Input.Mapping.LHS); + if (prof <= 1 || LHSSize > 15) { + return false; + } + if (!InitSymbolTable(Input.Mapping.LHS, Input.Mapping.RHS, Out, Syms)) { return false; } @@ -684,7 +695,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn if (!Syms.GenPCConstraints(Input.PCs)) return false; Syms.PrintConstraintsPre(Out); - Out << " St.hit(" << OptID << ");\n"; + Out << " St.hit(" << OptID << ", " << prof << ");\n"; Syms.PrintConstDecls(Out); @@ -719,11 +730,6 @@ std::string getLLVMInstKindName(Inst::Kind K) { return str.str(); } -int profitability(const ParsedReplacement &Input) { - return souper::cost(Input.Mapping.LHS) - - souper::cost(Input.Mapping.RHS); -} - bool PCHasVar(const ParsedReplacement &Input) { std::vector Vars; for (auto &&PC : Input.PCs) { diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 64c0d60c0..a602aa43f 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -450,13 +450,15 @@ namespace util { } struct Stats { - void hit(size_t opt) { + void hit(size_t opt, int cost) { Hits[opt]++; + Cost[opt] = cost; } // void dcmiss(size_t opt) { // DCMiss[opt]++; // } std::map Hits; + std::map Cost; // std::map DCMiss; void print() { std::vector> Copy(Hits.size(), std::make_pair(0, 0)); @@ -467,7 +469,13 @@ namespace util { size_t sum = 0; for (auto &&P : Copy) { sum += P.second; - llvm::errs() << "OptID " << P.first << " matched " << P.second << " time(s).\n"; + int64_t cost; + if (Cost.find(P.first) == Cost.end()) { + cost = 1; + } else { + cost = Cost[P.first]; + } + llvm::errs() << "OptID " << P.first << " matched " << P.second << " time(s). Cost " << int(P.second) * cost << "\n"; } llvm::errs() << "Hits end. Total = " << sum << ".\n"; } From e6922823491ed67ad83d4c2ec0e7b30cba060616 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 8 Nov 2022 00:56:43 -0700 Subject: [PATCH 124/165] foo --- tools/matcher-gen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 2082a7cc0..4d3fe0730 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -668,7 +668,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn int prof = profitability(Input); size_t LHSSize = souper::instCount(Input.Mapping.LHS); - if (prof <= 1 || LHSSize > 15) { + if (prof < 1 || LHSSize > 15) { return false; } From da1903e47024892decd1b4acc007d3f69dfff934 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 9 Nov 2022 03:51:27 -0700 Subject: [PATCH 125/165] foo --- tools/matcher-gen.cpp | 41 +++++++++++++++++++++------ tools/pass-generator/CMakeLists.txt | 2 ++ tools/pass-generator/src/template.cpp | 3 ++ 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 4d3fe0730..f6c18792c 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -33,6 +33,16 @@ static llvm::cl::opt IgnoreDF("ignore-df", "(default=false)"), llvm::cl::init(false)); +static llvm::cl::opt NoDispatch("no-dispatch", + llvm::cl::desc("Do not generate code to dispatch on root instruction kind." + "(default=false)"), + llvm::cl::init(false)); + +static llvm::cl::opt Sort("sortf", + llvm::cl::desc("Sort matchers according to listfile" + "(default=false)"), + llvm::cl::init(false)); + static llvm::cl::opt ListFile("listfile", llvm::cl::desc("List of optimization indexes to include.\n" "(default=empty-string)"), @@ -668,7 +678,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn int prof = profitability(Input); size_t LHSSize = souper::instCount(Input.Mapping.LHS); - if (prof < 1 || LHSSize > 15) { + if (prof < 0 || LHSSize > 15) { return false; } @@ -802,11 +812,15 @@ int main(int argc, char **argv) { S = GetSolver(KV); std::unordered_set optnumbers; + std::vector Ordered; if (ListFile != "") { std::ifstream in(ListFile); size_t num; while (in >> num) { optnumbers.insert(num); + if (Sort) { + Ordered.push_back(num); + } } } @@ -845,12 +859,13 @@ int main(int argc, char **argv) { } size_t optnumber = 0; -// genDispatchCode(Kinds); + Inst::Kind Last = Inst::Kind::None; bool first = true; bool outputs = false; + std::map Results; for (auto &&Input: Inputs) { auto SKIP = [&] (auto Msg) { @@ -898,7 +913,7 @@ int main(int argc, char **argv) { } } - if (Input.Mapping.LHS->K != Last) { + if (Input.Mapping.LHS->K != Last && !NoDispatch) { if (!first) { llvm::outs() << "}\n"; } @@ -981,14 +996,16 @@ int main(int argc, char **argv) { SKIP("SKIP Filtered."); continue; } - llvm::outs() << "/* Opt : " << current << "\n"; - Input.print(llvm::outs(), true); - llvm::outs() << "*/\n"; + std::string IRComment = "/* Opt : " + std::to_string(current) + "\n" + Input.getString(true) + "*/\n"; - llvm::outs() << Str << "\n"; + if (NoDispatch && Sort && !Ordered.empty()) { + Results[current] = IRComment + Str + "\n"; + } else { + llvm::outs() << IRComment << Str << "\n"; + llvm::outs().flush(); + outputs= true; + } - llvm::outs().flush(); - outputs= true; } else { SKIP("SKIP Failed to generate matcher."); } @@ -996,6 +1013,12 @@ int main(int argc, char **argv) { if (outputs) { llvm::outs() << "}\n"; } + + if (NoDispatch && Sort && !Ordered.empty()) { + for (auto N : Ordered) { + llvm::outs() << Results[N]; + } + } // llvm::outs() << "end:\n"; diff --git a/tools/pass-generator/CMakeLists.txt b/tools/pass-generator/CMakeLists.txt index ebb7dd798..8c78bd769 100644 --- a/tools/pass-generator/CMakeLists.txt +++ b/tools/pass-generator/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.7) project(souper-combine) +cmake_policy(SET CMP0074 NEW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") find_package(LLVM 14.0 REQUIRED CONFIG) diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index a602aa43f..099dcd408 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -290,6 +290,9 @@ namespace util { } bool dc(llvm::DominatorTree *DT, llvm::Instruction *I, llvm::Value *V) { + if (!V) { + return false; + } if (auto Def = dyn_cast(V)) { if (I->getParent() == Def->getParent()) { return true; From 651a9b02c93e020e6b1afc8e326c84560c9e1fa1 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 3 Jan 2023 00:07:54 -0700 Subject: [PATCH 126/165] Optimization harvesting --- include/souper/Infer/SynthUtils.h | 2 +- include/souper/Tool/CandidateMapUtils.h | 2 + lib/Extractor/Candidates.cpp | 7 +++ lib/Infer/SynthUtils.cpp | 15 ++--- lib/Tool/CandidateMapUtils.cpp | 82 ++++++++++++++++++++++++- tools/generalize.cpp | 9 +-- tools/souper.cpp | 9 +++ 7 files changed, 110 insertions(+), 16 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 1c0cacb7f..26cee4a3e 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -5,6 +5,7 @@ #include "souper/Infer/EnumerativeSynthesis.h" #include "souper/Infer/ConstantSynthesis.h" #include "souper/Parser/Parser.h" +#include "souper/Infer/Pruning.h" namespace souper { @@ -107,7 +108,6 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC); // Returns clone if verified, nullptrs if not ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S); - std::map findOneConstSet(ParsedReplacement Input, const std::set &SymCS, InstContext &IC, Solver *S); std::vector> findValidConsts(ParsedReplacement Input, const std::set &Insts, InstContext &IC, Solver *S, size_t MaxCount); diff --git a/include/souper/Tool/CandidateMapUtils.h b/include/souper/Tool/CandidateMapUtils.h index 1699d5942..5c298a616 100644 --- a/include/souper/Tool/CandidateMapUtils.h +++ b/include/souper/Tool/CandidateMapUtils.h @@ -35,6 +35,8 @@ typedef std::vector CandidateMap; void AddToCandidateMap(CandidateMap &M, const CandidateReplacement &CR); +void HarvestAndPrintOpts(InstContext &IC, ExprBuilderContext &EBC, llvm::Module *M, Solver *S); + void AddModuleToCandidateMap(InstContext &IC, ExprBuilderContext &EBC, CandidateMap &CandMap, llvm::Module *M); diff --git a/lib/Extractor/Candidates.cpp b/lib/Extractor/Candidates.cpp index ced018a8b..867079a64 100644 --- a/lib/Extractor/Candidates.cpp +++ b/lib/Extractor/Candidates.cpp @@ -76,6 +76,10 @@ static llvm::cl::opt PrintSignBitsAtReturn( "print-sign-bits-at-return", llvm::cl::desc("Print sign bits dfa in each value returned from a function (default=false)"), llvm::cl::init(false)); +static llvm::cl::opt NoExternalUses( + "no-external-uses", + llvm::cl::desc("Do not mark external uses. (default=false)"), + llvm::cl::init(false)); static llvm::cl::opt PrintRangeAtReturn( "print-range-at-return", llvm::cl::desc("Print range inforation in each value returned from a function (default=false)"), @@ -294,6 +298,9 @@ Inst *ExprBuilder::buildGEP(Inst *Ptr, gep_type_iterator begin, #endif void ExprBuilder::markExternalUses (Inst *I) { + if (NoExternalUses) { + return; + } std::map UsesCount; std::unordered_set Visited; std::vector Stack; diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index 11c84d67a..b60950bfe 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -77,16 +77,13 @@ ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { std::vector Vars; findVars(Input.Mapping.LHS, Vars); - // TODO figure out why prunning isn't working - // PruningManager Pruner(SC, Vars, 5); - -// Input.print(llvm::errs(), true); - -// if (Pruner.isInfeasibleWithSolver(Input.Mapping.RHS, 5)) { -// llvm::errs() << "FOOOO\n"; -// } else { -// llvm::errs() << "BAAAR\n"; +// Pruner.init(); +// +// if (Pruner.isInfeasible(Input.Mapping.RHS, 0)) { +// Input.Mapping.LHS = nullptr; +// Input.Mapping.RHS = nullptr; +// return Input; // } Input = Clone(Input, IC); diff --git a/lib/Tool/CandidateMapUtils.cpp b/lib/Tool/CandidateMapUtils.cpp index df3b3fa7d..68ff68222 100644 --- a/lib/Tool/CandidateMapUtils.cpp +++ b/lib/Tool/CandidateMapUtils.cpp @@ -14,7 +14,7 @@ #include "souper/Tool/CandidateMapUtils.h" #include "souper/Util/DfaUtils.h" - +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/LLVMContext.h" @@ -24,13 +24,90 @@ #include "llvm/Support/raw_ostream.h" #include "souper/KVStore/KVStore.h" #include "souper/SMTLIB2/Solver.h" - +#include "souper/Infer/SynthUtils.h" +#include "llvm/Transforms/Scalar/ADCE.h" +#include "llvm/Transforms/InstCombine/InstCombine.h" void souper::AddToCandidateMap(CandidateMap &M, const CandidateReplacement &CR) { M.emplace_back(CR); } + +void souper::HarvestAndPrintOpts(InstContext &IC, ExprBuilderContext &EBC, llvm::Module *M, Solver *S) { + legacy::FunctionPassManager P(M); + P.add(createInstructionCombiningPass()); + P.doInitialization(); + for (auto &F : *M) { + std::vector LHSs, RHSs; + FunctionCandidateSet CS1 = ExtractCandidates(&F, IC, EBC); + for (auto &B : CS1.Blocks) { + for (auto &R : B->Replacements) { + LHSs.push_back(R.Mapping.LHS); + } + } + +// F.dump(); + P.run(F); +// F.dump(); + + FunctionCandidateSet CS2 = ExtractCandidates(&F, IC, EBC); + for (auto &B : CS2.Blocks) { + for (auto &R : B->Replacements) { + RHSs.push_back(R.Mapping.LHS); + } + } + + for (auto LHS : LHSs) { + std::vector LHSVars; + findVars(LHS, LHSVars); + std::set LHSVarSet; + for (auto V : LHSVars) { + LHSVarSet.insert(V); + } + + for (auto RHS : RHSs) { + if (LHS != RHS && LHS->Width == RHS->Width) { + + std::vector RHSVars; + findVars(RHS, RHSVars); + + std::set RHSVarSet; + for (auto RV : RHSVars) { + if (LHSVarSet.find(RV) == LHSVarSet.end()) { + continue; + } + RHSVarSet.insert(RV); + } + if (LHSVarSet.size() != RHSVarSet.size()) { + continue; + } + + ParsedReplacement Rep; + Rep.Mapping.LHS = LHS; + Rep.Mapping.RHS = RHS; + +// Rep.print(llvm::errs(), true); + + auto Clone = Verify(Rep, IC, S); + if (Clone.Mapping.RHS && Clone.Mapping.LHS) { + ReplacementContext RC; + auto LS = RC.printInst(Clone.Mapping.LHS, llvm::outs(), true); + llvm::outs() << "infer " << LS << '\n'; + auto RS = RC.printInst(Clone.Mapping.RHS, llvm::outs(), true); + llvm::outs() << "result " << RS << '\n'; + llvm::outs().flush(); + } + + } + } + } + + } + P.doFinalization(); + +} + void souper::AddModuleToCandidateMap(InstContext &IC, ExprBuilderContext &EBC, CandidateMap &CandMap, llvm::Module *M) { for (auto &F : *M) { @@ -41,6 +118,7 @@ void souper::AddModuleToCandidateMap(InstContext &IC, ExprBuilderContext &EBC, } } } + } namespace souper { diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 49a80be59..c2ef8a5d4 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -734,6 +734,7 @@ ParsedReplacement DFPreconditionsAndVerifyGreedy( } } +// llvm::errs() << "HERE " << BitsWeakened << "\n"; if (BitsWeakened >= 32) { // compute better threshold somehow return Input; } else { @@ -1375,10 +1376,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } } - Clone = DFPreconditionsAndVerifyGreedy(Result, IC, S, SymCS); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } +// Clone = DFPreconditionsAndVerifyGreedy(Result, IC, S, SymCS); +// if (Clone.Mapping.LHS && Clone.Mapping.RHS) { +// return Clone; +// } } diff --git a/tools/souper.cpp b/tools/souper.cpp index bf783cf9e..059b1e85a 100644 --- a/tools/souper.cpp +++ b/tools/souper.cpp @@ -53,6 +53,10 @@ OutputFilename("o", cl::desc("Override output filename"), static cl::opt StaticProfile("souper-static-profile", cl::init(false), cl::desc("Static profiling of Souper optimizations (default=false)")); +static cl::opt HarvestOpts("harvest-opts", cl::init(false), + cl::desc("Harvest optimizations performed by InstCombine (default=false)")); + + static cl::opt Check("check", cl::desc("Check input for expected results"), cl::init(false)); @@ -106,6 +110,11 @@ int main(int argc, char **argv) { ExprBuilderContext EBC; CandidateMap CandMap; + if (HarvestOpts) { + HarvestAndPrintOpts(IC, EBC, M.get(), S.get()); + return 0; + } + AddModuleToCandidateMap(IC, EBC, CandMap, M.get()); if (Check) { From a5e0d57373535f3a64c82de1bcce12438062cda0 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 3 Jan 2023 22:57:28 -0700 Subject: [PATCH 127/165] better printing --- lib/Tool/CandidateMapUtils.cpp | 18 ++++++------------ tools/generalize.cpp | 13 +++++++++---- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/Tool/CandidateMapUtils.cpp b/lib/Tool/CandidateMapUtils.cpp index 68ff68222..0512f47f1 100644 --- a/lib/Tool/CandidateMapUtils.cpp +++ b/lib/Tool/CandidateMapUtils.cpp @@ -65,13 +65,10 @@ void souper::HarvestAndPrintOpts(InstContext &IC, ExprBuilderContext &EBC, llvm: for (auto V : LHSVars) { LHSVarSet.insert(V); } - for (auto RHS : RHSs) { if (LHS != RHS && LHS->Width == RHS->Width) { - std::vector RHSVars; findVars(RHS, RHSVars); - std::set RHSVarSet; for (auto RV : RHSVars) { if (LHSVarSet.find(RV) == LHSVarSet.end()) { @@ -82,30 +79,27 @@ void souper::HarvestAndPrintOpts(InstContext &IC, ExprBuilderContext &EBC, llvm: if (LHSVarSet.size() != RHSVarSet.size()) { continue; } - ParsedReplacement Rep; Rep.Mapping.LHS = LHS; Rep.Mapping.RHS = RHS; -// Rep.print(llvm::errs(), true); +// Rep.print(llvm::outs(), true); auto Clone = Verify(Rep, IC, S); if (Clone.Mapping.RHS && Clone.Mapping.LHS) { + BlockPCs BPCs; + std::vector PCs; ReplacementContext RC; - auto LS = RC.printInst(Clone.Mapping.LHS, llvm::outs(), true); - llvm::outs() << "infer " << LS << '\n'; - auto RS = RC.printInst(Clone.Mapping.RHS, llvm::outs(), true); - llvm::outs() << "result " << RS << '\n'; + souper::PrintReplacementLHS(llvm::outs(), BPCs, PCs, Rep.Mapping.LHS, RC, true); + souper::PrintReplacementRHS(llvm::outs(), Rep.Mapping.RHS, RC, true); + llvm::outs() << "\n"; llvm::outs().flush(); } - } } } - } P.doFinalization(); - } void souper::AddModuleToCandidateMap(InstContext &IC, ExprBuilderContext &EBC, diff --git a/tools/generalize.cpp b/tools/generalize.cpp index c2ef8a5d4..8324c4cc1 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1293,7 +1293,9 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Fresh = Clone(Input, IC); auto Refresh = [&] (auto Msg) { Input = Fresh; -// llvm::errs() << "POST " << Msg << "\n"; + if (DebugLevel > 2) { + llvm::errs() << "POST " << Msg << "\n"; + } Changed = true; return Fresh; }; @@ -1507,7 +1509,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Enumerated exprs with constraints"); } - + if (RHSFresh.size() == 1) { // Enumerated Expressions with some relational constraints if (CMap.size() == 2) { @@ -1604,7 +1606,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } - // std::vector SymDFVars; // std::set LHSConstsAndSymDF; @@ -1863,7 +1864,11 @@ int main(int argc, char **argv) { // Result.print(llvm::errs(), true); } while (--MaxTries && Changed); } - Result.print(llvm::outs(), true); + ReplacementContext RC; + RC.printPCs(Result.PCs, llvm::outs(), true); + RC.printBlockPCs(Result.BPCs, llvm::outs(), true); + Result.printLHS(llvm::outs(), RC, true); + Result.printRHS(llvm::outs(), RC, true); llvm::outs() << "\n"; continue; } From b5c686b9df688dd1d2ed75c1d35b97c67ede8a66 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 25 Jan 2023 01:36:43 -0700 Subject: [PATCH 128/165] More generalization --- include/souper/Inst/Inst.h | 2 +- lib/Infer/AliveDriver.cpp | 9 +- lib/Inst/Inst.cpp | 5 +- lib/Tool/CandidateMapUtils.cpp | 50 ++++++-- tools/generalize.cpp | 223 ++++++++++++++++++++++----------- tools/matcher-gen.cpp | 10 +- 6 files changed, 213 insertions(+), 86 deletions(-) diff --git a/include/souper/Inst/Inst.h b/include/souper/Inst/Inst.h index ee1cae397..6703fbad8 100644 --- a/include/souper/Inst/Inst.h +++ b/include/souper/Inst/Inst.h @@ -291,7 +291,7 @@ int cost(Inst *I, bool IgnoreDepsWithExternalUses = false); int backendCost(Inst *I, bool IgnoreDepsWithExternalUses = false); int countHelper(Inst *I, std::set &Visited); int instCount(Inst *I); -int benefit(Inst *LHS, Inst *RHS); +int benefit(Inst *LHS, Inst *RHS, bool IgnoreDepsWithExternalUses = true); void PrintReplacement(llvm::raw_ostream &Out, const BlockPCs &BPCs, const std::vector &PCs, InstMapping Mapping, diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index 303142394..f2846d806 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -417,6 +417,12 @@ bool souper::AliveDriver::verify (Inst *RHS, Inst *RHSAssumptions) { RExprCache.clear(); IR::Function RHSF; copyInputs(RExprCache, RHSF); + + for (const IR::Value &I : RHSF.getInputs()) { + std::cerr << I << "\n"; + std::cerr << I.getType() << "\n"; + } + if (!translateRoot(RHS, RHSAssumptions, RHSF, RExprCache)) { llvm::errs() << "Failed to translate RHS.\n"; // TODO: Eventually turn this into an assertion @@ -761,7 +767,8 @@ souper::AliveDriver::translateDemandedBits(const souper::Inst* I, IR::Type &souper::AliveDriver::getType(int Width) { std::string n = "i" + std::to_string(Width); if (TypeCache.find(n) == TypeCache.end()) { - TypeCache[n] = new IR::IntType(std::move(n), Width); +// TypeCache[n] = new IR::IntType(std::move(n), Width); + TypeCache[n] = new IR::SymbolicType(std::to_string(Width)); } return *TypeCache[n]; } diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index 63979d8b4..c76c96639 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -20,6 +20,7 @@ #include #include +#include using namespace souper; @@ -1015,8 +1016,8 @@ int souper::instCount(Inst *I) { return countHelper(I, Visited); } -int souper::benefit(Inst *LHS, Inst *RHS) { - return cost(LHS, /*IgnoreDepsWithExternalUses=*/true) - cost(RHS); +int souper::benefit(Inst *LHS, Inst *RHS, bool IgnoreDepsWithExternalUses) { + return cost(LHS, IgnoreDepsWithExternalUses) - cost(RHS); } void souper::PrintReplacement(llvm::raw_ostream &Out, diff --git a/lib/Tool/CandidateMapUtils.cpp b/lib/Tool/CandidateMapUtils.cpp index 0512f47f1..76453265b 100644 --- a/lib/Tool/CandidateMapUtils.cpp +++ b/lib/Tool/CandidateMapUtils.cpp @@ -33,6 +33,31 @@ void souper::AddToCandidateMap(CandidateMap &M, M.emplace_back(CR); } +// limited implementation to filter out specific buggy harvests +bool isWellTyped(souper::Inst *I) { + if (I->K == souper::Inst::Kind::Select) { + return I->Ops[0]->Width == 1 + && (I->Ops[1]->Width == I->Ops[2]->Width) + && isWellTyped(I->Ops[1]) + && isWellTyped(I->Ops[2]); + } + + if (I->Ops.size() == 2) { + return (I->Ops[0]->Width == I->Ops[1]->Width) + && isWellTyped(I->Ops[0]) + && isWellTyped(I->Ops[1]); + } + return true; +} + +bool isProfitable(souper::ParsedReplacement &R) { + if (R.Mapping.LHS->Width == 1 || R.Mapping.RHS->K == souper::Inst::Select) { + return true; + // TODO: Improved cost model for Select + } else { + return souper::benefit(R.Mapping.LHS, R.Mapping.RHS, false) >= 0; + } +} void souper::HarvestAndPrintOpts(InstContext &IC, ExprBuilderContext &EBC, llvm::Module *M, Solver *S) { legacy::FunctionPassManager P(M); @@ -65,7 +90,16 @@ void souper::HarvestAndPrintOpts(InstContext &IC, ExprBuilderContext &EBC, llvm: for (auto V : LHSVars) { LHSVarSet.insert(V); } + + if (!isWellTyped(LHS)) { + continue; + } + for (auto RHS : RHSs) { + if (!isWellTyped(RHS)) { + continue; + } + if (LHS != RHS && LHS->Width == RHS->Width) { std::vector RHSVars; findVars(RHS, RHSVars); @@ -87,13 +121,15 @@ void souper::HarvestAndPrintOpts(InstContext &IC, ExprBuilderContext &EBC, llvm: auto Clone = Verify(Rep, IC, S); if (Clone.Mapping.RHS && Clone.Mapping.LHS) { - BlockPCs BPCs; - std::vector PCs; - ReplacementContext RC; - souper::PrintReplacementLHS(llvm::outs(), BPCs, PCs, Rep.Mapping.LHS, RC, true); - souper::PrintReplacementRHS(llvm::outs(), Rep.Mapping.RHS, RC, true); - llvm::outs() << "\n"; - llvm::outs().flush(); + if (isProfitable(Rep)) { + BlockPCs BPCs; + std::vector PCs; + ReplacementContext RC; + souper::PrintReplacementLHS(llvm::outs(), BPCs, PCs, Rep.Mapping.LHS, RC, true); + souper::PrintReplacementRHS(llvm::outs(), Rep.Mapping.RHS, RC, true); + llvm::outs() << "\n"; + llvm::outs().flush(); + } } } } diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 8324c4cc1..6f863e5ab 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -157,7 +157,6 @@ void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { } } - // This can probably be done more efficiently, but likely not the bottleneck anywhere std::vector> GetCombinations(std::vector Counts) { if (Counts.size() == 1) { @@ -258,16 +257,6 @@ void SymbolizeWidthNew(InstContext &IC, Solver *S, ParsedReplacement Input, } } -void ReplaceConstsSimple(InstContext &IC, Solver *S, - ParsedReplacement Input, - std::vector LHSConsts, - std::vector RHSConsts, - CandidateMap &Results) { - // FIXME Start from here - // Try replacing each constant with a width independent - // expr or a kb expr -} - template bool All(const C &c, F f) { for (auto &&m : c) { @@ -280,7 +269,7 @@ bool All(const C &c, F f) { bool InferPreconditionsAndVerify(ParsedReplacement Input, CandidateMap &Results, std::vector> &SymCS, InstContext &IC, Solver *S) { - + auto SOLVE = [&]() { auto Result = Verify(Input, IC, S); if (Result.Mapping.LHS && Result.Mapping.RHS) { @@ -292,25 +281,25 @@ bool InferPreconditionsAndVerify(ParsedReplacement Input, CandidateMap &Results, return false; } }; - + if (SOLVE()) return true; - + std::vector Insts; findVars(Input.Mapping.LHS, Insts); - + std::set ModelInsts; for (auto I : SymCS) { ModelInsts.insert(I.first); } - - - + + + std::vector> Inputs; Inputs.push_back({}); for (auto &&P : SymCS) { Inputs.back()[P.first] = P.second; } - + // TODO Is this worth using? bool SynthNewConsts = false; if (SynthNewConsts) { @@ -318,21 +307,21 @@ bool InferPreconditionsAndVerify(ParsedReplacement Input, CandidateMap &Results, Inputs.push_back(I); } } - + std::map> CVals; - + for (auto &&I : Inputs) { for (auto &&P: I) { CVals[P.first].push_back(P.second); } } - + if (Inputs.empty()) { if (DebugLevel > 4) llvm::errs() << "Could not find valid concrete constants.\n"; return false; } - + if (SymbolizeSimpleDF) { #define DF(Fact, Check) \ @@ -351,12 +340,64 @@ C->Fact = true; if (SOLVE()) return true; C->Fact = false;}; if (SymbolizeKBDF) { // Reducer R(IC, S); - + } - + return false; } +std::vector findConcreteConsts(const ParsedReplacement &Input) { + std::vector Consts; + auto Pred = [](Inst *I) { + return I->K == Inst::Const && I->Name.find("sym") == std::string::npos; + }; + + findInsts(Input.Mapping.LHS, Consts, Pred); + findInsts(Input.Mapping.RHS, Consts, Pred); + std::set ResultSet; // For deduplication + for (auto &&C : Consts) { + ResultSet.insert(C); + } + std::vector Result; + for (auto &&C : ResultSet) { + Result.push_back(C); + } + return Result; +} + +std::vector InferConstantLimits( + const std::vector> &CMap, + InstContext &IC, const ParsedReplacement &Input) { + std::vector Results; + if (!FindConstantRelations) { + return Results; + } + auto ConcreteConsts = findConcreteConsts(Input); + std::sort(ConcreteConsts.begin(), ConcreteConsts.end(), + [](auto A, auto B) { return A->Val.ugt(B->Val); }); + + for (auto &&[XI, XC] : CMap) { + for (auto &&[YI, YC] : CMap) { + // Sum less than const, Sum greater= than const + for (auto C : ConcreteConsts) { + auto Sum = Builder(XI, IC).Add(YI)(); + Results.push_back(Builder(Sum, IC).Ult(C->Val)()); + Results.push_back(Builder(Sum, IC).Ult(C->Val).Xor(1)()); + } + // 2 * X < C, 2 * X >= C + for (auto C : ConcreteConsts) { + auto Sum = Builder(XI, IC).Add(XI)(); + Results.push_back(Builder(Sum, IC).Ult(C->Val)()); + Results.push_back(Builder(Sum, IC).Ult(C->Val).Xor(1)()); + } + } + } + return Results; +} + +// This was originally intended to fine relational constraints +// but we also use to fine some ad hoc constraints now. +// TODO: Filter relations by concrete interpretation std::vector InferPotentialRelations( const std::vector> &CMap, InstContext &IC, const ParsedReplacement &Input) { @@ -364,15 +405,20 @@ std::vector InferPotentialRelations( if (!FindConstantRelations) { return Results; } + // Generate a set of pairwise relations for (auto &&[XI, XC] : CMap) { + // llvm::errs() << "HERE: " << XC << "\n"; for (auto &&[YI, YC] : CMap) { + if (XI == YI || XC.getBitWidth() != YC.getBitWidth()) { continue; } - // Add C -// auto Diff = XC - YC; -// Results.push_back(Builder(XI, IC).Sub(Diff).Eq(YI)()); + + // // Add C + // auto Diff = XC - YC; + // Results.push_back(Builder(XI, IC).Sub(Diff).Eq(YI)()); + // Mul C if (YC!= 0 && XC.urem(YC) == 0) { auto Fact = XC.udiv(YC); @@ -383,7 +429,7 @@ std::vector InferPotentialRelations( Results.push_back(Builder(XI, IC).Mul(Fact).Eq(YI)()); } - // TODO CHeck if this is too slow + // TODO Check if this is too slow if (Input.Mapping.LHS->Width == 1) { // need both signed and unsigned? // What about s/t/e/ versions? @@ -394,9 +440,8 @@ std::vector InferPotentialRelations( } } } - return Results; -}; +} // FIXME Other interesting things to try // Symbolic KB in preconditions @@ -407,7 +452,7 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In std::vector LHSConsts, std::vector RHSConsts, CandidateMap &Results) { - + if (RHSConsts.empty()) { // Handled in another function return; @@ -417,10 +462,10 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In std::vector Vars; std::vector SymDFVars; findVars(Input.Mapping.LHS, Vars); - + std::map InstCache; ValueCache VC; - + // Create a symbolic const for each LHS const for (size_t i = 0; i < LHSConsts.size(); ++i) { auto C = IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i)); @@ -431,7 +476,7 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In auto Relations = InferPotentialRelations(SymCS, IC, Input); std::vector Components; - + // // Symbolic known bits // if (false) { // for (size_t i = 0; i < Vars.size(); ++i) { @@ -461,7 +506,7 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In // Shiftmask // Components.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C.first->Width)).Shl(C.first)()); - + // Custom test // auto M1 = IC.getConst(llvm::APInt(C->Width, -1)); // auto Test = Builder(C, IC).Add(M1).Xor(M1).And(M1); @@ -552,7 +597,7 @@ void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement In InstMapping Mapping(LHS, RHS); auto Copy = Input; Copy.Mapping = Mapping; - + //if (Pr.isInfeasible(RHS, 0)) { // llvm::errs() << "PRUNED\n"; // Figure out why this never succeeds :( //} else { @@ -582,10 +627,10 @@ void SymbolizeAndGeneralizeOnlyLHS(InstContext &IC, std::vector Vars; std::vector SymDFVars; findVars(Input.Mapping.LHS, Vars); - + std::map InstCache; ValueCache VC; - + // Create a symbolic const for each LHS const for (size_t i = 0; i < LHSConsts.size(); ++i) { auto C = IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i)); @@ -593,10 +638,10 @@ void SymbolizeAndGeneralizeOnlyLHS(InstContext &IC, InstCache[LHSConsts[i]] = C; VC[C] = EvalValue(LHSConsts[i]->Val); } - + auto LHS = Replace(Input.Mapping.LHS, IC, InstCache); auto RHS = Replace(Input.Mapping.RHS, IC, InstCache); - + InstMapping Mapping(LHS, RHS); auto Copy = Input; Copy.Mapping = Mapping; @@ -619,7 +664,7 @@ void SymbolizeAndGeneralize(InstContext &IC, findInsts(Input.Mapping.RHS, RHSConsts, Pred); CandidateMap Results; - + if (RHSConsts.empty()) { SymbolizeAndGeneralizeOnlyLHS(IC, S, Input, LHSConsts, Results); } else { @@ -662,7 +707,7 @@ void SymbolizeAndGeneralize(InstContext &IC, } int n = 5; - for (auto &&Str : ResultStrs) { + for (auto &&Str : ResultStrs) { // if (!n--) break; llvm::outs() << Str << "\n"; if (Everything) { @@ -1019,12 +1064,17 @@ FirstValidCombination(ParsedReplacement Input, return false; }; - auto Copy = Replace(Input, IC, InstCacheRHS); + auto Copy = Input; + Copy.Mapping.LHS = Replace(Input.Mapping.LHS, IC, InstCacheRHS); + Copy.Mapping.RHS = Replace(Input.Mapping.RHS, IC, InstCacheRHS); + + // Copy.PCs = Input.PCs; if (SOLVE(Copy)) { return Clone; } - Copy = Replace(Copy, IC, ReverseMap); + Copy.Mapping.LHS = Replace(Copy.Mapping.LHS, IC, ReverseMap); + Copy.Mapping.RHS = Replace(Copy.Mapping.RHS, IC, ReverseMap); if (SOLVE(Copy)) { return Clone; } @@ -1036,7 +1086,7 @@ FirstValidCombination(ParsedReplacement Input, return Input; } - +// TODO: Prevent NOPs from being synthesized by passing parent instruction std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, std::map SMap, InstContext &IC, size_t Threshold, bool ConstMode) { @@ -1145,7 +1195,7 @@ std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, if (Target == C->Val.logBase2()) { Results.push_back(Builder(SMap[C], IC).LogB()()); } - + if (Target == C->Val.reverseBits()) { Results.push_back(Builder(SMap[C], IC).BitReverse()()); } @@ -1169,20 +1219,18 @@ std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, Results.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C->Width)).Sub(SMap[C])()); } - if (Threshold == 1) { - for (auto C2 : LHSConsts) { - if (C == C2 || C->Width != C2->Width) { - continue; - } - if ((C->Val & C2->Val) == Target) { - Results.push_back(Builder(SMap[C], IC).And(SMap[C2])()); - } - if ((C->Val | C2->Val) == Target) { - Results.push_back(Builder(SMap[C], IC).Or(SMap[C2])()); - } - if ((C->Val ^ C2->Val) == Target) { - Results.push_back(Builder(SMap[C], IC).Xor(SMap[C2])()); - } + for (auto C2 : LHSConsts) { + if (C == C2 || C->Width != C2->Width) { + continue; + } + if ((C->Val & C2->Val) == Target) { + Results.push_back(Builder(SMap[C], IC).And(SMap[C2])()); + } + if ((C->Val | C2->Val) == Target) { + Results.push_back(Builder(SMap[C], IC).Or(SMap[C2])()); + } + if ((C->Val ^ C2->Val) == Target) { + Results.push_back(Builder(SMap[C], IC).Xor(SMap[C2])()); } } } @@ -1192,11 +1240,13 @@ std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, std::vector> InferSpecialConstExprsAllSym(std::vector RHS, std::set - LHS, std::map SMap, - InstContext &IC) { + LHS, std::map SMap, + InstContext &IC, int depth = 3) { std::vector> Results; for (auto R : RHS) { - Results.push_back(IOSynthesize(R->Val, LHS, SMap, IC, 3, false)); + Results.push_back(IOSynthesize(R->Val, LHS, SMap, IC, depth, false)); + std::sort(Results.back().begin(), Results.back().end(), + [](Inst *A, Inst *B) { return instCount(A) < instCount(B);}); } return Results; } @@ -1481,6 +1531,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } + Input.PCs.pop_back(); } } Refresh("Relational constraints for enumerated cands."); @@ -1499,7 +1550,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } Refresh("Enumerated 2 insts"); } - + if (!EnumeratedCandidates.empty()) { auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, InstCache, IC, S, SymCS, true, true, true); @@ -1510,12 +1561,27 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Enumerated exprs with constraints"); } + { + auto Copy = Replace(Input, IC, JustLHSSymConstMap); + auto ConstantLimits = InferConstantLimits(CMap, IC, Input); + for (auto &&R : ConstantLimits) { + Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + // Copy.print(llvm::errs(), true); + // llvm::errs() << "\n\n"; + auto Clone = Verify(Copy, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + Copy.PCs.pop_back(); + } + Refresh("Constant limit constraints on LHS"); + } + if (RHSFresh.size() == 1) { // Enumerated Expressions with some relational constraints if (CMap.size() == 2) { for (auto &&R : Relations) { Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, InstCache, IC, S, SymCS, true, false, false); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { @@ -1605,6 +1671,23 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Simple cands+consts with constraints and relations"); } + { + if (!RHSFresh.empty()) { + std::vector> SimpleCandidatesMoreInsts = + InferSpecialConstExprsAllSym(RHSFresh, LHSConsts, SymConstMap, IC, /*depth =*/ 5); + + if (!SimpleCandidates.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesMoreInsts, + InstCache, IC, S, SymCS, + true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } + + Refresh("Special expressions, no constants"); + } + } // std::vector SymDFVars; // std::set LHSConstsAndSymDF; @@ -1865,8 +1948,6 @@ int main(int argc, char **argv) { } while (--MaxTries && Changed); } ReplacementContext RC; - RC.printPCs(Result.PCs, llvm::outs(), true); - RC.printBlockPCs(Result.BPCs, llvm::outs(), true); Result.printLHS(llvm::outs(), RC, true); Result.printRHS(llvm::outs(), RC, true); llvm::outs() << "\n"; @@ -1903,9 +1984,3 @@ int main(int argc, char **argv) { } return 0; } - -// TODO List -// Derive relations between LHSConsts and use them as preconditions -// Test phase before verification -// Is it possible to pre-generate the set of all possible constants? No. -// Some? definitely. diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index f6c18792c..19117f65c 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -759,6 +759,9 @@ bool PCHasVar(const ParsedReplacement &Input) { bool IsWidthIndependent(InstContext &IC, Solver *S, ParsedReplacement Input) { + // FIXME Re-enable this later + return false; + if (Input.Mapping.LHS->Width == 1) { return false; } @@ -996,7 +999,12 @@ int main(int argc, char **argv) { SKIP("SKIP Filtered."); continue; } - std::string IRComment = "/* Opt : " + std::to_string(current) + "\n" + Input.getString(true) + "*/\n"; + ReplacementContext RC; + std::string IRComment = + "/* Opt : " + + std::to_string(current) + "\n" + + Input.getLHSString(RC, true) + + Input.getRHSString(RC, true) + "*/\n"; if (NoDispatch && Sort && !Ordered.empty()) { Results[current] = IRComment + Str + "\n"; From 227cb3f2638fb55ffc170e6ba9a478192cf35288 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 31 Jan 2023 16:17:51 -0700 Subject: [PATCH 129/165] Remove redundant code --- include/souper/Infer/AliveDriver.h | 7 +- lib/Infer/AliveDriver.cpp | 77 +++- lib/Tool/CandidateMapUtils.cpp | 5 + tools/generalize.cpp | 706 +---------------------------- 4 files changed, 101 insertions(+), 694 deletions(-) diff --git a/include/souper/Infer/AliveDriver.h b/include/souper/Infer/AliveDriver.h index a2fc40d4f..9b0b897e1 100644 --- a/include/souper/Infer/AliveDriver.h +++ b/include/souper/Infer/AliveDriver.h @@ -30,7 +30,7 @@ class AliveDriver { typedef std::unordered_map Cache; public: AliveDriver(Inst *LHS_, Inst *PreCondition_, InstContext &IC_, - std::vector ExtraInputs = {}); + std::vector ExtraInputs = {}, bool WidthIndep = false); std::map synthesizeConstants(souper::Inst *RHS); std::map synthesizeConstantsWithCegis(souper::Inst *RHS, InstContext &IC); @@ -41,6 +41,8 @@ class AliveDriver { delete(p.second); } } + + bool WidthIndependentMode; // This probably doesn't need to be public private: Inst *LHS, *PreCondition; @@ -51,7 +53,6 @@ class AliveDriver { std::unordered_map TypeCache; - IR::Type &getType(int n); IR::Type &getOverflowType(int n); @@ -65,6 +66,8 @@ class AliveDriver { std::unordered_map NamesCache; bool IsLHS; + std::vector> ValidTypings; + InstContext &IC; smt::smt_initializer smt_init; }; diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index f2846d806..9cb9b9e4d 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -43,6 +43,15 @@ static llvm::cl::opt SkipAliveSolver("alive-skip-solver", llvm::cl::desc("Omit Alive solver calls for performance testing (default = false)"), llvm::cl::init(false)); +static llvm::cl::opt WidthIndepOpt("alive-all-widths", + llvm::cl::desc("Ignore Souper type widths and verify for all widths."), + llvm::cl::init(false)); + +static llvm::cl::opt ShowValidWidths("show-valid-widths", + llvm::cl::desc("Show widths for which the input is valid."), + llvm::cl::init(true)); + + class FunctionBuilder { public: FunctionBuilder(IR::Function &F_) : F(F_) {} @@ -284,10 +293,14 @@ synthesizeConstantUsingSolver(tools::Transform &t, } souper::AliveDriver::AliveDriver(Inst *LHS_, Inst *PreCondition_, InstContext &IC_, - std::vector ExtraInputs) + std::vector ExtraInputs, bool WidthIndep) : LHS(LHS_), PreCondition(PreCondition_), IC(IC_) { smt::set_query_timeout(std::to_string(60000)); // milliseconds IsLHS = true; + WidthIndependentMode = WidthIndep; + if (WidthIndepOpt) { + WidthIndependentMode = true; + } InstNumbers = 101; //FIXME: Magic number. 101 is chosen arbitrarily. //This should go away once non-input variable names are not discarded @@ -415,14 +428,9 @@ void souper::AliveDriver::copyInputs(souper::AliveDriver::Cache &To, bool souper::AliveDriver::verify (Inst *RHS, Inst *RHSAssumptions) { RExprCache.clear(); + ValidTypings.clear(); IR::Function RHSF; copyInputs(RExprCache, RHSF); - - for (const IR::Value &I : RHSF.getInputs()) { - std::cerr << I << "\n"; - std::cerr << I.getType() << "\n"; - } - if (!translateRoot(RHS, RHSAssumptions, RHSF, RExprCache)) { llvm::errs() << "Failed to translate RHS.\n"; // TODO: Eventually turn this into an assertion @@ -442,6 +450,52 @@ bool souper::AliveDriver::verify (Inst *RHS, Inst *RHSAssumptions) { t.tgt = std::move(RHSF); tools::TransformVerify tv(t, /*check_each_var=*/false); + auto types = tv.getTypings(); + + if (!types.hasSingleTyping()) { + unsigned i = 0; + size_t correct = 0; + size_t incorrect = 0; + for (; types; ++types) { + + tv.fixupTypes(types); + if (auto errs = tv.verify()) { + if (DebugLevel > 4) { + llvm::errs() << "Invalid typing: "; + for (auto &&P : Inputs) { + llvm::errs() << P.first->Name << ' ' << P.second->bits() << "\n"; + } + } + incorrect++; + } else { + std::map Typing; + for (auto &&P : Inputs) { + Typing[P.first] = P.second->bits(); + } + ValidTypings.push_back(Typing); + correct++; + } + } + if (!incorrect) { + return true; + } else if (!correct) { + return false; + } else { + if (ShowValidWidths) { + llvm::outs() << "Transformation seems to be correct for some widths!\n"; + std::sort(ValidTypings.begin(), ValidTypings.end(), + [](const auto &A, const auto &B) {return A.begin()->second < B.begin()->second;}); + for (auto &&P : ValidTypings) { + for (auto &&I : P) { + llvm::outs() << I.first->Name << ' ' << I.second << '\t'; + } + llvm::outs() << '\n'; + } + } + return false; + } + } + if (SkipAliveSolver) return false; @@ -767,10 +821,13 @@ souper::AliveDriver::translateDemandedBits(const souper::Inst* I, IR::Type &souper::AliveDriver::getType(int Width) { std::string n = "i" + std::to_string(Width); if (TypeCache.find(n) == TypeCache.end()) { -// TypeCache[n] = new IR::IntType(std::move(n), Width); - TypeCache[n] = new IR::SymbolicType(std::to_string(Width)); + if (WidthIndependentMode) { + TypeCache[""] = new IR::SymbolicType("symty_", (1 << IR::SymbolicType::Int)); + } else { + TypeCache[n] = new IR::IntType(std::move(n), Width); + } } - return *TypeCache[n]; + return WidthIndependentMode ? *TypeCache[""] : *TypeCache[n]; } IR::Type &souper::AliveDriver::getOverflowType(int Width) { diff --git a/lib/Tool/CandidateMapUtils.cpp b/lib/Tool/CandidateMapUtils.cpp index 76453265b..17056a368 100644 --- a/lib/Tool/CandidateMapUtils.cpp +++ b/lib/Tool/CandidateMapUtils.cpp @@ -101,6 +101,11 @@ void souper::HarvestAndPrintOpts(InstContext &IC, ExprBuilderContext &EBC, llvm: } if (LHS != RHS && LHS->Width == RHS->Width) { + if ((RHS->K == Inst::ZExt || RHS->K == Inst::Freeze) + && RHS->Ops[0] == LHS) { + continue; + } + std::vector RHSVars; findVars(RHS, RHSVars); std::set RHSVarSet; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 6f863e5ab..cdb18e738 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -31,54 +31,21 @@ static cl::opt InputFilename(cl::Positional, cl::desc(""), cl::init("-")); -static llvm::cl::opt Reduce("reduce", - llvm::cl::desc("Try to reduce the number of instructions by replacing instructions with variables." - "(default=false)"), - llvm::cl::init(false)); - static llvm::cl::opt ReduceKBIFY("reduce-kbify", llvm::cl::desc("Try to reduce the number of instructions by introducing known bits constraints." "(default=false)"), llvm::cl::init(true)); - -static llvm::cl::opt ReducePrintAll("reduce-all-results", - llvm::cl::desc("Print all reduced results." - "(default=false)"), - llvm::cl::init(false)); - -static llvm::cl::opt SymbolizeConstant("symbolize", - llvm::cl::desc("Try to replace a concrete constant with a symbolic constant." - "(default=false)"), - llvm::cl::init(true)); - static llvm::cl::opt FindConstantRelations("relational", llvm::cl::desc("Find constant relations." - "(default=false)"), + "(default=true)"), llvm::cl::init(true)); -static llvm::cl::opt SymbolizeWidth("symbolize-width", - llvm::cl::desc("Try to replace a concrete constant with a function of bitwidth." - "(default=false)"), - llvm::cl::init(false)); - static llvm::cl::opt SymbolizeNumInsts("symbolize-num-insts", llvm::cl::desc("Number of instructions to synthesize" "(default=1)"), llvm::cl::init(1)); -static llvm::cl::opt SymbolizeNoDFP("symbolize-no-dataflow", - llvm::cl::desc("Do not generate optimizations with dataflow preconditions."), - llvm::cl::init(false)); - -static llvm::cl::opt SymbolizeSimpleDF("symbolize-simple-dataflow", - llvm::cl::desc("Generate simple dataflow facts supported by LLVM."), - llvm::cl::init(true)); - -static llvm::cl::opt SymbolizeKBDF("symbolize-infer-kb", - llvm::cl::desc("Generate KB constraints for symbolic constants."), - llvm::cl::init(true)); - static llvm::cl::opt SymbolizeConstSynthesis("symbolize-constant-synthesis", llvm::cl::desc("Allow concrete constants in the generated code."), llvm::cl::init(false)); @@ -92,29 +59,10 @@ static llvm::cl::opt FixIt("fixit", "(default=false)"), llvm::cl::init(false)); -static llvm::cl::opt GeneralizeWidth("all-widths", - llvm::cl::desc("Given a valid optimization, output all bitwidths." - "(default=false)"), - llvm::cl::init(false)); - -static llvm::cl::opt GeneralizeWidthVerify("all-widths-verify", - llvm::cl::desc("Verify for all bitwidths" - "(default=false)"), - llvm::cl::init(false)); - -static llvm::cl::opt MinimizeWidth("minimize-width", - llvm::cl::desc("Find valid version with minimal width" - "(default=false)"), - llvm::cl::init(false)); - static cl::opt NumResults("generalization-num-results", cl::desc("Number of Generalization Results"), cl::init(1)); -static cl::opt Everything("everything", - cl::desc("Run everything, output one result."), - cl::init(false)); - static cl::opt JustReduce("just-reduce", cl::desc("JustReduce"), cl::init(false)); @@ -131,32 +79,6 @@ static cl::opt SymbolicDF("symbolic-df", cl::desc("Generalize with symbolic dataflow facts."), cl::init(false)); -void Generalize(InstContext &IC, Solver *S, ParsedReplacement Input) { - bool FoundWP = false; - std::vector> KBResults; - std::vector> CRResults; - S->abstractPrecondition(Input.BPCs, Input.PCs, Input.Mapping, IC, FoundWP, KBResults, CRResults); - - if (FoundWP && KBResults.empty() && CRResults.empty()) { - Input.print(llvm::outs(), true); - } else if (!KBResults.empty()) { - for (auto &&Result : KBResults) { // Each result is a disjunction - for (auto &Pair: Result) { - Pair.first->KnownOnes = Pair.second.One; - Pair.first->KnownZeros = Pair.second.Zero; - } - Input.print(llvm::outs(), true); - } - } else if (!CRResults.empty()) { - for (auto &&Result : CRResults) { // Each result is a disjunction - for (auto &Pair: Result) { - Pair.first->Range = Pair.second; - } - Input.print(llvm::outs(), true); - } - } -} - // This can probably be done more efficiently, but likely not the bottleneck anywhere std::vector> GetCombinations(std::vector Counts) { if (Counts.size() == 1) { @@ -181,82 +103,6 @@ std::vector> GetCombinations(std::vector Counts) { return Result; } -void SymbolizeWidthNew(InstContext &IC, Solver *S, ParsedReplacement Input, - CandidateMap &Results) { - std::vector Consts; - std::vector Vars; - findVars(Input.Mapping.LHS, Vars); - - auto Pred = [](Inst *I) {return I->K == Inst::Const;}; - findInsts(Input.Mapping.LHS, Consts, Pred); - findInsts(Input.Mapping.RHS, Consts, Pred); - - for (auto &&C : Consts) { - std::vector Components; - Components.push_back(IC.getInst(Inst::BitWidth, C->Width, {Vars[0]})); - - EnumerativeSynthesis ES; - auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, - C->Width); - - for (auto &&G : Guesses) { - std::map InstCache; - InstCache[C] = G; - int SymExprCount = 0; - - - auto LHS = Replace(Input.Mapping.LHS, IC, InstCache); - auto RHS = Replace(Input.Mapping.RHS, IC, InstCache); - - InstMapping Mapping(LHS, RHS); - auto Copy = Input; - Copy.Mapping = Mapping; - bool IsValid = false; - - auto CheckAndSave = [&] () { - auto Result = Verify(Copy, IC, S); - if (Result.Mapping.LHS && Result.Mapping.RHS) { - CandidateReplacement Rep(nullptr, Result.Mapping); - Rep.PCs = Result.PCs; - Results.push_back(Rep); - } - }; - - CheckAndSave(); - - // TODO Make preconditions consistent - // if (SymbolizeSimpleDF) { - // for (auto &&C : SymCS) { - // if (!IsValid) { - // C->PowOfTwo = true; - // CheckAndSave(); - // C->PowOfTwo = false; - // } - // if (!IsValid) { - // C->NonZero = true; - // CheckAndSave(); - // C->NonZero = false; - // } - // if (!IsValid) { - // C->NonNegative = true; - // CheckAndSave(); - // C->NonNegative = false; - // } - // if (!IsValid) { - // C->Negative = true; - // CheckAndSave(); - // C->Negative = false; - // } - // } - // } - // TODO Is there a better way of doing this? - // TODO Other kinds of preconditions? - - } - - } -} - template bool All(const C &c, F f) { for (auto &&m : c) { @@ -267,85 +113,6 @@ bool All(const C &c, F f) { return true; } -bool InferPreconditionsAndVerify(ParsedReplacement Input, CandidateMap &Results, - std::vector> &SymCS, InstContext &IC, Solver *S) { - - auto SOLVE = [&]() { - auto Result = Verify(Input, IC, S); - if (Result.Mapping.LHS && Result.Mapping.RHS) { - CandidateReplacement Rep(nullptr, Result.Mapping); - Rep.PCs = Result.PCs; - Results.push_back(Rep); - return true; - } else { - return false; - } - }; - - if (SOLVE()) return true; - - std::vector Insts; - findVars(Input.Mapping.LHS, Insts); - - std::set ModelInsts; - for (auto I : SymCS) { - ModelInsts.insert(I.first); - } - - - - std::vector> Inputs; - Inputs.push_back({}); - for (auto &&P : SymCS) { - Inputs.back()[P.first] = P.second; - } - - // TODO Is this worth using? - bool SynthNewConsts = false; - if (SynthNewConsts) { - for (auto &&I : findValidConsts(Input, ModelInsts, IC, S, 5)) { - Inputs.push_back(I); - } - } - - std::map> CVals; - - for (auto &&I : Inputs) { - for (auto &&P: I) { - CVals[P.first].push_back(P.second); - } - } - - if (Inputs.empty()) { - if (DebugLevel > 4) - llvm::errs() << "Could not find valid concrete constants.\n"; - return false; - } - - if (SymbolizeSimpleDF) { - -#define DF(Fact, Check) \ -if (All(CVals[C], [](auto Val) { return Check;})) { \ -C->Fact = true; if (SOLVE()) return true; C->Fact = false;}; - - for (auto &&P : SymCS) { - auto C = P.first; - DF(PowOfTwo, Val.isPowerOf2()) - DF(NonZero, Val != 0); - DF(NonNegative, Val.uge(0)); - DF(Negative, Val.slt(0)); - } -#undef DF - } - - if (SymbolizeKBDF) { -// Reducer R(IC, S); - - } - - return false; -} - std::vector findConcreteConsts(const ParsedReplacement &Input) { std::vector Consts; auto Pred = [](Inst *I) { @@ -443,282 +210,6 @@ std::vector InferPotentialRelations( return Results; } -// FIXME Other interesting things to try -// Symbolic KB in preconditions -// Symbolic KB with extra constraints. - -// TODO Document options -void SymbolizeAndGeneralizeImpl(InstContext &IC, Solver *S, ParsedReplacement Input, - std::vector LHSConsts, - std::vector RHSConsts, - CandidateMap &Results) { - - if (RHSConsts.empty()) { - // Handled in another function - return; - } - - std::vector> SymCS; - std::vector Vars; - std::vector SymDFVars; - findVars(Input.Mapping.LHS, Vars); - - std::map InstCache; - ValueCache VC; - - // Create a symbolic const for each LHS const - for (size_t i = 0; i < LHSConsts.size(); ++i) { - auto C = IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i)); - SymCS.push_back({C, LHSConsts[i]->Val}); - InstCache[LHSConsts[i]] = C; - VC[C] = EvalValue(LHSConsts[i]->Val); - } - - auto Relations = InferPotentialRelations(SymCS, IC, Input); - std::vector Components; - -// // Symbolic known bits -// if (false) { -// for (size_t i = 0; i < Vars.size(); ++i) { -// SymDFVars.push_back(IC.createVar(Vars[i]->Width, "symk_one_" + std::to_string(i))); -// SymDFVars.back()->SymOneOf = Vars[i]; -//// Vars[i]->SymKnownOnes = SymDFVars.back(); -// Components.push_back(SymDFVars.back()); - -// SymDFVars.push_back(IC.createVar(Vars[i]->Width, "symk_zero_" + std::to_string(i))); -// SymDFVars.back()->SymZeroOf = Vars[i]; -//// Vars[i]->SymKnownZeros = SymDFVars.back(); -// Components.push_back(SymDFVars.back()); -// } -// } - - - // Put custom components here - if (SymbolizeConstant || Everything) { - for (auto &&C : SymCS) { - if (Everything) { - Components.push_back(Builder(C.first, IC).LogB()()); - } - // Minus One -// Components.push_back(Builder(C.first, IC).Sub(1)()); - // Flip bits -// Components.push_back(Builder(C.first, IC).Xor(-1)()); - - // Shiftmask -// Components.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C.first->Width)).Shl(C.first)()); - - // Custom test - // auto M1 = IC.getConst(llvm::APInt(C->Width, -1)); - // auto Test = Builder(C, IC).Add(M1).Xor(M1).And(M1); - // Components.push_back(Test()); -// auto M0 = IC.getConst(llvm::APInt(C->Width, 0)); -// auto Test = Builder(M0, IC).Sub(C); -// Components.push_back(Test()); - } - } - - std::set ConcreteConsts; // for deduplication - - if (!SymbolizeConstSynthesis) { - for (auto C : LHSConsts) { -// ConcreteConsts.insert(C); -// ConcreteConsts.insert(IC.getConst(llvm::APInt(C->Width, 1))); - ConcreteConsts.insert(IC.getConst(llvm::APInt::getAllOnesValue(C->Width))); - } -// for (auto C : RHSConsts) { -// ConcreteConsts.insert(C); -// } -// for (auto C : ConcreteConsts) { -// Components.push_back(C); -// } - } - - for (auto &&ConC : ConcreteConsts) { - Components.push_back(ConC); - } - - for (auto &&SymC : SymCS) { - Components.push_back(SymC.first); - } - - std::vector> Candidates; - - ConcreteInterpreter CI(VC); - for (auto &&Target : RHSConsts) { - Candidates.push_back({}); - EnumerativeSynthesis ES; - auto Guesses = ES.generateExprs(IC, SymbolizeNumInsts, Components, - Target->Width); - for (auto &&Guess : Guesses) { - - if (ConcreteConsts.find(Guess) != ConcreteConsts.end()) { - continue; - } - - std::set ConstSet; - souper::getConstants(Guess, ConstSet); - if (!ConstSet.empty()) { - if (SymbolizeConstSynthesis) { - Candidates.back().push_back(Guess); - } - } else { - Candidates.back().push_back(Guess); - } - } - } - - std::vector Counts; - for (auto &&Cand : Candidates) { - Counts.push_back(Cand.size()); - } - -// SynthesisContext SC{IC, S->getSMTLIBSolver(), Input.Mapping.LHS, nullptr, Input.PCs, Input.BPCs, false, 10}; - auto LHS = Replace(Input.Mapping.LHS, IC, InstCache); -// std::vector NewVars; -// findVars(LHS, NewVars); - -// PruningManager Pr(SC, Vars, 0); - - // Generate all combination of candidates - std::vector> Combinations = GetCombinations(Counts); - - for (auto &&Comb : Combinations) { - static int SymExprCount = 0; - auto InstCacheRHS = InstCache; - for (int i = 0; i < RHSConsts.size(); ++i) { - InstCacheRHS[RHSConsts[i]] = Candidates[i][Comb[i]]; - if (Candidates[i][Comb[i]]->K != Inst::Var) { - Candidates[i][Comb[i]]->Name = std::string("constexpr_") + std::to_string(SymExprCount++); - } - } - - auto RHS = Replace(Input.Mapping.RHS, IC, InstCacheRHS); - - InstMapping Mapping(LHS, RHS); - auto Copy = Input; - Copy.Mapping = Mapping; - - //if (Pr.isInfeasible(RHS, 0)) { -// llvm::errs() << "PRUNED\n"; // Figure out why this never succeeds :( - //} else { - //llvm::errs() << "NP"; - if (!InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S)) { - for (auto R : Relations) { - Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); - Copy.PCs.pop_back(); - } - } - - //} - } -} - -// This is a simpler version of the above -void SymbolizeAndGeneralizeOnlyLHS(InstContext &IC, - Solver *S, - ParsedReplacement Input, - const std::vector &LHSConsts, - CandidateMap &Results) { - if (LHSConsts.empty()) { - return; // What are we even doing here? - } - std::vector> SymCS; - std::vector Vars; - std::vector SymDFVars; - findVars(Input.Mapping.LHS, Vars); - - std::map InstCache; - ValueCache VC; - - // Create a symbolic const for each LHS const - for (size_t i = 0; i < LHSConsts.size(); ++i) { - auto C = IC.createVar(LHSConsts[i]->Width, "symconst_" + std::to_string(i)); - SymCS.push_back({C, LHSConsts[i]->Val}); - InstCache[LHSConsts[i]] = C; - VC[C] = EvalValue(LHSConsts[i]->Val); - } - - auto LHS = Replace(Input.Mapping.LHS, IC, InstCache); - auto RHS = Replace(Input.Mapping.RHS, IC, InstCache); - - InstMapping Mapping(LHS, RHS); - auto Copy = Input; - Copy.Mapping = Mapping; - - if (!InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S)) { - auto Relations = InferPotentialRelations(SymCS, IC, Input); - for (auto R : Relations) { - Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - InferPreconditionsAndVerify(Copy, Results, SymCS, IC, S); - Copy.PCs.pop_back(); - } - } -} - -void SymbolizeAndGeneralize(InstContext &IC, - Solver *S, ParsedReplacement Input) { - std::vector LHSConsts, RHSConsts; - auto Pred = [](Inst *I) {return I->K == Inst::Const;}; - findInsts(Input.Mapping.LHS, LHSConsts, Pred); - findInsts(Input.Mapping.RHS, RHSConsts, Pred); - - CandidateMap Results; - - if (RHSConsts.empty()) { - SymbolizeAndGeneralizeOnlyLHS(IC, S, Input, LHSConsts, Results); - } else { - // One at a time - for (auto LHSConst : LHSConsts) { - SymbolizeAndGeneralizeImpl(IC, S, Input, {LHSConst}, RHSConsts, Results); - } - - // All subsets? - // TODO: Is it possible to encode this logically. - - // All at once - SymbolizeAndGeneralizeImpl(IC, S, Input, LHSConsts, RHSConsts, Results); - } - if (!Everything) { - llvm::outs() << ";Input:\n"; - Input.print(llvm::outs(), true); - llvm::outs() << "\n;Results:\n"; - } - // TODO : Improve sorting. - // Here are some ideas - // Prioritize results with more symbolic constants - // If same number of symbolic constants - prefer lower number of runtime instructions - - auto cmp = [](const std::string &a, const std::string &b) { - if (a.length() < b.length()) { - return true; - } else if (a.length() == b.length()) { - return a < b; - } else { - return false; - } - }; - std::set ResultStrs(cmp); - for (auto &&Result : Results) { - std::string str; - llvm::raw_string_ostream ostr(str); - Result.print(ostr, true); - ResultStrs.insert(str); - } - - int n = 5; - for (auto &&Str : ResultStrs) { -// if (!n--) break; - llvm::outs() << Str << "\n"; - if (Everything) { - break; - } - } - if (ResultStrs.empty()) { - Input.print(llvm::outs(), true); - } -} - std::set findConcreteConsts(Inst *I) { std::vector Results; std::set Ret; @@ -811,7 +302,6 @@ ParsedReplacement SimplePreconditionsAndVerifyGreedy( Clone.Mapping.RHS = nullptr; auto SOLVE = [&]() -> bool { -// Input.print(llvm::errs(), true); Clone = Verify(Input, IC, S); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return true; @@ -1046,16 +536,16 @@ FirstValidCombination(ParsedReplacement Input, } } - if (DFF) { - Clone = DFPreconditionsAndVerifyGreedy(P, IC, S, SymCS); + if (SDF) { + Clone = SimplePreconditionsAndVerifyGreedy(P, IC, S, SymCS); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return true; } } - if (SDF) { - Clone = SimplePreconditionsAndVerifyGreedy(P, IC, S, SymCS); - + if (DFF) { + Clone = DFPreconditionsAndVerifyGreedy(P, IC, S, SymCS); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return true; } @@ -1553,14 +1043,28 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (!EnumeratedCandidates.empty()) { auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, - InstCache, IC, S, SymCS, true, true, true); + InstCache, IC, S, SymCS, false, true, true); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } + } + Refresh("Enumerated exprs with constraints"); - Refresh("Enumerated exprs with constraints"); + if (RHSFresh.size() == 1) { + // Enumerated Expressions with some relational constraints + if (CMap.size() == 2) { + for (auto &&R : Relations) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, + InstCache, IC, S, SymCS, true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + } + } } + { auto Copy = Replace(Input, IC, JustLHSSymConstMap); auto ConstantLimits = InferConstantLimits(CMap, IC, Input); @@ -1577,21 +1081,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Constant limit constraints on LHS"); } - if (RHSFresh.size() == 1) { - // Enumerated Expressions with some relational constraints - if (CMap.size() == 2) { - for (auto &&R : Relations) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, - InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - } - Refresh("Enumerated 2 insts some constraints"); - } - } - // Step 4.8 : Special RHS constant exprs, with constants std::vector> SimpleCandidatesWithConsts = @@ -1763,54 +1252,6 @@ Inst *CloneInst(InstContext &IC, Inst *I, std::map &Vars) { } } -void GeneralizeBitWidth(InstContext &IC, Solver *S, - ParsedReplacement Input) { - auto Vars = IC.getVariablesFor(Input.Mapping.LHS); - - assert(Vars.size() == 1 && "Multiple variables unimplemented."); - - for (int i = 1; i <= 64; ++i) { - std::map Reps; - Reps[Vars[0]] = IC.createVar(i, Vars[0]->Name); - - auto LHS = CloneInst(IC, Input.Mapping.LHS, Reps); - auto RHS = CloneInst(IC, Input.Mapping.RHS, Reps); - - if (!GeneralizeWidthVerify && !MinimizeWidth) { - ReplacementContext RC; - auto str = RC.printInst(LHS, llvm::outs(), true); - llvm::outs() << "infer " << str << "\n"; - str = RC.printInst(RHS, llvm::outs(), true); - llvm::outs() << "result " << str << "\n\n"; - } else { - bool Valid; - InstMapping M(LHS, RHS); - std::vector> Models; - if (std::error_code EC = S->isValid(IC, {}, {}, M, Valid, &Models)) { - llvm::errs() << EC.message() << '\n'; - } - - if (Valid) { - if (MinimizeWidth) { - ReplacementContext RC; - auto str = RC.printInst(LHS, llvm::outs(), true); - llvm::outs() << "infer " << str << "\n"; - str = RC.printInst(RHS, llvm::outs(), true); - llvm::outs() << "result " << str << "\n\n"; - break; - } - llvm::outs () << "valid " << i << "\n"; - } else { - if (!MinimizeWidth) { - llvm::outs () << "invalid " << i << "\n"; - } - } - - } - } - -} - ParsedReplacement ReduceBasic(InstContext &IC, Solver *S, ParsedReplacement Input) { Reducer R(IC, S); @@ -1831,83 +1272,6 @@ ParsedReplacement ReduceBasic(InstContext &IC, return Input; } -std::vector ReduceAndGeneralize(InstContext &IC, - Solver *S, ParsedReplacement Input) { - std::vector> Models; - bool Valid; - if (std::error_code EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, Valid, &Models)) { - llvm::errs() << EC.message() << '\n'; - } - if (!Valid) { - llvm::errs() << "Invalid Input.\n"; - return {}; - } - - Reducer R(IC, S); - - std::vector Results; - Input = R.ReducePCs(Input); - Input = R.ReduceRedundantPhis(Input); - Input = R.ReduceGreedy(Input); - Input = R.WeakenKB(Input); - Input = R.WeakenCR(Input); - Input = R.WeakenDB(Input); - Input = R.WeakenOther(Input); - if (ReduceKBIFY) { - Input = R.ReduceGreedyKBIFY(Input); - } - Input = R.ReducePCs(Input); - -// llvm::outs() << "HERE5\n"; - Input.print(llvm::outs(), true); - return {Input.getString(true)}; - - R.ReduceRec(Input, Results); - - if (DebugLevel > 3) { - R.Stats(); - } -// llvm::errs() << "HERE0: " << Results.size(); - if (!Results.empty()) { - std::set DedupedResults; - for (auto &&Result : Results) { - DedupedResults.insert(Result.getString(false)); - } - - std::vector SortedResults(DedupedResults.begin(), DedupedResults.end()); - std::sort(SortedResults.begin(), SortedResults.end(), [](auto a, auto b){return a.length() < b.length();}); - - if (Basic) { -// llvm::errs() << "HERE: " << SortedResults.size(); - return SortedResults; - } - - if (!Everything && !Basic && !Advanced) { - for (auto &&S : SortedResults) { - if (DebugLevel > 2) { - llvm::outs() << "\n\nResult:\n"; - } - llvm::outs() << S << '\n'; - if (!ReducePrintAll) { - break; - } - } - if (DebugLevel > 2) { - llvm::outs() << "Number of Results: " < 2) { - llvm::errs() << "Failed to Generalize.\n"; - } - } - return {}; - } -} - int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); KVStore *KV = 0; @@ -1954,32 +1318,10 @@ int main(int argc, char **argv) { continue; } -// if (Advanced) { -// auto Result = SuccessiveSymbolize(IC, S.get(), Input); -// Result.print(llvm::outs()); -// llvm::outs() << "\n"; -// continue; -// } if (FixIt) { - // TODO: Verify that inputs are valid optimizations - Generalize(IC, S.get(), Input); - } - if (Reduce) { - ReduceAndGeneralize(IC, S.get(), Input); - } - if (SymbolizeConstant) { - SymbolizeAndGeneralize(IC, S.get(), Input); - } - - if (SymbolizeWidth) { - CandidateMap Results; - SymbolizeWidthNew(IC, S.get(), Input, Results); - - for (auto Result : Results) { - Result.print(llvm::outs()); - llvm::outs() << "\n"; - } + // TODO: Implement fixit with existing functionality when needed + llvm::errs() << "FixIt not implemented yet.\n"; } } return 0; From e864d58e9fe1164038ab8d06f08e8adb257f9f4f Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 16 Feb 2023 14:22:41 -0700 Subject: [PATCH 130/165] Width Independence and more relations --- include/souper/Infer/AliveDriver.h | 6 +- include/souper/Infer/SynthUtils.h | 1 + lib/Infer/AliveDriver.cpp | 25 ++++- lib/Infer/Interpreter.cpp | 5 + tools/generalize.cpp | 145 ++++++++++++++++++++++++++--- 5 files changed, 166 insertions(+), 16 deletions(-) diff --git a/include/souper/Infer/AliveDriver.h b/include/souper/Infer/AliveDriver.h index 9b0b897e1..18d4c9b74 100644 --- a/include/souper/Infer/AliveDriver.h +++ b/include/souper/Infer/AliveDriver.h @@ -30,7 +30,7 @@ class AliveDriver { typedef std::unordered_map Cache; public: AliveDriver(Inst *LHS_, Inst *PreCondition_, InstContext &IC_, - std::vector ExtraInputs = {}, bool WidthIndep = false); + const std::vector &ExtraInputs = {}, bool WidthIndep = false); std::map synthesizeConstants(souper::Inst *RHS); std::map synthesizeConstantsWithCegis(souper::Inst *RHS, InstContext &IC); @@ -42,6 +42,10 @@ class AliveDriver { } } + std::vector> getValidTypings() { + return ValidTypings; + } + bool WidthIndependentMode; // This probably doesn't need to be public private: Inst *LHS, *PreCondition; diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 26cee4a3e..269f1064d 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -54,6 +54,7 @@ class Builder { return Builder(IC.getInst(Inst::K, L->Width, {L}), IC); \ } UNOP(LogB) UNOP(BitReverse) UNOP(BSwap) UNOP(Cttz) UNOP(Ctlz) + UNOP(BitWidth) UNOP(CtPop) #undef UNOP diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index 9cb9b9e4d..f6a2290e9 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -49,7 +49,7 @@ static llvm::cl::opt WidthIndepOpt("alive-all-widths", static llvm::cl::opt ShowValidWidths("show-valid-widths", llvm::cl::desc("Show widths for which the input is valid."), - llvm::cl::init(true)); + llvm::cl::init(false)); class FunctionBuilder { @@ -62,6 +62,15 @@ class FunctionBuilder { (std::make_unique(t, std::move(name), *toValue(t, a))); } + template + IR::Value *width(IR::Type &t, std::string name, A a) { + auto fc = std::make_unique(IR::ConstantFn(t, "width", {toValue(t, a)})); + // make_unique fails template type deduction + auto ret = fc.get(); + F.addConstant(std::move(fc)); + return ret; + } + IR::Value *undef(IR::Type &t, std::string name) { auto undef = std::make_unique(t); auto undef_ptr = undef.get(); @@ -293,9 +302,9 @@ synthesizeConstantUsingSolver(tools::Transform &t, } souper::AliveDriver::AliveDriver(Inst *LHS_, Inst *PreCondition_, InstContext &IC_, - std::vector ExtraInputs, bool WidthIndep) + const std::vector &ExtraInputs, bool WidthIndep) : LHS(LHS_), PreCondition(PreCondition_), IC(IC_) { - smt::set_query_timeout(std::to_string(60000)); // milliseconds + smt::set_query_timeout(std::to_string(30000)); // milliseconds IsLHS = true; WidthIndependentMode = WidthIndep; if (WidthIndepOpt) { @@ -461,7 +470,7 @@ bool souper::AliveDriver::verify (Inst *RHS, Inst *RHSAssumptions) { tv.fixupTypes(types); if (auto errs = tv.verify()) { if (DebugLevel > 4) { - llvm::errs() << "Invalid typing: "; + llvm::errs() << "Invalid typing: \n"; for (auto &&P : Inputs) { llvm::errs() << P.first->Name << ' ' << P.second->bits() << "\n"; } @@ -774,6 +783,14 @@ bool souper::AliveDriver::translateAndCache(const souper::Inst *I, UNARYOP(BSwap, BSwap); UNARYOP(BitReverse, BitReverse); + case souper::Inst::BitWidth: { + ExprCache[I] = Builder.width(t, Name /*is ignored*/, + ExprCache[I->Ops[0]]); + return true; + } + + // TODO: Desugar log2. Alive2 only supports log2 for concrete constants. + default:{ llvm::outs() << "Unsupported Instruction Kind : " << I->getKindName(I->K) << "\n"; return false; diff --git a/lib/Infer/Interpreter.cpp b/lib/Infer/Interpreter.cpp index a5b902470..e87215e8b 100644 --- a/lib/Infer/Interpreter.cpp +++ b/lib/Infer/Interpreter.cpp @@ -448,6 +448,11 @@ namespace souper { return {llvm::APInt(Inst->Width, ARG0.logBase2())}; } + case Inst::BitWidth: { + return {llvm::APInt(Inst->Width, Inst->Width)}; + // Is the result always of this width? + } + default: llvm::report_fatal_error("unimplemented instruction kind " + std::string(Inst::getKindName(Inst->K)) + diff --git a/tools/generalize.cpp b/tools/generalize.cpp index cdb18e738..534c610b8 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -4,6 +4,7 @@ #include "llvm/Support/GraphWriter.h" #include "llvm/Support/KnownBits.h" +#include "souper/Infer/AliveDriver.h" #include "souper/Infer/Preconditions.h" #include "souper/Infer/EnumerativeSynthesis.h" #include "souper/Infer/ConstantSynthesis.h" @@ -68,9 +69,18 @@ static cl::opt JustReduce("just-reduce", cl::init(false)); static cl::opt Basic("basic", - cl::desc("Run all fast techniques, no synthesis^2."), + cl::desc("Run all fast techniques."), cl::init(false)); +static cl::opt OnlyWidth("only-width", + cl::desc("Only infer width checks, no synthesis."), + cl::init(false)); + +static cl::opt NoWidth("no-width", + cl::desc("No width independence checks."), + cl::init(false)); + + static cl::opt Advanced("advanced", cl::desc("Just run more advanced stuff. Assume -basic."), cl::init(false)); @@ -162,7 +172,39 @@ std::vector InferConstantLimits( return Results; } -// This was originally intended to fine relational constraints +std::vector FilterRelationsByValue(const std::vector &Relations, + const std::vector> &CMap) { + std::unordered_map ValueCache; + for (auto &&[I, V] : CMap) { + ValueCache[I] = EvalValue(V); + } + ConcreteInterpreter CI(ValueCache); + std::vector FilteredRelations; + for (auto &&R : Relations) { + auto Result = CI.evaluateInst(R); + // llvm::errs() << "HERE: " << Result.getValue().toString(2, false) << "\n"; + if (Result.hasValue() && Result.getValue().isAllOnesValue()) { + FilteredRelations.push_back(R); + } + } + return FilteredRelations; +} + +std::vector BitFuncs(Inst *I, InstContext &IC) { + std::vector Results; + Results.push_back(Builder(I, IC).CtPop()()); + Results.push_back(Builder(I, IC).Ctlz()()); + Results.push_back(Builder(I, IC).Cttz()()); + + auto Copy = Results; + for (auto &&C : Copy) { + Results.push_back(Builder(C, IC).BitWidth().Sub(C)()); + } + + return Results; +} + +// This was originally intended to find relational constraints // but we also use to fine some ad hoc constraints now. // TODO: Filter relations by concrete interpretation std::vector InferPotentialRelations( @@ -197,17 +239,25 @@ std::vector InferPotentialRelations( } // TODO Check if this is too slow - if (Input.Mapping.LHS->Width == 1) { + // if (Input.Mapping.LHS->Width == 1) { // need both signed and unsigned? // What about s/t/e/ versions? if (XC.slt(YC)) Results.push_back(Builder(XI, IC).Slt(YI)()); if (XC.ult(YC)) Results.push_back(Builder(XI, IC).Ult(YI)()); if (YC.slt(XC)) Results.push_back(Builder(YI, IC).Slt(XI)()); if (YC.ult(XC)) Results.push_back(Builder(YI, IC).Ult(XI)()); + // } + + for (auto &&XBit : BitFuncs(XI, IC)) { + for (auto &&YBit : BitFuncs(YI, IC)) { + Results.push_back(Builder(XBit, IC).Eq(YBit)()); + Results.push_back(Builder(XBit, IC).Ule(YBit)()); + Results.push_back(Builder(XBit, IC).Ult(YBit)()); + } } } } - return Results; + return FilterRelationsByValue(Results, CMap); } std::set findConcreteConsts(Inst *I) { @@ -771,6 +821,7 @@ std::vector> Enumerate(std::vector RHSConsts, Components.push_back(Builder(C, IC).Sub(1)()); Components.push_back(Builder(C, IC).Xor(-1)()); Components.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C->Width)).Shl(C)()); + // TODO: Add a few more, we can afford to run generalization longer } for (auto &&Target : RHSConsts) { @@ -1252,6 +1303,68 @@ Inst *CloneInst(InstContext &IC, Inst *I, std::map &Vars) { } } +InstMapping GetEqWidthConstraint(Inst *I, size_t Width, InstContext &IC) { + return {Builder(I, IC).BitWidth().Eq(Width)(), IC.getConst(llvm::APInt(1, 1))}; +} + +InstMapping GetLessThanWidthConstraint(Inst *I, size_t Width, InstContext &IC) { + // Don't need to check for >0. + return {Builder(I, IC).BitWidth().Ule(Width)(), IC.getConst(llvm::APInt(1, 1))}; +} +// TODO: More as needed. + +Inst *CombinePCs(const std::vector &PCs, InstContext &IC) { + Inst *Ante = IC.getConst(llvm::APInt(1, true)); + for (auto PC : PCs ) { + Inst *Eq = IC.getInst(Inst::Eq, 1, {PC.LHS, PC.RHS}); + Ante = IC.getInst(Inst::And, 1, {Ante, Eq}); + } + return Ante; +} + +ParsedReplacement InstantiateWidthChecks(InstContext &IC, + Solver *S, ParsedReplacement Input) { + // TODO: minimize width? + + // Instantiate Alive driver with Symbolic width. + AliveDriver Alive(Input.Mapping.LHS, + Input.PCs.empty() ? nullptr : CombinePCs(Input.PCs, IC), + IC, {}, true); + + // Find set of valid widths. + if (Alive.verify(Input.Mapping.RHS)) { + if (DebugLevel > 4) { + llvm::errs() << "WIDTH: Generalized opt is valid for all widths.\n"; + } + // Completely width independent. No width checks needed. + return Input; + } + + auto &&ValidTypings = Alive.getValidTypings(); + + if (ValidTypings.empty()) { + // Something went wrong, generalized opt is not valid at any width. + if (DebugLevel > 4) { + llvm::errs() << "WIDTH: Generalized opt is not valid for any width.\n"; + } + Input.Mapping.LHS = nullptr; + Input.Mapping.RHS = nullptr; + return Input; + } + + // Abstract width to a range or relational precondition + // TODO: Abstraction + + + // If abstraction fails, insert checks for existing widths. + std::vector Inputs; + findVars(Input.Mapping.LHS, Inputs); + for (auto &&I : Inputs) { + Input.PCs.push_back(GetEqWidthConstraint(I, I->Width, IC)); + } + return Input; +} + ParsedReplacement ReduceBasic(InstContext &IC, Solver *S, ParsedReplacement Input) { Reducer R(IC, S); @@ -1304,17 +1417,27 @@ int main(int argc, char **argv) { ParsedReplacement Result = ReduceBasic(IC, S.get(), Input); if (!JustReduce) { bool Changed = false; - size_t MaxTries = 1; // Increase this if we even run with 10/100x timeout. + size_t MaxTries = 1; // Increase this if we ever run with 10/100x timeout. do { - Result = ReduceBasic(IC, S.get(), Input); - Result = SuccessiveSymbolize(IC, S.get(), Result, Changed); + if (!OnlyWidth) { + Result = ReduceBasic(IC, S.get(), Input); + Result = SuccessiveSymbolize(IC, S.get(), Result, Changed); + } + if (!NoWidth) { + Result = InstantiateWidthChecks(IC, S.get(), Result); + } // Result.print(llvm::errs(), true); + if (!Result.Mapping.LHS) { + break; + } } while (--MaxTries && Changed); } - ReplacementContext RC; - Result.printLHS(llvm::outs(), RC, true); - Result.printRHS(llvm::outs(), RC, true); - llvm::outs() << "\n"; + if (Result.Mapping.LHS && Result.Mapping.RHS) { + ReplacementContext RC; + Result.printLHS(llvm::outs(), RC, true); + Result.printRHS(llvm::outs(), RC, true); + llvm::outs() << "\n"; + } continue; } From 4853b63c6b09393b95e0be8737ebb540fa616a71 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 16 Feb 2023 15:08:34 -0700 Subject: [PATCH 131/165] foo --- tools/generalize.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 534c610b8..78c6b1eb0 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -248,13 +248,24 @@ std::vector InferPotentialRelations( if (YC.ult(XC)) Results.push_back(Builder(YI, IC).Ult(XI)()); // } - for (auto &&XBit : BitFuncs(XI, IC)) { - for (auto &&YBit : BitFuncs(YI, IC)) { - Results.push_back(Builder(XBit, IC).Eq(YBit)()); + auto XBits = BitFuncs(XI, IC); + auto YBits = BitFuncs(YI, IC); + + for (auto &&XBit : XBits) { + for (auto &&YBit : YBits) { Results.push_back(Builder(XBit, IC).Ule(YBit)()); Results.push_back(Builder(XBit, IC).Ult(YBit)()); } } + + // No example yet where this is useful + // for (auto &&XBit : XBits) { + // for (auto &&YBit : YBits) { + // Results.push_back(Builder(XBit, IC).Ne(YBit)()); + // Results.push_back(Builder(XBit, IC).Eq(YBit)()); + // } + // } + } } return FilterRelationsByValue(Results, CMap); From b38b636aeab058d5bbb4655b2eb6deaff72bbaa0 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 16 Feb 2023 22:59:31 -0700 Subject: [PATCH 132/165] foo --- tools/generalize.cpp | 129 ++++++++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 32 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 78c6b1eb0..adb9308f2 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -852,7 +852,6 @@ std::vector> Enumerate(std::vector RHSConsts, } } } - return Candidates; } @@ -903,6 +902,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, }; auto LHSConsts = findConcreteConsts(Input.Mapping.LHS); + auto RHSConsts = findConcreteConsts(Input.Mapping.RHS); std::set ConstsBlackList; @@ -925,19 +925,24 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, int i = 1; for (auto I : LHSConsts) { - SymConstMap[I] = IC.createVar(I->Width, "symconst_" + - std::to_string(i++)); + auto Name = "symconst_" + std::to_string(i++); + if (I->Name != "") { + Name = I->Name; + } + SymConstMap[I] = IC.createVar(I->Width, Name); InstCache[I] = SymConstMap[I]; SymCS[SymConstMap[I]] = I->Val; } - for (auto I : RHSConsts) { if (SymConstMap.find(I) != SymConstMap.end()) { continue; } - SymConstMap[I] = IC.createVar(I->Width, "symconst_" + - std::to_string(i++)); + auto Name = "symconst_" + std::to_string(i++); + if (I->Name != "") { + Name = I->Name; + } + SymConstMap[I] = IC.createVar(I->Width, Name); InstCache[I] = SymConstMap[I]; // SymCS[SymConstMap[I]] = I->Val; } @@ -1239,41 +1244,101 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Special expressions, no constants"); } } + } -// std::vector SymDFVars; -// std::set LHSConstsAndSymDF; + Refresh("PUSH SYMDF_DB"); + if (Input.Mapping.LHS->DemandedBits.getBitWidth() == Input.Mapping.LHS->Width && + !Input.Mapping.LHS->DemandedBits.isAllOnesValue()) { + auto DB = Input.Mapping.LHS->DemandedBits; + auto SymDFVar = IC.getConst(DB); + SymDFVar->Name = "SYMDF_DB"; -// auto Clone = souper::Clone(Input, IC); -// std::vector Vars; -// findVars(Clone.Mapping.LHS, Vars); + SymDFVar->KnownOnes = llvm::APInt(DB.getBitWidth(), 0); + SymDFVar->KnownZeros = llvm::APInt(DB.getBitWidth(), 0); + SymDFVar->Val = DB; + auto LHS = Input.Mapping.LHS; + auto RHS = Input.Mapping.RHS; -// std::set Visited; -// for (size_t i = 0; i < Vars.size(); ++i) { -// if (Visited.find(Vars[i]) != Visited.end()/* || Vars[i]->Width == 7*/) { -// continue; -// } -// if (Vars[i]->KnownOnes.getBitWidth() != Vars[i]->Width || -// Vars[i]->KnownZeros.getBitWidth() != Vars[i]->Width) { -// continue; -// } + Input.Mapping.LHS->DemandedBits.setAllBits(); + Input.Mapping.RHS->DemandedBits.setAllBits(); + + Input.Mapping.LHS = Builder(Input.Mapping.LHS, IC).And(SymDFVar)(); + Input.Mapping.RHS = Builder(Input.Mapping.RHS, IC).And(SymDFVar)(); -// SymDFVars.push_back(IC.createVar(Vars[i]->Width, "skb_one_" + std::to_string(i))); -// SymDFVars.back()->SymOneOf = Vars[i]; -// Vars[i]->SymKnownOnes = SymDFVars.back(); -// LHSConstsAndSymDF.insert(SymDFVars.back()); -// Vars[i]->KnownOnes = llvm::APInt(); + bool SymDFChanged = false; + auto Generalized = SuccessiveSymbolize(IC, S, Input, SymDFChanged); + + if (SymDFChanged) { + return Generalized; + } else { + Input.Mapping.LHS = LHS; + Input.Mapping.RHS = RHS; + Input.Mapping.LHS->DemandedBits = DB; + Input.Mapping.RHS->DemandedBits = DB; + } + } + Refresh("POP SYMDF_DB"); + Refresh("PUSH SYMDF_KB"); + { + // Find good examples and test + std::vector Inputs; + findVars(Input.Mapping.LHS, Inputs); + + std::map KnownZero, KnownOne; + auto PCs = Input.PCs; + + for (auto &&I : Inputs) { + auto Width = I->Width; + + if (I->KnownZeros.getBitWidth() == I->Width && + I->KnownOnes.getBitWidth() == I->Width && + !(I->KnownZeros == 0 && I->KnownOnes == 0)) { + KnownZero[I] = I->KnownZeros; + KnownOne[I] = I->KnownOnes; + + I->KnownZeros = llvm::APInt(I->Width, 0); + I->KnownOnes = llvm::APInt(I->Width, 0); + + if (I->KnownZeros != 0) { + Inst *Zeros = IC.getConst(I->KnownZeros); + Zeros->Name = "SYMDF_KZ"; + Inst *AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(Width)); + Inst *NotZeros = IC.getInst(Inst::Xor, Width, + {Zeros, AllOnes}); + Inst *VarNotZero = IC.getInst(Inst::Or, Width, {I, NotZeros}); + Inst *ZeroBits = IC.getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); + PCs.push_back({ZeroBits, IC.getConst(llvm::APInt(1, 1))}); + } -// SymDFVars.push_back(IC.createVar(Vars[i]->Width, "skb_zero_" + std::to_string(i))); -// SymDFVars.back()->SymZeroOf = Vars[i]; -// Vars[i]->SymKnownZeros = SymDFVars.back(); -// LHSConstsAndSymDF.insert(SymDFVars.back()); -// Vars[i]->KnownZeros = llvm::APInt(); -// } + if (I->KnownOnes != 0) { + Inst *Ones = IC.getConst(I->KnownOnes); + Ones->Name = "SYMDF_KO"; + Inst *VarAndOnes = IC.getInst(Inst::And, Width, {I, Ones}); + Inst *OneBits = IC.getInst(Inst::Eq, 1, {VarAndOnes, Ones}); + PCs.push_back({OneBits, IC.getConst(llvm::APInt(1, 1))}); + } + } + } + if (!KnownZero.empty() || !KnownOne.empty()) { + bool SymDFChanged = false; + auto Generalized = SuccessiveSymbolize(IC, S, Input, SymDFChanged); -// Refresh("Symbolic known bits"); + if (SymDFChanged) { + return Generalized; + } else { + Input.PCs = PCs; + for (auto &&I : Inputs) { + I->KnownZeros = KnownZero[I]; + I->KnownOnes = KnownOne[I]; + } + } + } } + + Refresh("POP SYMDF_KB"); + Refresh("END"); Changed = false; return Input; From bede2cb27f9f99067b31fcd081330dfb02c89e9a Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Fri, 17 Feb 2023 17:54:49 -0700 Subject: [PATCH 133/165] foo --- tools/generalize.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index adb9308f2..7b82c82c2 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -395,7 +395,7 @@ if(s) return Clone;}; for (auto &&P : SymCS) { auto C = P.first; - DF(PowOfTwo, Val.isPowerOf2()); + DF(PowOfTwo, Val.isPowerOf2()); // Invoke solver only if Val is a power of 2 DF(NonNegative, Val.uge(0)); DF(NonZero, Val != 0); DF(Negative, Val.slt(0)); @@ -959,15 +959,11 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Step 1 : Just direct symbolize for common consts, no constraints std::map CommonConsts; - for (auto C : RHSConsts) { - if (LHSConsts.find(C) != LHSConsts.end()) { - CommonConsts[C] = SymConstMap[C]; - } + for (auto C : LHSConsts) { + CommonConsts[C] = SymConstMap[C]; } - if (!CommonConsts.empty()) { Result = Replace(Result, IC, CommonConsts); - auto Clone = Verify(Result, IC, S); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; @@ -1297,26 +1293,25 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, KnownZero[I] = I->KnownZeros; KnownOne[I] = I->KnownOnes; - I->KnownZeros = llvm::APInt(I->Width, 0); - I->KnownOnes = llvm::APInt(I->Width, 0); - if (I->KnownZeros != 0) { Inst *Zeros = IC.getConst(I->KnownZeros); - Zeros->Name = "SYMDF_KZ"; + Zeros->Name = "SYMDF_K0"; Inst *AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(Width)); Inst *NotZeros = IC.getInst(Inst::Xor, Width, {Zeros, AllOnes}); Inst *VarNotZero = IC.getInst(Inst::Or, Width, {I, NotZeros}); Inst *ZeroBits = IC.getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); - PCs.push_back({ZeroBits, IC.getConst(llvm::APInt(1, 1))}); + Input.PCs.push_back({ZeroBits, IC.getConst(llvm::APInt(1, 1))}); + I->KnownZeros = llvm::APInt(I->Width, 0); } if (I->KnownOnes != 0) { Inst *Ones = IC.getConst(I->KnownOnes); - Ones->Name = "SYMDF_KO"; + Ones->Name = "SYMDF_K1"; Inst *VarAndOnes = IC.getInst(Inst::And, Width, {I, Ones}); Inst *OneBits = IC.getInst(Inst::Eq, 1, {VarAndOnes, Ones}); - PCs.push_back({OneBits, IC.getConst(llvm::APInt(1, 1))}); + Input.PCs.push_back({OneBits, IC.getConst(llvm::APInt(1, 1))}); + I->KnownOnes = llvm::APInt(I->Width, 0); } } } @@ -1324,7 +1319,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (!KnownZero.empty() || !KnownOne.empty()) { bool SymDFChanged = false; auto Generalized = SuccessiveSymbolize(IC, S, Input, SymDFChanged); - if (SymDFChanged) { return Generalized; } else { From 8693f1bcce279a541bd6a91cb6838c1928fe59b8 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 19 Feb 2023 14:38:54 -0700 Subject: [PATCH 134/165] foo --- tools/generalize.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 7b82c82c2..e714a0ef9 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -831,8 +831,11 @@ std::vector> Enumerate(std::vector RHSConsts, Components.push_back(Builder(C, IC).LogB()()); Components.push_back(Builder(C, IC).Sub(1)()); Components.push_back(Builder(C, IC).Xor(-1)()); - Components.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C->Width)).Shl(C)()); - // TODO: Add a few more, we can afford to run generalization longer + if (SymbolizeHackersDelight) { + Components.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C->Width)).Shl(C)()); + Components.push_back(Builder(IC, llvm::APInt(C->Width, 1)).Shl(C)()); + // TODO: Add a few more, we can afford to run generalization longer + } } for (auto &&Target : RHSConsts) { From 13468f2c9540cb0ad61835157b254d57d49dd990 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 20 Feb 2023 21:11:59 -0700 Subject: [PATCH 135/165] foo --- include/souper/Infer/SynthUtils.h | 6 ++ tools/generalize.cpp | 113 ++++++++++++++++++------------ 2 files changed, 75 insertions(+), 44 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 269f1064d..4bea142ca 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -15,6 +15,7 @@ namespace souper { class Builder { public: Builder(Inst *I_, InstContext &IC_) : I(I_), IC(IC_) {} + Builder(InstContext &IC_, Inst *I_) : I(I_), IC(IC_) {} Builder(InstContext &IC_, llvm::APInt Value) : IC(IC_) { I = IC.getConst(Value); } @@ -39,6 +40,11 @@ class Builder { BINOP(SDiv) #undef BINOP + template Builder Ugt(T t) { \ + auto L = I; auto R = i(t, *this); \ + return Builder(IC.getInst(Inst::Ult, 1, {R, L}), IC); \ + } + #define BINOPW(K) \ template Builder K(T t) { \ auto L = I; auto R = i(t, *this); \ diff --git a/tools/generalize.cpp b/tools/generalize.cpp index e714a0ef9..6ad9042d2 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -142,6 +142,24 @@ std::vector findConcreteConsts(const ParsedReplacement &Input) { return Result; } +std::vector FilterRelationsByValue(const std::vector &Relations, + const std::vector> &CMap) { + std::unordered_map ValueCache; + for (auto &&[I, V] : CMap) { + ValueCache[I] = EvalValue(V); + } + ConcreteInterpreter CI(ValueCache); + std::vector FilteredRelations; + for (auto &&R : Relations) { + auto Result = CI.evaluateInst(R); + // llvm::errs() << "HERE: " << Result.getValue().toString(2, false) << "\n"; + if (Result.hasValue() && Result.getValue().isAllOnesValue()) { + FilteredRelations.push_back(R); + } + } + return FilteredRelations; +} + std::vector InferConstantLimits( const std::vector> &CMap, InstContext &IC, const ParsedReplacement &Input) { @@ -153,41 +171,43 @@ std::vector InferConstantLimits( std::sort(ConcreteConsts.begin(), ConcreteConsts.end(), [](auto A, auto B) { return A->Val.ugt(B->Val); }); + for (auto &&[XI, XC] : CMap) { + // X < Width, X <= Width + auto Width = Builder(XI, IC).BitWidth(); + Results.push_back(Builder(XI, IC).Ult(Width)()); + Results.push_back(Builder(XI, IC).Ule(Width)()); + + auto gZ = Builder(XI, IC).Ugt(0)(); + + Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); + Results.push_back(Builder(XI, IC).Ule(Width).And(gZ)()); + + // 2 * X < C, 2 * X >= C + for (auto C : ConcreteConsts) { + auto Sum = Builder(XI, IC).Add(XI)(); + Results.push_back(Builder(Sum, IC).Ult(C->Val)()); + Results.push_back(Builder(Sum, IC).Ult(C->Val).Xor(1)()); + } + } + for (auto &&[XI, XC] : CMap) { for (auto &&[YI, YC] : CMap) { + auto Sum = Builder(XI, IC).Add(YI)(); + // Sum related to width + auto Width = Builder(Sum, IC).BitWidth(); + Results.push_back(Builder(Sum, IC).Ult(Width)()); + Results.push_back(Builder(Sum, IC).Ule(Width)()); + Results.push_back(Builder(Sum, IC).Eq(Width)()); + // Sum less than const, Sum greater= than const for (auto C : ConcreteConsts) { - auto Sum = Builder(XI, IC).Add(YI)(); - Results.push_back(Builder(Sum, IC).Ult(C->Val)()); - Results.push_back(Builder(Sum, IC).Ult(C->Val).Xor(1)()); - } - // 2 * X < C, 2 * X >= C - for (auto C : ConcreteConsts) { - auto Sum = Builder(XI, IC).Add(XI)(); + Results.push_back(Builder(Sum, IC).Ult(C->Val)()); Results.push_back(Builder(Sum, IC).Ult(C->Val).Xor(1)()); } } } - return Results; -} - -std::vector FilterRelationsByValue(const std::vector &Relations, - const std::vector> &CMap) { - std::unordered_map ValueCache; - for (auto &&[I, V] : CMap) { - ValueCache[I] = EvalValue(V); - } - ConcreteInterpreter CI(ValueCache); - std::vector FilteredRelations; - for (auto &&R : Relations) { - auto Result = CI.evaluateInst(R); - // llvm::errs() << "HERE: " << Result.getValue().toString(2, false) << "\n"; - if (Result.hasValue() && Result.getValue().isAllOnesValue()) { - FilteredRelations.push_back(R); - } - } - return FilteredRelations; + return FilterRelationsByValue(Results, CMap); } std::vector BitFuncs(Inst *I, InstContext &IC) { @@ -267,6 +287,12 @@ std::vector InferPotentialRelations( // } } + Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth().Sub(1))()); + Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth().UDiv(2))()); + Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth())()); + } + for (auto R : InferConstantLimits(CMap, IC, Input)) { + Results.push_back(R); } return FilterRelationsByValue(Results, CMap); } @@ -444,7 +470,6 @@ ParsedReplacement SymKBPreconditionsAndVerifyGreedy( return Result; }; - // Pairwise expressions, all boolean for (auto &&P1 : SymKMap) { @@ -828,12 +853,15 @@ std::vector> Enumerate(std::vector RHSConsts, std::vector Components; for (auto &&C : LHSConsts) { Components.push_back(C); + // Components.push_back(Builder(C, IC).BSwap()()); Components.push_back(Builder(C, IC).LogB()()); Components.push_back(Builder(C, IC).Sub(1)()); Components.push_back(Builder(C, IC).Xor(-1)()); if (SymbolizeHackersDelight) { Components.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C->Width)).Shl(C)()); Components.push_back(Builder(IC, llvm::APInt(C->Width, 1)).Shl(C)()); + Components.push_back(Builder(IC, C).BitWidth().Sub(1)()); + Components.push_back(Builder(IC, C).BitWidth().Sub(C)()); // TODO: Add a few more, we can afford to run generalization longer } } @@ -1130,23 +1158,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } } - - { - auto Copy = Replace(Input, IC, JustLHSSymConstMap); - auto ConstantLimits = InferConstantLimits(CMap, IC, Input); - for (auto &&R : ConstantLimits) { - Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - // Copy.print(llvm::errs(), true); - // llvm::errs() << "\n\n"; - auto Clone = Verify(Copy, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - Copy.PCs.pop_back(); - } - Refresh("Constant limit constraints on LHS"); - } - // Step 4.8 : Special RHS constant exprs, with constants std::vector> SimpleCandidatesWithConsts = @@ -1245,6 +1256,20 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } } + { + auto Copy = Replace(Input, IC, JustLHSSymConstMap); + auto ConstantLimits = InferConstantLimits(CMap, IC, Input); + for (auto &&R : ConstantLimits) { + Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + auto Clone = Verify(Copy, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + Copy.PCs.pop_back(); + } + Refresh("Constant limit constraints on LHS"); + } + Refresh("PUSH SYMDF_DB"); if (Input.Mapping.LHS->DemandedBits.getBitWidth() == Input.Mapping.LHS->Width && !Input.Mapping.LHS->DemandedBits.isAllOnesValue()) { From af8c9c7b444ac9415e74f17230342b6dc0e28e6c Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 20 Feb 2023 21:50:12 -0700 Subject: [PATCH 136/165] foo --- tools/generalize.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 6ad9042d2..0871bd00b 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -186,7 +186,7 @@ std::vector InferConstantLimits( for (auto C : ConcreteConsts) { auto Sum = Builder(XI, IC).Add(XI)(); Results.push_back(Builder(Sum, IC).Ult(C->Val)()); - Results.push_back(Builder(Sum, IC).Ult(C->Val).Xor(1)()); + Results.push_back(Builder(Sum, IC).Ugt(C->Val)()); } } @@ -203,7 +203,7 @@ std::vector InferConstantLimits( for (auto C : ConcreteConsts) { Results.push_back(Builder(Sum, IC).Ult(C->Val)()); - Results.push_back(Builder(Sum, IC).Ult(C->Val).Xor(1)()); + Results.push_back(Builder(Sum, IC).Ugt(C->Val)()); } } } From 794e425ccb5174f8c5cfa98bea30c1e7d388ff77 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 21 Feb 2023 00:32:40 -0700 Subject: [PATCH 137/165] foo --- tools/generalize.cpp | 48 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 0871bd00b..a705e7ee2 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -177,6 +177,11 @@ std::vector InferConstantLimits( Results.push_back(Builder(XI, IC).Ult(Width)()); Results.push_back(Builder(XI, IC).Ule(Width)()); + // X slt SMAX, x ult UMAX + auto WM1 = Width.Sub(1); + auto SMax = Builder(IC, llvm::APInt(XI->Width, 1)).Shl(WM1).Sub(1)(); + Results.push_back(Builder(XI, IC).Slt(SMax)()); + auto gZ = Builder(XI, IC).Ugt(0)(); Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); @@ -291,9 +296,9 @@ std::vector InferPotentialRelations( Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth().UDiv(2))()); Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth())()); } - for (auto R : InferConstantLimits(CMap, IC, Input)) { - Results.push_back(R); - } + // for (auto R : InferConstantLimits(CMap, IC, Input)) { + // Results.push_back(R); + // } return FilterRelationsByValue(Results, CMap); } @@ -1069,6 +1074,9 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("All LHS Constraints"); + auto ConstantLimits = InferConstantLimits(CMap, IC, Input); + + // Step 3 : Special RHS constant exprs, no constants if (!RHSFresh.empty()) { @@ -1150,13 +1158,15 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, for (auto &&R : Relations) { Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, - InstCache, IC, S, SymCS, true, false, false); + InstCache, IC, S, SymCS, true, true, false); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } + Input.PCs.pop_back(); } } } + Refresh("Enumerated 2 insts exprs with relations"); // Step 4.8 : Special RHS constant exprs, with constants @@ -1254,11 +1264,39 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Special expressions, no constants"); } } + + if (!EnumeratedCandidates.empty()) { + for (auto &&R : ConstantLimits) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, true, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + Input.PCs.pop_back(); + } + Refresh("Enumerated expressions+consts and constant limits"); + } + + if (!SimpleCandidatesWithConsts.empty()) { + for (auto &&R : ConstantLimits) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, + InstCache, IC, S, SymCS, true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + Input.PCs.pop_back(); + } + Refresh("Simple expressions+consts and constant limits"); + } + } { auto Copy = Replace(Input, IC, JustLHSSymConstMap); - auto ConstantLimits = InferConstantLimits(CMap, IC, Input); for (auto &&R : ConstantLimits) { Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); auto Clone = Verify(Copy, IC, S); From 27dc10865ee95f2d39e8e6a170cc4217f568a21b Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 23 Feb 2023 16:00:44 -0700 Subject: [PATCH 138/165] foo --- include/souper/Infer/SynthUtils.h | 9 ++++- lib/Infer/AliveDriver.cpp | 8 ++-- tools/generalize.cpp | 48 +++++++++++++++++++---- tools/matcher-gen.cpp | 14 ++++--- tools/pass-generator/src/template.cpp | 55 ++++++++++++++++++++++++--- 5 files changed, 111 insertions(+), 23 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 4bea142ca..6e4618f1d 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -61,9 +61,16 @@ class Builder { } UNOP(LogB) UNOP(BitReverse) UNOP(BSwap) UNOP(Cttz) UNOP(Ctlz) UNOP(BitWidth) UNOP(CtPop) - #undef UNOP +#define UNOPW(K) \ + Builder K(size_t W) { \ + auto L = I; \ + return Builder(IC.getInst(Inst::K, W, {L}), IC); \ + } + UNOPW(ZExt) +#undef UNOPW + private: Inst *I = nullptr; InstContext &IC; diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index f6a2290e9..402df29ea 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -304,7 +304,7 @@ synthesizeConstantUsingSolver(tools::Transform &t, souper::AliveDriver::AliveDriver(Inst *LHS_, Inst *PreCondition_, InstContext &IC_, const std::vector &ExtraInputs, bool WidthIndep) : LHS(LHS_), PreCondition(PreCondition_), IC(IC_) { - smt::set_query_timeout(std::to_string(30000)); // milliseconds + smt::set_query_timeout(std::to_string(10000)); // milliseconds IsLHS = true; WidthIndependentMode = WidthIndep; if (WidthIndepOpt) { @@ -491,10 +491,11 @@ bool souper::AliveDriver::verify (Inst *RHS, Inst *RHSAssumptions) { return false; } else { if (ShowValidWidths) { - llvm::outs() << "Transformation seems to be correct for some widths!\n"; + llvm::outs() << "; Partially Valid.\n"; std::sort(ValidTypings.begin(), ValidTypings.end(), [](const auto &A, const auto &B) {return A.begin()->second < B.begin()->second;}); for (auto &&P : ValidTypings) { + llvm::outs() << "; "; for (auto &&I : P) { llvm::outs() << I.first->Name << ' ' << I.second << '\t'; } @@ -839,7 +840,8 @@ IR::Type &souper::AliveDriver::getType(int Width) { std::string n = "i" + std::to_string(Width); if (TypeCache.find(n) == TypeCache.end()) { if (WidthIndependentMode) { - TypeCache[""] = new IR::SymbolicType("symty_", (1 << IR::SymbolicType::Int)); + auto t = new IR::SymbolicType("symty_", (1 << IR::SymbolicType::Int)); + TypeCache[""] = t; } else { TypeCache[n] = new IR::IntType(std::move(n), Width); } diff --git a/tools/generalize.cpp b/tools/generalize.cpp index a705e7ee2..ec098a1f7 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -169,7 +169,13 @@ std::vector InferConstantLimits( } auto ConcreteConsts = findConcreteConsts(Input); std::sort(ConcreteConsts.begin(), ConcreteConsts.end(), - [](auto A, auto B) { return A->Val.ugt(B->Val); }); + [](auto A, auto B) { + if (A->Width == B->Width) { + return A->Val.ugt(B->Val); + } else { + return A->Width < B->Width; + } + }); for (auto &&[XI, XC] : CMap) { // X < Width, X <= Width @@ -189,6 +195,9 @@ std::vector InferConstantLimits( // 2 * X < C, 2 * X >= C for (auto C : ConcreteConsts) { + if (C->Width != XI->Width) { + continue; + } auto Sum = Builder(XI, IC).Add(XI)(); Results.push_back(Builder(Sum, IC).Ult(C->Val)()); Results.push_back(Builder(Sum, IC).Ugt(C->Val)()); @@ -197,6 +206,9 @@ std::vector InferConstantLimits( for (auto &&[XI, XC] : CMap) { for (auto &&[YI, YC] : CMap) { + if (XI == YI) { + continue; + } auto Sum = Builder(XI, IC).Add(YI)(); // Sum related to width auto Width = Builder(Sum, IC).BitWidth(); @@ -206,7 +218,9 @@ std::vector InferConstantLimits( // Sum less than const, Sum greater= than const for (auto C : ConcreteConsts) { - + if (Sum->Width != C->Width) { + continue; + } Results.push_back(Builder(Sum, IC).Ult(C->Val)()); Results.push_back(Builder(Sum, IC).Ugt(C->Val)()); } @@ -240,6 +254,24 @@ std::vector InferPotentialRelations( return Results; } + for (auto &&[XI, XC] : CMap) { + for (auto &&[YI, YC] : CMap) { + if (XI == YI || XC.getBitWidth() == YC.getBitWidth()) { + continue; + } + llvm::errs() << "HERE: " << XC.getLimitedValue() << ' ' << YC.getLimitedValue() << '\n'; + if (XC.getLimitedValue() == YC.getLimitedValue()) { + if (XI->Width > YI->Width) { + Builder(YI, IC).ZExt(XI->Width).Eq(XI)()->Print(); + Results.push_back(Builder(YI, IC).ZExt(XI->Width).Eq(XI)()); + } else { + Results.push_back(Builder(XI, IC).ZExt(YI->Width).Eq(YI)()); + } + } + } + } + + // Generate a set of pairwise relations for (auto &&[XI, XC] : CMap) { // llvm::errs() << "HERE: " << XC << "\n"; @@ -899,10 +931,10 @@ void findDangerousConstants(Inst *I, std::set &Results) { Stack.pop_back(); Visited.insert(Cur); - if (Cur->K == Inst::Const && Cur->Val == 0) { - // Don't try to 'generalize' zero! - Results.insert(Cur); - } + // if (Cur->K == Inst::Const && Cur->Val == 0) { + // // Don't try to 'generalize' zero! + // Results.insert(Cur); + // } if (Visited.find(Cur) == Visited.end()) { continue; @@ -1307,7 +1339,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } Refresh("Constant limit constraints on LHS"); } - + if (SymbolicDF) { Refresh("PUSH SYMDF_DB"); if (Input.Mapping.LHS->DemandedBits.getBitWidth() == Input.Mapping.LHS->Width && !Input.Mapping.LHS->DemandedBits.isAllOnesValue()) { @@ -1396,8 +1428,8 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } } } - Refresh("POP SYMDF_KB"); + } Refresh("END"); Changed = false; diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 19117f65c..70ce059ac 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -66,6 +66,8 @@ static const std::map MatchOps = { {Inst::SDiv, "m_SDiv("}, {Inst::UDiv, "m_UDiv("}, {Inst::SRem, "m_SRem("}, {Inst::URem, "m_URem("}, + {Inst::AShrExact, "m_AShrExact("}, {Inst::LShrExact, "m_LShrExact("}, + {Inst::UDivExact, "m_UDivExact("}, {Inst::SDivExact, "m_SDivExact("}, {Inst::And, "m_c_And("}, {Inst::Or, "m_c_Or("}, {Inst::Xor, "m_c_Xor("}, @@ -90,6 +92,8 @@ static const std::map CreateOps = { {Inst::SDiv, "CreateSDiv("}, {Inst::UDiv, "CreateUDiv("}, {Inst::SRem, "CreateSRem("}, {Inst::URem, "CreateURem("}, {Inst::Or, "CreateOr("}, {Inst::And, "CreateAnd("}, {Inst::Xor, "CreateXor("}, + {Inst::AShrExact, "CreateAShrExact("},// {Inst::LShrExact, "CreateExactLShr("}, + // {Inst::UDivExact, "CreateExactUDiv("}, {Inst::SDivExact, "CreateExactSDiv("}, // FakeOps {Inst::LogB, "CreateLogB("}, @@ -157,7 +161,7 @@ struct WidthEq : public Constraint { struct DomCheck : public Constraint { DomCheck(std::string Name_) : Name(Name_) {} std::string Name; - + std::string print() override { return "util::dc(DT, I, " + Name + ")"; } @@ -349,7 +353,7 @@ struct SymbolTable : public std::map> { } return true; } - + void GenDomConstraints(Inst *RHS) { static std::set Visited; Visited.insert(RHS); @@ -492,7 +496,7 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms, bool IsRoot = false) llvm::errs() << "\nUnimplemented matcher:" << Inst::getKindName(I->K) << "\n"; return false; } - + auto Op = It->second; Out << Op; @@ -500,7 +504,7 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms, bool IsRoot = false) if (I->K == Inst::SExt || I->K == Inst::ZExt || I->K == Inst::Trunc) { Out << I->Width << ", "; } - + if (PredNames.find(I->K) != PredNames.end()) { Out << Syms.Preds[I] << ", "; } @@ -1027,7 +1031,7 @@ int main(int argc, char **argv) { llvm::outs() << Results[N]; } } - + // llvm::outs() << "end:\n"; return 0; diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 099dcd408..3655b882f 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -50,7 +50,7 @@ static llvm::cl::opt High("high", // TODO Make the commutative operations work // This is critical because commutative operations // sometimes have the arguments inverted for canonicalization - + namespace { // Custom Creators @@ -68,6 +68,8 @@ class IRBuilder : public llvm::IRBuilder { } } + + // TODO Verify that these work, the mangling argument is weird llvm::Value *CreateFShl(llvm::Value *A, llvm::Value *B, llvm::Value *C) { return CreateIntrinsic(Intrinsic::fshl, {A->getType()}, {A, B, C}); @@ -78,6 +80,19 @@ class IRBuilder : public llvm::IRBuilder { llvm::Value *CreateBSwap(llvm::Value *A) { return CreateIntrinsic(Intrinsic::bswap, {A->getType()}, {A}); } + + llvm::Value *CreateAShrExact(llvm::Value *A, llvm::Value *B) { + return llvm::BinaryOperator::CreateExact(Instruction::AShr, A, B); + } + llvm::Value *CreateLShrExact(llvm::Value *A, llvm::Value *B) { + return llvm::BinaryOperator::CreateExact(Instruction::LShr, A, B); + } + llvm::Value *CreateUDivExact(llvm::Value *A, llvm::Value *B) { + return llvm::BinaryOperator::CreateExact(Instruction::UDiv, A, B); + } + llvm::Value *CreateSDivExact(llvm::Value *A, llvm::Value *B) { + return llvm::BinaryOperator::CreateExact(Instruction::SDiv, A, B); + } }; @@ -117,7 +132,7 @@ struct phi_match { return runtime_get(func, tup, idx); } } - + bool match_nth(size_t n, Value *V) { bool Ret = false; auto F = [&](auto M) {Ret = M.match(V);}; @@ -147,6 +162,34 @@ phi_match m_Phi(Args... args) { return phi_match(args...); } +template +inline Exact_match> +m_AShrExact(const LHS &L, const RHS &R) { + return Exact_match>( + BinaryOp_match(L, R)); +} + +template +inline Exact_match> +m_LShrExact(const LHS &L, const RHS &R) { + return Exact_match>( + BinaryOp_match(L, R)); +} + +template +inline Exact_match> +m_UDivExact(const LHS &L, const RHS &R) { + return Exact_match>( + BinaryOp_match(L, R)); +} + +template +inline Exact_match> +m_SDivExact(const LHS &L, const RHS &R) { + return Exact_match>( + BinaryOp_match(L, R)); +} + struct bind_apint { APInt &VR; @@ -166,7 +209,7 @@ struct bind_apint { struct width_specific_intval : public specific_intval { size_t Width; width_specific_intval(llvm::APInt V, size_t W) : specific_intval(V), Width(W) {} - + template bool match(ITy *V) { if (V->getType()->getScalarSizeInBits() != Width) { return false; @@ -580,7 +623,7 @@ struct SouperCombine : public FunctionPass { } return Changed; } - + Value *getReplacement(llvm::Instruction *I, IRBuilder *B) { // if (!I->hasOneUse()) { // return nullptr; @@ -592,10 +635,10 @@ struct SouperCombine : public FunctionPass { // Autogenerated transforms #include "gen.cpp.inc" - + return nullptr; } - + Value *C(size_t Width, size_t Value, IRBuilder *B) { return B->getIntN(Width, Value); } From 29d9d0cf78af34ce01b6f1f465da8cbddbd4da74 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 1 Mar 2023 20:49:01 -0700 Subject: [PATCH 139/165] foo --- include/souper/Infer/SynthUtils.h | 2 + lib/Infer/SynthUtils.cpp | 72 ++- tools/generalize.cpp | 782 +++++++++++++++++------------- 3 files changed, 493 insertions(+), 363 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 6e4618f1d..0e54a2790 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -126,5 +126,7 @@ std::map findOneConstSet(ParsedReplacement Input, const std std::vector> findValidConsts(ParsedReplacement Input, const std::set &Insts, InstContext &IC, Solver *S, size_t MaxCount); +ValueCache GetCEX(const ParsedReplacement &Input, InstContext &IC, Solver *S); + } #endif diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index b60950bfe..d3cc664bc 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -13,15 +13,15 @@ ParsedReplacement Replace(ParsedReplacement I, InstContext &IC, std::map &M) { std::map BlockCache; std::map ConstMap; - + I.Mapping.LHS = getInstCopy(I.Mapping.LHS, IC, M, BlockCache, &ConstMap, false); I.Mapping.RHS = getInstCopy(I.Mapping.RHS, IC, M, BlockCache, &ConstMap, false); - + for (auto &PC : I.PCs) { PC.LHS = getInstCopy(PC.LHS, IC, M, BlockCache, &ConstMap, false, false); PC.RHS = getInstCopy(PC.RHS, IC, M, BlockCache, &ConstMap, false, false); } - + return I; } @@ -63,7 +63,7 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { InstCache[V->SymZeroOf]->SymKnownZeros = InstCache[V]; } } - + return In; } @@ -77,14 +77,14 @@ ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { std::vector Vars; findVars(Input.Mapping.LHS, Vars); -// PruningManager Pruner(SC, Vars, 5); -// Pruner.init(); -// -// if (Pruner.isInfeasible(Input.Mapping.RHS, 0)) { -// Input.Mapping.LHS = nullptr; -// Input.Mapping.RHS = nullptr; -// return Input; -// } + PruningManager Pruner(SC, Vars, 0); + Pruner.init(); + + if (Pruner.isInfeasible(Input.Mapping.RHS, 0)) { + Input.Mapping.LHS = nullptr; + Input.Mapping.RHS = nullptr; + return Input; + } Input = Clone(Input, IC); std::set ConstSet; @@ -93,7 +93,7 @@ ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { std::map ResultConstMap; ConstantSynthesis CS; auto SMTSolver = S->getSMTLIBSolver(); - + auto EC = CS.synthesize(SMTSolver, Input.BPCs, Input.PCs, Input.Mapping, ConstSet, ResultConstMap, IC, /*MaxTries=*/30, 10, @@ -134,44 +134,44 @@ ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { } std::map findOneConstSet(ParsedReplacement Input, const std::set &SymCS, InstContext &IC, Solver *S) { - + std::map InstCache; - + std::set SynthCS; - + size_t cid = 0; for (auto C : SymCS) { InstCache[C] = IC.createSynthesisConstant(C->Width, cid++); SynthCS.insert(InstCache[C]); } Input = Replace(Input, IC, InstCache); - + std::map ResultConstMap; ConstantSynthesis CS; auto EC = CS.synthesize(S->getSMTLIBSolver(), Input.BPCs, Input.PCs, Input.Mapping, SynthCS, ResultConstMap, IC, /*MaxTries=*/30, 10, /*AvoidNops=*/true); - + std::map Result; if (!ResultConstMap.empty()) { for (auto C : SymCS) { Result[C] = ResultConstMap[InstCache[C]]; } } - + return Result; - + } std::vector> findValidConsts(ParsedReplacement Input, const std::set &Insts, InstContext &IC, Solver *S, size_t MaxCount = 1) { - + // FIXME: Ignores Count std::vector> Results; - + Inst *T = IC.getConst(llvm::APInt(1, 1)); // true Inst *F = IC.getConst(llvm::APInt(1, 0)); // false - + while (MaxCount-- ) { auto &&Result = findOneConstSet(Input, Insts, IC, S); if (Result.empty()) { @@ -183,8 +183,32 @@ std::vector> findValidConsts(ParsedReplacement Inp } } } - + return Results; } +// Find a single counterexample +ValueCache GetCEX(const ParsedReplacement &Input, InstContext &IC, Solver *S) { + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); + std::vector> Models; + bool IsValid; + if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, IsValid, &Models)) { + llvm::errs() << EC.message() << '\n'; + } + if (IsValid) { + return ValueCache(); + } else { + ValueCache Result; + for (auto &V : Vars) { + for (auto &M : Models) { + if (M.first == V) { + Result[V] = M.second; + } + } + } + return Result; + } +} + } diff --git a/tools/generalize.cpp b/tools/generalize.cpp index ec098a1f7..7861f711a 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -15,6 +15,7 @@ #include "souper/Generalize/Reducer.h" #include "souper/Tool/GetSolver.h" #include "souper/Util/DfaUtils.h" +#include using namespace llvm; using namespace souper; @@ -143,18 +144,38 @@ std::vector findConcreteConsts(const ParsedReplacement &Input) { } std::vector FilterRelationsByValue(const std::vector &Relations, - const std::vector> &CMap) { + const std::vector> &CMap, + ValueCache CEX) { std::unordered_map ValueCache; for (auto &&[I, V] : CMap) { ValueCache[I] = EvalValue(V); } - ConcreteInterpreter CI(ValueCache); + + // for (auto P : CEX) { + // llvm::errs() << "CEX: " << P.first->Name << ' ' + // << P.second.getValue().toString(2, false) << "\n"; + // } + + ConcreteInterpreter CPos(ValueCache); + ConcreteInterpreter CNeg(CEX); + std::vector FilteredRelations; for (auto &&R : Relations) { - auto Result = CI.evaluateInst(R); - // llvm::errs() << "HERE: " << Result.getValue().toString(2, false) << "\n"; + auto Result = CPos.evaluateInst(R); + EvalValue ResultNeg = CEX.empty() ? EvalValue() : CNeg.evaluateInst(R); + + // llvm::errs() << "P: " << Result.getValue().toString(2, false) << ' ' << Result.getValue().isAllOnesValue() << "\n"; + // llvm::errs() << "N: " << ResultNeg.getValue().toString(2, false) << ' ' << ResultNeg.getValue().isNullValue()<< "\n"; + if (Result.hasValue() && Result.getValue().isAllOnesValue()) { - FilteredRelations.push_back(R); + // llvm::errs() << "Keeping "<< "\n"; + if (ResultNeg.hasValue()) { + if (ResultNeg.getValue().isNullValue()) { + FilteredRelations.push_back(R); + } + } else { + FilteredRelations.push_back(R); + } } } return FilteredRelations; @@ -162,7 +183,7 @@ std::vector FilterRelationsByValue(const std::vector &Relations, std::vector InferConstantLimits( const std::vector> &CMap, - InstContext &IC, const ParsedReplacement &Input) { + InstContext &IC, const ParsedReplacement &Input, ValueCache CEX) { std::vector Results; if (!FindConstantRelations) { return Results; @@ -226,7 +247,15 @@ std::vector InferConstantLimits( } } } - return FilterRelationsByValue(Results, CMap); + return FilterRelationsByValue(Results, CMap, CEX); +} + +// Enforce commutativity to prune search space +bool comm(Inst *A, Inst *B, Inst *C) { + return A > B && B > C; +} +bool comm(Inst *A, Inst *B) { + return A > B; } std::vector BitFuncs(Inst *I, InstContext &IC) { @@ -246,51 +275,82 @@ std::vector BitFuncs(Inst *I, InstContext &IC) { // This was originally intended to find relational constraints // but we also use to fine some ad hoc constraints now. // TODO: Filter relations by concrete interpretation +#define C2 comm(XI, YI) +#define C3 comm(XI, YI, ZI) + std::vector InferPotentialRelations( const std::vector> &CMap, - InstContext &IC, const ParsedReplacement &Input) { + InstContext &IC, const ParsedReplacement &Input, ValueCache CEX) { std::vector Results; if (!FindConstantRelations) { return Results; } - for (auto &&[XI, XC] : CMap) { - for (auto &&[YI, YC] : CMap) { - if (XI == YI || XC.getBitWidth() == YC.getBitWidth()) { - continue; - } - llvm::errs() << "HERE: " << XC.getLimitedValue() << ' ' << YC.getLimitedValue() << '\n'; - if (XC.getLimitedValue() == YC.getLimitedValue()) { - if (XI->Width > YI->Width) { - Builder(YI, IC).ZExt(XI->Width).Eq(XI)()->Print(); - Results.push_back(Builder(YI, IC).ZExt(XI->Width).Eq(XI)()); - } else { - Results.push_back(Builder(XI, IC).ZExt(YI->Width).Eq(YI)()); + + // if (DebugLevel) { + // llvm::errs() << "Symconsts for rels: " << CMap.size() << "\n"; + // } + // Triple rels + if (CMap.size() >= 3) { + for (auto &&[XI, XC] : CMap) { + for (auto &&[YI, YC] : CMap) { + for (auto &&[ZI, ZC] : CMap) { + if (XI == YI || XI == ZI || YI == ZI) { + continue; + } + if (XC.getBitWidth() != YC.getBitWidth() || + XC.getBitWidth() != ZC.getBitWidth()) { + continue; + } + + if (C3 && (XC | YC | ZC).isAllOnesValue()) { + Results.push_back(Builder(XI, IC).Or(YI).Or(ZI) + .Eq(llvm::APInt::getAllOnesValue(XI->Width))()); + // TODO Make width independent by using bitwidth inst + } } } } } - - // Generate a set of pairwise relations + // Pairwise relations for (auto &&[XI, XC] : CMap) { // llvm::errs() << "HERE: " << XC << "\n"; for (auto &&[YI, YC] : CMap) { - if (XI == YI || XC.getBitWidth() != YC.getBitWidth()) { continue; } + if (C2 && XC == YC) { + Results.push_back(Builder(XI, IC).Eq(YI)()); + } + + if ((XC & YC) == XC) { + Results.push_back(Builder(XI, IC).And(YI).Eq(XI)()); + } + + if ((XC & YC) == YC) { + Results.push_back(Builder(XI, IC).And(YI).Eq(YI)()); + } + + if ((XC | YC) == XC) { + Results.push_back(Builder(XI, IC).Or(YI).Eq(XI)()); + } + + if ((XC | YC) == YC) { + Results.push_back(Builder(XI, IC).Or(YI).Eq(YI)()); + } + // // Add C // auto Diff = XC - YC; // Results.push_back(Builder(XI, IC).Sub(Diff).Eq(YI)()); // Mul C - if (YC!= 0 && XC.urem(YC) == 0) { + if (C2 && YC!= 0 && XC.urem(YC) == 0) { auto Fact = XC.udiv(YC); Results.push_back(Builder(YI, IC).Mul(Fact).Eq(XI)()); } - if (XC != 0 && YC.urem(XC) == 0) { + if (C2 && XC != 0 && YC.urem(XC) == 0) { auto Fact = YC.udiv(XC); Results.push_back(Builder(XI, IC).Mul(Fact).Eq(YI)()); } @@ -328,10 +388,33 @@ std::vector InferPotentialRelations( Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth().UDiv(2))()); Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth())()); } + + // TODO: Make sure this works. + for (auto &&[XI, XC] : CMap) { + for (auto &&[YI, YC] : CMap) { + if (XI == YI || XC.getBitWidth() == YC.getBitWidth()) { + continue; + } + + // llvm::errs() << "HERE: " << XI->Name << ' ' << YI->Name << ' ' << XC.getLimitedValue() << ' ' << YC.getLimitedValue() << '\n'; + + // llvm::errs() << "HERE: " << XC.getLimitedValue() << ' ' << YC.getLimitedValue() << '\n'; + if (XC.getLimitedValue() == YC.getLimitedValue()) { + if (XI->Width > YI->Width) { + // Builder(YI, IC).ZExt(XI->Width).Eq(XI)()->Print(); + Results.push_back(Builder(YI, IC).ZExt(XI->Width).Eq(XI)()); + } else { + Results.push_back(Builder(XI, IC).ZExt(YI->Width).Eq(YI)()); + } + } + } + } + // for (auto R : InferConstantLimits(CMap, IC, Input)) { // Results.push_back(R); // } - return FilterRelationsByValue(Results, CMap); + // llvm::errs() << "HERE: " << Results.size() << '\n'; + return FilterRelationsByValue(Results, CMap, CEX); } std::set findConcreteConsts(Inst *I) { @@ -468,126 +551,6 @@ if(s) return Clone;}; return Clone; } -ParsedReplacement SymKBPreconditionsAndVerifyGreedy( - ParsedReplacement Input, InstContext &IC, - Solver *S, std::map SymCS) { - - std::map SymKMap; - static size_t i = 0; - for (auto &&C : SymCS) { - SymKMap[IC.createVar(C.first->Width, "symconst_k0_" + std::to_string(i++))] = C.first; - SymKMap[IC.createVar(C.first->Width, "symconst_k1_" + std::to_string(i++))] = C.first; - // Only discriminant for these two are in Name - } - - auto KPC = [&](Inst *SymK) -> InstMapping { - // true : Constraint for known zero - // false : Constraint for known one - - InstMapping Result; - Result.RHS = IC.getConst(llvm::APInt(1, 1)); - - auto I = SymKMap[SymK]; - auto Width = I->Width; - - auto K0 = SymK->Name.starts_with("symconst_k0_"); - - if (K0) { - Inst *AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(Width)); - Inst *NotZeros = IC.getInst(Inst::Xor, Width, {SymK, AllOnes}); - Inst *VarNotZero = IC.getInst(Inst::Or, Width, {I, NotZeros}); - Inst *ZeroBits = IC.getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); - Result.LHS = ZeroBits; - } else { - Inst *VarAndOnes = IC.getInst(Inst::And, Width, {I, SymK}); - Inst *OneBits = IC.getInst(Inst::Eq, 1, {VarAndOnes, SymK}); - Result.LHS = OneBits; - } - - return Result; - }; - - // Pairwise expressions, all boolean - - for (auto &&P1 : SymKMap) { - for (auto &&P2 : SymKMap) { - if (P1.first == P2.first || P1.first->Width != P2.first->Width) { - continue; - } - - auto X = P1.first; - auto Y = P2.first; - - auto W = P1.first->Width; - - std::vector Exprs; - - auto TrueVal = IC.getConst(llvm::APInt(1, 1)); - - // bit flip x == ~y - Exprs.push_back(Builder(X, IC).Xor(Y).Eq(llvm::APInt::getAllOnesValue(X->Width))()); - - // cttz(val) + ctlz(val) >= Width - auto XV = X; - if (X->Name.starts_with("symconst_k0_")) { - XV = Builder(X, IC).Xor(llvm::APInt::getAllOnesValue(W))(); - } - auto YV = Y; - if (Y->Name.starts_with("symconst_k0_")) { - YV = Builder(Y, IC).Xor(llvm::APInt::getAllOnesValue(W))(); - } - Exprs.push_back(Builder(IC, llvm::APInt(W, W)).Ule( - Builder(XV, IC).Cttz().Add( - Builder(YV, IC).Ctlz()())())()); - - - std::vector Components{X, Y, XV, YV}; - Components.push_back(IC.getConst(llvm::APInt::getAllOnesValue(W))); - - EnumerativeSynthesis ES; - auto Guesses = ES.generateExprs(IC, 2, Components, 1); - for (auto &&Guess : Guesses) { - std::set ConstSet; - souper::getConstants(Guess, ConstSet); - if (!ConstSet.empty()) { - if (SymbolizeConstSynthesis) { - Exprs.push_back(Guess); - } - } else { - Exprs.push_back(Guess); - } - } - - - for (auto &&E : Exprs) { - - auto Backup = Input.PCs; - - InstMapping M(E, TrueVal); - - Input.PCs.push_back(M); - Input.PCs.push_back(KPC(X)); - Input.PCs.push_back(KPC(Y)); - -// Input.print(llvm::errs(), true); -// llvm::errs() << "\n"; - - auto Clone = Verify(Input, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - - Input.PCs = Backup; - } - } - } - - Input.Mapping.LHS = nullptr; - Input.Mapping.RHS = nullptr; - //TODO Better failure indicator - return Input; -} - ParsedReplacement FirstValidCombination(ParsedReplacement Input, const std::vector &Targets, @@ -682,6 +645,10 @@ FirstValidCombination(ParsedReplacement Input, Copy.Mapping.RHS = Replace(Input.Mapping.RHS, IC, InstCacheRHS); // Copy.PCs = Input.PCs; + + // Copy.print(llvm::errs(), true); + // llvm::errs() << "\n"; + if (SOLVE(Copy)) { return Clone; } @@ -699,21 +666,24 @@ FirstValidCombination(ParsedReplacement Input, return Input; } -// TODO: Prevent NOPs from being synthesized by passing parent instruction -std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, - std::map SMap, InstContext &IC, size_t Threshold, bool ConstMode) { +std::vector IOSynthesize(llvm::APInt Target, +const std::vector> &ConstMap, +InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) { std::vector Results; // Just symbolic or Concrete constant - for (auto C : LHSConsts) { + for (const auto &[I, Val] : ConstMap) { + if (I == ParentConst) { + continue; + } if (!ConstMode) { - if (C->Width == Target.getBitWidth() && C->Val == Target) { - Results.push_back(SMap[C]); + if (I->Width == Target.getBitWidth() && Val == Target) { + Results.push_back(I); } } else { - if (C->Width == Target.getBitWidth()) { + if (I->Width == Target.getBitWidth()) { Results.push_back(Builder(IC, Target)()); } } @@ -725,79 +695,79 @@ std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, // Recursive formulation - for (auto C : LHSConsts) { - if (C->Width != Target.getBitWidth()) { + #define for_no_nop(X, x) \ + if (Target != x) for (auto X : \ + IOSynthesize(x, ConstMap, IC, Threshold - 1, ConstMode, ParentConst)) + + for (const auto &[I, Val] : ConstMap) { + if (I->Width != Target.getBitWidth()) { + continue; + } + + if (I == ParentConst) { continue; } + ParentConst = I; // Binary operators // C + X == Target - for (auto X : IOSynthesize(Target - C->Val, LHSConsts, SMap, IC, - Threshold - 1, ConstMode)) { - Results.push_back(Builder(SMap[C], IC).Add(X)()); + for_no_nop(X, Target - Val) { + Results.push_back(Builder(I, IC).Add(X)()); } // C - X == Target - for (auto X : IOSynthesize(C->Val - Target, LHSConsts, SMap, IC, - Threshold - 1, ConstMode)) { - Results.push_back(Builder(SMap[C], IC).Sub(X)()); + for_no_nop(X, Val - Target) { + Results.push_back(Builder(I, IC).Sub(X)()); } // X - C == Target - for (auto X : IOSynthesize(Target + C->Val, LHSConsts, SMap, IC, - Threshold - 1, ConstMode)) { - Results.push_back(Builder(X, IC).Sub(SMap[C])()); + for_no_nop(X, Target + Val) { + Results.push_back(Builder(X, IC).Sub(I)()); } // C * X == Target - if (C->Val.isNegative() || Target.isNegative()) { - if (C->Val != 0 && Target.srem(C->Val) == 0) { - for (auto X : IOSynthesize(Target.sdiv(C->Val), LHSConsts, SMap, - IC, Threshold - 1, ConstMode)) { - Results.push_back(Builder(X, IC).Mul(SMap[C])()); + if (Val.isNegative() || Target.isNegative()) { + if (Val != 0 && Target.srem(Val) == 0) { + for_no_nop(X, Target.sdiv(Val)) { + Results.push_back(Builder(X, IC).Mul(I)()); } } } else { - if (C->Val != 0 && Target.urem(C->Val) == 0) { - for (auto X : IOSynthesize(Target.udiv(C->Val), LHSConsts, SMap, - IC, Threshold - 1, ConstMode)) { - Results.push_back(Builder(X, IC).Mul(SMap[C])()); + if (Val != 0 && Target.urem(Val) == 0) { + for_no_nop(X, Target.udiv(Val)) { + Results.push_back(Builder(X, IC).Mul(I)()); } } } // C / X == Target - if (C->Val.isNegative() || Target.isNegative()) { - if (Target != 0 && C->Val.srem(Target) == 0) { - for (auto X : IOSynthesize(C->Val.sdiv(Target), LHSConsts, SMap, - IC, Threshold - 1, ConstMode)) { - Results.push_back(Builder(SMap[C], IC).SDiv(X)()); + if (Val.isNegative() || Target.isNegative()) { + if (Target != 0 && Val.srem(Target) == 0) { + for_no_nop(X, Val.sdiv(Target)) { + Results.push_back(Builder(I, IC).SDiv(X)()); } } } else { - if (Target != 0 && C->Val.urem(Target) == 0) { - for (auto X : IOSynthesize(C->Val.udiv(Target), LHSConsts, SMap, - IC, Threshold - 1, ConstMode)) { - Results.push_back(Builder(SMap[C], IC).UDiv(X)()); + if (Target != 0 && Val.urem(Target) == 0) { + for_no_nop(X, Val.udiv(Target)) { + Results.push_back(Builder(I, IC).UDiv(X)()); } } } // X / C == Target - if (C->Val.isNegative() || Target.isNegative()) { - if (C->Val != 0 && Target.srem(C->Val) == 0) { - for (auto X : IOSynthesize(C->Val * Target, LHSConsts, SMap, - IC, Threshold - 1, ConstMode)) { - Results.push_back(Builder(X, IC).SDiv(SMap[C])()); + if (Val.isNegative() || Target.isNegative()) { + if (Val != 0 && Target.srem(Val) == 0) { + for_no_nop(X, Val * Target) { + Results.push_back(Builder(X, IC).SDiv(I)()); } } } else { - if (C->Val != 0 && Target.urem(C->Val) == 0) { - for (auto X : IOSynthesize(C->Val * Target, LHSConsts, SMap, - IC, Threshold - 1, ConstMode)) { - Results.push_back(Builder(X, IC).UDiv(SMap[C])()); + if (Val != 0 && Target.urem(Val) == 0) { + for_no_nop(X, Val * Target) { + Results.push_back(Builder(X, IC).UDiv(I)()); } } } @@ -805,45 +775,45 @@ std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, // Shifts? // Unary operators (no recursion required) - if (Target == C->Val.logBase2()) { - Results.push_back(Builder(SMap[C], IC).LogB()()); + if (Target == Val.logBase2()) { + Results.push_back(Builder(I, IC).LogB()()); } - if (Target == C->Val.reverseBits()) { - Results.push_back(Builder(SMap[C], IC).BitReverse()()); + if (Target == Val.reverseBits()) { + Results.push_back(Builder(I, IC).BitReverse()()); } // TODO Add others // bit flip - llvm::APInt D = C->Val; + llvm::APInt D = Val; D.flipAllBits(); if (Target == D) { - Results.push_back(Builder(SMap[C], IC).Xor(llvm::APInt::getAllOnesValue(C->Width))()); + Results.push_back(Builder(I, IC).Xor(llvm::APInt::getAllOnesValue(I->Width))()); } if (Target == D + 1) { - Results.push_back(Builder(SMap[C], IC).Xor(llvm::APInt::getAllOnesValue(C->Width)).Add(1)()); + Results.push_back(Builder(I, IC).Xor(llvm::APInt::getAllOnesValue(I->Width)).Add(1)()); } // neg - D = C->Val; + D = Val; D.negate(); - if (Target == D) { - Results.push_back(Builder(IC, llvm::APInt::getAllOnesValue(C->Width)).Sub(SMap[C])()); + if (Target == D && D != Val) { + Results.push_back(Builder(IC, llvm::APInt::getAllOnesValue(I->Width)).Sub(I)()); } - for (auto C2 : LHSConsts) { - if (C == C2 || C->Width != C2->Width) { + for (const auto &[I2, Val2] : ConstMap) { + if (I == I2 || I->Width != I2->Width || I2 == ParentConst) { continue; } - if ((C->Val & C2->Val) == Target) { - Results.push_back(Builder(SMap[C], IC).And(SMap[C2])()); + if ((Val & Val2) == Target && !Val.isAllOnesValue() && !Val2.isAllOnesValue()) { + Results.push_back(Builder(I, IC).And(I2)()); } - if ((C->Val | C2->Val) == Target) { - Results.push_back(Builder(SMap[C], IC).Or(SMap[C2])()); + if ((Val | Val2) == Target && Val != 0 && Val2 != 0) { + Results.push_back(Builder(I, IC).Or(I2)()); } - if ((C->Val ^ C2->Val) == Target) { - Results.push_back(Builder(SMap[C], IC).Xor(SMap[C2])()); + if ((Val ^ Val2) == Target && Val != Target && Val2 != Target) { + Results.push_back(Builder(I, IC).Xor(I2)()); } } } @@ -851,26 +821,142 @@ std::vector IOSynthesize(llvm::APInt Target, std::set LHSConsts, return Results; } +std::map CountUses(Inst *I) { + std::vector Stack{I}; + std::set Visited; + std::map Count; + while (!Stack.empty()) { + auto *I = Stack.back(); + Stack.pop_back(); + if (Visited.count(I)) { + continue; + } + Visited.insert(I); + for (auto *U : I->Ops) { + if (U->K == Inst::Var) { + Count[U]++; + } + Stack.push_back(U); + } + } + return Count; +} + +// // Filter candidates to rule out NOPs as much as possible +// std::vector FilterCand(std::vector Cands, +// const std::vector> &ConstMap) { +// return Cands; +// std::vector Results; +// for (auto &&C : Cands) { +// std::map VarCount = CountUses(C); + +// C->Print(); +// for (auto &[I, Count] : VarCount) { +// llvm::errs() << I->Name << " " << Count << "\t"; +// } +// llvm::errs() << "\n\n"; + + +// bool hasDupe = false; +// for (auto &[_, Count] : VarCount) { +// if (Count > 4) { +// hasDupe = true; +// break; +// } +// } +// if (hasDupe) { +// continue; +// } + +// Results.push_back(C); +// } +// return Results; +// } + std::vector> -InferSpecialConstExprsAllSym(std::vector RHS, std::set - LHS, std::map SMap, +InferSpecialConstExprsAllSym(std::vector RHS, +const std::vector> &ConstMap, InstContext &IC, int depth = 3) { std::vector> Results; for (auto R : RHS) { - Results.push_back(IOSynthesize(R->Val, LHS, SMap, IC, depth, false)); + auto Cands = IOSynthesize(R->Val, ConstMap, IC, depth, false); + Results.push_back(Cands); std::sort(Results.back().begin(), Results.back().end(), [](Inst *A, Inst *B) { return instCount(A) < instCount(B);}); } return Results; } +using ConstMapT = std::vector>; + +std::pair +AugmentForSymDB(ParsedReplacement Original, InstContext &IC) { + auto Input = Clone(Original, IC); + std::vector> ConstMap; + if (Input.Mapping.LHS->DemandedBits.getBitWidth() == Input.Mapping.LHS->Width && + !Input.Mapping.LHS->DemandedBits.isAllOnesValue()) { + auto DB = Input.Mapping.LHS->DemandedBits; + auto SymDFVar = IC.createVar(DB.getBitWidth(), "symDF_DB"); + // SymDFVar->Name = "symDF_DB"; + + SymDFVar->KnownOnes = llvm::APInt(DB.getBitWidth(), 0); + SymDFVar->KnownZeros = llvm::APInt(DB.getBitWidth(), 0); + // SymDFVar->Val = DB; + + Input.Mapping.LHS->DemandedBits.setAllBits(); + Input.Mapping.RHS->DemandedBits.setAllBits(); + + Input.Mapping.LHS = Builder(Input.Mapping.LHS, IC).And(SymDFVar)(); + Input.Mapping.RHS = Builder(Input.Mapping.RHS, IC).And(SymDFVar)(); + ConstMap.push_back({SymDFVar, DB}); + } + return {ConstMap, Input}; +} + +std::pair AugmentForSymKB(ParsedReplacement Original, InstContext &IC) { + auto Input = Clone(Original, IC); + ConstMapT ConstMap; + std::vector Inputs; + findVars(Input.Mapping.LHS, Inputs); + + for (auto &&I : Inputs) { + auto Width = I->Width; + if (I->KnownZeros.getBitWidth() == I->Width && + I->KnownOnes.getBitWidth() == I->Width && + !(I->KnownZeros == 0 && I->KnownOnes == 0)) { + if (I->KnownZeros != 0) { + Inst *Zeros = IC.createVar(Width, "symDF_K0"); + + Inst *AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(Width)); + Inst *NotZeros = IC.getInst(Inst::Xor, Width, + {Zeros, AllOnes}); + Inst *VarNotZero = IC.getInst(Inst::Or, Width, {I, NotZeros}); + Inst *ZeroBits = IC.getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); + Input.PCs.push_back({ZeroBits, IC.getConst(llvm::APInt(1, 1))}); + ConstMap.push_back({Zeros, I->KnownZeros}); + I->KnownZeros = llvm::APInt(I->Width, 0); + } + + if (I->KnownOnes != 0) { + Inst *Ones = IC.createVar(Width, "symDF_K1"); + Inst *VarAndOnes = IC.getInst(Inst::And, Width, {I, Ones}); + Inst *OneBits = IC.getInst(Inst::Eq, 1, {VarAndOnes, Ones}); + Input.PCs.push_back({OneBits, IC.getConst(llvm::APInt(1, 1))}); + ConstMap.push_back({Ones, I->KnownOnes}); + I->KnownOnes = llvm::APInt(I->Width, 0); + } + } + } + return {ConstMap, Input}; +} + std::vector> -InferSpecialConstExprsWithConcretes(std::vector RHS, std::set - LHS, std::map SMap, - InstContext &IC) { +InferSpecialConstExprsWithConcretes(std::vector RHS, +const std::vector> &ConstMap, + InstContext &IC, int depth = 3) { std::vector> Results; for (auto R : RHS) { - auto Cands = IOSynthesize(R->Val, LHS, SMap, IC, 3, true); + auto Cands = IOSynthesize(R->Val, ConstMap, IC, depth, true); std::vector Filtered; for (auto Cand : Cands) { if (Cand->K != Inst::Const) { @@ -883,12 +969,12 @@ InferSpecialConstExprsWithConcretes(std::vector RHS, std::set } std::vector> Enumerate(std::vector RHSConsts, - std::set LHSConsts, InstContext &IC, + std::set AtomicComps, InstContext &IC, size_t NumInsts = 1) { std::vector> Candidates; std::vector Components; - for (auto &&C : LHSConsts) { + for (auto &&C : AtomicComps) { Components.push_back(C); // Components.push_back(Builder(C, IC).BSwap()()); Components.push_back(Builder(C, IC).LogB()()); @@ -953,22 +1039,27 @@ void findDangerousConstants(Inst *I, std::set &Results) { // Assuming the input has leaves pruned and preconditions weakened ParsedReplacement SuccessiveSymbolize(InstContext &IC, - Solver *S, ParsedReplacement Input, bool &Changed) { + Solver *S, ParsedReplacement Input, bool &Changed, + std::vector> ConstMap = {}) { // Print first successful result and exit, no result sorting. - // Prelude - auto Fresh = Clone(Input, IC); + auto Fresh = Input; + size_t ticks = std::clock(); auto Refresh = [&] (auto Msg) { + // Input = Clone(Fresh, IC); Input = Fresh; if (DebugLevel > 2) { - llvm::errs() << "POST " << Msg << "\n"; + auto now = std::clock(); + llvm::errs() << "POST " << Msg << " - " << (now - ticks)*1000/CLOCKS_PER_SEC << " ms\n"; + ticks = now; } Changed = true; - return Fresh; }; + bool Nested = !ConstMap.empty(); + auto LHSConsts = findConcreteConsts(Input.Mapping.LHS); auto RHSConsts = findConcreteConsts(Input.Mapping.RHS); @@ -1042,13 +1133,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Clone; } - if (Advanced) { - Clone = SymKBPreconditionsAndVerifyGreedy(Result, IC, S, SymCS); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - } - // Clone = DFPreconditionsAndVerifyGreedy(Result, IC, S, SymCS); // if (Clone.Mapping.LHS && Clone.Mapping.RHS) { // return Clone; @@ -1060,13 +1144,15 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Step 1.5 : Direct symbolize, simple rel constraints on LHS - std::vector> CMap; - for (auto &&C : LHSConsts) { - CMap.push_back({SymConstMap[C], C->Val}); + ConstMap.push_back({SymConstMap[C], C->Val}); } - - auto Relations = InferPotentialRelations(CMap, IC, Input); + auto CEX = GetCEX(Result, IC, S); + if (Nested) { + CEX = {}; + // FIXME : Figure out how to get CEX for symbolic dataflow + } + auto Relations = InferPotentialRelations(ConstMap, IC, Input, CEX); std::map JustLHSSymConstMap; @@ -1077,6 +1163,8 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Copy = Replace(Input, IC, JustLHSSymConstMap); for (auto &&R : Relations) { Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + // Copy.print(llvm::errs(), true); + // llvm::errs() << "\n"; auto Clone = Verify(Copy, IC, S); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; @@ -1101,22 +1189,46 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } - } - Refresh("All LHS Constraints"); + Refresh("All LHS Constraints"); - auto ConstantLimits = InferConstantLimits(CMap, IC, Input); - + auto ConstantLimits = InferConstantLimits(ConstMap, IC, Input, CEX); // Step 3 : Special RHS constant exprs, no constants if (!RHSFresh.empty()) { + std::vector> UnitaryCandidates = + InferSpecialConstExprsAllSym(RHSFresh, ConstMap, IC, /*depth*/0); + + if (!UnitaryCandidates.empty()) { + + // if (DebugLevel > 4) { + // llvm::errs() << "Rels " << Relations.size() << "\n"; + // llvm::errs() << "Unitary candidates: " << UnitaryCandidates[0].size() << "\n"; + // } + + for (auto &&R : Relations) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + + auto Clone = FirstValidCombination(Input, RHSFresh, UnitaryCandidates, + InstCache, IC, S, SymCS, true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + Input.PCs.pop_back(); + } + Refresh("Unitary cands, rel constraints"); + } + std::vector> SimpleCandidates = - InferSpecialConstExprsAllSym(RHSFresh, LHSConsts, SymConstMap, IC); + InferSpecialConstExprsAllSym(RHSFresh, ConstMap, IC, /*depth=*/ 4); if (!SimpleCandidates.empty()) { + if (DebugLevel > 4) { + llvm::errs() << "InferSpecialConstExprsAllSym candidates: " << SimpleCandidates[0].size() << "\n"; + } auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, InstCache, IC, S, SymCS, true, false, false); @@ -1124,18 +1236,21 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Clone; } } - Refresh("Special expressions, no constants"); - // Step 4 : Enumerated expressions std::set Components; - for (auto C : LHSConsts) { - Components.insert(SymConstMap[C]); + for (auto C : ConstMap) { + Components.insert(C.first); } auto EnumeratedCandidates = Enumerate(RHSFresh, Components, IC); + // if (DebugLevel > 4) { + // llvm::errs() << "RHSFresh: " << RHSFresh.size() << "\n"; + // llvm::errs() << "Components: " << Components.size() << "\n"; + // llvm::errs() << "EnumeratedCandidates: " << EnumeratedCandidates[0].size() << "\n"; + // } if (!EnumeratedCandidates.empty()) { auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, @@ -1146,7 +1261,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Enumerated cands, no constraints"); // Enumerated Expressions with some relational constraints - if (CMap.size() == 2) { + if (ConstMap.size() == 2) { + // llvm::errs() << "Relations: " << Relations.size() << "\n"; + // llvm::errs() << "Guesses: " << EnumeratedCandidates[0].size() << "\n"; + for (auto &&R : Relations) { Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); @@ -1167,13 +1285,15 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (RHSFresh.size() == 1) { EnumeratedCandidatesTwoInsts = Enumerate(RHSFresh, Components, IC, 2); + // llvm::errs() << "Guesses: " << EnumeratedCandidatesTwoInsts[0].size() << "\n"; + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, InstCache, IC, S, SymCS, true, false, false); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } - Refresh("Enumerated 2 insts"); } + Refresh("Enumerated 2 insts for single RHS const cases"); if (!EnumeratedCandidates.empty()) { auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, @@ -1184,13 +1304,13 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } Refresh("Enumerated exprs with constraints"); - if (RHSFresh.size() == 1) { + if (RHSFresh.size() == 1 && !Nested) { // Enumerated Expressions with some relational constraints - if (CMap.size() == 2) { + if (ConstMap.size() == 2) { for (auto &&R : Relations) { Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, - InstCache, IC, S, SymCS, true, true, false); + InstCache, IC, S, SymCS, true, false, false); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } @@ -1203,9 +1323,9 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Step 4.8 : Special RHS constant exprs, with constants std::vector> SimpleCandidatesWithConsts = - InferSpecialConstExprsWithConcretes(RHSFresh, LHSConsts, SymConstMap, IC); + InferSpecialConstExprsWithConcretes(RHSFresh, ConstMap, IC, /*depth=*/ 2); - if (!SimpleCandidatesWithConsts.empty()) { + if (!SimpleCandidatesWithConsts.empty() && !Nested) { auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, InstCache, IC, S, SymCS, true, false, false); @@ -1218,7 +1338,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Enumerated exprs with constraints - if (!EnumeratedCandidates.empty()) { + if (!EnumeratedCandidates.empty() && !Nested) { for (auto &&R : Relations) { Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); @@ -1245,7 +1365,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, - InstCache, IC, S, SymCS, true, true, true); + InstCache, IC, S, SymCS, true, false, false); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } @@ -1257,7 +1377,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Step 5.5 : Simple exprs with constraints - if (!SimpleCandidatesWithConsts.empty()) { + if (!SimpleCandidatesWithConsts.empty() && !Nested) { auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, InstCache, IC, S, SymCS, false, true, true); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { @@ -1279,23 +1399,23 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("Simple cands+consts with constraints and relations"); } - { - if (!RHSFresh.empty()) { - std::vector> SimpleCandidatesMoreInsts = - InferSpecialConstExprsAllSym(RHSFresh, LHSConsts, SymConstMap, IC, /*depth =*/ 5); - - if (!SimpleCandidates.empty()) { - auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesMoreInsts, - InstCache, IC, S, SymCS, - true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - } + // { + // if (!RHSFresh.empty()) { + // std::vector> SimpleCandidatesMoreInsts = + // InferSpecialConstExprsAllSym(RHSFresh, ConstMap, IC, /*depth =*/ 5); - Refresh("Special expressions, no constants"); - } - } + // if (!SimpleCandidates.empty()) { + // auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesMoreInsts, + // InstCache, IC, S, SymCS, + // true, false, false); + // if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + // return Clone; + // } + // } + + // Refresh("Special expressions, no constants"); + // } + // } if (!EnumeratedCandidates.empty()) { for (auto &&R : ConstantLimits) { @@ -1339,96 +1459,80 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } Refresh("Constant limit constraints on LHS"); } - if (SymbolicDF) { - Refresh("PUSH SYMDF_DB"); - if (Input.Mapping.LHS->DemandedBits.getBitWidth() == Input.Mapping.LHS->Width && - !Input.Mapping.LHS->DemandedBits.isAllOnesValue()) { - auto DB = Input.Mapping.LHS->DemandedBits; - auto SymDFVar = IC.getConst(DB); - SymDFVar->Name = "SYMDF_DB"; - - SymDFVar->KnownOnes = llvm::APInt(DB.getBitWidth(), 0); - SymDFVar->KnownZeros = llvm::APInt(DB.getBitWidth(), 0); - SymDFVar->Val = DB; - - auto LHS = Input.Mapping.LHS; - auto RHS = Input.Mapping.RHS; - - Input.Mapping.LHS->DemandedBits.setAllBits(); - Input.Mapping.RHS->DemandedBits.setAllBits(); - Input.Mapping.LHS = Builder(Input.Mapping.LHS, IC).And(SymDFVar)(); - Input.Mapping.RHS = Builder(Input.Mapping.RHS, IC).And(SymDFVar)(); + if (SymbolicDF) { + bool canTrySymDB = false; + bool canTrySymKB = false; + Refresh("PUSH SYMDF_DB"); + auto [SymDBConstMap, Augmented] = AugmentForSymDB(Input, IC); + canTrySymDB = !SymDBConstMap.empty(); + if (canTrySymDB) { bool SymDFChanged = false; - auto Generalized = SuccessiveSymbolize(IC, S, Input, SymDFChanged); + // Augmented.print(llvm::errs(), true); + auto Clone = Verify(Augmented, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + // Symbolic demanded bits can be unconstrained + return Clone; + } + auto Generalized = SuccessiveSymbolize(IC, S, Augmented, SymDFChanged, SymDBConstMap); if (SymDFChanged) { return Generalized; - } else { - Input.Mapping.LHS = LHS; - Input.Mapping.RHS = RHS; - Input.Mapping.LHS->DemandedBits = DB; - Input.Mapping.RHS->DemandedBits = DB; } } Refresh("POP SYMDF_DB"); + Refresh("PUSH SYMDF_KB"); { - // Find good examples and test - std::vector Inputs; - findVars(Input.Mapping.LHS, Inputs); - - std::map KnownZero, KnownOne; - auto PCs = Input.PCs; - - for (auto &&I : Inputs) { - auto Width = I->Width; - - if (I->KnownZeros.getBitWidth() == I->Width && - I->KnownOnes.getBitWidth() == I->Width && - !(I->KnownZeros == 0 && I->KnownOnes == 0)) { - KnownZero[I] = I->KnownZeros; - KnownOne[I] = I->KnownOnes; - - if (I->KnownZeros != 0) { - Inst *Zeros = IC.getConst(I->KnownZeros); - Zeros->Name = "SYMDF_K0"; - Inst *AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(Width)); - Inst *NotZeros = IC.getInst(Inst::Xor, Width, - {Zeros, AllOnes}); - Inst *VarNotZero = IC.getInst(Inst::Or, Width, {I, NotZeros}); - Inst *ZeroBits = IC.getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); - Input.PCs.push_back({ZeroBits, IC.getConst(llvm::APInt(1, 1))}); - I->KnownZeros = llvm::APInt(I->Width, 0); - } + auto [SymKBConstMap, Augmented] = AugmentForSymKB(Input, IC); + canTrySymKB = !SymKBConstMap.empty(); - if (I->KnownOnes != 0) { - Inst *Ones = IC.getConst(I->KnownOnes); - Ones->Name = "SYMDF_K1"; - Inst *VarAndOnes = IC.getInst(Inst::And, Width, {I, Ones}); - Inst *OneBits = IC.getInst(Inst::Eq, 1, {VarAndOnes, Ones}); - Input.PCs.push_back({OneBits, IC.getConst(llvm::APInt(1, 1))}); - I->KnownOnes = llvm::APInt(I->Width, 0); - } - } + auto Clone = Verify(Augmented, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + // Symbolic known bits can be unconstrained + return Clone; } - if (!KnownZero.empty() || !KnownOne.empty()) { + if (canTrySymKB) { bool SymDFChanged = false; - auto Generalized = SuccessiveSymbolize(IC, S, Input, SymDFChanged); + auto Generalized = SuccessiveSymbolize(IC, S, Augmented, + SymDFChanged, SymKBConstMap); if (SymDFChanged) { return Generalized; - } else { - Input.PCs = PCs; - for (auto &&I : Inputs) { - I->KnownZeros = KnownZero[I]; - I->KnownOnes = KnownOne[I]; - } } } } Refresh("POP SYMDF_KB"); + + + + if (canTrySymDB && canTrySymKB) { + Refresh("PUSH SYMDF_KB_DB"); + auto [CM1, Aug1] = AugmentForSymDB(Input, IC); + auto [CM2, Aug2] = AugmentForSymKB(Aug1, IC); + bool SymDFChanged = false; + + // Aug2.print(llvm::errs(), true); + + for (auto P : CM1) { + CM2.push_back(P); + } + + auto Clone = Verify(Aug2, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + // Symbolic db+kb can be unconstrained + // very unlikely? test if needed + return Clone; + } + + auto Generalized = SuccessiveSymbolize(IC, S, Aug2, SymDFChanged, CM2); + if (SymDFChanged) { + return Generalized; + } + Refresh("POP SYMDF_KB_DB"); + } + } Refresh("END"); From 1e18cf30eb849a33c6525d6f7e19308fb9c039c7 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 8 Mar 2023 20:15:59 -0700 Subject: [PATCH 140/165] foo --- include/souper/Infer/SynthUtils.h | 7 + include/souper/Inst/Inst.h | 5 + lib/Extractor/KLEEBuilder.cpp | 31 ++++ lib/Infer/Interpreter.cpp | 12 ++ lib/Infer/SynthUtils.cpp | 45 +++-- lib/Inst/Inst.cpp | 12 ++ lib/Parser/Parser.cpp | 7 + tools/generalize.cpp | 268 ++++++++++++++++++++++-------- 8 files changed, 305 insertions(+), 82 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 0e54a2790..1417225a5 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -63,6 +63,12 @@ class Builder { UNOP(BitWidth) UNOP(CtPop) #undef UNOP + Builder Flip() { + auto L = I; + auto AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(L->Width)); + return Builder(IC.getInst(Inst::Xor, L->Width, {L, AllOnes}), IC); + } + #define UNOPW(K) \ Builder K(size_t W) { \ auto L = I; \ @@ -121,6 +127,7 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC); // Also Synthesizes given constants // Returns clone if verified, nullptrs if not ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S); +// bool IsValid(ParsedReplacement Input, InstContext &IC, Solver *S); std::map findOneConstSet(ParsedReplacement Input, const std::set &SymCS, InstContext &IC, Solver *S); diff --git a/include/souper/Inst/Inst.h b/include/souper/Inst/Inst.h index 6703fbad8..860982e97 100644 --- a/include/souper/Inst/Inst.h +++ b/include/souper/Inst/Inst.h @@ -127,6 +127,11 @@ struct Inst : llvm::FoldingSetNode { ReservedConst, ReservedInst, + KnownOnesP, + KnownZerosP, + RangeP, + DemandedMask, + None, } Kind; diff --git a/lib/Extractor/KLEEBuilder.cpp b/lib/Extractor/KLEEBuilder.cpp index fbbea5ee7..1ea8a86aa 100644 --- a/lib/Extractor/KLEEBuilder.cpp +++ b/lib/Extractor/KLEEBuilder.cpp @@ -359,6 +359,37 @@ class KLEEBuilder : public ExprBuilder { unsigned Width = L->getWidth(); return klee::ConstantExpr::create(Width, Width); } + + case Inst::KnownOnesP: { + auto VarAndOnes = klee::AndExpr::create(get(Ops[0]), get(Ops[1])); + return klee::EqExpr::create(VarAndOnes, get(Ops[1])); + } + case Inst::KnownZerosP: { + auto NotZeros = klee::NotExpr::create(get(Ops[1])); + auto VarNotZero = klee::OrExpr::create(get(Ops[0]), NotZeros); + return klee::EqExpr::create(VarNotZero, NotZeros); + } + case Inst::RangeP: { + auto Var = get(Ops[0]); + auto Lower = get(Ops[1]); + auto Upper = get(Ops[2]); + auto GELower = klee::SgeExpr::create(Var, Lower); + auto LTUpper = klee::SltExpr::create(Var, Upper); + auto Ordinary = klee::AndExpr::create(GELower, LTUpper); + + auto GEUpper = klee::SgeExpr::create(Var, Upper); + auto LTLower = klee::SltExpr::create(Var, Lower); + auto Wrapped = klee::OrExpr::create(GEUpper, LTLower); + + auto Cond = klee::SgtExpr::create(Upper, Lower); + + return klee::SelectExpr::create(Cond, Ordinary, Wrapped); + } + + case Inst::DemandedMask: { + return klee::AndExpr::create(get(Ops[0]), get(Ops[1])); + } + case Inst::FShl: case Inst::FShr: { unsigned IWidth = I->Width; diff --git a/lib/Infer/Interpreter.cpp b/lib/Infer/Interpreter.cpp index e87215e8b..38b990dbb 100644 --- a/lib/Infer/Interpreter.cpp +++ b/lib/Infer/Interpreter.cpp @@ -453,6 +453,18 @@ namespace souper { // Is the result always of this width? } + case Inst::KnownOnesP: { + auto A = ARG0; + return A & ARG1 == A; + } + case Inst::KnownZerosP: { + auto Z = ARG1; + return ARG0 | ~Z == Z; + } + case Inst::DemandedMask: { + return ARG0 & ARG1; + } + default: llvm::report_fatal_error("unimplemented instruction kind " + std::string(Inst::getKindName(Inst->K)) + diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index d3cc664bc..c45e1eb5d 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -67,23 +67,48 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { return In; } +// bool IsValid(ParsedReplacement Input, InstContext &IC, Solver *S) { +// if (Input.PCs.empty()) { +// SynthesisContext SC{IC, S->getSMTLIBSolver(), Input.Mapping.LHS, nullptr, +// Input.PCs,Input.BPCs, false, 15}; +// std::vector Vars; +// findVars(Input.Mapping.LHS, Vars); + +// PruningManager Pruner(SC, Vars, 0); +// Pruner.init(); + +// if (Pruner.isInfeasible(Input.Mapping.RHS, 0)) { +// return false; +// } +// } + +// bool IsValid; +// if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, IsValid, nullptr)) { +// llvm::errs() << EC.message() << '\n'; +// } +// return IsValid; +// } + //std::map ConstantSynthesis // Also Synthesizes given constants // Returns clone if verified, nullptrs if not ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { - SynthesisContext SC{IC, S->getSMTLIBSolver(), Input.Mapping.LHS, nullptr, - Input.PCs,Input.BPCs, false, 15}; - std::vector Vars; - findVars(Input.Mapping.LHS, Vars); - PruningManager Pruner(SC, Vars, 0); - Pruner.init(); + if (Input.PCs.empty()) { + SynthesisContext SC{IC, S->getSMTLIBSolver(), Input.Mapping.LHS, nullptr, + Input.PCs,Input.BPCs, false, 15}; + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); - if (Pruner.isInfeasible(Input.Mapping.RHS, 0)) { - Input.Mapping.LHS = nullptr; - Input.Mapping.RHS = nullptr; - return Input; + PruningManager Pruner(SC, Vars, 0); + Pruner.init(); + + if (Pruner.isInfeasible(Input.Mapping.RHS, 0)) { + Input.Mapping.LHS = nullptr; + Input.Mapping.RHS = nullptr; + return Input; + } } Input = Clone(Input, IC); diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index c76c96639..7f448e39c 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -437,6 +437,14 @@ const char *Inst::getKindName(Kind K) { return "logb"; case BitWidth: return "width"; + case KnownOnesP: + return "knownones"; + case KnownZerosP: + return "knownzeros"; + case RangeP: + return "range"; + case DemandedMask: + return "demandedmask"; case FShl: return "fshl"; case FShr: @@ -533,6 +541,10 @@ Inst::Kind Inst::getKind(std::string Name) { .Case("ctlz", Inst::Ctlz) .Case("logb", Inst::LogB) .Case("width", Inst::BitWidth) + .Case("knownones", Inst::KnownOnesP) + .Case("knownzeros", Inst::KnownZerosP) + .Case("range", Inst::RangeP) + .Case("demandedmask", Inst::DemandedMask) .Case("fshl", Inst::FShl) .Case("fshr", Inst::FShr) .Case("sadd.with.overflow", Inst::SAddWithOverflow) diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp index e2b91fabb..5be83e303 100644 --- a/lib/Parser/Parser.cpp +++ b/lib/Parser/Parser.cpp @@ -544,6 +544,9 @@ bool Parser::typeCheckInst(Inst::Kind IK, unsigned &Width, case Inst::UAddSat: case Inst::SSubSat: case Inst::USubSat: + case Inst::KnownOnesP: + case Inst::KnownZerosP: + case Inst::DemandedMask: MinOps = MaxOps = 2; break; @@ -597,6 +600,7 @@ bool Parser::typeCheckInst(Inst::Kind IK, unsigned &Width, break; case Inst::FShl: case Inst::FShr: + case Inst::RangeP: MaxOps = MinOps = 3; break; @@ -660,6 +664,9 @@ bool Parser::typeCheckInst(Inst::Kind IK, unsigned &Width, case Inst::Slt: case Inst::Ule: case Inst::Sle: + case Inst::KnownOnesP: + case Inst::KnownZerosP: + case Inst::RangeP: ExpectedWidth = 1; break; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 7861f711a..60a15637c 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -280,7 +280,8 @@ std::vector BitFuncs(Inst *I, InstContext &IC) { std::vector InferPotentialRelations( const std::vector> &CMap, - InstContext &IC, const ParsedReplacement &Input, ValueCache CEX) { + InstContext &IC, const ParsedReplacement &Input, ValueCache CEX, + bool LatticeChecks = false) { std::vector Results; if (!FindConstantRelations) { return Results; @@ -306,7 +307,33 @@ std::vector InferPotentialRelations( if (C3 && (XC | YC | ZC).isAllOnesValue()) { Results.push_back(Builder(XI, IC).Or(YI).Or(ZI) .Eq(llvm::APInt::getAllOnesValue(XI->Width))()); - // TODO Make width independent by using bitwidth inst + } + + if (C3 && (XC & YC & ZC) == 0) { + Results.push_back(Builder(XI, IC).And(YI).And(ZI) + .Eq(llvm::APInt(XI->Width, 0))()); + } + + if (C2 && (XC & YC).eq(ZC)) { + Results.push_back(Builder(XI, IC).And(YI).Eq(ZI)()); + } + + if (C2 && (XC | YC).eq(ZC)) { + Results.push_back(Builder(XI, IC).Or(YI).Eq(ZI)()); + } + + if (C2 && (XC ^ YC).eq(ZC)) { + Results.push_back(Builder(XI, IC).Xor(YI).Eq(ZI)()); + } + + if (C2 && (XC != 0 && YC != 0) && (XC + YC).eq(ZC)) { + Results.push_back(Builder(XI, IC).Add(YI).Eq(ZI)()); + } + + // TODO Make width independent by using bitwidth insts + if (C2 && (XC | YC | ~ZC).isAllOnesValue()) { + Results.push_back(Builder(XI, IC).Or(YI).Or(Builder(ZI, IC).Flip()) + .Eq(llvm::APInt::getAllOnesValue(XI->Width))()); } } } @@ -321,38 +348,54 @@ std::vector InferPotentialRelations( continue; } - if (C2 && XC == YC) { - Results.push_back(Builder(XI, IC).Eq(YI)()); - } + // if (C2 && XC == YC) { + // Results.push_back(Builder(XI, IC).Eq(YI)()); + // } - if ((XC & YC) == XC) { - Results.push_back(Builder(XI, IC).And(YI).Eq(XI)()); - } + // if ((XC & YC) == XC) { + // Results.push_back(Builder(XI, IC).And(YI).Eq(XI)()); - if ((XC & YC) == YC) { - Results.push_back(Builder(XI, IC).And(YI).Eq(YI)()); - } + // } - if ((XC | YC) == XC) { - Results.push_back(Builder(XI, IC).Or(YI).Eq(XI)()); - } + // if ((XC & YC) == YC) { + // auto W = XI->Width; + // Results.push_back(IC.getInst(Inst::KnownOnesP, W, {XI, YI})); + // } - if ((XC | YC) == YC) { - Results.push_back(Builder(XI, IC).Or(YI).Eq(YI)()); - } + // TODO guard + // Results.back()->Print(); + + // Results.push_back(IC.getInst(Inst::KnownZerosP, W, {XI, YI})); - // // Add C - // auto Diff = XC - YC; - // Results.push_back(Builder(XI, IC).Sub(Diff).Eq(YI)()); + // todo knownzerosp + + // if ((XC | YC) == XC) { + // Results.push_back(Builder(XI, IC).Or(YI).Eq(XI)()); + // } + + // if ((XC | YC) == YC) { + // Results.push_back(Builder(XI, IC).Or(YI).Eq(YI)()); + // } // Mul C if (C2 && YC!= 0 && XC.urem(YC) == 0) { auto Fact = XC.udiv(YC); - Results.push_back(Builder(YI, IC).Mul(Fact).Eq(XI)()); + if (Fact != 1) { + Results.push_back(Builder(YI, IC).Mul(Fact).Eq(XI)()); + } + } + + // Add C + auto Diff = XC - YC; + if (Diff != 0) { + Results.push_back(Builder(XI, IC).Sub(Diff).Eq(YI)()); } + if (C2 && XC != 0 && YC.urem(XC) == 0) { auto Fact = YC.udiv(XC); - Results.push_back(Builder(XI, IC).Mul(Fact).Eq(YI)()); + if (Fact != 1) { + Results.push_back(Builder(XI, IC).Mul(Fact).Eq(YI)()); + } } // TODO Check if this is too slow @@ -414,7 +457,22 @@ std::vector InferPotentialRelations( // Results.push_back(R); // } // llvm::errs() << "HERE: " << Results.size() << '\n'; - return FilterRelationsByValue(Results, CMap, CEX); + Results = FilterRelationsByValue(Results, CMap, CEX); + + if (LatticeChecks) { + // TODO Less brute force + for (auto &&[XI, XC] : CMap) { + for (auto &&[YI, YC] : CMap) { + if (XI == YI || XC.getBitWidth() != YC.getBitWidth()) { + continue; + } + Results.push_back(IC.getInst(Inst::KnownOnesP, 1, {XI, YI})); + Results.push_back(IC.getInst(Inst::KnownZerosP, 1, {XI, YI})); + } + } + } + + return Results; } std::set findConcreteConsts(Inst *I) { @@ -611,12 +669,9 @@ FirstValidCombination(ParsedReplacement Input, Clone.Mapping.RHS = nullptr; auto SOLVE = [&](ParsedReplacement P) -> bool { -// P.print(llvm::errs(), true); -// llvm::errs() << "\n"; - + // P.print(llvm::errs(), true); if (GEN) { Clone = Verify(P, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return true; } @@ -906,14 +961,18 @@ AugmentForSymDB(ParsedReplacement Original, InstContext &IC) { Input.Mapping.LHS->DemandedBits.setAllBits(); Input.Mapping.RHS->DemandedBits.setAllBits(); - Input.Mapping.LHS = Builder(Input.Mapping.LHS, IC).And(SymDFVar)(); - Input.Mapping.RHS = Builder(Input.Mapping.RHS, IC).And(SymDFVar)(); + auto W = Input.Mapping.LHS->Width; + + Input.Mapping.LHS = IC.getInst(Inst::DemandedMask, W, {Input.Mapping.LHS, SymDFVar}); + Input.Mapping.RHS = IC.getInst(Inst::DemandedMask, W, {Input.Mapping.RHS, SymDFVar}); + ConstMap.push_back({SymDFVar, DB}); } return {ConstMap, Input}; } -std::pair AugmentForSymKB(ParsedReplacement Original, InstContext &IC) { +std::pair +AugmentForSymKB(ParsedReplacement Original, InstContext &IC) { auto Input = Clone(Original, IC); ConstMapT ConstMap; std::vector Inputs; @@ -927,11 +986,12 @@ std::pair AugmentForSymKB(ParsedReplacement Origin if (I->KnownZeros != 0) { Inst *Zeros = IC.createVar(Width, "symDF_K0"); - Inst *AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(Width)); - Inst *NotZeros = IC.getInst(Inst::Xor, Width, - {Zeros, AllOnes}); - Inst *VarNotZero = IC.getInst(Inst::Or, Width, {I, NotZeros}); - Inst *ZeroBits = IC.getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); + // Inst *AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(Width)); + // Inst *NotZeros = IC.getInst(Inst::Xor, Width, + // {Zeros, AllOnes}); + // Inst *VarNotZero = IC.getInst(Inst::Or, Width, {I, NotZeros}); + // Inst *ZeroBits = IC.getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); + Inst *ZeroBits = IC.getInst(Inst::KnownZerosP, 1, {I, Zeros}); Input.PCs.push_back({ZeroBits, IC.getConst(llvm::APInt(1, 1))}); ConstMap.push_back({Zeros, I->KnownZeros}); I->KnownZeros = llvm::APInt(I->Width, 0); @@ -939,8 +999,9 @@ std::pair AugmentForSymKB(ParsedReplacement Origin if (I->KnownOnes != 0) { Inst *Ones = IC.createVar(Width, "symDF_K1"); - Inst *VarAndOnes = IC.getInst(Inst::And, Width, {I, Ones}); - Inst *OneBits = IC.getInst(Inst::Eq, 1, {VarAndOnes, Ones}); + // Inst *VarAndOnes = IC.getInst(Inst::And, Width, {I, Ones}); + // Inst *OneBits = IC.getInst(Inst::Eq, 1, {VarAndOnes, Ones}); + Inst *OneBits = IC.getInst(Inst::KnownOnesP, 1, {I, Ones}); Input.PCs.push_back({OneBits, IC.getConst(llvm::APInt(1, 1))}); ConstMap.push_back({Ones, I->KnownOnes}); I->KnownOnes = llvm::APInt(I->Width, 0); @@ -950,6 +1011,69 @@ std::pair AugmentForSymKB(ParsedReplacement Origin return {ConstMap, Input}; } +std::pair +AugmentForSymKBDB(ParsedReplacement Original, InstContext &IC) { + auto Input = Clone(Original, IC); + std::vector> ConstMap; + if (Input.Mapping.LHS->DemandedBits.getBitWidth() == Input.Mapping.LHS->Width && + !Input.Mapping.LHS->DemandedBits.isAllOnesValue()) { + auto DB = Input.Mapping.LHS->DemandedBits; + auto SymDFVar = IC.createVar(DB.getBitWidth(), "symDF_DB"); + // SymDFVar->Name = "symDF_DB"; + + SymDFVar->KnownOnes = llvm::APInt(DB.getBitWidth(), 0); + SymDFVar->KnownZeros = llvm::APInt(DB.getBitWidth(), 0); + // SymDFVar->Val = DB; + + Input.Mapping.LHS->DemandedBits.setAllBits(); + Input.Mapping.RHS->DemandedBits.setAllBits(); + + auto W = Input.Mapping.LHS->Width; + + Input.Mapping.LHS = IC.getInst(Inst::DemandedMask, W, {Input.Mapping.LHS, SymDFVar}); + Input.Mapping.RHS = IC.getInst(Inst::DemandedMask, W, {Input.Mapping.RHS, SymDFVar}); + + ConstMap.push_back({SymDFVar, DB}); + } + + std::vector Inputs; + findVars(Input.Mapping.LHS, Inputs); + + for (auto &&I : Inputs) { + auto Width = I->Width; + if (I->KnownZeros.getBitWidth() == I->Width && + I->KnownOnes.getBitWidth() == I->Width && + !(I->KnownZeros == 0 && I->KnownOnes == 0)) { + if (I->KnownZeros != 0) { + Inst *Zeros = IC.createVar(Width, "symDF_K0"); + + // Inst *AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(Width)); + // Inst *NotZeros = IC.getInst(Inst::Xor, Width, + // {Zeros, AllOnes}); + // Inst *VarNotZero = IC.getInst(Inst::Or, Width, {I, NotZeros}); + // Inst *ZeroBits = IC.getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); + Inst *ZeroBits = IC.getInst(Inst::KnownZerosP, 1, {I, Zeros}); + Input.PCs.push_back({ZeroBits, IC.getConst(llvm::APInt(1, 1))}); + ConstMap.push_back({Zeros, I->KnownZeros}); + I->KnownZeros = llvm::APInt(I->Width, 0); + } + + if (I->KnownOnes != 0) { + Inst *Ones = IC.createVar(Width, "symDF_K1"); + // Inst *VarAndOnes = IC.getInst(Inst::And, Width, {I, Ones}); + // Inst *OneBits = IC.getInst(Inst::Eq, 1, {VarAndOnes, Ones}); + Inst *OneBits = IC.getInst(Inst::KnownOnesP, 1, {I, Ones}); + Input.PCs.push_back({OneBits, IC.getConst(llvm::APInt(1, 1))}); + ConstMap.push_back({Ones, I->KnownOnes}); + I->KnownOnes = llvm::APInt(I->Width, 0); + } + } + } + + return {ConstMap, Input}; +} + + std::vector> InferSpecialConstExprsWithConcretes(std::vector RHS, const std::vector> &ConstMap, @@ -1152,7 +1276,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, CEX = {}; // FIXME : Figure out how to get CEX for symbolic dataflow } - auto Relations = InferPotentialRelations(ConstMap, IC, Input, CEX); + auto Relations = InferPotentialRelations(ConstMap, IC, Input, CEX, Nested); std::map JustLHSSymConstMap; @@ -1164,7 +1288,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, for (auto &&R : Relations) { Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); // Copy.print(llvm::errs(), true); - // llvm::errs() << "\n"; auto Clone = Verify(Copy, IC, S); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; @@ -1203,15 +1326,15 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, InferSpecialConstExprsAllSym(RHSFresh, ConstMap, IC, /*depth*/0); if (!UnitaryCandidates.empty()) { - - // if (DebugLevel > 4) { + // if (Nested && DebugLevel > 4) { // llvm::errs() << "Rels " << Relations.size() << "\n"; // llvm::errs() << "Unitary candidates: " << UnitaryCandidates[0].size() << "\n"; + // llvm::errs() << "FOO: " << UnitaryCandidates[0][0]->Name << "\n"; // } for (auto &&R : Relations) { Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - + // Input.print(llvm::errs(), true); auto Clone = FirstValidCombination(Input, RHSFresh, UnitaryCandidates, InstCache, IC, S, SymCS, true, false, false); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { @@ -1468,18 +1591,18 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto [SymDBConstMap, Augmented] = AugmentForSymDB(Input, IC); canTrySymDB = !SymDBConstMap.empty(); if (canTrySymDB) { - bool SymDFChanged = false; + // bool SymDFChanged = false; // Augmented.print(llvm::errs(), true); - auto Clone = Verify(Augmented, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - // Symbolic demanded bits can be unconstrained - return Clone; - } + // auto Clone = Verify(Augmented, IC, S); + // if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + // // Symbolic demanded bits can be unconstrained + // return Clone; + // } - auto Generalized = SuccessiveSymbolize(IC, S, Augmented, SymDFChanged, SymDBConstMap); - if (SymDFChanged) { - return Generalized; - } + // auto Generalized = SuccessiveSymbolize(IC, S, Augmented, SymDFChanged, SymDBConstMap); + // if (SymDFChanged) { + // return Generalized; + // } } Refresh("POP SYMDF_DB"); @@ -1488,20 +1611,21 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto [SymKBConstMap, Augmented] = AugmentForSymKB(Input, IC); canTrySymKB = !SymKBConstMap.empty(); - auto Clone = Verify(Augmented, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - // Symbolic known bits can be unconstrained - return Clone; - } + // auto Clone = Verify(Augmented, IC, S); + // if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + // // Symbolic known bits can be unconstrained + // return Clone; + // } - if (canTrySymKB) { - bool SymDFChanged = false; - auto Generalized = SuccessiveSymbolize(IC, S, Augmented, - SymDFChanged, SymKBConstMap); - if (SymDFChanged) { - return Generalized; - } - } + // if (canTrySymKB) { + // bool SymDFChanged = false; + // // Augmented.print(llvm::errs(), true); + // auto Generalized = SuccessiveSymbolize(IC, S, Augmented, + // SymDFChanged, SymKBConstMap); + // if (SymDFChanged) { + // return Generalized; + // } + // } } Refresh("POP SYMDF_KB"); @@ -1509,24 +1633,24 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (canTrySymDB && canTrySymKB) { Refresh("PUSH SYMDF_KB_DB"); - auto [CM1, Aug1] = AugmentForSymDB(Input, IC); - auto [CM2, Aug2] = AugmentForSymKB(Aug1, IC); + auto [CM, Aug] = AugmentForSymKBDB(Input, IC); + // auto [CM2, Aug2] = AugmentForSymKB(Aug1, IC); bool SymDFChanged = false; // Aug2.print(llvm::errs(), true); - for (auto P : CM1) { - CM2.push_back(P); - } + // for (auto P : CM1) { + // CM2.push_back(P); + // } - auto Clone = Verify(Aug2, IC, S); + auto Clone = Verify(Aug, IC, S); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { // Symbolic db+kb can be unconstrained // very unlikely? test if needed return Clone; } - auto Generalized = SuccessiveSymbolize(IC, S, Aug2, SymDFChanged, CM2); + auto Generalized = SuccessiveSymbolize(IC, S, Aug, SymDFChanged, CM); if (SymDFChanged) { return Generalized; } From ec0f96866abe7dd91ea69c7926d368ac49005f99 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 8 Mar 2023 20:46:03 -0700 Subject: [PATCH 141/165] foo --- tools/generalize.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 60a15637c..f2270c9e6 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -314,21 +314,21 @@ std::vector InferPotentialRelations( .Eq(llvm::APInt(XI->Width, 0))()); } - if (C2 && (XC & YC).eq(ZC)) { - Results.push_back(Builder(XI, IC).And(YI).Eq(ZI)()); - } + // if (C2 && (XC & YC).eq(ZC)) { + // Results.push_back(Builder(XI, IC).And(YI).Eq(ZI)()); + // } - if (C2 && (XC | YC).eq(ZC)) { - Results.push_back(Builder(XI, IC).Or(YI).Eq(ZI)()); - } + // if (C2 && (XC | YC).eq(ZC)) { + // Results.push_back(Builder(XI, IC).Or(YI).Eq(ZI)()); + // } - if (C2 && (XC ^ YC).eq(ZC)) { - Results.push_back(Builder(XI, IC).Xor(YI).Eq(ZI)()); - } + // if (C2 && (XC ^ YC).eq(ZC)) { + // Results.push_back(Builder(XI, IC).Xor(YI).Eq(ZI)()); + // } - if (C2 && (XC != 0 && YC != 0) && (XC + YC).eq(ZC)) { - Results.push_back(Builder(XI, IC).Add(YI).Eq(ZI)()); - } + // if (C2 && (XC != 0 && YC != 0) && (XC + YC).eq(ZC)) { + // Results.push_back(Builder(XI, IC).Add(YI).Eq(ZI)()); + // } // TODO Make width independent by using bitwidth insts if (C2 && (XC | YC | ~ZC).isAllOnesValue()) { From cf5d2584e4951831bbbf640ce52491a252c1da54 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 15 Mar 2023 03:14:29 -0600 Subject: [PATCH 142/165] foo --- include/souper/Inst/Inst.h | 2 - lib/Extractor/ExprBuilder.cpp | 16 +- lib/Infer/AliveDriver.cpp | 2 +- lib/Infer/SynthUtils.cpp | 9 - lib/Inst/Inst.cpp | 11 +- test/Generalize/addc.opt | 11 ++ test/Generalize/addshlsub.opt | 16 ++ test/Generalize/addsub.opt | 12 ++ test/Generalize/ctpop.opt | 16 ++ test/Generalize/fixit.opt | 42 ----- test/Generalize/leaf.opt | 22 --- test/Generalize/maskoff.opt | 13 ++ test/Generalize/multoshl.opt | 11 ++ test/Generalize/symbolize.opt | 21 --- test/lit.cfg | 1 + tools/generalize.cpp | 309 ++++++++++++++++++++++++++++++++-- tools/matcher-gen.cpp | 51 +++++- 17 files changed, 427 insertions(+), 138 deletions(-) create mode 100644 test/Generalize/addc.opt create mode 100644 test/Generalize/addshlsub.opt create mode 100644 test/Generalize/addsub.opt create mode 100644 test/Generalize/ctpop.opt delete mode 100644 test/Generalize/fixit.opt delete mode 100644 test/Generalize/leaf.opt create mode 100644 test/Generalize/maskoff.opt create mode 100644 test/Generalize/multoshl.opt delete mode 100644 test/Generalize/symbolize.opt diff --git a/include/souper/Inst/Inst.h b/include/souper/Inst/Inst.h index 860982e97..084ecb5f5 100644 --- a/include/souper/Inst/Inst.h +++ b/include/souper/Inst/Inst.h @@ -179,8 +179,6 @@ struct Inst : llvm::FoldingSetNode { static int getCost(Kind K); llvm::APInt KnownZeros; llvm::APInt KnownOnes; - Inst *SymKnownZeros = nullptr, *SymKnownOnes = nullptr; - Inst *SymZeroOf = nullptr, *SymOneOf = nullptr; bool NonZero; bool NonNegative; bool PowOfTwo; diff --git a/lib/Extractor/ExprBuilder.cpp b/lib/Extractor/ExprBuilder.cpp index 2287a226a..54016f5eb 100644 --- a/lib/Extractor/ExprBuilder.cpp +++ b/lib/Extractor/ExprBuilder.cpp @@ -344,21 +344,7 @@ Inst *ExprBuilder::getDataflowConditions(Inst *I) { Inst *OneBits = LIC->getInst(Inst::Eq, 1, {VarAndOnes, Ones}); Result = LIC->getInst(Inst::And, 1, {Result, OneBits}); } - - if (I->SymKnownZeros) { - Inst *AllOnes = LIC->getConst(llvm::APInt::getAllOnesValue(Width)); - Inst *NotZeros = LIC->getInst(Inst::Xor, Width, - {I->SymKnownZeros, AllOnes}); - 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}); - } - if (I->SymKnownOnes) { - Inst *VarAndOnes = LIC->getInst(Inst::And, Width, {I, I->SymKnownOnes}); - Inst *OneBits = LIC->getInst(Inst::Eq, 1, {VarAndOnes, I->SymKnownOnes}); - Result = LIC->getInst(Inst::And, 1, {Result, OneBits}); - } - + if (I->NonZero) { Inst *NonZeroBits = LIC->getInst(Inst::Ne, 1, {I, Zero}); Result = LIC->getInst(Inst::And, 1, {Result, NonZeroBits}); diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index 402df29ea..36df263b1 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -37,7 +37,7 @@ namespace { static llvm::cl::opt DisableUndefInput("alive-disable-undef-input", llvm::cl::desc("Assume inputs can not be undef (default = false)"), - llvm::cl::init(false)); + llvm::cl::init(true)); static llvm::cl::opt SkipAliveSolver("alive-skip-solver", llvm::cl::desc("Omit Alive solver calls for performance testing (default = false)"), diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index c45e1eb5d..1d11e8152 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -55,15 +55,6 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { PC.RHS = getInstCopy(PC.RHS, IC, InstCache, BlockCache, &ConstMap, false, false); } - for (auto &V : RHSVars) { - if (V->SymOneOf) { - InstCache[V->SymOneOf]->SymKnownOnes = InstCache[V]; - } - if (V->SymZeroOf) { - InstCache[V->SymZeroOf]->SymKnownZeros = InstCache[V]; - } - } - return In; } diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index 7f448e39c..e0eb46566 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -198,12 +198,7 @@ std::string ReplacementContext::printInstImpl(Inst *I, llvm::raw_ostream &Out, if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) Out << " (knownBits=" << Inst::getKnownBitsString(I->KnownZeros, I->KnownOnes) << ")"; - if (I->SymKnownZeros) { - Out << "(knownZeros=%" << I->SymKnownZeros->Name << ")"; - } - if (I->SymKnownOnes) { - Out << "(knownOnes=%" << I->SymKnownOnes->Name << ")"; - } + if (I->NonNegative) Out << " (nonNegative)"; if (I->Negative) @@ -1275,10 +1270,6 @@ Inst *souper::getInstCopy(Inst *I, InstContext &IC, assert(Copy); InstCache[I] = Copy; Copy->Name = I->Name; - Copy->SymKnownOnes = I->SymKnownOnes; - Copy->SymKnownZeros = I->SymKnownZeros; - Copy->SymOneOf = I->SymOneOf; - Copy->SymZeroOf = I->SymZeroOf; return Copy; } diff --git a/test/Generalize/addc.opt b/test/Generalize/addc.opt new file mode 100644 index 000000000..a14289991 --- /dev/null +++ b/test/Generalize/addc.opt @@ -0,0 +1,11 @@ +; RUN: %generalize -basic -no-width -souper-debug-level=2 %s > /dev/null 2>%t +; RUN: %FileCheck %s < %t + +%x:i8 = var +%foo = add %x, 2 +%bar = sub %foo, %x +infer %bar +result 2:i8 +; CHECK:(x:i8 + C1:i8) - x +; CHECK: => +; CHECK:C1 diff --git a/test/Generalize/addshlsub.opt b/test/Generalize/addshlsub.opt new file mode 100644 index 000000000..583d36604 --- /dev/null +++ b/test/Generalize/addshlsub.opt @@ -0,0 +1,16 @@ +; RUN: %generalize -basic -no-width -souper-debug-level=2 %s > /dev/null 2>%t +; RUN: %FileCheck %s < %t + +%v0:i32 = var ; v0 +%1:i32 = add 4:i32, %v0 +%2:i32 = shl %1, 2:i32 +%3:i32 = sub %2, 16:i32 +infer %3 +%4:i32 = shl %v0, 2:i32 +result %4 + +; CHECK: C3:i32 == (C1:i32 << C2:i32) +; CHECK: |= +; CHECK: ((v0:i32 + C1) << C2) - C3 +; CHECK: => +; CHECK: v0 << C2 \ No newline at end of file diff --git a/test/Generalize/addsub.opt b/test/Generalize/addsub.opt new file mode 100644 index 000000000..28c1ec4c5 --- /dev/null +++ b/test/Generalize/addsub.opt @@ -0,0 +1,12 @@ +; RUN: %generalize -basic -no-width -souper-debug-level=2 %s > /dev/null 2>%t +; RUN: %FileCheck %s < %t + +%x:i8 = var +%foo = add %x, 42 +%bar = sub %foo, 31 +infer %bar +%xip = add %x, 11 +result %xip +; CHECK: (x:i8 + C1:i8) - C2:i8 +; CHECK: => +; CHECK: x + (C1 - C2) diff --git a/test/Generalize/ctpop.opt b/test/Generalize/ctpop.opt new file mode 100644 index 000000000..471aa58a2 --- /dev/null +++ b/test/Generalize/ctpop.opt @@ -0,0 +1,16 @@ +; RUN: %generalize -basic -no-width -souper-debug-level=2 %s > /dev/null 2>%t +; RUN: %FileCheck %s < %t + +%v0:i8 = var ; v0 +%1:i8 = ctpop %v0 +%2:i1 = ult 7:i8, %1 +infer %2 +%3:i1 = eq 255:i8, %v0 +result %3 + +; CHECK: C1:i8 == (width(C1) - 1) +; CHECK: |= +; CHECK: C1 +; CHECK: v0 == 0xFF +; TODO: synthesize independent fn instead of 255 \ No newline at end of file diff --git a/test/Generalize/fixit.opt b/test/Generalize/fixit.opt deleted file mode 100644 index 782c10e56..000000000 --- a/test/Generalize/fixit.opt +++ /dev/null @@ -1,42 +0,0 @@ -; REQUIRES: solver, synthesis -; RUN: %generalize -fixit %s | %souper-check > %t -; RUN: %FileCheck %s < %t - -%x:i8 = var -%y:i8 = var -%z = add %x, %y -%t = add %z, 42 -%u = sub %t, %y -infer %u -%v = add %x, 42 -result %v -;CHECK: LGTM - -%x:i8 = var -%y:i8 = var -%t = add %x, 42 -%u = sub %t, %y -infer %u -%v = add %x, 42 -result %v -;CHECK: LGTM - -%x:i8 = var -%y:i8 = var -%t = and %x, 137 -%u = xor %t, %y -infer %u -%v = or %x, %y -result %v -;CHECK: LGTM -;CHECK-NEXT: LGTM - -%x:i8 = var -%y:i8 = var -%t = or %x, 42 -%u = and %t, %y -infer %u -%v = and %x, %y -result %v -;CHECK: LGTM -;CHECK-NEXT: LGTM diff --git a/test/Generalize/leaf.opt b/test/Generalize/leaf.opt deleted file mode 100644 index c3ac27865..000000000 --- a/test/Generalize/leaf.opt +++ /dev/null @@ -1,22 +0,0 @@ -; REQUIRES: solver, synthesis -; RUN: %generalize -remove-leaf %s | %souper-check > %t -; RUN: %FileCheck %s < %t - -%x:i8 = var -%y:i8 = var -%masked = and %x, 3 -%and = and %masked, %y -%foo = lshr %and, 2 -infer %and -result 0:i8 -; CHECK: LGTM -; CHECK: LGTM - -%x:i8 = var -%y:i8 = var -%a = and %x, 15 -%b = and %y, 240 -%foo = or %a, %b -infer %foo -result 0:i8 -; CHECK: LGTM diff --git a/test/Generalize/maskoff.opt b/test/Generalize/maskoff.opt new file mode 100644 index 000000000..b2d11c245 --- /dev/null +++ b/test/Generalize/maskoff.opt @@ -0,0 +1,13 @@ +; RUN: %generalize -basic -no-width -souper-debug-level=2 %s > /dev/null 2>%t +; RUN: %FileCheck %s < %t + +%0:i32 = var +%1:i32 = shl %0, 12:i32 +%2:i32 = lshr %1, 12:i32 +%3:i32 = and 1048575:i32, %0 +cand %2 %3 + + +; CHECK: (v0:i32 << C1:i32) >> C1 +; CHECK: => +; CHECK: v0 & (-1 >> C1) \ No newline at end of file diff --git a/test/Generalize/multoshl.opt b/test/Generalize/multoshl.opt new file mode 100644 index 000000000..458a65d71 --- /dev/null +++ b/test/Generalize/multoshl.opt @@ -0,0 +1,11 @@ +; RUN: %generalize -basic -no-width -souper-debug-level=2 %s > /dev/null 2>%t +; RUN: %FileCheck %s < %t + +%x:i8 = var +%y = mul %x, 2 +%z = shl %x, 1 +cand %y %z + +; CHECK: x:i8 * C1:i8 (powerOfTwo) +; CHECK: => +; CHECK: x << logb(C1) \ No newline at end of file diff --git a/test/Generalize/symbolize.opt b/test/Generalize/symbolize.opt deleted file mode 100644 index 99d9277dc..000000000 --- a/test/Generalize/symbolize.opt +++ /dev/null @@ -1,21 +0,0 @@ -; REQUIRES: solver, synthesis -; RUN: %generalize -symbolize --souper-synthesize-freeze=false --generalization-num-results=2 %s | %souper-check > %t -; RUN: %FileCheck %s < %t - -%x:i8 = var -%foo = add %x, 2 -%bar = sub %foo, %x -infer %bar -result 2:i8 -;CHECK: LGTM -;CHECK: LGTM - -%x:i8 = var -%foo = add %x, 42 -%bar = sub %foo, 31 -infer %bar -%xip = add %x, 11 -result %xip -;CHECK: LGTM -;CHECK: LGTM -;CHECK: LGTM diff --git a/test/lit.cfg b/test/lit.cfg index a8878a934..c20888050 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -26,6 +26,7 @@ else: config.substitutions.append(('%pass', config.builddir + '/libsouperPass.so')) config.substitutions.append(('%souper', config.builddir + '/souper')) config.substitutions.append(('%souper-check', config.builddir + '/souper-check')) +config.substitutions.append(('%generalize', config.builddir + '/generalize')) config.substitutions.append(('%souper2llvm', config.builddir + '/souper2llvm')) config.substitutions.append(('%sclang', config.builddir + '/sclang')) config.substitutions.append(('%sclang\+\+', config.builddir + '/sclang++')) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index f2270c9e6..0899f1fa1 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -16,6 +16,7 @@ #include "souper/Tool/GetSolver.h" #include "souper/Util/DfaUtils.h" #include +#include using namespace llvm; using namespace souper; @@ -314,6 +315,20 @@ std::vector InferPotentialRelations( .Eq(llvm::APInt(XI->Width, 0))()); } + // TODO Make width independent by using bitwidth insts + if (C2 && (XC | YC | ~ZC).isAllOnesValue()) { + Results.push_back(Builder(XI, IC).Or(YI).Or(Builder(ZI, IC).Flip()) + .Eq(llvm::APInt::getAllOnesValue(XI->Width))()); + } + + if (XC << YC == ZC) { + Results.push_back(Builder(XI, IC).Shl(YI).Eq(ZI)()); + } + + if (XC.lshr(YC) == ZC) { + Results.push_back(Builder(XI, IC).LShr(YI).Eq(ZI)()); + } + // if (C2 && (XC & YC).eq(ZC)) { // Results.push_back(Builder(XI, IC).And(YI).Eq(ZI)()); // } @@ -330,11 +345,6 @@ std::vector InferPotentialRelations( // Results.push_back(Builder(XI, IC).Add(YI).Eq(ZI)()); // } - // TODO Make width independent by using bitwidth insts - if (C2 && (XC | YC | ~ZC).isAllOnesValue()) { - Results.push_back(Builder(XI, IC).Or(YI).Or(Builder(ZI, IC).Flip()) - .Eq(llvm::APInt::getAllOnesValue(XI->Width))()); - } } } } @@ -386,10 +396,10 @@ std::vector InferPotentialRelations( } // Add C - auto Diff = XC - YC; - if (Diff != 0) { - Results.push_back(Builder(XI, IC).Sub(Diff).Eq(YI)()); - } + // auto Diff = XC - YC; + // if (Diff != 0) { + // Results.push_back(Builder(XI, IC).Sub(Diff).Eq(YI)()); + // } if (C2 && XC != 0 && YC.urem(XC) == 0) { auto Fact = YC.udiv(XC); @@ -1011,6 +1021,14 @@ AugmentForSymKB(ParsedReplacement Original, InstContext &IC) { return {ConstMap, Input}; } +// // Harvest synthesis sketch from LHS +// std::function)> GetSketch(Inst *LHS) { +// std::vector Inputs; +// findVars(LHS, Inputs); + + +// } + std::pair AugmentForSymKBDB(ParsedReplacement Original, InstContext &IC) { auto Input = Clone(Original, IC); @@ -1161,6 +1179,11 @@ void findDangerousConstants(Inst *I, std::set &Results) { } } +struct GeneralizationProblem { + ParsedReplacement Input; + +}; + // Assuming the input has leaves pruned and preconditions weakened ParsedReplacement SuccessiveSymbolize(InstContext &IC, Solver *S, ParsedReplacement Input, bool &Changed, @@ -1358,6 +1381,18 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } + + for (auto &&R : ConstantLimits) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + // Input.print(llvm::errs(), true); + Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, + InstCache, IC, S, SymCS, true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + Input.PCs.pop_back(); + } + } Refresh("Special expressions, no constants"); @@ -1781,6 +1816,252 @@ ParsedReplacement ReduceBasic(InstContext &IC, return Input; } +struct InfixPrinter { + InfixPrinter(ParsedReplacement P_) : P(P_) { + varnum = 0; + std::vector NewPCs; + for (auto &&PC : P.PCs) { + countUses(PC.LHS); + countUses(PC.RHS); + if (!registerSymDFVars(PC.LHS)) { + NewPCs.push_back(PC); + } + countUses(P.Mapping.LHS); + countUses(P.Mapping.RHS); + } + P.PCs = NewPCs; + registerSymDBVar(); + } + + void registerSymDBVar() { + if (P.Mapping.LHS->K == Inst::DemandedMask) { + Syms[P.Mapping.LHS->Ops[1]] = "@db"; + assert(P.Mapping.RHS->K == Inst::DemandedMask && "Expected RHS to be a demanded mask."); + assert(P.Mapping.LHS->Ops[1] == P.Mapping.RHS->Ops[1] && "Expected same mask."); + P.Mapping.LHS = P.Mapping.LHS->Ops[0]; + P.Mapping.RHS = P.Mapping.RHS->Ops[0]; + } + } + + bool registerSymDFVars(Inst *I) { + if (I->K == Inst::KnownOnesP && I->Ops[0]->K == Inst::Var && + I->Ops[1]->Name.starts_with("sym")) { + Syms[I->Ops[1]] = I->Ops[0]->Name + ".k1"; + // VisitedVars.insert(I->Ops[1]->Name); + return true; + } + if (I->K == Inst::KnownZerosP && I->Ops[0]->K == Inst::Var && + I->Ops[1]->Name.starts_with("sym")) { + Syms[I->Ops[1]] = I->Ops[0]->Name + ".k0"; + // VisitedVars.insert(I->Ops[1]->Name); + return true; + } + return false; + } + + void countUses(Inst *I) { + for (auto &&Op : I->Ops) { + if (Op->K != Inst::Var && Op->K != Inst::Const) { + UseCount[Op]++; + } + countUses(Op); + } + } + + template + void operator()(Stream &S) { + if (!P.PCs.empty()) { + printPCs(S); + S << "\n |= \n"; + } + S << printInst(P.Mapping.LHS, S, true); + if (!P.Mapping.LHS->DemandedBits.isAllOnesValue()) { + S << " (" << "demandedBits=" + << Inst::getDemandedBitsString(P.Mapping.LHS->DemandedBits) + << ")"; + } + S << "\n =>\n"; + + S << printInst(P.Mapping.RHS, S, true); + } + + template + std::string printInst(Inst *I, Stream &S, bool Root = false) { + if (Syms.count(I)) { + return Syms[I]; + } + + // x ^ -1 => ~x + if (I->K == Inst::Xor && I->Ops[1]->K == Inst::Const && + I->Ops[1]->Val.isAllOnesValue()) { + return "~" + printInst(I->Ops[0], S); + } + if (I->K == Inst::Xor && I->Ops[0]->K == Inst::Const && + I->Ops[0]->Val.isAllOnesValue()) { + return "~" + printInst(I->Ops[1], S); + } + + + if (UseCount[I] > 1) { + std::string Name = "var" + std::to_string(varnum++); + Syms[I] = Name; + S << "let " << Name << " = "; + } + + if (I->K == Inst::Const) { + if (I->Val.ule(16)) { + return I->Val.toString(10, false); + } else { + return "0x" + I->Val.toString(16, false); + } + } else if (I->K == Inst::Var) { + auto Name = I->Name; + if (isDigit(Name[0])) { + Name = "x" + Name; + } + if (I->Name.starts_with("symconst_")) { + Name = "C" + I->Name.substr(9); + } + if (VisitedVars.count(I->Name)) { + return Name; + } else { + VisitedVars.insert(I->Name); + Inst::getKnownBitsString(I->KnownZeros, I->KnownOnes); + + std::string Buf; + llvm::raw_string_ostream Out(Buf); + + if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) + Out << " (knownBits=" << Inst::getKnownBitsString(I->KnownZeros, I->KnownOnes) + << ")"; + if (I->NonNegative) + Out << " (nonNegative)"; + if (I->Negative) + Out << " (negative)"; + if (I->NonZero) + Out << " (nonZero)"; + if (I->PowOfTwo) + Out << " (powerOfTwo)"; + if (I->NumSignBits > 1) + Out << " (signBits=" << I->NumSignBits << ")"; + if (!I->Range.isFullSet()) + Out << " (range=[" << I->Range.getLower() + << "," << I->Range.getUpper() << "))"; + return Name + ":i" + std::to_string(I->Width) + Out.str(); + } + } else { + std::string Op; + switch (I->K) { + case Inst::Add: Op = "+"; break; + case Inst::Sub: Op = "-"; break; + case Inst::Mul: Op = "*"; break; + case Inst::UDiv: Op = "/u"; break; + case Inst::SDiv: Op = "/s"; break; + case Inst::URem: Op = "\%u"; break; + case Inst::SRem: Op = "\%s"; break; + case Inst::And: Op = "&"; break; + case Inst::Or: Op = "|"; break; + case Inst::Xor: Op = "^"; break; + case Inst::Shl: Op = "<<"; break; + case Inst::LShr: Op = ">>"; break; + case Inst::AShr: Op = ">>"; break; + case Inst::Eq: Op = "=="; break; + case Inst::Ne: Op = "!="; break; + case Inst::Ult: Op = "K); break; + } + + std::string Result; + + std::vector Ops = I->orderedOps(); + + if (Inst::isCommutative(I->K)) { + std::sort(Ops.begin(), Ops.end(), [](Inst *A, Inst *B) { + if (A->K == Inst::Const) { + return false; // c OP expr + } else if (B->K == Inst::Const) { + return true; // expr OP c + } else if (A->K == Inst::Var && B->K != Inst::Var) { + return true; // var OP expr + } else if (A->K != Inst::Var && B->K == Inst::Var) { + return false; // expr OP var + } else if (A->K == Inst::Var && B->K == Inst::Var) { + return A->Name > B->Name; // Tends to put vars before symconsts + } else { + return A->K < B->K; // expr OP expr + } + }); + } + + if (Ops.size() == 2) { + auto Meat = printInst(Ops[0], S) + " " + Op + " " + printInst(Ops[1], S); + Result = Root ? Meat : "(" + Meat + ")"; + } else if (Ops.size() == 1) { + Result = Op + "(" + printInst(Ops[0], S) + ")"; + } + else { + std::string Ret = Root ? "" : "("; + Ret += Op; + Ret += " "; + for (auto &&Op : Ops) { + Ret += printInst(Op, S) + " "; + } + while (Ret.back() == ' ') { + Ret.pop_back(); + } + if (!Root) { + Ret += ")"; + } + Result = Ret; + } + if (UseCount[I] > 1) { + S << Result << ";\n"; + return Syms[I]; + } else { + return Result; + } + } + } + + template + void printPCs(Stream &S) { + bool first = true; + for (auto &&PC : P.PCs) { + // if (PC.LHS->K == Inst::KnownOnesP || PC.LHS->K == Inst::KnownZerosP) { + // continue; + // } + if (first) { + first = false; + } else { + S << " && \n"; + } + if (PC.RHS->K == Inst::Const && PC.RHS->Val == 0) { + S << "!(" << printInst(PC.LHS, S, true) << ")"; + } else if (PC.RHS->K == Inst::Const && PC.RHS->Val == 1) { + S << printInst(PC.LHS, S, true); + } else { + S << printInst(PC.LHS, S, true) << " == " << printInst(PC.RHS, S); + } + } + } + + ParsedReplacement P; + std::set VisitedVars; + std::map Syms; + size_t varnum; + std::map UseCount; +}; + +template +Stream &operator<<(Stream &S, InfixPrinter IP) { + IP(S); + return S; +} + + int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); KVStore *KV = 0; @@ -1812,11 +2093,14 @@ int main(int argc, char **argv) { if (Basic) { ParsedReplacement Result = ReduceBasic(IC, S.get(), Input); if (!JustReduce) { + bool Changed = false; size_t MaxTries = 1; // Increase this if we ever run with 10/100x timeout. do { if (!OnlyWidth) { - Result = ReduceBasic(IC, S.get(), Input); + if (Changed) { + Result = ReduceBasic(IC, S.get(), Result); + } Result = SuccessiveSymbolize(IC, S.get(), Result, Changed); } if (!NoWidth) { @@ -1833,6 +2117,11 @@ int main(int argc, char **argv) { Result.printLHS(llvm::outs(), RC, true); Result.printRHS(llvm::outs(), RC, true); llvm::outs() << "\n"; + + if (DebugLevel > 1) { + llvm::errs() << "\n\tInput:\n\n"; + llvm::errs() << InfixPrinter(Input) << "\n\n\tGeneralized:\n\n" << InfixPrinter(Result); + } } continue; } diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 70ce059ac..92a1cb9d5 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -192,6 +192,14 @@ struct DB : public Constraint { std::string Val; }; +struct SymDB : public Constraint { + SymDB(std::string Name_) : Name(Name_) {} + std::string print() override { + return "util::symdb(DB, I, " + Name + ")"; + } + std::string Name; +}; + struct K0 : public Constraint { K0(std::string Name_, std::string Val_) : Name(Name_), Val(Val_) {} std::string print() override { @@ -491,6 +499,11 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms, bool IsRoot = false) } } + if (IsRoot && I->K == Inst::Var) { + Out << "m_Value(" << Syms[I].front() << ")"; + return true; + } + auto It = MatchOps.find(I->K); if (It == MatchOps.end()) { llvm::errs() << "\nUnimplemented matcher:" << Inst::getKindName(I->K) << "\n"; @@ -695,18 +708,31 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn Out << "if (" << F << "match(I, "; SymbolTable SymsCopy = Syms; - if (!GenLHSMatcher(Input.Mapping.LHS, Out, SymsCopy, /*IsRoot = */true)) { - return false; + if (Input.Mapping.LHS->K == Inst::DemandedMask) { + if (!GenLHSMatcher(Input.Mapping.LHS->Ops[0], Out, SymsCopy, /*IsRoot = */true)) { + return false; + } + } else { + if (!GenLHSMatcher(Input.Mapping.LHS, Out, SymsCopy, /*IsRoot = */true)) { + return false; + } } Out << ")) {\n"; // Input.print(llvm::errs(), true); - + Inst *DemandedMask = nullptr; + if (Input.Mapping.LHS->K == Inst::DemandedMask) { + DemandedMask = Input.Mapping.LHS->Ops[1]; + Syms.Constraints.push_back(new SymDB(Syms[Input.Mapping.LHS->Ops[1]].back())); + } Syms.GenVarEqConstraints(); Syms.GenVarPropConstraints(Input.Mapping.LHS, WidthIndependent); Syms.GenDomConstraints(Input.Mapping.RHS); Syms.GenDFConstraints(Input.Mapping.LHS); - if (!Syms.GenPCConstraints(Input.PCs)) return false; + if (!Syms.GenPCConstraints(Input.PCs)) { + llvm::errs() << "Failed to generate PC constraints.\n"; + return false; + } Syms.PrintConstraintsPre(Out); Out << " St.hit(" << OptID << ", " << prof << ");\n"; @@ -715,6 +741,9 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn if (Syms.find(Input.Mapping.RHS) != Syms.end()) { Out << " return " << Syms[Input.Mapping.RHS][0] << ";"; + } else if (Input.Mapping.RHS->K == Inst::DemandedMask && Syms.find(Input.Mapping.RHS->Ops[0]) != Syms.end()) { + assert(DemandedMask == Input.Mapping.RHS->Ops[1] && "DemandedMask mismatch"); + Out << " return " << Syms[Input.Mapping.RHS->Ops[0]][0] << ";"; } else if (Input.Mapping.RHS->K == Inst::Const) { Out << " APInt Result(" << Input.Mapping.RHS->Width <<", " @@ -722,8 +751,15 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn Out << " return ConstantInt::get(TheContext, Result);"; } else { Out << " return "; - if (!GenRHSCreator(Input.Mapping.RHS, Out, Syms)) { - return false; + if (Input.Mapping.RHS->K == Inst::DemandedMask) { + assert(DemandedMask == Input.Mapping.RHS->Ops[1] && "DemandedMask mismatch"); + if (!GenRHSCreator(Input.Mapping.RHS->Ops[0], Out, Syms)) { + return false; + } + } else { + if (!GenRHSCreator(Input.Mapping.RHS, Out, Syms)) { + return false; + } } Out << ";"; } @@ -747,11 +783,14 @@ std::string getLLVMInstKindName(Inst::Kind K) { bool PCHasVar(const ParsedReplacement &Input) { std::vector Vars; for (auto &&PC : Input.PCs) { + if (PC.LHS->K == Inst::KnownOnesP || PC.LHS->K == Inst::KnownZerosP) + continue; findVars(PC.LHS, Vars); findVars(PC.RHS, Vars); } for (auto &&V : Vars) { + // llvm::errs() << V->Name << "\n"; if (!V->Name.starts_with("sym")) { return true; } From f45da2b13572340e7280aaaf33de4c878309677d Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 16 Mar 2023 13:58:46 -0600 Subject: [PATCH 143/165] foo --- lib/Infer/AliveDriver.cpp | 9 + lib/Infer/SynthUtils.cpp | 31 +- tools/generalize.cpp | 795 +++++++++++++++++++++++--------------- 3 files changed, 512 insertions(+), 323 deletions(-) diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index 36df263b1..0e6b9cb7b 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -197,6 +197,14 @@ class FunctionBuilder { identifiers[x] = ptr; return ptr; } + if (x.find("var_sym") != std::string::npos) { + auto i = std::make_unique(t, std::move(x)); + auto ptr = i.get(); + F.addInput(std::move(i)); + // FIXME: force non poison + identifiers[x] = ptr; + return ptr; + } auto i = std::make_unique(t, std::move(x)); auto ptr = i.get(); F.addInput(std::move(i)); @@ -626,6 +634,7 @@ bool souper::AliveDriver::translateAndCache(const souper::Inst *I, switch (I->K) { case souper::Inst::Var: { ExprCache[I] = Builder.var(t, Name); + // llvm::errs() << "Var: " << Name << "\n"; if (IsLHS) { Inputs.push_back({I, ExprCache[I]}); } diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index 1d11e8152..fedc94bdb 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -86,25 +86,26 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { // Returns clone if verified, nullptrs if not ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { - if (Input.PCs.empty()) { - SynthesisContext SC{IC, S->getSMTLIBSolver(), Input.Mapping.LHS, nullptr, - Input.PCs,Input.BPCs, false, 15}; - std::vector Vars; - findVars(Input.Mapping.LHS, Vars); - - PruningManager Pruner(SC, Vars, 0); - Pruner.init(); - - if (Pruner.isInfeasible(Input.Mapping.RHS, 0)) { - Input.Mapping.LHS = nullptr; - Input.Mapping.RHS = nullptr; - return Input; - } - } + // if (Input.PCs.empty()) { + // SynthesisContext SC{IC, S->getSMTLIBSolver(), Input.Mapping.LHS, nullptr, + // Input.PCs,Input.BPCs, false, 15}; + // std::vector Vars; + // findVars(Input.Mapping.LHS, Vars); + + // PruningManager Pruner(SC, Vars, 0); + // Pruner.init(); + + // if (Pruner.isInfeasible(Input.Mapping.RHS, 0)) { + // Input.Mapping.LHS = nullptr; + // Input.Mapping.RHS = nullptr; + // return Input; + // } + // } Input = Clone(Input, IC); std::set ConstSet; souper::getConstants(Input.Mapping.RHS, ConstSet); + souper::getConstants(Input.Mapping.LHS, ConstSet); if (!ConstSet.empty()) { std::map ResultConstMap; ConstantSynthesis CS; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 0899f1fa1..70531b60a 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -17,6 +17,7 @@ #include "souper/Util/DfaUtils.h" #include #include +#include using namespace llvm; using namespace souper; @@ -125,6 +126,377 @@ bool All(const C &c, F f) { return true; } +size_t InferWidth(Inst::Kind K, const std::vector &Ops) { + switch (K) { + case Inst::KnownOnesP: + case Inst::KnownZerosP: + case Inst::Slt: + case Inst::Sle: + case Inst::Ult: + case Inst::Ule: return 1; + default: return Ops[0]->Width; + } +} + +struct InfixPrinter { + InfixPrinter(ParsedReplacement P_, bool ShowImplicitWidths = true) + : P(P_), ShowImplicitWidths(ShowImplicitWidths) { + varnum = 0; + std::vector NewPCs; + for (auto &&PC : P.PCs) { + countUses(PC.LHS); + countUses(PC.RHS); + if (!registerSymDFVars(PC.LHS)) { + NewPCs.push_back(PC); + } + countUses(P.Mapping.LHS); + countUses(P.Mapping.RHS); + } + P.PCs = NewPCs; + registerSymDBVar(); + registerWidthConstraints(); + } + + void registerWidthConstraints() { + for (auto &&PC : P.PCs) { + if (PC.LHS->K == Inst::Eq && PC.LHS->Ops[0]->K == Inst::BitWidth) { + // PC.LHS looks like (width %x) == 32 + WidthConstraints[PC.LHS->Ops[0]->Ops[0]] = PC.LHS->Ops[1]->Val.getZExtValue(); + } + } + } + + void registerSymDBVar() { + if (P.Mapping.LHS->K == Inst::DemandedMask) { + Syms[P.Mapping.LHS->Ops[1]] = "@db"; + assert(P.Mapping.RHS->K == Inst::DemandedMask && "Expected RHS to be a demanded mask."); + assert(P.Mapping.LHS->Ops[1] == P.Mapping.RHS->Ops[1] && "Expected same mask."); + P.Mapping.LHS = P.Mapping.LHS->Ops[0]; + P.Mapping.RHS = P.Mapping.RHS->Ops[0]; + } + } + + bool registerSymDFVars(Inst *I) { + if (I->K == Inst::KnownOnesP && I->Ops[0]->K == Inst::Var && + I->Ops[1]->Name.starts_with("sym")) { + Syms[I->Ops[1]] = I->Ops[0]->Name + ".k1"; + // VisitedVars.insert(I->Ops[1]->Name); + return true; + } + if (I->K == Inst::KnownZerosP && I->Ops[0]->K == Inst::Var && + I->Ops[1]->Name.starts_with("sym")) { + Syms[I->Ops[1]] = I->Ops[0]->Name + ".k0"; + // VisitedVars.insert(I->Ops[1]->Name); + return true; + } + return false; + } + + void countUses(Inst *I) { + for (auto &&Op : I->Ops) { + if (Op->K != Inst::Var && Op->K != Inst::Const) { + UseCount[Op]++; + } + countUses(Op); + } + } + + template + void operator()(Stream &S) { + if (!P.PCs.empty()) { + printPCs(S); + S << "\n |= \n"; + } + S << printInst(P.Mapping.LHS, S, true); + if (!P.Mapping.LHS->DemandedBits.isAllOnesValue()) { + S << " (" << "demandedBits=" + << Inst::getDemandedBitsString(P.Mapping.LHS->DemandedBits) + << ")"; + } + S << "\n =>\n"; + + S << printInst(P.Mapping.RHS, S, true) << "\n"; + } + + template + std::string printInst(Inst *I, Stream &S, bool Root = false) { + if (Syms.count(I)) { + return Syms[I]; + } + + // x ^ -1 => ~x + if (I->K == Inst::Xor && I->Ops[1]->K == Inst::Const && + I->Ops[1]->Val.isAllOnesValue()) { + return "~" + printInst(I->Ops[0], S); + } + if (I->K == Inst::Xor && I->Ops[0]->K == Inst::Const && + I->Ops[0]->Val.isAllOnesValue()) { + return "~" + printInst(I->Ops[1], S); + } + + + if (UseCount[I] > 1) { + std::string Name = "var" + std::to_string(varnum++); + Syms[I] = Name; + S << "let " << Name << " = "; + } + + if (I->K == Inst::Const) { + if (I->Val.ule(16)) { + return I->Val.toString(10, false); + } else { + return "0x" + I->Val.toString(16, false); + } + } else if (I->K == Inst::Var) { + auto Name = I->Name; + if (isDigit(Name[0])) { + Name = "x" + Name; + } + if (I->Name.starts_with("symconst_")) { + Name = "C" + I->Name.substr(9); + } + if (VisitedVars.count(I->Name)) { + return Name; + } else { + VisitedVars.insert(I->Name); + Inst::getKnownBitsString(I->KnownZeros, I->KnownOnes); + + std::string Buf; + llvm::raw_string_ostream Out(Buf); + + if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) + Out << " (knownBits=" << Inst::getKnownBitsString(I->KnownZeros, I->KnownOnes) + << ")"; + if (I->NonNegative) + Out << " (nonNegative)"; + if (I->Negative) + Out << " (negative)"; + if (I->NonZero) + Out << " (nonZero)"; + if (I->PowOfTwo) + Out << " (powerOfTwo)"; + if (I->NumSignBits > 1) + Out << " (signBits=" << I->NumSignBits << ")"; + if (!I->Range.isFullSet()) + Out << " (range=[" << I->Range.getLower() + << "," << I->Range.getUpper() << "))"; + + std::string W = ShowImplicitWidths ? ":i" + std::to_string(I->Width) : ""; + + if (WidthConstraints.count(I)) { + W = ":i" + std::to_string(WidthConstraints[I]); + } + + return Name + W + Out.str(); + } + } else { + std::string Op; + switch (I->K) { + case Inst::Add: Op = "+"; break; + case Inst::AddNSW: Op = "+nsw"; break; + case Inst::AddNUW: Op = "+nuw"; break; + case Inst::AddNW: Op = "+nw"; break; + case Inst::Sub: Op = "-"; break; + case Inst::SubNSW: Op = "-nsw"; break; + case Inst::SubNUW: Op = "-nuw"; break; + case Inst::SubNW: Op = "-nw"; break; + case Inst::Mul: Op = "*"; break; + case Inst::MulNSW: Op = "*nsw"; break; + case Inst::MulNUW: Op = "*nuw"; break; + case Inst::MulNW: Op = "*nw"; break; + case Inst::UDiv: Op = "/u"; break; + case Inst::SDiv: Op = "/s"; break; + case Inst::URem: Op = "\%u"; break; + case Inst::SRem: Op = "\%s"; break; + case Inst::And: Op = "&"; break; + case Inst::Or: Op = "|"; break; + case Inst::Xor: Op = "^"; break; + case Inst::Shl: Op = "<<"; break; + case Inst::ShlNSW: Op = "<K); break; + } + + std::string Result; + + std::vector Ops = I->orderedOps(); + + if (Inst::isCommutative(I->K)) { + std::sort(Ops.begin(), Ops.end(), [](Inst *A, Inst *B) { + if (A->K == Inst::Const) { + return false; // c OP expr + } else if (B->K == Inst::Const) { + return true; // expr OP c + } else if (A->K == Inst::Var && B->K != Inst::Var) { + return true; // var OP expr + } else if (A->K != Inst::Var && B->K == Inst::Var) { + return false; // expr OP var + } else if (A->K == Inst::Var && B->K == Inst::Var) { + return A->Name > B->Name; // Tends to put vars before symconsts + } else { + return A->K < B->K; // expr OP expr + } + }); + } + + if (Ops.size() == 2) { + auto Meat = printInst(Ops[0], S) + " " + Op + " " + printInst(Ops[1], S); + Result = Root ? Meat : "(" + Meat + ")"; + } else if (Ops.size() == 1) { + Result = Op + "(" + printInst(Ops[0], S) + ")"; + } + else { + std::string Ret = Root ? "" : "("; + Ret += Op; + Ret += " "; + for (auto &&Op : Ops) { + Ret += printInst(Op, S) + " "; + } + while (Ret.back() == ' ') { + Ret.pop_back(); + } + if (!Root) { + Ret += ")"; + } + Result = Ret; + } + if (UseCount[I] > 1) { + S << Result << ";\n"; + return Syms[I]; + } else { + return Result; + } + } + } + + template + void printPCs(Stream &S) { + bool first = true; + for (auto &&PC : P.PCs) { + // if (PC.LHS->K == Inst::KnownOnesP || PC.LHS->K == Inst::KnownZerosP) { + // continue; + // } + if (first) { + first = false; + } else { + S << " && \n"; + } + if (PC.RHS->K == Inst::Const && PC.RHS->Val == 0) { + S << "!(" << printInst(PC.LHS, S, true) << ")"; + } else if (PC.RHS->K == Inst::Const && PC.RHS->Val == 1) { + S << printInst(PC.LHS, S, true); + } else { + S << printInst(PC.LHS, S, true) << " == " << printInst(PC.RHS, S); + } + } + } + + ParsedReplacement P; + std::set VisitedVars; + std::map Syms; + size_t varnum; + std::map UseCount; + std::map WidthConstraints; + bool ShowImplicitWidths; +}; + +struct ShrinkWrap { + ShrinkWrap(InstContext &IC, Solver *S, ParsedReplacement Input, + size_t TargetWidth = 8) : IC(IC), S(S), Input(Input), + TargetWidth(TargetWidth) {} + InstContext &IC; + Solver *S; + ParsedReplacement Input; + size_t TargetWidth; + + std::map InstCache; + + Inst *ShrinkInst(Inst *I) { + if (InstCache.count(I)) { + return InstCache[I]; + } + if (I->K == Inst::Var) { + auto V = IC.createVar(TargetWidth, I->Name); + InstCache[I] = V; + return V; + } else if (I->K == Inst::Const) { + if (I->Val.getLimitedValue() == 0) { + auto C = IC.getConst(APInt(TargetWidth, 0)); + InstCache[I] = C; + return C; + } else if (I->Val.getLimitedValue() == 1) { + auto C = IC.getConst(APInt(TargetWidth, 1)); + InstCache[I] = C; + return C; + } else if (I->Val.isAllOnesValue()) { + auto C = IC.getConst(APInt::getAllOnesValue(TargetWidth)); + InstCache[I] = C; + return C; + } else { + auto C = IC.createSynthesisConstant(TargetWidth, I->Val.getLimitedValue()); + InstCache[I] = C; + return C; + } + } else { + std::vector Ops; + for (auto Op : I->Ops) { + Ops.push_back(ShrinkInst(Op)); + } + return IC.getInst(I->K, InferWidth(I->K, Ops), Ops); + } + } + + std::optional operator()() { + // Find Sext, Zext, Trunc + std::vector WidthChangeInsts; + findInsts(Input.Mapping.LHS, WidthChangeInsts, [&](Inst *I) { + return I->K == Inst::SExt || I->K == Inst::ZExt || I->K == Inst::Trunc;}); + findInsts(Input.Mapping.RHS, WidthChangeInsts, [&](Inst *I) { + return I->K == Inst::SExt || I->K == Inst::ZExt || I->K == Inst::Trunc;}); + + // Ignore PC for now + + // This can be relaxed a bit + if (!WidthChangeInsts.empty() || Input.Mapping.LHS->Width <= TargetWidth) { + return {}; + } + + // Abort if inputs are of <= Target width + std::vector Inputs; + findVars(Input.Mapping.LHS, Inputs); + for (auto I : Inputs) { + if (I->Width <= TargetWidth) { + return {}; + } + } + + ParsedReplacement New; + New.Mapping.LHS = ShrinkInst(Input.Mapping.LHS); + New.Mapping.RHS = ShrinkInst(Input.Mapping.RHS); + for (auto PC : Input.PCs) { + New.PCs.push_back({ShrinkInst(PC.LHS), ShrinkInst(PC.RHS)}); + } + + New.print(llvm::errs(), true); + + auto Clone = Verify(New, IC, S); + if (Clone.Mapping.LHS) { + return Clone; + } else { + return {}; + } + } +}; + std::vector findConcreteConsts(const ParsedReplacement &Input) { std::vector Consts; auto Pred = [](Inst *I) { @@ -144,6 +516,28 @@ std::vector findConcreteConsts(const ParsedReplacement &Input) { return Result; } +std::vector FilterExprsByValue(const std::vector &Exprs, + llvm::APInt TargetVal, const std::vector> &CMap) { + std::unordered_map ValueCache; + for (auto &&[I, V] : CMap) { + ValueCache[I] = EvalValue(V); + } + std::vector FilteredExprs; + ConcreteInterpreter CPos(ValueCache); + for (auto &&E : Exprs) { + auto Result = CPos.evaluateInst(E); + if (!Result.hasValue()) { + // Don't want to drop a candidate just because we couldn't evaluate it + FilteredExprs.push_back(E); + } else { + if (Result.getValue() == TargetVal) { + FilteredExprs.push_back(E); + } + } + } + return FilteredExprs; +} + std::vector FilterRelationsByValue(const std::vector &Relations, const std::vector> &CMap, ValueCache CEX) { @@ -679,7 +1073,10 @@ FirstValidCombination(ParsedReplacement Input, Clone.Mapping.RHS = nullptr; auto SOLVE = [&](ParsedReplacement P) -> bool { - // P.print(llvm::errs(), true); + // InfixPrinter IP(P); + // IP(llvm::errs()); + // llvm::errs() << "\n"; + if (GEN) { Clone = Verify(P, IC, S); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { @@ -718,10 +1115,12 @@ FirstValidCombination(ParsedReplacement Input, return Clone; } - Copy.Mapping.LHS = Replace(Copy.Mapping.LHS, IC, ReverseMap); - Copy.Mapping.RHS = Replace(Copy.Mapping.RHS, IC, ReverseMap); - if (SOLVE(Copy)) { - return Clone; + if (!ReverseMap.empty()) { + Copy.Mapping.LHS = Replace(Copy.Mapping.LHS, IC, ReverseMap); + Copy.Mapping.RHS = Replace(Copy.Mapping.RHS, IC, ReverseMap); + if (SOLVE(Copy)) { + return Clone; + } } } @@ -743,12 +1142,19 @@ InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) if (I == ParentConst) { continue; } + if (I->Width != Target.getBitWidth()) { + continue; + } if (!ConstMode) { - if (I->Width == Target.getBitWidth() && Val == Target) { + if (Val == Target) { Results.push_back(I); } + auto One = llvm::APInt(I->Width, 1); + if (One.shl(Val) == Target) { + Results.push_back(Builder(IC, One).Shl(I)()); + } } else { - if (I->Width == Target.getBitWidth()) { + if (ParentConst) { Results.push_back(Builder(IC, Target)()); } } @@ -945,7 +1351,15 @@ const std::vector> &ConstMap, std::vector> Results; for (auto R : RHS) { auto Cands = IOSynthesize(R->Val, ConstMap, IC, depth, false); - Results.push_back(Cands); + std::set Temp; + for (auto C : Cands) { + Temp.insert(C); + } + std::vector DedupedCands; + for (auto C : Temp) { + DedupedCands.push_back(C); + } + Results.push_back(DedupedCands); std::sort(Results.back().begin(), Results.back().end(), [](Inst *A, Inst *B) { return instCount(A) < instCount(B);}); } @@ -1112,6 +1526,7 @@ const std::vector> &ConstMap, std::vector> Enumerate(std::vector RHSConsts, std::set AtomicComps, InstContext &IC, + const std::vector> &ConstMap, size_t NumInsts = 1) { std::vector> Candidates; @@ -1132,7 +1547,7 @@ std::vector> Enumerate(std::vector RHSConsts, } for (auto &&Target : RHSConsts) { - Candidates.push_back({}); + std::vector CandsForTarget; EnumerativeSynthesis ES; auto Guesses = ES.generateExprs(IC, NumInsts, Components, Target->Width); @@ -1141,12 +1556,14 @@ std::vector> Enumerate(std::vector RHSConsts, souper::getConstants(Guess, ConstSet); if (!ConstSet.empty()) { if (SymbolizeConstSynthesis) { - Candidates.back().push_back(Guess); + CandsForTarget.push_back(Guess); } } else { - Candidates.back().push_back(Guess); + CandsForTarget.push_back(Guess); } } + // Filter by value + Candidates.push_back(FilterExprsByValue(CandsForTarget, Target->Val, ConstMap)); } return Candidates; } @@ -1191,6 +1608,25 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Print first successful result and exit, no result sorting. // Prelude + bool Nested = !ConstMap.empty(); + + if (!NoWidth && !Nested) { + ShrinkWrap Shrink(IC, S, Input, 4); + auto Smol = Shrink(); + if (Smol) { + if (DebugLevel > 2) { + llvm::errs() << "Shrinked: \n"; + InfixPrinter P(Smol.value()); + P(llvm::errs()); + Smol->print(llvm::errs(), true); + llvm::errs() << "\n"; + } + Input = Smol.value(); + + // Input.print(llvm::errs(), true); + + } + } auto Fresh = Input; size_t ticks = std::clock(); @@ -1205,8 +1641,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Changed = true; }; - bool Nested = !ConstMap.empty(); - auto LHSConsts = findConcreteConsts(Input.Mapping.LHS); auto RHSConsts = findConcreteConsts(Input.Mapping.RHS); @@ -1220,7 +1654,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, RHSConsts.erase(C); } - ParsedReplacement Result = Input; std::map SymConstMap; @@ -1232,11 +1665,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, int i = 1; for (auto I : LHSConsts) { auto Name = "symconst_" + std::to_string(i++); - if (I->Name != "") { - Name = I->Name; - } SymConstMap[I] = IC.createVar(I->Width, Name); + // llvm::errs() << "HERE : " << Name << '\t' << SymConstMap[I]->Name << "\n"; + InstCache[I] = SymConstMap[I]; SymCS[SymConstMap[I]] = I->Val; } @@ -1245,9 +1677,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, continue; } auto Name = "symconst_" + std::to_string(i++); - if (I->Name != "") { - Name = I->Name; - } SymConstMap[I] = IC.createVar(I->Width, Name); InstCache[I] = SymConstMap[I]; // SymCS[SymConstMap[I]] = I->Val; @@ -1267,6 +1696,9 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, std::map CommonConsts; for (auto C : LHSConsts) { CommonConsts[C] = SymConstMap[C]; + + llvm::errs() << "Common Const: " << C->Val << "\t" << SymConstMap[C]->Name << "\n"; + } if (!CommonConsts.empty()) { Result = Replace(Result, IC, CommonConsts); @@ -1369,11 +1801,11 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } std::vector> SimpleCandidates = - InferSpecialConstExprsAllSym(RHSFresh, ConstMap, IC, /*depth=*/ 4); + InferSpecialConstExprsAllSym(RHSFresh, ConstMap, IC, /*depth=*/ 3); if (!SimpleCandidates.empty()) { if (DebugLevel > 4) { - llvm::errs() << "InferSpecialConstExprsAllSym candidates: " << SimpleCandidates[0].size() << "\n"; + llvm::errs() << "InferSpecialConstExprsAllSym candidates: " << SimpleCandidates[0].size() << " x " << ConstantLimits.size() << "\n"; } auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, InstCache, IC, S, SymCS, @@ -1403,7 +1835,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Components.insert(C.first); } - auto EnumeratedCandidates = Enumerate(RHSFresh, Components, IC); + auto EnumeratedCandidates = Enumerate(RHSFresh, Components, IC, ConstMap); // if (DebugLevel > 4) { // llvm::errs() << "RHSFresh: " << RHSFresh.size() << "\n"; // llvm::errs() << "Components: " << Components.size() << "\n"; @@ -1417,31 +1849,13 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Clone; } Refresh("Enumerated cands, no constraints"); - - // Enumerated Expressions with some relational constraints - if (ConstMap.size() == 2) { - // llvm::errs() << "Relations: " << Relations.size() << "\n"; - // llvm::errs() << "Guesses: " << EnumeratedCandidates[0].size() << "\n"; - - for (auto &&R : Relations) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, - InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - Input.PCs.pop_back(); - } - } - Refresh("Relational constraints for enumerated cands."); } // Step 4.75 : Enumerate 2 instructions when single RHS Constant. std::vector> EnumeratedCandidatesTwoInsts; if (RHSFresh.size() == 1) { - EnumeratedCandidatesTwoInsts = Enumerate(RHSFresh, Components, IC, 2); + EnumeratedCandidatesTwoInsts = Enumerate(RHSFresh, Components, IC, ConstMap, 2); // llvm::errs() << "Guesses: " << EnumeratedCandidatesTwoInsts[0].size() << "\n"; @@ -1450,21 +1864,42 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (Clone.Mapping.LHS && Clone.Mapping.RHS) { return Clone; } - } - Refresh("Enumerated 2 insts for single RHS const cases"); + } + Refresh("Enumerated 2 insts for single RHS const cases"); + + if (!EnumeratedCandidates.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, false, true, true); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + + // Enumerated Expressions with some relational constraints + if (ConstMap.size() == 2) { + // llvm::errs() << "Relations: " << Relations.size() << "\n"; + // llvm::errs() << "Guesses: " << EnumeratedCandidates[0].size() << "\n"; + + for (auto &&R : Relations) { + Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, false, false); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; + } + Input.PCs.pop_back(); + } + } + Refresh("Relational constraints for enumerated cands."); - if (!EnumeratedCandidates.empty()) { - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, - InstCache, IC, S, SymCS, false, true, true); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } } Refresh("Enumerated exprs with constraints"); if (RHSFresh.size() == 1 && !Nested) { // Enumerated Expressions with some relational constraints if (ConstMap.size() == 2) { + llvm::errs() << "Enum2 : " << EnumeratedCandidatesTwoInsts.back().size() + << "\tRels: " << Relations.size() << "\n"; for (auto &&R : Relations) { Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, @@ -1699,24 +2134,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Input; } -size_t InferWidth(Inst::Kind K, const std::vector &Ops) { - switch (K) { - case Inst::LShr: - case Inst::Shl: - case Inst::And: - case Inst::Or: - case Inst::Xor: - case Inst::Sub: - case Inst::Mul: - case Inst::Add: return Ops[0]->Width; - case Inst::Slt: - case Inst::Sle: - case Inst::Ult: - case Inst::Ule: return 1; - default: llvm_unreachable((std::string("Unimplemented ") + Inst::getKindName(K)).c_str()); - } -} - Inst *CloneInst(InstContext &IC, Inst *I, std::map &Vars) { if (I->K == Inst::Var) { return Vars[I]; @@ -1796,6 +2213,7 @@ ParsedReplacement InstantiateWidthChecks(InstContext &IC, return Input; } + ParsedReplacement ReduceBasic(InstContext &IC, Solver *S, ParsedReplacement Input) { Reducer R(IC, S); @@ -1816,245 +2234,6 @@ ParsedReplacement ReduceBasic(InstContext &IC, return Input; } -struct InfixPrinter { - InfixPrinter(ParsedReplacement P_) : P(P_) { - varnum = 0; - std::vector NewPCs; - for (auto &&PC : P.PCs) { - countUses(PC.LHS); - countUses(PC.RHS); - if (!registerSymDFVars(PC.LHS)) { - NewPCs.push_back(PC); - } - countUses(P.Mapping.LHS); - countUses(P.Mapping.RHS); - } - P.PCs = NewPCs; - registerSymDBVar(); - } - - void registerSymDBVar() { - if (P.Mapping.LHS->K == Inst::DemandedMask) { - Syms[P.Mapping.LHS->Ops[1]] = "@db"; - assert(P.Mapping.RHS->K == Inst::DemandedMask && "Expected RHS to be a demanded mask."); - assert(P.Mapping.LHS->Ops[1] == P.Mapping.RHS->Ops[1] && "Expected same mask."); - P.Mapping.LHS = P.Mapping.LHS->Ops[0]; - P.Mapping.RHS = P.Mapping.RHS->Ops[0]; - } - } - - bool registerSymDFVars(Inst *I) { - if (I->K == Inst::KnownOnesP && I->Ops[0]->K == Inst::Var && - I->Ops[1]->Name.starts_with("sym")) { - Syms[I->Ops[1]] = I->Ops[0]->Name + ".k1"; - // VisitedVars.insert(I->Ops[1]->Name); - return true; - } - if (I->K == Inst::KnownZerosP && I->Ops[0]->K == Inst::Var && - I->Ops[1]->Name.starts_with("sym")) { - Syms[I->Ops[1]] = I->Ops[0]->Name + ".k0"; - // VisitedVars.insert(I->Ops[1]->Name); - return true; - } - return false; - } - - void countUses(Inst *I) { - for (auto &&Op : I->Ops) { - if (Op->K != Inst::Var && Op->K != Inst::Const) { - UseCount[Op]++; - } - countUses(Op); - } - } - - template - void operator()(Stream &S) { - if (!P.PCs.empty()) { - printPCs(S); - S << "\n |= \n"; - } - S << printInst(P.Mapping.LHS, S, true); - if (!P.Mapping.LHS->DemandedBits.isAllOnesValue()) { - S << " (" << "demandedBits=" - << Inst::getDemandedBitsString(P.Mapping.LHS->DemandedBits) - << ")"; - } - S << "\n =>\n"; - - S << printInst(P.Mapping.RHS, S, true); - } - - template - std::string printInst(Inst *I, Stream &S, bool Root = false) { - if (Syms.count(I)) { - return Syms[I]; - } - - // x ^ -1 => ~x - if (I->K == Inst::Xor && I->Ops[1]->K == Inst::Const && - I->Ops[1]->Val.isAllOnesValue()) { - return "~" + printInst(I->Ops[0], S); - } - if (I->K == Inst::Xor && I->Ops[0]->K == Inst::Const && - I->Ops[0]->Val.isAllOnesValue()) { - return "~" + printInst(I->Ops[1], S); - } - - - if (UseCount[I] > 1) { - std::string Name = "var" + std::to_string(varnum++); - Syms[I] = Name; - S << "let " << Name << " = "; - } - - if (I->K == Inst::Const) { - if (I->Val.ule(16)) { - return I->Val.toString(10, false); - } else { - return "0x" + I->Val.toString(16, false); - } - } else if (I->K == Inst::Var) { - auto Name = I->Name; - if (isDigit(Name[0])) { - Name = "x" + Name; - } - if (I->Name.starts_with("symconst_")) { - Name = "C" + I->Name.substr(9); - } - if (VisitedVars.count(I->Name)) { - return Name; - } else { - VisitedVars.insert(I->Name); - Inst::getKnownBitsString(I->KnownZeros, I->KnownOnes); - - std::string Buf; - llvm::raw_string_ostream Out(Buf); - - if (I->KnownZeros.getBoolValue() || I->KnownOnes.getBoolValue()) - Out << " (knownBits=" << Inst::getKnownBitsString(I->KnownZeros, I->KnownOnes) - << ")"; - if (I->NonNegative) - Out << " (nonNegative)"; - if (I->Negative) - Out << " (negative)"; - if (I->NonZero) - Out << " (nonZero)"; - if (I->PowOfTwo) - Out << " (powerOfTwo)"; - if (I->NumSignBits > 1) - Out << " (signBits=" << I->NumSignBits << ")"; - if (!I->Range.isFullSet()) - Out << " (range=[" << I->Range.getLower() - << "," << I->Range.getUpper() << "))"; - return Name + ":i" + std::to_string(I->Width) + Out.str(); - } - } else { - std::string Op; - switch (I->K) { - case Inst::Add: Op = "+"; break; - case Inst::Sub: Op = "-"; break; - case Inst::Mul: Op = "*"; break; - case Inst::UDiv: Op = "/u"; break; - case Inst::SDiv: Op = "/s"; break; - case Inst::URem: Op = "\%u"; break; - case Inst::SRem: Op = "\%s"; break; - case Inst::And: Op = "&"; break; - case Inst::Or: Op = "|"; break; - case Inst::Xor: Op = "^"; break; - case Inst::Shl: Op = "<<"; break; - case Inst::LShr: Op = ">>"; break; - case Inst::AShr: Op = ">>"; break; - case Inst::Eq: Op = "=="; break; - case Inst::Ne: Op = "!="; break; - case Inst::Ult: Op = "K); break; - } - - std::string Result; - - std::vector Ops = I->orderedOps(); - - if (Inst::isCommutative(I->K)) { - std::sort(Ops.begin(), Ops.end(), [](Inst *A, Inst *B) { - if (A->K == Inst::Const) { - return false; // c OP expr - } else if (B->K == Inst::Const) { - return true; // expr OP c - } else if (A->K == Inst::Var && B->K != Inst::Var) { - return true; // var OP expr - } else if (A->K != Inst::Var && B->K == Inst::Var) { - return false; // expr OP var - } else if (A->K == Inst::Var && B->K == Inst::Var) { - return A->Name > B->Name; // Tends to put vars before symconsts - } else { - return A->K < B->K; // expr OP expr - } - }); - } - - if (Ops.size() == 2) { - auto Meat = printInst(Ops[0], S) + " " + Op + " " + printInst(Ops[1], S); - Result = Root ? Meat : "(" + Meat + ")"; - } else if (Ops.size() == 1) { - Result = Op + "(" + printInst(Ops[0], S) + ")"; - } - else { - std::string Ret = Root ? "" : "("; - Ret += Op; - Ret += " "; - for (auto &&Op : Ops) { - Ret += printInst(Op, S) + " "; - } - while (Ret.back() == ' ') { - Ret.pop_back(); - } - if (!Root) { - Ret += ")"; - } - Result = Ret; - } - if (UseCount[I] > 1) { - S << Result << ";\n"; - return Syms[I]; - } else { - return Result; - } - } - } - - template - void printPCs(Stream &S) { - bool first = true; - for (auto &&PC : P.PCs) { - // if (PC.LHS->K == Inst::KnownOnesP || PC.LHS->K == Inst::KnownZerosP) { - // continue; - // } - if (first) { - first = false; - } else { - S << " && \n"; - } - if (PC.RHS->K == Inst::Const && PC.RHS->Val == 0) { - S << "!(" << printInst(PC.LHS, S, true) << ")"; - } else if (PC.RHS->K == Inst::Const && PC.RHS->Val == 1) { - S << printInst(PC.LHS, S, true); - } else { - S << printInst(PC.LHS, S, true) << " == " << printInst(PC.RHS, S); - } - } - } - - ParsedReplacement P; - std::set VisitedVars; - std::map Syms; - size_t varnum; - std::map UseCount; -}; - template Stream &operator<<(Stream &S, InfixPrinter IP) { IP(S); @@ -2120,7 +2299,7 @@ int main(int argc, char **argv) { if (DebugLevel > 1) { llvm::errs() << "\n\tInput:\n\n"; - llvm::errs() << InfixPrinter(Input) << "\n\n\tGeneralized:\n\n" << InfixPrinter(Result); + llvm::errs() << InfixPrinter(Input) << "\n\tGeneralized:\n\n" << InfixPrinter(Result, NoWidth); } } continue; From c3c4b883f132d4652b7c0418bbfdb8e7661f7ea1 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Thu, 16 Mar 2023 21:03:17 -0600 Subject: [PATCH 144/165] foo --- include/souper/Infer/SynthUtils.h | 3 ++ lib/Infer/SynthUtils.cpp | 20 ++++++++++++ test/Generalize/maskoff.opt | 2 +- tools/generalize.cpp | 51 ++++++++++++++++++------------- 4 files changed, 53 insertions(+), 23 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 1417225a5..a1f59559c 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -135,5 +135,8 @@ std::vector> findValidConsts(ParsedReplacement Inp ValueCache GetCEX(const ParsedReplacement &Input, InstContext &IC, Solver *S); +std::vector GetMultipleCEX(ParsedReplacement Input, InstContext &IC, Solver *S, size_t MaxCount); + + } #endif diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index fedc94bdb..b69f86444 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -228,4 +228,24 @@ ValueCache GetCEX(const ParsedReplacement &Input, InstContext &IC, Solver *S) { } } +std::vector GetMultipleCEX(ParsedReplacement Input, InstContext &IC, Solver *S, size_t MaxCount = 2) { + std::vector Results; + while (MaxCount--) { + auto &&Result = GetCEX(Input, IC, S); + if (Result.empty()) { + return Results; + } + for (auto &&CEX : Result) { + if (!CEX.second.hasValue()) { + return Results; + } + } + Results.push_back(Result); + for (auto &&CEX : Result) { + Input.PCs.push_back({Builder(IC, CEX.first).Ne(CEX.second.getValue())(), IC.getConst(llvm::APInt(1, 1))}); + } + } + return Results; +} + } diff --git a/test/Generalize/maskoff.opt b/test/Generalize/maskoff.opt index b2d11c245..5a20e6d85 100644 --- a/test/Generalize/maskoff.opt +++ b/test/Generalize/maskoff.opt @@ -10,4 +10,4 @@ cand %2 %3 ; CHECK: (v0:i32 << C1:i32) >> C1 ; CHECK: => -; CHECK: v0 & (-1 >> C1) \ No newline at end of file +; CHECK: v0 & (-1 >>l C1) \ No newline at end of file diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 70531b60a..cdb479f45 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -540,7 +540,7 @@ std::vector FilterExprsByValue(const std::vector &Exprs, std::vector FilterRelationsByValue(const std::vector &Relations, const std::vector> &CMap, - ValueCache CEX) { + std::vector CEXs) { std::unordered_map ValueCache; for (auto &&[I, V] : CMap) { ValueCache[I] = EvalValue(V); @@ -552,33 +552,40 @@ std::vector FilterRelationsByValue(const std::vector &Relations, // } ConcreteInterpreter CPos(ValueCache); - ConcreteInterpreter CNeg(CEX); + std::vector CNegs; + for (auto &&CEX : CEXs) { + CNegs.push_back(CEX); + } std::vector FilteredRelations; for (auto &&R : Relations) { auto Result = CPos.evaluateInst(R); - EvalValue ResultNeg = CEX.empty() ? EvalValue() : CNeg.evaluateInst(R); - - // llvm::errs() << "P: " << Result.getValue().toString(2, false) << ' ' << Result.getValue().isAllOnesValue() << "\n"; - // llvm::errs() << "N: " << ResultNeg.getValue().toString(2, false) << ' ' << ResultNeg.getValue().isNullValue()<< "\n"; + // Positive example + if (Result.hasValue() && !Result.getValue().isAllOnesValue()) { + continue; + } - if (Result.hasValue() && Result.getValue().isAllOnesValue()) { - // llvm::errs() << "Keeping "<< "\n"; - if (ResultNeg.hasValue()) { - if (ResultNeg.getValue().isNullValue()) { - FilteredRelations.push_back(R); - } - } else { - FilteredRelations.push_back(R); + // Negative examples + bool foundUnsound = false; + for (auto &&CNeg : CNegs) { + auto ResultNeg = CNeg.evaluateInst(R); + if (ResultNeg.hasValue() && !ResultNeg.getValue().isNullValue()) { + foundUnsound = true; + break; } } + if (foundUnsound) { + continue; + } + FilteredRelations.push_back(R); } return FilteredRelations; } std::vector InferConstantLimits( const std::vector> &CMap, - InstContext &IC, const ParsedReplacement &Input, ValueCache CEX) { + InstContext &IC, const ParsedReplacement &Input, + std::vector CEXs) { std::vector Results; if (!FindConstantRelations) { return Results; @@ -642,7 +649,7 @@ std::vector InferConstantLimits( } } } - return FilterRelationsByValue(Results, CMap, CEX); + return FilterRelationsByValue(Results, CMap, CEXs); } // Enforce commutativity to prune search space @@ -675,7 +682,7 @@ std::vector BitFuncs(Inst *I, InstContext &IC) { std::vector InferPotentialRelations( const std::vector> &CMap, - InstContext &IC, const ParsedReplacement &Input, ValueCache CEX, + InstContext &IC, const ParsedReplacement &Input, std::vector CEXs, bool LatticeChecks = false) { std::vector Results; if (!FindConstantRelations) { @@ -861,7 +868,7 @@ std::vector InferPotentialRelations( // Results.push_back(R); // } // llvm::errs() << "HERE: " << Results.size() << '\n'; - Results = FilterRelationsByValue(Results, CMap, CEX); + Results = FilterRelationsByValue(Results, CMap, CEXs); if (LatticeChecks) { // TODO Less brute force @@ -1726,12 +1733,12 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, for (auto &&C : LHSConsts) { ConstMap.push_back({SymConstMap[C], C->Val}); } - auto CEX = GetCEX(Result, IC, S); + auto CounterExamples = GetMultipleCEX(Result, IC, S, 3); if (Nested) { - CEX = {}; + CounterExamples = {}; // FIXME : Figure out how to get CEX for symbolic dataflow } - auto Relations = InferPotentialRelations(ConstMap, IC, Input, CEX, Nested); + auto Relations = InferPotentialRelations(ConstMap, IC, Input, CounterExamples, Nested); std::map JustLHSSymConstMap; @@ -1771,7 +1778,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, Refresh("All LHS Constraints"); - auto ConstantLimits = InferConstantLimits(ConstMap, IC, Input, CEX); + auto ConstantLimits = InferConstantLimits(ConstMap, IC, Input, CounterExamples); // Step 3 : Special RHS constant exprs, no constants From 2316ed5081282b5d40d49f446c46bdb8d5c1f3dc Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sat, 18 Mar 2023 15:58:58 -0600 Subject: [PATCH 145/165] foo --- include/souper/Infer/Interpreter.h | 6 +- lib/Infer/Pruning.cpp | 3 +- tools/generalize.cpp | 118 ++++++++++++++++++++++++++--- 3 files changed, 112 insertions(+), 15 deletions(-) diff --git a/include/souper/Infer/Interpreter.h b/include/souper/Infer/Interpreter.h index 43ad8e544..0041ac9e5 100644 --- a/include/souper/Infer/Interpreter.h +++ b/include/souper/Infer/Interpreter.h @@ -115,9 +115,9 @@ EvalValue evaluateAShr(llvm::APInt A, llvm::APInt B); EvalValue evaluateSingleInst(Inst *I, std::vector &Args); public: - ConcreteInterpreter() {} - ConcreteInterpreter(ValueCache &Input) : Cache(Input) {} - ConcreteInterpreter(Inst *I, ValueCache &Input) : Cache(Input) { + ConcreteInterpreter() : Cache() {} + ConcreteInterpreter(ValueCache Input) : Cache(Input) {} + ConcreteInterpreter(Inst *I, ValueCache Input) : Cache(Input) { CacheWritable = true; evaluateInst(I); CacheWritable = false; diff --git a/lib/Infer/Pruning.cpp b/lib/Infer/Pruning.cpp index e7b00165b..fdfb2dc0a 100644 --- a/lib/Infer/Pruning.cpp +++ b/lib/Infer/Pruning.cpp @@ -605,7 +605,8 @@ void PruningManager::init() { }; } - ConcreteInterpreter BlankCI; + ValueCache C; + ConcreteInterpreter BlankCI(C); LHSKnownBitsNoSpec = KnownBitsAnalysis().findKnownBits(SC.LHS, BlankCI, false); LHSMustDemandedBits = MustDemandedBitsAnalysis().findMustDemandedBits(SC.LHS); improveMustDemandedBits(LHSMustDemandedBits); diff --git a/tools/generalize.cpp b/tools/generalize.cpp index cdb479f45..7557d1e84 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1603,10 +1603,102 @@ void findDangerousConstants(Inst *I, std::set &Results) { } } -struct GeneralizationProblem { - ParsedReplacement Input; +size_t BruteForceModelCount(Inst *Pred) { + if (Pred->Width >= 8) { + llvm::errs() << "Too wide for brute force model counting.\n"; + return 0; + } -}; + std::vector Inputs; + findVars(Pred, Inputs); + + ValueCache Cache; + for (auto I : Inputs) { + Cache[I] = EvalValue(llvm::APInt(I->Width, 0)); + } + + auto Update = [&]() { + for (auto I : Inputs) { + if (Cache[I].getValue() == llvm::APInt(I->Width, -1)) { + continue; + } else { + Cache[I] = EvalValue(Cache[I].getValue() + 1); + return true; + } + } + return false; + }; + + size_t ModelCount = 0; + + do { + ConcreteInterpreter CI(Cache); + if (CI.evaluateInst(Pred).getValue().getBoolValue()) { + ++ModelCount; + } + } while (Update()); + + return ModelCount; +} + +void SortPredsByModelCount(std::vector &Preds) { + std::unordered_map ModelCounts; + for (auto P : Preds) { + ModelCounts[P] = BruteForceModelCount(P); + } + std::sort(Preds.begin(), Preds.end(), [&](Inst *A, Inst *B) { + return ModelCounts[A] > ModelCounts[B]; + }); +} + +std::optional VerifyWithRels(InstContext &IC, Solver *S, + ParsedReplacement Input, + std::vector &Rels) { + std::vector ValidRels; + + ParsedReplacement FirstValidResult = Input; + + for (auto Rel : Rels) { + Input.PCs.push_back({Rel, IC.getConst(llvm::APInt(1, 1))}); + auto Clone = Verify(Input, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + ValidRels.push_back(Rel); + FirstValidResult = Clone; + if (Rels.size() > 10) { + return Clone; + } + } + Input.PCs.pop_back(); + } + + if (ValidRels.empty()) { + return std::nullopt; + } + + std::vector Inputs; + findVars(Input.Mapping.LHS, Inputs); + + size_t MaxWidth = 0; + for (auto I : Inputs) { + if (I->Width > MaxWidth) { + MaxWidth = I->Width; + } + } + + if (MaxWidth > 8) { + if (DebugLevel > 4) { + llvm::errs() << "Too wide for brute force model counting.\n"; + } + // TODO: Use approximate model counting? + return FirstValidResult; + } + + SortPredsByModelCount(ValidRels); + // TODO: Construct WP + // For now, return the weakest valid result + Input.PCs.push_back({ValidRels[0], IC.getConst(llvm::APInt(1, 1))}); + return Input; +} // Assuming the input has leaves pruned and preconditions weakened ParsedReplacement SuccessiveSymbolize(InstContext &IC, @@ -1747,14 +1839,18 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } auto Copy = Replace(Input, IC, JustLHSSymConstMap); - for (auto &&R : Relations) { - Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - // Copy.print(llvm::errs(), true); - auto Clone = Verify(Copy, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - Copy.PCs.pop_back(); + // for (auto &&R : Relations) { + // Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); + // // Copy.print(llvm::errs(), true); + // auto Clone = Verify(Copy, IC, S); + // if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + // return Clone; + // } + // Copy.PCs.pop_back(); + // } + + if (auto RelV = VerifyWithRels(IC, S, Copy, Relations)) { + return RelV.value(); } Refresh("Direct + simple rel constraints"); From d0d19eefc741fa126b91e69520a268bbc5604531 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sat, 18 Mar 2023 16:26:28 -0600 Subject: [PATCH 146/165] foo --- tools/generalize.cpp | 333 +++++++++++++++++++------------------------ 1 file changed, 147 insertions(+), 186 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 7557d1e84..587972d7a 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1020,6 +1020,104 @@ if(s) return Clone;}; return Clone; } +size_t BruteForceModelCount(Inst *Pred) { + if (Pred->Width >= 8) { + llvm::errs() << "Too wide for brute force model counting.\n"; + return 0; + } + + std::vector Inputs; + findVars(Pred, Inputs); + + ValueCache Cache; + for (auto I : Inputs) { + Cache[I] = EvalValue(llvm::APInt(I->Width, 0)); + } + + auto Update = [&]() { + for (auto I : Inputs) { + if (Cache[I].getValue() == llvm::APInt(I->Width, -1)) { + continue; + } else { + Cache[I] = EvalValue(Cache[I].getValue() + 1); + return true; + } + } + return false; + }; + + size_t ModelCount = 0; + + do { + ConcreteInterpreter CI(Cache); + if (CI.evaluateInst(Pred).getValue().getBoolValue()) { + ++ModelCount; + } + } while (Update()); + + return ModelCount; +} + +void SortPredsByModelCount(std::vector &Preds) { + std::unordered_map ModelCounts; + for (auto P : Preds) { + ModelCounts[P] = BruteForceModelCount(P); + } + std::sort(Preds.begin(), Preds.end(), [&](Inst *A, Inst *B) { + return ModelCounts[A] > ModelCounts[B]; + }); +} + +std::optional VerifyWithRels(InstContext &IC, Solver *S, + ParsedReplacement Input, + std::vector &Rels) { + std::vector ValidRels; + + ParsedReplacement FirstValidResult = Input; + + for (auto Rel : Rels) { + Input.PCs.push_back({Rel, IC.getConst(llvm::APInt(1, 1))}); + auto Clone = Verify(Input, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + ValidRels.push_back(Rel); + FirstValidResult = Clone; + if (Rels.size() > 10) { + return Clone; + } + } + Input.PCs.pop_back(); + } + + if (ValidRels.empty()) { + return std::nullopt; + } + + std::vector Inputs; + findVars(Input.Mapping.LHS, Inputs); + + size_t MaxWidth = 0; + for (auto I : Inputs) { + if (I->Width > MaxWidth) { + MaxWidth = I->Width; + } + } + + if (MaxWidth > 8) { + if (DebugLevel > 4) { + llvm::errs() << "Too wide for brute force model counting.\n"; + } + // TODO: Use approximate model counting? + return FirstValidResult; + } + + SortPredsByModelCount(ValidRels); + // TODO: Construct WP + // For now, return the weakest valid result + Input.PCs.push_back({ValidRels[0], IC.getConst(llvm::APInt(1, 1))}); + return Input; +} + + ParsedReplacement FirstValidCombination(ParsedReplacement Input, const std::vector &Targets, @@ -1029,7 +1127,8 @@ FirstValidCombination(ParsedReplacement Input, std::map SymCS, bool GEN, bool SDF, - bool DFF) { + bool DFF, + std::vector Rels = {}) { std::vector Counts; for (auto &&Cand : Candidates) { Counts.push_back(Cand.size()); @@ -1091,6 +1190,14 @@ FirstValidCombination(ParsedReplacement Input, } } + if (!Rels.empty()) { + auto Result = VerifyWithRels(IC, S, P, Rels); + if (Result) { + Clone = *Result; + return true; + } + } + if (SDF) { Clone = SimplePreconditionsAndVerifyGreedy(P, IC, S, SymCS); @@ -1603,103 +1710,6 @@ void findDangerousConstants(Inst *I, std::set &Results) { } } -size_t BruteForceModelCount(Inst *Pred) { - if (Pred->Width >= 8) { - llvm::errs() << "Too wide for brute force model counting.\n"; - return 0; - } - - std::vector Inputs; - findVars(Pred, Inputs); - - ValueCache Cache; - for (auto I : Inputs) { - Cache[I] = EvalValue(llvm::APInt(I->Width, 0)); - } - - auto Update = [&]() { - for (auto I : Inputs) { - if (Cache[I].getValue() == llvm::APInt(I->Width, -1)) { - continue; - } else { - Cache[I] = EvalValue(Cache[I].getValue() + 1); - return true; - } - } - return false; - }; - - size_t ModelCount = 0; - - do { - ConcreteInterpreter CI(Cache); - if (CI.evaluateInst(Pred).getValue().getBoolValue()) { - ++ModelCount; - } - } while (Update()); - - return ModelCount; -} - -void SortPredsByModelCount(std::vector &Preds) { - std::unordered_map ModelCounts; - for (auto P : Preds) { - ModelCounts[P] = BruteForceModelCount(P); - } - std::sort(Preds.begin(), Preds.end(), [&](Inst *A, Inst *B) { - return ModelCounts[A] > ModelCounts[B]; - }); -} - -std::optional VerifyWithRels(InstContext &IC, Solver *S, - ParsedReplacement Input, - std::vector &Rels) { - std::vector ValidRels; - - ParsedReplacement FirstValidResult = Input; - - for (auto Rel : Rels) { - Input.PCs.push_back({Rel, IC.getConst(llvm::APInt(1, 1))}); - auto Clone = Verify(Input, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - ValidRels.push_back(Rel); - FirstValidResult = Clone; - if (Rels.size() > 10) { - return Clone; - } - } - Input.PCs.pop_back(); - } - - if (ValidRels.empty()) { - return std::nullopt; - } - - std::vector Inputs; - findVars(Input.Mapping.LHS, Inputs); - - size_t MaxWidth = 0; - for (auto I : Inputs) { - if (I->Width > MaxWidth) { - MaxWidth = I->Width; - } - } - - if (MaxWidth > 8) { - if (DebugLevel > 4) { - llvm::errs() << "Too wide for brute force model counting.\n"; - } - // TODO: Use approximate model counting? - return FirstValidResult; - } - - SortPredsByModelCount(ValidRels); - // TODO: Construct WP - // For now, return the weakest valid result - Input.PCs.push_back({ValidRels[0], IC.getConst(llvm::APInt(1, 1))}); - return Input; -} - // Assuming the input has leaves pruned and preconditions weakened ParsedReplacement SuccessiveSymbolize(InstContext &IC, Solver *S, ParsedReplacement Input, bool &Changed, @@ -1890,15 +1900,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // llvm::errs() << "FOO: " << UnitaryCandidates[0][0]->Name << "\n"; // } - for (auto &&R : Relations) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - // Input.print(llvm::errs(), true); - auto Clone = FirstValidCombination(Input, RHSFresh, UnitaryCandidates, - InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - Input.PCs.pop_back(); + auto Clone = FirstValidCombination(Input, RHSFresh, UnitaryCandidates, + InstCache, IC, S, SymCS, true, false, false, Relations); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } Refresh("Unitary cands, rel constraints"); } @@ -1917,15 +1922,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, return Clone; } - for (auto &&R : ConstantLimits) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - // Input.print(llvm::errs(), true); - Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, - InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - Input.PCs.pop_back(); + Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, + InstCache, IC, S, SymCS, true, false, false, ConstantLimits); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } } @@ -1982,15 +1982,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // llvm::errs() << "Relations: " << Relations.size() << "\n"; // llvm::errs() << "Guesses: " << EnumeratedCandidates[0].size() << "\n"; - for (auto &&R : Relations) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, - InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - Input.PCs.pop_back(); + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, false, false, Relations); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } } Refresh("Relational constraints for enumerated cands."); @@ -2003,14 +1998,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (ConstMap.size() == 2) { llvm::errs() << "Enum2 : " << EnumeratedCandidatesTwoInsts.back().size() << "\tRels: " << Relations.size() << "\n"; - for (auto &&R : Relations) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, - InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - Input.PCs.pop_back(); + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, + InstCache, IC, S, SymCS, true, false, false, Relations); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } } } @@ -2035,14 +2026,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Enumerated exprs with constraints if (!EnumeratedCandidates.empty() && !Nested) { - for (auto &&R : Relations) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, - InstCache, IC, S, SymCS, true, true, true); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, true, true, Relations); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } Refresh("Enumerated exprs with constraints and relations"); } @@ -2057,16 +2044,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } Refresh("Simple cands with constraints"); - for (auto &&R : Relations) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - - auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, - InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - - Input.PCs.pop_back(); + Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, + InstCache, IC, S, SymCS, true, false, false, Relations); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } Refresh("Simple cands with constraints and relations"); } @@ -2081,17 +2062,12 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } Refresh("Simple cands+consts with constraints"); - for (auto &&R : Relations) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - - auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, - InstCache, IC, S, SymCS, true, true, true); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - - Input.PCs.pop_back(); + Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, + InstCache, IC, S, SymCS, true, true, true, Relations); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } + Refresh("Simple cands+consts with constraints and relations"); } @@ -2114,29 +2090,19 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // } if (!EnumeratedCandidates.empty()) { - for (auto &&R : ConstantLimits) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - - auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, - InstCache, IC, S, SymCS, true, true, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - Input.PCs.pop_back(); + auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, + InstCache, IC, S, SymCS, true, true, false, ConstantLimits); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } Refresh("Enumerated expressions+consts and constant limits"); } if (!SimpleCandidatesWithConsts.empty()) { - for (auto &&R : ConstantLimits) { - Input.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - - auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, - InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - Input.PCs.pop_back(); + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, + InstCache, IC, S, SymCS, true, false, false, ConstantLimits); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + return Clone; } Refresh("Simple expressions+consts and constant limits"); } @@ -2145,13 +2111,8 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, { auto Copy = Replace(Input, IC, JustLHSSymConstMap); - for (auto &&R : ConstantLimits) { - Copy.PCs.push_back({R, IC.getConst(llvm::APInt(1, 1))}); - auto Clone = Verify(Copy, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - Copy.PCs.pop_back(); + if (auto VRel = VerifyWithRels(IC, S, Copy, ConstantLimits)) { + return VRel.value(); } Refresh("Constant limit constraints on LHS"); } From b440cccbf50e09a5fa16078353cfa2f6d145e80f Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 19 Mar 2023 20:09:03 -0600 Subject: [PATCH 147/165] foo --- lib/Infer/AliveDriver.cpp | 18 +++ lib/Infer/ConstantSynthesis.cpp | 11 +- tools/generalize.cpp | 273 ++++++++++++++------------------ 3 files changed, 147 insertions(+), 155 deletions(-) diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index 0e6b9cb7b..8322cf545 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -593,6 +593,23 @@ bool souper::AliveDriver::translateAndCache(const souper::Inst *I, return true; // Already translated } + if (I->K == Inst::KnownOnesP) { + auto *VarAndOnes = IC.getInst(Inst::And, I->Width, {I->Ops[0], I->Ops[1]}); + auto *Eq = IC.getInst(Inst::Eq, 1, {VarAndOnes, I->Ops[1]}); + auto Ret = translateAndCache(Eq, F, ExprCache); + ExprCache[I] = ExprCache[Eq]; + return Ret; + } + if (I->K == Inst::KnownZerosP) { + auto *FlipZeros = IC.getInst(Inst::Xor, I->Width, {I->Ops[1], + IC.getConst(llvm::APInt::getAllOnesValue(I->Width))}); + auto *VarNotZeros = IC.getInst(Inst::Or, I->Width, {I->Ops[0], FlipZeros}); + auto *Eq = IC.getInst(Inst::Eq, 1, {VarNotZeros, FlipZeros}); + auto Ret = translateAndCache(Eq, F, ExprCache); + ExprCache[I] = ExprCache[Eq]; + return Ret; + } + auto Ops = I->Ops; if (souper::Inst::isOverflowIntrinsicMain(I->K)) { Ops = Ops[0]->Ops; @@ -722,6 +739,7 @@ bool souper::AliveDriver::translateAndCache(const souper::Inst *I, BINOPF(MulNUW, Mul, NUW); BINOPF(MulNW, Mul, NSW | IR::BinOp::NUW); BINOP(And, And); + BINOP(DemandedMask, And); BINOP(Or, Or); BINOP(Xor, Xor); BINOP(Shl, Shl); diff --git a/lib/Infer/ConstantSynthesis.cpp b/lib/Infer/ConstantSynthesis.cpp index bfd1ae831..17b83fa00 100644 --- a/lib/Infer/ConstantSynthesis.cpp +++ b/lib/Infer/ConstantSynthesis.cpp @@ -43,7 +43,7 @@ Inst *getUBConstraint(Inst::Kind K, unsigned OpNum, Inst *C, case Inst::AShr: // right operand has to be < Width return (OpNum == 0) ? - IC.getConst(llvm::APInt(1, true)) : + IC.getConst(llvm::APInt(1, true)) : IC.getInst(Inst::Ult, 1, { C, IC.getConst(llvm::APInt(C->Width, C->Width)) }); case Inst::UDiv: @@ -81,7 +81,7 @@ Inst *getConstConstraint(Inst::Kind K, unsigned OpNum, Inst *C, case Inst::USubSat: // left operand cannot be 0, right operand cannot be 0 or -1 return (OpNum == 0) ? - IC.getInst(Inst::Ne, 1, { IC.getConst(llvm::APInt(C->Width, 0)), C }) : + IC.getInst(Inst::Ne, 1, { IC.getConst(llvm::APInt(C->Width, 0)), C }) : IC.getInst(Inst::And, 1, { IC.getInst(Inst::Ne, 1, { IC.getConst(llvm::APInt(C->Width, 0)), C }), IC.getInst(Inst::Ne, 1, { IC.getConst(llvm::APInt::getAllOnesValue(C->Width)), C }) @@ -94,6 +94,7 @@ Inst *getConstConstraint(Inst::Kind K, unsigned OpNum, Inst *C, IC.getInst(Inst::Ne, 1, { IC.getConst(llvm::APInt(C->Width, 1)), C }) }); + case Inst::DemandedMask: case Inst::And: case Inst::Or: // neither operand can be 0 or -1 @@ -147,7 +148,7 @@ Inst *getConstConstraint(Inst::Kind K, unsigned OpNum, Inst *C, IC.getInst(Inst::Ult, 1, { IC.getConst(llvm::APInt(C->Width, 2)), C }), IC.getInst(Inst::Ne, 1, { IC.getConst(llvm::APInt::getAllOnesValue(C->Width)), C }) }); - + case Inst::SDiv: case Inst::SRem: case Inst::URem: @@ -193,7 +194,7 @@ Inst *getConstConstraint(Inst::Kind K, unsigned OpNum, Inst *C, IC.getInst(Inst::And, 1, { IC.getInst(Inst::Ult, 1, { C, IC.getConst(llvm::APInt::getAllOnesValue(C->Width) - 1) }), IC.getInst(Inst::Ne, 1, { IC.getConst(llvm::APInt(C->Width, 0)), C }) - }); + }); case Inst::Slt: // we don't want: @@ -257,7 +258,7 @@ void addComplexConstraints(Inst *I, // --x // ~~x // 2 * x / 2 - + // first and second arguments to funnel shift can't both be zero if (I->K == Inst::FShl || I->K == Inst::FShr) { if (ConstSet.find(I->Ops[0]) != ConstSet.end() && diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 587972d7a..dc7176b20 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -409,6 +409,69 @@ struct InfixPrinter { bool ShowImplicitWidths; }; +using ConstMapT = std::vector>; +std::pair +AugmentForSymKBDB(ParsedReplacement Original, InstContext &IC) { + auto Input = Clone(Original, IC); + std::vector> ConstMap; + if (Input.Mapping.LHS->DemandedBits.getBitWidth() == Input.Mapping.LHS->Width && + !Input.Mapping.LHS->DemandedBits.isAllOnesValue()) { + auto DB = Input.Mapping.LHS->DemandedBits; + auto SymDFVar = IC.createVar(DB.getBitWidth(), "symDF_DB"); + // SymDFVar->Name = "symDF_DB"; + + SymDFVar->KnownOnes = llvm::APInt(DB.getBitWidth(), 0); + SymDFVar->KnownZeros = llvm::APInt(DB.getBitWidth(), 0); + // SymDFVar->Val = DB; + + Input.Mapping.LHS->DemandedBits.setAllBits(); + Input.Mapping.RHS->DemandedBits.setAllBits(); + + auto W = Input.Mapping.LHS->Width; + + Input.Mapping.LHS = IC.getInst(Inst::DemandedMask, W, {Input.Mapping.LHS, SymDFVar}); + Input.Mapping.RHS = IC.getInst(Inst::DemandedMask, W, {Input.Mapping.RHS, SymDFVar}); + + ConstMap.push_back({SymDFVar, DB}); + } + + std::vector Inputs; + findVars(Input.Mapping.LHS, Inputs); + + for (auto &&I : Inputs) { + auto Width = I->Width; + if (I->KnownZeros.getBitWidth() == I->Width && + I->KnownOnes.getBitWidth() == I->Width && + !(I->KnownZeros == 0 && I->KnownOnes == 0)) { + if (I->KnownZeros != 0) { + Inst *Zeros = IC.createVar(Width, "symDF_K0"); + + // Inst *AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(Width)); + // Inst *NotZeros = IC.getInst(Inst::Xor, Width, + // {Zeros, AllOnes}); + // Inst *VarNotZero = IC.getInst(Inst::Or, Width, {I, NotZeros}); + // Inst *ZeroBits = IC.getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); + Inst *ZeroBits = IC.getInst(Inst::KnownZerosP, 1, {I, Zeros}); + Input.PCs.push_back({ZeroBits, IC.getConst(llvm::APInt(1, 1))}); + ConstMap.push_back({Zeros, I->KnownZeros}); + I->KnownZeros = llvm::APInt(I->Width, 0); + } + + if (I->KnownOnes != 0) { + Inst *Ones = IC.createVar(Width, "symDF_K1"); + // Inst *VarAndOnes = IC.getInst(Inst::And, Width, {I, Ones}); + // Inst *OneBits = IC.getInst(Inst::Eq, 1, {VarAndOnes, Ones}); + Inst *OneBits = IC.getInst(Inst::KnownOnesP, 1, {I, Ones}); + Input.PCs.push_back({OneBits, IC.getConst(llvm::APInt(1, 1))}); + ConstMap.push_back({Ones, I->KnownOnes}); + I->KnownOnes = llvm::APInt(I->Width, 0); + } + } + } + + return {ConstMap, Input}; +} + struct ShrinkWrap { ShrinkWrap(InstContext &IC, Solver *S, ParsedReplacement Input, size_t TargetWidth = 8) : IC(IC), S(S), Input(Input), @@ -420,58 +483,85 @@ struct ShrinkWrap { std::map InstCache; - Inst *ShrinkInst(Inst *I) { + Inst *ShrinkInst(Inst *I, Inst *Parent, size_t ResultWidth) { if (InstCache.count(I)) { return InstCache[I]; } if (I->K == Inst::Var) { - auto V = IC.createVar(TargetWidth, I->Name); + if (I->Width == 1) { + return I; + } + auto V = IC.createVar(ResultWidth, I->Name); InstCache[I] = V; return V; } else if (I->K == Inst::Const) { + if (I->Width == 1) { + return I; + } + // Treat 0, 1, and -1 specially if (I->Val.getLimitedValue() == 0) { - auto C = IC.getConst(APInt(TargetWidth, 0)); + auto C = IC.getConst(APInt(ResultWidth, 0)); InstCache[I] = C; return C; } else if (I->Val.getLimitedValue() == 1) { - auto C = IC.getConst(APInt(TargetWidth, 1)); + auto C = IC.getConst(APInt(ResultWidth, 1)); InstCache[I] = C; return C; } else if (I->Val.isAllOnesValue()) { - auto C = IC.getConst(APInt::getAllOnesValue(TargetWidth)); + auto C = IC.getConst(APInt::getAllOnesValue(ResultWidth)); InstCache[I] = C; return C; } else { - auto C = IC.createSynthesisConstant(TargetWidth, I->Val.getLimitedValue()); + auto C = IC.createSynthesisConstant(ResultWidth, I->Val.getLimitedValue()); InstCache[I] = C; return C; } } else { + + if (I->K == Inst::Trunc) { + size_t Target = 0; + if (I->Ops[0]->Width == I->Width + 1) { + Target = ResultWidth + 1; + } else if (I->Ops[0]->Width == 2 * I->Width) { + Target = ResultWidth * 2; + } else { + // Maintain ratio + Target = ResultWidth * I->Ops[0]->Width * 1.0 / I->Width; + } + return IC.getInst(Inst::Trunc, ResultWidth, { ShrinkInst(I->Ops[0], I, Target)}); + } + if (I->K == Inst::ZExt || I->K == Inst::SExt) { + size_t Target = 0; + if (I->Ops[0]->Width == I->Width - 1) { + Target = ResultWidth - 1; + } else if (I->Ops[0]->Width == I->Width / 2) { + Target = ResultWidth / 2; + } else { + // Maintain ratio + Target = ResultWidth * I->Ops[0]->Width * 1.0 / I->Width; + } + return IC.getInst(I->K, ResultWidth, { ShrinkInst(I->Ops[0], I, Target)}); + } + std::vector Ops; for (auto Op : I->Ops) { - Ops.push_back(ShrinkInst(Op)); + Ops.push_back(ShrinkInst(Op, I, ResultWidth)); } return IC.getInst(I->K, InferWidth(I->K, Ops), Ops); } } std::optional operator()() { - // Find Sext, Zext, Trunc - std::vector WidthChangeInsts; - findInsts(Input.Mapping.LHS, WidthChangeInsts, [&](Inst *I) { - return I->K == Inst::SExt || I->K == Inst::ZExt || I->K == Inst::Trunc;}); - findInsts(Input.Mapping.RHS, WidthChangeInsts, [&](Inst *I) { - return I->K == Inst::SExt || I->K == Inst::ZExt || I->K == Inst::Trunc;}); - // Ignore PC for now + auto [CM, Aug] = AugmentForSymKBDB(Input, IC); - // This can be relaxed a bit - if (!WidthChangeInsts.empty() || Input.Mapping.LHS->Width <= TargetWidth) { - return {}; + if (!CM.empty()) { + Input = Aug; } // Abort if inputs are of <= Target width std::vector Inputs; + // TODO: Is there a better decision here? findVars(Input.Mapping.LHS, Inputs); for (auto I : Inputs) { if (I->Width <= TargetWidth) { @@ -480,10 +570,11 @@ struct ShrinkWrap { } ParsedReplacement New; - New.Mapping.LHS = ShrinkInst(Input.Mapping.LHS); - New.Mapping.RHS = ShrinkInst(Input.Mapping.RHS); + New.Mapping.LHS = ShrinkInst(Input.Mapping.LHS, nullptr, TargetWidth); + New.Mapping.RHS = ShrinkInst(Input.Mapping.RHS, nullptr, TargetWidth); for (auto PC : Input.PCs) { - New.PCs.push_back({ShrinkInst(PC.LHS), ShrinkInst(PC.RHS)}); + New.PCs.push_back({ShrinkInst(PC.LHS, nullptr, TargetWidth), + ShrinkInst(PC.RHS, nullptr, TargetWidth)}); } New.print(llvm::errs(), true); @@ -1480,8 +1571,6 @@ const std::vector> &ConstMap, return Results; } -using ConstMapT = std::vector>; - std::pair AugmentForSymDB(ParsedReplacement Original, InstContext &IC) { auto Input = Clone(Original, IC); @@ -1557,69 +1646,6 @@ AugmentForSymKB(ParsedReplacement Original, InstContext &IC) { // } -std::pair -AugmentForSymKBDB(ParsedReplacement Original, InstContext &IC) { - auto Input = Clone(Original, IC); - std::vector> ConstMap; - if (Input.Mapping.LHS->DemandedBits.getBitWidth() == Input.Mapping.LHS->Width && - !Input.Mapping.LHS->DemandedBits.isAllOnesValue()) { - auto DB = Input.Mapping.LHS->DemandedBits; - auto SymDFVar = IC.createVar(DB.getBitWidth(), "symDF_DB"); - // SymDFVar->Name = "symDF_DB"; - - SymDFVar->KnownOnes = llvm::APInt(DB.getBitWidth(), 0); - SymDFVar->KnownZeros = llvm::APInt(DB.getBitWidth(), 0); - // SymDFVar->Val = DB; - - Input.Mapping.LHS->DemandedBits.setAllBits(); - Input.Mapping.RHS->DemandedBits.setAllBits(); - - auto W = Input.Mapping.LHS->Width; - - Input.Mapping.LHS = IC.getInst(Inst::DemandedMask, W, {Input.Mapping.LHS, SymDFVar}); - Input.Mapping.RHS = IC.getInst(Inst::DemandedMask, W, {Input.Mapping.RHS, SymDFVar}); - - ConstMap.push_back({SymDFVar, DB}); - } - - std::vector Inputs; - findVars(Input.Mapping.LHS, Inputs); - - for (auto &&I : Inputs) { - auto Width = I->Width; - if (I->KnownZeros.getBitWidth() == I->Width && - I->KnownOnes.getBitWidth() == I->Width && - !(I->KnownZeros == 0 && I->KnownOnes == 0)) { - if (I->KnownZeros != 0) { - Inst *Zeros = IC.createVar(Width, "symDF_K0"); - - // Inst *AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(Width)); - // Inst *NotZeros = IC.getInst(Inst::Xor, Width, - // {Zeros, AllOnes}); - // Inst *VarNotZero = IC.getInst(Inst::Or, Width, {I, NotZeros}); - // Inst *ZeroBits = IC.getInst(Inst::Eq, 1, {VarNotZero, NotZeros}); - Inst *ZeroBits = IC.getInst(Inst::KnownZerosP, 1, {I, Zeros}); - Input.PCs.push_back({ZeroBits, IC.getConst(llvm::APInt(1, 1))}); - ConstMap.push_back({Zeros, I->KnownZeros}); - I->KnownZeros = llvm::APInt(I->Width, 0); - } - - if (I->KnownOnes != 0) { - Inst *Ones = IC.createVar(Width, "symDF_K1"); - // Inst *VarAndOnes = IC.getInst(Inst::And, Width, {I, Ones}); - // Inst *OneBits = IC.getInst(Inst::Eq, 1, {VarAndOnes, Ones}); - Inst *OneBits = IC.getInst(Inst::KnownOnesP, 1, {I, Ones}); - Input.PCs.push_back({OneBits, IC.getConst(llvm::APInt(1, 1))}); - ConstMap.push_back({Ones, I->KnownOnes}); - I->KnownOnes = llvm::APInt(I->Width, 0); - } - } - } - - return {ConstMap, Input}; -} - - std::vector> InferSpecialConstExprsWithConcretes(std::vector RHS, const std::vector> &ConstMap, @@ -2118,78 +2144,25 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } if (SymbolicDF) { - bool canTrySymDB = false; - bool canTrySymKB = false; - - Refresh("PUSH SYMDF_DB"); - auto [SymDBConstMap, Augmented] = AugmentForSymDB(Input, IC); - canTrySymDB = !SymDBConstMap.empty(); - if (canTrySymDB) { - // bool SymDFChanged = false; - // Augmented.print(llvm::errs(), true); - // auto Clone = Verify(Augmented, IC, S); - // if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - // // Symbolic demanded bits can be unconstrained - // return Clone; - // } - - // auto Generalized = SuccessiveSymbolize(IC, S, Augmented, SymDFChanged, SymDBConstMap); - // if (SymDFChanged) { - // return Generalized; - // } - } - Refresh("POP SYMDF_DB"); - - Refresh("PUSH SYMDF_KB"); - { - auto [SymKBConstMap, Augmented] = AugmentForSymKB(Input, IC); - canTrySymKB = !SymKBConstMap.empty(); - - // auto Clone = Verify(Augmented, IC, S); - // if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - // // Symbolic known bits can be unconstrained - // return Clone; - // } - - // if (canTrySymKB) { - // bool SymDFChanged = false; - // // Augmented.print(llvm::errs(), true); - // auto Generalized = SuccessiveSymbolize(IC, S, Augmented, - // SymDFChanged, SymKBConstMap); - // if (SymDFChanged) { - // return Generalized; - // } - // } - } - Refresh("POP SYMDF_KB"); - - - - if (canTrySymDB && canTrySymKB) { Refresh("PUSH SYMDF_KB_DB"); auto [CM, Aug] = AugmentForSymKBDB(Input, IC); // auto [CM2, Aug2] = AugmentForSymKB(Aug1, IC); - bool SymDFChanged = false; - - // Aug2.print(llvm::errs(), true); + if (!CM.empty()) { + bool SymDFChanged = false; - // for (auto P : CM1) { - // CM2.push_back(P); - // } - - auto Clone = Verify(Aug, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - // Symbolic db+kb can be unconstrained - // very unlikely? test if needed - return Clone; - } + auto Clone = Verify(Aug, IC, S); + if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + // Symbolic db+kb can be unconstrained + // very unlikely? test if needed + return Clone; + } - auto Generalized = SuccessiveSymbolize(IC, S, Aug, SymDFChanged, CM); - if (SymDFChanged) { - return Generalized; + auto Generalized = SuccessiveSymbolize(IC, S, Aug, SymDFChanged, CM); + if (SymDFChanged) { + return Generalized; + } } Refresh("POP SYMDF_KB_DB"); - } } From d376a99a6334d087d64aae5c9d2d3f007b9d063f Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 21 Mar 2023 11:10:14 -0600 Subject: [PATCH 148/165] foo --- include/souper/Infer/SynthUtils.h | 7 +- lib/Infer/AliveDriver.cpp | 2 +- lib/Infer/ConstantSynthesis.cpp | 15 +-- lib/Infer/SynthUtils.cpp | 2 +- tools/generalize.cpp | 193 +++++++++++++++++++++++++----- utils/parallel.sh | 3 +- 6 files changed, 172 insertions(+), 50 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index a1f59559c..7d1707b54 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -68,13 +68,18 @@ class Builder { auto AllOnes = IC.getConst(llvm::APInt::getAllOnesValue(L->Width)); return Builder(IC.getInst(Inst::Xor, L->Width, {L, AllOnes}), IC); } + Builder Negate() { + auto L = I; + auto Zero = IC.getConst(llvm::APInt(L->Width, 0)); + return Builder(IC.getInst(Inst::Sub, L->Width, {Zero, L}), IC); + } #define UNOPW(K) \ Builder K(size_t W) { \ auto L = I; \ return Builder(IC.getInst(Inst::K, W, {L}), IC); \ } - UNOPW(ZExt) + UNOPW(ZExt) UNOPW(SExt) UNOPW(Trunc) #undef UNOPW private: diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index 8322cf545..52814037a 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -474,7 +474,6 @@ bool souper::AliveDriver::verify (Inst *RHS, Inst *RHSAssumptions) { size_t correct = 0; size_t incorrect = 0; for (; types; ++types) { - tv.fixupTypes(types); if (auto errs = tv.verify()) { if (DebugLevel > 4) { @@ -534,6 +533,7 @@ bool souper::AliveDriver::verify (Inst *RHS, Inst *RHSAssumptions) { bool souper::AliveDriver::translateRoot(const souper::Inst *I, const Inst *PC, IR::Function &F, Cache &ExprCache) { + if (!translateAndCache(I, F, ExprCache)) { return false; } diff --git a/lib/Infer/ConstantSynthesis.cpp b/lib/Infer/ConstantSynthesis.cpp index 17b83fa00..16882fdac 100644 --- a/lib/Infer/ConstantSynthesis.cpp +++ b/lib/Infer/ConstantSynthesis.cpp @@ -232,21 +232,10 @@ Inst *getConstConstraint(Inst::Kind K, unsigned OpNum, Inst *C, IC.getInst(Inst::Ne, 1, { IC.getConst(llvm::APInt::getSignedMinValue(C->Width)), C }) }); - case Inst::LogB: - case Inst::Freeze: - case Inst::Eq: - case Inst::Ne: - case Inst::SAddO: - case Inst::UAddO: - case Inst::SSubO: - case Inst::USubO: - case Inst::SMulO: - case Inst::UMulO: case Inst::Select: // handled elsewhere: 2nd and 3rd arguments can't be same constant - // no constraint - return IC.getConst(llvm::APInt(1, true)); default: - llvm::report_fatal_error("unmatched: " + (std::string)Inst::getKindName(K)); + // no constraint + return IC.getConst(llvm::APInt(1, true)); } } diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index b69f86444..0282df117 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -101,7 +101,7 @@ ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { // return Input; // } // } - + // Input.print(llvm::errs(), true); Input = Clone(Input, IC); std::set ConstSet; souper::getConstants(Input.Mapping.RHS, ConstSet); diff --git a/tools/generalize.cpp b/tools/generalize.cpp index dc7176b20..d85c7e6c9 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -130,10 +130,13 @@ size_t InferWidth(Inst::Kind K, const std::vector &Ops) { switch (K) { case Inst::KnownOnesP: case Inst::KnownZerosP: + case Inst::Eq: + case Inst::Ne: case Inst::Slt: case Inst::Sle: case Inst::Ult: case Inst::Ule: return 1; + case Inst::Select: return Ops[1]->Width; default: return Ops[0]->Width; } } @@ -238,7 +241,7 @@ struct InfixPrinter { if (UseCount[I] > 1) { std::string Name = "var" + std::to_string(varnum++); Syms[I] = Name; - S << "let " << Name << " = "; + S << "(let " << Name << " = "; } if (I->K == Inst::Const) { @@ -370,7 +373,7 @@ struct InfixPrinter { Result = Ret; } if (UseCount[I] > 1) { - S << Result << ";\n"; + S << Result << ")"; return Syms[I]; } else { return Result; @@ -472,6 +475,55 @@ AugmentForSymKBDB(ParsedReplacement Original, InstContext &IC) { return {ConstMap, Input}; } +bool typeCheck(Inst *I) { + if (I->Ops.size() == 2) { + if (I->Ops[0]->Width != I->Ops[1]->Width) { + if (DebugLevel > 4) llvm::errs() << "Operands must have the same width\n"; + return false; + } + } + if (I->K == Inst::Select) { + if (I->Ops[0]->Width != 1) { + if (DebugLevel > 4) llvm::errs() << "Select condition must be 1 bit wide\n"; + return false; + } + if (I->Ops[1]->Width != I->Ops[2]->Width) { + if (DebugLevel > 4) llvm::errs() << "Select operands must have the same width\n"; + return false; + } + } + if (Inst::isCmp(I->K)) { + if (I->Width != 1) { + if (DebugLevel > 4) llvm::errs() << "Comparison must be 1 bit wide\n"; + return false; + } + } + return true; +} +bool typeCheck(ParsedReplacement &R) { + if (R.Mapping.LHS->Width != R.Mapping.RHS->Width) { + if (DebugLevel > 4) llvm::errs() << "LHS and RHS must have the same width\n"; + return false; + } + + if (!typeCheck(R.Mapping.LHS)) { + return false; + } + if (!typeCheck(R.Mapping.RHS)) { + return false; + } + + for (auto &&PC : R.PCs) { + if (!typeCheck(PC.LHS)) { + return false; + } + if (!typeCheck(PC.RHS)) { + return false; + } + } + return true; +} + struct ShrinkWrap { ShrinkWrap(InstContext &IC, Solver *S, ParsedReplacement Input, size_t TargetWidth = 8) : IC(IC), S(S), Input(Input), @@ -517,17 +569,25 @@ struct ShrinkWrap { return C; } } else { - if (I->K == Inst::Trunc) { size_t Target = 0; + // llvm::errs() << "HERE: " << I->Width << " " << I->Ops[0]->Width << '\n'; if (I->Ops[0]->Width == I->Width + 1) { + // llvm::errs() << "a\n"; Target = ResultWidth + 1; } else if (I->Ops[0]->Width == 2 * I->Width) { Target = ResultWidth * 2; + // llvm::errs() << "b\n"; + } else if (I->Width == 1 && I->Ops[0]->Width != 1) { + // llvm::errs() << "c\n"; + Target = TargetWidth; + ResultWidth = 1; } else { // Maintain ratio + // llvm::errs() << "d\n"; Target = ResultWidth * I->Ops[0]->Width * 1.0 / I->Width; } + // llvm::errs() << "HERE: " << ResultWidth << " " << Target << '\n'; return IC.getInst(Inst::Trunc, ResultWidth, { ShrinkInst(I->Ops[0], I, Target)}); } if (I->K == Inst::ZExt || I->K == Inst::SExt) { @@ -536,6 +596,8 @@ struct ShrinkWrap { Target = ResultWidth - 1; } else if (I->Ops[0]->Width == I->Width / 2) { Target = ResultWidth / 2; + } else if (I->Ops[0]->Width == 1) { + Target = 1; } else { // Maintain ratio Target = ResultWidth * I->Ops[0]->Width * 1.0 / I->Width; @@ -543,6 +605,13 @@ struct ShrinkWrap { return IC.getInst(I->K, ResultWidth, { ShrinkInst(I->Ops[0], I, Target)}); } + if (I->K == Inst::Eq || I->K == Inst::Ne || + I->K == Inst::Ult || I->K == Inst::Slt || + I->K == Inst::Ule || I->K == Inst::Sle || + I->K == Inst::KnownOnesP || I->K == Inst::KnownZerosP) { + ResultWidth = TargetWidth; + } + std::vector Ops; for (auto Op : I->Ops) { Ops.push_back(ShrinkInst(Op, I, ResultWidth)); @@ -567,6 +636,9 @@ struct ShrinkWrap { if (I->Width <= TargetWidth) { return {}; } + if (!I->Range.isFullSet()) { + return {}; + } } ParsedReplacement New; @@ -577,8 +649,11 @@ struct ShrinkWrap { ShrinkInst(PC.RHS, nullptr, TargetWidth)}); } - New.print(llvm::errs(), true); - + // New.print(llvm::errs(), true); + if (!typeCheck(New)) { + llvm::errs() << "Type check failed\n"; + return {}; + } auto Clone = Verify(New, IC, S); if (Clone.Mapping.LHS) { return Clone; @@ -723,6 +798,9 @@ std::vector InferConstantLimits( if (XI == YI) { continue; } + if (XI->Width != YI->Width) { + continue; + } auto Sum = Builder(XI, IC).Add(YI)(); // Sum related to width auto Width = Builder(Sum, IC).BitWidth(); @@ -1335,14 +1413,40 @@ FirstValidCombination(ParsedReplacement Input, return Input; } + + std::vector IOSynthesize(llvm::APInt Target, const std::vector> &ConstMap, InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) { std::vector Results; - // Just symbolic or Concrete constant + // Handle width changes + for (const auto &[I, Val] : ConstMap) { + if (Target.getBitWidth() == I->Width) { + continue; + } + + llvm::APInt NewTarget = Target; + if (Target.getBitWidth() < I->Width) { + NewTarget = Target.sgt(0) ? Target.zext(I->Width) : Target.sext(I->Width); + } else { + NewTarget = Target.trunc(I->Width); + } + for (auto X : IOSynthesize(NewTarget, ConstMap, IC, Threshold - 1, ConstMode, nullptr)) { + ReplacementContext RC; + RC.printInst(X, llvm::errs(), true); + if (X->Width < Target.getBitWidth()) { + Results.push_back(Builder(IC, X).Trunc(Target.getBitWidth())()); + } else { + Results.push_back(Builder(IC, X).SExt(Target.getBitWidth())()); + Results.push_back(Builder(IC, X).ZExt(Target.getBitWidth())()); + } + } + } + + // Just symbolic or Concrete constant for (const auto &[I, Val] : ConstMap) { if (I == ParentConst) { continue; @@ -1353,7 +1457,12 @@ InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) if (!ConstMode) { if (Val == Target) { Results.push_back(I); + } else if (Val == 0 - Target) { + Results.push_back(Builder(IC, I).Negate()()); + } else if (Val == ~Target) { + Results.push_back(Builder(IC, I).Flip()()); } + auto One = llvm::APInt(I->Width, 1); if (One.shl(Val) == Target) { Results.push_back(Builder(IC, One).Shl(I)()); @@ -1736,6 +1845,20 @@ void findDangerousConstants(Inst *I, std::set &Results) { } } +// TODO: memoize +bool hasMultiArgumentPhi(Inst *I) { + if (I->K == Inst::Phi) { + return I->Ops.size() > 1; + } + for (auto Op : I->Ops) { + if (hasMultiArgumentPhi(Op)) { + return true; + } + } + return false; +} + + // Assuming the input has leaves pruned and preconditions weakened ParsedReplacement SuccessiveSymbolize(InstContext &IC, Solver *S, ParsedReplacement Input, bool &Changed, @@ -1745,8 +1868,8 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Prelude bool Nested = !ConstMap.empty(); - if (!NoWidth && !Nested) { - ShrinkWrap Shrink(IC, S, Input, 4); + if (!NoWidth && !Nested && !hasMultiArgumentPhi(Input.Mapping.LHS)) { + ShrinkWrap Shrink(IC, S, Input, 8); auto Smol = Shrink(); if (Smol) { if (DebugLevel > 2) { @@ -1760,6 +1883,10 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Input.print(llvm::errs(), true); + } else { + if (DebugLevel > 2) { + llvm::errs() << "Shrinking failed\n"; + } } } @@ -1832,7 +1959,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, for (auto C : LHSConsts) { CommonConsts[C] = SymConstMap[C]; - llvm::errs() << "Common Const: " << C->Val << "\t" << SymConstMap[C]->Name << "\n"; + // llvm::errs() << "Common Const: " << C->Val << "\t" << SymConstMap[C]->Name << "\n"; } if (!CommonConsts.empty()) { @@ -2022,8 +2149,8 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (RHSFresh.size() == 1 && !Nested) { // Enumerated Expressions with some relational constraints if (ConstMap.size() == 2) { - llvm::errs() << "Enum2 : " << EnumeratedCandidatesTwoInsts.back().size() - << "\tRels: " << Relations.size() << "\n"; + // llvm::errs() << "Enum2 : " << EnumeratedCandidatesTwoInsts.back().size() + // << "\tRels: " << Relations.size() << "\n"; auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, InstCache, IC, S, SymCS, true, false, false, Relations); if (Clone.Mapping.LHS && Clone.Mapping.RHS) { @@ -2209,37 +2336,37 @@ Inst *CombinePCs(const std::vector &PCs, InstContext &IC) { ParsedReplacement InstantiateWidthChecks(InstContext &IC, Solver *S, ParsedReplacement Input) { - // TODO: minimize width? - // Instantiate Alive driver with Symbolic width. - AliveDriver Alive(Input.Mapping.LHS, - Input.PCs.empty() ? nullptr : CombinePCs(Input.PCs, IC), - IC, {}, true); + if (!hasMultiArgumentPhi(Input.Mapping.LHS)) { + // Instantiate Alive driver with Symbolic width. + AliveDriver Alive(Input.Mapping.LHS, + Input.PCs.empty() ? nullptr : CombinePCs(Input.PCs, IC), + IC, {}, true); - // Find set of valid widths. - if (Alive.verify(Input.Mapping.RHS)) { - if (DebugLevel > 4) { - llvm::errs() << "WIDTH: Generalized opt is valid for all widths.\n"; + // Find set of valid widths. + if (Alive.verify(Input.Mapping.RHS)) { + if (DebugLevel > 4) { + llvm::errs() << "WIDTH: Generalized opt is valid for all widths.\n"; + } + // Completely width independent. No width checks needed. + return Input; } - // Completely width independent. No width checks needed. - return Input; - } - auto &&ValidTypings = Alive.getValidTypings(); + auto &&ValidTypings = Alive.getValidTypings(); - if (ValidTypings.empty()) { - // Something went wrong, generalized opt is not valid at any width. - if (DebugLevel > 4) { - llvm::errs() << "WIDTH: Generalized opt is not valid for any width.\n"; + if (ValidTypings.empty()) { + // Something went wrong, generalized opt is not valid at any width. + if (DebugLevel > 4) { + llvm::errs() << "WIDTH: Generalized opt is not valid for any width.\n"; + } + Input.Mapping.LHS = nullptr; + Input.Mapping.RHS = nullptr; + return Input; } - Input.Mapping.LHS = nullptr; - Input.Mapping.RHS = nullptr; - return Input; - } // Abstract width to a range or relational precondition // TODO: Abstraction - + } // If abstraction fails, insert checks for existing widths. std::vector Inputs; diff --git a/utils/parallel.sh b/utils/parallel.sh index 20a702c00..1a165036d 100755 --- a/utils/parallel.sh +++ b/utils/parallel.sh @@ -5,6 +5,7 @@ indir=${@: -1} # Last argument cmd=${*%${!#}} # All but the last argument mkdir -p "${indir}r" +mkdir -p "${indir}d" rm "${indir}r"/* cp "${indir}"/* "${indir}r" @@ -12,7 +13,7 @@ cp "${indir}"/* "${indir}r" mkdir -p "${indir}t" rm "${indir}t"/* -for i in `ls -v $indir/*`; do echo "timeout 300" $cmd $i " > " ${indir}t/`basename $i` " && cp " ${indir}t/`basename $i` ${indir}r/ ;done > /tmp/cmdfile.txt +for i in `ls -v $indir/*`; do echo "timeout 300" $cmd $i " > " ${indir}t/`basename $i` " 2> " ${indir}d/`basename $i` " && cp " ${indir}t/`basename $i` ${indir}r/ ;done > /tmp/cmdfile.txt # for i in `ls -v $indir/*`; do echo "timeout 300" $cmd $i " > " ${indir}r/`basename $i`;done > /tmp/cmdfile.txt From 10fa8fb74ec5be5a79ea2820c80c417d33e08fc7 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 21 Mar 2023 23:16:24 -0600 Subject: [PATCH 149/165] foo --- test/Generalize/maskoff.opt | 4 ++-- tools/generalize.cpp | 35 +++++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/test/Generalize/maskoff.opt b/test/Generalize/maskoff.opt index 5a20e6d85..1403806a7 100644 --- a/test/Generalize/maskoff.opt +++ b/test/Generalize/maskoff.opt @@ -8,6 +8,6 @@ cand %2 %3 -; CHECK: (v0:i32 << C1:i32) >> C1 +; CHECK: (v0:i32 << C1:i32) >>l C1 ; CHECK: => -; CHECK: v0 & (-1 >>l C1) \ No newline at end of file +; CHECK: v0 & (sext(1) >>l C1) \ No newline at end of file diff --git a/tools/generalize.cpp b/tools/generalize.cpp index d85c7e6c9..c2cadb9ec 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -802,11 +802,11 @@ std::vector InferConstantLimits( continue; } auto Sum = Builder(XI, IC).Add(YI)(); - // Sum related to width - auto Width = Builder(Sum, IC).BitWidth(); - Results.push_back(Builder(Sum, IC).Ult(Width)()); - Results.push_back(Builder(Sum, IC).Ule(Width)()); - Results.push_back(Builder(Sum, IC).Eq(Width)()); + // // Sum related to width + // auto Width = Builder(Sum, IC).BitWidth(); + // Results.push_back(Builder(Sum, IC).Ult(Width)()); + // Results.push_back(Builder(Sum, IC).Ule(Width)()); + // Results.push_back(Builder(Sum, IC).Eq(Width)()); // Sum less than const, Sum greater= than const for (auto C : ConcreteConsts) { @@ -1008,8 +1008,8 @@ std::vector InferPotentialRelations( } Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth().Sub(1))()); - Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth().UDiv(2))()); - Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth())()); + // Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth().UDiv(2))()); + // Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth())()); } // TODO: Make sure this works. @@ -1446,7 +1446,6 @@ InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) } } - // Just symbolic or Concrete constant for (const auto &[I, Val] : ConstMap) { if (I == ParentConst) { continue; @@ -1463,10 +1462,26 @@ InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) Results.push_back(Builder(IC, I).Flip()()); } + // llvm::errs() << "Trying to synthesize " << Target << " from " << Val << "\n"; + auto One = llvm::APInt(I->Width, 1); + // llvm::errs() << "1: " << One.shl(Val) << "\n"; if (One.shl(Val) == Target) { Results.push_back(Builder(IC, One).Shl(I)()); } + auto MinusOneVal = llvm::APInt::getAllOnesValue(I->Width); + + auto OneBitOne = llvm::APInt(1, 1); + auto MinusOne = Builder(IC, OneBitOne).SExt(I->Width)(); + + // llvm::errs() << "2: " << MinusOne.shl(Val) << "\n"; + if (MinusOneVal.shl(Val) == Target) { + Results.push_back(Builder(IC, MinusOne).Shl(I)()); + } + // llvm::errs() << "3: " << MinusOne.lshr(Val) << "\n"; + if (MinusOneVal.lshr(Val) == Target) { + Results.push_back(Builder(IC, MinusOne).LShr(I)()); + } } else { if (ParentConst) { Results.push_back(Builder(IC, Target)()); @@ -2336,6 +2351,10 @@ Inst *CombinePCs(const std::vector &PCs, InstContext &IC) { ParsedReplacement InstantiateWidthChecks(InstContext &IC, Solver *S, ParsedReplacement Input) { + Input.print(llvm::errs(), true); + InfixPrinter IP(Input, true); + llvm::errs() << "WIDTH: Instantiating width checks.\n"; + IP(llvm::errs()); if (!hasMultiArgumentPhi(Input.Mapping.LHS)) { // Instantiate Alive driver with Symbolic width. From 6d30a9c10a0585eafd55ab32facbfda057902f07 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 22 Mar 2023 00:02:13 -0600 Subject: [PATCH 150/165] foo --- tools/generalize.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index c2cadb9ec..b4799b557 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -227,6 +227,14 @@ struct InfixPrinter { return Syms[I]; } + std::ostringstream OS; + + if (UseCount[I] > 1) { + std::string Name = "var" + std::to_string(varnum++); + Syms[I] = Name; + OS << "let " << Name << " = "; + } + // x ^ -1 => ~x if (I->K == Inst::Xor && I->Ops[1]->K == Inst::Const && I->Ops[1]->Val.isAllOnesValue()) { @@ -237,13 +245,6 @@ struct InfixPrinter { return "~" + printInst(I->Ops[1], S); } - - if (UseCount[I] > 1) { - std::string Name = "var" + std::to_string(varnum++); - Syms[I] = Name; - S << "(let " << Name << " = "; - } - if (I->K == Inst::Const) { if (I->Val.ule(16)) { return I->Val.toString(10, false); @@ -373,7 +374,8 @@ struct InfixPrinter { Result = Ret; } if (UseCount[I] > 1) { - S << Result << ")"; + OS << Result << ";\n"; + S << OS.str(); return Syms[I]; } else { return Result; @@ -1423,7 +1425,7 @@ InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) // Handle width changes for (const auto &[I, Val] : ConstMap) { - if (Target.getBitWidth() == I->Width) { + if (Target.getBitWidth() == I->Width || !Threshold ) { continue; } @@ -1434,9 +1436,8 @@ InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) NewTarget = Target.trunc(I->Width); } for (auto X : IOSynthesize(NewTarget, ConstMap, IC, Threshold - 1, ConstMode, nullptr)) { - ReplacementContext RC; - RC.printInst(X, llvm::errs(), true); - + // ReplacementContext RC; + // RC.printInst(X, llvm::errs(), true); if (X->Width < Target.getBitWidth()) { Results.push_back(Builder(IC, X).Trunc(Target.getBitWidth())()); } else { From b70314656b37e574990645114e098c8c44e7436c Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 2 Apr 2023 19:22:00 -0600 Subject: [PATCH 151/165] foo --- include/souper/Infer/Interpreter.h | 3 + include/souper/Inst/Inst.h | 2 +- lib/Infer/AliveDriver.cpp | 2 +- lib/Infer/Interpreter.cpp | 7 + lib/Infer/SynthUtils.cpp | 66 +++++++ lib/Inst/Inst.cpp | 4 +- tools/generalize.cpp | 256 +++++++++++++++++--------- tools/matcher-gen.cpp | 115 +++++++++--- tools/pass-generator/src/template.cpp | 61 ++++-- 9 files changed, 389 insertions(+), 127 deletions(-) diff --git a/include/souper/Infer/Interpreter.h b/include/souper/Infer/Interpreter.h index 0041ac9e5..d07353b38 100644 --- a/include/souper/Infer/Interpreter.h +++ b/include/souper/Infer/Interpreter.h @@ -124,6 +124,9 @@ EvalValue evaluateAShr(llvm::APInt A, llvm::APInt B); } void setEvalPhiFirstBranch() {EvalPhiFirstBranch = true;}; EvalValue evaluateInst(Inst *Root); + + void printCache(llvm::raw_ostream &Out); + }; } diff --git a/include/souper/Inst/Inst.h b/include/souper/Inst/Inst.h index 084ecb5f5..97326eb15 100644 --- a/include/souper/Inst/Inst.h +++ b/include/souper/Inst/Inst.h @@ -290,7 +290,7 @@ struct SynthesisContext { unsigned Timeout; }; -int cost(Inst *I, bool IgnoreDepsWithExternalUses = false); +int cost(Inst *I, bool IgnoreDepsWithExternalUses = false, std::set Ignore = {}); int backendCost(Inst *I, bool IgnoreDepsWithExternalUses = false); int countHelper(Inst *I, std::set &Visited); int instCount(Inst *I); diff --git a/lib/Infer/AliveDriver.cpp b/lib/Infer/AliveDriver.cpp index 52814037a..1e010dd2a 100644 --- a/lib/Infer/AliveDriver.cpp +++ b/lib/Infer/AliveDriver.cpp @@ -820,7 +820,7 @@ bool souper::AliveDriver::translateAndCache(const souper::Inst *I, // TODO: Desugar log2. Alive2 only supports log2 for concrete constants. default:{ - llvm::outs() << "Unsupported Instruction Kind : " << I->getKindName(I->K) << "\n"; + llvm::errs() << "Unsupported Instruction Kind : " << I->getKindName(I->K) << "\n"; return false; } } diff --git a/lib/Infer/Interpreter.cpp b/lib/Infer/Interpreter.cpp index 38b990dbb..ad306bea1 100644 --- a/lib/Infer/Interpreter.cpp +++ b/lib/Infer/Interpreter.cpp @@ -489,4 +489,11 @@ namespace souper { Cache[Root] = Result; return Result; } + + void ConcreteInterpreter::printCache(llvm::raw_ostream &Out) { + for (auto &&KV : Cache) { + Out << KV.first->Name << " = " << KV.second.getValue() << '\n'; + } + } + } diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index 0282df117..206bd78a2 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -208,6 +208,7 @@ std::vector> findValidConsts(ParsedReplacement Inp ValueCache GetCEX(const ParsedReplacement &Input, InstContext &IC, Solver *S) { std::vector Vars; findVars(Input.Mapping.LHS, Vars); + findVars(Input.Mapping.RHS, Vars); std::vector> Models; bool IsValid; if (auto EC = S->isValid(IC, Input.BPCs, Input.PCs, Input.Mapping, IsValid, &Models)) { @@ -228,7 +229,72 @@ ValueCache GetCEX(const ParsedReplacement &Input, InstContext &IC, Solver *S) { } } +// ParsedReplacement MakeDummyConstexprs(ParsedReplacement Input, InstContext &IC) { +// std::map InstCache; + +// std::vector Stack{Input.Mapping.RHS}; + +// std::set Visited; + +// size_t DummyConstID = 0; + +// // DFS to find all RHS constants +// while (!Stack.empty()) { +// auto I = Stack.back(); +// Stack.pop_back(); +// Visited.insert(I); + +// if (I->K == Inst::Const) { +// if (InstCache.find(I) == InstCache.end()) { +// InstCache[I] = IC.createVar(I->Width, "dummy" + std::to_string(DummyConstID++)); +// } +// } else { +// for (auto &&Op : I->Ops) { +// if (Visited.find(Op) == Visited.end()) { +// Stack.push_back(Op); +// } +// } +// } +// } +// if (!InstCache.empty()) { +// Input.Mapping.RHS = Replace(Input.Mapping.RHS, IC, InstCache); +// } +// return Input; +// } + +bool hasRHSConsts(ParsedReplacement Input) { + std::vector Stack{Input.Mapping.RHS}; + + std::set Visited; + + // DFS to find all RHS constants + while (!Stack.empty()) { + auto I = Stack.back(); + Stack.pop_back(); + Visited.insert(I); + + if (I->K == Inst::Const) { + return true; + } else { + for (auto &&Op : I->Ops) { + if (Visited.find(Op) == Visited.end()) { + Stack.push_back(Op); + } + } + } + } + return false; +} + std::vector GetMultipleCEX(ParsedReplacement Input, InstContext &IC, Solver *S, size_t MaxCount = 2) { + // auto Input = MakeDummyConstexprs(Original, IC); + + // Is there a way to get a CEX when there are RHS constants? + + if (hasRHSConsts(Input)) { + return {}; + } + std::vector Results; while (MaxCount--) { auto &&Result = GetCEX(Input, IC, S); diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index e0eb46566..b56b74a72 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -994,8 +994,8 @@ static int costHelper(Inst *I, Inst *Root, std::set &Visited, return Cost; } -int souper::cost(Inst *I, bool IgnoreDepsWithExternalUses) { - std::set Visited; +int souper::cost(Inst *I, bool IgnoreDepsWithExternalUses, std::set Ignore) { + std::set Visited = Ignore; return costHelper(I, I, Visited, IgnoreDepsWithExternalUses); } diff --git a/tools/generalize.cpp b/tools/generalize.cpp index b4799b557..974554c2e 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -500,6 +500,18 @@ bool typeCheck(Inst *I) { return false; } } + if (I->K == Inst::Trunc) { + if (I->Ops[0]->Width <= I->Width) { + if (DebugLevel > 4) llvm::errs() << "Trunc operand must be wider than result\n"; + return false; + } + } + if (I->K == Inst::ZExt || I->K == Inst::SExt) { + if (I->Ops[0]->Width >= I->Width) { + if (DebugLevel > 4) llvm::errs() << "Ext operand must be narrower than result\n"; + return false; + } + } return true; } bool typeCheck(ParsedReplacement &R) { @@ -714,11 +726,6 @@ std::vector FilterRelationsByValue(const std::vector &Relations, ValueCache[I] = EvalValue(V); } - // for (auto P : CEX) { - // llvm::errs() << "CEX: " << P.first->Name << ' ' - // << P.second.getValue().toString(2, false) << "\n"; - // } - ConcreteInterpreter CPos(ValueCache); std::vector CNegs; for (auto &&CEX : CEXs) { @@ -771,18 +778,18 @@ std::vector InferConstantLimits( for (auto &&[XI, XC] : CMap) { // X < Width, X <= Width auto Width = Builder(XI, IC).BitWidth(); - Results.push_back(Builder(XI, IC).Ult(Width)()); - Results.push_back(Builder(XI, IC).Ule(Width)()); + // Results.push_back(Builder(XI, IC).Ult(Width)()); + // Results.push_back(Builder(XI, IC).Ule(Width)()); // X slt SMAX, x ult UMAX auto WM1 = Width.Sub(1); auto SMax = Builder(IC, llvm::APInt(XI->Width, 1)).Shl(WM1).Sub(1)(); Results.push_back(Builder(XI, IC).Slt(SMax)()); - auto gZ = Builder(XI, IC).Ugt(0)(); + // auto gZ = Builder(XI, IC).Ugt(0)(); - Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); - Results.push_back(Builder(XI, IC).Ule(Width).And(gZ)()); + // Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); + // Results.push_back(Builder(XI, IC).Ule(Width).And(gZ)()); // 2 * X < C, 2 * X >= C for (auto C : ConcreteConsts) { @@ -930,6 +937,10 @@ std::vector InferPotentialRelations( continue; } + if (~XC == YC) { + Results.push_back(Builder(XI, IC).Flip().Eq(YI)()); + } + // if (C2 && XC == YC) { // Results.push_back(Builder(XI, IC).Eq(YI)()); // } @@ -980,25 +991,25 @@ std::vector InferPotentialRelations( } } - // TODO Check if this is too slow - // if (Input.Mapping.LHS->Width == 1) { - // need both signed and unsigned? - // What about s/t/e/ versions? - if (XC.slt(YC)) Results.push_back(Builder(XI, IC).Slt(YI)()); - if (XC.ult(YC)) Results.push_back(Builder(XI, IC).Ult(YI)()); - if (YC.slt(XC)) Results.push_back(Builder(YI, IC).Slt(XI)()); - if (YC.ult(XC)) Results.push_back(Builder(YI, IC).Ult(XI)()); - // } + // // TODO Check if this is too slow + // // if (Input.Mapping.LHS->Width == 1) { + // // need both signed and unsigned? + // // What about s/t/e/ versions? + // if (XC.slt(YC)) Results.push_back(Builder(XI, IC).Slt(YI)()); + // if (XC.ult(YC)) Results.push_back(Builder(XI, IC).Ult(YI)()); + // if (YC.slt(XC)) Results.push_back(Builder(YI, IC).Slt(XI)()); + // if (YC.ult(XC)) Results.push_back(Builder(YI, IC).Ult(XI)()); + // // } - auto XBits = BitFuncs(XI, IC); - auto YBits = BitFuncs(YI, IC); + // auto XBits = BitFuncs(XI, IC); + // auto YBits = BitFuncs(YI, IC); - for (auto &&XBit : XBits) { - for (auto &&YBit : YBits) { - Results.push_back(Builder(XBit, IC).Ule(YBit)()); - Results.push_back(Builder(XBit, IC).Ult(YBit)()); - } - } + // for (auto &&XBit : XBits) { + // for (auto &&YBit : YBits) { + // Results.push_back(Builder(XBit, IC).Ule(YBit)()); + // Results.push_back(Builder(XBit, IC).Ult(YBit)()); + // } + // } // No example yet where this is useful // for (auto &&XBit : XBits) { @@ -1438,11 +1449,11 @@ InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) for (auto X : IOSynthesize(NewTarget, ConstMap, IC, Threshold - 1, ConstMode, nullptr)) { // ReplacementContext RC; // RC.printInst(X, llvm::errs(), true); - if (X->Width < Target.getBitWidth()) { - Results.push_back(Builder(IC, X).Trunc(Target.getBitWidth())()); - } else { - Results.push_back(Builder(IC, X).SExt(Target.getBitWidth())()); + if (I->Width < X->Width) { Results.push_back(Builder(IC, X).ZExt(Target.getBitWidth())()); + Results.push_back(Builder(IC, X).SExt(Target.getBitWidth())()); + } else { + Results.push_back(Builder(IC, X).Trunc(Target.getBitWidth())()); } } } @@ -1874,6 +1885,50 @@ bool hasMultiArgumentPhi(Inst *I) { return false; } +ParsedReplacement ReduceBasic(InstContext &IC, + Solver *S, ParsedReplacement Input) { + Reducer R(IC, S); + Input = R.ReducePCs(Input); + Input = R.ReduceRedundantPhis(Input); + Input = R.ReduceGreedy(Input); + Input = R.ReducePairsGreedy(Input); + Input = R.ReduceTriplesGreedy(Input); + Input = R.WeakenKB(Input); + Input = R.WeakenCR(Input); + Input = R.WeakenDB(Input); + Input = R.WeakenOther(Input); + if (ReduceKBIFY) { + Input = R.ReduceGreedyKBIFY(Input); + } + Input = R.ReducePCs(Input); + Input = R.ReducePCsToDF(Input); + return Input; +} + +ParsedReplacement DeAugment(InstContext &IC, + Solver *S, ParsedReplacement Augmented) { + auto Result = ReduceBasic(IC, S, Augmented); + Inst *SymDBVar = nullptr; + if (Result.Mapping.LHS->K == Inst::DemandedMask) { + SymDBVar = Result.Mapping.LHS->Ops[1]; + } + + if (!SymDBVar) { + return Result; + } + + auto LHSUses = CountUses(Result.Mapping.LHS); + auto RHSUses = CountUses(Result.Mapping.RHS); + + if (LHSUses[SymDBVar] == 1 && RHSUses[SymDBVar] == 1) { + // We can remove the SymDBVar + Result.Mapping.LHS = Result.Mapping.LHS->Ops[0]; + Result.Mapping.RHS = Result.Mapping.RHS->Ops[0]; + return Result; + } else { + return Result; + } +} // Assuming the input has leaves pruned and preconditions weakened ParsedReplacement SuccessiveSymbolize(InstContext &IC, @@ -1883,7 +1938,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Print first successful result and exit, no result sorting. // Prelude bool Nested = !ConstMap.empty(); - + auto Original = Input; if (!NoWidth && !Nested && !hasMultiArgumentPhi(Input.Mapping.LHS)) { ShrinkWrap Shrink(IC, S, Input, 8); auto Smol = Shrink(); @@ -1894,6 +1949,9 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, P(llvm::errs()); Smol->print(llvm::errs(), true); llvm::errs() << "\n"; + if (DebugLevel > 4) { + Smol.value().print(llvm::errs(), true); + } } Input = Smol.value(); @@ -2078,7 +2136,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, } std::vector> SimpleCandidates = - InferSpecialConstExprsAllSym(RHSFresh, ConstMap, IC, /*depth=*/ 3); + InferSpecialConstExprsAllSym(RHSFresh, ConstMap, IC, /*depth=*/ 2); if (!SimpleCandidates.empty()) { if (DebugLevel > 4) { @@ -2350,14 +2408,10 @@ Inst *CombinePCs(const std::vector &PCs, InstContext &IC) { return Ante; } -ParsedReplacement InstantiateWidthChecks(InstContext &IC, +std::pair +InstantiateWidthChecks(InstContext &IC, Solver *S, ParsedReplacement Input) { - Input.print(llvm::errs(), true); - InfixPrinter IP(Input, true); - llvm::errs() << "WIDTH: Instantiating width checks.\n"; - IP(llvm::errs()); - - if (!hasMultiArgumentPhi(Input.Mapping.LHS)) { + if (!NoWidth && !hasMultiArgumentPhi(Input.Mapping.LHS)) { // Instantiate Alive driver with Symbolic width. AliveDriver Alive(Input.Mapping.LHS, Input.PCs.empty() ? nullptr : CombinePCs(Input.PCs, IC), @@ -2369,7 +2423,7 @@ ParsedReplacement InstantiateWidthChecks(InstContext &IC, llvm::errs() << "WIDTH: Generalized opt is valid for all widths.\n"; } // Completely width independent. No width checks needed. - return Input; + return {Input, true}; } auto &&ValidTypings = Alive.getValidTypings(); @@ -2381,7 +2435,7 @@ ParsedReplacement InstantiateWidthChecks(InstContext &IC, } Input.Mapping.LHS = nullptr; Input.Mapping.RHS = nullptr; - return Input; + return {Input, false}; } // Abstract width to a range or relational precondition @@ -2394,28 +2448,7 @@ ParsedReplacement InstantiateWidthChecks(InstContext &IC, for (auto &&I : Inputs) { Input.PCs.push_back(GetEqWidthConstraint(I, I->Width, IC)); } - return Input; -} - - -ParsedReplacement ReduceBasic(InstContext &IC, - Solver *S, ParsedReplacement Input) { - Reducer R(IC, S); - Input = R.ReducePCs(Input); - Input = R.ReduceRedundantPhis(Input); - Input = R.ReduceGreedy(Input); - Input = R.ReducePairsGreedy(Input); - Input = R.ReduceTriplesGreedy(Input); - Input = R.WeakenKB(Input); - Input = R.WeakenCR(Input); - Input = R.WeakenDB(Input); - Input = R.WeakenOther(Input); - if (ReduceKBIFY) { - Input = R.ReduceGreedyKBIFY(Input); - } - Input = R.ReducePCs(Input); - Input = R.ReducePCsToDF(Input); - return Input; + return {Input, false}; } template @@ -2424,6 +2457,58 @@ Stream &operator<<(Stream &S, InfixPrinter IP) { return S; } +void tagConstExprs(Inst *I, std::set &Set) { + if (I->K == Inst::Const || (I->K == Inst::Var && I->Name.starts_with("sym"))) { + Set.insert(I); + } else { + for (auto Op : I->Ops) { + tagConstExprs(Op, Set); + } + } + + if (I->Ops.size() > 0) { + bool foundNonConst = false; + for (auto Op : I->Ops) { + if (Set.find(Op) == Set.end()) { + foundNonConst = true; + break; + } + } + if (!foundNonConst) { + Set.insert(I); + } + } +} + +size_t constAwareCost(Inst *I) { + std::set ConstExprs; + tagConstExprs(I, ConstExprs); + return souper::cost(I, false, ConstExprs); +} + +int profit(const ParsedReplacement &P) { + return constAwareCost(P.Mapping.LHS) - constAwareCost(P.Mapping.RHS); +} + +void PrintInputAndResult(ParsedReplacement Input, ParsedReplacement Result) { + ReplacementContext RC; + Result.printLHS(llvm::outs(), RC, true); + Result.printRHS(llvm::outs(), RC, true); + llvm::outs() << "\n"; + + if (DebugLevel > 1) { + llvm::errs() << "IR Input: \n"; + ReplacementContext RC; + Input.printLHS(llvm::outs(), RC, true); + Input.printRHS(llvm::outs(), RC, true); + llvm::outs() << "\n"; + llvm::errs() << "\n\tInput (profit=" << profit(Input) << "):\n\n" + << InfixPrinter(Input) + << "\n\tGeneralized (profit=" << profit(Result) << "):\n\n" + << InfixPrinter(Result, NoWidth) << "\n"; + Result.print(llvm::errs(), true); + } +} int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); @@ -2453,6 +2538,13 @@ int main(int argc, char **argv) { // TODO: Write default action which chooses what to do based on input structure for (auto &&Input: Inputs) { + if (Input.Mapping.LHS == Input.Mapping.RHS) { + if (DebugLevel > 2) llvm::errs() << "Input == Output\n"; + continue; + } else if (profit(Input) < 0) { + if (DebugLevel > 2) llvm::errs() << "Not an optimization\n"; + continue; + } if (Basic) { ParsedReplacement Result = ReduceBasic(IC, S.get(), Input); if (!JustReduce) { @@ -2466,33 +2558,31 @@ int main(int argc, char **argv) { } Result = SuccessiveSymbolize(IC, S.get(), Result, Changed); } + bool Indep = false; if (!NoWidth) { - Result = InstantiateWidthChecks(IC, S.get(), Result); + std::tie(Result, Indep) = InstantiateWidthChecks(IC, S.get(), Result); } // Result.print(llvm::errs(), true); - if (!Result.Mapping.LHS) { - break; + if (!Result.Mapping.LHS && !NoWidth) { + Result = Input; + MaxTries++; + NoWidth = true; + continue; // Retry with no width checks } + + if (!Indep && Result.Mapping.LHS && !NoWidth) { + MaxTries++; + NoWidth = true; + PrintInputAndResult(Input, Result); + Result = Input; + continue; // Retry with no width checks + } + Result = DeAugment(IC, S.get(), Result); } while (--MaxTries && Changed); } if (Result.Mapping.LHS && Result.Mapping.RHS) { - ReplacementContext RC; - Result.printLHS(llvm::outs(), RC, true); - Result.printRHS(llvm::outs(), RC, true); - llvm::outs() << "\n"; - - if (DebugLevel > 1) { - llvm::errs() << "\n\tInput:\n\n"; - llvm::errs() << InfixPrinter(Input) << "\n\tGeneralized:\n\n" << InfixPrinter(Result, NoWidth); - } + PrintInputAndResult(Input, Result); } - continue; - } - - - if (FixIt) { - // TODO: Implement fixit with existing functionality when needed - llvm::errs() << "FixIt not implemented yet.\n"; } } return 0; diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 92a1cb9d5..2cafdc051 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -38,6 +38,11 @@ static llvm::cl::opt NoDispatch("no-dispatch", "(default=false)"), llvm::cl::init(false)); +static llvm::cl::opt ExplicitWidths("explicit-width-checks", + llvm::cl::desc("Only generate width checks when explicitly specified." + "(default=false)"), + llvm::cl::init(false)); + static llvm::cl::opt Sort("sortf", llvm::cl::desc("Sort matchers according to listfile" "(default=false)"), @@ -216,6 +221,22 @@ struct K1 : public Constraint { std::string Name, Val; }; +struct SymK0 : public Constraint { + SymK0(std::string Name_, std::string Bind_) : Name(Name_), Bind(Bind_) {} + std::string print() override { + return "util::symk0(" + Name + ", " + Bind + ")"; + } + std::string Name, Bind; +}; + +struct SymK1 : public Constraint { + SymK1(std::string Name_, std::string Bind_) : Name(Name_), Bind(Bind_) {} + std::string print() override { + return "util::symk1(" + Name + ", " + Bind + ")"; + } + std::string Name, Bind; +}; + struct CR : public Constraint { CR(std::string Name_, std::string L_, std::string H_) : Name(Name_), L(L_), H(H_) {} std::string print() override { @@ -294,6 +315,10 @@ struct SymbolTable : public std::map> { return Children[0].first + "." + Str + "(" + Children[1].first + ")"; }; + auto WC = [&](auto Str) { + return Children[0].first + "." + Str + "(" + std::to_string(I->Width) + ")"; + }; + // auto B = [] auto OP = [&](auto Str) { @@ -344,20 +369,52 @@ struct SymbolTable : public std::map> { case Inst::Ule : return {MET("ule"), true}; case Inst::Eq : return {MET("eq"), true}; case Inst::Ne : return {MET("ne"), true}; + case Inst::ZExt : return {WC("zext"), true}; + case Inst::SExt : return {WC("sext"), true}; + case Inst::Trunc : return {WC("trunc"), true}; - default: return {"", false}; + default: { + llvm::errs() << "Unimplemented op in PC: " << Inst::getKindName(I->K) << "\n"; + return {"", false}; } + } + + } + Constraint *ConvertPCToWidthConstraint(InstMapping PC) { + if (PC.LHS->K != Inst::Eq) + return nullptr; + if (PC.LHS->Ops[0]->K == Inst::BitWidth) { + return new WidthEq(this->at(PC.LHS->Ops[0]->Ops[0])[0], + PC.LHS->Ops[1]->Val.getLimitedValue()); + } + if (PC.LHS->Ops.size() > 1 && PC.LHS->Ops[1]->K == Inst::BitWidth) { + return new WidthEq(this->at(PC.LHS->Ops[1]->Ops[0])[0], + PC.LHS->Ops[0]->Val.getLimitedValue()); + } + return nullptr; } bool GenPCConstraints(std::vector PCs) { for (auto M : PCs) { - auto L = Translate(M.LHS); - auto R = Translate(M.RHS); - if (!L.second || !R.second) { - return false; + if (M.LHS->K == Inst::KnownZerosP) { + Constraint *C = new SymK0(this->at(M.LHS->Ops[0])[0], + this->at(M.LHS->Ops[1])[0]); + Constraints.push_back(C); + } else if (M.LHS->K == Inst::KnownOnesP) { + Constraint *C = new SymK1(this->at(M.LHS->Ops[0])[0], + this->at(M.LHS->Ops[1])[0]); + Constraints.push_back(C); + } else if (auto WC = ConvertPCToWidthConstraint(M)) { + Constraints.push_back(WC); + } else { + auto L = Translate(M.LHS); + auto R = Translate(M.RHS); + if (!L.second || !R.second) { + return false; + } + Constraints.push_back(new PC(L.first, R.first)); } - Constraints.push_back(new PC(L.first, R.first)); } return true; } @@ -418,7 +475,7 @@ struct SymbolTable : public std::map> { for (auto V : Vars) { auto Name = this->at(V)[0]; - if (!WidthIndependent) { + if (!WidthIndependent || LHS->Width == 1 || V->Width == 1) { Constraints.push_back(new WidthEq(Name, V->Width)); } @@ -592,12 +649,17 @@ bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms) { } template -bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { +bool InitSymbolTable(ParsedReplacement Input, Stream &Out, SymbolTable &Syms) { + auto Root = Input.Mapping.LHS; + auto RHS = Input.Mapping.RHS; std::set LHSInsts; -// Paths[Root] = {}; // root has an empty path std::vector Stack{Root}; -// + for (auto M : Input.PCs) { + Stack.push_back(M.LHS); + Stack.push_back(M.RHS); + } + int varnum = 0; while (!Stack.empty()) { auto I = Stack.back(); @@ -611,15 +673,13 @@ bool InitSymbolTable(Inst *Root, Inst *RHS, Stream &Out, SymbolTable &Syms) { Syms.Consts.insert(I); } for (int i = 0; i < I->Ops.size(); ++i) { -// Paths[I->Ops[i]] = Paths[I]; // Child inherits parent's path -// Paths[I->Ops[i]].push_back(i); Stack.push_back(I->Ops[i]); // Souper exprs are DAGs } } - std::set LHSRefs; std::set Visited; Stack.push_back(RHS); + while (!Stack.empty()) { auto I = Stack.back(); Stack.pop_back(); @@ -699,7 +759,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn return false; } - if (!InitSymbolTable(Input.Mapping.LHS, Input.Mapping.RHS, Out, Syms)) { + if (!InitSymbolTable(Input, Out, Syms)) { return false; } // Out << " llvm::errs() << \"NOW \" << " << OptID << "<< \"\\n\";\n"; @@ -735,22 +795,22 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn } Syms.PrintConstraintsPre(Out); - Out << " St.hit(" << OptID << ", " << prof << ");\n"; - Syms.PrintConstDecls(Out); + Out << " auto ret"; + if (Syms.find(Input.Mapping.RHS) != Syms.end()) { - Out << " return " << Syms[Input.Mapping.RHS][0] << ";"; + Out << " = " << Syms[Input.Mapping.RHS][0] << ";"; } else if (Input.Mapping.RHS->K == Inst::DemandedMask && Syms.find(Input.Mapping.RHS->Ops[0]) != Syms.end()) { assert(DemandedMask == Input.Mapping.RHS->Ops[1] && "DemandedMask mismatch"); - Out << " return " << Syms[Input.Mapping.RHS->Ops[0]][0] << ";"; + Out << " = " << Syms[Input.Mapping.RHS->Ops[0]][0] << ";"; } else if (Input.Mapping.RHS->K == Inst::Const) { - Out << " APInt Result(" + Out << " APInt Result(" << Input.Mapping.RHS->Width <<", " << Input.Mapping.RHS->Val << ");\n"; - Out << " return ConstantInt::get(TheContext, Result);"; + Out << " = ConstantInt::get(TheContext, Result);"; } else { - Out << " return "; + Out << " = "; if (Input.Mapping.RHS->K == Inst::DemandedMask) { assert(DemandedMask == Input.Mapping.RHS->Ops[1] && "DemandedMask mismatch"); if (!GenRHSCreator(Input.Mapping.RHS->Ops[0], Out, Syms)) { @@ -763,7 +823,10 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn } Out << ";"; } - Out << "\n}\n}"; + Out << "\nif (util::check_width(ret, I)) {\n"; + Out << " St.hit(" << OptID << ", " << prof << ");\n"; + Out << " return ret;\n"; + Out << "\n}\n}\n}"; Syms.PrintConstraintsPost(Out); @@ -785,6 +848,12 @@ bool PCHasVar(const ParsedReplacement &Input) { for (auto &&PC : Input.PCs) { if (PC.LHS->K == Inst::KnownOnesP || PC.LHS->K == Inst::KnownZerosP) continue; + + if (PC.LHS->K == Inst::Eq && (PC.LHS->Ops[0]->K == Inst::BitWidth || + PC.LHS->Ops[1]->K == Inst::BitWidth )) { + continue; + } + findVars(PC.LHS, Vars); findVars(PC.RHS, Vars); } @@ -1032,7 +1101,7 @@ int main(int argc, char **argv) { std::string Str; llvm::raw_string_ostream Out(Str); - if (GenMatcher(Input, Out, optnumber, IsWidthIndependent(IC, S.get(), Input))) { + if (GenMatcher(Input, Out, optnumber, ExplicitWidths)) { auto current = optnumber++; if (!optnumbers.empty() && optnumbers.find(current) == optnumbers.end()) { diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 3655b882f..cdbe14d1e 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -314,24 +314,7 @@ inline CastClass_match_width m_Trunc(size_t W, const O return CastClass_match_width(W, Op); } -// Utility functions to use in the DSL namespace util { - Value *node(Instruction *I, const std::vector &Path) { - Value *Current = I; - for (auto &&P : Path) { - if (Instruction *CI = dyn_cast(Current)) { - if (CI->getNumOperands() > P) { - Current = CI->getOperand(P); - } else { - return nullptr; - } - } else { - return nullptr; - } - } - return Current; - } - bool dc(llvm::DominatorTree *DT, llvm::Instruction *I, llvm::Value *V) { if (!V) { return false; @@ -353,6 +336,14 @@ namespace util { } } + bool check_width(llvm::Value *V, Instruction *I) { + if (V && V->getType() && V->getType()->isIntegerTy()) { + return V->getType()->getScalarSizeInBits() == I->getType()->getScalarSizeInBits(); + } else { + return false; + } + } + template bool check_related(Out Result, FT F, Args... args) { return Result == F(args...); @@ -461,6 +452,22 @@ namespace util { return (V | ~ComputedDB).isAllOnes(); } + // TODO Implement + bool symk0(llvm::Value *V, llvm::Value *&Bind) { + return false; + } + bool symk1(llvm::Value *V, llvm::Value *&Bind) { + return false; + } + + bool symdb(llvm::DemandedBits *DB, llvm::Instruction *I, llvm::Value *&V) { + auto ComputedDB = DB->getDemandedBits(I); + + // Todo make a new llvm constant from ComputedDb and assign to V + + return false; + } + bool nz(llvm::Value *V) { if (ConstantInt *Con = llvm::dyn_cast(V)) { return !Con->getValue().isZero(); @@ -639,10 +646,30 @@ struct SouperCombine : public FunctionPass { return nullptr; } + // struct SymConst { + // SymConst(size_t Width, size_t Value, IRBuilder *B) : Width(Width), Value(Value), B(B) {} + // size_t Width; + // size_t Value; // TODO: APInt + // IRBuilder *B; + + // llvm::Value *operator()() { + // return B->getIntN(Width, Value); + // } + + // llvm::Value *operator()(llvm::Value *Ctx) { + // return B->getIntN(Ctx->getType()->getIntegerBitWidth(), Value); + // } + // }; + + // SymConst C(size_t Width, size_t Value, IRBuilder *B) { + // return SymConst(Width, Value, B); + // } + Value *C(size_t Width, size_t Value, IRBuilder *B) { return B->getIntN(Width, Value); } + Value *C(llvm::APInt Value, IRBuilder *B) { return ConstantInt::get(B->getIntNTy(Value.getBitWidth()), Value); // return B->getIntN(Value.getBitWidth(), Value.getLimitedValue()); From 4ee78840390428f55dd28b633e5893b5a738f589 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 2 Apr 2023 19:51:58 -0600 Subject: [PATCH 152/165] foo --- tools/generalize.cpp | 8 +++++--- tools/souper-check.cpp | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 974554c2e..9cee1aad1 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -2578,11 +2578,13 @@ int main(int argc, char **argv) { continue; // Retry with no width checks } Result = DeAugment(IC, S.get(), Result); + + if (Result.Mapping.LHS && Result.Mapping.RHS) { + PrintInputAndResult(Input, Result); + } + } while (--MaxTries && Changed); } - if (Result.Mapping.LHS && Result.Mapping.RHS) { - PrintInputAndResult(Input, Result); - } } } return 0; diff --git a/tools/souper-check.cpp b/tools/souper-check.cpp index 663d19eed..f28523d95 100644 --- a/tools/souper-check.cpp +++ b/tools/souper-check.cpp @@ -89,7 +89,11 @@ static cl::opt CheckAllGuesses("souper-check-all-guesses", cl::init(false)); static cl::opt Hash("hash", - cl::desc("Hash a trasnformation."), + cl::desc("Hash a trasnformation. (default=false)"), + cl::init(false)); + +static cl::opt FilterRedundant("filter-redundant", + cl::desc("Filter redundant transformations based on static hashing (default=false)"), cl::init(false)); @@ -184,12 +188,43 @@ int SolveInst(const MemoryBufferRef &MB, Solver *S) { unsigned Index = 0; int Ret = 0; int Success = 0, Fail = 0, Error = 0; + + std::unordered_set Hashes; + for (auto Rep : Reps) { if (Hash) { llvm::outs() << HashRep(Rep) << '\n'; continue; } + if (FilterRedundant) { + auto Hash = HashRep(Rep); + if (Hashes.find(Hash) == Hashes.end()) { + Hashes.insert(Hash); + ReplacementContext RC; + Rep.printLHS(llvm::outs(), RC, true); + Rep.printRHS(llvm::outs(), RC, true); + } else { + llvm::outs() << "; Skipping redundant transformation.\n"; + std::string S; + llvm::raw_string_ostream Str(S); + ReplacementContext RC; + Rep.printLHS(Str, RC, true); + Rep.printRHS(Str, RC, true); + Str.flush(); + llvm::outs() << ';'; + for (size_t i = 0; i < S.length(); ++i) { + auto c = S[i]; + if ((c == '\n' || c == '\r') && i != S.length() - 1) { + llvm::outs() << c << ';'; + } else { + llvm::outs() << c; + } + } + } + continue; + } + if (isInferDFA()) { if (InferNeg) { bool Negative; From c51ea71474e68571cea78230d21a000ce3eab0a9 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 2 Apr 2023 19:59:16 -0600 Subject: [PATCH 153/165] foo --- tools/generalize.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 9cee1aad1..dbad6b48d 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -2550,7 +2550,8 @@ int main(int argc, char **argv) { if (!JustReduce) { bool Changed = false; - size_t MaxTries = 1; // Increase this if we ever run with 10/100x timeout. + size_t MaxTries = 3; // Increase this if we ever run with 10/100x timeout. + bool FirstTime = true; do { if (!OnlyWidth) { if (Changed) { @@ -2565,13 +2566,13 @@ int main(int argc, char **argv) { // Result.print(llvm::errs(), true); if (!Result.Mapping.LHS && !NoWidth) { Result = Input; - MaxTries++; + if (MaxTries == 1) MaxTries++; NoWidth = true; continue; // Retry with no width checks } if (!Indep && Result.Mapping.LHS && !NoWidth) { - MaxTries++; + if (MaxTries == 1) MaxTries++; NoWidth = true; PrintInputAndResult(Input, Result); Result = Input; @@ -2579,10 +2580,10 @@ int main(int argc, char **argv) { } Result = DeAugment(IC, S.get(), Result); - if (Result.Mapping.LHS && Result.Mapping.RHS) { + if ((Changed || FirstTime) && Result.Mapping.LHS && Result.Mapping.RHS) { PrintInputAndResult(Input, Result); } - + if (FirstTime) FirstTime = false; } while (--MaxTries && Changed); } } From ed9f98f50479d506b469b7e559e97e34e4ae7484 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 3 Apr 2023 01:41:48 -0600 Subject: [PATCH 154/165] foo --- include/souper/Infer/SynthUtils.h | 1 + lib/Infer/SynthUtils.cpp | 33 +++++++++++++++++ tools/generalize.cpp | 37 ++----------------- tools/matcher-gen.cpp | 52 ++++++++++++++++++++------- tools/pass-generator/src/template.cpp | 44 +++++++++++++---------- utils/parallel.sh | 5 ++- 6 files changed, 105 insertions(+), 67 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 7d1707b54..d207c855c 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -142,6 +142,7 @@ ValueCache GetCEX(const ParsedReplacement &Input, InstContext &IC, Solver *S); std::vector GetMultipleCEX(ParsedReplacement Input, InstContext &IC, Solver *S, size_t MaxCount); +int profit(const ParsedReplacement &P); } #endif diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index 206bd78a2..d1252481d 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -314,4 +314,37 @@ std::vector GetMultipleCEX(ParsedReplacement Input, InstContext &IC, return Results; } +void tagConstExprs(Inst *I, std::set &Set) { + if (I->K == Inst::Const || (I->K == Inst::Var && I->Name.starts_with("sym"))) { + Set.insert(I); + } else { + for (auto Op : I->Ops) { + tagConstExprs(Op, Set); + } + } + + if (I->Ops.size() > 0) { + bool foundNonConst = false; + for (auto Op : I->Ops) { + if (Set.find(Op) == Set.end()) { + foundNonConst = true; + break; + } + } + if (!foundNonConst) { + Set.insert(I); + } + } +} + +size_t constAwareCost(Inst *I) { + std::set ConstExprs; + tagConstExprs(I, ConstExprs); + return souper::cost(I, false, ConstExprs); +} + +int profit(const ParsedReplacement &P) { + return constAwareCost(P.Mapping.LHS) - constAwareCost(P.Mapping.RHS); +} + } diff --git a/tools/generalize.cpp b/tools/generalize.cpp index dbad6b48d..c46adb0b7 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1998,7 +1998,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, std::map SymCS; - int i = 1; + static int i = 1; for (auto I : LHSConsts) { auto Name = "symconst_" + std::to_string(i++); SymConstMap[I] = IC.createVar(I->Width, Name); @@ -2457,38 +2457,6 @@ Stream &operator<<(Stream &S, InfixPrinter IP) { return S; } -void tagConstExprs(Inst *I, std::set &Set) { - if (I->K == Inst::Const || (I->K == Inst::Var && I->Name.starts_with("sym"))) { - Set.insert(I); - } else { - for (auto Op : I->Ops) { - tagConstExprs(Op, Set); - } - } - - if (I->Ops.size() > 0) { - bool foundNonConst = false; - for (auto Op : I->Ops) { - if (Set.find(Op) == Set.end()) { - foundNonConst = true; - break; - } - } - if (!foundNonConst) { - Set.insert(I); - } - } -} - -size_t constAwareCost(Inst *I) { - std::set ConstExprs; - tagConstExprs(I, ConstExprs); - return souper::cost(I, false, ConstExprs); -} - -int profit(const ParsedReplacement &P) { - return constAwareCost(P.Mapping.LHS) - constAwareCost(P.Mapping.RHS); -} void PrintInputAndResult(ParsedReplacement Input, ParsedReplacement Result) { ReplacementContext RC; @@ -2508,6 +2476,7 @@ void PrintInputAndResult(ParsedReplacement Input, ParsedReplacement Result) { << InfixPrinter(Result, NoWidth) << "\n"; Result.print(llvm::errs(), true); } + llvm::outs().flush(); } int main(int argc, char **argv) { @@ -2550,7 +2519,7 @@ int main(int argc, char **argv) { if (!JustReduce) { bool Changed = false; - size_t MaxTries = 3; // Increase this if we ever run with 10/100x timeout. + size_t MaxTries = 2; // Increase this if we ever run with 10/100x timeout. bool FirstTime = true; do { if (!OnlyWidth) { diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 2cafdc051..7fed6bd8d 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -2,6 +2,7 @@ #include "souper/Infer/Preconditions.h" #include "souper/Infer/EnumerativeSynthesis.h" +#include "souper/Infer/SynthUtils.h" #include "souper/Parser/Parser.h" #include "souper/Tool/GetSolver.h" @@ -319,10 +320,8 @@ struct SymbolTable : public std::map> { return Children[0].first + "." + Str + "(" + std::to_string(I->Width) + ")"; }; -// auto B = [] - auto OP = [&](auto Str) { - return Children[0].first + " " + Str + " " + Children[1].first; + return "(" + Children[0].first + " " + Str + " " + Children[1].first + ")"; }; switch (I->K) { @@ -528,7 +527,7 @@ struct SymbolTable : public std::map> { auto Print = [&](SymbolTable &Syms, Inst *C){ auto Name = "C" + std::to_string(varnum++); - if (C->Width < 64) { + if (C->Width <= 64) { Out << " auto " << Name << " = C(" << C->Val.getBitWidth() <<", " << C->Val << ", B);\n"; @@ -592,7 +591,11 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms, bool IsRoot = false) Out << "&" << Syms[Child].back() << " <<= "; } auto Str = Child->Val.toString(10, false); - Out << "m_SpecificInt( " << Child->Width << ", \"" << Str << "\")"; + if (ExplicitWidths) { + Out << "m_SpecificInt(\"" << Str << "\")"; + } else { + Out << "m_SpecificInt( " << Child->Width << ", \"" << Str << "\")"; + } } else if (Child->K == Inst::Var) { if (Child->Name.starts_with("symconst")) { Out << "m_Constant(&" << Syms[Child].back() << ")"; @@ -614,6 +617,19 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms, bool IsRoot = false) return true; } +Inst *getSibling(Inst *Child, Inst *Parent) { + if (!Child || !Parent) { + return nullptr; + } + + for (auto Op : Parent->Ops) { + if (Op != Child && Op->Width == Child->Width) { + return Op; + } + } + return nullptr; +} + template bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms) { auto It = CreateOps.find(I->K); @@ -633,6 +649,16 @@ bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms) { } if (Syms.find(Child) != Syms.end()) { Out << Syms[Child][0]; + if (Child->K == Inst::Const && Syms[Child][0].starts_with("C")) { + auto Sib = getSibling(Child, I); + std::string S; + if (Syms.find(Sib) != Syms.end()) { + if (Syms[Sib][0].starts_with("x")) { + S = Syms[Sib][0]; + } + } + Out << "(" << S << ")"; + } } else { if (!GenRHSCreator(Child, Out, Syms)) { return false; @@ -743,19 +769,15 @@ bool InitSymbolTable(ParsedReplacement Input, Stream &Out, SymbolTable &Syms) { return true; } -int profitability(const ParsedReplacement &Input) { - return souper::cost(Input.Mapping.LHS) - - souper::cost(Input.Mapping.RHS); -} - template bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIndependent) { SymbolTable Syms; Out << "{\n"; - int prof = profitability(Input); + int prof = profit(Input); size_t LHSSize = souper::instCount(Input.Mapping.LHS); - if (prof < 0 || LHSSize > 15) { + if (prof <= 0 || LHSSize > 15) { + llvm::errs() << "Skipping replacement profit < 0 or LHS size > 15\n"; return false; } @@ -800,7 +822,11 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn Out << " auto ret"; if (Syms.find(Input.Mapping.RHS) != Syms.end()) { - Out << " = " << Syms[Input.Mapping.RHS][0] << ";"; + Out << " = " << Syms[Input.Mapping.RHS][0]; + if (Syms[Input.Mapping.RHS][0].starts_with("C")) { + Out << "(I)"; + } + Out << ";"; } else if (Input.Mapping.RHS->K == Inst::DemandedMask && Syms.find(Input.Mapping.RHS->Ops[0]) != Syms.end()) { assert(DemandedMask == Input.Mapping.RHS->Ops[1] && "DemandedMask mismatch"); Out << " = " << Syms[Input.Mapping.RHS->Ops[0]][0] << ";"; diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index cdbe14d1e..6da2cf1e4 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -218,7 +218,6 @@ struct width_specific_intval : public specific_intval { } }; -// FIXME Widths beyond 64 inline width_specific_intval m_SpecificInt(size_t W, uint64_t V) { return width_specific_intval(APInt(64, V), W); } @@ -227,6 +226,10 @@ inline width_specific_intval m_SpecificInt(size_t W, std::string S) { return width_specific_intval(APInt(W, S, 10), W); } +inline specific_intval m_SpecificInt(std::string S) { + return specific_intval(APInt(64, S, 10)); +} + struct constant_matcher { llvm::Value** Captured; constant_matcher(llvm::Value** C) : Captured(C) {} @@ -547,6 +550,9 @@ namespace util { llvm::APInt V(size_t Width, std::string Val) { return llvm::APInt(Width, Val, 2); } + llvm::APInt V(llvm::Value *Ctx, std::string Val) { + return llvm::APInt(Ctx->getType()->getIntegerBitWidth(), Val, 2); + } } struct SouperCombine : public FunctionPass { @@ -646,29 +652,29 @@ struct SouperCombine : public FunctionPass { return nullptr; } - // struct SymConst { - // SymConst(size_t Width, size_t Value, IRBuilder *B) : Width(Width), Value(Value), B(B) {} - // size_t Width; - // size_t Value; // TODO: APInt - // IRBuilder *B; + struct SymConst { + SymConst(size_t Width, size_t Value, IRBuilder *B) : Width(Width), Value(Value), B(B) {} + size_t Width; + size_t Value; // TODO: APInt + IRBuilder *B; - // llvm::Value *operator()() { - // return B->getIntN(Width, Value); - // } - - // llvm::Value *operator()(llvm::Value *Ctx) { - // return B->getIntN(Ctx->getType()->getIntegerBitWidth(), Value); - // } - // }; + llvm::Value *operator()() { + return B->getIntN(Width, Value); + } - // SymConst C(size_t Width, size_t Value, IRBuilder *B) { - // return SymConst(Width, Value, B); - // } + llvm::Value *operator()(llvm::Value *Ctx) { + return B->getIntN(Ctx->getType()->getIntegerBitWidth(), Value); + } + }; - Value *C(size_t Width, size_t Value, IRBuilder *B) { - return B->getIntN(Width, Value); + SymConst C(size_t Width, size_t Value, IRBuilder *B) { + return SymConst(Width, Value, B); } + // Value *C(size_t Width, size_t Value, IRBuilder *B) { + // return B->getIntN(Width, Value); + // } + Value *C(llvm::APInt Value, IRBuilder *B) { return ConstantInt::get(B->getIntNTy(Value.getBitWidth()), Value); diff --git a/utils/parallel.sh b/utils/parallel.sh index 1a165036d..864ead744 100755 --- a/utils/parallel.sh +++ b/utils/parallel.sh @@ -13,8 +13,11 @@ cp "${indir}"/* "${indir}r" mkdir -p "${indir}t" rm "${indir}t"/* +mkdir -p "${indir}d" +rm "${indir}d"/* + for i in `ls -v $indir/*`; do echo "timeout 300" $cmd $i " > " ${indir}t/`basename $i` " 2> " ${indir}d/`basename $i` " && cp " ${indir}t/`basename $i` ${indir}r/ ;done > /tmp/cmdfile.txt # for i in `ls -v $indir/*`; do echo "timeout 300" $cmd $i " > " ${indir}r/`basename $i`;done > /tmp/cmdfile.txt -#parallel --will-cite -k < /tmp/cmdfile.txt +parallel --will-cite < /tmp/cmdfile.txt From 17a6e06e4a018169044e978b72ac1c067f710238 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 3 Apr 2023 19:31:06 -0600 Subject: [PATCH 155/165] foo --- include/souper/Generalize/Reducer.h | 4 +- include/souper/Infer/SynthUtils.h | 2 +- lib/Generalize/Reducer.cpp | 114 +++++++++++--- lib/Infer/SynthUtils.cpp | 8 +- lib/Inst/Inst.cpp | 2 +- lib/Tool/CandidateMapUtils.cpp | 3 +- tools/generalize.cpp | 210 +++++++++++++++----------- tools/pass-generator/src/template.cpp | 17 ++- 8 files changed, 235 insertions(+), 125 deletions(-) diff --git a/include/souper/Generalize/Reducer.h b/include/souper/Generalize/Reducer.h index a228aa2e2..701151765 100644 --- a/include/souper/Generalize/Reducer.h +++ b/include/souper/Generalize/Reducer.h @@ -25,7 +25,7 @@ class Reducer { // Eventually replace the functions in Preconditions{.h/.cpp} with this. // Does not produce exhaustive result. TODO Have an option to wrap in a cegis loop. bool inferKBPrecondition(ParsedReplacement &Input, std::vector Targets); - + ParsedReplacement ReduceGreedyKBIFY(ParsedReplacement Input); ParsedReplacement ReduceRedundantPhis(ParsedReplacement Input); @@ -43,6 +43,8 @@ class Reducer { ParsedReplacement ReducePCsToDF(ParsedReplacement Input); + ParsedReplacement ReducePoison(ParsedReplacement Input); + bool VerifyInput(ParsedReplacement &Input); bool safeToRemove(Inst *I, ParsedReplacement &Input); diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index d207c855c..b31c321a3 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -131,7 +131,7 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC); // Also Synthesizes given constants // Returns clone if verified, nullptrs if not -ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S); +std::optional Verify(ParsedReplacement Input, InstContext &IC, Solver *S); // bool IsValid(ParsedReplacement Input, InstContext &IC, Solver *S); std::map findOneConstSet(ParsedReplacement Input, const std::set &SymCS, InstContext &IC, Solver *S); diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index 6f1926005..1f442f529 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -461,16 +461,6 @@ size_t WeakenSingleCR(ParsedReplacement Input, InstContext &IC, Solver *S, return 0; // fail } - ParsedReplacement Ret; - auto SOLVE = [&]() -> bool { - Ret = Verify(Input, IC, S); - if (Ret.Mapping.LHS && Ret.Mapping.RHS) { - return true; - } else { - return false; - } - }; - auto Restore = Target->Range; // Binary search to extend upper and lower boundaries @@ -494,7 +484,7 @@ size_t WeakenSingleCR(ParsedReplacement Input, InstContext &IC, Solver *S, Attempt = Full.getLower(); } Target->Range = llvm::ConstantRange(L, Attempt); - if (SOLVE()) { + if (Verify(Input, IC, S)) { U = Attempt; // llvm::errs() << "U " << Attempt << '\n'; inc *= 2; @@ -513,7 +503,7 @@ size_t WeakenSingleCR(ParsedReplacement Input, InstContext &IC, Solver *S, Attempt = Full.getLower(); } Target->Range = llvm::ConstantRange(Attempt, U); - if (SOLVE()) { + if (Verify(Input, IC, S)) { L = Attempt; // llvm::errs() << "L " << Attempt << '\n'; dec *= 2; @@ -571,16 +561,6 @@ size_t WeakenSingleKB(ParsedReplacement Input, InstContext &IC, Solver *S, return 0; // No bits weakened } - ParsedReplacement Ret; - auto SOLVE = [&]() -> bool { - Ret = Verify(Input, IC, S); - if (Ret.Mapping.LHS && Ret.Mapping.RHS) { - return true; - } else { - return false; - } - }; - llvm::APInt RestoreZero = Target->KnownZeros; llvm::APInt RestoreOne = Target->KnownOnes; @@ -598,7 +578,7 @@ size_t WeakenSingleKB(ParsedReplacement Input, InstContext &IC, Solver *S, if (OriO[i] == 1) Target->KnownOnes.clearBit(i); if (OriZ[i] == 1) Target->KnownZeros.clearBit(i); - if (!SOLVE()) { + if (!Verify(Input, IC, S)) { Target->KnownZeros = OriZ; Target->KnownOnes = OriO; } else { @@ -665,7 +645,7 @@ ParsedReplacement Reducer::ReducePCs(ParsedReplacement Input) { } auto Clone = Verify(Result, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return ReducePCs(Result); } } @@ -965,5 +945,91 @@ void Reducer::ReduceRec(ParsedReplacement Input_, std::vector } } +Inst *NonPoisonReplacement(Inst *I, InstContext &IC) { + Inst::Kind K = I->K; + switch (I->K) { + case Inst::AddNW: + case Inst::AddNUW: + case Inst::AddNSW: + K = Inst::Add; + break; + case Inst::SubNW: + case Inst::SubNUW: + case Inst::SubNSW: + K = Inst::Sub; + break; + case Inst::MulNW: + case Inst::MulNUW: + case Inst::MulNSW: + K = Inst::Mul; + break; + case Inst::ShlNW: + case Inst::ShlNUW: + case Inst::ShlNSW: + K = Inst::Shl; + break; + case Inst::UDivExact: + K = Inst::UDiv; + break; + case Inst::SDivExact: + K = Inst::SDiv; + break; + default: + llvm_unreachable("Expected instruction with poison flag."); + } + + auto Ret = IC.getInst(K, I->Width, I->Ops); + Ret->Name = I->Name; + Ret->DemandedBits = I->DemandedBits; + return Ret; +} + +void CollectPoisonInsts(Inst *I, std::set &PoisonInsts, + std::set &Visited) { + if (Visited.find(I) != Visited.end()) { + return; + } + Visited.insert(I); + + if (I->K == Inst::AddNSW || I->K == Inst::AddNUW || I->K == Inst::AddNW || + I->K == Inst::SubNSW || I->K == Inst::SubNUW || I->K == Inst::SubNW || + I->K == Inst::MulNSW || I->K == Inst::MulNUW || I->K == Inst::MulNW || + I->K == Inst::ShlNSW || I->K == Inst::ShlNUW || I->K == Inst::ShlNW || + I->K == Inst::UDivExact || I->K == Inst::SDivExact) { + PoisonInsts.insert(I); + } + + for (auto &&Op : I->Ops) { + CollectPoisonInsts(Op, PoisonInsts, Visited); + } +} + +ParsedReplacement Reducer::ReducePoison(ParsedReplacement Input) { + std::set PoisonInsts; + std::set Visited; + CollectPoisonInsts(Input.Mapping.LHS, PoisonInsts, Visited); + CollectPoisonInsts(Input.Mapping.RHS, PoisonInsts, Visited); + for (auto &&PC : Input.PCs) { + CollectPoisonInsts(PC.LHS, PoisonInsts, Visited); + CollectPoisonInsts(PC.RHS, PoisonInsts, Visited); + } + + for (auto I : PoisonInsts) { + auto Rep = NonPoisonReplacement(I, IC); + if (!Rep) { + continue; + } + std::map Cache = {{I, NonPoisonReplacement(I, IC)}}; + + auto Cand = Replace(Input, IC, Cache); + + if (VerifyInput(Cand)) { + Input = Cand; + } + } + + return Input; +} + } diff --git a/lib/Infer/SynthUtils.cpp b/lib/Infer/SynthUtils.cpp index d1252481d..bbc0fa446 100644 --- a/lib/Infer/SynthUtils.cpp +++ b/lib/Infer/SynthUtils.cpp @@ -84,7 +84,7 @@ ParsedReplacement Clone(ParsedReplacement In, InstContext &IC) { // Also Synthesizes given constants // Returns clone if verified, nullptrs if not -ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { +std::optional Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { // if (Input.PCs.empty()) { // SynthesisContext SC{IC, S->getSMTLIBSolver(), Input.Mapping.LHS, nullptr, @@ -131,8 +131,7 @@ ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { llvm::errs() << "Constant Synthesis ((no Dataflow Preconditions)) failed. \n"; } } - Input.Mapping = InstMapping(nullptr, nullptr); - return Input; + return std::nullopt; } std::vector> Models; bool IsValid; @@ -144,8 +143,7 @@ ParsedReplacement Verify(ParsedReplacement Input, InstContext &IC, Solver *S) { } else { static int C = 0; // llvm::errs() << "C " << C++ << '\n'; - Input.Mapping = InstMapping(nullptr, nullptr); - return Input; + return std::nullopt; // TODO: Better failure indication? } } diff --git a/lib/Inst/Inst.cpp b/lib/Inst/Inst.cpp index b56b74a72..4d2382f12 100644 --- a/lib/Inst/Inst.cpp +++ b/lib/Inst/Inst.cpp @@ -1089,7 +1089,7 @@ std::string souper::GetReplacementLHSString(const BlockPCs &BPCs, Inst *LHS, ReplacementContext &Context, bool printNames) { std::string Str; llvm::raw_string_ostream SS(Str); - PrintReplacementLHS(SS, BPCs, PCs, LHS, Context); + PrintReplacementLHS(SS, BPCs, PCs, LHS, Context, printNames); return SS.str(); } diff --git a/lib/Tool/CandidateMapUtils.cpp b/lib/Tool/CandidateMapUtils.cpp index 17056a368..b1787eb9f 100644 --- a/lib/Tool/CandidateMapUtils.cpp +++ b/lib/Tool/CandidateMapUtils.cpp @@ -124,8 +124,7 @@ void souper::HarvestAndPrintOpts(InstContext &IC, ExprBuilderContext &EBC, llvm: // Rep.print(llvm::outs(), true); - auto Clone = Verify(Rep, IC, S); - if (Clone.Mapping.RHS && Clone.Mapping.LHS) { + if (Verify(Rep, IC, S)) { if (isProfitable(Rep)) { BlockPCs BPCs; std::vector PCs; diff --git a/tools/generalize.cpp b/tools/generalize.cpp index c46adb0b7..2b9d67196 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -668,12 +668,7 @@ struct ShrinkWrap { llvm::errs() << "Type check failed\n"; return {}; } - auto Clone = Verify(New, IC, S); - if (Clone.Mapping.LHS) { - return Clone; - } else { - return {}; - } + return Verify(New, IC, S); } }; @@ -778,18 +773,18 @@ std::vector InferConstantLimits( for (auto &&[XI, XC] : CMap) { // X < Width, X <= Width auto Width = Builder(XI, IC).BitWidth(); - // Results.push_back(Builder(XI, IC).Ult(Width)()); - // Results.push_back(Builder(XI, IC).Ule(Width)()); + Results.push_back(Builder(XI, IC).Ult(Width)()); + Results.push_back(Builder(XI, IC).Ule(Width)()); // X slt SMAX, x ult UMAX auto WM1 = Width.Sub(1); auto SMax = Builder(IC, llvm::APInt(XI->Width, 1)).Shl(WM1).Sub(1)(); Results.push_back(Builder(XI, IC).Slt(SMax)()); - // auto gZ = Builder(XI, IC).Ugt(0)(); + auto gZ = Builder(XI, IC).Ugt(0)(); - // Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); - // Results.push_back(Builder(XI, IC).Ule(Width).And(gZ)()); + Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); + Results.push_back(Builder(XI, IC).Ule(Width).And(gZ)()); // 2 * X < C, 2 * X >= C for (auto C : ConcreteConsts) { @@ -1079,7 +1074,7 @@ std::set findConcreteConsts(Inst *I) { return Ret; } -ParsedReplacement DFPreconditionsAndVerifyGreedy( +std::optional DFPreconditionsAndVerifyGreedy( ParsedReplacement Input, InstContext &IC, Solver *S, std::map SymCS) { @@ -1096,10 +1091,10 @@ ParsedReplacement DFPreconditionsAndVerifyGreedy( C.first->KnownOnes = C.second; } - ParsedReplacement Ret; + std::optional Ret; auto SOLVE = [&]() -> bool { Ret = Verify(Input, IC, S); - if (Ret.Mapping.LHS && Ret.Mapping.RHS) { + if (Ret) { return true; } else { return false; @@ -1136,14 +1131,12 @@ ParsedReplacement DFPreconditionsAndVerifyGreedy( P.first->KnownZeros = P.second.first; P.first->KnownOnes = P.second.second; } - Clone.Mapping.LHS = nullptr; - Clone.Mapping.RHS = nullptr; - return Clone; + return Ret; } } -ParsedReplacement SimplePreconditionsAndVerifyGreedy( +std::optional SimplePreconditionsAndVerifyGreedy( ParsedReplacement Input, InstContext &IC, Solver *S, std::map SymCS) { // Assume Input is not valid @@ -1155,13 +1148,11 @@ ParsedReplacement SimplePreconditionsAndVerifyGreedy( } std::swap(SymCS, NonBools); - ParsedReplacement Clone; - Clone.Mapping.LHS = nullptr; - Clone.Mapping.RHS = nullptr; + std::optional Clone = std::nullopt; auto SOLVE = [&]() -> bool { Clone = Verify(Input, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return true; } else { return false; @@ -1232,7 +1223,9 @@ size_t BruteForceModelCount(Inst *Pred) { do { ConcreteInterpreter CI(Cache); - if (CI.evaluateInst(Pred).getValue().getBoolValue()) { + + if (CI.evaluateInst(Pred).hasValue() && + CI.evaluateInst(Pred).getValue().getBoolValue()) { ++ModelCount; } } while (Update()); @@ -1260,9 +1253,9 @@ std::optional VerifyWithRels(InstContext &IC, Solver *S, for (auto Rel : Rels) { Input.PCs.push_back({Rel, IC.getConst(llvm::APInt(1, 1))}); auto Clone = Verify(Input, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { ValidRels.push_back(Rel); - FirstValidResult = Clone; + FirstValidResult = Clone.value(); if (Rels.size() > 10) { return Clone; } @@ -1300,7 +1293,7 @@ std::optional VerifyWithRels(InstContext &IC, Solver *S, } -ParsedReplacement +std::optional FirstValidCombination(ParsedReplacement Input, const std::vector &Targets, const std::vector> &Candidates, @@ -1356,9 +1349,7 @@ FirstValidCombination(ParsedReplacement Input, } } - auto Clone = Input; - Clone.Mapping.LHS = nullptr; - Clone.Mapping.RHS = nullptr; + std::optional Clone = std::nullopt; auto SOLVE = [&](ParsedReplacement P) -> bool { // InfixPrinter IP(P); @@ -1367,7 +1358,7 @@ FirstValidCombination(ParsedReplacement Input, if (GEN) { Clone = Verify(P, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return true; } } @@ -1383,14 +1374,14 @@ FirstValidCombination(ParsedReplacement Input, if (SDF) { Clone = SimplePreconditionsAndVerifyGreedy(P, IC, S, SymCS); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return true; } } if (DFF) { Clone = DFPreconditionsAndVerifyGreedy(P, IC, S, SymCS); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return true; } } @@ -1421,9 +1412,7 @@ FirstValidCombination(ParsedReplacement Input, } - Input.Mapping.LHS = nullptr; - Input.Mapping.RHS = nullptr; - return Input; + return std::nullopt; } @@ -1902,6 +1891,7 @@ ParsedReplacement ReduceBasic(InstContext &IC, } Input = R.ReducePCs(Input); Input = R.ReducePCsToDF(Input); + Input = R.ReducePoison(Input); return Input; } @@ -1931,7 +1921,7 @@ ParsedReplacement DeAugment(InstContext &IC, } // Assuming the input has leaves pruned and preconditions weakened -ParsedReplacement SuccessiveSymbolize(InstContext &IC, +std::optional SuccessiveSymbolize(InstContext &IC, Solver *S, ParsedReplacement Input, bool &Changed, std::vector> ConstMap = {}) { @@ -1939,30 +1929,6 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // Prelude bool Nested = !ConstMap.empty(); auto Original = Input; - if (!NoWidth && !Nested && !hasMultiArgumentPhi(Input.Mapping.LHS)) { - ShrinkWrap Shrink(IC, S, Input, 8); - auto Smol = Shrink(); - if (Smol) { - if (DebugLevel > 2) { - llvm::errs() << "Shrinked: \n"; - InfixPrinter P(Smol.value()); - P(llvm::errs()); - Smol->print(llvm::errs(), true); - llvm::errs() << "\n"; - if (DebugLevel > 4) { - Smol.value().print(llvm::errs(), true); - } - } - Input = Smol.value(); - - // Input.print(llvm::errs(), true); - - } else { - if (DebugLevel > 2) { - llvm::errs() << "Shrinking failed\n"; - } - } - } auto Fresh = Input; size_t ticks = std::clock(); @@ -2039,12 +2005,12 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (!CommonConsts.empty()) { Result = Replace(Result, IC, CommonConsts); auto Clone = Verify(Result, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } Clone = SimplePreconditionsAndVerifyGreedy(Result, IC, S, SymCS); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } @@ -2097,14 +2063,14 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Copy = Replace(Input, IC, JustLHSSymConstMap); auto Clone = SimplePreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } Refresh("LHS Constraints"); Clone = DFPreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } } @@ -2129,7 +2095,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Clone = FirstValidCombination(Input, RHSFresh, UnitaryCandidates, InstCache, IC, S, SymCS, true, false, false, Relations); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } Refresh("Unitary cands, rel constraints"); @@ -2145,16 +2111,9 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { - return Clone; - } - - Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, - InstCache, IC, S, SymCS, true, false, false, ConstantLimits); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } - } Refresh("Special expressions, no constants"); @@ -2175,7 +2134,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (!EnumeratedCandidates.empty()) { auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } Refresh("Enumerated cands, no constraints"); @@ -2191,7 +2150,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } } @@ -2200,7 +2159,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (!EnumeratedCandidates.empty()) { auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, InstCache, IC, S, SymCS, false, true, true); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } @@ -2211,7 +2170,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, InstCache, IC, S, SymCS, true, false, false, Relations); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } } @@ -2227,7 +2186,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, // << "\tRels: " << Relations.size() << "\n"; auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidatesTwoInsts, InstCache, IC, S, SymCS, true, false, false, Relations); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } } @@ -2243,7 +2202,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, InstCache, IC, S, SymCS, true, false, false); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } } @@ -2255,7 +2214,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (!EnumeratedCandidates.empty() && !Nested) { auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, InstCache, IC, S, SymCS, true, true, true, Relations); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } Refresh("Enumerated exprs with constraints and relations"); @@ -2266,14 +2225,14 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (!SimpleCandidates.empty()) { auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, InstCache, IC, S, SymCS, false, true, true); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } Refresh("Simple cands with constraints"); Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, InstCache, IC, S, SymCS, true, false, false, Relations); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } Refresh("Simple cands with constraints and relations"); @@ -2284,14 +2243,14 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (!SimpleCandidatesWithConsts.empty() && !Nested) { auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, InstCache, IC, S, SymCS, false, true, true); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } Refresh("Simple cands+consts with constraints"); Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, InstCache, IC, S, SymCS, true, true, true, Relations); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } @@ -2319,16 +2278,23 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, if (!EnumeratedCandidates.empty()) { auto Clone = FirstValidCombination(Input, RHSFresh, EnumeratedCandidates, InstCache, IC, S, SymCS, true, true, false, ConstantLimits); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } Refresh("Enumerated expressions+consts and constant limits"); } + if (!SimpleCandidates.empty()) { + auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidates, + InstCache, IC, S, SymCS, true, false, false, ConstantLimits); + if (Clone) { + return Clone; + } + } if (!SimpleCandidatesWithConsts.empty()) { auto Clone = FirstValidCombination(Input, RHSFresh, SimpleCandidatesWithConsts, InstCache, IC, S, SymCS, true, false, false, ConstantLimits); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { return Clone; } Refresh("Simple expressions+consts and constant limits"); @@ -2352,7 +2318,7 @@ ParsedReplacement SuccessiveSymbolize(InstContext &IC, bool SymDFChanged = false; auto Clone = Verify(Aug, IC, S); - if (Clone.Mapping.LHS && Clone.Mapping.RHS) { + if (Clone) { // Symbolic db+kb can be unconstrained // very unlikely? test if needed return Clone; @@ -2451,13 +2417,63 @@ InstantiateWidthChecks(InstContext &IC, return {Input, false}; } +std::optional GeneralizeShrinked( + ParsedReplacement Input, InstContext &IC, Solver *S) { + + if (hasMultiArgumentPhi(Input.Mapping.LHS)) { + return std::nullopt; + } + + ShrinkWrap Shrink(IC, S, Input, 8); + auto Smol = Shrink(); + + if (Smol) { + if (DebugLevel > 2) { + llvm::errs() << "Shrinked: \n"; + InfixPrinter P(Smol.value()); + P(llvm::errs()); + Smol->print(llvm::errs(), true); + llvm::errs() << "\n"; + if (DebugLevel > 4) { + Smol.value().print(llvm::errs(), true); + } + } + Input = Smol.value(); + + // Input.print(llvm::errs(), true); + + } else { + if (DebugLevel > 2) { + llvm::errs() << "Shrinking failed\n"; + } + return std::nullopt; + } + + bool Changed = false; + + auto Gen = SuccessiveSymbolize(IC, S, Smol.value(), Changed); + + if (!Changed || !Gen) { + if (DebugLevel > 2) { + llvm::errs() << "Shrinking failed\n"; + } + return std::nullopt; // Generalization failed. + } + + auto [GenWidth, WidthChanged] = InstantiateWidthChecks(IC, S, Gen.value()); + + if (!WidthChanged) { + return std::nullopt; // Width independence check failed. + } + return Gen; +} + template Stream &operator<<(Stream &S, InfixPrinter IP) { IP(S); return S; } - void PrintInputAndResult(ParsedReplacement Input, ParsedReplacement Result) { ReplacementContext RC; Result.printLHS(llvm::outs(), RC, true); @@ -2519,14 +2535,28 @@ int main(int argc, char **argv) { if (!JustReduce) { bool Changed = false; - size_t MaxTries = 2; // Increase this if we ever run with 10/100x timeout. + size_t MaxTries = 1; // Increase this if we ever run with 10/100x timeout. bool FirstTime = true; do { if (!OnlyWidth) { if (Changed) { Result = ReduceBasic(IC, S.get(), Result); } - Result = SuccessiveSymbolize(IC, S.get(), Result, Changed); + + std::optional Opt; + if (!NoWidth) { + Opt = GeneralizeShrinked(Result, IC, S.get()); + } + + if (!Opt) { + Opt = SuccessiveSymbolize(IC, S.get(), Result, Changed); + } else { + Changed = true; + } + + if (Opt) { + Result = *Opt; + } } bool Indep = false; if (!NoWidth) { diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 6da2cf1e4..4196131a1 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -391,6 +391,10 @@ namespace util { } auto W = V->getType()->getIntegerBitWidth(); + // if (Val.size() != W) { + // return false; + // } + llvm::APInt Value(W, Val, 2); if (ConstantInt *Con = llvm::dyn_cast(V)) { auto X = Con->getUniqueInteger(); @@ -417,6 +421,11 @@ namespace util { return false; } auto W = V->getType()->getIntegerBitWidth(); + + // if (Val.size() != W) { + // return false; + // } + llvm::APInt Value(W, Val, 2); if (ConstantInt *Con = llvm::dyn_cast(V)) { auto X = Con->getUniqueInteger(); @@ -445,6 +454,11 @@ namespace util { } bool vdb(llvm::DemandedBits *DB, llvm::Instruction *I, std::string DBUnderApprox) { + + // if (DBUnderApprox.size() != I->getType()->getIntegerBitWidth()) { + // return false; + // } + llvm::APInt V = llvm::APInt(I->getType()->getIntegerBitWidth(), DBUnderApprox, 2); auto ComputedDB = DB->getDemandedBits(I); @@ -597,7 +611,8 @@ struct SouperCombine : public FunctionPass { !isa(&I) && !isa(&I) && !isa(&I) && - !isa(&I)) { + !isa(&I) && + I.getType()->isIntegerTy()) { W.push(&I); } } From 09991efe5f83a8f96bc8c8679069bee384039075 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 3 Apr 2023 20:47:01 -0600 Subject: [PATCH 156/165] foo --- include/souper/Infer/SynthUtils.h | 4 +- lib/Infer/Interpreter.cpp | 11 +++-- test/Generalize/ctpop.opt | 6 +-- tools/generalize.cpp | 74 +++++++++++++++++++++++-------- 4 files changed, 68 insertions(+), 27 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index b31c321a3..954b467f8 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -36,8 +36,8 @@ class Builder { BINOP(Add) BINOP(Sub) BINOP(Mul) BINOP(And) BINOP(Xor) BINOP(Or) - BINOP(Shl) BINOP(LShr) BINOP(UDiv) - BINOP(SDiv) + BINOP(Shl) BINOP(LShr) BINOP(AShr) + BINOP(UDiv) BINOP(SDiv) #undef BINOP template Builder Ugt(T t) { \ diff --git a/lib/Infer/Interpreter.cpp b/lib/Infer/Interpreter.cpp index ad306bea1..9197cb9d3 100644 --- a/lib/Infer/Interpreter.cpp +++ b/lib/Infer/Interpreter.cpp @@ -480,13 +480,16 @@ namespace souper { if (Cache.find(Root) != Cache.end()) return Cache[Root]; - // TODO SmallVector + if (Root->K == Inst::BitWidth) { + return {llvm::APInt(Root->Width, Root->Width)}; + } + std::vector EvaluatedArgs; for (auto &&I : Root->Ops) EvaluatedArgs.push_back(evaluateInst(I)); - auto Result = evaluateSingleInst(Root, EvaluatedArgs); - if (CacheWritable) - Cache[Root] = Result; + auto Result = evaluateSingleInst(Root, EvaluatedArgs); + if (CacheWritable) + Cache[Root] = Result; return Result; } diff --git a/test/Generalize/ctpop.opt b/test/Generalize/ctpop.opt index 471aa58a2..fecdaa884 100644 --- a/test/Generalize/ctpop.opt +++ b/test/Generalize/ctpop.opt @@ -8,9 +8,9 @@ infer %2 %3:i1 = eq 255:i8, %v0 result %3 -; CHECK: C1:i8 == (width(C1) - 1) +; CHECK: C1:i8 == (width(v0:i8) - 1) ; CHECK: |= -; CHECK: C1 ; CHECK: v0 == 0xFF -; TODO: synthesize independent fn instead of 255 \ No newline at end of file +; TODO: synthesize independent fn instead of 255 diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 2b9d67196..5c25f262a 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -729,11 +729,11 @@ std::vector FilterRelationsByValue(const std::vector &Relations, std::vector FilteredRelations; for (auto &&R : Relations) { - auto Result = CPos.evaluateInst(R); - // Positive example - if (Result.hasValue() && !Result.getValue().isAllOnesValue()) { - continue; - } + // auto Result = CPos.evaluateInst(R); + // // Positive example + // if (Result.hasValue() && !Result.getValue().isAllOnesValue()) { + // continue; + // } // Negative examples bool foundUnsound = false; @@ -760,6 +760,10 @@ std::vector InferConstantLimits( if (!FindConstantRelations) { return Results; } + + std::vector Inputs; + findVars(Input.Mapping.LHS, Inputs); + auto ConcreteConsts = findConcreteConsts(Input); std::sort(ConcreteConsts.begin(), ConcreteConsts.end(), [](auto A, auto B) { @@ -772,19 +776,40 @@ std::vector InferConstantLimits( for (auto &&[XI, XC] : CMap) { // X < Width, X <= Width - auto Width = Builder(XI, IC).BitWidth(); - Results.push_back(Builder(XI, IC).Ult(Width)()); - Results.push_back(Builder(XI, IC).Ule(Width)()); + Inputs.push_back(XI); + for (auto I : Inputs) { + Inst *W = Builder(I, IC).BitWidth()(); + + if (I->Width > XI->Width) { + W = Builder(W, IC).Trunc(XI->Width)(); + } else if (I->Width < XI->Width) { + W = Builder(W, IC).ZExt(XI->Width)(); + } + + auto Width = Builder(W, IC); + + // X Ule SMAX, x Ule UMAX + auto WM1 = Width.Sub(1); + auto SMax = Builder(IC, llvm::APInt(XI->Width, 1)).Shl(WM1).Sub(1); + auto UMax = SMax.Shl(1).Add(1); + Results.push_back(Builder(XI, IC).Ule(UMax)()); + Results.push_back(Builder(XI, IC).Ule(SMax)()); + Results.push_back(Builder(XI, IC).Ult(UMax)()); + Results.push_back(Builder(XI, IC).Ult(SMax)()); + + Results.push_back(Builder(XI, IC).Ult(Width)()); + Results.push_back(Builder(XI, IC).Ule(Width)()); - // X slt SMAX, x ult UMAX - auto WM1 = Width.Sub(1); - auto SMax = Builder(IC, llvm::APInt(XI->Width, 1)).Shl(WM1).Sub(1)(); - Results.push_back(Builder(XI, IC).Slt(SMax)()); + auto gZ = Builder(XI, IC).Ugt(0)(); - auto gZ = Builder(XI, IC).Ugt(0)(); + Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); + Results.push_back(Builder(XI, IC).Ule(Width).And(gZ)()); - Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); - Results.push_back(Builder(XI, IC).Ule(Width).And(gZ)()); + Results.push_back(Builder(XI, IC).Eq(Width.Sub(1))()); + Results.push_back(Builder(XI, IC).Eq(Width.UDiv(2))()); + Results.push_back(Builder(XI, IC).Eq(Width)()); + } + Inputs.pop_back(); // 2 * X < C, 2 * X >= C for (auto C : ConcreteConsts) { @@ -822,6 +847,7 @@ std::vector InferConstantLimits( } } } + // return Results; return FilterRelationsByValue(Results, CMap, CEXs); } @@ -1015,9 +1041,6 @@ std::vector InferPotentialRelations( // } } - Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth().Sub(1))()); - // Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth().UDiv(2))()); - // Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth())()); } // TODO: Make sure this works. @@ -1252,7 +1275,22 @@ std::optional VerifyWithRels(InstContext &IC, Solver *S, for (auto Rel : Rels) { Input.PCs.push_back({Rel, IC.getConst(llvm::APInt(1, 1))}); + + // Input.print(llvm::errs(), true); + + // llvm::errs() << "\n"; + + // InfixPrinter IP(Input, true); + // IP(llvm::errs()); + + // llvm::errs() << "\n"; + + auto Clone = Verify(Input, IC, S); + + // llvm::errs() << "Valid? " << (Clone ? "yes" : "no") << "\n"; + + if (Clone) { ValidRels.push_back(Rel); FirstValidResult = Clone.value(); From af84b4a1c43a2e1b68575387d3d5e20a13c1d876 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 4 Apr 2023 00:02:42 -0600 Subject: [PATCH 157/165] Revert "foo" This reverts commit 09991efe5f83a8f96bc8c8679069bee384039075. --- include/souper/Infer/SynthUtils.h | 4 +- lib/Infer/Interpreter.cpp | 11 ++--- test/Generalize/ctpop.opt | 6 +-- tools/generalize.cpp | 74 ++++++++----------------------- 4 files changed, 27 insertions(+), 68 deletions(-) diff --git a/include/souper/Infer/SynthUtils.h b/include/souper/Infer/SynthUtils.h index 954b467f8..b31c321a3 100644 --- a/include/souper/Infer/SynthUtils.h +++ b/include/souper/Infer/SynthUtils.h @@ -36,8 +36,8 @@ class Builder { BINOP(Add) BINOP(Sub) BINOP(Mul) BINOP(And) BINOP(Xor) BINOP(Or) - BINOP(Shl) BINOP(LShr) BINOP(AShr) - BINOP(UDiv) BINOP(SDiv) + BINOP(Shl) BINOP(LShr) BINOP(UDiv) + BINOP(SDiv) #undef BINOP template Builder Ugt(T t) { \ diff --git a/lib/Infer/Interpreter.cpp b/lib/Infer/Interpreter.cpp index 9197cb9d3..ad306bea1 100644 --- a/lib/Infer/Interpreter.cpp +++ b/lib/Infer/Interpreter.cpp @@ -480,16 +480,13 @@ namespace souper { if (Cache.find(Root) != Cache.end()) return Cache[Root]; - if (Root->K == Inst::BitWidth) { - return {llvm::APInt(Root->Width, Root->Width)}; - } - + // TODO SmallVector std::vector EvaluatedArgs; for (auto &&I : Root->Ops) EvaluatedArgs.push_back(evaluateInst(I)); - auto Result = evaluateSingleInst(Root, EvaluatedArgs); - if (CacheWritable) - Cache[Root] = Result; + auto Result = evaluateSingleInst(Root, EvaluatedArgs); + if (CacheWritable) + Cache[Root] = Result; return Result; } diff --git a/test/Generalize/ctpop.opt b/test/Generalize/ctpop.opt index fecdaa884..471aa58a2 100644 --- a/test/Generalize/ctpop.opt +++ b/test/Generalize/ctpop.opt @@ -8,9 +8,9 @@ infer %2 %3:i1 = eq 255:i8, %v0 result %3 -; CHECK: C1:i8 == (width(v0:i8) - 1) +; CHECK: C1:i8 == (width(C1) - 1) ; CHECK: |= -; CHECK: C1 ; CHECK: v0 == 0xFF -; TODO: synthesize independent fn instead of 255 +; TODO: synthesize independent fn instead of 255 \ No newline at end of file diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 5c25f262a..2b9d67196 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -729,11 +729,11 @@ std::vector FilterRelationsByValue(const std::vector &Relations, std::vector FilteredRelations; for (auto &&R : Relations) { - // auto Result = CPos.evaluateInst(R); - // // Positive example - // if (Result.hasValue() && !Result.getValue().isAllOnesValue()) { - // continue; - // } + auto Result = CPos.evaluateInst(R); + // Positive example + if (Result.hasValue() && !Result.getValue().isAllOnesValue()) { + continue; + } // Negative examples bool foundUnsound = false; @@ -760,10 +760,6 @@ std::vector InferConstantLimits( if (!FindConstantRelations) { return Results; } - - std::vector Inputs; - findVars(Input.Mapping.LHS, Inputs); - auto ConcreteConsts = findConcreteConsts(Input); std::sort(ConcreteConsts.begin(), ConcreteConsts.end(), [](auto A, auto B) { @@ -776,40 +772,19 @@ std::vector InferConstantLimits( for (auto &&[XI, XC] : CMap) { // X < Width, X <= Width - Inputs.push_back(XI); - for (auto I : Inputs) { - Inst *W = Builder(I, IC).BitWidth()(); - - if (I->Width > XI->Width) { - W = Builder(W, IC).Trunc(XI->Width)(); - } else if (I->Width < XI->Width) { - W = Builder(W, IC).ZExt(XI->Width)(); - } - - auto Width = Builder(W, IC); - - // X Ule SMAX, x Ule UMAX - auto WM1 = Width.Sub(1); - auto SMax = Builder(IC, llvm::APInt(XI->Width, 1)).Shl(WM1).Sub(1); - auto UMax = SMax.Shl(1).Add(1); - Results.push_back(Builder(XI, IC).Ule(UMax)()); - Results.push_back(Builder(XI, IC).Ule(SMax)()); - Results.push_back(Builder(XI, IC).Ult(UMax)()); - Results.push_back(Builder(XI, IC).Ult(SMax)()); - - Results.push_back(Builder(XI, IC).Ult(Width)()); - Results.push_back(Builder(XI, IC).Ule(Width)()); + auto Width = Builder(XI, IC).BitWidth(); + Results.push_back(Builder(XI, IC).Ult(Width)()); + Results.push_back(Builder(XI, IC).Ule(Width)()); - auto gZ = Builder(XI, IC).Ugt(0)(); + // X slt SMAX, x ult UMAX + auto WM1 = Width.Sub(1); + auto SMax = Builder(IC, llvm::APInt(XI->Width, 1)).Shl(WM1).Sub(1)(); + Results.push_back(Builder(XI, IC).Slt(SMax)()); - Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); - Results.push_back(Builder(XI, IC).Ule(Width).And(gZ)()); + auto gZ = Builder(XI, IC).Ugt(0)(); - Results.push_back(Builder(XI, IC).Eq(Width.Sub(1))()); - Results.push_back(Builder(XI, IC).Eq(Width.UDiv(2))()); - Results.push_back(Builder(XI, IC).Eq(Width)()); - } - Inputs.pop_back(); + Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); + Results.push_back(Builder(XI, IC).Ule(Width).And(gZ)()); // 2 * X < C, 2 * X >= C for (auto C : ConcreteConsts) { @@ -847,7 +822,6 @@ std::vector InferConstantLimits( } } } - // return Results; return FilterRelationsByValue(Results, CMap, CEXs); } @@ -1041,6 +1015,9 @@ std::vector InferPotentialRelations( // } } + Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth().Sub(1))()); + // Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth().UDiv(2))()); + // Results.push_back(Builder(XI, IC).Eq(Builder(XI, IC).BitWidth())()); } // TODO: Make sure this works. @@ -1275,22 +1252,7 @@ std::optional VerifyWithRels(InstContext &IC, Solver *S, for (auto Rel : Rels) { Input.PCs.push_back({Rel, IC.getConst(llvm::APInt(1, 1))}); - - // Input.print(llvm::errs(), true); - - // llvm::errs() << "\n"; - - // InfixPrinter IP(Input, true); - // IP(llvm::errs()); - - // llvm::errs() << "\n"; - - auto Clone = Verify(Input, IC, S); - - // llvm::errs() << "Valid? " << (Clone ? "yes" : "no") << "\n"; - - if (Clone) { ValidRels.push_back(Rel); FirstValidResult = Clone.value(); From 7beb5ba275439e3f952202341966768be133556e Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 4 Apr 2023 04:49:06 -0600 Subject: [PATCH 158/165] foo --- tools/generalize.cpp | 15 +- tools/matcher-gen.cpp | 237 ++++++++++++++++++-------- tools/pass-generator/src/template.cpp | 19 +++ 3 files changed, 198 insertions(+), 73 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 2b9d67196..72218f7ef 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -771,6 +771,9 @@ std::vector InferConstantLimits( }); for (auto &&[XI, XC] : CMap) { + if (XI->Width == 1) { + continue; + } // X < Width, X <= Width auto Width = Builder(XI, IC).BitWidth(); Results.push_back(Builder(XI, IC).Ult(Width)()); @@ -968,7 +971,7 @@ std::vector InferPotentialRelations( // Mul C if (C2 && YC!= 0 && XC.urem(YC) == 0) { auto Fact = XC.udiv(YC); - if (Fact != 1) { + if (Fact != 1 && Fact != 0) { Results.push_back(Builder(YI, IC).Mul(Fact).Eq(XI)()); } } @@ -981,7 +984,7 @@ std::vector InferPotentialRelations( if (C2 && XC != 0 && YC.urem(XC) == 0) { auto Fact = YC.udiv(XC); - if (Fact != 1) { + if (Fact != 1 && Fact != 0) { Results.push_back(Builder(XI, IC).Mul(Fact).Eq(YI)()); } } @@ -2483,14 +2486,14 @@ void PrintInputAndResult(ParsedReplacement Input, ParsedReplacement Result) { if (DebugLevel > 1) { llvm::errs() << "IR Input: \n"; ReplacementContext RC; - Input.printLHS(llvm::outs(), RC, true); - Input.printRHS(llvm::outs(), RC, true); - llvm::outs() << "\n"; + Input.printLHS(llvm::errs(), RC, true); + Input.printRHS(llvm::errs(), RC, true); + llvm::errs() << "\n"; llvm::errs() << "\n\tInput (profit=" << profit(Input) << "):\n\n" << InfixPrinter(Input) << "\n\tGeneralized (profit=" << profit(Result) << "):\n\n" << InfixPrinter(Result, NoWidth) << "\n"; - Result.print(llvm::errs(), true); + // Result.print(llvm::errs(), true); } llvm::outs().flush(); } diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 7fed6bd8d..aa8c2c704 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -39,7 +39,7 @@ static llvm::cl::opt NoDispatch("no-dispatch", "(default=false)"), llvm::cl::init(false)); -static llvm::cl::opt ExplicitWidths("explicit-width-checks", +static llvm::cl::opt OnlyExplicitWidths("explicit-width-checks", llvm::cl::desc("Only generate width checks when explicitly specified." "(default=false)"), llvm::cl::init(false)); @@ -246,7 +246,7 @@ struct CR : public Constraint { std::string Name, L, H; }; -struct SymbolTable : public std::map> { +struct SymbolTable : public std::map { std::vector Constraints; std::map Preds; @@ -292,19 +292,27 @@ struct SymbolTable : public std::map> { Out << ";\n"; } void GenVarEqConstraints() { - for (auto &&S : *this) { - if (S.second.size() > 1) { - for (size_t i = 1; i < S.second.size(); ++i) { - Constraints.push_back(new VarEq(S.second[0], S.second[i])); - } - } - } + // for (auto &&S : *this) { + // if (S.second.size() > 1) { + // for (size_t i = 1; i < S.second.size(); ++i) { + // Constraints.push_back(new VarEq(S.second[0], S.second[i])); + // } + // } + // } } // Try to translate Souper expressions to APInt operations. std::pair Translate(souper::Inst *I) { std::vector> Children; + if (I->K == Inst::BitWidth) { + if (at(I->Ops[0]).empty()) { + return {"", false}; + } + auto Sym = at(I->Ops[0]); + return {"util::W(" + Sym + ")", true}; + } + for (auto Op : I ->Ops) { Children.push_back(Translate(Op)); if (!Children.back().second) { @@ -324,15 +332,24 @@ struct SymbolTable : public std::map> { return "(" + Children[0].first + " " + Str + " " + Children[1].first + ")"; }; + auto FUN = [&](auto Str) { + return std::string(Str) + "(" + Children[0].first + ", " + Children[1].first + ")"; + }; + switch (I->K) { - case Inst::Var : if (exists(I)) { - return {"util::V(" + at(I)[0] + ")", true}; + case Inst::Var : + if (exists(I)) { + return {"util::V(" + at(I) + ")", true}; } else { return {"", false}; } case Inst::Const : - return {"util::V(" + std::to_string(I->Width) - + ", \"" + I->Val.toString(10, false) + "\")", true}; + if (I->Width <= 64) { + return {I->Val.toString(10, false), true}; + } else { + return {"util::V(" + std::to_string(I->Width) + + ", \"" + I->Val.toString(10, false) + "\")", true}; + } case Inst::AddNW : case Inst::AddNUW : @@ -349,7 +366,13 @@ struct SymbolTable : public std::map> { case Inst::MulNSW : case Inst::Mul : return {OP("*"), true}; - case Inst::Shl : return {MET("shl"), true}; + case Inst::Shl : { + if (isdigit(Children[0].first[0])) { + return {FUN("shl"), true}; + } else { + return {MET("shl"), true}; + } + } case Inst::LShr : return {MET("lshr"), true}; case Inst::AShr : return {MET("ashr"), true}; @@ -362,12 +385,48 @@ struct SymbolTable : public std::map> { case Inst::UDiv : return {MET("udiv"), true}; case Inst::SDiv : return {MET("sdiv"), true}; - case Inst::Slt : return {MET("slt"), true}; - case Inst::Sle : return {MET("sle"), true}; - case Inst::Ult : return {MET("ult"), true}; - case Inst::Ule : return {MET("ule"), true}; - case Inst::Eq : return {MET("eq"), true}; - case Inst::Ne : return {MET("ne"), true}; + case Inst::Slt : { + if (isdigit(Children[0].first[0])) { + return {OP("<"), true}; + } else { + return {MET("slt"), true}; + } + } + case Inst::Sle : { + if (isdigit(Children[0].first[0])) { + return {OP("<="), true}; + } else { + return {MET("sle"), true}; + } + } + case Inst::Ult : { + if (isdigit(Children[0].first[0])) { + return {OP("<"), true}; + } else { + return {MET("ult"), true}; + } + } + case Inst::Ule : { + if (isdigit(Children[0].first[0])) { + return {OP("<="), true}; + } else { + return {MET("ule"), true}; + } + } + case Inst::Eq : { + if (isdigit(Children[0].first[0])) { + return {OP("=="), true}; + } else { + return {MET("eq"), true}; + } + } + case Inst::Ne : { + if (isdigit(Children[0].first[0])) { + return {OP("!="), true}; + } else { + return {MET("ne"), true}; + } + } case Inst::ZExt : return {WC("zext"), true}; case Inst::SExt : return {WC("sext"), true}; case Inst::Trunc : return {WC("trunc"), true}; @@ -384,11 +443,11 @@ struct SymbolTable : public std::map> { if (PC.LHS->K != Inst::Eq) return nullptr; if (PC.LHS->Ops[0]->K == Inst::BitWidth) { - return new WidthEq(this->at(PC.LHS->Ops[0]->Ops[0])[0], + return new WidthEq(this->at(PC.LHS->Ops[0]->Ops[0]), PC.LHS->Ops[1]->Val.getLimitedValue()); } if (PC.LHS->Ops.size() > 1 && PC.LHS->Ops[1]->K == Inst::BitWidth) { - return new WidthEq(this->at(PC.LHS->Ops[1]->Ops[0])[0], + return new WidthEq(this->at(PC.LHS->Ops[1]->Ops[0]), PC.LHS->Ops[0]->Val.getLimitedValue()); } return nullptr; @@ -397,12 +456,12 @@ struct SymbolTable : public std::map> { bool GenPCConstraints(std::vector PCs) { for (auto M : PCs) { if (M.LHS->K == Inst::KnownZerosP) { - Constraint *C = new SymK0(this->at(M.LHS->Ops[0])[0], - this->at(M.LHS->Ops[1])[0]); + Constraint *C = new SymK0(this->at(M.LHS->Ops[0]), + this->at(M.LHS->Ops[1])); Constraints.push_back(C); } else if (M.LHS->K == Inst::KnownOnesP) { - Constraint *C = new SymK1(this->at(M.LHS->Ops[0])[0], - this->at(M.LHS->Ops[1])[0]); + Constraint *C = new SymK1(this->at(M.LHS->Ops[0]), + this->at(M.LHS->Ops[1])); Constraints.push_back(C); } else if (auto WC = ConvertPCToWidthConstraint(M)) { Constraints.push_back(WC); @@ -429,7 +488,7 @@ struct SymbolTable : public std::map> { auto It = find(Op); if (It != end()) { if (Visited.find(Op) == Visited.end()) { - Constraints.push_back(new DomCheck(It->second[0])); + Constraints.push_back(new DomCheck(It->second)); GenDomConstraints(Op); } } @@ -451,7 +510,7 @@ struct SymbolTable : public std::map> { } for (auto &&V : VarSet) { - auto Name = this->at(V)[0]; + auto Name = this->at(V); if (V->KnownOnes.getBitWidth() == V->Width && V->KnownOnes != 0) { Constraints.push_back(new K1(Name, V->KnownOnes.toString(2, false))); @@ -472,7 +531,7 @@ struct SymbolTable : public std::map> { findVars(LHS, Vars); for (auto V : Vars) { - auto Name = this->at(V)[0]; + auto Name = this->at(V); if (!WidthIndependent || LHS->Width == 1 || V->Width == 1) { Constraints.push_back(new WidthEq(Name, V->Width)); @@ -536,13 +595,13 @@ struct SymbolTable : public std::map> { << "APInt(" << C->Val.getBitWidth() << ", " << "\"" << C->Val.toString(10, false) << "\", 10), B);\n"; } - Syms[C].push_back(Name); + Syms[C] = Name; }; for (auto C : ConstRefs) { - if (Consts.find(C) == Consts.end()) { + // if (Consts.find(C) == Consts.end()) { Print(*this, C); - } + // } } } }; @@ -551,12 +610,19 @@ template bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms, bool IsRoot = false) { if (!IsRoot) { if (I->K != souper::Inst::Var && Syms.Used.find(I) != Syms.Used.end()) { - Out << "&" << Syms[I].back() << " <<= "; + Out << "&" << Syms[I] << " <<= "; } } + static std::set MatchedVals; if (IsRoot && I->K == Inst::Var) { - Out << "m_Value(" << Syms[I].front() << ")"; + if (MatchedVals.find(I) == MatchedVals.end()) { + MatchedVals.insert(I); + Out << "m_Value(" << Syms[I] << ")"; + return true; + } else { + Out << "m_Deferred(" << Syms[I] << ")"; + } return true; } @@ -570,8 +636,10 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms, bool IsRoot = false) Out << Op; - if (I->K == Inst::SExt || I->K == Inst::ZExt || I->K == Inst::Trunc) { - Out << I->Width << ", "; + if (!OnlyExplicitWidths) { + if (I->K == Inst::SExt || I->K == Inst::ZExt || I->K == Inst::Trunc) { + Out << I->Width << ", "; + } } if (PredNames.find(I->K) != PredNames.end()) { @@ -588,24 +656,29 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms, bool IsRoot = false) if (Child->K == Inst::Const) { if (Child->K != souper::Inst::Var && Syms.Used.find(Child) != Syms.Used.end()) { - Out << "&" << Syms[Child].back() << " <<= "; + Out << "&" << Syms[Child] << " <<= "; } auto Str = Child->Val.toString(10, false); - if (ExplicitWidths) { + if (OnlyExplicitWidths) { Out << "m_SpecificInt(\"" << Str << "\")"; } else { Out << "m_SpecificInt( " << Child->Width << ", \"" << Str << "\")"; } } else if (Child->K == Inst::Var) { if (Child->Name.starts_with("symconst")) { - Out << "m_Constant(&" << Syms[Child].back() << ")"; + Out << "m_Constant(&" << Syms[Child] << ")"; } else if (Child->Name.starts_with("constexpr")) { llvm::errs() << "FOUND A CONSTEXPR\n"; return false; } else { - Out << "m_Value(" << Syms[Child].back() << ")"; + if (MatchedVals.find(Child) == MatchedVals.end()) { + MatchedVals.insert(Child); + Out << "m_Value(" << Syms[Child] << ")"; + } else { + Out << "m_Deferred(" << Syms[Child] << ")"; + } } - Syms[Child].pop_back(); + // Syms[Child].pop_back(); } else { if (!GenLHSMatcher(Child, Out, Syms)) { return false; @@ -631,7 +704,7 @@ Inst *getSibling(Inst *Child, Inst *Parent) { } template -bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms) { +bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms, Inst *Parent = nullptr) { auto It = CreateOps.find(I->K); if (It == CreateOps.end()) { llvm::errs() << "\nUnimplemented creator:" << Inst::getKindName(I->K) << "\n"; @@ -648,26 +721,37 @@ bool GenRHSCreator(Inst *I, Stream &Out, SymbolTable &Syms) { Out << ", "; } if (Syms.find(Child) != Syms.end()) { - Out << Syms[Child][0]; - if (Child->K == Inst::Const && Syms[Child][0].starts_with("C")) { + Out << Syms[Child]; + if (Child->K == Inst::Const && Syms[Child].starts_with("C")) { auto Sib = getSibling(Child, I); std::string S; if (Syms.find(Sib) != Syms.end()) { - if (Syms[Sib][0].starts_with("x")) { - S = Syms[Sib][0]; + if (Syms[Sib].starts_with("x")) { + S = Syms[Sib]; } } - Out << "(" << S << ")"; + Out << "(" << S << ")"; // Ad-hoc type inference } } else { - if (!GenRHSCreator(Child, Out, Syms)) { + if (!GenRHSCreator(Child, Out, Syms, I)) { return false; } } } if (I->K == Inst::Trunc || I->K == Inst::SExt || I->K == Inst::ZExt) { - Out << ", T(" << I->Width << ", B)"; + auto Cousin = getSibling(I, Parent); + std::string S; + if (Syms.find(Cousin) != Syms.end()) { + if (Syms[Cousin].starts_with("x")) { + S = Syms[Cousin]; + } + } + if (!S.empty()) { + Out << ", T(" << S << ")"; // Ad-hoc type inference + } else { + Out << ", T(" << I->Width << ", B)"; + } } Out << ")"; @@ -679,6 +763,7 @@ bool InitSymbolTable(ParsedReplacement Input, Stream &Out, SymbolTable &Syms) { auto Root = Input.Mapping.LHS; auto RHS = Input.Mapping.RHS; std::set LHSInsts; + std::set Visited; std::vector Stack{Root}; for (auto M : Input.PCs) { @@ -690,20 +775,39 @@ bool InitSymbolTable(ParsedReplacement Input, Stream &Out, SymbolTable &Syms) { while (!Stack.empty()) { auto I = Stack.back(); Stack.pop_back(); - Syms.RegisterPred(I); LHSInsts.insert(I); + Visited.insert(I); if (I->K == Inst::Var) { - Syms[I].push_back("x" + std::to_string(varnum++)); + if (Syms.find(I) == Syms.end()) { + Syms[I] = ("x" + std::to_string(varnum++)); + // llvm::errs() << "Var1: " << I->Name << " -> " << Syms[I] << "\n"; + } } if (I->K == Inst::Const) { Syms.Consts.insert(I); } for (int i = 0; i < I->Ops.size(); ++i) { - Stack.push_back(I->Ops[i]); // Souper exprs are DAGs + if (Visited.find(I->Ops[i]) == Visited.end()) { + Stack.push_back(I->Ops[i]); + } } } - std::set Visited; + Visited.clear(); + Stack = {Root}; + while (!Stack.empty()) { + auto I = Stack.back(); + Stack.pop_back(); + Visited.insert(I); + Syms.RegisterPred(I); + for (int i = 0; i < I->Ops.size(); ++i) { + if (Visited.find(I->Ops[i]) == Visited.end()) { + Stack.push_back(I->Ops[i]); + } + } + } + + Visited.clear(); Stack.push_back(RHS); while (!Stack.empty()) { @@ -716,7 +820,8 @@ bool InitSymbolTable(ParsedReplacement Input, Stream &Out, SymbolTable &Syms) { if (LHSInsts.find(I) != LHSInsts.end()) { if (Syms.Used.insert(I).second && Syms.find(I) == Syms.end()) { - Syms[I].push_back("x" + std::to_string(varnum++)); + Syms[I] = ("x" + std::to_string(varnum++)); + // llvm::errs() << "Var0: " << I->Name << " -> " << Syms[I] << "\n"; } } for (auto Child : I->Ops) { @@ -731,14 +836,12 @@ bool InitSymbolTable(ParsedReplacement Input, Stream &Out, SymbolTable &Syms) { Out << "llvm::Value "; bool first = true; for (auto &&S : Syms) { - for (auto &&Name : S.second) { - if (first) { - first = false; - } else { - Out << ", "; - } - Out << "*" << Name; + if (first) { + first = false; + } else { + Out << ", "; } + Out << "*" << S.second; } Out << ";\n"; } @@ -764,7 +867,7 @@ bool InitSymbolTable(ParsedReplacement Input, Stream &Out, SymbolTable &Syms) { // Out << ");\n"; // Syms[P.first].push_back(Name); // } - Syms[Root].push_back("I"); + // Syms[Root].push_back("I"); Syms.PrintPreds(Out); return true; } @@ -805,7 +908,7 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn Inst *DemandedMask = nullptr; if (Input.Mapping.LHS->K == Inst::DemandedMask) { DemandedMask = Input.Mapping.LHS->Ops[1]; - Syms.Constraints.push_back(new SymDB(Syms[Input.Mapping.LHS->Ops[1]].back())); + Syms.Constraints.push_back(new SymDB(Syms[Input.Mapping.LHS->Ops[1]])); } Syms.GenVarEqConstraints(); Syms.GenVarPropConstraints(Input.Mapping.LHS, WidthIndependent); @@ -822,14 +925,14 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn Out << " auto ret"; if (Syms.find(Input.Mapping.RHS) != Syms.end()) { - Out << " = " << Syms[Input.Mapping.RHS][0]; - if (Syms[Input.Mapping.RHS][0].starts_with("C")) { + Out << " = " << Syms[Input.Mapping.RHS]; + if (Syms[Input.Mapping.RHS].starts_with("C")) { Out << "(I)"; } Out << ";"; } else if (Input.Mapping.RHS->K == Inst::DemandedMask && Syms.find(Input.Mapping.RHS->Ops[0]) != Syms.end()) { assert(DemandedMask == Input.Mapping.RHS->Ops[1] && "DemandedMask mismatch"); - Out << " = " << Syms[Input.Mapping.RHS->Ops[0]][0] << ";"; + Out << " = " << Syms[Input.Mapping.RHS->Ops[0]] << ";"; } else if (Input.Mapping.RHS->K == Inst::Const) { Out << " APInt Result(" << Input.Mapping.RHS->Width <<", " @@ -1127,7 +1230,7 @@ int main(int argc, char **argv) { std::string Str; llvm::raw_string_ostream Out(Str); - if (GenMatcher(Input, Out, optnumber, ExplicitWidths)) { + if (GenMatcher(Input, Out, optnumber, OnlyExplicitWidths)) { auto current = optnumber++; if (!optnumbers.empty() && optnumbers.find(current) == optnumbers.end()) { diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 4196131a1..874afea3a 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -567,6 +567,21 @@ namespace util { llvm::APInt V(llvm::Value *Ctx, std::string Val) { return llvm::APInt(Ctx->getType()->getIntegerBitWidth(), Val, 2); } + + llvm::APInt W(llvm::Value *Ctx) { + return llvm::APInt(Ctx->getType()->getIntegerBitWidth(), Ctx->getType()->getIntegerBitWidth()); + } + llvm::APInt W(llvm::Value *Ctx, size_t WidthOfWidth) { + return llvm::APInt(WidthOfWidth, Ctx->getType()->getIntegerBitWidth()); + } +} + +bool operator < (int x, const llvm::APInt &B) { + return llvm::APInt(B.getBitWidth(), x).ult(B); +} + +llvm::APInt shl(int A, llvm::APInt B) { + return llvm::APInt(B.getBitWidth(), A).shl(B); } struct SouperCombine : public FunctionPass { @@ -700,6 +715,10 @@ struct SouperCombine : public FunctionPass { return B->getIntNTy(W); } + Type *T(llvm::Value *V) { + return V->getType(); + } + InstructionWorklist W; util::Stats St; DominatorTree *DT; From db262b9a1929f6c71b53cb65215384976e97db20 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 4 Apr 2023 23:51:28 -0600 Subject: [PATCH 159/165] foo --- lib/Infer/Interpreter.cpp | 4 ++ tools/generalize.cpp | 94 ++++++++++++++++++++------- tools/matcher-gen.cpp | 4 +- tools/pass-generator/src/template.cpp | 46 +++++++++++-- 4 files changed, 118 insertions(+), 30 deletions(-) diff --git a/lib/Infer/Interpreter.cpp b/lib/Infer/Interpreter.cpp index ad306bea1..4220da1f6 100644 --- a/lib/Infer/Interpreter.cpp +++ b/lib/Infer/Interpreter.cpp @@ -480,6 +480,10 @@ namespace souper { if (Cache.find(Root) != Cache.end()) return Cache[Root]; + if (Root->K == Inst::BitWidth) { + return {llvm::APInt(Root->Width, Root->Width)}; + } + // TODO SmallVector std::vector EvaluatedArgs; for (auto &&I : Root->Ops) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 72218f7ef..79dcae893 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -626,10 +626,39 @@ struct ShrinkWrap { ResultWidth = TargetWidth; } + + // print kind name + // llvm::errs() << "Par " << Inst::getKindName(I->K) << " " << I->Width << " " << ResultWidth << '\n'; + + std::map OpMap; + std::vector OriginalOps = I->Ops; + + std::sort(OriginalOps.begin(), OriginalOps.end(), [&](Inst *A, Inst *B) { + if (InstCache.find(A) != InstCache.end()) { + return true; + } + if (A->K == Inst::Const) { + return false; + } + + if (A->K == Inst::Var && !(B->K == Inst::Var || B->K == Inst::Const)) { + return false; + } + return A->Width > B->Width; + }); + + for (auto Op : OriginalOps) { + OpMap[Op] = ShrinkInst(Op, I, ResultWidth); + if (Op->Width != 1) { + ResultWidth = OpMap[Op]->Width; + } + } + std::vector Ops; for (auto Op : I->Ops) { - Ops.push_back(ShrinkInst(Op, I, ResultWidth)); + Ops.push_back(OpMap[Op]); } + return IC.getInst(I->K, InferWidth(I->K, Ops), Ops); } } @@ -770,36 +799,54 @@ std::vector InferConstantLimits( } }); - for (auto &&[XI, XC] : CMap) { - if (XI->Width == 1) { - continue; - } - // X < Width, X <= Width - auto Width = Builder(XI, IC).BitWidth(); - Results.push_back(Builder(XI, IC).Ult(Width)()); - Results.push_back(Builder(XI, IC).Ule(Width)()); + std::vector Vars; + findVars(Input.Mapping.LHS, Vars); - // X slt SMAX, x ult UMAX - auto WM1 = Width.Sub(1); - auto SMax = Builder(IC, llvm::APInt(XI->Width, 1)).Shl(WM1).Sub(1)(); - Results.push_back(Builder(XI, IC).Slt(SMax)()); + for (auto V : Vars) { + for (auto &&[XI, XC] : CMap) { + if (XI->Width == 1) { + continue; + } + // X < Width, X <= Width + auto Width = Builder(V, IC).BitWidth()(); + + if (XI->Width < V->Width) { + Width = Builder(Width, IC).Trunc(XI->Width)(); + } else if (XI->Width > V->Width) { + Width = Builder(Width, IC).ZExt(XI->Width)(); + } + + Results.push_back(Builder(XI, IC).Ult(Width)()); + Results.push_back(Builder(XI, IC).Ule(Width)()); - auto gZ = Builder(XI, IC).Ugt(0)(); + // x ule UMAX + if (V->Width < XI->Width) { + auto UMax = Builder(IC, llvm::APInt(XI->Width, 1)).Shl(Width).Sub(1); + Results.push_back(Builder(XI, IC).Ule(UMax)()); + } - Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); - Results.push_back(Builder(XI, IC).Ule(Width).And(gZ)()); + // X ule SMAX + auto WM1 = Builder(Width, IC).Sub(1); + auto SMax = Builder(IC, llvm::APInt(XI->Width, 1)).Shl(WM1).Sub(1)(); + Results.push_back(Builder(XI, IC).Ule(SMax)()); - // 2 * X < C, 2 * X >= C - for (auto C : ConcreteConsts) { - if (C->Width != XI->Width) { - continue; + auto gZ = Builder(XI, IC).Ugt(0)(); + Results.push_back(Builder(XI, IC).Ult(Width).And(gZ)()); + Results.push_back(Builder(XI, IC).Ule(Width).And(gZ)()); + + // 2 * X < C, 2 * X >= C + for (auto C : ConcreteConsts) { + if (C->Width != XI->Width) { + continue; + } + auto Sum = Builder(XI, IC).Add(XI)(); + Results.push_back(Builder(Sum, IC).Ult(C->Val)()); + Results.push_back(Builder(Sum, IC).Ugt(C->Val)()); } - auto Sum = Builder(XI, IC).Add(XI)(); - Results.push_back(Builder(Sum, IC).Ult(C->Val)()); - Results.push_back(Builder(Sum, IC).Ugt(C->Val)()); } } + for (auto &&[XI, XC] : CMap) { for (auto &&[YI, YC] : CMap) { if (XI == YI) { @@ -825,6 +872,7 @@ std::vector InferConstantLimits( } } } + return FilterRelationsByValue(Results, CMap, CEXs); } diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index aa8c2c704..eb06a3903 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -533,7 +533,7 @@ struct SymbolTable : public std::map { for (auto V : Vars) { auto Name = this->at(V); - if (!WidthIndependent || LHS->Width == 1 || V->Width == 1) { + if (!WidthIndependent || V->Width == 1) { Constraints.push_back(new WidthEq(Name, V->Width)); } @@ -660,7 +660,7 @@ bool GenLHSMatcher(Inst *I, Stream &Out, SymbolTable &Syms, bool IsRoot = false) } auto Str = Child->Val.toString(10, false); if (OnlyExplicitWidths) { - Out << "m_SpecificInt(\"" << Str << "\")"; + Out << "m_ExtInt(\"" << Str << "\", " << Child->Width << ")"; } else { Out << "m_SpecificInt( " << Child->Width << ", \"" << Str << "\")"; } diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 874afea3a..52c1cff20 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -226,8 +226,36 @@ inline width_specific_intval m_SpecificInt(size_t W, std::string S) { return width_specific_intval(APInt(W, S, 10), W); } -inline specific_intval m_SpecificInt(std::string S) { - return specific_intval(APInt(64, S, 10)); +struct specific_ext_intval { + llvm::APInt Val; + + specific_ext_intval(std::string S, size_t W) : Val(llvm::APInt(W, S, 10)) {} + + template bool match(ITy *V) { + const auto *CI = dyn_cast(V); + if (!CI && V->getType()->isVectorTy()) + if (const auto *C = dyn_cast(V)) + CI = dyn_cast_or_null(C->getSplatValue(true)); + + if (!CI) + return false; + + auto TargetVal = CI->getValue(); + auto TargetWidth = TargetVal.getBitWidth(); + + if (llvm::APInt::isSameValue(TargetVal, Val.zextOrTrunc(TargetWidth))) { + return true; + + } else if (llvm::APInt::isSameValue(TargetVal, Val.sextOrTrunc(TargetWidth))) { + return true; + } else { + return false; + } + } +}; + +inline specific_ext_intval m_ExtInt(std::string S, size_t W) { + return specific_ext_intval(S, W); } struct constant_matcher { @@ -469,11 +497,19 @@ namespace util { return (V | ~ComputedDB).isAllOnes(); } - // TODO Implement - bool symk0(llvm::Value *V, llvm::Value *&Bind) { + bool symk0bind(llvm::Value *V, llvm::Value *&Bind) { return false; } - bool symk1(llvm::Value *V, llvm::Value *&Bind) { + + bool symk0test(llvm::Value *V, llvm::Value *&Bind) { + return false; + } + + bool symk1bind(llvm::Value *V, llvm::Value *&Bind) { + return false; + } + + bool symk1test(llvm::Value *V, llvm::Value *&Bind) { return false; } From 94f86ac3bb191954ad7fe62df254ba385c83b2c8 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 5 Apr 2023 00:07:56 -0600 Subject: [PATCH 160/165] foo --- tools/matcher-gen.cpp | 21 ++++++++++++--------- tools/pass-generator/src/template.cpp | 22 +++++++++++++--------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index eb06a3903..11688db46 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -191,11 +191,12 @@ struct PC : public Constraint { }; struct DB : public Constraint { - DB(std::string Val_) : Val(Val_) {} + DB(std::string Val_, size_t W_) : Val(Val_), W(W_) {} std::string print() override { - return "util::vdb(DB, I, \"" + Val + "\")"; + return "util::vdb(DB, I, \"" + Val + "\", " + std::to_string(W) + ")"; } std::string Val; + size_t W; }; struct SymDB : public Constraint { @@ -207,19 +208,21 @@ struct SymDB : public Constraint { }; struct K0 : public Constraint { - K0(std::string Name_, std::string Val_) : Name(Name_), Val(Val_) {} + K0(std::string Name_, std::string Val_, size_t W_) : Name(Name_), Val(Val_), W(W_) {} std::string print() override { - return "util::k0(" + Name + ", \"" + Val + "\")"; + return "util::k0(" + Name + ", \"" + Val + "\", " + std::to_string(W) + ")"; } std::string Name, Val; + size_t W; }; struct K1 : public Constraint { - K1(std::string Name_, std::string Val_) : Name(Name_), Val(Val_) {} + K1(std::string Name_, std::string Val_, size_t W_) : Name(Name_), Val(Val_), W(W_) {} std::string print() override { - return "util::k1(" + Name + ", \"" + Val + "\")"; + return "util::k1(" + Name + ", \"" + Val + "\", " + std::to_string(W) + ")"; } std::string Name, Val; + size_t W; }; struct SymK0 : public Constraint { @@ -498,7 +501,7 @@ struct SymbolTable : public std::map { void GenDFConstraints(Inst *LHS) { if (LHS->DemandedBits.getBitWidth() == LHS->Width && !LHS->DemandedBits.isAllOnesValue()) { - Constraints.push_back(new DB(LHS->DemandedBits.toString(2, false))); + Constraints.push_back(new DB(LHS->DemandedBits.toString(2, false), LHS->Width)); } std::vector Vars; @@ -513,11 +516,11 @@ struct SymbolTable : public std::map { auto Name = this->at(V); if (V->KnownOnes.getBitWidth() == V->Width && V->KnownOnes != 0) { - Constraints.push_back(new K1(Name, V->KnownOnes.toString(2, false))); + Constraints.push_back(new K1(Name, V->KnownOnes.toString(2, false), V->Width)); } if (V->KnownZeros.getBitWidth() == V->Width && V->KnownZeros != 0) { - Constraints.push_back(new K0(Name, V->KnownZeros.toString(2, false))); + Constraints.push_back(new K0(Name, V->KnownZeros.toString(2, false), V->Width)); } if (!V->Range.isFullSet()) { diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 52c1cff20..c518f9d16 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -413,12 +413,16 @@ namespace util { return (~Big | Small).isAllOnes(); } - bool k0(llvm::Value *V, std::string Val) { + bool k0(llvm::Value *V, std::string Val, size_t ExpectedWidth) { if (!V || !V->getType() || !V->getType()->isIntegerTy() ) { return false; } auto W = V->getType()->getIntegerBitWidth(); + if (W != ExpectedWidth) { + return false; + } + // if (Val.size() != W) { // return false; // } @@ -444,15 +448,15 @@ namespace util { return false; } - bool k1(llvm::Value *V, std::string Val) { + bool k1(llvm::Value *V, std::string Val, size_t ExpectedWidth) { if (!V || !V->getType() || !V->getType()->isIntegerTy()) { return false; } auto W = V->getType()->getIntegerBitWidth(); - // if (Val.size() != W) { - // return false; - // } + if (ExpectedWidth != W) { + return false; + } llvm::APInt Value(W, Val, 2); if (ConstantInt *Con = llvm::dyn_cast(V)) { @@ -481,11 +485,11 @@ namespace util { return R.contains(CR); } - bool vdb(llvm::DemandedBits *DB, llvm::Instruction *I, std::string DBUnderApprox) { + bool vdb(llvm::DemandedBits *DB, llvm::Instruction *I, std::string DBUnderApprox, size_t ExpectedWidth) { - // if (DBUnderApprox.size() != I->getType()->getIntegerBitWidth()) { - // return false; - // } + if (I->getType()->getIntegerBitWidth() != ExpectedWidth) { + return false; + } llvm::APInt V = llvm::APInt(I->getType()->getIntegerBitWidth(), DBUnderApprox, 2); auto ComputedDB = DB->getDemandedBits(I); From 1cbfa0537b0a4ee7e2e3e8e349de0d0966b00066 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Wed, 5 Apr 2023 02:36:27 -0600 Subject: [PATCH 161/165] foo --- tools/generalize.cpp | 89 ++++++++++++++---------- tools/matcher-gen.cpp | 69 ++++++++++++------- tools/pass-generator/src/template.cpp | 99 +++++++++++++++++++++------ 3 files changed, 176 insertions(+), 81 deletions(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 79dcae893..95a9fdd2a 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -181,13 +181,13 @@ struct InfixPrinter { bool registerSymDFVars(Inst *I) { if (I->K == Inst::KnownOnesP && I->Ops[0]->K == Inst::Var && - I->Ops[1]->Name.starts_with("sym")) { + I->Ops[1]->Name.starts_with("symDF_K")) { Syms[I->Ops[1]] = I->Ops[0]->Name + ".k1"; // VisitedVars.insert(I->Ops[1]->Name); return true; } if (I->K == Inst::KnownZerosP && I->Ops[0]->K == Inst::Var && - I->Ops[1]->Name.starts_with("sym")) { + I->Ops[1]->Name.starts_with("symDF_K")) { Syms[I->Ops[1]] = I->Ops[0]->Name + ".k0"; // VisitedVars.insert(I->Ops[1]->Name); return true; @@ -327,6 +327,8 @@ struct InfixPrinter { case Inst::Slt: Op = "K); break; } @@ -1673,10 +1675,9 @@ InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) return Results; } -std::map CountUses(Inst *I) { +void CountUses(Inst *I, std::map &Count) { std::vector Stack{I}; std::set Visited; - std::map Count; while (!Stack.empty()) { auto *I = Stack.back(); Stack.pop_back(); @@ -1691,7 +1692,6 @@ std::map CountUses(Inst *I) { Stack.push_back(U); } } - return Count; } // // Filter candidates to rule out NOPs as much as possible @@ -1927,7 +1927,7 @@ bool hasMultiArgumentPhi(Inst *I) { ParsedReplacement ReduceBasic(InstContext &IC, Solver *S, ParsedReplacement Input) { - Reducer R(IC, S); + static Reducer R(IC, S); Input = R.ReducePCs(Input); Input = R.ReduceRedundantPhis(Input); Input = R.ReduceGreedy(Input); @@ -1958,10 +1958,18 @@ ParsedReplacement DeAugment(InstContext &IC, return Result; } - auto LHSUses = CountUses(Result.Mapping.LHS); - auto RHSUses = CountUses(Result.Mapping.RHS); + std::map LHSCount, RHSCount; + CountUses(Result.Mapping.LHS, LHSCount); + for (auto M : Result.PCs) { + CountUses(M.LHS, LHSCount); + CountUses(M.RHS, LHSCount); + } + CountUses(Result.Mapping.RHS, RHSCount); + + - if (LHSUses[SymDBVar] == 1 && RHSUses[SymDBVar] == 1) { + + if (LHSCount[SymDBVar] == 1 && RHSCount[SymDBVar] == 1) { // We can remove the SymDBVar Result.Mapping.LHS = Result.Mapping.LHS->Ops[0]; Result.Mapping.RHS = Result.Mapping.RHS->Ops[0]; @@ -2120,10 +2128,10 @@ std::optional SuccessiveSymbolize(InstContext &IC, Refresh("LHS Constraints"); - Clone = DFPreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); - if (Clone) { - return Clone; - } + // Clone = DFPreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); + // if (Clone) { + // return Clone; + // } } Refresh("All LHS Constraints"); @@ -2137,6 +2145,8 @@ std::optional SuccessiveSymbolize(InstContext &IC, std::vector> UnitaryCandidates = InferSpecialConstExprsAllSym(RHSFresh, ConstMap, IC, /*depth*/0); + // llvm::errs() << "Unitary candidates: " << UnitaryCandidates[0].size() << "\n"; + if (!UnitaryCandidates.empty()) { // if (Nested && DebugLevel > 4) { // llvm::errs() << "Rels " << Relations.size() << "\n"; @@ -2361,29 +2371,6 @@ std::optional SuccessiveSymbolize(InstContext &IC, Refresh("Constant limit constraints on LHS"); } - if (SymbolicDF) { - Refresh("PUSH SYMDF_KB_DB"); - auto [CM, Aug] = AugmentForSymKBDB(Input, IC); - // auto [CM2, Aug2] = AugmentForSymKB(Aug1, IC); - if (!CM.empty()) { - bool SymDFChanged = false; - - auto Clone = Verify(Aug, IC, S); - if (Clone) { - // Symbolic db+kb can be unconstrained - // very unlikely? test if needed - return Clone; - } - - auto Generalized = SuccessiveSymbolize(IC, S, Aug, SymDFChanged, CM); - if (SymDFChanged) { - return Generalized; - } - } - Refresh("POP SYMDF_KB_DB"); - - } - Refresh("END"); Changed = false; return Input; @@ -2608,6 +2595,34 @@ int main(int argc, char **argv) { if (Opt) { Result = *Opt; } + + if (SymbolicDF) { + // Refresh("PUSH SYMDF_KB_DB"); + auto [CM, Aug] = AugmentForSymKBDB(Input, IC); + // auto [CM2, Aug2] = AugmentForSymKB(Aug1, IC); + if (!CM.empty()) { + bool SymDFChanged = false; + + // auto Clone = Verify(Aug, IC, S); + // if (Clone) { + // // Symbolic db+kb can be unconstrained + // // Is this actually possible in practice? + // return Clone; + // } + + // Aug.print(llvm::errs(), true); + + // llvm::errs() << "\n\n"; + + auto Generalized = SuccessiveSymbolize(IC, S.get(), Aug, SymDFChanged, CM); + if (Generalized) { + Result = DeAugment(IC, S.get(), Generalized.value()); + Changed = true; + } + } + // Refresh("POP SYMDF_KB_DB"); + } + } bool Indep = false; if (!NoWidth) { @@ -2628,7 +2643,7 @@ int main(int argc, char **argv) { Result = Input; continue; // Retry with no width checks } - Result = DeAugment(IC, S.get(), Result); + // Result = DeAugment(IC, S.get(), Result); if ((Changed || FirstTime) && Result.Mapping.LHS && Result.Mapping.RHS) { PrintInputAndResult(Input, Result); diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index 11688db46..c9ed5be82 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -202,7 +202,7 @@ struct DB : public Constraint { struct SymDB : public Constraint { SymDB(std::string Name_) : Name(Name_) {} std::string print() override { - return "util::symdb(DB, I, " + Name + ")"; + return "util::symdb(DB, I, " + Name + ", B)"; } std::string Name; }; @@ -225,22 +225,39 @@ struct K1 : public Constraint { size_t W; }; -struct SymK0 : public Constraint { - SymK0(std::string Name_, std::string Bind_) : Name(Name_), Bind(Bind_) {} +struct SymK0Bind : public Constraint { + SymK0Bind(std::string Name_, std::string Bind_) : Name(Name_), Bind(Bind_) {} std::string print() override { - return "util::symk0(" + Name + ", " + Bind + ")"; + return "util::symk0bind(" + Name + ", " + Bind + ", B)"; } std::string Name, Bind; }; -struct SymK1 : public Constraint { - SymK1(std::string Name_, std::string Bind_) : Name(Name_), Bind(Bind_) {} +struct SymK1Bind : public Constraint { + SymK1Bind(std::string Name_, std::string Bind_) : Name(Name_), Bind(Bind_) {} std::string print() override { - return "util::symk1(" + Name + ", " + Bind + ")"; + return "util::symk1bind(" + Name + ", " + Bind + ", B)"; } std::string Name, Bind; }; +struct SymK0Test : public Constraint { + SymK0Test(std::string Name_, std::string Name2_) : Name(Name_), Name2(Name2_) {} + std::string print() override { + return "util::symk0test(" + Name + ", " + Name2 + ")"; + } + std::string Name, Name2; +}; + +struct SymK1Test : public Constraint { + SymK1Test(std::string Name_, std::string Name2_) : Name(Name_), Name2(Name2_) {} + std::string print() override { + return "util::symk1test(" + Name + ", " + Name2 + ")"; + } + std::string Name, Name2; +}; + + struct CR : public Constraint { CR(std::string Name_, std::string L_, std::string H_) : Name(Name_), L(L_), H(H_) {} std::string print() override { @@ -250,7 +267,7 @@ struct CR : public Constraint { }; struct SymbolTable : public std::map { - std::vector Constraints; + std::deque Constraints; std::map Preds; std::vector Vars; @@ -294,15 +311,6 @@ struct SymbolTable : public std::map { } Out << ";\n"; } - void GenVarEqConstraints() { - // for (auto &&S : *this) { - // if (S.second.size() > 1) { - // for (size_t i = 1; i < S.second.size(); ++i) { - // Constraints.push_back(new VarEq(S.second[0], S.second[i])); - // } - // } - // } - } // Try to translate Souper expressions to APInt operations. std::pair Translate(souper::Inst *I) { @@ -459,13 +467,27 @@ struct SymbolTable : public std::map { bool GenPCConstraints(std::vector PCs) { for (auto M : PCs) { if (M.LHS->K == Inst::KnownZerosP) { - Constraint *C = new SymK0(this->at(M.LHS->Ops[0]), - this->at(M.LHS->Ops[1])); - Constraints.push_back(C); + if (M.LHS->Ops[0]->K == Inst::Var && M.LHS->Ops[1]->Name.starts_with("symDF_K")) { + auto C = new SymK0Bind(this->at(M.LHS->Ops[0]), + this->at(M.LHS->Ops[1])); + Constraints.push_front(C); + // Binds have side effects, have to go in front. + } else { + auto C = new SymK0Test(this->at(M.LHS->Ops[0]), + this->at(M.LHS->Ops[1])); + Constraints.push_back(C); + } } else if (M.LHS->K == Inst::KnownOnesP) { - Constraint *C = new SymK1(this->at(M.LHS->Ops[0]), - this->at(M.LHS->Ops[1])); - Constraints.push_back(C); + if (M.LHS->Ops[0]->K == Inst::Var && M.LHS->Ops[1]->Name.starts_with("symDF_K")) { + auto C = new SymK1Bind(this->at(M.LHS->Ops[0]), + this->at(M.LHS->Ops[1])); + Constraints.push_front(C); + // Binds have side effects, have to go in front. + } else { + auto C = new SymK1Test(this->at(M.LHS->Ops[0]), + this->at(M.LHS->Ops[1])); + Constraints.push_back(C); + } } else if (auto WC = ConvertPCToWidthConstraint(M)) { Constraints.push_back(WC); } else { @@ -913,7 +935,6 @@ bool GenMatcher(ParsedReplacement Input, Stream &Out, size_t OptID, bool WidthIn DemandedMask = Input.Mapping.LHS->Ops[1]; Syms.Constraints.push_back(new SymDB(Syms[Input.Mapping.LHS->Ops[1]])); } - Syms.GenVarEqConstraints(); Syms.GenVarPropConstraints(Input.Mapping.LHS, WidthIndependent); Syms.GenDomConstraints(Input.Mapping.RHS); Syms.GenDFConstraints(Input.Mapping.LHS); diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index c518f9d16..0d2c9421a 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -347,9 +347,6 @@ inline CastClass_match_width m_Trunc(size_t W, const O namespace util { bool dc(llvm::DominatorTree *DT, llvm::Instruction *I, llvm::Value *V) { - if (!V) { - return false; - } if (auto Def = dyn_cast(V)) { if (I->getParent() == Def->getParent()) { return true; @@ -423,10 +420,6 @@ namespace util { return false; } - // if (Val.size() != W) { - // return false; - // } - llvm::APInt Value(W, Val, 2); if (ConstantInt *Con = llvm::dyn_cast(V)) { auto X = Con->getUniqueInteger(); @@ -437,8 +430,8 @@ namespace util { DataLayout DL(I->getParent()->getParent()->getParent()); computeKnownBits(V, Analyzed, DL, 4); - llvm::SmallVector Result; - Analyzed.Zero.toString(Result, 2, false); + // llvm::SmallVector Result; + // Analyzed.Zero.toString(Result, 2, false); auto b = KnownBitImplies(Value, Analyzed.Zero); // llvm::errs() << "HERE: " << Result << ' ' << Val @@ -501,28 +494,94 @@ namespace util { return (V | ~ComputedDB).isAllOnes(); } - bool symk0bind(llvm::Value *V, llvm::Value *&Bind) { - return false; - } + bool symk0bind(llvm::Value *V, llvm::Value *&Bind, IRBuilder *B) { + if (!V || !V->getType() || !V->getType()->isIntegerTy() ) { + return false; + } + + auto W = V->getType()->getIntegerBitWidth(); + + auto Analyzed = llvm::KnownBits(W); + if (Instruction *I = llvm::dyn_cast(V)) { + DataLayout DL(I->getParent()->getParent()->getParent()); + computeKnownBits(V, Analyzed, DL, 4); + if (Analyzed.Zero == 0) { + return false; + } + Bind = B->getInt(Analyzed.Zero); + return true; + } - bool symk0test(llvm::Value *V, llvm::Value *&Bind) { return false; } - bool symk1bind(llvm::Value *V, llvm::Value *&Bind) { + bool symk1bind(llvm::Value *V, llvm::Value *&Bind, IRBuilder *B) { + if (!V || !V->getType() || !V->getType()->isIntegerTy() ) { + return false; + } + + auto W = V->getType()->getIntegerBitWidth(); + + auto Analyzed = llvm::KnownBits(W); + if (Instruction *I = llvm::dyn_cast(V)) { + DataLayout DL(I->getParent()->getParent()->getParent()); + computeKnownBits(V, Analyzed, DL, 4); + if (Analyzed.One == 0) { + return false; + } + Bind = B->getInt(Analyzed.One); + return true; + } + return false; } - bool symk1test(llvm::Value *V, llvm::Value *&Bind) { - return false; + bool symk0test(llvm::Value *Bound, llvm::Value *OtherSymConst) { + llvm::Constant *BoundC = llvm::dyn_cast(Bound); + llvm::Constant *OtherC = llvm::dyn_cast(OtherSymConst); + + if (!BoundC || !OtherC) { + return false; + } + + // Width sanity check + if (BoundC->getType()->getIntegerBitWidth() != OtherC->getType()->getIntegerBitWidth()) { + return false; + } + + return KnownBitImplies(OtherC->getUniqueInteger(), ~BoundC->getUniqueInteger()); } - bool symdb(llvm::DemandedBits *DB, llvm::Instruction *I, llvm::Value *&V) { - auto ComputedDB = DB->getDemandedBits(I); + bool symk1test(llvm::Value *Bound, llvm::Value *OtherSymConst) { + llvm::Constant *BoundC = llvm::dyn_cast(Bound); + llvm::Constant *OtherC = llvm::dyn_cast(OtherSymConst); - // Todo make a new llvm constant from ComputedDb and assign to V + if (!BoundC || !OtherC) { + return false; + } - return false; + // Width sanity check + if (BoundC->getType()->getIntegerBitWidth() != OtherC->getType()->getIntegerBitWidth()) { + return false; + } + + // llvm::errs() << "SymK1Test: " << llvm::toString(OtherC->getUniqueInteger(), 2, false) << ' ' + // << llvm::toString(BoundC->getUniqueInteger(), 2, false) << "\n"; + + // llvm::errs() << "Result: " << KnownBitImplies(OtherC->getUniqueInteger(), BoundC->getUniqueInteger()) << "\n"; + + return KnownBitImplies(OtherC->getUniqueInteger(), BoundC->getUniqueInteger()); + } + + bool symdb(llvm::DemandedBits *DB, llvm::Instruction *I, llvm::Value *&V, IRBuilder *B) { + auto ComputedDB = DB->getDemandedBits(I); + // Are there other non trivial failure modes? + if (ComputedDB == 0) { + return false; + } + V = B->getInt(ComputedDB); + llvm::errs() << "SymDB: " << llvm::toString(ComputedDB, 2, false) << "\n"; + return true; } bool nz(llvm::Value *V) { From 4d9d1c6a9f3c8bf0e86922b05c4e4bf14997862c Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 9 Apr 2023 01:53:14 -0600 Subject: [PATCH 162/165] foo --- CMakeLists.txt | 8 +- lib/Generalize/Reducer.cpp | 4 +- tools/generalize.cpp | 120 +++++++++++++++++++++++--- tools/matcher-gen.cpp | 87 +++++++------------ tools/pass-generator/src/template.cpp | 10 +-- 5 files changed, 147 insertions(+), 82 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 55d946ef1..14f24bb58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -411,7 +411,7 @@ configure_file( ) foreach(target souper internal-solver-test lexer-test parser-test souper-check count-insts - souper2llvm souper-interpret generalize matcher-gen + souper2llvm souper-interpret generalize matcher-gen souperExtractor souperInfer souperGeneralize souperInst souperKVStore souperParser souperSMTLIB2 souperTool souperPass souperPassProfileAll kleeExpr souperCodegen) @@ -511,8 +511,10 @@ configure_file(${CMAKE_SOURCE_DIR}/utils/py_souper2llvm.in ${CMAKE_BINARY_DIR}/p configure_file(${CMAKE_SOURCE_DIR}/include/souper/Tool/GetSolver.h.in ${CMAKE_BINARY_DIR}/include/souper/Tool/GetSolver.h @ONLY) if (BUILD_CLANG_TOOL) - configure_file(${CMAKE_SOURCE_DIR}/utils/sclang.in ${CMAKE_BINARY_DIR}/sclang @ONLY) - configure_file(${CMAKE_SOURCE_DIR}/utils/sclang.in ${CMAKE_BINARY_DIR}/sclang++ @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/utils/sclang.in ${CMAKE_BINARY_DIR}/sclang @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/utils/sclang.in ${CMAKE_BINARY_DIR}/sclang++ @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/utils/mclang.in ${CMAKE_BINARY_DIR}/mclang @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/utils/mclang.in ${CMAKE_BINARY_DIR}/mclang++ @ONLY) endif() add_subdirectory(docs) diff --git a/lib/Generalize/Reducer.cpp b/lib/Generalize/Reducer.cpp index 1f442f529..a1ddfc8a8 100644 --- a/lib/Generalize/Reducer.cpp +++ b/lib/Generalize/Reducer.cpp @@ -77,6 +77,8 @@ ParsedReplacement Reducer::ReducePairsGreedy(ParsedReplacement Input) { continue; } + // Input.print(llvm::errs(), true); + if (!VerifyInput(Input)) { Input = Copy; continue; @@ -833,7 +835,7 @@ bool Reducer::VerifyInput(ParsedReplacement &Input) { } bool Reducer::safeToRemove(Inst *I, ParsedReplacement &Input) { - if (I == Input.Mapping.LHS || I == Input.Mapping.RHS || I->K == Inst::Var || I->K == Inst::Const || + if (I == Input.Mapping.LHS || I->K == Inst::Var || I->K == Inst::Const || I->K == Inst::UMulWithOverflow || I->K == Inst::UMulO || I->K == Inst::SMulWithOverflow || I->K == Inst::SMulO || I->K == Inst::UAddWithOverflow || I->K == Inst::UAddO || diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 95a9fdd2a..9961aeda7 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1039,15 +1039,19 @@ std::vector InferPotentialRelations( } } - // // TODO Check if this is too slow - // // if (Input.Mapping.LHS->Width == 1) { - // // need both signed and unsigned? - // // What about s/t/e/ versions? - // if (XC.slt(YC)) Results.push_back(Builder(XI, IC).Slt(YI)()); - // if (XC.ult(YC)) Results.push_back(Builder(XI, IC).Ult(YI)()); - // if (YC.slt(XC)) Results.push_back(Builder(YI, IC).Slt(XI)()); - // if (YC.ult(XC)) Results.push_back(Builder(YI, IC).Ult(XI)()); - // // } + auto One = llvm::APInt(XC.getBitWidth(), 1); + + auto GENComps = [&] (Inst *A, llvm::APInt AVal, Inst *B, llvm::APInt BVal) { + if (AVal.sle(BVal)) Results.push_back(Builder(A, IC).Sle(B)()); + if (AVal.ule(BVal)) Results.push_back(Builder(A, IC).Ule(B)()); + if (AVal.slt(BVal)) Results.push_back(Builder(A, IC).Slt(B)()); + if (AVal.ult(BVal)) Results.push_back(Builder(A, IC).Ult(B)()); + }; + + GENComps(XI, XC, YI, YC); + // GENComps(Builder(IC, One).Shl(XI)() , One.shl(XC), YI, YC); + // GENComps(XI, XC, Builder(IC, One).Shl(YI)() , One.shl(YC)); + // auto XBits = BitFuncs(XI, IC); // auto YBits = BitFuncs(YI, IC); @@ -1306,6 +1310,12 @@ std::optional VerifyWithRels(InstContext &IC, Solver *S, for (auto Rel : Rels) { Input.PCs.push_back({Rel, IC.getConst(llvm::APInt(1, 1))}); auto Clone = Verify(Input, IC, S); + + // InfixPrinter IP(Input); + // IP(llvm::errs()); + + // llvm::errs() << "RESULT: " << Clone.has_value() << "\n"; + if (Clone) { ValidRels.push_back(Rel); FirstValidResult = Clone.value(); @@ -2111,8 +2121,10 @@ std::optional SuccessiveSymbolize(InstContext &IC, // Copy.PCs.pop_back(); // } + // llvm::errs() << "Relations : " << Relations.size() << "\n"; + if (auto RelV = VerifyWithRels(IC, S, Copy, Relations)) { - return RelV.value(); + return RelV; } Refresh("Direct + simple rel constraints"); @@ -2128,10 +2140,10 @@ std::optional SuccessiveSymbolize(InstContext &IC, Refresh("LHS Constraints"); - // Clone = DFPreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); - // if (Clone) { - // return Clone; - // } + Clone = DFPreconditionsAndVerifyGreedy(Copy, IC, S, SymCS); + if (Clone) { + return Clone; + } } Refresh("All LHS Constraints"); @@ -2401,6 +2413,13 @@ InstMapping GetLessThanWidthConstraint(Inst *I, size_t Width, InstContext &IC) { // Don't need to check for >0. return {Builder(I, IC).BitWidth().Ule(Width)(), IC.getConst(llvm::APInt(1, 1))}; } + +InstMapping GetWidthRangeConstraint(Inst *I, size_t Min, size_t Max, InstContext &IC) { + auto Right = Builder(I, IC).BitWidth().Ule(Max); + auto Left = Builder(IC, llvm::APInt(I->Width, Min)).BitWidth().Ule(Builder(I, IC).BitWidth()); + return {Left.And(Right)(), IC.getConst(llvm::APInt(1, 1))}; +} + // TODO: More as needed. Inst *CombinePCs(const std::vector &PCs, InstContext &IC) { @@ -2412,9 +2431,57 @@ Inst *CombinePCs(const std::vector &PCs, InstContext &IC) { return Ante; } +bool IsStaticallyWidthIndependent(ParsedReplacement Input) { + + if (Input.Mapping.LHS->Width == 1) { + return false; + } + + std::vector Consts; + auto Pred = [](Inst *I) {return I->K == Inst::Const;}; + findInsts(Input.Mapping.LHS, Consts, Pred); + findInsts(Input.Mapping.RHS, Consts, Pred); + for (auto M : Input.PCs) { + findInsts(M.LHS, Consts, Pred); + findInsts(M.RHS, Consts, Pred); + } + + std::vector WidthChanges; + auto WPred = [](Inst *I) {return I->K == Inst::Trunc || I->K == Inst::SExt + || I->K == Inst::ZExt;}; + + findInsts(Input.Mapping.LHS, WidthChanges, WPred); + findInsts(Input.Mapping.RHS, WidthChanges, WPred); + for (auto M : Input.PCs) { + findInsts(M.LHS, WidthChanges, WPred); + findInsts(M.RHS, WidthChanges, WPred); + } + + if (!WidthChanges.empty()) { + return false; + } + + // False if non zero or non -1 const + for (auto &&C : Consts) { + if (C->K == Inst::Const && (C->Val != 0 || !C->Val.isAllOnesValue())) { + return false; + } + } + + // TODO Set up constant synthesis problem to see if subexpressions + // simplify to non zero consts + + return true; +} + std::pair InstantiateWidthChecks(InstContext &IC, Solver *S, ParsedReplacement Input) { + + if (IsStaticallyWidthIndependent(Input)) { + return {Input, true}; + } + if (!NoWidth && !hasMultiArgumentPhi(Input.Mapping.LHS)) { // Instantiate Alive driver with Symbolic width. AliveDriver Alive(Input.Mapping.LHS, @@ -2444,6 +2511,27 @@ InstantiateWidthChecks(InstContext &IC, // Abstract width to a range or relational precondition // TODO: Abstraction + + std::vector Inputs; + findVars(Input.Mapping.LHS, Inputs); + if (Inputs.size() == 1 && ValidTypings.size() > 1) { + auto I = Inputs[0]; + auto Width = I->Width; + + std::vector Widths; + for (auto &&V : ValidTypings) { + Widths.push_back(V[I]); + } + + size_t MaxWidth = *std::max_element(Widths.begin(), Widths.end()); + size_t MinWidth = *std::min_element(Widths.begin(), Widths.end()); + + if (ValidTypings.size() == (MaxWidth - MinWidth + 1)) { + Input.PCs.push_back(GetWidthRangeConstraint(I, MinWidth, MaxWidth, IC)); + return {Input, false}; + } + } + } // If abstraction fails, insert checks for existing widths. @@ -2650,6 +2738,10 @@ int main(int argc, char **argv) { } if (FirstTime) FirstTime = false; } while (--MaxTries && Changed); + } else { + if (Result.Mapping.LHS && Result.Mapping.RHS) { + PrintInputAndResult(Input, Result); + } } } } diff --git a/tools/matcher-gen.cpp b/tools/matcher-gen.cpp index c9ed5be82..e13f9d0e6 100644 --- a/tools/matcher-gen.cpp +++ b/tools/matcher-gen.cpp @@ -997,20 +997,43 @@ std::string getLLVMInstKindName(Inst::Kind K) { } bool PCHasVar(const ParsedReplacement &Input) { - std::vector Vars; + std::vector Stack; for (auto &&PC : Input.PCs) { - if (PC.LHS->K == Inst::KnownOnesP || PC.LHS->K == Inst::KnownZerosP) - continue; + // if (PC.LHS->K == Inst::KnownOnesP || PC.LHS->K == Inst::KnownZerosP) + // continue; + + // if (PC.LHS->K == Inst::Eq && (PC.LHS->Ops[0]->K == Inst::BitWidth || + // PC.LHS->Ops[1]->K == Inst::BitWidth )) { + // continue; + // } + Stack.push_back(PC.LHS); + Stack.push_back(PC.RHS); + } + + std::set Visited; + std::vector Vars; - if (PC.LHS->K == Inst::Eq && (PC.LHS->Ops[0]->K == Inst::BitWidth || - PC.LHS->Ops[1]->K == Inst::BitWidth )) { + while (!Stack.empty()) { + Inst *I = Stack.back(); + Stack.pop_back(); + + if (Visited.count(I)) { continue; } + Visited.insert(I); + + if (I->K == Inst::Var) { + Vars.push_back(I); + } - findVars(PC.LHS, Vars); - findVars(PC.RHS, Vars); + for (auto &&Op : I->Ops) { + if (I->K == Inst::KnownOnesP || I->K == Inst::KnownZerosP || I->K == Inst::BitWidth) + continue; + Stack.push_back(Op); + } } + for (auto &&V : Vars) { // llvm::errs() << V->Name << "\n"; if (!V->Name.starts_with("sym")) { @@ -1021,56 +1044,6 @@ bool PCHasVar(const ParsedReplacement &Input) { return false; } -bool IsWidthIndependent(InstContext &IC, - Solver *S, ParsedReplacement Input) { - - // FIXME Re-enable this later - return false; - - if (Input.Mapping.LHS->Width == 1) { - return false; - } - - - - std::vector Consts; - auto Pred = [](Inst *I) {return I->K == Inst::Const;}; - findInsts(Input.Mapping.LHS, Consts, Pred); - findInsts(Input.Mapping.RHS, Consts, Pred); - for (auto M : Input.PCs) { - findInsts(M.LHS, Consts, Pred); - findInsts(M.RHS, Consts, Pred); - } - - std::vector WidthChanges; - auto WPred = [](Inst *I) {return I->K == Inst::Trunc || I->K == Inst::SExt - || I->K == Inst::ZExt;}; - - findInsts(Input.Mapping.LHS, WidthChanges, WPred); - findInsts(Input.Mapping.RHS, WidthChanges, WPred); - for (auto M : Input.PCs) { - findInsts(M.LHS, WidthChanges, WPred); - findInsts(M.RHS, WidthChanges, WPred); - } - - if (!WidthChanges.empty()) { - return false; - // TODO This is too conservative. - // Figure out where this is allowed in a width independent manner. - } - - // False if non zero const - for (auto &&C : Consts) { - if (C->K == Inst::Const && C->Val != 0) { - return false; - } - } - - // TODO Set up constant sytnthesis problem to see if subexpressions - // simplify to non zero consts - - return true; -} int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); diff --git a/tools/pass-generator/src/template.cpp b/tools/pass-generator/src/template.cpp index 0d2c9421a..8ad66ac56 100644 --- a/tools/pass-generator/src/template.cpp +++ b/tools/pass-generator/src/template.cpp @@ -243,14 +243,9 @@ struct specific_ext_intval { auto TargetVal = CI->getValue(); auto TargetWidth = TargetVal.getBitWidth(); - if (llvm::APInt::isSameValue(TargetVal, Val.zextOrTrunc(TargetWidth))) { - return true; + return llvm::APInt::isSameValue(TargetVal, Val.zextOrTrunc(TargetWidth)) || + llvm::APInt::isSameValue(TargetVal, Val.sextOrTrunc(TargetWidth)); - } else if (llvm::APInt::isSameValue(TargetVal, Val.sextOrTrunc(TargetWidth))) { - return true; - } else { - return false; - } } }; @@ -709,6 +704,7 @@ struct SouperCombine : public FunctionPass { bool runOnFunction(Function &F) override { + llvm::errs() << "SouperCombine: " << F.getName() << "\n"; AssumptionCache AC(F); DT = new DominatorTree(F); From 84fe39a2c70dd36cc2b56d92ee4ded9b3df78c16 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Sun, 9 Apr 2023 02:17:02 -0600 Subject: [PATCH 163/165] foo --- utils/mclang.in | 297 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100755 utils/mclang.in diff --git a/utils/mclang.in b/utils/mclang.in new file mode 100755 index 000000000..1a410ea3f --- /dev/null +++ b/utils/mclang.in @@ -0,0 +1,297 @@ +#!/usr/bin/env perl + +# 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. + +use warnings; +use strict; +use File::Temp; + +sub compiling() { + foreach my $arg (@ARGV) { + return 1 + if ($arg =~ /\.c$|\.cpp$|\.CC$|\.c\+\+$|\.cc$|\.cxx$|\.C$|\.c\+$/); + } + return 0; +} + +sub linkp() { + foreach my $arg (@ARGV) { + return 0 if ($arg eq "-S" || $arg eq "-c" || $arg eq "-shared"); + } + return 1; +} + +if ($0 =~ /clang$/) { + unshift @ARGV, "@LLVM_BINDIR@/clang"; +} elsif ($0 =~ /clang\+\+$/) { + unshift @ARGV, "@LLVM_BINDIR@/clang++"; +} else { + die "Didn't expect sclang to be invoked as '$0'"; +} + +foreach my $arg (@ARGV) { + if ($arg eq "-help" || $arg eq "--help") { + print <new(UNLINK => 1, DIR => $bitcodedir)->filename; + push @ARGV, "-c", "-emit-llvm"; + push @ARGV, "-o", "${tmp}.bc"; + my $ofn = "${tmp}.cmd"; + open OUTF, ">$ofn" or die; + foreach my $a (@ARGV) { + print OUTF "$a "; + } + print OUTF "\n"; + close OUTF; + open STDOUT, '>/dev/null'; + open STDERR, '>/dev/null'; + exec @ARGV; + die "bailing, exec failed"; +} + +my $souper = 1; +# this environment variable is a comma-separated list of source files that +# souper should avoid processing, for example because they trigger known bugs +my $skip_files = getenv("SOUPER_SKIP_FILES"); +if (defined $skip_files) { + my %skips; + foreach my $f (split(',', $skip_files)) { + $skips{$f} = 1; + } + foreach my $a (@ARGV) { + $souper = 0 if ($skips{$a}); + } +} + +$souper = 0 if getenv("SOUPER_NO_SOUPER"); +$souper = 0 unless compiling(); + +if ($souper) { + push @ARGV, ( + "-Xclang", "-load", + "-mllvm", "-solver-timeout=15", + ); +} + +if ($souper) { + push @ARGV, ("-Xclang", getenv("SOUPER_MATCHER_LIB")); + # push @ARGV, ("-Xclang --souper-combine")); +} + +# if (getenv("SOUPER_DYNAMIC_PROFILE_ALL")) { +# if ($souper) { +# push @ARGV, ("-Xclang", "@SOUPER_PASS_PROFILE_ALL@"); +# } +# } else { +# if ($souper) { +# push @ARGV, ("-Xclang", "@SOUPER_PASS@"); +# } +# } + +# if (getenv("SOUPER_DEBUG") && $souper) { +# push @ARGV, ("-mllvm", "-souper-debug-level=".getenv("SOUPER_DEBUG")); +# } + +# if (getenv("SOUPER_EXPLOIT_BLOCKPCS") && $souper) { +# push @ARGV, ("-mllvm", "-souper-exploit-blockpcs"); +# } + +# if (!getenv("SOUPER_NO_EXTERNAL_CACHE") && $souper) { +# push @ARGV, ("-mllvm", "-souper-external-cache"); +# } + +# if (getenv("SOUPER_NO_INFER") && $souper) { +# push @ARGV, ("-mllvm", "-souper-no-infer"); +# } + +# if (getenv("SOUPER_FIRST_OPT") && $souper) { +# push @ARGV, ("-mllvm", "-souper-first-opt=".$ENV{"SOUPER_FIRST_OPT"}); +# } + +# if (getenv("SOUPER_LAST_OPT") && $souper) { +# push @ARGV, ("-mllvm", "-souper-last-opt=".$ENV{"SOUPER_LAST_OPT"}); +# } + +# if (getenv("SOUPER_STATIC_PROFILE") && $souper) { +# push @ARGV, ("-mllvm", "-souper-static-profile"); +# } + +# if (getenv("SOUPER_DYNAMIC_PROFILE") || +# getenv("SOUPER_DYNAMIC_PROFILE_ALL") && $souper) { +# push @ARGV, ("-g", "-mllvm", "-souper-dynamic-profile"); +# } + +# if (getenv("SOUPER_USE_ALIVE") && $souper) { +# push @ARGV, ("-mllvm", "-souper-use-alive"); +# } + +# if (getenv("SOUPER_DOUBLE_CHECK") && $souper) { +# push @ARGV, ("-mllvm", "-souper-double-check"); +# } + +# if (getenv("SOUPER_INFER_INST") && $souper) { +# push @ARGV, ("-mllvm", "-souper-infer-inst"); +# } + +# if (getenv("SOUPER_ENUMERATIVE_SYNTHESIS_MAX_INSTS") && $souper) { +# push @ARGV, ("-mllvm", "-souper-enumerative-synthesis-max-instructions=".$ENV{"SOUPER_ENUMERATIVE_SYNTHESIS_MAX_INSTS"}); +# } + +# if (getenv("SOUPER_DATAFLOW_PRUNING") && $souper) { +# push @ARGV, ("-mllvm", "-souper-dataflow-pruning"); +# } + +# if (getenv("SOUPER_REDIS_PORT") && $souper) { +# push @ARGV, ("-mllvm", "-souper-redis-port=".$ENV{"SOUPER_REDIS_PORT"}); +# } + +# if (getenv("SOUPER_STATS") && $souper) { +# push @ARGV, ("-mllvm", "-stats"); +# } + +# if (getenv("SOUPER_TIME_REPORT") && $souper) { +# push @ARGV, ("-ftime-report"); +# } + +# if (getenv("SOUPER_VERIFY") && $souper) { +# push @ARGV, ("-mllvm", "-souper-verify"); +# } + +# if (getenv("SOUPER_NO_HARVEST_DATAFLOW_FACTS") && $souper) { +# push @ARGV, ("-mllvm", "-souper-harvest-dataflow-facts=false"); +# } + +# if (getenv("SOUPER_HARVEST_USES") && $souper) { +# push @ARGV, ("-mllvm", "-souper-harvest-uses"); +# } + +if (getenv("SOUPER_DISABLE_LLVM_PEEPHOLES") && $souper) { + push @ARGV, ("-mllvm", "-disable-peepholes"); +} + +# if ((getenv("SOUPER_DYNAMIC_PROFILE") || +# getenv("SOUPER_DYNAMIC_PROFILE_ALL")) && linkp() && $souper) { +# push @ARGV, ("@PROFILE_LIBRARY@", "@HIREDIS_LIBRARY@"); +# } + +if (getenv("SOUPER_DEBUG") && $souper) { + foreach my $arg (@ARGV) { + print STDERR "$arg "; + } + print STDERR "\n"; +} + +foreach my $e (keys %ENV) { + next unless $e =~ /^SOUPER_/; + die "unexpected Souper-related environment variable '${e}'" unless $whitelist{$e}; +} + +exec @ARGV; From f1c31c937b86283930f350edc65a1f22da1cf909 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Mon, 10 Apr 2023 21:47:43 -0600 Subject: [PATCH 164/165] foo --- test/Generalize/nonneg.opt | 13 +++++++++++++ test/Generalize/shiftmask.opt | 16 ++++++++++++++++ test/Generalize/shrink.opt | 13 +++++++++++++ test/Generalize/smax.opt | 15 +++++++++++++++ test/Generalize/widthchange.opt | 14 ++++++++++++++ 5 files changed, 71 insertions(+) create mode 100644 test/Generalize/nonneg.opt create mode 100644 test/Generalize/shiftmask.opt create mode 100644 test/Generalize/shrink.opt create mode 100644 test/Generalize/smax.opt create mode 100644 test/Generalize/widthchange.opt diff --git a/test/Generalize/nonneg.opt b/test/Generalize/nonneg.opt new file mode 100644 index 000000000..05a433bcf --- /dev/null +++ b/test/Generalize/nonneg.opt @@ -0,0 +1,13 @@ +; RUN: %generalize -basic -no-width -souper-debug-level=2 %s > /dev/null 2>%t +; RUN: %FileCheck %s < %t + +%0:i4 = var +%1 = lshr %0, 1 +%2 = udiv %1, 2 +infer %2 +%3 = udiv %0, 4 +result %3 + +; CHECK: (v0:i4 >>l 1) /u C2:i4 (nonNegative) +; CHECK: => +; CHECK: v0 /u (C2 + C2) \ No newline at end of file diff --git a/test/Generalize/shiftmask.opt b/test/Generalize/shiftmask.opt new file mode 100644 index 000000000..ef463bcac --- /dev/null +++ b/test/Generalize/shiftmask.opt @@ -0,0 +1,16 @@ +; RUN: %generalize -basic -souper-debug-level=2 %s > /dev/null 2>%t +; RUN: %FileCheck %s < %t + +%x:i8 = var +%y = shl %x, 2 +%z = lshr %y, 4 +%t = shl %z, 2 +infer %t +%foo = and 60, %x +result %foo + +; CHECK: C2 == (C1 * 2) +; CHECK: |= +; CHECK: ((x << C1) >>l C2) << C1 +; CHECK: => +; CHECK: x & ((0xFF << C2) >>l C1) \ No newline at end of file diff --git a/test/Generalize/shrink.opt b/test/Generalize/shrink.opt new file mode 100644 index 000000000..fe11d6870 --- /dev/null +++ b/test/Generalize/shrink.opt @@ -0,0 +1,13 @@ +; RUN: %generalize -basic -souper-debug-level=2 %s > /dev/null 2>%t +; RUN: %FileCheck %s < %t + +%0:i64 = var +%1 = lshr %0, 1 +%2 = udiv %1, 100 +infer %2 +%3 = udiv %0, 200 +result %3 + +; CHECK: (v0 >>l 1) /u C2 (nonNegative) +; CHECK: => +; CHECK: v0 /u (C2 + C2) \ No newline at end of file diff --git a/test/Generalize/smax.opt b/test/Generalize/smax.opt new file mode 100644 index 000000000..cebe6e5ac --- /dev/null +++ b/test/Generalize/smax.opt @@ -0,0 +1,15 @@ +; RUN: %generalize -basic -souper-debug-level=2 %s > /dev/null 2>%t +; RUN: %FileCheck %s < %t + +%v0:i8 = var ; v0 +%1:i32 = sext %v0 +%2:i1 = eq 42:i32, %1 +infer %2 +%3:i1 = eq 42:i8, %v0 +result %3 + +; CHECK: C1 <=u ((1 << (zext(width(v0)) - 1)) - 1) +; CHECK: |= +; CHECK: C1 == sext(v0) +; CHECK: => +; CHECK: v0 == trunc(C1) \ No newline at end of file diff --git a/test/Generalize/widthchange.opt b/test/Generalize/widthchange.opt new file mode 100644 index 000000000..f99e4ca09 --- /dev/null +++ b/test/Generalize/widthchange.opt @@ -0,0 +1,14 @@ +; RUN: %generalize -basic -souper-debug-level=2 %s > /dev/null 2>%t +; RUN: %FileCheck %s < %t + +%v0:i16 = var +%x:i32 = sext %v0 +%y:i32 = sub %x, 20:i32; hex 0x14 +%yt:i16 = trunc %y +infer %yt +%z = add %v0, -20:i16; hex 0xFFEC +result %z + +; CHECK: trunc((sext(v0) - C1)) +; CHECK: => +; CHECK: v0 + trunc((0 - C1)) From 43daca7629035bf77c954213809c5bda0631a0e7 Mon Sep 17 00:00:00 2001 From: Manasij Mukherjee Date: Tue, 11 Apr 2023 03:32:50 -0600 Subject: [PATCH 165/165] Fix width jump --- tools/generalize.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/generalize.cpp b/tools/generalize.cpp index 9961aeda7..a52b66e24 100644 --- a/tools/generalize.cpp +++ b/tools/generalize.cpp @@ -1488,6 +1488,9 @@ InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) // Handle width changes for (const auto &[I, Val] : ConstMap) { + if (I == ParentConst) { + continue; + } if (Target.getBitWidth() == I->Width || !Threshold ) { continue; } @@ -1501,7 +1504,7 @@ InstContext &IC, size_t Threshold, bool ConstMode, Inst *ParentConst = nullptr) for (auto X : IOSynthesize(NewTarget, ConstMap, IC, Threshold - 1, ConstMode, nullptr)) { // ReplacementContext RC; // RC.printInst(X, llvm::errs(), true); - if (I->Width < X->Width) { + if (NewTarget.getBitWidth() < Target.getBitWidth()) { Results.push_back(Builder(IC, X).ZExt(Target.getBitWidth())()); Results.push_back(Builder(IC, X).SExt(Target.getBitWidth())()); } else {