1 /*
   2  * Copyright (c) 2009, 2012, 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 package com.oracle.graal.asm.hsail;
  25 
  26 import com.oracle.graal.api.code.*;
  27 
  28 import static com.oracle.graal.api.code.ValueUtil.*;
  29 import com.oracle.graal.api.meta.*;
  30 import com.oracle.graal.hsail.*;
  31 import com.oracle.graal.graph.GraalInternalError;
  32 import com.amd.okra.OkraUtil;
  33 
  34 /**
  35  * This class contains routines to emit HSAIL assembly code.
  36  */
  37 public class HSAILAssembler extends AbstractHSAILAssembler {
  38 
  39     /**
  40      * Stack size in bytes (used to keep track of spilling).
  41      */
  42     private int maxDataTypeSize;
  43 
  44     /**
  45      * Maximum stack offset used by a store operation.
  46      */
  47     private long maxStackOffset = 0;
  48 
  49     public long upperBoundStackSize() {
  50         return maxStackOffset + maxDataTypeSize;
  51     }
  52 
  53     public HSAILAssembler(TargetDescription target) {
  54         super(target);
  55     }
  56 
  57     @Override
  58     public HSAILAddress makeAddress(Register base, int displacement) {
  59         return new HSAILAddress(base, displacement);
  60     }
  61 
  62     @Override
  63     public HSAILAddress getPlaceholder() {
  64         return null;
  65     }
  66 
  67     public final void undefined(String str) {
  68         emitString("undefined operation " + str);
  69     }
  70 
  71     public final void exit() {
  72         emitString("ret;" + "");
  73     }
  74 
  75     /**
  76      * An Object is only moved into a register when it is a class constant (which is not really a
  77      * constant because it can be moved by GC). Because we can't patch the HSAIL once it is
  78      * finalized, we handle changes due to GC movement by dereferencing a global reference that is
  79      * created by JNI since these JNI global references do not move.
  80      */
  81     public final void mov(Register a, Object obj) {
  82         if (obj instanceof Class) {
  83             Class<?> clazz = (Class<?>) obj;
  84             long refHandle = OkraUtil.getRefHandle(clazz);
  85             String className = clazz.getName();
  86             String regName = "$d" + a.encoding();
  87             emitString("mov_b64 " + regName + ", 0x" + Long.toHexString(refHandle) + ";  // handle for " + className);
  88             emitString("ld_global_u64 " + regName + ", [" + regName + "];");
  89         } else {
  90             throw GraalInternalError.shouldNotReachHere("mov from object not a class");
  91         }
  92 
  93     }
  94 
  95     public final void emitMov(Value dst, Value src) {
  96         if (isRegister(dst) && isConstant(src) && src.getKind().getStackKind() == Kind.Object) {
  97             mov(asRegister(dst), (asConstant(src)).asObject());
  98         } else {
  99             String argtype = getArgType(dst).substring(1);
 100             emitString("mov_b" + argtype + " " + mapRegOrConstToString(dst) + ", " + mapRegOrConstToString(src) + ";");
 101         }
 102     }
 103 
 104     public final void emitLoad(Value dest, HSAILAddress addr) {
 105         emitString("ld_global_" + getArgType(dest) + " " + HSAIL.mapRegister(dest) + ", " + mapAddress(addr) + ";");
 106     }
 107 
 108     public final void emitSpillLoad(Value dest, Value src) {
 109         emitString("ld_spill_" + getArgType(dest) + " " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapStackSlot(src) + ";");
 110     }
 111 
 112     public final void emitStore(Value src, HSAILAddress addr) {
 113         emitString("st_global_" + getArgType(src) + " " + HSAIL.mapRegister(src) + ", " + mapAddress(addr) + ";");
 114     }
 115 
 116     public final void emitSpillStore(Value src, Value dest) {
 117         int sizestored = getArgSize(src);
 118         if (maxDataTypeSize < sizestored) {
 119             maxDataTypeSize = sizestored;
 120         }
 121         int stackoffset = HSAIL.getStackOffset(dest);
 122         if (maxStackOffset < stackoffset) {
 123             maxStackOffset = stackoffset;
 124         }
 125         emitString("st_spill_" + getArgType(src) + " " + HSAIL.mapRegister(src) + ", " + HSAIL.mapStackSlot(dest) + ";");
 126     }
 127 
 128     public void cbr(String target1) {
 129         emitString("cbr " + "$c0" + ", " + target1 + ";");
 130     }
 131 
 132     public int getArgSize(Value src) {
 133         switch (src.getKind()) {
 134             case Int:
 135             case Float:
 136                 return 32;
 137             case Double:
 138             case Long:
 139             case Object:
 140                 return 64;
 141             default:
 142                 throw GraalInternalError.shouldNotReachHere();
 143         }
 144     }
 145 
 146     public static final String getArgType(Value src) {
 147         String prefix = "";
 148         switch (src.getKind()) {
 149             case Float:
 150                 prefix = "f32";
 151                 break;
 152             case Double:
 153                 prefix = "f64";
 154                 break;
 155             case Int:
 156                 prefix = "s32";
 157                 break;
 158             case Long:
 159                 prefix = "s64";
 160                 break;
 161             case Object:
 162                 prefix = "u64";
 163                 break;
 164             default:
 165                 throw GraalInternalError.shouldNotReachHere();
 166         }
 167         return prefix;
 168     }
 169 
 170     public static final String getArgTypeForceUnsigned(Value src) {
 171         switch (src.getKind()) {
 172             case Int:
 173                 return "u32";
 174             case Long:
 175             case Object:
 176                 return "u64";
 177             default:
 178                 throw GraalInternalError.shouldNotReachHere();
 179         }
 180     }
 181 
 182     public void emitCompare(Value src0, Value src1, String condition, boolean unordered, boolean isUnsignedCompare) {
 183         String prefix = "cmp_" + condition + (unordered ? "u" : "") + "_b1_" + (isUnsignedCompare ? getArgTypeForceUnsigned(src1) : getArgType(src1));
 184         emitString(prefix + " $c0, " + mapRegOrConstToString(src0) + ", " + mapRegOrConstToString(src1) + ";");
 185     }
 186 
 187     public void emitConvert(Value dest, Value src) {
 188         String prefix = (getArgType(dest).equals("f32") && getArgType(src).equals("f64")) ? "cvt_near_" : "cvt_";
 189         emitString(prefix + getArgType(dest) + "_" + getArgType(src) + " " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapRegister(src) + ";");
 190     }
 191 
 192     public void emitArg1(String mnemonic, Value dest, Value src) {
 193         emitString(mnemonic + "_" + getArgType(src) + " " + HSAIL.mapRegister(dest) + ", " + mapRegOrConstToString(src) + ";" + "");
 194     }
 195 
 196     public static String mapAddress(HSAILAddress addr) {
 197         return "[$d" + addr.getBase().encoding() + " + " + addr.getDisplacement() + "]";
 198     }
 199 
 200     private static String mapRegOrConstToString(Value src) {
 201         if (!isConstant(src)) {
 202             return HSAIL.mapRegister(src);
 203         } else {
 204             Constant consrc = asConstant(src);
 205             switch (src.getKind()) {
 206                 case Int:
 207                     return Integer.toString(consrc.asInt());
 208                 case Float:
 209                     return Float.toString(consrc.asFloat()) + "f";
 210                 case Double:
 211                     return Double.toString(consrc.asDouble());
 212                 case Long:
 213                     return Long.toString(consrc.asLong());
 214                 default:
 215                     throw GraalInternalError.shouldNotReachHere("unknown type: " + src);
 216             }
 217         }
 218 
 219     }
 220 
 221     public final void emit(String mnemonic, Value dest, Value src0, Value src1) {
 222         String prefix = getArgType(dest);
 223         emit(mnemonic + "_" + prefix, dest, "", src0, src1);
 224     }
 225 
 226     private void emit(String instr, Value dest, String controlRegString, Value src0, Value src1) {
 227         assert (!isConstant(dest));
 228         emitString(String.format("%s %s, %s%s, %s;", instr, HSAIL.mapRegister(dest), controlRegString, mapRegOrConstToString(src0), mapRegOrConstToString(src1)));
 229     }
 230 
 231     public final void cmovCommon(Value dest, Value trueReg, Value falseReg, int width) {
 232         String instr = (width == 32 ? "cmov_b32" : "cmov_b64");
 233         emit(instr, dest, "$c0, ", trueReg, falseReg);
 234     }
 235 
 236 }