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 package com.oracle.graal.asm.hsail;
  24 
  25 import static com.oracle.graal.api.code.MemoryBarriers.*;
  26 import static com.oracle.graal.api.code.ValueUtil.*;
  27 
  28 import com.oracle.graal.api.code.*;
  29 import com.oracle.graal.api.meta.*;
  30 import com.oracle.graal.compiler.common.*;
  31 import com.oracle.graal.hsail.*;
  32 
  33 /**
  34  * This class contains routines to emit HSAIL assembly code.
  35  */
  36 public abstract class HSAILAssembler extends AbstractHSAILAssembler {
  37 
  38     /**
  39      * Stack size in bytes (used to keep track of spilling).
  40      */
  41     private int maxDataTypeSize;
  42 
  43     /**
  44      * Maximum stack offset used by a store operation.
  45      */
  46     private long maxStackOffset = 0;
  47 
  48     public long upperBoundStackSize() {
  49         return maxStackOffset + maxDataTypeSize;
  50     }
  51 
  52     public HSAILAssembler(TargetDescription target) {
  53         super(target);
  54     }
  55 
  56     @Override
  57     public HSAILAddress makeAddress(Register base, int displacement) {
  58         return new HSAILAddress(base, displacement);
  59     }
  60 
  61     @Override
  62     public HSAILAddress getPlaceholder() {
  63         return null;
  64     }
  65 
  66     @Override
  67     public final void ensureUniquePC() {
  68         throw GraalInternalError.unimplemented();
  69     }
  70 
  71     public final void undefined(String str) {
  72         emitString("undefined operation " + str);
  73     }
  74 
  75     public final void exit() {
  76         emitString("ret;" + "");
  77     }
  78 
  79     /**
  80      * Moves an Object into a register.
  81      *
  82      * Because Object references become stale after Garbage collection (GC) the technique used here
  83      * is to load a JNI global reference to that Object into the register. These JNI global
  84      * references get updated by the GC whenever the GC moves an Object.
  85      *
  86      * @param a the destination register
  87      * @param src the Object Constant being moved
  88      */
  89     public abstract void mov(Register a, Constant src);
  90 
  91     public final void emitMov(Kind kind, Value dst, Value src) {
  92         if (isRegister(dst) && isConstant(src) && kind.getStackKind() == Kind.Object) {
  93             mov(asRegister(dst), asConstant(src));
  94         } else {
  95             String argtype = getArgTypeFromKind(kind).substring(1);
  96             emitString("mov_b" + argtype + " " + mapRegOrConstToString(dst) + ", " + mapRegOrConstToString(src) + ";");
  97         }
  98     }
  99 
 100     private void emitAddrOp(String instr, Value reg, HSAILAddress addr) {
 101         String storeValue = mapRegOrConstToString(reg);
 102         emitString(instr + " " + storeValue + ", " + mapAddress(addr) + ";");
 103     }
 104 
 105     /**
 106      * Emits a memory barrier instruction.
 107      *
 108      * @param barriers the kind of barrier to emit
 109      */
 110     public final void emitMembar(int barriers) {
 111         if (barriers == 0) {
 112             emitString("// no barrier before volatile read");
 113         } else if (barriers == JMM_POST_VOLATILE_READ) {
 114             emitString("sync; // barriers=" + MemoryBarriers.barriersString(barriers));
 115         } else if (barriers == JMM_PRE_VOLATILE_WRITE) {
 116             emitString("sync; // barriers=" + MemoryBarriers.barriersString(barriers));
 117         } else if (barriers == JMM_POST_VOLATILE_WRITE) {
 118             emitString("sync; // barriers=" + MemoryBarriers.barriersString(barriers));
 119         }
 120     }
 121 
 122     public final void emitLoad(Kind kind, Value dest, HSAILAddress addr) {
 123         emitLoad(dest, addr, getArgTypeFromKind(kind));
 124     }
 125 
 126     public final void emitLoad(Value dest, HSAILAddress addr, String argTypeStr) {
 127         emitAddrOp("ld_global_" + argTypeStr, dest, addr);
 128     }
 129 
 130     public final void emitLda(Value dest, HSAILAddress addr) {
 131         emitAddrOp("lda_global_u64", dest, addr);
 132     }
 133 
 134     public final void emitLea(Value dest, HSAILAddress addr) {
 135         String prefix = getArgType(dest);
 136         emitString(String.format("add_%s %s, $%s, 0x%s;", prefix, HSAIL.mapRegister(dest), addr.getBase().name, Long.toHexString(addr.getDisplacement())));
 137     }
 138 
 139     public final void emitLoadKernelArg(Value dest, String kernArgName, String argTypeStr) {
 140         emitString("ld_kernarg_" + argTypeStr + " " + HSAIL.mapRegister(dest) + ", [" + kernArgName + "];");
 141     }
 142 
 143     public final void emitStore(Kind kind, Value src, HSAILAddress addr) {
 144         emitStore(src, addr, getArgTypeFromKind(kind));
 145     }
 146 
 147     public final void emitStore(Value dest, HSAILAddress addr, String argTypeStr) {
 148         emitAddrOp("st_global_" + argTypeStr, dest, addr);
 149     }
 150 
 151     private void storeImmediateImpl(String storeType, String value, HSAILAddress addr) {
 152         emitString("st_global_" + storeType + " " + value + ", " + mapAddress(addr) + ";");
 153     }
 154 
 155     public final void emitStoreImmediate(Kind kind, long src, HSAILAddress addr) {
 156         assert (kind != Kind.Float && kind != Kind.Double);
 157         storeImmediateImpl(getArgTypeFromKind(kind), Long.toString(src), addr);
 158     }
 159 
 160     public final void emitStoreImmediate(float src, HSAILAddress addr) {
 161         storeImmediateImpl("f32", floatToString(src), addr);
 162     }
 163 
 164     public final void emitStoreImmediate(double src, HSAILAddress addr) {
 165         storeImmediateImpl("f64", doubleToString(src), addr);
 166     }
 167 
 168     public final void emitSpillLoad(Kind kind, Value dest, Value src) {
 169         emitString("ld_spill_" + getArgTypeFromKind(kind) + " " + HSAIL.mapRegister(dest) + ", " + mapStackSlot(src, getArgSizeFromKind(kind)) + ";");
 170     }
 171 
 172     public final void emitStore(Value src, HSAILAddress addr) {
 173         emitString("st_global_" + getArgType(src) + " " + HSAIL.mapRegister(src) + ", " + mapAddress(addr) + ";");
 174     }
 175 
 176     public final void emitSpillStore(Kind kind, Value src, Value dest) {
 177         int sizestored = getArgSizeFromKind(kind);
 178         if (maxDataTypeSize < sizestored) {
 179             maxDataTypeSize = sizestored;
 180         }
 181         int stackoffset = HSAIL.getStackOffset(dest);
 182         if (maxStackOffset < stackoffset) {
 183             maxStackOffset = stackoffset;
 184         }
 185         emitString("st_spill_" + getArgTypeFromKind(kind) + " " + HSAIL.mapRegister(src) + ", " + mapStackSlot(dest, getArgSizeFromKind(kind)) + ";");
 186     }
 187 
 188     public static String mapStackSlot(Value reg, int argSize) {
 189         long startOffset = HSAIL.getStackOffsetStart(reg, argSize);
 190         return "[%spillseg]" + "[" + startOffset + "]";
 191     }
 192 
 193     public void cbr(String target1) {
 194         emitString("cbr " + "$c0" + ", " + target1 + ";");
 195     }
 196 
 197     public int getArgSize(Value src) {
 198         return getArgSizeFromKind(src.getKind());
 199     }
 200 
 201     private static int getArgSizeFromKind(Kind kind) {
 202         switch (kind) {
 203             case Int:
 204             case Float:
 205                 return 32;
 206             case Double:
 207             case Long:
 208             case Object:
 209                 return 64;
 210             default:
 211                 throw GraalInternalError.shouldNotReachHere();
 212         }
 213     }
 214 
 215     private static String getArgType(Value src) {
 216         return getArgTypeFromKind(src.getKind());
 217     }
 218 
 219     private static String getArgTypeFromKind(Kind kind) {
 220         String prefix = "";
 221         switch (kind) {
 222             case Float:
 223                 prefix = "f32";
 224                 break;
 225             case Double:
 226                 prefix = "f64";
 227                 break;
 228             case Int:
 229                 prefix = "s32";
 230                 break;
 231             case Long:
 232                 prefix = "s64";
 233                 break;
 234             case Object:
 235                 prefix = "u64";
 236                 break;
 237             case Char:
 238                 prefix = "u16";
 239                 break;
 240             case Short:
 241                 prefix = "s16";
 242                 break;
 243             case Byte:
 244                 prefix = "s8";
 245                 break;
 246             case Boolean:
 247                 prefix = "u8";
 248                 break;
 249             default:
 250                 throw GraalInternalError.shouldNotReachHere();
 251         }
 252         return prefix;
 253     }
 254 
 255     public static final String getArgTypeForceUnsigned(Value src) {
 256         return getArgTypeForceUnsignedKind(src.getKind());
 257     }
 258 
 259     public static final String getArgTypeForceUnsignedKind(Kind kind) {
 260         switch (kind) {
 261             case Int:
 262                 return "u32";
 263             case Long:
 264             case Object:
 265                 return "u64";
 266             default:
 267                 throw GraalInternalError.shouldNotReachHere();
 268         }
 269     }
 270 
 271     public static final String getArgTypeBitwiseLogical(Value src) {
 272         String length = getArgType(src);
 273         String prefix = "_b" + (length.endsWith("64") ? "64" : "32");
 274         return prefix;
 275     }
 276 
 277     /**
 278      * Emits a compare instruction.
 279      *
 280      * @param src0 - the first source register
 281      * @param src1 - the second source register
 282      * @param condition - the compare condition i.e., eq, ne, lt, gt
 283      * @param unordered - flag specifying if this is an unordered compare. This only applies to
 284      *            float compares.
 285      * @param isUnsignedCompare - flag specifying if this is a compare of unsigned values.
 286      */
 287     public void emitCompare(Kind compareKind, Value src0, Value src1, String condition, boolean unordered, boolean isUnsignedCompare) {
 288         // Formulate the prefix of the instruction.
 289         // if unordered is true, it should be ignored unless the src type is f32 or f64
 290         String argType = getArgTypeFromKind(compareKind);
 291         String unorderedPrefix = (argType.startsWith("f") && unordered ? "u" : "");
 292         String prefix = "cmp_" + condition + unorderedPrefix + "_b1_" + (isUnsignedCompare ? getArgTypeForceUnsigned(src1) : argType);
 293         // Generate a comment for debugging purposes
 294         String comment = (isConstant(src1) && (src1.getKind() == Kind.Object) && (asConstant(src1).isNull()) ? " // null test " : "");
 295         // Emit the instruction.
 296         emitString(prefix + " $c0, " + mapRegOrConstToString(src0) + ", " + mapRegOrConstToString(src1) + ";" + comment);
 297     }
 298 
 299     public void emitConvert(Value dest, Value src, String destType, String srcType) {
 300         String prefix = "cvt_";
 301         if (destType.equals("f32") && srcType.equals("f64")) {
 302             prefix = "cvt_near_";
 303         } else if (srcType.startsWith("f") && (destType.startsWith("s") || destType.startsWith("u"))) {
 304             prefix = "cvt_zeroi_sat_";
 305         }
 306         emitString(prefix + destType + "_" + srcType + " " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapRegister(src) + ";");
 307     }
 308 
 309     public void emitConvert(Value dest, Value src, Kind destKind, Kind srcKind) {
 310         String destType = getArgTypeFromKind(destKind);
 311         String srcType = getArgTypeFromKind(srcKind);
 312         emitConvert(dest, src, destType, srcType);
 313     }
 314 
 315     /**
 316      * Emits a convert instruction that uses unsigned prefix, regardless of the type of dest and
 317      * src.
 318      *
 319      * @param dest the destination operand
 320      * @param src the source operand
 321      */
 322     public void emitConvertForceUnsigned(Value dest, Value src) {
 323         emitString("cvt_" + getArgTypeForceUnsigned(dest) + "_" + getArgTypeForceUnsigned(src) + " " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapRegister(src) + ";");
 324     }
 325 
 326     public static String mapAddress(HSAILAddress addr) {
 327         if (addr.getBase().encoding() < 0) {
 328             return "[0x" + Long.toHexString(addr.getDisplacement()) + "]";
 329         } else {
 330             return "[$d" + addr.getBase().encoding() + " + " + addr.getDisplacement() + "]";
 331         }
 332     }
 333 
 334     private static String doubleToString(double dval) {
 335         long lval = Double.doubleToRawLongBits(dval);
 336         long lvalIgnoreSign = lval & 0x7fffffffffffffffL;
 337         if (lvalIgnoreSign >= 0x7ff0000000000000L) {
 338             return "0D" + String.format("%16x", lval);
 339         } else {
 340             return Double.toString(dval);
 341         }
 342     }
 343 
 344     private static String floatToString(float fval) {
 345         int ival = Float.floatToRawIntBits(fval);
 346         int ivalIgnoreSign = ival & 0x7fffffff;
 347         if (ivalIgnoreSign >= 0x7f800000) {
 348             return "0F" + String.format("%8x", ival);
 349         } else {
 350             return Float.toString(fval) + "f";
 351         }
 352     }
 353 
 354     private static String mapRegOrConstToString(Value src) {
 355         if (!isConstant(src)) {
 356             return HSAIL.mapRegister(src);
 357         } else {
 358             Constant consrc = asConstant(src);
 359             switch (src.getKind()) {
 360                 case Boolean:
 361                 case Int:
 362                     return Integer.toString(consrc.asInt());
 363                 case Float:
 364                     return floatToString(consrc.asFloat());
 365                 case Double:
 366                     return doubleToString(consrc.asDouble());
 367                 case Long:
 368                     return "0x" + Long.toHexString(consrc.asLong());
 369                 case Object:
 370                     if (consrc.isNull()) {
 371                         return "0";
 372                     } else {
 373                         throw GraalInternalError.shouldNotReachHere("unknown type: " + src);
 374                     }
 375                 default:
 376                     throw GraalInternalError.shouldNotReachHere("unknown type: " + src);
 377             }
 378         }
 379 
 380     }
 381 
 382     /**
 383      * Emits an instruction.
 384      *
 385      * @param mnemonic the instruction mnemonic
 386      * @param dest the destination operand
 387      * @param sources the source operands
 388      */
 389     public final void emit(String mnemonic, Value dest, Value... sources) {
 390         String prefix = getArgType(dest);
 391         emitTextFormattedInstruction(mnemonic + "_" + prefix, dest, sources);
 392     }
 393 
 394     /**
 395      * Emits an unsigned instruction.
 396      *
 397      * @param mnemonic the instruction mnemonic
 398      * @param dest the destination argument
 399      * @param sources the source arguments
 400      *
 401      */
 402     public final void emitForceUnsigned(String mnemonic, Value dest, Value... sources) {
 403         String prefix = getArgTypeForceUnsigned(dest);
 404         emitTextFormattedInstruction(mnemonic + "_" + prefix, dest, sources);
 405     }
 406 
 407     public final void emitForceUnsignedKind(String mnemonic, Kind kind, Value dest, Value... sources) {
 408         String prefix = getArgTypeForceUnsignedKind(kind);
 409         emitTextFormattedInstruction(mnemonic + "_" + prefix, dest, sources);
 410     }
 411 
 412     /**
 413      * Emits an instruction for a bitwise logical operation.
 414      *
 415      * @param mnemonic the instruction mnemonic
 416      * @param dest the destination
 417      * @param sources the source operands
 418      */
 419     public final void emitForceBitwise(String mnemonic, Value dest, Value... sources) {
 420         String prefix = getArgTypeBitwiseLogical(dest);
 421         emitTextFormattedInstruction(mnemonic + prefix, dest, sources);
 422     }
 423 
 424     /**
 425      * Central helper routine that emits a text formatted HSAIL instruction via call to
 426      * AbstractAssembler.emitString. All the emit routines in the assembler end up calling this one.
 427      *
 428      * @param instr the full instruction mnenomics including any prefixes
 429      * @param dest the destination operand
 430      * @param sources the source operand
 431      */
 432     private void emitTextFormattedInstruction(String instr, Value dest, Value... sources) {
 433         /**
 434          * Destination can't be a constant and no instruction has > 3 source operands.
 435          */
 436         assert (!isConstant(dest) && sources.length <= 3);
 437         switch (sources.length) {
 438             case 3:
 439                 // Emit an instruction with three source operands.
 440                 emitString(String.format("%s %s, %s, %s, %s;", instr, HSAIL.mapRegister(dest), mapRegOrConstToString(sources[0]), mapRegOrConstToString(sources[1]), mapRegOrConstToString(sources[2])));
 441                 break;
 442             case 2:
 443                 // Emit an instruction with two source operands.
 444                 emitString(String.format("%s %s, %s, %s;", instr, HSAIL.mapRegister(dest), mapRegOrConstToString(sources[0]), mapRegOrConstToString(sources[1])));
 445                 break;
 446             case 1:
 447                 // Emit an instruction with one source operand.
 448                 emitString(String.format("%s %s, %s;", instr, HSAIL.mapRegister(dest), mapRegOrConstToString(sources[0])));
 449                 break;
 450             default:
 451                 // Emit an instruction with one source operand.
 452                 emitString(String.format("%s %s;", instr, HSAIL.mapRegister(dest)));
 453                 break;
 454         }
 455     }
 456 
 457     /**
 458      * Emits a conditional move instruction.
 459      *
 460      * @param dest the destination operand storing result of the move
 461      * @param trueReg the register that should be copied to dest if the condition is true
 462      * @param falseReg the register that should be copied to dest if the condition is false
 463      * @param width the width of the instruction (32 or 64 bits)
 464      */
 465     public final void emitConditionalMove(Value dest, Value trueReg, Value falseReg, int width) {
 466         assert (!isConstant(dest));
 467         String instr = (width == 32 ? "cmov_b32" : "cmov_b64");
 468         emitString(String.format("%s %s, %s%s, %s;", instr, HSAIL.mapRegister(dest), "$c0, ", mapRegOrConstToString(trueReg), mapRegOrConstToString(falseReg)));
 469     }
 470 
 471     /**
 472      * Emits code to build a 64-bit pointer from a compressed value and the associated base and
 473      * shift. The compressed value could represent either a normal oop or a klass ptr. If the
 474      * compressed value is 0, the uncompressed must also be 0. We only emit this if base and shift
 475      * are not both zero.
 476      *
 477      * @param result the register containing the compressed value on input and the uncompressed ptr
 478      *            on output
 479      * @param base the amount to be added to the compressed value
 480      * @param shift the number of bits to shift left the compressed value
 481      * @param testForNull true if the compressed value might be null
 482      */
 483     public void emitCompressedOopDecode(Value result, long base, int shift, boolean testForNull) {
 484         assert (base != 0 || shift != 0);
 485         assert (!isConstant(result));
 486         if (base == 0) {
 487             // we don't have to test for null if shl is the only operation
 488             emitForceUnsignedKind("shl", Kind.Long, result, result, Constant.forInt(shift));
 489         } else if (shift == 0) {
 490             // only use add if result is not starting as null (test only if testForNull is true)
 491             emitWithOptionalTestForNull(testForNull, "add", result, result, Constant.forLong(base));
 492         } else {
 493             // only use mad if result is not starting as null (test only if testForNull is true)
 494             emitWithOptionalTestForNull(testForNull, "mad", result, result, Constant.forInt(1 << shift), Constant.forLong(base));
 495         }
 496     }
 497 
 498     /**
 499      * Emits code to build a compressed value from a full 64-bit pointer using the associated base
 500      * and shift. The compressed value could represent either a normal oop or a klass ptr. If the
 501      * ptr is 0, the compressed value must also be 0. We only emit this if base and shift are not
 502      * both zero.
 503      *
 504      * @param result the register containing the 64-bit pointer on input and the compressed value on
 505      *            output
 506      * @param base the amount to be subtracted from the 64-bit pointer
 507      * @param shift the number of bits to shift right the 64-bit pointer
 508      * @param testForNull true if the 64-bit pointer might be null
 509      */
 510     public void emitCompressedOopEncode(Value result, long base, int shift, boolean testForNull) {
 511         assert (base != 0 || shift != 0);
 512         assert (!isConstant(result));
 513         if (base != 0) {
 514             // only use sub if result is not starting as null (test only if testForNull is true)
 515             emitWithOptionalTestForNull(testForNull, "sub", result, result, Constant.forLong(base));
 516         }
 517         if (shift != 0) {
 518             // note that the shr can still be done even if the result is null
 519             emitForceUnsignedKind("shr", Kind.Long, result, result, Constant.forInt(shift));
 520         }
 521     }
 522 
 523     /**
 524      * Emits code for the requested mnemonic on the result and sources. In addition, if testForNull
 525      * is true, surrounds the instruction with code that will guarantee that if the result starts as
 526      * 0, it will remain 0.
 527      *
 528      * @param testForNull true if we want to add the code to check for and preserve null
 529      * @param mnemonic the instruction to be applied (without size prefix)
 530      * @param result the register which is both an input and the final output
 531      * @param sources the sources for the mnemonic instruction
 532      */
 533     private void emitWithOptionalTestForNull(boolean testForNull, String mnemonic, Value result, Value... sources) {
 534         if (testForNull) {
 535             emitCompare(Kind.Long, result, Constant.forLong(0), "eq", false, true);
 536         }
 537         emitForceUnsigned(mnemonic, result, sources);
 538         if (testForNull) {
 539             emitConditionalMove(result, Constant.forLong(0), result, 64);
 540         }
 541     }
 542 
 543     /**
 544      * Emits an atomic_cas_global instruction.
 545      *
 546      * @param result result operand that gets the original contents of the memory location
 547      * @param address the memory location
 548      * @param cmpValue the value that will be compared against the memory location
 549      * @param newValue the new value that will be written to the memory location if the cmpValue
 550      *            comparison matches
 551      */
 552     public void emitAtomicCas(Kind accessKind, AllocatableValue result, HSAILAddress address, Value cmpValue, Value newValue) {
 553         emitString(String.format("atomic_cas_global_b%d   %s, %s, %s, %s;", getArgSizeFromKind(accessKind), HSAIL.mapRegister(result), mapAddress(address), mapRegOrConstToString(cmpValue),
 554                         mapRegOrConstToString(newValue)));
 555     }
 556 
 557     /**
 558      * Emits an atomic_add_global instruction.
 559      *
 560      * @param result result operand that gets the original contents of the memory location
 561      * @param address the memory location
 562      * @param delta the amount to add
 563      */
 564     public void emitAtomicAdd(AllocatableValue result, HSAILAddress address, Value delta) {
 565         // ensure result and delta agree (this should probably be at some higher level)
 566         Value mydelta = delta;
 567         if (!isConstant(delta) && (getArgSize(result) != getArgSize(delta))) {
 568             emitConvert(result, delta, result.getKind(), delta.getKind());
 569             mydelta = result;
 570         }
 571         String prefix = getArgTypeForceUnsigned(result);
 572         emitString(String.format("atomic_add_global_%s   %s, %s, %s;", prefix, HSAIL.mapRegister(result), mapAddress(address), mapRegOrConstToString(mydelta)));
 573     }
 574 
 575     /**
 576      * Emits an atomic_exch_global instruction.
 577      *
 578      * @param result result operand that gets the original contents of the memory location
 579      * @param address the memory location
 580      * @param newValue the new value to write to the memory location
 581      */
 582     public void emitAtomicExch(Kind accessKind, AllocatableValue result, HSAILAddress address, Value newValue) {
 583         emitString(String.format("atomic_exch_global_b%d   %s, %s, %s;", getArgSizeFromKind(accessKind), HSAIL.mapRegister(result), mapAddress(address), mapRegOrConstToString(newValue)));
 584     }
 585 
 586     /**
 587      * Emits a comment. Useful for debugging purposes.
 588      *
 589      * @param comment
 590      */
 591     public void emitComment(String comment) {
 592         emitString(comment);
 593     }
 594 
 595     public String getDeoptInfoName() {
 596         return "%_deoptInfo";
 597     }
 598 
 599     public String getDeoptLabelName() {
 600         return "@L_Deopt";
 601     }
 602 
 603     public void emitWorkItemAbsId(Value dest) {
 604         emitString(String.format("workitemabsid_u32 %s, 0;", HSAIL.mapRegister(dest)));
 605     }
 606 
 607     public void emitCuId(Value dest) {
 608         emitString(String.format("cuid_u32 %s;", HSAIL.mapRegister(dest)));
 609     }
 610 
 611     public void emitLaneId(Value dest) {
 612         emitString(String.format("laneid_u32 %s;", HSAIL.mapRegister(dest)));
 613     }
 614 
 615     public void emitWaveId(Value dest) {
 616         emitString(String.format("waveid_u32 %s;", HSAIL.mapRegister(dest)));
 617     }
 618 
 619     public void emitMaxWaveId(Value dest) {
 620         // emitString(String.format("maxwaveid_u32 %s;", HSAIL.mapRegister(dest)));
 621         int hardCodedMaxWaveId = 36;
 622         emitComment("// Hard-coded maxwaveid=" + hardCodedMaxWaveId + " until it works");
 623         emitMov(Kind.Int, dest, Constant.forInt(hardCodedMaxWaveId));
 624     }
 625 
 626     public void emitMultiplyByWavesize(Value dest) {
 627         String regName = HSAIL.mapRegister(dest);
 628         emitString(String.format("mul_u%d %s, %s, WAVESIZE;", getArgSize(dest), regName, regName));
 629     }
 630 
 631     public void emitGetWavesize(Value dest) {
 632         String regName = HSAIL.mapRegister(dest);
 633         emitString(String.format("mov_b%d %s, WAVESIZE;", getArgSize(dest), regName));
 634     }
 635 
 636     public void emitLoadAcquire(Value dest, HSAILAddress address) {
 637         emitString(String.format("ld_global_acq_u%d %s, %s;", getArgSize(dest), HSAIL.mapRegister(dest), mapAddress(address)));
 638     }
 639 
 640     public void emitStoreRelease(Value src, HSAILAddress address) {
 641         emitString(String.format("st_global_rel_u%d %s, %s;", getArgSize(src), HSAIL.mapRegister(src), mapAddress(address)));
 642     }
 643 }