-
Notifications
You must be signed in to change notification settings - Fork 171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Floating point cost values with some heuristics for ExhaustiveSynthesis #399
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,8 @@ namespace { | |
static cl::opt<bool> EnableBigQuery("souper-exhaustive-synthesis-enable-big-query", | ||
cl::desc("Enable big query in exhaustive synthesis (default=false)"), | ||
cl::init(false)); | ||
static cl::opt<std::string> CostModel("souper-cost-model", cl::desc("Cost Model"), | ||
cl::init("default")); | ||
} | ||
|
||
// TODO | ||
|
@@ -86,6 +88,60 @@ namespace { | |
// experiment with synthesizing at reduced bitwidth, then expanding the result | ||
// aggressively avoid calling into the solver | ||
|
||
using CostFunctionType = std::function<float(Inst *, bool)>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's use double instead of float everywhere |
||
|
||
float defaultCostFunction(Inst* I, bool IgnoreDepsWithExternalUses) { | ||
return souper::cost(I, IgnoreDepsWithExternalUses); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. might as well move the code over here, instead of calling out to somewhere else There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The old synthesis still relies on this. |
||
} | ||
|
||
// TODO : Derive these randomly to maximize infer rate with test-infer.sh | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what does "derive these randomly" mean? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pick a plausible cost range and a sample frequency for each instruction. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't explain it here, explain it in the code |
||
float getCost(Inst::Kind K) { | ||
switch (K) { | ||
case souper::Inst::Var: | ||
case souper::Inst::Const: | ||
case souper::Inst::Phi: | ||
return 0; | ||
case souper::Inst::BSwap: | ||
case souper::Inst::CtPop: | ||
case souper::Inst::Cttz: | ||
case souper::Inst::Ctlz: | ||
case souper::Inst::SDiv: | ||
case souper::Inst::UDiv: | ||
case souper::Inst::SRem: | ||
case souper::Inst::URem: | ||
return 5; | ||
case souper::Inst::Select: | ||
return 3; | ||
case souper::Inst::Mul: | ||
return 2.5f; | ||
case souper::Inst::Add: | ||
case souper::Inst::Sub: | ||
return 1.5f; | ||
default: | ||
return 1; | ||
} | ||
} | ||
|
||
// TODO: Recognize simple patterns | ||
static float costHelper(Inst *I, Inst *Root, std::set<Inst *> &Visited, | ||
bool IgnoreDepsWithExternalUses) { | ||
if (!Visited.insert(I).second) | ||
return 0; | ||
if (IgnoreDepsWithExternalUses && I != Root && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you should leave a comment explaining the rationale for counting things with external uses are zero cost |
||
Root->DepsWithExternalUses.find(I) != Root->DepsWithExternalUses.end()) { | ||
return 0; | ||
} | ||
float Cost = getCost(I->K); | ||
for (auto Op : I->Ops) | ||
Cost += costHelper(Op, Root, Visited, IgnoreDepsWithExternalUses); | ||
return Cost; | ||
} | ||
|
||
float simpleHeuristicsCostFunction(Inst* I, bool IgnoreDepsWithExternalUses) { | ||
std::set<Inst *> Visited; | ||
return costHelper(I, I, Visited, IgnoreDepsWithExternalUses); | ||
} | ||
|
||
void hasConstantHelper(Inst *I, std::set<Inst *> &Visited, | ||
std::vector<Inst *> &ConstList) { | ||
// FIXME this only works for one constant and keying by name is bad | ||
|
@@ -119,9 +175,9 @@ std::vector<Inst *> matchWidth(Inst *I, unsigned NewW, InstContext &IC) { | |
return { I }; | ||
} | ||
|
||
void addGuess(Inst *RHS, int MaxCost, std::vector<Inst *> &Guesses, | ||
int &TooExpensive) { | ||
if (souper::cost(RHS) < MaxCost) | ||
void addGuess(Inst *RHS, float MaxCost, std::vector<Inst *> &Guesses, | ||
float &TooExpensive, CostFunctionType &Cost) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rather than passing the cost function around a lot, investigate whether there's a better place to stash this pointer, for example in one of the context objects |
||
if (Cost(RHS, false) < MaxCost) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when passing a boolean constant, follow the convention of including the name of the flag as a comment |
||
Guesses.push_back(RHS); | ||
else | ||
TooExpensive++; | ||
|
@@ -138,9 +194,9 @@ bool prune (Inst *I, std::vector<Inst *> &ReservedInsts) { | |
|
||
void getGuesses(std::vector<Inst *> &Guesses, | ||
const std::vector<Inst *> &Inputs, | ||
int Width, int LHSCost, | ||
int Width, float LHSCost, | ||
InstContext &IC, Inst *PrevInst, Inst *PrevSlot, | ||
int &TooExpensive) { | ||
float &TooExpensive, CostFunctionType &Cost) { | ||
|
||
std::vector<Inst *> PartialGuesses; | ||
|
||
|
@@ -177,7 +233,7 @@ void getGuesses(std::vector<Inst *> &Guesses, | |
|
||
for (auto V : matchWidth(Comp, Width, IC)) { | ||
auto N = IC.getInst(K, Width, { V }); | ||
addGuess(N, LHSCost, PartialGuesses, TooExpensive); | ||
addGuess(N, LHSCost, PartialGuesses, TooExpensive, Cost); | ||
} | ||
} | ||
} | ||
|
@@ -264,7 +320,7 @@ void getGuesses(std::vector<Inst *> &Guesses, | |
continue; | ||
auto N = IC.getInst(K, Inst::isCmp(K) ? 1 : OpWidth, { V1i, V2i }); | ||
for (auto MatchedWidthN : matchWidth(N, Width, IC)) { | ||
addGuess(MatchedWidthN, LHSCost, PartialGuesses, TooExpensive); | ||
addGuess(MatchedWidthN, LHSCost, PartialGuesses, TooExpensive, Cost); | ||
} | ||
} | ||
} | ||
|
@@ -318,7 +374,7 @@ void getGuesses(std::vector<Inst *> &Guesses, | |
auto MatchedWidthL = matchWidth(L, 1, IC); | ||
auto SelectInst = IC.getInst(Inst::Select, | ||
Width, { MatchedWidthL[0], V1i, V2i }); | ||
addGuess(SelectInst, LHSCost, PartialGuesses, TooExpensive); | ||
addGuess(SelectInst, LHSCost, PartialGuesses, TooExpensive, Cost); | ||
} | ||
} | ||
} | ||
|
@@ -351,7 +407,7 @@ void getGuesses(std::vector<Inst *> &Guesses, | |
if (prune(JoinedGuess, CurrSlots)) { | ||
for (auto S : CurrSlots) | ||
getGuesses(Guesses, Inputs, S->Width, | ||
LHSCost, IC, JoinedGuess, S, TooExpensive); | ||
LHSCost, IC, JoinedGuess, S, TooExpensive, Cost); | ||
} | ||
} | ||
} | ||
|
@@ -445,18 +501,24 @@ ExhaustiveSynthesis::synthesize(SMTLIBSolver *SMTSolver, | |
if (DebugLevel > 1) | ||
llvm::errs() << "got " << Inputs.size() << " candidates from LHS\n"; | ||
|
||
CostFunctionType Cost; | ||
if (CostModel == "default") { | ||
Cost = defaultCostFunction; | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the else clause needs to be an error |
||
Cost = simpleHeuristicsCostFunction; | ||
} | ||
|
||
int LHSCost = souper::cost(LHS, /*IgnoreDepsWithExternalUses=*/true); | ||
float LHSCost = Cost(LHS, /*IgnoreDepsWithExternalUses=*/true); | ||
|
||
int TooExpensive = 0; | ||
float TooExpensive = 0; | ||
std::vector<Inst *> Guesses; | ||
getGuesses(Guesses, Inputs, LHS->Width, | ||
LHSCost, IC, nullptr, nullptr, TooExpensive); | ||
LHSCost, IC, nullptr, nullptr, TooExpensive, Cost); | ||
|
||
// add nops guesses separately | ||
for (auto I : Inputs) { | ||
for (auto V : matchWidth(I, LHS->Width, IC)) | ||
addGuess(V, LHSCost, Guesses, TooExpensive); | ||
addGuess(V, LHSCost, Guesses, TooExpensive, Cost); | ||
} | ||
|
||
std::error_code EC; | ||
|
@@ -467,8 +529,8 @@ ExhaustiveSynthesis::synthesize(SMTLIBSolver *SMTSolver, | |
// CEGIS is that we can synthesize in precisely increasing cost | ||
// order, and not try to somehow teach the solver how to do that | ||
std::stable_sort(Guesses.begin(), Guesses.end(), | ||
[](Inst *a, Inst *b) -> bool { | ||
return souper::cost(a) < souper::cost(b); | ||
[&Cost](Inst *a, Inst *b) -> bool { | ||
return Cost(a, false) < Cost(b, false); | ||
}); | ||
|
||
if (DebugLevel > 1) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
; REQUIRES: solver, solver-model | ||
|
||
; RUN: %souper-check %solver -reinfer-rhs -souper-exhaustive-synthesis -souper-exhaustive-synthesis-num-instructions=1 -souper-cost-model=heuristics %s > %t | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this isn't a great cost model test, since many different cost models would allow this optimization to go. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The default one (without ignoring cost) does not infer this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's not a good test case and wants to be improved |
||
; RUN: %FileCheck %s < %t | ||
|
||
%b:i64 = var | ||
%a = add %b, %b | ||
infer %a | ||
%r2 = shl %b, 1 | ||
result %r2 | ||
; CHECK: RHS inferred successfully, no cost regression |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in the description you should list the possible choices