001/*
002 * Copyright (c) 2013, 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.lir.amd64;
024
025import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
026import static jdk.internal.jvmci.code.ValueUtil.*;
027
028import java.util.*;
029
030import jdk.internal.jvmci.code.*;
031import jdk.internal.jvmci.meta.*;
032
033import com.oracle.graal.asm.amd64.*;
034import com.oracle.graal.asm.amd64.AMD64Address.*;
035import com.oracle.graal.lir.*;
036import com.oracle.graal.lir.LIRInstruction.OperandFlag;
037import com.oracle.graal.lir.LIRInstruction.OperandMode;
038
039public final class AMD64AddressValue extends CompositeValue {
040
041    @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base;
042    @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index;
043    protected final Scale scale;
044    protected final int displacement;
045
046    private static final EnumSet<OperandFlag> flags = EnumSet.of(OperandFlag.REG, OperandFlag.ILLEGAL);
047
048    public AMD64AddressValue(LIRKind kind, AllocatableValue base, int displacement) {
049        this(kind, base, Value.ILLEGAL, Scale.Times1, displacement);
050    }
051
052    public AMD64AddressValue(LIRKind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) {
053        super(kind);
054        this.base = base;
055        this.index = index;
056        this.scale = scale;
057        this.displacement = displacement;
058
059        assert scale != null;
060    }
061
062    @Override
063    public CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
064        AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags);
065        AllocatableValue newIndex = (AllocatableValue) proc.doValue(inst, index, mode, flags);
066        if (!base.identityEquals(newBase) || !index.identityEquals(newIndex)) {
067            return new AMD64AddressValue(getLIRKind(), newBase, newIndex, scale, displacement);
068        }
069        return this;
070    }
071
072    @Override
073    protected void forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc) {
074        proc.visitValue(inst, base, mode, flags);
075        proc.visitValue(inst, index, mode, flags);
076    }
077
078    private static Register toRegister(AllocatableValue value) {
079        if (value.equals(Value.ILLEGAL)) {
080            return Register.None;
081        } else {
082            RegisterValue reg = (RegisterValue) value;
083            return reg.getRegister();
084        }
085    }
086
087    public AMD64Address toAddress() {
088        return new AMD64Address(toRegister(base), toRegister(index), scale, displacement);
089    }
090
091    @Override
092    public String toString() {
093        StringBuilder s = new StringBuilder("[");
094        String sep = "";
095        if (isLegal(base)) {
096            s.append(base);
097            sep = " + ";
098        }
099        if (isLegal(index)) {
100            s.append(sep).append(index).append(" * ").append(scale.value);
101            sep = " + ";
102        }
103        if (displacement < 0) {
104            s.append(" - ").append(-displacement);
105        } else if (displacement > 0) {
106            s.append(sep).append(displacement);
107        }
108        s.append("]");
109        return s.toString();
110    }
111
112    public boolean isValidImplicitNullCheckFor(Value value, int implicitNullCheckLimit) {
113        return value.equals(base) && index.equals(Value.ILLEGAL) && displacement >= 0 && displacement < implicitNullCheckLimit;
114    }
115
116    @Override
117    public boolean equals(Object obj) {
118        if (obj instanceof AMD64AddressValue) {
119            AMD64AddressValue addr = (AMD64AddressValue) obj;
120            return getLIRKind().equals(addr.getLIRKind()) && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index);
121        }
122        return false;
123    }
124
125    @Override
126    public int hashCode() {
127        return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ getLIRKind().hashCode();
128    }
129}