Main Content

coder.inline

Control inlining of current function in generated code

Description

example

coder.inline("always") inlines the current function (the function in which coder.inline appears) in the generated code. Use the coder.inline("always") optimization directive to replace a function call with the body of the called function. Inlining eliminates the overhead of a function call and can create opportunities for further optimization of the generated C/C++ code. However, inlining can generate larger, more complex C/C++ code.

The coder.inline("always") directive does not support the inlining of:

  • Entry-point functions

  • Recursive functions

  • Functions that contain parfor-loops

  • Functions called from parfor-loops

example

coder.inline("never") prevents inlining of the function in which it is used in the generated code. Use the coder.inline("never") optimization directive when you want to simplify the mapping between the MATLAB® source code and the generated code.

The coder.inline("never") directive does not prevent the inlining of:

  • Empty functions

  • Functions that return constant output

To prevent inlining even in these situations, use the coder.ignoreConst (MATLAB Coder) function on an input at the function call site in your MATLAB code. For more information, see Resolve Issue: coder.inline("never") and coder.nonInlineCall Do Not Prevent Function Inlining (MATLAB Coder).

example

coder.inline("default") instructs the code generator to use internal heuristics to determine whether to inline the current function. Usually, these heuristics produce highly optimized code.

Examples

collapse all

Create an entry-point function inliningEntryPoint that calls two local functions, local_Inline and local_NoInline. Both local functions return the square of the input value, but local_Inline uses the directive coder.inline("always"), while local_NoInline uses the directive 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

Generate C code for inliningEntryPoint and inspect the entry-point function in the generated code. The code generator inlines the call to local_Inline but does not inline the call to 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  : 12-Feb-2024 20:58:22
 */

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

You can use multiple coder.inline directives to control function inlining based on parameters such as input arguments.

Create the entry-point function conditionalInlining, which calls the local function simpleDivision. Use multiple coder.inline directives to instruct the code generator to inline simpleDivision only if both input arguments are scalar.

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

Generate C code for conditionalInlining, specifying scalar inputs, and examine the entry-point function in the generated code. The code generator inlines simpleDivision in the generated code.

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  : 12-Feb-2024 20:59:25
 */

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

Generate C code for conditionalInlining, specifying vector inputs, and examine the entry-point function in the generated code. The code generator uses internal heuristics to determine whether or not to inline simpleDivision in the generated code.

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  : 12-Feb-2024 20:59:28
 */

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

Tips

  • If you use the codegen (MATLAB Coder) or the fiaccel command, you can disable inlining for all functions by using the -O disable:inline option.

  • You might have different speed and readability requirements for C/C++ code generated from functions that you write as compared to C/C++ code generated from MathWorks® functions. Additional global settings enable you to control inlining for these two parts of the generated code base. See Control Inlining to Fine-Tune Performance and Readability of Generated Code (MATLAB Coder).

Extended Capabilities

C/C++ Code Generation
Generate C and C++ code using MATLAB® Coder™.

GPU Code Generation
Generate CUDA® code for NVIDIA® GPUs using GPU Coder™.

Version History

Introduced in R2011a