1 /*
   2  * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.asm.sparc;
  24 
  25 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
  26 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN;
  27 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Icc;
  28 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
  29 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Always;
  30 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal;
  31 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z;
  32 import static jdk.vm.ci.sparc.SPARC.g0;
  33 import static jdk.vm.ci.sparc.SPARC.g3;
  34 import static jdk.vm.ci.sparc.SPARC.i7;
  35 import static jdk.vm.ci.sparc.SPARC.o7;
  36 
  37 import org.graalvm.compiler.asm.AbstractAddress;
  38 import org.graalvm.compiler.asm.Label;
  39 
  40 import jdk.vm.ci.code.Register;
  41 import jdk.vm.ci.code.TargetDescription;
  42 import jdk.vm.ci.sparc.SPARC.CPUFeature;
  43 
  44 public class SPARCMacroAssembler extends SPARCAssembler {
  45 
  46     /**
  47      * A sentinel value used as a place holder in an instruction stream for an address that will be
  48      * patched.
  49      */
  50     private static final SPARCAddress Placeholder = new SPARCAddress(g0, 0);
  51     private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(g3), new ScratchRegister(o7)};
  52     // Points to the next free scratch register
  53     private int nextFreeScratchRegister = 0;
  54     /**
  55      * Use ld [reg+simm13], reg for loading constants (User has to make sure, that the size of the
  56      * constant table does not exceed simm13).
  57      */
  58     private boolean immediateConstantLoad;
  59 
  60     public SPARCMacroAssembler(TargetDescription target) {
  61         super(target);
  62     }
  63 
  64     /**
  65      * @see #immediateConstantLoad
  66      */
  67     public void setImmediateConstantLoad(boolean immediateConstantLoad) {
  68         this.immediateConstantLoad = immediateConstantLoad;
  69     }
  70 
  71     @Override
  72     public void align(int modulus) {
  73         while (position() % modulus != 0) {
  74             nop();
  75         }
  76     }
  77 
  78     @Override
  79     public void jmp(Label l) {
  80         BPCC.emit(this, Xcc, Always, NOT_ANNUL, PREDICT_NOT_TAKEN, l);
  81         nop();  // delay slot
  82     }
  83 
  84     @Override
  85     protected final void patchJumpTarget(int branch, int branchTarget) {
  86         final int disp = (branchTarget - branch) / 4;
  87         final int inst = getInt(branch);
  88         ControlTransferOp op = (ControlTransferOp) getSPARCOp(inst);
  89         int newInst = op.setDisp(inst, disp);
  90         emitInt(newInst, branch);
  91     }
  92 
  93     @Override
  94     public AbstractAddress makeAddress(Register base, int displacement) {
  95         return new SPARCAddress(base, displacement);
  96     }
  97 
  98     @Override
  99     public AbstractAddress getPlaceholder(int instructionStartPosition) {
 100         return Placeholder;
 101     }
 102 
 103     @Override
 104     public final void ensureUniquePC() {
 105         nop();
 106     }
 107 
 108     public void cas(Register rs1, Register rs2, Register rd) {
 109         casa(rs1, rs2, rd, Asi.ASI_PRIMARY);
 110     }
 111 
 112     public void casx(Register rs1, Register rs2, Register rd) {
 113         casxa(rs1, rs2, rd, Asi.ASI_PRIMARY);
 114     }
 115 
 116     public void clr(Register dst) {
 117         or(g0, g0, dst);
 118     }
 119 
 120     public void clrb(SPARCAddress addr) {
 121         stb(g0, addr);
 122     }
 123 
 124     public void clrh(SPARCAddress addr) {
 125         sth(g0, addr);
 126     }
 127 
 128     public void clrx(SPARCAddress addr) {
 129         stx(g0, addr);
 130     }
 131 
 132     public void cmp(Register rs1, Register rs2) {
 133         subcc(rs1, rs2, g0);
 134     }
 135 
 136     public void cmp(Register rs1, int simm13) {
 137         subcc(rs1, simm13, g0);
 138     }
 139 
 140     public void dec(Register rd) {
 141         sub(rd, 1, rd);
 142     }
 143 
 144     public void dec(int simm13, Register rd) {
 145         sub(rd, simm13, rd);
 146     }
 147 
 148     public void jmp(SPARCAddress address) {
 149         jmpl(address.getBase(), address.getDisplacement(), g0);
 150     }
 151 
 152     public void jmp(Register rd) {
 153         jmpl(rd, 0, g0);
 154     }
 155 
 156     public void neg(Register rs1, Register rd) {
 157         sub(g0, rs1, rd);
 158     }
 159 
 160     public void neg(Register rd) {
 161         sub(g0, rd, rd);
 162     }
 163 
 164     public void mov(Register rs, Register rd) {
 165         or(g0, rs, rd);
 166     }
 167 
 168     public void mov(int simm13, Register rd) {
 169         or(g0, simm13, rd);
 170     }
 171 
 172     public void not(Register rs1, Register rd) {
 173         xnor(rs1, g0, rd);
 174     }
 175 
 176     public void not(Register rd) {
 177         xnor(rd, g0, rd);
 178     }
 179 
 180     public void restoreWindow() {
 181         restore(g0, g0, g0);
 182     }
 183 
 184     public void ret() {
 185         jmpl(i7, 8, g0);
 186     }
 187 
 188     /**
 189      * Generates sethi hi22(value), dst; or dst, lo10(value), dst; code.
 190      */
 191     public void setw(int value, Register dst, boolean forceRelocatable) {
 192         if (!forceRelocatable && isSimm13(value)) {
 193             or(g0, value, dst);
 194         } else {
 195             sethi(hi22(value), dst);
 196             or(dst, lo10(value), dst);
 197         }
 198     }
 199 
 200     public void setx(long value, Register dst, boolean forceRelocatable) {
 201         int lo = (int) (value & ~0);
 202         sethix(value, dst, forceRelocatable);
 203         if (lo10(lo) != 0 || forceRelocatable) {
 204             add(dst, lo10(lo), dst);
 205         }
 206     }
 207 
 208     public void sethix(long value, Register dst, boolean forceRelocatable) {
 209         final int hi = (int) (value >> 32);
 210         final int lo = (int) (value & ~0);
 211 
 212         // This is the same logic as MacroAssembler::internal_set.
 213         final int startPc = position();
 214         if (hi == 0 && lo >= 0) {
 215             sethi(hi22(lo), dst);
 216         } else if (hi == -1) {
 217             sethi(hi22(~lo), dst);
 218             xor(dst, ~lo10(~0), dst);
 219         } else {
 220             final int shiftcnt;
 221             final int shiftcnt2;
 222             sethi(hi22(hi), dst);
 223             if ((hi & 0x3ff) != 0) {                                  // Any bits?
 224                 // msb 32-bits are now in lsb 32
 225                 or(dst, hi & 0x3ff, dst);
 226             }
 227             if ((lo & 0xFFFFFC00) != 0) {                             // done?
 228                 if (((lo >> 20) & 0xfff) != 0) {                      // Any bits set?
 229                     // Make room for next 12 bits
 230                     sllx(dst, 12, dst);
 231                     // Or in next 12
 232                     or(dst, (lo >> 20) & 0xfff, dst);
 233                     shiftcnt = 0;                                     // We already shifted
 234                 } else {
 235                     shiftcnt = 12;
 236                 }
 237                 if (((lo >> 10) & 0x3ff) != 0) {
 238                     // Make room for last 10 bits
 239                     sllx(dst, shiftcnt + 10, dst);
 240                     // Or in next 10
 241                     or(dst, (lo >> 10) & 0x3ff, dst);
 242                     shiftcnt2 = 0;
 243                 } else {
 244                     shiftcnt2 = 10;
 245                 }
 246                 // Shift leaving disp field 0'd
 247                 sllx(dst, shiftcnt2 + 10, dst);
 248             } else {
 249                 sllx(dst, 32, dst);
 250             }
 251         }
 252         // Pad out the instruction sequence so it can be patched later.
 253         if (forceRelocatable) {
 254             while (position() < (startPc + (INSTRUCTION_SIZE * 7))) {
 255                 nop();
 256             }
 257         }
 258     }
 259 
 260     public void signx(Register rs, Register rd) {
 261         sra(rs, g0, rd);
 262     }
 263 
 264     public void signx(Register rd) {
 265         sra(rd, g0, rd);
 266     }
 267 
 268     public boolean isImmediateConstantLoad() {
 269         return immediateConstantLoad;
 270     }
 271 
 272     public ScratchRegister getScratchRegister() {
 273         return scratchRegister[nextFreeScratchRegister++];
 274     }
 275 
 276     public class ScratchRegister implements AutoCloseable {
 277         private final Register register;
 278 
 279         public ScratchRegister(Register register) {
 280             super();
 281             this.register = register;
 282         }
 283 
 284         public Register getRegister() {
 285             return register;
 286         }
 287 
 288         @Override
 289         public void close() {
 290             assert nextFreeScratchRegister > 0 : "Close called too often";
 291             nextFreeScratchRegister--;
 292         }
 293     }
 294 
 295     public void compareBranch(Register rs1, Register rs2, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction) {
 296         assert isCPURegister(rs1, rs2);
 297         assert ccRegister == Icc || ccRegister == Xcc;
 298         if (hasFeature(CPUFeature.CBCOND)) {
 299             if (delaySlotInstruction != null) {
 300                 delaySlotInstruction.run();
 301             }
 302             CBCOND.emit(this, cond, ccRegister == Xcc, rs1, rs2, label);
 303         } else {
 304             if (cond == Equal && rs1.equals(g0)) {
 305                 BPR.emit(this, Rc_z, NOT_ANNUL, predict, rs1, label);
 306             } else {
 307                 cmp(rs1, rs2);
 308                 BPCC.emit(this, ccRegister, cond, NOT_ANNUL, predict, label);
 309             }
 310             if (delaySlotInstruction != null) {
 311                 int positionBefore = position();
 312                 delaySlotInstruction.run();
 313                 int positionAfter = position();
 314                 assert positionBefore - positionAfter > INSTRUCTION_SIZE : "Emitted more than one instruction into delay slot";
 315             } else {
 316                 nop();
 317             }
 318         }
 319     }
 320 
 321     public void compareBranch(Register rs1, int simm, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction) {
 322         assert isCPURegister(rs1);
 323         assert ccRegister == Icc || ccRegister == Xcc;
 324         if (hasFeature(CPUFeature.CBCOND)) {
 325             if (delaySlotInstruction != null) {
 326                 delaySlotInstruction.run();
 327             }
 328             CBCOND.emit(this, cond, ccRegister == Xcc, rs1, simm, label);
 329         } else {
 330             if (cond == Equal && simm == 0) {
 331                 BPR.emit(this, Rc_z, NOT_ANNUL, PREDICT_NOT_TAKEN, rs1, label);
 332             } else {
 333                 cmp(rs1, simm);
 334                 BPCC.emit(this, ccRegister, cond, NOT_ANNUL, predict, label);
 335             }
 336             if (delaySlotInstruction != null) {
 337                 int positionBefore = position();
 338                 delaySlotInstruction.run();
 339                 int positionAfter = position();
 340                 assert positionBefore - positionAfter > INSTRUCTION_SIZE : "Emitted more than one instruction into delay slot";
 341             } else {
 342                 nop();
 343             }
 344         }
 345     }
 346 }