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 }