8177046: Update Graal
Update Graal, make appropriate changes to AOT, and the build system. Reviewed-by: kvn
This commit is contained in:
parent
2fd9f38a31
commit
d405f1648b
@ -47,11 +47,9 @@ ifeq ($(INCLUDE_GRAAL), true)
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.collections/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.asm/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.bytecode/src \
|
||||
@ -68,6 +66,7 @@ ifeq ($(INCLUDE_GRAAL), true)
|
||||
$(SRC_DIR)/org.graalvm.compiler.phases.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.virtual/src \
|
||||
$(SRC_DIR)/org.graalvm.util/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
|
||||
@ -102,6 +101,7 @@ ifeq ($(INCLUDE_GRAAL), true)
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options.processor/src \
|
||||
$(SRC_DIR)/org.graalvm.util/src \
|
||||
, \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar, \
|
||||
@ -114,9 +114,7 @@ ifeq ($(INCLUDE_GRAAL), true)
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.collections/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.code/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.common/src \
|
||||
@ -125,6 +123,7 @@ ifeq ($(INCLUDE_GRAAL), true)
|
||||
$(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
|
||||
$(SRC_DIR)/org.graalvm.util/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
|
||||
|
@ -37,7 +37,6 @@ SRC_DIR := $(HOTSPOT_TOPDIR)/src/$(MODULE)/share/classes
|
||||
|
||||
PROC_SRC_SUBDIRS := \
|
||||
org.graalvm.compiler.code \
|
||||
org.graalvm.compiler.common \
|
||||
org.graalvm.compiler.core \
|
||||
org.graalvm.compiler.core.aarch64 \
|
||||
org.graalvm.compiler.core.amd64 \
|
||||
|
@ -40,14 +40,15 @@ import jdk.tools.jaotc.binformat.macho.JMachORelocObject;
|
||||
import jdk.tools.jaotc.binformat.pecoff.JPECoffRelocObject;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
/**
|
||||
* A format-agnostic container class that holds various components of a binary.
|
||||
*
|
||||
* <p>
|
||||
* This class holds information necessary to create platform-specific binary containers such as
|
||||
* ELFContainer for Linux and Solaris operating systems or MachOContainer for Mac
|
||||
* OS or PEContainer for MS Windows operating systems.
|
||||
* ELFContainer for Linux and Solaris operating systems or MachOContainer for Mac OS or PEContainer
|
||||
* for MS Windows operating systems.
|
||||
*
|
||||
* <p>
|
||||
* Method APIs provided by this class are used to construct and populate platform-independent
|
||||
@ -58,6 +59,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
* Methods to record and access code section contents, symbols and relocations are provided.
|
||||
*/
|
||||
public class BinaryContainer implements SymbolTable {
|
||||
private final OptionValues graalOptions;
|
||||
|
||||
private final int codeSegmentSize;
|
||||
|
||||
@ -259,8 +261,12 @@ public class BinaryContainer implements SymbolTable {
|
||||
* Allocates a {@code BinaryContainer} object whose content will be generated in a file with the
|
||||
* prefix {@code prefix}. It also initializes internal code container, symbol table and
|
||||
* relocation tables.
|
||||
*
|
||||
* @param graalOptions
|
||||
*/
|
||||
public BinaryContainer(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) {
|
||||
public BinaryContainer(OptionValues graalOptions, GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) {
|
||||
this.graalOptions = graalOptions;
|
||||
|
||||
this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize;
|
||||
this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
|
||||
|
||||
@ -305,17 +311,17 @@ public class BinaryContainer implements SymbolTable {
|
||||
graalHotSpotVMConfig.useCMSGC,
|
||||
graalHotSpotVMConfig.useTLAB,
|
||||
graalHotSpotVMConfig.useBiasedLocking,
|
||||
TieredAOT.getValue(),
|
||||
TieredAOT.getValue(graalOptions),
|
||||
graalHotSpotVMConfig.enableContended,
|
||||
graalHotSpotVMConfig.restrictContended,
|
||||
graphBuilderConfig.omitAssertions()
|
||||
};
|
||||
|
||||
int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().shift,
|
||||
graalHotSpotVMConfig.getKlassEncoding().shift,
|
||||
int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().getShift(),
|
||||
graalHotSpotVMConfig.getKlassEncoding().getShift(),
|
||||
graalHotSpotVMConfig.contendedPaddingWidth,
|
||||
graalHotSpotVMConfig.fieldsAllocationStyle,
|
||||
1 << graalHotSpotVMConfig.getOopEncoding().alignment,
|
||||
1 << graalHotSpotVMConfig.logMinObjAlignment(),
|
||||
graalHotSpotVMConfig.codeSegmentSize,
|
||||
};
|
||||
// @formatter:on
|
||||
@ -511,8 +517,7 @@ public class BinaryContainer implements SymbolTable {
|
||||
JPECoffRelocObject pecoffobj = new JPECoffRelocObject(this, outputFileName, aotVersion);
|
||||
pecoffobj.createPECoffRelocObject(relocationTable, symbolTable.values());
|
||||
break;
|
||||
}
|
||||
else
|
||||
} else
|
||||
throw new InternalError("Unsupported platform: " + osName);
|
||||
}
|
||||
}
|
||||
|
@ -23,17 +23,12 @@
|
||||
|
||||
package jdk.tools.jaotc;
|
||||
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.core.GraalCompiler;
|
||||
import org.graalvm.compiler.core.common.CompilationIdentifier;
|
||||
import org.graalvm.compiler.debug.Debug;
|
||||
import org.graalvm.compiler.debug.Debug.Scope;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.hotspot.HotSpotBackend;
|
||||
import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
|
||||
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
|
||||
@ -43,8 +38,7 @@ import org.graalvm.compiler.lir.phases.LIRSuites;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
|
||||
import org.graalvm.compiler.options.OptionValue;
|
||||
import org.graalvm.compiler.options.OptionValue.OverrideScope;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.phases.BasePhase;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.graalvm.compiler.phases.PhaseSuite;
|
||||
@ -62,6 +56,7 @@ import jdk.vm.ci.meta.TriState;
|
||||
public class AOTBackend {
|
||||
|
||||
private final Main main;
|
||||
private final OptionValues graalOptions;
|
||||
|
||||
private final HotSpotBackend backend;
|
||||
|
||||
@ -71,8 +66,9 @@ public class AOTBackend {
|
||||
private final HighTierContext highTierContext;
|
||||
private final GraalFilters filters;
|
||||
|
||||
public AOTBackend(Main main, HotSpotBackend backend, GraalFilters filters) {
|
||||
public AOTBackend(Main main, OptionValues graalOptions, HotSpotBackend backend, GraalFilters filters) {
|
||||
this.main = main;
|
||||
this.graalOptions = graalOptions;
|
||||
this.backend = backend;
|
||||
this.filters = filters;
|
||||
providers = backend.getProviders();
|
||||
@ -87,23 +83,21 @@ public class AOTBackend {
|
||||
|
||||
private Suites getSuites() {
|
||||
// create suites every time, as we modify options for the compiler
|
||||
return backend.getSuites().getDefaultSuites();
|
||||
return backend.getSuites().getDefaultSuites(graalOptions);
|
||||
}
|
||||
|
||||
private LIRSuites getLirSuites() {
|
||||
// create suites every time, as we modify options for the compiler
|
||||
return backend.getSuites().getDefaultLIRSuites();
|
||||
return backend.getSuites().getDefaultLIRSuites(graalOptions);
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
public CompilationResult compileMethod(ResolvedJavaMethod resolvedMethod) {
|
||||
try (OverrideScope s = OptionValue.override(ImmutableCode, true, GeneratePIC, true)) {
|
||||
StructuredGraph graph = buildStructuredGraph(resolvedMethod);
|
||||
if (graph != null) {
|
||||
return compileGraph(resolvedMethod, graph);
|
||||
}
|
||||
return null;
|
||||
StructuredGraph graph = buildStructuredGraph(resolvedMethod);
|
||||
if (graph != null) {
|
||||
return compileGraph(resolvedMethod, graph);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,7 +109,7 @@ public class AOTBackend {
|
||||
@SuppressWarnings("try")
|
||||
private StructuredGraph buildStructuredGraph(ResolvedJavaMethod javaMethod) {
|
||||
try (Scope s = Debug.scope("AOTParseMethod")) {
|
||||
StructuredGraph graph = new StructuredGraph(javaMethod, StructuredGraph.AllowAssumptions.NO, false, CompilationIdentifier.INVALID_COMPILATION_ID);
|
||||
StructuredGraph graph = new StructuredGraph.Builder(graalOptions).method(javaMethod).useProfilingInfo(false).build();
|
||||
graphBuilderSuite.apply(graph, highTierContext);
|
||||
return graph;
|
||||
} catch (Throwable e) {
|
||||
|
@ -33,6 +33,7 @@ import org.graalvm.compiler.debug.DebugEnvironment;
|
||||
import org.graalvm.compiler.debug.Management;
|
||||
import org.graalvm.compiler.debug.TTY;
|
||||
import org.graalvm.compiler.debug.internal.DebugScope;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
|
||||
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
|
||||
@ -54,6 +55,8 @@ public class AOTCompilationTask implements Runnable, Comparable<Object> {
|
||||
|
||||
private final Main main;
|
||||
|
||||
private OptionValues graalOptions;
|
||||
|
||||
/**
|
||||
* The compilation id of this task.
|
||||
*/
|
||||
@ -73,8 +76,9 @@ public class AOTCompilationTask implements Runnable, Comparable<Object> {
|
||||
*/
|
||||
private CompiledMethodInfo result;
|
||||
|
||||
public AOTCompilationTask(Main main, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) {
|
||||
public AOTCompilationTask(Main main, OptionValues graalOptions, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) {
|
||||
this.main = main;
|
||||
this.graalOptions = graalOptions;
|
||||
this.id = ids.getAndIncrement();
|
||||
this.holder = holder;
|
||||
this.method = method;
|
||||
@ -91,14 +95,14 @@ public class AOTCompilationTask implements Runnable, Comparable<Object> {
|
||||
|
||||
// Ensure a debug configuration for this thread is initialized
|
||||
if (Debug.isEnabled() && DebugScope.getConfig() == null) {
|
||||
DebugEnvironment.initialize(TTY.out);
|
||||
DebugEnvironment.ensureInitialized(graalOptions);
|
||||
}
|
||||
AOTCompiler.logCompilation(MiscUtils.uniqueMethodName(method), "Compiling");
|
||||
|
||||
final long threadId = Thread.currentThread().getId();
|
||||
|
||||
final boolean printCompilation = GraalCompilerOptions.PrintCompilation.getValue() && !TTY.isSuppressed();
|
||||
final boolean printAfterCompilation = GraalCompilerOptions.PrintAfterCompilation.getValue() && !TTY.isSuppressed();
|
||||
final boolean printCompilation = GraalCompilerOptions.PrintCompilation.getValue(graalOptions) && !TTY.isSuppressed();
|
||||
final boolean printAfterCompilation = GraalCompilerOptions.PrintAfterCompilation.getValue(graalOptions) && !TTY.isSuppressed();
|
||||
if (printCompilation) {
|
||||
TTY.println(getMethodDescription() + "...");
|
||||
}
|
||||
|
@ -31,12 +31,16 @@ import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public class AOTCompiler {
|
||||
|
||||
private final Main main;
|
||||
|
||||
private final OptionValues graalOptions;
|
||||
|
||||
private CompileQueue compileQueue;
|
||||
|
||||
private final AOTBackend backend;
|
||||
@ -102,11 +106,13 @@ public class AOTCompiler {
|
||||
|
||||
/**
|
||||
* @param main
|
||||
* @param graalOptions
|
||||
* @param aotBackend
|
||||
* @param threads number of compilation threads
|
||||
*/
|
||||
public AOTCompiler(Main main, AOTBackend aotBackend, final int threads) {
|
||||
public AOTCompiler(Main main, OptionValues graalOptions, AOTBackend aotBackend, final int threads) {
|
||||
this.main = main;
|
||||
this.graalOptions = graalOptions;
|
||||
this.compileQueue = new CompileQueue(threads);
|
||||
this.backend = aotBackend;
|
||||
}
|
||||
@ -146,7 +152,7 @@ public class AOTCompiler {
|
||||
* @param method method to be enqueued
|
||||
*/
|
||||
private void enqueueMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method) {
|
||||
AOTCompilationTask task = new AOTCompilationTask(main, aotClass, method, backend);
|
||||
AOTCompilationTask task = new AOTCompilationTask(main, graalOptions, aotClass, method, backend);
|
||||
try {
|
||||
compileQueue.execute(task);
|
||||
} catch (RejectedExecutionException e) {
|
||||
|
@ -36,6 +36,7 @@ import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.debug.Debug;
|
||||
import org.graalvm.compiler.debug.Debug.Scope;
|
||||
import org.graalvm.compiler.hotspot.HotSpotHostBackend;
|
||||
import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
|
||||
import org.graalvm.compiler.hotspot.stubs.Stub;
|
||||
|
||||
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
|
||||
@ -180,7 +181,8 @@ class DataBuilder {
|
||||
@SuppressWarnings("try")
|
||||
private AOTCompiledClass retrieveStubCode() {
|
||||
ArrayList<CompiledMethodInfo> stubs = new ArrayList<>();
|
||||
for (Stub stub : Stub.getStubs()) {
|
||||
HotSpotForeignCallsProvider foreignCallsProvider = backend.getProviders().getForeignCalls();
|
||||
for (Stub stub : foreignCallsProvider.getStubs()) {
|
||||
try (Scope scope = Debug.scope("CompileStubs")) {
|
||||
CompilationResult result = stub.getCompilationResult(backend);
|
||||
CompiledMethodInfo cm = new CompiledMethodInfo(result, new AOTStub(stub, backend));
|
||||
|
@ -60,11 +60,15 @@ import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
|
||||
import jdk.tools.jaotc.utils.Timer;
|
||||
|
||||
import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
|
||||
import org.graalvm.compiler.hotspot.CompilerConfigurationFactory;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory;
|
||||
import org.graalvm.compiler.hotspot.HotSpotGraalOptionValues;
|
||||
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
|
||||
import org.graalvm.compiler.hotspot.HotSpotHostBackend;
|
||||
import org.graalvm.compiler.java.GraphBuilderPhase;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.phases.BasePhase;
|
||||
import org.graalvm.compiler.phases.PhaseSuite;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
@ -76,11 +80,6 @@ import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
import jdk.vm.ci.runtime.JVMCI;
|
||||
|
||||
public class Main implements LogPrinter {
|
||||
static {
|
||||
GeneratePIC.setValue(true);
|
||||
ImmutableCode.setValue(true);
|
||||
}
|
||||
|
||||
static class BadArgs extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
final String key;
|
||||
@ -132,7 +131,7 @@ public class Main implements LogPrinter {
|
||||
abstract void process(Main task, String opt, String arg) throws BadArgs;
|
||||
}
|
||||
|
||||
static Option[] recognizedOptions = { new Option(" --output <file> Output file name", true, "--output") {
|
||||
static Option[] recognizedOptions = {new Option(" --output <file> Output file name", true, "--output") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
String name = arg;
|
||||
@ -172,7 +171,7 @@ public class Main implements LogPrinter {
|
||||
}, new Option(" --compile-for-tiered Generate profiling code for tiered compilation", false, "--compile-for-tiered") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
TieredAOT.setValue(true);
|
||||
task.options.tiered = true;
|
||||
}
|
||||
}, new Option(" --compile-with-assertions Compile with java assertions", false, "--compile-with-assertions") {
|
||||
@Override
|
||||
@ -265,6 +264,7 @@ public class Main implements LogPrinter {
|
||||
public boolean help;
|
||||
public boolean version;
|
||||
public boolean compileWithAssertions;
|
||||
public boolean tiered;
|
||||
}
|
||||
|
||||
/* package */final Options options = new Options();
|
||||
@ -307,7 +307,7 @@ public class Main implements LogPrinter {
|
||||
printlnInfo("Compiling " + options.outputName + "...");
|
||||
final long start = System.currentTimeMillis();
|
||||
if (!run()) {
|
||||
return EXIT_ABNORMAL;
|
||||
return EXIT_ABNORMAL;
|
||||
}
|
||||
final long end = System.currentTimeMillis();
|
||||
printlnInfo("Total time: " + (end - start) + " ms");
|
||||
@ -351,8 +351,7 @@ public class Main implements LogPrinter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Visual Studio supported versions
|
||||
* Search Order is: VS2013, VS2015, VS2012
|
||||
* Visual Studio supported versions Search Order is: VS2013, VS2015, VS2012
|
||||
*/
|
||||
public enum VSVERSIONS {
|
||||
VS2013("VS120COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\link.exe"),
|
||||
@ -367,20 +366,23 @@ public class Main implements LogPrinter {
|
||||
this.wkp = wellknownpath;
|
||||
}
|
||||
|
||||
String EnvVariable() { return envvariable; }
|
||||
String WellKnownPath() { return wkp; }
|
||||
String EnvVariable() {
|
||||
return envvariable;
|
||||
}
|
||||
|
||||
String WellKnownPath() {
|
||||
return wkp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for Visual Studio link.exe
|
||||
* Search Order is: VS2013, VS2015, VS2012
|
||||
* Search for Visual Studio link.exe Search Order is: VS2013, VS2015, VS2012
|
||||
*/
|
||||
private static String getWindowsLinkPath() {
|
||||
String link = "\\VC\\bin\\amd64\\link.exe";
|
||||
|
||||
/**
|
||||
* First try searching the paths pointed to by
|
||||
* the VS environment variables.
|
||||
* First try searching the paths pointed to by the VS environment variables.
|
||||
*/
|
||||
for (VSVERSIONS vs : VSVERSIONS.values()) {
|
||||
String vspath = System.getenv(vs.EnvVariable());
|
||||
@ -388,13 +390,13 @@ public class Main implements LogPrinter {
|
||||
File commonTools = new File(vspath);
|
||||
File vsRoot = commonTools.getParentFile().getParentFile();
|
||||
File linkPath = new File(vsRoot, link);
|
||||
if (linkPath.exists()) return linkPath.getPath();
|
||||
if (linkPath.exists())
|
||||
return linkPath.getPath();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we didn't find via the VS environment variables,
|
||||
* try the well known paths
|
||||
* If we didn't find via the VS environment variables, try the well known paths
|
||||
*/
|
||||
for (VSVERSIONS vs : VSVERSIONS.values()) {
|
||||
String wkp = vs.WellKnownPath();
|
||||
@ -438,7 +440,13 @@ public class Main implements LogPrinter {
|
||||
printInfo(classesToCompile.size() + " classes found");
|
||||
}
|
||||
|
||||
GraalJVMCICompiler graalCompiler = (GraalJVMCICompiler) JVMCI.getRuntime().getCompiler();
|
||||
OptionValues graalOptions = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
|
||||
// Setting -Dgraal.TieredAOT overrides --compile-for-tiered
|
||||
if (!TieredAOT.hasBeenSet(graalOptions)) {
|
||||
graalOptions = new OptionValues(graalOptions, TieredAOT, options.tiered);
|
||||
}
|
||||
graalOptions = new OptionValues(HotSpotGraalOptionValues.HOTSPOT_OPTIONS, GeneratePIC, true, ImmutableCode, true);
|
||||
GraalJVMCICompiler graalCompiler = HotSpotGraalCompilerFactory.createCompiler(JVMCI.getRuntime(), graalOptions, CompilerConfigurationFactory.selectFactory(null, graalOptions));
|
||||
HotSpotGraalRuntimeProvider runtime = (HotSpotGraalRuntimeProvider) graalCompiler.getGraalRuntime();
|
||||
HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend();
|
||||
MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess();
|
||||
@ -458,8 +466,8 @@ public class Main implements LogPrinter {
|
||||
System.gc();
|
||||
}
|
||||
|
||||
AOTBackend aotBackend = new AOTBackend(this, backend, filters);
|
||||
AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads);
|
||||
AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, filters);
|
||||
AOTCompiler compiler = new AOTCompiler(this, graalOptions, aotBackend, options.threads);
|
||||
classes = compiler.compileClasses(classes);
|
||||
|
||||
GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig();
|
||||
@ -475,7 +483,7 @@ public class Main implements LogPrinter {
|
||||
System.gc();
|
||||
}
|
||||
|
||||
BinaryContainer binaryContainer = new BinaryContainer(graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION);
|
||||
BinaryContainer binaryContainer = new BinaryContainer(graalOptions, graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION);
|
||||
DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer);
|
||||
dataBuilder.prepareData();
|
||||
|
||||
@ -524,11 +532,9 @@ public class Main implements LogPrinter {
|
||||
|
||||
if (name.endsWith(".so")) {
|
||||
objectFileName = name.substring(0, name.length() - ".so".length());
|
||||
}
|
||||
else if (name.endsWith(".dylib")) {
|
||||
} else if (name.endsWith(".dylib")) {
|
||||
objectFileName = name.substring(0, name.length() - ".dylib".length());
|
||||
}
|
||||
else if (name.endsWith(".dll")) {
|
||||
} else if (name.endsWith(".dll")) {
|
||||
objectFileName = name.substring(0, name.length() - ".dll".length());
|
||||
}
|
||||
|
||||
@ -536,34 +542,32 @@ public class Main implements LogPrinter {
|
||||
case "Linux":
|
||||
// libraryFileName = options.outputName + ".so";
|
||||
objectFileName = objectFileName + ".o";
|
||||
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
|
||||
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
|
||||
linkerCmd = linkerPath + " -shared -z noexecstack -o " + libraryFileName + " " + objectFileName;
|
||||
break;
|
||||
case "SunOS":
|
||||
// libraryFileName = options.outputName + ".so";
|
||||
objectFileName = objectFileName + ".o";
|
||||
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
|
||||
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
|
||||
linkerCmd = linkerPath + " -shared -o " + libraryFileName + " " + objectFileName;
|
||||
break;
|
||||
case "Mac OS X":
|
||||
// libraryFileName = options.outputName + ".dylib";
|
||||
objectFileName = objectFileName + ".o";
|
||||
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
|
||||
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
|
||||
linkerCmd = linkerPath + " -dylib -o " + libraryFileName + " " + objectFileName;
|
||||
break;
|
||||
default:
|
||||
if (osName.startsWith("Windows")) {
|
||||
// libraryFileName = options.outputName + ".dll";
|
||||
objectFileName = objectFileName + ".obj";
|
||||
linkerPath = (options.linkerpath != null) ?
|
||||
options.linkerpath : getWindowsLinkPath();
|
||||
linkerPath = (options.linkerpath != null) ? options.linkerpath : getWindowsLinkPath();
|
||||
if (linkerPath == null) {
|
||||
throw new InternalError("Can't locate Microsoft Visual Studio amd64 link.exe");
|
||||
}
|
||||
linkerCmd = linkerPath + " /DLL /OPT:NOREF /NOLOGO /NOENTRY" + " /OUT:" + libraryFileName + " " + objectFileName;
|
||||
break;
|
||||
}
|
||||
else
|
||||
} else
|
||||
throw new InternalError("Unsupported platform: " + osName);
|
||||
}
|
||||
|
||||
|
@ -17,18 +17,22 @@ suite = {
|
||||
"sha1" : "476d9a44cd19d6b55f81571077dfa972a4f8a083",
|
||||
"bootClassPathAgent" : "true",
|
||||
},
|
||||
|
||||
"ASM5" : {
|
||||
"sha1" : "0da08b8cce7bbf903602a25a3a163ae252435795",
|
||||
"urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/asm-5.0.4.jar"],
|
||||
},
|
||||
|
||||
"ASM_TREE5" : {
|
||||
"sha1" : "396ce0c07ba2b481f25a70195c7c94922f0d1b0b",
|
||||
"urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/asm-tree-5.0.4.jar"],
|
||||
"dependencies" : ["ASM5"],
|
||||
},
|
||||
},
|
||||
|
||||
"projects" : {
|
||||
|
||||
# ------------- Graal -------------
|
||||
"org.graalvm.compiler.common" : {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
"javaCompliance" : "1.8",
|
||||
"workingSets" : "API,Graal",
|
||||
},
|
||||
|
||||
"org.graalvm.compiler.serviceprovider" : {
|
||||
"subDir" : "share/classes",
|
||||
@ -50,7 +54,9 @@ suite = {
|
||||
"org.graalvm.compiler.options" : {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : ["org.graalvm.util"],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
"uses" : ["org.graalvm.compiler.options.OptionDescriptors"],
|
||||
"javaCompliance" : "1.8",
|
||||
"workingSets" : "Graal",
|
||||
},
|
||||
@ -82,6 +88,11 @@ suite = {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
"uses" : [
|
||||
"org.graalvm.compiler.debug.DebugConfigCustomizer",
|
||||
"org.graalvm.compiler.debug.DebugInitializationParticipant",
|
||||
"org.graalvm.compiler.debug.TTYStreamProvider",
|
||||
],
|
||||
"dependencies" : [
|
||||
"org.graalvm.compiler.serviceprovider",
|
||||
"org.graalvm.compiler.options"
|
||||
@ -108,7 +119,6 @@ suite = {
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"org.graalvm.compiler.graph",
|
||||
"org.graalvm.compiler.common",
|
||||
],
|
||||
"annotationProcessors" : ["GRAAL_SERVICEPROVIDER_PROCESSOR"],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
@ -116,7 +126,7 @@ suite = {
|
||||
"workingSets" : "Graal",
|
||||
},
|
||||
|
||||
"org.graalvm.compiler.api.collections" : {
|
||||
"org.graalvm.util" : {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
@ -124,6 +134,18 @@ suite = {
|
||||
"workingSets" : "API,Graal",
|
||||
},
|
||||
|
||||
"org.graalvm.util.test" : {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"mx:JUNIT",
|
||||
"org.graalvm.util",
|
||||
],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
"javaCompliance" : "1.8",
|
||||
"workingSets" : "API,Graal",
|
||||
},
|
||||
|
||||
"org.graalvm.compiler.api.directives" : {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
@ -179,6 +201,11 @@ suite = {
|
||||
"org.graalvm.compiler.replacements",
|
||||
"org.graalvm.compiler.runtime",
|
||||
],
|
||||
"imports" : [
|
||||
# All other internal packages are exported dynamically -
|
||||
# see org.graalvm.compiler.hotspot.HotSpotGraalJVMCIServiceLocator
|
||||
"jdk.internal.module",
|
||||
],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
"annotationProcessors" : [
|
||||
"GRAAL_NODEINFO_PROCESSOR",
|
||||
@ -320,7 +347,6 @@ suite = {
|
||||
"dependencies" : [
|
||||
"org.graalvm.compiler.nodeinfo",
|
||||
"org.graalvm.compiler.core.common",
|
||||
"org.graalvm.compiler.api.collections",
|
||||
],
|
||||
"javaCompliance" : "1.8",
|
||||
"annotationProcessors" : [
|
||||
@ -347,6 +373,9 @@ suite = {
|
||||
"org.graalvm.compiler.asm" : {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"org.graalvm.compiler.core.common"
|
||||
],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
"javaCompliance" : "1.8",
|
||||
"workingSets" : "Graal,Assembler",
|
||||
@ -356,7 +385,6 @@ suite = {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"org.graalvm.compiler.debug",
|
||||
"org.graalvm.compiler.asm",
|
||||
],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
@ -379,9 +407,7 @@ suite = {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"org.graalvm.compiler.debug",
|
||||
"org.graalvm.compiler.asm",
|
||||
"org.graalvm.compiler.common"
|
||||
],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
"javaCompliance" : "1.8",
|
||||
@ -711,6 +737,18 @@ suite = {
|
||||
"workingSets" : "Graal",
|
||||
},
|
||||
|
||||
"org.graalvm.compiler.loop.test" : {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"org.graalvm.compiler.loop",
|
||||
"org.graalvm.compiler.core.test"
|
||||
],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
"javaCompliance" : "1.8",
|
||||
"workingSets" : "Graal,Test",
|
||||
},
|
||||
|
||||
"org.graalvm.compiler.loop.phases" : {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
@ -731,6 +769,7 @@ suite = {
|
||||
"org.graalvm.compiler.virtual",
|
||||
"org.graalvm.compiler.loop.phases",
|
||||
],
|
||||
"uses" : ["org.graalvm.compiler.core.match.MatchStatementSet"],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
"javaCompliance" : "1.8",
|
||||
"annotationProcessors" : [
|
||||
@ -908,7 +947,9 @@ suite = {
|
||||
"org.graalvm.compiler.graph.test",
|
||||
"org.graalvm.compiler.printer",
|
||||
"JAVA_ALLOCATION_INSTRUMENTER",
|
||||
"ASM_TREE5",
|
||||
],
|
||||
"uses" : ["org.graalvm.compiler.options.OptionDescriptors"],
|
||||
"annotationProcessors" : ["GRAAL_NODEINFO_PROCESSOR"],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
"javaCompliance" : "1.8",
|
||||
@ -929,21 +970,6 @@ suite = {
|
||||
"findbugs" : "false",
|
||||
},
|
||||
|
||||
# ------------- Salver -------------
|
||||
|
||||
"org.graalvm.compiler.salver" : {
|
||||
"subDir" : "share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : ["org.graalvm.compiler.phases"],
|
||||
"annotationProcessors" : [
|
||||
"GRAAL_OPTIONS_PROCESSOR",
|
||||
"GRAAL_SERVICEPROVIDER_PROCESSOR",
|
||||
],
|
||||
"checkstyle" : "org.graalvm.compiler.graph",
|
||||
"javaCompliance" : "1.8",
|
||||
"workingSets" : "Graal",
|
||||
},
|
||||
|
||||
# ------------- AOT -------------
|
||||
|
||||
"jdk.tools.jaotc" : {
|
||||
@ -1073,7 +1099,6 @@ suite = {
|
||||
"org.graalvm.compiler.replacements.amd64",
|
||||
"org.graalvm.compiler.core.sparc",
|
||||
"org.graalvm.compiler.replacements.sparc",
|
||||
"org.graalvm.compiler.salver",
|
||||
],
|
||||
"distDependencies" : [
|
||||
"GRAAL_API",
|
||||
@ -1197,7 +1222,6 @@ suite = {
|
||||
"org.graalvm.compiler.replacements.amd64",
|
||||
"org.graalvm.compiler.core.sparc",
|
||||
"org.graalvm.compiler.replacements.sparc",
|
||||
"org.graalvm.compiler.salver",
|
||||
"org.graalvm.compiler.hotspot.aarch64",
|
||||
"org.graalvm.compiler.hotspot.amd64",
|
||||
"org.graalvm.compiler.hotspot.sparc",
|
||||
|
@ -39,6 +39,7 @@ module jdk.internal.vm.compiler {
|
||||
uses org.graalvm.compiler.debug.TTYStreamProvider;
|
||||
uses org.graalvm.compiler.hotspot.CompilerConfigurationFactory;
|
||||
uses org.graalvm.compiler.hotspot.HotSpotBackendFactory;
|
||||
uses org.graalvm.compiler.options.OptionValuesAccess;
|
||||
uses org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
|
||||
|
||||
exports org.graalvm.compiler.api.directives to jdk.aot;
|
||||
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.api.collections;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A factory for creating collections.
|
||||
*/
|
||||
public interface CollectionsProvider {
|
||||
|
||||
/**
|
||||
* Creates a set that uses reference-equality in place of object-equality when comparing
|
||||
* entries.
|
||||
*/
|
||||
<E> Set<E> newIdentitySet();
|
||||
|
||||
/**
|
||||
* Creates a map that uses reference-equality in place of object-equality when comparing keys.
|
||||
*/
|
||||
<K, V> Map<K, V> newIdentityMap();
|
||||
|
||||
/**
|
||||
* Creates a map that uses reference-equality in place of object-equality when comparing keys.
|
||||
*
|
||||
* @param expectedMaxSize the expected maximum size of the map
|
||||
*/
|
||||
<K, V> Map<K, V> newIdentityMap(int expectedMaxSize);
|
||||
|
||||
/**
|
||||
* Creates a map that uses reference-equality in place of object-equality when comparing keys.
|
||||
*
|
||||
* @param initFrom the returned map is populated with the entries in this map
|
||||
*/
|
||||
<K, V> Map<K, V> newIdentityMap(Map<K, V> initFrom);
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.common.GraalOptions;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.options.OptionValue;
|
||||
import org.graalvm.compiler.options.OptionValue.OverrideScope;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.vm.ci.code.InstalledCode;
|
||||
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
@SuppressWarnings("try")
|
||||
public class AllocationInstrumentationTest extends GraalCompilerTest {
|
||||
|
||||
private TinyInstrumentor instrumentor;
|
||||
|
||||
public AllocationInstrumentationTest() {
|
||||
HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(ClassA.class, "notInlinedMethod");
|
||||
method.setNotInlineable();
|
||||
|
||||
try {
|
||||
instrumentor = new TinyInstrumentor(AllocationInstrumentationTest.class, "instrumentation");
|
||||
} catch (IOException e) {
|
||||
Assert.fail("unable to initialize the instrumentor: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ClassA {
|
||||
// This method should be marked as not inlineable
|
||||
public void notInlinedMethod() {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean allocationWasExecuted;
|
||||
|
||||
private static void resetFlag() {
|
||||
allocationWasExecuted = false;
|
||||
}
|
||||
|
||||
static void instrumentation() {
|
||||
GraalDirectives.instrumentationBeginForPredecessor();
|
||||
allocationWasExecuted = true;
|
||||
GraalDirectives.instrumentationEnd();
|
||||
}
|
||||
|
||||
public static void notEscapeSnippet() {
|
||||
@SuppressWarnings("unused")
|
||||
ClassA a = new ClassA(); // a does not escape
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEscape() {
|
||||
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
|
||||
Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "notEscapeSnippet", Opcodes.NEW);
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "notEscapeSnippet");
|
||||
executeExpected(method, null); // ensure the method is fully resolved
|
||||
resetFlag();
|
||||
// The allocation in the snippet does not escape and will be optimized away. We expect
|
||||
// the instrumentation is removed.
|
||||
InstalledCode code = getCode(method);
|
||||
code.executeVarargs();
|
||||
Assert.assertFalse("allocation should not take place", allocationWasExecuted);
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void mustEscapeSnippet() {
|
||||
ClassA a = new ClassA();
|
||||
a.notInlinedMethod(); // a escapses
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMustEscape() {
|
||||
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
|
||||
Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "mustEscapeSnippet", Opcodes.NEW);
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "mustEscapeSnippet");
|
||||
executeExpected(method, null); // ensure the method is fully resolved
|
||||
resetFlag();
|
||||
// The allocation in the snippet escapes. We expect the instrumentation is preserved.
|
||||
InstalledCode code = getCode(method);
|
||||
code.executeVarargs();
|
||||
Assert.assertTrue("allocation should take place", allocationWasExecuted);
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void partialEscapeSnippet(boolean condition) {
|
||||
ClassA a = new ClassA();
|
||||
|
||||
if (condition) {
|
||||
a.notInlinedMethod(); // a escapes in the then-clause
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartialEscape() {
|
||||
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
|
||||
Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "partialEscapeSnippet", Opcodes.NEW);
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "partialEscapeSnippet");
|
||||
executeExpected(method, null, true); // ensure the method is fully resolved
|
||||
resetFlag();
|
||||
// The allocation in the snippet escapes in the then-clause, and will be relocated to
|
||||
// this branch. We expect the instrumentation follows and will only be effective when
|
||||
// the then-clause is taken.
|
||||
InstalledCode code = getCode(method);
|
||||
code.executeVarargs(false);
|
||||
Assert.assertFalse("allocation should not take place", allocationWasExecuted);
|
||||
code.executeVarargs(true);
|
||||
Assert.assertTrue("allocation should take place", allocationWasExecuted);
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -70,7 +70,7 @@ public class DeoptimizeDirectiveTest extends GraalCompilerTest {
|
||||
Result actual;
|
||||
try {
|
||||
actual = new Result(code.executeVarargs(), null);
|
||||
} catch (Throwable e) {
|
||||
} catch (Exception e) {
|
||||
actual = new Result(null, e);
|
||||
}
|
||||
|
||||
|
@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.common.GraalOptions;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.options.OptionValue;
|
||||
import org.graalvm.compiler.options.OptionValue.OverrideScope;
|
||||
|
||||
import jdk.vm.ci.code.InstalledCode;
|
||||
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public class IsMethodInlineDirectiveTest extends GraalCompilerTest {
|
||||
|
||||
public IsMethodInlineDirectiveTest() {
|
||||
HotSpotResolvedJavaMethod calleeSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(IsMethodInlineDirectiveTest.class, "calleeSnippet");
|
||||
calleeSnippet.shouldBeInlined();
|
||||
|
||||
HotSpotResolvedJavaMethod calleeWithInstrumentationSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(IsMethodInlineDirectiveTest.class, "calleeWithInstrumentationSnippet");
|
||||
calleeWithInstrumentationSnippet.shouldBeInlined();
|
||||
}
|
||||
|
||||
public static boolean rootMethodSnippet() {
|
||||
return GraalDirectives.isMethodInlined();
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
@Test
|
||||
public void testRootMethod() {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("rootMethodSnippet");
|
||||
executeExpected(method, null); // ensure the method is fully resolved
|
||||
// The target method is not inlined. We expect the result to be false.
|
||||
InstalledCode code = getCode(method);
|
||||
try {
|
||||
Result result = new Result(code.executeVarargs(), null);
|
||||
assertEquals(new Result(false, null), result);
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean calleeSnippet() {
|
||||
return GraalDirectives.isMethodInlined();
|
||||
}
|
||||
|
||||
public static boolean callerSnippet() {
|
||||
return calleeSnippet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInlinedCallee() {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet");
|
||||
executeExpected(method, null); // ensure the method is fully resolved
|
||||
// calleeSnippet will be inlined. We expect the result to be true.
|
||||
InstalledCode code = getCode(method);
|
||||
try {
|
||||
Result result = new Result(code.executeVarargs(), null);
|
||||
assertEquals(new Result(true, null), result);
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isCalleeInlined;
|
||||
static boolean isCallerInlined;
|
||||
|
||||
public static void calleeWithInstrumentationSnippet() {
|
||||
GraalDirectives.instrumentationBegin();
|
||||
isCalleeInlined = GraalDirectives.isMethodInlined();
|
||||
GraalDirectives.instrumentationEnd();
|
||||
}
|
||||
|
||||
public static void callerSnippet1() {
|
||||
calleeWithInstrumentationSnippet();
|
||||
|
||||
GraalDirectives.instrumentationBegin();
|
||||
isCallerInlined = GraalDirectives.isMethodInlined();
|
||||
GraalDirectives.instrumentationEnd();
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
@Test
|
||||
public void testInlinedCalleeWithInstrumentation() {
|
||||
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet1");
|
||||
executeExpected(method, null); // ensure the method is fully resolved
|
||||
isCalleeInlined = false;
|
||||
isCallerInlined = false;
|
||||
// calleeWithInstrumentationSnippet will be inlined. We expect the flag1 set in
|
||||
// calleeWithInstrumentationSnippet to be true, and the flag2 set in callerSnippet1 to
|
||||
// be false.
|
||||
InstalledCode code = getCode(method);
|
||||
code.executeVarargs();
|
||||
assertTrue("calleWithInstrumentationSnippet should be inlined", isCalleeInlined);
|
||||
assertFalse("callerSnippet1 should not be inlined", isCallerInlined);
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.common.GraalOptions;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.options.OptionValue;
|
||||
import org.graalvm.compiler.options.OptionValue.OverrideScope;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.vm.ci.code.InstalledCode;
|
||||
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
@SuppressWarnings("try")
|
||||
public class LockInstrumentationTest extends GraalCompilerTest {
|
||||
|
||||
private TinyInstrumentor instrumentor;
|
||||
|
||||
public LockInstrumentationTest() {
|
||||
HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(ClassA.class, "notInlinedMethod");
|
||||
method.setNotInlineable();
|
||||
|
||||
try {
|
||||
instrumentor = new TinyInstrumentor(LockInstrumentationTest.class, "instrumentation");
|
||||
} catch (IOException e) {
|
||||
Assert.fail("unable to initialize the instrumentor: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ClassA {
|
||||
|
||||
// This method should be marked as not inlineable
|
||||
public void notInlinedMethod() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final Object lock = new Object();
|
||||
public static boolean lockAfterCheckPoint;
|
||||
public static boolean checkpoint;
|
||||
|
||||
private static void resetFlags() {
|
||||
lockAfterCheckPoint = false;
|
||||
checkpoint = false;
|
||||
}
|
||||
|
||||
static void instrumentation() {
|
||||
GraalDirectives.instrumentationBeginForPredecessor();
|
||||
lockAfterCheckPoint = checkpoint;
|
||||
GraalDirectives.instrumentationEnd();
|
||||
}
|
||||
|
||||
public static void lockSnippet() {
|
||||
synchronized (lock) {
|
||||
checkpoint = true;
|
||||
ClassA a = new ClassA();
|
||||
a.notInlinedMethod();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLock() {
|
||||
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
|
||||
Class<?> clazz = instrumentor.instrument(LockInstrumentationTest.class, "lockSnippet", Opcodes.MONITORENTER);
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "lockSnippet");
|
||||
executeExpected(method, null); // ensure the method is fully resolved
|
||||
resetFlags();
|
||||
// The monitorenter anchors. We expect the instrumentation set the flag before passing
|
||||
// the checkpoint.
|
||||
InstalledCode code = getCode(method);
|
||||
code.executeVarargs();
|
||||
Assert.assertFalse("expected lock was performed before checkpoint", lockAfterCheckPoint);
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void postponeLockSnippet() {
|
||||
ClassA a = new ClassA();
|
||||
|
||||
synchronized (a) {
|
||||
checkpoint = true;
|
||||
a.notInlinedMethod();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonEscapeLock() {
|
||||
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
|
||||
Class<?> clazz = instrumentor.instrument(LockInstrumentationTest.class, "postponeLockSnippet", Opcodes.MONITORENTER);
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "postponeLockSnippet");
|
||||
executeExpected(method, null); // ensure the method is fully resolved
|
||||
resetFlags();
|
||||
// The lock in the snippet will be relocated before the invocation to
|
||||
// notInlinedMethod(), i.e., after the checkpoint. We expect the instrumentation follows
|
||||
// and flag will be set to true.
|
||||
InstalledCode code = getCode(method);
|
||||
code.executeVarargs();
|
||||
Assert.assertTrue("expected lock was performed after checkpoint", lockAfterCheckPoint);
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Formatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.monitoring.runtime.instrumentation.common.com.google.common.base.Objects;
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.common.GraalOptions;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.debug.Debug;
|
||||
import org.graalvm.compiler.debug.Debug.Scope;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.options.OptionValue;
|
||||
import org.graalvm.compiler.options.OptionValue.OverrideScope;
|
||||
import org.graalvm.compiler.printer.IdealGraphPrinter;
|
||||
|
||||
import jdk.vm.ci.code.CodeCacheProvider;
|
||||
import jdk.vm.ci.code.InstalledCode;
|
||||
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public class RootNameDirectiveTest extends GraalCompilerTest {
|
||||
|
||||
public RootNameDirectiveTest() {
|
||||
HotSpotResolvedJavaMethod rootNameAtCalleeSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(RootNameDirectiveTest.class, "rootNameAtCalleeSnippet");
|
||||
rootNameAtCalleeSnippet.shouldBeInlined();
|
||||
|
||||
HotSpotResolvedJavaMethod rootNameWithinInstrumentationSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(RootNameDirectiveTest.class, "rootNameWithinInstrumentationSnippet");
|
||||
rootNameWithinInstrumentationSnippet.shouldBeInlined();
|
||||
}
|
||||
|
||||
private static String toString(ResolvedJavaMethod method) {
|
||||
return method.getDeclaringClass().toJavaName() + "." + method.getName() + method.getSignature().toMethodDescriptor();
|
||||
}
|
||||
|
||||
public static String rootNameSnippet() {
|
||||
return GraalDirectives.rootName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRootName() {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("rootNameSnippet");
|
||||
executeExpected(method, null); // ensure the method is fully resolved
|
||||
// The target snippet is already the root method. We expect the name of the target snippet
|
||||
// is returned.
|
||||
InstalledCode code = getCode(method);
|
||||
try {
|
||||
Result result = new Result(code.executeVarargs(), null);
|
||||
assertEquals(new Result(toString(method), null), result);
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String rootNameAtCalleeSnippet() {
|
||||
return GraalDirectives.rootName();
|
||||
}
|
||||
|
||||
public static String callerSnippet() {
|
||||
return rootNameAtCalleeSnippet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRootNameAtCallee() {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet");
|
||||
executeExpected(method, null); // ensure the method is fully resolved
|
||||
// The target snippet is the compilation root of rootNameAtCalleeSnippet() because the later
|
||||
// will be inlined. We expect the name of the target snippet is returned.
|
||||
InstalledCode code = getCode(method);
|
||||
try {
|
||||
Result result = new Result(code.executeVarargs(), null);
|
||||
assertEquals(new Result(toString(method), null), result);
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
static String rootNameInCallee;
|
||||
static String rootNameInCaller;
|
||||
|
||||
@BytecodeParserForceInline
|
||||
public static void rootNameWithinInstrumentationSnippet() {
|
||||
GraalDirectives.instrumentationBegin();
|
||||
rootNameInCallee = GraalDirectives.rootName();
|
||||
GraalDirectives.instrumentationEnd();
|
||||
}
|
||||
|
||||
public static void callerSnippet1() {
|
||||
rootNameWithinInstrumentationSnippet();
|
||||
|
||||
GraalDirectives.instrumentationBegin();
|
||||
rootNameInCaller = GraalDirectives.rootName();
|
||||
GraalDirectives.instrumentationEnd();
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
private void assertEquals(StructuredGraph graph, InstalledCode code, Object expected, Object actual) {
|
||||
if (!Objects.equal(expected, actual)) {
|
||||
Formatter buf = new Formatter();
|
||||
|
||||
try (Scope s = Debug.sandbox("PrintingGraph", null)) {
|
||||
Map<Object, Object> properties = new HashMap<>();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
IdealGraphPrinter printer = new IdealGraphPrinter(baos, true, getSnippetReflection());
|
||||
printer.beginGroup("RootNameDirectiveTest", "RootNameDirectiveTest", graph.method(), -1, null);
|
||||
properties.put("graph", graph.toString());
|
||||
properties.put("scope", Debug.currentScope());
|
||||
printer.print(graph, graph.method().format("%H.%n(%p)"), properties);
|
||||
printer.endGroup();
|
||||
printer.close();
|
||||
buf.format("-- Graph -- %n%s", baos.toString());
|
||||
} catch (Throwable e) {
|
||||
buf.format("%nError printing graph: %s", e);
|
||||
}
|
||||
try {
|
||||
CodeCacheProvider codeCache = getCodeCache();
|
||||
Method disassemble = codeCache.getClass().getMethod("disassemble", InstalledCode.class);
|
||||
buf.format("%n-- Code -- %n%s", disassemble.invoke(codeCache, code));
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Not a HotSpotCodeCacheProvider
|
||||
} catch (Exception e) {
|
||||
buf.format("%nError disassembling code: %s", e);
|
||||
}
|
||||
Assert.assertEquals(buf.toString(), expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
@Test
|
||||
public void testRootNameWithinInstrumentationAtCallee() {
|
||||
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet1");
|
||||
executeExpected(method, null); // ensure the method is fully resolved
|
||||
rootNameInCallee = null;
|
||||
rootNameInCaller = null;
|
||||
// We expect both rootName1 and rootName2 are set to the name of the target snippet.
|
||||
StructuredGraph graph = parseForCompile(method);
|
||||
InstalledCode code = getCode(method, graph);
|
||||
code.executeVarargs();
|
||||
assertEquals(graph, code, toString(method), rootNameInCallee);
|
||||
assertEquals(graph, code, rootNameInCallee, rootNameInCaller);
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,242 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.graalvm.compiler.test.ExportingClassLoader;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.ClassNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.IincInsnNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.InsnList;
|
||||
import jdk.internal.org.objectweb.asm.tree.JumpInsnNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.LabelNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.LineNumberNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.MethodNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
/**
|
||||
* The {@code TinyInstrumentor} is a bytecode instrumentor using ASM bytecode manipulation
|
||||
* framework. It injects given code snippet into a target method and creates a temporary class as
|
||||
* the container. Because the target method is cloned into the temporary class, it is required that
|
||||
* the target method is public static. Any referred method/field in the target method or the
|
||||
* instrumentation snippet should be made public as well.
|
||||
*/
|
||||
public class TinyInstrumentor implements Opcodes {
|
||||
|
||||
private InsnList instrumentationInstructions;
|
||||
private int instrumentationMaxLocal;
|
||||
|
||||
/**
|
||||
* Create a instrumentor with a instrumentation snippet. The snippet is specified with the given
|
||||
* class {@code instrumentationClass} and the given method name {@code methodName}.
|
||||
*/
|
||||
public TinyInstrumentor(Class<?> instrumentationClass, String methodName) throws IOException {
|
||||
MethodNode instrumentationMethod = getMethodNode(instrumentationClass, methodName);
|
||||
assert instrumentationMethod != null;
|
||||
assert (instrumentationMethod.access | ACC_STATIC) != 0;
|
||||
assert "()V".equals(instrumentationMethod.desc);
|
||||
instrumentationInstructions = cloneInstructions(instrumentationMethod.instructions);
|
||||
instrumentationMaxLocal = instrumentationMethod.maxLocals;
|
||||
// replace return instructions with a goto unless there is a single return at the end. In
|
||||
// that case, simply remove the return.
|
||||
List<AbstractInsnNode> returnInstructions = new ArrayList<>();
|
||||
for (AbstractInsnNode instruction : selectAll(instrumentationInstructions)) {
|
||||
if (instruction instanceof LineNumberNode) {
|
||||
instrumentationInstructions.remove(instruction);
|
||||
} else if (instruction.getOpcode() == RETURN) {
|
||||
returnInstructions.add(instruction);
|
||||
}
|
||||
}
|
||||
LabelNode exit = new LabelNode();
|
||||
if (returnInstructions.size() == 1) {
|
||||
AbstractInsnNode returnInstruction = returnInstructions.get(0);
|
||||
if (instrumentationInstructions.getLast() != returnInstruction) {
|
||||
instrumentationInstructions.insertBefore(returnInstruction, new JumpInsnNode(GOTO, exit));
|
||||
}
|
||||
instrumentationInstructions.remove(returnInstruction);
|
||||
} else {
|
||||
for (AbstractInsnNode returnInstruction : returnInstructions) {
|
||||
instrumentationInstructions.insertBefore(returnInstruction, new JumpInsnNode(GOTO, exit));
|
||||
instrumentationInstructions.remove(returnInstruction);
|
||||
}
|
||||
}
|
||||
instrumentationInstructions.add(exit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a {@link MethodNode} called {@code methodName} in the given class.
|
||||
*/
|
||||
private static MethodNode getMethodNode(Class<?> clazz, String methodName) throws IOException {
|
||||
ClassReader classReader = new ClassReader(clazz.getName());
|
||||
ClassNode classNode = new ClassNode();
|
||||
classReader.accept(classNode, ClassReader.SKIP_FRAMES);
|
||||
|
||||
for (MethodNode methodNode : classNode.methods) {
|
||||
if (methodNode.name.equals(methodName)) {
|
||||
return methodNode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ClassNode} with empty constructor.
|
||||
*/
|
||||
private static ClassNode emptyClass(String name) {
|
||||
ClassNode classNode = new ClassNode();
|
||||
classNode.visit(52, ACC_SUPER | ACC_PUBLIC, name.replace('.', '/'), null, "java/lang/Object", new String[]{});
|
||||
|
||||
MethodVisitor mv = classNode.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
Label l0 = new Label();
|
||||
mv.visitLabel(l0);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
Label l1 = new Label();
|
||||
mv.visitLabel(l1);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
|
||||
return classNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for iterating the given {@link InsnList}.
|
||||
*/
|
||||
private static Iterable<AbstractInsnNode> selectAll(InsnList instructions) {
|
||||
return new Iterable<AbstractInsnNode>() {
|
||||
@Override
|
||||
public Iterator<AbstractInsnNode> iterator() {
|
||||
return instructions.iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a clone of the given {@link InsnList}.
|
||||
*/
|
||||
private static InsnList cloneInstructions(InsnList instructions) {
|
||||
Map<LabelNode, LabelNode> labelMap = new HashMap<>();
|
||||
for (AbstractInsnNode instruction : selectAll(instructions)) {
|
||||
if (instruction instanceof LabelNode) {
|
||||
LabelNode clone = new LabelNode(new Label());
|
||||
LabelNode original = (LabelNode) instruction;
|
||||
labelMap.put(original, clone);
|
||||
}
|
||||
}
|
||||
InsnList clone = new InsnList();
|
||||
for (AbstractInsnNode insn : selectAll(instructions)) {
|
||||
clone.add(insn.clone(labelMap));
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts all local variable slot references by a specified amount.
|
||||
*/
|
||||
private static void shiftLocalSlots(InsnList instructions, int offset) {
|
||||
for (AbstractInsnNode insn : selectAll(instructions)) {
|
||||
if (insn instanceof VarInsnNode) {
|
||||
VarInsnNode varInsn = (VarInsnNode) insn;
|
||||
varInsn.var += offset;
|
||||
|
||||
} else if (insn instanceof IincInsnNode) {
|
||||
IincInsnNode iincInsn = (IincInsnNode) insn;
|
||||
iincInsn.var += offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instrument the target method specified by the class {@code targetClass} and the method name
|
||||
* {@code methodName}. For each occurrence of the {@code opcode}, the instrumentor injects a
|
||||
* copy of the instrumentation snippet.
|
||||
*/
|
||||
public Class<?> instrument(Class<?> targetClass, String methodName, int opcode) throws IOException, ClassNotFoundException {
|
||||
return instrument(targetClass, methodName, opcode, true);
|
||||
}
|
||||
|
||||
public Class<?> instrument(Class<?> targetClass, String methodName, int opcode, boolean insertAfter) throws IOException, ClassNotFoundException {
|
||||
// create a container class
|
||||
String className = targetClass.getName() + "$$" + methodName;
|
||||
ClassNode classNode = emptyClass(className);
|
||||
// duplicate the target method and add to the container class
|
||||
MethodNode methodNode = getMethodNode(targetClass, methodName);
|
||||
MethodNode newMethodNode = new MethodNode(methodNode.access, methodNode.name, methodNode.desc, methodNode.signature, methodNode.exceptions.toArray(new String[methodNode.exceptions.size()]));
|
||||
methodNode.accept(newMethodNode);
|
||||
classNode.methods.add(newMethodNode);
|
||||
// perform bytecode instrumentation
|
||||
for (AbstractInsnNode instruction : selectAll(newMethodNode.instructions)) {
|
||||
if (instruction.getOpcode() == opcode) {
|
||||
InsnList instrumentation = cloneInstructions(instrumentationInstructions);
|
||||
shiftLocalSlots(instrumentation, newMethodNode.maxLocals);
|
||||
newMethodNode.maxLocals += instrumentationMaxLocal;
|
||||
if (insertAfter) {
|
||||
newMethodNode.instructions.insert(instruction, instrumentation);
|
||||
} else {
|
||||
newMethodNode.instructions.insertBefore(instruction, instrumentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
// dump a byte array and load the class with a dedicated loader to separate the namespace
|
||||
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
classNode.accept(classWriter);
|
||||
byte[] bytes = classWriter.toByteArray();
|
||||
return new Loader(className, bytes).findClass(className);
|
||||
}
|
||||
|
||||
private static class Loader extends ExportingClassLoader {
|
||||
|
||||
private String className;
|
||||
private byte[] bytes;
|
||||
|
||||
Loader(String className, byte[] bytes) {
|
||||
super(TinyInstrumentor.class.getClassLoader());
|
||||
this.className = className;
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
if (name.equals(className)) {
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
} else {
|
||||
return super.findClass(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -22,8 +22,6 @@
|
||||
*/
|
||||
package org.graalvm.compiler.api.directives;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
// JaCoCo Exclude
|
||||
|
||||
/**
|
||||
@ -367,67 +365,4 @@ public final class GraalDirectives {
|
||||
*/
|
||||
public static void ensureVirtualizedHere(@SuppressWarnings("unused") Object object) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the beginning of an instrumentation boundary. The instrumentation code will be folded
|
||||
* during compilation and will not affect inlining heuristics regarding graph size except one on
|
||||
* compiled low-level graph size (e.g., {@code GraalOptions.SmallCompiledLowLevelGraphSize}).
|
||||
*/
|
||||
public static void instrumentationBegin() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the beginning of an instrumentation boundary and associates the instrumentation with
|
||||
* the preceding bytecode. If the instrumented instruction is {@code new}, then instrumentation
|
||||
* will adapt to optimizations concerning allocation, and only be executed if allocation really
|
||||
* happens.
|
||||
*
|
||||
* Example (the instrumentation is associated with {@code new}):
|
||||
*
|
||||
* <blockquote>
|
||||
*
|
||||
* <pre>
|
||||
* 0 new java.lang.Object
|
||||
* 3 invokestatic org.graalvm.compiler.api.directives.GraalDirectives.instrumentationBeginForPredecessor() : void
|
||||
* 6 invokestatic AllocationProfiler.countActualAllocation() : void
|
||||
* 9 invokestatic org.graalvm.compiler.api.directives.GraalDirectives.instrumentationEnd() : void
|
||||
* 12 invokespecial java.lang.Object()
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @see #instrumentationBegin()
|
||||
*/
|
||||
public static void instrumentationBeginForPredecessor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of the instrumentation boundary.
|
||||
*
|
||||
* @see #instrumentationBegin()
|
||||
*/
|
||||
public static void instrumentationEnd() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the enclosing method is inlined.
|
||||
*/
|
||||
public static boolean isMethodInlined() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
|
||||
/**
|
||||
* @return the name of the root method for the current compilation task. If the enclosing method
|
||||
* is inlined, it returns the name of the method into which it is inlined.
|
||||
*/
|
||||
public static String rootName() {
|
||||
return new String(rawRootName(), UTF8);
|
||||
}
|
||||
|
||||
public static byte[] rawRootName() {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -54,4 +54,13 @@ public @interface Snippet {
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface ConstantParameter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Denotes a snippet parameter that will bound to a non-null value during snippet template
|
||||
* instantiation.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface NonNullParameter {
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64Address;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
|
||||
|
@ -226,12 +226,12 @@ class TestProtectedAssembler extends AArch64Assembler {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
public void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
super.adds(size, dst, src1, src2, shiftType, imm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
public void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
super.subs(size, dst, src1, src2, shiftType, imm);
|
||||
}
|
||||
|
||||
@ -261,7 +261,7 @@ class TestProtectedAssembler extends AArch64Assembler {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
|
||||
public void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
|
||||
super.subs(size, dst, src1, src2, extendType, shiftAmt);
|
||||
}
|
||||
|
||||
@ -336,7 +336,7 @@ class TestProtectedAssembler extends AArch64Assembler {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void rbit(int size, Register dst, Register src) {
|
||||
public void rbit(int size, Register dst, Register src) {
|
||||
super.rbit(size, dst, src);
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ package org.graalvm.compiler.asm.aarch64;
|
||||
import static jdk.vm.ci.aarch64.AArch64.zr;
|
||||
|
||||
import org.graalvm.compiler.asm.AbstractAddress;
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64;
|
||||
@ -274,7 +274,7 @@ public final class AArch64Address extends AbstractAddress {
|
||||
/**
|
||||
* @return immediate in correct representation for the given addressing mode. For example in
|
||||
* case of <code>addressingMode ==IMMEDIATE_UNSCALED </code> the value will be returned
|
||||
* as the 9bit signed representation.
|
||||
* as the 9-bit signed representation.
|
||||
*/
|
||||
public int getImmediate() {
|
||||
switch (addressingMode) {
|
||||
@ -282,12 +282,15 @@ public final class AArch64Address extends AbstractAddress {
|
||||
case IMMEDIATE_POST_INDEXED:
|
||||
case IMMEDIATE_PRE_INDEXED:
|
||||
// 9-bit signed value
|
||||
assert NumUtil.isSignedNbit(9, immediate);
|
||||
return immediate & NumUtil.getNbitNumberInt(9);
|
||||
case IMMEDIATE_SCALED:
|
||||
// Unsigned value can be returned as-is.
|
||||
assert NumUtil.isUnsignedNbit(9, immediate);
|
||||
return immediate;
|
||||
case PC_LITERAL:
|
||||
// 21-bit signed value, but lower 2 bits are always 0 and are shifted out.
|
||||
assert NumUtil.isSignedNbit(19, immediate >> 2);
|
||||
return (immediate >> 2) & NumUtil.getNbitNumberInt(19);
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
|
||||
@ -356,4 +359,29 @@ public final class AArch64Address extends AbstractAddress {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an address into Register r.
|
||||
*
|
||||
* @param masm the macro assembler.
|
||||
* @param r general purpose register. May not be null.
|
||||
*/
|
||||
public void lea(AArch64MacroAssembler masm, Register r) {
|
||||
switch (addressingMode) {
|
||||
case IMMEDIATE_UNSCALED:
|
||||
if (immediate == 0 && base.equals(r)) { // it's a nop
|
||||
break;
|
||||
}
|
||||
masm.add(64, r, base, immediate);
|
||||
break;
|
||||
case REGISTER_OFFSET:
|
||||
masm.add(64, r, base, offset);
|
||||
break;
|
||||
case PC_LITERAL: {
|
||||
masm.mov(r, getImmediate());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ import static jdk.vm.ci.aarch64.AArch64.zr;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.graalvm.compiler.asm.Assembler;
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
|
||||
@ -347,6 +347,11 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
return reg.encoding << RnOffset;
|
||||
}
|
||||
|
||||
private static int maskField(int sizeInBits, int n) {
|
||||
assert NumUtil.isSignedNbit(sizeInBits, n);
|
||||
return n & NumUtil.getNbitNumberInt(sizeInBits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration of all different instruction kinds: General32/64 are the general instructions
|
||||
* (integer, branch, etc.), for 32-, respectively 64-bit operands. FP32/64 is the encoding for
|
||||
@ -448,7 +453,7 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
private static final int LoadStoreFpFlagOffset = 26;
|
||||
private static final int LoadLiteralImmeOffset = 5;
|
||||
|
||||
private static final int LoadStorePairOp = 0b101_0_010 << 23;
|
||||
private static final int LoadStorePairOp = 0b101_0 << 26;
|
||||
@SuppressWarnings("unused") private static final int LoadStorePairPostIndexOp = 0b101_0_001 << 23;
|
||||
@SuppressWarnings("unused") private static final int LoadStorePairPreIndexOp = 0b101_0_011 << 23;
|
||||
private static final int LoadStorePairImm7Offset = 15;
|
||||
@ -978,7 +983,9 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Load Pair of Registers calculates an address from a base register value and an immediate
|
||||
* offset, and stores two 32-bit words or two 64-bit doublewords to the calculated address, from
|
||||
* two registers.
|
||||
*/
|
||||
public void ldp(int size, Register rt, Register rt2, AArch64Address address) {
|
||||
assert size == 32 || size == 64;
|
||||
@ -996,10 +1003,18 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
}
|
||||
|
||||
private void loadStorePairInstruction(Instruction instr, Register rt, Register rt2, AArch64Address address, InstructionType type) {
|
||||
int memop = type.encoding | instr.encoding | address.getImmediate() << LoadStorePairImm7Offset | rt2(rt2) | rn(address.getBase()) | rt(rt);
|
||||
int scaledOffset = maskField(7, address.getImmediateRaw()); // LDP/STP use a 7-bit scaled
|
||||
// offset
|
||||
int memop = type.encoding | instr.encoding | scaledOffset << LoadStorePairImm7Offset | rt2(rt2) | rn(address.getBase()) | rt(rt);
|
||||
switch (address.getAddressingMode()) {
|
||||
case IMMEDIATE_UNSCALED:
|
||||
emitInt(memop | LoadStorePairOp);
|
||||
case IMMEDIATE_SCALED:
|
||||
emitInt(memop | LoadStorePairOp | (0b010 << 23));
|
||||
break;
|
||||
case IMMEDIATE_POST_INDEXED:
|
||||
emitInt(memop | LoadStorePairOp | (0b001 << 23));
|
||||
break;
|
||||
case IMMEDIATE_PRE_INDEXED:
|
||||
emitInt(memop | LoadStorePairOp | (0b011 << 23));
|
||||
break;
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode());
|
||||
@ -1471,7 +1486,7 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
* @param shiftType any type but ROR.
|
||||
* @param imm must be in range 0 to size - 1.
|
||||
*/
|
||||
protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
public void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
addSubShiftedInstruction(ADDS, dst, src1, src2, shiftType, imm, generalFromSize(size));
|
||||
}
|
||||
|
||||
@ -1499,7 +1514,7 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
* @param shiftType any type but ROR.
|
||||
* @param imm must be in range 0 to size - 1.
|
||||
*/
|
||||
protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
public void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
addSubShiftedInstruction(SUBS, dst, src1, src2, shiftType, imm, generalFromSize(size));
|
||||
}
|
||||
|
||||
@ -1571,7 +1586,7 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
* @param extendType defines how src2 is extended to the same size as src1.
|
||||
* @param shiftAmt must be in range 0 to 4.
|
||||
*/
|
||||
protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
|
||||
public void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
|
||||
assert !dst.equals(sp);
|
||||
assert !src1.equals(zr);
|
||||
assert !src2.equals(sp);
|
||||
@ -1786,7 +1801,7 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
* @param dst general purpose register. May not be null, zero-register or the stackpointer.
|
||||
* @param src source register. May not be null, zero-register or the stackpointer.
|
||||
*/
|
||||
protected void rbit(int size, Register dst, Register src) {
|
||||
public void rbit(int size, Register dst, Register src) {
|
||||
dataProcessing1SourceOp(RBIT, dst, src, generalFromSize(size));
|
||||
}
|
||||
|
||||
@ -1934,7 +1949,7 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
* @param src2 general purpose register. May not be null or the stackpointer.
|
||||
* @param src3 general purpose register. May not be null or the stackpointer.
|
||||
*/
|
||||
protected void smaddl(Register dst, Register src1, Register src2, Register src3) {
|
||||
public void smaddl(Register dst, Register src1, Register src2, Register src3) {
|
||||
assert !dst.equals(sp);
|
||||
assert !src1.equals(sp);
|
||||
assert !src2.equals(sp);
|
||||
|
@ -39,7 +39,7 @@ import static jdk.vm.ci.aarch64.AArch64.zr;
|
||||
|
||||
import org.graalvm.compiler.asm.AbstractAddress;
|
||||
import org.graalvm.compiler.asm.Label;
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64;
|
||||
@ -196,6 +196,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
break;
|
||||
case ADD_TO_INDEX:
|
||||
newIndex = allowOverwrite ? index : additionalReg;
|
||||
assert !newIndex.equals(sp) && !newIndex.equals(zr);
|
||||
if (plan.needsScratch) {
|
||||
mov(additionalReg, scaledDisplacement);
|
||||
add(signExtendIndex ? 32 : 64, newIndex, index, additionalReg);
|
||||
@ -206,6 +207,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
break;
|
||||
case ADD_TO_BASE:
|
||||
newBase = allowOverwrite ? base : additionalReg;
|
||||
assert !newBase.equals(sp) && !newBase.equals(zr);
|
||||
if (plan.needsScratch) {
|
||||
mov(additionalReg, displacement);
|
||||
add(64, newBase, base, additionalReg);
|
||||
@ -411,6 +413,19 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
assert !firstMove;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a 32-bit immediate move code sequence. The immediate may later be updated by
|
||||
* HotSpot.
|
||||
*
|
||||
* @param dst general purpose register. May not be null, stackpointer or zero-register.
|
||||
* @param imm
|
||||
*/
|
||||
public void movNarrowAddress(Register dst, long imm) {
|
||||
assert (imm & 0xFFFF_FFFF_0000_0000L) == 0;
|
||||
movz(64, dst, (int) (imm >>> 16), 16);
|
||||
movk(64, dst, (int) (imm & 0xffff), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of instructions necessary to load immediate into register.
|
||||
*/
|
||||
@ -455,6 +470,19 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a srcSize value from address into rt zero-extending it if necessary.
|
||||
*
|
||||
* @param srcSize size of memory read in bits. Must be 8, 16 or 32 and smaller or equal to
|
||||
* targetSize.
|
||||
* @param rt general purpose register. May not be null or stackpointer.
|
||||
* @param address all addressing modes allowed. May not be null.
|
||||
*/
|
||||
@Override
|
||||
public void ldr(int srcSize, Register rt, AArch64Address address) {
|
||||
super.ldr(srcSize, rt, address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditional move. dst = src1 if condition else src2.
|
||||
*
|
||||
@ -482,52 +510,47 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
* dst = src1 + src2.
|
||||
*
|
||||
* @param size register size. Has to be 32 or 64.
|
||||
* @param dst general purpose register. May not be null or stackpointer.
|
||||
* @param src1 general purpose register. May not be null or stackpointer.
|
||||
* @param dst general purpose register. May not be null.
|
||||
* @param src1 general purpose register. May not be null.
|
||||
* @param src2 general purpose register. May not be null or stackpointer.
|
||||
*/
|
||||
public void add(int size, Register dst, Register src1, Register src2) {
|
||||
super.add(size, dst, src1, src2, ShiftType.LSL, 0);
|
||||
if (dst.equals(sp) || src1.equals(sp)) {
|
||||
super.add(size, dst, src1, src2, ExtendType.UXTX, 0);
|
||||
} else {
|
||||
super.add(size, dst, src1, src2, ShiftType.LSL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dst = src1 + src2 and sets condition flags.
|
||||
*
|
||||
* @param size register size. Has to be 32 or 64.
|
||||
* @param dst general purpose register. May not be null or stackpointer.
|
||||
* @param src1 general purpose register. May not be null or stackpointer.
|
||||
* @param dst general purpose register. May not be null.
|
||||
* @param src1 general purpose register. May not be null.
|
||||
* @param src2 general purpose register. May not be null or stackpointer.
|
||||
*/
|
||||
public void adds(int size, Register dst, Register src1, Register src2) {
|
||||
super.adds(size, dst, src1, src2, getNopExtendType(size), 0);
|
||||
if (dst.equals(sp) || src1.equals(sp)) {
|
||||
super.adds(size, dst, src1, src2, ExtendType.UXTX, 0);
|
||||
} else {
|
||||
super.adds(size, dst, src1, src2, ShiftType.LSL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dst = src1 - src2 and sets condition flags.
|
||||
*
|
||||
* @param size register size. Has to be 32 or 64.
|
||||
* @param dst general purpose register. May not be null or stackpointer.
|
||||
* @param src1 general purpose register. May not be null or stackpointer.
|
||||
* @param dst general purpose register. May not be null.
|
||||
* @param src1 general purpose register. May not be null.
|
||||
* @param src2 general purpose register. May not be null or stackpointer.
|
||||
*/
|
||||
public void subs(int size, Register dst, Register src1, Register src2) {
|
||||
super.subs(size, dst, src1, src2, getNopExtendType(size), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ExtendType for the given size that corresponds to a no-op.
|
||||
*
|
||||
* I.e. when doing add X0, X1, X2, the actual instruction has the form add X0, X1, X2 UXTX.
|
||||
*
|
||||
* @param size
|
||||
*/
|
||||
private static ExtendType getNopExtendType(int size) {
|
||||
if (size == 64) {
|
||||
return ExtendType.UXTX;
|
||||
} else if (size == 32) {
|
||||
return ExtendType.UXTW;
|
||||
if (dst.equals(sp) || src1.equals(sp)) {
|
||||
super.subs(size, dst, src1, src2, ExtendType.UXTX, 0);
|
||||
} else {
|
||||
throw GraalError.shouldNotReachHere("No-op ");
|
||||
super.subs(size, dst, src1, src2, ShiftType.LSL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -535,12 +558,16 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
* dst = src1 - src2.
|
||||
*
|
||||
* @param size register size. Has to be 32 or 64.
|
||||
* @param dst general purpose register. May not be null or stackpointer.
|
||||
* @param src1 general purpose register. May not be null or stackpointer.
|
||||
* @param dst general purpose register. May not be null.
|
||||
* @param src1 general purpose register. May not be null.
|
||||
* @param src2 general purpose register. May not be null or stackpointer.
|
||||
*/
|
||||
public void sub(int size, Register dst, Register src1, Register src2) {
|
||||
super.sub(size, dst, src1, src2, ShiftType.LSL, 0);
|
||||
if (dst.equals(sp) || src1.equals(sp)) {
|
||||
super.sub(size, dst, src1, src2, ExtendType.UXTX, 0);
|
||||
} else {
|
||||
super.sub(size, dst, src1, src2, ShiftType.LSL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -590,16 +617,26 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
* dst = src + immediate.
|
||||
*
|
||||
* @param size register size. Has to be 32 or 64.
|
||||
* @param dst general purpose register. May not be null or stackpointer.
|
||||
* @param src general purpose register. May not be null or stackpointer.
|
||||
* @param immediate arithmetic immediate
|
||||
* @param dst general purpose register. May not be null or zero-register.
|
||||
* @param src general purpose register. May not be null or zero-register.
|
||||
* @param immediate 32-bit signed int
|
||||
*/
|
||||
@Override
|
||||
public void add(int size, Register dst, Register src, int immediate) {
|
||||
assert (!dst.equals(zr) && !src.equals(zr));
|
||||
if (immediate < 0) {
|
||||
sub(size, dst, src, -immediate);
|
||||
} else if (!(dst.equals(src) && immediate == 0)) {
|
||||
super.add(size, dst, src, immediate);
|
||||
} else if (isAimm(immediate)) {
|
||||
if (!(dst.equals(src) && immediate == 0)) {
|
||||
super.add(size, dst, src, immediate);
|
||||
}
|
||||
} else if (immediate >= -(1 << 24) && immediate < (1 << 24)) {
|
||||
super.add(size, dst, src, immediate & -(1 << 12));
|
||||
super.add(size, dst, dst, immediate & ((1 << 12) - 1));
|
||||
} else {
|
||||
assert !dst.equals(src);
|
||||
mov(dst, immediate);
|
||||
add(size, src, dst, dst);
|
||||
}
|
||||
}
|
||||
|
||||
@ -613,6 +650,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
*/
|
||||
@Override
|
||||
public void adds(int size, Register dst, Register src, int immediate) {
|
||||
assert (!dst.equals(sp) && !src.equals(zr));
|
||||
if (immediate < 0) {
|
||||
subs(size, dst, src, -immediate);
|
||||
} else if (!(dst.equals(src) && immediate == 0)) {
|
||||
@ -624,16 +662,26 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
* dst = src - immediate.
|
||||
*
|
||||
* @param size register size. Has to be 32 or 64.
|
||||
* @param dst general purpose register. May not be null or stackpointer.
|
||||
* @param src general purpose register. May not be null or stackpointer.
|
||||
* @param immediate arithmetic immediate
|
||||
* @param dst general purpose register. May not be null or zero-register.
|
||||
* @param src general purpose register. May not be null or zero-register.
|
||||
* @param immediate 32-bit signed int
|
||||
*/
|
||||
@Override
|
||||
public void sub(int size, Register dst, Register src, int immediate) {
|
||||
assert (!dst.equals(zr) && !src.equals(zr));
|
||||
if (immediate < 0) {
|
||||
add(size, dst, src, -immediate);
|
||||
} else if (!dst.equals(src) || immediate != 0) {
|
||||
super.sub(size, dst, src, immediate);
|
||||
} else if (isAimm(immediate)) {
|
||||
if (!(dst.equals(src) && immediate == 0)) {
|
||||
super.sub(size, dst, src, immediate);
|
||||
}
|
||||
} else if (immediate >= -(1 << 24) && immediate < (1 << 24)) {
|
||||
super.sub(size, dst, src, immediate & -(1 << 12));
|
||||
super.sub(size, dst, dst, immediate & ((1 << 12) - 1));
|
||||
} else {
|
||||
assert !dst.equals(src);
|
||||
mov(dst, immediate);
|
||||
sub(size, src, dst, dst);
|
||||
}
|
||||
}
|
||||
|
||||
@ -647,10 +695,11 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
*/
|
||||
@Override
|
||||
public void subs(int size, Register dst, Register src, int immediate) {
|
||||
assert (!dst.equals(sp) && !src.equals(zr));
|
||||
if (immediate < 0) {
|
||||
adds(size, dst, src, -immediate);
|
||||
} else if (!dst.equals(src) || immediate != 0) {
|
||||
super.sub(size, dst, src, immediate);
|
||||
super.subs(size, dst, src, immediate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -675,6 +724,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
* @param src2 general purpose register. May not be null or the stackpointer.
|
||||
*/
|
||||
public void umulh(int size, Register dst, Register src1, Register src2) {
|
||||
assert (!dst.equals(sp) && !src1.equals(sp) && !src2.equals(sp));
|
||||
assert size == 32 || size == 64;
|
||||
if (size == 64) {
|
||||
super.umulh(dst, src1, src2);
|
||||
@ -695,6 +745,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
* @param src2 general purpose register. May not be null or the stackpointer.
|
||||
*/
|
||||
public void smulh(int size, Register dst, Register src1, Register src2) {
|
||||
assert (!dst.equals(sp) && !src1.equals(sp) && !src2.equals(sp));
|
||||
assert size == 32 || size == 64;
|
||||
if (size == 64) {
|
||||
super.smulh(dst, src1, src2);
|
||||
@ -715,6 +766,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
* @param d denominator. General purpose register. Divisor May not be null or the stackpointer.
|
||||
*/
|
||||
public void rem(int size, Register dst, Register n, Register d) {
|
||||
assert (!dst.equals(sp) && !n.equals(sp) && !d.equals(sp));
|
||||
// There is no irem or similar instruction. Instead we use the relation:
|
||||
// n % d = n - Floor(n / d) * d if nd >= 0
|
||||
// n % d = n - Ceil(n / d) * d else
|
||||
@ -940,16 +992,14 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
/**
|
||||
* Sign-extend value from src into dst.
|
||||
*
|
||||
* @param destSize destination register size. Has to be 32 or 64.
|
||||
* @param srcSize source register size. May be 8, 16 or 32 and smaller than destSize.
|
||||
* @param destSize destination register size. Must be 32 or 64.
|
||||
* @param srcSize source register size. Must be smaller than destSize.
|
||||
* @param dst general purpose register. May not be null, stackpointer or zero-register.
|
||||
* @param src general purpose register. May not be null, stackpointer or zero-register.
|
||||
*/
|
||||
public void sxt(int destSize, int srcSize, Register dst, Register src) {
|
||||
assert (destSize == 32 || destSize == 64) && srcSize < destSize;
|
||||
assert srcSize == 8 || srcSize == 16 || srcSize == 32;
|
||||
int[] srcSizeValues = {7, 15, 31};
|
||||
super.sbfm(destSize, dst, src, 0, srcSizeValues[NumUtil.log2Ceil(srcSize / 8)]);
|
||||
assert (srcSize < destSize && srcSize > 0);
|
||||
super.sbfm(destSize, dst, src, 0, srcSize - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1078,6 +1128,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
* @param y general purpose register. May not be null or stackpointer.
|
||||
*/
|
||||
public void cmp(int size, Register x, Register y) {
|
||||
assert size == 32 || size == 64;
|
||||
super.subs(size, zr, x, y, ShiftType.LSL, 0);
|
||||
}
|
||||
|
||||
@ -1089,6 +1140,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
* @param y comparison immediate, {@link #isComparisonImmediate(long)} has to be true for it.
|
||||
*/
|
||||
public void cmp(int size, Register x, int y) {
|
||||
assert size == 32 || size == 64;
|
||||
if (y < 0) {
|
||||
super.adds(size, zr, x, -y);
|
||||
} else {
|
||||
@ -1108,6 +1160,54 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
super.ands(size, dst, x, y, ShiftType.LSL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets overflow flag according to result of x * y.
|
||||
*
|
||||
* @param size register size. Has to be 32 or 64.
|
||||
* @param dst general purpose register. May not be null or stack-pointer.
|
||||
* @param x general purpose register. May not be null or stackpointer.
|
||||
* @param y general purpose register. May not be null or stackpointer.
|
||||
*/
|
||||
public void mulvs(int size, Register dst, Register x, Register y) {
|
||||
try (ScratchRegister sc1 = getScratchRegister();
|
||||
ScratchRegister sc2 = getScratchRegister()) {
|
||||
switch (size) {
|
||||
case 64: {
|
||||
// Be careful with registers: it's possible that x, y, and dst are the same
|
||||
// register.
|
||||
Register rscratch1 = sc1.getRegister();
|
||||
Register rscratch2 = sc2.getRegister();
|
||||
mul(64, rscratch1, x, y); // Result bits 0..63
|
||||
smulh(64, rscratch2, x, y); // Result bits 64..127
|
||||
// Top is pure sign ext
|
||||
subs(64, zr, rscratch2, rscratch1, ShiftType.ASR, 63);
|
||||
// Copy all 64 bits of the result into dst
|
||||
mov(64, dst, rscratch1);
|
||||
mov(rscratch1, 0x80000000);
|
||||
// Develop 0 (EQ), or 0x80000000 (NE)
|
||||
cmov(32, rscratch1, rscratch1, zr, ConditionFlag.NE);
|
||||
cmp(32, rscratch1, 1);
|
||||
// 0x80000000 - 1 => VS
|
||||
break;
|
||||
}
|
||||
case 32: {
|
||||
Register rscratch1 = sc1.getRegister();
|
||||
smaddl(rscratch1, x, y, zr);
|
||||
// Copy the low 32 bits of the result into dst
|
||||
mov(32, dst, rscratch1);
|
||||
subs(64, zr, rscratch1, rscratch1, ExtendType.SXTW, 0);
|
||||
// NE => overflow
|
||||
mov(rscratch1, 0x80000000);
|
||||
// Develop 0 (EQ), or 0x80000000 (NE)
|
||||
cmov(32, rscratch1, rscratch1, zr, ConditionFlag.NE);
|
||||
cmp(32, rscratch1, 1);
|
||||
// 0x80000000 - 1 => VS
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When patching up Labels we have to know what kind of code to generate.
|
||||
*/
|
||||
@ -1353,7 +1453,8 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
super.b(branchOffset, branch);
|
||||
break;
|
||||
case JUMP_ADDRESS:
|
||||
emitInt(jumpTarget, branch);
|
||||
int offset = instruction >>> PatchLabelKind.INFORMATION_OFFSET;
|
||||
emitInt(jumpTarget - offset, branch);
|
||||
break;
|
||||
case BRANCH_NONZERO:
|
||||
case BRANCH_ZERO: {
|
||||
@ -1404,4 +1505,14 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
public AbstractAddress getPlaceholder(int instructionStartPosition) {
|
||||
return AArch64Address.PLACEHOLDER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an address into Register d.
|
||||
*
|
||||
* @param d general purpose register. May not be null.
|
||||
* @param a AArch64Address the address of an operand.
|
||||
*/
|
||||
public void lea(Register d, AArch64Address a) {
|
||||
a.lea(this, d);
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,18 @@ public final class AMD64Address extends AbstractAddress {
|
||||
this(base, Register.None, Scale.Times1, displacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AMD64Address} with given base and index registers, scaling and 0
|
||||
* displacement.
|
||||
*
|
||||
* @param base the base register
|
||||
* @param index the index register
|
||||
* @param scale the scaling factor
|
||||
*/
|
||||
public AMD64Address(Register base, Register index, Scale scale) {
|
||||
this(base, index, scale, 0, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AMD64Address} with given base and index registers, scaling and
|
||||
* displacement. This is the most general constructor.
|
||||
|
@ -22,10 +22,10 @@
|
||||
*/
|
||||
package org.graalvm.compiler.asm.amd64;
|
||||
|
||||
import static org.graalvm.compiler.asm.NumUtil.isByte;
|
||||
import static org.graalvm.compiler.asm.NumUtil.isInt;
|
||||
import static org.graalvm.compiler.asm.NumUtil.isShiftCount;
|
||||
import static org.graalvm.compiler.asm.NumUtil.isUByte;
|
||||
import static org.graalvm.compiler.core.common.NumUtil.isByte;
|
||||
import static org.graalvm.compiler.core.common.NumUtil.isInt;
|
||||
import static org.graalvm.compiler.core.common.NumUtil.isShiftCount;
|
||||
import static org.graalvm.compiler.core.common.NumUtil.isUByte;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseAddressNop;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseNormalNop;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
|
||||
@ -58,7 +58,7 @@ import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
|
||||
|
||||
import org.graalvm.compiler.asm.Assembler;
|
||||
import org.graalvm.compiler.asm.Label;
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
@ -2494,6 +2494,24 @@ public class AMD64Assembler extends Assembler {
|
||||
emitByte(0xC0 | encode);
|
||||
}
|
||||
|
||||
void pcmpestri(Register dst, AMD64Address src, int imm8) {
|
||||
assert supports(CPUFeature.SSE4_2);
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
|
||||
simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_3A, attributes);
|
||||
emitByte(0x61);
|
||||
emitOperandHelper(dst, src, 0);
|
||||
emitByte(imm8);
|
||||
}
|
||||
|
||||
void pcmpestri(Register dst, Register src, int imm8) {
|
||||
assert supports(CPUFeature.SSE4_2);
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
|
||||
int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_3A, attributes);
|
||||
emitByte(0x61);
|
||||
emitByte(0xC0 | encode);
|
||||
emitByte(imm8);
|
||||
}
|
||||
|
||||
public final void push(Register src) {
|
||||
int encode = prefixAndEncode(src.encoding);
|
||||
emitByte(0x50 | encode);
|
||||
@ -2633,6 +2651,16 @@ public class AMD64Assembler extends Assembler {
|
||||
emitByte(imm8);
|
||||
}
|
||||
|
||||
public final void psrldq(Register dst, int imm8) {
|
||||
assert isUByte(imm8) : "invalid value";
|
||||
assert dst.getRegisterCategory().equals(AMD64.XMM);
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
|
||||
int encode = simdPrefixAndEncode(AMD64.xmm3, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
|
||||
emitByte(0x73);
|
||||
emitByte(0xC0 | encode);
|
||||
emitByte(imm8);
|
||||
}
|
||||
|
||||
public final void pshufd(Register dst, Register src, int imm8) {
|
||||
assert isUByte(imm8) : "invalid value";
|
||||
assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
|
||||
@ -3322,6 +3350,13 @@ public class AMD64Assembler extends Assembler {
|
||||
}
|
||||
}
|
||||
|
||||
public final void movdl(Register dst, AMD64Address src) {
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
|
||||
simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
|
||||
emitByte(0x6E);
|
||||
emitOperandHelper(dst, src, 0);
|
||||
}
|
||||
|
||||
public final void movddup(Register dst, Register src) {
|
||||
assert supports(CPUFeature.SSE3);
|
||||
assert dst.getRegisterCategory().equals(AMD64.XMM);
|
||||
|
@ -22,11 +22,17 @@
|
||||
*/
|
||||
package org.graalvm.compiler.asm.amd64;
|
||||
|
||||
import static jdk.vm.ci.amd64.AMD64.rax;
|
||||
import static jdk.vm.ci.amd64.AMD64.rcx;
|
||||
import static jdk.vm.ci.amd64.AMD64.rdx;
|
||||
import static jdk.vm.ci.amd64.AMD64.rsp;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseIncDec;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmLoadAndClearUpper;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmRegToRegMoveAll;
|
||||
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.asm.Label;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
import jdk.vm.ci.amd64.AMD64Kind;
|
||||
@ -138,6 +144,10 @@ public class AMD64MacroAssembler extends AMD64Assembler {
|
||||
cmpq(src1, src2);
|
||||
}
|
||||
|
||||
public final void decrementl(Register reg) {
|
||||
decrementl(reg, 1);
|
||||
}
|
||||
|
||||
public final void decrementl(Register reg, int value) {
|
||||
if (value == Integer.MIN_VALUE) {
|
||||
subl(reg, value);
|
||||
@ -321,4 +331,434 @@ public class AMD64MacroAssembler extends AMD64Assembler {
|
||||
movdbl(dest, tmp);
|
||||
addq(AMD64.rsp, AMD64Kind.DOUBLE.getSizeInBytes());
|
||||
}
|
||||
|
||||
// IndexOf for constant substrings with size >= 8 chars
|
||||
// which don't need to be loaded through stack.
|
||||
public void stringIndexofC8(Register str1, Register str2,
|
||||
Register cnt1, Register cnt2,
|
||||
int intCnt2, Register result,
|
||||
Register vec, Register tmp) {
|
||||
// assert(UseSSE42Intrinsics, "SSE4.2 is required");
|
||||
|
||||
// This method uses pcmpestri inxtruction with bound registers
|
||||
// inputs:
|
||||
// xmm - substring
|
||||
// rax - substring length (elements count)
|
||||
// mem - scanned string
|
||||
// rdx - string length (elements count)
|
||||
// 0xd - mode: 1100 (substring search) + 01 (unsigned shorts)
|
||||
// outputs:
|
||||
// rcx - matched index in string
|
||||
assert cnt1.equals(rdx) && cnt2.equals(rax) && tmp.equals(rcx) : "pcmpestri";
|
||||
|
||||
Label reloadSubstr = new Label();
|
||||
Label scanToSubstr = new Label();
|
||||
Label scanSubstr = new Label();
|
||||
Label retFound = new Label();
|
||||
Label retNotFound = new Label();
|
||||
Label exit = new Label();
|
||||
Label foundSubstr = new Label();
|
||||
Label matchSubstrHead = new Label();
|
||||
Label reloadStr = new Label();
|
||||
Label foundCandidate = new Label();
|
||||
|
||||
// Note, inline_string_indexOf() generates checks:
|
||||
// if (substr.count > string.count) return -1;
|
||||
// if (substr.count == 0) return 0;
|
||||
assert intCnt2 >= 8 : "this code isused only for cnt2 >= 8 chars";
|
||||
|
||||
// Load substring.
|
||||
movdqu(vec, new AMD64Address(str2, 0));
|
||||
movl(cnt2, intCnt2);
|
||||
movq(result, str1); // string addr
|
||||
|
||||
if (intCnt2 > 8) {
|
||||
jmpb(scanToSubstr);
|
||||
|
||||
// Reload substr for rescan, this code
|
||||
// is executed only for large substrings (> 8 chars)
|
||||
bind(reloadSubstr);
|
||||
movdqu(vec, new AMD64Address(str2, 0));
|
||||
negq(cnt2); // Jumped here with negative cnt2, convert to positive
|
||||
|
||||
bind(reloadStr);
|
||||
// We came here after the beginning of the substring was
|
||||
// matched but the rest of it was not so we need to search
|
||||
// again. Start from the next element after the previous match.
|
||||
|
||||
// cnt2 is number of substring reminding elements and
|
||||
// cnt1 is number of string reminding elements when cmp failed.
|
||||
// Restored cnt1 = cnt1 - cnt2 + int_cnt2
|
||||
subl(cnt1, cnt2);
|
||||
addl(cnt1, intCnt2);
|
||||
movl(cnt2, intCnt2); // Now restore cnt2
|
||||
|
||||
decrementl(cnt1, 1); // Shift to next element
|
||||
cmpl(cnt1, cnt2);
|
||||
jccb(ConditionFlag.Negative, retNotFound); // Left less then substring
|
||||
|
||||
addq(result, 2);
|
||||
|
||||
} // (int_cnt2 > 8)
|
||||
|
||||
// Scan string for start of substr in 16-byte vectors
|
||||
bind(scanToSubstr);
|
||||
pcmpestri(vec, new AMD64Address(result, 0), 0x0d);
|
||||
jccb(ConditionFlag.Below, foundCandidate); // CF == 1
|
||||
subl(cnt1, 8);
|
||||
jccb(ConditionFlag.LessEqual, retNotFound); // Scanned full string
|
||||
cmpl(cnt1, cnt2);
|
||||
jccb(ConditionFlag.Negative, retNotFound); // Left less then substring
|
||||
addq(result, 16);
|
||||
jmpb(scanToSubstr);
|
||||
|
||||
// Found a potential substr
|
||||
bind(foundCandidate);
|
||||
// Matched whole vector if first element matched (tmp(rcx) == 0).
|
||||
if (intCnt2 == 8) {
|
||||
jccb(ConditionFlag.Overflow, retFound); // OF == 1
|
||||
} else { // int_cnt2 > 8
|
||||
jccb(ConditionFlag.Overflow, foundSubstr);
|
||||
}
|
||||
// After pcmpestri tmp(rcx) contains matched element index
|
||||
// Compute start addr of substr
|
||||
leaq(result, new AMD64Address(result, tmp, Scale.Times2, 0));
|
||||
|
||||
// Make sure string is still long enough
|
||||
subl(cnt1, tmp);
|
||||
cmpl(cnt1, cnt2);
|
||||
if (intCnt2 == 8) {
|
||||
jccb(ConditionFlag.GreaterEqual, scanToSubstr);
|
||||
} else { // int_cnt2 > 8
|
||||
jccb(ConditionFlag.GreaterEqual, matchSubstrHead);
|
||||
}
|
||||
// Left less then substring.
|
||||
|
||||
bind(retNotFound);
|
||||
movl(result, -1);
|
||||
jmpb(exit);
|
||||
|
||||
if (intCnt2 > 8) {
|
||||
// This code is optimized for the case when whole substring
|
||||
// is matched if its head is matched.
|
||||
bind(matchSubstrHead);
|
||||
pcmpestri(vec, new AMD64Address(result, 0), 0x0d);
|
||||
// Reload only string if does not match
|
||||
jccb(ConditionFlag.NoOverflow, reloadStr); // OF == 0
|
||||
|
||||
Label contScanSubstr = new Label();
|
||||
// Compare the rest of substring (> 8 chars).
|
||||
bind(foundSubstr);
|
||||
// First 8 chars are already matched.
|
||||
negq(cnt2);
|
||||
addq(cnt2, 8);
|
||||
|
||||
bind(scanSubstr);
|
||||
subl(cnt1, 8);
|
||||
cmpl(cnt2, -8); // Do not read beyond substring
|
||||
jccb(ConditionFlag.LessEqual, contScanSubstr);
|
||||
// Back-up strings to avoid reading beyond substring:
|
||||
// cnt1 = cnt1 - cnt2 + 8
|
||||
addl(cnt1, cnt2); // cnt2 is negative
|
||||
addl(cnt1, 8);
|
||||
movl(cnt2, 8);
|
||||
negq(cnt2);
|
||||
bind(contScanSubstr);
|
||||
if (intCnt2 < 1024 * 1024 * 1024) {
|
||||
movdqu(vec, new AMD64Address(str2, cnt2, Scale.Times2, intCnt2 * 2));
|
||||
pcmpestri(vec, new AMD64Address(result, cnt2, Scale.Times2, intCnt2 * 2), 0x0d);
|
||||
} else {
|
||||
// calculate index in register to avoid integer overflow (int_cnt2*2)
|
||||
movl(tmp, intCnt2);
|
||||
addq(tmp, cnt2);
|
||||
movdqu(vec, new AMD64Address(str2, tmp, Scale.Times2, 0));
|
||||
pcmpestri(vec, new AMD64Address(result, tmp, Scale.Times2, 0), 0x0d);
|
||||
}
|
||||
// Need to reload strings pointers if not matched whole vector
|
||||
jcc(ConditionFlag.NoOverflow, reloadSubstr); // OF == 0
|
||||
addq(cnt2, 8);
|
||||
jcc(ConditionFlag.Negative, scanSubstr);
|
||||
// Fall through if found full substring
|
||||
|
||||
} // (int_cnt2 > 8)
|
||||
|
||||
bind(retFound);
|
||||
// Found result if we matched full small substring.
|
||||
// Compute substr offset
|
||||
subq(result, str1);
|
||||
shrl(result, 1); // index
|
||||
bind(exit);
|
||||
|
||||
} // string_indexofC8
|
||||
|
||||
// Small strings are loaded through stack if they cross page boundary.
|
||||
public void stringIndexOf(Register str1, Register str2,
|
||||
Register cnt1, Register cnt2,
|
||||
int intCnt2, Register result,
|
||||
Register vec, Register tmp, int vmPageSize) {
|
||||
//
|
||||
// int_cnt2 is length of small (< 8 chars) constant substring
|
||||
// or (-1) for non constant substring in which case its length
|
||||
// is in cnt2 register.
|
||||
//
|
||||
// Note, inline_string_indexOf() generates checks:
|
||||
// if (substr.count > string.count) return -1;
|
||||
// if (substr.count == 0) return 0;
|
||||
//
|
||||
assert intCnt2 == -1 || (0 < intCnt2 && intCnt2 < 8) : "should be != 0";
|
||||
|
||||
// This method uses pcmpestri instruction with bound registers
|
||||
// inputs:
|
||||
// xmm - substring
|
||||
// rax - substring length (elements count)
|
||||
// mem - scanned string
|
||||
// rdx - string length (elements count)
|
||||
// 0xd - mode: 1100 (substring search) + 01 (unsigned shorts)
|
||||
// outputs:
|
||||
// rcx - matched index in string
|
||||
assert cnt1.equals(rdx) && cnt2.equals(rax) && tmp.equals(rcx) : "pcmpestri";
|
||||
|
||||
Label reloadSubstr = new Label();
|
||||
Label scanToSubstr = new Label();
|
||||
Label scanSubstr = new Label();
|
||||
Label adjustStr = new Label();
|
||||
Label retFound = new Label();
|
||||
Label retNotFound = new Label();
|
||||
Label cleanup = new Label();
|
||||
Label foundSubstr = new Label();
|
||||
Label foundCandidate = new Label();
|
||||
|
||||
int wordSize = 8;
|
||||
// We don't know where these strings are located
|
||||
// and we can't read beyond them. Load them through stack.
|
||||
Label bigStrings = new Label();
|
||||
Label checkStr = new Label();
|
||||
Label copySubstr = new Label();
|
||||
Label copyStr = new Label();
|
||||
|
||||
movq(tmp, rsp); // save old SP
|
||||
|
||||
if (intCnt2 > 0) { // small (< 8 chars) constant substring
|
||||
if (intCnt2 == 1) { // One char
|
||||
movzwl(result, new AMD64Address(str2, 0));
|
||||
movdl(vec, result); // move 32 bits
|
||||
} else if (intCnt2 == 2) { // Two chars
|
||||
movdl(vec, new AMD64Address(str2, 0)); // move 32 bits
|
||||
} else if (intCnt2 == 4) { // Four chars
|
||||
movq(vec, new AMD64Address(str2, 0)); // move 64 bits
|
||||
} else { // cnt2 = { 3, 5, 6, 7 }
|
||||
// Array header size is 12 bytes in 32-bit VM
|
||||
// + 6 bytes for 3 chars == 18 bytes,
|
||||
// enough space to load vec and shift.
|
||||
movdqu(vec, new AMD64Address(str2, (intCnt2 * 2) - 16));
|
||||
psrldq(vec, 16 - (intCnt2 * 2));
|
||||
}
|
||||
} else { // not constant substring
|
||||
cmpl(cnt2, 8);
|
||||
jccb(ConditionFlag.AboveEqual, bigStrings); // Both strings are big enough
|
||||
|
||||
// We can read beyond string if str+16 does not cross page boundary
|
||||
// since heaps are aligned and mapped by pages.
|
||||
assert vmPageSize < 1024 * 1024 * 1024 : "default page should be small";
|
||||
movl(result, str2); // We need only low 32 bits
|
||||
andl(result, (vmPageSize - 1));
|
||||
cmpl(result, (vmPageSize - 16));
|
||||
jccb(ConditionFlag.BelowEqual, checkStr);
|
||||
|
||||
// Move small strings to stack to allow load 16 bytes into vec.
|
||||
subq(rsp, 16);
|
||||
int stackOffset = wordSize - 2;
|
||||
push(cnt2);
|
||||
|
||||
bind(copySubstr);
|
||||
movzwl(result, new AMD64Address(str2, cnt2, Scale.Times2, -2));
|
||||
movw(new AMD64Address(rsp, cnt2, Scale.Times2, stackOffset), result);
|
||||
decrementl(cnt2, 1);
|
||||
jccb(ConditionFlag.NotZero, copySubstr);
|
||||
|
||||
pop(cnt2);
|
||||
movq(str2, rsp); // New substring address
|
||||
} // non constant
|
||||
|
||||
bind(checkStr);
|
||||
cmpl(cnt1, 8);
|
||||
jccb(ConditionFlag.AboveEqual, bigStrings);
|
||||
|
||||
// Check cross page boundary.
|
||||
movl(result, str1); // We need only low 32 bits
|
||||
andl(result, (vmPageSize - 1));
|
||||
cmpl(result, (vmPageSize - 16));
|
||||
jccb(ConditionFlag.BelowEqual, bigStrings);
|
||||
|
||||
subq(rsp, 16);
|
||||
int stackOffset = -2;
|
||||
if (intCnt2 < 0) { // not constant
|
||||
push(cnt2);
|
||||
stackOffset += wordSize;
|
||||
}
|
||||
movl(cnt2, cnt1);
|
||||
|
||||
bind(copyStr);
|
||||
movzwl(result, new AMD64Address(str1, cnt2, Scale.Times2, -2));
|
||||
movw(new AMD64Address(rsp, cnt2, Scale.Times2, stackOffset), result);
|
||||
decrementl(cnt2, 1);
|
||||
jccb(ConditionFlag.NotZero, copyStr);
|
||||
|
||||
if (intCnt2 < 0) { // not constant
|
||||
pop(cnt2);
|
||||
}
|
||||
movq(str1, rsp); // New string address
|
||||
|
||||
bind(bigStrings);
|
||||
// Load substring.
|
||||
if (intCnt2 < 0) { // -1
|
||||
movdqu(vec, new AMD64Address(str2, 0));
|
||||
push(cnt2); // substr count
|
||||
push(str2); // substr addr
|
||||
push(str1); // string addr
|
||||
} else {
|
||||
// Small (< 8 chars) constant substrings are loaded already.
|
||||
movl(cnt2, intCnt2);
|
||||
}
|
||||
push(tmp); // original SP
|
||||
// Finished loading
|
||||
|
||||
// ========================================================
|
||||
// Start search
|
||||
//
|
||||
|
||||
movq(result, str1); // string addr
|
||||
|
||||
if (intCnt2 < 0) { // Only for non constant substring
|
||||
jmpb(scanToSubstr);
|
||||
|
||||
// SP saved at sp+0
|
||||
// String saved at sp+1*wordSize
|
||||
// Substr saved at sp+2*wordSize
|
||||
// Substr count saved at sp+3*wordSize
|
||||
|
||||
// Reload substr for rescan, this code
|
||||
// is executed only for large substrings (> 8 chars)
|
||||
bind(reloadSubstr);
|
||||
movq(str2, new AMD64Address(rsp, 2 * wordSize));
|
||||
movl(cnt2, new AMD64Address(rsp, 3 * wordSize));
|
||||
movdqu(vec, new AMD64Address(str2, 0));
|
||||
// We came here after the beginning of the substring was
|
||||
// matched but the rest of it was not so we need to search
|
||||
// again. Start from the next element after the previous match.
|
||||
subq(str1, result); // Restore counter
|
||||
shrl(str1, 1);
|
||||
addl(cnt1, str1);
|
||||
decrementl(cnt1); // Shift to next element
|
||||
cmpl(cnt1, cnt2);
|
||||
jccb(ConditionFlag.Negative, retNotFound); // Left less then substring
|
||||
|
||||
addq(result, 2);
|
||||
} // non constant
|
||||
|
||||
// Scan string for start of substr in 16-byte vectors
|
||||
bind(scanToSubstr);
|
||||
assert cnt1.equals(rdx) && cnt2.equals(rax) && tmp.equals(rcx) : "pcmpestri";
|
||||
pcmpestri(vec, new AMD64Address(result, 0), 0x0d);
|
||||
jccb(ConditionFlag.Below, foundCandidate); // CF == 1
|
||||
subl(cnt1, 8);
|
||||
jccb(ConditionFlag.LessEqual, retNotFound); // Scanned full string
|
||||
cmpl(cnt1, cnt2);
|
||||
jccb(ConditionFlag.Negative, retNotFound); // Left less then substring
|
||||
addq(result, 16);
|
||||
|
||||
bind(adjustStr);
|
||||
cmpl(cnt1, 8); // Do not read beyond string
|
||||
jccb(ConditionFlag.GreaterEqual, scanToSubstr);
|
||||
// Back-up string to avoid reading beyond string.
|
||||
leaq(result, new AMD64Address(result, cnt1, Scale.Times2, -16));
|
||||
movl(cnt1, 8);
|
||||
jmpb(scanToSubstr);
|
||||
|
||||
// Found a potential substr
|
||||
bind(foundCandidate);
|
||||
// After pcmpestri tmp(rcx) contains matched element index
|
||||
|
||||
// Make sure string is still long enough
|
||||
subl(cnt1, tmp);
|
||||
cmpl(cnt1, cnt2);
|
||||
jccb(ConditionFlag.GreaterEqual, foundSubstr);
|
||||
// Left less then substring.
|
||||
|
||||
bind(retNotFound);
|
||||
movl(result, -1);
|
||||
jmpb(cleanup);
|
||||
|
||||
bind(foundSubstr);
|
||||
// Compute start addr of substr
|
||||
leaq(result, new AMD64Address(result, tmp, Scale.Times2));
|
||||
|
||||
if (intCnt2 > 0) { // Constant substring
|
||||
// Repeat search for small substring (< 8 chars)
|
||||
// from new point without reloading substring.
|
||||
// Have to check that we don't read beyond string.
|
||||
cmpl(tmp, 8 - intCnt2);
|
||||
jccb(ConditionFlag.Greater, adjustStr);
|
||||
// Fall through if matched whole substring.
|
||||
} else { // non constant
|
||||
assert intCnt2 == -1 : "should be != 0";
|
||||
|
||||
addl(tmp, cnt2);
|
||||
// Found result if we matched whole substring.
|
||||
cmpl(tmp, 8);
|
||||
jccb(ConditionFlag.LessEqual, retFound);
|
||||
|
||||
// Repeat search for small substring (<= 8 chars)
|
||||
// from new point 'str1' without reloading substring.
|
||||
cmpl(cnt2, 8);
|
||||
// Have to check that we don't read beyond string.
|
||||
jccb(ConditionFlag.LessEqual, adjustStr);
|
||||
|
||||
Label checkNext = new Label();
|
||||
Label contScanSubstr = new Label();
|
||||
Label retFoundLong = new Label();
|
||||
// Compare the rest of substring (> 8 chars).
|
||||
movq(str1, result);
|
||||
|
||||
cmpl(tmp, cnt2);
|
||||
// First 8 chars are already matched.
|
||||
jccb(ConditionFlag.Equal, checkNext);
|
||||
|
||||
bind(scanSubstr);
|
||||
pcmpestri(vec, new AMD64Address(str1, 0), 0x0d);
|
||||
// Need to reload strings pointers if not matched whole vector
|
||||
jcc(ConditionFlag.NoOverflow, reloadSubstr); // OF == 0
|
||||
|
||||
bind(checkNext);
|
||||
subl(cnt2, 8);
|
||||
jccb(ConditionFlag.LessEqual, retFoundLong); // Found full substring
|
||||
addq(str1, 16);
|
||||
addq(str2, 16);
|
||||
subl(cnt1, 8);
|
||||
cmpl(cnt2, 8); // Do not read beyond substring
|
||||
jccb(ConditionFlag.GreaterEqual, contScanSubstr);
|
||||
// Back-up strings to avoid reading beyond substring.
|
||||
leaq(str2, new AMD64Address(str2, cnt2, Scale.Times2, -16));
|
||||
leaq(str1, new AMD64Address(str1, cnt2, Scale.Times2, -16));
|
||||
subl(cnt1, cnt2);
|
||||
movl(cnt2, 8);
|
||||
addl(cnt1, 8);
|
||||
bind(contScanSubstr);
|
||||
movdqu(vec, new AMD64Address(str2, 0));
|
||||
jmpb(scanSubstr);
|
||||
|
||||
bind(retFoundLong);
|
||||
movq(str1, new AMD64Address(rsp, wordSize));
|
||||
} // non constant
|
||||
|
||||
bind(retFound);
|
||||
// Compute substr offset
|
||||
subq(result, str1);
|
||||
shrl(result, 1); // index
|
||||
|
||||
bind(cleanup);
|
||||
pop(rsp); // restore SP
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -135,8 +135,8 @@ import java.util.Map;
|
||||
|
||||
import org.graalvm.compiler.asm.Assembler;
|
||||
import org.graalvm.compiler.asm.Label;
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.common.PermanentBailoutException;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.core.common.PermanentBailoutException;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
|
||||
import jdk.vm.ci.code.Register;
|
||||
|
@ -26,8 +26,6 @@ import static org.graalvm.compiler.core.common.CompilationRequestIdentifier.asCo
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import org.graalvm.compiler.api.test.Graal;
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.code.DisassemblerProvider;
|
||||
@ -36,10 +34,12 @@ import org.graalvm.compiler.core.target.Backend;
|
||||
import org.graalvm.compiler.debug.Debug;
|
||||
import org.graalvm.compiler.debug.Debug.Scope;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.runtime.RuntimeProvider;
|
||||
import org.graalvm.compiler.serviceprovider.GraalServices;
|
||||
import org.graalvm.compiler.test.AddExports;
|
||||
import org.graalvm.compiler.test.GraalTest;
|
||||
import org.junit.Assert;
|
||||
|
||||
import jdk.vm.ci.code.CallingConvention;
|
||||
import jdk.vm.ci.code.CodeCacheProvider;
|
||||
@ -52,6 +52,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.runtime.JVMCI;
|
||||
import jdk.vm.ci.runtime.JVMCIBackend;
|
||||
|
||||
@AddExports("jdk.internal.vm.ci/jdk.vm.ci.runtime")
|
||||
public abstract class AssemblerTest extends GraalTest {
|
||||
|
||||
private final MetaAccessProvider metaAccess;
|
||||
@ -62,6 +63,14 @@ public abstract class AssemblerTest extends GraalTest {
|
||||
byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the initial option values provided by the Graal runtime. These are option values
|
||||
* typically parsed from the command line.
|
||||
*/
|
||||
public static OptionValues getInitialOptions() {
|
||||
return Graal.getRequiredCapability(OptionValues.class);
|
||||
}
|
||||
|
||||
public AssemblerTest() {
|
||||
JVMCIBackend providers = JVMCI.getRuntime().getHostJVMCIBackend();
|
||||
this.metaAccess = providers.getMetaAccess();
|
||||
@ -79,7 +88,8 @@ public abstract class AssemblerTest extends GraalTest {
|
||||
try (Scope s = Debug.scope("assembleMethod", method, codeCache)) {
|
||||
RegisterConfig registerConfig = codeCache.getRegisterConfig();
|
||||
CompilationIdentifier compilationId = backend.getCompilationIdentifier(method);
|
||||
CallingConvention cc = backend.newLIRGenerationResult(compilationId, null, null, new StructuredGraph(method, AllowAssumptions.NO, compilationId), null).getCallingConvention();
|
||||
StructuredGraph graph = new StructuredGraph.Builder(getInitialOptions()).method(method).compilationId(compilationId).build();
|
||||
CallingConvention cc = backend.newLIRGenerationResult(compilationId, null, null, graph, null).getCallingConvention();
|
||||
|
||||
CompilationResult compResult = new CompilationResult();
|
||||
byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);
|
||||
|
@ -22,6 +22,8 @@
|
||||
*/
|
||||
package org.graalvm.compiler.asm;
|
||||
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
@ -34,6 +34,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.graalvm.compiler.graph.NodeSourcePosition;
|
||||
import org.graalvm.util.EconomicSet;
|
||||
|
||||
import jdk.vm.ci.code.DebugInfo;
|
||||
import jdk.vm.ci.code.StackSlot;
|
||||
@ -363,9 +364,10 @@ public class CompilationResult {
|
||||
*
|
||||
* @param accessedFields the collected set of fields accessed during compilation
|
||||
*/
|
||||
public void setFields(Collection<ResolvedJavaField> accessedFields) {
|
||||
assert accessedFields != null;
|
||||
fields = accessedFields.toArray(new ResolvedJavaField[accessedFields.size()]);
|
||||
public void setFields(EconomicSet<ResolvedJavaField> accessedFields) {
|
||||
if (accessedFields != null) {
|
||||
fields = accessedFields.toArray(new ResolvedJavaField[accessedFields.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,7 @@
|
||||
*/
|
||||
package org.graalvm.compiler.code;
|
||||
|
||||
import org.graalvm.compiler.common.PermanentBailoutException;
|
||||
import org.graalvm.compiler.core.common.PermanentBailoutException;
|
||||
|
||||
/**
|
||||
* Represents a bailout exception with a stack trace in terms of the Java source being compiled
|
||||
|
@ -90,6 +90,7 @@ public class AArch64AddressNode extends AddressNode implements LIRLowerable {
|
||||
gen.setResult(this, new AArch64AddressValue(kind, baseValue, indexValue, displacement, scaled, addressingMode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode getBase() {
|
||||
return base;
|
||||
}
|
||||
@ -102,6 +103,7 @@ public class AArch64AddressNode extends AddressNode implements LIRLowerable {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode getIndex() {
|
||||
return index;
|
||||
}
|
||||
@ -121,4 +123,9 @@ public class AArch64AddressNode extends AddressNode implements LIRLowerable {
|
||||
public void setDisplacement(int displacement) {
|
||||
this.displacement = displacement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxConstantDisplacement() {
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
@ -23,13 +23,16 @@
|
||||
|
||||
package org.graalvm.compiler.core.aarch64;
|
||||
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
|
||||
import static jdk.vm.ci.aarch64.AArch64.sp;
|
||||
import static jdk.vm.ci.aarch64.AArch64Kind.DWORD;
|
||||
import static jdk.vm.ci.aarch64.AArch64Kind.QWORD;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
|
||||
import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.BSR;
|
||||
import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.CLZ;
|
||||
import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.CTZ;
|
||||
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
|
||||
import org.graalvm.compiler.core.common.LIRKind;
|
||||
import org.graalvm.compiler.core.common.calc.FloatConvert;
|
||||
@ -41,12 +44,12 @@ import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticLIRGeneratorTool;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64Move.LoadOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreConstantOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64ReinterpretOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64SignExtendOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64Unary;
|
||||
import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64Kind;
|
||||
@ -91,11 +94,30 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
|
||||
}
|
||||
}
|
||||
|
||||
protected Value emitExtendMemory(boolean isSigned, AArch64Kind memoryKind, int resultBits, AArch64AddressValue address, LIRFrameState state) {
|
||||
// Issue a zero extending load of the proper bit size and set the result to
|
||||
// the proper kind.
|
||||
Variable result = getLIRGen().newVariable(LIRKind.value(resultBits == 32 ? AArch64Kind.DWORD : AArch64Kind.QWORD));
|
||||
|
||||
int targetSize = resultBits <= 32 ? 32 : 64;
|
||||
switch (memoryKind) {
|
||||
case BYTE:
|
||||
case WORD:
|
||||
case DWORD:
|
||||
case QWORD:
|
||||
getLIRGen().append(new AArch64Unary.MemoryOp(isSigned, targetSize,
|
||||
memoryKind.getSizeInBytes() * 8, result, address, state));
|
||||
break;
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitMul(Value a, Value b, boolean setFlags) {
|
||||
// TODO (das) setFlags handling - should be handled higher up. Ask for ideas at mailing list
|
||||
assert !setFlags : "Set flags on multiplication is not supported";
|
||||
return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.MUL, AArch64ArithmeticOp.FMUL), true, a, b);
|
||||
AArch64ArithmeticOp intOp = setFlags ? AArch64ArithmeticOp.MULVS : AArch64ArithmeticOp.MUL;
|
||||
return emitBinary(LIRKind.combine(a, b), getOpCode(a, intOp, AArch64ArithmeticOp.FMUL), true, a, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -223,7 +245,7 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
|
||||
|
||||
@Override
|
||||
public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
|
||||
assert fromBits <= toBits && (toBits == 32 || toBits == 64);
|
||||
assert fromBits <= toBits && toBits <= 64;
|
||||
if (fromBits == toBits) {
|
||||
return inputVal;
|
||||
}
|
||||
@ -235,11 +257,21 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
|
||||
|
||||
@Override
|
||||
public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
|
||||
assert fromBits <= toBits && (toBits == 32 || toBits == 64);
|
||||
LIRKind resultKind = getResultLirKind(toBits, inputVal);
|
||||
assert fromBits <= toBits && toBits <= 64;
|
||||
if (fromBits == toBits) {
|
||||
return inputVal;
|
||||
} else if (isJavaConstant(inputVal)) {
|
||||
JavaConstant javaConstant = asJavaConstant(inputVal);
|
||||
long constant;
|
||||
if (javaConstant.isNull()) {
|
||||
constant = 0;
|
||||
} else {
|
||||
constant = javaConstant.asLong();
|
||||
}
|
||||
int shiftCount = QWORD.getSizeInBytes() * 8 - fromBits;
|
||||
return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount));
|
||||
}
|
||||
LIRKind resultKind = getResultLirKind(toBits, inputVal);
|
||||
Variable result = getLIRGen().newVariable(resultKind);
|
||||
getLIRGen().append(new AArch64SignExtendOp(result, getLIRGen().asAllocatable(inputVal), fromBits, toBits));
|
||||
return result;
|
||||
@ -249,7 +281,8 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
|
||||
if (resultBitSize == 64) {
|
||||
return LIRKind.combine(inputValues).changeType(QWORD);
|
||||
} else {
|
||||
assert resultBitSize == 32;
|
||||
// FIXME: I have no idea what this assert was ever for
|
||||
// assert resultBitSize == 32;
|
||||
return LIRKind.combine(inputValues).changeType(DWORD);
|
||||
}
|
||||
}
|
||||
@ -352,8 +385,8 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitBitScanForward(Value inputVal) {
|
||||
return emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode.BSF, inputVal);
|
||||
public Variable emitBitScanForward(Value value) {
|
||||
throw GraalError.unimplemented();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -362,27 +395,23 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitBitScanReverse(Value inputVal) {
|
||||
// TODO (das) old implementation said to use emitCountLeadingZeros instead - need extra node
|
||||
// for that though
|
||||
return emitBitManipulation(BitManipulationOpCode.BSR, inputVal);
|
||||
public Value emitBitScanReverse(Value value) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AArch64Kind.DWORD));
|
||||
getLIRGen().append(new AArch64BitManipulationOp(BSR, result, getLIRGen().asAllocatable(value)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitCountLeadingZeros(Value value) {
|
||||
return emitBitManipulation(BitManipulationOpCode.CLZ, value);
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AArch64Kind.DWORD));
|
||||
getLIRGen().append(new AArch64BitManipulationOp(CLZ, result, getLIRGen().asAllocatable(value)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitCountTrailingZeros(Value value) {
|
||||
throw GraalError.unimplemented();
|
||||
}
|
||||
|
||||
private Variable emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode op, Value inputVal) {
|
||||
assert isNumericInteger(inputVal.getPlatformKind());
|
||||
AllocatableValue input = getLIRGen().asAllocatable(inputVal);
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
getLIRGen().append(new AArch64BitManipulationOp(op, result, input));
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AArch64Kind.DWORD));
|
||||
getLIRGen().append(new AArch64BitManipulationOp(CTZ, result, getLIRGen().asAllocatable(value)));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -42,11 +42,14 @@ import org.graalvm.compiler.lir.SwitchStrategy;
|
||||
import org.graalvm.compiler.lir.Variable;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64ArrayEqualsOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64ByteSwapOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64Compare;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.BranchOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.CondMoveOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.TableSwitchOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64Move;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64Move.CompareAndSwapOp;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64Move.MembarOp;
|
||||
@ -56,6 +59,7 @@ import org.graalvm.compiler.lir.gen.LIRGenerator;
|
||||
import org.graalvm.compiler.phases.util.Providers;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64Kind;
|
||||
import jdk.vm.ci.code.CallingConvention;
|
||||
import jdk.vm.ci.code.RegisterValue;
|
||||
import jdk.vm.ci.meta.AllocatableValue;
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
@ -121,8 +125,19 @@ public abstract class AArch64LIRGenerator extends LIRGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
|
||||
public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
|
||||
Variable prevValue = newVariable(expectedValue.getValueKind());
|
||||
Variable scratch = newVariable(LIRKind.value(AArch64Kind.DWORD));
|
||||
append(new CompareAndSwapOp(prevValue, loadReg(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
|
||||
assert trueValue.getValueKind().equals(falseValue.getValueKind());
|
||||
Variable result = newVariable(trueValue.getValueKind());
|
||||
append(new CondMoveOp(result, ConditionFlag.EQ, asAllocatable(trueValue), asAllocatable(falseValue)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
|
||||
Variable result = newVariable(newValue.getValueKind());
|
||||
Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
|
||||
append(new CompareAndSwapOp(result, loadNonCompareConst(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
|
||||
return result;
|
||||
@ -271,13 +286,25 @@ public abstract class AArch64LIRGenerator extends LIRGenerator {
|
||||
boolean mirrored;
|
||||
AArch64Kind kind = (AArch64Kind) cmpKind;
|
||||
if (kind.isInteger()) {
|
||||
if (LIRValueUtil.isVariable(b)) {
|
||||
left = load(b);
|
||||
right = loadNonConst(a);
|
||||
Value aExt = a;
|
||||
Value bExt = b;
|
||||
|
||||
int compareBytes = cmpKind.getSizeInBytes();
|
||||
// AArch64 compares 32 or 64 bits: sign extend a and b as required.
|
||||
if (compareBytes < a.getPlatformKind().getSizeInBytes()) {
|
||||
aExt = arithmeticLIRGen.emitSignExtend(a, compareBytes * 8, 64);
|
||||
}
|
||||
if (compareBytes < b.getPlatformKind().getSizeInBytes()) {
|
||||
bExt = arithmeticLIRGen.emitSignExtend(b, compareBytes * 8, 64);
|
||||
}
|
||||
|
||||
if (LIRValueUtil.isVariable(bExt)) {
|
||||
left = load(bExt);
|
||||
right = loadNonConst(aExt);
|
||||
mirrored = true;
|
||||
} else {
|
||||
left = load(a);
|
||||
right = loadNonConst(b);
|
||||
left = load(aExt);
|
||||
right = loadNonConst(bExt);
|
||||
mirrored = false;
|
||||
}
|
||||
append(new AArch64Compare.CompareOp(left, loadNonCompareConst(right)));
|
||||
@ -367,7 +394,7 @@ public abstract class AArch64LIRGenerator extends LIRGenerator {
|
||||
public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
|
||||
assert ((AArch64Kind) left.getPlatformKind()).isInteger() && ((AArch64Kind) right.getPlatformKind()).isInteger();
|
||||
assert ((AArch64Kind) trueValue.getPlatformKind()).isInteger() && ((AArch64Kind) falseValue.getPlatformKind()).isInteger();
|
||||
((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(trueValue.getValueKind(), AArch64ArithmeticOp.ANDS, true, left, right);
|
||||
((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(left.getValueKind(), AArch64ArithmeticOp.ANDS, true, left, right);
|
||||
Variable result = newVariable(trueValue.getValueKind());
|
||||
append(new CondMoveOp(result, ConditionFlag.EQ, load(trueValue), load(falseValue)));
|
||||
return result;
|
||||
@ -385,22 +412,21 @@ public abstract class AArch64LIRGenerator extends LIRGenerator {
|
||||
|
||||
@Override
|
||||
protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
|
||||
// Make copy of key since the TableSwitch destroys its input.
|
||||
Variable tmp = emitMove(key);
|
||||
Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
|
||||
append(new AArch64ControlFlow.TableSwitchOp(lowKey, defaultTarget, targets, tmp, scratch));
|
||||
append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().arch.getWordKind())), newVariable(key.getValueKind())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitByteSwap(Value operand) {
|
||||
// TODO (das) Do not generate until we support vector instructions
|
||||
throw GraalError.unimplemented("Do not generate until we support vector instructions");
|
||||
public Variable emitByteSwap(Value input) {
|
||||
Variable result = newVariable(LIRKind.combine(input));
|
||||
append(new AArch64ByteSwapOp(result, input));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
|
||||
// TODO (das) Do not generate until we support vector instructions
|
||||
throw GraalError.unimplemented("Do not generate until we support vector instructions");
|
||||
Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD));
|
||||
append(new AArch64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -443,4 +469,6 @@ public abstract class AArch64LIRGenerator extends LIRGenerator {
|
||||
public void emitPause() {
|
||||
append(new AArch64PauseOp());
|
||||
}
|
||||
|
||||
public abstract void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args);
|
||||
}
|
||||
|
@ -86,21 +86,25 @@ public class AArch64MoveFactory implements MoveFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInlineConstant(JavaConstant c) {
|
||||
switch (c.getJavaKind()) {
|
||||
case Boolean:
|
||||
case Byte:
|
||||
case Char:
|
||||
case Short:
|
||||
case Int:
|
||||
return AArch64MacroAssembler.isMovableImmediate(c.asInt());
|
||||
case Long:
|
||||
return AArch64MacroAssembler.isMovableImmediate(c.asLong());
|
||||
case Object:
|
||||
return c.isNull();
|
||||
default:
|
||||
return false;
|
||||
public boolean canInlineConstant(Constant con) {
|
||||
if (con instanceof JavaConstant) {
|
||||
JavaConstant c = (JavaConstant) con;
|
||||
switch (c.getJavaKind()) {
|
||||
case Boolean:
|
||||
case Byte:
|
||||
case Char:
|
||||
case Short:
|
||||
case Int:
|
||||
return AArch64MacroAssembler.isMovableImmediate(c.asInt());
|
||||
case Long:
|
||||
return AArch64MacroAssembler.isMovableImmediate(c.asLong());
|
||||
case Object:
|
||||
return c.isNull();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -24,9 +24,14 @@
|
||||
package org.graalvm.compiler.core.aarch64;
|
||||
|
||||
import org.graalvm.compiler.core.gen.NodeMatchRules;
|
||||
import org.graalvm.compiler.core.match.ComplexMatchResult;
|
||||
import org.graalvm.compiler.core.match.MatchRule;
|
||||
import org.graalvm.compiler.lir.LIRFrameState;
|
||||
import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
|
||||
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
|
||||
import org.graalvm.compiler.nodes.DeoptimizingNode;
|
||||
import org.graalvm.compiler.nodes.calc.SignExtendNode;
|
||||
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
|
||||
import org.graalvm.compiler.nodes.memory.Access;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64Kind;
|
||||
@ -56,4 +61,18 @@ public class AArch64NodeMatchRules extends NodeMatchRules {
|
||||
protected AArch64ArithmeticLIRGenerator getArithmeticLIRGenerator() {
|
||||
return (AArch64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic();
|
||||
}
|
||||
|
||||
@MatchRule("(ZeroExtend Read=access)")
|
||||
@MatchRule("(ZeroExtend FloatingRead=access)")
|
||||
public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
|
||||
AArch64Kind memoryKind = getMemoryKind(access);
|
||||
return builder -> getArithmeticLIRGenerator().emitExtendMemory(false, memoryKind, root.getResultBits(), (AArch64AddressValue) operand(access.getAddress()), getState(access));
|
||||
}
|
||||
|
||||
@MatchRule("(SignExtend Read=access)")
|
||||
@MatchRule("(SignExtend FloatingRead=access)")
|
||||
public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
|
||||
AArch64Kind memoryKind = getMemoryKind(access);
|
||||
return builder -> getArithmeticLIRGenerator().emitExtendMemory(true, memoryKind, root.getResultBits(), (AArch64AddressValue) operand(access.getAddress()), getState(access));
|
||||
}
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ public class AMD64AllocatorTest extends AllocatorTest {
|
||||
@Before
|
||||
public void checkAMD64() {
|
||||
assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
|
||||
assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue() == null);
|
||||
assumeTrue("TraceRA is set -> skip", !TraceRA.getValue());
|
||||
assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue(getInitialOptions()) == null);
|
||||
assumeTrue("TraceRA is set -> skip", !TraceRA.getValue(getInitialOptions()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -24,22 +24,23 @@ package org.graalvm.compiler.core.amd64.test;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.lir.LIR;
|
||||
import org.graalvm.compiler.lir.LIRInstruction;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer.MemoryConstOp;
|
||||
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
|
||||
import org.graalvm.compiler.lir.jtt.LIRTest;
|
||||
import org.graalvm.compiler.lir.phases.LIRPhase;
|
||||
import org.graalvm.compiler.lir.phases.LIRSuites;
|
||||
import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
|
||||
public class MatchRuleTest extends LIRTest {
|
||||
private static LIR lir;
|
||||
private LIR lir;
|
||||
|
||||
@Before
|
||||
public void checkAMD64() {
|
||||
@ -54,13 +55,19 @@ public class MatchRuleTest extends LIRTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LIRSuites createLIRSuites(OptionValues options) {
|
||||
LIRSuites suites = super.createLIRSuites(options);
|
||||
suites.getPreAllocationOptimizationStage().appendPhase(new CheckPhase());
|
||||
return suites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies, if the match rules in AMD64NodeMatchRules do work on the graphs by compiling and
|
||||
* checking if the expected LIR instruction show up.
|
||||
*/
|
||||
@Test
|
||||
public void test1() {
|
||||
getLIRSuites().getPreAllocationOptimizationStage().appendPhase(new CheckPhase());
|
||||
compile(getResolvedJavaMethod("test1Snippet"), null);
|
||||
boolean found = false;
|
||||
for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) {
|
||||
@ -83,7 +90,7 @@ public class MatchRuleTest extends LIRTest {
|
||||
}
|
||||
}
|
||||
|
||||
public static class CheckPhase extends LIRPhase<PreAllocationOptimizationContext> {
|
||||
public class CheckPhase extends LIRPhase<PreAllocationOptimizationContext> {
|
||||
@Override
|
||||
protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) {
|
||||
lir = lirGenRes.getLIR();
|
||||
|
@ -25,7 +25,7 @@ package org.graalvm.compiler.core.amd64;
|
||||
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
|
||||
import org.graalvm.compiler.core.common.type.IntegerStamp;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
|
@ -87,6 +87,7 @@ public class AMD64AddressNode extends AddressNode implements LIRLowerable {
|
||||
gen.setResult(this, new AMD64AddressValue(kind, baseValue, indexValue, scale, displacement));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode getBase() {
|
||||
return base;
|
||||
}
|
||||
@ -99,6 +100,7 @@ public class AMD64AddressNode extends AddressNode implements LIRLowerable {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode getIndex() {
|
||||
return index;
|
||||
}
|
||||
@ -126,4 +128,9 @@ public class AMD64AddressNode extends AddressNode implements LIRLowerable {
|
||||
public void setDisplacement(int displacement) {
|
||||
this.displacement = displacement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxConstantDisplacement() {
|
||||
return displacement;
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntr
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.EXP;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp.BinaryIntrinsicOpcode.POW;
|
||||
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
|
||||
@ -1234,7 +1234,7 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen
|
||||
return;
|
||||
} else if (c instanceof VMConstant) {
|
||||
VMConstant vc = (VMConstant) c;
|
||||
if (size == DWORD && !GeneratePIC.getValue()) {
|
||||
if (size == DWORD && !GeneratePIC.getValue(getOptions())) {
|
||||
getLIRGen().append(new AMD64BinaryConsumer.VMConstOp(CMP.getMIOpcode(DWORD, false), left, vc));
|
||||
} else {
|
||||
getLIRGen().append(new AMD64BinaryConsumer.DataOp(CMP.getRMOpcode(size), size, left, vc));
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
package org.graalvm.compiler.core.amd64;
|
||||
|
||||
import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.CMP;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PD;
|
||||
@ -31,10 +32,10 @@ import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
|
||||
import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
|
||||
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
|
||||
@ -72,6 +73,7 @@ import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64Move.MembarOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64Move.StackLeaOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64PauseOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64StringIndexOfOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64ZapRegistersOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64ZapStackOp;
|
||||
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
|
||||
@ -112,10 +114,8 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
|
||||
protected static final boolean canStoreConstant(JavaConstant c) {
|
||||
// there is no immediate move of 64-bit constants on Intel
|
||||
switch (c.getJavaKind()) {
|
||||
case Long: {
|
||||
long l = c.asLong();
|
||||
return (int) l == l;
|
||||
}
|
||||
case Long:
|
||||
return NumUtil.isInt(c.asLong());
|
||||
case Double:
|
||||
return false;
|
||||
case Object:
|
||||
@ -183,7 +183,7 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
|
||||
public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
|
||||
ValueKind<?> kind = newValue.getValueKind();
|
||||
assert kind.equals(expectedValue.getValueKind());
|
||||
AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
|
||||
@ -199,6 +199,33 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
|
||||
ValueKind<?> kind = newValue.getValueKind();
|
||||
assert kind.equals(expectedValue.getValueKind());
|
||||
AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
|
||||
|
||||
AMD64AddressValue addressValue = asAddressValue(address);
|
||||
RegisterValue raxRes = AMD64.rax.asValue(kind);
|
||||
emitMove(raxRes, expectedValue);
|
||||
append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
|
||||
Variable result = newVariable(kind);
|
||||
emitMove(result, raxRes);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void emitCompareAndSwapBranch(ValueKind<?> kind, AMD64AddressValue address, Value expectedValue, Value newValue, Condition condition, LabelRef trueLabel, LabelRef falseLabel,
|
||||
double trueLabelProbability) {
|
||||
assert kind.equals(expectedValue.getValueKind());
|
||||
assert kind.equals(newValue.getValueKind());
|
||||
assert condition == Condition.EQ || condition == Condition.NE;
|
||||
AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
|
||||
RegisterValue raxValue = AMD64.rax.asValue(kind);
|
||||
emitMove(raxValue, expectedValue);
|
||||
append(new CompareAndSwapOp(memKind, raxValue, address, raxValue, asAllocatable(newValue)));
|
||||
append(new BranchOp(condition, trueLabel, falseLabel, trueLabelProbability));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitAtomicReadAndAdd(Value address, Value delta) {
|
||||
ValueKind<?> kind = delta.getValueKind();
|
||||
@ -329,7 +356,7 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
|
||||
throw GraalError.shouldNotReachHere("unexpected kind: " + cmpKind);
|
||||
}
|
||||
|
||||
if (isJavaConstant(a)) {
|
||||
if (isConstantValue(a)) {
|
||||
return emitCompareMemoryConOp(size, asConstantValue(a), b, state);
|
||||
} else {
|
||||
return emitCompareRegMemoryOp(size, asAllocatable(a), b, state);
|
||||
@ -399,7 +426,7 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
|
||||
@Override
|
||||
protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
|
||||
long maxOffset = linkage.getMaxCallTargetOffset();
|
||||
if (maxOffset != (int) maxOffset && !GeneratePIC.getValue()) {
|
||||
if (maxOffset != (int) maxOffset && !GeneratePIC.getValue(getResult().getLIR().getOptions())) {
|
||||
append(new AMD64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info));
|
||||
} else {
|
||||
append(new AMD64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
|
||||
@ -420,6 +447,24 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a conservative estimate of the page size for use by the String.indexOf intrinsic.
|
||||
*/
|
||||
protected int getVMPageSize() {
|
||||
return 4096;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitStringIndexOf(Value source, Value sourceCount, Value target, Value targetCount, int constantTargetCount) {
|
||||
Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
|
||||
RegisterValue cnt1 = AMD64.rdx.asValue(sourceCount.getValueKind());
|
||||
emitMove(cnt1, sourceCount);
|
||||
RegisterValue cnt2 = AMD64.rax.asValue(targetCount.getValueKind());
|
||||
emitMove(cnt2, targetCount);
|
||||
append(new AMD64StringIndexOfOp(this, result, source, target, cnt1, cnt2, AMD64.rcx.asValue(), AMD64.xmm0.asValue(), constantTargetCount, getVMPageSize()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitReturn(JavaKind kind, Value input) {
|
||||
AllocatableValue operand = Value.ILLEGAL;
|
||||
|
@ -28,7 +28,7 @@ import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
|
||||
import static jdk.vm.ci.code.ValueUtil.isRegister;
|
||||
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.core.common.type.DataPointerConstant;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
|
||||
@ -54,15 +54,19 @@ public abstract class AMD64MoveFactory extends AMD64MoveFactoryBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInlineConstant(JavaConstant c) {
|
||||
switch (c.getJavaKind()) {
|
||||
case Long:
|
||||
return NumUtil.isInt(c.asLong());
|
||||
case Object:
|
||||
return c.isNull();
|
||||
default:
|
||||
return true;
|
||||
public boolean canInlineConstant(Constant con) {
|
||||
if (con instanceof JavaConstant) {
|
||||
JavaConstant c = (JavaConstant) con;
|
||||
switch (c.getJavaKind()) {
|
||||
case Long:
|
||||
return NumUtil.isInt(c.asLong());
|
||||
case Object:
|
||||
return c.isNull();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -26,15 +26,14 @@ package org.graalvm.compiler.core.amd64;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.graalvm.compiler.core.common.LIRKind;
|
||||
import org.graalvm.compiler.lir.VirtualStackSlot;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64PushPopStackMove;
|
||||
import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
|
||||
import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
|
||||
import org.graalvm.util.Equivalence;
|
||||
import org.graalvm.util.EconomicMap;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64Kind;
|
||||
import jdk.vm.ci.code.Architecture;
|
||||
@ -61,7 +60,7 @@ public abstract class AMD64MoveFactoryBase implements MoveFactory {
|
||||
public static final class BackupSlotProvider {
|
||||
|
||||
private final FrameMapBuilder frameMapBuilder;
|
||||
private Map<PlatformKind.Key, RegisterBackupPair> categorized;
|
||||
private EconomicMap<PlatformKind.Key, RegisterBackupPair> categorized;
|
||||
|
||||
public BackupSlotProvider(FrameMapBuilder frameMapBuilder) {
|
||||
this.frameMapBuilder = frameMapBuilder;
|
||||
@ -70,7 +69,7 @@ public abstract class AMD64MoveFactoryBase implements MoveFactory {
|
||||
protected RegisterBackupPair getScratchRegister(PlatformKind kind) {
|
||||
PlatformKind.Key key = kind.getKey();
|
||||
if (categorized == null) {
|
||||
categorized = new HashMap<>();
|
||||
categorized = EconomicMap.create(Equivalence.DEFAULT);
|
||||
} else if (categorized.containsKey(key)) {
|
||||
return categorized.get(key);
|
||||
}
|
||||
|
@ -36,13 +36,13 @@ import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SD;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SS;
|
||||
|
||||
import org.graalvm.compiler.asm.NumUtil;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp;
|
||||
import org.graalvm.compiler.core.common.LIRKind;
|
||||
import org.graalvm.compiler.core.common.calc.Condition;
|
||||
import org.graalvm.compiler.core.gen.NodeLIRBuilder;
|
||||
@ -52,6 +52,7 @@ import org.graalvm.compiler.core.match.MatchRule;
|
||||
import org.graalvm.compiler.debug.Debug;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.lir.LIRFrameState;
|
||||
import org.graalvm.compiler.lir.LIRValueUtil;
|
||||
import org.graalvm.compiler.lir.LabelRef;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
|
||||
@ -69,18 +70,22 @@ import org.graalvm.compiler.nodes.calc.ReinterpretNode;
|
||||
import org.graalvm.compiler.nodes.calc.SignExtendNode;
|
||||
import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode;
|
||||
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
|
||||
import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
|
||||
import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode;
|
||||
import org.graalvm.compiler.nodes.memory.Access;
|
||||
import org.graalvm.compiler.nodes.memory.LIRLowerableAccess;
|
||||
import org.graalvm.compiler.nodes.memory.WriteNode;
|
||||
import org.graalvm.compiler.nodes.util.GraphUtil;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
import jdk.vm.ci.amd64.AMD64Kind;
|
||||
import jdk.vm.ci.amd64.AMD64.CPUFeature;
|
||||
import jdk.vm.ci.amd64.AMD64Kind;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.meta.AllocatableValue;
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.PlatformKind;
|
||||
import jdk.vm.ci.meta.Value;
|
||||
import jdk.vm.ci.meta.ValueKind;
|
||||
|
||||
public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
|
||||
@ -95,11 +100,15 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected AMD64Kind getMemoryKind(Access access) {
|
||||
return (AMD64Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind();
|
||||
protected AMD64Kind getMemoryKind(LIRLowerableAccess access) {
|
||||
return (AMD64Kind) getLirKind(access).getPlatformKind();
|
||||
}
|
||||
|
||||
protected OperandSize getMemorySize(Access access) {
|
||||
protected LIRKind getLirKind(LIRLowerableAccess access) {
|
||||
return gen.getLIRKind(access.getAccessStamp());
|
||||
}
|
||||
|
||||
protected OperandSize getMemorySize(LIRLowerableAccess access) {
|
||||
switch (getMemoryKind(access)) {
|
||||
case BYTE:
|
||||
return OperandSize.BYTE;
|
||||
@ -118,25 +127,36 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
}
|
||||
}
|
||||
|
||||
protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, Access access) {
|
||||
protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, LIRLowerableAccess access) {
|
||||
Condition cond = compare.condition();
|
||||
AMD64Kind kind = getMemoryKind(access);
|
||||
boolean matchedAsConstant = false; // For assertion checking
|
||||
|
||||
if (value.isConstant()) {
|
||||
JavaConstant constant = value.asJavaConstant();
|
||||
if (constant != null && kind == AMD64Kind.QWORD && !constant.getJavaKind().isObject() && !NumUtil.isInt(constant.asLong())) {
|
||||
// Only imm32 as long
|
||||
return null;
|
||||
if (constant != null) {
|
||||
if (kind == AMD64Kind.QWORD && !constant.getJavaKind().isObject() && !NumUtil.isInt(constant.asLong())) {
|
||||
// Only imm32 as long
|
||||
return null;
|
||||
}
|
||||
// A QWORD that can be encoded as int can be embedded as a constant
|
||||
matchedAsConstant = kind == AMD64Kind.QWORD && !constant.getJavaKind().isObject() && NumUtil.isInt(constant.asLong());
|
||||
}
|
||||
if (kind == AMD64Kind.DWORD) {
|
||||
// Any DWORD value should be embeddable as a constant
|
||||
matchedAsConstant = true;
|
||||
}
|
||||
if (kind.isXMM()) {
|
||||
Debug.log("Skipping constant compares for float kinds");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
boolean matchedAsConstantFinal = matchedAsConstant;
|
||||
|
||||
// emitCompareBranchMemory expects the memory on the right, so mirror the condition if
|
||||
// that's not true. It might be mirrored again the actual compare is emitted but that's
|
||||
// ok.
|
||||
/*
|
||||
* emitCompareBranchMemory expects the memory on the right, so mirror the condition if
|
||||
* that's not true. It might be mirrored again the actual compare is emitted but that's ok.
|
||||
*/
|
||||
Condition finalCondition = GraphUtil.unproxify(compare.getX()) == access ? cond.mirror() : cond;
|
||||
return new ComplexMatchResult() {
|
||||
@Override
|
||||
@ -146,6 +166,11 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
boolean unorderedIsTrue = compare.unorderedIsTrue();
|
||||
double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
|
||||
Value other = operand(value);
|
||||
/*
|
||||
* Check that patterns which were matched as a constant actually end up seeing a
|
||||
* constant in the LIR.
|
||||
*/
|
||||
assert !matchedAsConstantFinal || !LIRValueUtil.isVariable(other) : "expected constant value " + value;
|
||||
AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
|
||||
getLIRGeneratorTool().emitCompareBranchMemory(kind, other, address, getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
|
||||
return null;
|
||||
@ -153,7 +178,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
};
|
||||
}
|
||||
|
||||
private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, Access access) {
|
||||
private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, LIRLowerableAccess access) {
|
||||
LabelRef trueLabel = getLIRBlock(x.trueSuccessor());
|
||||
LabelRef falseLabel = getLIRBlock(x.falseSuccessor());
|
||||
double trueLabelProbability = x.probability(x.trueSuccessor());
|
||||
@ -181,15 +206,22 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
}
|
||||
}
|
||||
|
||||
protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access) {
|
||||
protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access, ValueKind<?> addressKind) {
|
||||
return builder -> {
|
||||
AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
|
||||
LIRFrameState state = getState(access);
|
||||
if (addressKind != null) {
|
||||
address = address.withKind(addressKind);
|
||||
}
|
||||
return getArithmeticLIRGenerator().emitConvertMemoryOp(kind, op, size, address, state);
|
||||
};
|
||||
}
|
||||
|
||||
private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
|
||||
protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access) {
|
||||
return emitConvertMemoryOp(kind, op, size, access, null);
|
||||
}
|
||||
|
||||
private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits, ValueKind<?> addressKind) {
|
||||
assert fromBits <= toBits && toBits <= 64;
|
||||
AMD64Kind kind = null;
|
||||
AMD64RMOp op;
|
||||
@ -231,7 +263,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
}
|
||||
}
|
||||
if (kind != null && op != null) {
|
||||
return emitConvertMemoryOp(kind, op, size, access);
|
||||
return emitConvertMemoryOp(kind, op, size, access, addressKind);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -244,7 +276,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
|
||||
@MatchRule("(If (IntegerTest Read=access value))")
|
||||
@MatchRule("(If (IntegerTest FloatingRead=access value))")
|
||||
public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) {
|
||||
public ComplexMatchResult integerTestBranchMemory(IfNode root, LIRLowerableAccess access, ValueNode value) {
|
||||
return emitIntegerTestBranchMemory(root, value, access);
|
||||
}
|
||||
|
||||
@ -262,7 +294,67 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
@MatchRule("(If (PointerEquals=compare value FloatingRead=access))")
|
||||
@MatchRule("(If (ObjectEquals=compare value Read=access))")
|
||||
@MatchRule("(If (ObjectEquals=compare value FloatingRead=access))")
|
||||
public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
|
||||
public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, LIRLowerableAccess access) {
|
||||
return emitCompareBranchMemory(root, compare, value, access);
|
||||
}
|
||||
|
||||
@MatchRule("(If (ObjectEquals=compare value ValueCompareAndSwap=cas))")
|
||||
@MatchRule("(If (PointerEquals=compare value ValueCompareAndSwap=cas))")
|
||||
@MatchRule("(If (FloatEquals=compare value ValueCompareAndSwap=cas))")
|
||||
@MatchRule("(If (IntegerEquals=compare value ValueCompareAndSwap=cas))")
|
||||
public ComplexMatchResult ifCompareValueCas(IfNode root, CompareNode compare, ValueNode value, ValueCompareAndSwapNode cas) {
|
||||
assert compare.condition() == Condition.EQ;
|
||||
if (value == cas.getExpectedValue() && cas.usages().count() == 1) {
|
||||
return builder -> {
|
||||
LIRKind kind = getLirKind(cas);
|
||||
LabelRef trueLabel = getLIRBlock(root.trueSuccessor());
|
||||
LabelRef falseLabel = getLIRBlock(root.falseSuccessor());
|
||||
double trueLabelProbability = root.probability(root.trueSuccessor());
|
||||
Value expectedValue = operand(cas.getExpectedValue());
|
||||
Value newValue = operand(cas.getNewValue());
|
||||
AMD64AddressValue address = (AMD64AddressValue) operand(cas.getAddress());
|
||||
getLIRGeneratorTool().emitCompareAndSwapBranch(kind, address, expectedValue, newValue, Condition.EQ, trueLabel, falseLabel, trueLabelProbability);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@MatchRule("(If (ObjectEquals=compare value LogicCompareAndSwap=cas))")
|
||||
@MatchRule("(If (PointerEquals=compare value LogicCompareAndSwap=cas))")
|
||||
@MatchRule("(If (FloatEquals=compare value LogicCompareAndSwap=cas))")
|
||||
@MatchRule("(If (IntegerEquals=compare value LogicCompareAndSwap=cas))")
|
||||
public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) {
|
||||
JavaConstant constant = value.asJavaConstant();
|
||||
assert compare.condition() == Condition.EQ;
|
||||
if (constant != null && cas.usages().count() == 1) {
|
||||
long constantValue = constant.asLong();
|
||||
boolean successIsTrue;
|
||||
if (constantValue == 0) {
|
||||
successIsTrue = false;
|
||||
} else if (constantValue == 1) {
|
||||
successIsTrue = true;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return builder -> {
|
||||
LIRKind kind = getLirKind(cas);
|
||||
LabelRef trueLabel = getLIRBlock(root.trueSuccessor());
|
||||
LabelRef falseLabel = getLIRBlock(root.falseSuccessor());
|
||||
double trueLabelProbability = root.probability(root.trueSuccessor());
|
||||
Value expectedValue = operand(cas.getExpectedValue());
|
||||
Value newValue = operand(cas.getNewValue());
|
||||
AMD64AddressValue address = (AMD64AddressValue) operand(cas.getAddress());
|
||||
Condition condition = successIsTrue ? Condition.EQ : Condition.NE;
|
||||
getLIRGeneratorTool().emitCompareAndSwapBranch(kind, address, expectedValue, newValue, condition, trueLabel, falseLabel, trueLabelProbability);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@MatchRule("(If (ObjectEquals=compare value FloatingRead=access))")
|
||||
public ComplexMatchResult ifLogicCas(IfNode root, CompareNode compare, ValueNode value, LIRLowerableAccess access) {
|
||||
return emitCompareBranchMemory(root, compare, value, access);
|
||||
}
|
||||
|
||||
@ -290,19 +382,19 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ComplexMatchResult binaryRead(AMD64RMOp op, OperandSize size, ValueNode value, Access access) {
|
||||
private ComplexMatchResult binaryRead(AMD64RMOp op, OperandSize size, ValueNode value, LIRLowerableAccess access) {
|
||||
return builder -> getArithmeticLIRGenerator().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()),
|
||||
getState(access));
|
||||
}
|
||||
|
||||
private ComplexMatchResult binaryRead(AMD64RRMOp op, OperandSize size, ValueNode value, Access access) {
|
||||
private ComplexMatchResult binaryRead(AMD64RRMOp op, OperandSize size, ValueNode value, LIRLowerableAccess access) {
|
||||
return builder -> getArithmeticLIRGenerator().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()),
|
||||
getState(access));
|
||||
}
|
||||
|
||||
@MatchRule("(Add value Read=access)")
|
||||
@MatchRule("(Add value FloatingRead=access)")
|
||||
public ComplexMatchResult addMemory(ValueNode value, Access access) {
|
||||
public ComplexMatchResult addMemory(ValueNode value, LIRLowerableAccess access) {
|
||||
OperandSize size = getMemorySize(access);
|
||||
if (size.isXmmType()) {
|
||||
TargetDescription target = getLIRGeneratorTool().target();
|
||||
@ -319,7 +411,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
|
||||
@MatchRule("(Sub value Read=access)")
|
||||
@MatchRule("(Sub value FloatingRead=access)")
|
||||
public ComplexMatchResult subMemory(ValueNode value, Access access) {
|
||||
public ComplexMatchResult subMemory(ValueNode value, LIRLowerableAccess access) {
|
||||
OperandSize size = getMemorySize(access);
|
||||
if (size.isXmmType()) {
|
||||
TargetDescription target = getLIRGeneratorTool().target();
|
||||
@ -336,7 +428,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
|
||||
@MatchRule("(Mul value Read=access)")
|
||||
@MatchRule("(Mul value FloatingRead=access)")
|
||||
public ComplexMatchResult mulMemory(ValueNode value, Access access) {
|
||||
public ComplexMatchResult mulMemory(ValueNode value, LIRLowerableAccess access) {
|
||||
OperandSize size = getMemorySize(access);
|
||||
if (size.isXmmType()) {
|
||||
TargetDescription target = getLIRGeneratorTool().target();
|
||||
@ -353,7 +445,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
|
||||
@MatchRule("(And value Read=access)")
|
||||
@MatchRule("(And value FloatingRead=access)")
|
||||
public ComplexMatchResult andMemory(ValueNode value, Access access) {
|
||||
public ComplexMatchResult andMemory(ValueNode value, LIRLowerableAccess access) {
|
||||
OperandSize size = getMemorySize(access);
|
||||
if (size.isXmmType()) {
|
||||
return null;
|
||||
@ -364,7 +456,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
|
||||
@MatchRule("(Or value Read=access)")
|
||||
@MatchRule("(Or value FloatingRead=access)")
|
||||
public ComplexMatchResult orMemory(ValueNode value, Access access) {
|
||||
public ComplexMatchResult orMemory(ValueNode value, LIRLowerableAccess access) {
|
||||
OperandSize size = getMemorySize(access);
|
||||
if (size.isXmmType()) {
|
||||
return null;
|
||||
@ -375,7 +467,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
|
||||
@MatchRule("(Xor value Read=access)")
|
||||
@MatchRule("(Xor value FloatingRead=access)")
|
||||
public ComplexMatchResult xorMemory(ValueNode value, Access access) {
|
||||
public ComplexMatchResult xorMemory(ValueNode value, LIRLowerableAccess access) {
|
||||
OperandSize size = getMemorySize(access);
|
||||
if (size.isXmmType()) {
|
||||
return null;
|
||||
@ -395,20 +487,44 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
|
||||
@MatchRule("(SignExtend Read=access)")
|
||||
@MatchRule("(SignExtend FloatingRead=access)")
|
||||
public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
|
||||
return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
|
||||
public ComplexMatchResult signExtend(SignExtendNode root, LIRLowerableAccess access) {
|
||||
return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits(), null);
|
||||
}
|
||||
|
||||
@MatchRule("(ZeroExtend Read=access)")
|
||||
@MatchRule("(ZeroExtend FloatingRead=access)")
|
||||
public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
|
||||
public ComplexMatchResult zeroExtend(ZeroExtendNode root, LIRLowerableAccess access) {
|
||||
AMD64Kind memoryKind = getMemoryKind(access);
|
||||
return builder -> getArithmeticLIRGenerator().emitZeroExtendMemory(memoryKind, root.getResultBits(), (AMD64AddressValue) operand(access.getAddress()), getState(access));
|
||||
}
|
||||
|
||||
@MatchRule("(Narrow Read=access)")
|
||||
@MatchRule("(Narrow FloatingRead=access)")
|
||||
public ComplexMatchResult narrowRead(NarrowNode root, LIRLowerableAccess access) {
|
||||
return new ComplexMatchResult() {
|
||||
@Override
|
||||
public Value evaluate(NodeLIRBuilder builder) {
|
||||
AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
|
||||
LIRKind addressKind = LIRKind.combineDerived(getLIRGeneratorTool().getLIRKind(root.asNode().stamp()),
|
||||
address.getBase(), address.getIndex());
|
||||
AMD64AddressValue newAddress = address.withKind(addressKind);
|
||||
LIRKind readKind = getLIRGeneratorTool().getLIRKind(root.stamp());
|
||||
return getArithmeticLIRGenerator().emitZeroExtendMemory((AMD64Kind) readKind.getPlatformKind(),
|
||||
root.getResultBits(), newAddress, getState(access));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@MatchRule("(SignExtend (Narrow=narrow Read=access))")
|
||||
@MatchRule("(SignExtend (Narrow=narrow FloatingRead=access))")
|
||||
public ComplexMatchResult signExtendNarrowRead(SignExtendNode root, NarrowNode narrow, LIRLowerableAccess access) {
|
||||
LIRKind kind = getLIRGeneratorTool().getLIRKind(narrow.stamp());
|
||||
return emitSignExtendMemory(access, narrow.getResultBits(), root.getResultBits(), kind);
|
||||
}
|
||||
|
||||
@MatchRule("(FloatConvert Read=access)")
|
||||
@MatchRule("(FloatConvert FloatingRead=access)")
|
||||
public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) {
|
||||
public ComplexMatchResult floatConvert(FloatConvertNode root, LIRLowerableAccess access) {
|
||||
switch (root.getFloatConvert()) {
|
||||
case D2F:
|
||||
return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSD2SS, SD, access);
|
||||
@ -437,7 +553,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
|
||||
|
||||
@MatchRule("(Reinterpret Read=access)")
|
||||
@MatchRule("(Reinterpret FloatingRead=access)")
|
||||
public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) {
|
||||
public ComplexMatchResult reinterpret(ReinterpretNode root, LIRLowerableAccess access) {
|
||||
return builder -> {
|
||||
LIRKind kind = getLIRGeneratorTool().getLIRKind(root.stamp());
|
||||
return emitReinterpretMemory(kind, access);
|
||||
|
@ -26,6 +26,7 @@ import org.graalvm.compiler.java.DefaultSuitesProvider;
|
||||
import org.graalvm.compiler.lir.amd64.phases.StackMoveOptimizationPhase;
|
||||
import org.graalvm.compiler.lir.phases.LIRSuites;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
|
||||
|
||||
public class AMD64SuitesProvider extends DefaultSuitesProvider {
|
||||
@ -35,9 +36,9 @@ public class AMD64SuitesProvider extends DefaultSuitesProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public LIRSuites createLIRSuites() {
|
||||
LIRSuites lirSuites = super.createLIRSuites();
|
||||
if (StackMoveOptimizationPhase.Options.LIROptStackMoveOptimizer.getValue()) {
|
||||
public LIRSuites createLIRSuites(OptionValues options) {
|
||||
LIRSuites lirSuites = super.createLIRSuites(options);
|
||||
if (StackMoveOptimizationPhase.Options.LIROptStackMoveOptimizer.getValue(options)) {
|
||||
/* Note: this phase must be inserted <b>after</b> RedundantMoveElimination */
|
||||
lirSuites.getPostAllocationOptimizationStage().appendPhase(new StackMoveOptimizationPhase());
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.core.common;
|
||||
|
||||
/**
|
||||
* A {@linkplain RetryableBailoutException} that will be thrown if an on-going compilation in the
|
||||
* compiler was cancelled.
|
||||
*/
|
||||
public final class CancellationBailoutException extends RetryableBailoutException {
|
||||
|
||||
private static final long serialVersionUID = 6551793589275293360L;
|
||||
|
||||
public CancellationBailoutException() {
|
||||
super("Compilation cancelled.");
|
||||
}
|
||||
|
||||
public static void cancelCompilation() {
|
||||
throw new CancellationBailoutException();
|
||||
}
|
||||
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.core.common;
|
||||
|
||||
import static org.graalvm.compiler.core.common.CollectionsFactory.Mode.STANDARD;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Factory for creating collection objects used during compilation.
|
||||
*/
|
||||
public class CollectionsFactory {
|
||||
|
||||
private static final ThreadLocal<Mode> tl = new ThreadLocal<>();
|
||||
|
||||
public static class ModeScope implements AutoCloseable {
|
||||
private final Mode previousMode;
|
||||
|
||||
public ModeScope(Mode previousMode) {
|
||||
this.previousMode = previousMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
tl.set(previousMode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constants denoting what type of collections are {@link CollectionsFactory#getMode()
|
||||
* currently} returned by the factory.
|
||||
*/
|
||||
public enum Mode {
|
||||
/**
|
||||
* Denotes standard collections such as {@link HashSet} and {@link HashMap}.
|
||||
*/
|
||||
STANDARD,
|
||||
|
||||
/**
|
||||
* Denotes collections that have a deterministic iteration order over their keys/entries.
|
||||
*/
|
||||
DETERMINISTIC_ITERATION_ORDER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current mode determining the type of collection objects created by this factory.
|
||||
*/
|
||||
public static Mode getMode() {
|
||||
Mode mode = tl.get();
|
||||
return mode == null ? Mode.STANDARD : mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the mode for the current thread.
|
||||
*
|
||||
* @return an object which when {@linkplain ModeScope#close() closed} will revert the mode of
|
||||
* the current thread to the state before calling this method
|
||||
*/
|
||||
public static ModeScope changeMode(Mode mode) {
|
||||
Mode previousMode = tl.get();
|
||||
tl.set(mode);
|
||||
return new ModeScope(previousMode);
|
||||
}
|
||||
|
||||
public static <K, V> HashMap<K, V> newMap() {
|
||||
return getMode() == STANDARD ? new HashMap<>() : new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public static <K, V> HashMap<K, V> newMap(Map<K, V> m) {
|
||||
return getMode() == STANDARD ? new HashMap<>(m) : new LinkedHashMap<>(m);
|
||||
}
|
||||
|
||||
public static <K, V> HashMap<K, V> newMap(int initialCapacity) {
|
||||
return getMode() == STANDARD ? new HashMap<>(initialCapacity) : new LinkedHashMap<>(initialCapacity);
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> newIdentityMap() {
|
||||
return getMode() == STANDARD ? new IdentityHashMap<>() : new LinkedIdentityHashMap<>();
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
|
||||
return getMode() == STANDARD ? new IdentityHashMap<>(expectedMaxSize) : new LinkedIdentityHashMap<>();
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> newIdentityMap(Map<K, V> m) {
|
||||
return getMode() == STANDARD ? new IdentityHashMap<>(m) : new LinkedIdentityHashMap<>(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a set. If the current thread is {@linkplain CollectionsFactory#getMode() using}
|
||||
* {@link Mode#DETERMINISTIC_ITERATION_ORDER} collections, the returned set will have an
|
||||
* iteration order determined by the order in which elements are inserted in the set.
|
||||
*/
|
||||
public static <E> Set<E> newSet() {
|
||||
return CollectionsFactory.getMode() == Mode.STANDARD ? new HashSet<>() : new LinkedHashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #newSet()
|
||||
*/
|
||||
public static <E> Set<E> newSet(Collection<? extends E> c) {
|
||||
return CollectionsFactory.getMode() == Mode.STANDARD ? new HashSet<>(c) : new LinkedHashSet<>(c);
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -20,20 +20,18 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot;
|
||||
package org.graalvm.compiler.core.common;
|
||||
|
||||
/**
|
||||
* A compact representation of the different encoding strategies for Objects and metadata.
|
||||
*/
|
||||
public class CompressEncoding {
|
||||
public final long base;
|
||||
public final int shift;
|
||||
public final int alignment;
|
||||
public final class CompressEncoding {
|
||||
private final long base;
|
||||
private final int shift;
|
||||
|
||||
CompressEncoding(long base, int shift, int alignment) {
|
||||
public CompressEncoding(long base, int shift) {
|
||||
this.base = base;
|
||||
this.shift = shift;
|
||||
this.alignment = alignment;
|
||||
}
|
||||
|
||||
public int compress(long ptr) {
|
||||
@ -44,6 +42,22 @@ public class CompressEncoding {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasBase() {
|
||||
return base != 0;
|
||||
}
|
||||
|
||||
public boolean hasShift() {
|
||||
return shift != 0;
|
||||
}
|
||||
|
||||
public long getBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
public int getShift() {
|
||||
return shift;
|
||||
}
|
||||
|
||||
public long uncompress(int ptr) {
|
||||
if (ptr == 0) {
|
||||
return 0L;
|
||||
@ -54,14 +68,13 @@ public class CompressEncoding {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "base: " + base + " shift: " + shift + " alignment: " + alignment;
|
||||
return "base: " + base + " shift: " + shift;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + alignment;
|
||||
result = prime * result + (int) (base ^ (base >>> 32));
|
||||
result = prime * result + shift;
|
||||
return result;
|
||||
@ -71,7 +84,7 @@ public class CompressEncoding {
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof CompressEncoding) {
|
||||
CompressEncoding other = (CompressEncoding) obj;
|
||||
return alignment == other.alignment && base == other.base && shift == other.shift;
|
||||
return base == other.base && shift == other.shift;
|
||||
} else {
|
||||
return false;
|
||||
}
|
@ -22,10 +22,10 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.common;
|
||||
|
||||
import org.graalvm.compiler.debug.Assertions;
|
||||
import org.graalvm.compiler.options.Option;
|
||||
import org.graalvm.compiler.options.OptionType;
|
||||
import org.graalvm.compiler.options.OptionValue;
|
||||
import org.graalvm.compiler.options.StableOptionValue;
|
||||
import org.graalvm.compiler.options.OptionKey;
|
||||
|
||||
/**
|
||||
* This class encapsulates options that control the behavior of the Graal compiler.
|
||||
@ -34,250 +34,242 @@ import org.graalvm.compiler.options.StableOptionValue;
|
||||
public final class GraalOptions {
|
||||
|
||||
@Option(help = "Use compiler intrinsifications.", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> Intrinsify = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> Intrinsify = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "Inline calls with monomorphic type profile.", type = OptionType.Expert)
|
||||
public static final OptionValue<Boolean> InlineMonomorphicCalls = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> InlineMonomorphicCalls = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "Inline calls with polymorphic type profile.", type = OptionType.Expert)
|
||||
public static final OptionValue<Boolean> InlinePolymorphicCalls = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> InlinePolymorphicCalls = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "Inline calls with megamorphic type profile (i.e., not all types could be recorded).", type = OptionType.Expert)
|
||||
public static final OptionValue<Boolean> InlineMegamorphicCalls = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> InlineMegamorphicCalls = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "Maximum desired size of the compiler graph in nodes.", type = OptionType.User)
|
||||
public static final OptionValue<Integer> MaximumDesiredSize = new OptionValue<>(20000);
|
||||
public static final OptionKey<Integer> MaximumDesiredSize = new OptionKey<>(20000);
|
||||
|
||||
@Option(help = "Minimum probability for methods to be inlined for megamorphic type profiles.", type = OptionType.Expert)
|
||||
public static final OptionValue<Double> MegamorphicInliningMinMethodProbability = new OptionValue<>(0.33D);
|
||||
public static final OptionKey<Double> MegamorphicInliningMinMethodProbability = new OptionKey<>(0.33D);
|
||||
|
||||
@Option(help = "Maximum level of recursive inlining.", type = OptionType.Expert)
|
||||
public static final OptionValue<Integer> MaximumRecursiveInlining = new OptionValue<>(5);
|
||||
public static final OptionKey<Integer> MaximumRecursiveInlining = new OptionKey<>(5);
|
||||
|
||||
@Option(help = "Graphs with less than this number of nodes are trivial and therefore always inlined.", type = OptionType.Expert)
|
||||
public static final OptionValue<Integer> TrivialInliningSize = new OptionValue<>(10);
|
||||
public static final OptionKey<Integer> TrivialInliningSize = new OptionKey<>(10);
|
||||
|
||||
@Option(help = "Inlining is explored up to this number of nodes in the graph for each call site.", type = OptionType.Expert)
|
||||
public static final OptionValue<Integer> MaximumInliningSize = new OptionValue<>(300);
|
||||
public static final OptionKey<Integer> MaximumInliningSize = new OptionKey<>(300);
|
||||
|
||||
@Option(help = "If the previous low-level graph size of the method exceeds the threshold, it is not inlined.", type = OptionType.Expert)
|
||||
public static final OptionValue<Integer> SmallCompiledLowLevelGraphSize = new OptionValue<>(300);
|
||||
public static final OptionKey<Integer> SmallCompiledLowLevelGraphSize = new OptionKey<>(300);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Double> LimitInlinedInvokes = new OptionValue<>(5.0);
|
||||
public static final OptionKey<Double> LimitInlinedInvokes = new OptionKey<>(5.0);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Boolean> InlineEverything = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> InlineEverything = new OptionKey<>(false);
|
||||
|
||||
// escape analysis settings
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> PartialEscapeAnalysis = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> PartialEscapeAnalysis = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Integer> EscapeAnalysisIterations = new OptionValue<>(2);
|
||||
public static final OptionKey<Integer> EscapeAnalysisIterations = new OptionKey<>(2);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Integer> EscapeAnalysisLoopCutoff = new OptionValue<>(20);
|
||||
public static final OptionKey<Integer> EscapeAnalysisLoopCutoff = new OptionKey<>(20);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<String> EscapeAnalyzeOnly = new OptionValue<>(null);
|
||||
public static final OptionKey<String> EscapeAnalyzeOnly = new OptionKey<>(null);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Integer> MaximumEscapeAnalysisArrayLength = new OptionValue<>(32);
|
||||
public static final OptionKey<Integer> MaximumEscapeAnalysisArrayLength = new OptionKey<>(32);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> PEAInliningHints = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> PEAInliningHints = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Double> TailDuplicationProbability = new OptionValue<>(0.5);
|
||||
public static final OptionKey<Double> TailDuplicationProbability = new OptionKey<>(0.5);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Integer> TailDuplicationTrivialSize = new OptionValue<>(1);
|
||||
public static final OptionKey<Integer> TailDuplicationTrivialSize = new OptionKey<>(1);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Integer> DeoptsToDisableOptimisticOptimization = new OptionValue<>(40);
|
||||
public static final OptionKey<Integer> DeoptsToDisableOptimisticOptimization = new OptionKey<>(40);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> LoopPeeling = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> LoopPeeling = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> ReassociateInvariants = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> ReassociateInvariants = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> FullUnroll = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> FullUnroll = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> LoopUnswitch = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> LoopUnswitch = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Float> MinimumPeelProbability = new OptionValue<>(0.35f);
|
||||
public static final OptionKey<Float> MinimumPeelProbability = new OptionKey<>(0.35f);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Integer> LoopMaxUnswitch = new OptionValue<>(3);
|
||||
public static final OptionKey<Integer> LoopMaxUnswitch = new OptionKey<>(3);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> UseLoopLimitChecks = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> UseLoopLimitChecks = new OptionKey<>(true);
|
||||
|
||||
// debugging settings
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> ZapStackOnMethodEntry = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> ZapStackOnMethodEntry = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> DeoptALot = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> DeoptALot = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "Stress the code emitting explicit exception throwing code.", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> StressExplicitExceptionCode = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> StressExplicitExceptionCode = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "Stress the code emitting invokes with explicit exception edges.", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> StressInvokeWithExceptionNode = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> StressInvokeWithExceptionNode = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "Stress the code by emitting reads at earliest instead of latest point.", type = OptionType.Debug)
|
||||
public static final OptionKey<Boolean> StressTestEarlyReads = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> VerifyPhases = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> VerifyPhases = new OptionKey<>(false);
|
||||
|
||||
// Debug settings:
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Integer> GCDebugStartCycle = new OptionValue<>(-1);
|
||||
public static final OptionKey<Integer> GCDebugStartCycle = new OptionKey<>(-1);
|
||||
|
||||
@Option(help = "Perform platform dependent validation of the Java heap at returns", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> VerifyHeapAtReturn = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> VerifyHeapAtReturn = new OptionKey<>(false);
|
||||
|
||||
// Other printing settings
|
||||
@Option(help = "Print profiling information when parsing a method's bytecode", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> PrintProfilingInformation = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> PrintProfilingInformation = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final StableOptionValue<Boolean> TraceEscapeAnalysis = new StableOptionValue<>(false);
|
||||
public static final OptionKey<Boolean> TraceEscapeAnalysis = new OptionKey<>(false);
|
||||
|
||||
// HotSpot command line options
|
||||
@Option(help = "Print inlining optimizations", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> HotSpotPrintInlining = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> HotSpotPrintInlining = new OptionKey<>(false);
|
||||
|
||||
// Register allocator debugging
|
||||
@Option(help = "Comma separated list of registers that register allocation is limited to.", type = OptionType.Debug)
|
||||
public static final OptionValue<String> RegisterPressure = new OptionValue<>(null);
|
||||
public static final OptionKey<String> RegisterPressure = new OptionKey<>(null);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> ConditionalElimination = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> ConditionalElimination = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> RemoveNeverExecutedCode = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> RawConditionalElimination = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> UseExceptionProbability = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> ReplaceInputsWithConstantsBasedOnStamps = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> UseExceptionProbabilityForOperations = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> RemoveNeverExecutedCode = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OmitHotExceptionStacktrace = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> UseExceptionProbability = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> GenSafepoints = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OmitHotExceptionStacktrace = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> GenLoopSafepoints = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> GenSafepoints = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> UseTypeCheckHints = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> GenLoopSafepoints = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionKey<Boolean> UseTypeCheckHints = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Boolean> InlineVTableStubs = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> InlineVTableStubs = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Boolean> AlwaysInlineVTableStubs = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> AlwaysInlineVTableStubs = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> ResolveClassBeforeStaticInvoke = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> ResolveClassBeforeStaticInvoke = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> CanOmitFrame = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> CanOmitFrame = new OptionKey<>(true);
|
||||
|
||||
// Ahead of time compilation
|
||||
@Option(help = "Try to avoid emitting code where patching is required", type = OptionType.Expert)
|
||||
public static final OptionValue<Boolean> ImmutableCode = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> ImmutableCode = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "Generate position independent code", type = OptionType.Expert)
|
||||
public static final OptionValue<Boolean> GeneratePIC = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> GeneratePIC = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Boolean> CallArrayCopy = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> CallArrayCopy = new OptionKey<>(true);
|
||||
|
||||
// Runtime settings
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Boolean> SupportJsrBytecodes = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> SupportJsrBytecodes = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Expert)
|
||||
public static final OptionValue<Boolean> OptAssumptions = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptAssumptions = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptConvertDeoptsToGuards = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptConvertDeoptsToGuards = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptReadElimination = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptReadElimination = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Integer> ReadEliminationMaxLoopVisits = new OptionValue<>(5);
|
||||
public static final OptionKey<Integer> ReadEliminationMaxLoopVisits = new OptionKey<>(5);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptDeoptimizationGrouping = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptDeoptimizationGrouping = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptScheduleOutOfLoops = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptScheduleOutOfLoops = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptEliminateGuards = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptEliminateGuards = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptImplicitNullChecks = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptImplicitNullChecks = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptClearNonLiveLocals = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptClearNonLiveLocals = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptLoopTransform = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptLoopTransform = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptFloatingReads = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptFloatingReads = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptEliminatePartiallyRedundantGuards = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptEliminatePartiallyRedundantGuards = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptFilterProfiledTypes = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptFilterProfiledTypes = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptDevirtualizeInvokesOptimistically = new OptionValue<>(true);
|
||||
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> OptPushThroughPi = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> OptDevirtualizeInvokesOptimistically = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "Allow backend to match complex expressions.", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> MatchExpressions = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> MatchExpressions = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "Enable counters for various paths in snippets.", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> SnippetCounters = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> SnippetCounters = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "Eagerly construct extra snippet info.", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> EagerSnippets = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> EagerSnippets = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "Use a cache for snippet graphs.", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> UseSnippetGraphCache = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> UseSnippetGraphCache = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "Enable expensive assertions", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> DetailedAsserts = new StableOptionValue<Boolean>() {
|
||||
@Override
|
||||
protected Boolean defaultValue() {
|
||||
boolean enabled = false;
|
||||
// turn detailed assertions on when the general assertions are on (misusing the assert keyword for this)
|
||||
assert (enabled = true) == true;
|
||||
return enabled;
|
||||
}
|
||||
};
|
||||
|
||||
@Option(help = "Enable Graal instrumentation")
|
||||
public static final OptionValue<Boolean> UseGraalInstrumentation = new OptionValue<>(false);
|
||||
@Option(help = "Enable expensive assertions.", type = OptionType.Debug)
|
||||
public static final OptionKey<Boolean> DetailedAsserts = new OptionKey<>(Assertions.ENABLED);
|
||||
|
||||
@Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug)
|
||||
public static final OptionValue<Boolean> TraceRA = new OptionValue<>(false);
|
||||
public static final OptionKey<Boolean> TraceRA = new OptionKey<>(false);
|
||||
|
||||
}
|
||||
|
@ -1,285 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.core.common;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A map that combines {@link IdentityHashMap} with {@link LinkedHashMap} for the purpose of
|
||||
* ensuring a deterministic execution order during a capturing compilation.
|
||||
*/
|
||||
final class LinkedIdentityHashMap<K, V> implements Map<K, V> {
|
||||
|
||||
private final LinkedHashMap<Id<K>, V> map;
|
||||
|
||||
LinkedIdentityHashMap() {
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
LinkedIdentityHashMap(Map<K, V> m) {
|
||||
map = new LinkedHashMap<>(m.size());
|
||||
putAll(m);
|
||||
}
|
||||
|
||||
LinkedIdentityHashMap(int expectedMaxSize) {
|
||||
map = new LinkedHashMap<>(expectedMaxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for an object that gives uses the object's identity for the purpose of equality
|
||||
* comparisons and computing a hash code.
|
||||
*/
|
||||
static final class Id<T> {
|
||||
final T object;
|
||||
|
||||
Id(T object) {
|
||||
assert object != null;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof Id && ((Id<T>) obj).object == object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(object);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return map.containsKey(id(key));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Id<K> id(Object key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
return new Id<>((K) key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
return map.get(id(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
return map.put(id(key), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
return map.remove(id(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
if (m == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (m.getClass() == getClass()) {
|
||||
LinkedIdentityHashMap<K, V> that = (LinkedIdentityHashMap<K, V>) m;
|
||||
map.putAll(that.map);
|
||||
|
||||
} else {
|
||||
for (K key : m.keySet()) {
|
||||
map.put(id(key), m.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
final class KeySet extends AbstractSet<K> {
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<K> iterator() {
|
||||
return new Iterator<K>() {
|
||||
final Iterator<Id<K>> i = map.keySet().iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K next() {
|
||||
return i.next().object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
i.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return containsKey(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return LinkedIdentityHashMap.this.remove(o) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<K> spliterator() {
|
||||
return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super K> action) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return new KeySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
final class EntrySet extends AbstractSet<Map.Entry<K, V>> {
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<K, V>> iterator() {
|
||||
return new Iterator<Map.Entry<K, V>>() {
|
||||
final Iterator<Map.Entry<Id<K>, V>> i = map.entrySet().iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map.Entry<K, V> next() {
|
||||
Map.Entry<Id<K>, V> e = i.next();
|
||||
return new Map.Entry<K, V>() {
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return e.getKey().object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return e.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
return e.setValue(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
i.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<Map.Entry<K, V>> spliterator() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super Map.Entry<K, V>> action) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Map.Entry<K, V>> entrySet() {
|
||||
return new EntrySet();
|
||||
}
|
||||
}
|
@ -22,8 +22,6 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.common;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
|
||||
// JaCoCo Exclude
|
||||
|
||||
/**
|
||||
@ -32,7 +30,7 @@ import java.util.IdentityHashMap;
|
||||
*
|
||||
* Clients of {@link LocationIdentity} must use {@link #equals(Object)}, not {@code ==}, when
|
||||
* comparing two {@link LocationIdentity} values for equality. Likewise, they must not use
|
||||
* {@link IdentityHashMap}s with {@link LocationIdentity} values as keys.
|
||||
* {@link java.util.IdentityHashMap}s with {@link LocationIdentity} values as keys.
|
||||
*/
|
||||
public abstract class LocationIdentity {
|
||||
|
||||
@ -48,12 +46,39 @@ public abstract class LocationIdentity {
|
||||
}
|
||||
}
|
||||
|
||||
public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity();
|
||||
private static final class InitLocationIdentity extends LocationIdentity {
|
||||
@Override
|
||||
public boolean isImmutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "INIT_LOCATION";
|
||||
}
|
||||
}
|
||||
|
||||
public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity();
|
||||
public static final LocationIdentity INIT_LOCATION = new InitLocationIdentity();
|
||||
|
||||
/**
|
||||
* Indicates that the given location is the union of all possible mutable locations. A write to
|
||||
* such a location kill all reads from mutable locations and a read from this location is killed
|
||||
* by any write (except for initialization writes).
|
||||
*/
|
||||
public static LocationIdentity any() {
|
||||
return ANY_LOCATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Location only allowed to be used for writes. Indicates that a completely new memory location
|
||||
* is written. Kills no read. The previous value at the given location must be either
|
||||
* uninitialized or null. Writes to this location do not need a GC pre-barrier.
|
||||
*/
|
||||
public static LocationIdentity init() {
|
||||
return INIT_LOCATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Denotes a location is unchanging in all cases. Not that this is different than the Java
|
||||
* notion of final which only requires definite assignment.
|
||||
@ -68,6 +93,10 @@ public abstract class LocationIdentity {
|
||||
return this == ANY_LOCATION;
|
||||
}
|
||||
|
||||
public final boolean isInit() {
|
||||
return this == INIT_LOCATION;
|
||||
}
|
||||
|
||||
public final boolean isSingle() {
|
||||
return this != ANY_LOCATION;
|
||||
}
|
||||
|
@ -20,10 +20,12 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.asm;
|
||||
package org.graalvm.compiler.core.common;
|
||||
|
||||
// JaCoCo Exclude
|
||||
|
||||
import jdk.vm.ci.code.CodeUtil;
|
||||
|
||||
/**
|
||||
* A collection of static utility functions that check ranges of numbers.
|
||||
*/
|
||||
@ -183,4 +185,43 @@ public class NumUtil {
|
||||
return 0xFFFFFFFFFFFFFFFFL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum value representable in a {@code bits} bit signed integer.
|
||||
*/
|
||||
public static long minValue(int bits) {
|
||||
return CodeUtil.minValue(bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum value representable in a {@code bits} bit signed integer.
|
||||
*/
|
||||
public static long maxValue(int bits) {
|
||||
return CodeUtil.maxValue(bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum value representable in a {@code bits} bit unsigned integer.
|
||||
*/
|
||||
public static long maxValueUnsigned(int bits) {
|
||||
return getNbitNumberLong(bits);
|
||||
}
|
||||
|
||||
public static long maxUnsigned(long a, long b) {
|
||||
if (Long.compareUnsigned(a, b) > 0) {
|
||||
return b;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
public static long minUnsigned(long a, long b) {
|
||||
if (Long.compareUnsigned(a, b) > 0) {
|
||||
return a;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
public static boolean sameSign(long a, long b) {
|
||||
return a < 0 == b < 0;
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.common;
|
||||
package org.graalvm.compiler.core.common;
|
||||
|
||||
import jdk.vm.ci.code.BailoutException;
|
||||
|
@ -20,7 +20,7 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.common;
|
||||
package org.graalvm.compiler.core.common;
|
||||
|
||||
import jdk.vm.ci.code.BailoutException;
|
||||
|
@ -22,18 +22,15 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.common.alloc;
|
||||
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.graalvm.compiler.core.common.GraalOptions;
|
||||
import org.graalvm.util.EconomicMap;
|
||||
import org.graalvm.util.Equivalence;
|
||||
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.RegisterArray;
|
||||
import jdk.vm.ci.code.RegisterConfig;
|
||||
import jdk.vm.ci.meta.PlatformKind;
|
||||
|
||||
import org.graalvm.compiler.core.common.GraalOptions;
|
||||
|
||||
/**
|
||||
* Configuration for register allocation. This is different to {@link RegisterConfig} as it only
|
||||
* returns registers specified by {@link GraalOptions#RegisterPressure}.
|
||||
@ -82,11 +79,10 @@ public class RegisterAllocationConfig {
|
||||
}
|
||||
|
||||
protected RegisterArray initAllocatable(RegisterArray registers) {
|
||||
if (RegisterPressure.getValue() != null && !RegisterPressure.getValue().equals(ALL_REGISTERS)) {
|
||||
String[] names = RegisterPressure.getValue().split(",");
|
||||
Register[] regs = new Register[names.length];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
regs[i] = findRegister(names[i], registers);
|
||||
if (allocationRestrictedTo != null) {
|
||||
Register[] regs = new Register[allocationRestrictedTo.length];
|
||||
for (int i = 0; i < allocationRestrictedTo.length; i++) {
|
||||
regs[i] = findRegister(allocationRestrictedTo[i], registers);
|
||||
}
|
||||
return new RegisterArray(regs);
|
||||
}
|
||||
@ -95,12 +91,18 @@ public class RegisterAllocationConfig {
|
||||
}
|
||||
|
||||
protected final RegisterConfig registerConfig;
|
||||
private final Map<PlatformKind.Key, AllocatableRegisters> categorized = new HashMap<>();
|
||||
private final EconomicMap<PlatformKind.Key, AllocatableRegisters> categorized = EconomicMap.create(Equivalence.DEFAULT);
|
||||
private final String[] allocationRestrictedTo;
|
||||
private RegisterArray cachedRegisters;
|
||||
|
||||
public RegisterAllocationConfig(RegisterConfig registerConfig) {
|
||||
/**
|
||||
* @param allocationRestrictedTo if not {@code null}, register allocation will be restricted to
|
||||
* registers whose names appear in this array
|
||||
*/
|
||||
public RegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) {
|
||||
assert registerConfig != null;
|
||||
this.registerConfig = registerConfig;
|
||||
this.allocationRestrictedTo = allocationRestrictedTo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,9 +22,6 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.common.cfg;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AbstractBlockBase<T extends AbstractBlockBase<T>> {
|
||||
|
||||
protected int id;
|
||||
@ -34,7 +31,8 @@ public abstract class AbstractBlockBase<T extends AbstractBlockBase<T>> {
|
||||
protected T[] successors;
|
||||
|
||||
private T dominator;
|
||||
private List<T> dominated;
|
||||
private T firstDominated;
|
||||
private T dominatedSibling;
|
||||
private int domNumber;
|
||||
private int maxChildDomNumber;
|
||||
|
||||
@ -97,19 +95,27 @@ public abstract class AbstractBlockBase<T extends AbstractBlockBase<T>> {
|
||||
this.domDepth = dominator.domDepth + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Level in the dominator tree starting with 0 for the start block.
|
||||
*/
|
||||
public int getDominatorDepth() {
|
||||
return domDepth;
|
||||
}
|
||||
|
||||
public List<T> getDominated() {
|
||||
if (dominated == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return dominated;
|
||||
public T getFirstDominated() {
|
||||
return this.firstDominated;
|
||||
}
|
||||
|
||||
public void setDominated(List<T> blocks) {
|
||||
dominated = blocks;
|
||||
public void setFirstDominated(T block) {
|
||||
this.firstDominated = block;
|
||||
}
|
||||
|
||||
public T getDominatedSibling() {
|
||||
return this.dominatedSibling;
|
||||
}
|
||||
|
||||
public void setDominatedSibling(T block) {
|
||||
this.dominatedSibling = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -158,4 +164,9 @@ public abstract class AbstractBlockBase<T extends AbstractBlockBase<T>> {
|
||||
public abstract double probability();
|
||||
|
||||
public abstract T getDominator(int distance);
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +81,8 @@ public interface AbstractControlFlowGraph<T extends AbstractBlockBase<T>> {
|
||||
return b;
|
||||
} else if (b == null) {
|
||||
return a;
|
||||
} else if (a == b) {
|
||||
return a;
|
||||
} else {
|
||||
int aDomDepth = a.getDominatorDepth();
|
||||
int bDomDepth = b.getDominatorDepth();
|
||||
|
@ -45,11 +45,22 @@ public class CFGVerifier {
|
||||
|
||||
if (block.getDominator() != null) {
|
||||
assert block.getDominator().getId() < block.getId();
|
||||
assert block.getDominator().getDominated().contains(block);
|
||||
|
||||
AbstractBlockBase<?> domChild = block.getDominator().getFirstDominated();
|
||||
while (domChild != null) {
|
||||
if (domChild == block) {
|
||||
break;
|
||||
}
|
||||
domChild = domChild.getDominatedSibling();
|
||||
}
|
||||
assert domChild != null : "dominators must contain block";
|
||||
}
|
||||
for (T dominated : block.getDominated()) {
|
||||
|
||||
T dominated = block.getFirstDominated();
|
||||
while (dominated != null) {
|
||||
assert dominated.getId() > block.getId();
|
||||
assert dominated.getDominator() == block;
|
||||
dominated = dominated.getDominatedSibling();
|
||||
}
|
||||
|
||||
T postDominatorBlock = block.getPostdominator();
|
||||
|
@ -105,4 +105,9 @@ public abstract class Loop<T extends AbstractBlockBase<T>> {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return index + depth * 31;
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.common.spi;
|
||||
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.ResolvedJavaField;
|
||||
|
||||
@ -32,6 +34,8 @@ public interface ConstantFieldProvider {
|
||||
|
||||
public interface ConstantFieldTool<T> {
|
||||
|
||||
OptionValues getOptions();
|
||||
|
||||
JavaConstant readValue();
|
||||
|
||||
JavaConstant getReceiver();
|
||||
|
@ -24,7 +24,7 @@ package org.graalvm.compiler.core.common.spi;
|
||||
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.options.Option;
|
||||
import org.graalvm.compiler.options.OptionValue;
|
||||
import org.graalvm.compiler.options.OptionKey;
|
||||
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.JavaType;
|
||||
@ -39,7 +39,7 @@ public abstract class JavaConstantFieldProvider implements ConstantFieldProvider
|
||||
|
||||
static class Options {
|
||||
@Option(help = "Determines whether to treat final fields with default values as constant.")//
|
||||
public static final OptionValue<Boolean> TrustFinalDefaultFields = new OptionValue<>(true);
|
||||
public static final OptionKey<Boolean> TrustFinalDefaultFields = new OptionKey<>(true);
|
||||
}
|
||||
|
||||
protected JavaConstantFieldProvider(MetaAccessProvider metaAccess) {
|
||||
@ -93,7 +93,7 @@ public abstract class JavaConstantFieldProvider implements ConstantFieldProvider
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) {
|
||||
return !value.isDefaultForKind() || Options.TrustFinalDefaultFields.getValue();
|
||||
return !value.isDefaultForKind() || Options.TrustFinalDefaultFields.getValue(tool.getOptions());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ -104,7 +104,7 @@ public abstract class JavaConstantFieldProvider implements ConstantFieldProvider
|
||||
if (isWellKnownImplicitStableField(field)) {
|
||||
return true;
|
||||
}
|
||||
if (field == stringHashField) {
|
||||
if (field.equals(stringHashField)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -59,8 +59,8 @@ public abstract class AbstractPointerStamp extends Stamp {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stamp join(Stamp stamp) {
|
||||
protected Stamp defaultPointerJoin(Stamp stamp) {
|
||||
assert getClass() == stamp.getClass();
|
||||
AbstractPointerStamp other = (AbstractPointerStamp) stamp;
|
||||
boolean joinNonNull = this.nonNull || other.nonNull;
|
||||
boolean joinAlwaysNull = this.alwaysNull || other.alwaysNull;
|
||||
@ -89,6 +89,42 @@ public abstract class AbstractPointerStamp extends Stamp {
|
||||
return copyWith(false, false);
|
||||
}
|
||||
|
||||
public static Stamp pointerNonNull(Stamp stamp) {
|
||||
AbstractPointerStamp pointer = (AbstractPointerStamp) stamp;
|
||||
return pointer.asNonNull();
|
||||
}
|
||||
|
||||
public static Stamp pointerMaybeNull(Stamp stamp) {
|
||||
AbstractPointerStamp pointer = (AbstractPointerStamp) stamp;
|
||||
return pointer.asMaybeNull();
|
||||
}
|
||||
|
||||
public static Stamp pointerAlwaysNull(Stamp stamp) {
|
||||
AbstractPointerStamp pointer = (AbstractPointerStamp) stamp;
|
||||
return pointer.asAlwaysNull();
|
||||
}
|
||||
|
||||
public Stamp asNonNull() {
|
||||
if (isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
return copyWith(true, false);
|
||||
}
|
||||
|
||||
public Stamp asMaybeNull() {
|
||||
if (isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
return copyWith(false, false);
|
||||
}
|
||||
|
||||
public Stamp asAlwaysNull() {
|
||||
if (isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
return copyWith(false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
|
@ -27,11 +27,6 @@ import static jdk.vm.ci.meta.MetaUtil.getSimpleName;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.vm.ci.meta.Constant;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
|
||||
import org.graalvm.compiler.core.common.calc.FloatConvert;
|
||||
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add;
|
||||
@ -52,6 +47,10 @@ import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Abs;
|
||||
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Neg;
|
||||
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Not;
|
||||
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Sqrt;
|
||||
import org.graalvm.util.CollectionsUtil;
|
||||
|
||||
import jdk.vm.ci.meta.Constant;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
|
||||
/**
|
||||
* Information about arithmetic operations.
|
||||
@ -95,12 +94,6 @@ public final class ArithmeticOpTable {
|
||||
|
||||
public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
|
||||
|
||||
public ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
|
||||
BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend,
|
||||
IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, FloatConvertOp... floatConvert) {
|
||||
this(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, Stream.of(floatConvert));
|
||||
}
|
||||
|
||||
public interface ArithmeticOpWrapper {
|
||||
|
||||
<OP> UnaryOp<OP> wrapUnaryOp(UnaryOp<OP> op);
|
||||
@ -147,14 +140,13 @@ public final class ArithmeticOpTable {
|
||||
IntegerConvertOp<SignExtend> signExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getSignExtend());
|
||||
IntegerConvertOp<Narrow> narrow = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getNarrow());
|
||||
|
||||
Stream<FloatConvertOp> floatConvert = Stream.of(inner.floatConvert).filter(Objects::nonNull).map(wrapper::wrapFloatConvertOp);
|
||||
|
||||
FloatConvertOp[] floatConvert = CollectionsUtil.filterAndMapToArray(inner.floatConvert, Objects::nonNull, wrapper::wrapFloatConvertOp, FloatConvertOp[]::new);
|
||||
return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert);
|
||||
}
|
||||
|
||||
private ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
|
||||
protected ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
|
||||
BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend,
|
||||
IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, Stream<FloatConvertOp> floatConvert) {
|
||||
IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, FloatConvertOp... floatConvert) {
|
||||
this.neg = neg;
|
||||
this.add = add;
|
||||
this.sub = sub;
|
||||
@ -174,7 +166,9 @@ public final class ArithmeticOpTable {
|
||||
this.signExtend = signExtend;
|
||||
this.narrow = narrow;
|
||||
this.floatConvert = new FloatConvertOp[FloatConvert.values().length];
|
||||
floatConvert.forEach(op -> this.floatConvert[op.getFloatConvert().ordinal()] = op);
|
||||
for (FloatConvertOp op : floatConvert) {
|
||||
this.floatConvert[op.getFloatConvert().ordinal()] = op;
|
||||
}
|
||||
|
||||
this.hash = Objects.hash(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow);
|
||||
}
|
||||
@ -318,7 +312,7 @@ public final class ArithmeticOpTable {
|
||||
}
|
||||
|
||||
public static String toString(Op... ops) {
|
||||
return Arrays.asList(ops).stream().map(o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}").collect(Collectors.joining(","));
|
||||
return CollectionsUtil.mapAndJoin(ops, o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}", ",");
|
||||
}
|
||||
|
||||
private boolean opsEquals(ArithmeticOpTable that) {
|
||||
@ -742,6 +736,11 @@ public final class ArithmeticOpTable {
|
||||
protected Narrow() {
|
||||
super("Narrow");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected IntegerConvertOp(String op) {
|
||||
@ -755,5 +754,10 @@ public final class ArithmeticOpTable {
|
||||
public IntegerConvertOp<T> unwrap() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the stamp of the input for the given output stamp.
|
||||
*/
|
||||
public abstract Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp);
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,11 @@ public abstract class ArithmeticStamp extends Stamp {
|
||||
|
||||
@Override
|
||||
public Stamp improveWith(Stamp other) {
|
||||
return this.join(other);
|
||||
if (this.isCompatible(other)) {
|
||||
return this.join(other);
|
||||
}
|
||||
// Cannot improve, because stamps are not compatible.
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,7 +69,7 @@ public abstract class ArithmeticStamp extends Stamp {
|
||||
if (!(obj instanceof ArithmeticStamp)) {
|
||||
return false;
|
||||
}
|
||||
assert Objects.equals(ops, ((ArithmeticStamp) obj).ops);
|
||||
assert Objects.equals(ops, ((ArithmeticStamp) obj).ops) : ops + " vs. " + ((ArithmeticStamp) obj).ops;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -301,10 +301,6 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isConstant() {
|
||||
return (nonNaN && Double.compare(lowerBound, upperBound) == 0);
|
||||
}
|
||||
|
||||
private static final ArithmeticOpTable OPS = new ArithmeticOpTable(
|
||||
|
||||
new UnaryOp.Neg() {
|
||||
|
@ -31,6 +31,7 @@ import java.nio.ByteBuffer;
|
||||
import java.util.Formatter;
|
||||
|
||||
import org.graalvm.compiler.core.common.LIRKind;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.core.common.spi.LIRKindTool;
|
||||
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
|
||||
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp;
|
||||
@ -54,41 +55,101 @@ import jdk.vm.ci.meta.SerializableConstant;
|
||||
* The description consists of (inclusive) lower and upper bounds and up (may be set) and down
|
||||
* (always set) bit-masks.
|
||||
*/
|
||||
public class IntegerStamp extends PrimitiveStamp {
|
||||
public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
private final long lowerBound;
|
||||
private final long upperBound;
|
||||
private final long downMask;
|
||||
private final long upMask;
|
||||
|
||||
public IntegerStamp(int bits, long lowerBound, long upperBound, long downMask, long upMask) {
|
||||
private IntegerStamp(int bits, long lowerBound, long upperBound, long downMask, long upMask) {
|
||||
super(bits, OPS);
|
||||
|
||||
this.lowerBound = lowerBound;
|
||||
this.upperBound = upperBound;
|
||||
this.downMask = downMask;
|
||||
this.upMask = upMask;
|
||||
|
||||
assert lowerBound >= CodeUtil.minValue(bits) : this;
|
||||
assert upperBound <= CodeUtil.maxValue(bits) : this;
|
||||
assert (downMask & CodeUtil.mask(bits)) == downMask : this;
|
||||
assert (upMask & CodeUtil.mask(bits)) == upMask : this;
|
||||
}
|
||||
|
||||
public static IntegerStamp stampForMask(int bits, long downMask, long upMask) {
|
||||
long lowerBound;
|
||||
long upperBound;
|
||||
if (((upMask >>> (bits - 1)) & 1) == 0) {
|
||||
lowerBound = downMask;
|
||||
upperBound = upMask;
|
||||
} else if (((downMask >>> (bits - 1)) & 1) == 1) {
|
||||
lowerBound = downMask;
|
||||
upperBound = upMask;
|
||||
public static IntegerStamp create(int bits, long lowerBoundInput, long upperBoundInput) {
|
||||
return create(bits, lowerBoundInput, upperBoundInput, 0, CodeUtil.mask(bits));
|
||||
}
|
||||
|
||||
public static IntegerStamp create(int bits, long lowerBoundInput, long upperBoundInput, long downMask, long upMask) {
|
||||
assert (downMask & ~upMask) == 0 : String.format("\u21ca: %016x \u21c8: %016x", downMask, upMask);
|
||||
|
||||
// Set lower bound, use masks to make it more precise
|
||||
long minValue = minValueForMasks(bits, downMask, upMask);
|
||||
long lowerBoundTmp = Math.max(lowerBoundInput, minValue);
|
||||
|
||||
// Set upper bound, use masks to make it more precise
|
||||
long maxValue = maxValueForMasks(bits, downMask, upMask);
|
||||
long upperBoundTmp = Math.min(upperBoundInput, maxValue);
|
||||
|
||||
// Assign masks now with the bounds in mind.
|
||||
final long boundedDownMask;
|
||||
final long boundedUpMask;
|
||||
long defaultMask = CodeUtil.mask(bits);
|
||||
if (lowerBoundTmp == upperBoundTmp) {
|
||||
boundedDownMask = lowerBoundTmp;
|
||||
boundedUpMask = lowerBoundTmp;
|
||||
} else if (lowerBoundTmp >= 0) {
|
||||
int upperBoundLeadingZeros = Long.numberOfLeadingZeros(upperBoundTmp);
|
||||
long differentBits = lowerBoundTmp ^ upperBoundTmp;
|
||||
int sameBitCount = Long.numberOfLeadingZeros(differentBits << upperBoundLeadingZeros);
|
||||
|
||||
boundedUpMask = upperBoundTmp | -1L >>> (upperBoundLeadingZeros + sameBitCount);
|
||||
boundedDownMask = upperBoundTmp & ~(-1L >>> (upperBoundLeadingZeros + sameBitCount));
|
||||
} else {
|
||||
lowerBound = downMask | (-1L << (bits - 1));
|
||||
upperBound = CodeUtil.maxValue(bits) & upMask;
|
||||
if (upperBoundTmp >= 0) {
|
||||
boundedUpMask = defaultMask;
|
||||
boundedDownMask = 0;
|
||||
} else {
|
||||
int lowerBoundLeadingOnes = Long.numberOfLeadingZeros(~lowerBoundTmp);
|
||||
long differentBits = lowerBoundTmp ^ upperBoundTmp;
|
||||
int sameBitCount = Long.numberOfLeadingZeros(differentBits << lowerBoundLeadingOnes);
|
||||
|
||||
boundedUpMask = lowerBoundTmp | -1L >>> (lowerBoundLeadingOnes + sameBitCount) | ~(-1L >>> lowerBoundLeadingOnes);
|
||||
boundedDownMask = lowerBoundTmp & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes);
|
||||
}
|
||||
}
|
||||
lowerBound = CodeUtil.convert(lowerBound, bits, false);
|
||||
upperBound = CodeUtil.convert(upperBound, bits, false);
|
||||
return new IntegerStamp(bits, lowerBound, upperBound, downMask, upMask);
|
||||
|
||||
return new IntegerStamp(bits, lowerBoundTmp, upperBoundTmp, defaultMask & (downMask | boundedDownMask), defaultMask & upMask & boundedUpMask);
|
||||
}
|
||||
|
||||
static long significantBit(long bits, long value) {
|
||||
return (value >>> (bits - 1)) & 1;
|
||||
}
|
||||
|
||||
static long minValueForMasks(int bits, long downMask, long upMask) {
|
||||
if (significantBit(bits, upMask) == 0) {
|
||||
// Value is always positive. Minimum value always positive.
|
||||
assert significantBit(bits, downMask) == 0;
|
||||
return downMask;
|
||||
} else {
|
||||
// Value can be positive or negative. Minimum value always negative.
|
||||
return downMask | (-1L << (bits - 1));
|
||||
}
|
||||
}
|
||||
|
||||
static long maxValueForMasks(int bits, long downMask, long upMask) {
|
||||
if (significantBit(bits, downMask) == 1) {
|
||||
// Value is always negative. Maximum value always negative.
|
||||
assert significantBit(bits, upMask) == 1;
|
||||
return CodeUtil.signExtend(upMask, bits);
|
||||
} else {
|
||||
// Value can be positive or negative. Maximum value always positive.
|
||||
return upMask & (CodeUtil.mask(bits) >>> 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static IntegerStamp stampForMask(int bits, long downMask, long upMask) {
|
||||
return new IntegerStamp(bits, minValueForMasks(bits, downMask, upMask), maxValueForMasks(bits, downMask, upMask), downMask, upMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -97,7 +158,7 @@ public class IntegerStamp extends PrimitiveStamp {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stamp empty() {
|
||||
public IntegerStamp empty() {
|
||||
return new IntegerStamp(getBits(), CodeUtil.maxValue(getBits()), CodeUtil.minValue(getBits()), CodeUtil.mask(getBits()), 0);
|
||||
}
|
||||
|
||||
@ -230,23 +291,27 @@ public class IntegerStamp extends PrimitiveStamp {
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append('i');
|
||||
str.append(getBits());
|
||||
if (lowerBound == upperBound) {
|
||||
str.append(" [").append(lowerBound).append(']');
|
||||
} else if (lowerBound != CodeUtil.minValue(getBits()) || upperBound != CodeUtil.maxValue(getBits())) {
|
||||
str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
|
||||
}
|
||||
if (downMask != 0) {
|
||||
str.append(" \u21ca");
|
||||
new Formatter(str).format("%016x", downMask);
|
||||
}
|
||||
if (upMask != CodeUtil.mask(getBits())) {
|
||||
str.append(" \u21c8");
|
||||
new Formatter(str).format("%016x", upMask);
|
||||
if (hasValues()) {
|
||||
if (lowerBound == upperBound) {
|
||||
str.append(" [").append(lowerBound).append(']');
|
||||
} else if (lowerBound != CodeUtil.minValue(getBits()) || upperBound != CodeUtil.maxValue(getBits())) {
|
||||
str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
|
||||
}
|
||||
if (downMask != 0) {
|
||||
str.append(" \u21ca");
|
||||
new Formatter(str).format("%016x", downMask);
|
||||
}
|
||||
if (upMask != CodeUtil.mask(getBits())) {
|
||||
str.append(" \u21c8");
|
||||
new Formatter(str).format("%016x", upMask);
|
||||
}
|
||||
} else {
|
||||
str.append("<empty>");
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
private Stamp createStamp(IntegerStamp other, long newUpperBound, long newLowerBound, long newDownMask, long newUpMask) {
|
||||
private IntegerStamp createStamp(IntegerStamp other, long newUpperBound, long newLowerBound, long newDownMask, long newUpMask) {
|
||||
assert getBits() == other.getBits();
|
||||
if (newLowerBound > newUpperBound || (newDownMask & (~newUpMask)) != 0 || (newUpMask == 0 && (newLowerBound > 0 || newUpperBound < 0))) {
|
||||
return empty();
|
||||
@ -255,7 +320,7 @@ public class IntegerStamp extends PrimitiveStamp {
|
||||
} else if (newLowerBound == other.lowerBound && newUpperBound == other.upperBound && newDownMask == other.downMask && newUpMask == other.upMask) {
|
||||
return other;
|
||||
} else {
|
||||
return new IntegerStamp(getBits(), newLowerBound, newUpperBound, newDownMask, newUpMask);
|
||||
return IntegerStamp.create(getBits(), newLowerBound, newUpperBound, newDownMask, newUpMask);
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,17 +334,16 @@ public class IntegerStamp extends PrimitiveStamp {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stamp join(Stamp otherStamp) {
|
||||
public IntegerStamp join(Stamp otherStamp) {
|
||||
if (otherStamp == this) {
|
||||
return this;
|
||||
}
|
||||
IntegerStamp other = (IntegerStamp) otherStamp;
|
||||
long newDownMask = downMask | other.downMask;
|
||||
long newLowerBound = Math.max(lowerBound, other.lowerBound) | newDownMask;
|
||||
long newLowerBound = Math.max(lowerBound, other.lowerBound);
|
||||
long newUpperBound = Math.min(upperBound, other.upperBound);
|
||||
long newUpMask = upMask & other.upMask;
|
||||
IntegerStamp limit = StampFactory.forInteger(getBits(), newLowerBound, newUpperBound);
|
||||
return createStamp(other, newUpperBound, newLowerBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
|
||||
return createStamp(other, newUpperBound, newLowerBound, newDownMask, newUpMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -303,6 +367,24 @@ public class IntegerStamp extends PrimitiveStamp {
|
||||
return false;
|
||||
}
|
||||
|
||||
public long unsignedUpperBound() {
|
||||
if (sameSignBounds()) {
|
||||
return CodeUtil.zeroExtend(upperBound(), getBits());
|
||||
}
|
||||
return NumUtil.maxValueUnsigned(getBits());
|
||||
}
|
||||
|
||||
public long unsignedLowerBound() {
|
||||
if (sameSignBounds()) {
|
||||
return CodeUtil.zeroExtend(lowerBound(), getBits());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private boolean sameSignBounds() {
|
||||
return NumUtil.sameSign(lowerBound, upperBound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
@ -369,6 +451,13 @@ public class IntegerStamp extends PrimitiveStamp {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean addCanOverflow(IntegerStamp a, IntegerStamp b) {
|
||||
assert a.getBits() == b.getBits();
|
||||
return addOverflowsPositively(a.upperBound(), b.upperBound(), a.getBits()) ||
|
||||
addOverflowsNegatively(a.lowerBound(), b.lowerBound(), a.getBits());
|
||||
|
||||
}
|
||||
|
||||
public static boolean addOverflowsPositively(long x, long y, int bits) {
|
||||
long result = x + y;
|
||||
if (bits == 64) {
|
||||
@ -430,15 +519,59 @@ public class IntegerStamp extends PrimitiveStamp {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean multiplicationCanOverflow(IntegerStamp a, IntegerStamp b) {
|
||||
// see IntegerStamp#foldStamp for details
|
||||
assert a.getBits() == b.getBits();
|
||||
if (a.upMask() == 0) {
|
||||
return false;
|
||||
} else if (b.upMask() == 0) {
|
||||
return false;
|
||||
}
|
||||
if (a.isUnrestricted()) {
|
||||
return true;
|
||||
}
|
||||
if (b.isUnrestricted()) {
|
||||
return true;
|
||||
}
|
||||
int bits = a.getBits();
|
||||
long minNegA = a.lowerBound();
|
||||
long maxNegA = Math.min(0, a.upperBound());
|
||||
long minPosA = Math.max(0, a.lowerBound());
|
||||
long maxPosA = a.upperBound();
|
||||
|
||||
long minNegB = b.lowerBound();
|
||||
long maxNegB = Math.min(0, b.upperBound());
|
||||
long minPosB = Math.max(0, b.lowerBound());
|
||||
long maxPosB = b.upperBound();
|
||||
|
||||
boolean mayOverflow = false;
|
||||
if (a.canBePositive()) {
|
||||
if (b.canBePositive()) {
|
||||
mayOverflow |= IntegerStamp.multiplicationOverflows(maxPosA, maxPosB, bits);
|
||||
mayOverflow |= IntegerStamp.multiplicationOverflows(minPosA, minPosB, bits);
|
||||
}
|
||||
if (b.canBeNegative()) {
|
||||
mayOverflow |= IntegerStamp.multiplicationOverflows(minPosA, maxNegB, bits);
|
||||
mayOverflow |= IntegerStamp.multiplicationOverflows(maxPosA, minNegB, bits);
|
||||
|
||||
}
|
||||
}
|
||||
if (a.canBeNegative()) {
|
||||
if (b.canBePositive()) {
|
||||
mayOverflow |= IntegerStamp.multiplicationOverflows(maxNegA, minPosB, bits);
|
||||
mayOverflow |= IntegerStamp.multiplicationOverflows(minNegA, maxPosB, bits);
|
||||
}
|
||||
if (b.canBeNegative()) {
|
||||
mayOverflow |= IntegerStamp.multiplicationOverflows(minNegA, minNegB, bits);
|
||||
mayOverflow |= IntegerStamp.multiplicationOverflows(maxNegA, maxNegB, bits);
|
||||
}
|
||||
}
|
||||
return mayOverflow;
|
||||
}
|
||||
|
||||
public static boolean subtractionCanOverflow(IntegerStamp x, IntegerStamp y) {
|
||||
assert x.getBits() == y.getBits();
|
||||
// Checkstyle: stop
|
||||
long x_l = x.lowerBound();
|
||||
long x_h = x.upperBound();
|
||||
long y_l = y.lowerBound();
|
||||
long y_h = y.upperBound();
|
||||
// Checkstyle: resume
|
||||
return subtractionOverflows(x_l, y_h, x.getBits()) || subtractionOverflows(x_h, y_l, x.getBits());
|
||||
return subtractionOverflows(x.lowerBound(), y.upperBound(), x.getBits()) || subtractionOverflows(x.upperBound(), y.lowerBound(), x.getBits());
|
||||
}
|
||||
|
||||
public static boolean subtractionOverflows(long x, long y, int bits) {
|
||||
@ -618,7 +751,7 @@ public class IntegerStamp extends PrimitiveStamp {
|
||||
* upper bound after multiplication.
|
||||
*
|
||||
* For example if we consider two stamps a & b that both contain
|
||||
* negative and positive values, the product of minN_a * minN_b
|
||||
* negative and positive values, the product of minNegA * minNegB
|
||||
* (both the smallest negative value for each stamp) can only be the
|
||||
* highest positive number. The other candidates can be computed in
|
||||
* a similar fashion. Some of them can never be a new minimum or
|
||||
@ -627,87 +760,86 @@ public class IntegerStamp extends PrimitiveStamp {
|
||||
*
|
||||
* @formatter:off
|
||||
*
|
||||
* [x..........0..........y]
|
||||
* -------------------------
|
||||
* [minN maxN minP maxP]
|
||||
* where maxN = min(0,y) && minP = max(0,x)
|
||||
* [x................0................y]
|
||||
* -------------------------------------
|
||||
* [minNeg maxNeg minPos maxPos]
|
||||
*
|
||||
* where maxNeg = min(0,y) && minPos = max(0,x)
|
||||
*
|
||||
*
|
||||
* |minN_a maxN_a minP_a maxP_a
|
||||
* _______|________________________________
|
||||
* minN_b |MAX / : / MIN
|
||||
* maxN_b | / MIN : MAX /
|
||||
* |---------------+----------------
|
||||
* minP_b | / MAX : MIN /
|
||||
* maxP_b |MIN / : / MAX
|
||||
* |minNegA maxNegA minPosA maxPosA
|
||||
* _______ |____________________________________
|
||||
* minNegB | MAX / : / MIN
|
||||
* maxNegB | / MIN : MAX /
|
||||
* |------------------+-----------------
|
||||
* minPosB | / MAX : MIN /
|
||||
* maxPosB | MIN / : / MAX
|
||||
*
|
||||
* @formatter:on
|
||||
*/
|
||||
// We materialize all factors here. If they are needed, the signs of
|
||||
// the stamp will ensure the correct value is used.
|
||||
// Checkstyle: stop
|
||||
long minN_a = a.lowerBound();
|
||||
long maxN_a = Math.min(0, a.upperBound());
|
||||
long minP_a = Math.max(0, a.lowerBound());
|
||||
long maxP_a = a.upperBound();
|
||||
long minNegA = a.lowerBound();
|
||||
long maxNegA = Math.min(0, a.upperBound());
|
||||
long minPosA = Math.max(0, a.lowerBound());
|
||||
long maxPosA = a.upperBound();
|
||||
|
||||
long minN_b = b.lowerBound();
|
||||
long maxN_b = Math.min(0, b.upperBound());
|
||||
long minP_b = Math.max(0, b.lowerBound());
|
||||
long maxP_b = b.upperBound();
|
||||
// Checkstyle: resume
|
||||
long minNegB = b.lowerBound();
|
||||
long maxNegB = Math.min(0, b.upperBound());
|
||||
long minPosB = Math.max(0, b.lowerBound());
|
||||
long maxPosB = b.upperBound();
|
||||
|
||||
// multiplication has shift semantics
|
||||
long newUpMask = ~CodeUtil.mask(Long.numberOfTrailingZeros(a.upMask) + Long.numberOfTrailingZeros(b.upMask)) & CodeUtil.mask(bits);
|
||||
|
||||
if (a.canBePositive()) {
|
||||
if (b.canBePositive()) {
|
||||
if (multiplicationOverflows(maxP_a, maxP_b, bits)) {
|
||||
if (multiplicationOverflows(maxPosA, maxPosB, bits)) {
|
||||
return a.unrestricted();
|
||||
}
|
||||
long maxCandidate = maxP_a * maxP_b;
|
||||
if (multiplicationOverflows(minP_a, minP_b, bits)) {
|
||||
long maxCandidate = maxPosA * maxPosB;
|
||||
if (multiplicationOverflows(minPosA, minPosB, bits)) {
|
||||
return a.unrestricted();
|
||||
}
|
||||
long minCandidate = minP_a * minP_b;
|
||||
long minCandidate = minPosA * minPosB;
|
||||
newLowerBound = Math.min(newLowerBound, minCandidate);
|
||||
newUpperBound = Math.max(newUpperBound, maxCandidate);
|
||||
}
|
||||
if (b.canBeNegative()) {
|
||||
if (multiplicationOverflows(minP_a, maxN_b, bits)) {
|
||||
if (multiplicationOverflows(minPosA, maxNegB, bits)) {
|
||||
return a.unrestricted();
|
||||
}
|
||||
long maxCandidate = minP_a * maxN_b;
|
||||
if (multiplicationOverflows(maxP_a, minN_b, bits)) {
|
||||
long maxCandidate = minPosA * maxNegB;
|
||||
if (multiplicationOverflows(maxPosA, minNegB, bits)) {
|
||||
return a.unrestricted();
|
||||
}
|
||||
long minCandidate = maxP_a * minN_b;
|
||||
long minCandidate = maxPosA * minNegB;
|
||||
newLowerBound = Math.min(newLowerBound, minCandidate);
|
||||
newUpperBound = Math.max(newUpperBound, maxCandidate);
|
||||
}
|
||||
}
|
||||
if (a.canBeNegative()) {
|
||||
if (b.canBePositive()) {
|
||||
if (multiplicationOverflows(maxN_a, minP_b, bits)) {
|
||||
if (multiplicationOverflows(maxNegA, minPosB, bits)) {
|
||||
return a.unrestricted();
|
||||
}
|
||||
long maxCandidate = maxN_a * minP_b;
|
||||
if (multiplicationOverflows(minN_a, maxP_b, bits)) {
|
||||
long maxCandidate = maxNegA * minPosB;
|
||||
if (multiplicationOverflows(minNegA, maxPosB, bits)) {
|
||||
return a.unrestricted();
|
||||
}
|
||||
long minCandidate = minN_a * maxP_b;
|
||||
long minCandidate = minNegA * maxPosB;
|
||||
newLowerBound = Math.min(newLowerBound, minCandidate);
|
||||
newUpperBound = Math.max(newUpperBound, maxCandidate);
|
||||
}
|
||||
if (b.canBeNegative()) {
|
||||
if (multiplicationOverflows(minN_a, minN_b, bits)) {
|
||||
if (multiplicationOverflows(minNegA, minNegB, bits)) {
|
||||
return a.unrestricted();
|
||||
}
|
||||
long maxCandidate = minN_a * minN_b;
|
||||
if (multiplicationOverflows(maxN_a, maxN_b, bits)) {
|
||||
long maxCandidate = minNegA * minNegB;
|
||||
if (multiplicationOverflows(maxNegA, maxNegB, bits)) {
|
||||
return a.unrestricted();
|
||||
}
|
||||
long minCandidate = maxN_a * maxN_b;
|
||||
long minCandidate = maxNegA * maxNegB;
|
||||
newLowerBound = Math.min(newLowerBound, minCandidate);
|
||||
newUpperBound = Math.max(newUpperBound, maxCandidate);
|
||||
}
|
||||
@ -1083,22 +1215,28 @@ public class IntegerStamp extends PrimitiveStamp {
|
||||
assert inputBits == stamp.getBits();
|
||||
assert inputBits <= resultBits;
|
||||
|
||||
long downMask = CodeUtil.zeroExtend(stamp.downMask(), inputBits);
|
||||
long upMask = CodeUtil.zeroExtend(stamp.upMask(), inputBits);
|
||||
|
||||
if (stamp.lowerBound() < 0 && stamp.upperBound() >= 0) {
|
||||
/* signed range including 0 and -1 */
|
||||
/*
|
||||
* after sign extension, the whole range from 0 to MAX_INT is
|
||||
* possible
|
||||
*/
|
||||
return IntegerStamp.stampForMask(resultBits, downMask, upMask);
|
||||
if (inputBits == resultBits) {
|
||||
return input;
|
||||
}
|
||||
|
||||
long lowerBound = CodeUtil.zeroExtend(stamp.lowerBound(), inputBits);
|
||||
long upperBound = CodeUtil.zeroExtend(stamp.upperBound(), inputBits);
|
||||
if (input.isEmpty()) {
|
||||
return StampFactory.forInteger(resultBits).empty();
|
||||
}
|
||||
|
||||
return new IntegerStamp(resultBits, lowerBound, upperBound, downMask, upMask);
|
||||
long downMask = CodeUtil.zeroExtend(stamp.downMask(), inputBits);
|
||||
long upMask = CodeUtil.zeroExtend(stamp.upMask(), inputBits);
|
||||
long lowerBound = stamp.unsignedLowerBound();
|
||||
long upperBound = stamp.unsignedUpperBound();
|
||||
return IntegerStamp.create(resultBits, lowerBound, upperBound, downMask, upMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) {
|
||||
IntegerStamp stamp = (IntegerStamp) outStamp;
|
||||
if (stamp.isEmpty()) {
|
||||
return StampFactory.forInteger(inputBits).empty();
|
||||
}
|
||||
return StampFactory.forUnsignedInteger(inputBits, stamp.lowerBound(), stamp.upperBound(), stamp.downMask(), stamp.upMask());
|
||||
}
|
||||
},
|
||||
|
||||
@ -1122,6 +1260,13 @@ public class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
return new IntegerStamp(resultBits, stamp.lowerBound(), stamp.upperBound(), downMask, upMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) {
|
||||
IntegerStamp stamp = (IntegerStamp) outStamp;
|
||||
long mask = CodeUtil.mask(inputBits);
|
||||
return StampFactory.forIntegerWithMask(inputBits, stamp.lowerBound(), stamp.upperBound(), stamp.downMask() & mask, stamp.upMask() & mask);
|
||||
}
|
||||
},
|
||||
|
||||
new IntegerConvertOp.Narrow() {
|
||||
|
@ -22,6 +22,9 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.common.type;
|
||||
|
||||
import static jdk.vm.ci.code.CodeUtil.signExtend;
|
||||
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
|
||||
import jdk.vm.ci.code.CodeUtil;
|
||||
@ -56,6 +59,11 @@ public class StampFactory {
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NodeIntrinsicStamp";
|
||||
}
|
||||
}
|
||||
|
||||
// JaCoCo Exclude
|
||||
@ -82,7 +90,7 @@ public class StampFactory {
|
||||
} else {
|
||||
mask = CodeUtil.mask(bits);
|
||||
}
|
||||
setCache(kind, new IntegerStamp(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask));
|
||||
setCache(kind, IntegerStamp.create(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask));
|
||||
}
|
||||
|
||||
private static void setFloatCache(JavaKind kind) {
|
||||
@ -156,7 +164,7 @@ public class StampFactory {
|
||||
}
|
||||
|
||||
public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound, long downMask, long upMask) {
|
||||
return new IntegerStamp(kind.getBitCount(), lowerBound, upperBound, downMask, upMask);
|
||||
return IntegerStamp.create(kind.getBitCount(), lowerBound, upperBound, downMask, upMask);
|
||||
}
|
||||
|
||||
public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound) {
|
||||
@ -176,46 +184,35 @@ public class StampFactory {
|
||||
*/
|
||||
public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, IntegerStamp maskStamp) {
|
||||
IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
|
||||
return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | maskStamp.downMask(), limit.upMask() & maskStamp.upMask());
|
||||
return IntegerStamp.create(bits, newLowerBound, newUpperBound, limit.downMask() | maskStamp.downMask(), limit.upMask() & maskStamp.upMask());
|
||||
}
|
||||
|
||||
public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, long newDownMask, long newUpMask) {
|
||||
IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
|
||||
return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
|
||||
return IntegerStamp.create(bits, newLowerBound, newUpperBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
|
||||
}
|
||||
|
||||
public static IntegerStamp forInteger(int bits) {
|
||||
return new IntegerStamp(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits));
|
||||
return IntegerStamp.create(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits));
|
||||
}
|
||||
|
||||
public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound) {
|
||||
return forUnsignedInteger(bits, unsignedLowerBound, unsignedUpperBound, 0, CodeUtil.mask(bits));
|
||||
}
|
||||
|
||||
public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound, long downMask, long upMask) {
|
||||
long lowerBound = signExtend(unsignedLowerBound, bits);
|
||||
long upperBound = signExtend(unsignedUpperBound, bits);
|
||||
if (!NumUtil.sameSign(lowerBound, upperBound)) {
|
||||
lowerBound = CodeUtil.minValue(bits);
|
||||
upperBound = CodeUtil.maxValue(bits);
|
||||
}
|
||||
long mask = CodeUtil.mask(bits);
|
||||
return IntegerStamp.create(bits, lowerBound, upperBound, downMask & mask, upMask & mask);
|
||||
}
|
||||
|
||||
public static IntegerStamp forInteger(int bits, long lowerBound, long upperBound) {
|
||||
long defaultMask = CodeUtil.mask(bits);
|
||||
if (lowerBound == upperBound) {
|
||||
return new IntegerStamp(bits, lowerBound, lowerBound, lowerBound & defaultMask, lowerBound & defaultMask);
|
||||
}
|
||||
final long downMask;
|
||||
final long upMask;
|
||||
if (lowerBound >= 0) {
|
||||
int upperBoundLeadingZeros = Long.numberOfLeadingZeros(upperBound);
|
||||
long differentBits = lowerBound ^ upperBound;
|
||||
int sameBitCount = Long.numberOfLeadingZeros(differentBits << upperBoundLeadingZeros);
|
||||
|
||||
upMask = upperBound | -1L >>> (upperBoundLeadingZeros + sameBitCount);
|
||||
downMask = upperBound & ~(-1L >>> (upperBoundLeadingZeros + sameBitCount));
|
||||
} else {
|
||||
if (upperBound >= 0) {
|
||||
upMask = defaultMask;
|
||||
downMask = 0;
|
||||
} else {
|
||||
int lowerBoundLeadingOnes = Long.numberOfLeadingZeros(~lowerBound);
|
||||
long differentBits = lowerBound ^ upperBound;
|
||||
int sameBitCount = Long.numberOfLeadingZeros(differentBits << lowerBoundLeadingOnes);
|
||||
|
||||
upMask = lowerBound | -1L >>> (lowerBoundLeadingOnes + sameBitCount) | ~(-1L >>> lowerBoundLeadingOnes);
|
||||
downMask = lowerBound & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes);
|
||||
}
|
||||
}
|
||||
return new IntegerStamp(bits, lowerBound, upperBound, downMask & defaultMask, upMask & defaultMask);
|
||||
return IntegerStamp.create(bits, lowerBound, upperBound, 0, CodeUtil.mask(bits));
|
||||
}
|
||||
|
||||
public static FloatStamp forFloat(JavaKind kind, double lowerBound, double upperBound, boolean nonNaN) {
|
||||
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.core.common.util;
|
||||
|
||||
/**
|
||||
* The {@code ArrayMap} class implements an efficient one-level map which is implemented as an
|
||||
* array. Note that because of the one-level array inside, this data structure performs best when
|
||||
* the range of integer keys is small and densely used. Note that the implementation can handle
|
||||
* arbitrary intervals, including negative numbers, up to intervals of size 2^31 - 1.
|
||||
*/
|
||||
public class ArrayMap<T> {
|
||||
|
||||
private static final int INITIAL_SIZE = 5; // how big the initial array should be
|
||||
private static final int EXTRA = 2; // how far on the left or right of a new element to grow
|
||||
|
||||
Object[] map;
|
||||
int low;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ArrayMap} with no initial assumptions.
|
||||
*/
|
||||
public ArrayMap() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ArrayMap} that initially covers the specified interval. Note that
|
||||
* this map will automatically expand if necessary later.
|
||||
*
|
||||
* @param low the low index, inclusive
|
||||
* @param high the high index, exclusive
|
||||
*/
|
||||
public ArrayMap(int low, int high) {
|
||||
this.low = low;
|
||||
this.map = new Object[high - low + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a new value in the map at the specified index.
|
||||
*
|
||||
* @param i the index at which to store the value
|
||||
* @param value the value to store at the specified index
|
||||
*/
|
||||
public void put(int i, T value) {
|
||||
int index = i - low;
|
||||
if (map == null) {
|
||||
// no map yet
|
||||
map = new Object[INITIAL_SIZE];
|
||||
low = index - 2;
|
||||
map[INITIAL_SIZE / 2] = value;
|
||||
} else if (index < 0) {
|
||||
// grow backwards
|
||||
growBackward(i, value);
|
||||
} else if (index >= map.length) {
|
||||
// grow forwards
|
||||
growForward(i, value);
|
||||
} else {
|
||||
// no growth necessary
|
||||
map[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value at the specified index in the map.
|
||||
*
|
||||
* @param i the index
|
||||
* @return the value at the specified index; {@code null} if there is no value at the specified
|
||||
* index, or if the index is out of the currently stored range
|
||||
*/
|
||||
public T get(int i) {
|
||||
int index = i - low;
|
||||
if (map == null || index < 0 || index >= map.length) {
|
||||
return null;
|
||||
}
|
||||
Class<T> type = null;
|
||||
return Util.uncheckedCast(type, map[index]);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return map.length;
|
||||
}
|
||||
|
||||
private void growBackward(int i, T value) {
|
||||
int nlow = i - EXTRA;
|
||||
Object[] nmap = new Object[low - nlow + map.length];
|
||||
System.arraycopy(map, 0, nmap, low - nlow, map.length);
|
||||
map = nmap;
|
||||
low = nlow;
|
||||
map[i - low] = value;
|
||||
}
|
||||
|
||||
private void growForward(int i, T value) {
|
||||
int nlen = i - low + 1 + EXTRA;
|
||||
Object[] nmap = new Object[nlen];
|
||||
System.arraycopy(map, 0, nmap, 0, map.length);
|
||||
map = nmap;
|
||||
map[i - low] = value;
|
||||
}
|
||||
}
|
@ -23,8 +23,9 @@
|
||||
package org.graalvm.compiler.core.common.util;
|
||||
|
||||
import org.graalvm.compiler.options.Option;
|
||||
import org.graalvm.compiler.options.OptionKey;
|
||||
import org.graalvm.compiler.options.OptionType;
|
||||
import org.graalvm.compiler.options.OptionValue;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
/**
|
||||
* Utility class that allows the compiler to monitor compilations that take a very long time.
|
||||
@ -34,80 +35,74 @@ public final class CompilationAlarm implements AutoCloseable {
|
||||
public static class Options {
|
||||
// @formatter:off
|
||||
@Option(help = "Time limit in seconds before a compilation expires (0 to disable the limit).", type = OptionType.Debug)
|
||||
public static final OptionValue<Integer> CompilationExpirationPeriod = new OptionValue<>(300);
|
||||
public static final OptionKey<Integer> CompilationExpirationPeriod = new OptionKey<>(300);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private CompilationAlarm() {
|
||||
}
|
||||
|
||||
private static boolean enabled() {
|
||||
return Options.CompilationExpirationPeriod.getValue() > 0;
|
||||
private CompilationAlarm(long expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread local storage for compilation start timestamps. Everytime a compiler thread calls
|
||||
* {@link #trackCompilationPeriod()} it will save the start timestamp of the compilation.
|
||||
* Thread local storage for the active compilation alarm.
|
||||
*/
|
||||
private static final ThreadLocal<Long> compilationStartedTimeStamps = new ThreadLocal<>();
|
||||
private static final ThreadLocal<CompilationAlarm> currentAlarm = new ThreadLocal<>();
|
||||
|
||||
private static boolean compilationStarted() {
|
||||
if (enabled()) {
|
||||
Long start = compilationStartedTimeStamps.get();
|
||||
if (start == null) {
|
||||
compilationStartedTimeStamps.set(System.currentTimeMillis());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static final CompilationAlarm NEVER_EXPIRES = new CompilationAlarm(0);
|
||||
|
||||
private static void compilationFinished() {
|
||||
if (enabled()) {
|
||||
assert compilationStartedTimeStamps.get() != null;
|
||||
compilationStartedTimeStamps.set(null);
|
||||
}
|
||||
/**
|
||||
* Gets the current compilation alarm. If there is no current alarm, a non-null value is
|
||||
* returned that will always return {@code false} for {@link #hasExpired()}.
|
||||
*/
|
||||
public static CompilationAlarm current() {
|
||||
CompilationAlarm alarm = currentAlarm.get();
|
||||
return alarm == null ? NEVER_EXPIRES : alarm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the current compilation is expired. A compilation expires if it takes longer
|
||||
* than {@linkplain CompilationAlarm.Options#CompilationExpirationPeriod}.
|
||||
* Determines if this alarm has expired. A compilation expires if it takes longer than
|
||||
* {@linkplain CompilationAlarm.Options#CompilationExpirationPeriod}.
|
||||
*
|
||||
* @return {@code true} if the current compilation already takes longer than
|
||||
* {@linkplain CompilationAlarm.Options#CompilationExpirationPeriod}, {@code false}
|
||||
* otherwise
|
||||
*/
|
||||
public static boolean hasExpired() {
|
||||
if (enabled()) {
|
||||
Long start = compilationStartedTimeStamps.get();
|
||||
if (start != null) {
|
||||
long time = System.currentTimeMillis();
|
||||
assert time >= start;
|
||||
return time - start > Options.CompilationExpirationPeriod.getValue() * 1000;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
public boolean hasExpired() {
|
||||
return this != NEVER_EXPIRES && System.currentTimeMillis() > expiration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
compilationFinished();
|
||||
if (this != NEVER_EXPIRES) {
|
||||
currentAlarm.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
private static final CompilationAlarm INSTANCE = enabled() ? new CompilationAlarm() : null;
|
||||
/**
|
||||
* The time at which this alarm expires.
|
||||
*/
|
||||
private final long expiration;
|
||||
|
||||
/**
|
||||
* Gets an object that can be used in a try-with-resource statement to set an time limit based
|
||||
* alarm for a compilation.
|
||||
* Starts an alarm for setting a time limit on a compilation if there isn't already an active
|
||||
* alarm and {@link CompilationAlarm.Options#CompilationExpirationPeriod}{@code > 0}. The
|
||||
* returned value can be used in a try-with-resource statement to disable the alarm once the
|
||||
* compilation is finished.
|
||||
*
|
||||
* @return a {@link CompilationAlarm} instance if there is no current alarm for the calling
|
||||
* thread otherwise {@code null}
|
||||
* @return a {@link CompilationAlarm} if there was no current alarm for the calling thread
|
||||
* before this call otherwise {@code null}
|
||||
*/
|
||||
public static CompilationAlarm trackCompilationPeriod() {
|
||||
if (compilationStarted()) {
|
||||
return INSTANCE;
|
||||
public static CompilationAlarm trackCompilationPeriod(OptionValues options) {
|
||||
int period = Options.CompilationExpirationPeriod.getValue(options);
|
||||
if (period > 0) {
|
||||
CompilationAlarm current = currentAlarm.get();
|
||||
if (current == null) {
|
||||
long expiration = System.currentTimeMillis() + period * 1000;
|
||||
current = new CompilationAlarm(expiration);
|
||||
currentAlarm.set(current);
|
||||
return current;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ import java.util.Arrays;
|
||||
*/
|
||||
public final class IntList {
|
||||
|
||||
private static final int[] EMPTY_INT_ARRAY = new int[0];
|
||||
|
||||
private int[] array;
|
||||
private int size;
|
||||
|
||||
@ -80,9 +82,13 @@ public final class IntList {
|
||||
*/
|
||||
public static IntList copy(IntList other, int startIndex, int length, int initialCapacity) {
|
||||
assert initialCapacity >= length : "initialCapacity < length";
|
||||
int[] array = new int[initialCapacity];
|
||||
System.arraycopy(other.array, startIndex, array, 0, length);
|
||||
return new IntList(array, length);
|
||||
if (initialCapacity == 0) {
|
||||
return new IntList(EMPTY_INT_ARRAY, 0);
|
||||
} else {
|
||||
int[] array = new int[initialCapacity];
|
||||
System.arraycopy(other.array, startIndex, array, 0, length);
|
||||
return new IntList(array, length);
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
|
@ -24,6 +24,7 @@ package org.graalvm.compiler.core.common.util;
|
||||
|
||||
import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
@ -57,11 +58,21 @@ public final class ModuleAPI {
|
||||
*/
|
||||
public static final ModuleAPI addExports;
|
||||
|
||||
/**
|
||||
* {@code jdk.internal.module.Modules.addOpens(Module, String, Module)}.
|
||||
*/
|
||||
public static final ModuleAPI addOpens;
|
||||
|
||||
/**
|
||||
* {@code java.lang.reflect.Module.getResourceAsStream(String)}.
|
||||
*/
|
||||
public static final ModuleAPI getResourceAsStream;
|
||||
|
||||
/**
|
||||
* {@code java.lang.reflect.Module.getPackages()}.
|
||||
*/
|
||||
public static final ModuleAPI getPackages;
|
||||
|
||||
/**
|
||||
* {@code java.lang.reflect.Module.canRead(Module)}.
|
||||
*/
|
||||
@ -105,6 +116,47 @@ public final class ModuleAPI {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens all packages in {@code moduleMember}'s module for deep reflection (i.e., allow
|
||||
* {@link AccessibleObject#setAccessible(boolean)} to be called for any class/method/field) by
|
||||
* {@code requestor}'s module.
|
||||
*/
|
||||
public static void openAllPackagesForReflectionTo(Class<?> moduleMember, Class<?> requestor) {
|
||||
Object moduleToOpen = getModule.invoke(moduleMember);
|
||||
Object requestorModule = getModule.invoke(requestor);
|
||||
if (moduleToOpen != requestorModule) {
|
||||
String[] packages = getPackages.invoke(moduleToOpen);
|
||||
for (String pkg : packages) {
|
||||
addOpens.invokeStatic(moduleToOpen, pkg, requestorModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens {@code declaringClass}'s package to allow a method declared in {@code accessor} to call
|
||||
* {@link AccessibleObject#setAccessible(boolean)} on an {@link AccessibleObject} representing a
|
||||
* field or method declared by {@code declaringClass}.
|
||||
*/
|
||||
public static void openForReflectionTo(Class<?> declaringClass, Class<?> accessor) {
|
||||
Object moduleToOpen = getModule.invoke(declaringClass);
|
||||
Object accessorModule = getModule.invoke(accessor);
|
||||
if (moduleToOpen != accessorModule) {
|
||||
addOpens.invokeStatic(moduleToOpen, declaringClass.getPackage().getName(), accessorModule);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the package named {@code packageName} declared in {@code moduleMember}'s module to
|
||||
* {@code requestor}'s module.
|
||||
*/
|
||||
public static void exportPackageTo(Class<?> moduleMember, String packageName, Class<?> requestor) {
|
||||
Object moduleToExport = getModule.invoke(moduleMember);
|
||||
Object requestorModule = getModule.invoke(requestor);
|
||||
if (moduleToExport != requestorModule) {
|
||||
addExports.invokeStatic(moduleToExport, packageName, requestorModule);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAvailability() throws InternalError {
|
||||
if (method == null) {
|
||||
throw new InternalError("Cannot use Module API on JDK " + JAVA_SPECIFICATION_VERSION);
|
||||
@ -118,10 +170,12 @@ public final class ModuleAPI {
|
||||
Class<?> moduleClass = getModule.method.getReturnType();
|
||||
Class<?> modulesClass = Class.forName("jdk.internal.module.Modules");
|
||||
getResourceAsStream = new ModuleAPI(moduleClass.getMethod("getResourceAsStream", String.class));
|
||||
getPackages = new ModuleAPI(moduleClass.getMethod("getPackages"));
|
||||
canRead = new ModuleAPI(moduleClass.getMethod("canRead", moduleClass));
|
||||
isExported = new ModuleAPI(moduleClass.getMethod("isExported", String.class));
|
||||
isExportedTo = new ModuleAPI(moduleClass.getMethod("isExported", String.class, moduleClass));
|
||||
addExports = new ModuleAPI(modulesClass.getDeclaredMethod("addExports", moduleClass, String.class, moduleClass));
|
||||
addOpens = new ModuleAPI(modulesClass.getDeclaredMethod("addOpens", moduleClass, String.class, moduleClass));
|
||||
} catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
@ -129,10 +183,12 @@ public final class ModuleAPI {
|
||||
ModuleAPI unavailable = new ModuleAPI(null);
|
||||
getModule = unavailable;
|
||||
getResourceAsStream = unavailable;
|
||||
getPackages = unavailable;
|
||||
canRead = unavailable;
|
||||
isExported = unavailable;
|
||||
isExportedTo = unavailable;
|
||||
addExports = unavailable;
|
||||
addOpens = unavailable;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -20,36 +20,39 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.api.collections;
|
||||
package org.graalvm.compiler.core.common.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.AbstractList;
|
||||
import java.util.List;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
/**
|
||||
* A default implementation of {@link CollectionsProvider} that creates standard JDK collection
|
||||
* class objects.
|
||||
* A {@code ReversedList} is a view on an other list with the elements in reverse order.
|
||||
*
|
||||
* This implementation is made for {@link RandomAccess} lists.
|
||||
*/
|
||||
public class DefaultCollectionsProvider implements CollectionsProvider {
|
||||
public class ReversedList<T> extends AbstractList<T> implements RandomAccess {
|
||||
private final List<T> original;
|
||||
|
||||
@Override
|
||||
public <E> Set<E> newIdentitySet() {
|
||||
return Collections.newSetFromMap(newIdentityMap());
|
||||
public ReversedList(List<T> original) {
|
||||
assert original instanceof RandomAccess;
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Map<K, V> newIdentityMap() {
|
||||
return new IdentityHashMap<>();
|
||||
public T get(int index) {
|
||||
return original.get(original.size() - index - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
|
||||
return new IdentityHashMap<>(expectedMaxSize);
|
||||
public int size() {
|
||||
return original.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Map<K, V> newIdentityMap(Map<K, V> initFrom) {
|
||||
return new IdentityHashMap<>(initFrom);
|
||||
/**
|
||||
* Creates a list that is a view on {@code list} in reverse order.
|
||||
*/
|
||||
public static <T> ReversedList<T> reversed(List<T> list) {
|
||||
return new ReversedList<>(list);
|
||||
}
|
||||
}
|
@ -22,9 +22,9 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.common.util;
|
||||
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
import org.graalvm.compiler.debug.TTY;
|
||||
@ -74,29 +74,6 @@ public class Util {
|
||||
return (T) object;
|
||||
}
|
||||
|
||||
public interface Stringify {
|
||||
String apply(Object o);
|
||||
}
|
||||
|
||||
public static String join(Collection<?> c, String sep) {
|
||||
return join(c, sep, "", "", null);
|
||||
}
|
||||
|
||||
public static String join(Collection<?> c, String sep, String prefix, String suffix, Stringify stringify) {
|
||||
StringBuilder buf = new StringBuilder(prefix);
|
||||
boolean first = true;
|
||||
for (Object e : c) {
|
||||
if (!first) {
|
||||
buf.append(sep);
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
buf.append(stringify != null ? stringify.apply(e) : String.valueOf(e));
|
||||
}
|
||||
buf.append(suffix);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the element at a given position of a list and ensures that this position exists. If the
|
||||
* list is current shorter than the position, intermediate positions are filled with a given
|
||||
@ -191,25 +168,45 @@ public class Util {
|
||||
* Print a HotSpot-style inlining message to the console.
|
||||
*/
|
||||
public static void printInlining(final ResolvedJavaMethod method, final int bci, final int inliningDepth, final boolean success, final String msg, final Object... args) {
|
||||
if (HotSpotPrintInlining.getValue()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// 1234567
|
||||
sb.append(" "); // print timestamp
|
||||
// 1234
|
||||
sb.append(" "); // print compilation number
|
||||
// % s ! b n
|
||||
sb.append(String.format("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' '));
|
||||
sb.append(" "); // more indent
|
||||
sb.append(" "); // initial inlining indent
|
||||
for (int i = 0; i < inliningDepth; i++) {
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(String.format("@ %d %s %s%s", bci, methodName(method), success ? "" : "not inlining ", String.format(msg, args)));
|
||||
TTY.println(sb.toString());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// 1234567
|
||||
sb.append(" "); // print timestamp
|
||||
// 1234
|
||||
sb.append(" "); // print compilation number
|
||||
// % s ! b n
|
||||
sb.append(String.format("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' '));
|
||||
sb.append(" "); // more indent
|
||||
sb.append(" "); // initial inlining indent
|
||||
for (int i = 0; i < inliningDepth; i++) {
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(String.format("@ %d %s %s%s", bci, methodName(method), success ? "" : "not inlining ", String.format(msg, args)));
|
||||
TTY.println(sb.toString());
|
||||
}
|
||||
|
||||
private static String methodName(ResolvedJavaMethod method) {
|
||||
return method.format("%H.%n(%p):%r") + " (" + method.getCodeSize() + " bytes)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link AccessibleObject#setAccessible(boolean)} on {@code field} with the value
|
||||
* {@code flag}.
|
||||
*/
|
||||
public static void setAccessible(Field field, boolean flag) {
|
||||
if (!Java8OrEarlier) {
|
||||
ModuleAPI.openForReflectionTo(field.getDeclaringClass(), Util.class);
|
||||
}
|
||||
field.setAccessible(flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link AccessibleObject#setAccessible(boolean)} on {@code executable} with the value
|
||||
* {@code flag}.
|
||||
*/
|
||||
public static void setAccessible(Executable executable, boolean flag) {
|
||||
if (!Java8OrEarlier) {
|
||||
ModuleAPI.openForReflectionTo(executable.getDeclaringClass(), Util.class);
|
||||
}
|
||||
executable.setAccessible(flag);
|
||||
}
|
||||
}
|
||||
|
@ -27,12 +27,8 @@ import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@ -74,6 +70,9 @@ import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.graph.Position;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.serviceprovider.ServiceProvider;
|
||||
import org.graalvm.util.Equivalence;
|
||||
import org.graalvm.util.EconomicMap;
|
||||
import org.graalvm.util.EconomicSet;
|
||||
|
||||
/**
|
||||
* Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
|
||||
@ -206,13 +205,13 @@ public class MatchProcessor extends AbstractProcessor {
|
||||
name = next();
|
||||
}
|
||||
originatingElements.addAll(type.originatingElements);
|
||||
requiredPackages.add(type.nodePackage);
|
||||
} else if (Character.isLowerCase(peek("name").charAt(0))) {
|
||||
name = next();
|
||||
type = valueType;
|
||||
} else {
|
||||
throw new RuleParseError("Unexpected token \"%s\" when looking for name or node type", peek(null));
|
||||
}
|
||||
requiredPackages.add(type.nodePackage);
|
||||
if (name != null) {
|
||||
if (!capturedNames.contains(name)) {
|
||||
capturedNames.add(name);
|
||||
@ -234,7 +233,7 @@ public class MatchProcessor extends AbstractProcessor {
|
||||
/**
|
||||
* Recursively accumulate any required Position declarations.
|
||||
*/
|
||||
void generatePositionDeclarations(Set<String> declarations) {
|
||||
void generatePositionDeclarations(EconomicSet<String> declarations) {
|
||||
matchDescriptor.generatePositionDeclarations(declarations);
|
||||
}
|
||||
|
||||
@ -366,7 +365,7 @@ public class MatchProcessor extends AbstractProcessor {
|
||||
/**
|
||||
* The types which are know for purpose of parsing MatchRule expressions.
|
||||
*/
|
||||
Map<String, TypeDescriptor> knownTypes = new HashMap<>();
|
||||
EconomicMap<String, TypeDescriptor> knownTypes = EconomicMap.create(Equivalence.DEFAULT);
|
||||
|
||||
private TypeDescriptor valueType;
|
||||
|
||||
@ -407,7 +406,7 @@ public class MatchProcessor extends AbstractProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
public void generatePositionDeclarations(Set<String> declarations) {
|
||||
public void generatePositionDeclarations(EconomicSet<String> declarations) {
|
||||
if (inputs.length == 0) {
|
||||
return;
|
||||
}
|
||||
@ -532,7 +531,7 @@ public class MatchProcessor extends AbstractProcessor {
|
||||
out.println();
|
||||
|
||||
// Generate declarations for the wrapper class to invoke the code generation methods.
|
||||
for (MethodInvokerItem invoker : info.invokers.values()) {
|
||||
for (MethodInvokerItem invoker : info.invokers.getValues()) {
|
||||
StringBuilder args = new StringBuilder();
|
||||
StringBuilder types = new StringBuilder();
|
||||
int count = invoker.fields.size();
|
||||
@ -663,14 +662,14 @@ public class MatchProcessor extends AbstractProcessor {
|
||||
|
||||
final TypeElement topDeclaringType;
|
||||
final List<MatchRuleItem> matchRules = new ArrayList<>();
|
||||
private final Set<Element> originatingElements = new HashSet<>();
|
||||
public Set<String> positionDeclarations = new LinkedHashSet<>();
|
||||
private final EconomicSet<Element> originatingElements = EconomicSet.create(Equivalence.DEFAULT);
|
||||
public EconomicSet<String> positionDeclarations = EconomicSet.create(Equivalence.DEFAULT);
|
||||
|
||||
/**
|
||||
* The mapping between elements with MatchRules and the wrapper class used invoke the code
|
||||
* generation after the match.
|
||||
*/
|
||||
Map<String, MethodInvokerItem> invokers = new LinkedHashMap<>();
|
||||
EconomicMap<String, MethodInvokerItem> invokers = EconomicMap.create(Equivalence.DEFAULT);
|
||||
|
||||
/**
|
||||
* The set of packages which must be imported to refer the classes mention in matchRules.
|
||||
@ -728,7 +727,7 @@ public class MatchProcessor extends AbstractProcessor {
|
||||
TypeMirror valueTypeMirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
|
||||
valueType = new TypeDescriptor(valueTypeMirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), new String[0], false, false);
|
||||
|
||||
Map<TypeElement, MatchRuleDescriptor> map = new LinkedHashMap<>();
|
||||
EconomicMap<TypeElement, MatchRuleDescriptor> map = EconomicMap.create(Equivalence.DEFAULT);
|
||||
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) {
|
||||
currentElement = element;
|
||||
@ -740,7 +739,7 @@ public class MatchProcessor extends AbstractProcessor {
|
||||
}
|
||||
|
||||
currentElement = null;
|
||||
for (MatchRuleDescriptor info : map.values()) {
|
||||
for (MatchRuleDescriptor info : map.getValues()) {
|
||||
createFiles(info);
|
||||
}
|
||||
|
||||
@ -834,7 +833,7 @@ public class MatchProcessor extends AbstractProcessor {
|
||||
declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), matchable.commutative(), matchable.shareable(), element);
|
||||
}
|
||||
|
||||
private void processMatchRule(Map<TypeElement, MatchRuleDescriptor> map, Element element, AnnotationMirror mirror) {
|
||||
private void processMatchRule(EconomicMap<TypeElement, MatchRuleDescriptor> map, Element element, AnnotationMirror mirror) {
|
||||
if (!processedMatchRule.contains(element)) {
|
||||
try {
|
||||
processedMatchRule.add(element);
|
||||
@ -961,7 +960,7 @@ public class MatchProcessor extends AbstractProcessor {
|
||||
Element enclosing = method.getEnclosingElement();
|
||||
String declaringClass = "";
|
||||
String separator = "";
|
||||
Set<Element> originatingElementsList = info.originatingElements;
|
||||
EconomicSet<Element> originatingElementsList = info.originatingElements;
|
||||
originatingElementsList.add(method);
|
||||
while (enclosing != null) {
|
||||
if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
|
||||
|
@ -22,23 +22,24 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.sparc.test;
|
||||
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.TraceRA;
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure;
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.TraceRA;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import jdk.vm.ci.sparc.SPARC;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.core.test.backend.AllocatorTest;
|
||||
|
||||
import jdk.vm.ci.sparc.SPARC;
|
||||
|
||||
public class SPARCAllocatorTest extends AllocatorTest {
|
||||
|
||||
@Before
|
||||
public void checkSPARC() {
|
||||
assumeTrue("skipping SPARC specific test", getTarget().arch instanceof SPARC);
|
||||
assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue() == null);
|
||||
assumeTrue("TraceRA is set -> skip", !TraceRA.getValue());
|
||||
assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue(getInitialOptions()) == null);
|
||||
assumeTrue("TraceRA is set -> skip", !TraceRA.getValue(getInitialOptions()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -47,7 +48,7 @@ public class SPARCAllocatorTest extends AllocatorTest {
|
||||
}
|
||||
|
||||
public static long test1snippet(long x) {
|
||||
return x + 5;
|
||||
return x + 41;
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -56,7 +57,7 @@ public class SPARCAllocatorTest extends AllocatorTest {
|
||||
}
|
||||
|
||||
public static long test2snippet(long x) {
|
||||
return x * 5;
|
||||
return x * 41;
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -65,7 +66,7 @@ public class SPARCAllocatorTest extends AllocatorTest {
|
||||
}
|
||||
|
||||
public static long test3snippet(long x) {
|
||||
return x / 3 + x % 3;
|
||||
return x / 41 + x % 41;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -113,12 +113,13 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
|
||||
@Override
|
||||
public Variable emitBitCount(Value operand) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
|
||||
Value usedOperand = operand;
|
||||
AllocatableValue usedOperand = getLIRGen().asAllocatable(operand);
|
||||
if (operand.getPlatformKind() == SPARCKind.WORD) { // Zero extend
|
||||
usedOperand = getLIRGen().newVariable(operand.getValueKind());
|
||||
getLIRGen().append(new SPARCOP3Op(Op3s.Srl, operand, SPARC.g0.asValue(), usedOperand));
|
||||
AllocatableValue intermediateOperand = getLIRGen().newVariable(operand.getValueKind());
|
||||
getLIRGen().append(new SPARCOP3Op(Op3s.Srl, usedOperand, g0.asValue(), intermediateOperand));
|
||||
usedOperand = intermediateOperand;
|
||||
}
|
||||
getLIRGen().append(new SPARCOP3Op(Op3s.Popc, SPARC.g0.asValue(), usedOperand, result));
|
||||
getLIRGen().append(new SPARCOP3Op(Op3s.Popc, g0.asValue(), usedOperand, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -141,9 +142,9 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitMathAbs(Value input) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
SPARCKind kind = (SPARCKind) input.getPlatformKind();
|
||||
public Value emitMathAbs(Value inputValue) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
|
||||
SPARCKind kind = (SPARCKind) inputValue.getPlatformKind();
|
||||
Opfs opf;
|
||||
switch (kind) {
|
||||
case SINGLE:
|
||||
@ -155,14 +156,14 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere("Input kind: " + kind);
|
||||
}
|
||||
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
|
||||
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), getLIRGen().asAllocatable(inputValue), result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitMathSqrt(Value input) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
SPARCKind kind = (SPARCKind) input.getPlatformKind();
|
||||
public Value emitMathSqrt(Value inputValue) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
|
||||
SPARCKind kind = (SPARCKind) inputValue.getPlatformKind();
|
||||
Opfs opf;
|
||||
switch (kind) {
|
||||
case SINGLE:
|
||||
@ -174,7 +175,7 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere("Input kind: " + kind);
|
||||
}
|
||||
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
|
||||
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), getLIRGen().asAllocatable(inputValue), result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -193,9 +194,9 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
|
||||
return emitUnary(Xnor, input);
|
||||
}
|
||||
|
||||
private Variable emitUnary(Opfs opf, Value input) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
|
||||
private Variable emitUnary(Opfs opf, Value inputValue) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
|
||||
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), getLIRGen().asAllocatable(inputValue), result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -211,11 +212,7 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
|
||||
|
||||
private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b, LIRFrameState state) {
|
||||
Variable result = getLIRGen().newVariable(resultKind);
|
||||
if (opf.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) {
|
||||
getLIRGen().append(new SPARCOPFOp(opf, b, a, result, state));
|
||||
} else {
|
||||
getLIRGen().append(new SPARCOPFOp(opf, a, b, result, state));
|
||||
}
|
||||
getLIRGen().append(new SPARCOPFOp(opf, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b), result, state));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -495,78 +492,78 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitFloatConvert(FloatConvert op, Value inputVal) {
|
||||
AllocatableValue input = getLIRGen().asAllocatable(inputVal);
|
||||
Value result;
|
||||
public Value emitFloatConvert(FloatConvert op, Value inputValue) {
|
||||
AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputValue);
|
||||
AllocatableValue result;
|
||||
switch (op) {
|
||||
case D2F:
|
||||
result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(SINGLE));
|
||||
getLIRGen().append(new SPARCOPFOp(Fdtos, inputVal, result));
|
||||
result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(SINGLE));
|
||||
getLIRGen().append(new SPARCOPFOp(Fdtos, inputAllocatable, result));
|
||||
break;
|
||||
case F2D:
|
||||
result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(DOUBLE));
|
||||
getLIRGen().append(new SPARCOPFOp(Fstod, inputVal, result));
|
||||
result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(DOUBLE));
|
||||
getLIRGen().append(new SPARCOPFOp(Fstod, inputAllocatable, result));
|
||||
break;
|
||||
case I2F: {
|
||||
AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
|
||||
AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
|
||||
result = getLIRGen().newVariable(intEncodedFloatReg.getValueKind());
|
||||
moveBetweenFpGp(intEncodedFloatReg, input);
|
||||
moveBetweenFpGp(intEncodedFloatReg, inputAllocatable);
|
||||
getLIRGen().append(new SPARCOPFOp(Fitos, intEncodedFloatReg, result));
|
||||
break;
|
||||
}
|
||||
case I2D: {
|
||||
// Unfortunately we must do int -> float -> double because fitod has float
|
||||
// and double encoding in one instruction
|
||||
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
|
||||
result = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
|
||||
moveBetweenFpGp(convertedFloatReg, input);
|
||||
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
|
||||
result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
|
||||
moveBetweenFpGp(convertedFloatReg, inputAllocatable);
|
||||
getLIRGen().append(new SPARCOPFOp(Fitod, convertedFloatReg, result));
|
||||
break;
|
||||
}
|
||||
case L2D: {
|
||||
AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
|
||||
moveBetweenFpGp(longEncodedDoubleReg, input);
|
||||
AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
|
||||
moveBetweenFpGp(longEncodedDoubleReg, inputAllocatable);
|
||||
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(longEncodedDoubleReg.getValueKind());
|
||||
getLIRGen().append(new SPARCOPFOp(Fxtod, longEncodedDoubleReg, convertedDoubleReg));
|
||||
result = convertedDoubleReg;
|
||||
break;
|
||||
}
|
||||
case D2I: {
|
||||
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
|
||||
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, input, convertedFloatReg));
|
||||
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
|
||||
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, inputAllocatable, convertedFloatReg));
|
||||
AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
|
||||
moveBetweenFpGp(convertedIntReg, convertedFloatReg);
|
||||
result = convertedIntReg;
|
||||
break;
|
||||
}
|
||||
case F2L: {
|
||||
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
|
||||
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, input, convertedDoubleReg));
|
||||
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
|
||||
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, inputAllocatable, convertedDoubleReg));
|
||||
AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
|
||||
moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
|
||||
result = convertedLongReg;
|
||||
break;
|
||||
}
|
||||
case F2I: {
|
||||
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
|
||||
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, input, convertedFloatReg));
|
||||
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
|
||||
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, inputAllocatable, convertedFloatReg));
|
||||
AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
|
||||
moveBetweenFpGp(convertedIntReg, convertedFloatReg);
|
||||
result = convertedIntReg;
|
||||
break;
|
||||
}
|
||||
case D2L: {
|
||||
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
|
||||
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, input, convertedDoubleReg));
|
||||
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
|
||||
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, inputAllocatable, convertedDoubleReg));
|
||||
AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
|
||||
moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
|
||||
result = convertedLongReg;
|
||||
break;
|
||||
}
|
||||
case L2F: {
|
||||
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
|
||||
result = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
|
||||
moveBetweenFpGp(convertedDoubleReg, input);
|
||||
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
|
||||
result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
|
||||
moveBetweenFpGp(convertedDoubleReg, inputAllocatable);
|
||||
getLIRGen().append(new SPARCOPFOp(Opfs.Fxtos, convertedDoubleReg, result));
|
||||
break;
|
||||
}
|
||||
@ -609,10 +606,9 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
|
||||
assert fromBits <= toBits && toBits <= XWORD.getSizeInBits();
|
||||
LIRKind shiftKind = LIRKind.value(WORD);
|
||||
LIRKind resultKind = LIRKind.combine(inputVal).changeType(toBits > 32 ? XWORD : WORD);
|
||||
Value result;
|
||||
int shiftCount = XWORD.getSizeInBits() - fromBits;
|
||||
if (fromBits == toBits) {
|
||||
result = inputVal;
|
||||
return inputVal;
|
||||
} else if (isJavaConstant(inputVal)) {
|
||||
JavaConstant javaConstant = asJavaConstant(inputVal);
|
||||
long constant;
|
||||
@ -622,30 +618,33 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
|
||||
constant = javaConstant.asLong();
|
||||
}
|
||||
return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount));
|
||||
} else if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) {
|
||||
result = getLIRGen().newVariable(resultKind);
|
||||
getLIRGen().append(new SPARCOP3Op(Sra, inputVal, SPARC.g0.asValue(LIRKind.value(WORD)), result));
|
||||
} else {
|
||||
Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD));
|
||||
result = getLIRGen().newVariable(resultKind);
|
||||
getLIRGen().append(new SPARCOP3Op(Sllx, inputVal, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), tmp));
|
||||
getLIRGen().append(new SPARCOP3Op(Srax, tmp, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), result));
|
||||
AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputVal);
|
||||
Variable result = getLIRGen().newVariable(resultKind);
|
||||
if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) {
|
||||
getLIRGen().append(new SPARCOP3Op(Sra, inputAllocatable, g0.asValue(LIRKind.value(WORD)), result));
|
||||
} else {
|
||||
Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD));
|
||||
getLIRGen().append(new SPARCOP3Op(Sllx, inputAllocatable, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), tmp));
|
||||
getLIRGen().append(new SPARCOP3Op(Srax, tmp, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
|
||||
public Value emitZeroExtend(Value inputValue, int fromBits, int toBits) {
|
||||
assert fromBits <= toBits && toBits <= 64;
|
||||
if (fromBits == toBits) {
|
||||
return inputVal;
|
||||
return inputValue;
|
||||
}
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD));
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD));
|
||||
AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputValue);
|
||||
if (fromBits == 32) {
|
||||
getLIRGen().append(new SPARCOP3Op(Srl, inputVal, g0.asValue(), result));
|
||||
getLIRGen().append(new SPARCOP3Op(Srl, inputAllocatable, g0.asValue(), result));
|
||||
} else {
|
||||
Value mask = getLIRGen().emitConstant(LIRKind.value(XWORD), forLong(mask(fromBits)));
|
||||
getLIRGen().append(new SPARCOP3Op(And, inputVal, mask, result));
|
||||
getLIRGen().append(new SPARCOP3Op(And, inputAllocatable, mask, result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -67,4 +67,19 @@ public class SPARCImmediateAddressNode extends AddressNode implements LIRLowerab
|
||||
|
||||
gen.setResult(this, new SPARCImmediateAddressValue(kind, baseValue, displacement));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode getBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxConstantDisplacement() {
|
||||
return displacement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode getIndex() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ public class SPARCIndexedAddressNode extends AddressNode implements LIRLowerable
|
||||
gen.setResult(this, new SPARCIndexedAddressValue(kind, baseValue, indexValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode getBase() {
|
||||
return base;
|
||||
}
|
||||
@ -74,6 +75,7 @@ public class SPARCIndexedAddressNode extends AddressNode implements LIRLowerable
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode getIndex() {
|
||||
return index;
|
||||
}
|
||||
@ -82,4 +84,9 @@ public class SPARCIndexedAddressNode extends AddressNode implements LIRLowerable
|
||||
updateUsages(this.index, index);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxConstantDisplacement() {
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
|
||||
@Override
|
||||
public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
|
||||
double trueDestinationProbability) {
|
||||
Value left;
|
||||
AllocatableValue left;
|
||||
Value right;
|
||||
Condition actualCondition;
|
||||
if (isJavaConstant(x)) {
|
||||
@ -234,9 +234,9 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
|
||||
private void emitIntegerTest(Value a, Value b) {
|
||||
assert ((SPARCKind) a.getPlatformKind()).isInteger();
|
||||
if (LIRValueUtil.isVariable(b)) {
|
||||
append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(b), loadNonConst(a)));
|
||||
append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(b), loadSimm13(a)));
|
||||
} else {
|
||||
append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(a), loadNonConst(b)));
|
||||
append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(a), loadSimm13(b)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,6 +250,16 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
|
||||
return load(value);
|
||||
}
|
||||
|
||||
private Value loadSimm13(Value value) {
|
||||
if (isJavaConstant(value)) {
|
||||
JavaConstant c = asJavaConstant(value);
|
||||
if (c.isNull() || SPARCAssembler.isSimm13(c)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return load(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
|
||||
// Emit compare
|
||||
@ -304,24 +314,24 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
|
||||
private boolean emitIntegerCompare(SPARCKind cmpKind, Value a, Value b) {
|
||||
boolean mirrored;
|
||||
assert cmpKind.isInteger();
|
||||
Value left;
|
||||
AllocatableValue left;
|
||||
Value right;
|
||||
if (LIRValueUtil.isVariable(b)) {
|
||||
left = load(b);
|
||||
right = loadNonConst(a);
|
||||
right = loadSimm13(a);
|
||||
mirrored = true;
|
||||
} else {
|
||||
left = load(a);
|
||||
right = loadNonConst(b);
|
||||
right = loadSimm13(b);
|
||||
mirrored = false;
|
||||
}
|
||||
int compareBytes = cmpKind.getSizeInBytes();
|
||||
// SPARC compares 32 or 64 bits
|
||||
if (compareBytes < left.getPlatformKind().getSizeInBytes()) {
|
||||
left = arithmeticLIRGen.emitSignExtend(left, compareBytes * 8, XWORD.getSizeInBytes() * 8);
|
||||
left = asAllocatable(arithmeticLIRGen.emitSignExtend(left, cmpKind.getSizeInBits(), XWORD.getSizeInBits()));
|
||||
}
|
||||
if (compareBytes < right.getPlatformKind().getSizeInBytes()) {
|
||||
right = arithmeticLIRGen.emitSignExtend(right, compareBytes * 8, XWORD.getSizeInBytes() * 8);
|
||||
right = arithmeticLIRGen.emitSignExtend(right, cmpKind.getSizeInBits(), XWORD.getSizeInBits());
|
||||
}
|
||||
append(SPARCOP3Op.newBinaryVoid(Subcc, left, right));
|
||||
return mirrored;
|
||||
@ -365,10 +375,10 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
|
||||
|
||||
@Override
|
||||
public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
|
||||
AllocatableValue scratchValue = newVariable(key.getValueKind());
|
||||
Variable scratchValue = newVariable(key.getValueKind());
|
||||
AllocatableValue base = AllocatableValue.ILLEGAL;
|
||||
for (Constant c : strategy.getKeyConstants()) {
|
||||
if (!(c instanceof JavaConstant) || !getMoveFactory().canInlineConstant((JavaConstant) c)) {
|
||||
if (!getMoveFactory().canInlineConstant(c)) {
|
||||
base = constantTableBaseProvider.getConstantTableBase();
|
||||
break;
|
||||
}
|
||||
@ -376,7 +386,7 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
|
||||
append(createStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue));
|
||||
}
|
||||
|
||||
protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue) {
|
||||
protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, Variable scratchValue) {
|
||||
return new StrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue);
|
||||
}
|
||||
|
||||
@ -396,7 +406,7 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
|
||||
@Override
|
||||
public Variable emitByteSwap(Value input) {
|
||||
Variable result = newVariable(LIRKind.combine(input));
|
||||
append(new SPARCByteSwapOp(this, result, input));
|
||||
append(new SPARCByteSwapOp(this, result, asAllocatable(input)));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -91,21 +91,25 @@ public class SPARCMoveFactory implements MoveFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInlineConstant(JavaConstant c) {
|
||||
switch (c.getJavaKind()) {
|
||||
case Boolean:
|
||||
case Byte:
|
||||
case Char:
|
||||
case Short:
|
||||
case Int:
|
||||
return SPARCAssembler.isSimm13(c.asInt());
|
||||
case Long:
|
||||
return SPARCAssembler.isSimm13(c.asLong());
|
||||
case Object:
|
||||
return c.isNull();
|
||||
default:
|
||||
return false;
|
||||
public boolean canInlineConstant(Constant con) {
|
||||
if (con instanceof JavaConstant) {
|
||||
JavaConstant c = (JavaConstant) con;
|
||||
switch (c.getJavaKind()) {
|
||||
case Boolean:
|
||||
case Byte:
|
||||
case Char:
|
||||
case Short:
|
||||
case Int:
|
||||
return SPARCAssembler.isSimm13(c.asInt());
|
||||
case Long:
|
||||
return SPARCAssembler.isSimm13(c.asLong());
|
||||
case Object:
|
||||
return c.isNull();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,17 +29,27 @@ import static jdk.vm.ci.sparc.SPARCKind.WORD;
|
||||
import static jdk.vm.ci.sparc.SPARCKind.XWORD;
|
||||
|
||||
import org.graalvm.compiler.core.common.LIRKind;
|
||||
import org.graalvm.compiler.core.common.calc.Condition;
|
||||
import org.graalvm.compiler.core.gen.NodeMatchRules;
|
||||
import org.graalvm.compiler.core.match.ComplexMatchResult;
|
||||
import org.graalvm.compiler.core.match.MatchRule;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.lir.LIRFrameState;
|
||||
import org.graalvm.compiler.lir.LabelRef;
|
||||
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
|
||||
import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
|
||||
import org.graalvm.compiler.nodes.DeoptimizingNode;
|
||||
import org.graalvm.compiler.nodes.IfNode;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.calc.CompareNode;
|
||||
import org.graalvm.compiler.nodes.calc.SignExtendNode;
|
||||
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
|
||||
import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
|
||||
import org.graalvm.compiler.nodes.memory.Access;
|
||||
import org.graalvm.compiler.nodes.memory.LIRLowerableAccess;
|
||||
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.Value;
|
||||
import jdk.vm.ci.sparc.SPARCKind;
|
||||
|
||||
/**
|
||||
@ -58,6 +68,10 @@ public class SPARCNodeMatchRules extends NodeMatchRules {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected LIRKind getLirKind(LIRLowerableAccess access) {
|
||||
return gen.getLIRKind(access.getAccessStamp());
|
||||
}
|
||||
|
||||
private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
|
||||
assert fromBits <= toBits && toBits <= 64;
|
||||
SPARCKind toKind = null;
|
||||
@ -127,6 +141,41 @@ public class SPARCNodeMatchRules extends NodeMatchRules {
|
||||
return emitZeroExtendMemory(access, root.getInputBits(), root.getResultBits());
|
||||
}
|
||||
|
||||
@MatchRule("(If (ObjectEquals=compare value LogicCompareAndSwap=cas))")
|
||||
@MatchRule("(If (PointerEquals=compare value LogicCompareAndSwap=cas))")
|
||||
@MatchRule("(If (FloatEquals=compare value LogicCompareAndSwap=cas))")
|
||||
@MatchRule("(If (IntegerEquals=compare value LogicCompareAndSwap=cas))")
|
||||
public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) {
|
||||
JavaConstant constant = value.asJavaConstant();
|
||||
assert compare.condition() == Condition.EQ;
|
||||
if (constant != null && cas.usages().count() == 1) {
|
||||
long constantValue = constant.asLong();
|
||||
boolean successIsTrue;
|
||||
if (constantValue == 0) {
|
||||
successIsTrue = false;
|
||||
} else if (constantValue == 1) {
|
||||
successIsTrue = true;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return builder -> {
|
||||
LIRKind kind = getLirKind(cas);
|
||||
LabelRef trueLabel = getLIRBlock(root.trueSuccessor());
|
||||
LabelRef falseLabel = getLIRBlock(root.falseSuccessor());
|
||||
double trueLabelProbability = root.probability(root.trueSuccessor());
|
||||
Value expectedValue = operand(cas.getExpectedValue());
|
||||
Value newValue = operand(cas.getNewValue());
|
||||
SPARCAddressValue address = (SPARCAddressValue) operand(cas.getAddress());
|
||||
Condition condition = successIsTrue ? Condition.EQ : Condition.NE;
|
||||
|
||||
Value result = getLIRGeneratorTool().emitValueCompareAndSwap(address, expectedValue, newValue);
|
||||
getLIRGeneratorTool().emitCompareBranch(kind.getPlatformKind(), result, expectedValue, condition, false, trueLabel, falseLabel, trueLabelProbability);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SPARCLIRGenerator getLIRGeneratorTool() {
|
||||
return (SPARCLIRGenerator) super.getLIRGeneratorTool();
|
||||
|
@ -26,6 +26,7 @@ import java.util.ListIterator;
|
||||
|
||||
import org.graalvm.compiler.java.DefaultSuitesProvider;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.phases.BasePhase;
|
||||
import org.graalvm.compiler.phases.PhaseSuite;
|
||||
import org.graalvm.compiler.phases.common.ExpandLogicPhase;
|
||||
@ -39,8 +40,8 @@ public class SPARCSuitesProvider extends DefaultSuitesProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Suites createSuites() {
|
||||
Suites s = super.createSuites();
|
||||
public Suites createSuites(OptionValues options) {
|
||||
Suites s = super.createSuites(options);
|
||||
ListIterator<BasePhase<? super LowTierContext>> l = s.getLowTier().findPhase(ExpandLogicPhase.class);
|
||||
while (PhaseSuite.findNextPhase(l, ExpandLogicPhase.class)) {
|
||||
// Search for last occurrence of ExpandLogicPhase
|
||||
|
@ -313,7 +313,7 @@ public class BoxingEliminationTest extends GraalCompilerTest {
|
||||
graph = parseEager(snippet, AllowAssumptions.NO);
|
||||
HighTierContext context = getDefaultHighTierContext();
|
||||
new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
|
||||
new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context);
|
||||
new PartialEscapePhase(false, new CanonicalizerPhase(), graph.getOptions()).apply(graph, context);
|
||||
}
|
||||
|
||||
private void compareGraphs(final String snippet, final String referenceSnippet) {
|
||||
@ -331,7 +331,7 @@ public class BoxingEliminationTest extends GraalCompilerTest {
|
||||
}
|
||||
new DeadCodeEliminationPhase().apply(graph);
|
||||
canonicalizer.apply(graph, context);
|
||||
new PartialEscapePhase(false, canonicalizer).apply(graph, context);
|
||||
new PartialEscapePhase(false, canonicalizer, graph.getOptions()).apply(graph, context);
|
||||
|
||||
new DeadCodeEliminationPhase().apply(graph);
|
||||
canonicalizer.apply(graph, context);
|
||||
|
@ -22,13 +22,13 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
|
||||
import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.INTERCEPT;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
@ -41,10 +41,10 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.api.replacements.Snippet;
|
||||
import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
|
||||
import org.graalvm.compiler.api.replacements.Snippet.NonNullParameter;
|
||||
import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
|
||||
import org.graalvm.compiler.api.test.Graal;
|
||||
import org.graalvm.compiler.bytecode.BridgeMethodUtils;
|
||||
import org.graalvm.compiler.core.CompilerThreadFactory;
|
||||
@ -67,6 +67,7 @@ import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.graalvm.compiler.phases.PhaseSuite;
|
||||
import org.graalvm.compiler.phases.VerifyPhase;
|
||||
@ -80,7 +81,9 @@ import org.graalvm.compiler.phases.verify.VerifyUpdateUsages;
|
||||
import org.graalvm.compiler.phases.verify.VerifyUsageWithEquals;
|
||||
import org.graalvm.compiler.phases.verify.VerifyVirtualizableUsage;
|
||||
import org.graalvm.compiler.runtime.RuntimeProvider;
|
||||
import org.graalvm.compiler.test.GraalTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.code.BailoutException;
|
||||
import jdk.vm.ci.code.Register;
|
||||
@ -98,7 +101,7 @@ import jdk.vm.ci.meta.Value;
|
||||
* global invariants such as using {@link Object#equals(Object)} to compare certain types instead of
|
||||
* identity comparisons.
|
||||
*/
|
||||
public class CheckGraalInvariants extends GraalTest {
|
||||
public class CheckGraalInvariants extends GraalCompilerTest {
|
||||
|
||||
private static boolean shouldVerifyEquals(ResolvedJavaMethod m) {
|
||||
if (m.getName().equals("identityEquals")) {
|
||||
@ -114,7 +117,7 @@ public class CheckGraalInvariants extends GraalTest {
|
||||
private static boolean shouldProcess(String classpathEntry) {
|
||||
if (classpathEntry.endsWith(".jar")) {
|
||||
String name = new File(classpathEntry).getName();
|
||||
return name.contains("jvmci") || name.contains("graal");
|
||||
return name.contains("jvmci") || name.contains("graal") || name.contains("jdk.internal.vm.compiler");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -134,9 +137,13 @@ public class CheckGraalInvariants extends GraalTest {
|
||||
|
||||
Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus());
|
||||
|
||||
String propertyName = Java8OrEarlier ? "sun.boot.class.path" : "jdk.module.path";
|
||||
String bootclasspath = System.getProperty(propertyName);
|
||||
Assert.assertNotNull("Cannot find value of " + propertyName, bootclasspath);
|
||||
String bootclasspath;
|
||||
if (Java8OrEarlier) {
|
||||
bootclasspath = System.getProperty("sun.boot.class.path");
|
||||
} else {
|
||||
bootclasspath = System.getProperty("jdk.module.path") + File.pathSeparatorChar + System.getProperty("jdk.module.upgrade.path");
|
||||
}
|
||||
Assert.assertNotNull("Cannot find boot class path", bootclasspath);
|
||||
|
||||
final List<String> classNames = new ArrayList<>();
|
||||
for (String path : bootclasspath.split(File.pathSeparator)) {
|
||||
@ -162,66 +169,85 @@ public class CheckGraalInvariants extends GraalTest {
|
||||
String property = System.getProperty(CheckGraalInvariants.class.getName() + ".filters");
|
||||
String[] filters = property == null ? null : property.split(",");
|
||||
|
||||
OptionValues options = getInitialOptions();
|
||||
CompilerThreadFactory factory = new CompilerThreadFactory("CheckInvariantsThread", new DebugConfigAccess() {
|
||||
@Override
|
||||
public GraalDebugConfig getDebugConfig() {
|
||||
return DebugEnvironment.initialize(System.out);
|
||||
return DebugEnvironment.ensureInitialized(options);
|
||||
}
|
||||
});
|
||||
int availableProcessors = Runtime.getRuntime().availableProcessors();
|
||||
ThreadPoolExecutor executor = new ThreadPoolExecutor(availableProcessors, availableProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
|
||||
|
||||
List<String> errors = Collections.synchronizedList(new ArrayList<>());
|
||||
// Order outer classes before the inner classes
|
||||
classNames.sort((String a, String b) -> a.compareTo(b));
|
||||
// Initialize classes in single thread to avoid deadlocking issues during initialization
|
||||
List<Class<?>> classes = initializeClasses(classNames);
|
||||
for (Class<?> c : classes) {
|
||||
String className = c.getName();
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
checkClass(c, metaAccess);
|
||||
} catch (Throwable e) {
|
||||
errors.add(String.format("Error while checking %s:%n%s", className, printStackTraceToString(e)));
|
||||
}
|
||||
});
|
||||
|
||||
for (Method m : c.getDeclaredMethods()) {
|
||||
if (Modifier.isNative(m.getModifiers()) || Modifier.isAbstract(m.getModifiers())) {
|
||||
// ignore
|
||||
} else {
|
||||
String methodName = className + "." + m.getName();
|
||||
if (matches(filters, methodName)) {
|
||||
executor.execute(() -> {
|
||||
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
|
||||
StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID);
|
||||
try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("CheckingGraph", graph, method)) {
|
||||
graphBuilderSuite.apply(graph, context);
|
||||
// update phi stamps
|
||||
graph.getNodes().filter(PhiNode.class).forEach(PhiNode::inferStamp);
|
||||
checkGraph(context, graph);
|
||||
} catch (VerificationError e) {
|
||||
errors.add(e.getMessage());
|
||||
} catch (LinkageError e) {
|
||||
// suppress linkages errors resulting from eager resolution
|
||||
} catch (BailoutException e) {
|
||||
// Graal bail outs on certain patterns in Java bytecode (e.g.,
|
||||
// unbalanced monitors introduced by jacoco).
|
||||
} catch (Throwable e) {
|
||||
errors.add(String.format("Error while checking %s:%n%s", methodName, printStackTraceToString(e)));
|
||||
}
|
||||
});
|
||||
for (Method m : BadUsageWithEquals.class.getDeclaredMethods()) {
|
||||
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
|
||||
StructuredGraph graph = new StructuredGraph.Builder(options, AllowAssumptions.YES).method(method).build();
|
||||
try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("CheckingGraph", graph, method)) {
|
||||
graphBuilderSuite.apply(graph, context);
|
||||
// update phi stamps
|
||||
graph.getNodes().filter(PhiNode.class).forEach(PhiNode::inferStamp);
|
||||
checkGraph(context, graph);
|
||||
errors.add(String.format("Expected error while checking %s", m));
|
||||
} catch (VerificationError e) {
|
||||
// expected!
|
||||
} catch (Throwable e) {
|
||||
errors.add(String.format("Error while checking %s:%n%s", m, printStackTraceToString(e)));
|
||||
}
|
||||
}
|
||||
if (errors.isEmpty()) {
|
||||
// Order outer classes before the inner classes
|
||||
classNames.sort((String a, String b) -> a.compareTo(b));
|
||||
// Initialize classes in single thread to avoid deadlocking issues during initialization
|
||||
List<Class<?>> classes = initializeClasses(classNames);
|
||||
for (Class<?> c : classes) {
|
||||
String className = c.getName();
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
checkClass(c, metaAccess);
|
||||
} catch (Throwable e) {
|
||||
errors.add(String.format("Error while checking %s:%n%s", className, printStackTraceToString(e)));
|
||||
}
|
||||
});
|
||||
|
||||
for (Method m : c.getDeclaredMethods()) {
|
||||
if (Modifier.isNative(m.getModifiers()) || Modifier.isAbstract(m.getModifiers())) {
|
||||
// ignore
|
||||
} else {
|
||||
String methodName = className + "." + m.getName();
|
||||
if (matches(filters, methodName)) {
|
||||
executor.execute(() -> {
|
||||
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
|
||||
StructuredGraph graph = new StructuredGraph.Builder(options).method(method).build();
|
||||
try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("CheckingGraph", graph, method)) {
|
||||
checkMethod(method);
|
||||
graphBuilderSuite.apply(graph, context);
|
||||
// update phi stamps
|
||||
graph.getNodes().filter(PhiNode.class).forEach(PhiNode::inferStamp);
|
||||
checkGraph(context, graph);
|
||||
} catch (VerificationError e) {
|
||||
errors.add(e.getMessage());
|
||||
} catch (LinkageError e) {
|
||||
// suppress linkages errors resulting from eager resolution
|
||||
} catch (BailoutException e) {
|
||||
// Graal bail outs on certain patterns in Java bytecode (e.g.,
|
||||
// unbalanced monitors introduced by jacoco).
|
||||
} catch (Throwable e) {
|
||||
errors.add(String.format("Error while checking %s:%n%s", methodName, printStackTraceToString(e)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
executor.shutdown();
|
||||
try {
|
||||
executor.awaitTermination(1, TimeUnit.HOURS);
|
||||
} catch (InterruptedException e1) {
|
||||
throw new RuntimeException(e1);
|
||||
}
|
||||
}
|
||||
executor.shutdown();
|
||||
try {
|
||||
executor.awaitTermination(1, TimeUnit.HOURS);
|
||||
} catch (InterruptedException e1) {
|
||||
throw new RuntimeException(e1);
|
||||
}
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
StringBuilder msg = new StringBuilder();
|
||||
String nl = String.format("%n");
|
||||
@ -262,11 +288,30 @@ public class CheckGraalInvariants extends GraalTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkMethod(ResolvedJavaMethod method) {
|
||||
if (method.getAnnotation(Snippet.class) == null) {
|
||||
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||
for (int i = 0; i < parameterAnnotations.length; i++) {
|
||||
for (Annotation a : parameterAnnotations[i]) {
|
||||
Class<? extends Annotation> annotationType = a.annotationType();
|
||||
if (annotationType == ConstantParameter.class || annotationType == VarargsParameter.class || annotationType == NonNullParameter.class) {
|
||||
VerificationError verificationError = new VerificationError("Parameter %d of %s is annotated with %s but the method is not annotated with %s", i, method,
|
||||
annotationType.getSimpleName(),
|
||||
Snippet.class.getSimpleName());
|
||||
throw verificationError;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the invariants for a single graph.
|
||||
*/
|
||||
private static void checkGraph(HighTierContext context, StructuredGraph graph) {
|
||||
if (shouldVerifyEquals(graph.method())) {
|
||||
// If you add a new type to test here, be sure to add appropriate
|
||||
// methods to the BadUsageWithEquals class below
|
||||
new VerifyUsageWithEquals(Value.class).apply(graph, context);
|
||||
new VerifyUsageWithEquals(Register.class).apply(graph, context);
|
||||
new VerifyUsageWithEquals(RegisterCategory.class).apply(graph, context);
|
||||
@ -305,4 +350,108 @@ public class CheckGraalInvariants extends GraalTest {
|
||||
t.printStackTrace(new PrintWriter(sw));
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
static class BadUsageWithEquals {
|
||||
Value aValue;
|
||||
Register aRegister;
|
||||
RegisterCategory aRegisterCategory;
|
||||
JavaType aJavaType;
|
||||
JavaField aJavaField;
|
||||
JavaMethod aJavaMethod;
|
||||
LocationIdentity aLocationIdentity;
|
||||
LIRKind aLIRKind;
|
||||
ArithmeticOpTable anArithmeticOpTable;
|
||||
ArithmeticOpTable.Op anArithmeticOpTableOp;
|
||||
|
||||
static Value aStaticValue;
|
||||
static Register aStaticRegister;
|
||||
static RegisterCategory aStaticRegisterCategory;
|
||||
static JavaType aStaticJavaType;
|
||||
static JavaField aStaticJavaField;
|
||||
static JavaMethod aStaticJavaMethod;
|
||||
static LocationIdentity aStaticLocationIdentity;
|
||||
static LIRKind aStaticLIRKind;
|
||||
static ArithmeticOpTable aStaticArithmeticOpTable;
|
||||
static ArithmeticOpTable.Op aStaticArithmeticOpTableOp;
|
||||
|
||||
boolean test01(Value f) {
|
||||
return aValue == f;
|
||||
}
|
||||
|
||||
boolean test02(Register f) {
|
||||
return aRegister == f;
|
||||
}
|
||||
|
||||
boolean test03(RegisterCategory f) {
|
||||
return aRegisterCategory == f;
|
||||
}
|
||||
|
||||
boolean test04(JavaType f) {
|
||||
return aJavaType == f;
|
||||
}
|
||||
|
||||
boolean test05(JavaField f) {
|
||||
return aJavaField == f;
|
||||
}
|
||||
|
||||
boolean test06(JavaMethod f) {
|
||||
return aJavaMethod == f;
|
||||
}
|
||||
|
||||
boolean test07(LocationIdentity f) {
|
||||
return aLocationIdentity == f;
|
||||
}
|
||||
|
||||
boolean test08(LIRKind f) {
|
||||
return aLIRKind == f;
|
||||
}
|
||||
|
||||
boolean test09(ArithmeticOpTable f) {
|
||||
return anArithmeticOpTable == f;
|
||||
}
|
||||
|
||||
boolean test10(ArithmeticOpTable.Op f) {
|
||||
return anArithmeticOpTableOp == f;
|
||||
}
|
||||
|
||||
boolean test12(Value f) {
|
||||
return aStaticValue == f;
|
||||
}
|
||||
|
||||
boolean test13(Register f) {
|
||||
return aStaticRegister == f;
|
||||
}
|
||||
|
||||
boolean test14(RegisterCategory f) {
|
||||
return aStaticRegisterCategory == f;
|
||||
}
|
||||
|
||||
boolean test15(JavaType f) {
|
||||
return aStaticJavaType == f;
|
||||
}
|
||||
|
||||
boolean test16(JavaField f) {
|
||||
return aStaticJavaField == f;
|
||||
}
|
||||
|
||||
boolean test17(JavaMethod f) {
|
||||
return aStaticJavaMethod == f;
|
||||
}
|
||||
|
||||
boolean test18(LocationIdentity f) {
|
||||
return aStaticLocationIdentity == f;
|
||||
}
|
||||
|
||||
boolean test19(LIRKind f) {
|
||||
return aStaticLIRKind == f;
|
||||
}
|
||||
|
||||
boolean test20(ArithmeticOpTable f) {
|
||||
return aStaticArithmeticOpTable == f;
|
||||
}
|
||||
|
||||
boolean test21(ArithmeticOpTable.Op f) {
|
||||
return aStaticArithmeticOpTableOp == f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ public class CommonedConstantsTest extends GraalCompilerTest {
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
getSuites().getHighTier().findPhase(AbstractInliningPhase.class).remove();
|
||||
createSuites(getInitialOptions()).getHighTier().findPhase(AbstractInliningPhase.class).remove();
|
||||
test1Snippet(new String(alphabet));
|
||||
|
||||
test("test1Snippet", (Object) null);
|
||||
@ -114,7 +114,7 @@ public class CommonedConstantsTest extends GraalCompilerTest {
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
assert getSuites().getHighTier().findPhase(AbstractInliningPhase.class).hasNext();
|
||||
assert createSuites(getInitialOptions()).getHighTier().findPhase(AbstractInliningPhase.class).hasNext();
|
||||
test2Snippet(new String(alphabet));
|
||||
|
||||
test("test2Snippet", (Object) null);
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isNotEmpty;
|
||||
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
|
||||
import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
|
||||
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
|
||||
import org.graalvm.compiler.phases.tiers.PhaseContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CompareCanonicalizerTest2 extends GraalCompilerTest {
|
||||
|
||||
@SuppressWarnings("unused") private static int sink0;
|
||||
@SuppressWarnings("unused") private static int sink1;
|
||||
|
||||
private StructuredGraph getCanonicalizedGraph(String name) {
|
||||
StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
|
||||
new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
|
||||
return graph;
|
||||
}
|
||||
|
||||
public void testIntegerTestCanonicalization(String name) {
|
||||
StructuredGraph graph = getCanonicalizedGraph(name);
|
||||
Assert.assertThat(graph.getNodes().filter(IntegerLessThanNode.class), isNotEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test0() {
|
||||
testIntegerTestCanonicalization("integerTestCanonicalization0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
testIntegerTestCanonicalization("integerTestCanonicalization1");
|
||||
}
|
||||
|
||||
public static void integerTestCanonicalization0(int a) {
|
||||
if (1 < a + 1) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void integerTestCanonicalization1(int a) {
|
||||
if (a - 1 < -1) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -33,7 +33,9 @@ import jdk.vm.ci.meta.JavaConstant;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.core.common.calc.Condition;
|
||||
import org.graalvm.compiler.test.AddExports;
|
||||
|
||||
@AddExports("jdk.internal.vm.ci/jdk.vm.ci.meta")
|
||||
public class ConditionTest {
|
||||
|
||||
@Test
|
||||
|
@ -1,289 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.nodes.IfNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
|
||||
import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
|
||||
import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
public class ConditionalEliminationLoadFieldConstantFoldTest extends GraalCompilerTest {
|
||||
public static int intSideEffect;
|
||||
|
||||
public static final B FinalField = new B(10);
|
||||
|
||||
private abstract static class A {
|
||||
|
||||
}
|
||||
|
||||
private static class B extends A {
|
||||
final int a;
|
||||
|
||||
B(int a) {
|
||||
this.a = a;
|
||||
}
|
||||
}
|
||||
|
||||
private static class C extends A {
|
||||
final B b;
|
||||
|
||||
C(B b) {
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
|
||||
private static class D extends A {
|
||||
final C c;
|
||||
|
||||
D(C c) {
|
||||
this.c = c;
|
||||
}
|
||||
}
|
||||
|
||||
private static class E extends D {
|
||||
final Object o;
|
||||
|
||||
E(C c, Object o) {
|
||||
super(c);
|
||||
this.o = o;
|
||||
}
|
||||
}
|
||||
|
||||
public static final B CONST_B = new B(10);
|
||||
public static final C CONST_C = new C(CONST_B);
|
||||
public static final D CONST_D = new D(CONST_C);
|
||||
|
||||
public int testReadConstInBranch(B b) {
|
||||
if (b == CONST_B) {
|
||||
if (b.a == 5) {
|
||||
intSideEffect = b.a;
|
||||
} else {
|
||||
intSideEffect = 10;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int testMultipleReadsConstInBranch(D d) {
|
||||
if (d == CONST_D) {
|
||||
C c = d.c;
|
||||
B b = c.b;
|
||||
int res = b.a + 12;
|
||||
if (res == 125) {
|
||||
intSideEffect = 12;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int testLoadFinalInstanceOf(E e) {
|
||||
Object o = e.o;
|
||||
if (o == CONST_C) {
|
||||
if (o instanceof A) {
|
||||
// eliminate, implied by a.x == Const(Subclass)
|
||||
intSideEffect = 1;
|
||||
} else {
|
||||
intSideEffect = 10;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int testLoadFinalTwiceInstanceOf(E e) {
|
||||
if (e.o == CONST_C) {
|
||||
if (e.o instanceof A) {
|
||||
intSideEffect = 1;
|
||||
} else {
|
||||
intSideEffect = 10;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static class C1 {
|
||||
final int a;
|
||||
|
||||
C1(int a) {
|
||||
this.a = a;
|
||||
}
|
||||
}
|
||||
|
||||
static class C2 {
|
||||
final C1 c1;
|
||||
|
||||
C2(C1 c1) {
|
||||
this.c1 = c1;
|
||||
}
|
||||
}
|
||||
|
||||
public static int foldThatIsNotAllowed(C2 c2) {
|
||||
// read before, this will be used to load through when folding
|
||||
C1 c1Unknown = c2.c1;
|
||||
|
||||
// be naughty (will be a store field after canonicalization as it has a constant offset, so
|
||||
// we would be able to eliminate the inner if after an early read elimination but we would
|
||||
// fold before and ce the inner if already)
|
||||
//
|
||||
// note: if the offset would not be constant but a parameter we would not even be able to
|
||||
// remove in inner most if as we cannot rewrite the unsafe store to a store field node as
|
||||
// the store might kill ANY_LOCATION
|
||||
UNSAFE.putObject(c2, C2_C1_OFFSET, C1_AFTER_READ_CONST);
|
||||
|
||||
if (c2 == C2_CONST) {
|
||||
if (c1Unknown == C1_CONST) {
|
||||
/*
|
||||
* This if can be eliminated (as we rewrite the unsafe store with a constant offset
|
||||
* to a store field node) but the remaining branch must be the false branch. If we
|
||||
* do not fold through both field loads we will canonicalize the unsafe store to a
|
||||
* store field, see the new value and can thus eliminate the true branch
|
||||
*
|
||||
* if we fold through the load fields we would load from the object read before the
|
||||
* store so we miss the unsafe update
|
||||
*/
|
||||
if (c2.c1.a == 10) {
|
||||
intSideEffect = 1;
|
||||
return 1;
|
||||
} else {
|
||||
intSideEffect = 2;
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
intSideEffect = -2;
|
||||
return -2;
|
||||
}
|
||||
} else {
|
||||
intSideEffect = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int testLoadFinalTwiceNoReadEliminationInstanceOf(E e) {
|
||||
if (e.o == CONST_C) {
|
||||
/*
|
||||
* we cannot eliminate the second read of e.o although it is a final field. the call to
|
||||
* System.gc (or any other memory checkpoint killing ANY_LOCATION) will prohibit the
|
||||
* elimination of the second load, thus we have two different load nodes, we know that
|
||||
* that first load field is a constant but we do not know for the second one, assuming
|
||||
* e.o is final, as it might have been written in between
|
||||
*
|
||||
* this prohibits us to remove the if (fold through all loads to final fields) and the
|
||||
* instance of e.o
|
||||
*/
|
||||
System.gc();
|
||||
C c = (C) e.o;
|
||||
if (c.b.a == 10) {
|
||||
intSideEffect = 1;
|
||||
} else {
|
||||
intSideEffect = 10;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
private static final C1 C1_CONST = new C1(0);
|
||||
private static final C2 C2_CONST = new C2(C1_CONST);
|
||||
private static final C1 C1_AFTER_READ_CONST = new C1(10);
|
||||
|
||||
private static Unsafe getUnsafe() {
|
||||
try {
|
||||
return Unsafe.getUnsafe();
|
||||
} catch (SecurityException e) {
|
||||
}
|
||||
try {
|
||||
Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafeInstance.setAccessible(true);
|
||||
return (Unsafe) theUnsafeInstance.get(Unsafe.class);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final sun.misc.Unsafe UNSAFE = getUnsafe();
|
||||
private static final long C2_C1_OFFSET;
|
||||
|
||||
static {
|
||||
try {
|
||||
Field f = C2.class.getDeclaredField("c1");
|
||||
C2_C1_OFFSET = UNSAFE.objectFieldOffset(f);
|
||||
} catch (NoSuchFieldException | SecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test01() {
|
||||
checkGraph("testReadConstInBranch", 1);
|
||||
test("testReadConstInBranch", new B(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test02() {
|
||||
checkGraph("testMultipleReadsConstInBranch", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test03() {
|
||||
checkGraph("testLoadFinalInstanceOf", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test04() {
|
||||
checkGraph("testLoadFinalTwiceInstanceOf", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test05() {
|
||||
checkGraph("testLoadFinalTwiceNoReadEliminationInstanceOf", 2);
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
@SuppressWarnings("try")
|
||||
public void test06() {
|
||||
Result actual = executeActual(getResolvedJavaMethod("foldThatIsNotAllowed"), null, C2_CONST);
|
||||
UNSAFE.putObject(C2_CONST, C2_C1_OFFSET, C1_CONST);
|
||||
Result expected = executeExpected(getResolvedJavaMethod("foldThatIsNotAllowed"), null, C2_CONST);
|
||||
Assert.assertEquals(expected.returnValue, actual.returnValue);
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
private StructuredGraph checkGraph(String name, int nrOfIfsAfter) {
|
||||
StructuredGraph g = parseForCompile(getResolvedJavaMethod(name));
|
||||
CanonicalizerPhase c = new CanonicalizerPhase();
|
||||
c.apply(g, getDefaultHighTierContext());
|
||||
new EarlyReadEliminationPhase(c).apply(g, getDefaultHighTierContext());
|
||||
new IterativeConditionalEliminationPhase(c, false).apply(g, getDefaultHighTierContext());
|
||||
Assert.assertEquals("Nr of Ifs left does not match", nrOfIfsAfter, g.getNodes().filter(IfNode.class).count());
|
||||
c.apply(g, getDefaultHighTierContext());
|
||||
return g;
|
||||
}
|
||||
|
||||
}
|
@ -22,13 +22,12 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
|
||||
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
|
||||
import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ConditionalEliminationMulTest extends GraalCompilerTest {
|
||||
|
||||
@ -76,11 +75,9 @@ public class ConditionalEliminationMulTest extends GraalCompilerTest {
|
||||
private StructuredGraph prepareGraph(String snippet) {
|
||||
StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
|
||||
HighTierContext context = getDefaultHighTierContext();
|
||||
DominatorConditionalEliminationPhase.create(false).apply(graph, context);
|
||||
CanonicalizerPhase c = new CanonicalizerPhase();
|
||||
c.apply(graph, context);
|
||||
new DominatorConditionalEliminationPhase(false).apply(graph, context);
|
||||
c.apply(graph, context);
|
||||
return graph;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -44,14 +44,17 @@ import org.graalvm.compiler.phases.tiers.PhaseContext;
|
||||
*/
|
||||
public class ConditionalEliminationTest10 extends ConditionalEliminationTestBase {
|
||||
|
||||
private static boolean condition1;
|
||||
private static boolean condition2;
|
||||
|
||||
private static class TestClass {
|
||||
int x;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static int testSnippet(int a, TestClass t) {
|
||||
public static int testSnippet1(TestClass t) {
|
||||
int result = 0;
|
||||
if (a == 0) {
|
||||
if (condition1) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
result = t.x;
|
||||
}
|
||||
@ -61,11 +64,38 @@ public class ConditionalEliminationTest10 extends ConditionalEliminationTestBase
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
StructuredGraph graph = parseEager("testSnippet", AllowAssumptions.YES);
|
||||
test("testSnippet1", 1);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static int testSnippet2(TestClass t) {
|
||||
int result = 0;
|
||||
if (condition1) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
result = t.x;
|
||||
} else {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
result = t.x;
|
||||
}
|
||||
|
||||
if (condition2) {
|
||||
result = t.x;
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
test("testSnippet2", 1);
|
||||
}
|
||||
|
||||
private void test(String snippet, int guardCount) {
|
||||
StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
|
||||
PhaseContext context = new PhaseContext(getProviders());
|
||||
new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
|
||||
Assert.assertEquals(2, graph.getNodes().filter(GuardNode.class).count());
|
||||
new DominatorConditionalEliminationPhase(true).apply(graph, context);
|
||||
Assert.assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
|
||||
DominatorConditionalEliminationPhase.create(true).apply(graph, context);
|
||||
Assert.assertEquals(guardCount, graph.getNodes().filter(GuardNode.class).count());
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
@SuppressWarnings("all")
|
||||
public static int referenceSnippet(int a) {
|
||||
if ((a & 15) != 15) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -54,10 +54,10 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
@SuppressWarnings("all")
|
||||
public static int test1Snippet(int a) {
|
||||
if ((a & 8) != 8) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 15) != 15) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -65,10 +65,10 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
@SuppressWarnings("all")
|
||||
public static int test2Snippet(int a) {
|
||||
if ((a & 8) == 0) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 15) != 15) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -81,10 +81,10 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
@SuppressWarnings("all")
|
||||
public static int test3Snippet(int a) {
|
||||
if ((a & 15) != 15) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 8) != 8) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -98,10 +98,10 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
@SuppressWarnings("all")
|
||||
public static int test4Snippet(int a) {
|
||||
if ((a & 15) != 15) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 8) == 0) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -114,7 +114,7 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
|
||||
public static int test5Snippet(int a) {
|
||||
if ((a & 5) == 5) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 7) != 0) {
|
||||
return 0;
|
||||
@ -130,19 +130,19 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
|
||||
public static int test6Snippet(int a) {
|
||||
if ((a & 8) != 0) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 15) != 15) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int reference6Snippet(int a) {
|
||||
if ((a & 8) != 0) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -153,17 +153,17 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
|
||||
public static int test7Snippet(int a) {
|
||||
if ((a & 15) == 15) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 8) == 8) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
public static int reference7Snippet(int a) {
|
||||
if ((a & 8) == 8) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
@ -175,20 +175,20 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
|
||||
public static int test8Snippet(int a) {
|
||||
if ((a & 16) == 16) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 8) != 8) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 44) != 44) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
public static int reference8Snippet(int a) {
|
||||
if ((a & 60) != 44) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
@ -201,23 +201,23 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
|
||||
public static int test9Snippet(int a) {
|
||||
if ((a & 16) == 16) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 8) != 8) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 44) != 44) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if (a != 44) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
public static int reference9Snippet(int a) {
|
||||
if (a != 44) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
@ -239,16 +239,16 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
int v = b.byteValue();
|
||||
long a = v & 0xffffffff;
|
||||
if (v != 44) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 16) == 16) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 8) != 8) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 44) != 44) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
|
||||
return v;
|
||||
@ -257,12 +257,13 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
public static int reference10Snippet(ByteHolder b) {
|
||||
byte v = b.byteValue();
|
||||
if (v != 44) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void test10() {
|
||||
testConditionalElimination("test10Snippet", "reference10Snippet");
|
||||
}
|
||||
@ -272,16 +273,16 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
long a = v & 0xffffffff;
|
||||
|
||||
if ((a & 16) == 16) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 8) != 8) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if ((a & 44) != 44) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if (v != 44) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
@ -289,12 +290,13 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
|
||||
public static int reference11Snippet(ByteHolder b) {
|
||||
byte v = b.byteValue();
|
||||
if (v != 44) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void test11() {
|
||||
testConditionalElimination("test11Snippet", "reference11Snippet");
|
||||
}
|
||||
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ConditionalEliminationTest12 extends ConditionalEliminationTestBase {
|
||||
|
||||
static class A {
|
||||
|
||||
}
|
||||
|
||||
static class B extends A {
|
||||
|
||||
}
|
||||
|
||||
static class C extends B {
|
||||
|
||||
}
|
||||
|
||||
static class D extends C {
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings({"static-method", "unused"})
|
||||
private int referenceMethod(Object a) {
|
||||
if (a instanceof A) {
|
||||
if (a instanceof C) {
|
||||
return 1;
|
||||
} else {
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"static-method", "unused"})
|
||||
private int testMethod(Object a) {
|
||||
if (a instanceof A) {
|
||||
if (a instanceof C) {
|
||||
if (a instanceof B) {
|
||||
B b = (B) a;
|
||||
if (b instanceof C) {
|
||||
return 1;
|
||||
} else {
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testFloatingGuards() {
|
||||
// Make sure class D is loaded.
|
||||
D d = new D();
|
||||
testConditionalElimination("testMethod", "referenceMethod");
|
||||
}
|
||||
}
|
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import org.graalvm.compiler.debug.Debug;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
|
||||
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
|
||||
import org.graalvm.compiler.phases.tiers.PhaseContext;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public class ConditionalEliminationTest13 extends ConditionalEliminationTestBase {
|
||||
public ConditionalEliminationTest13() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
private static int sink0;
|
||||
private static int sink1;
|
||||
private static int sink2;
|
||||
|
||||
@Override
|
||||
protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
|
||||
return InlineInvokePlugin.InlineInfo.createStandardInlineInfo(method);
|
||||
}
|
||||
|
||||
public static void referenceSnippet1(int a) {
|
||||
if (Integer.compareUnsigned(a, a + 1) < 0) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void testSnippet1(int a) {
|
||||
if (Integer.compareUnsigned(a, a + 1) < 0 || a == 0) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void referenceSnippet2(int a) {
|
||||
if (0 < a) {
|
||||
sink1 = 0;
|
||||
}
|
||||
sink0 = -1;
|
||||
}
|
||||
|
||||
public static void testSnippet2(int a) {
|
||||
if (0 < a) {
|
||||
if (a == -1) {
|
||||
sink2 = -2;
|
||||
}
|
||||
sink1 = 0;
|
||||
}
|
||||
sink0 = -1;
|
||||
}
|
||||
|
||||
public static void testSnippet3(int a) {
|
||||
if (0 < a) {
|
||||
if (a == 1) {
|
||||
sink2 = -2;
|
||||
}
|
||||
sink1 = 0;
|
||||
}
|
||||
sink0 = -1;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void referenceSnippet4(int a) {
|
||||
sink1 = 0;
|
||||
}
|
||||
|
||||
public static void testSnippet4(int a) {
|
||||
if (Integer.compareUnsigned(a - 1, a) < 0 || a == 0) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void testSnippet5(int a) {
|
||||
if (a < 0) {
|
||||
if (a == -1) {
|
||||
sink2 = -2;
|
||||
}
|
||||
sink1 = 0;
|
||||
}
|
||||
sink0 = -1;
|
||||
}
|
||||
|
||||
public static void referenceSnippet6(int a) {
|
||||
if (a < 0) {
|
||||
sink1 = 0;
|
||||
}
|
||||
sink0 = -1;
|
||||
}
|
||||
|
||||
public static void testSnippet6(int a) {
|
||||
if (a < 0) {
|
||||
if (a == 0) {
|
||||
sink2 = -2;
|
||||
}
|
||||
sink1 = 0;
|
||||
}
|
||||
sink0 = -1;
|
||||
}
|
||||
|
||||
public static void testSnippet7(int a) {
|
||||
if (0 < a) {
|
||||
if (a == 0) {
|
||||
sink2 = -2;
|
||||
}
|
||||
sink1 = 0;
|
||||
}
|
||||
sink0 = -1;
|
||||
}
|
||||
|
||||
public static void testSnippet8(int a) {
|
||||
if (Integer.compareUnsigned(a, a + 1) < 0 || a == 0xffff_ffff) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void referenceSnippet9(int a) {
|
||||
if (Integer.compareUnsigned(a - 1, a) < 0) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void testSnippet9(int a) {
|
||||
if (Integer.compareUnsigned(a - 1, a) < 0 || a == 0xffff_ffff) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int either(int a, int b) {
|
||||
return (sink0 + sink1 + sink2) == 0 ? a : b;
|
||||
}
|
||||
|
||||
public static void testSnippet10(int a) {
|
||||
if (Integer.compareUnsigned(a, a + either(1, 2)) < 0 || a == 0xffff_ffff || a == 0xffff_fffe) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void referenceSnippet11(int a) {
|
||||
if (Integer.compareUnsigned(a, Integer.MAX_VALUE + 1) > 0) {
|
||||
sink1 = 0;
|
||||
}
|
||||
sink0 = -1;
|
||||
}
|
||||
|
||||
public static void testSnippet11(int a) {
|
||||
if (Integer.compareUnsigned(a, Integer.MAX_VALUE + 1) > 0) {
|
||||
if (Integer.compareUnsigned(a, 42) <= 0) {
|
||||
sink2 = -2;
|
||||
}
|
||||
sink1 = 0;
|
||||
}
|
||||
sink0 = -1;
|
||||
}
|
||||
|
||||
public static void referenceSnippet12(int a) {
|
||||
if (Integer.compareUnsigned(a, 0xffff_ffff) >= 0) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void testSnippet12(int a) {
|
||||
if (Integer.compareUnsigned(a, 0xffff_ffff) >= 0 && a == 0xffff_ffff) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void testSnippet13(int a) {
|
||||
int x = either(0, 1);
|
||||
if (a <= a + x) {
|
||||
if (a == Integer.MAX_VALUE) {
|
||||
sink2 = -2;
|
||||
}
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void referenceSnippet14(int a) {
|
||||
int x = either(0, 1);
|
||||
if (a < a + x) {
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void testSnippet14(int a) {
|
||||
int x = either(0, 1);
|
||||
if (a < a + x) {
|
||||
if (a == Integer.MAX_VALUE) {
|
||||
sink2 = -2;
|
||||
}
|
||||
sink1 = 0;
|
||||
} else {
|
||||
sink0 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
testConditionalElimination("testSnippet1", "referenceSnippet1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
testConditionalElimination("testSnippet2", "referenceSnippet2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3() {
|
||||
testConditionalElimination("testSnippet3", "testSnippet3");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4() {
|
||||
testConditionalElimination("testSnippet4", "referenceSnippet4");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test5() {
|
||||
testConditionalElimination("testSnippet5", "testSnippet5");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test6() {
|
||||
testConditionalElimination("testSnippet6", "referenceSnippet6");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test7() {
|
||||
testConditionalElimination("testSnippet7", "referenceSnippet2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test8() {
|
||||
testConditionalElimination("testSnippet8", "referenceSnippet4");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test9() {
|
||||
testConditionalElimination("testSnippet9", "referenceSnippet9");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test10() {
|
||||
testConditionalElimination("testSnippet10", "referenceSnippet4");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test11() {
|
||||
testConditionalElimination("testSnippet11", "referenceSnippet11");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test12() {
|
||||
testConditionalElimination("testSnippet12", "referenceSnippet12");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test13() {
|
||||
testConditionalElimination("testSnippet13", "testSnippet13");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test14() {
|
||||
testConditionalElimination("testSnippet14", "referenceSnippet14");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareGraph(StructuredGraph graph, CanonicalizerPhase canonicalizer, PhaseContext context, boolean applyLowering) {
|
||||
super.prepareGraph(graph, canonicalizer, context, applyLowering);
|
||||
graph.clearAllStateAfter();
|
||||
graph.setGuardsStage(StructuredGraph.GuardsStage.AFTER_FSA);
|
||||
Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After preparation");
|
||||
canonicalizer.apply(graph, context);
|
||||
}
|
||||
}
|
@ -103,7 +103,7 @@ public class ConditionalEliminationTest2 extends ConditionalEliminationTestBase
|
||||
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
|
||||
canonicalizer.apply(graph, context);
|
||||
new FloatingReadPhase().apply(graph);
|
||||
new DominatorConditionalEliminationPhase(true).apply(graph, context);
|
||||
DominatorConditionalEliminationPhase.create(true).apply(graph, context);
|
||||
canonicalizer.apply(graph, context);
|
||||
|
||||
assertDeepEquals(1, graph.getNodes().filter(GuardNode.class).count());
|
||||
@ -125,7 +125,7 @@ public class ConditionalEliminationTest2 extends ConditionalEliminationTestBase
|
||||
|
||||
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
|
||||
canonicalizer.apply(graph, context);
|
||||
new DominatorConditionalEliminationPhase(true).apply(graph, context);
|
||||
DominatorConditionalEliminationPhase.create(true).apply(graph, context);
|
||||
canonicalizer.apply(graph, context);
|
||||
|
||||
assertDeepEquals(0, graph.getNodes().filter(GuardNode.class).count());
|
||||
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
@ -29,6 +30,7 @@ import org.junit.Test;
|
||||
* {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
|
||||
* that triggered bugs in this phase.
|
||||
*/
|
||||
@Ignore
|
||||
public class ConditionalEliminationTest3 extends ConditionalEliminationTestBase {
|
||||
|
||||
private static final String REFERENCE_SNIPPET = "referenceSnippet";
|
||||
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
@ -39,6 +40,10 @@ public class ConditionalEliminationTest5 extends ConditionalEliminationTestBase
|
||||
interface B extends A {
|
||||
}
|
||||
|
||||
interface C extends B {
|
||||
|
||||
}
|
||||
|
||||
static final class DistinctA {
|
||||
}
|
||||
|
||||
@ -115,32 +120,63 @@ public class ConditionalEliminationTest5 extends ConditionalEliminationTestBase
|
||||
|
||||
@Test
|
||||
public void test3() {
|
||||
testConditionalElimination("test3Snippet", "reference3Snippet", true);
|
||||
testConditionalElimination("test3Snippet", "reference3Snippet", true, false);
|
||||
}
|
||||
|
||||
public static int reference4Snippet(Object a) {
|
||||
if (!(a instanceof B)) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static int test4Snippet1(Object a) {
|
||||
if (!(a instanceof B)) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if (!(a instanceof A)) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static int test4Snippet2(Object a) {
|
||||
if (!(a instanceof A)) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if (!(a instanceof B)) {
|
||||
GraalDirectives.deoptimize();
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"cast", "unused"})
|
||||
public static int test4Snippet3(Object a) {
|
||||
Object pi = (A) a;
|
||||
if (!(a instanceof B)) {
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static int test4Snippet4(Object a) {
|
||||
if (!(a instanceof A)) {
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if (!(((A) a) instanceof B)) {
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"cast"})
|
||||
public static int test4Snippet5(Object a) {
|
||||
Object pi = (A) a;
|
||||
if (pi == null) {
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
if (!(a instanceof B)) {
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -149,5 +185,13 @@ public class ConditionalEliminationTest5 extends ConditionalEliminationTestBase
|
||||
public void test4() {
|
||||
testConditionalElimination("test4Snippet1", "reference4Snippet");
|
||||
testConditionalElimination("test4Snippet2", "reference4Snippet");
|
||||
testConditionalElimination("test4Snippet3", "reference4Snippet");
|
||||
testConditionalElimination("test4Snippet5", "reference4Snippet");
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void test5() {
|
||||
testConditionalElimination("test4Snippet4", "reference4Snippet", false, true);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
@ -29,6 +30,7 @@ import org.junit.Test;
|
||||
* {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
|
||||
* that triggered bugs in this phase.
|
||||
*/
|
||||
@Ignore
|
||||
public class ConditionalEliminationTest7 extends ConditionalEliminationTestBase {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
|
@ -22,8 +22,6 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import org.graalvm.compiler.debug.Debug;
|
||||
import org.graalvm.compiler.nodes.ProxyNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
@ -36,6 +34,7 @@ import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
|
||||
import org.graalvm.compiler.phases.common.LoweringPhase;
|
||||
import org.graalvm.compiler.phases.schedule.SchedulePhase;
|
||||
import org.graalvm.compiler.phases.tiers.PhaseContext;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
* Collection of tests for
|
||||
@ -43,11 +42,10 @@ import org.graalvm.compiler.phases.tiers.PhaseContext;
|
||||
* that triggered bugs in this phase.
|
||||
*/
|
||||
public class ConditionalEliminationTestBase extends GraalCompilerTest {
|
||||
|
||||
private final boolean disableSimplification;
|
||||
|
||||
protected ConditionalEliminationTestBase() {
|
||||
disableSimplification = true;
|
||||
this(true);
|
||||
}
|
||||
|
||||
protected ConditionalEliminationTestBase(boolean disableSimplification) {
|
||||
@ -55,11 +53,11 @@ public class ConditionalEliminationTestBase extends GraalCompilerTest {
|
||||
}
|
||||
|
||||
protected void testConditionalElimination(String snippet, String referenceSnippet) {
|
||||
testConditionalElimination(snippet, referenceSnippet, false);
|
||||
testConditionalElimination(snippet, referenceSnippet, false, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
protected void testConditionalElimination(String snippet, String referenceSnippet, boolean applyConditionalEliminationOnReference) {
|
||||
protected void testConditionalElimination(String snippet, String referenceSnippet, boolean applyConditionalEliminationOnReference, boolean applyLowering) {
|
||||
StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
|
||||
Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
|
||||
PhaseContext context = new PhaseContext(getProviders());
|
||||
@ -72,9 +70,7 @@ public class ConditionalEliminationTestBase extends GraalCompilerTest {
|
||||
}
|
||||
CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
|
||||
try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest", graph)) {
|
||||
canonicalizer1.apply(graph, context);
|
||||
new ConvertDeoptimizeToGuardPhase().apply(graph, context);
|
||||
// new DominatorConditionalEliminationPhase(true).apply(graph, context);
|
||||
prepareGraph(graph, canonicalizer1, context, applyLowering);
|
||||
new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
|
||||
canonicalizer.apply(graph, context);
|
||||
canonicalizer.apply(graph, context);
|
||||
@ -84,21 +80,29 @@ public class ConditionalEliminationTestBase extends GraalCompilerTest {
|
||||
}
|
||||
StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.YES);
|
||||
try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest.ReferenceGraph", referenceGraph)) {
|
||||
|
||||
new ConvertDeoptimizeToGuardPhase().apply(referenceGraph, context);
|
||||
prepareGraph(referenceGraph, canonicalizer, context, applyLowering);
|
||||
if (applyConditionalEliminationOnReference) {
|
||||
new DominatorConditionalEliminationPhase(true).apply(referenceGraph, context);
|
||||
canonicalizer.apply(referenceGraph, context);
|
||||
canonicalizer.apply(referenceGraph, context);
|
||||
} else {
|
||||
canonicalizer.apply(referenceGraph, context);
|
||||
DominatorConditionalEliminationPhase.create(true).apply(referenceGraph, context);
|
||||
}
|
||||
canonicalizer.apply(referenceGraph, context);
|
||||
canonicalizer.apply(referenceGraph, context);
|
||||
new ConvertDeoptimizeToGuardPhase().apply(graph, context);
|
||||
} catch (Throwable t) {
|
||||
Debug.handle(t);
|
||||
}
|
||||
assertEquals(referenceGraph, graph);
|
||||
}
|
||||
|
||||
protected void prepareGraph(StructuredGraph graph, CanonicalizerPhase canonicalizer, PhaseContext context, boolean applyLowering) {
|
||||
if (applyLowering) {
|
||||
new ConvertDeoptimizeToGuardPhase().apply(graph, context);
|
||||
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
|
||||
canonicalizer.apply(graph, context);
|
||||
}
|
||||
canonicalizer.apply(graph, context);
|
||||
new ConvertDeoptimizeToGuardPhase().apply(graph, context);
|
||||
}
|
||||
|
||||
public void testProxies(String snippet, int expectedProxiesCreated) {
|
||||
StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
|
||||
PhaseContext context = new PhaseContext(getProviders());
|
||||
@ -110,9 +114,9 @@ public class ConditionalEliminationTestBase extends GraalCompilerTest {
|
||||
canonicalizer.apply(graph, context);
|
||||
|
||||
int baseProxyCount = graph.getNodes().filter(ProxyNode.class).count();
|
||||
new DominatorConditionalEliminationPhase(true).apply(graph, context);
|
||||
DominatorConditionalEliminationPhase.create(true).apply(graph, context);
|
||||
canonicalizer.apply(graph, context);
|
||||
new SchedulePhase().apply(graph, context);
|
||||
new SchedulePhase(graph.getOptions()).apply(graph, context);
|
||||
int actualProxiesCreated = graph.getNodes().filter(ProxyNode.class).count() - baseProxyCount;
|
||||
Assert.assertEquals(expectedProxiesCreated, actualProxiesCreated);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user