Main Content

coder.inline

控制生成代码中当前函数的内联

说明

示例

coder.inline("always") 在生成代码中内联当前函数(coder.inline 所在的函数)。使用 coder.inline("always") 优化指令将函数调用替换为被调函数的函数体。内联消除了函数调用的开销,并为进一步优化生成的 C/C++ 代码提供了机会。但是,内联可能生成更庞大、更复杂的 C/C++ 代码。

coder.inline("always") 指令不支持以下项的内联:

  • 入口函数

  • 递归函数

  • 包含 parfor 循环的函数

  • parfor 循环中调用的函数

示例

coder.inline("never") 可阻止在生成的代码中内联使用它的函数。当您要简化 MATLAB® 源代码和生成代码之间的映射时,请使用 coder.inline("never") 优化指令。

coder.inline("never") 指令不会阻止以下项的内联:

  • 空函数

  • 返回常量输出的函数

若要即使在这些情况下也防止内联,请在 MATLAB 代码中的函数调用点对输入使用 coder.ignoreConst 函数。有关详细信息,请参阅Resolve Issue: coder.inline("never") and coder.nonInlineCall Do Not Prevent Function Inlining

示例

coder.inline("default") 指示代码生成器使用内部启发式方法来确定是否内联当前函数。通常,这些启发式方法会产生高度优化的代码。

示例

全部折叠

创建一个入口函数 inliningEntryPoint,该函数调用两个局部函数 local_Inlinelocal_NoInline。这两个局部函数都返回输入值的平方,但 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  : 20-Apr-2024 06:06:37
 */

/* 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 指令根据输入参量等参数来控制函数内联。

创建入口函数 conditionalInlining,该函数调用局部函数 simpleDivision。仅当两个输入参量均为标量时,才使用多个 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  : 20-Apr-2024 06:07:41
 */

/* 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  : 20-Apr-2024 06:07:45
 */

/* 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]
 */

提示

  • 如果使用 codegenfiaccel (Fixed-Point Designer) 命令,则可以使用 -O disable:inline 选项对所有函数禁用内联。

  • 与从 MathWorks® 函数生成的 C/C++ 代码相比,从您编写的函数生成的 C/C++ 代码可能有不同速度和可读性要求。附加的全局设置使您能够控制生成的代码库的这两部分的内联。请参阅Control Inlining to Fine-Tune Performance and Readability of Generated Code

扩展功能

C/C++ 代码生成
使用 MATLAB® Coder™ 生成 C 代码和 C++ 代码。

GPU 代码生成
使用 GPU Coder™ 为 NVIDIA® GPU 生成 CUDA® 代码。

版本历史记录

在 R2011a 中推出