public void issue(StringBuilder sbResult) { sbResult.append(m_strInstructionName); sbResult.append(" "); boolean bFirst = true; for (IOperand op : m_rgOperands) { if (!bFirst) sbResult.append(", "); sbResult.append(op.toString()); bFirst = false; } sbResult.append("\\n\\t"); }
@Override public String toJavaCode(Map<IOperand, String> mapOperands) { StringBuilder sb = new StringBuilder(); StringBuilder sbInstr = new StringBuilder("il.addInstruction (new Instruction (\""); sbInstr.append(m_strInstructionName); sbInstr.append('"'); if (m_intrinsic != null) { sbInstr.append(", TypeBaseIntrinsicEnum."); sbInstr.append(m_intrinsic.value()); } for (IOperand op : m_rgOperands) { String strOp = mapOperands.get(op); if (strOp == null) { strOp = op.toJavaCode(); String[] strParts = strOp.split(" "); if (strParts[0].equals("new")) { String strOperand = StringUtil.concat("op", mapOperands.size()); sb.append(strParts[1]); sb.append(' '); sb.append(strOperand); sb.append(" = "); sb.append(strOp); sb.append(";\n"); strOp = strOperand; } mapOperands.put(op, strOp); } sbInstr.append(", "); sbInstr.append(strOp); } sbInstr.append("));"); sb.append(sbInstr); return sb.toString(); }
/** * Translates the generic instruction <code>instruction</code> into an architecture-specific one. * The generated instruction(s) are added to the <code>m_ilOut</code> instruction list. * * @param instruction The instruction to translate */ private void translateInstruction(Instruction instruction) { Intrinsic intrinsic = getIntrinsicForInstruction(instruction); if (intrinsic == null) { LOGGER.debug( StringUtil.concat( "No intrinsic found for the instruction ", instruction.getInstructionName())); m_ilOut.addInstruction(instruction); return; } // get the source operands, i.e., the instruction arguments IOperand[] rgSourceOps = instruction.getOperands(); IOperand opSourceOutput = rgSourceOps[rgSourceOps.length - 1]; // get the destination operands, i.e., the arguments of the architecture-specific intrinsic Argument[] rgDestArgs = null; if (intrinsic.getArguments() != null) rgDestArgs = Arguments.parseArguments(intrinsic.getArguments()); else { LOGGER.debug( StringUtil.concat( "No arguments were defined for the intrinsic ", intrinsic.getBaseName(), ". Assuming generic arguments.")); rgDestArgs = InstructionListTranslator.createGenericArguments(rgSourceOps.length); } // check whether the number of arguments of the instruction and the intrinsic to be generated // match // the source instruction always has a result operand (the last instruction argument); in the // intrinsic // the result might be merged into one of the operands, so there might be one argument less if (rgSourceOps.length != rgDestArgs.length && rgSourceOps.length - 1 != rgDestArgs.length) { LOGGER.error( StringUtil.concat( "The arguments for the instruction ", instruction.toString(), " mapped to the intrinsic ", intrinsic.getBaseName(), " don't match")); return; } boolean bIntrinsicHasSharedResult = rgSourceOps.length - 1 == rgDestArgs.length; int nOutputArgDestIndex = InstructionListTranslator.getOutputArgumentIndex(rgDestArgs); int[] rgPermSourceToDest = new int[rgSourceOps.length]; int[] rgPermDestToSource = new int[rgDestArgs.length]; InstructionListTranslator.getArgumentPermutations( intrinsic, rgSourceOps, rgDestArgs, rgPermSourceToDest, rgPermDestToSource); if (!bIntrinsicHasSharedResult) { // the intrinsic to generate has a distinct output operand // if possible, swap commutative operands if that helps saving MOVs rgSourceOps = InstructionListTranslator.compatibilizeCommutatives( intrinsic, rgSourceOps, rgDestArgs, rgPermSourceToDest, rgPermDestToSource, nOutputArgDestIndex, bIntrinsicHasSharedResult); } else { // the intrinsic to generate has an operand which is used for shared input and output, // i.e., upon completion of the instruction, the shared operand is overwritten with the result if (opSourceOutput.equals(rgSourceOps[rgPermDestToSource[nOutputArgDestIndex]])) { // the argument of the instruction corresponding to the shared intrinsic operand // is the same as the instruction's result argument } else { if (rgSourceOps[rgSourceOps.length - 1] instanceof IOperand.IRegisterOperand) { // if possible, swap commutative operands if that helps saving MOVs rgSourceOps = InstructionListTranslator.compatibilizeCommutatives( intrinsic, rgSourceOps, rgDestArgs, rgPermSourceToDest, rgPermDestToSource, nOutputArgDestIndex, bIntrinsicHasSharedResult); } } } createInstructions( instruction, intrinsic, rgSourceOps, rgDestArgs, rgPermSourceToDest, rgPermDestToSource, nOutputArgDestIndex, bIntrinsicHasSharedResult); }
/** * Creates the architecture-specific instructions to implement the generic instruction <code> * instruction</code> for the intrinsic <code>intrinsic</code>. * * @param instruction The generic instruction * @param intrinsic The intrinsic corresponding to <code>instruction</code> * @param rgSourceOps The array of operands of the generic instruction * @param rgDestArgs The array of intrinsic arguments * @param rgPermSourceToDest The argument permutation source → destination (where source is * the generic instruction, destination is the target architecture specific instruction) * @param rgPermDestToSource The argument permutation destination → source (where source is * the generic instruction, destination is the target architecture specific instruction) * @param nOutputArgDestIndex The index of the output argument in the array of intrinsic * arguments, <code>rgDestArgs</code> * @param bIntrinsicHasSharedResult <code>true</code> iff the intrinsic requires that an argument * is a shared in/out */ private void createInstructions( Instruction instruction, Intrinsic intrinsic, IOperand[] rgSourceOps, Argument[] rgDestArgs, int[] rgPermSourceToDest, int[] rgPermDestToSource, int nOutputArgDestIndex, boolean bIntrinsicHasSharedResult) { // maps operands to substitute operands within the actual generated computation instruction Map<IOperand, IOperand> mapSubstitutions = new HashMap<>(); IOperand[] rgDestOps = new IOperand[rgDestArgs.length]; IOperand opSourceOutput = rgSourceOps[rgSourceOps.length - 1]; boolean bHasNonCompatibleResultOperand = false; IOperand opTmpResultOperand = null; if (bIntrinsicHasSharedResult) { // find the operand which, in the intrinsic, is both input and output IOperand opShared = rgSourceOps[rgPermDestToSource[nOutputArgDestIndex]]; // if the respective input and the output arguments are different, move the value of the input // to the result // the result will then be overwritten by the intrinsic if (!opSourceOutput.equals(opShared)) { IOperand opOut = opSourceOutput; boolean bIsOneOfNonSharedInputArgsResult = InstructionListTranslator.getIndexOfNonSharedInputArgsResult(rgSourceOps, opShared) != -1; if (!(opSourceOutput instanceof IOperand.IRegisterOperand) || bIsOneOfNonSharedInputArgsResult) { bHasNonCompatibleResultOperand = true; opTmpResultOperand = new IOperand.PseudoRegister(TypeRegisterType.SIMD); opOut = opTmpResultOperand; } // opOut can replace both opShared (the input operand, which in the architecture-specific // intrinsic // is also an output argument) and opOut (the operand, to which the result is written) mapSubstitutions.put(opShared, opOut); if (!bIsOneOfNonSharedInputArgsResult) mapSubstitutions.put(opSourceOutput, opOut); Instruction instrNewMov = new Instruction( getMovFpr(opShared instanceof IOperand.Address, opShared), opShared, opOut); instrNewMov.setParameterAssignment(instruction.getParameterAssignment()); translateInstruction(instrNewMov); } } // gather operands and issue move instructions for non-compatible operands for (int i = 0; i < rgSourceOps.length; i++) { if (rgPermSourceToDest[i] != UNDEFINED) { boolean bIsResultOperand = i == rgSourceOps.length - 1; IOperand opSubstitute = mapSubstitutions.get(rgSourceOps[i]); if (opSubstitute != null) { // if already a non-compatible result operand has been found, // substitute the corresponding operand with the temporary one rgDestOps[rgPermSourceToDest[i]] = opSubstitute; } else { boolean bIsCompatible = isCompatible(rgSourceOps[i], rgDestArgs[rgPermSourceToDest[i]]); rgDestOps[rgPermSourceToDest[i]] = bIsCompatible ? rgSourceOps[i] : new IOperand.PseudoRegister(TypeRegisterType.SIMD); if (!bIsCompatible) { if (bIsResultOperand) { // this is the result operand // move instruction will be generated after issuing the main instruction bHasNonCompatibleResultOperand = true; opTmpResultOperand = rgDestOps[rgPermSourceToDest[i]]; } else { // mov arg_i, tmp mapSubstitutions.put(rgSourceOps[i], rgDestOps[rgPermSourceToDest[i]]); Instruction instrNewMov = new Instruction( getMovFpr(rgSourceOps[i] instanceof IOperand.Address, rgSourceOps[i]), rgSourceOps[i], rgDestOps[rgPermSourceToDest[i]]); instrNewMov.setParameterAssignment(instruction.getParameterAssignment()); translateInstruction(instrNewMov); } } } } } // add the main instruction //// // if (instruction.getIntrinsicBaseName ().equals (TypeBaseIntrinsicEnum.DIVIDE.value ())) // { // IOperand.PseudoRegister opTmp = new IOperand.PseudoRegister (TypeRegisterType.SIMD); // m_ilOut.addInstruction (new Instruction ("vrcpps", rgDestOps[0], opTmp)); // m_ilOut.addInstruction (new Instruction ("vmulps", rgDestOps[1], opTmp, rgDestOps[2])); // } // else //// String strInstruction = intrinsic.getName(); boolean bIsLoad = intrinsic.getBaseName().equals(TypeBaseIntrinsicEnum.LOAD_FPR_ALIGNED.value()); boolean bIsStore = intrinsic.getBaseName().equals(TypeBaseIntrinsicEnum.STORE_FPR_ALIGNED.value()); if (bIsLoad || bIsStore) { Intrinsic i = m_data .getArchitectureDescription() .getIntrinsic(getMovFpr(bIsLoad, rgDestOps).value(), m_specDatatype); if (i != null) strInstruction = i.getName(); } Instruction instrNew = new Instruction(strInstruction, instruction.getIntrinsic(), rgDestOps); instrNew.setParameterAssignment(instruction.getParameterAssignment()); m_ilOut.addInstruction(instrNew); // add a move-result instruction if needed if (bHasNonCompatibleResultOperand) { // mov tmp, result Instruction instrNewMov = new Instruction( getMovFpr(opTmpResultOperand instanceof IOperand.Address, opTmpResultOperand), opTmpResultOperand, rgSourceOps[rgSourceOps.length - 1]); instrNewMov.setParameterAssignment(instruction.getParameterAssignment()); translateInstruction(instrNewMov); } }