/*
* Copyright (c) 2018, 2019, 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.lir.hashing;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.Value;
This class provides a set of cheap imperfect hash functions based on the paper "Improving Switch
Statement Performance with Hashing Optimized at Compile Time".
(http://programming.sirrida.de/hashsuper.pdf)
/**
* This class provides a set of cheap imperfect hash functions based on the paper "Improving Switch
* Statement Performance with Hashing Optimized at Compile Time".
* (http://programming.sirrida.de/hashsuper.pdf)
*/
public abstract class HashFunction {
Applies the hash function.
Params: - value – the value to be hashed
- min –
value
is guaranteed to be greater or equal to this minimum
Returns: the hash value within int range
/**
* Applies the hash function.
*
* @param value the value to be hashed
* @param min {@code value} is guaranteed to be greater or equal to this minimum
* @return the hash value within int range
*/
public abstract int apply(int value, int min);
Generates LIR that implements the hash function in terms of value and min.
Params: - value – the value to be hashed
- min – the lowest key
- gen – the lir generator
Returns: new lir value with the hash function applied
/**
* Generates LIR that implements the hash function in terms of value and min.
*
* @param value the value to be hashed
* @param min the lowest key
* @param gen the lir generator
* @return new lir value with the hash function applied
*/
public abstract Value gen(Value value, Value min, ArithmeticLIRGenerator gen);
Returns an estimate of number of CPU cycles necessary to apply the hash function.
/**
* Returns an estimate of number of CPU cycles necessary to apply the hash function.
*/
public abstract int effort();
Returns: a list of all available hash functions
/**
* @return a list of all available hash functions
*/
public static final List<HashFunction> instances() {
return Collections.unmodifiableList(instances);
}
private static List<HashFunction> instances = new ArrayList<>();
private static int[] mersennePrimes = {3, 7, 31, 127, 8191, 131071, 524287, 2147483647};
static {
//@formatter:off
add("val", 0,
(val, min) -> val,
gen -> (val, min) -> val);
add("val - min", 1,
(val, min) -> val - min,
gen -> (val, min) -> gen.emitSub(val, min, false));
add("val >> min", 1,
(val, min) -> val >> min,
gen -> (val, min) -> gen.emitShr(val, min));
add("val >> (val & min)", 2,
(val, min) -> val >> (val & min),
gen -> (val, min) -> gen.emitShr(val, gen.emitAnd(val, min)));
add("(val >> min) ^ val", 2,
(val, min) -> (val >> min) ^ val,
gen -> (val, min) -> gen.emitXor(gen.emitShr(val, min), val));
add("(val >> min) * val", 3,
(val, min) -> (val >> min) * val,
gen -> (val, min) -> gen.emitMul(gen.emitShr(val, min), val, false));
addWithPrimes("(val * prime) >> min", 3,
prime -> (val, min) -> (val * prime) >> min,
(gen, prime) -> (val, min) -> gen.emitShr(gen.emitMul(val, prime, false), min));
addWithPrimes("rotateRight(val, prime)", 3,
prime -> (val, min) -> Integer.rotateRight(val, prime),
(gen, prime) -> (val, min) -> gen.emitRor(val, prime));
addWithPrimes("rotateRight(val, prime) + val", 4,
prime -> (val, min) -> Integer.rotateRight(val, prime) + val,
(gen, prime) -> (val, min) -> gen.emitAdd(gen.emitRor(val, prime), val, false));
addWithPrimes("rotateRight(val, prime) ^ val", 4,
prime -> (val, min) -> Integer.rotateRight(val, prime) ^ val,
(gen, prime) -> (val, min) -> gen.emitXor(gen.emitRor(val, prime), val));
//@formatter:on
}
private static void add(String toString, int effort, BiFunction<Integer, Integer, Integer> f, Function<ArithmeticLIRGenerator, BiFunction<Value, Value, Value>> gen) {
instances.add(new HashFunction() {
@Override
public int apply(int value, int min) {
return f.apply(value, min);
}
@Override
public int effort() {
return effort;
}
@Override
public String toString() {
return toString;
}
@Override
public Value gen(Value val, Value min, ArithmeticLIRGenerator t) {
return gen.apply(t).apply(t.emitNarrow(val, 32), t.emitNarrow(min, 32));
}
});
}
private static void addWithPrimes(String toString, int effort, Function<Integer, BiFunction<Integer, Integer, Integer>> f,
BiFunction<ArithmeticLIRGenerator, Value, BiFunction<Value, Value, Value>> gen) {
for (int p : mersennePrimes) {
add(toString, effort, f.apply(p), g -> gen.apply(g, g.getLIRGen().emitJavaConstant(JavaConstant.forInt(p))));
}
}
}