--- /dev/null 2013-07-08 15:00:58.000000000 -0700 +++ new/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILBackend.java 2013-07-08 15:00:58.000000000 -0700 @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.hsail; + +import static com.oracle.graal.api.code.CallingConvention.Type.*; + +import static com.oracle.graal.api.code.ValueUtil.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.hsail.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.hsail.*; + +import java.util.Map; +import java.util.HashMap; +import java.lang.reflect.Modifier; +import java.util.Arrays; + +/** + * HSAIL specific backend. + */ +public class HSAILBackend extends Backend { + + private Map paramTypeMap = new HashMap<>(); + private Buffer codeBuffer; + + public HSAILBackend(CodeCacheProvider runtime, TargetDescription target) { + super(runtime, target); + paramTypeMap.put("HotSpotResolvedPrimitiveType", "s32"); + paramTypeMap.put("HotSpotResolvedPrimitiveType", "f32"); + paramTypeMap.put("HotSpotResolvedPrimitiveType", "f64"); + paramTypeMap.put("HotSpotResolvedPrimitiveType", "s64"); + } + + @Override + public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir) { + return new HSAILLIRGenerator(graph, runtime(), target, frameMap, cc, lir); + } + + public String getPartialCodeString() { + return (codeBuffer == null ? "" : new String(codeBuffer.copyData(0, codeBuffer.position()))); + } + + class HotSpotFrameContext implements FrameContext { + + @Override + public void enter(TargetMethodAssembler tasm) { + Debug.log("Nothing to do here"); + } + + @Override + public void leave(TargetMethodAssembler tasm) { + Debug.log("Nothing to do here"); + } + } + + @Override + protected AbstractAssembler createAssembler(FrameMap frameMap) { + return new HSAILAssembler(target); + } + + @Override + public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) { + FrameMap frameMap = lirGen.frameMap; + AbstractAssembler masm = new HSAILAssembler(target); + HotSpotFrameContext frameContext = new HotSpotFrameContext(); + TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult); + tasm.setFrameSize(frameMap.frameSize()); + return tasm; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod method) { + assert method != null : lirGen.getGraph() + " is not associated with a method"; + // Emit the prologue. + codeBuffer = tasm.asm.codeBuffer; + codeBuffer.emitString0("version 0:95: $full : $large;"); + codeBuffer.emitString(""); + Signature signature = method.getSignature(); + int sigParamCount = signature.getParameterCount(false); + // We're subtracting 1 because we're not making the final gid as a parameter. + int nonConstantParamCount = sigParamCount - 1; + boolean isStatic = (Modifier.isStatic(method.getModifiers())); + // Determine if this is an object lambda. + boolean isObjectLambda = true; + if (signature.getParameterType(nonConstantParamCount, null).getKind() == Kind.Int) { + isObjectLambda = false; + } else { + // Add space for gid int reg. + nonConstantParamCount++; + } + + // If this is an instance method, include mappings for the "this" parameter + // as the first parameter. + if (!isStatic) { + nonConstantParamCount++; + } + // Add in any "constant" parameters (currently none). + int totalParamCount = nonConstantParamCount; + JavaType[] paramtypes = new JavaType[totalParamCount]; + String[] paramNames = new String[totalParamCount]; + int pidx = 0; + for (int i = 0; i < totalParamCount; i++) { + if (i == 0 && !isStatic) { + paramtypes[i] = runtime().lookupJavaType(Object.class); + paramNames[i] = "%_this"; + } else if (i < nonConstantParamCount) { + if (isObjectLambda && (i == (nonConstantParamCount))) { + // Set up the gid register mapping. + paramtypes[i] = runtime().lookupJavaType(int.class); + paramNames[i] = "%_gid"; + } else { + paramtypes[i] = signature.getParameterType(pidx++, null); + paramNames[i] = "%_arg" + i; + } + } + } + codeBuffer.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method); + codeBuffer.emitString(""); + codeBuffer.emitString0("kernel &run ("); + codeBuffer.emitString(""); + FrameMap frameMap = tasm.frameMap; + RegisterConfig regConfig = frameMap.registerConfig; + // Build list of param types which does include the gid (for cc register mapping query). + JavaType[] ccParamTypes = new JavaType[nonConstantParamCount + 1]; + // Include the gid. + System.arraycopy(paramtypes, 0, ccParamTypes, 0, nonConstantParamCount); + // Last entry comes from the signature. + ccParamTypes[ccParamTypes.length - 1] = signature.getParameterType(sigParamCount - 1, null); + CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, ccParamTypes, target, false); + /** + * Compute the hsail size mappings up to but not including the last non-constant parameter + * (which is the gid). + * + */ + String[] paramHsailSizes = new String[totalParamCount]; + for (int i = 0; i < totalParamCount; i++) { + String paramtypeStr = paramtypes[i].toString(); + String sizeStr = paramTypeMap.get(paramtypeStr); + // Catch all for any unmapped paramtype that is u64 (address of an object). + paramHsailSizes[i] = (sizeStr != null ? sizeStr : "u64"); + } + // Emit the kernel function parameters. + for (int i = 0; i < totalParamCount; i++) { + String str = "kernarg_" + paramHsailSizes[i] + " " + paramNames[i]; + if (i != totalParamCount - 1) { + str += ","; + } + codeBuffer.emitString(str); + } + codeBuffer.emitString(") {"); + + /* + * End of parameters start of prolog code. Emit the load instructions for loading of the + * kernel non-constant parameters into registers. The constant class parameters will not be + * loaded up front but will be loaded as needed. + */ + for (int i = 0; i < nonConstantParamCount; i++) { + codeBuffer.emitString("ld_kernarg_" + paramHsailSizes[i] + " " + HSAIL.mapRegister(cc.getArgument(i)) + ", [" + paramNames[i] + "];"); + } + + /* + * Emit the workitemaid instruction for loading the hidden gid parameter. This is assigned + * the register as if it were the last of the nonConstant parameters. + */ + String workItemReg = "$s" + Integer.toString(asRegister(cc.getArgument(nonConstantParamCount)).encoding()); + codeBuffer.emitString("workitemabsid_u32 " + workItemReg + ", 0;"); + + /* + * Note the logic used for this spillseg size is to leave space and then go back and patch + * in the correct size once we have generated all the instructions. This should probably be + * done in a more robust way by implementing something like codeBuffer.insertString. + */ + int spillsegDeclarationPosition = codeBuffer.position() + 1; + String spillsegTemplate = "align 4 spill_u8 %spillseg[123456];"; + codeBuffer.emitString(spillsegTemplate); + // Emit object array load prologue here. + if (isObjectLambda) { + final int arrayElementsOffset = 24; + String iterationObjArgReg = HSAIL.mapRegister(cc.getArgument(nonConstantParamCount - 1)); + String tmpReg = workItemReg.replace("s", "d"); // "$d1"; + // Convert gid to long. + codeBuffer.emitString("cvt_u64_s32 " + tmpReg + ", " + workItemReg + "; // Convert gid to long"); + // Adjust index for sizeof ref. + codeBuffer.emitString("mul_u64 " + tmpReg + ", " + tmpReg + ", " + 8 + "; // Adjust index for sizeof ref"); + // Adjust for actual data start. + codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + arrayElementsOffset + "; // Adjust for actual elements data start"); + // Add to array ref ptr. + codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + iterationObjArgReg + "; // Add to array ref ptr"); + // Load the object into the parameter reg. + codeBuffer.emitString("ld_global_u64 " + iterationObjArgReg + ", " + "[" + tmpReg + "]" + "; // Load from array element into parameter reg"); + } + // Prologue done, Emit code for the LIR. + lirGen.lir.emitCode(tasm); + // Now that code is emitted go back and figure out what the upper Bound stack size was. + long maxStackSize = ((HSAILAssembler) tasm.asm).upperBoundStackSize(); + String spillsegStringFinal; + if (maxStackSize == 0) { + // If no spilling, get rid of spillseg declaration. + char[] array = new char[spillsegTemplate.length()]; + Arrays.fill(array, ' '); + spillsegStringFinal = new String(array); + } else { + spillsegStringFinal = spillsegTemplate.replace("123456", String.format("%6d", maxStackSize)); + } + codeBuffer.emitString(spillsegStringFinal, spillsegDeclarationPosition); + // Emit the epilogue. + codeBuffer.emitString0("};"); + codeBuffer.emitString(""); + } +}