%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function needsPreFallback = construct_module(chart, instanceHandle, specialization, fileNameInfo,needsPreFallback,preFallBackReason)

% Copyright 2002-2021 The MathWorks, Inc.

% CONSTRUCT_MODULE - This function attemps to generate code for a
% particular chart.
% WARNING: In the case of failure, an MException is thrown, but only
% after module is destroyed first.
%
%%%%%%%%%%%%
% NOTE: Module is NOT destroyed if no exception is thrown.
%%%%%%%%%%%%

global gTargetInfo gChartInfo gMachineInfo %#ok<GVMIS>

if nargin < 3
specialization = '';
end

if nargin < 4
fileNameInfo = [];
end

if nargin < 5
needsPreFallback = false;
preFallBackReason = '';
end

compute_chart_instance_var_names(chart, specialization);
compute_state_variable_names(chart, specialization);
compute_state_event_enums(chart);
mustExportChartFunctions = export_chart_functions(chart);
targetName = sf('get',gMachineInfo.parentTarget,'target.name');

cdrModuleInfo.chartId = chart;
cdrModuleInfo.instanceHandle = instanceHandle;
cdrModuleInfo.specialization = specialization;
cdrModuleInfo.codingMultiInstance = gTargetInfo.codingMultiInstance;
cdrModuleInfo.mustExportChartFunctions = mustExportChartFunctions;
cdrModuleInfo.chartInstanceTypedef = gChartInfo.chartInstanceTypedef;
cdrModuleInfo.chartInputDataTypedef = gChartInfo.chartInputDataTypedef;
cdrModuleInfo.chartOutputDataTypedef = gChartInfo.chartOutputDataTypedef;
cdrModuleInfo.chartInstanceArgumentName = gChartInfo.chartInstanceArgumentName;
cdrModuleInfo.chartInputDataArgumentName = gChartInfo.chartInputDataArgumentName;
cdrModuleInfo.chartOutputDataArgumentName = gChartInfo.chartOutputDataArgumentName;
cdrModuleInfo.codingNoInitializer = gTargetInfo.codingNoInitializer;
cdrModuleInfo.rtwFcnName = '';
cdrModuleInfo.rtwUseSFS = 0;
cdrModuleInfo.forceJitOff=false;
gChartInfo.jitFallbackInfo = [];

if(gTargetInfo.codingRTW)
cdrModuleInfo.codingSharedUtils = rtw_gen_shared_utils(gMachineInfo.mainMachineName);
cdrModuleInfo.usedTargetFunctionLib = gTargetInfo.rtwProps.usedTargetFunctionLib;
% Use the TFL control object attached to the model for TFL replacements.
% Pass this handle into construct module.
cdrModuleInfo.usedTargetFunctionLibH = gMachineInfo.ctxInfo.usedTargetFunctionLibH;

% set up the RTWFcnName field of cdrModuleInfo to be used for naming
% atomic subchart functions.
chartBlockH = sfprivate('chart2block', chart);
if strcmpi(get_param(chartBlockH, 'RTWFcnNameOpts'), 'auto') || ...
strcmpi(get_param(chartBlockH, 'RTWFcnNameOpts'), 'Use subsystem name')
fcnName = get_param(chartBlockH, 'Name');
cdrModuleInfo.rtwUseSFS = 1;
else
fcnName = get_param(chartBlockH, 'RTWFcnName');
cdrModuleInfo.rtwUseSFS = 0;
end
% Remove the leading A.B. stuff in case this atomic subchart is used in
% a nested context.
fcnName = regexp(fcnName, '\w*$', 'match');
if ~isempty(fcnName)
cdrModuleInfo.rtwFcnName = fcnName{1};
else
cdrModuleInfo.rtwFcnName = '';
end
elseif gTargetInfo.codingSFunction

if(needsPreFallback)
gChartInfo.jitFallbackInfo.fallbackType = 'pre';
gChartInfo.jitFallbackInfo.fallbackReason = preFallBackReason;
cdrModuleInfo.forceJitOff = true;
else
gChartInfo.jitFallbackInfo.fallbackType = '';
gChartInfo.jitFallbackInfo.fallbackReason = '';
end
gChartInfo.jitFallbackInfo.incompatibleSymbol = '';

cdrModuleInfo.codingSharedUtils = false;
cdrModuleInfo.usedTargetFunctionLib = 'NULL';
cdrModuleInfo.usedTargetFunctionLibH = gMachineInfo.ctxInfo.usedTargetFunctionLibH;
tfl_recording('start',cdrModuleInfo.usedTargetFunctionLibH);
else
cdrModuleInfo.codingSharedUtils = false;
cdrModuleInfo.usedTargetFunctionLib = 'NULL';
cdrModuleInfo.usedTargetFunctionLibH = 0;
end

try
[occurredFallbackType,hiddenFallbackType,fallbackReason,incompatibleSymbol] = sf('Cg','construct_module',cdrModuleInfo);

if gTargetInfo.codingSFunction
redoCodegen = false;
rejitChart = false;

% After one compile is completed, need to check whether we'll need
% to rerun the compile with debugger instrumentation enabled.
encodedPostCodegen = sf('Cg', 'get_encoded_postcodegen_info', cdrModuleInfo.chartId);
postCodegen = sf('Cg', 'mx_decode', encodedPostCodegen);
nrInfo = postCodegen.nameResolutionInfo;
hasScriptBreakpoints = sfprivate('compute_breakpoints_in_resolved_functions',nrInfo);
if hasScriptBreakpoints && ~sf('get', chart, '.hadBreakpoints' )
rejitChart = true;
sf('set', chart, '.hadBreakpoints', 1 );
end

switch(occurredFallbackType)
case 'none'
% no fallback occurred. check if we need to do a tfl late
% fallback
[fallbackReason,incompatibleSymbol] = compute_tfl_late_fallback_info(cdrModuleInfo);
if ~isempty(fallbackReason)
fallbackType = 'late';
redoCodegen = true;
Stateflow.JIT.Utils.destroyJITEngineForChartSpecialization(chart,specialization);
gChartInfo.jitFallbackInfo.fallbackType = fallbackType;
gChartInfo.jitFallbackInfo.hiddenFallbackType = '';
gChartInfo.jitFallbackInfo.fallbackReason = fallbackReason;
gChartInfo.jitFallbackInfo.hiddenFallbackReason = '';
gChartInfo.jitFallbackInfo.incompatibleSymbol = incompatibleSymbol;
end
case 'pre'
gChartInfo.jitFallbackInfo.fallbackType='pre';
gChartInfo.jitFallbackInfo.hiddenFallbackType = hiddenFallbackType;
gChartInfo.jitFallbackInfo.fallbackReason = preFallBackReason;
gChartInfo.jitFallbackInfo.hiddenFallbackReason = fallbackReason;
gChartInfo.jitFallbackInfo.incompatibleSymbol = incompatibleSymbol;
case 'early'
gChartInfo.jitFallbackInfo.fallbackType='early';
gChartInfo.jitFallbackInfo.hiddenFallbackType = '';
gChartInfo.jitFallbackInfo.fallbackReason = fallbackReason;
gChartInfo.jitFallbackInfo.hiddenFallbackReason = '';
gChartInfo.jitFallbackInfo.incompatibleSymbol = incompatibleSymbol;
case {'late','very late'}
gChartInfo.jitFallbackInfo.fallbackType=occurredFallbackType;
gChartInfo.jitFallbackInfo.hiddenFallbackType = '';
gChartInfo.jitFallbackInfo.fallbackReason = fallbackReason;
gChartInfo.jitFallbackInfo.hiddenFallbackReason = '';
gChartInfo.jitFallbackInfo.incompatibleSymbol = incompatibleSymbol;
redoCodegen = true;
end

if(redoCodegen)
sf('Cg','destroy_module',chart);
cdrModuleInfo.forceJitOff = true;
sf('Cg','construct_module',cdrModuleInfo);
elseif rejitChart
sf('Cg','destroy_module',chart);
sf('Cg','construct_module',cdrModuleInfo);
end

% Checking for relinkToExistingJITEngine is a means of figuring out
% whether the construct_module we just tried resulted in a JIT
% engine or not. It might not have due to a late fallback.
if ~cdrModuleInfo.forceJitOff && ...
Stateflow.JIT.Utils.relinkToExistingJITEngine(chart, specialization, false)
% This means, we have just generated a jitEngine and it is in memory

if(~sfprivate('chart_requests_zero_emissions',chart))
try
[jitEngineByteCodeFile,jitEngineInfoMatFile] =...
sfprivate('jit_engine_file_name_info',specialization);
create_jit_project_dir_path_just_in_time();
Stateflow.JIT.Utils.serializeJITEngine(specialization,jitEngineByteCodeFile, ...
jitEngineInfoMatFile);
catch ME %#ok<NASGU>
% ignore this error as it is not fatal
end
end
else
% this means, we did not use jit for this chart/spec combo
% let's dump the information on why this did not happen
% these MAT files can be examined to lock down jittability
display_chart_codegen_message(chart,'sfun',fallbackReason);
% Add a few more fields to save in the MAT file
jitFallbackInfo = gChartInfo.jitFallbackInfo;
jitFallbackInfo.modelName = gMachineInfo.machineName;
jitFallbackInfo.chartFileNumber = sf('get',chart,'chart.chartFileNumber');
jitFallbackInfo.specialization = specialization;
jitFallbackInfo.lateFallback = double(strcmp(jitFallbackInfo.fallbackType,'late') || strcmp(jitFallbackInfo.fallbackType,'very late'));
create_project_dir_path_just_in_time(fileNameInfo,'ji');
jitFallbackInfoFileName = sprintf('c%d_%s.mat',jitFallbackInfo.chartFileNumber,specialization);
if(jitFallbackInfo.lateFallback)
jitFallbackInfoFileName = fullfile(fileNameInfo.targetDirName,'ji',['late_',jitFallbackInfoFileName]);
else
jitFallbackInfoFileName = fullfile(fileNameInfo.targetDirName,'ji',['early_',jitFallbackInfoFileName]);
end
save(jitFallbackInfoFileName,'jitFallbackInfo');
end
tfl_recording('stop',cdrModuleInfo.usedTargetFunctionLibH);
end
collect_chart_aux_dependencies(chart, cdrModuleInfo, fileNameInfo);
compute_implicit_event_information();

catch ME
sfprivate('coder_error_count_man','add',1);
if ~gTargetInfo.codingRTW % We delay the destruction at the end of mdlRTWCG(). Needs to be delayed in this case since the order of deletion can be different from the order of creation.
sf('Cg','destroy_module',chart);
end
if gTargetInfo.codingSFunction
tfl_recording('stop',cdrModuleInfo.usedTargetFunctionLibH);
end
rethrow(ME);
end

if(strcmp(targetName,'testgen') && gTargetInfo.codingForAutoVerifier)
% WISH: This is a temporary hack for Bill to do his testgen
% work. MUST GET RID OF IT AS SOON AS POSSIBLE!!!!!!!
if exist('slavt_gateway.m','file')
try
slavt_gateway('chart_analyze',chart,true);
catch ME
disp(ME.message);
end
end
end

return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Look for TFL auxInfo that forces late fallback
function [fallbackReason,incompatibleSymbol] = compute_tfl_late_fallback_info(cdrModuleInfo)

fallbackReason='';
incompatibleSymbol='';

% Get the TFL usage for the specified chartId. The TFL usage is
% the 'recorded' usage, i.e., the per-chart usage. There is
% currently no single API function to retrieve this data, so we
% must iterate over the TFL controller's hit cache.
tflControl = cdrModuleInfo.usedTargetFunctionLibH;
hitCache = tflControl.HitCache;
numEnts = length(hitCache);
for idx = 1:numEnts
if hitCache(idx).RecordedUsageCount ~= 0
hit = hitCache(idx);
name = hit.Implementation.SourceFile;
if ~isempty(name)
fallbackReason='TFL Source Files';
incompatibleSymbol=name;
return;
end
for i = 1:numel(hit.AdditionalSourceFiles)
name = hit.AdditionalSourceFiles{i};
if ~isempty(name)
fallbackReason='TFL Source Files';
incompatibleSymbol=name;
return;
end
end
for i = 1:numel(hit.AdditionalLinkObjs)
name = hit.AdditionalLinkObjs{i};
if ~isempty(name)
fallbackReason='TFL Link Objects';
incompatibleSymbol=name;
return;
end
end
end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Collect the TFL and MATLAB function auxiliary build dependency info
function collect_chart_aux_dependencies(chartId, cdrModuleInfo, fileNameInfo)
global gTargetInfo %#ok<GVMIS>

shouldCacheAuxInfo = gTargetInfo.codingSFunction || (gTargetInfo.codingRTW && ~gTargetInfo.codingIRConstructionForRTW);
if ~shouldCacheAuxInfo
return;
end

% Get the MATLAB function aux buildinfo for the chart
auxInfo = sf('Cg','get_recorded_eml_buildinfo',chartId);

if gTargetInfo.codingSFunction
auxInfo = cgxeprivate('collect_crl_dependencies',cdrModuleInfo.usedTargetFunctionLibH, ...
fileNameInfo.targetDirName, auxInfo);
end

sfprivate('auxInfoChartCache','set',chartId,auxInfo);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function tfl_recording(method,tfl)
switch(method)
case 'start'
% Indicate to the TFL that TLC will not be invoked. This prevents TFL entries that
% contain TLC code gen callbacks from being used as replacements. Also, start recording
% TFL replacements. This is needed so that we can ensure the correct (minimal) set of header
% files is included into the chart source file.
tfl.TLCSupported = false;
tfl.Recording = true;
case 'stop'
% stop recording as we are done with the codegen for this chart
tfl.TLCSupported = true;
tfl.Recording = false;
end
return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function compute_chart_instance_var_names(chart, specialization)

global gTargetInfo gChartInfo %#ok<GVMIS>

chartUniqueName = sf('CodegenNameOf',chart,specialization);

if(gTargetInfo.codingRTW)
gChartInfo.chartInstanceTypedef = '';
gChartInfo.chartInstanceArgumentName = '';
else
gChartInfo.chartInstanceTypedef = ['SF',chartUniqueName,'InstanceStruct'];
gChartInfo.chartInstanceArgumentName = 'chartInstance';
end
gChartInfo.chartInputDataTypedef = ['SF',chartUniqueName,'InputDataStruct'];
gChartInfo.chartOutputDataTypedef = ['SF',chartUniqueName,'OutputDataStruct'];
gChartInfo.chartInputDataArgumentName = 'chartInputData';
gChartInfo.chartOutputDataArgumentName = 'chartOutputData';

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function compute_state_variable_names(chart, specialization)

global gChartInfo %#ok<GVMIS>

for state = [chart,gChartInfo.states]
uniqStateName = sf('CodegenNameOf',state,specialization);
if(state==chart || sf('get',state,'state.type')==1)
% chart, AND states get their own bit
fieldName = ['is_active_',uniqStateName];
sf('set',state,'.unique.isActive',fieldName);
else
% optimize it away
sf('set',state,'.unique.isActive','');
end
subStates = sf('SubstatesOf',state);
if(~isempty(subStates))
switch sf('get',state,'.decomposition')
case 0 % CLUSTER_STATE
fieldName = ['is_',uniqStateName];
sf('set',state,'.unique.activeChild',fieldName);
if sf('get',state,'.history')
fieldName = ['was_',uniqStateName];
sf('set',state,'.unique.prevActiveChild',fieldName);
end
case 1 % SET_STATE
otherwise
construct_coder_error(state,'Bad decomposition');
end
end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function compute_state_event_enums(chart)
global gMachineInfo gChartInfo %#ok<GVMIS>

if(~isempty(gChartInfo.chartEvents))
chartEventNumbers = sf('get',gChartInfo.chartEvents,'event.number')+gMachineInfo.machineEventThreshold;
sf('set',gChartInfo.chartEvents,'event.number',chartEventNumbers);
end

file = ''; % Dummy argument, not used in the functions

compute_event_enum_values(chart,file,1);
compute_state_enums(file,chart);

return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function compute_implicit_event_information()
global gChartInfo %#ok<GVMIS>

gChartInfo.statesWithEntryEvent = sf('find',gChartInfo.states,'state.hasEntryEvent',1);
gChartInfo.statesWithExitEvent = sf('find',gChartInfo.states,'state.hasExitEvent',1);
gChartInfo.dataWithChangeEvent = sf('find',gChartInfo.chartData,'data.hasChangeEvent',1);

% Machine-level explicit or implicit events are not supported; so there is no need to account
% for them.
gChartInfo.dataChangeEventThreshold = 0;
if(~isempty(gChartInfo.chartEvents))
gChartInfo.dataChangeEventThreshold = max(sf('get',gChartInfo.chartEvents,'event.number'))+1;
end
gChartInfo.stateEntryEventThreshold = gChartInfo.dataChangeEventThreshold + length(gChartInfo.dataWithChangeEvent);
gChartInfo.stateExitEventThreshold = gChartInfo.stateEntryEventThreshold + length(gChartInfo.statesWithEntryEvent);

return;