001/*
002 * Copyright (c) 2010, 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 */
023package com.oracle.graal.asm.amd64;
024
025import jdk.internal.jvmci.code.*;
026
027/**
028 * Represents an address in target machine memory, specified via some combination of a base
029 * register, an index register, a displacement and a scale. Note that the base and index registers
030 * may be a variable that will get a register assigned later by the register allocator.
031 */
032public final class AMD64Address extends AbstractAddress {
033
034    private final Register base;
035    private final Register index;
036    private final Scale scale;
037    private final int displacement;
038
039    /**
040     * Creates an {@link AMD64Address} with given base register, no scaling and no displacement.
041     *
042     * @param base the base register
043     */
044    public AMD64Address(Register base) {
045        this(base, Register.None, Scale.Times1, 0);
046    }
047
048    /**
049     * Creates an {@link AMD64Address} with given base register, no scaling and a given
050     * displacement.
051     *
052     * @param base the base register
053     * @param displacement the displacement
054     */
055    public AMD64Address(Register base, int displacement) {
056        this(base, Register.None, Scale.Times1, displacement);
057    }
058
059    /**
060     * Creates an {@link AMD64Address} with given base and index registers, scaling and
061     * displacement. This is the most general constructor.
062     *
063     * @param base the base register
064     * @param index the index register
065     * @param scale the scaling factor
066     * @param displacement the displacement
067     */
068    public AMD64Address(Register base, Register index, Scale scale, int displacement) {
069        this.base = base;
070        this.index = index;
071        this.scale = scale;
072        this.displacement = displacement;
073
074        assert scale != null;
075    }
076
077    /**
078     * A scaling factor used in the SIB addressing mode.
079     */
080    public enum Scale {
081        Times1(1, 0),
082        Times2(2, 1),
083        Times4(4, 2),
084        Times8(8, 3);
085
086        private Scale(int value, int log2) {
087            this.value = value;
088            this.log2 = log2;
089        }
090
091        /**
092         * The value (or multiplier) of this scale.
093         */
094        public final int value;
095
096        /**
097         * The {@linkplain #value value} of this scale log 2.
098         */
099        public final int log2;
100
101        public static Scale fromInt(int scale) {
102            switch (scale) {
103                case 1:
104                    return Times1;
105                case 2:
106                    return Times2;
107                case 4:
108                    return Times4;
109                case 8:
110                    return Times8;
111                default:
112                    return null;
113            }
114        }
115
116        public static Scale fromShift(int shift) {
117            switch (shift) {
118                case 0:
119                    return Times1;
120                case 1:
121                    return Times2;
122                case 2:
123                    return Times4;
124                case 3:
125                    return Times8;
126                default:
127                    return null;
128            }
129        }
130    }
131
132    @Override
133    public String toString() {
134        StringBuilder s = new StringBuilder();
135        s.append("[");
136        String sep = "";
137        if (!getBase().equals(Register.None)) {
138            s.append(getBase());
139            sep = " + ";
140        }
141        if (!getIndex().equals(Register.None)) {
142            s.append(sep).append(getIndex()).append(" * ").append(getScale().value);
143            sep = " + ";
144        }
145        if (getDisplacement() < 0) {
146            s.append(" - ").append(-getDisplacement());
147        } else if (getDisplacement() > 0) {
148            s.append(sep).append(getDisplacement());
149        }
150        s.append("]");
151        return s.toString();
152    }
153
154    /**
155     * @return Base register that defines the start of the address computation. If not present, is
156     *         denoted by {@link Register#None}.
157     */
158    public Register getBase() {
159        return base;
160    }
161
162    /**
163     * @return Index register, the value of which (possibly scaled by {@link #getScale}) is added to
164     *         {@link #getBase}. If not present, is denoted by {@link Register#None}.
165     */
166    public Register getIndex() {
167        return index;
168    }
169
170    /**
171     * @return Scaling factor for indexing, dependent on target operand size.
172     */
173    public Scale getScale() {
174        return scale;
175    }
176
177    /**
178     * @return Optional additive displacement.
179     */
180    public int getDisplacement() {
181        return displacement;
182    }
183}