Main Content

coder.inline

生成されたコードで現在の関数のインライン化を制御する

説明

coder.inline("always") は、生成されたコードで現在の関数 (coder.inline がある関数) をインライン化します。coder.inline("always") 最適化命令を使用して、関数呼び出しを呼び出される関数の本文に置き換えます。インライン化により、関数呼び出しのオーバーヘッドがなくなり、生成された C/C++ コードをさらに最適化できます。ただし、インライン化で生成される C/C++ コードは大きく、複雑になることがあります。

coder.inline("always") 命令では以下のインライン化はサポートされていません。

  • エントリポイント関数

  • 再帰関数

  • parfor ループを含む関数

  • parfor ループから呼び出される関数

coder.inline("never") は、生成コードで使用されている関数がインライン化されるのを防ぎます。coder.inline("never") 最適化命令は、MATLAB® ソース コードと生成コードの間のマッピングを単純化する場合に使用します。

coder.inline("never") 命令では以下のインライン化は阻止されません。

  • 空の関数

  • 定数出力を返す関数

上記の状況でもインライン化を阻止するには、MATLAB コードの関数呼び出しサイトの入力で関数 coder.ignoreConst (MATLAB Coder) を使用します。詳細については、Resolve Issue: coder.inline("never") and coder.nonInlineCall Do Not Prevent Function Inlining (MATLAB Coder)を参照してください。

coder.inline("default") は、コード ジェネレーターに対して、内部のヒューリスティックな方法を使用して現在の関数をインライン化するかどうかを指示します。通常は、そうしたヒューリスティックな方法によって高度に最適化されたコードが生成されます。

すべて折りたたむ

2 つのローカル関数 local_Inlinelocal_NoInline を呼び出すエントリポイント関数 inliningEntryPoint を作成します。どちらのローカル関数も入力値の 2 乗を返します。ただし、local_Inline は命令 coder.inline("always") を使用しますが、local_NoInline は命令 coder.inline("never") を使用します。

type inliningEntryPoint.m
function [x,y] = inliningEntryPoint(n) %#codegen
arguments
    n (1,1) double
end
x = local_Inline(n);
y = local_NoInline(n);
end

function y = local_Inline(x)
coder.inline("always");
y = x^2;
end

function y = local_NoInline(x)
coder.inline("never");
y = x^2;
end

inliningEntryPoint の C コードを生成し、生成コード内のエントリポイント関数を検査します。コード ジェネレーターは、local_Inline の呼び出しをインライン化しますが、local_NoInline の呼び出しはインライン化しません。

codegen -config:lib inliningEntryPoint
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.

Code generation successful (with warnings): To view the report, open('codegen/lib/inliningEntryPoint/html/report.mldatx')
type(fullfile("codegen","lib","inliningEntryPoint","inliningEntryPoint.c"))
/*
 * File: inliningEntryPoint.c
 *
 * MATLAB Coder version            : 24.1
 * C/C++ source code generated on  : 07-Mar-2024 13:16:09
 */

/* Include Files */
#include "inliningEntryPoint.h"

/* Function Declarations */
static double local_NoInline(double x);

/* Function Definitions */
/*
 * Arguments    : double x
 * Return Type  : double
 */
static double local_NoInline(double x)
{
  return x * x;
}

/*
 * Arguments    : double n
 *                double *x
 *                double *y
 * Return Type  : void
 */
void inliningEntryPoint(double n, double *x, double *y)
{
  *x = n * n;
  *y = local_NoInline(n);
}

/*
 * File trailer for inliningEntryPoint.c
 *
 * [EOF]
 */

複数の coder.inline 命令を使用して、入力引数などのパラメーターに基づいて関数のインライン化を制御できます。

ローカル関数 simpleDivision を呼び出すエントリポイント関数 conditionalInlining を作成します。複数の coder.inline 命令を使用して、両方の入力引数がスカラーの場合にのみ simpleDivision をインライン化するようにコード ジェネレーターに指示します。

type conditionalInlining.m
function out = conditionalInlining(x,y) %#codegen
out = simpleDivision(x,y);
end

function y = simpleDivision(dividend, divisor)
if isscalar(dividend) && isscalar(divisor)
    forceInlining = "always";
else
    forceInlining = "default";
end
coder.inline(forceInlining)
y = dividend / divisor;
end

スカラー入力を指定して conditionalInlining の C コードを生成し、生成されたコード内のエントリポイント関数を調べます。コード ジェネレーターは、生成されたコードで simpleDivision をインライン化します。

codegen -config:lib conditionalInlining -args {3 4}
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.

Code generation successful (with warnings): To view the report, open('codegen/lib/conditionalInlining/html/report.mldatx')
type(fullfile("codegen","lib","conditionalInlining","conditionalInlining.c"))
/*
 * File: conditionalInlining.c
 *
 * MATLAB Coder version            : 24.1
 * C/C++ source code generated on  : 07-Mar-2024 13:17:31
 */

/* Include Files */
#include "conditionalInlining.h"

/* Function Definitions */
/*
 * Arguments    : double x
 *                double y
 * Return Type  : double
 */
double conditionalInlining(double x, double y)
{
  return x / y;
}

/*
 * File trailer for conditionalInlining.c
 *
 * [EOF]
 */

ベクトル入力を指定して conditionalInlining の C コードを生成し、生成されたコード内のエントリポイント関数を調べます。コード ジェネレーターは内部のヒューリスティックな方法を使用して、生成されたコード内で simpleDivision をインライン化するかどうかを決定します。

codegen -config:lib conditionalInlining -args {1:10 11:20}
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.

Code generation successful (with warnings): To view the report, open('codegen/lib/conditionalInlining/html/report.mldatx')
type(fullfile("codegen","lib","conditionalInlining","conditionalInlining.c"))
/*
 * File: conditionalInlining.c
 *
 * MATLAB Coder version            : 24.1
 * C/C++ source code generated on  : 07-Mar-2024 13:17:36
 */

/* Include Files */
#include "conditionalInlining.h"
#include "rt_nonfinite.h"
#include "xnrm2.h"
#include "rt_nonfinite.h"
#include <emmintrin.h>
#include <math.h>
#include <string.h>

/* Function Declarations */
static double rt_hypotd_snf(double u0, double u1);

/* Function Definitions */
/*
 * Arguments    : double u0
 *                double u1
 * Return Type  : double
 */
static double rt_hypotd_snf(double u0, double u1)
{
  double a;
  double b;
  double y;
  a = fabs(u0);
  b = fabs(u1);
  if (a < b) {
    a /= b;
    y = b * sqrt(a * a + 1.0);
  } else if (a > b) {
    b /= a;
    y = a * sqrt(b * b + 1.0);
  } else if (rtIsNaN(b)) {
    y = rtNaN;
  } else {
    y = a * 1.4142135623730951;
  }
  return y;
}

/*
 * Arguments    : const double x[10]
 *                const double y[10]
 * Return Type  : double
 */
double conditionalInlining(const double x[10], const double y[10])
{
  __m128d r;
  __m128d r1;
  double A[10];
  double B[10];
  double out;
  double tau;
  double wj;
  int i;
  int knt;
  int rankA;
  memcpy(&A[0], &y[0], 10U * sizeof(double));
  memcpy(&B[0], &x[0], 10U * sizeof(double));
  tau = 0.0;
  for (i = 0; i < 1; i++) {
    double atmp;
    atmp = A[0];
    tau = 0.0;
    wj = xnrm2(A);
    if (wj != 0.0) {
      double beta1;
      beta1 = rt_hypotd_snf(A[0], wj);
      if (A[0] >= 0.0) {
        beta1 = -beta1;
      }
      if (fabs(beta1) < 1.0020841800044864E-292) {
        knt = 0;
        do {
          knt++;
          r = _mm_loadu_pd(&A[1]);
          r1 = _mm_set1_pd(9.9792015476736E+291);
          _mm_storeu_pd(&A[1], _mm_mul_pd(r1, r));
          r = _mm_loadu_pd(&A[3]);
          _mm_storeu_pd(&A[3], _mm_mul_pd(r1, r));
          r = _mm_loadu_pd(&A[5]);
          _mm_storeu_pd(&A[5], _mm_mul_pd(r1, r));
          r = _mm_loadu_pd(&A[7]);
          _mm_storeu_pd(&A[7], _mm_mul_pd(r1, r));
          A[9] *= 9.9792015476736E+291;
          beta1 *= 9.9792015476736E+291;
          atmp *= 9.9792015476736E+291;
        } while ((fabs(beta1) < 1.0020841800044864E-292) && (knt < 20));
        beta1 = rt_hypotd_snf(atmp, xnrm2(A));
        if (atmp >= 0.0) {
          beta1 = -beta1;
        }
        tau = (beta1 - atmp) / beta1;
        wj = 1.0 / (atmp - beta1);
        r = _mm_loadu_pd(&A[1]);
        r1 = _mm_set1_pd(wj);
        _mm_storeu_pd(&A[1], _mm_mul_pd(r1, r));
        r = _mm_loadu_pd(&A[3]);
        _mm_storeu_pd(&A[3], _mm_mul_pd(r1, r));
        r = _mm_loadu_pd(&A[5]);
        _mm_storeu_pd(&A[5], _mm_mul_pd(r1, r));
        r = _mm_loadu_pd(&A[7]);
        _mm_storeu_pd(&A[7], _mm_mul_pd(r1, r));
        A[9] *= wj;
        for (rankA = 0; rankA < knt; rankA++) {
          beta1 *= 1.0020841800044864E-292;
        }
        atmp = beta1;
      } else {
        tau = (beta1 - A[0]) / beta1;
        wj = 1.0 / (A[0] - beta1);
        r = _mm_loadu_pd(&A[1]);
        r1 = _mm_set1_pd(wj);
        _mm_storeu_pd(&A[1], _mm_mul_pd(r1, r));
        r = _mm_loadu_pd(&A[3]);
        _mm_storeu_pd(&A[3], _mm_mul_pd(r1, r));
        r = _mm_loadu_pd(&A[5]);
        _mm_storeu_pd(&A[5], _mm_mul_pd(r1, r));
        r = _mm_loadu_pd(&A[7]);
        _mm_storeu_pd(&A[7], _mm_mul_pd(r1, r));
        A[9] *= wj;
        atmp = beta1;
      }
    }
    A[0] = atmp;
  }
  rankA = 0;
  wj = fabs(A[0]);
  if (!(wj <= 2.2204460492503131E-14 * wj)) {
    rankA = 1;
  }
  out = 0.0;
  if (tau != 0.0) {
    wj = x[0];
    for (i = 0; i < 9; i++) {
      wj += A[i + 1] * x[i + 1];
    }
    wj *= tau;
    if (wj != 0.0) {
      __m128d r2;
      B[0] = x[0] - wj;
      r = _mm_loadu_pd(&A[1]);
      r1 = _mm_loadu_pd(&B[1]);
      r2 = _mm_set1_pd(wj);
      _mm_storeu_pd(&B[1], _mm_sub_pd(r1, _mm_mul_pd(r, r2)));
      r = _mm_loadu_pd(&A[3]);
      r1 = _mm_loadu_pd(&B[3]);
      _mm_storeu_pd(&B[3], _mm_sub_pd(r1, _mm_mul_pd(r, r2)));
      r = _mm_loadu_pd(&A[5]);
      r1 = _mm_loadu_pd(&B[5]);
      _mm_storeu_pd(&B[5], _mm_sub_pd(r1, _mm_mul_pd(r, r2)));
      r = _mm_loadu_pd(&A[7]);
      r1 = _mm_loadu_pd(&B[7]);
      _mm_storeu_pd(&B[7], _mm_sub_pd(r1, _mm_mul_pd(r, r2)));
    }
  }
  for (i = 0; i < rankA; i++) {
    out = B[0];
  }
  for (knt = rankA; knt >= 1; knt--) {
    out /= A[0];
  }
  return out;
}

/*
 * File trailer for conditionalInlining.c
 *
 * [EOF]
 */

ヒント

  • codegen (MATLAB Coder) コマンドまたは fiaccel (Fixed-Point Designer) コマンドを使用する場合に、-O disable:inline オプションを使用することで、すべての関数のインライン化を無効にできます。

  • 作成した関数から生成された C/C++ コードと、MathWorks® 関数から生成された C/C++ コードでは、速度と読みやすさの要件が異なる場合があります。追加のグローバル設定を使用すると、生成されたコード ベースのこれらの 2 つの部分のインライン化を制御できます。生成コードのパフォーマンスと可読性を微調整するためのインライン化の制御 (MATLAB Coder)を参照してください。

拡張機能

C/C++ コード生成
MATLAB® Coder™ を使用して C および C++ コードを生成します。

GPU コード生成
GPU Coder™ を使用して NVIDIA® GPU のための CUDA® コードを生成します。

バージョン履歴

R2011a で導入