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