Metropoli BBS
VIEWER: codegen.pas MODE: TEXT (CP437)
{$ifdef tp}
{E+,N+}
{$endif}
{****************************************************************************

                   Copyright (c) 1993,96 by Florian Klämpfl

 ****************************************************************************}

unit codegen;

  interface

    uses
       cobjects,systems,globals,tree,asmgen,symtable,tempad,types,strings,
       i386,pass_1,hcodegen;

    { erzeugt für den durch p übergebenen Ausdruck Assembler }
    { und erzeugt am Ende eine Assembler-Node                }

    procedure generatecode(var p : ptree);

    { erzeugt den eigentlichen Code }
    function do_secondpass(var p : ptree) : boolean;

    { initilisiert bzw beendet den Codegenerator }
    procedure codegeninit;
    procedure codegendone;

    { erzeugt bei bool'schen Ausdrücken die Sprünge zu true bzw falselabel }
    procedure maketojumpbool(p : ptree);

    procedure concatcopy(source,dest : treferenz;size : longint;delsource : boolean);

    { siehe Implementation }
    procedure maybe_loadesi;

  implementation

    procedure secondpass(var p : ptree);forward;

    procedure error(const t : errorconst);

      begin
         if not(codegenerror) then
           globals.error(t);
         codegenerror:=true;
      end;

    type
       secondpassproc = procedure(var p : ptree);

    function ispowerof2(value : longint;var power : longint) : boolean;

      var
         hl : longint;
         i : longint;

      begin
         hl:=1;
         ispowerof2:=true;
         for i:=0 to 31 do
           begin
              if hl=value then
                begin
                   power:=i;
                   exit;
                end;
              hl:=hl shl 1;
           end;
         ispowerof2:=false;
      end;

    procedure emit(i : tasmop;s : topsize;const t : string);

      var
         p : pasmrec;
         b : array[0..255] of char;

      begin
         if (i=PUSH) or (i=PUSHAD) then pushgened:=true;
{$ifdef tp}
         if use_big then
           p:=hasmrec
         else
{$endif}
         new(p);
         p^.linenr:=inputstack^.line_no;
         p^.infile:=inputstack;
         p^.instruc:=i;
         p^.disposing:=D_STRING;
         p^.opsize:=s;
{$ifdef tp}
         if use_big then
           begin
              strpcopy(b,t);
              p^.t:=pchar(symbolstream.size);
              symbolstream.seek(longint(p^.t));
              symbolstream.strwrite(b);
           end
        else
{$endif}
           p^.t:=strpnew(t);
         p^.next:=nil;
{$ifdef tp}
         if use_big then
           begin
              p:=pasmrec(symbolstream.size);
              symbolstream.seek(symbolstream.size);
              symbolstream.write(hasmrec^,sizeof(tasmrec));
              if exprasmlist.wurzel=nil then
                exprasmlist.wurzel:=p
              else setnext(exprasmlist.last,p);
              exprasmlist.last:=p;
           end
        else
{$endif}
         begin
            if exprasmlist.wurzel=nil then exprasmlist.wurzel:=p
              else exprasmlist.last^.next:=p;
            exprasmlist.last:=p;
         end;
      end;

    procedure emitl(i : tasmop;l : longint);

      var
         p : pasmrec;

      begin
{$ifdef tp}
         if use_big then
           p:=hasmrec
         else
{$endif}
         new(p);
{         if jumpoptimize then
           begin
              if i<>A_LABEL then registerused(p,l)
              else getinforec(l)^.defined:=p;
           end; }
         p^.linenr:=inputstack^.line_no;
         p^.infile:=inputstack;
         p^.instruc:=i;
         p^.opsize:=S_NO;
         p^.disposing:=D_LABEL;
         p^.l:=l;
         p^.next:=nil;
{$ifdef tp}
         if use_big then
           begin
              p:=pasmrec(symbolstream.size);
              symbolstream.seek(symbolstream.size);
              symbolstream.write(hasmrec^,sizeof(tasmrec));
              if exprasmlist.wurzel=nil then
                exprasmlist.wurzel:=p
              else setnext(exprasmlist.last,p);
              exprasmlist.last:=p;
           end
        else
{$endif}
           begin
              if exprasmlist.wurzel=nil then exprasmlist.wurzel:=p
                else exprasmlist.last^.next:=p;
              exprasmlist.last:=p;
           end;
      end;

    procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);

      begin
         if (reg1<>reg2) or (i<>MOV) then
           emit(i,s,regid2str[reg1]+','+regid2str[reg2]);
      end;

    procedure maketojumpbool(p : ptree);

      begin
         if p^.error then
           exit;
         if (p^.resulttype^.deftype=grunddef) and
            (pgrunddef(p^.resulttype)^.typ=bool8bit) then
           begin
              if is_constboolnode(p) then
                begin
                   if p^.value<>0 then
                     emitl(JMP,truelabel)
                   else emitl(JMP,falselabel);
                end
              else
                begin
                   case p^.location.loc of
                      LOC_CREGISTER,LOC_REGISTER : begin
                                        emit(A_OR,S_B,regid2str[p^.location.register]+
                                          ','+regid2str[p^.location.register]);
                                        emitl(JNZ,truelabel);
                                        emitl(JMP,falselabel);
                                     end;
                      LOC_MEM,LOC_REFERENZ : begin
                                        emit(CMP,S_B,'$0,'+getreferenzstring(p^.location.referenz));
                                        emitl(JNZ,truelabel);
                                        emitl(JMP,falselabel);
                                     end;
                      LOC_FLAGS : begin
                                     emitl(flag_2_jmp[p^.location.resflags],truelabel);
                                     emitl(JMP,falselabel);
                                  end;
                   end;
                end;
           end
         else
           error(type_mismatch);
      end;

    procedure emitoverflowcheck;

      var
         hl : longint;

      begin
         if cs_check_overflow in aktswitches  then
           begin
              hl:=getlabel;
              emitl(JNO,hl);
              emit(CALL,S_NO,'RE_OVERFLOW');
              emitl(A_LABEL,hl);
           end;
      end;

    procedure emitpushreferenzaddr(const ref : treferenz);

      begin
         if ref.isintvalue then
           emit(PUSH,S_L,'$'+tostr(ref.offset))
         else
           begin
              if (ref.base=R_NO) and (ref.index=R_NO) then
                emit(PUSH,S_L,'$'+getreferenzstring(ref))
              else if (ref.base=R_NO) and (ref.index<>R_NO) and
                 (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
                emit(PUSH,S_L,regid2str[ref.index])
              else if (ref.base<>R_NO) and (ref.index=R_NO) and
                 (ref.offset=0) and (ref.symbol=nil) then
                emit(PUSH,S_L,regid2str[ref.base])
              else
                begin
                   emit(LEA,S_L,getreferenzstring(ref)+',%edi');
                   emit(PUSH,S_L,'%edi');
                end;
           end;
        end;

    { lädt falls notwendig, ESI nach einem Call neu }

    procedure maybe_loadesi;

      begin
         if assigned(procinfo._class) then
           emit(MOV,S_NO,tostr(procinfo.ESI_offset)+'(%ebp),%esi');
      end;

    type
       tpushed = array[R_EAX..R_EBX] of boolean;

    procedure pushusedregisters(var pushed : tpushed;b : byte);

      var
         r : tregister;

      begin
         for r:=R_EAX to R_EBX do
           begin
              pushed[r]:=false;
              { wenn das Register von dem aufgerufenen Unterprogramm }
              { verwendet wird:                                      }
              if ((b and ($80 shr byte(r)))<>0) then
                begin
                   { und momentan belegt ist }
                   if not(r in unused) then
                     begin
                        { dann retten... }
                        emit(PUSH,S_L,regid2str[r]);
                        unused:=unused+[r];
                        pushed[r]:=true;
                     end;
                end;
           end;
      end;

    procedure genconstadd(size : topsize;l : longint;const str : string);

      begin
         if l=0 then
         else if l=1 then
           emit(A_INC,size,str)
         else if l=-1 then
           emit(A_INC,size,str)
         else
           emit(ADD,size,'$'+tostr(l)+','+str);
      end;

    procedure popusedregisters(const pushed : tpushed);

      var
         r : tregister;

      begin
         for r:=R_EBX downto R_EAX do
           if pushed[r] then
             begin
                emit(POP,S_L,regid2str[r]);
                unused:=unused-[r];
             end;
      end;

    procedure concatcopy(source,dest : treferenz;size : longint;delsource : boolean);

      var
         ecxpushed : boolean;
         helpsize : longint;
         i : byte;
         reg8,reg32 : tregister;
         swap : boolean;

      begin

         if delsource then
           del_referenz(source);

         { ab 12 Bytes wird movs verwendet }
         if (size<=8) or (not(cs_littlesize in aktswitches ) and (size<=12)) then
           begin
              helpsize:=size div 4;
              for i:=1 to helpsize do
                begin
                   emit(MOV,S_L,getreferenzstring(source)+',%edi');
                   emit(MOV,S_L,'%edi,'+getreferenzstring(dest));
                   inc(source.offset,4);
                   inc(dest.offset,4);
                   dec(size,4);
                end;
              if size>1 then
                begin
                   emit(MOV,S_W,getreferenzstring(source)+',%di');
                   emit(MOV,S_W,'%di,'+getreferenzstring(dest));
                   inc(source.offset,2);
                   inc(dest.offset,2);
                   dec(size,2);
                end;
              if size>0 then
                begin

                   { nun ein 8-Bit Register suchen }
                   swap:=false;
                   if R_EAX in unused then reg8:=R_AL
                   else if R_EBX in unused then reg8:=R_BL
                   else if R_ECX in unused then reg8:=R_CL
                   else if R_EDX in unused then reg8:=R_DL
                   else
                      begin
                         swap:=true;

                         { wir müssen nur 3 Register untersuchen, da dann }
                         { immer eines nicht Index oder Base ist          }
                         if (dest.base<>R_EAX) and (dest.index<>R_EAX) then
                           begin
                              reg8:=R_AL;
                              reg32:=R_EAX;
                           end
                         else if (dest.base<>R_EBX) and (dest.index<>R_EBX) then
                           begin
                              reg8:=R_BL;
                              reg32:=R_EBX;
                           end
                         else if (dest.base<>R_ECX) and (dest.index<>R_ECX) then
                           begin
                              reg8:=R_CL;
                              reg32:=R_ECX;
                           end;
                      end;
                   if swap then
                     { war früher XCHG, natürlich Quatsch }
                     emit_reg_reg(MOV,S_L,reg32,R_EDI);
                   emit(MOV,S_B,getreferenzstring(source)+','+regid2str[reg8]);
                   emit(MOV,S_B,regid2str[reg8]+','+getreferenzstring(dest));
                   if swap then
                     emit_reg_reg(MOV,S_L,R_EDI,reg32);
                end;
           end
         else
           begin
              emit(LEA,S_L,getreferenzstring(source)+',%esi');
              emit(LEA,S_L,getreferenzstring(dest)+',%edi');
              del_referenz(dest);
              if not(R_ECX in unused) then
                begin
                   emit(PUSH,S_L,'%ecx');
                   ecxpushed:=true;
                end
              else ecxpushed:=false;
              emit(CLD,S_NO,'');
              if cs_littlesize in aktswitches  then
                begin

                   if size mod 4=0 then
                     begin
                        emit(MOV,S_L,'$'+tostr(size div 4)+',%ecx');
                        emit(REP,S_NO,'');
                        emit(MOVS,S_L,'');
                     end
                   else if size mod 2=0 then
                     begin
                        emit(MOV,S_L,'$'+tostr(size div 2)+',%ecx');
                        emit(REP,S_NO,'');
                        emit(MOVS,S_W,'');
                     end
                   else
                     begin
                        emit(MOV,S_L,'$'+tostr(size)+',%ecx');
                        emit(REP,S_NO,'');
                        emit(MOVS,S_B,'');
                     end;
                end
              else
                begin
                   helpsize:=size-size mod 4;
                   size:=size mod 4;
                   emit(MOV,S_L,'$'+tostr(helpsize div 4)+',%ecx');
                   emit(REP,S_NO,'');
                   emit(MOVS,S_L,'');
                   if size>1 then
                     begin
                        dec(size,2);
                        emit(MOVS,S_W,'');
                     end;
                   if size=1 then
                     emit(MOVS,S_B,'');
                end;
              if ecxpushed then
                emit(POP,S_L,'%ecx');

              { SELF-Referenz wieder laden }
              if assigned(procinfo._class) then
                emit(MOV,S_NO,tostr(procinfo.ESI_offset)+'(%ebp),%esi');
           end;
      end;

    procedure copystring(const dref,sref : treferenz;len : byte);

      var
         pushed : tpushed;

      begin
         pushusedregisters(pushed,$ff);
         emitpushreferenzaddr(dref);
         emitpushreferenzaddr(sref);
         emit(PUSH,S_L,'$'+tostr(len));
         emit(CALL,S_NO,'STRCOPY');
         maybe_loadesi;
         popusedregisters(pushed);
      end;

    procedure restore(p : ptree);

      var
         hregister :  tregister;

      begin
         hregister:=getregister32;
         emit(POP,S_L,regid2str[hregister]);
         if (p^.location.loc=LOC_REGISTER) or (p^.location.loc=LOC_CREGISTER) then
           begin
              p^.location.register:=hregister;
           end
         else
           begin
              clear_referenz(p^.location.referenz);
              p^.location.referenz.index:=hregister;
           end;
      end;

    function maybe_push(needed : byte;p : ptree) : boolean;

      var
         pushed : boolean;
         hregister : tregister;

      begin
         if needed>usablereg32 then
           begin
              if (p^.location.loc=LOC_REGISTER) or
                 (p^.location.loc=LOC_CREGISTER) then
                begin
                   pushed:=true;
                   emit(PUSH,S_L,regid2str[p^.location.register]);
                   ungetregister32(p^.location.register);
                end
              else if ((p^.location.loc=LOC_MEM) or
                       (p^.location.loc=LOC_REFERENZ)
                      ) and
                      ((p^.location.referenz.base<>R_NO) or
                       (p^.location.referenz.index<>R_NO)
                      ) then
                  begin
                     del_referenz(p^.location.referenz);
                     hregister:=getregister32;
                     emit(LEA,S_L,getreferenzstring(p^.location.referenz)+','
                       +regid2str[hregister]);
                     emit(PUSH,S_L,regid2str[hregister]);
                     ungetregister32(hregister);
                     pushed:=true;
                  end
              else pushed:=false;
           end
         else pushed:=false;
         maybe_push:=pushed;
      end;

    procedure seconderror(var p : ptree);far;

      begin
         p^.error:=true;
         codegenerror:=true;
      end;

    procedure secondload(var p : ptree);far;

      var
         hregister : tregister;
         symtabletype,i : longint;

      begin
         simple_loadn:=true;
         clear_referenz(p^.location.referenz);
         case p^.symtableentry^.typ of
              varsym :
                 begin
                    hregister:=R_NO;
                    symtabletype:=p^.symtable^.symtabletype;
                    { falls es sich um eine Registervariable handelt: }
                    if pvarsym(p^.symtableentry)^.reg<>R_NO then
                      begin
                         p^.location.loc:=LOC_CREGISTER;
                         p^.location.register:=pvarsym(p^.symtableentry)^.reg;
                      end
                    else
                      begin
                         { erst lokale und Uebergabevariablen behandeln }
                         if (symtabletype and $c000)<>0 then
                           begin
                              p^.location.referenz.base:=R_EBP;
                              p^.location.referenz.offset:=pvarsym(p^.symtableentry)^.adresse;
                              if (symtabletype and $8000<>0) then
                                p^.location.referenz.offset:=-p^.location.referenz.offset;
                              if (symtabletype and $4000<>0) then
                                inc(p^.location.referenz.offset,longint(p^.symtable^.name));
                              if (lexlevel>(p^.symtable^.symtabletype and $3fff)) then
                                begin
                                   hregister:=getregister32;
                                   emit(MOV,S_L,tostr(procinfo.framepointer)+'(%ebp),'+regid2str[hregister]);
                                   simple_loadn:=false;
                                   i:=lexlevel-1;
                                   while i>(p^.symtable^.symtabletype and $3fff) do
                                     begin
                                        if procinfo.exceptions then
                                          emit(MOV,S_L,'12('+regid2str[hregister]+'),'+regid2str[hregister])
                                        else
                                          emit(MOV,S_L,'8('+regid2str[hregister]+'),'+regid2str[hregister]);
                                        dec(i);
                                     end;
                                   p^.location.referenz.base:=hregister;
                                end;
                           end
                         else
                           case p^.symtable^.symtabletype of
                              staticsymtable : begin
                                                  p^.location.referenz.symbol:=stringdup('_'+p^.symtableentry^.name);
                                               end;
                              unitsymtable,globalsymtable : begin
                                                  p^.location.referenz.symbol:=stringdup('U_'+
                                                  p^.symtable^.name^+'_'+p^.symtableentry^.name);
                                               end;
                              objectsymtable : begin
                                                  p^.location.referenz.base:=R_ESI;
                                                  p^.location.referenz.offset:=pvarsym(p^.symtableentry)^.adresse;
                                               end;
                              withsymtable :   begin
                                                  hregister:=getregister32;
                                                  p^.location.referenz.base:=hregister;
                                                  emit(MOV,S_L,tostr(p^.symtable^.datasize)+'(%ebp),'+
                                                    regid2str[hregister]);
                                                  p^.location.referenz.offset:=
                                                    pvarsym(p^.symtableentry)^.adresse;
                                               end;
                           end;
                         { falls Call by Referenz, dann berechenen: }
                         if (pvarsym(p^.symtableentry)^.varspez=vs_var) or
                            ((pvarsym(p^.symtableentry)^.varspez=vs_const) and
                             (
                               (pvarsym(p^.symtableentry)^.definition^.deftype=stringdef) or
                               (pvarsym(p^.symtableentry)^.definition^.deftype=arraydef) or
                               (pvarsym(p^.symtableentry)^.definition^.deftype=recorddef) or
                               (pvarsym(p^.symtableentry)^.definition^.deftype=classdef) or
                               (pvarsym(p^.symtableentry)^.definition^.deftype=setdef)
                             )
                            ) then
                           begin
                              simple_loadn:=false;
                              if hregister=R_NO then
                                hregister:=getregister32;
                              emit(MOV,S_L,getreferenzstring(p^.location.referenz)+','+regid2str[hregister]);
                              clear_referenz(p^.location.referenz);
                              p^.location.referenz.base:=hregister;
                          end;
                      end;
                 end;
              procsym:
                 begin
                    {!!!!! Vorsicht, auch virtuelle Methoden bearbeiten}
                    p^.location.referenz.symbol:=
                      stringdup(pprocsym(p^.symtableentry)^.definition^.mangledname);
                 end;
              typedconstsym :
                 begin
                    p^.location.referenz.symbol:=stringdup(
                      'TC_'+ptypedconstsym(p^.symtableentry)^.prefix^+'_'+
                      +p^.symtableentry^.name);
                 end;
              else internalerror(4);
         end;
      end;

    procedure firstcomplex(p : ptree);

      var
         hp : ptree;

      begin
         { boolsches AND und OR immer von links nach rechts auswerten }
         if ((p^.treetype=orn) or (p^.treetype=andn)) and
           (p^.left^.resulttype^.deftype=grunddef) and
           (pgrunddef(p^.left^.resulttype)^.typ=bool8bit) then
           exit;

         if (p^.left^.registers32<p^.right^.registers32)

           { folgende Abfrage ist sinnvoll, da  }
           { selten alle 4 Register gebraucht werden und   }
           { damit erreicht wird, daß der zusätzliche Code }
           { bei vertauschten nichtkommutativen Operatoren }
           { entfällt                                      }
           and (p^.right^.registers32<=4) then
           begin
              hp:=p^.left;
              p^.left:=p^.right;
              p^.right:=hp;
              p^.swaped:=true;
           end
         else p^.swaped:=false;
      end;

    procedure secondadd(var p : ptree);far;

    { (wird auch für xor,and,"mul","sub",or und Vergleichsoperatoren }
    { verwendet)                                                     }

      var
         swapp : ptree;
         hregister : tregister;
         pushed,mboverflow,cmpop : boolean;
         op : tasmop;
         swapl : tlocation;
         pushedregs : tpushed;
         flags : tresflags;
         otl,ofl,power : longint;
         href : treferenz;
         opsize : topsize;

         { true, falls vorzeichenlose Typen verglichen werden }
         unsigned : boolean;

      begin
         unsigned:=false;
         opsize:=S_L;
         { den komplexeren Operanden berechnen }
         firstcomplex(p);
         { bool'sche Ausdruecke extra behandeln: }
         if ((p^.left^.resulttype^.deftype=grunddef) and
            (pgrunddef(p^.left^.resulttype)^.typ=bool8bit)) then
{            ((p^.right^.resulttype^.deftype=grunddef) and
            (pgrunddef(p^.right^.resulttype)^.typ=bool8bit)) then }
           begin
              if (p^.treetype=andn) or (p^.treetype=orn) then
                begin
                   p^.location.loc:=LOC_JUMP;
                   cmpop:=false;
                   case p^.treetype of
                     andn : begin
                               otl:=truelabel;
                               truelabel:=getlabel;
                               secondpass(p^.left);
                               maketojumpbool(p^.left);
                               emitl(A_LABEL,truelabel);
                               truelabel:=otl;
                            end;
                     orn : begin
                              ofl:=falselabel;
                              falselabel:=getlabel;
                              secondpass(p^.left);
                              maketojumpbool(p^.left);
                              emitl(A_LABEL,falselabel);
                              falselabel:=ofl;
                           end;
                     else error(type_mismatch);
                   end;
                  secondpass(p^.right);
                  maketojumpbool(p^.right);
                end
{              else if (p^.treetype=unequaln) or (p^.treetype=equaln) then
                begin
                   opsize:=S_B;
                   if p^.left^.treetype=boolconstn then
                     begin
                        swapp:=p^.right;
                        p^.right:=p^.left;
                        p^.left:=swapp;
                        p^.swaped:=not(p^.swaped);
                     end;
                   secondpass(p^.left);
                   p^.location:=p^.left^.location;
                   (* sind zuwenig Register frei? *)
                   pushed:=maybe_push(p^.right^.registers32,p);
                   secondpass(p^.right);
                   if pushed then restore(p);
                   goto do_normal;
                end }
              else error(type_mismatch);
           end
         { Stringooperationen auch seperat behandeln }
         else if (p^.left^.resulttype^.deftype=stringdef) then
           begin
              { String-Operationen sind nicht kommutativ }
              if p^.swaped then
                begin
                   swapp:=p^.left;
                   p^.left:=p^.right;
                   p^.right:=swapp;
                   { wegen der Sprungerzeugung bei Vergleichen unten: }
                   p^.swaped:=not(p^.swaped);
                end;
              case p^.treetype of
                 addn : begin
                           cmpop:=false;
                           secondpass(p^.left);
                           if (p^.left^.treetype<>addn) then
                             begin
                                { kann nur Referenz sein }
                                { String in Register wäre komisch }
                                { also einen temporären String erzeugen }

                                del_referenz(p^.left^.location.referenz);
                                pushusedregisters(pushedregs,$ff);
                                clear_referenz(href);
                                href.offset:=gettempofsize(256);
                                href.base:=R_EBP;
                                emitpushreferenzaddr(href);
                                emitpushreferenzaddr(p^.left^.location.referenz);
                                emit(PUSH,S_L,'$255');
                                emit(CALL,S_NO,'STRCOPY');
                                maybe_loadesi;
                                popusedregisters(pushedregs);

                                { schadet nicht: }
                                p^.left^.location.loc:=LOC_MEM;
                                p^.left^.location.referenz:=href;
                             end;
                           secondpass(p^.right);
                           { Rechts brauchen wir die Register auch nicht mehr }
                           del_referenz(p^.right^.location.referenz);
                           pushusedregisters(pushedregs,$ff);
                           emitpushreferenzaddr(p^.left^.location.referenz);
                           emitpushreferenzaddr(p^.right^.location.referenz);
                           emit(CALL,S_NO,'STRCONCAT');
                           p^.location:=p^.left^.location;
                           maybe_loadesi;
                           popusedregisters(pushedregs);
                        end;
              ltn,lten,gtn,gten,
                equaln,unequaln :
                        begin
                           secondpass(p^.left);
                           { sind zuwenig Register frei? }
                           pushed:=maybe_push(p^.right^.registers32,p);
                           secondpass(p^.right);
                           if pushed then restore(p);
                           cmpop:=true;
                           del_referenz(p^.right^.location.referenz);
                           del_referenz(p^.left^.location.referenz);
                           pushusedregisters(pushedregs,$ff);
                           emitpushreferenzaddr(p^.left^.location.referenz);
                           emitpushreferenzaddr(p^.right^.location.referenz);
                           emit(CALL,S_NO,'STRCMP');
                           maybe_loadesi;
                           popusedregisters(pushedregs);
                        end;
                else error(type_mismatch);
              end;
           end
         else
           begin
              { falls eine Konstante dabei, so kommt diese nach rechts }
              if p^.left^.treetype=ordconstn then
                begin
                   swapp:=p^.right;
                   p^.right:=p^.left;
                   p^.left:=swapp;
                   p^.swaped:=not(p^.swaped);
                end;
              secondpass(p^.left);
              p^.location:=p^.left^.location;
              { sind zuwenig Register frei? }
              pushed:=maybe_push(p^.right^.registers32,p);
              secondpass(p^.right);
              if pushed then restore(p);
              if (p^.left^.resulttype^.deftype=pointerdef) or
                 (p^.right^.resulttype^.deftype=pointerdef) or
                 (p^.left^.resulttype^.deftype=procvardef) or
                 (p^.left^.resulttype^.deftype=aufzaehldef) or
                 ((p^.left^.resulttype^.deftype=grunddef) and
                 (pgrunddef(p^.left^.resulttype)^.typ=s32bit)) or
                 ((p^.right^.resulttype^.deftype=grunddef) and
                 (pgrunddef(p^.right^.resulttype)^.typ=s32bit)) then
                begin
{           do_normal: }
                   mboverflow:=false;
                   cmpop:=false;
                   if (p^.left^.resulttype^.deftype=pointerdef) or
                      (p^.right^.resulttype^.deftype=pointerdef) then
                     unsigned:=true;
                   case p^.treetype of
                      addn : begin
                                op:=ADD;
                                mboverflow:=true;
                             end;
                      muln : begin
                                op:=IMUL;
                                mboverflow:=true;
                             end;
                      subn : begin
                                op:=SUB;
                                mboverflow:=true;
                             end;
                      ltn,lten,gtn,gten,
                      equaln,unequaln :
                             begin
                                op:=CMP;
                                cmpop:=true;
                             end;
                      xorn : op:=A_XOR;
                      orn : op:=A_OR;
                      andn : op:=A_AND;
                      slashn : begin
                                  op:=SUB;
                                  error(use_int_div_int_op);
                               end;
                      else error(type_mismatch);
                   end;
                   { links und rechts kein Register ? }
                   { dann muß eins angefordert werden }
                   if (p^.location.loc<>LOC_REGISTER) and
                     (p^.right^.location.loc<>LOC_REGISTER) then
                     begin
                        { Registervariable ? }
                        if (p^.location.loc=LOC_CREGISTER) then
                          begin
                             if cmpop then
                               begin
                                  { zerstört das Register nicht }
                                  hregister:=p^.location.register;
                               end
                             else
                               begin
                                  case opsize of
                                     S_L : hregister:=getregister32;
                                     S_B : hregister:=reg32toreg8(getregister32);
                                  end;
                                  emit_reg_reg(MOV,opsize,p^.location.register,
                                    hregister);
                               end

                          end
                        else
                          begin
                             del_referenz(p^.location.referenz);

                             { erst freigeben, dann neues Register anfordern }
                             case opsize of
                                S_L : hregister:=getregister32;
                                S_B : hregister:=reg32toreg8(getregister32);
                             end;
                             emit(MOV,opsize,getreferenzstring(p^.location.referenz)+','
                               +regid2str[hregister]);
                          end;
                        p^.location.loc:=LOC_REGISTER;
                        p^.location.register:=hregister;

                     end
                   else
                     { wenn rechts das Register, dann vertauschen }
                     if (p^.right^.location.loc=LOC_REGISTER) then
                       begin
                          swapl:=p^.location;
                          p^.location:=p^.right^.location;
                          p^.right^.location:=swapl;

                          { erneut vertauscht, also swaped-Flag neu setzten }
                          p^.swaped:=not(p^.swaped);
                       end;
                   if p^.right^.location.loc<>LOC_REGISTER then
                     begin
                        if (p^.treetype=subn) and p^.swaped then
                          begin
                             if p^.right^.location.loc=LOC_CREGISTER then
                               begin
                                  emit_reg_reg(MOV,opsize,p^.right^.location.register,R_EDI);
                                  emit_reg_reg(SUB,opsize,p^.location.register,R_EDI);
                                  emit_reg_reg(MOV,opsize,R_EDI,p^.location.register);
                               end
                             else
                               begin
                                  emit(MOV,opsize,getreferenzstring(p^.right^.location.referenz)+',%edi');
                                  emit(SUB,opsize,regid2str[p^.location.register]+',%edi');
                                  emit(MOV,opsize,'%edi,'+regid2str[p^.location.register]);
                                  del_referenz(p^.right^.location.referenz);
                               end;
                          end
                        else
                          begin
                             if (p^.right^.treetype=ordconstn) and
                                (op=CMP) and
                                (p^.right^.value=0) then
                               begin
                                  emit(A_TEST,opsize,
                                    regid2str[p^.location.register]+','
                                    +regid2str[p^.location.register]);
                               end
                             else if (p^.right^.treetype=ordconstn) and
                                (op=ADD) and
                                (p^.right^.value=1) then
                               begin
                                  emit(A_INC,opsize,
                                    regid2str[p^.location.register]);
                               end
                             else if (p^.right^.treetype=ordconstn) and
                                (op=SUB) and
                                (p^.right^.value=1) then
                               begin
                                  emit(A_DEC,opsize,
                                    regid2str[p^.location.register]);
                               end
                             else if (p^.right^.treetype=ordconstn) and
                                (op=IMUL) and
                                (ispowerof2(p^.right^.value,power)) then
                               begin
                                  emit(A_SHL,opsize,'$'+tostr(power)+','+
                                    +regid2str[p^.location.register]);
                               end
                             else
                               begin
                                  if (p^.right^.location.loc=LOC_CREGISTER) then
                                    begin
                                       emit_reg_reg(op,opsize,p^.right^.location.register,
                                         p^.location.register);
                                    end
                                  else
                                    begin
                                       emit(op,opsize,getreferenzstring(
                                         p^.right^.location.referenz)+','
                                         +regid2str[p^.location.register]);
                                       del_referenz(p^.right^.location.referenz);
                                    end;
                               end;
                          end;
                     end
                   else
                     begin
                        { wenn vertauscht, anderes Ergebnis-Register }
                        if (p^.treetype=subn) and p^.swaped then
                          begin
                             emit(SUB,opsize,
                               regid2str[p^.location.register]+','+
                               regid2str[p^.right^.location.register]);

                               swapl:=p^.location;
                               p^.location:=p^.right^.location;
                               p^.right^.location:=swapl;

                               { erneut vertauscht, also swaped-Flag }
                               { neu setzten (nur der Ordnung halber) }
                               p^.swaped:=not(p^.swaped);
                          end
                        else
                          begin
                             emit(op,opsize,
                               regid2str[p^.right^.location.register]+','
                               +regid2str[p^.location.register]);
                          end;
                        case opsize of
                           S_L : ungetregister32(p^.right^.location.register);
                           S_B : ungetregister32(reg8toreg32(p^.right^.location.register));
                        end;
                     end;

                   if cmpop then
                     case opsize of
                        S_L : ungetregister32(p^.location.register);
                        S_B : ungetregister32(reg8toreg32(p^.location.register));
                     end;

                   { Nur wenn Overflow verdächtige Operation }
                   { Overflow-Code erzeugen }
                   if mboverflow then
                     emitoverflowcheck;
                end
              else if ((p^.left^.resulttype^.deftype=grunddef) and
                 (pgrunddef(p^.left^.resulttype)^.typ=uchar)) then
                begin
                   case p^.treetype of
                      ltn,lten,gtn,gten,
                      equaln,unequaln :
                                cmpop:=true;
                      else error(type_mismatch);
                   end;
                   unsigned:=true;
                   { links und rechts kein Register ? }
                   { dann muß eins angefordert werden }
                   if (p^.location.loc<>LOC_REGISTER) and
                     (p^.right^.location.loc<>LOC_REGISTER) then
                     begin
                        if p^.location.loc=LOC_CREGISTER then
                          begin
                             if cmpop then
                               { zerstört kein Register }
                               hregister:=p^.location.register
                             else
                               begin
                                  hregister:=reg32toreg8(getregister32);
                                  emit_reg_reg(MOV,S_B,p^.location.register,
                                    hregister);
                               end;
                          end
                        else
                          begin
                             del_referenz(p^.location.referenz);

                             { erst freigeben, dann neues Register anfordern }
                             hregister:=reg32toreg8(getregister32);
                             emit(MOV,S_B,getreferenzstring(p^.location.referenz)+','
                               +regid2str[hregister]);
                          end;
                        p^.location.loc:=LOC_REGISTER;
                        p^.location.register:=hregister;
                     end;

                   { nun p nun auf jeden Fall Register }
                   if (p^.right^.location.loc=LOC_REGISTER) and
                      (p^.location.loc<>LOC_REGISTER) then
                     begin
                        swapl:=p^.location;
                        p^.location:=p^.right^.location;
                        p^.right^.location:=swapl;

                        { erneut vertauscht, also swaped-Flag neu setzten }
                        p^.swaped:=not(p^.swaped);
                     end;
                   if p^.right^.location.loc<>LOC_REGISTER then
                     begin
                        if p^.right^.location.loc=LOC_CREGISTER then
                          begin
                             emit_reg_reg(CMP,S_B,
                                p^.right^.location.register,p^.location.register);
                          end
                        else
                          begin
                             emit(CMP,S_B,getreferenzstring(
                                p^.right^.location.referenz)+','
                                +regid2str[p^.location.register]);
                             del_referenz(p^.right^.location.referenz);
                          end;
                     end
                   else
                     begin
                        emit_reg_reg(CMP,S_L,p^.right^.location.register,
                          p^.location.register);
                        ungetregister32(reg8toreg32(p^.right^.location.register));
                     end;
                   ungetregister32(reg8toreg32(p^.location.register));
                end
              else if ((p^.left^.resulttype^.deftype=grunddef) and
                  (pgrunddef(p^.left^.resulttype)^.typ=s64real)) then
                 begin
                    { Realkonstante nach rechts }
                    if p^.left^.treetype=realconstn then
                      begin
                         swapp:=p^.right;
                         p^.right:=p^.left;
                         p^.left:=swapp;
                         p^.swaped:=not(p^.swaped);
                      end;
                    cmpop:=false;
                    case p^.treetype of
                       addn : op:=FADDP;
                       muln : op:=FMULP;
                       subn : op:=FSUBP;
                       slashn : op:=FDIVP;
                       ltn,lten,gtn,gten,
                       equaln,unequaln : begin
                                            op:=FCOMPP;
                                            cmpop:=true;
                                         end;
                       else error(type_mismatch);
                    end;
                    { links nicht auf dem Stack, dann laden }
                    if (p^.left^.location.loc<>LOC_FPUSTACK) then
                      emit(FLD,S_L,getreferenzstring(p^.left^.location.referenz));
                    if (p^.right^.location.loc<>LOC_FPUSTACK) then
                      emit(FLD,S_L,getreferenzstring(p^.right^.location.referenz));
                    if p^.swaped then
                      begin
                         if (p^.treetype=slashn) then
                           op:=FDIVRP;
                         if (p^.treetype=subn) then
                           op:=FSUBRP;
                      end;
                    {
                    if (op=FDIVP) and (opt_processors=pentium) then
                      emit(CALL,S_NO,'EMUL_FDIVP')
                    else
                    }
                    emit(op,S_NO,'');
                    { bei Vergleich Flags laden }
                    if cmpop then
                      begin
                         if not(R_EAX in unused) then
                           emit_reg_reg(MOV,S_L,R_EAX,R_EDI);
                         emit(FNSTS,S_W,'%ax');
                         emit(SAHF,S_NO,'');
                         if not(R_EAX in unused) then
                           emit_reg_reg(MOV,S_L,R_EDI,R_EAX);
                         if p^.swaped then
                           case p^.treetype of
                              equaln : flags:=F_E;
                              unequaln : flags:=F_NE;
                              ltn : flags:=F_B;
                              lten : flags:=F_AE;
                              gtn : flags:=F_B;
                              gten : flags:=F_AE;
                           end
                         else
                           case p^.treetype of
                              equaln : flags:=F_E;
                              unequaln : flags:=F_NE;
                              ltn : flags:=F_A;
                              lten : flags:=F_AE;
                              gtn : flags:=F_B;
                              gten : flags:=F_BE;
                           end;
                         p^.location.loc:=LOC_FLAGS;
                         p^.location.resflags:=flags;
                         cmpop:=false;
                      end
                    else
                      p^.location.loc:=LOC_FPUSTACK;
                 end
              else if (p^.left^.resulttype^.deftype=setdef) then
                begin
                   { nicht kommutativ }
                   if p^.swaped then
                     begin
                        swapp:=p^.left;
                        p^.left:=p^.right;
                        p^.right:=swapp;
                        { wegen der Sprungerzeugung bei Vergleichen }
                        p^.swaped:=not(p^.swaped);
                     end;
                   case p^.treetype of
                      addn,subn,muln : begin
                                     cmpop:=false;
                                     del_referenz(p^.left^.location.referenz);
                                     del_referenz(p^.right^.location.referenz);
                                     clear_referenz(href);
                                     href.offset:=gettempofsize(32);
                                     href.base:=R_EBP;
                                     emitpushreferenzaddr(href);
                                     pushusedregisters(pushedregs,$ff);
                                     emitpushreferenzaddr(p^.right^.location.referenz);
                                     emitpushreferenzaddr(p^.left^.location.referenz);
                                     case p^.treetype of
                                       subn : emit(CALL,S_NO,'SET_SUB_SETS');
                                       addn : emit(CALL,S_NO,'SET_ADD_SETS');
                                       muln : emit(CALL,S_NO,'SET_MUL_SETS');
                                     end;
                                     maybe_loadesi;
                                     popusedregisters(pushedregs);
                                     p^.location.loc:=LOC_MEM;
                                     p^.location.referenz:=href;
                                  end;
                      else error(type_mismatch);
                   end;
                end
              else error(type_mismatch);
           end;
         { Sollte es ein Vergleichsoperator sein, dann Ergebnis in den Flags }
         if cmpop then
           begin
              if not(unsigned) then
                begin
                   if p^.swaped then
                     case p^.treetype of
                        equaln : flags:=F_E;
                        unequaln : flags:=F_NE;
                        ltn : flags:=F_G;
                        lten : flags:=F_GE;
                        gtn : flags:=F_L;
                        gten : flags:=F_LE;
                     end
                   else
                     case p^.treetype of
                        equaln : flags:=F_E;
                        unequaln : flags:=F_NE;
                        ltn : flags:=F_L;
                        lten : flags:=F_LE;
                        gtn : flags:=F_G;
                        gten : flags:=F_GE;
                     end;
                end
              else
                begin
                   if p^.swaped then
                     case p^.treetype of
                        equaln : flags:=F_E;
                        unequaln : flags:=F_NE;
                        ltn : flags:=F_A;
                        lten : flags:=F_AE;
                        gtn : flags:=F_B;
                        gten : flags:=F_BE;
                     end
                   else
                     case p^.treetype of
                        equaln : flags:=F_E;
                        unequaln : flags:=F_NE;
                        ltn : flags:=F_B;
                        lten : flags:=F_BE;
                        gtn : flags:=F_A;
                        gten : flags:=F_AE;
                     end;
                end;
              p^.location.loc:=LOC_FLAGS;
              p^.location.resflags:=flags;
           end;
      end;

    procedure secondmoddiv(var p : ptree);far;

      var
         hreg1 : tregister;
         pushed,popeax,popedx : boolean;
         power,hl : longint;

      begin
         secondpass(p^.left);
         p^.location:=p^.left^.location;
         pushed:=maybe_push(p^.right^.registers32,p);
         secondpass(p^.right);
         if pushed then restore(p);

         { Zaehler in Register bringen }
         if p^.left^.location.loc<>LOC_REGISTER then
           begin
              if p^.left^.location.loc=LOC_CREGISTER then
                begin
                  hreg1:=getregister32;
                  emit_reg_reg(MOV,S_L,p^.left^.location.register,hreg1);
                end
              else
                begin
                  del_referenz(p^.left^.location.referenz);
                  hreg1:=getregister32;
                  emit(MOV,S_L,getreferenzstring(p^.left^.location.referenz)+','+
                    regid2str[hreg1]);
                end;
              p^.left^.location.loc:=LOC_REGISTER;
              p^.left^.location.register:=hreg1;
           end
         else hreg1:=p^.left^.location.register;

         if (p^.treetype=divn) and (p^.right^.treetype=ordconstn) and
            ispowerof2(p^.right^.value,power) then
           begin
              emit(A_OR,S_L,regid2str[hreg1]+','+
                regid2str[hreg1]);
              hl:=getlabel;
              emitl(JNS,hl);
              if power=1 then
                emit(A_INC,S_L,regid2str[hreg1])
              else emit(ADD,S_L,'$'+tostr(p^.right^.value-1)+','+regid2str[hreg1]);
              emitl(A_LABEL,hl);
              emit(SAR,S_L,'$'+tostr(power)+','+regid2str[hreg1]);
           end
         else
           begin
              { Nenner nach EDI bringen }
              if (p^.right^.location.loc<>LOC_REGISTER) and
                 (p^.right^.location.loc<>LOC_CREGISTER) then
                begin
                   del_referenz(p^.right^.location.referenz);
                   p^.left^.location.loc:=LOC_REGISTER;
                   emit(MOV,S_L,getreferenzstring(p^.right^.location.referenz)+',%edi');
                end
              else
                begin
                   ungetregister32(p^.right^.location.register);
                   emit_reg_reg(MOV,S_L,p^.right^.location.register,R_EDI);
                end;
              popedx:=false;
              popeax:=false;
              if hreg1=R_EDX then
                begin
                   if not(R_EAX in unused) then
                     begin
                        emit(PUSH,S_L,'%eax');
                        popeax:=true;
                     end;
                   emit_reg_reg(MOV,S_L,R_EDX,R_EAX);
                end
              else
                begin
                   if not(R_EDX in unused) then
                     begin
                        emit(PUSH,S_L,'%edx');
                        popedx:=true;
                     end;
                   if hreg1<>R_EAX then
                     begin
                        if not(R_EAX in unused) then
                          begin
                             emit(PUSH,S_L,'%eax');
                             popeax:=true;
                          end;
                        emit_reg_reg(MOV,S_L,hreg1,R_EAX);
                     end;
                end;
              emit(CLTD,S_NO,'');
              emit(IDIV,S_L,'%edi');
              if p^.treetype=divn then
                begin
                   { wenn das Ergebnisregister belegt ist, dann umkopieren }
                   if popeax then
                     begin
                        if hreg1=R_EAX then
                          internalerror(112);
                        emit_reg_reg(MOV,S_L,R_EAX,hreg1)
                     end
                   else
                     if hreg1<>R_EAX then
                       emit_reg_reg(MOV,S_L,R_EAX,hreg1);
                end
              else
                begin
                   if popedx then
                     begin
                        if hreg1=R_EDX then
                          internalerror(112);
                        emit_reg_reg(MOV,S_L,R_EDX,hreg1)
                     end
                   else
                     if hreg1<>R_EDX then
                       emit_reg_reg(MOV,S_L,R_EDX,hreg1);
                end;
              if popeax then
                emit(POP,S_L,'%eax');
              if popedx then
                emit(POP,S_L,'%edx');
           end;
         p^.location.loc:=LOC_REGISTER;
         p^.location.register:=hreg1;
      end;

    procedure secondshlshr(var p : ptree);far;

      var
         hregister1,hregister2,hregister3 : tregister;
         pushed,popecx : boolean;
         op : tasmop;

      begin
         popecx:=false;

         secondpass(p^.left);
         pushed:=maybe_push(p^.right^.registers32,p);
         secondpass(p^.right);
         if pushed then restore(p);

         { linken Operanden in ein Register laden }
         if p^.left^.location.loc<>LOC_REGISTER then
           begin
              if p^.left^.location.loc=LOC_CREGISTER then
                begin
                   hregister1:=getregister32;
                   emit_reg_reg(MOV,S_L,p^.left^.location.register,
                     hregister1);
                end
              else
                begin
                   del_referenz(p^.left^.location.referenz);
                   hregister1:=getregister32;
                   emit(MOV,S_L,getreferenzstring(p^.left^.location.referenz)+
                     ','+regid2str[hregister1]);
                end;
           end
         else hregister1:=p^.left^.location.register;

         { Operator feststellen }
         if p^.treetype=shln then
           op:=A_SHL
         else
           op:=A_SHR;

         { Verschiebung mit einer Konstante direkt auscodieren: }
         if (p^.right^.treetype=ordconstn) then
           begin
              emit(op,S_L,'$'+tostr(p^.right^.location.referenz.offset mod 32)
                +','+regid2str[hregister1]);
              p^.location.loc:=LOC_REGISTER;
              p^.location.register:=hregister1;
           end
         else
           begin
              { rechten Operanden in ein Register laden }
              if p^.right^.location.loc<>LOC_REGISTER then
                begin
                   if p^.right^.location.loc=LOC_CREGISTER then
                     begin
                        hregister2:=getregister32;
                        emit_reg_reg(MOV,S_L,p^.right^.location.register,
                          hregister2);
                     end
                   else
                     begin
                        del_referenz(p^.right^.location.referenz);
                        hregister2:=getregister32;
                        emit(MOV,S_L,getreferenzstring(p^.right^.location.referenz)+
                          ','+regid2str[hregister2]);
                     end;
                end
              else hregister2:=p^.right^.location.register;

              { linker Operand ist schon in einem Register }
              { also sind beide in einem Register }
              { handelt es sich dabei um ECX ? }
              if (hregister1=R_ECX) then
                begin
                   { dann nur vertauschen }
                   emit(XCHG,S_L,regid2str[hregister1]+','+
                     regid2str[hregister2]);

                   hregister3:=hregister1;
                   hregister1:=hregister2;
                   hregister2:=hregister3;
                end
              { wenn zweiter Operand nicht in ECX ? }
              else if (hregister2<>R_ECX) then
                begin
                   { ECX nicht belegt, dann mit rechtem Register austauschen }
                   if R_ECX in unused then
                     begin
                        emit_reg_reg(MOV,S_L,hregister2,R_ECX);
                        ungetregister32(hregister2);
                     end
                   else
                     begin
                        { ansonsten ECX retten und dann umkopieren }
                        popecx:=true;
                        emit(PUSH,S_L,'%ecx');
                        emit_reg_reg(MOV,S_L,hregister2,R_ECX);
                        ungetregister32(hregister2);
                     end;
                end;
              { rechter Operand ist in ECX }
              emit_reg_reg(op,S_L,R_CL,hregister1);
              { vielleicht ECX zurück }
              if popecx then
                emit(POP,S_L,'%ecx');
              p^.location.register:=hregister1;
           end;
      end;

    procedure secondrealconst(var p : ptree);far;

      begin
         clear_referenz(p^.location.referenz);
         if p^.labnumber=-1 then
           begin
              p^.labnumber:=getlabel;
              constsegment.insert(gennasmrec(A_DOUBLE,S_NO,double2str(p^.valued)));
              constsegment.insert(genlasmrec(A_LABEL,p^.labnumber));
           end;
         p^.location.referenz.symbol:=stringdup(tolabel(p^.labnumber));
      end;

    procedure secondordconst(var p : ptree);far;

      begin
         { eine Intconst. tut so, als ob sie eine Memoryreferenz wäre }
         p^.location.loc:=LOC_MEM;
         p^.location.referenz.isintvalue:=true;
         p^.location.referenz.offset:=p^.value;
      end;

    procedure secondniln(var p : ptree);far;

      begin
         p^.location.loc:=LOC_MEM;
         p^.location.referenz.isintvalue:=true;
         p^.location.referenz.offset:=0;
      end;

    procedure secondstringconst(var p : ptree);far;

      var
         l : longint;

      begin
         clear_referenz(p^.location.referenz);
         l:=getconstlabel;
         p^.location.referenz.symbol:=stringdup('L'+tostr(l));
         constsegment.concat(gennasmrec(DIRECT,S_NO,'L'+tostr(l)+':'));
         constsegment.concat(gennasmrec(ASCII,S_NO,'"'+ibm2ascii(char(length(p^.values^))+p^.values^)+'\0"'));
      end;

    procedure secondumminus(var p : ptree);far;

      begin
         secondpass(p^.left);
         p^.location.loc:=LOC_REGISTER;
         case p^.left^.location.loc of
            LOC_REGISTER : begin
                              p^.location.register:=p^.left^.location.register;
                              emit(NEG,S_L,regid2str[p^.location.register]);
                           end;
            LOC_CREGISTER : begin
                               p^.location.register:=getregister32;
                               emit_reg_reg(MOV,S_L,p^.location.register,
                                 p^.location.register);
                               emit(NEG,S_L,regid2str[p^.location.register]);
                            end;
            LOC_REFERENZ,LOC_MEM :
                           begin
                              del_referenz(p^.left^.location.referenz);
                              if pgrunddef(p^.left^.resulttype)^.typ=s64real then
                                begin
                                   p^.location.loc:=LOC_FPUSTACK;
                                   emit(FLD,S_NO,getreferenzstring(p^.left^.location.referenz));
                                   emit(FCHS,S_NO,'');
                                end
                              else
                                begin
                                   p^.location.register:=getregister32;
                                   emit(MOV,S_L,getreferenzstring(p^.left^.location.referenz)+
                                      ','+regid2str[p^.location.register]);
                                   emit(NEG,S_L,regid2str[p^.location.register]);
                                end;
                           end;
            LOC_FPUSTACK : begin
                              p^.location.loc:=LOC_FPUSTACK;
                              emit(FCHS,S_NO,'');
                           end;
         end;
         emitoverflowcheck;
      end;

    procedure secondaddr(var p : ptree);far;

      begin
         secondpass(p^.left);
         p^.location.loc:=LOC_REGISTER;
         del_referenz(p^.left^.location.referenz);
         p^.location.register:=getregister32;
         emit(LEA,S_L,getreferenzstring(p^.left^.location.referenz)+','+
           regid2str[p^.location.register]);
      end;

    procedure secondnot(var p : ptree);far;

      const
         flagsinvers : array[F_E..F_BE] of tresflags =
            (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
             F_A,F_AE,F_B,F_BE);

      var
         hl : longint;

      begin
         if (p^.resulttype^.deftype=grunddef) and
            (pgrunddef(p^.resulttype)^.typ=bool8bit) then
              begin
                 case p^.location.loc of
                    LOC_JUMP : begin
                                  hl:=truelabel;
                                  truelabel:=falselabel;
                                  falselabel:=hl;
                                  secondpass(p^.left);
                                  maketojumpbool(p^.left);
                                  hl:=truelabel;
                                  truelabel:=falselabel;
                                  falselabel:=hl;
                               end;
                    LOC_FLAGS : begin
                                   secondpass(p^.left);
                                   p^.location.resflags:=flagsinvers[p^.left^.location.resflags];
                                end;
                    LOC_REGISTER : begin
                                      secondpass(p^.left);
                                      p^.location.register:=p^.left^.location.register;
                                      emit(A_XOR,S_B,'$1,'+regid2str[p^.location.register]);
                                   end;
                    LOC_CREGISTER : begin
                                       secondpass(p^.left);
                                       p^.location.loc:=LOC_REGISTER;
                                       p^.location.register:=reg32toreg8(getregister32);
                                       emit_reg_reg(MOV,S_B,p^.left^.location.register,
                                         p^.location.register);
                                       emit(A_XOR,S_B,'$1,'+regid2str[p^.location.register]);
                                    end;
                    LOC_REFERENZ,LOC_MEM : begin
                                              secondpass(p^.left);
                                              del_referenz(p^.left^.location.referenz);
                                              p^.location.loc:=LOC_REGISTER;
                                              p^.location.register:=reg32toreg8(getregister32);
                                              emit(MOV,S_B,getreferenzstring(p^.left^.location.referenz)+
                                                ','+regid2str[p^.location.register]);
                                                emit(A_XOR,S_B,'$1,'+regid2str[p^.location.register]);
                                           end;
                 end;
              end
            else
              begin
                secondpass(p^.left);
                p^.location.loc:=LOC_REGISTER;
                case p^.left^.location.loc of
                   LOC_REGISTER : begin
                                     p^.location.register:=p^.left^.location.register;
                                     emit(A_NOT,S_L,regid2str[p^.location.register]);
                                  end;
                   LOC_CREGISTER : begin
                                     p^.location.register:=getregister32;
                                     emit_reg_reg(MOV,S_L,p^.left^.location.register,
                                       p^.location.register);
                                     emit(A_NOT,S_L,regid2str[p^.location.register]);
                                   end;
                   LOC_REFERENZ,LOC_MEM :
                                  begin
                                     del_referenz(p^.left^.location.referenz);
                                     p^.location.register:=getregister32;
                                     emit(MOV,S_L,getreferenzstring(p^.left^.location.referenz)+
                                       ','+regid2str[p^.location.register]);
                                     emit(A_NOT,S_L,regid2str[p^.location.register]);
                                  end;
                end;
             end;
      end;

    procedure secondnothing(var p : ptree);far;

      begin
      end;

    procedure secondassignment(var p : ptree);far;

      var
         opsize : topsize;
         pushed,withresult : boolean;
         otlabel,hlabel,oflabel : longint;
         lstr : string;
         hregister : tregister;

      begin
         otlabel:=truelabel;
         oflabel:=falselabel;
         truelabel:=getlabel;
         falselabel:=getlabel;
         withresult:=not(aktexprlevel<4);
         { linke Seite berechnen }
         secondpass(p^.left);
         case p^.left^.location.loc of
            LOC_REFERENZ : begin
                              { falls der linke Operand zwei Register benötigt, }
                              { aber zu wenige frei sind, dann LEA }
                              if (p^.left^.location.referenz.base<>R_NO) and
                                 (p^.left^.location.referenz.index<>R_NO) and
                                 (usablereg32<p^.right^.registers32) then
                                begin
                                   del_referenz(p^.left^.location.referenz);
                                   hregister:=getregister32;
                                   emit(LEA,S_L,getreferenzstring(
                                     p^.left^.location.referenz)+','+
                                     regid2str[hregister]);
                                   p^.left^.location.referenz.base:=hregister;
                                   p^.left^.location.referenz.index:=R_NO;
                                end;
                              lstr:=getreferenzstring(p^.left^.location.referenz);
                           end;
            LOC_CREGISTER : lstr:=regid2str[p^.left^.location.register];
            else
               begin
                  error(error_in_expression);
                  exit;
               end;
         end;
         secondpass(p^.right);
         if p^.right^.resulttype^.deftype=stringdef then
           begin
              { das Ziel brauchen wir sicher nicht mehr }
              del_referenz(p^.left^.location.referenz);
              { die Quelle nur, wenn withresult gesetzt: }
              if not(withresult) then
                del_referenz(p^.right^.location.referenz);
              copystring(p^.left^.location.referenz,p^.right^.location.referenz,
                min(pstringdef(p^.right^.resulttype)^.len,pstringdef(p^.left^.resulttype)^.len));
           end
         else case p^.right^.location.loc of
            LOC_REFERENZ,
            LOC_MEM : begin
                         { ordinale Konstanten getrennt bearbeiten }
                         if (p^.right^.treetype=ordconstn) or
                            (p^.left^.location.loc=LOC_CREGISTER) then
                           begin
                              case p^.left^.resulttype^.size of
                                 1 : opsize:=S_B;
                                 2 : opsize:=S_W;
                                 4 : opsize:=S_L;
                              end;
                              emit(MOV,opsize,
                                getreferenzstring(p^.right^.location.referenz)+','+
                                   lstr);
                           end
                         else
                           begin
                              concatcopy(p^.right^.location.referenz,
                                p^.left^.location.referenz,p^.left^.resulttype^.size,
                              withresult);
                           end;
                      end;
            LOC_REGISTER,
            LOC_CREGISTER : begin
                              case p^.right^.resulttype^.size of
                                 1 : opsize:=S_B;
                                 2 : opsize:=S_W;
                                 4 : opsize:=S_L;
                              end;
                              emit(MOV,opsize,
                                regid2str[p^.right^.location.register]+','+
                                lstr);
                           end;
            LOC_FPUSTACK : emit(FSTP,S_L,lstr);
            LOC_JUMP     : begin
                              hlabel:=getlabel;
                              emitl(A_LABEL,truelabel);
                              emit(MOV,S_B,'$1,'+lstr);
                              emitl(JMP,hlabel);
                              emitl(A_LABEL,falselabel);
                              emit(MOV,S_B,'$0,'+lstr);
                              emitl(A_LABEL,hlabel);
                           end;
            LOC_FLAGS    : emit(flag_2_set[p^.right^.location.resflags],S_NO,lstr);
         end;
         truelabel:=otlabel;
         falselabel:=oflabel;
      end;

    procedure secondderef(var p : ptree);far;

      var
         hr : tregister;

      begin
         secondpass(p^.left);
         clear_referenz(p^.location.referenz);
         case p^.left^.location.loc of
            LOC_REGISTER : p^.location.referenz.base:=p^.left^.location.register;
            LOC_CREGISTER : begin
                               { ...und eines für den Pointer reservieren }
                               hr:=getregister32;
                               emit_reg_reg(MOV,S_L,p^.left^.location.register,hr);
                               p^.location.referenz.base:=hr;
                            end;
            else
              begin
                 { Register freigeben }
                 del_referenz(p^.left^.location.referenz);

                 { ...und eines für den Pointer reservieren }
                 hr:=getregister32;
                 emit(
                 MOV,S_L,getreferenzstring(p^.left^.location.referenz)+','+
                   regid2str[hr]);
                 p^.location.referenz.base:=hr;
              end;
         end;
      end;

    procedure secondvecn(var p : ptree);far;

      var
         pushed : boolean;
         ind : tregister;
         _p : ptree;

      procedure calc_emit_mul;

        var
           l1,l2 : longint;

        begin
           l1:=p^.resulttype^.size;
           case l1 of
              1,2,4,8 : p^.location.referenz.scalefactor:=l1;
           else
                begin
                   if ispowerof2(l1,l2) then
                     emit(A_SHL,S_L,'$'+tostr(l2)+','+regid2str[ind])
                   else
                     emit(IMUL,S_L,'$'+tostr(l1)+','+regid2str[ind]);
                end;
           end;
        end;

      var
         extraoffset : longint;
         t : ptree;

      begin
         secondpass(p^.left);
         p^.location:=p^.left^.location;

         { Offset kann nur ungleich 0 sein, wenn arraydef }
         if p^.left^.resulttype^.deftype=arraydef then
           dec(p^.location.referenz.offset,
             p^.resulttype^.size*
             parraydef(p^.left^.resulttype)^.lowrange);
         if p^.right^.treetype=ordconstn then
           begin

              { Offset kann nur ungleich 0, wenn arraydef }
              if p^.left^.resulttype^.deftype=arraydef then
                begin
                   if (p^.right^.value>parraydef(p^.left^.resulttype)^.highrange) or
                      (p^.right^.value<parraydef(p^.left^.resulttype)^.lowrange) then
                     error(range_check_error);

                   dec(p^.left^.location.referenz.offset,
                      p^.resulttype^.size*parraydef(p^.left^.resulttype)^.lowrange);
                end;
              inc(p^.left^.location.referenz.offset,
                 p^.right^.value*p^.resulttype^.size);
              p^.left^.resulttype:=p^.resulttype;
              disposetree(p^.right);
              _p:=p^.left;
              putnode(p);
              p:=_p;
           end
         else
           begin
              { quick hack, to overcome Delphi 2 }
              if (cs_maxoptimieren in aktswitches) and (p^.right^.resulttype^.deftype=arraydef) then
                begin
                   extraoffset:=0;
                   if (p^.right^.treetype=addn) then
                     begin
                        if p^.right^.right^.treetype=ordconstn then
                          begin
                             extraoffset:=p^.right^.right^.value;
                             t:=p^.right^.left;
                             putnode(p^.right);
                             putnode(p^.right^.right);
                             p^.right:=t
                          end
                        else if p^.right^.left^.treetype=ordconstn then
                          begin
                             extraoffset:=p^.right^.left^.value;
                             t:=p^.right^.right;
                             putnode(p^.right);
                             putnode(p^.right^.left);
                             p^.right:=t
                          end;
                     end
                   else if (p^.right^.treetype=subn) then
                     begin
                        if p^.right^.right^.treetype=ordconstn then
                          begin
                             extraoffset:=p^.right^.right^.value;
                             t:=p^.right^.left;
                             putnode(p^.right);
                             putnode(p^.right^.right);
                             p^.right:=t
                          end
                        else if p^.right^.left^.treetype=ordconstn then
                          begin
                             extraoffset:=p^.right^.left^.value;
                             t:=p^.right^.right;
                             putnode(p^.right);
                             putnode(p^.right^.left);
                             p^.right:=t
                          end;
                     end;
                   inc(p^.location.referenz.offset,
                    p^.resulttype^.size*extraoffset);
                end;
              { von links nach rechts rechnen }
              if (p^.location.loc<>LOC_REFERENZ) and
                 (p^.location.loc<>LOC_MEM) then
                error(error_in_expression);
              pushed:=maybe_push(p^.right^.registers32,p);
              secondpass(p^.right);
              if pushed then restore(p);
              case p^.right^.location.loc of
                LOC_REGISTER : ind:=p^.right^.location.register;
                LOC_CREGISTER : begin
                                   ind:=getregister32;
                                   emit_reg_reg(MOV,S_L,p^.right^.location.register,ind);
                                end;
                else
                   begin
                      del_referenz(p^.right^.location.referenz);
                      ind:=getregister32;
                      emit(MOV,S_L,getreferenzstring(p^.right^.location.referenz)+
                         ','+regid2str[ind]);
                   end;
              end;
              { moeglichen Rangecheckcode erzeugen: }
              if cs_rangechecking in aktswitches  then
                begin
                   if p^.left^.resulttype^.deftype=arraydef then
                     begin
                        parraydef(p^.left^.resulttype)^.genrangecheck;
                        emit(A_BOUND,S_L,regid2str[ind]+
                          ',R_'+tostr(parraydef(p^.left^.resulttype)^.rangenr));
                     end;
                end;
              if p^.location.referenz.index=R_NO then
                begin
                   p^.location.referenz.index:=ind;
                   calc_emit_mul;
                end
              else
                begin
                   if p^.location.referenz.base=R_NO then
                     begin
                        calc_emit_mul;
                        p^.location.referenz.base:=p^.location.referenz.index;
                        p^.location.referenz.index:=ind;
                     end
                   else
                     begin
                        emit(
                           LEA,S_L,getreferenzstring(p^.location.referenz)+','+
                             regid2str[p^.location.referenz.index]);
                        ungetregister32(p^.location.referenz.base);
                        stringdispose(p^.location.referenz.symbol);
                        p^.location.referenz.offset:=0;
                        calc_emit_mul;
                        p^.location.referenz.base:=p^.location.referenz.index;
                        p^.location.referenz.index:=ind;
                     end;
                end;
           end;
      end;

    { *************** Typekonvertierungen **************** }

    { erzeugt, falls noetig Rangecheckcode }

    procedure maybe_rangechecking(p : ptree;p2,p1 : pdef);

      var
         hregister : tregister;

      begin
         if (cs_rangechecking in aktswitches)  and
           ((pgrunddef(p1)^.von>pgrunddef(p2)^.von) or
           (pgrunddef(p1)^.bis<pgrunddef(p2)^.bis)) then
           begin
              pgrunddef(p1)^.genrangecheck;
              if pgrunddef(p1)^.typ=u8bit then
                begin
                   if (p^.location.loc=LOC_REGISTER) or
                      (p^.location.loc=LOC_CREGISTER) then
                     emit(MOVZX,S_BL,regid2str[p^.location.register]+',%edi')
                   else
                     emit(MOVZX,S_BL,getreferenzstring(p^.location.referenz)+',%edi');
                   hregister:=R_EDI;
                end
              else if pgrunddef(p1)^.typ=s8bit then
                begin
                   if (p^.location.loc=LOC_REGISTER) or
                      (p^.location.loc=LOC_CREGISTER) then
                     emit(MOVSX,S_BL,regid2str[p^.location.register]+',%edi')
                   else
                     emit(MOVSX,S_BL,getreferenzstring(p^.location.referenz)+',%edi');
                   hregister:=R_EDI;
                end
              else if pgrunddef(p1)^.typ=s32bit then
                begin
                   if (p^.location.loc=LOC_REGISTER) or
                      (p^.location.loc=LOC_CREGISTER) then
                     hregister:=p^.location.register
                   else
                     begin
                        emit(MOV,S_L,getreferenzstring(p^.location.referenz)+',%edi');
                        hregister:=R_EDI;
                     end;
                end
              else if pgrunddef(p1)^.typ=u16bit then
                begin
                   if (p^.location.loc=LOC_REGISTER) or
                      (p^.location.loc=LOC_CREGISTER) then
                     emit(MOVZX,S_WL,regid2str[p^.location.register]+',%edi')
                   else
                     emit(MOVZX,S_WL,getreferenzstring(p^.location.referenz)+',%edi');
                   hregister:=R_EDI;
                end
              else if pgrunddef(p1)^.typ=s16bit then
                begin
                   if (p^.location.loc=LOC_REGISTER) or
                      (p^.location.loc=LOC_CREGISTER) then
                     emit(MOVSX,S_WL,regid2str[p^.location.register]+',%edi')
                   else
                     emit(MOVSX,S_WL,getreferenzstring(p^.location.referenz)+',%edi');
                   hregister:=R_EDI;
                end
              else internalerror(6);
              emit(A_BOUND,S_L,regid2str[hregister]+',R_'+tostr(pgrunddef(p1)^.rangenr))
           end;
      end;

    type
       tsecondconvproc = procedure(p,hp : ptree;convtyp : tconverttype);

    procedure second_only_rangecheck(p,hp : ptree;convtyp : tconverttype);far;

      begin
         maybe_rangechecking(p,hp^.resulttype,p^.resulttype);
      end;

    procedure second_bigger(p,hp : ptree;convtyp : tconverttype);far;

      var
         hregister : tregister;
         opsize : topsize;
         op : tasmop;
         is_register : boolean;

      begin
         is_register:=p^.left^.location.loc=LOC_REGISTER;
         if not(is_register) and (p^.left^.location.loc<>LOC_CREGISTER) then
           del_referenz(p^.left^.location.referenz);
         case convtyp of
            tc_u8bit_2_s32bit :
              begin
                 if is_register then
                   hregister:=reg8toreg32(p^.left^.location.register)
                 else hregister:=getregister32;
                 op:=MOVZX;
                 opsize:=S_BL;
              end;
            tc_s8bit_2_s32bit :
              begin
                 if is_register then
                   hregister:=reg8toreg32(p^.left^.location.register)
                 else hregister:=getregister32;
                 op:=MOVSX;
                 opsize:=S_BL;
              end;
            tc_u16bit_2_s32bit :
              begin
                 if is_register then
                   hregister:=reg16toreg32(p^.left^.location.register)
                 else hregister:=getregister32;
                 op:=MOVZX;
                 opsize:=S_WL;
              end;
            tc_s16bit_2_s32bit :
              begin
                 if is_register then
                   hregister:=reg16toreg32(p^.left^.location.register)
                 else hregister:=getregister32;
                 op:=MOVSX;
                 opsize:=S_WL;
              end;
            tc_s8bit_2_u16bit,
            tc_u8bit_2_s16bit,
            tc_u8bit_2_u16bit :
              begin
                 if is_register then
                   hregister:=reg8toreg16(p^.left^.location.register)
                 else hregister:=reg32toreg16(getregister32);
                 op:=MOVZX;
                 opsize:=S_BW;
              end;
            tc_s8bit_2_s16bit :
              begin
                 if is_register then
                   hregister:=reg8toreg16(p^.left^.location.register)
                 else hregister:=reg32toreg16(getregister32);
                 op:=MOVSX;
                 opsize:=S_BW;
              end;
         end;
         if is_register then
           begin
              emit_reg_reg(op,opsize,p^.left^.location.register,hregister);
           end
         else
           begin
              if p^.left^.location.loc=LOC_CREGISTER then
                emit_reg_reg(op,opsize,p^.left^.location.register,hregister)
              else emit(op,opsize,
                getreferenzstring(p^.left^.location.referenz)+','+regid2str[hregister]);
           end;
         maybe_rangechecking(p,p^.left^.resulttype,p^.resulttype);
         p^.location.loc:=LOC_REGISTER;
         p^.location.register:=hregister;
      end;

    procedure second_string_string(p,hp : ptree;convtyp : tconverttype);far;

      var
         pushedregs : tpushed;

      begin
         clear_referenz(p^.location.referenz);
         p^.location.referenz.base:=R_EBP;
         p^.location.referenz.offset:=gettempofsize(p^.resulttype^.size);
         del_referenz(p^.left^.location.referenz);
         pushusedregisters(pushedregs,$ff);
         emitpushreferenzaddr(p^.location.referenz);
         emitpushreferenzaddr(p^.left^.location.referenz);
         emit(PUSH,S_L,'$'+tostr(pstringdef(p^.resulttype)^.len));
         emit(CALL,S_NO,'STRCOPY');
         maybe_loadesi;
         popusedregisters(pushedregs);
      end;

    procedure second_cstring_charpointer(p,hp : ptree;convtyp : tconverttype);far;

      begin
         p^.location.loc:=LOC_REGISTER;
         p^.location.register:=getregister32;
         inc(p^.left^.location.referenz.offset);
         emit(LEA,S_L,getreferenzstring(p^.left^.location.referenz)+
           ','+regid2str[p^.location.register]);
      end;

    procedure second_cchar_charpointer(p,hp : ptree;convtyp : tconverttype);far;

      begin
         {!!!!}
         p^.location.loc:=LOC_REGISTER;
         p^.location.register:=getregister32;
         inc(p^.left^.location.referenz.offset);
         emit(LEA,S_L,getreferenzstring(p^.left^.location.referenz)+
           ','+regid2str[p^.location.register]);
      end;

    procedure second_cstring_chararray(p,hp : ptree;convtyp : tconverttype);far;

      begin
         p^.location.referenz:=p^.left^.location.referenz;
         inc(p^.location.referenz.offset);
      end;

    procedure second_array_to_pointer(p,hp : ptree;convtyp : tconverttype);far;

      begin
         del_referenz(p^.left^.location.referenz);
         p^.location.loc:=LOC_REGISTER;
         p^.location.register:=getregister32;
         emit(LEA,S_L,getreferenzstring(p^.left^.location.referenz)+','+
           regid2str[p^.location.register]);
      end;

    procedure second_pointer_to_array(p,hp : ptree;convtyp : tconverttype);far;

      begin
         p^.location.loc:=LOC_REFERENZ;
         clear_referenz(p^.location.referenz);
         if p^.left^.location.loc=LOC_REGISTER then
           p^.location.referenz.base:=p^.left^.location.register
         else
           begin
              if p^.left^.location.loc=LOC_CREGISTER then
                begin
                   p^.location.referenz.base:=getregister32;
                   emit_reg_reg(MOV,S_L,p^.left^.location.register,
                     p^.location.referenz.base);
                end
              else
                begin
                   del_referenz(p^.left^.location.referenz);
                   p^.location.referenz.base:=getregister32;
                   emit(MOV,S_L,getreferenzstring(p^.left^.location.referenz)+','+
                     regid2str[p^.location.referenz.base]);
                end;
           end;
      end;

    procedure second_char_to_string(p,hp : ptree;convtyp : tconverttype);far;

      begin
         clear_referenz(p^.location.referenz);
         p^.location.referenz.offset:=gettempofsize(256);
         p^.location.referenz.base:=R_EBP;
         if p^.left^.treetype=ordconstn { eigentlich charconst } then
           emit(MOV,S_W,'$'+tostr(p^.left^.value*256+1)+','+getreferenzstring(p^.location.referenz))
         else
           begin
              { nicht so elegant (ging besser mit extra Register }
              if (p^.left^.location.loc=LOC_REGISTER) or
                 (p^.left^.location.loc=LOC_CREGISTER) then
                begin
                   emit(MOVZX,S_BW,regid2str[p^.left^.location.register]+',%di');
                   ungetregister32(reg8toreg32(p^.left^.location.register));
                end
              else
                begin
                   emit(MOVZX,S_BW,getreferenzstring(p^.left^.location.referenz)+',%di');
                   del_referenz(p^.left^.location.referenz);
                end;
              emit(A_SHL,S_W,'$8,%di');
              emit(A_OR,S_W,'$1,%di');
              emit(MOV,S_W,'%di,'+getreferenzstring(p^.location.referenz));
           end;
      end;

    procedure second_int_real(p,hp : ptree;convtyp : tconverttype);far;

      var
         hs : string;

      begin
         if (p^.left^.location.loc=LOC_REGISTER) or
            (p^.left^.location.loc=LOC_CREGISTER) then
           begin
              hs:=regid2str[p^.left^.location.register];
              ungetregister(p^.left^.location.register);
           end
         else
           begin
              hs:=getreferenzstring(p^.left^.location.referenz);
              del_referenz(p^.left^.location.referenz);
           end;
         hs:=hs+',%edi';
         case pgrunddef(p^.left^.resulttype)^.typ of
            s8bit : emit(MOVSX,S_BL,hs);
            u8bit : emit(MOVZX,S_BL,hs);
            s16bit : emit(MOVSX,S_WL,hs);
            u16bit : emit(MOVZX,S_WL,hs);
            s32bit : emit(MOV,S_L,hs);
         end;
         emit(PUSH,S_L,'%edi');
         emit(FILD,S_L,'(%esp)');
         emit(ADD,S_L,'$4,%esp');
         p^.location.loc:=LOC_FPUSTACK;
      end;

    procedure second_smaller(p,hp : ptree;convtyp : tconverttype);far;

      var
         destregister : tregister;
         opsize : topsize;
         ref : boolean;

      begin
         { !!!!!!!! Rangechecking }
         ref:=false;
         if (p^.left^.location.loc=LOC_REGISTER) or
           (p^.left^.location.loc=LOC_CREGISTER) then
           begin
              destregister:=p^.location.register;
              case convtyp of
                 tc_s32bit_2_s8bit,
                 tc_s32bit_2_u8bit : destregister:=reg32toreg8(destregister);
                 tc_s32bit_2_s16bit,
                 tc_s32bit_2_u16bit : destregister:=reg32toreg16(destregister);
                 tc_s16bit_2_s8bit,
                 tc_s16bit_2_u8bit,
                 tc_u16bit_2_s8bit,
                 tc_u16bit_2_u8bit : destregister:=reg16toreg8(destregister);
              end;
              p^.location.register:=destregister;
           end;
      end;

    procedure secondtypeconv(var p : ptree);far;

      const
         secondconvert : array[tc_u8bit_2_s32bit..tc_int_2_real] of
           tsecondconvproc = (second_bigger,second_only_rangecheck,
                              second_bigger,second_bigger,second_bigger,
                              second_smaller,second_smaller,
                              second_smaller,second_string_string,
                              second_cstring_charpointer,second_cstring_chararray,
                              second_array_to_pointer,second_pointer_to_array,
                              second_char_to_string,second_bigger,
                              second_bigger,second_bigger,
                              second_smaller,second_smaller,
                              second_smaller,second_smaller,
                              second_bigger,second_smaller,
                              second_int_real); {,second_cchar_charpointer); }

      begin
         secondpass(p^.left);
         p^.location:=p^.left^.location;
         if p^.convtyp<>tc_equal then
           secondconvert[p^.convtyp](p,p,p^.convtyp)
      end;

    { speichert die Größe der gepushten Parameter }
    var
       pushedparasize : longint;

    procedure secondcallparan(var p : ptree;defcoll : pdefcoll);

      var
         regstr : string[3];
         size : longint;
         stackref : treferenz;
         otlabel,hlabel,oflabel : longint;

         { Temporäre Variablen: }
         tempdeftype : tdeftype;
         tempreferenz : treferenz;

      begin
         otlabel:=truelabel;
         oflabel:=falselabel;
         truelabel:=getlabel;
         falselabel:=getlabel;
         secondpass(p^.left);
         { in codegen.handleread.. wird defcoll^.data auf nil }
         { gesetzt                                            }
         if assigned(defcoll^.data) and
           (defcoll^.data^.deftype=formaldef) then
           begin
              if (p^.left^.location.loc<>LOC_REFERENZ) and
                 (p^.left^.location.loc<>LOC_MEM) then
                error(type_mismatch);
              emitpushreferenzaddr(p^.left^.location.referenz);
              del_referenz(p^.left^.location.referenz);
              inc(pushedparasize,4);
           end
         else if (defcoll^.paratyp=vs_var) then
           begin
              if (p^.left^.location.loc<>LOC_REFERENZ) then
                error(var_must_be_referenz);
              del_referenz(p^.left^.location.referenz);
              emitpushreferenzaddr(p^.left^.location.referenz);
              inc(pushedparasize,4);
           end
         else
           begin
              tempdeftype:=p^.resulttype^.deftype;
              if tempdeftype=filedef then
                error(file_must_call_by_referenz);
              if (defcoll^.paratyp=vs_const) and
                 (
                   (tempdeftype=stringdef) or
                   (tempdeftype=arraydef) or
                   (tempdeftype=recorddef) or
                   (tempdeftype=classdef) or
                   (tempdeftype=setdef)
                 ) then
                begin
                   emitpushreferenzaddr(p^.left^.location.referenz);
                   del_referenz(p^.left^.location.referenz);
                   inc(pushedparasize,4);
                end
              else
                case p^.left^.location.loc of
                   LOC_REGISTER,
                   LOC_CREGISTER : begin
                                     case p^.left^.location.register of
                                        R_EAX,R_EBX,R_ECX,R_EDX,R_ESI,
                                        R_EDI,R_ESP,R_EBP :
                                          begin
                                             emit(PUSH,S_L,regid2str[p^.left^.location.register]);
                                             inc(pushedparasize,4);
                                             ungetregister32(p^.left^.location.register);
                                          end;
                                        R_AX,R_BX,R_CX,R_DX,R_SI,R_DI : begin
                                              emit(PUSH,S_W,regid2str[p^.left^.location.register]);
                                              inc(pushedparasize,2);
                                              ungetregister32(reg16toreg32(p^.left^.location.register));
                                           end;
                                        R_AL,R_BL,R_CL,R_DL:
                                          begin
                                             { hier etwas Schnipseln um die 8-Bit }
                                             { Register auf den Stack zu bringen: }
                                             regstr:=regid2str[p^.left^.location.register];
                                             emit(PUSH,S_W,'%'+regstr[2]+'x');
                                             inc(pushedparasize,2);
                                             ungetregister32(reg8toreg32(p^.left^.location.register));
                                          end;
                                     end;
                                  end;
                   LOC_FPUSTACK : begin
                                        inc(pushedparasize,8);
                                        emit(SUB,S_L,'$8,%esp');
                                        emit(FSTP,S_L,'(%esp)');
                                     end;
                   LOC_REFERENZ,LOC_MEM :
                               begin
                                  del_referenz(p^.left^.location.referenz);
                                  tempreferenz:=p^.left^.location.referenz;
                                  case p^.resulttype^.deftype of
                                     grunddef : begin
                                                   case pgrunddef(p^.resulttype)^.typ of
                                                      s32bit :
                                                        begin
                                                           emit(PUSH,S_L,getreferenzstring(tempreferenz));
                                                           inc(pushedparasize,4);
                                                        end;
                                                      s8bit,u8bit,uchar,bool8bit,s16bit,u16bit : begin
                                                          emit(PUSH,S_W,getreferenzstring(tempreferenz));
                                                          inc(pushedparasize,2);
                                                       end;
                                                      s64real : begin
                                                                   inc(tempreferenz.offset,4);
                                                                   emit(PUSH,S_L,getreferenzstring(tempreferenz));
                                                                   dec(tempreferenz.offset,4);
                                                                   emit(PUSH,S_L,getreferenzstring(tempreferenz));
                                                                   inc(pushedparasize,8);
                                                                end;
                                                   end;
                                                end;
                                     pointerdef,procvardef,aufzaehldef : begin
                                                      emit(PUSH,S_L,getreferenzstring(tempreferenz));
                                                      inc(pushedparasize,4);
                                                   end;
                                     arraydef,recorddef,stringdef,setdef,classdef :
                                                begin
                                                   size:=p^.resulttype^.size;

                                                   { Alignment }
                                                   {
                                                   if (size>=4) and ((size and 3)<>0) then
                                                     inc(size,4-(size and 3))
                                                   else if (size>=2) and ((size and 1)<>0) then
                                                     inc(size,2-(size and 1))
                                                   else
                                                   if size=1 then size:=2;
                                                   }
                                                   { Stackraum schaffen }
                                                   emit(SUB,S_L,'$'+tostr(size)+',%esp');
                                                   inc(pushedparasize,size);
                                                   { Stackreferenz erstellen }
                                                   clear_referenz(stackref);
                                                   stackref.base:=R_ESP;
                                                   { Kopie erzeugen }
                                                   if p^.resulttype^.deftype=stringdef then
                                                     begin
                                                        copystring(stackref,p^.left^.location.referenz,
                                                          pstringdef(p^.resulttype)^.len);
                                                     end
                                                   else
                                                     begin
                                                        concatcopy(p^.left^.location.referenz,
                                                          stackref,p^.resulttype^.size,true);
                                                     end;
                                                end;
                                     else error(error_in_expression);
                                  end;
                               end;
                 LOC_JUMP     : begin
                                   hlabel:=getlabel;
                                   inc(pushedparasize,2);
                                   emitl(A_LABEL,truelabel);
                                   emit(PUSH,S_W,'$1');
                                   emitl(JMP,hlabel);
                                   emitl(A_LABEL,falselabel);
                                   emit(PUSH,S_W,'$0');
                                   emitl(A_LABEL,hlabel);
                                end;
                 LOC_FLAGS    : begin
                                   if not(R_EAX in unused) then
                                     emit(MOV,S_L,'%eax,%edi');
                                   emit(A_XOR,S_W,'%ax,%ax');
                                   emit(flag_2_set[p^.left^.location.resflags],S_NO,
                                     '%al');
                                   inc(pushedparasize,2);
                                   emit(PUSH,S_W,'%ax');
                                   if not(R_EAX in unused) then
                                     emit(MOV,S_L,'%edi,%eax');
                                end;
                end;
           end;
         truelabel:=otlabel;
         falselabel:=oflabel;
         { von rechts nach links pushen }
         if assigned(p^.right) then
           secondcallparan(p^.right,defcoll^.next);
      end;

    procedure pushexceptlabel;

      begin
         if not(procinfo.exceptions) then
           error(proc_must_handleexceptions);
         emit(PUSH,S_L,'$'+tolabel(aktexceptlabel));
      end;

    procedure secondcalln(var p : ptree);far;

      var
         unusedregisters : tregisterset;
         asmrec : pasmrec;
         pushed : tpushed;
         funcretref : treferenz;
         hregister : tregister;
         oldpushedparasize : longint;
         { true, wenn ESI nach dem Unterprogramm neu geladen werden muß }
         loadesi : boolean;
         { true, wenn eine virtueller Methode direkt aufgerufen werden soll }
         no_virtual_call : boolean;
         { true, wenn wir in einen Call für einen Kon- oder Destruktor erzeugen }
         is_con_or_destructor : boolean;
         { true, wenn ein Konstruktor von new aufgerufen wird }
         extended_new : boolean;
         { Adresse, die bei einem I/O-Error angegeben wird }
         iolabel : longint;

      begin
         extended_new:=false;
         loadesi:=true;
         no_virtual_call:=false;
         unusedregisters:=unused;
         { only if no proc var }
         if not(assigned(p^.right)) then
           is_con_or_destructor:=((p^.procdefinition^.options and poconstructor)<>0)
             or ((p^.procdefinition^.options and podestructor)<>0);
         { proc variables destroy all registers }
         if (p^.right=nil) and
         { virtual methods too }
          ((p^.procdefinition^.options and povirtualmethod)=0) then

           begin
              if ((p^.procdefinition^.options and poiocheck)<>0)
                and (cs_iocheck in aktswitches) then
                begin
                   iolabel:=getlabel;
                   emitl(A_LABEL,iolabel);
                end
              else iolabel:=0;

              { alle benutzen Register pushen: }
              pushusedregisters(pushed,p^.procdefinition^.usedregisters);

              { benutzte Register durchreichen: }
              usedinproc:=usedinproc or p^.procdefinition^.usedregisters;
           end
         else
           begin
              pushusedregisters(pushed,$ff);
              usedinproc:=$ff;
              { natürlich keine I/O-Überprüfung }
              iolabel:=0;
           end;

         { Parameter berechnen und pushen }
         oldpushedparasize:=pushedparasize;
         if assigned(p^.left) then
           begin
              pushedparasize:=0;
              { bei Prozedurvariablen sind die Definitionen woanders }
              { zu finden }
              if assigned(p^.right) then
                secondcallparan(p^.left,pprocvardef(p^.right^.resulttype)^.para1)
              else
                secondcallparan(p^.left,p^.procdefinition^.para1);
           end;
         if (p^.resulttype<>pdef(voiddef)) and
            ((p^.resulttype^.deftype=arraydef) or
            (p^.resulttype^.deftype=stringdef) or
            (p^.resulttype^.deftype=classdef) or
            (p^.resulttype^.deftype=recorddef) or
            (p^.resulttype^.deftype=setdef)) then
           begin
              clear_referenz(funcretref);
              funcretref.base:=R_EBP;
              funcretref.offset:=gettempofsize(p^.procdefinition^.retdef^.size);
              emitpushreferenzaddr(funcretref);
              inc(pushedparasize,4);
           end;
         if (p^.right=nil) then
           begin
              { self pushen }
              if (p^.symtable^.symtabletype and $3fff)=objectsymtable then
                begin
                   if assigned(p^.methodpointer) then
                     begin
                        { direkter Aufruf einer vererbten Methode }
                        case p^.methodpointer^.treetype of
                           typen : begin
                                      { keinen virtuellen Aufruf erzeugen }
                                      no_virtual_call:=true;
                                      { Memberaufruf, also ESI nicht verändern }
                                      loadesi:=false;
                                      emit(PUSH,S_L,'%esi');
                                      { sollte ein vererbter Con- oder Destructor nicht   }
                                      { in einem Con- oder Destructor aufgerufen werden,  }
                                      { so wird eine Warnung ausgegeben                   }
                                      if is_con_or_destructor and
                                        not(
                                        (((aktprocsym^.definition^.options and poconstructor)<>0) and
                                         ((p^.procdefinition^.options and poconstructor)<>0)) or
                                        (((aktprocsym^.definition^.options and podestructor)<>0) and
                                         ((p^.procdefinition^.options and podestructor)<>0))) then
                                        warning(member_cd_call_from_method);
                                      { bei Kon- oder Destructoraufrufen wird noch ein Zeiger }
                                      { auf eine VMT erwartet...                              }
                                      if is_con_or_destructor then
                                        begin
                                           { ...der allerdings in diesem Kontext einen Sch... interessiert}
                                           emit(PUSH,S_L,'$0');
                                        end;
                                   end;
                           hnewn : begin
                                     { Constructor mit erweitertem Syntax von New aufrufen }
                                     { ESI muß schon gelöscht sein }
                                     emit(A_XOR,S_L,'%esi,%esi');
                                     emit(PUSH,S_L,'%esi');
                                     emit(PUSH,S_L,'$VMT_'+pclassdef(p^.methodpointer^.resulttype)^.name^);
                                     extended_new:=true;
                                  end;
                           hdisposen : begin
                                          secondpass(p^.methodpointer);
                                          { Destruktor mit erweitertem Syntax von Dispose aufrufen }
                                          { hdisposen liefert immer LOC_REFERENZ }
                                          emit(LEA,S_L,getreferenzstring(p^.methodpointer^.location.referenz)+',%esi');
                                          del_referenz(p^.methodpointer^.location.referenz);
                                          emit(PUSH,S_L,'%esi');
                                          emit(PUSH,S_L,'$VMT_'+pclassdef(p^.methodpointer^.resulttype)^.name^)
                                       end;
                           else
                             begin
                                { irgendein Methodenaufruf }
                                secondpass(p^.methodpointer);
                                { %esi gleich laden (wegen virtuellen Methoden) }
                                case p^.methodpointer^.location.loc of
                                   LOC_REGISTER : begin
                                                     ungetregister32(p^.methodpointer^.location.register);
                                                     emit_reg_reg(MOV,S_L,p^.methodpointer^.location.register,R_ESI);
                                                  end;
                                   else begin
                                           emit(LEA,S_L,getreferenzstring(p^.methodpointer^.location.referenz)+',%esi');
                                           del_referenz(p^.methodpointer^.location.referenz);
                                        end;
                                end;
                                emit(PUSH,S_L,'%esi');
                                if is_con_or_destructor then
                                  begin
                                     if ((p^.procdefinition^.options and poconstructor)<>0) then
                                       { hier muß die VMT natürlich eingetragen werden }
                                       emit(PUSH,S_L,'$VMT_'+pclassdef(p^.methodpointer^.resulttype)^.name^)
                                     { beim Destruktor Objekt nicht! löschen }
                                     else emit(PUSH,S_L,'$0');
                                  end;
                             end;
                        end;
                     end
                   else
                     begin
                        { Memberaufruf, also ESI nicht verändern }
                        loadesi:=false;
                        emit(PUSH,S_L,'%esi');
                        { aber ein Kon- oder Destruktor wäre hier wohl fast immer }
                        { fehl am Platze                                          }
                        if is_con_or_destructor then
                          begin
                             warning(member_cd_call_from_method);
                             { VMT-Zeiger nicht eintragen }
                             emit(PUSH,S_L,'$0');
                          end;
                     end;
                end;

              { Basepointer ?}
              if (lexlevel>0) and assigned(pprocdef(p^.procdefinition)^.parast) and
                  ((p^.procdefinition^.parast^.symtabletype and $3fff)>1) then
                begin
                   if (lexlevel=(p^.procdefinition^.parast^.symtabletype and $3fff)) then
                     emit(PUSH,S_L,tostr(procinfo.framepointer)+'(%ebp)')
                   else if lexlevel<(p^.procdefinition^.parast^.symtabletype and $3fff) then
                     emit(PUSH,S_L,'%ebp');
                end;
              { Exceptionadresse pushen }
              if ((p^.procdefinition^.options and poexceptions)<>0) then
                begin
                   pushexceptlabel;
                   inc(pushedparasize,4);
                end;
              if (p^.procdefinition^.options and poexports)<>0 then
                error(dont_call_exported_direct);

              if ((p^.procdefinition^.options and povirtualmethod)<>0) and
                 not(no_virtual_call) then
                begin
                   emit(MOV,S_L,'(%esi),%edi');
                   emit(CALL,S_NO,tostr(p^.procdefinition^.extnumber*4+12)+'(%edi)');
                end
              else
                 emit(CALL,S_NO,p^.procdefinition^.mangledname);
              if ((p^.procdefinition^.options and poclearstack)<>0) then
                emit(ADD,S_L,'$'+tostr(pushedparasize)+',%esp');
           end
         else
           begin
              { Exceptionadresse pushen (Prozedurvariable) }
              if ((pprocvardef(p^.right^.resulttype)^.options and poexceptions)<>0) then
                begin
                   pushexceptlabel;
                   inc(pushedparasize,4);
                end;
              secondpass(p^.right);
              case p^.right^.location.loc of
                 LOC_REGISTER,
                 LOC_CREGISTER : begin
                                   emit(CALL,S_NO,regid2str[p^.right^.location.register]);
                                   ungetregister32(p^.right^.location.register);
                                end
                 else
                    begin
                       emit(CALL,S_NO,'*'+getreferenzstring(p^.right^.location.referenz));
                       del_referenz(p^.right^.location.referenz);
                    end;
              end;
           end;

         pushedparasize:=oldpushedparasize;
         unused:=unusedregisters;
         { Register restaurieren }
         if p^.resulttype<>pdef(voiddef) then
           begin
              if (p^.right=nil) and
                 ((p^.procdefinition^.options and poconstructor)<>0) then
                begin
                   p^.location.loc:=LOC_FLAGS;
                   p^.location.resflags:=F_NE;
                   if extended_new then
                     begin
                        { sollte EAX belegt sein, dann umkopieren }
                        hregister:=getregister32;
                        emit_reg_reg(MOV,S_L,R_EAX,hregister);
                        p^.location.register:=hregister;
                     end;
                end
              else if ((p^.resulttype^.deftype=arraydef) or
                  (p^.resulttype^.deftype=stringdef) or
                  (p^.resulttype^.deftype=classdef) or
                  (p^.resulttype^.deftype=recorddef) or
                  (p^.resulttype^.deftype=setdef)) then
                begin
                   p^.location.loc:=LOC_MEM;
                   p^.location.referenz:=funcretref;
                end
              else
                begin
                   p^.location.loc:=LOC_REGISTER;
                   hregister:=getregister32;
                   if (p^.resulttype^.deftype=grunddef) then
                     begin
                        case pgrunddef(p^.resulttype)^.typ of
                           s32bit : begin
                                       emit_reg_reg(MOV,S_L,R_EAX,hregister);
                                       p^.location.register:=hregister;
                                    end;
                           uchar,u8bit,bool8bit,s8bit : begin
                                       emit_reg_reg(MOV,S_B,R_AL,reg32toreg8(hregister));
                                       p^.location.register:=reg32toreg8(hregister);
                                    end;
                           s16bit,u16bit : begin
                                       emit_reg_reg(MOV,S_W,R_AX,reg32toreg16(hregister));
                                       p^.location.register:=reg32toreg16(hregister);
                                    end;
                           s64real : p^.location.loc:=LOC_FPUSTACK;
                           else internalerror(7);
                        end
                     end
                   else
                     begin
                        emit_reg_reg(MOV,S_L,R_EAX,hregister);
                        p^.location.register:=hregister;
                     end;
                end;
           end;
         { vielleicht I/O-Check ? }
         if iolabel<>0 then
           begin
              emit(PUSH,S_L,tolabel(iolabel));
              emit(CALL,S_NO,'IOCHECK');
           end;
         popusedregisters(pushed);
         if loadesi then
           maybe_loadesi;
      end;

    procedure secondfuncret(var p : ptree);far;

      var
         hregister : tregister;

      begin
         clear_referenz(p^.location.referenz);
         p^.location.referenz.base:=R_EBP;
         p^.location.referenz.offset:=procinfo.retoffset;
         if (procinfo.retdef^.deftype=arraydef) or
            (procinfo.retdef^.deftype=stringdef) or
            (procinfo.retdef^.deftype=classdef) or
            (procinfo.retdef^.deftype=recorddef) or
            (procinfo.retdef^.deftype=setdef) then
           begin
              hregister:=getregister32;
              emit(MOV,S_L,getreferenzstring(p^.location.referenz)+','+regid2str[hregister]);
              p^.location.referenz.base:=hregister;
              p^.location.referenz.offset:=0;
           end;
      end;

    { dreht die Parameterliste um }

    function reversparameter(p : ptree) : ptree;

      var
         hp1,hp2 : ptree;

      begin
         hp1:=nil;
         while assigned(p) do
           begin
              { Aushaengen }
              hp2:=p;
              p:=p^.right;

              { Neu Einhaengen }
              hp2^.right:=hp1;
              hp1:=hp2;
           end;
         reversparameter:=hp1;
      end;

    procedure secondinline(var p : ptree);far;

      var
         aktfile : treferenz;
         ft : tfiletyp;
         pushed : tpushed;

      { Behandelt die Codeerzeugung für READ(LN) und WRITE(LN) }

      procedure handlereadwrite(doread,callwriteln : boolean);

        procedure loadstream;

          begin
             if doread then
               emit(LEA,S_L,'U_'+target_info.system_unit+'_INPUT,%edi')
             else emit(LEA,S_L,'U_'+target_info.system_unit+'_OUTPUT,%edi');
          end;

        var
           node,hp : ptree;
           typedtyp,pararesult : pdef;
           doflush : boolean;
           dummycoll : tdefcoll;
           iolabel : longint;

        begin
           { I/O-Prüfung ? }
           if cs_iocheck in aktswitches then
             begin
                iolabel:=getlabel;
                emitl(A_LABEL,iolabel);
             end
           else iolabel:=0;
           { kein  automatischer Aufruf von Flush }
           doflush:=false;
           { temporären Zeiger auf Dateivariable reservieren }
           gettempofsizereferenz(4,aktfile);
           { erst einmal Textdatei angeben }
           ft:=ft_text;
           { auch ein Parameter angegeben ? }
           if p^.left=nil then
             begin
                { Bildschirmausgabe, also gleich ausgeben }
                doflush:=true;
                { die folgenden Anweisungen sind für "writeln;" }
                loadstream;
                { @Dateivariable in temp. Var. abspeichern }
                emit(MOV,S_L,'%edi,'+getreferenzstring(aktfile));
             end
           else
             begin
                { Parameter umdrehen ! }
                node:=reversparameter(p^.left);

                { Dateivariable berechnen }
                { erster Parameter ein Filetyp ? }
                if node^.left^.resulttype^.deftype=filedef then
                  begin
                     ft:=pfiledef(node^.left^.resulttype)^.filetyp;
                     if ft=ft_typed then
                       typedtyp:=pfiledef(node^.left^.resulttype)^.typed_as;

                     secondpass(node^.left);
                     if codegenerror then
                       exit;

                     { Referenz in temporäre Variable retten }
                     if node^.left^.location.loc<>LOC_REFERENZ then
                       begin
                          error(error_in_expression);
                          exit;
                       end;

                     emit(LEA,S_L,getreferenzstring(node^.left^.location.referenz)+',%edi');

                     { erster Parameter ist behandelt, also löschen }
                     node:=node^.right;
                  end
                else
                  begin
                     { Bildschirmausgabe, also gleich ausgeben }
                     doflush:=true;
                     loadstream;
                  end;

                { @Dateivariable in temp. Var. abspeichern }
                emit(MOV,S_L,'%edi,'+getreferenzstring(aktfile));
                if doread then
                  { Paramter an READ werden Call by Referenz übergeben }
                  dummycoll.paratyp:=vs_var
                  { an WRITE Call by "Const" }
                else dummycoll.paratyp:=vs_const;

                { wegen secondcallparan, welches sonst daraufzugreift }
                dummycoll.data:=nil;

                while node<>nil do
                  begin
                     pushusedregisters(pushed,$ff);
                     hp:=node;
                     node:=node^.right;
                     hp^.right:=nil;
                     if hp^.is_colon_para then
                       error(ill_colon_qualifier);
                     secondcallparan(hp,@dummycoll);
                     if codegenerror then
                       exit;

                     emit(PUSH,S_L,getreferenzstring(aktfile));
                     if (ft=ft_typed) then
                       begin
                          {!!!!!!!}
                       end
                     else
                       begin

                          pararesult:=hp^.left^.resulttype;
                          { mögliche Feldbreitenangabe bearbeiten }
                          { natürlich nur bei write(ln)           }
                          if not doread then
                            begin
                               if assigned(node) and node^.is_colon_para then
                                 begin
                                    hp:=node;
                                    node:=node^.right;
                                    hp^.right:=nil;
                                    secondcallparan(hp,@dummycoll);
                                    if codegenerror then
                                      exit;
                                 end
                               else
                                 emit(PUSH,S_L,'$0');
                            end;
                          { keine Exceptions mehr in der RTL pushexceptlabel; }
                          case hp^.left^.resulttype^.deftype of
                             stringdef : begin
                                            if doread then
                                              emit(CALL,S_NO,'READ_TEXT_STRING')
                                            else emit(CALL,S_NO,'WRITE_TEXT_STRING');
                                         end;
                             pointerdef : begin
                                             if (ppointerdef(pararesult)^.definition^.deftype=grunddef)
                                               and (pgrunddef(ppointerdef(pararesult)^.definition)^.typ=uchar) then
                                               begin
                                                  if doread then
                                                    emit(CALL,S_NO,'READ_TEXT_PCHAR_AS_POINTER')
                                                  else emit(CALL,S_NO,'WRITE_TEXT_PCHAR_AS_POINTER');
                                               end
                                             else error(no_para_match);
                                          end;
                             arraydef : begin
                                           if (parraydef(pararesult)^.lowrange=0)
                                             and (parraydef(pararesult)^.definition^.deftype=grunddef)
                                             and (pgrunddef(parraydef(pararesult)^.definition)^.typ=uchar) then
                                             begin
                                                if doread then
                                                  emit(CALL,S_NO,'READ_TEXT_PCHAR_AS_ARRAY')
                                                else emit(CALL,S_NO,'WRITE_TEXT_PCHAR_AS_ARRAY');
                                             end
                                           else error(no_para_match);
                                        end;
                             grunddef : begin
                                           case pgrunddef(pararesult)^.typ of
                                              s32bit : if doread then
                                                         emit(CALL,S_NO,'READ_TEXT_LONGINT')
                                                       else emit(CALL,S_NO,'WRITE_TEXT_LONGINT');
                                              uchar : if doread then
                                                         emit(CALL,S_NO,'READ_TEXT_CHAR')
                                                       else emit(CALL,S_NO,'WRITE_TEXT_CHAR');
                                              s64real : if doread then
                                                         emit(CALL,S_NO,'READ_TEXT_REAL')
                                                       else
                                                         begin
                                                            { Fixkommaangabe auf den Stack kopieren }
                                                            if assigned(node) and node^.is_colon_para then
                                                              begin
                                                                 hp:=node;
                                                                 node:=node^.right;
                                                                 hp^.right:=nil;
                                                                 secondcallparan(hp,@dummycoll);
                                                                 if codegenerror then
                                                                   exit;
                                                              end
                                                            else
                                                              emit(PUSH,S_L,'$-1');
                                                            emit(CALL,S_NO,'WRITE_TEXT_REAL');
                                                         end;
                                              else error(no_para_match);
                                           end;
                                        end;
                             else error(no_para_match);
                          end;
                       end;
                     { in Methoden ESI neu laden }
                     popusedregisters(pushed);
                     maybe_loadesi;
                  end;
             end;
           if callwriteln then
             begin
                pushusedregisters(pushed,$ff);
                emit(PUSH,S_L,getreferenzstring(aktfile));
                { pushexceptlabel; }
                if ft<>ft_text then
                  error(no_para_match);
                emit(CALL,S_NO,'WRITELN_TEXT');
                popusedregisters(pushed);
                maybe_loadesi;
             end;
           if doflush and not(doread) then
             begin
               pushusedregisters(pushed,$ff);
               { pushexceptlabel; }
               emit(CALL,S_NO,'FLUSH_STDOUT');
               popusedregisters(pushed);
               maybe_loadesi;
             end;
           if iolabel<>0 then
             begin
                { registers are saved in the procedure }
                emit(PUSH,S_L,tolabel(iolabel));
                emit(CALL,S_NO,'IOCHECK');
             end;
        end;

      procedure handle_str;

        var
           hp,node : ptree;
           dummycoll : tdefcoll;
           is_real : boolean;

        begin
           pushusedregisters(pushed,$ff);
           node:=p^.left;
           while assigned(node) do
             begin
                hp:=node;
                node:=node^.right;
                hp^.right:=nil;
                if hp^.left^.resulttype^.deftype=stringdef then
                  dummycoll.paratyp:=vs_var
                else
                  dummycoll.paratyp:=vs_const;

                { wenn irgendwo ein Realparameter vorkommt, dann }
                { REALSTR aufrufen                               }
                if (hp^.left^.resulttype^.deftype=grunddef)
                   and (pgrunddef(hp^.left^.resulttype)^.typ=s64real) then
                  is_real:=true;

                secondcallparan(hp,@dummycoll);
                if codegenerror then
                  exit;
             end;
           popusedregisters(pushed);
        end;

      begin
         case p^.inlinenumber of
            in_lo_word,
            in_hi_word : begin
                       secondpass(p^.left);
                       p^.location.loc:=LOC_REGISTER;
                       if p^.left^.location.loc<>LOC_REGISTER then
                         begin
                            if p^.left^.location.loc=LOC_CREGISTER then
                              begin
                                 p^.location.register:=reg32toreg16(getregister32);
                                 emit_reg_reg(MOV,S_W,p^.left^.location.register,
                                   p^.location.register);
                              end
                            else
                              begin
                                 del_referenz(p^.left^.location.referenz);
                                 p^.location.register:=reg32toreg16(getregister32);
                                 emit(MOV,S_W,getreferenzstring(p^.left^.location.referenz)
                                   +','+regid2str[p^.location.register]);
                              end;
                         end
                       else p^.location.register:=p^.left^.location.register;
                       if p^.inlinenumber=in_hi_word then
                         emit(A_SHR,S_W,'$8,'+regid2str[p^.location.register]);
                       p^.location.register:=reg16toreg8(p^.location.register);
                    end;
            in_sizeof_x,
            in_typeof_x : begin
                             secondpass(p^.left);
                             del_referenz(p^.left^.location.referenz);
                             p^.location.loc:=LOC_REGISTER;
                             p^.location.register:=getregister32;
                             { VMT-Zeiger laden }
                             emit(MOV,S_L,getreferenzstring(p^.left^.location.referenz)+
                               +','+regid2str[p^.location.register]);
                             if p^.inlinenumber=in_sizeof_x then
                               begin
                                  emit(MOV,S_L,'('+regid2str[p^.location.register]+'),'+
                                    regid2str[p^.location.register]);
                               end;
                          end;
            in_lo_long,
            in_hi_long : begin
                       secondpass(p^.left);
                       p^.location.loc:=LOC_REGISTER;
                       if p^.left^.location.loc<>LOC_REGISTER then
                         begin
                            if p^.left^.location.loc=LOC_CREGISTER then
                              begin
                                 p^.location.register:=getregister32;
                                 emit_reg_reg(MOV,S_L,p^.left^.location.register,
                                   p^.location.register);
                              end
                            else
                              begin
                                 del_referenz(p^.left^.location.referenz);
                                 p^.location.register:=getregister32;
                                 emit(MOV,S_L,getreferenzstring(p^.left^.location.referenz)
                                   +','+regid2str[p^.location.register]);
                              end;
                         end
                       else p^.location.register:=p^.left^.location.register;
                       if p^.inlinenumber=in_hi_long then
                         emit(A_SHR,S_L,'$16,'+regid2str[p^.location.register]);
                       p^.location.register:=reg32toreg16(p^.location.register);
                    end;
            in_ord_char,
            in_chr_byte,
            in_length_string : begin
                       secondpass(p^.left);
                       p^.location:=p^.left^.location;
                    end;
            in_inc_dword : begin
                              secondpass(p^.left);
                              emit(A_INC,S_L,getreferenzstring(p^.left^.location.referenz));
                              emitoverflowcheck;
                           end;
            in_inc_word : begin
                              secondpass(p^.left);
                              emit(A_INC,S_W,getreferenzstring(p^.left^.location.referenz));
                              emitoverflowcheck;
                           end;
            in_inc_byte : begin
                              secondpass(p^.left);
                              emit(A_INC,S_B,getreferenzstring(p^.left^.location.referenz));
                              emitoverflowcheck;
                           end;
            in_dec_dword : begin
                              secondpass(p^.left);
                              emit(A_DEC,S_L,getreferenzstring(p^.left^.location.referenz));
                              emitoverflowcheck;
                           end;
            in_dec_word : begin
                              secondpass(p^.left);
                              emit(A_DEC,S_W,getreferenzstring(p^.left^.location.referenz));
                              emitoverflowcheck;
                           end;
            in_dec_byte : begin
                              secondpass(p^.left);
                              emit(A_DEC,S_B,getreferenzstring(p^.left^.location.referenz));
                              emitoverflowcheck;
                           end;
            in_assigned_x : begin
                               secondpass(p^.left^.left);
                               p^.location.loc:=LOC_FLAGS;
                               if (p^.left^.left^.location.loc=LOC_REGISTER) or
                                  (p^.left^.left^.location.loc=LOC_CREGISTER) then
                                 begin
                                    emit(A_OR,S_L,regid2str[p^.left^.left^.location.register]+','+
                                      regid2str[p^.left^.left^.location.register]);
                                    ungetregister32(p^.left^.left^.location.register);
                                 end
                               else
                                 begin
                                    emit(CMP,S_L,'$0,'+getreferenzstring(p^.left^.left^.location.referenz));
                                    del_referenz(p^.left^.left^.location.referenz);
                                 end;
                               p^.location.resflags:=F_NE;
                            end;
            in_write_x : handlereadwrite(false,false);
            in_writeln_x : handlereadwrite(false,true);
            in_read_x : handlereadwrite(true,false);
            in_readln_x : begin
                              handlereadwrite(true,false);
                              pushusedregisters(pushed,$ff);
                              emit(PUSH,S_L,getreferenzstring(aktfile));
                              { pushexceptlabel; }
                              if ft<>ft_text then
                                error(no_para_match);
                              emit(CALL,S_NO,'READLN_TEXT');
                              popusedregisters(pushed);
                              maybe_loadesi;
                           end;
            in_str_x_string : begin
                                 handle_str;
                                 maybe_loadesi;
                              end;
            else internalerror(9);
         end;
      end;

    procedure secondsubscriptn(var p : ptree);far;

      begin
         secondpass(p^.left);

         if codegenerror then
           exit;

         p^.location:=p^.left^.location;
         inc(p^.location.referenz.offset,p^.vs^.adresse);
      end;

    procedure secondselfn(var p : ptree);far;

      begin
         clear_referenz(p^.location.referenz);
         p^.location.referenz.base:=R_ESI;
      end;

    procedure secondhdisposen(var p : ptree);far;

      begin
         secondpass(p^.left);

         if codegenerror then
           exit;
         clear_referenz(p^.location.referenz);
         case p^.left^.location.loc of
            LOC_REGISTER,
            LOC_CREGISTER : begin
                               p^.location.referenz.index:=getregister32;
                               emit(MOV,S_L,
                                 regid2str[p^.left^.location.register]+','+
                                 regid2str[p^.location.referenz.index]);
                            end;
            LOC_MEM,LOC_REFERENZ :
                            begin
                               del_referenz(p^.left^.location.referenz);
                               p^.location.referenz.index:=getregister32;
                               emit(MOV,S_L,getreferenzstring(p^.left^.location.referenz)+','+
                                 regid2str[p^.location.referenz.index]);
                            end;
         end;
      end;

    procedure secondhnewn(var p : ptree);far;

      begin
      end;

    procedure secondnewn(var p : ptree);far;

      begin
         secondpass(p^.left);

         if codegenerror then
           exit;

         p^.location.register:=p^.left^.location.register;
      end;

    procedure secondsimplenewdispose(var p : ptree);far;

      begin
         secondpass(p^.left);
         if codegenerror then
           exit;

         { determines the size of the mem block }
         emit(PUSH,S_L,
           '$'+tostr(ppointerdef(p^.left^.resulttype)^.definition^.size));

         { push pointer adress }
         case p^.left^.location.loc of
            LOC_CREGISTER : emit(PUSH,S_L,
              regid2str[p^.left^.location.register]);
            LOC_REFERENZ : emitpushreferenzaddr(p^.left^.location.referenz);
         end;

         { call the mem handling procedures }
         case p^.treetype of
            simpledisposen : emit(CALL,S_NO,'FREEMEM');
            simplenewn : emit(CALL,S_NO,'GETMEM');
         end;

         { may be load ESI }
         maybe_loadesi;
      end;

    { kopiert p als Setelement auf den Stack }
    procedure pushsetelement(var p : ptree);

      var
         hr : tregister;

      begin
         { das Element auf den Stack kopieren, etwas kompliziert }
         case p^.location.loc of
            LOC_REGISTER,
            LOC_CREGISTER : begin
                              hr:=p^.location.register;
                              case hr of
                                 R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
                                   begin
                                      ungetregister32(hr);
                                      emit(PUSH,S_W,regid2str[reg32toreg16(hr)]);
                                   end;
                                 R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
                                   begin
                                      ungetregister32(reg16toreg32(hr));
                                      emit(PUSH,S_W,regid2str[hr]);
                                   end;
                                 R_AL,R_BL,R_CL,R_DL :
                                   begin
                                      ungetregister32(reg8toreg32(hr));
                                      emit(PUSH,S_W,regid2str[reg8toreg16(hr)]);
                                   end;
                              end;
                           end;
            else
               begin
                  emit(PUSH,S_W,getreferenzstring(p^.location.referenz));
                  del_referenz(p^.location.referenz);
               end;
         end;
      end;

    procedure secondsetcons(var p : ptree);far;

      var
         l,i : longint;
         hp : ptree;
         href,sref : treferenz;

      begin
         { konstanten Teil erzeugen }
         clear_referenz(href);
         l:=getconstlabel;
         href.symbol:=stringdup('L'+tostr(l));
         constsegment.concat(gennasmrec(DIRECT,S_NO,'L'+tostr(l)+':'));
         for i:=0 to 31 do
           constsegment.concat(gennasmrec(A_BYTE,S_NO,tostr(p^.constset^[i])));
         hp:=p^.left;
         if assigned(hp) then
           begin
              gettempofsizereferenz(32,sref);
              concatcopy(href,sref,32,false);
              while assigned(hp) do
                begin
                   secondpass(hp^.left);
                   if codegenerror then
                     exit;

                   pushsetelement(hp^.left);
                   emitpushreferenzaddr(sref);
                   { Register werden im Unterprogramm gerettet }
                   emit(CALL,S_NO,'SET_SET_BYTE');
                   hp:=hp^.right;
                end;
              p^.location.referenz:=sref;
           end
         else p^.location.referenz:=href;
      end;

    { ließe sich auch in secondadd einbauen }
    { aber es soll ja übersichtlich bleiben }

    procedure secondin(var p : ptree);far;

      var
         pushed : boolean;
         swapp : ptree;

      begin
         if p^.left^.treetype=ordconstn then
           begin
              { nur obligatorisch }
              secondpass(p^.left);

              secondpass(p^.right);
              if codegenerror then
                exit;
              p^.location.resflags:=F_NE;
              inc(p^.right^.location.referenz.offset,p^.left^.value div 8);
              emit(A_TEST,S_B,'$'+tostr(1 shl (p^.left^.value mod 8))+
                ','+getreferenzstring(p^.right^.location.referenz));
              del_referenz(p^.right^.location.referenz);
           end
         else
           begin
              { beide Operanden berechnen }
              { den schwierigeren zuerst }
              firstcomplex(p);
              secondpass(p^.left);
              p^.location:=p^.left^.location;
              { sind zuwenig Register frei? }
              pushed:=maybe_push(p^.right^.registers32,p);
              secondpass(p^.right);
              if pushed then restore(p);
              { natürlich nicht kommutativ }
              if p^.swaped then
                begin
                   swapp:=p^.left;
                   p^.left:=p^.right;
                   p^.right:=swapp;
                   p^.swaped:=not(p^.swaped);
                end;
              pushsetelement(p^.left);
              emitpushreferenzaddr(p^.right^.location.referenz);
              del_referenz(p^.right^.location.referenz);
              { Register müssen keine gerettet werden, das geschieht in }
              { SET_IN_BYTE (EDI wird verändert)                        }
              emit(CALL,S_NO,'SET_IN_BYTE');
              p^.location.loc:=LOC_FLAGS;
              p^.location.resflags:=F_C;
           end;
      end;

    procedure secondexpr(var p : ptree);far;

      begin
         secondpass(p^.left);
      end;

    procedure secondblockn(var p : ptree);far;

      var
         hp : ptree;

      begin
         hp:=p^.left;
         while assigned(hp) do
           begin
              { Anweisungen können wegoptimiert sein }
              if assigned(hp^.right) then
                begin
                   cleartempgen;
                   secondpass(hp^.right);
                end;

              hp:=hp^.left;
           end;
      end;

    procedure second_while_repeatn(var p : ptree);far;

      var
         l1,l2,l3,oldclabel,oldblabel : longint;

      begin
         l1:=getlabel;
         l2:=getlabel;
         { Continue und Breaklabels einrichten: }
         oldclabel:=aktcontinuelabel;
         oldblabel:=aktbreaklabel;
         if p^.treetype=repeatn then
           begin
              aktcontinuelabel:=l1;
              aktbreaklabel:=l2;

              emitl(A_LABEL,l1);
              cleartempgen;
              secondpass(p^.right);

              truelabel:=l2;
              falselabel:=l1;
              cleartempgen;
              secondpass(p^.left);
              maketojumpbool(p^.left);

              emitl(A_LABEL,l2);
           end
         else
           begin
              l3:=getlabel;
              aktcontinuelabel:=l1;
              aktbreaklabel:=l3;
              { Bedingungscode kommt ans Ende, da dies meist effizienter ist }
              emitl(JMP,l2);

              emitl(A_LABEL,l1);
              cleartempgen;
              secondpass(p^.right);

              emitl(A_LABEL,l2);
              truelabel:=l1;
              falselabel:=l3;
              cleartempgen;
              secondpass(p^.left);
              maketojumpbool(p^.left);

              emitl(A_LABEL,l3);
           end;
         aktcontinuelabel:=oldclabel;
         aktbreaklabel:=oldblabel;
      end;

    procedure secondifn(var p : ptree);far;

      var
         l1,l2,hl : longint;

      begin
         l1:=getlabel;
         l2:=getlabel;
         truelabel:=l1;
         falselabel:=l2;
         cleartempgen;
         secondpass(p^.left);
         maketojumpbool(p^.left);
         if assigned(p^.right) then
           begin
              emitl(A_LABEL,l1);
              cleartempgen;
              secondpass(p^.right);
           end;
         if assigned(p^.t1) then
           begin
              if assigned(p^.right) then
                begin
                   hl:=getlabel;
                   emitl(JMP,hl);
                end;
              emitl(A_LABEL,l2);
              cleartempgen;
              secondpass(p^.t1);
              if assigned(p^.right) then
                emitl(A_LABEL,hl);
           end
         else
           emitl(A_LABEL,l2);
         if not(assigned(p^.right)) then
           emitl(A_LABEL,l1);
      end;

    procedure secondbreakn(var p : ptree);far;

      begin
         if aktbreaklabel<>0 then
           emitl(JMP,aktbreaklabel)
         else
           error(break_not_allowed);
      end;

    procedure secondcontinuen(var p : ptree);far;

      begin
         if aktcontinuelabel<>0 then
           emitl(JMP,aktcontinuelabel)
         else
           error(continue_not_allowed);
      end;

    procedure secondfor(var p : ptree);far;

      var
         l1,l2,oldclabel,oldblabel : longint;
         omitfirstcomp,temptovalue : boolean;
         hs : byte;
         temp1 : treferenz;
         hop : tasmop;
         cmpreg,cmp32 : tregister;
         opsize : topsize;

      begin
         oldclabel:=aktcontinuelabel;
         oldblabel:=aktbreaklabel;
         l1:=getlabel;
         l2:=getlabel;
         aktbreaklabel:=l2;
         aktcontinuelabel:=l1;

         { können wir uns den ersten Vergleich sparen ? }
         omitfirstcomp:=false;
         if p^.right^.treetype=ordconstn then
           if p^.left^.right^.treetype=ordconstn then
             omitfirstcomp:=(p^.backward and (p^.left^.right^.value>=p^.right^.value))
               or (not(p^.backward) and (p^.left^.right^.value<=p^.right^.value));

         { nur Referenz berechnen }
         cleartempgen;
         secondpass(p^.t2);
         if not(simple_loadn) then
           error(invalid_for_var);

         { Startzuweisung erzeugen }
         cleartempgen;
         secondpass(p^.left);

         hs:=p^.t2^.resulttype^.size;
         cmp32:=getregister32;
         case hs of
            1 : begin
                   opsize:=S_B;
                   cmpreg:=reg32toreg8(cmp32);
                end;
            2 : begin
                   opsize:=S_W;
                   cmpreg:=reg32toreg16(cmp32);
                end;
            4 : begin
                   opsize:=S_L;
                   cmpreg:=cmp32;
                end;
         end;
         cleartempgen;
         secondpass(p^.right);
         { Zielwert berechnen und prüfen ob vielleicht veränderlich }
         { falls dem so ist, in temporäre Variable laden            }
         if p^.right^.treetype<>ordconstn then
           begin
              gettempofsizereferenz(hs,temp1);
              temptovalue:=true;
              if (p^.right^.location.loc=LOC_REGISTER) or
                 (p^.right^.location.loc=LOC_CREGISTER) then
                begin
                   emit(MOV,opsize,regid2str[p^.right^.location.register]
                      +','+getreferenzstring(temp1));
                 end
              else
                 concatcopy(p^.right^.location.referenz,temp1,hs,false);
           end
         else temptovalue:=false;

         if temptovalue then
           begin
              if p^.t2^.location.loc=LOC_CREGISTER then
                emit(MOV,opsize,regid2str[p^.t2^.location.register]+','+
                  regid2str[cmpreg])
              else
                emit(MOV,opsize,getreferenzstring(p^.t2^.location.referenz)+','+
                  regid2str[cmpreg]);

              emit(CMP,opsize,getreferenzstring(temp1)+','+
                regid2str[cmpreg]);
           end
         else
           begin
              if not(omitfirstcomp) then
                begin
                   if p^.t2^.location.loc=LOC_CREGISTER then
                     emit(CMP,opsize,'$'+tostr(p^.right^.value)+','+
                       regid2str[p^.t2^.location.register])
                   else
                     emit(CMP,opsize,'$'+tostr(p^.right^.value)+','+
                       getreferenzstring(p^.t2^.location.referenz));
                end;
           end;
         if p^.backward then
           hop:=JL
         else hop:=JG;

         if not(omitfirstcomp) or temptovalue then
          emitl(hop,aktbreaklabel);

         emitl(A_LABEL,aktcontinuelabel);

         { Hilfsregister darf im Anweisungsblock nicht belegt sein }
         cleartempgen;
         if assigned(p^.t1) then
           secondpass(p^.t1);
         { schadet hier absolut nicht }
         cleartempgen;

         { Hilfsregister wieder anfordern }
         cmp32:=getregister32;
         case hs of
            1 : begin
                   opsize:=S_B;
                   cmpreg:=reg32toreg8(cmp32);
                end;
            2 : begin
                   opsize:=S_W;
                   cmpreg:=reg32toreg16(cmp32);
                end;
            4 : opsize:=S_L;
         end;

         { je nach Zählrichtung DEC oder INC...}
         if p^.backward then
           hop:=A_DEC
         else hop:=A_INC;

         if p^.t2^.location.loc=LOC_CREGISTER then
           emit(hop,opsize,regid2str[p^.t2^.location.register])
         else
           emit(hop,opsize,getreferenzstring(p^.t2^.location.referenz));

         { Vergleich erzeugen und den entsprechenden }
         { Sprung                                    }
         if temptovalue then
           begin
              if p^.t2^.location.loc=LOC_CREGISTER then
                emit(MOV,opsize,regid2str[p^.t2^.location.register]+','+
                  regid2str[cmpreg])
              else
                emit(MOV,opsize,getreferenzstring(p^.t2^.location.referenz)+','+
                  regid2str[cmpreg]);
              emit(CMP,opsize,getreferenzstring(temp1)+','+
                regid2str[cmpreg]);
           end
         else
           begin
              if p^.t2^.location.loc=LOC_CREGISTER then
                emit(CMP,opsize,'$'+tostr(p^.right^.value)+','+
                  regid2str[p^.t2^.location.register])
              else
                emit(CMP,opsize,'$'+tostr(p^.right^.value)+','+
                  getreferenzstring(p^.t2^.location.referenz));
           end;
         if p^.backward then
           hop:=JGE
         else hop:=JLE;
         emitl(hop,aktcontinuelabel);
         { break-Label: }
         emitl(A_LABEL,aktbreaklabel);
         ungetregister32(cmp32);

         aktcontinuelabel:=oldclabel;
         aktbreaklabel:=oldblabel;
      end;

    var
       hs : string;

    procedure secondexitn(var p : ptree);far;

      label
         do_jmp;

      begin
         if assigned(p^.left) then
           begin
              truelabel:=getlabel;
              falselabel:=getlabel;
              secondpass(p^.left);
              case p^.left^.location.loc of
                 LOC_MEM,LOC_REFERENZ : hs:=getreferenzstring(p^.left^.location.referenz);
                 LOC_CREGISTER,
                 LOC_REGISTER : hs:=regid2str[p^.left^.location.register];
                 LOC_FLAGS : begin
                                emit(flag_2_set[p^.right^.location.resflags],S_NO,'%al');
                                goto do_jmp;
                             end;
                 LOC_JUMP : begin
                               emitl(A_LABEL,truelabel);
                               emit(MOV,S_B,'$1,%al');
                               emitl(JMP,aktexit2label);
                               emit(A_XOR,S_B,'%al,%al');
                               goto do_jmp;
                            end;
                 else internalerror(2001);
              end;
              if (procinfo.retdef^.deftype=grunddef) then
                begin
                   case pgrunddef(procinfo.retdef)^.typ of
                      s32bit : emit(MOV,S_L,hs+',%eax');
                      u8bit,s8bit,uchar,bool8bit :
                        emit(MOV,S_B,hs+',%al');
                      s16bit,u16bit :
                        emit(MOV,S_W,hs+',%ax');
                      s64real :
                        emit(FLD,S_L,hs);
                   end;
                end
               else
                 if (procinfo.retdef^.deftype=pointerdef) or
                    (procinfo.retdef^.deftype=aufzaehldef) or
                    (procinfo.retdef^.deftype=procvardef) then
                    emit(MOV,S_L,hs+',%eax');
do_jmp:
              emitl(JMP,aktexit2label);
           end
         else
           begin
              emitl(JMP,aktexitlabel);
           end;
      end;

    procedure secondgoto(var p : ptree);far;

      begin
         emitl(JMP,p^.labelnr);
      end;

    procedure secondlabel(var p : ptree);far;

      begin
         emitl(A_LABEL,p^.labelnr);
         cleartempgen;
         secondpass(p^.left);
      end;

    procedure secondasm(var p : ptree);far;

      begin
         exprasmlist.concatlist(p^.p_asm);
      end;

    procedure secondcase(var p : ptree);far;

      var
         with_sign : boolean;
         opsize : topsize;
         jmp_gt,jmp_le,jmp_lee : tasmop;
         hp : ptree;
         { register with case expression }
         hregister : tregister;
         endlabel,elselabel : longint;

      procedure gentreejmp(p : pcaserecord);

        var
           lesslabel,greaterlabel : longint;

        begin
           emitl(A_LABEL,p^.at);

           { Labels für links und rechts berechnen }
           if (p^.less=nil) then
             lesslabel:=elselabel
           else
             lesslabel:=p^.less^.at;
           if (p^.greater=nil) then
             greaterlabel:=elselabel
           else
             greaterlabel:=p^.greater^.at;

           { keine Bereichslabel :}
           if p^.low=p^.high then
             begin
                emit(CMP,opsize,'$'+tostr(p^.low)+','+regid2str[hregister]);
                if greaterlabel=lesslabel then
                  begin
                     emitl(JNE,lesslabel);
                  end
                else
                  begin
                     emitl(jmp_le,lesslabel);
                     emitl(jmp_gt,greaterlabel);
                  end;
                emitl(JMP,p^.anweisung);
             end
           else
           { Bereichslabel: }
             begin
                emit(CMP,opsize,'$'+tostr(p^.low)+','+regid2str[hregister]);
                emitl(jmp_le,lesslabel);
                emit(CMP,opsize,'$'+tostr(p^.high)+','+regid2str[hregister]);
                emitl(jmp_gt,greaterlabel);
                emitl(JMP,p^.anweisung);
             end;
           if assigned(p^.less) then
             gentreejmp(p^.less);
           if assigned(p^.greater) then
             gentreejmp(p^.greater);
        end;

      procedure genlinearlist(hp : pcaserecord);

        var
           first : boolean;
           last : longint;
           helplabel : longint;

        procedure genitem(t : pcaserecord);

          begin
             if assigned(t^.less) then
               genitem(t^.less);
             if t^.low=t^.high then
               begin
                  if t^.low-last=1 then
                    emit(A_DEC,opsize,regid2str[hregister])
                  else if t^.low-last=0 then
                    emit(A_OR,opsize,regid2str[hregister]+','+regid2str[hregister])
                  else
                    emit(SUB,opsize,'$'+tostr(t^.low-last)+','+regid2str[hregister]);
                  last:=t^.low;

                  emitl(JZ,t^.anweisung);
               end
             else
               begin
                  { es wird mit dem kleinsten Label angefangen,    }
                  { sollte der Wert noch kleiner sein, dann gleich }
                  { zum ELSE-Label springen                        }
                  if first then
                    begin
                       if t^.low-1=1 then
                         emit(A_DEC,opsize,regid2str[hregister])
                       else if t^.low-1=0 then
                         emit(A_OR,opsize,regid2str[hregister]+','+regid2str[hregister])
                       else
                         emit(SUB,opsize,'$'+tostr(t^.low-1)+','+regid2str[hregister]);
                       emitl(jmp_lee,elselabel);
                    end
                  { ist zwischen dem letzten und dem aktuellen Label }
                  { keine Lücke, so kann direkt die untere Grenze    }
                  { geprüft werden                                   }
                  { ansonsten auf Bereich dazwischen prüfen:         }
                  else if (t^.low-last>1)then

                    begin
                       if t^.low-last-1=1 then
                         emit(A_DEC,opsize,regid2str[hregister])
                       else
                         emit(SUB,opsize,'$'+tostr(t^.low-last-1)+','+regid2str[hregister]);
                       emitl(jmp_lee,elselabel);
                    end;
                  emit(SUB,opsize,'$'+tostr(t^.high-t^.low+1)+','+regid2str[hregister]);
                  emitl(jmp_lee,t^.anweisung);

                  last:=t^.high;
               end;
             first:=false;
             if assigned(t^.greater) then
               genitem(t^.greater);
          end;

        var
           hr : tregister;

        begin
           { case register is modified by the list evalution }
           if (p^.left^.location.loc=LOC_CREGISTER) then
             begin
                hr:=getregister32;
                case opsize of
                   S_B : hregister:=reg32toreg8(hr);
                   S_W : hregister:=reg32toreg16(hr);
                   S_L : hregister:=hr;
                end;
             end;
           last:=0;
           first:=true;
           genitem(hp);
           emitl(JMP,elselabel);
        end;

      procedure genjumptable(hp : pcaserecord;min_,max_ : longint);

        var
           table,last : longint;

        procedure genitem(t : pcaserecord);

          var
             i : longint;

          begin
             if assigned(t^.less) then
               genitem(t^.less);
             { mögliche Lücken füllen }
             for i:=last+1 to t^.low-1 do
               emit(A_LONG,S_NO,tolabel(elselabel));
             for i:=t^.low to t^.high do
               emit(A_LONG,S_NO,tolabel(t^.anweisung));
             last:=t^.high;
             if assigned(t^.greater) then
               genitem(t^.greater);
          end;

        begin
           emit(CMP,opsize,'$'+tostr(min_)+','+regid2str[hregister]);
           { cas expr less than min_ => goto elselabel }
           emitl(jmp_le,elselabel);
           emit(CMP,opsize,'$'+tostr(max_)+','+regid2str[hregister]);
           emitl(jmp_gt,elselabel);
           table:=getlabel;
           { Vorzeichen erweitern }
           if opsize=S_W then
             begin
                emit(MOVZX,S_WL,regid2str[hregister]+
                  ','+regid2str[reg16toreg32(hregister)]);
                hregister:=reg16toreg32(hregister);
             end
           else if opsize=S_B then
             begin
                emit(MOVZX,S_BL,regid2str[hregister]+
                  ','+regid2str[reg8toreg32(hregister)]);
                hregister:=reg8toreg32(hregister);
             end;
           emit(JMP,S_NO,'*'+tolabel(table)+tostr_with_plus((-min_)*4)+'(,'+regid2str[hregister]+',4)');
           { Tabelle erzeugen }
           if not(cs_littlesize in aktswitches ) then
             emit(A_ALIGN,S_NO,'4,0x90');
           emitl(A_LABEL,table);
           last:=min_;
           genitem(hp);
           if not(cs_littlesize in aktswitches ) then
             emit(A_ALIGN,S_NO,'4,0x90');
        end;

      var
         min_label,max_label,labels : longint;

      begin
         endlabel:=getlabel;
         elselabel:=getlabel;
         with_sign:=is_signed(p^.left^.resulttype);
         if with_sign then
           begin
              jmp_gt:=JG;
              jmp_le:=JL;
              jmp_lee:=JLE;
           end
         else
           begin
              jmp_gt:=JA;
              jmp_le:=JB;
              jmp_lee:=JBE;
           end;
         cleartempgen;
         secondpass(p^.left);

         { determines the size of the operand }
         case p^.left^.resulttype^.size of
            1 : opsize:=S_B;
            2 : opsize:=S_W;
            4 : opsize:=S_L;
            else internalerror(2003);
         end;

         { copy the case expression to a register }
         case p^.left^.location.loc of
           LOC_REGISTER,
           LOC_CREGISTER : hregister:=p^.left^.location.register;
           LOC_MEM,LOC_REFERENZ : begin
                                     del_referenz(p^.left^.location.referenz);
                                     hregister:=getregister32;
                                     case opsize of
                                        S_B : hregister:=reg32toreg8(hregister);
                                        S_W : hregister:=reg32toreg16(hregister);
                                     end;
                                     emit(MOV,opsize,getreferenzstring(
                                       p^.left^.location.referenz)+','+regid2str[hregister]);
                                  end;
           else internalerror(2002);
         end;
         { now generate the jumps }
         if cs_optimize in aktswitches  then
           begin
              { Verfahren wird empirisch ermittelt        }
              { der Aufwand wäre auch berechenbar         }
              { aber lohnt sich das bei den verschiedenen }
              { Prozessoren ?                             }
              { außerdem ließe sich die Größe auch nur    }
              { ungefähr berechnen, da dei nicht bekannt  }
              { ist, ob rel8,rel16 oder rel32 Sprünge be- }
              { nötigt werden                             }
              min_label:=case_get_min(p^.nodes);
              max_label:=case_get_max(p^.nodes);
              labels:=case_count_labels(p^.nodes);
              { optimize for size ? }
              if cs_littlesize in aktswitches  then
                begin
                   { if the labels less or more a continuum then }
                   { generate a jump table                       }
                   if (labels<=2) or ((max_label-min_label)>3*labels) then

                   { a linear list is always smaller than a jump tree }
                     genlinearlist(p^.nodes)
                   else
                     genjumptable(p^.nodes,min_label,max_label);
                end
              else
                begin
                   if (labels<=2) then
                     genlinearlist(p^.nodes)
                   else
                     begin
                        if ((max_label-min_label)>6*labels) then
                          begin
                             if labels>16 then
                               gentreejmp(p^.nodes)
                             else
                               genlinearlist(p^.nodes);
                          end
                        else
                          genjumptable(p^.nodes,min_label,max_label);
                     end;
                end;
           end
         else
           { it's always not bad }
           genlinearlist(p^.nodes);

         { now generate the instructions }
         hp:=p^.right;
         while assigned(hp) do
           begin
              cleartempgen;
              secondpass(hp^.right);
              emitl(JMP,endlabel);
              hp:=hp^.left;
           end;
         emitl(A_LABEL,elselabel);
         { ... and the else block }
         if assigned(p^.elseblock) then
           begin
              cleartempgen;
              secondpass(p^.elseblock);
           end;
         emitl(A_LABEL,endlabel);
      end;

    procedure secondpass(var p : ptree);

      const
         procedures : array[addn..simplenewn] of secondpassproc =
            (secondadd,secondadd,secondadd,secondmoddiv,
             secondmoddiv,secondassignment,secondload,secondnothing,
             secondadd,secondadd,secondadd,secondadd,
             secondadd,secondadd,secondin,secondadd,
             secondadd,secondshlshr,secondshlshr,secondadd,
             secondadd,secondsubscriptn,secondderef,secondaddr,
             secondordconst,secondtypeconv,secondcalln,secondnothing,
             secondrealconst,secondumminus,secondasm,secondvecn,
             secondstringconst,secondfuncret,secondselfn,
             secondnot,secondinline,secondniln,seconderror,
             secondnothing,secondhnewn,secondhdisposen,secondnewn,
             secondsimplenewdispose,secondnothing,secondsetcons,secondblockn,
             secondnothing,secondnothing,secondifn,secondbreakn,
             secondcontinuen,second_while_repeatn,second_while_repeatn,secondfor,
             secondexitn,secondnothing,secondcase,secondlabel,
             secondgoto,secondsimplenewdispose);

      var
         oldcodegenerror : boolean;

      begin
         oldcodegenerror:=codegenerror;
         codegenerror:=false;
         inputstack:=p^.inputfile;
         inputstack^.line_no:=p^.line;
         if not(p^.error) then
           begin
              procedures[p^.treetype](p);
              p^.error:=codegenerror;
              codegenerror:=codegenerror or oldcodegenerror;
           end
         else codegenerror:=true;
      end;

    function do_secondpass(var p : ptree) : boolean;

      begin
         codegenerror:=false;
         if not(p^.error) then
           secondpass(p);
         do_secondpass:=codegenerror;
      end;

    var
       regvars : array[1..maxvarregs] of pvarsym;

    procedure searchregvars(p : psym);far;

      var
         i,j : longint;

      begin
         if (p^.typ=varsym) and (pvarsym(p)^.regable) then
           begin
              { alle momentanen Registervariablen durchlaufen }
              for i:=1 to maxvarregs do
                begin
                   { noch ein Register frei? }
                   if regvars[i]=nil then
                     begin
                        regvars[i]:=pvarsym(p);
                        break;
                     end;
                   { oder eine Variable hinauswerfen? }
                   if pvarsym(p)^.refs>regvars[i]^.refs then
                     begin
                        for j:=maxvarregs-1 downto i do
                          regvars[j+1]:=regvars[j];
                        regvars[i]:=pvarsym(p);
                        break;
                     end;
                end;
           end;
      end;

    procedure generatecode(var p : ptree);

      var
         { *pass modifiziert für jede Node aktlinenr und inputstack, }
         { um immer richtige Zeilennummern zu erhalten               }
         oldis : pinputstack;
         oldnr,i : longint;

      begin
         cleartempgen;
         oldis:=inputstack;
         oldnr:=inputstack^.line_no;

         { bei Größe nur Vorkommen zählen      }
         if cs_littlesize in aktswitches  then
           t_times:=1
         else
         { Referenz für Wiederholungen ist 100, }
         { wenn auf Geschwindigkeit optimiert   }
         { wird                                 }
           t_times:=100;

         if not(do_firstpass(p)) then
           begin
              { Registervariablen möglich ? }
              if (cs_maxoptimieren in aktswitches) and (p^.registers32<4) and
                 not(procinfo.uses_asm) then
                begin
                   { Kandidaten für Register heraussuchen }
                   for i:=1 to maxvarregs do
                     regvars[i]:=nil;
{$ifdef tp}
                   symtablestack^.foreach(searchregvars);
{$else}
                   symtablestack^.foreach(@searchregvars);
{$endif}

                   { benötigte Register freihalten }
                   for i:=maxvarregs downto maxvarregs-p^.registers32+1 do
                     regvars[i]:=nil;
                   { nun die Register aufteilen }
                   for i:=1 to maxvarregs do
                     begin
                        if assigned(regvars[i]) then
                          begin
                             { Register ist nicht mehr für Ausdrücke }
                             { verfügbar                             }
                             usableregs:=usableregs-[varregs[i]];
                             dec(c_usableregs);

                             { möglicherweise werden keine 32 Bit Register }
                             { gebraucht:                                  }
                             if  (regvars[i]^.definition^.deftype=grunddef) and
                                 (
                                  (pgrunddef(regvars[i]^.definition)^.typ=bool8bit) or
                                  (pgrunddef(regvars[i]^.definition)^.typ=uchar) or
                                  (pgrunddef(regvars[i]^.definition)^.typ=u8bit) or
                                  (pgrunddef(regvars[i]^.definition)^.typ=s8bit)
                                 ) then
                               regvars[i]^.reg:=reg32toreg8(varregs[i])
                             else if  (regvars[i]^.definition^.deftype=grunddef) and
                                 (
                                  (pgrunddef(regvars[i]^.definition)^.typ=u16bit) or
                                  (pgrunddef(regvars[i]^.definition)^.typ=s16bit)
                                 ) then
                               regvars[i]^.reg:=reg32toreg16(varregs[i])
                             else regvars[i]^.reg:=varregs[i];
                             { Register ist im Unterprogramm belegt }
                             usedinproc:=usedinproc or ($80 shr byte(varregs[i]));
                          end;
                     end;
{$ifdef EXTDEBUG}
                   for i:=1 to maxvarregs do
                     begin
                        if assigned(regvars[i]) then
                          writeln('  Register ',regid2str[regvars[i]^.reg],': ',regvars[i]^.name,
                            '  Gewichtung: ',regvars[i]^.refs);
                     end;
{$endif}
                end;
              do_secondpass(p);

              { alle Register sind wieder benutzbar }
              usableregs:=[R_EAX,R_EBX,R_ECX,R_EDX];
              c_usableregs:=4;
           end;
         aktproccode.concatlist(@exprasmlist);

         inputstack:=oldis;
         inputstack^.line_no:=oldnr;
      end;

    procedure codegeninit;

      begin
         aktbreaklabel:=0;
         aktexitlabel:=0;
         aktcontinuelabel:=0;
         aktexitlabel:=0;
         aktexceptlabel:=0;
         aktentrycode.init;
         aktexitcode.init;
         aktexceptcode.init;
         aktproccode.init;
         exprasmlist.init;
         datasegment.init;
         constsegment.init;
         vmtasmlist.init;
         debuginfos.init;
      end;

    procedure codegendone;

      begin
         aktentrycode.done;
         aktexitcode.done;
         aktexceptcode.done;
         aktproccode.done;
         exprasmlist.done;
         datasegment.done;
         constsegment.done;
         vmtasmlist.done;
         debuginfos.done;
      end;

end.
[ RETURN TO DIRECTORY ]