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