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