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.compiler.hsail;
  24 
  25 import static com.oracle.graal.api.code.CallingConvention.Type.*;
  26 
  27 import static com.oracle.graal.api.code.ValueUtil.*;
  28 
  29 import com.oracle.graal.api.code.*;
  30 import com.oracle.graal.api.meta.*;
  31 import com.oracle.graal.asm.*;
  32 import com.oracle.graal.asm.hsail.*;
  33 import com.oracle.graal.compiler.gen.*;
  34 import com.oracle.graal.compiler.target.*;
  35 import com.oracle.graal.debug.*;
  36 import com.oracle.graal.lir.*;
  37 import com.oracle.graal.lir.asm.*;
  38 import com.oracle.graal.nodes.*;
  39 import com.oracle.graal.hsail.*;
  40 
  41 import java.util.Map;
  42 import java.util.HashMap;
  43 import java.lang.reflect.Modifier;
  44 import java.util.Arrays;
  45 
  46 /**
  47  * HSAIL specific backend.
  48  */
  49 public class HSAILBackend extends Backend {
  50 
  51     private Map<String, String> paramTypeMap = new HashMap<>();
  52     private Buffer codeBuffer;
  53 
  54     public HSAILBackend(CodeCacheProvider runtime, TargetDescription target) {
  55         super(runtime, target);
  56         paramTypeMap.put("HotSpotResolvedPrimitiveType<int>", "s32");
  57         paramTypeMap.put("HotSpotResolvedPrimitiveType<float>", "f32");
  58         paramTypeMap.put("HotSpotResolvedPrimitiveType<double>", "f64");
  59         paramTypeMap.put("HotSpotResolvedPrimitiveType<long>", "s64");
  60     }
  61 
  62     @Override
  63     public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir) {
  64         return new HSAILLIRGenerator(graph, runtime(), target, frameMap, cc, lir);
  65     }
  66 
  67     public String getPartialCodeString() {
  68         return (codeBuffer == null ? "" : new String(codeBuffer.copyData(0, codeBuffer.position())));
  69     }
  70 
  71     class HotSpotFrameContext implements FrameContext {
  72 
  73         @Override
  74         public void enter(TargetMethodAssembler tasm) {
  75             Debug.log("Nothing to do here");
  76         }
  77 
  78         @Override
  79         public void leave(TargetMethodAssembler tasm) {
  80             Debug.log("Nothing to do here");
  81         }
  82     }
  83 
  84     @Override
  85     protected AbstractAssembler createAssembler(FrameMap frameMap) {
  86         return new HSAILAssembler(target);
  87     }
  88 
  89     @Override
  90     public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) {
  91         FrameMap frameMap = lirGen.frameMap;
  92         AbstractAssembler masm = new HSAILAssembler(target);
  93         HotSpotFrameContext frameContext = new HotSpotFrameContext();
  94         TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult);
  95         tasm.setFrameSize(frameMap.frameSize());
  96         return tasm;
  97     }
  98 
  99     @Override
 100     public void emitCode(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod method) {
 101         assert method != null : lirGen.getGraph() + " is not associated with a method";
 102         // Emit the prologue.
 103         codeBuffer = tasm.asm.codeBuffer;
 104         codeBuffer.emitString0("version 0:95: $full : $large;");
 105         codeBuffer.emitString("");
 106         Signature signature = method.getSignature();
 107         int sigParamCount = signature.getParameterCount(false);
 108         // We're subtracting 1 because we're not making the final gid as a parameter.
 109         int nonConstantParamCount = sigParamCount - 1;
 110         boolean isStatic = (Modifier.isStatic(method.getModifiers()));
 111         // Determine if this is an object lambda.
 112         boolean isObjectLambda = true;
 113         if (signature.getParameterType(nonConstantParamCount, null).getKind() == Kind.Int) {
 114             isObjectLambda = false;
 115         } else {
 116             // Add space for gid int reg.
 117             nonConstantParamCount++;
 118         }
 119 
 120         // If this is an instance method, include mappings for the "this" parameter
 121         // as the first parameter.
 122         if (!isStatic) {
 123             nonConstantParamCount++;
 124         }
 125         // Add in any "constant" parameters (currently none).
 126         int totalParamCount = nonConstantParamCount;
 127         JavaType[] paramtypes = new JavaType[totalParamCount];
 128         String[] paramNames = new String[totalParamCount];
 129         int pidx = 0;
 130         for (int i = 0; i < totalParamCount; i++) {
 131             if (i == 0 && !isStatic) {
 132                 paramtypes[i] = runtime().lookupJavaType(Object.class);
 133                 paramNames[i] = "%_this";
 134             } else if (i < nonConstantParamCount) {
 135                 if (isObjectLambda && (i == (nonConstantParamCount))) {
 136                     // Set up the gid register mapping.
 137                     paramtypes[i] = runtime().lookupJavaType(int.class);
 138                     paramNames[i] = "%_gid";
 139                 } else {
 140                     paramtypes[i] = signature.getParameterType(pidx++, null);
 141                     paramNames[i] = "%_arg" + i;
 142                 }
 143             }
 144         }
 145         codeBuffer.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method);
 146         codeBuffer.emitString("");
 147         codeBuffer.emitString0("kernel &run (");
 148         codeBuffer.emitString("");
 149         FrameMap frameMap = tasm.frameMap;
 150         RegisterConfig regConfig = frameMap.registerConfig;
 151         // Build list of param types which does include the gid (for cc register mapping query).
 152         JavaType[] ccParamTypes = new JavaType[nonConstantParamCount + 1];
 153         // Include the gid.
 154         System.arraycopy(paramtypes, 0, ccParamTypes, 0, nonConstantParamCount);
 155         // Last entry comes from the signature.
 156         ccParamTypes[ccParamTypes.length - 1] = signature.getParameterType(sigParamCount - 1, null);
 157         CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, ccParamTypes, target, false);
 158         /**
 159          * Compute the hsail size mappings up to but not including the last non-constant parameter
 160          * (which is the gid).
 161          * 
 162          */
 163         String[] paramHsailSizes = new String[totalParamCount];
 164         for (int i = 0; i < totalParamCount; i++) {
 165             String paramtypeStr = paramtypes[i].toString();
 166             String sizeStr = paramTypeMap.get(paramtypeStr);
 167             // Catch all for any unmapped paramtype that is u64 (address of an object).
 168             paramHsailSizes[i] = (sizeStr != null ? sizeStr : "u64");
 169         }
 170         // Emit the kernel function parameters.
 171         for (int i = 0; i < totalParamCount; i++) {
 172             String str = "kernarg_" + paramHsailSizes[i] + " " + paramNames[i];
 173             if (i != totalParamCount - 1) {
 174                 str += ",";
 175             }
 176             codeBuffer.emitString(str);
 177         }
 178         codeBuffer.emitString(") {");
 179 
 180         /*
 181          * End of parameters start of prolog code. Emit the load instructions for loading of the
 182          * kernel non-constant parameters into registers. The constant class parameters will not be
 183          * loaded up front but will be loaded as needed.
 184          */
 185         for (int i = 0; i < nonConstantParamCount; i++) {
 186             codeBuffer.emitString("ld_kernarg_" + paramHsailSizes[i] + "  " + HSAIL.mapRegister(cc.getArgument(i)) + ", [" + paramNames[i] + "];");
 187         }
 188 
 189         /*
 190          * Emit the workitemaid instruction for loading the hidden gid parameter. This is assigned
 191          * the register as if it were the last of the nonConstant parameters.
 192          */
 193         String workItemReg = "$s" + Integer.toString(asRegister(cc.getArgument(nonConstantParamCount)).encoding());
 194         codeBuffer.emitString("workitemabsid_u32 " + workItemReg + ", 0;");
 195 
 196         /*
 197          * Note the logic used for this spillseg size is to leave space and then go back and patch
 198          * in the correct size once we have generated all the instructions. This should probably be
 199          * done in a more robust way by implementing something like codeBuffer.insertString.
 200          */
 201         int spillsegDeclarationPosition = codeBuffer.position() + 1;
 202         String spillsegTemplate = "align 4 spill_u8 %spillseg[123456];";
 203         codeBuffer.emitString(spillsegTemplate);
 204         // Emit object array load prologue here.
 205         if (isObjectLambda) {
 206             final int arrayElementsOffset = 24;
 207             String iterationObjArgReg = HSAIL.mapRegister(cc.getArgument(nonConstantParamCount - 1));
 208             String tmpReg = workItemReg.replace("s", "d"); // "$d1";
 209             // Convert gid to long.
 210             codeBuffer.emitString("cvt_u64_s32 " + tmpReg + ", " + workItemReg + "; // Convert gid to long");
 211             // Adjust index for sizeof ref.
 212             codeBuffer.emitString("mul_u64 " + tmpReg + ", " + tmpReg + ", " + 8 + "; // Adjust index for sizeof ref");
 213             // Adjust for actual data start.
 214             codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + arrayElementsOffset + "; // Adjust for actual elements data start");
 215             // Add to array ref ptr.
 216             codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + iterationObjArgReg + "; // Add to array ref ptr");
 217             // Load the object into the parameter reg.
 218             codeBuffer.emitString("ld_global_u64 " + iterationObjArgReg + ", " + "[" + tmpReg + "]" + "; // Load from array element into parameter reg");
 219         }
 220         // Prologue done, Emit code for the LIR.
 221         lirGen.lir.emitCode(tasm);
 222         // Now that code is emitted go back and figure out what the upper Bound stack size was.
 223         long maxStackSize = ((HSAILAssembler) tasm.asm).upperBoundStackSize();
 224         String spillsegStringFinal;
 225         if (maxStackSize == 0) {
 226             // If no spilling, get rid of spillseg declaration.
 227             char[] array = new char[spillsegTemplate.length()];
 228             Arrays.fill(array, ' ');
 229             spillsegStringFinal = new String(array);
 230         } else {
 231             spillsegStringFinal = spillsegTemplate.replace("123456", String.format("%6d", maxStackSize));
 232         }
 233         codeBuffer.emitString(spillsegStringFinal, spillsegDeclarationPosition);
 234         // Emit the epilogue.
 235         codeBuffer.emitString0("};");
 236         codeBuffer.emitString("");
 237     }
 238 }