1 /*
   2  * Copyright (c) 2013, 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.lir.hsail;
  24 
  25 import static com.oracle.graal.api.code.ValueUtil.*;
  26 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
  27 
  28 import com.oracle.graal.api.code.*;
  29 import com.oracle.graal.api.meta.*;
  30 import com.oracle.graal.asm.hsail.*;
  31 import com.oracle.graal.debug.*;
  32 import com.oracle.graal.graph.*;
  33 import com.oracle.graal.lir.*;
  34 import com.oracle.graal.lir.StandardOp.MoveOp;
  35 import com.oracle.graal.lir.asm.*;
  36 
  37 /**
  38  * Implementation of move instructions.
  39  */
  40 public class HSAILMove {
  41 
  42     // Stack size in bytes (used to keep track of spilling).
  43     static int maxDatatypeSize;
  44     // Maximum stack offset used by a store operation.
  45     static long maxStackOffset = 0;
  46 
  47     public static long upperBoundStackSize() {
  48         return maxStackOffset + maxDatatypeSize;
  49     }
  50 
  51     @Opcode("MOVE")
  52     public static class SpillMoveOp extends HSAILLIRInstruction implements MoveOp {
  53 
  54         @Def({REG, STACK}) protected AllocatableValue result;
  55         @Use({REG, STACK, CONST}) protected Value input;
  56 
  57         public SpillMoveOp(AllocatableValue result, Value input) {
  58             this.result = result;
  59             this.input = input;
  60         }
  61 
  62         @Override
  63         public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) {
  64             move(tasm, masm, getResult(), getInput());
  65         }
  66 
  67         @Override
  68         public Value getInput() {
  69             return input;
  70         }
  71 
  72         @Override
  73         public AllocatableValue getResult() {
  74             return result;
  75         }
  76     }
  77 
  78     @Opcode("MOVE")
  79     public static class MoveToRegOp extends HSAILLIRInstruction implements MoveOp {
  80 
  81         @Def({REG, HINT}) protected AllocatableValue result;
  82         @Use({REG, STACK, CONST}) protected Value input;
  83 
  84         public MoveToRegOp(AllocatableValue result, Value input) {
  85             this.result = result;
  86             this.input = input;
  87         }
  88 
  89         @Override
  90         public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) {
  91             move(tasm, masm, getResult(), getInput());
  92         }
  93 
  94         @Override
  95         public Value getInput() {
  96             return input;
  97         }
  98 
  99         @Override
 100         public AllocatableValue getResult() {
 101             return result;
 102         }
 103     }
 104 
 105     @Opcode("MOVE")
 106     public static class MoveFromRegOp extends HSAILLIRInstruction implements MoveOp {
 107 
 108         @Def({REG, STACK}) protected AllocatableValue result;
 109         @Use({REG, CONST, HINT}) protected Value input;
 110 
 111         public MoveFromRegOp(AllocatableValue result, Value input) {
 112             this.result = result;
 113             this.input = input;
 114         }
 115 
 116         @Override
 117         public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) {
 118             move(tasm, masm, getResult(), getInput());
 119         }
 120 
 121         @Override
 122         public Value getInput() {
 123             return input;
 124         }
 125 
 126         @Override
 127         public AllocatableValue getResult() {
 128             return result;
 129         }
 130     }
 131 
 132 
 133     public abstract static class MemOp extends HSAILLIRInstruction {
 134 
 135         protected final Kind kind;
 136         @Use({COMPOSITE}) protected HSAILAddressValue address;
 137         @State protected LIRFrameState state;
 138 
 139         public MemOp(Kind kind, HSAILAddressValue address, LIRFrameState state) {
 140             this.kind = kind;
 141             this.address = address;
 142             this.state = state;
 143         }
 144 
 145         protected abstract void emitMemAccess(HSAILAssembler masm);
 146 
 147         @Override
 148         public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) {
 149             if (state != null) {
 150                 // tasm.recordImplicitException(masm.codeBuffer.position(), state);
 151                 throw new InternalError("NYI");
 152             }
 153             emitMemAccess(masm);
 154         }
 155     }
 156 
 157     public static class LoadOp extends MemOp {
 158 
 159         @Def({REG}) protected AllocatableValue result;
 160 
 161         public LoadOp(Kind kind, AllocatableValue result, HSAILAddressValue address, LIRFrameState state) {
 162             super(kind, address, state);
 163             this.result = result;
 164         }
 165 
 166         @Override
 167         public void emitMemAccess(HSAILAssembler masm) {
 168             HSAILAddress addr = address.toAddress();
 169             masm.emitLoad(result, addr);
 170         }
 171     }
 172 
 173     public static class StoreOp extends MemOp {
 174 
 175         @Use({REG}) protected AllocatableValue input;
 176 
 177         public StoreOp(Kind kind, HSAILAddressValue address, AllocatableValue input, LIRFrameState state) {
 178             super(kind, address, state);
 179             this.input = input;
 180         }
 181 
 182         @Override
 183         public void emitMemAccess(HSAILAssembler masm) {
 184             assert isRegister(input);
 185             HSAILAddress addr = address.toAddress();
 186             masm.emitStore(input, addr);
 187         }
 188     }
 189 
 190     public static class LoadCompressedPointer extends LoadOp {
 191 
 192         private long narrowOopBase;
 193         private int narrowOopShift;
 194         private int logMinObjAlignment;
 195         @Temp({REG}) private AllocatableValue scratch;
 196 
 197         public LoadCompressedPointer(Kind kind, AllocatableValue result, AllocatableValue scratch, HSAILAddressValue address, LIRFrameState state, long narrowOopBase, int narrowOopShift,
 198                         int logMinObjAlignment) {
 199             super(kind, result, address, state);
 200             this.narrowOopBase = narrowOopBase;
 201             this.narrowOopShift = narrowOopShift;
 202             this.logMinObjAlignment = logMinObjAlignment;
 203             this.scratch = scratch;
 204             assert kind == Kind.Object;
 205         }
 206 
 207         @Override
 208         public void emitMemAccess(HSAILAssembler masm) {
 209             // we will do a 32 bit load, zero extending into a 64 bit register
 210             masm.emitLoad(result, address.toAddress(), "u32");
 211             decodePointer(masm, result, narrowOopBase, narrowOopShift, logMinObjAlignment);
 212         }
 213     }
 214 
 215     public static class StoreCompressedPointer extends HSAILLIRInstruction {
 216 
 217         protected final Kind kind;
 218         private long narrowOopBase;
 219         private int narrowOopShift;
 220         private int logMinObjAlignment;
 221         @Temp({REG}) private AllocatableValue scratch;
 222         @Alive({REG}) protected AllocatableValue input;
 223         @Alive({COMPOSITE}) protected HSAILAddressValue address;
 224         @State protected LIRFrameState state;
 225 
 226         public StoreCompressedPointer(Kind kind, HSAILAddressValue address, AllocatableValue input, AllocatableValue scratch, LIRFrameState state, long narrowOopBase, int narrowOopShift,
 227                         int logMinObjAlignment) {
 228             this.narrowOopBase = narrowOopBase;
 229             this.narrowOopShift = narrowOopShift;
 230             this.logMinObjAlignment = logMinObjAlignment;
 231             this.scratch = scratch;
 232             this.kind = kind;
 233             this.address = address;
 234             this.state = state;
 235             this.input = input;
 236             assert kind == Kind.Object;
 237         }
 238 
 239         @Override
 240         public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) {
 241             masm.emitMov(scratch, input);
 242             encodePointer(masm, scratch, narrowOopBase, narrowOopShift, logMinObjAlignment);
 243             if (state != null) {
 244                 throw new InternalError("NYI");
 245                 // tasm.recordImplicitException(masm.codeBuffer.position(), state);
 246             }
 247             masm.emitStore(scratch, address.toAddress(), "u32");
 248         }
 249     }
 250 
 251     private static void encodePointer(HSAILAssembler masm, Value scratch, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) {
 252         if (narrowOopBase == 0 && narrowOopShift == 0) {
 253             return;
 254         }
 255         if (narrowOopShift != 0) {
 256             assert logMinObjAlignment == narrowOopShift : "Encode algorithm is wrong";
 257         }
 258         masm.emitCompressedOopEncode(scratch, narrowOopBase, narrowOopShift);
 259     }
 260 
 261     private static void decodePointer(HSAILAssembler masm, Value result, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) {
 262         if (narrowOopBase == 0 && narrowOopShift == 0) {
 263             return;
 264         }
 265         if (narrowOopShift != 0) {
 266             assert logMinObjAlignment == narrowOopShift : "Decode algorithm is wrong";
 267         }
 268         masm.emitCompressedOopDecode(result, narrowOopBase, narrowOopShift);
 269     }
 270 
 271 
 272 
 273     public static class LeaOp extends HSAILLIRInstruction {
 274 
 275         @Def({REG}) protected AllocatableValue result;
 276         @Use({COMPOSITE, UNINITIALIZED}) protected HSAILAddressValue address;
 277 
 278         public LeaOp(AllocatableValue result, HSAILAddressValue address) {
 279             this.result = result;
 280             this.address = address;
 281         }
 282 
 283         @Override
 284         public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) {
 285             throw new InternalError("NYI");
 286         }
 287     }
 288 
 289     public static class StackLeaOp extends HSAILLIRInstruction {
 290 
 291         @Def({REG}) protected AllocatableValue result;
 292         @Use({STACK, UNINITIALIZED}) protected StackSlot slot;
 293 
 294         public StackLeaOp(AllocatableValue result, StackSlot slot) {
 295             this.result = result;
 296             this.slot = slot;
 297         }
 298 
 299         @Override
 300         public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) {
 301             throw new InternalError("NYI");
 302         }
 303     }
 304 
 305     @Opcode("CAS")
 306     public static class CompareAndSwapOp extends HSAILLIRInstruction {
 307 
 308         @Def protected AllocatableValue result;
 309         @Use({COMPOSITE}) protected HSAILAddressValue address;
 310         @Use protected AllocatableValue cmpValue;
 311         @Use protected AllocatableValue newValue;
 312 
 313         public CompareAndSwapOp(AllocatableValue result, HSAILAddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
 314             this.result = result;
 315             this.address = address;
 316             this.cmpValue = cmpValue;
 317             this.newValue = newValue;
 318         }
 319 
 320         @Override
 321         public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) {
 322             compareAndSwap(tasm, masm, result, address, cmpValue, newValue);
 323         }
 324     }
 325 
 326     public static class NullCheckOp extends HSAILLIRInstruction {
 327 
 328         @Use protected Value input;
 329         @State protected LIRFrameState state;
 330 
 331         public NullCheckOp(Variable input, LIRFrameState state) {
 332             this.input = input;
 333             this.state = state;
 334         }
 335 
 336         @Override
 337         public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) {
 338             Debug.log("NullCheckOp unimplemented");
 339         }
 340     }
 341 
 342     @SuppressWarnings("unused")
 343     public static void move(TargetMethodAssembler tasm, HSAILAssembler masm, Value result, Value input) {
 344         if (isRegister(input)) {
 345             if (isRegister(result)) {
 346                 masm.emitMov(result, input);
 347             } else if (isStackSlot(result)) {
 348                 masm.emitSpillStore(input, result);
 349             } else {
 350                 throw GraalInternalError.shouldNotReachHere();
 351             }
 352         } else if (isStackSlot(input)) {
 353             if (isRegister(result)) {
 354                 masm.emitSpillLoad(result, input);
 355             } else {
 356                 throw GraalInternalError.shouldNotReachHere();
 357             }
 358         } else if (isConstant(input)) {
 359             if (isRegister(result)) {
 360                 masm.emitMov(result, input);
 361             } else {
 362                 throw GraalInternalError.shouldNotReachHere();
 363             }
 364         } else {
 365             throw GraalInternalError.shouldNotReachHere();
 366         }
 367     }
 368 
 369     @SuppressWarnings("unused")
 370     protected static void compareAndSwap(TargetMethodAssembler tasm, HSAILAssembler masm, AllocatableValue result, HSAILAddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
 371         throw new InternalError("NYI");
 372     }
 373 }