function hLib = make_simtgt_blas_tfl_table
%MAKE_SIMTGT_BLAS_TFL_TABLE
%    
% Utility for building Target Function Libraries

% Copyright 2011-2013 The MathWorks, Inc.
%
% Create the Simulation Targets instance of the BLAS library
%   

hLib = RTW.TflTable;

% Use expandToken to determine blas library path
LibPath = '$getBlasRtwLibPath$';

% Initialize the extension of libmwblas library 
if ispc
    LibExt = 'lib';
elseif ismac
    LibExt = 'dylib';
elseif isunix
    LibExt = 'so';
end

% ptrdiff_t is created as signed fixpoint of size sizeof(ptrdiff_t) 
% by createEmbeddedTypeFromStrPtrdiff_t (TflArgFactory.cpp) and converted
% to int32 or int64 by CG::TflTools::convertToCGType
PTRDIFF_T_TYPE = 'ptrdiff_t';

% Add entries for BLAS
entInfoAlg = 'RTW_BLAS';



%% BLAS Matrix Multiply 
%locAddBLASFuncEntGemm( hLib, key, implName, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, LibPath, LibExt, PTRDIFF_T_TYPE, algorithmInfo )
locAddBLASFuncEntGemm( hLib, 'multiply', 'dgemm', 'double',  [2 2; inf inf], 'double',  [2 1; inf inf], 'double',  [1 2; inf inf], 'double',  'double',  LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASFuncEntGemm( hLib, 'multiply', 'sgemm', 'single',  [2 2; inf inf], 'single',  [2 1; inf inf], 'single',  [1 2; inf inf], 'single',  'single',  LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASFuncEntGemm( hLib, 'multiply', 'zgemm', 'cdouble', [2 2; inf inf], 'cdouble', [2 1; inf inf], 'cdouble', [1 2; inf inf], 'cdouble', 'cdouble', LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASFuncEntGemm( hLib, 'multiply', 'cgemm', 'csingle', [2 2; inf inf], 'csingle', [2 1; inf inf], 'csingle', [1 2; inf inf], 'csingle', 'csingle', LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );

%locAddBLASFuncEntGemv( hLib, key, implName, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, LibPath, LibExt, PTRDIFF_T_TYPE, argorithmInfo )
locAddBLASFuncEntGemv( hLib, 'multiply', 'dgemv', 'double',  [2 1; inf 1], 'double',  [2 2; inf inf], 'double',  [2 1; inf 1], 'double',  'double',  LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASFuncEntGemv( hLib, 'multiply', 'sgemv', 'single',  [2 1; inf 1], 'single',  [2 2; inf inf], 'single',  [2 1; inf 1], 'single',  'single',  LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASFuncEntGemv( hLib, 'multiply', 'zgemv', 'cdouble', [2 1; inf 1], 'cdouble', [2 2; inf inf], 'cdouble', [2 1; inf 1], 'cdouble', 'cdouble', LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASFuncEntGemv( hLib, 'multiply', 'cgemv', 'csingle', [2 1; inf 1], 'csingle', [2 2; inf inf], 'csingle', [2 1; inf 1], 'csingle', 'csingle', LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );

%locAddBLASFuncEntGevm( hLib, key, implName, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, LibPath, LibExt, PTRDIFF_T_TYPE, argorithmInfo )
locAddBLASFuncEntGevm( hLib, 'multiply', 'dgemv', 'double',  [1 2; 1 inf], 'double',  [1 2; 1 inf], 'double',  [2 2; inf inf], 'double',  'double',  LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASFuncEntGevm( hLib, 'multiply', 'sgemv', 'single',  [1 2; 1 inf], 'single',  [1 2; 1 inf], 'single',  [2 2; inf inf], 'single',  'single',  LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASFuncEntGevm( hLib, 'multiply', 'zgemv', 'cdouble', [1 2; 1 inf], 'cdouble', [1 2; 1 inf], 'cdouble', [2 2; inf inf], 'cdouble', 'cdouble', LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASFuncEntGevm( hLib, 'multiply', 'cgemv', 'csingle', [1 2; 1 inf], 'csingle', [1 2; 1 inf], 'csingle', [2 2; inf inf], 'csingle', 'csingle', LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );

% ROW_VECTOR MUL COL_VECTOR is handled by BLAS level one for real and level two for cmplx  
locAddBLASOpEntGevv( hLib,  'multiply', 'ddot',  'double',  'double',  [1 1; 1 inf], 'double',  [1 1; inf 1], LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASOpEntGevv( hLib,  'multiply', 'sdot',  'single',  'single',  [1 1; 1 inf], 'single',  [1 1; inf 1], LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASFuncEntGemv( hLib, 'multiply', 'zgemv', 'cdouble', [1 1; 1 1], 'cdouble', [1 1; 1 inf], 'cdouble', [1 1; inf 1], 'cdouble', 'cdouble', LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );
locAddBLASFuncEntGemv( hLib, 'multiply', 'cgemv', 'csingle', [1 1; 1 1], 'csingle', [1 1; 1 inf], 'csingle', [1 1; inf 1], 'csingle', 'csingle', LibPath, LibExt, PTRDIFF_T_TYPE, entInfoAlg );


%% Local Function
function locAddBLASFuncEntGemm( hLib, key, implName, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, LibPath, LibExt, PTRDIFF_T_TYPE, algorithmInfo )
  if isempty(hLib)
    return;
  end
  
  hEnt = RTW.TflIPPBlasEntryGenerator;
  locSetBLASProps( hEnt, key, implName, LibPath, LibExt );
  locAddGemmArgsToEntry( hLib, hEnt, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, PTRDIFF_T_TYPE );
  % Add the Algorithm Info to the entry
  if ~isempty(algorithmInfo)
      hEnt.EntryInfo.Algorithm = algorithmInfo;
  end  
  hLib.addEntry( hEnt );
  
      
%  
function locAddBLASFuncEntGemv( hLib, key, implName, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, LibPath, LibExt, PTRDIFF_T_TYPE, algorithmInfo )
  if isempty(hLib)
    return;
  end
  
  hEnt = RTW.TflIPPBlasEntryGenerator;
  locSetBLASProps( hEnt, key, implName, LibPath, LibExt );
  locAddGemvArgsToEntry( hLib, hEnt, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, PTRDIFF_T_TYPE );
  % Add the Algorithm Info to the entry
  if ~isempty(algorithmInfo)
      hEnt.EntryInfo.Algorithm = algorithmInfo;
  end   
  hLib.addEntry( hEnt );
  
  
%  
function locAddBLASFuncEntGevm( hLib, key, implName, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, LibPath, LibExt, PTRDIFF_T_TYPE, algorithmInfo )
  if isempty(hLib)
    return;
  end
  
  hEnt = RTW.TflIPPBlasEntryGenerator;
  locSetBLASProps( hEnt, key, implName, LibPath, LibExt );
  locAddGevmArgsToEntry( hLib, hEnt, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, PTRDIFF_T_TYPE );
  % Add the Algorithm Info to the entry
  if ~isempty(algorithmInfo)
      hEnt.EntryInfo.Algorithm = algorithmInfo;
  end   
  hLib.addEntry( hEnt );
  
  
%  
function locAddBLASOpEntGevv( hLib, key, implName, out, in1, in1Dims, in2, in2Dims, LibPath, LibExt, PTRDIFF_T_TYPE, algorithmInfo )
  if isempty(hLib)
    return;
  end
  
  hEnt = RTW.TflIPPBlasEntryGenerator;
  locSetBLASProps( hEnt, key, implName, LibPath, LibExt );
  locAddGevvArgsToEntry( hLib, hEnt, out, in1, in1Dims, in2, in2Dims, PTRDIFF_T_TYPE );
  % Add the Algorithm Info to the entry
  if ~isempty(algorithmInfo)
      hEnt.EntryInfo.Algorithm = algorithmInfo;
  end 
  hLib.addEntry( hEnt );


%
function locSetBLASProps( hEnt, key, implName, LibPath, LibExt )
  if isempty( hEnt )
    return;
  end
  
  hEnt.setTflCFunctionEntryParameters( ...
      'Key',                         key, ...
      'Priority',                    100, ...
      'ImplementationName',          implName, ...
      'ImplementationHeaderFile',    'blas.h', ...
      'ImplementationHeaderPath',    fullfile('$(MATLAB_ROOT)','extern','include'), ...
      'AdditionalLinkObjs',          {['libmwblas.' LibExt]}, ...
      'AdditionalLinkObjsPaths',     {LibPath}, ...
      'SideEffects',                 true);
  
%
function locAddGemmArgsToEntry( hLib, hEnt, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, PTRDIFF_T_TYPE )
  if isempty(hLib) || isempty( hEnt )
    return;
  end
  
  % No need of alignment for BLAS

hEnt.createAndAddConceptualArg('RTW.TflArgMatrix',...
                            'Name',         'y1', ...
                            'IOType',       'RTW_IO_OUTPUT', ...
                            'BaseType',     out, ...
                            'DimRange',     outDims);

hEnt.createAndAddConceptualArg('RTW.TflArgMatrix',...
                            'Name',         'u1', ...
                            'BaseType',     in1, ...
                            'DimRange',     in1Dims);
                        
hEnt.createAndAddConceptualArg('RTW.TflArgMatrix',...
                            'Name',         'u2', ...
                            'BaseType',     in2, ...
                            'DimRange',     in2Dims);                        
 
arg = hLib.getTflArgFromString('y2', 'void');
arg.IOType = 'RTW_IO_OUTPUT';
hEnt.Implementation.setReturn(arg);

arg = RTW.TflArgCharConstant('TRANSA');
arg.PassByType = 'RTW_PASSBY_POINTER';
% (dyang) TODO: need pass a constant pointer
hEnt.Implementation.addArgument(arg);

arg = RTW.TflArgCharConstant('TRANSB');
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('M', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('N',PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('K', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('ALPHA',alpha, 0);
arg.PassByType = 'RTW_PASSBY_BASE_POINTER';
hEnt.Implementation.addArgument(arg);

if ~isempty(strfind(in1, 'double'))
    arg = hLib.getTflArgFromString('u1','double*');
else
    arg = hLib.getTflArgFromString('u1','single*');
end
arg.PassByType = 'RTW_PASSBY_POINTER';

hEnt.Implementation.addArgument(arg);


arg = hLib.getTflArgFromString('LDA', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

if ~isempty(strfind(in2, 'double'))
    arg = hLib.getTflArgFromString('u2','double*');
else
    arg = hLib.getTflArgFromString('u2','single*');
end
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('LDB', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('BETA',beta, 0);
arg.PassByType = 'RTW_PASSBY_BASE_POINTER';
hEnt.Implementation.addArgument(arg);

if ~isempty(strfind(out, 'double'))
    arg = hLib.getTflArgFromString('y1', 'double*');
else
    arg = hLib.getTflArgFromString('y1', 'single*');
end
arg.IOType = 'RTW_IO_OUTPUT';

arg.PassByType = 'RTW_PASSBY_POINTER';

hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('LDC', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);  


%
function locAddGemvArgsToEntry( hLib, hEnt, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, PTRDIFF_T_TYPE )
  if isempty(hLib) || isempty( hEnt )
    return;
  end

if in1Dims(1,1) == 1
    arg = hEnt.getTflArgFromString('y1', out);
    arg.IOType = 'RTW_IO_OUTPUT';
    hEnt.addConceptualArg(arg);
else
    hEnt.createAndAddConceptualArg('RTW.TflArgMatrix',...
                                   'Name',         'y1', ...
                                   'IOType',       'RTW_IO_OUTPUT', ...
                                   'BaseType',     out, ...
                                   'DimRange',     outDims);
end

hEnt.createAndAddConceptualArg('RTW.TflArgMatrix',...
                               'Name',         'u1', ...
                               'BaseType',     in1, ...
                               'DimRange',     in1Dims);
                        
hEnt.createAndAddConceptualArg('RTW.TflArgMatrix',...
                               'Name',         'u2', ...
                               'BaseType',     in2, ...
                               'DimRange',     in2Dims);

 
arg = hLib.getTflArgFromString('y2','void');
arg.IOType = 'RTW_IO_OUTPUT';
hEnt.Implementation.setReturn(arg);

arg = RTW.TflArgCharConstant('TRANS');
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('M', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('N', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('ALPHA',alpha, 0);
arg.PassByType = 'RTW_PASSBY_BASE_POINTER';
hEnt.Implementation.addArgument(arg);

if ~isempty(strfind(in1, 'double'))
    arg = hLib.getTflArgFromString('u1','double*');
else
    arg = hLib.getTflArgFromString('u1','single*');
end
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('LDA', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

if ~isempty(strfind(in1, 'double'))
    arg = hLib.getTflArgFromString('u2','double*');
else
    arg = hLib.getTflArgFromString('u2','single*');
end
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('INCX', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('BETA',beta, 0);
arg.PassByType = 'RTW_PASSBY_BASE_POINTER';
hEnt.Implementation.addArgument(arg);

if ~isempty(strfind(out, 'double'))
    arg = hLib.getTflArgFromString('y1','double*');
else
    arg = hLib.getTflArgFromString('y1','single*');
end
arg.PassByType = 'RTW_PASSBY_BASE_POINTER';

arg.IOType = 'RTW_IO_OUTPUT';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('INCY', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg); 



%
function locAddGevmArgsToEntry( hLib, hEnt, out, outDims, in1, in1Dims, in2, in2Dims, alpha, beta, PTRDIFF_T_TYPE )
  if isempty(hLib) || isempty( hEnt )
    return;
  end

hEnt.createAndAddConceptualArg('RTW.TflArgMatrix',...
                               'Name',         'y1', ...
                               'IOType',       'RTW_IO_OUTPUT', ...
                               'BaseType',     out, ...
                               'DimRange',     outDims);

hEnt.createAndAddConceptualArg('RTW.TflArgMatrix',...
                               'Name',         'u1', ...
                               'BaseType',     in1, ...
                               'DimRange',     in1Dims);

hEnt.createAndAddConceptualArg('RTW.TflArgMatrix',...
                               'Name',         'u2', ...
                               'BaseType',     in2, ...
                               'DimRange',     in2Dims);
                        
 
arg = hLib.getTflArgFromString('y2','void');
arg.IOType = 'RTW_IO_OUTPUT';
hEnt.Implementation.setReturn(arg);

arg = RTW.TflArgCharConstant('TRANS');
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('M', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('N', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('ALPHA',alpha, 0);
arg.PassByType = 'RTW_PASSBY_BASE_POINTER';
hEnt.Implementation.addArgument(arg);

if ~isempty(strfind(in1, 'double'))
    arg = hLib.getTflArgFromString('u2','double*');
else
    arg = hLib.getTflArgFromString('u2','single*');
end
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('LDA', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

if ~isempty(strfind(in1, 'double'))
    arg = hLib.getTflArgFromString('u1','double*');
else
    arg = hLib.getTflArgFromString('u1','single*');
end
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('INCX', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('BETA',beta, 0);
arg.PassByType = 'RTW_PASSBY_BASE_POINTER';
hEnt.Implementation.addArgument(arg);

if ~isempty(strfind(out, 'double'))
    arg = hLib.getTflArgFromString('y1','double*');
else
    arg = hLib.getTflArgFromString('y1','single*');
end
arg.PassByType = 'RTW_PASSBY_POINTER';
arg.IOType = 'RTW_IO_OUTPUT';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('INCY', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg); 
%



%
function locAddGevvArgsToEntry( hLib, hEnt, out, in1, in1Dims, in2, in2Dims, PTRDIFF_T_TYPE )
  if isempty(hLib) || isempty( hEnt )
    return;
  end
  
arg = hEnt.getTflArgFromString('y1', out);
arg.IOType = 'RTW_IO_OUTPUT';
hEnt.addConceptualArg(arg);

hEnt.createAndAddConceptualArg('RTW.TflArgMatrix',...
                            'Name',         'u1', ...
                            'BaseType',     in1, ...
                            'DimRange',     in1Dims);
                        
hEnt.createAndAddConceptualArg('RTW.TflArgMatrix',...
                            'Name',         'u2', ...
                            'BaseType',     in2, ...
                            'DimRange',     in2Dims);

            
arg = hLib.getTflArgFromString('y1', out);
arg.IOType = 'RTW_IO_OUTPUT';
hEnt.Implementation.setReturn(arg);


arg = hLib.getTflArgFromString('N', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('u1',[in1 '*']);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('INCX', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('u2',[in2 '*']);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg);

arg = hLib.getTflArgFromString('INCY', PTRDIFF_T_TYPE, 0);
arg.PassByType = 'RTW_PASSBY_POINTER';
hEnt.Implementation.addArgument(arg); 
%-----------------------------------------------------------

% EOF
