1 /*
   2  * Copyright (c) 2009, 2018, 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.amd64;
  26 
  27 import static jdk.vm.ci.amd64.AMD64.rbp;
  28 import static jdk.vm.ci.amd64.AMD64.rsp;
  29 import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseIncDec;
  30 import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmLoadAndClearUpper;
  31 import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmRegToRegMoveAll;
  32 
  33 import org.graalvm.compiler.core.common.NumUtil;
  34 
  35 import jdk.vm.ci.amd64.AMD64;
  36 import jdk.vm.ci.amd64.AMD64Kind;
  37 import jdk.vm.ci.code.Register;
  38 import jdk.vm.ci.code.TargetDescription;
  39 
  40 /**
  41  * This class implements commonly used X86 code patterns.
  42  */
  43 public class AMD64MacroAssembler extends AMD64Assembler {
  44 
  45     public AMD64MacroAssembler(TargetDescription target) {
  46         super(target);
  47     }
  48 
  49     public final void decrementq(Register reg, int value) {
  50         if (value == Integer.MIN_VALUE) {
  51             subq(reg, value);
  52             return;
  53         }
  54         if (value < 0) {
  55             incrementq(reg, -value);
  56             return;
  57         }
  58         if (value == 0) {
  59             return;
  60         }
  61         if (value == 1 && UseIncDec) {
  62             decq(reg);
  63         } else {
  64             subq(reg, value);
  65         }
  66     }
  67 
  68     public final void decrementq(AMD64Address dst, int value) {
  69         if (value == Integer.MIN_VALUE) {
  70             subq(dst, value);
  71             return;
  72         }
  73         if (value < 0) {
  74             incrementq(dst, -value);
  75             return;
  76         }
  77         if (value == 0) {
  78             return;
  79         }
  80         if (value == 1 && UseIncDec) {
  81             decq(dst);
  82         } else {
  83             subq(dst, value);
  84         }
  85     }
  86 
  87     public final void enter(int frameSize) {
  88         if (NumUtil.isUShort(frameSize)) {
  89             // Can use enter instruction only for frame size that fits in 16 bits.
  90             emitByte(0xC8);
  91             emitShort(frameSize);
  92             emitByte(0x00);
  93         } else {
  94             // Fall back to manual sequence.
  95             push(rbp);
  96             movq(rbp, rsp);
  97             decrementq(rsp, frameSize);
  98         }
  99     }
 100 
 101     public void incrementq(Register reg, int value) {
 102         if (value == Integer.MIN_VALUE) {
 103             addq(reg, value);
 104             return;
 105         }
 106         if (value < 0) {
 107             decrementq(reg, -value);
 108             return;
 109         }
 110         if (value == 0) {
 111             return;
 112         }
 113         if (value == 1 && UseIncDec) {
 114             incq(reg);
 115         } else {
 116             addq(reg, value);
 117         }
 118     }
 119 
 120     public final void incrementq(AMD64Address dst, int value) {
 121         if (value == Integer.MIN_VALUE) {
 122             addq(dst, value);
 123             return;
 124         }
 125         if (value < 0) {
 126             decrementq(dst, -value);
 127             return;
 128         }
 129         if (value == 0) {
 130             return;
 131         }
 132         if (value == 1 && UseIncDec) {
 133             incq(dst);
 134         } else {
 135             addq(dst, value);
 136         }
 137     }
 138 
 139     public final void movptr(Register dst, AMD64Address src) {
 140         movq(dst, src);
 141     }
 142 
 143     public final void movptr(AMD64Address dst, Register src) {
 144         movq(dst, src);
 145     }
 146 
 147     public final void movptr(AMD64Address dst, int src) {
 148         movslq(dst, src);
 149     }
 150 
 151     public final void cmpptr(Register src1, Register src2) {
 152         cmpq(src1, src2);
 153     }
 154 
 155     public final void cmpptr(Register src1, AMD64Address src2) {
 156         cmpq(src1, src2);
 157     }
 158 
 159     public final void decrementl(Register reg) {
 160         decrementl(reg, 1);
 161     }
 162 
 163     public final void decrementl(Register reg, int value) {
 164         if (value == Integer.MIN_VALUE) {
 165             subl(reg, value);
 166             return;
 167         }
 168         if (value < 0) {
 169             incrementl(reg, -value);
 170             return;
 171         }
 172         if (value == 0) {
 173             return;
 174         }
 175         if (value == 1 && UseIncDec) {
 176             decl(reg);
 177         } else {
 178             subl(reg, value);
 179         }
 180     }
 181 
 182     public final void decrementl(AMD64Address dst, int value) {
 183         if (value == Integer.MIN_VALUE) {
 184             subl(dst, value);
 185             return;
 186         }
 187         if (value < 0) {
 188             incrementl(dst, -value);
 189             return;
 190         }
 191         if (value == 0) {
 192             return;
 193         }
 194         if (value == 1 && UseIncDec) {
 195             decl(dst);
 196         } else {
 197             subl(dst, value);
 198         }
 199     }
 200 
 201     public final void incrementl(Register reg, int value) {
 202         if (value == Integer.MIN_VALUE) {
 203             addl(reg, value);
 204             return;
 205         }
 206         if (value < 0) {
 207             decrementl(reg, -value);
 208             return;
 209         }
 210         if (value == 0) {
 211             return;
 212         }
 213         if (value == 1 && UseIncDec) {
 214             incl(reg);
 215         } else {
 216             addl(reg, value);
 217         }
 218     }
 219 
 220     public final void incrementl(AMD64Address dst, int value) {
 221         if (value == Integer.MIN_VALUE) {
 222             addl(dst, value);
 223             return;
 224         }
 225         if (value < 0) {
 226             decrementl(dst, -value);
 227             return;
 228         }
 229         if (value == 0) {
 230             return;
 231         }
 232         if (value == 1 && UseIncDec) {
 233             incl(dst);
 234         } else {
 235             addl(dst, value);
 236         }
 237     }
 238 
 239     public void movflt(Register dst, Register src) {
 240         assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
 241         if (UseXmmRegToRegMoveAll) {
 242             movaps(dst, src);
 243         } else {
 244             movss(dst, src);
 245         }
 246     }
 247 
 248     public void movflt(Register dst, AMD64Address src) {
 249         assert dst.getRegisterCategory().equals(AMD64.XMM);
 250         movss(dst, src);
 251     }
 252 
 253     public void movflt(AMD64Address dst, Register src) {
 254         assert src.getRegisterCategory().equals(AMD64.XMM);
 255         movss(dst, src);
 256     }
 257 
 258     public void movdbl(Register dst, Register src) {
 259         assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
 260         if (UseXmmRegToRegMoveAll) {
 261             movapd(dst, src);
 262         } else {
 263             movsd(dst, src);
 264         }
 265     }
 266 
 267     public void movdbl(Register dst, AMD64Address src) {
 268         assert dst.getRegisterCategory().equals(AMD64.XMM);
 269         if (UseXmmLoadAndClearUpper) {
 270             movsd(dst, src);
 271         } else {
 272             movlpd(dst, src);
 273         }
 274     }
 275 
 276     public void movdbl(AMD64Address dst, Register src) {
 277         assert src.getRegisterCategory().equals(AMD64.XMM);
 278         movsd(dst, src);
 279     }
 280 
 281     /**
 282      * Non-atomic write of a 64-bit constant to memory. Do not use if the address might be a
 283      * volatile field!
 284      */
 285     public final void movlong(AMD64Address dst, long src) {
 286         if (NumUtil.isInt(src)) {
 287             AMD64MIOp.MOV.emit(this, OperandSize.QWORD, dst, (int) src);
 288         } else {
 289             AMD64Address high = new AMD64Address(dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4);
 290             movl(dst, (int) (src & 0xFFFFFFFF));
 291             movl(high, (int) (src >> 32));
 292         }
 293     }
 294 
 295     public final void setl(ConditionFlag cc, Register dst) {
 296         setb(cc, dst);
 297         movzbl(dst, dst);
 298     }
 299 
 300     public final void setq(ConditionFlag cc, Register dst) {
 301         setb(cc, dst);
 302         movzbq(dst, dst);
 303     }
 304 
 305     public final void flog(Register dest, Register value, boolean base10) {
 306         if (base10) {
 307             fldlg2();
 308         } else {
 309             fldln2();
 310         }
 311         AMD64Address tmp = trigPrologue(value);
 312         fyl2x();
 313         trigEpilogue(dest, tmp);
 314     }
 315 
 316     public final void fsin(Register dest, Register value) {
 317         AMD64Address tmp = trigPrologue(value);
 318         fsin();
 319         trigEpilogue(dest, tmp);
 320     }
 321 
 322     public final void fcos(Register dest, Register value) {
 323         AMD64Address tmp = trigPrologue(value);
 324         fcos();
 325         trigEpilogue(dest, tmp);
 326     }
 327 
 328     public final void ftan(Register dest, Register value) {
 329         AMD64Address tmp = trigPrologue(value);
 330         fptan();
 331         fstp(0); // ftan pushes 1.0 in addition to the actual result, pop
 332         trigEpilogue(dest, tmp);
 333     }
 334 
 335     public final void fpop() {
 336         ffree(0);
 337         fincstp();
 338     }
 339 
 340     private AMD64Address trigPrologue(Register value) {
 341         assert value.getRegisterCategory().equals(AMD64.XMM);
 342         AMD64Address tmp = new AMD64Address(AMD64.rsp);
 343         subq(AMD64.rsp, AMD64Kind.DOUBLE.getSizeInBytes());
 344         movdbl(tmp, value);
 345         fldd(tmp);
 346         return tmp;
 347     }
 348 
 349     private void trigEpilogue(Register dest, AMD64Address tmp) {
 350         assert dest.getRegisterCategory().equals(AMD64.XMM);
 351         fstpd(tmp);
 352         movdbl(dest, tmp);
 353         addq(AMD64.rsp, AMD64Kind.DOUBLE.getSizeInBytes());
 354     }
 355 
 356 }