/** * Creates a copy of <code>instruction</code>. The operands are <b>not</b> deep-copied. * * @param instruction The instruction to copy */ public Instruction(Instruction instruction) { this(instruction.getInstructionName(), instruction.getIntrinsic(), instruction.getOperands()); }
/** * 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); } }
/** * 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); }
/** * Finds the intrinsic for the instruction <code>instruction</code>. * * @param instruction The instruction for which to find the corresponding intrinsic. * @return The instrinsic corresponding to the instruction <code>instruction</code> */ private Intrinsic getIntrinsicForInstruction(Instruction instruction) { return m_data .getArchitectureDescription() .getIntrinsic(instruction.getInstructionName(), m_specDatatype); }