program mkx86inl;

{$mode objfpc}
{$H+}

uses
  sysutils, classes;

type
  TOperDirection = (operIn, operVar, operOut);

  TOperand = record
    name,
    typ: string;
    direction: TOperDirection;
  end;

const
  DirLUT: array[TOperDirection] of string = ('','var ','out ');

{ ***************************************************************************
  the routines Copy2SymbDel, PosSetEx, PosSet, RemoveTrailingChars, TrimRightSet are copied and reformatted
  from StrUtils and thus covered by the copyright of strutils (see below) as compiler utilities cannot
  depend on packages

    This file is part of the Free Pascal run time library.
    Copyright (c) 1999-2005 by the Free Pascal development team

    See the file COPYING.FPC, included in this distribution,
    for details about the copyright.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*************************************************************************** }

function Copy2SymbDel(var S: string; Symb: Char): string;
  var
    p: SizeInt;
  begin
    p:=Pos(Symb,S);
    if p=0 then
      begin
        result:=s;
        s:='';
      end
    else
      begin
        Result:=Copy(S,1,p-1);
        delete(s,1,p);
      end;
  end;


function PosSetEx(const c: TSysCharSet; const s: ansistring; count: Integer): SizeInt;
  var
    i,j:SizeInt;
  begin
   if pchar(pointer(s))=nil then
    j:=0
   else
    begin
     i:=length(s);
     j:=count;
     if j>i then
      begin
       result:=0;
       exit;
      end;
     while (j<=i) and (not (s[j] in c)) do inc(j);
     if (j>i) then
      j:=0;                                         // not found.
    end;
   result:=j;
  end;

function PosSet(const c: TSysCharSet; const s: ansistring): SizeInt;
  begin
    result:=possetex(c,s,1);
  end;

procedure RemoveTrailingChars(VAR S: AnsiString; const CSet: TSysCharset);
  var
    I,J: LONGINT;

  Begin
   I:=Length(S);
   IF (I>0) Then
    Begin
     J:=I;
     While (j>0) and (S[J] IN CSet) DO DEC(J);
     IF J<>I Then
      SetLength(S,J);
    End;
  End;

function TrimRightSet(const S: String; const CSet: TSysCharSet): String;

begin
  result:=s;
  RemoveTrailingchars(result,cset);
end;

{ ***************************************************************************
   end of StrUtils code
  ***************************************************************************}

function GetPascalType(const ATyp: string): string;
  begin
    case ATyp of
      'r8':    exit('byte');
      'rs8':   exit('shortint');
      'r16':   exit('word');
      'rs16':  exit('smallint');
      'r32':   exit('longword');
      'rs32':  exit('longint');
      'r64':   exit('qword');
      'rs64':  exit('int64');
      'reg':   exit('NativeUInt');
      'sreg':  exit('NativeInt');
      'f32':   exit('single');
      'f64':   exit('double');
      'mm':    exit('__m64');
      'implicit_xmm0',
      'xmm':   exit('__m128');
      'i32':   exit('longint');

      'edi_ptr':   exit('pointer');

      'ptr8',
      'ptr16',
      'ptr32',
      'ptr64',
      'ptr128': exit('pointer');
    else
      exit(ATyp);
    end;
  end;

function GetTypeDef(const ATyp: string): string;
  begin
    case ATyp of
      'r8':    exit('u8inttype');
      'rs8':   exit('s8inttype');
      'r16':   exit('u16inttype');
      'rs16':  exit('s16inttype');
      'r32':   exit('u32inttype');
      'rs32':  exit('s32inttype');
      'r64':   exit('u64inttype');
      'rs64':  exit('s64inttype');
      'reg':   exit('uinttype');
      'sreg':  exit('sinttype');
      'f32':   exit('s32floattype');
      'f64':   exit('s64floattype');
      'mm':    exit('x86_m64type');
      'implicit_xmm0',
      'xmm':   exit('x86_m128type');
      'i32':   exit('s32inttype');

      'edi_ptr':   exit('voidpointertype');

      'ptr8',
      'ptr16',
      'ptr32',
      'ptr64',
      'ptr128': exit('voidpointertype');
    else
      exit(ATyp);
    end;
  end;

function GetOper(const ATyp: string): string;
  begin
    case ATyp of
      'r8':    exit('_reg');
      'rs8':   exit('_reg');
      'r16':   exit('_reg');
      'rs16':  exit('_reg');
      'r32':   exit('_reg');
      'rs32':  exit('_reg');
      'r64':   exit('_reg_reg');
      'rs64':  exit('_reg_reg');
      'reg':   exit('_reg');
      'sreg':  exit('_reg');
      'f32':   exit('_reg');
      'f64':   exit('_reg');
      'mm':    exit('_reg');
      'xmm':   exit('_reg');
      'i32':   exit('_const');

      'implicit_xmm0',
      'edi_ptr':   exit('');

      'ptr8',
      'ptr16',
      'ptr32',
      'ptr64',
      'ptr128': exit('_ref');
    else
      exit('');
    end;
  end;

function GetOperand(const ATyp: string; AIndex: longint): string;
  begin
    case ATyp of
      'r8':    exit(format(',paraarray[%d].location.register', [AIndex]));
      'rs8':   exit(format(',paraarray[%d].location.register', [AIndex]));
      'r16':   exit(format(',paraarray[%d].location.register', [AIndex]));
      'rs16':  exit(format(',paraarray[%d].location.register', [AIndex]));
      'r32':   exit(format(',paraarray[%d].location.register', [AIndex]));
      'rs32':  exit(format(',paraarray[%d].location.register', [AIndex]));
      'r64':   exit(format(',paraarray[%d].location.register64.reglo,paraarray[%d].location.register64.reghi', [AIndex,AIndex]));
      'rs64':  exit(format(',paraarray[%d].location.register64.reglo,paraarray[%d].location.register64.reghi', [AIndex,AIndex]));
      'reg':   exit(format(',paraarray[%d].location.register', [AIndex]));
      'sreg':  exit(format(',paraarray[%d].location.register', [AIndex]));
      'f32':   exit(format(',paraarray[%d].location.register', [AIndex]));
      'f64':   exit(format(',paraarray[%d].location.register', [AIndex]));
      'mm':    exit(format(',paraarray[%d].location.register', [AIndex]));
      'xmm':   exit(format(',paraarray[%d].location.register', [AIndex]));
      'i32':   exit(format(',GetConstInt(paraarray[%d])',[AIndex]));

      'implicit_xmm0',
      'edi_ptr': exit('');

      'ptr8',
      'ptr16',
      'ptr32',
      'ptr64',
      'ptr128': exit(format(',paraarray[%d].location.reference', [AIndex]));
    else
      exit(ATyp);
    end;
  end;

function GetOperandLoc(const ATyp: string): string;
  begin
    result:='';
    case ATyp of
      'r8':   exit(',location.register');
      'rs8':  exit(',location.register');
      'r16':  exit(',location.register');
      'rs16': exit(',location.register');
      'r32':  exit(',location.register');
      'rs32': exit(',location.register');
      'r64':  exit(',location.register64.reglo,location.register64.reghi');
      'rs64': exit(',location.register64.reglo,location.register64.reghi');
      'reg':  exit(',location.register');
      'sreg': exit(',location.register');
      'f32':  exit(',location.register');
      'f64':  exit(',location.register');
      'mm':   exit(',location.register');
      'implicit_xmm0',
      'xmm':  exit(',location.register');

      'edi_ptr': exit(',location.register');

      'ptr8',
      'ptr16',
      'ptr32',
      'ptr64',
      'ptr128': exit(',location.register');
    end;
  end;

function GetLocStatement(AIndex: longint; const ATyp: string; AConst: boolean): string;
  begin
    result:='';
    case ATyp of
      'r8':    exit(format('hlcg.location_force_reg(current_asmdata.CurrAsmList, paraarray[%d].location, paraarray[%d].resultdef,u8inttype,%s);', [AIndex+1, AIndex+1, BoolToStr(aconst,'true','false')]));
      'rs8':   exit(format('hlcg.location_force_reg(current_asmdata.CurrAsmList, paraarray[%d].location, paraarray[%d].resultdef,u8inttype,%s);', [AIndex+1, AIndex+1, BoolToStr(aconst,'true','false')]));
      'r16':   exit(format('hlcg.location_force_reg(current_asmdata.CurrAsmList, paraarray[%d].location, paraarray[%d].resultdef,u16inttype,%s);', [AIndex+1, AIndex+1, BoolToStr(aconst,'true','false')]));
      'rs16':  exit(format('hlcg.location_force_reg(current_asmdata.CurrAsmList, paraarray[%d].location, paraarray[%d].resultdef,u16inttype,%s);', [AIndex+1, AIndex+1, BoolToStr(aconst,'true','false')]));
      'r32':   exit(format('hlcg.location_force_reg(current_asmdata.CurrAsmList, paraarray[%d].location, paraarray[%d].resultdef,u32inttype,%s);', [AIndex+1, AIndex+1, BoolToStr(aconst,'true','false')]));
      'rs32':  exit(format('hlcg.location_force_reg(current_asmdata.CurrAsmList, paraarray[%d].location, paraarray[%d].resultdef,u32inttype,%s);', [AIndex+1, AIndex+1, BoolToStr(aconst,'true','false')]));
      'r64':   exit(format('hlcg.location_force_reg(current_asmdata.CurrAsmList, paraarray[%d].location, paraarray[%d].resultdef,u64inttype,%s);', [AIndex+1, AIndex+1, BoolToStr(aconst,'true','false')]));
      'rs64':  exit(format('hlcg.location_force_reg(current_asmdata.CurrAsmList, paraarray[%d].location, paraarray[%d].resultdef,u64inttype,%s);', [AIndex+1, AIndex+1, BoolToStr(aconst,'true','false')]));
      'reg':   exit(format('hlcg.location_force_reg(current_asmdata.CurrAsmList, paraarray[%d].location, paraarray[%d].resultdef,uinttype,%s);', [AIndex+1, AIndex+1, BoolToStr(aconst,'true','false')]));
      'sreg':  exit(format('hlcg.location_force_reg(current_asmdata.CurrAsmList, paraarray[%d].location, paraarray[%d].resultdef,sinttype,%s);', [AIndex+1, AIndex+1, BoolToStr(aconst,'true','false')]));
      'f32':   exit(format('location_force_mmreg(current_asmdata.CurrAsmList, paraarray[%d].location, %s);', [AIndex+1, BoolToStr(aconst,'true','false')]));
      'f64':   exit(format('location_force_mmreg(current_asmdata.CurrAsmList, paraarray[%d].location, %s);', [AIndex+1, BoolToStr(aconst,'true','false')]));
      'mm':    exit(format('location_force_mmxreg(current_asmdata.CurrAsmList, paraarray[%d].location, %s);', [AIndex+1, BoolToStr(aconst,'true','false')]));
      'xmm':   exit(format('location_force_mmreg(current_asmdata.CurrAsmList, paraarray[%d].location, %s);', [AIndex+1, BoolToStr(aconst,'true','false')]));

      'implicit_xmm0':
        exit(format('location_force_mmreg(current_asmdata.CurrAsmList, paraarray[%d].location, %s);'+LineEnding+
                    '    hlcg.getcpuregister(current_asmdata.CurrAsmList,NR_XMM0);'+LineEnding+
                    '    hlcg.a_loadmm_loc_reg(current_asmdata.CurrAsmList,paraarray[%d].resultdef,x86_m128type,paraarray[%d].location,NR_XMM0,nil);',
                      [AIndex+1, BoolToStr(aconst,'true','false'), AIndex+1, AIndex+1]));
      'edi_ptr':
        exit(format('hlcg.getcpuregister(current_asmdata.CurrAsmList,{$if defined(cpu64bitalu)}NR_RDI{$else}NR_EDI{$endif});'+LineEnding+
                    '    hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,paraarray[%d].resultdef,voidpointertype,paraarray[%d].location,{$if defined(cpu64bitalu)}NR_RDI{$else}NR_EDI{$endif});',
                      [AIndex+1, AIndex+1]));

      'ptr8',
      'ptr16',
      'ptr32',
      'ptr64',
      'ptr128':exit(format('location_make_ref(paraarray[%d].location);', [AIndex+1]));
    end;
  end;

function GetDeallocStatement(AIndex: longint; const ATyp: string): string;
  begin
    result:='';
    case ATyp of
      'implicit_xmm0':
        exit('hlcg.ungetcpuregister(current_asmdata.CurrAsmList,NR_XMM0);');
      'edi_ptr':
        exit('hlcg.ungetcpuregister(current_asmdata.CurrAsmList,{$if defined(cpu64bitalu)}NR_RDI{$else}NR_EDI{$endif});');
    end;
  end;

function GetLoc(const ATyp: string; AWithSize: boolean = true): string;
  begin
    result:='';
    if AWithSize then
      case ATyp of
        'r8':    exit('LOC_REGISTER,OS_8');
        'rs8':   exit('LOC_REGISTER,OS_S8');
        'r16':   exit('LOC_REGISTER,OS_16');
        'rs16':  exit('LOC_REGISTER,OS_S16');
        'r32':   exit('LOC_REGISTER,OS_32');
        'rs32':  exit('LOC_REGISTER,OS_S32');
        'r64':   exit('LOC_REGISTER,OS_64');
        'rs64':  exit('LOC_REGISTER,OS_S64');
        'reg':   exit('LOC_REGISTER,OS_INT');
        'sreg':  exit('LOC_REGISTER,OS_SINT');
        'f32':   exit('LOC_MMREGISTER,OS_M128');
        'f64':   exit('LOC_MMREGISTER,OS_M128');
        'mm':    exit('LOC_MMXREGISTER,OS_M64');
        'implicit_xmm0',
        'xmm':   exit('LOC_MMREGISTER,OS_M128');

        'edi_ptr':   exit('LOC_REGISTER,OS_INT');

        'ptr8':  exit('LOC_MEM,OS_8');
        'ptr16': exit('LOC_MEM,OS_16');
        'ptr32': exit('LOC_MEM,OS_32');
        'ptr64': exit('LOC_MEM,OS_64');
        'ptr128':exit('LOC_MEM,OS_128');
      end
    else
      case ATyp of
        'r8':    exit('LOC_REGISTER');
        'rs8':   exit('LOC_REGISTER');
        'r16':   exit('LOC_REGISTER');
        'rs16':  exit('LOC_REGISTER');
        'r32':   exit('LOC_REGISTER');
        'rs32':  exit('LOC_REGISTER');
        'r64':   exit('LOC_REGISTER');
        'rs64':  exit('LOC_REGISTER');
        'reg':   exit('LOC_REGISTER');
        'sreg':  exit('LOC_REGISTER');
        'f32':   exit('LOC_MMREGISTER');
        'f64':   exit('LOC_MMREGISTER');
        'mm':    exit('LOC_MMXREGISTER');
        'implicit_xmm0',
        'xmm':   exit('LOC_MMREGISTER');

        'edi_ptr':   exit('LOC_REGISTER');

        'ptr8',
        'ptr16',
        'ptr32',
        'ptr64',
        'ptr128':exit('LOC_MEM');
      end;
  end;

function GetLocAllocation(const ATyp: string): string;
  begin
    result:='';
    case ATyp of
      'r8':  exit('location.register:=cg.getintregister(current_asmdata.CurrAsmList, OS_8);');
      'rs8': exit('location.register:=cg.getintregister(current_asmdata.CurrAsmList, OS_8);');
      'r16':  exit('location.register:=cg.getintregister(current_asmdata.CurrAsmList, OS_16);');
      'rs16': exit('location.register:=cg.getintregister(current_asmdata.CurrAsmList, OS_16);');
      'r32':  exit('location.register:=cg.getintregister(current_asmdata.CurrAsmList, OS_32);');
      'rs32': exit('location.register:=cg.getintregister(current_asmdata.CurrAsmList, OS_32);');
      'r64':  exit('location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList, OS_32); location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList, OS_32);');
      'rs64': exit('location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList, OS_32); location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList, OS_32);');
      'reg':  exit('location.register:=cg.getintregister(current_asmdata.CurrAsmList, OS_INT);');
      'sreg': exit('location.register:=cg.getintregister(current_asmdata.CurrAsmList, OS_INT);');
      'f32':  exit('location.register:=cg.getmmregister(current_asmdata.CurrAsmList, OS_M128);');
      'f64':  exit('location.register:=cg.getmmregister(current_asmdata.CurrAsmList, OS_M128);');
      'mm':   exit('location.register:=tcgx86(cg).getmmxregister(current_asmdata.CurrAsmList);');
      'xmm':  exit('location.register:=cg.getmmregister(current_asmdata.CurrAsmList, OS_M128);');
    end;
  end;

function GetPostFix(const APF: string): string;
  begin
    if APF<>'' then
      result:='PF_'+APF
    else
      result:='PF_None';
  end;

procedure ParseList(const APrefix, AFilename: string);
  var
    f: TextFile;

    fprocs,
    fcinnr, fcpumminnr: TextFile;
    ftypechk, ffirst, fsecond: TStringList;

    str,
    instrPart,postfix,_alias,
    params, operline: String;

    opers: array[0..7] of TOperand;
    opercnt: longint;

    hasOutput: boolean;
    outputType: string;
    cnt,
    i, intrnum: longint;
    tmp, condition, target: String;

  function ParseOperands(AIndex: longint = -1): string;
    var
      idx: LongInt;
      pt: Integer;
      c: Char;
    begin
      idx:=opercnt;

      params:=trim(params);
      if params='' then
        exit('');

      inc(opercnt);

      if pos('var ', params)=1 then
        begin
          opers[idx].direction:=operVar;
          Delete(params,1,4);
          params:=trim(params);
          hasOutput:=true;
        end
      else if pos('out ', params)=1 then
        begin
          opers[idx].direction:=operOut;
          Delete(params,1,4);
          params:=trim(params);
          hasOutput:=true;
        end
      else
        begin
          if AIndex<>-1 then
            opers[idx].direction:=opers[AIndex].direction
          else
            opers[idx].direction:=operIn;
        end;

          pt:=PosSet([',',':'], params);

      c:=params[pt];
      opers[idx].name:=Copy2SymbDel(params, c);
      params:=trim(params);

      if c = ':' then
        begin
          opers[idx].typ:=Copy2SymbDel(params, ';');
          result:=opers[idx].typ;
        end
      else
        begin
          opers[idx].typ:=ParseOperands(idx);
          result:=opers[idx].typ;
        end;

      if opers[idx].direction<>operIn then
        outputType:=opers[idx].typ;
    end;

  function GetOperLine: string;
    var
      i: longint;
    begin
      result:='';
      for i := 0 to opercnt-1 do
        result:=result+DirLUT[opers[i].direction]+opers[i].name+':'+opers[i].typ+';';
    end;

  function GetParams: longint;
    var
      i: longint;
    begin
      result:=0;
      for i := 0 to opercnt-1 do
        if opers[i].direction in [operIn,operVar] then
          inc(result);
    end;

  function FindOperIdx(const AOper: string): longint;
    var
      i,cnt: longint;
    begin
      cnt:=0;
      result:=0;
      for i := 0 to opercnt-1 do
        if (opers[i].direction in [operIn,operVar]) then
          begin
            if opers[i].name=AOper then
              exit(cnt);
            inc(cnt);
          end;
    end;

  begin
    intrnum:=0;

    assignfile(f, AFilename);
    reset(f);

    assignfile(fprocs, 'cpummprocs.inc'); rewrite(fprocs);
    assignfile(fcinnr, 'c'+APrefix+'mminnr.inc'); rewrite(fcinnr);
    assignfile(fcpumminnr, 'cpumminnr.inc'); rewrite(fcpumminnr);

//    writeln(finnr,'const');

    ftypechk:=TStringList.Create;
    ffirst:=TStringList.Create;
    fsecond:=TStringList.Create;

//    writeln(finnr, '  fpc_in_', APrefix,'_first = fpc_in_',APrefix,'_base;');

    while not EOF(f) do
      begin
        readln(f, str);

        str:=trim(str);

        if (str='') or (Pos(';',str)=1) then
          continue;

        instrPart:=Copy2SymbDel(str, '(');

        // Check for postfix
        if pos('{',instrPart)>0 then
          begin
            postfix:=instrPart;
            instrPart:=Copy2SymbDel(postfix, '{');
            postfix:=TrimRightSet(postfix,['}']);
          end
        else
          postfix:='';

        // Check for alias
        if pos('[',instrPart)>0 then
          begin
            _alias:=instrPart;
            instrPart:=Copy2SymbDel(_alias, '[');
            _alias:='_'+TrimRightSet(_alias,[']']);
          end
        else
          _alias:='';

        // Get parameters
        params:=trim(Copy2SymbDel(str,')'));
        str:=trim(str);

        // Parse condition and target
        if pos('|', str)>0 then
        begin
          condition:=trim(Copy2SymbDel(str, '|'));
          target:=trim(str);
        end
        else
        begin
          condition:=str;
          target:='';
        end;

        hasOutput:=false;
        opercnt:=0;
        outputType:='';

        while params<>'' do
          ParseOperands;

        operline:=GetOperLine;
        // Write typecheck code
        i:=ftypechk.IndexOf(': //'+operline);
        if (i>=0) and (target='') then
          ftypechk.Insert(i,',in_'+APrefix+'_'+instrPart+postfix+_alias)
        else
          begin
            if target<>'' then
              ftypechk.add(format('{$ifdef %s}', [target]));

            ftypechk.Add('in_'+APrefix+'_'+instrPart+postfix+_alias);
            ftypechk.Add(': //'+operline);
            ftypechk.Add('  begin');
            ftypechk.Add('    CheckParameters('+inttostr(GetParams())+');');
            if hasOutput then
              ftypechk.Add('    resultdef:='+GetTypeDef(outputType)+';')
            else
              ftypechk.Add('    resultdef:=voidtype;');
            ftypechk.Add('  end;');

            if target<>'' then
              ftypechk.add('{$endif}');
          end;

        // Write firstpass code
        i:=ffirst.IndexOf(': //'+operline);
        if (i>=0) and (target='') then
          ffirst.Insert(i,',in_'+APrefix+'_'+instrPart+postfix+_alias)
        else
          begin
            if target<>'' then
              ffirst.add(format('{$ifdef %s}', [target]));

            ffirst.Add('in_'+APrefix+'_'+instrPart+postfix+_alias);
            ffirst.Add(': //'+operline);
            ffirst.Add('  begin');
            if hasOutput then
              ffirst.Add('    expectloc:='+GetLoc(outputType,false)+';')
            else
              ffirst.Add('    expectloc:=LOC_VOID;');
            ffirst.Add('    result:=nil;');
            ffirst.Add('  end;');

            if target<>'' then
              ffirst.add('{$endif}');
          end;

        // Write secondpass code
        i:=fsecond.IndexOf(': //'+operline);
        if (i>=0) and (target='') then
          begin
            fsecond.Insert(i+3,'      in_'+APrefix+'_'+instrPart+postfix+_alias+': begin op:=A_'+instrPart+' end;');
            fsecond.Insert(i,',in_'+APrefix+'_'+instrPart+postfix+_alias);
          end
        else
          begin
            if target<>'' then
              fsecond.add(format('{$ifdef %s}', [target]));

            fsecond.Add('in_'+APrefix+'_'+instrPart+postfix+_alias);
            fsecond.Add(': //'+operline);
            fsecond.Add('  begin');
            fsecond.Add('    case inlinenumber of');
            fsecond.Add('      in_'+APrefix+'_'+instrPart+postfix+_alias+': begin op:=A_'+instrPart+'; end;');
            fsecond.Add('      else');
            fsecond.Add('        Internalerror(2020010201);');
            fsecond.Add('    end;');
            fsecond.Add('');

            i:=GetParams;
            fsecond.Add('    GetParameters('+inttostr(i)+');');
            fsecond.Add('');

            fsecond.Add('    for i := 1 to '+inttostr(i)+' do secondpass(paraarray[i]);');
            fsecond.Add('');

            // Force inputs
            cnt:=0;
            for i := 0 to opercnt-1 do
              begin
                case opers[i].direction of
                  operIn:
                    begin
                      tmp:=GetLocStatement(cnt, opers[i].typ, true);
                      if tmp<>'' then
                        fsecond.add('    '+tmp);
                      inc(cnt);
                    end;
                  operVar:
                    begin
                      tmp:=GetLocStatement(cnt, opers[i].typ, false);
                      if tmp<>'' then
                        fsecond.add('    '+tmp);
                      inc(cnt);
                    end;
                  else
                    ;
                end;
              end;

            // Allocate output
            cnt:=0;
            for i := 0 to opercnt-1 do
              begin
                case opers[i].direction of
                  operOut:
                    begin
                      fsecond.add('    location_reset(location,'+GetLoc(opers[i].typ)+');');
                      fsecond.Add('    '+GetLocAllocation(opers[i].typ));
                    end;
                  operVar:
                    begin
                      fsecond.Add('    location:=paraarray['+inttostr(cnt+1)+'].location;');
                      inc(cnt);
                    end;
                  operIn:
                    inc(cnt);
                end;
              end;

            operline:='taicpu.op';
            //for i := 0 to opercnt-1 do
            for i := opercnt-1 downto 0 do
              begin
                case opers[i].direction of
                  operOut:
                    operline:=operline+GetOper(opers[i].typ);
                  operVar:
                    operline:=operline+GetOper(opers[i].typ);
                  operIn:
                    operline:=operline+GetOper(opers[i].typ);
                end;
              end;

            if operline='taicpu.op' then
              operline:='taicpu.op_none(op,S_NO'
            else
              operline:=operline+'(op,S_NO';

            //for i := 0 to opercnt-1 do
            for i := opercnt-1 downto 0 do
              begin
                case opers[i].direction of
                  operOut:
                    operline:=operline+GetOperandLoc(opers[i].typ);
                  operIn,
                  operVar:
                    begin
                      dec(cnt);
                      operline:=operline+GetOperand(opers[i].typ, cnt+1);
                    end;
                end;
              end;

            operline:=operline+')';

            fsecond.Add('    current_asmdata.CurrAsmList.concat('+operline+');');

            // Deallocate CPU registers
            for i := 0 to opercnt-1 do
              begin
                tmp:=GetDeallocStatement(cnt, opers[i].typ);
                if tmp<>'' then
                  fsecond.add('    '+tmp);
              end;

            fsecond.Add('  end;');

            if target<>'' then
              fsecond.add('{$endif}');
          end;

        // Write innr
        writeln(fcinnr, '  in_', APrefix,'_',instrPart,postfix+_alias,' = in_',APrefix,'_mm_first+',intrnum,',');
        writeln(fcpumminnr, '  fpc_in_', APrefix,'_',instrPart,postfix+_alias,' = fpc_in_',APrefix,'_mm_first+',intrnum,';');

        // Write function
        if target<>'' then
          writeln(fprocs, '{$ifdef ',target,'}');

        if hasOutput then write(fprocs,'function ') else write(fprocs,'procedure ');
        write(fprocs,APrefix,'_',instrPart,postfix,'(');

        cnt:=0;
        for i:=0 to opercnt-1 do
          begin
            if opers[i].direction=operOut then
              Continue;

            if cnt>0 then
              begin
                if opers[i].typ<>opers[i-1].typ then
                  write(fprocs,': ',GetPascalType(opers[i-1].typ),'; ')
                else
                  write(fprocs,', ');
              end;

            write(fprocs,opers[i].name);
            if i=opercnt-1 then
              write(fprocs,': ',GetPascalType(opers[i].typ));

            inc(cnt);
          end;

        write(fprocs,')');

        if hasOutput then write(fprocs,': ',GetPascalType(outputType));
        writeln(fprocs,'; [INTERNPROC: fpc_in_',APrefix,'_',instrPart,postfix+_alias,'];');

        if target<>'' then
          writeln(fprocs, '{$endif}');

        // Str now contains conditionals

        inc(intrnum);
      end;

    writeln(fcinnr, '  in_', APrefix,'mm_last = in_',APrefix,'_mm_first+',intrnum-1);

    ftypechk.SaveToFile(APrefix+'mmtype.inc');
    ffirst.SaveToFile(APrefix+'mmfirst.inc');
    fsecond.SaveToFile(APrefix+'mmsecond.inc');

    ftypechk.Free;
    ffirst.Free;
    fsecond.Free;

    CloseFile(fprocs);
    CloseFile(fcinnr);
    CloseFile(fcpumminnr);

    closefile(f);
  end;

begin
  ParseList('x86', 'x86intr.dat');
end.

