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