Пример #1
0
 /**
  * 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 &rarr; destination (where source is
   *     the generic instruction, destination is the target architecture specific instruction)
   * @param rgPermDestToSource The argument permutation destination &rarr; 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);
 }