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.hotspot.hsail;
  24 
  25 import static com.oracle.graal.api.code.CallingConvention.Type.*;
  26 import static com.oracle.graal.api.code.ValueUtil.*;
  27 
  28 import java.lang.reflect.*;
  29 import java.util.*;
  30 
  31 import com.oracle.graal.api.code.*;
  32 import com.oracle.graal.api.meta.*;
  33 import com.oracle.graal.asm.*;
  34 import com.oracle.graal.asm.hsail.*;
  35 import com.oracle.graal.compiler.gen.*;
  36 import com.oracle.graal.debug.*;
  37 import com.oracle.graal.hotspot.*;
  38 import com.oracle.graal.hotspot.meta.*;
  39 import com.oracle.graal.hsail.*;
  40 import com.oracle.graal.lir.*;
  41 import com.oracle.graal.lir.asm.*;
  42 import com.oracle.graal.lir.hsail.*;
  43 import com.oracle.graal.nodes.*;
  44 
  45 /**
  46  * HSAIL specific backend.
  47  */
  48 public class HSAILHotSpotBackend extends HotSpotBackend {
  49 
  50     private Map<String, String> paramTypeMap = new HashMap<>();
  51     private Buffer codeBuffer;
  52 
  53     public HSAILHotSpotBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) {
  54         super(runtime, providers);
  55         paramTypeMap.put("HotSpotResolvedPrimitiveType<int>", "s32");
  56         paramTypeMap.put("HotSpotResolvedPrimitiveType<float>", "f32");
  57         paramTypeMap.put("HotSpotResolvedPrimitiveType<double>", "f64");
  58         paramTypeMap.put("HotSpotResolvedPrimitiveType<long>", "s64");
  59     }
  60 
  61     @Override
  62     public boolean shouldAllocateRegisters() {
  63         return true;
  64     }
  65 
  66     @Override
  67     public void completeInitialization() {
  68         final HotSpotProviders providers = getProviders();
  69         HotSpotVMConfig config = getRuntime().getConfig();
  70         final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
  71         lowerer.initialize(providers, config);
  72     }
  73 
  74     /**
  75      * Use the HSAIL register set when the compilation target is HSAIL.
  76      */
  77     @Override
  78     public FrameMap newFrameMap() {
  79         return new HSAILFrameMap(getCodeCache());
  80     }
  81 
  82     @Override
  83     public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir) {
  84         return new HSAILHotSpotLIRGenerator(graph, getProviders(), getRuntime().getConfig(), frameMap, cc, lir);
  85     }
  86 
  87     public String getPartialCodeString() {
  88         if (codeBuffer == null) {
  89             return "";
  90         }
  91         byte[] data = codeBuffer.copyData(0, codeBuffer.position());
  92         return (data == null ? "" : new String(data));
  93     }
  94 
  95     class HotSpotFrameContext implements FrameContext {
  96 
  97         public boolean hasFrame() {
  98             return true;
  99         }
 100 
 101         @Override
 102         public void enter(CompilationResultBuilder crb) {
 103             Debug.log("Nothing to do here");
 104         }
 105 
 106         @Override
 107         public void leave(CompilationResultBuilder crb) {
 108             Debug.log("Nothing to do here");
 109         }
 110     }
 111 
 112     @Override
 113     protected AbstractAssembler createAssembler(FrameMap frameMap) {
 114         return new HSAILAssembler(getTarget());
 115     }
 116 
 117     @Override
 118     public CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
 119         FrameMap frameMap = lirGen.frameMap;
 120         AbstractAssembler masm = createAssembler(frameMap);
 121         HotSpotFrameContext frameContext = new HotSpotFrameContext();
 122         CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult);
 123         crb.setFrameSize(frameMap.frameSize());
 124         return crb;
 125     }
 126 
 127     @Override
 128     public void emitCode(CompilationResultBuilder crb, LIRGenerator lirGen, ResolvedJavaMethod method) {
 129         assert method != null : lirGen.getGraph() + " is not associated with a method";
 130         // Emit the prologue.
 131         codeBuffer = crb.asm.codeBuffer;
 132         codeBuffer.emitString0("version 0:95: $full : $large;");
 133         codeBuffer.emitString("");
 134 
 135         Signature signature = method.getSignature();
 136         int sigParamCount = signature.getParameterCount(false);
 137         // We're subtracting 1 because we're not making the final gid as a parameter.
 138 
 139         int nonConstantParamCount = sigParamCount - 1;
 140         boolean isStatic = (Modifier.isStatic(method.getModifiers()));
 141         // Determine if this is an object lambda.
 142         boolean isObjectLambda = true;
 143 
 144         if (signature.getParameterType(nonConstantParamCount, null).getKind() == Kind.Int) {
 145             isObjectLambda = false;
 146         } else {
 147             // Add space for gid int reg.
 148             nonConstantParamCount++;
 149         }
 150 
 151         // If this is an instance method, include mappings for the "this" parameter
 152         // as the first parameter.
 153         if (!isStatic) {
 154             nonConstantParamCount++;
 155         }
 156         // Add in any "constant" parameters (currently none).
 157         int totalParamCount = nonConstantParamCount;
 158         JavaType[] paramtypes = new JavaType[totalParamCount];
 159         String[] paramNames = new String[totalParamCount];
 160         int pidx = 0;
 161         MetaAccessProvider metaAccess = getProviders().getMetaAccess();
 162         for (int i = 0; i < totalParamCount; i++) {
 163             if (i == 0 && !isStatic) {
 164                 paramtypes[i] = metaAccess.lookupJavaType(Object.class);
 165                 paramNames[i] = "%_this";
 166             } else if (i < nonConstantParamCount) {
 167                 if (isObjectLambda && (i == (nonConstantParamCount))) {
 168                     // Set up the gid register mapping.
 169                     paramtypes[i] = metaAccess.lookupJavaType(int.class);
 170                     paramNames[i] = "%_gid";
 171                 } else {
 172                     paramtypes[i] = signature.getParameterType(pidx++, null);
 173                     paramNames[i] = "%_arg" + i;
 174                 }
 175             }
 176         }
 177 
 178         codeBuffer.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method);
 179         codeBuffer.emitString("");
 180         codeBuffer.emitString0("kernel &run (");
 181         codeBuffer.emitString("");
 182 
 183         FrameMap frameMap = crb.frameMap;
 184         RegisterConfig regConfig = frameMap.registerConfig;
 185         // Build list of param types which does include the gid (for cc register mapping query).
 186         JavaType[] ccParamTypes = new JavaType[nonConstantParamCount + 1];
 187         // Include the gid.
 188         System.arraycopy(paramtypes, 0, ccParamTypes, 0, nonConstantParamCount);
 189 
 190         // Last entry is always int (its register gets used in the workitemabsid instruction)
 191         // this is true even for object stream labmdas
 192         if (sigParamCount > 0) {
 193             ccParamTypes[ccParamTypes.length - 1] = metaAccess.lookupJavaType(int.class);
 194         }
 195         CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, ccParamTypes, getTarget(), false);
 196 
 197         /**
 198          * Compute the hsail size mappings up to but not including the last non-constant parameter
 199          * (which is the gid).
 200          * 
 201          */
 202         String[] paramHsailSizes = new String[totalParamCount];
 203         for (int i = 0; i < totalParamCount; i++) {
 204             String paramtypeStr = paramtypes[i].toString();
 205             String sizeStr = paramTypeMap.get(paramtypeStr);
 206             // Catch all for any unmapped paramtype that is u64 (address of an object).
 207             paramHsailSizes[i] = (sizeStr != null ? sizeStr : "u64");
 208         }
 209         // Emit the kernel function parameters.
 210         for (int i = 0; i < totalParamCount; i++) {
 211             String str = "kernarg_" + paramHsailSizes[i] + " " + paramNames[i];
 212 
 213             if (i != totalParamCount - 1) {
 214                 str += ",";
 215             }
 216             codeBuffer.emitString(str);
 217         }
 218         codeBuffer.emitString(") {");
 219 
 220         /*
 221          * End of parameters start of prolog code. Emit the load instructions for loading of the
 222          * kernel non-constant parameters into registers. The constant class parameters will not be
 223          * loaded up front but will be loaded as needed.
 224          */
 225         for (int i = 0; i < nonConstantParamCount; i++) {
 226             codeBuffer.emitString("ld_kernarg_" + paramHsailSizes[i] + "  " + HSAIL.mapRegister(cc.getArgument(i)) + ", [" + paramNames[i] + "];");
 227         }
 228 
 229         /*
 230          * Emit the workitemaid instruction for loading the hidden gid parameter. This is assigned
 231          * the register as if it were the last of the nonConstant parameters.
 232          */
 233         String workItemReg = "$s" + Integer.toString(asRegister(cc.getArgument(nonConstantParamCount)).encoding());
 234         codeBuffer.emitString("workitemabsid_u32 " + workItemReg + ", 0;");
 235 
 236         /*
 237          * Note the logic used for this spillseg size is to leave space and then go back and patch
 238          * in the correct size once we have generated all the instructions. This should probably be
 239          * done in a more robust way by implementing something like codeBuffer.insertString.
 240          */
 241         int spillsegDeclarationPosition = codeBuffer.position() + 1;
 242         String spillsegTemplate = "align 4 spill_u8 %spillseg[123456];";
 243         codeBuffer.emitString(spillsegTemplate);
 244         // Emit object array load prologue here.
 245         if (isObjectLambda) {
 246             boolean useCompressedOops = getRuntime().getConfig().useCompressedOops;
 247             final int arrayElementsOffset = HotSpotGraalRuntime.getArrayBaseOffset(Kind.Object);
 248             String iterationObjArgReg = HSAIL.mapRegister(cc.getArgument(nonConstantParamCount - 1));
 249             // iterationObjArgReg will be the highest $d register in use (it is the last parameter)
 250             // so tempReg can be the next higher $d register
 251             String tmpReg = "$d" + (asRegister(cc.getArgument(nonConstantParamCount - 1)).encoding() + 1);
 252             // Convert gid to long.
 253             codeBuffer.emitString("cvt_u64_s32 " + tmpReg + ", " + workItemReg + "; // Convert gid to long");
 254             // Adjust index for sizeof ref. Where to pull this size from?
 255             codeBuffer.emitString("mul_u64 " + tmpReg + ", " + tmpReg + ", " + (useCompressedOops ? 4 : 8) + "; // Adjust index for sizeof ref");
 256             // Adjust for actual data start.
 257             codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + arrayElementsOffset + "; // Adjust for actual elements data start");
 258             // Add to array ref ptr.
 259             codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + iterationObjArgReg + "; // Add to array ref ptr");
 260             // Load the object into the parameter reg.
 261             if (useCompressedOops) {
 262 
 263                 // Load u32 into the d 64 reg since it will become an object address
 264                 codeBuffer.emitString("ld_global_u32 " + tmpReg + ", " + "[" + tmpReg + "]" + "; // Load compressed ptr from array");
 265 
 266                 long narrowOopBase = getRuntime().getConfig().narrowOopBase;
 267                 long narrowOopShift = getRuntime().getConfig().narrowOopShift;
 268 
 269                 if (narrowOopBase == 0 && narrowOopShift == 0) {
 270                     // No more calculation to do, mov to target register
 271                     codeBuffer.emitString("mov_b64 " + iterationObjArgReg + ", " + tmpReg + "; // no shift or base addition");
 272                 } else {
 273                     if (narrowOopBase == 0) {
 274                         codeBuffer.emitString("shl_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopShift + "; // do narrowOopShift");
 275                     } else if (narrowOopShift == 0) {
 276                         codeBuffer.emitString("add_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopBase + "; // add narrowOopBase");
 277                     } else {
 278                         codeBuffer.emitString("mad_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + (1 << narrowOopShift) + ", " + narrowOopBase + "; // shift and add narrowOopBase");
 279                     }
 280                 }
 281 
 282             } else {
 283                 codeBuffer.emitString("ld_global_u64 " + iterationObjArgReg + ", " + "[" + tmpReg + "]" + "; // Load from array element into parameter reg");
 284             }
 285         }
 286         // Prologue done, Emit code for the LIR.
 287         lirGen.lir.emitCode(crb);
 288         // Now that code is emitted go back and figure out what the upper Bound stack size was.
 289         long maxStackSize = ((HSAILAssembler) crb.asm).upperBoundStackSize();
 290         String spillsegStringFinal;
 291         if (maxStackSize == 0) {
 292             // If no spilling, get rid of spillseg declaration.
 293             char[] array = new char[spillsegTemplate.length()];
 294             Arrays.fill(array, ' ');
 295             spillsegStringFinal = new String(array);
 296         } else {
 297             spillsegStringFinal = spillsegTemplate.replace("123456", String.format("%6d", maxStackSize));
 298         }
 299         codeBuffer.emitString(spillsegStringFinal, spillsegDeclarationPosition);
 300         // Emit the epilogue.
 301         codeBuffer.emitString0("};");
 302         codeBuffer.emitString("");
 303     }
 304 }