Contenu principal

coder.const

R2026b

Fold expressions into constants in generated code

Description

out = coder.const(expr) instructs the code generator to replace the variable out with the constant value of expr in the generated code. If the value of expr is not a constant during code generation, the code generator produces an error.

If the code generator is able to evaluate the expression expr during code generation, the generated code does not contain any expressions derived from expr. Otherwise, the generated code contains expressions derived from expr that are evaluated at run time.

Note

Replacing a constant expression with its value in the generated code is a code optimization that is referred to as constant folding. Because the generated code does not have to evaluate the expression, this optimization reduces the execution time and memory use of the generated code.

example

[out1,...,outM] = coder.const(@fun,arg1,...,argN) allows you to create a coder.const call that evaluates the multi-output function [out1,...,outM] = fun(arg1,...,argN). Other than the ability to return multiple outputs, this coder.const call behaves the same as coder.const(fun(arg1,...,argN)).

To learn about the behavior of coder.const when fun accepts zero inputs and returns zero or one outputs, see Tips.

example

Examples

collapse all

This example shows how to instruct the code generator to constant-fold an expression in the generated code using coder.const.

Write a function AddShift that takes a scalar double input Shift and adds it to the elements of a constant vector that the function generates. The vector consists of the squares of the first 10 natural numbers.

function y = AddShift(Shift) %#codegen
y = (1:10).^2 + Shift;
end

Generate C source code for AddShift using the codegen command. To improve the readability of the generated code, disable generation of SIMD instructions for the purposes of this example.

cfg = coder.config("lib");
cfg.InstructionSetExtensions = "None";
cfg.GenCodeOnly = true;
codegen -config cfg AddShift -args 0 -launchreport

Open the code generation report and inspect he generated AddShift function. This function contains instructions for creating the constant vector elements:

void AddShift(double Shift, double y[10])
{
  int k;
  for (k = 0; k < 10; k++) {
    y[k] = (double)((k + 1) * (k + 1)) + Shift;
  }
}

In your MATLAB® code, replace the expression:

(1:10).^2

with:

coder.const((1:10).^2)
Then generate code for AddShift again and open the code generation report.

The code generator now hard-codes the vector containing the squares of the first 10 natural numbers in the body of the generated function:

void AddShift(double Shift, double y[10])
{
  static const signed char iv[10] = {1, 4, 9, 16, 25, 36, 49, 64, 81, 100};
  int i;
  for (i = 0; i < 10; i++) {
    y[i] = Shift + (double)iv[i];
  }
}

This example shows how to constant fold a call to a user-written function in the generated code.

Write a function getsine that takes an integer input index and returns the element referred to by index from a lookup table of sines. The function getsine creates the lookup table calling another function gettable that you will create in the next step.

function y = getsine(index) %#codegen
tbl = gettable(1024);
y = tbl(index);
end

Create the function gettable that returns the lookup table of sines.

function y = gettable(n)
y = zeros(1,n);
for i = 1:n
    y(i) = sin((i-1)/(2*pi*n));
end

Generate C source code for getsine. Specify the input to be a scalar of type int32.

codegen -config:lib -c getsine -args int32(0) -launchreport

Open the code generation report. Observe that the generated code contains instructions for creating the lookup table.

In your MATLAB code, replace the statement:

tbl = gettable(1024);

with:

tbl = coder.const(gettable(1024));

Generate code for getsine again. The array of sine values is now hardcoded in the generated code.

This example shows how to constant fold a multi-output function call in the generated code by using coder.const.

Write a function MultiplyConst that takes an input factor and multiplies every element of two constant vectors vec1 and vec2 with factor. The function generates vec1 and vec2 using another function EvalConsts that you will define in the next step.

function [y1,y2] = MultiplyConst(factor) %#codegen
[vec1,vec2] = EvalConsts(pi.*(1./2.^(1:10)),2);
y1 = vec1.*factor;
y2 = vec2.*factor;
end

Define the EvalConsts function in a separate file.

function [f1,f2] = EvalConsts(z,n)
f1 = z.^(2*n)/factorial(2*n);
f2 = z.^(2*n+1)/factorial(2*n+1);
end

Generate C source code for MultiplyConst using the codegen command.

codegen -config:lib -c -launchreport MultiplyConst -args 0

Open the code generation report. The code generator produces the code for creating the two constant vectors.

In your MATLAB code, replace the statement:

[vec1,vec2] = EvalConsts(pi.*(1./2.^(1:10)),2);

with:

[vec1,vec2] = coder.const(@EvalConsts,pi.*(1./2.^(1:10)),2);

Generate code again by calling the same codegen command. The generated function does not contain code for creating the vectors. Instead, the code generator calculates the constant vectors and includes the calculated vectors in the generated function.

If you call an extrinsic function that returns a constant value, you can instruct the code generator to evaluate the extrinsic function during code generation by using coder.const. The code generator uses the constant value in the generated code. You can use this coding pattern to generate standalone code that uses the output of extrinsic functions. In addition, if you generate code for computationally intensive functions that return constant values, using this coding pattern can improve the speed of code generation. See Reduce Code Generation Time.

For example, consider this function, which uses coder.extrinsic to force the code generator to execute a computationally expensive call to besselj extrinsically at code generation time. The function also uses coder.extrinsic to call readmatrix, which is not supported for code generation. During code generation, the code generator reads the file mytable.txt and calculates the Bessel function. The code generator includes zTable and jTable in the generated code as constants.

function out = forceConstFold(in) %#codegen
coder.extrinsic("besselj","readmatrix");
zTable = coder.const(readmatrix("mytable.txt"));
jTable = coder.const(besselj(3,zTable));
out = interp1(zTable,jTable,in);
end

Because the function uses coder.const to force the code generator to call both readmatrix and besselj at code generation time, both MEX generation and standalone code generation for this function succeed. In addition, because the extrinsic calls occur at code generation time, not run time, neither zTable nor jTable are an mxArray. However, because the code generator includes these variables in the generated code as constants, changes to the mytable.txt file after code generation are not reflected in the generated code.

This example shows what the generated code looks like when you constant fold a function call that, in addition to returning a constant value, produces side effects.

Define a function returnConstantValue that returns a constant value of 10. However, this function also creates a text file myFile.txt that contains a message saying the function successfully returned the value 10.

function v = returnConstantValue
v = 10;
fileID = fopen('myFile.txt','w');
fprintf(fileID, 'Success: Returned %f\n', v);     
fclose(fileID);
end

Define an entry-point function testConstantFolding that calls returnConstantValue using coder.const.

function y = testConstantFolding
y = coder.const(returnConstantValue);
end

Generate C source code for the testConstantFolding function.

codegen -config:lib -c testConstantFolding -report

Open the code generation report and inspect the generated testConstantFolding C function.

double testConstantFolding(void)
{
  FILE *filestar;
  signed char fileid;
  boolean_T autoflush;
  if (!isInitialized_testConstantFolding) {
    testConstantFolding_initialize();
  }
  fileid = cfopen();
  filestar = fileManager(fileid, &autoflush);
  if (!(filestar == NULL)) {
    fprintf(filestar, "Success: Returned %f\n", 10.0);
    if (autoflush) {
      fflush(filestar);
    }
  }
  cfclose(fileid);
  return 10.0;
}

The generated function does return the constant value 10.0. However, even though the side-effect of returnConstantValue did not depend on run-time inputs, the code generator was unable to evaluate the call to returnConstantValue during code generation. Therefore, the generated code contains the instructions for creating the text file.

To force the code generator to evaluate the returnConstantValue call during code generation, declare this function as extrinsic in the body of the callee.

function y = testConstantFolding2
coder.extrinsic("returnConstantValue");
y = coder.const(returnConstantValue);
end

Generate C source code for the testConstantFolding2 function.

codegen -config:lib -c testConstantFolding2 -report

Because the code generator now evaluates the returnConstantValue call during code generation, the text file myFile.txt appears in your working directory.

Open the code generation report and inspect the generated testConstantFolding2 C function.

double testConstantFolding2(void)
{
  return 10.0;
}

The generated function only returns the value of the constant-folded expression. The instructions to carry out the side effects of the constant-folded expression do not appear in the generated code.

Input Arguments

collapse all

MATLAB expression or user-defined single-output function call.

The expression or function call must use compile-time constants only. For example, code generation produces an error for this entry-point function, because x is not a compile-time constant.

function y = func(x)
y = coder.const(log10(x));
end

To fix the error, assign x to a constant in the body of the function func.

Alternatively, during code generation, use coder.Constant to define the type of the input x:

codegen -config:lib func -args coder.Constant(10)

Example: 2*pi, factorial(10)

Handle to MathWorks®-written or user-written function fun.

Example: @log, @sin

Data Types: function_handle

Arguments to the function with handle @fun.

The arguments must be compile-time constants. For example, attempting to generate code for this function produces a code generation error, because x and y are not compile-time constants.

function y = func(x,y)
y = coder.const(@nchoosek,x,y);
end

To fix the error, assign x and y to constants in the MATLAB code.

Alternatively, during code generation, use coder.Constant to define the input types:

codegen -config:lib func -args {coder.Constant(10),coder.Constant(2)}

Limitations

  • The code generator does not support using coder.const on dictionaries, dictionary keys, or dictionary values.

Tips

  • If coder.const is unable to constant-fold a function call, try to force constant-folding by making the function call extrinsic. Extrinsic calls are not evaluated by the code generator, these calls are dispatched to MATLAB. For example:

    function yi = fcn(xi)
    y = coder.const(feval('rand',1,100));
    yi = interp1(y,xi);
    end

    See Reduce Code Generation Time.

  • Suppose that you call coder.const on a function handle with zero inputs and zero or one outputs. For example:

    out = coder.const(@fcn);
    In such situations, the code generator does not evaluate fcn, and sets out to the function handle @fcn itself. To force the evaluation of fcn in this special case, call the function explicitly inside the coder.const command. For example:
    out = coder.const(fcn());

  • To specify input values or global variables as constants during code generation, use a coder.Constant object.

Extended Capabilities

expand all

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 R2013b