function c = bitshift(a,k,assumedtype)
%MATLAB Code Generation Library Function

%   Copyright 1984-2023 The MathWorks, Inc.
%#codegen

coder.internal.allowEnumInputs;
coder.internal.assert(nargin >= 2,'MATLAB:minrhs');
coder.internal.prefer_const(k);
if nargin == 3
    coder.internal.prefer_const(assumedtype);
    coder.internal.assert(coder.internal.isConst(assumedtype), ...
        'Coder:toolbox:TrailingStringInputMustBeConstant');
end

% Handle Simulink size propagation.
if coder.internal.isAmbiguousTypes
    c = coder.internal.scalexpAlloc(0,a,k);
    c(:) = 0;
    return
end

% Constant-fold with an extrinsic call.
if ~coder.target('MATLAB') && ...
        coder.internal.isConst(a) && ...
        coder.internal.isConst(k)
    if nargin == 2
        c = coder.const(feval('bitshift',a,k));
    else
        c = coder.const(feval('bitshift',a,k,assumedtype));
    end
    return
end

% Validate input types.
coder.internal.assert(isinteger(a) || isa(a,'double'), ...
    'Coder:toolbox:unsupportedClass','bitshift',class(a));
coder.internal.assert(isreal(a) && isreal(k), ...
    'MATLAB:bitshift:complexArgs','IfNotConst','Fail');
coder.internal.assert(allinteger(k), ...
    'MATLAB:bitshift:inputsMustBeIntegers');

% Determine assumed and output classes.
outputcls = coder.internal.builtinClass(a);
if nargin == 3
    coder.internal.assert(coder.internal.isTextRow(assumedtype), ...
        'MATLAB:bitshift:NDiscontinueSupport');
    assumedcls = char(assumedtype);
    coder.internal.assert(coder.internal.isIntegerClass(assumedcls), ...
        'MATLAB:bitshift:unknownTypeString');
    coder.internal.assert(isa(a,assumedcls) || isa(a,'double'), ...
        'MATLAB:bitshift:invalidTypeString');
elseif isinteger(a)
    assumedcls = outputcls;
else
    assumedcls = 'uint64';
end

% Validate double values, if any.
if ~isa(a,assumedcls)
    imin = intmin(assumedcls);
    imax = intmax(assumedcls);
    coder.internal.assert(all_in_integer_range(a,imin,imax), ...
        'MATLAB:bitshift:outOfRange');
end

% Perform the operation.
if coder.target('HDL') || coder.target('MATLAB')
    coder.inline('always');
    c = coder.internal.scalexpAlloc(zeros(outputcls),a,k);
    for m = 1:numel(c)
        c(m) = shift( ...
            coder.internal.scalexpSubsref(a,m), ...
            coder.internal.scalexpSubsref(k,m), ...
            assumedcls,outputcls);
    end
elseif coder.internal.isConstTrue(isscalar(a)) && ...
        coder.internal.isConstTrue(isscalar(k))
    coder.inline('always');
    c = shift(a(1),k(1),assumedcls,outputcls);
else
    f = @(a1,k1)shift(a1,k1,assumedcls,outputcls);
    c = coder.internal.sxfun('bitshift',f,a,k);
end

%--------------------------------------------------------------------------

function c = shift(a,k,assumedcls,outputcls)
coder.inline('always');
coder.internal.prefer_const(assumedcls,outputcls);
atmp = cast(a,coder.internal.builtinClass(a,mfilename));
a1 = eml_cast(atmp,assumedcls,'to zero','spill');
k1 = cast(k,coder.internal.builtinClass(k,mfilename));
maxshift = int8(coder.internal.int_nbits(assumedcls) - 1);
c = coder.nullcopy(zeros(outputcls));
if k1 >= zeros('like',k1)
    if k1 <= maxshift
        if isfloat(k1)
            absk1 = eml_cast(k1,'uint8','to zero','spill');
        else
            absk1 = k1;
        end
        c(1) = eml_lshift(a1,absk1);
    else
        c(1) = zeros(outputcls);
    end
elseif k1 >= -maxshift
    if isfloat(k1)
        absk1 = eml_cast(-k1,'uint8','to zero','spill');
    else
        absk1 = eml_uminus(k1,'spill');
    end
    c(1) = eml_rshift(a1,absk1);
elseif ~coder.internal.isaUint(a1) && a1 < zeros(assumedcls)
    % Shifting preserves the sign bit in MATLAB, so if we are
    % shifting a negative number, the result can never be zero.
    c(1) = cast(-1,outputcls);
else
    c(1) = zeros(outputcls);
end

%--------------------------------------------------------------------------

function p = allinteger(x)
p = isnumeric(x);
SHORTC = ~coder.target('hdl');
if p && isfloat(x)
    for k = 1:numel(x)
        if x(k) ~= floor(x(k))
            p = false;
            if SHORTC
                break
            end
        end
    end
end

%--------------------------------------------------------------------------
