Skip to content

Commit

Permalink
Use subcolon args to simplify optimizer options
Browse files Browse the repository at this point in the history
  • Loading branch information
som-snytt committed Nov 16, 2021
1 parent 5697b87 commit ba7d4f0
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 110 deletions.
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
36 changes: 27 additions & 9 deletions src/compiler/scala/tools/nsc/settings/MutableSettings.scala
Expand Up @@ -22,6 +22,7 @@ import scala.collection.mutable.Clearable
import scala.io.Source
import scala.reflect.internal.util.{SomeOfNil, StringOps}
import scala.reflect.{ClassTag, classTag}
import scala.util.chaining._

/** A mutable Settings object.
*/
Expand Down Expand Up @@ -122,11 +123,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 @@ -142,9 +139,20 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
if (s endsWith ":") {
clearIfExists(s.init)
} else {
StringOps.splitWhere(s, _ == ':', doDropIndex = true).flatMap {
import StringOps.splitWhere
def splitColon(sc: String) = splitWhere(sc, _ == ':', doDropIndex = true)
splitColon(s).flatMap {
case (p, args) =>
tryToSetIfExists(p, (args split ",").toList, (s: Setting) => s.tryToSetColon(_))
if (args.contains(":")) {
val Some((sub, rest)) = splitColon(args): @unchecked
tryToSetIfExists(p, List(sub), (s: Setting) => x =>
s.tryToSetColon(x).tap(_ => s match {
case mcs: MultiChoiceSetting[_] if rest.nonEmpty => mcs.add(sub, rest.split(",").toList)
case _ =>
})
)
} else
tryToSetIfExists(p, args.split(",").toList, (s: Setting) => s.tryToSetColon(_))
}
}

Expand Down Expand Up @@ -559,7 +567,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) 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 @@ -672,6 +682,9 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
compute()
}

def add(arg: String, selections: List[String]): Unit =
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,6 +693,10 @@ 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
*/
Expand Down Expand Up @@ -736,7 +753,8 @@ 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
Expand Down
69 changes: 36 additions & 33 deletions src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
Expand Up @@ -307,30 +307,29 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
val allowSkipCoreModuleInit = Choice("allow-skip-core-module-init", "Allow eliminating unused module loads for core modules of the standard library (e.g., Predef, ClassTag).")
val assumeModulesNonNull = Choice("assume-modules-non-null", "Assume loading a module never results in null (happens if the module is accessed in its super constructor).")
val allowSkipClassLoading = Choice("allow-skip-class-loading", "Allow optimizations that can skip or delay class loading.")
val inline = Choice("inline", "Inline method invocations according to -Yopt-inline-heuristics and -opt-inline-from.")
val inline = Choice("inline", "Inline method invocations from specified sites; also see -Yopt-inline-heuristics.")

// l:none is not an expanding option, unlike the other l: levels. But it is excluded from -opt:_ below.
val lNone = Choice("l:none",
"Disable optimizations. Takes precedence: `-opt:l:none,+box-unbox` / `-opt:l:none -opt:box-unbox` don't enable box-unbox.")
// none is not an expanding option. It is excluded from -opt:_ below.
val lNone = Choice("none", "Disable all optimizations, including explicit options.")

private val defaultChoices = List(unreachableCode)
private val defaultOptimizations = List(unreachableCode)
val lDefault = Choice(
"l:default",
"Enable default optimizations: " + defaultChoices.mkString("", ",", "."),
expandsTo = defaultChoices)
"default",
defaultOptimizations.mkString("Enable default optimizations: ", ",", "."),
expandsTo = defaultOptimizations)

private val methodChoices = List(unreachableCode, simplifyJumps, compactLocals, copyPropagation, redundantCasts, boxUnbox, nullnessTracking, closureInvocations, allowSkipCoreModuleInit, assumeModulesNonNull, allowSkipClassLoading)
val localOptimizations = List(simplifyJumps, compactLocals, copyPropagation, redundantCasts, boxUnbox, nullnessTracking, closureInvocations, allowSkipCoreModuleInit, assumeModulesNonNull, allowSkipClassLoading)
val lMethod = Choice(
"l:method",
"Enable intra-method optimizations: " + methodChoices.mkString("", ",", "."),
expandsTo = methodChoices)
"local",
localOptimizations.mkString("Enable intra-method optimizations: ", ",", "."),
expandsTo = defaultOptimizations ::: localOptimizations)

private val inlineChoices = List(lMethod, inline)
val lInline = Choice("l:inline",
"Enable cross-method optimizations (note: inlining requires -opt-inline-from): " + inlineChoices.mkString("", ",", "."),
expandsTo = inlineChoices)
val lInline = Choice(
"all",
"Enable inlining, cross-method and local optimizations. To restrict inlining, use -opt:inline:sites as follows:\n" + inlineHelp,
expandsTo = inline :: defaultOptimizations ::: localOptimizations)

// "l:none" is excluded from wildcard expansion so that -opt:_ does not disable all settings
// "none" is excluded from wildcard expansion so that -opt:_ does not disable all settings
override def wildcardChoices = super.wildcardChoices.filter(_ ne lNone)
}

Expand All @@ -342,14 +341,13 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
helpArg = "optimization",
descr = "Enable optimizations, `help` for details.",
domain = optChoices,
)
).withPostSetHook(ss => if (ss.contains(optChoices.inline) && optChoices.inline.selections.isEmpty) optChoices.inline.selections = List("**"))

private def optEnabled(choice: optChoices.Choice) = {
private def optEnabled(choice: optChoices.Choice) =
!opt.contains(optChoices.lNone) && {
opt.contains(choice) ||
!opt.isSetByUser && optChoices.lDefault.expandsTo.contains(choice)
}
}

def optNone = opt.contains(optChoices.lNone)
def optUnreachableCode = optEnabled(optChoices.unreachableCode)
Expand All @@ -369,11 +367,9 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
def optAddToBytecodeRepository = optBuildCallGraph || optInlinerEnabled || optClosureInvocations
def optUseAnalyzerCache = opt.isSetByUser && !optNone && (optBuildCallGraph || opt.value.size > 1)

val optInlineFrom = MultiStringSetting(
"-opt-inline-from",
"patterns",
"Patterns for classfile names from which to allow inlining, `help` for details.",
helpText = Some(
def optInlineFrom = optChoices.inline.selections

def inlineHelp =
"""Patterns for classfile names from which the inliner is allowed to pull in code.
| * Matches classes in the empty package
| ** All classes
Expand All @@ -387,13 +383,19 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
| <sources> Classes defined in source files compiled in the current compilation, either
| passed explicitly to the compiler or picked up from the `-sourcepath`
|
|The setting accepts a list of patterns: `-opt-inline-from:p1,p2`. The setting can be passed
|The setting accepts a list of patterns: `-opt:inline:p1,p2`. The setting can be passed
|multiple times, the list of patterns gets extended. A leading `!` marks a pattern excluding.
|The last matching pattern defines whether a classfile is included or excluded (default: excluded).
|For example, `a.**,!a.b.**` includes classes in a and sub-packages, but not in a.b and sub-packages.
|
|Note: on the command-line you might need to quote patterns containing `*` to prevent the shell
|from expanding it to a list of files in the current directory.""".stripMargin))
|from expanding it to a list of files in the current directory.""".stripMargin

val xoptInlineFrom = MultiStringSetting(
"-opt-inline-from",
"patterns",
"Patterns for classfile names from which to allow inlining, `help` for details.",
helpText = Some(inlineHelp)).withDeprecationMessage("use -opt:inline:**")

val YoptInlineHeuristics = ChoiceSetting(
name = "-Yopt-inline-heuristics",
Expand All @@ -413,11 +415,12 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
}

val optWarnings = MultiChoiceSetting(
name = "-opt-warnings",
name = "-Wopt",
helpArg = "warning",
descr = "Enable optimizer warnings, `help` for details.",
domain = optWarningsChoices,
default = Some(List(optWarningsChoices.atInlineFailed.name))) withPostSetHook { _ =>
default = Some(List(optWarningsChoices.atInlineFailed.name))
).withPostSetHook { _ =>
// no need to set `Wconf` to `silent` if optWarnings is none, since no warnings are reported
if (optWarningsSummaryOnly) Wconf.tryToSet(List(s"cat=optimizer:ws"))
else Wconf.tryToSet(List(s"cat=optimizer:w"))
Expand Down Expand Up @@ -519,11 +522,11 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
val future = BooleanSetting("-Xfuture", "Replaced by -Xsource.").withDeprecationMessage("Not used since 2.13.")
val optimise = BooleanSetting("-optimize", "Enables optimizations.")
.withAbbreviation("-optimise")
.withDeprecationMessage("Since 2.12, enables -opt:l:inline -opt-inline-from:**. See -opt:help.")
.withPostSetHook(_ => {
.withDeprecationMessage("Since 2.12, enables -opt:inline:**. This can be dangerous.")
.withPostSetHook { _ =>
opt.enable(optChoices.lInline)
optInlineFrom.value = List("**")
})
optChoices.inline.selections = List("**")
}
val Xexperimental = BooleanSetting("-Xexperimental", "Former graveyard for language-forking extensions.")
.withDeprecationMessage("Not used since 2.13.")

Expand Down
6 changes: 4 additions & 2 deletions src/reflect/scala/reflect/internal/util/StringOps.scala
Expand Up @@ -15,7 +15,7 @@ package reflect
package internal
package util

import java.lang.System.{lineSeparator => EOL}
import java.lang.System.lineSeparator

/** This object provides utility methods to extract elements
* from Strings.
Expand Down Expand Up @@ -46,7 +46,7 @@ trait StringOps {
else s.substring(0, end)
}
/** Breaks the string into lines and strips each line before reassembling. */
def trimAllTrailingSpace(s: String): String = s.linesIterator.map(trimTrailingSpace).mkString(EOL)
def trimAllTrailingSpace(s: String): String = s.linesIterator.map(trimTrailingSpace).mkString(lineSeparator)

def decompose(str: String, sep: Char): List[String] = {
def ws(start: Int): List[String] =
Expand All @@ -65,6 +65,8 @@ trait StringOps {
def splitWhere(str: String, f: Char => Boolean, doDropIndex: Boolean = false): Option[(String, String)] =
splitAt(str, str indexWhere f, doDropIndex)

def splitAround(str: String, idx: Int): Option[(String, String)] = splitAt(str, idx, doDropIndex = true)

def splitAt(str: String, idx: Int, doDropIndex: Boolean = false): Option[(String, String)] =
if (idx == -1) None
else Some((str take idx, str drop (if (doDropIndex) idx + 1 else idx)))
Expand Down
Expand Up @@ -17,7 +17,8 @@ class InlineSourceMatcherTest extends BytecodeTesting {

override def compilerArgs = "-opt:l:inline -opt-warnings"
def setInlineFrom(s: String): Unit = {
global.settings.optInlineFrom.value = s.split(':').toList
//global.settings.optInlineFrom.value = s.split(':').toList
global.settings.optChoices.inline.selections = s.split(':').toList
}

case class E(regex: String, negated: Boolean = false, terminal: Boolean = true)
Expand Down

0 comments on commit ba7d4f0

Please sign in to comment.