001/*
002 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023
024package com.oracle.graal.compiler.amd64;
025
026import jdk.internal.jvmci.code.*;
027import jdk.internal.jvmci.meta.*;
028
029import com.oracle.graal.asm.*;
030import com.oracle.graal.asm.amd64.AMD64Address.Scale;
031import com.oracle.graal.compiler.common.type.*;
032import com.oracle.graal.nodes.*;
033import com.oracle.graal.nodes.calc.*;
034import com.oracle.graal.nodes.memory.address.*;
035import com.oracle.graal.phases.common.AddressLoweringPhase.AddressLowering;
036
037public class AMD64AddressLowering extends AddressLowering {
038
039    private final CodeCacheProvider codeCache;
040
041    public AMD64AddressLowering(CodeCacheProvider codeCache) {
042        this.codeCache = codeCache;
043    }
044
045    @Override
046    public AddressNode lower(ValueNode address) {
047        return lower(address, null);
048    }
049
050    @Override
051    public AddressNode lower(ValueNode base, ValueNode offset) {
052        AMD64AddressNode ret = new AMD64AddressNode(base, offset);
053        boolean changed;
054        do {
055            changed = improve(ret);
056        } while (changed);
057        return base.graph().unique(ret);
058    }
059
060    protected boolean improve(AMD64AddressNode ret) {
061        ValueNode newBase = improveInput(ret, ret.getBase(), 0);
062        if (newBase != ret.getBase()) {
063            ret.setBase(newBase);
064            return true;
065        }
066
067        ValueNode newIdx = improveInput(ret, ret.getIndex(), ret.getScale().log2);
068        if (newIdx != ret.getIndex()) {
069            ret.setIndex(newIdx);
070            return true;
071        }
072
073        if (ret.getIndex() instanceof LeftShiftNode) {
074            LeftShiftNode shift = (LeftShiftNode) ret.getIndex();
075            if (shift.getY().isConstant()) {
076                int amount = ret.getScale().log2 + shift.getY().asJavaConstant().asInt();
077                Scale scale = Scale.fromShift(amount);
078                if (scale != null) {
079                    ret.setIndex(shift.getX());
080                    ret.setScale(scale);
081                    return true;
082                }
083            }
084        }
085
086        if (ret.getScale() == Scale.Times1) {
087            if (ret.getBase() == null || ret.getIndex() == null) {
088                if (ret.getBase() instanceof AddNode) {
089                    AddNode add = (AddNode) ret.getBase();
090                    ret.setBase(add.getX());
091                    ret.setIndex(add.getY());
092                    return true;
093                } else if (ret.getIndex() instanceof AddNode) {
094                    AddNode add = (AddNode) ret.getIndex();
095                    ret.setBase(add.getX());
096                    ret.setIndex(add.getY());
097                    return true;
098                }
099            }
100
101            if (ret.getBase() instanceof LeftShiftNode && !(ret.getIndex() instanceof LeftShiftNode)) {
102                ValueNode tmp = ret.getBase();
103                ret.setBase(ret.getIndex());
104                ret.setIndex(tmp);
105                return true;
106            }
107        }
108
109        return false;
110    }
111
112    private ValueNode improveInput(AMD64AddressNode address, ValueNode node, int shift) {
113        if (node == null) {
114            return null;
115        }
116
117        if (node.isConstant()) {
118            return improveConstDisp(address, node, node.asJavaConstant(), null, shift);
119        } else {
120            if (node.stamp() instanceof IntegerStamp && ((IntegerStamp) node.stamp()).getBits() == 64) {
121                if (node instanceof ZeroExtendNode) {
122                    if (((ZeroExtendNode) node).getInputBits() == 32) {
123                        /*
124                         * We can just swallow a zero-extend from 32 bit to 64 bit because the upper
125                         * half of the register will always be zero.
126                         */
127                        return ((ZeroExtendNode) node).getValue();
128                    }
129                } else if (node instanceof AddNode) {
130                    AddNode add = (AddNode) node;
131                    if (add.getX().isConstant()) {
132                        return improveConstDisp(address, node, add.getX().asJavaConstant(), add.getY(), shift);
133                    } else if (add.getY().isConstant()) {
134                        return improveConstDisp(address, node, add.getY().asJavaConstant(), add.getX(), shift);
135                    }
136                }
137            }
138        }
139
140        return node;
141    }
142
143    private ValueNode improveConstDisp(AMD64AddressNode address, ValueNode original, JavaConstant c, ValueNode other, int shift) {
144        if (c.getKind().isNumericInteger() && !codeCache.needsDataPatch(c)) {
145            long disp = address.getDisplacement();
146            disp += c.asLong() << shift;
147            if (NumUtil.isInt(disp)) {
148                address.setDisplacement((int) disp);
149                return other;
150            }
151        }
152        return original;
153    }
154}