blob: a43d03467b10162586d5d80fb8919d8282cb18f7 [file] [log] [blame]
/*
* Copyright (c) 2015, 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.amd64;
import jdk.vm.ci.meta.JavaConstant;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.AddNode;
import org.graalvm.compiler.nodes.calc.LeftShiftNode;
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
import org.graalvm.compiler.nodes.memory.address.AddressNode;
import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering;
public class AMD64AddressLowering extends AddressLowering {
@Override
public AddressNode lower(ValueNode address) {
return lower(address, null);
}
@Override
public AddressNode lower(ValueNode base, ValueNode offset) {
AMD64AddressNode ret = new AMD64AddressNode(base, offset);
boolean changed;
do {
changed = improve(ret);
} while (changed);
return base.graph().unique(ret);
}
protected boolean improve(AMD64AddressNode ret) {
ValueNode newBase = improveInput(ret, ret.getBase(), 0);
if (newBase != ret.getBase()) {
ret.setBase(newBase);
return true;
}
ValueNode newIdx = improveInput(ret, ret.getIndex(), ret.getScale().log2);
if (newIdx != ret.getIndex()) {
ret.setIndex(newIdx);
return true;
}
if (ret.getIndex() instanceof LeftShiftNode) {
LeftShiftNode shift = (LeftShiftNode) ret.getIndex();
if (shift.getY().isConstant()) {
int amount = ret.getScale().log2 + shift.getY().asJavaConstant().asInt();
Scale scale = Scale.fromShift(amount);
if (scale != null) {
ret.setIndex(shift.getX());
ret.setScale(scale);
return true;
}
}
}
if (ret.getScale() == Scale.Times1) {
if (ret.getBase() == null || ret.getIndex() == null) {
if (ret.getBase() instanceof AddNode) {
AddNode add = (AddNode) ret.getBase();
ret.setBase(add.getX());
ret.setIndex(add.getY());
return true;
} else if (ret.getIndex() instanceof AddNode) {
AddNode add = (AddNode) ret.getIndex();
ret.setBase(add.getX());
ret.setIndex(add.getY());
return true;
}
}
if (ret.getBase() instanceof LeftShiftNode && !(ret.getIndex() instanceof LeftShiftNode)) {
ValueNode tmp = ret.getBase();
ret.setBase(ret.getIndex());
ret.setIndex(tmp);
return true;
}
}
return false;
}
private static ValueNode improveInput(AMD64AddressNode address, ValueNode node, int shift) {
if (node == null) {
return null;
}
JavaConstant c = node.asJavaConstant();
if (c != null) {
return improveConstDisp(address, node, c, null, shift);
} else {
if (node.stamp() instanceof IntegerStamp && ((IntegerStamp) node.stamp()).getBits() == 64) {
if (node instanceof ZeroExtendNode) {
if (((ZeroExtendNode) node).getInputBits() == 32) {
/*
* We can just swallow a zero-extend from 32 bit to 64 bit because the upper
* half of the register will always be zero.
*/
return ((ZeroExtendNode) node).getValue();
}
} else if (node instanceof AddNode) {
AddNode add = (AddNode) node;
if (add.getX().isConstant()) {
return improveConstDisp(address, node, add.getX().asJavaConstant(), add.getY(), shift);
} else if (add.getY().isConstant()) {
return improveConstDisp(address, node, add.getY().asJavaConstant(), add.getX(), shift);
}
}
}
}
return node;
}
private static ValueNode improveConstDisp(AMD64AddressNode address, ValueNode original, JavaConstant c, ValueNode other, int shift) {
if (c.getJavaKind().isNumericInteger()) {
long disp = address.getDisplacement();
disp += c.asLong() << shift;
if (NumUtil.isInt(disp)) {
address.setDisplacement((int) disp);
return other;
}
}
return original;
}
}