changeset 23260:206bf428d745

Merge
author Christian Wimmer <christian.wimmer@oracle.com>
date Tue, 05 Jan 2016 16:42:05 -0800
parents 47e45579e9ce 61e5bc24179e
children 2ea1d1979187 c95a2eaf97e1
files graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctFilteredNodeIterable.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctPredicatedProxyNodeIterator.java
diffstat 271 files changed, 16550 insertions(+), 1923 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Tue Jan 05 16:32:42 2016 -0800
+++ b/.hgtags	Tue Jan 05 16:42:05 2016 -0800
@@ -620,3 +620,4 @@
 3c622007e098d8905d8e0947362a3894a629a5f1 graal-0.8
 3e8357b49024cb168ab5ebd511d8b5c03c068f75 graal-0.9
 795ada9208d8f35991b98bb934f624c70b8a0183 graal-0.10
+2643ba182e6f704aab7222d49f72456411e60c7b graal-0.11
--- a/CHANGELOG.md	Tue Jan 05 16:32:42 2016 -0800
+++ b/CHANGELOG.md	Tue Jan 05 16:42:05 2016 -0800
@@ -5,6 +5,16 @@
 ## `tip`
 ...
 
+## Version 0.11
+23-Dec-2015, [Repository Revision](http://hg.openjdk.java.net/graal/graal-compiler/shortlog/graal-0.11)
+* Moved support for command line options from JVMCI to Graal.
+* Made invocation plugin initialization lazy: plugins for a class are initialized first time compiler parses a method in the class.
+* Removed method handle special case logic for 8u60 and later.
+* Generate graph builder plugins for @NodeIntrinsic and @Fold methods instead of using reflection.
+* Converted LoadHubNode into normal FloatingNode from FloatingGuardedNode.
+* Enabled CRC32 intrinsics on SPARC.
+* Added log methods to Debug with 9 and 10 arguments.
+
 ## Version 0.10
 17-Nov-2015, [Repository Revision](http://hg.openjdk.java.net/graal/graal-compiler/shortlog/graal-0.10)
 * Added experimental Trace Register Allocator.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.aarch64.test/src/com/oracle/graal/asm/aarch64/test/AArch64MacroAssemblerTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2013, 2015, 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 com.oracle.graal.asm.aarch64.test;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.util.EnumSet;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan;
+import com.oracle.graal.test.GraalTest;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.aarch64.AArch64.CPUFeature;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+public class AArch64MacroAssemblerTest extends GraalTest {
+
+    private AArch64MacroAssembler masm;
+    private TestProtectedAssembler asm;
+    private Register base;
+    private Register index;
+    private Register scratch;
+
+    private static EnumSet<AArch64.CPUFeature> computeFeatures() {
+        EnumSet<AArch64.CPUFeature> features = EnumSet.noneOf(AArch64.CPUFeature.class);
+        features.add(CPUFeature.FP);
+        return features;
+    }
+
+    private static EnumSet<AArch64.Flag> computeFlags() {
+        EnumSet<AArch64.Flag> flags = EnumSet.noneOf(AArch64.Flag.class);
+        return flags;
+    }
+
+    private static TargetDescription createTarget() {
+        final int stackFrameAlignment = 16;
+        final int implicitNullCheckLimit = 4096;
+        final boolean inlineObjects = true;
+        Architecture arch = new AArch64(computeFeatures(), computeFlags());
+        return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
+    }
+
+    @Before
+    public void setupEnvironment() {
+        TargetDescription target = createTarget();
+        masm = new AArch64MacroAssembler(target);
+        asm = new TestProtectedAssembler(target);
+        base = AArch64.r10;
+        index = AArch64.r13;
+        scratch = AArch64.r15;
+    }
+
+    @Test
+    public void testGenerateAddressPlan() {
+        AddressGenerationPlan plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(8), false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch &&
+                        (plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED || plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED));
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(8), false, 1);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch &&
+                        (plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED || plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED));
+
+        plan = AArch64MacroAssembler.generateAddressPlan(-NumUtil.getNbitNumberInt(8) - 1, false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), false, 1);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12) << 2, false, 4);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(0, false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(0, false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(9), false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(13), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(-NumUtil.getNbitNumberInt(12), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(-(NumUtil.getNbitNumberInt(12) << 12), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), true, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12) << 3, true, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_INDEX && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(13) << 3, true, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_INDEX && plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+    }
+
+    @Test
+    public void testMakeAddressNoAction() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12) << 3, AArch64.zr, false, 8, null, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.IMMEDIATE_SCALED && address.getBase().equals(base) &&
+                        address.getOffset().equals(AArch64.zr) && address.getImmediateRaw() == NumUtil.getNbitNumberInt(12));
+        // No code generated.
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndex() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, false, 8, null, true);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(index));
+        asm.add(64, index, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndexNoOverwrite() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, false, 8, scratch, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(scratch));
+        asm.add(64, scratch, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddBaseNoOverwrite() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12), index, false, 8, scratch, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(scratch) && address.getOffset().equals(index));
+        asm.add(64, scratch, base, NumUtil.getNbitNumberInt(12));
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddBase() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12), index, false, 8, null, true);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(index));
+        asm.add(64, base, base, NumUtil.getNbitNumberInt(12));
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndexNoOverwriteExtend() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, true, 8, scratch, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET && address.getBase().equals(base) &&
+                        address.getOffset().equals(scratch) && address.getExtendType() == AArch64Assembler.ExtendType.SXTW);
+        asm.add(32, scratch, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndexExtend() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, true, 8, scratch, true);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET && address.getBase().equals(base) &&
+                        address.getOffset().equals(index) && address.getExtendType() == AArch64Assembler.ExtendType.SXTW);
+        asm.add(32, index, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressUnscaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createUnscaledImmediateAddress(base, NumUtil.getNbitNumberInt(8));
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, NumUtil.getNbitNumberInt(8));
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressUnscaled2() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createUnscaledImmediateAddress(base, -NumUtil.getNbitNumberInt(8));
+        masm.loadAddress(dst, address, 8);
+        asm.sub(64, dst, base, NumUtil.getNbitNumberInt(8));
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressScaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createScaledImmediateAddress(base, NumUtil.getNbitNumberInt(12));
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, NumUtil.getNbitNumberInt(9) << 3);
+        asm.add(64, dst, dst, NumUtil.getNbitNumberInt(3) << 12);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressScaledLowerOnly() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createScaledImmediateAddress(base, NumUtil.getNbitNumberInt(5));
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, NumUtil.getNbitNumberInt(5) << 3);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressScaledHigherOnly() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createScaledImmediateAddress(base, 1 << 11);
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, 1 << 11 << 3);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressRegisterOffsetUnscaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createRegisterOffsetAddress(base, index, false);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ShiftType.LSL, 0);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressRegisterOffsetScaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createRegisterOffsetAddress(base, index, true);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ShiftType.LSL, 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressExtendedRegisterOffsetUnscaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createExtendedRegisterOffsetAddress(base, index, false, AArch64Assembler.ExtendType.SXTW);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ExtendType.SXTW, 0);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressExtendedRegisterOffsetScaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createExtendedRegisterOffsetAddress(base, index, true, AArch64Assembler.ExtendType.SXTW);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ExtendType.SXTW, 2);
+        compareAssembly();
+    }
+
+    /**
+     * Compares assembly generated by the macro assembler to the hand-generated assembly.
+     */
+    private void compareAssembly() {
+        byte[] expected = asm.close(true);
+        byte[] actual = masm.close(true);
+        assertArrayEquals(expected, actual);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.aarch64.test/src/com/oracle/graal/asm/aarch64/test/TestProtectedAssembler.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2013, 2015, 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 com.oracle.graal.asm.aarch64.test;
+
+import com.oracle.graal.asm.AbstractAddress;
+import com.oracle.graal.asm.Label;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Cheat so that we can test protected functions of assembler.
+ */
+class TestProtectedAssembler extends AArch64Assembler {
+
+    public TestProtectedAssembler(TargetDescription target) {
+        super(target);
+    }
+
+    @Override
+    protected void cbnz(int size, Register reg, int imm21, int pos) {
+        super.cbnz(size, reg, imm21, pos);
+    }
+
+    @Override
+    protected void cbz(int size, Register reg, int imm21, int pos) {
+        super.cbz(size, reg, imm21, pos);
+    }
+
+    @Override
+    public void ands(int size, Register dst, Register src, long bimm) {
+        super.ands(size, dst, src, bimm);
+    }
+
+    @Override
+    protected void b(ConditionFlag condition, int imm21) {
+        super.b(condition, imm21);
+    }
+
+    @Override
+    protected void b(ConditionFlag condition, int imm21, int pos) {
+        super.b(condition, imm21, pos);
+    }
+
+    @Override
+    protected void cbnz(int size, Register reg, int imm21) {
+        super.cbnz(size, reg, imm21);
+    }
+
+    @Override
+    protected void cbz(int size, Register reg, int imm21) {
+        super.cbz(size, reg, imm21);
+    }
+
+    @Override
+    protected void b(int imm28) {
+        super.b(imm28);
+    }
+
+    @Override
+    protected void b(int imm28, int pos) {
+        super.b(imm28, pos);
+    }
+
+    @Override
+    public void bl(int imm28) {
+        super.bl(imm28);
+    }
+
+    @Override
+    public void blr(Register reg) {
+        super.blr(reg);
+    }
+
+    @Override
+    protected void br(Register reg) {
+        super.br(reg);
+    }
+
+    @Override
+    public void ret(Register reg) {
+        super.ret(reg);
+    }
+
+    @Override
+    public void ldr(int srcSize, Register rt, AArch64Address address) {
+        super.ldr(srcSize, rt, address);
+    }
+
+    @Override
+    public void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) {
+        super.ldrs(targetSize, srcSize, rt, address);
+    }
+
+    @Override
+    public void str(int destSize, Register rt, AArch64Address address) {
+        super.str(destSize, rt, address);
+    }
+
+    @Override
+    protected void ldxr(int size, Register rt, AArch64Address address) {
+        super.ldxr(size, rt, address);
+    }
+
+    @Override
+    protected void stxr(int size, Register rs, Register rt, AArch64Address address) {
+        super.stxr(size, rs, rt, address);
+    }
+
+    @Override
+    protected void ldar(int size, Register rt, AArch64Address address) {
+        super.ldar(size, rt, address);
+    }
+
+    @Override
+    protected void stlr(int size, Register rt, AArch64Address address) {
+        super.stlr(size, rt, address);
+    }
+
+    @Override
+    public void ldaxr(int size, Register rt, AArch64Address address) {
+        super.ldaxr(size, rt, address);
+    }
+
+    @Override
+    public void stlxr(int size, Register rs, Register rt, AArch64Address address) {
+        super.stlxr(size, rs, rt, address);
+    }
+
+    @Override
+    public void adr(Register dst, int imm21) {
+        super.adr(dst, imm21);
+    }
+
+    @Override
+    protected void add(int size, Register dst, Register src, int aimm) {
+        super.add(size, dst, src, aimm);
+    }
+
+    @Override
+    protected void adds(int size, Register dst, Register src, int aimm) {
+        super.adds(size, dst, src, aimm);
+    }
+
+    @Override
+    protected void sub(int size, Register dst, Register src, int aimm) {
+        super.sub(size, dst, src, aimm);
+    }
+
+    @Override
+    protected void subs(int size, Register dst, Register src, int aimm) {
+        super.subs(size, dst, src, aimm);
+    }
+
+    @Override
+    public void and(int size, Register dst, Register src, long bimm) {
+        super.and(size, dst, src, bimm);
+    }
+
+    @Override
+    public void eor(int size, Register dst, Register src, long bimm) {
+        super.eor(size, dst, src, bimm);
+    }
+
+    @Override
+    protected void orr(int size, Register dst, Register src, long bimm) {
+        super.orr(size, dst, src, bimm);
+    }
+
+    @Override
+    protected void movz(int size, Register dst, int uimm16, int shiftAmt) {
+        super.movz(size, dst, uimm16, shiftAmt);
+    }
+
+    @Override
+    protected void movn(int size, Register dst, int uimm16, int shiftAmt) {
+        super.movn(size, dst, uimm16, shiftAmt);
+    }
+
+    @Override
+    protected void movk(int size, Register dst, int uimm16, int pos) {
+        super.movk(size, dst, uimm16, pos);
+    }
+
+    @Override
+    protected void bfm(int size, Register dst, Register src, int r, int s) {
+        super.bfm(size, dst, src, r, s);
+    }
+
+    @Override
+    protected void ubfm(int size, Register dst, Register src, int r, int s) {
+        super.ubfm(size, dst, src, r, s);
+    }
+
+    @Override
+    protected void sbfm(int size, Register dst, Register src, int r, int s) {
+        super.sbfm(size, dst, src, r, s);
+    }
+
+    @Override
+    protected void extr(int size, Register dst, Register src1, Register src2, int lsb) {
+        super.extr(size, dst, src1, src2, lsb);
+    }
+
+    @Override
+    protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.adds(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.subs(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.add(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.sub(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.add(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.adds(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.sub(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.subs(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.and(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.ands(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.bic(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.bics(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.eon(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.eor(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.orr(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.orn(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void asr(int size, Register dst, Register src1, Register src2) {
+        super.asr(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void lsl(int size, Register dst, Register src1, Register src2) {
+        super.lsl(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void lsr(int size, Register dst, Register src1, Register src2) {
+        super.lsr(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void ror(int size, Register dst, Register src1, Register src2) {
+        super.ror(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void cls(int size, Register dst, Register src) {
+        super.cls(size, dst, src);
+    }
+
+    @Override
+    public void clz(int size, Register dst, Register src) {
+        super.clz(size, dst, src);
+    }
+
+    @Override
+    protected void rbit(int size, Register dst, Register src) {
+        super.rbit(size, dst, src);
+    }
+
+    @Override
+    public void rev(int size, Register dst, Register src) {
+        super.rev(size, dst, src);
+    }
+
+    @Override
+    protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.csel(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.csneg(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.csinc(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void madd(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.madd(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    protected void msub(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.msub(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    public void sdiv(int size, Register dst, Register src1, Register src2) {
+        super.sdiv(size, dst, src1, src2);
+    }
+
+    @Override
+    public void udiv(int size, Register dst, Register src1, Register src2) {
+        super.udiv(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fldr(int size, Register rt, AArch64Address address) {
+        super.fldr(size, rt, address);
+    }
+
+    @Override
+    public void fstr(int size, Register rt, AArch64Address address) {
+        super.fstr(size, rt, address);
+    }
+
+    @Override
+    protected void fmov(int size, Register dst, Register src) {
+        super.fmov(size, dst, src);
+    }
+
+    @Override
+    protected void fmovFpu2Cpu(int size, Register dst, Register src) {
+        super.fmovFpu2Cpu(size, dst, src);
+    }
+
+    @Override
+    protected void fmovCpu2Fpu(int size, Register dst, Register src) {
+        super.fmovCpu2Fpu(size, dst, src);
+    }
+
+    @Override
+    protected void fmov(int size, Register dst, double imm) {
+        super.fmov(size, dst, imm);
+    }
+
+    @Override
+    public void fcvt(int srcSize, Register dst, Register src) {
+        super.fcvt(srcSize, dst, src);
+    }
+
+    @Override
+    public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) {
+        super.fcvtzs(targetSize, srcSize, dst, src);
+    }
+
+    @Override
+    public void scvtf(int targetSize, int srcSize, Register dst, Register src) {
+        super.scvtf(targetSize, srcSize, dst, src);
+    }
+
+    @Override
+    protected void frintz(int size, Register dst, Register src) {
+        super.frintz(size, dst, src);
+    }
+
+    @Override
+    public void fabs(int size, Register dst, Register src) {
+        super.fabs(size, dst, src);
+    }
+
+    @Override
+    public void fneg(int size, Register dst, Register src) {
+        super.fneg(size, dst, src);
+    }
+
+    @Override
+    public void fsqrt(int size, Register dst, Register src) {
+        super.fsqrt(size, dst, src);
+    }
+
+    @Override
+    public void fadd(int size, Register dst, Register src1, Register src2) {
+        super.fadd(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fsub(int size, Register dst, Register src1, Register src2) {
+        super.fsub(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fmul(int size, Register dst, Register src1, Register src2) {
+        super.fmul(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fdiv(int size, Register dst, Register src1, Register src2) {
+        super.fdiv(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.fmadd(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.fmsub(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    public void fcmp(int size, Register src1, Register src2) {
+        super.fcmp(size, src1, src2);
+    }
+
+    @Override
+    public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) {
+        super.fccmp(size, src1, src2, uimm4, condition);
+    }
+
+    @Override
+    public void fcmpZero(int size, Register src) {
+        super.fcmpZero(size, src);
+    }
+
+    @Override
+    protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.fcsel(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void hlt(int uimm16) {
+        super.hlt(uimm16);
+    }
+
+    @Override
+    protected void brk(int uimm16) {
+        super.brk(uimm16);
+    }
+
+    @Override
+    protected void hint(SystemHint hint) {
+        super.hint(hint);
+    }
+
+    @Override
+    protected void clrex() {
+        super.clrex();
+    }
+
+    @Override
+    public void dmb(BarrierKind barrierKind) {
+        super.dmb(barrierKind);
+    }
+
+    @Override
+    public void align(int modulus) {
+    }
+
+    @Override
+    public void jmp(Label l) {
+    }
+
+    @Override
+    protected void patchJumpTarget(int branch, int jumpTarget) {
+
+    }
+
+    @Override
+    public AbstractAddress makeAddress(Register base, int displacement) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AbstractAddress getPlaceholder() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void ensureUniquePC() {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.aarch64/src/com/oracle/graal/asm/aarch64/AArch64Address.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2013, 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 com.oracle.graal.asm.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.zr;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Register;
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.AbstractAddress;
+
+import jdk.vm.ci.common.JVMCIError;
+
+/**
+ * Represents an address in target machine memory, specified using one of the different addressing
+ * modes of the AArch64 ISA. - Base register only - Base register + immediate or register with
+ * shifted offset - Pre-indexed: base + immediate offset are written back to base register, value
+ * used in instruction is base + offset - Post-indexed: base + offset (immediate or register) are
+ * written back to base register, value used in instruction is base only - Literal: PC + 19-bit
+ * signed word aligned offset
+ * <p>
+ * Not all addressing modes are supported for all instructions.
+ */
+public final class AArch64Address extends AbstractAddress {
+    // Placeholder for addresses that get patched later.
+    public static final AArch64Address PLACEHOLDER = createPcLiteralAddress(0);
+
+    public enum AddressingMode {
+        /**
+         * base + uimm12 << log2(memory_transfer_size).
+         */
+        IMMEDIATE_SCALED,
+        /**
+         * base + imm9.
+         */
+        IMMEDIATE_UNSCALED,
+        /**
+         * base.
+         */
+        BASE_REGISTER_ONLY,
+        /**
+         * base + offset [<< log2(memory_transfer_size)].
+         */
+        REGISTER_OFFSET,
+        /**
+         * base + extend(offset) [<< log2(memory_transfer_size)].
+         */
+        EXTENDED_REGISTER_OFFSET,
+        /**
+         * PC + imm21 (word aligned).
+         */
+        PC_LITERAL,
+        /**
+         * address = base. base is updated to base + imm9
+         */
+        IMMEDIATE_POST_INDEXED,
+        /**
+         * address = base + imm9. base is updated to base + imm9
+         */
+        IMMEDIATE_PRE_INDEXED,
+        AddressingMode,
+    }
+
+    private final Register base;
+    private final Register offset;
+    private final int immediate;
+    /**
+     * Should register offset be scaled or not.
+     */
+    private final boolean scaled;
+    private final AArch64Assembler.ExtendType extendType;
+    private final AddressingMode addressingMode;
+
+    /**
+     * General address generation mechanism. Accepted values for all parameters depend on the
+     * addressingMode. Null is never accepted for a register, if an addressMode doesn't use a
+     * register the register has to be the zero-register. extendType has to be null for every
+     * addressingMode except EXTENDED_REGISTER_OFFSET.
+     */
+    public static AArch64Address createAddress(AddressingMode addressingMode, Register base, Register offset, int immediate, boolean isScaled, AArch64Assembler.ExtendType extendType) {
+        return new AArch64Address(base, offset, immediate, isScaled, extendType, addressingMode);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm9 Signed 9 bit immediate value.
+     * @return AArch64Address specifying a post-indexed immediate address pointing to base. After
+     *         ldr/str instruction, base is updated to point to base + imm9
+     */
+    public static AArch64Address createPostIndexedImmediateAddress(Register base, int imm9) {
+        return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_POST_INDEXED);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm9 Signed 9 bit immediate value.
+     * @return AArch64Address specifying a pre-indexed immediate address pointing to base + imm9.
+     *         After ldr/str instruction, base is updated to point to base + imm9
+     */
+    public static AArch64Address createPreIndexedImmediateAddress(Register base, int imm9) {
+        return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_PRE_INDEXED);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm12 Unsigned 12 bit immediate value. This is scaled by the word access size. This
+     *            means if this address is used to load/store a word, the immediate is shifted by 2
+     *            (log2Ceil(4)).
+     * @return AArch64Address specifying a signed address of the form base + imm12 <<
+     *         log2(memory_transfer_size).
+     */
+    public static AArch64Address createScaledImmediateAddress(Register base, int imm12) {
+        return new AArch64Address(base, zr, imm12, true, null, AddressingMode.IMMEDIATE_SCALED);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm9 Signed 9 bit immediate value.
+     * @return AArch64Address specifying an unscaled immediate address of the form base + imm9
+     */
+    public static AArch64Address createUnscaledImmediateAddress(Register base, int imm9) {
+        return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_UNSCALED);
+    }
+
+    /**
+     * @param base May not be null or the zero register.
+     * @return AArch64Address specifying the address pointed to by base.
+     */
+    public static AArch64Address createBaseRegisterOnlyAddress(Register base) {
+        return createRegisterOffsetAddress(base, zr, false);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param offset Register specifying some offset, optionally scaled by the memory_transfer_size.
+     *            May not be null or the stackpointer.
+     * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not.
+     * @return AArch64Address specifying a register offset address of the form base + offset [<<
+     *         log2 (memory_transfer_size)]
+     */
+    public static AArch64Address createRegisterOffsetAddress(Register base, Register offset, boolean scaled) {
+        return new AArch64Address(base, offset, 0, scaled, null, AddressingMode.REGISTER_OFFSET);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param offset Word register specifying some offset, optionally scaled by the
+     *            memory_transfer_size. May not be null or the stackpointer.
+     * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not.
+     * @param extendType Describes whether register is zero- or sign-extended. May not be null.
+     * @return AArch64Address specifying an extended register offset of the form base +
+     *         extendType(offset) [<< log2(memory_transfer_size)]
+     */
+    public static AArch64Address createExtendedRegisterOffsetAddress(Register base, Register offset, boolean scaled, AArch64Assembler.ExtendType extendType) {
+        return new AArch64Address(base, offset, 0, scaled, extendType, AddressingMode.EXTENDED_REGISTER_OFFSET);
+    }
+
+    /**
+     * @param imm21 Signed 21-bit offset, word aligned.
+     * @return AArch64Address specifying a PC-literal address of the form PC + offset
+     */
+    public static AArch64Address createPcLiteralAddress(int imm21) {
+        return new AArch64Address(zr, zr, imm21, false, null, AddressingMode.PC_LITERAL);
+    }
+
+    private AArch64Address(Register base, Register offset, int immediate, boolean scaled, AArch64Assembler.ExtendType extendType, AddressingMode addressingMode) {
+        this.base = base;
+        this.offset = offset;
+        if ((addressingMode == AddressingMode.REGISTER_OFFSET || addressingMode == AddressingMode.EXTENDED_REGISTER_OFFSET) && offset.equals(zr)) {
+            this.addressingMode = AddressingMode.BASE_REGISTER_ONLY;
+        } else {
+            this.addressingMode = addressingMode;
+        }
+        this.immediate = immediate;
+        this.scaled = scaled;
+        this.extendType = extendType;
+        assert verify();
+    }
+
+    private boolean verify() {
+        assert addressingMode != null;
+        assert base.getRegisterCategory().equals(AArch64.CPU) && offset.getRegisterCategory().equals(AArch64.CPU);
+
+        switch (addressingMode) {
+            case IMMEDIATE_SCALED:
+                return !base.equals(zr) && offset.equals(zr) && extendType == null && NumUtil.isUnsignedNbit(12, immediate);
+            case IMMEDIATE_UNSCALED:
+                return !base.equals(zr) && offset.equals(zr) && extendType == null && NumUtil.isSignedNbit(9, immediate);
+            case BASE_REGISTER_ONLY:
+                return !base.equals(zr) && offset.equals(zr) && extendType == null && immediate == 0;
+            case REGISTER_OFFSET:
+                return !base.equals(zr) && offset.getRegisterCategory().equals(AArch64.CPU) && extendType == null && immediate == 0;
+            case EXTENDED_REGISTER_OFFSET:
+                return !base.equals(zr) && offset.getRegisterCategory().equals(AArch64.CPU) && (extendType == AArch64Assembler.ExtendType.SXTW || extendType == AArch64Assembler.ExtendType.UXTW) &&
+                                immediate == 0;
+            case PC_LITERAL:
+                return base.equals(zr) && offset.equals(zr) && extendType == null && NumUtil.isSignedNbit(21, immediate) && ((immediate & 0x3) == 0);
+            case IMMEDIATE_POST_INDEXED:
+            case IMMEDIATE_PRE_INDEXED:
+                return !base.equals(zr) && offset.equals(zr) && extendType == null && NumUtil.isSignedNbit(9, immediate);
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    public Register getBase() {
+        return base;
+    }
+
+    public Register getOffset() {
+        return offset;
+    }
+
+    /**
+     * @return immediate in correct representation for the given addressing mode. For example in
+     *         case of <code>addressingMode ==IMMEDIATE_UNSCALED </code> the value will be returned
+     *         as the 9bit signed representation.
+     */
+    public int getImmediate() {
+        switch (addressingMode) {
+            case IMMEDIATE_UNSCALED:
+            case IMMEDIATE_POST_INDEXED:
+            case IMMEDIATE_PRE_INDEXED:
+                // 9-bit signed value
+                return immediate & NumUtil.getNbitNumberInt(9);
+            case IMMEDIATE_SCALED:
+                // Unsigned value can be returned as-is.
+                return immediate;
+            case PC_LITERAL:
+                // 21-bit signed value, but lower 2 bits are always 0 and are shifted out.
+                return (immediate >> 2) & NumUtil.getNbitNumberInt(19);
+            default:
+                throw JVMCIError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
+        }
+    }
+
+    /**
+     * @return Raw immediate as a 32-bit signed value.
+     */
+    public int getImmediateRaw() {
+        switch (addressingMode) {
+            case IMMEDIATE_UNSCALED:
+            case IMMEDIATE_SCALED:
+            case IMMEDIATE_POST_INDEXED:
+            case IMMEDIATE_PRE_INDEXED:
+            case PC_LITERAL:
+                return immediate;
+            default:
+                throw JVMCIError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
+        }
+    }
+
+    public boolean isScaled() {
+        return scaled;
+    }
+
+    public AArch64Assembler.ExtendType getExtendType() {
+        return extendType;
+    }
+
+    public AddressingMode getAddressingMode() {
+        return addressingMode;
+    }
+
+    public String toString(int log2TransferSize) {
+        int shiftVal = scaled ? log2TransferSize : 0;
+        switch (addressingMode) {
+            case IMMEDIATE_SCALED:
+                return String.format("[X%d, %d]", base.encoding, immediate << log2TransferSize);
+            case IMMEDIATE_UNSCALED:
+                return String.format("[X%d, %d]", base.encoding, immediate);
+            case BASE_REGISTER_ONLY:
+                return String.format("[X%d]", base.encoding);
+            case EXTENDED_REGISTER_OFFSET:
+                if (shiftVal != 0) {
+                    return String.format("[X%d, W%d, %s %d]", base.encoding, offset.encoding, extendType.name(), shiftVal);
+                } else {
+                    return String.format("[X%d, W%d, %s]", base.encoding, offset.encoding, extendType.name());
+                }
+            case REGISTER_OFFSET:
+                if (shiftVal != 0) {
+                    return String.format("[X%d, X%d, LSL %d]", base.encoding, offset.encoding, shiftVal);
+                } else {
+                    // LSL 0 may be optional, but still encoded differently so we always leave it
+                    // off
+                    return String.format("[X%d, X%d]", base.encoding, offset.encoding);
+                }
+            case PC_LITERAL:
+                return String.format(".%s%d", immediate >= 0 ? "+" : "", immediate);
+            case IMMEDIATE_POST_INDEXED:
+                return String.format("[X%d],%d", base.encoding, immediate);
+            case IMMEDIATE_PRE_INDEXED:
+                return String.format("[X%d,%d]!", base.encoding, immediate);
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.aarch64/src/com/oracle/graal/asm/aarch64/AArch64Assembler.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,2490 @@
+/*
+ * Copyright (c) 2013, 2015, 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 com.oracle.graal.asm.aarch64;
+
+import static com.oracle.graal.asm.aarch64.AArch64Assembler.InstructionType.floatFromSize;
+import static com.oracle.graal.asm.aarch64.AArch64Assembler.InstructionType.generalFromSize;
+import static jdk.vm.ci.aarch64.AArch64.CPU;
+import static jdk.vm.ci.aarch64.AArch64.SIMD;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+
+import java.util.Arrays;
+
+import com.oracle.graal.asm.Assembler;
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.JavaKind;
+
+public abstract class AArch64Assembler extends Assembler {
+
+    public static class LogicalImmediateTable {
+
+        private static final Immediate[] IMMEDIATE_TABLE = buildImmediateTable();
+
+        private static final int ImmediateOffset = 10;
+        private static final int ImmediateRotateOffset = 16;
+        private static final int ImmediateSizeOffset = 22;
+
+        /**
+         * Specifies whether immediate can be represented in all cases (YES), as a 64bit instruction
+         * (SIXTY_FOUR_BIT_ONLY) or not at all (NO).
+         */
+        static enum Representable {
+            YES,
+            SIXTY_FOUR_BIT_ONLY,
+            NO
+        }
+
+        /**
+         * Tests whether an immediate can be encoded for logical instructions.
+         *
+         * @param is64bit if true immediate is considered a 64-bit pattern. If false we may use a
+         *            64-bit instruction to load the 32-bit pattern into a register.
+         * @return enum specifying whether immediate can be used for 32- and 64-bit logical
+         *         instructions ({@code #Representable.YES}), for 64-bit instructions only (
+         *         {@code #Representable.SIXTY_FOUR_BIT_ONLY}) or not at all (
+         *         {@code #Representable.NO} ).
+         */
+        public static Representable isRepresentable(boolean is64bit, long immediate) {
+            int pos = getLogicalImmTablePos(is64bit, immediate);
+            if (pos < 0) {
+                // if 32bit instruction we can try again as 64bit immediate which may succeed.
+                // i.e. 0xffffffff fails as a 32bit immediate but works as 64bit one.
+                if (!is64bit) {
+                    assert NumUtil.isUnsignedNbit(32, immediate);
+                    pos = getLogicalImmTablePos(true, immediate);
+                    return pos >= 0 ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.NO;
+                }
+                return Representable.NO;
+            }
+            Immediate imm = IMMEDIATE_TABLE[pos];
+            return imm.only64bit() ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.YES;
+        }
+
+        public static Representable isRepresentable(int immediate) {
+            return isRepresentable(false, immediate & 0xFFFF_FFFFL);
+        }
+
+        public static int getLogicalImmEncoding(boolean is64bit, long value) {
+            int pos = getLogicalImmTablePos(is64bit, value);
+            assert pos >= 0 : "Value cannot be represented as logical immediate";
+            Immediate imm = IMMEDIATE_TABLE[pos];
+            assert is64bit || !imm.only64bit() : "Immediate can only be represented for 64bit, but 32bit instruction specified";
+            return IMMEDIATE_TABLE[pos].encoding;
+        }
+
+        /**
+         * @param is64bit if true also allow 64-bit only encodings to be returned.
+         * @return If positive the return value is the position into the IMMEDIATE_TABLE for the
+         *         given immediate, if negative the immediate cannot be encoded.
+         */
+        private static int getLogicalImmTablePos(boolean is64bit, long value) {
+            Immediate imm;
+            if (!is64bit) {
+                // 32bit instructions can only have 32bit immediates.
+                if (!NumUtil.isUnsignedNbit(32, value)) {
+                    return -1;
+                }
+                // If we have a 32bit instruction (and therefore immediate) we have to duplicate it
+                // across 64bit to find it in the table.
+                imm = new Immediate(value << 32 | value);
+            } else {
+                imm = new Immediate(value);
+            }
+            int pos = Arrays.binarySearch(IMMEDIATE_TABLE, imm);
+            if (pos < 0) {
+                return -1;
+            }
+            if (!is64bit && IMMEDIATE_TABLE[pos].only64bit()) {
+                return -1;
+            }
+            return pos;
+        }
+
+        /**
+         * To quote 5.4.2: [..] an immediate is a 32 or 64 bit pattern viewed as a vector of
+         * identical elements of size e = 2, 4, 8, 16, 32 or (in the case of bimm64) 64 bits. Each
+         * element contains the same sub-pattern: a single run of 1 to e-1 non-zero bits, rotated by
+         * 0 to e-1 bits. It is encoded in the following: 10-16: rotation amount (6bit) starting
+         * from 1s in the LSB (i.e. 0111->1011->1101->1110) 16-22: This stores a combination of the
+         * number of set bits and the pattern size. The pattern size is encoded as follows (x is
+         * used to store the number of 1 bits - 1) e pattern 2 1111xx 4 1110xx 8 110xxx 16 10xxxx 32
+         * 0xxxxx 64 xxxxxx 22: if set we have an instruction with 64bit pattern?
+         */
+        private static final class Immediate implements Comparable<Immediate> {
+            public final long imm;
+            public final int encoding;
+
+            public Immediate(long imm, boolean is64, int s, int r) {
+                this.imm = imm;
+                this.encoding = computeEncoding(is64, s, r);
+            }
+
+            // Used to be able to binary search for an immediate in the table.
+            public Immediate(long imm) {
+                this(imm, false, 0, 0);
+            }
+
+            /**
+             * Returns true if this pattern is only representable as 64bit.
+             */
+            public boolean only64bit() {
+                return (encoding & (1 << ImmediateSizeOffset)) != 0;
+            }
+
+            private static int computeEncoding(boolean is64, int s, int r) {
+                int sf = is64 ? 1 : 0;
+                return sf << ImmediateSizeOffset | r << ImmediateRotateOffset | s << ImmediateOffset;
+            }
+
+            @Override
+            public int compareTo(Immediate o) {
+                return Long.compare(imm, o.imm);
+            }
+        }
+
+        private static Immediate[] buildImmediateTable() {
+            final int nrImmediates = 5334;
+            final Immediate[] table = new Immediate[nrImmediates];
+            int nrImms = 0;
+            for (int logE = 1; logE <= 6; logE++) {
+                int e = 1 << logE;
+                long mask = NumUtil.getNbitNumberLong(e);
+                for (int nrOnes = 1; nrOnes < e; nrOnes++) {
+                    long val = (1L << nrOnes) - 1;
+                    // r specifies how much we rotate the value
+                    for (int r = 0; r < e; r++) {
+                        long immediate = (val >>> r | val << (e - r)) & mask;
+                        // Duplicate pattern to fill whole 64bit range.
+                        switch (logE) {
+                            case 1:
+                                immediate |= immediate << 2;
+                                immediate |= immediate << 4;
+                                immediate |= immediate << 8;
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 2:
+                                immediate |= immediate << 4;
+                                immediate |= immediate << 8;
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 3:
+                                immediate |= immediate << 8;
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 4:
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 5:
+                                immediate |= immediate << 32;
+                                break;
+                        }
+                        // 5 - logE can underflow to -1, but we shift this bogus result
+                        // out of the masked area.
+                        int sizeEncoding = (1 << (5 - logE)) - 1;
+                        int s = ((sizeEncoding << (logE + 1)) & 0x3f) | (nrOnes - 1);
+                        table[nrImms++] = new Immediate(immediate, /* is64bit */e == 64, s, r);
+                    }
+                }
+            }
+            Arrays.sort(table);
+            assert nrImms == nrImmediates : nrImms + " instead of " + nrImmediates + " in table.";
+            assert checkDuplicates(table) : "Duplicate values in table.";
+            return table;
+        }
+
+        private static boolean checkDuplicates(Immediate[] table) {
+            for (int i = 0; i < table.length - 1; i++) {
+                if (table[i].imm >= table[i + 1].imm) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    private static final int RdOffset = 0;
+    private static final int Rs1Offset = 5;
+    private static final int Rs2Offset = 16;
+    private static final int Rs3Offset = 10;
+    private static final int RtOffset = 0;
+
+    /**
+     * Enumeration of all different instruction kinds: General32/64 are the general instructions
+     * (integer, branch, etc.), for 32-, respectively 64-bit operands. FP32/64 is the encoding for
+     * the 32/64bit float operations
+     */
+    protected enum InstructionType {
+        General32(0x00000000, 32, true),
+        General64(0x80000000, 64, true),
+        FP32(0x00000000, 32, false),
+        FP64(0x00400000, 64, false);
+
+        public final int encoding;
+        public final int width;
+        public final boolean isGeneral;
+
+        private InstructionType(int encoding, int width, boolean isGeneral) {
+            this.encoding = encoding;
+            this.width = width;
+            this.isGeneral = isGeneral;
+        }
+
+        public static InstructionType generalFromSize(int size) {
+            assert size == 32 || size == 64;
+            return size == 32 ? General32 : General64;
+        }
+
+        public static InstructionType floatFromSize(int size) {
+            assert size == 32 || size == 64;
+            return size == 32 ? FP32 : FP64;
+        }
+
+    }
+
+    private static final int ImmediateOffset = 10;
+    private static final int ImmediateRotateOffset = 16;
+    private static final int ImmediateSizeOffset = 22;
+    private static final int ExtendTypeOffset = 13;
+
+    private static final int AddSubImmOp = 0x11000000;
+    // If 1 the immediate is interpreted as being left-shifted by 12 bits.
+    private static final int AddSubShiftOffset = 22;
+    private static final int AddSubSetFlag = 0x20000000;
+
+    private static final int LogicalImmOp = 0x12000000;
+
+    private static final int MoveWideImmOp = 0x12800000;
+    private static final int MoveWideImmOffset = 5;
+    private static final int MoveWideShiftOffset = 21;
+
+    private static final int BitfieldImmOp = 0x13000000;
+
+    private static final int AddSubShiftedOp = 0x0B000000;
+    private static final int ShiftTypeOffset = 22;
+
+    private static final int AddSubExtendedOp = 0x0B200000;
+
+    private static final int MulOp = 0x1B000000;
+    private static final int DataProcessing1SourceOp = 0x5AC00000;
+    private static final int DataProcessing2SourceOp = 0x1AC00000;
+
+    private static final int Fp1SourceOp = 0x1E204000;
+    private static final int Fp2SourceOp = 0x1E200800;
+    private static final int Fp3SourceOp = 0x1F000000;
+
+    private static final int FpConvertOp = 0x1E200000;
+    private static final int FpImmOp = 0x1E201000;
+    private static final int FpImmOffset = 13;
+
+    private static final int FpCmpOp = 0x1E202000;
+
+    private static final int PcRelImmHiOffset = 5;
+    private static final int PcRelImmLoOffset = 29;
+
+    private static final int PcRelImmOp = 0x10000000;
+
+    private static final int UnconditionalBranchImmOp = 0x14000000;
+    private static final int UnconditionalBranchRegOp = 0xD6000000;
+    private static final int CompareBranchOp = 0x34000000;
+
+    private static final int ConditionalBranchImmOffset = 5;
+
+    private static final int ConditionalSelectOp = 0x1A800000;
+    private static final int ConditionalConditionOffset = 12;
+
+    private static final int LoadStoreScaledOp = 0x39000000;
+    private static final int LoadStoreUnscaledOp = 0x38000000;
+    private static final int LoadStoreRegisterOp = 0x38200800;
+    private static final int LoadLiteralOp = 0x18000000;
+    private static final int LoadStorePostIndexedOp = 0x38000400;
+    private static final int LoadStorePreIndexedOp = 0x38000C00;
+
+    private static final int LoadStoreUnscaledImmOffset = 12;
+    private static final int LoadStoreScaledImmOffset = 10;
+    private static final int LoadStoreScaledRegOffset = 12;
+    private static final int LoadStoreIndexedImmOffset = 12;
+    private static final int LoadStoreTransferSizeOffset = 30;
+    private static final int LoadStoreFpFlagOffset = 26;
+    private static final int LoadLiteralImmeOffset = 5;
+
+    private static final int LogicalShiftOp = 0x0A000000;
+
+    private static final int ExceptionOp = 0xD4000000;
+    private static final int SystemImmediateOffset = 5;
+
+    @SuppressWarnings("unused") private static final int SimdImmediateOffset = 16;
+
+    private static final int BarrierOp = 0xD503301F;
+    private static final int BarrierKindOffset = 8;
+
+    /**
+     * Encoding for all instructions.
+     */
+    private enum Instruction {
+        BCOND(0x54000000),
+        CBNZ(0x01000000),
+        CBZ(0x00000000),
+
+        B(0x00000000),
+        BL(0x80000000),
+        BR(0x001F0000),
+        BLR(0x003F0000),
+        RET(0x005F0000),
+
+        LDR(0x00000000),
+        LDRS(0x00800000),
+        LDXR(0x081f7c00),
+        LDAR(0x8dffc00),
+        LDAXR(0x85ffc00),
+
+        STR(0x00000000),
+        STXR(0x08007c00),
+        STLR(0x089ffc00),
+        STLXR(0x0800fc00),
+
+        ADR(0x00000000),
+        ADRP(0x80000000),
+
+        ADD(0x00000000),
+        ADDS(ADD.encoding | AddSubSetFlag),
+        SUB(0x40000000),
+        SUBS(SUB.encoding | AddSubSetFlag),
+
+        NOT(0x00200000),
+        AND(0x00000000),
+        BIC(AND.encoding | NOT.encoding),
+        ORR(0x20000000),
+        ORN(ORR.encoding | NOT.encoding),
+        EOR(0x40000000),
+        EON(EOR.encoding | NOT.encoding),
+        ANDS(0x60000000),
+        BICS(ANDS.encoding | NOT.encoding),
+
+        ASRV(0x00002800),
+        RORV(0x00002C00),
+        LSRV(0x00002400),
+        LSLV(0x00002000),
+
+        CLS(0x00001400),
+        CLZ(0x00001000),
+        RBIT(0x00000000),
+        REVX(0x00000C00),
+        REVW(0x00000800),
+
+        MOVN(0x00000000),
+        MOVZ(0x40000000),
+        MOVK(0x60000000),
+
+        CSEL(0x00000000),
+        CSNEG(0x40000400),
+        CSINC(0x00000400),
+
+        BFM(0x20000000),
+        SBFM(0x00000000),
+        UBFM(0x40000000),
+        EXTR(0x13800000),
+
+        MADD(0x00000000),
+        MSUB(0x00008000),
+        SDIV(0x00000C00),
+        UDIV(0x00000800),
+
+        FMOV(0x00000000),
+        FMOVCPU2FPU(0x00070000),
+        FMOVFPU2CPU(0x00060000),
+
+        FCVTDS(0x00028000),
+        FCVTSD(0x00020000),
+
+        FCVTZS(0x00180000),
+        SCVTF(0x00020000),
+
+        FABS(0x00008000),
+        FSQRT(0x00018000),
+        FNEG(0x00010000),
+
+        FRINTZ(0x00058000),
+
+        FADD(0x00002000),
+        FSUB(0x00003000),
+        FMUL(0x00000000),
+        FDIV(0x00001000),
+        FMAX(0x00004000),
+        FMIN(0x00005000),
+
+        FMADD(0x00000000),
+        FMSUB(0x00008000),
+
+        FCMP(0x00000000),
+        FCMPZERO(0x00000008),
+        FCCMP(0x1E200400),
+        FCSEL(0x1E200C00),
+
+        INS(0x4e081c00),
+        UMOV(0x4e083c00),
+
+        CNT(0xe205800),
+        USRA(0x6f001400),
+
+        HLT(0x00400000),
+        BRK(0x00200000),
+
+        CLREX(0xd5033f5f),
+        HINT(0xD503201F),
+        DMB(0x000000A0),
+
+        BLR_NATIVE(0xc0000000);
+
+        public final int encoding;
+
+        private Instruction(int encoding) {
+            this.encoding = encoding;
+        }
+
+    }
+
+    public enum ShiftType {
+        LSL(0),
+        LSR(1),
+        ASR(2),
+        ROR(3);
+
+        public final int encoding;
+
+        private ShiftType(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    public enum ExtendType {
+        UXTB(0),
+        UXTH(1),
+        UXTW(2),
+        UXTX(3),
+        SXTB(4),
+        SXTH(5),
+        SXTW(6),
+        SXTX(7);
+
+        public final int encoding;
+
+        private ExtendType(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    /**
+     * Condition Flags for branches. See 4.3
+     */
+    public enum ConditionFlag {
+        // Integer | Floating-point meanings
+        /**
+         * Equal | Equal.
+         */
+        EQ(0x0),
+        /**
+         * Not Equal | Not equal or unordered.
+         */
+        NE(0x1),
+        /**
+         * Unsigned Higher or Same | Greater than, equal or unordered.
+         */
+        HS(0x2),
+        /**
+         * unsigned lower | less than.
+         */
+        LO(0x3),
+        /**
+         * minus (negative) | less than.
+         */
+        MI(0x4),
+        /**
+         * plus (positive or zero) | greater than, equal or unordered.
+         */
+        PL(0x5),
+        /**
+         * overflow set | unordered.
+         */
+        VS(0x6),
+        /**
+         * overflow clear | ordered.
+         */
+        VC(0x7),
+        /**
+         * unsigned higher | greater than or unordered.
+         */
+        HI(0x8),
+        /**
+         * unsigned lower or same | less than or equal.
+         */
+        LS(0x9),
+        /**
+         * signed greater than or equal | greater than or equal.
+         */
+        GE(0xA),
+        /**
+         * signed less than | less than or unordered.
+         */
+        LT(0xB),
+        /**
+         * signed greater than | greater than.
+         */
+        GT(0xC),
+        /**
+         * signed less than or equal | less than, equal or unordered.
+         */
+        LE(0xD),
+        /**
+         * always | always.
+         */
+        AL(0xE),
+        /**
+         * always | always (identical to AL, just to have valid 0b1111 encoding).
+         */
+        NV(0xF);
+
+        public final int encoding;
+
+        private ConditionFlag(int encoding) {
+            this.encoding = encoding;
+        }
+
+        /**
+         * @return ConditionFlag specified by decoding.
+         */
+        public static ConditionFlag fromEncoding(int encoding) {
+            return values()[encoding];
+        }
+
+        public ConditionFlag negate() {
+            switch (this) {
+                case EQ:
+                    return NE;
+                case NE:
+                    return EQ;
+                case HS:
+                    return LO;
+                case LO:
+                    return HS;
+                case MI:
+                    return PL;
+                case PL:
+                    return MI;
+                case VS:
+                    return VC;
+                case VC:
+                    return VS;
+                case HI:
+                    return LS;
+                case LS:
+                    return HI;
+                case GE:
+                    return LT;
+                case LT:
+                    return GE;
+                case GT:
+                    return LE;
+                case LE:
+                    return GT;
+                case AL:
+                case NV:
+                default:
+                    throw JVMCIError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public AArch64Assembler(TargetDescription target) {
+        super(target);
+    }
+
+    /* Conditional Branch (5.2.1) */
+
+    /**
+     * Branch conditionally.
+     *
+     * @param condition may not be null.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     */
+    protected void b(ConditionFlag condition, int imm21) {
+        b(condition, imm21, -1);
+    }
+
+    /**
+     * Branch conditionally. Inserts instruction into code buffer at pos.
+     *
+     * @param condition may not be null.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     * @param pos Position at which instruction is inserted into buffer. -1 means insert at end.
+     */
+    protected void b(ConditionFlag condition, int imm21, int pos) {
+        if (pos == -1) {
+            emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding);
+        } else {
+            emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding, pos);
+        }
+    }
+
+    /**
+     * Compare register and branch if non-zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     */
+    protected void cbnz(int size, Register reg, int imm21) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, -1);
+    }
+
+    /**
+     * Compare register and branch if non-zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     * @param pos Position at which instruction is inserted into buffer. -1 means insert at end.
+     */
+    protected void cbnz(int size, Register reg, int imm21, int pos) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, pos);
+    }
+
+    /**
+     * Compare and branch if zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     */
+    protected void cbz(int size, Register reg, int imm21) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, -1);
+    }
+
+    /**
+     * Compare register and branch if zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     * @param pos Position at which instruction is inserted into buffer. -1 means insert at end.
+     */
+    protected void cbz(int size, Register reg, int imm21, int pos) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, pos);
+    }
+
+    private void conditionalBranchInstruction(Register reg, int imm21, InstructionType type, Instruction instr, int pos) {
+        assert reg.getRegisterCategory().equals(CPU);
+        int instrEncoding = instr.encoding | CompareBranchOp;
+        if (pos == -1) {
+            emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg));
+        } else {
+            emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg), pos);
+        }
+    }
+
+    private static int getConditionalBranchImm(int imm21) {
+        assert NumUtil.isSignedNbit(21, imm21) && (imm21 & 0x3) == 0 : "Immediate has to be 21bit signed number and word aligned";
+        int imm = (imm21 & NumUtil.getNbitNumberInt(21)) >> 2;
+        return imm << ConditionalBranchImmOffset;
+    }
+
+    /* Unconditional Branch (immediate) (5.2.2) */
+
+    /**
+     * @param imm28 Signed 28-bit offset, has to be word aligned.
+     */
+    protected void b(int imm28) {
+        unconditionalBranchImmInstruction(imm28, Instruction.B, -1);
+    }
+
+    /**
+     *
+     * @param imm28 Signed 28-bit offset, has to be word aligned.
+     * @param pos Position where instruction is inserted into code buffer.
+     */
+    protected void b(int imm28, int pos) {
+        unconditionalBranchImmInstruction(imm28, Instruction.B, pos);
+    }
+
+    /**
+     * Branch and link return address to register X30.
+     *
+     * @param imm28 Signed 28-bit offset, has to be word aligned.
+     */
+    public void bl(int imm28) {
+        unconditionalBranchImmInstruction(imm28, Instruction.BL, -1);
+    }
+
+    private void unconditionalBranchImmInstruction(int imm28, Instruction instr, int pos) {
+        assert NumUtil.isSignedNbit(28, imm28) && (imm28 & 0x3) == 0 : "Immediate has to be 28bit signed number and word aligned";
+        int imm = (imm28 & NumUtil.getNbitNumberInt(28)) >> 2;
+        int instrEncoding = instr.encoding | UnconditionalBranchImmOp;
+        if (pos == -1) {
+            emitInt(instrEncoding | imm);
+        } else {
+            emitInt(instrEncoding | imm, pos);
+        }
+    }
+
+    /* Unconditional Branch (register) (5.2.3) */
+
+    /**
+     * Branches to address in register and writes return address into register X30.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     */
+    public void blr(Register reg) {
+        unconditionalBranchRegInstruction(reg, Instruction.BLR);
+    }
+
+    /**
+     * Branches to address in register.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     */
+    protected void br(Register reg) {
+        unconditionalBranchRegInstruction(reg, Instruction.BR);
+    }
+
+    /**
+     * Return to address in register.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     */
+    public void ret(Register reg) {
+        unconditionalBranchRegInstruction(reg, Instruction.RET);
+    }
+
+    private void unconditionalBranchRegInstruction(Register reg, Instruction instr) {
+        assert reg.getRegisterCategory().equals(CPU) && !reg.equals(zr) && !reg.equals(sp);
+        final int instrEncoding = instr.encoding | UnconditionalBranchRegOp;
+        emitInt(instrEncoding | rs1(reg));
+    }
+
+    /* Load-Store Single Register (5.3.1) */
+
+    /**
+     * Loads a srcSize value from address into rt zero-extending it.
+     *
+     * @param srcSize size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void ldr(int srcSize, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(CPU);
+        assert srcSize == 8 || srcSize == 16 || srcSize == 32 || srcSize == 64;
+        int transferSize = NumUtil.log2Ceil(srcSize / 8);
+        loadStoreInstruction(rt, address, InstructionType.General32, Instruction.LDR, transferSize);
+    }
+
+    /**
+     * Loads a srcSize value from address into rt sign-extending it.
+     *
+     * @param targetSize size of target register in bits. Must be 32 or 64.
+     * @param srcSize size of memory read in bits. Must be 8, 16 or 32, but may not be equivalent to
+     *            targetSize.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    protected void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(CPU);
+        assert (srcSize == 8 || srcSize == 16 || srcSize == 32) && srcSize != targetSize;
+        int transferSize = NumUtil.log2Ceil(srcSize / 8);
+        loadStoreInstruction(rt, address, generalFromSize(targetSize), Instruction.LDRS, transferSize);
+    }
+
+    /**
+     * Stores register rt into memory pointed by address.
+     *
+     * @param destSize number of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void str(int destSize, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(CPU);
+        assert destSize == 8 || destSize == 16 || destSize == 32 || destSize == 64;
+        int transferSize = NumUtil.log2Ceil(destSize / 8);
+        loadStoreInstruction(rt, address, InstructionType.General64, Instruction.STR, transferSize);
+    }
+
+    private void loadStoreInstruction(Register reg, AArch64Address address, InstructionType type, Instruction instr, int log2TransferSize) {
+        assert log2TransferSize >= 0 && log2TransferSize < 4;
+        int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
+        int is32Bit = type.width == 32 ? 1 << ImmediateSizeOffset : 0;
+        int isFloat = !type.isGeneral ? 1 << LoadStoreFpFlagOffset : 0;
+        int memop = instr.encoding | transferSizeEncoding | is32Bit | isFloat | rt(reg);
+        switch (address.getAddressingMode()) {
+            case IMMEDIATE_SCALED:
+                emitInt(memop | LoadStoreScaledOp | address.getImmediate() << LoadStoreScaledImmOffset | rs1(address.getBase()));
+                break;
+            case IMMEDIATE_UNSCALED:
+                emitInt(memop | LoadStoreUnscaledOp | address.getImmediate() << LoadStoreUnscaledImmOffset | rs1(address.getBase()));
+                break;
+            case BASE_REGISTER_ONLY:
+                emitInt(memop | LoadStoreScaledOp | rs1(address.getBase()));
+                break;
+            case EXTENDED_REGISTER_OFFSET:
+            case REGISTER_OFFSET:
+                ExtendType extendType = address.getAddressingMode() == AddressingMode.EXTENDED_REGISTER_OFFSET ? address.getExtendType() : ExtendType.UXTX;
+                boolean shouldScale = address.isScaled() && log2TransferSize != 0;
+                emitInt(memop | LoadStoreRegisterOp | rs2(address.getOffset()) | extendType.encoding << ExtendTypeOffset | (shouldScale ? 1 : 0) << LoadStoreScaledRegOffset | rs1(address.getBase()));
+                break;
+            case PC_LITERAL:
+                assert log2TransferSize >= 2 : "PC literal loads only works for load/stores of 32-bit and larger";
+                transferSizeEncoding = (log2TransferSize - 2) << LoadStoreTransferSizeOffset;
+                emitInt(transferSizeEncoding | isFloat | LoadLiteralOp | rd(reg) | address.getImmediate() << LoadLiteralImmeOffset);
+                break;
+            case IMMEDIATE_POST_INDEXED:
+                emitInt(memop | LoadStorePostIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset);
+                break;
+            case IMMEDIATE_PRE_INDEXED:
+                emitInt(memop | LoadStorePreIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset);
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    /* Load-Store Exclusive (5.3.6) */
+
+    /**
+     * Load address exclusive. Natural alignment of address is required.
+     *
+     * @param size size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    protected void ldxr(int size, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveLoadInstruction(rt, address, transferSize, Instruction.LDXR);
+    }
+
+    /**
+     * Store address exclusive. Natural alignment of address is required. rs and rt may not point to
+     * the same register.
+     *
+     * @param size size of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rs general purpose register. Set to exclusive access status. 0 means success,
+     *            everything else failure. May not be null, or stackpointer.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    protected void stxr(int size, Register rs, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveStoreInstruction(rs, rt, address, transferSize, Instruction.STXR);
+    }
+
+    /* Load-Acquire/Store-Release (5.3.7) */
+
+    /* non exclusive access */
+    /**
+     * Load acquire. Natural alignment of address is required.
+     *
+     * @param size size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    protected void ldar(int size, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveLoadInstruction(rt, address, transferSize, Instruction.LDAR);
+    }
+
+    /**
+     * Store-release. Natural alignment of address is required.
+     *
+     * @param size size of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    protected void stlr(int size, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        // Hack: Passing the zero-register means it is ignored when building the encoding.
+        exclusiveStoreInstruction(AArch64.r0, rt, address, transferSize, Instruction.STLR);
+    }
+
+    /* exclusive access */
+    /**
+     * Load acquire exclusive. Natural alignment of address is required.
+     *
+     * @param size size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    public void ldaxr(int size, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveLoadInstruction(rt, address, transferSize, Instruction.LDAXR);
+    }
+
+    /**
+     * Store-release exclusive. Natural alignment of address is required. rs and rt may not point to
+     * the same register.
+     *
+     * @param size size of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rs general purpose register. Set to exclusive access status. 0 means success,
+     *            everything else failure. May not be null, or stackpointer.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    public void stlxr(int size, Register rs, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveStoreInstruction(rs, rt, address, transferSize, Instruction.STLXR);
+    }
+
+    private void exclusiveLoadInstruction(Register reg, AArch64Address address, int log2TransferSize, Instruction instr) {
+        assert address.getAddressingMode() == AddressingMode.BASE_REGISTER_ONLY;
+        assert log2TransferSize >= 0 && log2TransferSize < 4;
+        assert reg.getRegisterCategory().equals(CPU);
+        int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
+        int instrEncoding = instr.encoding;
+        emitInt(transferSizeEncoding | instrEncoding | 1 << ImmediateSizeOffset | rt(reg) | rs1(address.getBase()));
+    }
+
+    /**
+     * Stores data from rt into address and sets rs to the returned exclusive access status.
+     *
+     * @param rs general purpose register into which the exclusive access status is written. May not
+     *            be null.
+     * @param rt general purpose register containing data to be written to memory at address. May
+     *            not be null
+     * @param address Address in base register without offset form specifying where rt is written
+     *            to.
+     * @param log2TransferSize log2Ceil of memory transfer size.
+     */
+    private void exclusiveStoreInstruction(Register rs, Register rt, AArch64Address address, int log2TransferSize, Instruction instr) {
+        assert address.getAddressingMode() == AddressingMode.BASE_REGISTER_ONLY;
+        assert log2TransferSize >= 0 && log2TransferSize < 4;
+        assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt);
+        int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
+        int instrEncoding = instr.encoding;
+        emitInt(transferSizeEncoding | instrEncoding | rs2(rs) | rt(rt) | rs1(address.getBase()));
+    }
+
+    /* PC-relative Address Calculation (5.4.4) */
+
+    /**
+     * Address of page: sign extends 21-bit offset, shifts if left by 12 and adds it to the value of
+     * the PC with its bottom 12-bits cleared, writing the result to dst.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm Signed 33-bit offset with lower 12bits clear.
+     */
+    // protected void adrp(Register dst, long imm) {
+    // assert (imm & NumUtil.getNbitNumberInt(12)) == 0 : "Lower 12-bit of immediate must be zero.";
+    // assert NumUtil.isSignedNbit(33, imm);
+    // addressCalculationInstruction(dst, (int) (imm >>> 12), Instruction.ADRP);
+    // }
+
+    /**
+     * Adds a 21-bit signed offset to the program counter and writes the result to dst.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm21 Signed 21-bit offset.
+     */
+    public void adr(Register dst, int imm21) {
+        addressCalculationInstruction(dst, imm21, Instruction.ADR);
+    }
+
+    private void addressCalculationInstruction(Register dst, int imm21, Instruction instr) {
+        assert dst.getRegisterCategory().equals(CPU);
+        int instrEncoding = instr.encoding | PcRelImmOp;
+        emitInt(instrEncoding | rd(dst) | getPcRelativeImmEncoding(imm21));
+    }
+
+    private static int getPcRelativeImmEncoding(int imm21) {
+        assert NumUtil.isSignedNbit(21, imm21);
+        int imm = imm21 & NumUtil.getNbitNumberInt(21);
+        // higher 19 bit
+        int immHi = (imm >> 2) << PcRelImmHiOffset;
+        // lower 2 bit
+        int immLo = (imm & 0x3) << PcRelImmLoOffset;
+        return immHi | immLo;
+    }
+
+    /* Arithmetic (Immediate) (5.4.1) */
+
+    /**
+     * dst = src + aimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void add(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(zr);
+        addSubImmInstruction(dst, src, aimm, generalFromSize(size), Instruction.ADD);
+    }
+
+    /**
+     * dst = src + aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void adds(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(sp);
+        assert !src.equals(zr);
+        addSubImmInstruction(dst, src, aimm, generalFromSize(size), Instruction.ADDS);
+    }
+
+    /**
+     * dst = src - aimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void sub(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(zr);
+        addSubImmInstruction(dst, src, aimm, generalFromSize(size), Instruction.SUB);
+    }
+
+    /**
+     * dst = src - aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void subs(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(sp);
+        assert !src.equals(zr);
+        addSubImmInstruction(dst, src, aimm, generalFromSize(size), Instruction.SUBS);
+    }
+
+    private void addSubImmInstruction(Register dst, Register src, int aimm, InstructionType type, Instruction instr) {
+        int instrEncoding = instr.encoding | AddSubImmOp;
+        emitInt(type.encoding | instrEncoding | encodeAimm(aimm) | rd(dst) | rs1(src));
+    }
+
+    /**
+     * Encodes arithmetic immediate.
+     *
+     * @param imm Immediate has to be either an unsigned 12bit value or un unsigned 24bit value with
+     *            the lower 12 bits 0.
+     * @return Representation of immediate for use with arithmetic instructions.
+     */
+    private static int encodeAimm(int imm) {
+        assert isAimm(imm) : "Immediate has to be legal arithmetic immediate value " + imm;
+        if (NumUtil.isUnsignedNbit(12, imm)) {
+            return imm << ImmediateOffset;
+        } else {
+            // First 12 bit are 0, so shift immediate 12 bit and set flag to indicate
+            // shifted immediate value.
+            return (imm >>> 12 << ImmediateOffset) | (1 << AddSubShiftOffset);
+        }
+    }
+
+    /**
+     * Checks whether immediate can be encoded as an arithmetic immediate.
+     *
+     * @param imm Immediate has to be either an unsigned 12bit value or un unsigned 24bit value with
+     *            the lower 12 bits 0.
+     * @return true if valid arithmetic immediate, false otherwise.
+     */
+    protected static boolean isAimm(int imm) {
+        return NumUtil.isUnsignedNbit(12, imm) || NumUtil.isUnsignedNbit(12, imm >>> 12) && (imm & 0xfff) == 0;
+    }
+
+    /* Logical (immediate) (5.4.2) */
+
+    /**
+     * dst = src & bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    public void and(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(sp);
+        logicalImmInstruction(dst, src, bimm, generalFromSize(size), Instruction.AND);
+    }
+
+    /**
+     * dst = src & bimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stack-pointer.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    public void ands(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(sp);
+        assert !src.equals(sp);
+        logicalImmInstruction(dst, src, bimm, generalFromSize(size), Instruction.ANDS);
+    }
+
+    /**
+     * dst = src ^ bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    public void eor(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(sp);
+        logicalImmInstruction(dst, src, bimm, generalFromSize(size), Instruction.EOR);
+    }
+
+    /**
+     * dst = src | bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    protected void orr(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(sp);
+        logicalImmInstruction(dst, src, bimm, generalFromSize(size), Instruction.ORR);
+    }
+
+    protected void logicalImmInstruction(Register dst, Register src, long bimm, InstructionType type, Instruction instr) {
+        // Mask higher bits off, since we always pass longs around even for the 32-bit instruction.
+        long bimmValue;
+        if (type == InstructionType.General32) {
+            assert (bimm >> 32) == 0 || (bimm >> 32) == -1L : "Higher order bits for 32-bit instruction must either all be 0 or 1.";
+            bimmValue = bimm & NumUtil.getNbitNumberLong(32);
+        } else {
+            bimmValue = bimm;
+        }
+        int immEncoding = LogicalImmediateTable.getLogicalImmEncoding(type == InstructionType.General64, bimmValue);
+        int instrEncoding = instr.encoding | LogicalImmOp;
+        emitInt(type.encoding | instrEncoding | immEncoding | rd(dst) | rs1(src));
+    }
+
+    /* Move (wide immediate) (5.4.3) */
+
+    /**
+     * dst = uimm16 << shiftAmt.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param uimm16 16-bit unsigned immediate
+     * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller
+     *            than size.
+     */
+    protected void movz(int size, Register dst, int uimm16, int shiftAmt) {
+        moveWideImmInstruction(dst, uimm16, shiftAmt, generalFromSize(size), Instruction.MOVZ);
+    }
+
+    /**
+     * dst = ~(uimm16 << shiftAmt).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param uimm16 16-bit unsigned immediate
+     * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller
+     *            than size.
+     */
+    protected void movn(int size, Register dst, int uimm16, int shiftAmt) {
+        moveWideImmInstruction(dst, uimm16, shiftAmt, generalFromSize(size), Instruction.MOVN);
+    }
+
+    /**
+     * dst<pos+15:pos> = uimm16.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param uimm16 16-bit unsigned immediate
+     * @param pos position into which uimm16 is inserted. Can be any multiple of 16 smaller than
+     *            size.
+     */
+    protected void movk(int size, Register dst, int uimm16, int pos) {
+        moveWideImmInstruction(dst, uimm16, pos, generalFromSize(size), Instruction.MOVK);
+    }
+
+    private void moveWideImmInstruction(Register dst, int uimm16, int shiftAmt, InstructionType type, Instruction instr) {
+        assert dst.getRegisterCategory().equals(CPU);
+        assert NumUtil.isUnsignedNbit(16, uimm16) : "Immediate has to be unsigned 16bit";
+        assert shiftAmt == 0 || shiftAmt == 16 || (type == InstructionType.General64 && (shiftAmt == 32 || shiftAmt == 48)) : "Invalid shift amount: " + shiftAmt;
+        int shiftValue = shiftAmt >> 4;
+        int instrEncoding = instr.encoding | MoveWideImmOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | uimm16 << MoveWideImmOffset | shiftValue << MoveWideShiftOffset);
+    }
+
+    /* Bitfield Operations (5.4.5) */
+
+    /**
+     * Bitfield move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param r must be in the range 0 to size - 1
+     * @param s must be in the range 0 to size - 1
+     */
+    protected void bfm(int size, Register dst, Register src, int r, int s) {
+        bitfieldInstruction(dst, src, r, s, generalFromSize(size), Instruction.BFM);
+    }
+
+    /**
+     * Unsigned bitfield move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param r must be in the range 0 to size - 1
+     * @param s must be in the range 0 to size - 1
+     */
+    protected void ubfm(int size, Register dst, Register src, int r, int s) {
+        bitfieldInstruction(dst, src, r, s, generalFromSize(size), Instruction.UBFM);
+    }
+
+    /**
+     * Signed bitfield move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param r must be in the range 0 to size - 1
+     * @param s must be in the range 0 to size - 1
+     */
+    protected void sbfm(int size, Register dst, Register src, int r, int s) {
+        bitfieldInstruction(dst, src, r, s, generalFromSize(size), Instruction.SBFM);
+    }
+
+    private void bitfieldInstruction(Register dst, Register src, int r, int s, InstructionType type, Instruction instr) {
+        assert !dst.equals(sp) && !dst.equals(zr);
+        assert !src.equals(sp) && !src.equals(zr);
+        assert s >= 0 && s < type.width && r >= 0 && r < type.width;
+        int instrEncoding = instr.encoding | BitfieldImmOp;
+        int sf = type == InstructionType.General64 ? 1 << ImmediateSizeOffset : 0;
+        emitInt(type.encoding | instrEncoding | sf | r << ImmediateRotateOffset | s << ImmediateOffset | rd(dst) | rs1(src));
+    }
+
+    /* Extract (Immediate) (5.4.6) */
+
+    /**
+     * Extract. dst = src1:src2<lsb+31:lsb>
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param lsb must be in range 0 to size - 1.
+     */
+    protected void extr(int size, Register dst, Register src1, Register src2, int lsb) {
+        extractInstruction(dst, src1, src2, lsb, generalFromSize(size));
+    }
+
+    private void extractInstruction(Register dst, Register src1, Register src2, int lsb, InstructionType type) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert lsb >= 0 && lsb < type.width;
+        int sf = type == InstructionType.General64 ? 1 << ImmediateSizeOffset : 0;
+        emitInt(type.encoding | Instruction.EXTR.encoding | sf | lsb << ImmediateOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Arithmetic (shifted register) (5.5.1) */
+
+    /**
+     * dst = src1 + shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(dst, src1, src2, shiftType, imm, generalFromSize(size), Instruction.ADD);
+    }
+
+    /**
+     * dst = src1 + shiftType(src2, imm) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(dst, src1, src2, shiftType, imm, generalFromSize(size), Instruction.ADDS);
+    }
+
+    /**
+     * dst = src1 - shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(dst, src1, src2, shiftType, imm, generalFromSize(size), Instruction.SUB);
+    }
+
+    /**
+     * dst = src1 - shiftType(src2, imm) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(dst, src1, src2, shiftType, imm, generalFromSize(size), Instruction.SUBS);
+    }
+
+    private void addSubShiftedInstruction(Register dst, Register src1, Register src2, ShiftType shiftType, int imm, InstructionType type, Instruction instr) {
+        assert shiftType != ShiftType.ROR;
+        assert imm >= 0 && imm < type.width;
+        int instrEncoding = instr.encoding | AddSubShiftedOp;
+        emitInt(type.encoding | instrEncoding | imm << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Arithmetic (extended register) (5.5.2) */
+    /**
+     * dst = src1 + extendType(src2) << imm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(zr);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(dst, src1, src2, extendType, shiftAmt, generalFromSize(size), Instruction.ADD);
+    }
+
+    /**
+     * dst = src1 + extendType(src2) << imm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(sp);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(dst, src1, src2, extendType, shiftAmt, generalFromSize(size), Instruction.ADDS);
+    }
+
+    /**
+     * dst = src1 - extendType(src2) << imm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(zr);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(dst, src1, src2, extendType, shiftAmt, generalFromSize(size), Instruction.SUB);
+    }
+
+    /**
+     * dst = src1 - extendType(src2) << imm and sets flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(sp);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(dst, src1, src2, extendType, shiftAmt, generalFromSize(size), Instruction.SUBS);
+    }
+
+    private void addSubExtendedInstruction(Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt, InstructionType type, Instruction instr) {
+        assert shiftAmt >= 0 && shiftAmt <= 4;
+        int instrEncoding = instr.encoding | AddSubExtendedOp;
+        emitInt(type.encoding | instrEncoding | shiftAmt << ImmediateOffset | extendType.encoding << ExtendTypeOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Logical (shifted register) (5.5.3) */
+    /**
+     * dst = src1 & shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.AND);
+    }
+
+    /**
+     * dst = src1 & shiftType(src2, imm) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.ANDS);
+    }
+
+    /**
+     * dst = src1 & ~(shiftType(src2, imm)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.BIC);
+    }
+
+    /**
+     * dst = src1 & ~(shiftType(src2, imm)) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.BICS);
+    }
+
+    /**
+     * dst = src1 ^ ~(shiftType(src2, imm)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.EON);
+    }
+
+    /**
+     * dst = src1 ^ shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.EOR);
+    }
+
+    /**
+     * dst = src1 | shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.ORR);
+    }
+
+    /**
+     * dst = src1 | ~(shiftType(src2, imm)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.ORN);
+    }
+
+    private void logicalRegInstruction(Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt, InstructionType type, Instruction instr) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert shiftAmt >= 0 && shiftAmt < type.width;
+        int instrEncoding = instr.encoding | LogicalShiftOp;
+        emitInt(type.encoding | instrEncoding | shiftAmt << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Variable Shift (5.5.4) */
+    /**
+     * dst = src1 >> (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void asr(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.ASRV);
+    }
+
+    /**
+     * dst = src1 << (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void lsl(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.LSLV);
+    }
+
+    /**
+     * dst = src1 >>> (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void lsr(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.LSRV);
+    }
+
+    /**
+     * dst = rotateRight(src1, (src2 & log2(size))).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void ror(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.RORV);
+    }
+
+    /* Bit Operations (5.5.5) */
+
+    /**
+     * Counts leading sign bits. Sets Wd to the number of consecutive bits following the topmost bit
+     * in dst, that are the same as the topmost bit. The count does not include the topmost bit
+     * itself , so the result will be in the range 0 to size-1 inclusive.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, zero-register or the stackpointer.
+     * @param src source register. May not be null, zero-register or the stackpointer.
+     */
+    protected void cls(int size, Register dst, Register src) {
+        dataProcessing1SourceOp(dst, src, generalFromSize(size), Instruction.CLS);
+    }
+
+    /**
+     * Counts leading zeros.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, zero-register or the stackpointer.
+     * @param src source register. May not be null, zero-register or the stackpointer.
+     */
+    public void clz(int size, Register dst, Register src) {
+        dataProcessing1SourceOp(dst, src, generalFromSize(size), Instruction.CLZ);
+    }
+
+    /**
+     * Reverses bits.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, zero-register or the stackpointer.
+     * @param src source register. May not be null, zero-register or the stackpointer.
+     */
+    protected void rbit(int size, Register dst, Register src) {
+        dataProcessing1SourceOp(dst, src, generalFromSize(size), Instruction.RBIT);
+    }
+
+    /**
+     * Reverses bytes.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src source register. May not be null or the stackpointer.
+     */
+    public void rev(int size, Register dst, Register src) {
+        if (size == 64) {
+            dataProcessing1SourceOp(dst, src, generalFromSize(size), Instruction.REVX);
+        } else {
+            assert size == 32;
+            dataProcessing1SourceOp(dst, src, generalFromSize(size), Instruction.REVW);
+        }
+    }
+
+    /* Conditional Data Processing (5.5.6) */
+
+    /**
+     * Conditional select. dst = src1 if condition else src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param condition any condition flag. May not be null.
+     */
+    protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        conditionalSelectInstruction(dst, src1, src2, condition, generalFromSize(size), Instruction.CSEL);
+    }
+
+    /**
+     * Conditional select negate. dst = src1 if condition else -src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param condition any condition flag. May not be null.
+     */
+    protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        conditionalSelectInstruction(dst, src1, src2, condition, generalFromSize(size), Instruction.CSNEG);
+    }
+
+    /**
+     * Conditional increase. dst = src1 if condition else src2 + 1.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param condition any condition flag. May not be null.
+     */
+    protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        conditionalSelectInstruction(dst, src1, src2, condition, generalFromSize(size), Instruction.CSINC);
+    }
+
+    private void conditionalSelectInstruction(Register dst, Register src1, Register src2, ConditionFlag condition, InstructionType type, Instruction instr) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        int instrEncoding = instr.encoding | ConditionalSelectOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset);
+    }
+
+    /* Integer Multiply/Divide (5.6) */
+
+    /**
+     * dst = src1 * src2 + src3.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void madd(int size, Register dst, Register src1, Register src2, Register src3) {
+        mulInstruction(dst, src1, src2, src3, generalFromSize(size), Instruction.MADD);
+    }
+
+    /**
+     * dst = src3 - src1 * src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void msub(int size, Register dst, Register src1, Register src2, Register src3) {
+        mulInstruction(dst, src1, src2, src3, generalFromSize(size), Instruction.MSUB);
+    }
+
+    /**
+     * Signed multiply high. dst = (src1 * src2)[127:64]
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    protected void smulh(Register dst, Register src1, Register src2) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        emitInt(0b10011011010 << 21 | dst.encoding | src1.encoding << 5 | src2.encoding << 16 | 0b011111 << 10);
+    }
+
+    /**
+     * unsigned multiply high. dst = (src1 * src2)[127:64]
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    protected void umulh(Register dst, Register src1, Register src2) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        emitInt(0b10011011110 << 21 | dst.encoding | src1.encoding << 5 | src2.encoding << 16 | 0b011111 << 10);
+    }
+
+    /**
+     * unsigned multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2)
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void umaddl(Register dst, Register src1, Register src2, Register src3) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert !src3.equals(sp);
+        emitInt(0b10011011101 << 21 | dst.encoding | src1.encoding << 5 | src2.encoding << 16 | 0b011111 << 10);
+    }
+
+    /**
+     * signed multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2)
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void smaddl(Register dst, Register src1, Register src2, Register src3) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert !src3.equals(sp);
+        emitInt(0b10011011001 << 21 | dst.encoding | src1.encoding << 5 | src2.encoding << 16 | src3.encoding << 10);
+    }
+
+    private void mulInstruction(Register dst, Register src1, Register src2, Register src3, InstructionType type, Instruction instr) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert !src3.equals(sp);
+        int instrEncoding = instr.encoding | MulOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3));
+    }
+
+    /**
+     * Signed divide. dst = src1 / src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void sdiv(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.SDIV);
+    }
+
+    /**
+     * Unsigned divide. dst = src1 / src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void udiv(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.UDIV);
+    }
+
+    private void dataProcessing2SourceOp(Register dst, Register src1, Register src2, InstructionType type, Instruction instr) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        int instrEncoding = instr.encoding | DataProcessing2SourceOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    private void dataProcessing1SourceOp(Register dst, Register src, InstructionType type, Instruction instr) {
+        int instrEncoding = instr.encoding | DataProcessing1SourceOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src));
+    }
+
+    /* Floating point operations */
+
+    /* Load-Store Single FP register (5.7.1.1) */
+    /**
+     * Floating point load.
+     *
+     * @param size number of bits read from memory into rt. Must be 32 or 64.
+     * @param rt floating point register. May not be null.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void fldr(int size, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(SIMD);
+        assert size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        loadStoreInstruction(rt, address, InstructionType.FP32, Instruction.LDR, transferSize);
+    }
+
+    /**
+     * Floating point store.
+     *
+     * @param size number of bits read from memory into rt. Must be 32 or 64.
+     * @param rt floating point register. May not be null.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void fstr(int size, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(SIMD);
+        assert size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        loadStoreInstruction(rt, address, InstructionType.FP64, Instruction.STR, transferSize);
+    }
+
+    /* Floating-point Move (register) (5.7.2) */
+
+    /**
+     * Floating point move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    protected void fmov(int size, Register dst, Register src) {
+        fpDataProcessing1Source(dst, src, floatFromSize(size), Instruction.FMOV);
+    }
+
+    /**
+     * Move size bits from floating point register unchanged to general purpose register.
+     *
+     * @param size number of bits read from memory into rt. Must be 32 or 64.
+     * @param dst general purpose register. May not be null, stack-pointer or zero-register
+     * @param src floating point register. May not be null.
+     */
+    protected void fmovFpu2Cpu(int size, Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(CPU);
+        assert src.getRegisterCategory().equals(SIMD);
+        fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVFPU2CPU);
+    }
+
+    /**
+     * Move size bits from general purpose register unchanged to floating point register.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param src general purpose register. May not be null or stack-pointer.
+     */
+    protected void fmovCpu2Fpu(int size, Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src.getRegisterCategory().equals(CPU);
+        fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVCPU2FPU);
+    }
+
+    private void fmovCpuFpuInstruction(Register dst, Register src, boolean is64bit, Instruction instr) {
+        int instrEncoding = instr.encoding | FpConvertOp;
+        int sf = is64bit ? InstructionType.FP64.encoding | InstructionType.General64.encoding : InstructionType.FP32.encoding | InstructionType.General32.encoding;
+        emitInt(sf | instrEncoding | rd(dst) | rs1(src));
+    }
+
+    /* Floating-point Move (immediate) (5.7.3) */
+
+    /**
+     * Move immediate into register.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be
+     *            loaded, i.e. (float) imm == imm must be true. In all cases
+     *            {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true
+     *            depending on size.
+     */
+    protected void fmov(int size, Register dst, double imm) {
+        fmovImmInstruction(dst, imm, floatFromSize(size));
+    }
+
+    private void fmovImmInstruction(Register dst, double imm, InstructionType type) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        int immEncoding;
+        if (type == InstructionType.FP64) {
+            immEncoding = getDoubleImmediate(imm);
+        } else {
+            assert imm == (float) imm : "float mov must use an immediate that can be represented using a float.";
+            immEncoding = getFloatImmediate((float) imm);
+        }
+        int instrEncoding = Instruction.FMOV.encoding | FpImmOp;
+        emitInt(type.encoding | instrEncoding | immEncoding | rd(dst));
+    }
+
+    private static int getDoubleImmediate(double imm) {
+        assert isDoubleImmediate(imm);
+        // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
+        // 0000.0000.0000.0000.0000.0000.0000.0000
+        long repr = Double.doubleToRawLongBits(imm);
+        int a = (int) (repr >>> 63) << 7;
+        int b = (int) ((repr >>> 61) & 0x1) << 6;
+        int cToH = (int) (repr >>> 48) & 0x3f;
+        return (a | b | cToH) << FpImmOffset;
+    }
+
+    protected static boolean isDoubleImmediate(double imm) {
+        // Valid values will have the form:
+        // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
+        // 0000.0000.0000.0000.0000.0000.0000.0000
+        long bits = Double.doubleToRawLongBits(imm);
+        // lower 48 bits are cleared
+        if ((bits & NumUtil.getNbitNumberLong(48)) != 0) {
+            return false;
+        }
+        // bits[61..54] are all set or all cleared.
+        long pattern = (bits >> 54) & NumUtil.getNbitNumberLong(7);
+        if (pattern != 0 && pattern != NumUtil.getNbitNumberLong(7)) {
+            return false;
+        }
+        // bits[62] and bits[61] are opposites.
+        return ((bits ^ (bits << 1)) & (1L << 62)) != 0;
+    }
+
+    private static int getFloatImmediate(float imm) {
+        assert isFloatImmediate(imm);
+        // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
+        int repr = Float.floatToRawIntBits(imm);
+        int a = (repr >>> 31) << 7;
+        int b = ((repr >>> 29) & 0x1) << 6;
+        int cToH = (repr >>> 19) & NumUtil.getNbitNumberInt(6);
+        return (a | b | cToH) << FpImmOffset;
+    }
+
+    protected static boolean isFloatImmediate(float imm) {
+        // Valid values will have the form:
+        // aBbb.bbbc.defg.h000.0000.0000.0000.0000
+        int bits = Float.floatToRawIntBits(imm);
+        // lower 20 bits are cleared.
+        if ((bits & NumUtil.getNbitNumberInt(19)) != 0) {
+            return false;
+        }
+        // bits[29..25] are all set or all cleared
+        int pattern = (bits >> 25) & NumUtil.getNbitNumberInt(5);
+        if (pattern != 0 && pattern != NumUtil.getNbitNumberInt(5)) {
+            return false;
+        }
+        // bits[29] and bits[30] have to be opposite
+        return ((bits ^ (bits << 1)) & (1 << 30)) != 0;
+    }
+
+    /* Convert Floating-point Precision (5.7.4.1) */
+    /* Converts float to double and vice-versa */
+
+    /**
+     * Convert float to double and vice-versa.
+     *
+     * @param srcSize size of source register in bits.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fcvt(int srcSize, Register dst, Register src) {
+        if (srcSize == 32) {
+            fpDataProcessing1Source(dst, src, floatFromSize(srcSize), Instruction.FCVTDS);
+        } else {
+            fpDataProcessing1Source(dst, src, floatFromSize(srcSize), Instruction.FCVTSD);
+        }
+    }
+
+    /* Convert to Integer (5.7.4.2) */
+
+    /**
+     * Convert floating point to integer. Rounds towards zero.
+     *
+     * @param targetSize size of integer register. 32 or 64.
+     * @param srcSize size of floating point register. 32 or 64.
+     * @param dst general purpose register. May not be null, the zero-register or the stackpointer.
+     * @param src floating point register. May not be null.
+     */
+    public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) {
+        assert !dst.equals(zr) && !dst.equals(sp);
+        assert src.getRegisterCategory().equals(SIMD);
+        fcvtCpuFpuInstruction(dst, src, generalFromSize(targetSize), floatFromSize(srcSize), Instruction.FCVTZS);
+    }
+
+    /* Convert from Integer (5.7.4.2) */
+    /**
+     * Converts integer to floating point. Uses rounding mode defined by FCPR.
+     *
+     * @param targetSize size of floating point register. 32 or 64.
+     * @param srcSize size of integer register. 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param src general purpose register. May not be null or the stackpointer.
+     */
+    public void scvtf(int targetSize, int srcSize, Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert !src.equals(sp);
+        fcvtCpuFpuInstruction(dst, src, floatFromSize(targetSize), generalFromSize(srcSize), Instruction.SCVTF);
+    }
+
+    private void fcvtCpuFpuInstruction(Register dst, Register src, InstructionType type1, InstructionType type2, Instruction instr) {
+        int instrEncoding = instr.encoding | FpConvertOp;
+        emitInt(type1.encoding | type2.encoding | instrEncoding | rd(dst) | rs1(src));
+    }
+
+    /* Floating-point Round to Integral (5.7.5) */
+
+    /**
+     * Rounds floating-point to integral. Rounds towards zero.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    protected void frintz(int size, Register dst, Register src) {
+        fpDataProcessing1Source(dst, src, floatFromSize(size), Instruction.FRINTZ);
+    }
+
+    /* Floating-point Arithmetic (1 source) (5.7.6) */
+
+    /**
+     * dst = |src|.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fabs(int size, Register dst, Register src) {
+        fpDataProcessing1Source(dst, src, floatFromSize(size), Instruction.FABS);
+    }
+
+    /**
+     * dst = -neg.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fneg(int size, Register dst, Register src) {
+        fpDataProcessing1Source(dst, src, floatFromSize(size), Instruction.FNEG);
+    }
+
+    /**
+     * dst = Sqrt(src).
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fsqrt(int size, Register dst, Register src) {
+        fpDataProcessing1Source(dst, src, floatFromSize(size), Instruction.FSQRT);
+    }
+
+    private void fpDataProcessing1Source(Register dst, Register src, InstructionType type, Instruction instr) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src.getRegisterCategory().equals(SIMD);
+        int instrEncoding = instr.encoding | Fp1SourceOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src));
+    }
+
+    /* Floating-point Arithmetic (2 source) (5.7.7) */
+
+    /**
+     * dst = src1 + src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fadd(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(dst, src1, src2, floatFromSize(size), Instruction.FADD);
+    }
+
+    /**
+     * dst = src1 - src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fsub(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(dst, src1, src2, floatFromSize(size), Instruction.FSUB);
+    }
+
+    /**
+     * dst = src1 * src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fmul(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(dst, src1, src2, floatFromSize(size), Instruction.FMUL);
+    }
+
+    /**
+     * dst = src1 / src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fdiv(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(dst, src1, src2, floatFromSize(size), Instruction.FDIV);
+    }
+
+    private void fpDataProcessing2Source(Register dst, Register src1, Register src2, InstructionType type, Instruction instr) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        int instrEncoding = instr.encoding | Fp2SourceOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Floating-point Multiply-Add (5.7.9) */
+
+    /**
+     * dst = src1 * src2 + src3.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param src3 floating point register. May not be null.
+     */
+    protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) {
+        fpDataProcessing3Source(dst, src1, src2, src3, floatFromSize(size), Instruction.FMADD);
+    }
+
+    /**
+     * dst = src3 - src1 * src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param src3 floating point register. May not be null.
+     */
+    protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) {
+        fpDataProcessing3Source(dst, src1, src2, src3, floatFromSize(size), Instruction.FMSUB);
+    }
+
+    private void fpDataProcessing3Source(Register dst, Register src1, Register src2, Register src3, InstructionType type, Instruction instr) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        assert src3.getRegisterCategory().equals(SIMD);
+        int instrEncoding = instr.encoding | Fp3SourceOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3));
+    }
+
+    /* Floating-point Comparison (5.7.10) */
+
+    /**
+     * Compares src1 to src2.
+     *
+     * @param size register size.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fcmp(int size, Register src1, Register src2) {
+        fcmpInstruction(src1, src2, floatFromSize(size));
+    }
+
+    private void fcmpInstruction(Register src1, Register src2, InstructionType type) {
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        int instrEncoding = Instruction.FCMP.encoding | FpCmpOp;
+        emitInt(type.encoding | instrEncoding | rs1(src1) | rs2(src2));
+    }
+
+    /**
+     * Conditional compare. NZCV = fcmp(src1, src2) if condition else uimm4.
+     *
+     * @param size register size.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param uimm4 condition flags that are used if condition is false.
+     * @param condition every condition allowed. May not be null.
+     */
+    public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) {
+        fConditionalCompareInstruction(src1, src2, uimm4, condition, floatFromSize(size));
+    }
+
+    private void fConditionalCompareInstruction(Register src1, Register src2, int uimm4, ConditionFlag condition, InstructionType type) {
+        assert NumUtil.isUnsignedNbit(4, uimm4);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        emitInt(type.encoding | Instruction.FCCMP.encoding | uimm4 | condition.encoding << ConditionalConditionOffset | rs1(src1) | rs2(src2));
+    }
+
+    /**
+     * Compare register to 0.0 .
+     *
+     * @param size register size.
+     * @param src floating point register. May not be null.
+     */
+    public void fcmpZero(int size, Register src) {
+        fcmpZeroInstruction(src, floatFromSize(size));
+    }
+
+    private void fcmpZeroInstruction(Register src, InstructionType type) {
+        assert src.getRegisterCategory().equals(SIMD);
+        int instrEncoding = Instruction.FCMPZERO.encoding | FpCmpOp;
+        emitInt(type.encoding | instrEncoding | rs1(src));
+    }
+
+    /* Floating-point Conditional Select (5.7.11) */
+
+    /**
+     * Conditional select. dst = src1 if condition else src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param condition every condition allowed. May not be null.
+     */
+    protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        fConditionalSelect(dst, src1, src2, condition, floatFromSize(size));
+    }
+
+    private void fConditionalSelect(Register dst, Register src1, Register src2, ConditionFlag condition, InstructionType type) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        emitInt(type.encoding | Instruction.FCSEL.encoding | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset);
+    }
+
+    /* Debug exceptions (5.9.1.2) */
+
+    /**
+     * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as
+     * UNALLOCATED instruction.
+     *
+     * @param uimm16 Arbitrary 16-bit unsigned payload.
+     */
+    protected void hlt(int uimm16) {
+        exceptionInstruction(uimm16, Instruction.HLT);
+    }
+
+    /**
+     * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher
+     * exception level.
+     *
+     * @param uimm16 Arbitrary 16-bit unsigned payload.
+     */
+    protected void brk(int uimm16) {
+        exceptionInstruction(uimm16, Instruction.BRK);
+    }
+
+    /* Architectural hints (5.9.4) */
+    public enum SystemHint {
+        NOP(0x0),
+        YIELD(0x1),
+        WFE(0x2),
+        WFI(0x3),
+        SEV(0x4),
+        SEVL(0x5);
+
+        private final int encoding;
+
+        private SystemHint(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    /**
+     * Architectural hints.
+     *
+     * @param hint Can be any of the defined hints. May not be null.
+     */
+    protected void hint(SystemHint hint) {
+        emitInt(Instruction.HINT.encoding | hint.encoding << SystemImmediateOffset);
+    }
+
+    private void exceptionInstruction(int uimm16, Instruction instr) {
+        assert NumUtil.isUnsignedNbit(16, uimm16);
+        int instrEncoding = instr.encoding | ExceptionOp;
+        emitInt(instrEncoding | uimm16 << SystemImmediateOffset);
+    }
+
+    /**
+     * Clear Exclusive: clears the local record of the executing processor that an address has had a
+     * request for an exclusive access.
+     */
+    protected void clrex() {
+        emitInt(Instruction.CLREX.encoding);
+    }
+
+    /**
+     * Possible barrier definitions for Aarch64. LOAD_LOAD and LOAD_STORE map to the same underlying
+     * barrier.
+     *
+     * We only need synchronization across the inner shareable domain (see B2-90 in the Reference
+     * documentation).
+     */
+    public enum BarrierKind {
+        LOAD_LOAD(0x9, "ISHLD"),
+        LOAD_STORE(0x9, "ISHLD"),
+        STORE_STORE(0xA, "ISHST"),
+        ANY_ANY(0xB, "ISH");
+
+        public final int encoding;
+        public final String optionName;
+
+        private BarrierKind(int encoding, String optionName) {
+            this.encoding = encoding;
+            this.optionName = optionName;
+        }
+    }
+
+    /**
+     * Data Memory Barrier.
+     *
+     * @param barrierKind barrier that is issued. May not be null.
+     */
+    public void dmb(BarrierKind barrierKind) {
+        barrierInstruction(barrierKind, Instruction.DMB);
+    }
+
+    private void barrierInstruction(BarrierKind barrierKind, Instruction instr) {
+        int instrEncoding = instr.encoding | BarrierOp;
+        emitInt(instrEncoding | barrierKind.encoding << BarrierKindOffset);
+    }
+
+    // Artificial instructions for simulator. These instructions are illegal in the normal aarch64
+    // ISA,
+    // but have special meaning for the simulator
+
+    /**
+     * Branch and link register instruction with the target code being native, i.e. not aarch64.
+     *
+     * The simulator has to do extra work so needs to know the number of arguments (both gp and fp)
+     * as well as the type of the return value. See assembler_aarch64.hpp.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer. Contains
+     *            address of target method.
+     * @param gpArgs number of general purpose arguments passed to the function. 4-bit unsigned.
+     * @param fpArgs number of floating point arguments passed to the function. 4-bit unsigned.
+     * @param returnType returnType of function. May not be null, or Kind.ILLEGAL.
+     */
+    public void blrNative(Register reg, int gpArgs, int fpArgs, JavaKind returnType) {
+        assert reg.getRegisterCategory().equals(CPU) && NumUtil.isUnsignedNbit(4, gpArgs) && NumUtil.isUnsignedNbit(4, fpArgs) && returnType != null;
+        emitInt(Instruction.BLR_NATIVE.encoding | reg.encoding | getReturnTypeEncoding(returnType) << 5 | fpArgs << 7 | gpArgs << 11);
+    }
+
+    private static int getReturnTypeEncoding(JavaKind returnType) {
+        // See assembler_aarch64.hpp for encoding details
+        switch (returnType) {
+            case Boolean:
+            case Byte:
+            case Short:
+            case Char:
+            case Int:
+            case Long:
+            case Object:
+                return 1;
+            case Float:
+                return 2;
+            case Double:
+                return 3;
+            case Void:
+            case Illegal:
+                // Void functions use a result of Kind.Illegal apparently
+                return 0;
+            default:
+                throw JVMCIError.shouldNotReachHere("Illegal kind");
+        }
+    }
+
+    /* Helper functions */
+    private static int rd(Register reg) {
+        return reg.encoding << RdOffset;
+    }
+
+    private static int rs1(Register reg) {
+        return reg.encoding << Rs1Offset;
+    }
+
+    private static int rs2(Register reg) {
+        return reg.encoding << Rs2Offset;
+    }
+
+    private static int rs3(Register reg) {
+        return reg.encoding << Rs3Offset;
+    }
+
+    private static int rt(Register reg) {
+        return reg.encoding << RtOffset;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.aarch64/src/com/oracle/graal/asm/aarch64/AArch64MacroAssembler.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,1366 @@
+/*
+ * Copyright (c) 2013, 2015, 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 com.oracle.graal.asm.aarch64;
+
+import static com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode.BASE_REGISTER_ONLY;
+import static com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET;
+import static com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_SCALED;
+import static com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_UNSCALED;
+import static com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode.REGISTER_OFFSET;
+import static com.oracle.graal.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_BASE;
+import static com.oracle.graal.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_INDEX;
+import static com.oracle.graal.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.NO_WORK;
+import static jdk.vm.ci.aarch64.AArch64.CPU;
+import static jdk.vm.ci.aarch64.AArch64.r8;
+import static jdk.vm.ci.aarch64.AArch64.r9;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+
+import com.oracle.graal.asm.AbstractAddress;
+import com.oracle.graal.asm.Label;
+import com.oracle.graal.asm.NumUtil;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+
+public class AArch64MacroAssembler extends AArch64Assembler {
+
+    private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(r8), new ScratchRegister(r9)};
+
+    // Points to the next free scratch register
+    private int nextFreeScratchRegister = 0;
+
+    public AArch64MacroAssembler(TargetDescription target) {
+        super(target);
+    }
+
+    public class ScratchRegister implements AutoCloseable {
+        private final Register register;
+
+        public ScratchRegister(Register register) {
+            this.register = register;
+        }
+
+        public Register getRegister() {
+            return register;
+        }
+
+        public void close() {
+            assert nextFreeScratchRegister > 0 : "Close called too often";
+            nextFreeScratchRegister--;
+        }
+    }
+
+    public ScratchRegister getScratchRegister() {
+        return scratchRegister[nextFreeScratchRegister++];
+    }
+
+    /**
+     * Specifies what actions have to be taken to turn an arbitrary address of the form
+     * {@code base + displacement [+ index [<< scale]]} into a valid AArch64Address.
+     */
+    public static class AddressGenerationPlan {
+        public final WorkPlan workPlan;
+        public final AArch64Address.AddressingMode addressingMode;
+        public final boolean needsScratch;
+
+        public enum WorkPlan {
+            /**
+             * Can be used as-is without extra work.
+             */
+            NO_WORK,
+            /**
+             * Add scaled displacement to index register.
+             */
+            ADD_TO_INDEX,
+            /**
+             * Add unscaled displacement to base register.
+             */
+            ADD_TO_BASE,
+        }
+
+        /**
+         * @param workPlan Work necessary to generate a valid address.
+         * @param addressingMode Addressing mode of generated address.
+         * @param needsScratch True if generating address needs a scatch register, false otherwise.
+         */
+        public AddressGenerationPlan(WorkPlan workPlan, AArch64Address.AddressingMode addressingMode, boolean needsScratch) {
+            this.workPlan = workPlan;
+            this.addressingMode = addressingMode;
+            this.needsScratch = needsScratch;
+        }
+    }
+
+    /**
+     * Generates an addressplan for an address of the form
+     * {@code base + displacement [+ index [<< log2(transferSize)]]} with the index register and
+     * scaling being optional.
+     *
+     * @param displacement an arbitrary displacement.
+     * @param hasIndexRegister true if the address uses an index register, false otherwise. non null
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8.
+     * @return AddressGenerationPlan that specifies the actions necessary to generate a valid
+     *         AArch64Address for the given parameters.
+     */
+    public static AddressGenerationPlan generateAddressPlan(long displacement, boolean hasIndexRegister, int transferSize) {
+        assert transferSize == 0 || transferSize == 1 || transferSize == 2 || transferSize == 4 || transferSize == 8;
+        boolean indexScaled = transferSize != 0;
+        int log2Scale = NumUtil.log2Ceil(transferSize);
+        long scaledDisplacement = displacement >> log2Scale;
+        boolean displacementScalable = indexScaled && (displacement & (transferSize - 1)) == 0;
+        if (displacement == 0) {
+            // register offset without any work beforehand.
+            return new AddressGenerationPlan(NO_WORK, REGISTER_OFFSET, false);
+        } else {
+            if (hasIndexRegister) {
+                if (displacementScalable) {
+                    boolean needsScratch = !isArithmeticImmediate(scaledDisplacement);
+                    return new AddressGenerationPlan(ADD_TO_INDEX, REGISTER_OFFSET, needsScratch);
+                } else {
+                    boolean needsScratch = !isArithmeticImmediate(displacement);
+                    return new AddressGenerationPlan(ADD_TO_BASE, REGISTER_OFFSET, needsScratch);
+                }
+            } else {
+                if (NumUtil.isSignedNbit(9, displacement)) {
+                    return new AddressGenerationPlan(NO_WORK, IMMEDIATE_UNSCALED, false);
+                } else if (displacementScalable && NumUtil.isUnsignedNbit(12, scaledDisplacement)) {
+                    return new AddressGenerationPlan(NO_WORK, IMMEDIATE_SCALED, false);
+                } else {
+                    boolean needsScratch = !isArithmeticImmediate(displacement);
+                    return new AddressGenerationPlan(ADD_TO_BASE, REGISTER_OFFSET, needsScratch);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns an AArch64Address pointing to
+     * {@code base + displacement + index << log2(transferSize)}.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @param index general purpose register. May not be null or the stack pointer.
+     * @param signExtendIndex if true consider index register a word register that should be
+     *            sign-extended before being added.
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8.
+     * @param additionalReg additional register used either as a scratch register or as part of the
+     *            final address, depending on whether allowOverwrite is true or not. May not be null
+     *            or stackpointer.
+     * @param allowOverwrite if true allows to change value of base or index register to generate
+     *            address.
+     * @return AArch64Address pointing to memory at
+     *         {@code base + displacement + index << log2(transferSize)}.
+     */
+    public AArch64Address makeAddress(Register base, long displacement, Register index, boolean signExtendIndex, int transferSize, Register additionalReg, boolean allowOverwrite) {
+        AddressGenerationPlan plan = generateAddressPlan(displacement, !index.equals(zr), transferSize);
+        assert allowOverwrite || !zr.equals(additionalReg) || plan.workPlan == NO_WORK;
+        assert !plan.needsScratch || !zr.equals(additionalReg);
+        int log2Scale = NumUtil.log2Ceil(transferSize);
+        long scaledDisplacement = displacement >> log2Scale;
+        Register newIndex = index;
+        Register newBase = base;
+        int immediate;
+        switch (plan.workPlan) {
+            case NO_WORK:
+                if (plan.addressingMode == IMMEDIATE_SCALED) {
+                    immediate = (int) scaledDisplacement;
+                } else {
+                    immediate = (int) displacement;
+                }
+                break;
+            case ADD_TO_INDEX:
+                newIndex = allowOverwrite ? index : additionalReg;
+                if (plan.needsScratch) {
+                    mov(additionalReg, scaledDisplacement);
+                    add(signExtendIndex ? 32 : 64, newIndex, index, additionalReg);
+                } else {
+                    add(signExtendIndex ? 32 : 64, newIndex, index, (int) scaledDisplacement);
+                }
+                immediate = 0;
+                break;
+            case ADD_TO_BASE:
+                newBase = allowOverwrite ? base : additionalReg;
+                if (plan.needsScratch) {
+                    mov(additionalReg, displacement);
+                    add(64, newBase, base, additionalReg);
+                } else {
+                    add(64, newBase, base, (int) displacement);
+                }
+                immediate = 0;
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+        AArch64Address.AddressingMode addressingMode = plan.addressingMode;
+        ExtendType extendType = null;
+        if (addressingMode == REGISTER_OFFSET) {
+            if (newIndex.equals(zr)) {
+                addressingMode = BASE_REGISTER_ONLY;
+            } else if (signExtendIndex) {
+                addressingMode = EXTENDED_REGISTER_OFFSET;
+                extendType = ExtendType.SXTW;
+            }
+        }
+        return AArch64Address.createAddress(addressingMode, newBase, newIndex, immediate, transferSize != 0, extendType);
+    }
+
+    /**
+     * Returns an AArch64Address pointing to {@code base + displacement}. Specifies the memory
+     * transfer size to allow some optimizations when building the address.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @param transferSize the memory transfer size in bytes.
+     * @param additionalReg additional register used either as a scratch register or as part of the
+     *            final address, depending on whether allowOverwrite is true or not. May not be
+     *            null, zero register or stackpointer.
+     * @param allowOverwrite if true allows to change value of base or index register to generate
+     *            address.
+     * @return AArch64Address pointing to memory at {@code base + displacement}.
+     */
+    public AArch64Address makeAddress(Register base, long displacement, Register additionalReg, int transferSize, boolean allowOverwrite) {
+        assert additionalReg.getRegisterCategory().equals(CPU);
+        return makeAddress(base, displacement, zr, /* sign-extend */false, transferSize, additionalReg, allowOverwrite);
+    }
+
+    /**
+     * Returns an AArch64Address pointing to {@code base + displacement}. Fails if address cannot be
+     * represented without overwriting base register or using a scratch register.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8.
+     * @return AArch64Address pointing to memory at {@code base + displacement}.
+     */
+    public AArch64Address makeAddress(Register base, long displacement, int transferSize) {
+        return makeAddress(base, displacement, zr, /* signExtend */false, transferSize, zr, /* allowOverwrite */false);
+    }
+
+    /**
+     * Loads memory address into register.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param address address whose value is loaded into dst. May not be null,
+     *            {@link com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode#IMMEDIATE_POST_INDEXED
+     *            POST_INDEXED} or
+     *            {@link com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode#IMMEDIATE_PRE_INDEXED
+     *            IMMEDIATE_PRE_INDEXED}
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. Can be 1, 2, 4 or 8.
+     */
+    public void loadAddress(Register dst, AArch64Address address, int transferSize) {
+        assert transferSize == 1 || transferSize == 2 || transferSize == 4 || transferSize == 8;
+        assert dst.getRegisterCategory().equals(CPU);
+        int shiftAmt = NumUtil.log2Ceil(transferSize);
+        switch (address.getAddressingMode()) {
+            case IMMEDIATE_SCALED:
+                int scaledImmediate = address.getImmediateRaw() << shiftAmt;
+                int lowerBits = scaledImmediate & NumUtil.getNbitNumberInt(12);
+                int higherBits = scaledImmediate & ~NumUtil.getNbitNumberInt(12);
+                boolean firstAdd = true;
+                if (lowerBits != 0) {
+                    add(64, dst, address.getBase(), lowerBits);
+                    firstAdd = false;
+                }
+                if (higherBits != 0) {
+                    Register src = firstAdd ? address.getBase() : dst;
+                    add(64, dst, src, higherBits);
+                }
+                break;
+            case IMMEDIATE_UNSCALED:
+                int immediate = address.getImmediateRaw();
+                add(64, dst, address.getBase(), immediate);
+                break;
+            case REGISTER_OFFSET:
+                add(64, dst, address.getBase(), address.getOffset(), ShiftType.LSL, address.isScaled() ? shiftAmt : 0);
+                break;
+            case EXTENDED_REGISTER_OFFSET:
+                add(64, dst, address.getBase(), address.getOffset(), address.getExtendType(), address.isScaled() ? shiftAmt : 0);
+                break;
+            case PC_LITERAL:
+                super.adr(dst, address.getImmediateRaw());
+                break;
+            case BASE_REGISTER_ONLY:
+                movx(dst, address.getBase());
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    public void movx(Register dst, Register src) {
+        mov(64, dst, src);
+    }
+
+    public void mov(int size, Register dst, Register src) {
+        if (dst.equals(src)) {
+            return;
+        }
+        if (dst.equals(sp) || src.equals(sp)) {
+            add(size, dst, src, 0);
+        } else {
+            or(size, dst, src, zr);
+        }
+    }
+
+    /**
+     * Generates a move 64-bit immediate code sequence. The immediate may later be updated by
+     * HotSpot.
+     *
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param imm
+     */
+    public void forceMov(Register dst, long imm, boolean optimize) {
+        // We have to move all non zero parts of the immediate in 16-bit chunks
+        boolean firstMove = true;
+        for (int offset = 0; offset < 64; offset += 16) {
+            int chunk = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16);
+            if (optimize && chunk == 0) {
+                continue;
+            }
+            if (firstMove) {
+                movz(64, dst, chunk, offset);
+                firstMove = false;
+            } else {
+                movk(64, dst, chunk, offset);
+            }
+        }
+        assert !firstMove;
+    }
+
+    public void forceMov(Register dst, long imm) {
+        forceMov(dst, imm, /* optimize */false);
+    }
+
+    /**
+     * Generates a move 64-bit immediate code sequence. The immediate may later be updated by
+     * HotSpot.
+     *
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     */
+    public void forceMov(Register dst, int imm) {
+        forceMov(dst, imm & 0xFFFF_FFFFL);
+    }
+
+    /**
+     * Loads immediate into register.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm immediate loaded into register.
+     */
+    public void mov(Register dst, long imm) {
+        assert dst.getRegisterCategory().equals(CPU);
+        if (imm == 0L) {
+            movx(dst, zr);
+        } else if (LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) {
+            or(64, dst, zr, imm);
+        } else if (imm >> 32 == -1L && (int) imm < 0 && LogicalImmediateTable.isRepresentable((int) imm) != LogicalImmediateTable.Representable.NO) {
+            // If the higher 32-bit are 1s and the sign bit of the lower 32-bits is set *and* we can
+            // represent the lower 32 bits as a logical immediate we can create the lower 32-bit and
+            // then sign extend
+            // them. This allows us to cover immediates like ~1L with 2 instructions.
+            mov(dst, (int) imm);
+            sxt(64, 32, dst, dst);
+        } else {
+            forceMov(dst, imm, /* optimize move */true);
+        }
+    }
+
+    /**
+     * Loads immediate into register.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm immediate loaded into register.
+     */
+    public void mov(Register dst, int imm) {
+        mov(dst, imm & 0xFFFF_FFFFL);
+    }
+
+    /**
+     * @return Number of instructions necessary to load immediate into register.
+     */
+    public static int nrInstructionsToMoveImmediate(long imm) {
+        if (imm == 0L || LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) {
+            return 1;
+        }
+        if (imm >> 32 == -1L && (int) imm < 0 && LogicalImmediateTable.isRepresentable((int) imm) != LogicalImmediateTable.Representable.NO) {
+            // If the higher 32-bit are 1s and the sign bit of the lower 32-bits is set *and* we can
+            // represent the lower 32 bits as a logical immediate we can create the lower 32-bit and
+            // then sign extend
+            // them. This allows us to cover immediates like ~1L with 2 instructions.
+            return 2;
+        }
+        int nrInstructions = 0;
+        for (int offset = 0; offset < 64; offset += 16) {
+            int part = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16);
+            if (part != 0) {
+                nrInstructions++;
+            }
+        }
+        return nrInstructions;
+    }
+
+    /**
+     * Loads a srcSize value from address into rt sign-extending it if necessary.
+     *
+     * @param targetSize size of target register in bits. Must be 32 or 64.
+     * @param srcSize size of memory read in bits. Must be 8, 16 or 32 and smaller or equal to
+     *            targetSize.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    @Override
+    public void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) {
+        assert targetSize == 32 || targetSize == 64;
+        assert srcSize <= targetSize;
+        if (targetSize == srcSize) {
+            super.ldr(srcSize, rt, address);
+        } else {
+            super.ldrs(targetSize, srcSize, rt, address);
+        }
+    }
+
+    /**
+     * Conditional move. dst = src1 if condition else src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param result general purpose register. May not be null or the stackpointer.
+     * @param trueValue general purpose register. May not be null or the stackpointer.
+     * @param falseValue general purpose register. May not be null or the stackpointer.
+     * @param cond any condition flag. May not be null.
+     */
+    public void cmov(int size, Register result, Register trueValue, Register falseValue, ConditionFlag cond) {
+        super.csel(size, result, trueValue, falseValue, cond);
+    }
+
+    /**
+     * Conditional set. dst = 1 if condition else 0.
+     *
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param condition any condition. May not be null.
+     */
+    public void cset(Register dst, ConditionFlag condition) {
+        super.csinc(32, dst, zr, zr, condition.negate());
+    }
+
+    /**
+     * dst = src1 + src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void add(int size, Register dst, Register src1, Register src2) {
+        super.add(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 + src2 and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void adds(int size, Register dst, Register src1, Register src2) {
+        super.adds(size, dst, src1, src2, getNopExtendType(size), 0);
+    }
+
+    /**
+     * dst = src1 - src2 and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void subs(int size, Register dst, Register src1, Register src2) {
+        super.subs(size, dst, src1, src2, getNopExtendType(size), 0);
+    }
+
+    /**
+     * Returns the ExtendType for the given size that corresponds to a no-op.
+     *
+     * I.e. when doing add X0, X1, X2, the actual instruction has the form add X0, X1, X2 UXTX.
+     *
+     * @param size
+     */
+    private static ExtendType getNopExtendType(int size) {
+        if (size == 64) {
+            return ExtendType.UXTX;
+        } else if (size == 32) {
+            return ExtendType.UXTW;
+        } else {
+            throw JVMCIError.shouldNotReachHere("No-op ");
+        }
+    }
+
+    /**
+     * dst = src1 - src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void sub(int size, Register dst, Register src1, Register src2) {
+        super.sub(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 + shiftType(src2, shiftAmt & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param shiftAmt arbitrary shift amount.
+     */
+    @Override
+    public void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.add(size, dst, src1, src2, shiftType, shift);
+    }
+
+    /**
+     * dst = src1 + shiftType(src2, shiftAmt & (size-1)) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param shiftAmt arbitrary shift amount.
+     */
+    @Override
+    public void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.sub(size, dst, src1, src2, shiftType, shift);
+    }
+
+    /**
+     * dst = -src1.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     */
+    public void neg(int size, Register dst, Register src) {
+        sub(size, dst, zr, src);
+    }
+
+    /**
+     * dst = src + immediate.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param immediate arithmetic immediate
+     */
+    @Override
+    public void add(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            sub(size, dst, src, -immediate);
+        } else if (!(dst.equals(src) && immediate == 0)) {
+            super.add(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src + aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param immediate arithmetic immediate.
+     */
+    @Override
+    public void adds(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            subs(size, dst, src, -immediate);
+        } else if (!(dst.equals(src) && immediate == 0)) {
+            super.adds(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src - immediate.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param immediate arithmetic immediate
+     */
+    @Override
+    public void sub(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            add(size, dst, src, -immediate);
+        } else if (!dst.equals(src) || immediate != 0) {
+            super.sub(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src - aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param immediate arithmetic immediate.
+     */
+    @Override
+    public void subs(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            adds(size, dst, src, -immediate);
+        } else if (!dst.equals(src) || immediate != 0) {
+            super.sub(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src1 * src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void mul(int size, Register dst, Register src1, Register src2) {
+        super.madd(size, dst, src1, src2, zr);
+    }
+
+    /**
+     * unsigned multiply high. dst = (src1 * src2) >> size
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void umulh(int size, Register dst, Register src1, Register src2) {
+        assert size == 32 || size == 64;
+        if (size == 64) {
+            super.umulh(dst, src1, src2);
+        } else {
+            // xDst = wSrc1 * wSrc2
+            super.umaddl(dst, src1, src2, zr);
+            // xDst = xDst >> 32
+            lshr(64, dst, dst, 32);
+        }
+    }
+
+    /**
+     * signed multiply high. dst = (src1 * src2) >> size
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void smulh(int size, Register dst, Register src1, Register src2) {
+        assert size == 32 || size == 64;
+        if (size == 64) {
+            super.smulh(dst, src1, src2);
+        } else {
+            // xDst = wSrc1 * wSrc2
+            super.smaddl(dst, src1, src2, zr);
+            // xDst = xDst >> 32
+            lshr(64, dst, dst, 32);
+        }
+    }
+
+    /**
+     * dst = src1 % src2. Signed.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param n numerator. General purpose register. May not be null or the stackpointer.
+     * @param d denominator. General purpose register. Divisor May not be null or the stackpointer.
+     */
+    public void rem(int size, Register dst, Register n, Register d) {
+        // There is no irem or similar instruction. Instead we use the relation:
+        // n % d = n - Floor(n / d) * d if nd >= 0
+        // n % d = n - Ceil(n / d) * d else
+        // Which is equivalent to n - TruncatingDivision(n, d) * d
+        super.sdiv(size, dst, n, d);
+        super.msub(size, dst, dst, d, n);
+    }
+
+    /**
+     * dst = src1 % src2. Unsigned.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param n numerator. General purpose register. May not be null or the stackpointer.
+     * @param d denominator. General purpose register. Divisor May not be null or the stackpointer.
+     */
+    public void urem(int size, Register dst, Register n, Register d) {
+        // There is no irem or similar instruction. Instead we use the relation:
+        // n % d = n - Floor(n / d) * d
+        // Which is equivalent to n - TruncatingDivision(n, d) * d
+        super.udiv(size, dst, n, d);
+        super.msub(size, dst, dst, d, n);
+    }
+
+    /**
+     * @return True if immediate can be used directly for arithmetic instructions (add/sub), false
+     *         otherwise.
+     */
+    public static boolean isArithmeticImmediate(long imm) {
+        // If we have a negative immediate we just use the opposite operator. I.e.: x - (-5) == x +
+        // 5.
+        return NumUtil.isInt(Math.abs(imm)) && isAimm((int) Math.abs(imm));
+    }
+
+    /**
+     * @return True if immediate can be used directly with comparison instructions, false otherwise.
+     */
+    public static boolean isComparisonImmediate(long imm) {
+        return isArithmeticImmediate(imm);
+    }
+
+    /**
+     * @return True if immediate can be moved directly into a register, false otherwise.
+     */
+    public static boolean isMovableImmediate(long imm) {
+        // Moves allow a 16bit immediate value that can be shifted by multiples of 16.
+        // Positions of first, respectively last set bit.
+        int start = Long.numberOfTrailingZeros(imm);
+        int end = 64 - Long.numberOfLeadingZeros(imm);
+        int length = end - start;
+        if (length > 16) {
+            return false;
+        }
+        // We can shift the necessary part of the immediate (i.e. everything between the first and
+        // last set bit) by as much as 16 - length around to arrive at a valid shift amount
+        int tolerance = 16 - length;
+        int prevMultiple = NumUtil.roundDown(start, 16);
+        int nextMultiple = NumUtil.roundUp(start, 16);
+        return start - prevMultiple <= tolerance || nextMultiple - start <= tolerance;
+    }
+
+    /**
+     * dst = src << (shiftAmt & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param shiftAmt amount by which src is shifted.
+     */
+    public void shl(int size, Register dst, Register src, long shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.ubfm(size, dst, src, (size - shift) & (size - 1), size - 1 - shift);
+    }
+
+    /**
+     * dst = src1 << (src2 & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param shift general purpose register. May not be null or stackpointer.
+     */
+    public void shl(int size, Register dst, Register src, Register shift) {
+        super.lsl(size, dst, src, shift);
+    }
+
+    /**
+     * dst = src >>> (shiftAmt & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param shiftAmt amount by which src is shifted.
+     */
+    public void lshr(int size, Register dst, Register src, long shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.ubfm(size, dst, src, shift, size - 1);
+    }
+
+    /**
+     * dst = src1 >>> (src2 & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param shift general purpose register. May not be null or stackpointer.
+     */
+    public void lshr(int size, Register dst, Register src, Register shift) {
+        super.lsr(size, dst, src, shift);
+    }
+
+    /**
+     * dst = src >> (shiftAmt & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param shiftAmt amount by which src is shifted.
+     */
+    public void ashr(int size, Register dst, Register src, long shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.sbfm(size, dst, src, shift, size - 1);
+    }
+
+    /**
+     * dst = src1 >> (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param shift general purpose register. May not be null or stackpointer.
+     */
+    public void ashr(int size, Register dst, Register src, Register shift) {
+        super.asr(size, dst, src, shift);
+    }
+
+    /**
+     * Clamps shiftAmt into range 0 <= shiftamt < size according to JLS.
+     *
+     * @param size size of operation.
+     * @param shiftAmt arbitrary shift amount.
+     * @return value between 0 and size - 1 inclusive that is equivalent to shiftAmt according to
+     *         JLS.
+     */
+    private static int clampShiftAmt(int size, long shiftAmt) {
+        return (int) (shiftAmt & (size - 1));
+    }
+
+    /**
+     * dst = src1 & src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void and(int size, Register dst, Register src1, Register src2) {
+        super.and(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 ^ src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void eor(int size, Register dst, Register src1, Register src2) {
+        super.eor(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 | src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void or(int size, Register dst, Register src1, Register src2) {
+        super.orr(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src | bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link AArch64Assembler.LogicalImmediateTable} for exact
+     *            definition.
+     */
+    public void or(int size, Register dst, Register src, long bimm) {
+        super.orr(size, dst, src, bimm);
+    }
+
+    /**
+     * dst = ~src.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     */
+    public void not(int size, Register dst, Register src) {
+        super.orn(size, dst, zr, src, ShiftType.LSL, 0);
+    }
+
+    /**
+     * Sign-extend value from src into dst.
+     *
+     * @param destSize destination register size. Has to be 32 or 64.
+     * @param srcSize source register size. May be 8, 16 or 32 and smaller than destSize.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     */
+    public void sxt(int destSize, int srcSize, Register dst, Register src) {
+        assert (destSize == 32 || destSize == 64) && srcSize < destSize;
+        assert srcSize == 8 || srcSize == 16 || srcSize == 32;
+        int[] srcSizeValues = {7, 15, 31};
+        super.sbfm(destSize, dst, src, 0, srcSizeValues[NumUtil.log2Ceil(srcSize / 8)]);
+    }
+
+    /**
+     * dst = src if condition else -src.
+     *
+     * @param size register size. Must be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src general purpose register. May not be null or the stackpointer.
+     * @param condition any condition except AV or NV. May not be null.
+     */
+    public void csneg(int size, Register dst, Register src, ConditionFlag condition) {
+        super.csneg(size, dst, src, src, condition.negate());
+    }
+
+    /**
+     * @return True if the immediate can be used directly for logical 64-bit instructions.
+     */
+    public static boolean isLogicalImmediate(long imm) {
+        return LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO;
+    }
+
+    /**
+     * @return True if the immediate can be used directly for logical 32-bit instructions.
+     */
+    public static boolean isLogicalImmediate(int imm) {
+        return LogicalImmediateTable.isRepresentable(imm) == LogicalImmediateTable.Representable.YES;
+    }
+
+    /* Float instructions */
+
+    /**
+     * Moves integer to float, float to integer, or float to float. Does not support integer to
+     * integer moves.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst Either floating-point or general-purpose register. If general-purpose register may
+     *            not be stackpointer or zero register. Cannot be null in any case.
+     * @param src Either floating-point or general-purpose register. If general-purpose register may
+     *            not be stackpointer. Cannot be null in any case.
+     */
+    @Override
+    public void fmov(int size, Register dst, Register src) {
+        assert !(dst.getRegisterCategory().equals(CPU) && src.getRegisterCategory().equals(CPU)) : "src and dst cannot both be integer registers.";
+        if (dst.equals(src)) {
+            return;
+        }
+        if (dst.getRegisterCategory().equals(CPU)) {
+            super.fmovFpu2Cpu(size, dst, src);
+        } else if (src.getRegisterCategory().equals(CPU)) {
+            super.fmovCpu2Fpu(size, dst, src);
+        } else {
+            super.fmov(size, dst, src);
+        }
+    }
+
+    /**
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be
+     *            loaded, i.e. (float) imm == imm must be true. In all cases
+     *            {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true
+     *            depending on size.
+     */
+    @Override
+    public void fmov(int size, Register dst, double imm) {
+        if (imm == 0.0) {
+            assert Double.doubleToRawLongBits(imm) == 0L : "-0.0 is no valid immediate.";
+            super.fmovCpu2Fpu(size, dst, zr);
+        } else {
+            super.fmov(size, dst, imm);
+        }
+    }
+
+    /**
+     *
+     * @return true if immediate can be loaded directly into floating-point register, false
+     *         otherwise.
+     */
+    public static boolean isDoubleImmediate(double imm) {
+        return Double.doubleToRawLongBits(imm) == 0L || AArch64Assembler.isDoubleImmediate(imm);
+    }
+
+    /**
+     *
+     * @return true if immediate can be loaded directly into floating-point register, false
+     *         otherwise.
+     */
+    public static boolean isFloatImmediate(float imm) {
+        return Float.floatToRawIntBits(imm) == 0 || AArch64Assembler.isFloatImmediate(imm);
+    }
+
+    /**
+     * Conditional move. dst = src1 if condition else src2.
+     *
+     * @param size register size.
+     * @param result floating point register. May not be null.
+     * @param trueValue floating point register. May not be null.
+     * @param falseValue floating point register. May not be null.
+     * @param condition every condition allowed. May not be null.
+     */
+    public void fcmov(int size, Register result, Register trueValue, Register falseValue, ConditionFlag condition) {
+        super.fcsel(size, result, trueValue, falseValue, condition);
+    }
+
+    /**
+     * dst = src1 % src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating-point register. May not be null.
+     * @param n numerator. Floating-point register. May not be null.
+     * @param d denominator. Floating-point register. May not be null.
+     */
+    public void frem(int size, Register dst, Register n, Register d) {
+        // There is no frem instruction, instead we compute the remainder using the relation:
+        // rem = n - Truncating(n / d) * d
+        super.fdiv(size, dst, n, d);
+        super.frintz(size, dst, dst);
+        super.fmsub(size, dst, dst, d, n);
+    }
+
+    /* Branches */
+
+    /**
+     * Compares x and y and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param x general purpose register. May not be null or stackpointer.
+     * @param y general purpose register. May not be null or stackpointer.
+     */
+    public void cmp(int size, Register x, Register y) {
+        super.subs(size, zr, x, y, ShiftType.LSL, 0);
+    }
+
+    /**
+     * Compares x to y and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param x general purpose register. May not be null or stackpointer.
+     * @param y comparison immediate, {@link #isComparisonImmediate(long)} has to be true for it.
+     */
+    public void cmp(int size, Register x, int y) {
+        if (y < 0) {
+            super.adds(size, zr, x, -y);
+        } else {
+            super.subs(size, zr, x, y);
+        }
+    }
+
+    /**
+     * Sets condition flags according to result of x & y.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stack-pointer.
+     * @param x general purpose register. May not be null or stackpointer.
+     * @param y general purpose register. May not be null or stackpointer.
+     */
+    public void ands(int size, Register dst, Register x, Register y) {
+        super.ands(size, dst, x, y, ShiftType.LSL, 0);
+    }
+
+    /**
+     * When patching up Labels we have to know what kind of code to generate.
+     */
+    public enum PatchLabelKind {
+        BRANCH_CONDITIONALLY(0x0),
+        BRANCH_UNCONDITIONALLY(0x1),
+        BRANCH_NONZERO(0x2),
+        BRANCH_ZERO(0x3),
+        JUMP_ADDRESS(0x4);
+
+        /**
+         * Offset by which additional information for branch conditionally, branch zero and branch
+         * non zero has to be shifted.
+         */
+        public static final int INFORMATION_OFFSET = 5;
+
+        public final int encoding;
+
+        private PatchLabelKind(int encoding) {
+            this.encoding = encoding;
+        }
+
+        /**
+         * @return PatchLabelKind with given encoding.
+         */
+        private static PatchLabelKind fromEncoding(int encoding) {
+            return values()[encoding & NumUtil.getNbitNumberInt(INFORMATION_OFFSET)];
+        }
+
+    }
+
+    /**
+     * Compare register and branch if non-zero.
+     *
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param cmp general purpose register. May not be null, zero-register or stackpointer.
+     * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null.
+     */
+    public void cbnz(int size, Register cmp, Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.cbnz(size, cmp, offset);
+        } else {
+            label.addPatchAt(position());
+            int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 1);
+            int sizeEncoding = (size == 64 ? 1 : 0) << PatchLabelKind.INFORMATION_OFFSET;
+            // Encode condition flag so that we know how to patch the instruction later
+            emitInt(PatchLabelKind.BRANCH_NONZERO.encoding | regEncoding | sizeEncoding);
+        }
+    }
+
+    /**
+     * Compare register and branch if zero.
+     *
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param cmp general purpose register. May not be null, zero-register or stackpointer.
+     * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null.
+     */
+    public void cbz(int size, Register cmp, Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.cbz(size, cmp, offset);
+        } else {
+            label.addPatchAt(position());
+            int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 1);
+            int sizeEncoding = (size == 64 ? 1 : 0) << PatchLabelKind.INFORMATION_OFFSET;
+            // Encode condition flag so that we know how to patch the instruction later
+            emitInt(PatchLabelKind.BRANCH_ZERO.encoding | regEncoding | sizeEncoding);
+        }
+    }
+
+    /**
+     * Branches to label if condition is true.
+     *
+     * @param condition any condition value allowed. Non null.
+     * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null.
+     */
+    public void branchConditionally(ConditionFlag condition, Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.b(condition, offset);
+        } else {
+            label.addPatchAt(position());
+            // Encode condition flag so that we know how to patch the instruction later
+            emitInt(PatchLabelKind.BRANCH_CONDITIONALLY.encoding | condition.encoding << PatchLabelKind.INFORMATION_OFFSET);
+        }
+    }
+
+    /**
+     * Branches if condition is true. Address of jump is patched up by HotSpot c++ code.
+     *
+     * @param condition any condition value allowed. Non null.
+     */
+    public void branchConditionally(ConditionFlag condition) {
+        // Correct offset is fixed up by HotSpot later.
+        super.b(condition, 0);
+    }
+
+    /**
+     * Jumps to label.
+     *
+     * param label Can only handle signed 28-bit offsets. May be unbound. Non null.
+     */
+    @Override
+    public void jmp(Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.b(offset);
+        } else {
+            label.addPatchAt(position());
+            emitInt(PatchLabelKind.BRANCH_UNCONDITIONALLY.encoding);
+        }
+    }
+
+    /**
+     * Jump to address in dest.
+     *
+     * @param dest General purpose register. May not be null, zero-register or stackpointer.
+     */
+    public void jmp(Register dest) {
+        super.br(dest);
+    }
+
+    /**
+     * Immediate jump instruction fixed up by HotSpot c++ code.
+     */
+    public void jmp() {
+        // Offset has to be fixed up by c++ code.
+        super.b(0);
+    }
+
+    /**
+     *
+     * @return true if immediate offset can be used in a single branch instruction.
+     */
+    public static boolean isBranchImmediateOffset(long imm) {
+        return NumUtil.isSignedNbit(28, imm);
+    }
+
+    /* system instructions */
+
+    /**
+     * Exception codes used when calling hlt instruction.
+     */
+    public enum AArch64ExceptionCode {
+        NO_SWITCH_TARGET(0x0),
+        BREAKPOINT(0x1);
+
+        public final int encoding;
+
+        private AArch64ExceptionCode(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    /**
+     * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as
+     * UNALLOCATED instruction.
+     *
+     * @param exceptionCode exception code specifying why halt was called. Non null.
+     */
+    public void hlt(AArch64ExceptionCode exceptionCode) {
+        super.hlt(exceptionCode.encoding);
+    }
+
+    /**
+     * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher
+     * exception level.
+     *
+     * @param exceptionCode exception code specifying why break was called. Non null.
+     */
+    public void brk(AArch64ExceptionCode exceptionCode) {
+        super.brk(exceptionCode.encoding);
+    }
+
+    public void pause() {
+        throw JVMCIError.unimplemented();
+    }
+
+    /**
+     * Executes no-op instruction. No registers or flags are updated, except for PC.
+     */
+    public void nop() {
+        super.hint(SystemHint.NOP);
+    }
+
+    /**
+     * Same as {@link #nop()}.
+     */
+    @Override
+    public void ensureUniquePC() {
+        nop();
+    }
+
+    /**
+     * Aligns PC.
+     *
+     * @param modulus Has to be positive multiple of 4.
+     */
+    @Override
+    public void align(int modulus) {
+        assert modulus > 0 && (modulus & 0x3) == 0 : "Modulus has to be a positive multiple of 4.";
+        if (position() % modulus == 0) {
+            return;
+        }
+        int offset = modulus - position() % modulus;
+        for (int i = 0; i < offset; i += 4) {
+            nop();
+        }
+    }
+
+    /**
+     * Patches jump targets when label gets bound.
+     */
+    @Override
+    protected void patchJumpTarget(int branch, int jumpTarget) {
+        int instruction = getInt(branch);
+        int branchOffset = jumpTarget - branch;
+        PatchLabelKind type = PatchLabelKind.fromEncoding(instruction);
+        switch (type) {
+            case BRANCH_CONDITIONALLY:
+                ConditionFlag cf = ConditionFlag.fromEncoding(instruction >>> PatchLabelKind.INFORMATION_OFFSET);
+                super.b(cf, branchOffset, /* pos */branch);
+                break;
+            case BRANCH_UNCONDITIONALLY:
+                super.b(branchOffset, /* pos */branch);
+                break;
+            case JUMP_ADDRESS:
+                emitInt(jumpTarget, /* pos */branch);
+                break;
+            case BRANCH_NONZERO:
+            case BRANCH_ZERO:
+                int information = instruction >>> PatchLabelKind.INFORMATION_OFFSET;
+                int sizeEncoding = information & 1;
+                int regEncoding = information >>> 1;
+                Register reg = AArch64.cpuRegisters[regEncoding];
+                // 1 => 64; 0 => 32
+                int size = sizeEncoding * 32 + 32;
+                switch (type) {
+                    case BRANCH_NONZERO:
+                        super.cbnz(size, reg, branchOffset, /* pos */branch);
+                        break;
+                    case BRANCH_ZERO:
+                        super.cbz(size, reg, branchOffset, /* pos */branch);
+                        break;
+                }
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Generates an address of the form {@code base + displacement}.
+     *
+     * Does not change base register to fulfil this requirement. Will fail if displacement cannot be
+     * represented directly as address.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @return AArch64Address referencing memory at {@code base + displacement}.
+     */
+    @Override
+    public AArch64Address makeAddress(Register base, int displacement) {
+        return makeAddress(base, displacement, zr, /* signExtend */false, /* transferSize */0, zr, /* allowOverwrite */false);
+    }
+
+    @Override
+    public AbstractAddress getPlaceholder() {
+        return AArch64Address.PLACEHOLDER;
+    }
+}
--- a/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -36,7 +36,7 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.runtime.JVMCI;
 import jdk.vm.ci.runtime.JVMCIBackend;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import org.junit.Assert;
 
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/NumUtil.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/NumUtil.java	Tue Jan 05 16:42:05 2016 -0800
@@ -113,4 +113,74 @@
     public static long roundUp(long number, long mod) {
         return ((number + mod - 1L) / mod) * mod;
     }
+
+    public static int roundDown(int number, int mod) {
+        return number / mod * mod;
+    }
+
+    public static long roundDown(long number, long mod) {
+        return number / mod * mod;
+    }
+
+    public static int log2Ceil(int val) {
+        int x = 1;
+        int log2 = 0;
+        while (x < val) {
+            log2++;
+            x *= 2;
+        }
+        return log2;
+    }
+
+    public static boolean isUnsignedNbit(int n, int value) {
+        assert n > 0 && n < 32;
+        return 32 - Integer.numberOfLeadingZeros(value) <= n;
+    }
+
+    public static boolean isUnsignedNbit(int n, long value) {
+        assert n > 0 && n < 64;
+        return 64 - Long.numberOfLeadingZeros(value) <= n;
+    }
+
+    public static boolean isSignedNbit(int n, int value) {
+        assert n > 0 && n < 32;
+        int min = -(1 << (n - 1));
+        int max = (1 << (n - 1)) - 1;
+        return value >= min && value <= max;
+    }
+
+    public static boolean isSignedNbit(int n, long value) {
+        assert n > 0 && n < 64;
+        long min = -(1L << (n - 1));
+        long max = (1L << (n - 1)) - 1;
+        return value >= min && value <= max;
+    }
+
+    /**
+     *
+     * @param n Number of bits that should be set to 1. Must be between 0 and 32 (inclusive).
+     * @return A number with n bits set to 1.
+     */
+    public static int getNbitNumberInt(int n) {
+        assert n >= 0 && n <= 32 : "0 <= n <= 32; instead: " + n;
+        if (n < 32) {
+            return (1 << n) - 1;
+        } else {
+            return 0xFFFFFFFF;
+        }
+    }
+
+    /**
+     *
+     * @param n Number of bits that should be set to 1. Must be between 0 and 64 (inclusive).
+     * @return A number with n bits set to 1.
+     */
+    public static long getNbitNumberLong(int n) {
+        assert n >= 0 && n <= 64;
+        if (n < 64) {
+            return (1L << n) - 1;
+        } else {
+            return 0xFFFFFFFFFFFFFFFFL;
+        }
+    }
 }
--- a/graal/com.oracle.graal.code/src/com/oracle/graal/code/HexCodeFileDisassemblerProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.code/src/com/oracle/graal/code/HexCodeFileDisassemblerProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -39,7 +39,8 @@
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterConfig;
 import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.service.ServiceProvider;
+
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 /**
  * {@link HexCodeFile} based implementation of {@link DisassemblerProvider}.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64AddressLowering.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015, 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 com.oracle.graal.compiler.aarch64;
+
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.memory.address.AddressNode;
+import com.oracle.graal.phases.common.AddressLoweringPhase.AddressLowering;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.JavaConstant;
+
+public class AArch64AddressLowering extends AddressLowering {
+
+    private final CodeCacheProvider codeCache;
+
+    public AArch64AddressLowering(CodeCacheProvider codeCache) {
+        this.codeCache = codeCache;
+    }
+
+    @Override
+    public AddressNode lower(ValueNode address) {
+        return lower(address, null);
+    }
+
+    @Override
+    public AddressNode lower(ValueNode base, ValueNode offset) {
+        asImmediate(base);
+        throw JVMCIError.unimplemented();
+    }
+
+    private JavaConstant asImmediate(ValueNode value) {
+        JavaConstant c = value.asJavaConstant();
+        if (c != null && c.getJavaKind().isNumericInteger() && !codeCache.needsDataPatch(c)) {
+            return c;
+        } else {
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64ArithmeticLIRGenerator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2015, 2015, 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 com.oracle.graal.compiler.aarch64;
+
+import static com.oracle.graal.lir.LIRValueUtil.asJavaConstant;
+import static com.oracle.graal.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64Kind.DWORD;
+import static jdk.vm.ci.aarch64.AArch64Kind.QWORD;
+
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.compiler.common.calc.FloatConvert;
+import com.oracle.graal.lir.ConstantValue;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.aarch64.AArch64AddressValue;
+import com.oracle.graal.lir.aarch64.AArch64ArithmeticLIRGeneratorTool;
+import com.oracle.graal.lir.aarch64.AArch64ArithmeticOp;
+import com.oracle.graal.lir.aarch64.AArch64BitManipulationOp;
+import com.oracle.graal.lir.aarch64.AArch64Move.LoadOp;
+import com.oracle.graal.lir.aarch64.AArch64Move.StoreConstantOp;
+import com.oracle.graal.lir.aarch64.AArch64Move.StoreOp;
+import com.oracle.graal.lir.aarch64.AArch64ReinterpretOp;
+import com.oracle.graal.lir.aarch64.AArch64SignExtendOp;
+import com.oracle.graal.lir.gen.ArithmeticLIRGenerator;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implements AArch64ArithmeticLIRGeneratorTool {
+
+    @Override
+    public AArch64LIRGenerator getLIRGen() {
+        return (AArch64LIRGenerator) super.getLIRGen();
+    }
+
+    @Override
+    protected boolean isNumericInteger(PlatformKind kind) {
+        return ((AArch64Kind) kind).isInteger();
+    }
+
+    @Override
+    protected Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
+        if (isNumericInteger(a.getPlatformKind())) {
+            AArch64ArithmeticOp op = setFlags ? AArch64ArithmeticOp.ADDS : AArch64ArithmeticOp.ADD;
+            return emitBinary(resultKind, op, true, a, b);
+        } else {
+            assert !setFlags : "Cannot set flags on floating point arithmetic";
+            return emitBinary(resultKind, AArch64ArithmeticOp.FADD, true, a, b);
+        }
+    }
+
+    @Override
+    protected Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
+        if (isNumericInteger(a.getPlatformKind())) {
+            AArch64ArithmeticOp op = setFlags ? AArch64ArithmeticOp.SUBS : AArch64ArithmeticOp.SUB;
+            return emitBinary(resultKind, op, false, a, b);
+        } else {
+            assert !setFlags : "Cannot set flags on floating point arithmetic";
+            return emitBinary(resultKind, AArch64ArithmeticOp.FSUB, false, a, b);
+        }
+    }
+
+    @Override
+    public Value emitMul(Value a, Value b, boolean setFlags) {
+        // TODO (das) setFlags handling - should be handled higher up. Ask for ideas at mailing list
+        assert !setFlags : "Set flags on multiplication is not supported";
+        return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.MUL, AArch64ArithmeticOp.FMUL), true, a, b);
+    }
+
+    @Override
+    public Value emitMulHigh(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.SMULH, true, a, b);
+    }
+
+    @Override
+    public Value emitUMulHigh(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UMULH, true, a, b);
+    }
+
+    @Override
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
+        return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.DIV, AArch64ArithmeticOp.FDIV), false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
+        return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.REM, AArch64ArithmeticOp.FREM), false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitUDiv(Value a, Value b, LIRFrameState state) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UDIV, false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitURem(Value a, Value b, LIRFrameState state) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UREM, false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitAnd(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.AND, true, a, b);
+    }
+
+    @Override
+    public Value emitOr(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.OR, true, a, b);
+    }
+
+    @Override
+    public Value emitXor(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.XOR, true, a, b);
+    }
+
+    @Override
+    public Value emitShl(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.SHL, false, a, b);
+    }
+
+    @Override
+    public Value emitShr(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.ASHR, false, a, b);
+    }
+
+    @Override
+    public Value emitUShr(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.LSHR, false, a, b);
+    }
+
+    @Override
+    public Value emitFloatConvert(FloatConvert op, Value inputVal) {
+        PlatformKind resultPlatformKind = getFloatConvertResultKind(op);
+        LIRKind resultLirKind = LIRKind.combine(inputVal).changeType(resultPlatformKind);
+        Variable result = getLIRGen().newVariable(resultLirKind);
+        getLIRGen().append(new AArch64FloatConvertOp(op, result, getLIRGen().asAllocatable(inputVal)));
+        return result;
+    }
+
+    private static PlatformKind getFloatConvertResultKind(FloatConvert op) {
+        switch (op) {
+            case F2I:
+            case D2I:
+                return AArch64Kind.DWORD;
+            case F2L:
+            case D2L:
+                return AArch64Kind.QWORD;
+            case I2F:
+            case L2F:
+            case D2F:
+                return AArch64Kind.SINGLE;
+            case I2D:
+            case L2D:
+            case F2D:
+                return AArch64Kind.DOUBLE;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Value emitReinterpret(LIRKind to, Value inputVal) {
+        LIRKind from = inputVal.getLIRKind();
+        if (to.equals(from)) {
+            return inputVal;
+        }
+        Variable result = getLIRGen().newVariable(to);
+        getLIRGen().append(new AArch64ReinterpretOp(result, getLIRGen().asAllocatable(inputVal)));
+        return result;
+    }
+
+    @Override
+    public Value emitNarrow(Value inputVal, int bits) {
+        assert inputVal.getPlatformKind() == AArch64Kind.QWORD && bits == 32 : "Can only convert from long to int";
+        LIRKind resultKind = getResultLirKind(bits, inputVal);
+        long mask = NumUtil.getNbitNumberLong(bits);
+        Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask));
+        return emitBinary(resultKind, AArch64ArithmeticOp.AND, true, inputVal, maskValue);
+    }
+
+    @Override
+    public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
+        assert fromBits <= toBits && (toBits == 32 || toBits == 64);
+        assert isNumericInteger(inputVal.getPlatformKind());
+        if (fromBits == toBits) {
+            return inputVal;
+        }
+        LIRKind resultKind = getResultLirKind(toBits, inputVal);
+        long mask = NumUtil.getNbitNumberLong(fromBits);
+        Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask));
+        return emitBinary(resultKind, AArch64ArithmeticOp.AND, true, inputVal, maskValue);
+    }
+
+    @Override
+    public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
+        assert fromBits <= toBits && (toBits == 32 || toBits == 64);
+        if (fromBits == toBits) {
+            return inputVal;
+        }
+        LIRKind resultKind = getResultLirKind(toBits, inputVal);
+        Variable result = getLIRGen().newVariable(resultKind);
+        getLIRGen().append(new AArch64SignExtendOp(result, getLIRGen().asAllocatable(inputVal)));
+        return result;
+    }
+
+    private static LIRKind getResultLirKind(int resultBitSize, Value... inputValues) {
+        if (resultBitSize == 64) {
+            return LIRKind.combine(inputValues).changeType(QWORD);
+        } else {
+            assert resultBitSize == 32;
+            return LIRKind.combine(inputValues).changeType(DWORD);
+        }
+    }
+
+    protected Variable emitBinary(LIRKind resultKind, AArch64ArithmeticOp op, boolean commutative, Value a, Value b) {
+        Variable result = getLIRGen().newVariable(resultKind);
+        if (isValidBinaryConstant(op, b)) {
+            emitBinaryConst(result, op, getLIRGen().asAllocatable(a), asJavaConstant(b));
+        } else if (commutative && isValidBinaryConstant(op, a)) {
+            emitBinaryConst(result, op, getLIRGen().asAllocatable(b), asJavaConstant(a));
+        } else {
+            emitBinaryVar(result, op, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+        }
+        return result;
+    }
+
+    private void emitBinaryVar(Variable result, AArch64ArithmeticOp op, AllocatableValue a, AllocatableValue b) {
+        AllocatableValue x = moveSp(a);
+        AllocatableValue y = moveSp(b);
+        switch (op) {
+            case FREM:
+            case REM:
+            case UREM:
+                getLIRGen().append(new AArch64ArithmeticOp.BinaryCompositeOp(op, result, x, y));
+                break;
+            default:
+                getLIRGen().append(new AArch64ArithmeticOp.BinaryOp(op, result, x, y));
+                break;
+        }
+    }
+
+    private void emitBinaryConst(Variable result, AArch64ArithmeticOp op, AllocatableValue a, JavaConstant b) {
+        AllocatableValue x = moveSp(a);
+        getLIRGen().append(new AArch64ArithmeticOp.BinaryConstOp(op, result, x, b));
+    }
+
+    private static boolean isValidBinaryConstant(AArch64ArithmeticOp op, Value val) {
+        if (!isJavaConstant(val)) {
+            return false;
+        }
+        JavaConstant constValue = asJavaConstant(val);
+        switch (op.category) {
+            case LOGICAL:
+                return isLogicalConstant(constValue);
+            case ARITHMETIC:
+                return isArithmeticConstant(constValue);
+            case SHIFT:
+                assert constValue.asLong() >= 0 && constValue.asLong() < val.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+                return true;
+            case NONE:
+                return false;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    private static boolean isLogicalConstant(JavaConstant constValue) {
+        switch (constValue.getJavaKind()) {
+            case Int:
+                return AArch64MacroAssembler.isLogicalImmediate(constValue.asInt());
+            case Long:
+                return AArch64MacroAssembler.isLogicalImmediate(constValue.asLong());
+            default:
+                return false;
+        }
+    }
+
+    protected static boolean isArithmeticConstant(JavaConstant constValue) {
+        switch (constValue.getJavaKind()) {
+            case Int:
+            case Long:
+                return AArch64MacroAssembler.isArithmeticImmediate(constValue.asLong());
+            case Object:
+                return constValue.isNull();
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public Value emitNegate(Value inputVal) {
+        return emitUnary(getOpCode(inputVal, AArch64ArithmeticOp.NEG, AArch64ArithmeticOp.FNEG), inputVal);
+    }
+
+    @Override
+    public Value emitNot(Value input) {
+        assert isNumericInteger(input.getPlatformKind());
+        return emitUnary(AArch64ArithmeticOp.NOT, input);
+    }
+
+    @Override
+    public Value emitMathAbs(Value input) {
+        return emitUnary(getOpCode(input, AArch64ArithmeticOp.ABS, AArch64ArithmeticOp.FABS), input);
+    }
+
+    @Override
+    public Value emitMathSqrt(Value input) {
+        assert input.getPlatformKind() == AArch64Kind.DOUBLE;
+        return emitUnary(AArch64ArithmeticOp.SQRT, input);
+    }
+
+    @Override
+    public Value emitBitScanForward(Value inputVal) {
+        return emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode.BSF, inputVal);
+    }
+
+    @Override
+    public Value emitBitCount(Value operand) {
+        throw JVMCIError.unimplemented("AArch64 ISA does not offer way to implement this more efficiently " + "than a simple Java algorithm.");
+    }
+
+    @Override
+    public Value emitBitScanReverse(Value inputVal) {
+        // TODO (das) old implementation said to use emitCountLeadingZeros instead - need extra node
+        // for that though
+        return emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode.BSR, inputVal);
+    }
+
+    private Variable emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode op, Value inputVal) {
+        assert isNumericInteger(inputVal.getPlatformKind());
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(new AArch64BitManipulationOp(op, result, input));
+        return result;
+    }
+
+    private Variable emitUnary(AArch64ArithmeticOp op, Value inputVal) {
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(new AArch64ArithmeticOp.UnaryOp(op, result, input));
+        return result;
+    }
+
+    /**
+     * If val denotes the stackpointer, move it to another location. This is necessary since most
+     * ops cannot handle the stackpointer as input or output.
+     */
+    private AllocatableValue moveSp(AllocatableValue val) {
+        if (val instanceof RegisterValue && ((RegisterValue) val).getRegister().equals(sp)) {
+            assert val.getPlatformKind() == AArch64Kind.QWORD : "Stackpointer must be long";
+            return getLIRGen().emitMove(val);
+        }
+        return val;
+    }
+
+    /**
+     * Returns the opcode depending on the platform kind of val.
+     */
+    private AArch64ArithmeticOp getOpCode(Value val, AArch64ArithmeticOp intOp, AArch64ArithmeticOp floatOp) {
+        return isNumericInteger(val.getPlatformKind()) ? intOp : floatOp;
+    }
+
+    @Override
+    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
+        AArch64AddressValue loadAddress = getLIRGen().asAddressValue(address);
+        Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
+        getLIRGen().append(new LoadOp((AArch64Kind) kind.getPlatformKind(), result, loadAddress, state));
+        return result;
+    }
+
+    @Override
+    public void emitStore(LIRKind lirKind, Value address, Value inputVal, LIRFrameState state) {
+        AArch64AddressValue storeAddress = getLIRGen().asAddressValue(address);
+        AArch64Kind kind = (AArch64Kind) lirKind.getPlatformKind();
+
+        if (isJavaConstant(inputVal) && kind.isInteger()) {
+            JavaConstant c = asJavaConstant(inputVal);
+            if (c.isDefaultForKind()) {
+                // We can load 0 directly into integer registers
+                getLIRGen().append(new StoreConstantOp(kind, storeAddress, c, state));
+                return;
+            }
+        }
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        getLIRGen().append(new StoreOp(kind, storeAddress, input, state));
+    }
+
+    public Value emitMathLog(Value input, boolean base10) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public Value emitMathCos(Value input) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public Value emitMathSin(Value input) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public Value emitMathTan(Value input) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public Value emitCountLeadingZeros(Value value) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public Value emitCountTrailingZeros(Value value) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public void emitCompareOp(AArch64Kind cmpKind, Variable left, Value right) {
+        throw JVMCIError.unimplemented();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64FloatConvertOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013, 2015, 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 com.oracle.graal.compiler.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.compiler.common.calc.FloatConvert;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.aarch64.AArch64LIRInstruction;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+
+public final class AArch64FloatConvertOp extends AArch64LIRInstruction {
+    private static final LIRInstructionClass<AArch64FloatConvertOp> TYPE = LIRInstructionClass.create(AArch64FloatConvertOp.class);
+
+    private final FloatConvert op;
+    @Def protected AllocatableValue resultValue;
+    @Use protected AllocatableValue inputValue;
+
+    protected AArch64FloatConvertOp(FloatConvert op, AllocatableValue resultValue, AllocatableValue inputValue) {
+        super(TYPE);
+        this.op = op;
+        this.resultValue = resultValue;
+        this.inputValue = inputValue;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        int fromSize = inputValue.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        int toSize = resultValue.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+
+        Register result = asRegister(resultValue);
+        Register input = asRegister(inputValue);
+        switch (op) {
+            case F2I:
+            case D2I:
+            case F2L:
+            case D2L:
+                masm.fcvtzs(toSize, fromSize, result, input);
+                break;
+            case I2F:
+            case I2D:
+            case L2F:
+            case L2D:
+                masm.scvtf(toSize, fromSize, result, input);
+                break;
+            case D2F:
+            case F2D:
+                masm.fcvt(fromSize, result, input);
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64LIRGenerator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 2013, 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 com.oracle.graal.compiler.aarch64;
+
+import static com.oracle.graal.lir.LIRValueUtil.asJavaConstant;
+import static com.oracle.graal.lir.LIRValueUtil.isJavaConstant;
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
+import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64Assembler.ConditionFlag;
+import com.oracle.graal.compiler.common.calc.Condition;
+import com.oracle.graal.compiler.common.spi.ForeignCallLinkage;
+import com.oracle.graal.compiler.common.spi.LIRKindTool;
+import com.oracle.graal.lir.ConstantValue;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRValueUtil;
+import com.oracle.graal.lir.LabelRef;
+import com.oracle.graal.lir.StandardOp;
+import com.oracle.graal.lir.SwitchStrategy;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.aarch64.AArch64AddressValue;
+import com.oracle.graal.lir.aarch64.AArch64ArithmeticOp;
+import com.oracle.graal.lir.aarch64.AArch64Call;
+import com.oracle.graal.lir.aarch64.AArch64Compare;
+import com.oracle.graal.lir.aarch64.AArch64ControlFlow;
+import com.oracle.graal.lir.aarch64.AArch64ControlFlow.BranchOp;
+import com.oracle.graal.lir.aarch64.AArch64ControlFlow.CondMoveOp;
+import com.oracle.graal.lir.aarch64.AArch64LIRInstruction;
+import com.oracle.graal.lir.aarch64.AArch64Move;
+import com.oracle.graal.lir.aarch64.AArch64Move.CompareAndSwap;
+import com.oracle.graal.lir.aarch64.AArch64Move.MembarOp;
+import com.oracle.graal.lir.aarch64.AArch64PauseOp;
+import com.oracle.graal.lir.gen.LIRGenerationResult;
+import com.oracle.graal.lir.gen.LIRGenerator;
+import com.oracle.graal.phases.util.Providers;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public abstract class AArch64LIRGenerator extends LIRGenerator {
+
+    @SuppressWarnings("unused") private final ConstantTableBaseProvider constantTableBaseProvider;
+
+    public static final class ConstantTableBaseProvider {
+        // private Variable constantTableBase;
+        @SuppressWarnings("unused") private boolean useConstantTableBase = false;
+
+        public Variable getConstantTableBase() {
+            useConstantTableBase = true;
+            // return constantTableBase;
+            return null;
+        }
+    }
+
+    public AArch64LIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, CallingConvention cc,
+                    LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) {
+        super(lirKindTool, arithmeticLIRGen, moveFactory, providers, cc, lirGenRes);
+        this.constantTableBaseProvider = constantTableBaseProvider;
+    }
+
+    /**
+     * Checks whether the supplied constant can be used without loading it into a register for store
+     * operations, i.e., on the right hand side of a memory access.
+     *
+     * @param c The constant to check.
+     * @return True if the constant can be used directly, false if the constant needs to be in a
+     *         register.
+     */
+    protected static final boolean canStoreConstant(JavaConstant c) {
+        // Our own code never calls this since we can't make a definite statement about whether or
+        // not we can inline a constant without knowing what kind of operation we execute. Let's be
+        // optimistic here and fix up mistakes later.
+        return true;
+    }
+
+    /**
+     * AArch64 cannot use anything smaller than a word in any instruction other than load and store.
+     */
+    @Override
+    public LIRKind toRegisterKind(LIRKind kind) {
+        switch ((AArch64Kind) kind.getPlatformKind()) {
+            case BYTE:
+            case WORD:
+                return kind.changeType(AMD64Kind.DWORD);
+            default:
+                return kind;
+        }
+    }
+
+    @Override
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        append(new AArch64Move.NullCheckOp(asAddressValue(address), state));
+    }
+
+    @Override
+    public Variable emitAddress(AllocatableValue stackslot) {
+        Variable result = newVariable(LIRKind.value(target().arch.getWordKind()));
+        append(new AArch64Move.StackLoadAddressOp(result, stackslot));
+        return result;
+    }
+
+    public AArch64AddressValue asAddressValue(Value address) {
+        if (address instanceof AArch64AddressValue) {
+            return (AArch64AddressValue) address;
+        } else {
+            return new AArch64AddressValue(address.getLIRKind(), asAllocatable(address), Value.ILLEGAL, 0, false, AddressingMode.BASE_REGISTER_ONLY);
+        }
+    }
+
+    @Override
+    public void emitMove(AllocatableValue dst, Value src) {
+        append(createMove(dst, src));
+    }
+
+    @Override
+    public void emitMoveConstant(AllocatableValue dst, Constant src) {
+        append(createMoveConstant(dst, (JavaConstant) src));
+    }
+
+    /**
+     * Moves src to dst.
+     *
+     * If src is AArch64AddressValue the address value is loaded into dst, not the value pointed to
+     * by address. All valid combinations of src and dst values are supported, except StackSlot to
+     * StackSlot.
+     *
+     * @param dst Value stored on stack or in register. Non null.
+     * @param src Arbitrary input value. Non null.
+     * @return AArch64LIRInstruction representing the move. Non null.
+     */
+    protected AArch64LIRInstruction createMove(AllocatableValue dst, Value src) {
+        if (src instanceof AArch64AddressValue) {
+            return new AArch64Move.LoadAddressOp(dst, (AArch64AddressValue) src);
+        } else if (isStackSlot(dst)) {
+            return new AArch64Move.MoveToStackOp(dst, asAllocatable(src));
+        } else {
+            return new AArch64Move.MoveToRegOp(dst, asAllocatable(src));
+        }
+    }
+
+    protected AArch64LIRInstruction createMoveConstant(AllocatableValue dst, JavaConstant src) {
+        if (isStackSlotValue(dst)) {
+            // constant -> stack is not possible so we need a scratch register in between.
+            Variable tmp = newVariable(dst.getLIRKind());
+            append(new AArch64Move.MoveFromConstOp(tmp, src));
+            return new AArch64Move.MoveToStackOp(dst, tmp);
+        } else {
+            return new AArch64Move.MoveFromConstOp(dst, src);
+        }
+    }
+
+    @Override
+    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+        AArch64AddressValue addressValue = convertToBaseRegisterOnlyAddress(asAddressValue(address));
+        Variable result = newVariable(trueValue.getLIRKind());
+        Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
+        append(new CompareAndSwap(result, loadNonCompareConst(expectedValue), loadReg(newValue), addressValue, scratch));
+        return result;
+    }
+
+    /**
+     * Converts an arbitrary address to a BASE_REGISTER_ONLY form. This is useful since several
+     * instructions (e.g. load-acquire/store-release) are limited to this addressing mode.
+     *
+     * @return An address using the
+     *         {@link com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode#BASE_REGISTER_ONLY}
+     *         addressingmode, pointing to the same location as address.
+     */
+    private AArch64AddressValue convertToBaseRegisterOnlyAddress(AArch64AddressValue address) {
+        AllocatableValue base = address.getBase();
+        AllocatableValue index = address.getOffset();
+        int immediate = address.getImmediate();
+        int shiftAmt;
+        if (address.isScaled()) {
+            shiftAmt = NumUtil.log2Ceil(address.getPlatformKind().getSizeInBytes() * Byte.SIZE);
+        } else {
+            shiftAmt = 0;
+        }
+        switch (address.getAddressingMode()) {
+            case IMMEDIATE_SCALED:
+            case IMMEDIATE_UNSCALED:
+                JavaConstant constVal = JavaConstant.forInt(immediate << shiftAmt);
+                ConstantValue constValue = new ConstantValue(LIRKind.value(AArch64Kind.WORD), constVal);
+                base = asAllocatable(getArithmetic().emitAdd(base, constValue, false));
+                break;
+            case REGISTER_OFFSET:
+                append(new AArch64ArithmeticOp.ExtendedAddShiftOp(base, base, index, AArch64Assembler.ExtendType.UXTX, shiftAmt));
+                break;
+            case EXTENDED_REGISTER_OFFSET:
+                append(new AArch64ArithmeticOp.ExtendedAddShiftOp(base, base, index, AArch64Assembler.ExtendType.SXTW, shiftAmt));
+                break;
+            case BASE_REGISTER_ONLY:
+                // nothing to do.
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+        return new AArch64AddressValue(address.getLIRKind(), base, Value.ILLEGAL, 0, false, AArch64Address.AddressingMode.BASE_REGISTER_ONLY);
+    }
+
+    @Override
+    public void emitData(AllocatableValue dst, byte[] data) {
+        append(new AArch64Move.LoadDataOp(dst, data));
+    }
+
+    @Override
+    public void emitMembar(int barriers) {
+        int necessaryBarriers = target().arch.requiredBarriers(barriers);
+        if (target().isMP && necessaryBarriers != 0) {
+            append(new MembarOp(necessaryBarriers));
+        }
+    }
+
+    @Override
+    public void emitJump(LabelRef label) {
+        assert label != null;
+        append(new StandardOp.JumpOp(label));
+    }
+
+    @Override
+    public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability) {
+        append(new AArch64ControlFlow.BranchOp(AArch64Assembler.ConditionFlag.VS, overflow, noOverflow, overflowProbability));
+    }
+
+    /**
+     * Branches to label if (left & right) == 0. If negated is true branchse on non-zero instead.
+     *
+     * @param left Integer kind. Non null.
+     * @param right Integer kind. Non null.
+     * @param trueDestination destination if left & right == 0. Non null.
+     * @param falseDestination destination if left & right != 0. Non null
+     * @param trueSuccessorProbability hoistoric probability that comparison is true
+     */
+    @Override
+    public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability) {
+        assert ((AArch64Kind) left.getPlatformKind()).isInteger() && left.getPlatformKind() == right.getPlatformKind();
+        ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(LIRKind.combine(left, right), AArch64ArithmeticOp.ANDS, true, left, right);
+        append(new AArch64ControlFlow.BranchOp(AArch64Assembler.ConditionFlag.EQ, trueDestination, falseDestination, trueSuccessorProbability));
+    }
+
+    /**
+     * Conditionally move trueValue into new variable if cond + unorderedIsTrue is true, else
+     * falseValue.
+     *
+     * @param left Arbitrary value. Has to have same type as right. Non null.
+     * @param right Arbitrary value. Has to have same type as left. Non null.
+     * @param cond condition that decides whether to move trueValue or falseValue into result. Non
+     *            null.
+     * @param unorderedIsTrue defines whether floating-point comparisons consider unordered true or
+     *            not. Ignored for integer comparisons.
+     * @param trueValue arbitrary value same type as falseValue. Non null.
+     * @param falseValue arbitrary value same type as trueValue. Non null.
+     * @return value containing trueValue if cond + unorderedIsTrue is true, else falseValue. Non
+     *         null.
+     */
+    @Override
+    public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
+        assert cmpKind == left.getPlatformKind() && cmpKind == right.getPlatformKind();
+        boolean mirrored = emitCompare(left, right, cond, unorderedIsTrue);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
+        ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
+        Variable result = newVariable(trueValue.getLIRKind());
+        append(new CondMoveOp(result, cmpCondition, loadReg(trueValue), loadReg(falseValue)));
+        return result;
+    }
+
+    @Override
+    public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability) {
+        assert cmpKind == left.getPlatformKind() && cmpKind == right.getPlatformKind();
+        boolean mirrored = emitCompare(left, right, cond, unorderedIsTrue);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
+        ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
+        append(new BranchOp(cmpCondition, trueDestination, falseDestination, trueDestinationProbability));
+    }
+
+    private static AArch64Assembler.ConditionFlag toConditionFlag(boolean isInt, Condition cond, boolean unorderedIsTrue) {
+        return isInt ? toIntConditionFlag(cond) : toFloatConditionFlag(cond, unorderedIsTrue);
+    }
+
+    /**
+     * Takes a Condition and unorderedIsTrue flag and returns the correct Aarch64 specific
+     * ConditionFlag. Note: This is only correct if the emitCompare code for floats has correctly
+     * handled the case of 'EQ && unorderedIsTrue', respectively 'NE && !unorderedIsTrue'!
+     */
+    private static AArch64Assembler.ConditionFlag toFloatConditionFlag(Condition cond, boolean unorderedIsTrue) {
+        switch (cond) {
+            case LT:
+                return unorderedIsTrue ? AArch64Assembler.ConditionFlag.LT : AArch64Assembler.ConditionFlag.LO;
+            case LE:
+                return unorderedIsTrue ? AArch64Assembler.ConditionFlag.LE : AArch64Assembler.ConditionFlag.LS;
+            case GE:
+                return unorderedIsTrue ? AArch64Assembler.ConditionFlag.PL : AArch64Assembler.ConditionFlag.GE;
+            case GT:
+                return unorderedIsTrue ? AArch64Assembler.ConditionFlag.HI : AArch64Assembler.ConditionFlag.GT;
+            case EQ:
+                return AArch64Assembler.ConditionFlag.EQ;
+            case NE:
+                return AArch64Assembler.ConditionFlag.NE;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Takes a Condition and returns the correct Aarch64 specific ConditionFlag.
+     */
+    private static AArch64Assembler.ConditionFlag toIntConditionFlag(Condition cond) {
+        switch (cond) {
+            case EQ:
+                return AArch64Assembler.ConditionFlag.EQ;
+            case NE:
+                return AArch64Assembler.ConditionFlag.NE;
+            case LT:
+                return AArch64Assembler.ConditionFlag.LT;
+            case LE:
+                return AArch64Assembler.ConditionFlag.LE;
+            case GT:
+                return AArch64Assembler.ConditionFlag.GT;
+            case GE:
+                return AArch64Assembler.ConditionFlag.GE;
+            case AE:
+                return AArch64Assembler.ConditionFlag.HS;
+            case BE:
+                return AArch64Assembler.ConditionFlag.LS;
+            case AT:
+                return AArch64Assembler.ConditionFlag.HI;
+            case BT:
+                return AArch64Assembler.ConditionFlag.LO;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Emits a gpCompare instruction, possibly reordering the parameters.
+     *
+     * @param a the left operand of the comparison. Has to have same type as b. Non null.
+     * @param b the right operand of the comparison. Has to have same type as a. Non null.
+     * @return true if mirrored (i.e. "b cmp a" instead of "a cmp b" was done).
+     */
+    private boolean emitCompare(Value a, Value b, Condition condition, boolean unorderedIsTrue) {
+        boolean mirrored;
+        AllocatableValue left;
+        Value right;
+        if (((AArch64Kind) a.getPlatformKind()).isInteger()) {
+            if (LIRValueUtil.isVariable(b) || b instanceof RegisterValue) {
+                left = loadReg(b);
+                right = loadNonConst(a);
+                mirrored = true;
+            } else {
+                left = loadReg(a);
+                right = loadNonConst(b);
+                mirrored = true;
+            }
+            append(new AArch64Compare.CompareOp(left, asAllocatable(right)));
+        } else {
+            if (AArch64Compare.FloatCompareOp.isFloatCmpConstant(a, condition, unorderedIsTrue)) {
+                left = loadReg(b);
+                right = a;
+                mirrored = true;
+            } else if (AArch64Compare.FloatCompareOp.isFloatCmpConstant(b, condition, unorderedIsTrue)) {
+                left = loadReg(a);
+                right = b;
+                mirrored = false;
+            } else {
+                left = loadReg(a);
+                right = loadReg(b);
+                mirrored = false;
+            }
+            append(new AArch64Compare.FloatCompareOp(left, asAllocatable(right), condition, unorderedIsTrue));
+        }
+        return mirrored;
+    }
+
+    /**
+     * Checks whether value can be used directly with a gpCompare instruction. This is <b>not</b>
+     * the same as {@link AArch64ArithmeticLIRGenerator#isArithmeticConstant(JavaConstant)}, because
+     * 0.0 is a valid compare constant for floats, while there are no arithmetic constants for
+     * floats.
+     *
+     * @param value any type. Non null.
+     * @return true if value can be used directly in comparison instruction, false otherwise.
+     */
+    public boolean isCompareConstant(Value value) {
+        if (!isJavaConstant(value)) {
+            return false;
+        }
+        JavaConstant constant = asJavaConstant(value);
+        if (((AArch64Kind) value.getPlatformKind()).isInteger()) {
+            return AArch64ArithmeticLIRGenerator.isArithmeticConstant(constant);
+        } else {
+            return constant.isDefaultForKind();
+        }
+    }
+
+    /**
+     * Moves trueValue into result if (left & right) == 0, else falseValue.
+     *
+     * @param left Integer kind. Non null.
+     * @param right Integer kind. Non null.
+     * @param trueValue Integer kind. Non null.
+     * @param falseValue Integer kind. Non null.
+     * @return virtual register containing trueValue if (left & right) == 0, else falseValue.
+     */
+    @Override
+    public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
+        assert ((AArch64Kind) left.getPlatformKind()).isInteger() && ((AArch64Kind) right.getPlatformKind()).isInteger();
+        assert ((AArch64Kind) trueValue.getPlatformKind()).isInteger() && ((AArch64Kind) falseValue.getPlatformKind()).isInteger();
+        ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(trueValue.getLIRKind(), AArch64ArithmeticOp.ANDS, true, left, right);
+        Variable result = newVariable(trueValue.getLIRKind());
+        append(new AArch64ControlFlow.CondMoveOp(result, AArch64Assembler.ConditionFlag.EQ, asAllocatableValue(trueValue), asAllocatableValue(falseValue)));
+        return result;
+    }
+
+    @Override
+    protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+        if (AArch64Call.isNearCall(linkage)) {
+            append(new AArch64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
+        } else {
+            append(new AArch64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info));
+        }
+    }
+
+    @Override
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+        append(new AArch64ControlFlow.StrategySwitchOp(strategy, keyTargets, defaultTarget, key, newVariable(key.getLIRKind()), AArch64LIRGenerator::toIntConditionFlag));
+    }
+
+    @Override
+    protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
+        // Make copy of key since the TableSwitch destroys its input.
+        Variable tmp = emitMove(key);
+        Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
+        append(new AArch64ControlFlow.TableSwitchOp(lowKey, defaultTarget, targets, tmp, scratch));
+    }
+
+    @Override
+    public Variable emitByteSwap(Value operand) {
+        // TODO (das) Do not generate until we support vector instructions
+        throw JVMCIError.unimplemented("Do not generate until we support vector instructions");
+    }
+
+    @Override
+    public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
+        // TODO (das) Do not generate until we support vector instructions
+        throw JVMCIError.unimplemented("Do not generate until we support vector instructions");
+    }
+
+    @Override
+    protected JavaConstant zapValueForKind(PlatformKind kind) {
+        long dead = 0xDEADDEADDEADDEADL;
+        switch ((AArch64Kind) kind) {
+            case BYTE:
+                return JavaConstant.forByte((byte) dead);
+            case WORD:
+                return JavaConstant.forShort((short) dead);
+            case DWORD:
+                return JavaConstant.forInt((int) dead);
+            case QWORD:
+                return JavaConstant.forLong(dead);
+            case SINGLE:
+                return JavaConstant.forFloat(Float.intBitsToFloat((int) dead));
+            case DOUBLE:
+                return JavaConstant.forDouble(Double.longBitsToDouble(dead));
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Loads value into virtual register. Contrary to {@link #load(Value)} this handles
+     * RegisterValues (i.e. values corresponding to fixed physical registers) correctly, by not
+     * creating an unnecessary move into a virtual register.
+     *
+     * This avoids generating the following code: mov x0, x19 # x19 is fixed thread register ldr x0,
+     * [x0] instead of: ldr x0, [x19].
+     */
+    protected AllocatableValue loadReg(Value val) {
+        if (!(val instanceof Variable || val instanceof RegisterValue)) {
+            return emitMove(val);
+        }
+        return (AllocatableValue) val;
+    }
+
+    /**
+     * If value is a constant that cannot be used directly with a gpCompare instruction load it into
+     * a register and return the register, otherwise return constant value unchanged.
+     */
+    protected Value loadNonCompareConst(Value value) {
+        if (!isCompareConstant(value)) {
+            return loadReg(value);
+        }
+        return value;
+    }
+
+    @Override
+    public void emitPause() {
+        append(new AArch64PauseOp());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64LIRKindTool.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, 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 com.oracle.graal.compiler.aarch64;
+
+import com.oracle.graal.compiler.common.spi.LIRKindTool;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.LIRKind;
+
+public class AArch64LIRKindTool implements LIRKindTool {
+
+    public LIRKind getIntegerKind(int bits) {
+        if (bits <= 8) {
+            return LIRKind.value(AArch64Kind.BYTE);
+        } else if (bits <= 16) {
+            return LIRKind.value(AArch64Kind.WORD);
+        } else if (bits <= 32) {
+            return LIRKind.value(AArch64Kind.DWORD);
+        } else {
+            assert bits <= 64;
+            return LIRKind.value(AArch64Kind.QWORD);
+        }
+    }
+
+    public LIRKind getFloatingKind(int bits) {
+        switch (bits) {
+            case 32:
+                return LIRKind.value(AArch64Kind.SINGLE);
+            case 64:
+                return LIRKind.value(AArch64Kind.DOUBLE);
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    public LIRKind getObjectKind() {
+        return LIRKind.reference(AArch64Kind.QWORD);
+    }
+
+    public LIRKind getWordKind() {
+        return LIRKind.value(AArch64Kind.QWORD);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64MoveFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015, 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 com.oracle.graal.compiler.aarch64;
+
+import static com.oracle.graal.lir.LIRValueUtil.asConstant;
+import static com.oracle.graal.lir.LIRValueUtil.isConstantValue;
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
+
+import com.oracle.graal.compiler.aarch64.AArch64LIRGenerator.ConstantTableBaseProvider;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.aarch64.AArch64AddressValue;
+import com.oracle.graal.lir.aarch64.AArch64Move.LoadAddressOp;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public class AArch64MoveFactory implements MoveFactory {
+
+    private final CodeCacheProvider codeCache;
+    protected final ConstantTableBaseProvider constantTableBaseProvider;
+
+    public AArch64MoveFactory(CodeCacheProvider codeCache, ConstantTableBaseProvider constantTableBaseProvider) {
+        this.codeCache = codeCache;
+        this.constantTableBaseProvider = constantTableBaseProvider;
+    }
+
+    @Override
+    public LIRInstruction createMove(AllocatableValue dst, Value src) {
+        boolean srcIsSlot = isStackSlotValue(src);
+        boolean dstIsSlot = isStackSlotValue(dst);
+        if (isConstantValue(src)) {
+            return createLoad(dst, asConstant(src));
+        } else if (src instanceof AArch64AddressValue) {
+            return new LoadAddressOp(dst, (AArch64AddressValue) src);
+        } else {
+            assert src instanceof AllocatableValue;
+            if (srcIsSlot && dstIsSlot) {
+                throw JVMCIError.shouldNotReachHere(src.getClass() + " " + dst.getClass());
+            } else {
+                // return new Move(dst, (AllocatableValue) src);
+                throw JVMCIError.unimplemented();
+            }
+        }
+    }
+
+    @Override
+    public LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) {
+        // return new AArch64Move.Move(result, input);
+        throw JVMCIError.unimplemented();
+    }
+
+    @Override
+    public LIRInstruction createLoad(AllocatableValue dst, Constant src) {
+        if (src instanceof JavaConstant) {
+            JavaConstant javaConstant = (JavaConstant) src;
+            if (canInlineConstant(javaConstant)) {
+                // return new AArch64Move.LoadInlineConstant(javaConstant, dst);
+                throw JVMCIError.unimplemented();
+            } else {
+                // return new AArch64Move.LoadConstantFromTable(javaConstant,
+                // constantTableBaseProvider.getConstantTableBase(), dst);
+                throw JVMCIError.unimplemented();
+            }
+        } else {
+            throw JVMCIError.shouldNotReachHere(src.getClass().toString());
+        }
+    }
+
+    @Override
+    public boolean canInlineConstant(JavaConstant c) {
+        switch (c.getJavaKind()) {
+            case Boolean:
+            case Byte:
+            case Char:
+            case Short:
+            case Int:
+                // return SPARCAssembler.isSimm13(c.asInt()) && !codeCache.needsDataPatch(c);
+                boolean x = !codeCache.needsDataPatch(c);
+                throw JVMCIError.unimplemented("needsDataPatch=" + x);
+            case Long:
+                // return SPARCAssembler.isSimm13(c.asLong()) && !codeCache.needsDataPatch(c);
+                boolean y = !codeCache.needsDataPatch(c);
+                throw JVMCIError.unimplemented("needsDataPatch=" + y);
+            case Object:
+                return c.isNull();
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public boolean allowConstantToStackMove(Constant value) {
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64NodeLIRBuilder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, 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 com.oracle.graal.compiler.aarch64;
+
+import com.oracle.graal.compiler.gen.NodeLIRBuilder;
+import com.oracle.graal.lir.aarch64.AArch64BreakpointOp;
+import com.oracle.graal.lir.gen.LIRGeneratorTool;
+import com.oracle.graal.nodes.BreakpointNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.ValueNode;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * This class implements the SPARC specific portion of the LIR generator.
+ */
+public abstract class AArch64NodeLIRBuilder extends NodeLIRBuilder {
+
+    public AArch64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, AArch64NodeMatchRules nodeMatchRules) {
+        super(graph, lirGen, nodeMatchRules);
+    }
+
+    @Override
+    protected boolean peephole(ValueNode valueNode) {
+        // No peephole optimizations for now
+        return false;
+    }
+
+    @Override
+    public void visitBreakpointNode(BreakpointNode node) {
+        JavaType[] sig = new JavaType[node.arguments().size()];
+        for (int i = 0; i < sig.length; i++) {
+            sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
+        }
+
+        Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(CallingConvention.Type.JavaCall, null, sig, gen.target(), false),
+                        node.arguments());
+        append(new AArch64BreakpointOp(parameters));
+    }
+
+    @Override
+    public AArch64LIRGenerator getLIRGeneratorTool() {
+        return (AArch64LIRGenerator) super.getLIRGeneratorTool();
+    }
+
+    @Override
+    protected void emitPrologue(StructuredGraph graph) {
+        // XXX Maybe we need something like this.
+        // getLIRGeneratorTool().emitLoadConstantTableBase();
+        super.emitPrologue(graph);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64NodeMatchRules.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, 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 com.oracle.graal.compiler.aarch64;
+
+import com.oracle.graal.compiler.gen.NodeMatchRules;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.gen.LIRGeneratorTool;
+import com.oracle.graal.nodes.DeoptimizingNode;
+import com.oracle.graal.nodes.memory.Access;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+
+public class AArch64NodeMatchRules extends NodeMatchRules {
+
+    public AArch64NodeMatchRules(LIRGeneratorTool gen) {
+        super(gen);
+    }
+
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    protected AArch64Kind getMemoryKind(Access access) {
+        return (AArch64Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind();
+    }
+
+    @Override
+    public AArch64LIRGenerator getLIRGeneratorTool() {
+        return (AArch64LIRGenerator) gen;
+    }
+
+    protected AArch64ArithmeticLIRGenerator getArithmeticLIRGenerator() {
+        return (AArch64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64SuitesProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, 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 com.oracle.graal.compiler.aarch64;
+
+import com.oracle.graal.java.DefaultSuitesProvider;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.phases.tiers.CompilerConfiguration;
+
+public class AArch64SuitesProvider extends DefaultSuitesProvider {
+
+    public AArch64SuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
+        super(compilerConfiguration, plugins);
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/BackendOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/BackendOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,11 +22,11 @@
  */
 package com.oracle.graal.compiler.common;
 
-import jdk.vm.ci.options.DerivedOptionValue;
-import jdk.vm.ci.options.DerivedOptionValue.OptionSupplier;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
+import com.oracle.graal.options.DerivedOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.DerivedOptionValue.OptionSupplier;
 
 /**
  * Options to control the backend configuration.
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.compiler.common;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.StableOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.StableOptionValue;
 
 /**
  * This class encapsulates options that control the behavior of the Graal compiler.
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/TraceBuilder.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/TraceBuilder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -93,7 +93,7 @@
 
     private TraceBuilder(List<T> blocks) {
         processed = new BitSet(blocks.size());
-        worklist = new PriorityQueue<T>(TraceBuilder::compare);
+        worklist = createQueue();
         assert (worklist != null);
 
         blocked = new int[blocks.size()];
@@ -103,7 +103,12 @@
         }
     }
 
-    private static <T extends AbstractBlockBase<T>> int compare(T a, T b) {
+    @SuppressWarnings("unchecked")
+    private PriorityQueue<T> createQueue() {
+        return (PriorityQueue<T>) new PriorityQueue<AbstractBlockBase<?>>(TraceBuilder::compare);
+    }
+
+    private static int compare(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
         return Double.compare(b.probability(), a.probability());
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/Util.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/Util.java	Tue Jan 05 16:42:05 2016 -0800
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.common.util;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.List;
 
@@ -151,6 +152,29 @@
         assert CodeUtil.isPowerOf2(64);
     }
 
+    public interface Stringify {
+        String apply(Object o);
+    }
+
+    public static String join(Collection<?> c, String sep) {
+        return join(c, sep, "", "", null);
+    }
+
+    public static String join(Collection<?> c, String sep, String prefix, String suffix, Stringify stringify) {
+        StringBuilder buf = new StringBuilder(prefix);
+        boolean first = true;
+        for (Object e : c) {
+            if (!first) {
+                buf.append(sep);
+            } else {
+                first = false;
+            }
+            buf.append(stringify != null ? stringify.apply(e) : String.valueOf(e));
+        }
+        buf.append(suffix);
+        return buf.toString();
+    }
+
     /**
      * Sets the element at a given position of a list and ensures that this position exists. If the
      * list is current shorter than the position, intermediate positions are filled with a given
@@ -243,10 +267,10 @@
         boolean newLine = true;
         for (int i = 0; i < length; i++) {
             if (newLine) {
-                TTY.print("%08x: ", address + i);
+                TTY.printf("%08x: ", address + i);
                 newLine = false;
             }
-            TTY.print("%02x ", array[i]);
+            TTY.printf("%02x ", array[i]);
             if (i % bytesPerLine == bytesPerLine - 1) {
                 TTY.println();
                 newLine = true;
--- a/graal/com.oracle.graal.compiler.match.processor/src/com/oracle/graal/compiler/match/processor/MatchProcessor.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.match.processor/src/com/oracle/graal/compiler/match/processor/MatchProcessor.java	Tue Jan 05 16:42:05 2016 -0800
@@ -63,7 +63,6 @@
 import javax.tools.StandardLocation;
 
 import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.service.ServiceProvider;
 
 import com.oracle.graal.compiler.gen.NodeMatchRules;
 import com.oracle.graal.compiler.match.ComplexMatchResult;
@@ -75,6 +74,7 @@
 import com.oracle.graal.compiler.match.MatchableNodes;
 import com.oracle.graal.graph.Position;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 /**
  * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCArithmeticLIRGenerator.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCArithmeticLIRGenerator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -457,7 +457,7 @@
                 op = Op3s.Sllx;
                 break;
             default:
-                throw JVMCIError.shouldNotReachHere();
+                throw JVMCIError.shouldNotReachHere(String.format("Unsupported kind %s", aKind));
         }
         return emitBinary(resultKind, op, a, b);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConstantArrayReadFoldingTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015, 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 com.oracle.graal.compiler.test;
+
+import org.junit.Test;
+
+public class ConstantArrayReadFoldingTest extends GraalCompilerTest {
+
+    enum E {
+        A(0.001),
+        B(0.01),
+        C(0.5),
+        D(2.0),
+        E(3.0),
+        F(4.0),
+        G(5.0);
+
+        public final double ceiling;
+        public double weight;
+
+        private E(double ceiling) {
+            this.ceiling = ceiling;
+        }
+    }
+
+    public Object test1Snippet(double value) {
+        for (E kind : E.values()) {
+            if (value <= kind.ceiling) {
+                return kind;
+            }
+        }
+        throw new IllegalArgumentException();
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet", 1.0);
+        test("test1Snippet", 2.0);
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CountedLoopTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CountedLoopTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -227,7 +227,7 @@
         public void rewrite(LoopsData loops) {
             InductionVariable inductionVariable = loops.getInductionVariable(iv);
             ValueNode node = property.get(inductionVariable);
-            graph().replaceFloating(this, node);
+            replaceAtUsagesAndDelete(node);
         }
 
         public void generate(NodeLIRBuilderTool gen) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -58,7 +58,6 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.SpeculationLog;
-import jdk.vm.ci.options.DerivedOptionValue;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -92,6 +91,7 @@
 import com.oracle.graal.nodes.ReturnNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
@@ -102,6 +102,7 @@
 import com.oracle.graal.nodes.spi.LoweringProvider;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.nodes.virtual.VirtualObjectNode;
+import com.oracle.graal.options.DerivedOptionValue;
 import com.oracle.graal.phases.BasePhase;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.Phase;
@@ -348,6 +349,7 @@
     protected static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) {
         SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
         schedule.apply(graph);
+        ScheduleResult scheduleResult = graph.getLastSchedule();
 
         NodeMap<Integer> canonicalId = graph.createNodeMap();
         int nextId = 0;
@@ -355,9 +357,9 @@
         List<String> constantsLines = new ArrayList<>();
 
         StringBuilder result = new StringBuilder();
-        for (Block block : schedule.getCFG().getBlocks()) {
+        for (Block block : scheduleResult.getCFG().getBlocks()) {
             result.append("Block " + block + " ");
-            if (block == schedule.getCFG().getStartBlock()) {
+            if (block == scheduleResult.getCFG().getStartBlock()) {
                 result.append("* ");
             }
             result.append("-> ");
@@ -365,7 +367,7 @@
                 result.append(succ + " ");
             }
             result.append("\n");
-            for (Node node : schedule.getBlockToNodesMap().get(block)) {
+            for (Node node : scheduleResult.getBlockToNodesMap().get(block)) {
                 if (node instanceof ValueNode && node.isAlive()) {
                     if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof InfopointNode)) {
                         if (node instanceof ConstantNode) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraphScheduleTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraphScheduleTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,6 +29,7 @@
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeMap;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.phases.schedule.SchedulePhase;
 
@@ -37,10 +38,10 @@
     protected void assertOrderedAfterSchedule(StructuredGraph graph, Node a, Node b) {
         SchedulePhase ibp = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST);
         ibp.apply(graph);
-        assertOrderedAfterSchedule(ibp, a, b);
+        assertOrderedAfterSchedule(graph.getLastSchedule(), a, b);
     }
 
-    protected void assertOrderedAfterSchedule(SchedulePhase ibp, Node a, Node b) {
+    protected void assertOrderedAfterSchedule(ScheduleResult ibp, Node a, Node b) {
         NodeMap<Block> nodeToBlock = ibp.getCFG().getNodeToBlock();
         Block bBlock = nodeToBlock.get(b);
         Block aBlock = nodeToBlock.get(a);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.isNotA;
-
 import org.junit.Test;
 
 import com.oracle.graal.debug.Debug;
@@ -216,8 +214,10 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         ParameterNode param = graph.getNodes(ParameterNode.TYPE).iterator().next();
         ConstantNode constant = ConstantNode.forInt(0, graph);
-        for (Node n : param.usages().filter(isNotA(FrameState.class)).snapshot()) {
-            n.replaceFirstInput(param, constant);
+        for (Node n : param.usages().snapshot()) {
+            if (!(n instanceof FrameState)) {
+                n.replaceFirstInput(param, constant);
+            }
         }
         Debug.dump(graph, "Graph");
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -27,10 +27,8 @@
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.DebugDumpScope;
-import com.oracle.graal.graph.Node;
 import com.oracle.graal.loop.DefaultLoopPolicies;
 import com.oracle.graal.loop.phases.LoopUnswitchingPhase;
-import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
@@ -132,12 +130,8 @@
         new LoopUnswitchingPhase(new DefaultLoopPolicies()).apply(graph);
 
         // Framestates create comparison problems
-        for (Node stateSplit : graph.getNodes().filterInterface(StateSplit.class)) {
-            ((StateSplit) stateSplit).setStateAfter(null);
-        }
-        for (Node stateSplit : referenceGraph.getNodes().filterInterface(StateSplit.class)) {
-            ((StateSplit) stateSplit).setStateAfter(null);
-        }
+        graph.clearAllStateAfter();
+        referenceGraph.clearAllStateAfter();
 
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
         new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -31,9 +31,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
-
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -42,17 +39,17 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.iterators.NodeIterable;
-import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.ReturnNode;
 import com.oracle.graal.nodes.StartNode;
-import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.memory.FloatingReadNode;
 import com.oracle.graal.nodes.memory.WriteNode;
 import com.oracle.graal.nodes.spi.LoweringTool;
-import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.FloatingReadPhase;
@@ -107,7 +104,7 @@
     @Test
     public void testSimple() {
         for (TestMode mode : TestMode.values()) {
-            SchedulePhase schedule = getFinalSchedule("testSimpleSnippet", mode);
+            ScheduleResult schedule = getFinalSchedule("testSimpleSnippet", mode);
             StructuredGraph graph = schedule.getCFG().graph;
             assertReadAndWriteInSameBlock(schedule, true);
             assertOrderedAfterSchedule(schedule, graph.getNodes().filter(FloatingReadNode.class).first(), graph.getNodes().filter(WriteNode.class).first());
@@ -132,7 +129,7 @@
     @Test
     public void testSplit1() {
         for (TestMode mode : TestMode.values()) {
-            SchedulePhase schedule = getFinalSchedule("testSplit1Snippet", mode);
+            ScheduleResult schedule = getFinalSchedule("testSplit1Snippet", mode);
             assertReadWithinStartBlock(schedule, true);
             assertReadWithinAllReturnBlocks(schedule, false);
         }
@@ -156,7 +153,7 @@
 
     @Test
     public void testSplit2() {
-        SchedulePhase schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
     }
@@ -180,7 +177,7 @@
 
     @Test
     public void testLoop1() {
-        SchedulePhase schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(6, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -205,7 +202,7 @@
 
     @Test
     public void testLoop2() {
-        SchedulePhase schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(6, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
@@ -227,7 +224,7 @@
 
     @Test
     public void testLoop3() {
-        SchedulePhase schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(6, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -263,7 +260,7 @@
 
     @Test
     public void testLoop5() {
-        SchedulePhase schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(10, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -292,7 +289,7 @@
 
     @Test
     public void testLoop6() {
-        SchedulePhase schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(13, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -325,7 +322,7 @@
 
     @Test
     public void testLoop7() {
-        SchedulePhase schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(18, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -352,7 +349,7 @@
 
     @Test
     public void testLoop8() {
-        SchedulePhase schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(10, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -372,7 +369,7 @@
 
     @Test
     public void testLoop9() {
-        SchedulePhase schedule = getFinalSchedule("testLoop9Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop9Snippet", TestMode.WITHOUT_FRAMESTATES);
         StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
         assertThat(graph.getNodes(ReturnNode.TYPE), hasCount(1));
         ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first();
@@ -391,7 +388,7 @@
 
     @Test
     public void testArrayCopy() {
-        SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
         StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
         assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
         ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first();
@@ -413,7 +410,7 @@
 
     @Test
     public void testIfRead1() {
-        SchedulePhase schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(3, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadAndWriteInSameBlock(schedule, false);
@@ -434,7 +431,7 @@
 
     @Test
     public void testIfRead2() {
-        SchedulePhase schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(3, schedule.getCFG().getBlocks().size());
         assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count());
         assertReadWithinStartBlock(schedule, false);
@@ -456,7 +453,7 @@
 
     @Test
     public void testIfRead3() {
-        SchedulePhase schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(4, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
@@ -477,7 +474,7 @@
 
     @Test
     public void testIfRead4() {
-        SchedulePhase schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(3, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -496,7 +493,7 @@
 
     @Test
     public void testIfRead5() {
-        SchedulePhase schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(4, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
@@ -522,7 +519,7 @@
 
     @Test
     public void testAntiDependency() {
-        SchedulePhase schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(4, schedule.getCFG().getBlocks().size());
         assertReadBeforeAllWritesInStartBlock(schedule);
     }
@@ -546,7 +543,7 @@
 
     @Test
     public void testBlockSchedule() {
-        SchedulePhase schedule = getFinalSchedule("testBlockScheduleSnippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testBlockScheduleSnippet", TestMode.WITHOUT_FRAMESTATES);
         StructuredGraph graph = schedule.getCFG().graph;
         NodeIterable<WriteNode> writeNodes = graph.getNodes().filter(WriteNode.class);
 
@@ -587,7 +584,7 @@
 
     @Test
     public void testBlockSchedule2() {
-        SchedulePhase schedule = getFinalSchedule("testBlockSchedule2Snippet", TestMode.WITHOUT_FRAMESTATES, SchedulingStrategy.LATEST);
+        ScheduleResult schedule = getFinalSchedule("testBlockSchedule2Snippet", TestMode.WITHOUT_FRAMESTATES, SchedulingStrategy.LATEST);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
         assertReadAndWriteInSameBlock(schedule, false);
@@ -610,7 +607,7 @@
 
     @Test
     public void testProxy() {
-        SchedulePhase schedule = getFinalSchedule("testProxySnippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testProxySnippet", TestMode.WITHOUT_FRAMESTATES);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -633,7 +630,7 @@
 
     @Test
     public void testStringHashCode() {
-        SchedulePhase schedule = getFinalSchedule("testStringHashCodeSnippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testStringHashCodeSnippet", TestMode.WITHOUT_FRAMESTATES);
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
 
@@ -665,12 +662,12 @@
 
     @Test
     public void testLoop4() {
-        SchedulePhase schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
 
-    private void assertReadWithinAllReturnBlocks(SchedulePhase schedule, boolean withinReturnBlock) {
+    private void assertReadWithinAllReturnBlocks(ScheduleResult schedule, boolean withinReturnBlock) {
         StructuredGraph graph = schedule.getCFG().graph;
         assertTrue(graph.getNodes(ReturnNode.TYPE).isNotEmpty());
 
@@ -689,7 +686,7 @@
         assertDeepEquals(withRead == returnBlocks, withinReturnBlock);
     }
 
-    private void assertReadWithinStartBlock(SchedulePhase schedule, boolean withinStartBlock) {
+    private void assertReadWithinStartBlock(ScheduleResult schedule, boolean withinStartBlock) {
         boolean readEncountered = false;
         for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) {
             if (node instanceof FloatingReadNode) {
@@ -699,14 +696,14 @@
         assertDeepEquals(withinStartBlock, readEncountered);
     }
 
-    private static void assertReadAndWriteInSameBlock(SchedulePhase schedule, boolean inSame) {
+    private static void assertReadAndWriteInSameBlock(ScheduleResult schedule, boolean inSame) {
         StructuredGraph graph = schedule.getCFG().graph;
         FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first();
         WriteNode write = graph.getNodes().filter(WriteNode.class).first();
         assertTrue(!(inSame ^ schedule.getCFG().blockFor(read) == schedule.getCFG().blockFor(write)));
     }
 
-    private static void assertReadBeforeAllWritesInStartBlock(SchedulePhase schedule) {
+    private static void assertReadBeforeAllWritesInStartBlock(ScheduleResult schedule) {
         boolean writeNodeFound = false;
         boolean readNodeFound = false;
         for (Node node : schedule.nodesFor(schedule.getCFG().getStartBlock())) {
@@ -720,12 +717,12 @@
         assertTrue(readNodeFound);
     }
 
-    private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode) {
+    private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode) {
         return getFinalSchedule(snippet, mode, SchedulingStrategy.LATEST_OUT_OF_LOOPS);
     }
 
     @SuppressWarnings("try")
-    private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) {
+    private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) {
         final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         try (Scope d = Debug.scope("FloatingReadTest", graph)) {
             try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) {
@@ -737,15 +734,7 @@
                 }
                 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
                 if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
-                    for (Node node : graph.getNodes()) {
-                        if (node instanceof StateSplit) {
-                            FrameState stateAfter = ((StateSplit) node).stateAfter();
-                            if (stateAfter != null) {
-                                ((StateSplit) node).setStateAfter(null);
-                                GraphUtil.killWithUnusedFloatingInputs(stateAfter);
-                            }
-                        }
-                    }
+                    graph.clearAllStateAfter();
                 }
                 Debug.dump(graph, "after removal of framestates");
 
@@ -760,7 +749,7 @@
                 SchedulePhase schedule = new SchedulePhase(schedulingStrategy);
                 schedule.apply(graph);
                 assertDeepEquals(1, graph.getNodes().filter(StartNode.class).count());
-                return schedule;
+                return graph.getLastSchedule();
             }
         } catch (Throwable e) {
             throw Debug.handle(e);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.isNotA;
-
 import java.util.HashMap;
 import java.util.Map;
 
@@ -94,8 +92,10 @@
         ParameterNode param = graph.getNodes(ParameterNode.TYPE).first();
         if (param != null) {
             ConstantNode constant = ConstantNode.forInt(0, graph);
-            for (Node n : param.usages().filter(isNotA(FrameState.class)).snapshot()) {
-                n.replaceFirstInput(param, constant);
+            for (Node n : param.usages().snapshot()) {
+                if (!(n instanceof FrameState)) {
+                    n.replaceFirstInput(param, constant);
+                }
             }
         }
         Map<Invoke, Double> hints = new HashMap<>();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/OptionsVerifierTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/OptionsVerifierTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -48,12 +48,13 @@
 import jdk.internal.org.objectweb.asm.MethodVisitor;
 import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.org.objectweb.asm.Type;
-import jdk.vm.ci.options.OptionDescriptor;
-import jdk.vm.ci.options.OptionDescriptors;
-import jdk.vm.ci.options.OptionValue;
 
 import org.junit.Test;
 
+import com.oracle.graal.options.OptionDescriptor;
+import com.oracle.graal.options.OptionDescriptors;
+import com.oracle.graal.options.OptionValue;
+
 /**
  * Verifies a class declaring one or more {@linkplain OptionValue options} has a class initializer
  * that only initializes the option(s). This sanity check mitigates the possibility of an option
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -32,6 +32,7 @@
 import com.oracle.graal.nodes.LoopExitNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.calc.AddNode;
 import com.oracle.graal.nodes.calc.BinaryArithmeticNode;
 import com.oracle.graal.nodes.cfg.Block;
@@ -59,8 +60,9 @@
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
         }
-        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.LATEST);
-        schedule.apply(graph);
+        SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST);
+        schedulePhase.apply(graph);
+        ScheduleResult schedule = graph.getLastSchedule();
         NodeMap<Block> nodeToBlock = schedule.getCFG().getNodeToBlock();
         assertTrue(graph.getNodes().filter(LoopExitNode.class).count() == 1);
         LoopExitNode loopExit = graph.getNodes().filter(LoopExitNode.class).first();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest2.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest2.java	Tue Jan 05 16:42:05 2016 -0800
@@ -37,6 +37,7 @@
 import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.calc.AddNode;
 import com.oracle.graal.nodes.calc.BinaryArithmeticNode;
 import com.oracle.graal.nodes.cfg.Block;
@@ -69,8 +70,9 @@
         returnNode.replaceAtPredecessor(beginNode);
         beginNode.setNext(returnNode);
         Debug.dump(graph, "Graph");
-        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
-        schedule.apply(graph);
+        SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST);
+        schedulePhase.apply(graph);
+        ScheduleResult schedule = graph.getLastSchedule();
         BlockMap<List<Node>> blockToNodesMap = schedule.getBlockToNodesMap();
         NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
         assertDeepEquals(2, schedule.getCFG().getBlocks().size());
@@ -103,8 +105,8 @@
         FrameStateAssignmentPhase phase = new FrameStateAssignmentPhase();
         phase.apply(graph);
 
-        schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
-        schedule.apply(graph);
+        schedulePhase.apply(graph);
+        schedule = graph.getLastSchedule();
         blockToNodesMap = schedule.getBlockToNodesMap();
         nodeToBlock = schedule.getNodeToBlockMap();
         for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -39,6 +39,7 @@
 import com.oracle.graal.nodes.PhiNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.java.CheckCastNode;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
@@ -191,6 +192,8 @@
         // a second canonicalizer is needed to process nested MaterializeNodes
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
         StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
+        new ConditionalEliminationPhase().apply(referenceGraph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
         new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
         assertEquals(referenceGraph, graph);
     }
@@ -206,8 +209,9 @@
 
     public static void outputGraph(StructuredGraph graph, String message) {
         TTY.println("========================= " + message);
-        SchedulePhase schedule = new SchedulePhase();
-        schedule.apply(graph);
+        SchedulePhase schedulePhase = new SchedulePhase();
+        schedulePhase.apply(graph);
+        ScheduleResult schedule = graph.getLastSchedule();
         for (Block block : schedule.getCFG().getBlocks()) {
             TTY.print("Block " + block + " ");
             if (block == schedule.getCFG().getStartBlock()) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/BackendTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/BackendTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -34,7 +34,6 @@
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.phases.OptimisticOptimizations;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 
 public abstract class BackendTest extends GraalCompilerTest {
 
@@ -48,15 +47,14 @@
 
     @SuppressWarnings("try")
     protected LIRGenerationResult getLIRGenerationResult(final StructuredGraph graph) {
-        SchedulePhase schedule = null;
         try (Scope s = Debug.scope("FrontEnd")) {
-            schedule = GraalCompiler.emitFrontEnd(getProviders(), getBackend(), graph, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE, graph.method().getProfilingInfo(), getSuites());
+            GraalCompiler.emitFrontEnd(getProviders(), getBackend(), graph, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE, graph.method().getProfilingInfo(), getSuites());
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
 
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
-        LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), schedule, graph, null, cc, null, getLIRSuites());
+        LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), graph, null, cc, null, getLIRSuites());
         return lirGen;
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -130,6 +130,20 @@
     }
 
     @Test
+    public void testArrayCopy() {
+        testPartialEscapeAnalysis("testArrayCopySnippet", 0, 0);
+    }
+
+    public static Object[] array = new Object[]{1, 2, 3, 4, 5, "asdf", "asdf"};
+
+    public static Object testArrayCopySnippet(int a) {
+        Object[] tmp = new Object[]{a != 1 ? array[a] : null};
+        Object[] tmp2 = new Object[5];
+        System.arraycopy(tmp, 0, tmp2, 4, 1);
+        return tmp2[4];
+    }
+
+    @Test
     @Ignore
     public void testCache() {
         testPartialEscapeAnalysis("testCacheSnippet", 0.75, 1);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Jan 05 16:42:05 2016 -0800
@@ -44,8 +44,6 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.TriState;
 import jdk.vm.ci.meta.VMConstant;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
 
 import com.oracle.graal.compiler.LIRGenerationPhase.LIRGenerationContext;
 import com.oracle.graal.compiler.common.alloc.ComputeBlockOrder;
@@ -70,8 +68,11 @@
 import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
 import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
@@ -176,8 +177,8 @@
     public static <T extends CompilationResult> T compile(Request<T> r) {
         assert !r.graph.isFrozen();
         try (Scope s0 = Debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache())) {
-            SchedulePhase schedule = emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
-            emitBackEnd(r.graph, null, r.cc, r.installedCodeOwner, r.backend, r.compilationResult, r.factory, schedule, null, r.lirSuites);
+            emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
+            emitBackEnd(r.graph, null, r.cc, r.installedCodeOwner, r.backend, r.compilationResult, r.factory, null, r.lirSuites);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -196,7 +197,7 @@
      * Builds the graph, optimizes it.
      */
     @SuppressWarnings("try")
-    public static SchedulePhase emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
+    public static void emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
                     ProfilingInfo profilingInfo, Suites suites) {
         try (Scope s = Debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start()) {
             HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts);
@@ -219,12 +220,8 @@
 
             LowTierContext lowTierContext = new LowTierContext(providers, target);
             suites.getLowTier().apply(graph, lowTierContext);
-            graph.maybeCompress();
 
-            SchedulePhase schedule = new SchedulePhase();
-            schedule.apply(graph);
-            Debug.dump(schedule, "Final HIR schedule");
-            return schedule;
+            Debug.dump(graph.getLastSchedule(), "Final HIR schedule");
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -232,17 +229,17 @@
 
     @SuppressWarnings("try")
     public static <T extends CompilationResult> void emitBackEnd(StructuredGraph graph, Object stub, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Backend backend, T compilationResult,
-                    CompilationResultBuilderFactory factory, SchedulePhase schedule, RegisterConfig registerConfig, LIRSuites lirSuites) {
-        try (Scope s = Debug.scope("BackEnd", schedule); DebugCloseable a = BackEnd.start()) {
+                    CompilationResultBuilderFactory factory, RegisterConfig registerConfig, LIRSuites lirSuites) {
+        try (Scope s = Debug.scope("BackEnd", graph.getLastSchedule()); DebugCloseable a = BackEnd.start()) {
             // Repeatedly run the LIR code generation pass to improve statistical profiling results.
             for (int i = 0; i < EmitLIRRepeatCount.getValue(); i++) {
                 SchedulePhase dummySchedule = new SchedulePhase();
                 dummySchedule.apply(graph);
-                emitLIR(backend, dummySchedule, graph, stub, cc, registerConfig, lirSuites);
+                emitLIR(backend, graph, stub, cc, registerConfig, lirSuites);
             }
 
             LIRGenerationResult lirGen = null;
-            lirGen = emitLIR(backend, schedule, graph, stub, cc, registerConfig, lirSuites);
+            lirGen = emitLIR(backend, graph, stub, cc, registerConfig, lirSuites);
             try (Scope s2 = Debug.scope("CodeGen", lirGen, lirGen.getLIR())) {
                 int bytecodeSize = graph.method() == null ? 0 : graph.getBytecodeSize();
                 compilationResult.setHasUnsafeAccess(graph.hasUnsafeAccess());
@@ -256,14 +253,14 @@
     }
 
     @SuppressWarnings("try")
-    public static LIRGenerationResult emitLIR(Backend backend, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc, RegisterConfig registerConfig, LIRSuites lirSuites) {
+    public static LIRGenerationResult emitLIR(Backend backend, StructuredGraph graph, Object stub, CallingConvention cc, RegisterConfig registerConfig, LIRSuites lirSuites) {
         try {
-            return emitLIR0(backend, schedule, graph, stub, cc, registerConfig, lirSuites);
+            return emitLIR0(backend, graph, stub, cc, registerConfig, lirSuites);
         } catch (OutOfRegistersException e) {
             if (RegisterPressure.getValue() != null && !RegisterPressure.getValue().equals(ALL_REGISTERS)) {
                 try (OverrideScope s = OptionValue.override(RegisterPressure, ALL_REGISTERS)) {
                     // retry with default register set
-                    return emitLIR0(backend, schedule, graph, stub, cc, registerConfig, lirSuites);
+                    return emitLIR0(backend, graph, stub, cc, registerConfig, lirSuites);
                 }
             } else {
                 throw e;
@@ -272,8 +269,9 @@
     }
 
     @SuppressWarnings("try")
-    private static LIRGenerationResult emitLIR0(Backend backend, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc, RegisterConfig registerConfig, LIRSuites lirSuites) {
+    private static LIRGenerationResult emitLIR0(Backend backend, StructuredGraph graph, Object stub, CallingConvention cc, RegisterConfig registerConfig, LIRSuites lirSuites) {
         try (Scope ds = Debug.scope("EmitLIR"); DebugCloseable a = EmitLIR.start()) {
+            ScheduleResult schedule = graph.getLastSchedule();
             List<Block> blocks = schedule.getCFG().getBlocks();
             Block startBlock = schedule.getCFG().getStartBlock();
             assert startBlock != null;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompilerOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompilerOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.compiler;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * Options related to {@link GraalCompiler}.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugInitializationPropertyProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugInitializationPropertyProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,11 +22,10 @@
  */
 package com.oracle.graal.compiler;
 
-import jdk.vm.ci.service.ServiceProvider;
-
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.DebugInitializationPropertyProvider;
 import com.oracle.graal.debug.GraalDebugConfig;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 /**
  * Sets system properties used in the initialization of {@link Debug} based on the values specified
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -36,9 +36,9 @@
 import com.oracle.graal.lir.phases.LIRPhase;
 import com.oracle.graal.lir.ssa.SSAUtil;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 
 public class LIRGenerationPhase extends LIRPhase<LIRGenerationPhase.LIRGenerationContext> {
 
@@ -46,9 +46,9 @@
         private final NodeLIRBuilderTool nodeLirBuilder;
         private final LIRGeneratorTool lirGen;
         private final StructuredGraph graph;
-        private final SchedulePhase schedule;
+        private final ScheduleResult schedule;
 
-        public LIRGenerationContext(LIRGeneratorTool lirGen, NodeLIRBuilderTool nodeLirBuilder, StructuredGraph graph, SchedulePhase schedule) {
+        public LIRGenerationContext(LIRGeneratorTool lirGen, NodeLIRBuilderTool nodeLirBuilder, StructuredGraph graph, ScheduleResult schedule) {
             this.nodeLirBuilder = nodeLirBuilder;
             this.lirGen = lirGen;
             this.graph = graph;
@@ -61,7 +61,7 @@
                     LIRGenerationPhase.LIRGenerationContext context) {
         NodeLIRBuilderTool nodeLirBuilder = context.nodeLirBuilder;
         StructuredGraph graph = context.graph;
-        SchedulePhase schedule = context.schedule;
+        ScheduleResult schedule = context.schedule;
         for (B b : linearScanOrder) {
             emitBlock(nodeLirBuilder, lirGenRes, (Block) b, graph, schedule.getBlockToNodesMap());
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Tue Jan 05 16:42:05 2016 -0800
@@ -31,7 +31,7 @@
 import java.util.Map.Entry;
 
 import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import com.oracle.graal.compiler.gen.NodeMatchRules;
 import com.oracle.graal.debug.Debug;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyLowTier.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyLowTier.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,6 +29,7 @@
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.ExpandLogicPhase;
 import com.oracle.graal.phases.common.LoweringPhase;
+import com.oracle.graal.phases.schedule.SchedulePhase;
 import com.oracle.graal.phases.tiers.LowTierContext;
 
 public class EconomyLowTier extends PhaseSuite<LowTierContext> {
@@ -42,5 +43,7 @@
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER));
 
         appendPhase(new ExpandLogicPhase());
+
+        appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.FINAL_SCHEDULE));
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Jan 05 16:42:05 2016 -0800
@@ -33,9 +33,6 @@
 import static com.oracle.graal.compiler.common.GraalOptions.PartialEscapeAnalysis;
 import static com.oracle.graal.compiler.common.GraalOptions.UseGraalInstrumentation;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.loop.DefaultLoopPolicies;
 import com.oracle.graal.loop.LoopPolicies;
@@ -43,6 +40,9 @@
 import com.oracle.graal.loop.phases.LoopPeelingPhase;
 import com.oracle.graal.loop.phases.LoopUnswitchingPhase;
 import com.oracle.graal.nodes.spi.LoweringTool;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.ConvertDeoptimizeToGuardPhase;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Tue Jan 05 16:42:05 2016 -0800
@@ -27,11 +27,11 @@
 import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer;
 import static com.oracle.graal.compiler.common.GraalOptions.UseGraalInstrumentation;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.Required;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.nodes.spi.LoweringTool;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
@@ -42,6 +42,7 @@
 import com.oracle.graal.phases.common.RemoveValueProxyPhase;
 import com.oracle.graal.phases.common.UseTrappingNullChecksPhase;
 import com.oracle.graal.phases.common.instrumentation.InlineInstrumentationPhase;
+import com.oracle.graal.phases.schedule.SchedulePhase;
 import com.oracle.graal.phases.tiers.LowTierContext;
 
 public class LowTier extends PhaseSuite<LowTierContext> {
@@ -84,5 +85,7 @@
         appendPhase(new UseTrappingNullChecksPhase());
 
         appendPhase(new DeadCodeEliminationPhase(Required));
+
+        appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.FINAL_SCHEDULE));
     }
 }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Tue Jan 05 16:42:05 2016 -0800
@@ -40,7 +40,7 @@
 import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import com.oracle.graal.debug.DelegatingDebugConfig.Level;
 import com.oracle.graal.debug.internal.DebugHistogramImpl;
@@ -1404,7 +1404,7 @@
     }
 
     private static boolean findMatch(Set<String> haystack, Set<String> haystackSubstrings, String needle) {
-        if (haystack.isEmpty()) {
+        if (haystack.isEmpty() && haystackSubstrings.isEmpty()) {
             // Empty haystack means match all
             return true;
         }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugEnvironment.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugEnvironment.java	Tue Jan 05 16:42:05 2016 -0800
@@ -35,7 +35,7 @@
 import java.util.List;
 
 import jdk.vm.ci.runtime.JVMCI;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 public class DebugEnvironment {
 
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/GraalDebugConfig.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/GraalDebugConfig.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,11 +29,12 @@
 import java.util.List;
 import java.util.Set;
 
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
+
 import jdk.vm.ci.code.BailoutException;
 import jdk.vm.ci.meta.JavaMethod;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 public class GraalDebugConfig implements DebugConfig {
     @SuppressWarnings("all")
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/TTY.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/TTY.java	Tue Jan 05 16:42:05 2016 -0800
@@ -30,7 +30,7 @@
 import java.util.Map;
 import java.util.regex.Pattern;
 
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 /**
  * A collection of static methods for printing debug and informational output to a global
@@ -235,7 +235,7 @@
         out().println(f);
     }
 
-    public static void print(String format, Object... args) {
+    public static void printf(String format, Object... args) {
         out().printf(format, args);
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Tue Jan 05 16:42:05 2016 -0800
@@ -32,9 +32,6 @@
 import java.util.function.Consumer;
 
 import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.compiler.common.CollectionsFactory;
 import com.oracle.graal.debug.Debug;
@@ -44,6 +41,9 @@
 import com.oracle.graal.debug.Fingerprint;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.graph.iterators.NodeIterable;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * This class is a graph container, it contains the set of nodes that belong to this graph.
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Jan 05 16:42:05 2016 -0800
@@ -188,6 +188,12 @@
          * ignored and can therefore safely be {@code null}.
          */
         boolean setStampFromReturnType() default false;
+
+        /**
+         * Determines if the stamp of the instantiated intrinsic node is guaranteed to be non-null.
+         * Generally used in conjunction with {@link #setStampFromReturnType()}.
+         */
+        boolean returnStampIsNonNull() default false;
     }
 
     /**
@@ -670,10 +676,24 @@
     }
 
     public final void replaceAtUsages(Node other) {
-        replaceAtUsages(other, null);
+        replaceAtUsages(other, null, null);
     }
 
     public final void replaceAtUsages(Node other, Predicate<Node> filter) {
+        replaceAtUsages(other, filter, null);
+    }
+
+    public final void replaceAtUsagesAndDelete(Node other) {
+        replaceAtUsages(other, null, this);
+        safeDelete();
+    }
+
+    public final void replaceAtUsagesAndDelete(Node other, Predicate<Node> filter) {
+        replaceAtUsages(other, filter, this);
+        safeDelete();
+    }
+
+    protected void replaceAtUsages(Node other, Predicate<Node> filter, Node toBeDeleted) {
         assert checkReplaceWith(other);
         int i = 0;
         while (i < this.getUsageCount()) {
@@ -681,7 +701,12 @@
             if (filter == null || filter.test(usage)) {
                 boolean result = usage.getNodeClass().getInputEdges().replaceFirst(usage, this, other);
                 assert assertTrue(result, "not found in inputs, usage: %s", usage);
-                maybeNotifyInputChanged(usage);
+                /*
+                 * Don't notify for nodes which are about to be deleted.
+                 */
+                if (toBeDeleted == null || usage != toBeDeleted) {
+                    maybeNotifyInputChanged(usage);
+                }
                 if (other != null) {
                     other.addUsage(usage);
                 }
@@ -823,6 +848,7 @@
     }
 
     private boolean checkDeletion() {
+        assertTrue(isAlive(), "must be alive");
         assertTrue(hasNoUsages(), "cannot delete node %s because of usages: %s", this, usages());
         assertTrue(predecessor == null, "cannot delete node %s because of predecessor: %s", this, predecessor);
         return true;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Tue Jan 05 16:42:05 2016 -0800
@@ -220,11 +220,6 @@
     }
 
     @Override
-    public NodeIterable<Node> distinct() {
-        return this;
-    }
-
-    @Override
     public int count() {
         int count = 0;
         for (long l : bits) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctFilteredNodeIterable.java	Tue Jan 05 16:32:42 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2012, 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 com.oracle.graal.graph.iterators;
-
-import java.util.Iterator;
-
-import com.oracle.graal.graph.Node;
-
-public class DistinctFilteredNodeIterable<T extends Node> extends FilteredNodeIterable<T> {
-
-    public DistinctFilteredNodeIterable(NodeIterable<T> nodeIterable) {
-        super(nodeIterable);
-    }
-
-    @Override
-    public DistinctFilteredNodeIterable<T> distinct() {
-        return this;
-    }
-
-    @Override
-    public Iterator<T> iterator() {
-        return new DistinctPredicatedProxyNodeIterator<>(nodeIterable.iterator(), predicate);
-    }
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctPredicatedProxyNodeIterator.java	Tue Jan 05 16:32:42 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2012, 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 com.oracle.graal.graph.iterators;
-
-import java.util.Iterator;
-
-import com.oracle.graal.graph.Node;
-import com.oracle.graal.graph.NodeBitMap;
-
-public class DistinctPredicatedProxyNodeIterator<T extends Node> extends PredicatedProxyNodeIterator<T> {
-
-    private NodeBitMap visited;
-
-    public DistinctPredicatedProxyNodeIterator(Iterator<T> iterator, NodePredicate predicate) {
-        super(iterator, predicate);
-    }
-
-    @Override
-    protected void forward() {
-        if (current == null) {
-            super.forward();
-            while (!accept(current)) {
-                current = null;
-                super.forward();
-            }
-        }
-    }
-
-    private boolean accept(T n) {
-        if (n == null) {
-            return true;
-        }
-        if (visited == null) {
-            visited = n.graph().createNodeBitMap();
-        }
-        boolean accept = !visited.isMarked(n);
-        visited.mark(n);
-        return accept;
-    }
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java	Tue Jan 05 16:42:05 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -40,24 +40,6 @@
         return this;
     }
 
-    public FilteredNodeIterable<T> or(NodePredicate nodePredicate) {
-        this.predicate = this.predicate.or(nodePredicate);
-        return this;
-    }
-
-    @Override
-    public FilteredNodeIterable<T> nonNull() {
-        this.predicate = this.predicate.and(NodePredicates.isNotNull());
-        return this;
-    }
-
-    @Override
-    public DistinctFilteredNodeIterable<T> distinct() {
-        DistinctFilteredNodeIterable<T> distinct = new DistinctFilteredNodeIterable<>(nodeIterable);
-        distinct.predicate = predicate;
-        return distinct;
-    }
-
     @Override
     public Iterator<T> iterator() {
         return new PredicatedProxyNodeIterator<>(nodeIterable.iterator(), predicate);
@@ -74,8 +56,4 @@
         return this.and(p);
     }
 
-    @Override
-    public FilteredNodeIterable<T> filterInterface(Class<?> iface) {
-        return this.and(NodePredicates.isAInterface(iface));
-    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java	Tue Jan 05 16:42:05 2016 -0800
@@ -36,22 +36,10 @@
         return (NodeIterable<F>) new FilteredNodeIterable<>(this).and(NodePredicates.isA(clazz));
     }
 
-    default NodeIterable<T> filterInterface(Class<?> iface) {
-        return new FilteredNodeIterable<>(this).and(NodePredicates.isAInterface(iface));
-    }
-
     default FilteredNodeIterable<T> filter(NodePredicate predicate) {
         return new FilteredNodeIterable<>(this).and(predicate);
     }
 
-    default FilteredNodeIterable<T> nonNull() {
-        return new FilteredNodeIterable<>(this).and(NodePredicates.isNotNull());
-    }
-
-    default NodeIterable<T> distinct() {
-        return new FilteredNodeIterable<>(this).distinct();
-    }
-
     default List<T> snapshot() {
         ArrayList<T> list = new ArrayList<>();
         snapshotTo(list);
@@ -91,6 +79,13 @@
     }
 
     default boolean contains(T node) {
-        return this.filter(NodePredicates.equals(node)).isNotEmpty();
+        Iterator<T> iterator = iterator();
+        while (iterator.hasNext()) {
+            T next = iterator.next();
+            if (next == node) {
+                return true;
+            }
+        }
+        return false;
     }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodePredicate.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodePredicate.java	Tue Jan 05 16:42:05 2016 -0800
@@ -24,8 +24,6 @@
 
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.iterators.NodePredicates.AndPredicate;
-import com.oracle.graal.graph.iterators.NodePredicates.NotPredicate;
-import com.oracle.graal.graph.iterators.NodePredicates.OrPredicate;
 
 public interface NodePredicate {
 
@@ -34,12 +32,4 @@
     default NodePredicate and(NodePredicate np) {
         return new AndPredicate(this, np);
     }
-
-    default NodePredicate or(NodePredicate np) {
-        return new OrPredicate(this, np);
-    }
-
-    default NodePredicate negate() {
-        return new NotPredicate(this);
-    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodePredicates.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodePredicates.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,7 +29,6 @@
     private static final TautologyPredicate TAUTOLOGY = new TautologyPredicate();
     private static final ContradictionPredicate CONTRADICTION = new ContradictionPredicate();
     private static final IsNullPredicate IS_NULL = new IsNullPredicate();
-    private static final IsNotNullPredicate IS_NOT_NULL = new IsNotNullPredicate();
 
     public static NodePredicate alwaysTrue() {
         return TAUTOLOGY;
@@ -43,18 +42,6 @@
         return IS_NULL;
     }
 
-    public static NodePredicate isNotNull() {
-        return IS_NOT_NULL;
-    }
-
-    public static NodePredicate equals(Node n) {
-        return new EqualsPredicate(n);
-    }
-
-    public static NodePredicate not(NodePredicate a) {
-        return a.negate();
-    }
-
     public static NegativeTypePredicate isNotA(Class<? extends Node> clazz) {
         return new NegativeTypePredicate(clazz);
     }
@@ -63,16 +50,6 @@
         return new PositiveTypePredicate(clazz);
     }
 
-    public static NodePredicate isAInterface(Class<?> iface) {
-        assert iface.isInterface();
-        return new PositiveTypePredicate(iface);
-    }
-
-    public static NodePredicate isNotAInterface(Class<?> iface) {
-        assert iface.isInterface();
-        return new NegativeTypePredicate(iface);
-    }
-
     static final class TautologyPredicate implements NodePredicate {
 
         @Override
@@ -83,14 +60,6 @@
         public NodePredicate and(NodePredicate np) {
             return np;
         }
-
-        public NodePredicate negate() {
-            return CONTRADICTION;
-        }
-
-        public NodePredicate or(NodePredicate np) {
-            return this;
-        }
     }
 
     static final class ContradictionPredicate implements NodePredicate {
@@ -103,14 +72,6 @@
         public NodePredicate and(NodePredicate np) {
             return this;
         }
-
-        public NodePredicate negate() {
-            return TAUTOLOGY;
-        }
-
-        public NodePredicate or(NodePredicate np) {
-            return np;
-        }
     }
 
     static final class AndPredicate implements NodePredicate {
@@ -147,80 +108,12 @@
         }
     }
 
-    static final class OrPredicate implements NodePredicate {
-
-        private final NodePredicate a;
-        private final NodePredicate b;
-
-        OrPredicate(NodePredicate a, NodePredicate b) {
-            this.a = a;
-            this.b = b;
-        }
-
-        @Override
-        public boolean apply(Node n) {
-            return a.apply(n) || b.apply(n);
-        }
-    }
-
     static final class IsNullPredicate implements NodePredicate {
 
         @Override
         public boolean apply(Node n) {
             return n == null;
         }
-
-        public NodePredicate negate() {
-            return IS_NOT_NULL;
-        }
-    }
-
-    static final class IsNotNullPredicate implements NodePredicate {
-
-        @Override
-        public boolean apply(Node n) {
-            return n != null;
-        }
-
-        public NodePredicate negate() {
-            return IS_NULL;
-        }
-    }
-
-    static final class EqualsPredicate implements NodePredicate {
-
-        private final Node u;
-
-        EqualsPredicate(Node u) {
-            this.u = u;
-        }
-
-        @Override
-        public boolean apply(Node n) {
-            return u == n;
-        }
-
-        public NodePredicate negate() {
-            return new NotEqualsPredicate(u);
-        }
-    }
-
-    static final class NotEqualsPredicate implements NodePredicate {
-
-        private final Node u;
-
-        NotEqualsPredicate(Node u) {
-            this.u = u;
-        }
-
-        @Override
-        public boolean apply(Node n) {
-            return u != n;
-        }
-
-        public NodePredicate negate() {
-            return new EqualsPredicate(u);
-        }
     }
 
     public static final class PositiveTypePredicate implements NodePredicate {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotBackend.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2013, 2015, 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 com.oracle.graal.hotspot.aarch64;
+
+import static com.oracle.graal.compiler.common.GraalOptions.ZapStackOnMethodEntry;
+import static java.lang.reflect.Modifier.isStatic;
+import static jdk.vm.ci.aarch64.AArch64.lr;
+import static jdk.vm.ci.aarch64.AArch64.r10;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+import static jdk.vm.ci.code.CallingConvention.Type.JavaCallee;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
+
+import java.lang.reflect.Field;
+import java.util.Set;
+
+import com.oracle.graal.asm.Assembler;
+import com.oracle.graal.asm.Label;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler.ScratchRegister;
+import com.oracle.graal.compiler.aarch64.AArch64NodeMatchRules;
+import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
+import com.oracle.graal.compiler.common.spi.ForeignCallLinkage;
+import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
+import com.oracle.graal.hotspot.HotSpotHostBackend;
+import com.oracle.graal.hotspot.meta.HotSpotForeignCallsProvider;
+import com.oracle.graal.hotspot.meta.HotSpotProviders;
+import com.oracle.graal.hotspot.stubs.Stub;
+import com.oracle.graal.lir.LIR;
+import com.oracle.graal.lir.aarch64.AArch64Call;
+import com.oracle.graal.lir.aarch64.AArch64FrameMap;
+import com.oracle.graal.lir.aarch64.AArch64FrameMapBuilder;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+import com.oracle.graal.lir.asm.CompilationResultBuilderFactory;
+import com.oracle.graal.lir.asm.FrameContext;
+import com.oracle.graal.lir.framemap.FrameMap;
+import com.oracle.graal.lir.framemap.FrameMapBuilder;
+import com.oracle.graal.lir.gen.LIRGenerationResult;
+import com.oracle.graal.lir.gen.LIRGeneratorTool;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CompilationResult;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
+
+/**
+ * HotSpot AArch64 specific backend.
+ */
+public class AArch64HotSpotBackend extends HotSpotHostBackend {
+
+    public AArch64HotSpotBackend(HotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+        super(config, runtime, providers);
+    }
+
+    @Override
+    public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new AArch64FrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull);
+    }
+
+    @Override
+    public FrameMap newFrameMap(RegisterConfig registerConfig) {
+        return new AArch64FrameMap(getCodeCache(), registerConfig, this);
+    }
+
+    @Override
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+        return new AArch64HotSpotLIRGenerator(getProviders(), config(), cc, lirGenRes);
+    }
+
+    @Override
+    public LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) {
+        return new AArch64HotSpotLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, stub);
+    }
+
+    @Override
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
+        return new AArch64HotSpotNodeLIRBuilder(graph, lirGen, new AArch64NodeMatchRules(lirGen));
+    }
+
+    /**
+     * Emits code to do stack overflow checking.
+     *
+     * @param afterFrameInit specifies if the stack pointer has already been adjusted to allocate
+     *            the current frame
+     */
+    protected static void emitStackOverflowCheck(CompilationResultBuilder crb, int pagesToBang, boolean afterFrameInit) {
+        if (pagesToBang > 0) {
+            AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+            int frameSize = crb.frameMap.totalFrameSize();
+            if (frameSize > 0) {
+                int lastFramePage = frameSize / UNSAFE.pageSize();
+                // emit multiple stack bangs for methods with frames larger than a page
+                for (int i = 0; i <= lastFramePage; i++) {
+                    int disp = (i + pagesToBang) * UNSAFE.pageSize();
+                    if (afterFrameInit) {
+                        disp -= frameSize;
+                    }
+                    crb.blockComment("[stack overflow check]");
+                    try (ScratchRegister sc = masm.getScratchRegister()) {
+                        Register scratch = sc.getRegister();
+                        AArch64Address address = masm.makeAddress(sp, -disp, scratch, 8, /* allowOverwrite */false);
+                        masm.str(64, zr, address);
+                    }
+                }
+            }
+        }
+    }
+
+    private class HotSpotFrameContext implements FrameContext {
+        final boolean isStub;
+
+        HotSpotFrameContext(boolean isStub) {
+            this.isStub = isStub;
+        }
+
+        @Override
+        public void enter(CompilationResultBuilder crb) {
+            FrameMap frameMap = crb.frameMap;
+            final int frameSize = frameMap.frameSize();
+            final int totalFrameSize = frameMap.totalFrameSize();
+            assert frameSize + 2 * crb.target.arch.getWordSize() == totalFrameSize : "total framesize should be framesize + 2 words";
+            AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+            if (!isStub && pagesToBang > 0) {
+                emitStackOverflowCheck(crb, pagesToBang, false);
+            }
+            crb.blockComment("[method prologue]");
+
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                // save link register and framepointer
+                masm.mov(64, scratch, sp);
+                AArch64Address address = AArch64Address.createPreIndexedImmediateAddress(scratch, -crb.target.arch.getWordSize());
+                masm.str(64, lr, address);
+                masm.str(64, fp, address);
+                // Update framepointer
+                masm.mov(64, fp, scratch);
+
+                if (ZapStackOnMethodEntry.getValue()) {
+                    int intSize = 4;
+                    address = AArch64Address.createPreIndexedImmediateAddress(scratch, -intSize);
+                    try (ScratchRegister sc2 = masm.getScratchRegister()) {
+                        Register value = sc2.getRegister();
+                        masm.mov(value, 0xC1C1C1C1);
+                        for (int i = 0; i < frameSize; i += intSize) {
+                            masm.str(32, value, address);
+                        }
+                    }
+                    masm.mov(64, sp, scratch);
+                } else {
+                    if (AArch64MacroAssembler.isArithmeticImmediate(totalFrameSize)) {
+                        masm.sub(64, sp, scratch, frameSize);
+                    } else {
+                        try (ScratchRegister sc2 = masm.getScratchRegister()) {
+                            Register scratch2 = sc2.getRegister();
+                            masm.mov(scratch2, frameSize);
+                            masm.sub(64, sp, scratch, scratch2);
+                        }
+                    }
+                }
+            }
+            crb.blockComment("[code body]");
+        }
+
+        @Override
+        public void leave(CompilationResultBuilder crb) {
+            AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+            crb.blockComment("[method epilogue]");
+            final int frameSize = crb.frameMap.totalFrameSize();
+            if (AArch64MacroAssembler.isArithmeticImmediate(frameSize)) {
+                masm.add(64, sp, sp, frameSize);
+            } else {
+                try (ScratchRegister sc = masm.getScratchRegister()) {
+                    Register scratch = sc.getRegister();
+                    masm.mov(scratch, frameSize);
+                    masm.add(64, sp, sp, scratch);
+                }
+            }
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                // restore link register and framepointer
+                masm.mov(64, scratch, sp);
+                AArch64Address address = AArch64Address.createPostIndexedImmediateAddress(scratch, crb.target.arch.getWordSize());
+                masm.ldr(64, fp, address);
+                masm.ldr(64, lr, address);
+                masm.mov(64, sp, scratch);
+            }
+        }
+
+        @Override
+        public boolean hasFrame() {
+            return true;
+        }
+    }
+
+    @Override
+    protected Assembler createAssembler(FrameMap frameMap) {
+        return new AArch64MacroAssembler(getTarget());
+    }
+
+    @Override
+    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRen, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
+        AArch64HotSpotLIRGenerationResult gen = (AArch64HotSpotLIRGenerationResult) lirGenRen;
+        LIR lir = gen.getLIR();
+        assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
+
+        Stub stub = gen.getStub();
+        Assembler masm = createAssembler(frameMap);
+        HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null);
+
+        CompilationResultBuilder crb = new CompilationResultBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult);
+        crb.setTotalFrameSize(frameMap.frameSize());
+        StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot();
+        if (deoptimizationRescueSlot != null && stub == null) {
+            crb.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot));
+        }
+
+        if (stub != null) {
+            Set<Register> definedRegisters = gatherDefinedRegisters(lir);
+            updateStub(stub, definedRegisters, gen.getCalleeSaveInfo(), frameMap);
+        }
+        return crb;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
+        AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig regConfig = frameMap.getRegisterConfig();
+        HotSpotVMConfig config = config();
+        Label verifiedStub = new Label();
+
+        emitCodePrefix(crb, installedCodeOwner, masm, regConfig, config, verifiedStub);
+        emitCodeBody(crb, lir);
+        emitCodeSuffix(crb, masm, config, frameMap);
+    }
+
+    private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod installedCodeOwner, AArch64MacroAssembler masm, RegisterConfig regConfig, HotSpotVMConfig config, Label verifiedStub) {
+        HotSpotProviders providers = getProviders();
+        if (installedCodeOwner != null && !isStatic(installedCodeOwner.getModifiers())) {
+            crb.recordMark(config.MARKID_UNVERIFIED_ENTRY);
+            CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, getTarget(), false);
+            // See definition of IC_Klass in c1_LIRAssembler_aarch64.cpp
+            // equal to scratch(1) careful!
+            Register inlineCacheKlass = AArch64HotSpotRegisterConfig.inlineCacheRegister;
+            Register receiver = asRegister(cc.getArgument(0));
+            int transferSize = config.useCompressedClassPointers ? 4 : 8;
+            AArch64Address klassAddress = masm.makeAddress(receiver, config.hubOffset, transferSize);
+
+            // Are r10 and r11 available scratch registers here? One would hope so.
+            Register klass = r10;
+            if (config.useCompressedClassPointers) {
+                masm.ldr(32, klass, klassAddress);
+                AArch64HotSpotMove.decodeKlassPointer(masm, klass, klass, providers.getRegisters().getHeapBaseRegister(), config.getKlassEncoding());
+            } else {
+                masm.ldr(64, klass, klassAddress);
+            }
+            masm.cmp(64, inlineCacheKlass, klass);
+            // conditional jumps have a much lower range than unconditional ones, which can be a
+            // problem because
+            // the miss handler could be out of range.
+            masm.branchConditionally(AArch64Assembler.ConditionFlag.EQ, verifiedStub);
+            AArch64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(IC_MISS_HANDLER));
+        }
+        masm.align(config.codeEntryAlignment);
+        crb.recordMark(config.MARKID_OSR_ENTRY);
+        masm.bind(verifiedStub);
+        crb.recordMark(config.MARKID_VERIFIED_ENTRY);
+    }
+
+    private static void emitCodeBody(CompilationResultBuilder crb, LIR lir) {
+        crb.emit(lir);
+    }
+
+    private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, HotSpotVMConfig config, FrameMap frameMap) {
+        HotSpotProviders providers = getProviders();
+        HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
+        if (!frameContext.isStub) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
+                crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
+                ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER);
+                Register helper = AArch64Call.isNearCall(linkage) ? null : scratch;
+                AArch64Call.directCall(crb, masm, linkage, helper, null);
+
+                crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
+                linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER);
+                helper = AArch64Call.isNearCall(linkage) ? null : scratch;
+                AArch64Call.directCall(crb, masm, linkage, helper, null);
+            }
+        } else {
+            // No need to emit the stubs for entries back into the method since
+            // it has no calls that can cause such "return" entries
+            assert !frameMap.accessesCallerFrame();
+        }
+    }
+
+    @Override
+    public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new AArch64HotSpotRegisterAllocationConfig(registerConfigNonNull);
+    }
+
+    private static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2013, 2015, 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 com.oracle.graal.hotspot.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.inittimer.InitTimer.timer;
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig;
+import jdk.vm.ci.inittimer.InitTimer;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.runtime.JVMCIBackend;
+
+import com.oracle.graal.api.replacements.SnippetReflectionProvider;
+import com.oracle.graal.compiler.aarch64.AArch64AddressLowering;
+import com.oracle.graal.compiler.aarch64.AArch64SuitesProvider;
+import com.oracle.graal.hotspot.DefaultHotSpotGraalCompilerFactory;
+import com.oracle.graal.hotspot.HotSpotBackend;
+import com.oracle.graal.hotspot.HotSpotBackendFactory;
+import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
+import com.oracle.graal.hotspot.HotSpotReplacementsImpl;
+import com.oracle.graal.hotspot.meta.HotSpotForeignCallsProvider;
+import com.oracle.graal.hotspot.meta.HotSpotGraalConstantReflectionProvider;
+import com.oracle.graal.hotspot.meta.HotSpotGraphBuilderPlugins;
+import com.oracle.graal.hotspot.meta.HotSpotHostForeignCallsProvider;
+import com.oracle.graal.hotspot.meta.HotSpotLoweringProvider;
+import com.oracle.graal.hotspot.meta.HotSpotProviders;
+import com.oracle.graal.hotspot.meta.HotSpotRegisters;
+import com.oracle.graal.hotspot.meta.HotSpotRegistersProvider;