Skip to content
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

Use subcolon args to simplify optimizer options #9810

Merged
merged 3 commits into from Feb 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions build.sbt
Expand Up @@ -682,6 +682,7 @@ lazy val bench = project.in(file("test") / "benchmarks")
if (benchmarkScalaVersion == "") Nil
else "org.scala-lang" % "scala-compiler" % benchmarkScalaVersion :: Nil
},
//scalacOptions ++= Seq("-feature", "-opt:inline:scala/**", "-Wopt"),
scalacOptions ++= Seq("-feature", "-opt:l:inline", "-opt-inline-from:scala/**", "-opt-warnings"),
// Skips JMH source generators during IDE import to avoid needing to compile scala-library during the import
// should not be needed once sbt-jmh 0.4.3 is out (https://github.com/sbt/sbt-jmh/pull/207)
Expand Down
1 change: 1 addition & 0 deletions project/ScriptCommands.scala
Expand Up @@ -161,6 +161,7 @@ object ScriptCommands {
}

private[this] val enableOptimizer = Seq(
//ThisBuild / Compile / scalacOptions ++= Seq("-opt:inline:scala/**")
ThisBuild / Compile / scalacOptions ++= Seq("-opt:l:inline", "-opt-inline-from:scala/**")
)

Expand Down
Expand Up @@ -211,7 +211,7 @@ object PostProcessorFrontendAccess {
val optAllowSkipClassLoading: Boolean = s.optAllowSkipClassLoading

val optInlinerEnabled: Boolean = s.optInlinerEnabled
val optInlineFrom: List[String] = s.optInlineFrom.value
val optInlineFrom: List[String] = s.optInlineFrom
val optInlineHeuristics: String = s.YoptInlineHeuristics.value

val optWarningNoInlineMixed: Boolean = s.optWarningNoInlineMixed
Expand Down
112 changes: 69 additions & 43 deletions src/compiler/scala/tools/nsc/settings/MutableSettings.scala
Expand Up @@ -122,11 +122,7 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
args: List[String],
setter: (Setting) => (List[String] => Option[List[String]])
): Option[List[String]] =
lookupSetting(cmd) match {
//case None => errorFn("Parameter '" + cmd + "' is not recognised by Scalac.") ; None
case None => None //error reported in processArguments
case Some(cmd) => setter(cmd)(args)
}
lookupSetting(cmd).flatMap(setter(_)(args))

// -Xfoo: clears Clearables
def clearIfExists(cmd: String): Option[List[String]] = lookupSetting(cmd) match {
Expand All @@ -139,14 +135,14 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
// the entire arg is consumed, so return None for failure
// any non-Nil return value means failure and we return s unmodified
def parseColonArg(s: String): Option[List[String]] =
if (s endsWith ":") {
if (s endsWith ":")
clearIfExists(s.init)
} else {
else
StringOps.splitWhere(s, _ == ':', doDropIndex = true).flatMap {
case (p, args) =>
tryToSetIfExists(p, (args split ",").toList, (s: Setting) => s.tryToSetColon(_))
// p:arg:a,b,c is taken as arg with selections a,b,c for a multichoice setting
case (p, args) if args.contains(":") && lookupSetting(p).map(_.isInstanceOf[MultiChoiceSetting[_]]).getOrElse(false) => tryToSetIfExists(p, List(args), (s: Setting) => s.tryToSetColon(_))
case (p, args) => tryToSetIfExists(p, args.split(",").toList, (s: Setting) => s.tryToSetColon(_))
}
}

// if arg is of form -Xfoo or -Xfoo bar (name = "-Xfoo")
def parseNormalArg(p: String, args: List[String]): Option[List[String]] =
Expand Down Expand Up @@ -559,7 +555,9 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
* not present in the multiChoiceSetting.value set, only their expansion.
*/
abstract class MultiChoiceEnumeration extends Enumeration {
case class Choice(name: String, help: String = "", expandsTo: List[Choice] = Nil) extends Val(name)
case class Choice(name: String, help: String = "", expandsTo: List[Choice] = Nil, requiresSelections: Boolean = false) extends Val(name) {
var selections: List[String] = Nil
}
def wildcardChoices: ValueSet = values.filter { case c: Choice => c.expandsTo.isEmpty case _ => true }
}

Expand Down Expand Up @@ -614,10 +612,11 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
private var sawAll = false

private def badChoice(s: String) = errorFn(s"'$s' is not a valid choice for '$name'")
private def isChoice(s: String) = (s == "_") || (choices contains pos(s))
private def isChoice(s: String) = s == "_" || choices.contains(pos(s))
private def choiceOf(s: String): domain.Choice = domain.withName(pos(s)).asInstanceOf[domain.Choice]

private def pos(s: String) = s stripPrefix "-"
private def isPos(s: String) = !(s startsWith "-")
private def pos(s: String) = s.stripPrefix("-")
private def isPos(s: String) = !s.startsWith("-")

override val choices: List[String] = domain.values.toList map {
case ChoiceOrVal(name, _, _) => name
Expand All @@ -629,7 +628,7 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
case _ => ""
}

/** (Re)compute from current yeas, nays, wildcard status. */
/** (Re)compute from current yeas, nays, wildcard status. Assign option value. */
def compute() = {
def simple(v: domain.Value) = v match {
case c: domain.Choice => c.expandsTo.isEmpty
Expand All @@ -648,8 +647,8 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
}

// yeas from _ or expansions are weak: an explicit nay will disable them
val weakYeas = if (sawAll) domain.wildcardChoices else expand(yeas filterNot simple)
value = (yeas filter simple) | (weakYeas &~ nays)
val weakYeas = if (sawAll) domain.wildcardChoices else expand(yeas.filterNot(simple))
value = yeas.filter(simple) | (weakYeas &~ nays)
}

/** Add a named choice to the multichoice value. */
Expand All @@ -660,10 +659,10 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
sawAll = true
compute()
case _ if isPos(arg) =>
yeas += domain withName arg
yeas += domain.withName(arg)
compute()
case _ =>
val choice = domain withName pos(arg)
val choice = domain.withName(pos(arg))
choice match {
case ChoiceOrVal(_, _, _ :: _) => errorFn(s"'${pos(arg)}' cannot be negated, it enables other arguments")
case _ =>
Expand All @@ -672,6 +671,12 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
compute()
}

// refine a choice with selections. -opt:inline:**
def add(arg: String, selections: List[String]): Unit = {
add(arg)
domain.withName(arg).asInstanceOf[domain.Choice].selections ++= selections
}

def tryToSet(args: List[String]) = tryToSetArgs(args, halting = true)
override def tryToSetColon(args: List[String]) = tryToSetArgs(args, halting = false)
override def tryToSetFromPropertyValue(s: String) = tryToSet(s.trim.split(',').toList) // used from ide
Expand All @@ -680,37 +685,57 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
* The "halting" parameter means args were "-option a b c -else" so halt
* on "-else" or other non-choice. Otherwise, args were "-option:a,b,c,d",
* so process all and report non-choices as errors.
*
* If a choice is seen as colonated, then set the choice selections:
* "-option:choice:selection1,selection2"
*
* @param args args to process
* @param halting stop on non-arg
*/
private def tryToSetArgs(args: List[String], halting: Boolean) = {
val added = collection.mutable.ListBuffer.empty[String]

def tryArg(arg: String) = arg match {
case "help" => sawHelp = true
case s if isChoice(s) => added += s // this case also adds "_"
case s => badChoice(s)
}
@tailrec
def loop(args: List[String]): List[String] = args match {
case arg :: _ if halting && (!isPos(arg) || !isChoice(arg)) => args
case arg :: rest => tryArg(arg) ; loop(rest)
case Nil => Nil
}
val rest = loop(args)

// if no arg consumed, use defaults or error; otherwise, add what they added
if (rest.size == args.size) default match {
case Some(defaults) => defaults foreach add
case None => errorFn(s"'$name' requires an option. See '$name:help'.")
} else {
added foreach add
val colonnade = raw"([^:]+):(.*)".r
var count = 0
val rest = {
@tailrec
def loop(args: List[String]): List[String] = args match {
case "help" :: rest =>
sawHelp = true
count += 1
loop(rest)
case arg :: rest =>
val (argx, selections) = arg match {
case colonnade(x, y) => (x, y)
case _ => (arg, "")
}
if (halting && (!isPos(argx) || !isChoice(argx)))
args
else {
if (isChoice(argx)) {
if (selections.nonEmpty) add(argx, selections.split(",").toList)
else if (argx != "_" && isPos(argx) && choiceOf(argx).requiresSelections) errorFn(s"'$argx' requires '$argx:<selection>'. See '$name:help'.")
else add(argx) // this case also adds "_"
postSetHook() // support -opt:l:method
}
else
badChoice(argx)
count += 1
loop(rest)
}
case _ => Nil
}
loop(args)
}

// if no arg applied, use defaults or error; otherwise, add what they added
if (count == 0)
default match {
case Some(defaults) => defaults.foreach(add)
case None => errorFn(s"'$name' requires an option. See '$name:help'.")
}
Some(rest)
}

def contains(choice: domain.Value): Boolean = value contains choice
def contains(choice: domain.Value): Boolean = value.contains(choice)

// programmatically.
def enable(choice: domain.Value): Unit = { nays -= choice ; yeas += choice ; compute() }
Expand All @@ -736,14 +761,15 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
choices.zipAll(descriptions, "", "").map(describe).mkString(f"${descr}%n", f"%n", orelse)
}

def clear(): Unit = {
def clear(): Unit = {
domain.values.foreach { case c: domain.Choice => c.selections = Nil ; case _ => }
v = domain.ValueSet.empty
yeas = domain.ValueSet.empty
nays = domain.ValueSet.empty
sawAll = false
sawHelp = false
}
def unparse: List[String] = value.toList map (s => s"$name:$s")
def unparse: List[String] = value.toList.map(s => s"$name:$s")
def contains(s: String) = domain.values.find(_.toString == s).exists(value.contains)
}

Expand Down