2
0
florian 25 жил өмнө
parent
commit
8ba7c62c93
1 өөрчлөгдсөн 2327 нэмэгдсэн , 0 устгасан
  1. 2327 0
      compiler/n386add.pas

+ 2327 - 0
compiler/n386add.pas

@@ -0,0 +1,2327 @@
+{
+    $Id$
+    Copyright (c) 2000 by Florian Klaempfl
+
+    Code generation for add nodes on the i386
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit n386add;
+
+  interface
+
+    uses
+       nadd;
+
+    ti386addnode = class(taddnode)
+      procedure pass_2;override;
+      function getresflags(unsigned : boolean) : tresflags;
+      procedure SetResultLocation(cmpop,unsigned : boolean);
+      procedure addstring;
+    end;
+
+  implementation
+
+    function ti386addnode.getresflags(unsigned : boolean) : tresflags;
+
+      begin
+         if not(unsigned) then
+           begin
+              if swaped then
+                case treetype of
+                   equaln : getresflags:=F_E;
+                   unequaln : getresflags:=F_NE;
+                   ltn : getresflags:=F_G;
+                   lten : getresflags:=F_GE;
+                   gtn : getresflags:=F_L;
+                   gten : getresflags:=F_LE;
+                end
+              else
+                case treetype of
+                   equaln : getresflags:=F_E;
+                   unequaln : getresflags:=F_NE;
+                   ltn : getresflags:=F_L;
+                   lten : getresflags:=F_LE;
+                   gtn : getresflags:=F_G;
+                   gten : getresflags:=F_GE;
+                end;
+           end
+         else
+           begin
+              if swaped then
+                case treetype of
+                   equaln : getresflags:=F_E;
+                   unequaln : getresflags:=F_NE;
+                   ltn : getresflags:=F_A;
+                   lten : getresflags:=F_AE;
+                   gtn : getresflags:=F_B;
+                   gten : getresflags:=F_BE;
+                end
+              else
+                case treetype of
+                   equaln : getresflags:=F_E;
+                   unequaln : getresflags:=F_NE;
+                   ltn : getresflags:=F_B;
+                   lten : getresflags:=F_BE;
+                   gtn : getresflags:=F_A;
+                   gten : getresflags:=F_AE;
+                end;
+           end;
+      end;
+
+
+    procedure ti386addnode.SetResultLocation(cmpop,unsigned : boolean);
+
+      begin
+         { remove temporary location if not a set or string }
+         { that's a bad hack (FK) who did this ?            }
+         if (left.resulttype^.deftype<>stringdef) and
+            ((left.resulttype^.deftype<>setdef) or (psetdef(left.resulttype)^.settype=smallset)) and
+            (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
+           ungetiftemp(left.location.reference);
+         if (right^.resulttype^.deftype<>stringdef) and
+            ((right^.resulttype^.deftype<>setdef) or (psetdef(right^.resulttype)^.settype=smallset)) and
+            (right^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
+           ungetiftemp(right^.location.reference);
+         { in case of comparison operation the put result in the flags }
+         if cmpop then
+           begin
+              clear_location(location);
+              location.loc:=LOC_FLAGS;
+              location.resflags:=getresflags(p,unsigned);
+           end;
+      end;
+
+
+{*****************************************************************************
+                                Addstring
+*****************************************************************************}
+
+    procedure ti386addnode.addstring;
+
+      var
+{$ifdef newoptimizations2}
+        l: pasmlabel;
+        hreg: tregister;
+        href2: preference;
+        oldregisterdef: boolean;
+{$endif newoptimizations2}
+        pushedregs : tpushed;
+        href       : treference;
+        pushed,
+        cmpop      : boolean;
+        regstopush : byte;
+      begin
+        { string operations are not commutative }
+        if swaped then
+          swapleftright;
+        case pstringdef(left.resulttype)^.string_typ of
+           st_ansistring:
+             begin
+                case treetype of
+                   addn:
+                     begin
+                        cmpop:=false;
+                        secondpass(left);
+                        { to avoid problem with maybe_push and restore }
+                        set_location(location,left.location);
+                        pushed:=maybe_push(right.registers32,self,false);
+                        secondpass(right);
+                        if pushed then
+                          begin
+                             restore(p,false);
+                             set_location(left.location,location);
+                          end;
+                        { get the temp location, must be done before regs are
+                          released/pushed because after the release the regs are
+                          still used for the push (PFV) }
+                        clear_location(location);
+                        location.loc:=LOC_MEM;
+                        gettempansistringreference(location.reference);
+                        decrstringref(cansistringdef,location.reference);
+                        { release used registers }
+                        del_location(right.location);
+                        del_location(left.location);
+                        { push the still used registers }
+                        pushusedregisters(pushedregs,$ff);
+                        { push data }
+                        emitpushreferenceaddr(location.reference);
+                        emit_push_loc(right.location);
+                        emit_push_loc(left.location);
+                        emitcall('FPC_ANSISTR_CONCAT');
+                        popusedregisters(pushedregs);
+                        maybe_loadesi;
+                        ungetiftempansi(left.location.reference);
+                        ungetiftempansi(right.location.reference);
+                     end;
+                   ltn,lten,gtn,gten,
+                   equaln,unequaln:
+                     begin
+                        cmpop:=true;
+                        if (treetype in [equaln,unequaln]) and
+                           (left.treetype=stringconstn) and
+                           (left.length=0) then
+                          begin
+                             secondpass(right);
+                             { release used registers }
+                             del_location(right.location);
+                             del_location(left.location);
+                             case right.location.loc of
+                               LOC_REFERENCE,LOC_MEM:
+                                 emit_const_ref(A_CMP,S_L,0,newreference(right.location.reference));
+                               LOC_REGISTER,LOC_CREGISTER:
+                                 emit_const_reg(A_CMP,S_L,0,right.location.register);
+                             end;
+                             ungetiftempansi(left.location.reference);
+                             ungetiftempansi(right.location.reference);
+                          end
+                        else if (treetype in [equaln,unequaln]) and
+                          (right.treetype=stringconstn) and
+                          (right.length=0) then
+                          begin
+                             secondpass(left);
+                             { release used registers }
+                             del_location(right.location);
+                             del_location(left.location);
+                             case right.location.loc of
+                               LOC_REFERENCE,LOC_MEM:
+                                 emit_const_ref(A_CMP,S_L,0,newreference(left.location.reference));
+                               LOC_REGISTER,LOC_CREGISTER:
+                                 emit_const_reg(A_CMP,S_L,0,left.location.register);
+                             end;
+                             ungetiftempansi(left.location.reference);
+                             ungetiftempansi(right.location.reference);
+                          end
+                        else
+                          begin
+                             secondpass(left);
+                             pushed:=maybe_push(right.registers32,left,false);
+                             secondpass(right);
+                             if pushed then
+                               restore(left,false);
+                             { release used registers }
+                             del_location(right.location);
+                             del_location(left.location);
+                             { push the still used registers }
+                             pushusedregisters(pushedregs,$ff);
+                             { push data }
+                             case right.location.loc of
+                               LOC_REFERENCE,LOC_MEM:
+                                 emit_push_mem(right.location.reference);
+                               LOC_REGISTER,LOC_CREGISTER:
+                                 emit_reg(A_PUSH,S_L,right.location.register);
+                             end;
+                             case left.location.loc of
+                               LOC_REFERENCE,LOC_MEM:
+                                 emit_push_mem(left.location.reference);
+                               LOC_REGISTER,LOC_CREGISTER:
+                                 emit_reg(A_PUSH,S_L,left.location.register);
+                             end;
+                             emitcall('FPC_ANSISTR_COMPARE');
+                             emit_reg_reg(A_OR,S_L,R_EAX,R_EAX);
+                             popusedregisters(pushedregs);
+                             maybe_loadesi;
+                             ungetiftempansi(left.location.reference);
+                             ungetiftempansi(right.location.reference);
+                          end;
+                     end;
+                end;
+               { the result of ansicompare is signed }
+               SetResultLocation(cmpop,false,p);
+             end;
+           st_shortstring:
+             begin
+                case treetype of
+                   addn:
+                     begin
+                        cmpop:=false;
+                        secondpass(left);
+                        { if str_concat is set in expr
+                          s:=s+ ... no need to create a temp string (PM) }
+
+                        if (left.treetype<>addn) and not (use_strconcat) then
+                          begin
+
+                             { can only reference be }
+                             { string in register would be funny    }
+                             { therefore produce a temporary string }
+
+                             gettempofsizereference(256,href);
+                             copyshortstring(href,left.location.reference,255,false,true);
+                             { release the registers }
+{                             done by copyshortstring now (JM)           }
+{                             del_reference(left.location.reference); }
+                             ungetiftemp(left.location.reference);
+
+                             { does not hurt: }
+                             clear_location(left.location);
+                             left.location.loc:=LOC_MEM;
+                             left.location.reference:=href;
+
+{$ifdef newoptimizations2}
+                             { length of temp string = 255 (JM) }
+                             { *** redefining a type is not allowed!! (thanks, Pierre) }
+                             { also problem with constant string!                      }
+                             pstringdef(left.resulttype)^.len := 255;
+
+{$endif newoptimizations2}
+                          end;
+
+                        secondpass(right);
+
+{$ifdef newoptimizations2}
+                        { special case for string := string + char (JM) }
+                        { needs string length stuff from above!         }
+                        hreg := R_NO;
+                        if is_shortstring(left.resulttype) and
+                           is_char(right.resulttype) then
+                          begin
+                            getlabel(l);
+                            getexplicitregister32(R_EDI);
+                            { load the current string length }
+                            emit_ref_reg(A_MOVZX,S_BL,
+                              newreference(left.location.reference),R_EDI);
+                            { is it already maximal? }
+                            emit_const_reg(A_CMP,S_L,
+                              pstringdef(left.resulttype)^.len,R_EDI);
+                            emitjmp(C_E,l);
+                            { no, so add the new character }
+                            { is it a constant char? }
+                            if (right.treetype <> ordconstn) then
+                              { no, make sure it is in a register }
+                              if right.location.loc in [LOC_REFERENCE,LOC_MEM] then
+                                begin
+                                  { free the registers of right }
+                                  del_reference(right.location.reference);
+                                  { get register for the char }
+                                  hreg := reg32toreg8(getregister32);
+                                  emit_ref_reg(A_MOV,S_B,
+                                    newreference(right.location.reference),
+                                    hreg);
+                                 { I don't think a temp char exists, but it won't hurt (JM)Ê}
+                                 ungetiftemp(right.location.reference);
+                                end
+                              else hreg := right.location.register;
+                            href2 := newreference(left.location.reference);
+                            { we need a new reference to store the character }
+                            { at the end of the string. Check if the base or }
+                            { index register is still free                   }
+                            if (left.location.reference.base <> R_NO) and
+                               (left.location.reference.index <> R_NO) then
+                              begin
+                                { they're not free, so add the base reg to }
+                                { the string length (since the index can   }
+                                { have a scalefactor) and use EDI as base  }
+                                emit_reg_reg(A_ADD,S_L,
+                                  left.location.reference.base,R_EDI);
+                                href2^.base := R_EDI;
+                              end
+                            else
+                              { at least one is still free, so put EDI there }
+                              if href2^.base = R_NO then
+                                href2^.base := R_EDI
+                              else
+                                begin
+                                  href2^.index := R_EDI;
+                                  href2^.scalefactor := 1;
+                                end;
+                            { we need to be one position after the last char }
+                            inc(href2^.offset);
+                            { increase the string length }
+                            emit_ref(A_INC,S_B,newreference(left.location.reference));
+                            { and store the character at the end of the string }
+                            if (right.treetype <> ordconstn) then
+                              begin
+                                { no new_reference(href2) because it's only }
+                                { used once (JM)                            }
+                                emit_reg_ref(A_MOV,S_B,hreg,href2);
+                                ungetregister(hreg);
+                              end
+                            else
+                              emit_const_ref(A_MOV,S_B,right.value,href2);
+                            emitlab(l);
+                            ungetregister32(R_EDI);
+                          end
+                        else
+                          begin
+{$endif  newoptimizations2}
+                        { on the right we do not need the register anymore too }
+                        { Instead of releasing them already, simply do not }
+                        { push them (so the release is in the right place, }
+                        { because emitpushreferenceaddr doesn't need extra }
+                        { registers) (JM)                                  }
+                            regstopush := $ff;
+                            remove_non_regvars_from_loc(right.location,
+                              regstopush);
+                           pushusedregisters(pushedregs,regstopush);
+                           { push the maximum possible length of the result }
+{$ifdef newoptimizations2}
+                           { string (could be < 255 chars now) (JM)         }
+                            emit_const(A_PUSH,S_L,
+                              pstringdef(left.resulttype)^.len);
+{$endif newoptimizations2}
+                            emitpushreferenceaddr(left.location.reference);
+                           { the optimizer can more easily put the          }
+                           { deallocations in the right place if it happens }
+                           { too early than when it happens too late (if    }
+                           { the pushref needs a "lea (..),edi; push edi")  }
+                            del_reference(right.location.reference);
+                            emitpushreferenceaddr(right.location.reference);
+{$ifdef newoptimizations2}
+                            emitcall('FPC_SHORTSTR_CONCAT_LEN');
+{$else newoptimizations2}
+                            emitcall('FPC_SHORTSTR_CONCAT');
+{$endif newoptimizations2}
+                            ungetiftemp(right.location.reference);
+                            maybe_loadesi;
+                            popusedregisters(pushedregs);
+{$ifdef newoptimizations2}
+                        end;
+{$endif newoptimizations2}
+                        set_location(location,left.location);
+                     end;
+                   ltn,lten,gtn,gten,
+                   equaln,unequaln :
+                     begin
+                        cmpop:=true;
+                        { generate better code for s='' and s<>'' }
+                        if (treetype in [equaln,unequaln]) and
+                           (((left.treetype=stringconstn) and (str_length(left)=0)) or
+                            ((right.treetype=stringconstn) and (str_length(right)=0))) then
+                          begin
+                             secondpass(left);
+                             { are too few registers free? }
+                             pushed:=maybe_push(right.registers32,left,false);
+                             secondpass(right);
+                             if pushed then
+                               restore(left,false);
+                             { only one node can be stringconstn }
+                             { else pass 1 would have evaluted   }
+                             { this node                         }
+                             if left.treetype=stringconstn then
+                               emit_const_ref(
+                                 A_CMP,S_B,0,newreference(right.location.reference))
+                             else
+                               emit_const_ref(
+                                 A_CMP,S_B,0,newreference(left.location.reference));
+                             del_reference(right.location.reference);
+                             del_reference(left.location.reference);
+                          end
+                        else
+                          begin
+                             pushusedregisters(pushedregs,$ff);
+                             secondpass(left);
+                             emitpushreferenceaddr(left.location.reference);
+                             del_reference(left.location.reference);
+                             secondpass(right);
+                             emitpushreferenceaddr(right.location.reference);
+                             del_reference(right.location.reference);
+                             emitcall('FPC_SHORTSTR_COMPARE');
+                             maybe_loadesi;
+                             popusedregisters(pushedregs);
+                          end;
+                        ungetiftemp(left.location.reference);
+                        ungetiftemp(right.location.reference);
+                     end;
+                   else CGMessage(type_e_mismatch);
+                end;
+               SetResultLocation(cmpop,true,p);
+             end;
+          end;
+      end;
+
+
+{*****************************************************************************
+                                Addset
+*****************************************************************************}
+
+    procedure addset(var p : ptree);
+      var
+        createset,
+        cmpop,
+        pushed : boolean;
+        href   : treference;
+        pushedregs : tpushed;
+        regstopush: byte;
+      begin
+        cmpop:=false;
+
+        { not commutative }
+        if swaped then
+         swaptree(p);
+
+        { optimize first loading of a set }
+{$ifdef usecreateset}
+        if (right.treetype=setelementn) and
+           not(assigned(right.right)) and
+           is_emptyset(left) then
+         createset:=true
+        else
+{$endif}
+         begin
+           createset:=false;
+           secondpass(left);
+         end;
+
+        { are too few registers free? }
+        pushed:=maybe_push(right.registers32,left,false);
+        secondpass(right);
+        if codegenerror then
+          exit;
+        if pushed then
+          restore(left,false);
+
+        set_location(location,left.location);
+
+        { handle operations }
+
+        case treetype of
+          equaln,
+        unequaln
+{$IfNDef NoSetInclusion}
+        ,lten, gten
+{$EndIf NoSetInclusion}
+                  : begin
+                     cmpop:=true;
+                     del_location(left.location);
+                     del_location(right.location);
+                     pushusedregisters(pushedregs,$ff);
+{$IfNDef NoSetInclusion}
+                     If (treetype in [equaln, unequaln, lten]) Then
+                       Begin
+{$EndIf NoSetInclusion}
+                         emitpushreferenceaddr(right.location.reference);
+                         emitpushreferenceaddr(left.location.reference);
+{$IfNDef NoSetInclusion}
+                       End
+                     Else  {gten = lten, if the arguments are reversed}
+                       Begin
+                         emitpushreferenceaddr(left.location.reference);
+                         emitpushreferenceaddr(right.location.reference);
+                       End;
+                     Case treetype of
+                       equaln, unequaln:
+{$EndIf NoSetInclusion}
+                         emitcall('FPC_SET_COMP_SETS');
+{$IfNDef NoSetInclusion}
+                       lten, gten:
+                         Begin
+                           emitcall('FPC_SET_CONTAINS_SETS');
+                           { we need a jne afterwards, not a jnbe/jnae }
+                           treetype := equaln;
+                        End;
+                     End;
+{$EndIf NoSetInclusion}
+                     maybe_loadesi;
+                     popusedregisters(pushedregs);
+                     ungetiftemp(left.location.reference);
+                     ungetiftemp(right.location.reference);
+                   end;
+            addn : begin
+                   { add can be an other SET or Range or Element ! }
+                     { del_location(right.location);
+                       done in pushsetelement below PM
+
+                     And someone added it again because those registers must
+                     not be pushed by the pushusedregisters, however this
+                     breaks the optimizer (JM)
+
+                     del_location(right.location);
+                     pushusedregisters(pushedregs,$ff);}
+
+                     regstopush := $ff;
+                     remove_non_regvars_from_loc(right.location,regstopush);
+                     remove_non_regvars_from_loc(left.location,regstopush);
+                     pushusedregisters(pushedregs,regstopush);
+                     { this is still right before the instruction that uses }
+                     { left.location, but that can be fixed by the      }
+                     { optimizer. There must never be an additional         }
+                     { between the release and the use, because that is not }
+                     { detected/fixed. As Pierre said above, right.loc  }
+                     { will be released in pushsetelement (JM)              }
+                     del_location(left.location);
+                     href.symbol:=nil;
+                     gettempofsizereference(32,href);
+                     if createset then
+                      begin
+                        pushsetelement(right.left);
+                        emitpushreferenceaddr(href);
+                        emitcall('FPC_SET_CREATE_ELEMENT');
+                      end
+                     else
+                      begin
+                      { add a range or a single element? }
+                        if right.treetype=setelementn then
+                         begin
+{$IfNDef regallocfix}
+                           concatcopy(left.location.reference,href,32,false,false);
+{$Else regallocfix}
+                           concatcopy(left.location.reference,href,32,true,false);
+{$EndIf regallocfix}
+                           if assigned(right.right) then
+                            begin
+                              pushsetelement(right.right);
+                              pushsetelement(right.left);
+                              emitpushreferenceaddr(href);
+                              emitcall('FPC_SET_SET_RANGE');
+                            end
+                           else
+                            begin
+                              pushsetelement(right.left);
+                              emitpushreferenceaddr(href);
+                              emitcall('FPC_SET_SET_BYTE');
+                            end;
+                         end
+                        else
+                         begin
+                         { must be an other set }
+                           emitpushreferenceaddr(href);
+                           emitpushreferenceaddr(right.location.reference);
+{$IfDef regallocfix}
+                           del_location(right.location);
+{$EndIf regallocfix}
+                           emitpushreferenceaddr(left.location.reference);
+{$IfDef regallocfix}
+                           del_location(left.location);
+{$EndIf regallocfix}
+                           emitcall('FPC_SET_ADD_SETS');
+                         end;
+                      end;
+                     maybe_loadesi;
+                     popusedregisters(pushedregs);
+                     ungetiftemp(left.location.reference);
+                     ungetiftemp(right.location.reference);
+                     location.loc:=LOC_MEM;
+                     location.reference:=href;
+                   end;
+            subn,
+         symdifn,
+            muln : begin
+                     { Find out which registers have to pushed (JM) }
+                     regstopush := $ff;
+                     remove_non_regvars_from_loc(left.location,regstopush);
+                     remove_non_regvars_from_loc(right.location,regstopush);
+                     { Push them (JM) }
+                     pushusedregisters(pushedregs,regstopush);
+                     href.symbol:=nil;
+                     gettempofsizereference(32,href);
+                     emitpushreferenceaddr(href);
+                     { Release the registers right before they're used,  }
+                     { see explanation in cgai386.pas:loadansistring for }
+                     { info why this is done right before the push (JM)  }
+                     del_location(right.location);
+                     emitpushreferenceaddr(right.location.reference);
+                     { The same here }
+                     del_location(left.location);
+                     emitpushreferenceaddr(left.location.reference);
+                     case treetype of
+                      subn : emitcall('FPC_SET_SUB_SETS');
+                   symdifn : emitcall('FPC_SET_SYMDIF_SETS');
+                      muln : emitcall('FPC_SET_MUL_SETS');
+                     end;
+                     maybe_loadesi;
+                     popusedregisters(pushedregs);
+                     ungetiftemp(left.location.reference);
+                     ungetiftemp(right.location.reference);
+                     location.loc:=LOC_MEM;
+                     location.reference:=href;
+                   end;
+        else
+          CGMessage(type_e_mismatch);
+        end;
+        SetResultLocation(cmpop,true,p);
+      end;
+
+
+{*****************************************************************************
+                                SecondAdd
+*****************************************************************************}
+
+    procedure secondadd(var p : ptree);
+    { is also being used for xor, and "mul", "sub, or and comparative }
+    { operators                                                }
+
+      label do_normal;
+
+      var
+         hregister,hregister2 : tregister;
+         noswap,popeax,popedx,
+         pushed,mboverflow,cmpop : boolean;
+         op,op2 : tasmop;
+         flags : tresflags;
+         otl,ofl : pasmlabel;
+         power : longint;
+         opsize : topsize;
+         hl4: pasmlabel;
+         hr : preference;
+
+         { true, if unsigned types are compared }
+         unsigned : boolean;
+         { true, if a small set is handled with the longint code }
+         is_set : boolean;
+         { is_in_dest if the result is put directly into }
+         { the resulting refernce or varregister }
+         is_in_dest : boolean;
+         { true, if for sets subtractions the extra not should generated }
+         extra_not : boolean;
+
+{$ifdef SUPPORT_MMX}
+         mmxbase : tmmxtype;
+{$endif SUPPORT_MMX}
+         pushedreg : tpushed;
+         hloc : tlocation;
+         regstopush: byte;
+
+      procedure firstjmp64bitcmp;
+
+        var
+           oldtreetype : ttreetyp;
+
+        begin
+           { the jump the sequence is a little bit hairy }
+           case treetype of
+              ltn,gtn:
+                begin
+                   emitjmp(flag_2_cond[getresflags(p,unsigned)],truelabel);
+                   { cheat a little bit for the negative test }
+                   swaped:=not(swaped);
+                   emitjmp(flag_2_cond[getresflags(p,unsigned)],falselabel);
+                   swaped:=not(swaped);
+                end;
+              lten,gten:
+                begin
+                   oldtreetype:=treetype;
+                   if treetype=lten then
+                     treetype:=ltn
+                   else
+                     treetype:=gtn;
+                   emitjmp(flag_2_cond[getresflags(p,unsigned)],truelabel);
+                   { cheat for the negative test }
+                   if treetype=ltn then
+                     treetype:=gtn
+                   else
+                     treetype:=ltn;
+                   emitjmp(flag_2_cond[getresflags(p,unsigned)],falselabel);
+                   treetype:=oldtreetype;
+                end;
+              equaln:
+                emitjmp(C_NE,falselabel);
+              unequaln:
+                emitjmp(C_NE,truelabel);
+           end;
+        end;
+
+      procedure secondjmp64bitcmp;
+
+        begin
+           { the jump the sequence is a little bit hairy }
+           case treetype of
+              ltn,gtn,lten,gten:
+                begin
+                   { the comparisaion of the low dword have to be }
+                   {  always unsigned!                            }
+                   emitjmp(flag_2_cond[getresflags(p,true)],truelabel);
+                   emitjmp(C_None,falselabel);
+                end;
+              equaln:
+                begin
+                   emitjmp(C_NE,falselabel);
+                   emitjmp(C_None,truelabel);
+                end;
+              unequaln:
+                begin
+                   emitjmp(C_NE,truelabel);
+                   emitjmp(C_None,falselabel);
+                end;
+           end;
+        end;
+
+      begin
+      { to make it more readable, string and set (not smallset!) have their
+        own procedures }
+         case left.resulttype^.deftype of
+         stringdef : begin
+                       addstring(p);
+                       exit;
+                     end;
+            setdef : begin
+                     { normalsets are handled separate }
+                       if not(psetdef(left.resulttype)^.settype=smallset) then
+                        begin
+                          addset(p);
+                          exit;
+                        end;
+                     end;
+         end;
+
+         { defaults }
+         unsigned:=false;
+         is_in_dest:=false;
+         extra_not:=false;
+         noswap:=false;
+         opsize:=S_L;
+
+         { are we a (small)set, must be set here because the side can be
+           swapped ! (PFV) }
+         is_set:=(left.resulttype^.deftype=setdef);
+
+         { calculate the operator which is more difficult }
+         firstcomplex(p);
+
+         { handling boolean expressions extra: }
+         if is_boolean(left.resulttype) and
+            is_boolean(right.resulttype) then
+           begin
+             if (porddef(left.resulttype)^.typ=bool8bit) or
+                (porddef(right.resulttype)^.typ=bool8bit) then
+               opsize:=S_B
+             else
+               if (porddef(left.resulttype)^.typ=bool16bit) or
+                  (porddef(right.resulttype)^.typ=bool16bit) then
+                 opsize:=S_W
+             else
+               opsize:=S_L;
+             case treetype of
+              andn,
+               orn : begin
+                       clear_location(location);
+                       location.loc:=LOC_JUMP;
+                       cmpop:=false;
+                       case treetype of
+                        andn : begin
+                                  otl:=truelabel;
+                                  getlabel(truelabel);
+                                  secondpass(left);
+                                  maketojumpbool(left);
+                                  emitlab(truelabel);
+                                  truelabel:=otl;
+                               end;
+                        orn : begin
+                                 ofl:=falselabel;
+                                 getlabel(falselabel);
+                                 secondpass(left);
+                                 maketojumpbool(left);
+                                 emitlab(falselabel);
+                                 falselabel:=ofl;
+                              end;
+                       else
+                         CGMessage(type_e_mismatch);
+                       end;
+                       secondpass(right);
+                       maketojumpbool(right);
+                     end;
+          unequaln,ltn,lten,gtn,gten,
+       equaln,xorn : begin
+                       if left.treetype=ordconstn then
+                        swaptree(p);
+                       if left.location.loc=LOC_JUMP then
+                         begin
+                            otl:=truelabel;
+                            getlabel(truelabel);
+                            ofl:=falselabel;
+                            getlabel(falselabel);
+                         end;
+
+                       secondpass(left);
+                       { if in flags then copy first to register, because the
+                         flags can be destroyed }
+                       case left.location.loc of
+                          LOC_FLAGS:
+                            locflags2reg(left.location,opsize);
+                          LOC_JUMP:
+                            locjump2reg(left.location,opsize, otl, ofl);
+                       end;
+                       set_location(location,left.location);
+                       pushed:=maybe_push(right.registers32,p,false);
+                       if right.location.loc=LOC_JUMP then
+                         begin
+                            otl:=truelabel;
+                            getlabel(truelabel);
+                            ofl:=falselabel;
+                            getlabel(falselabel);
+                         end;
+                       secondpass(right);
+                       if pushed then
+                         begin
+                            restore(p,false);
+                            set_location(left.location,location);
+                         end;
+                       case right.location.loc of
+                          LOC_FLAGS:
+                            locflags2reg(right.location,opsize);
+                          LOC_JUMP:
+                            locjump2reg(right.location,opsize,otl,ofl);
+                       end;
+                       goto do_normal;
+                    end
+             else
+               CGMessage(type_e_mismatch);
+             end
+           end
+         else
+           begin
+              { in case of constant put it to the left }
+              if (left.treetype=ordconstn) then
+               swaptree(p);
+              secondpass(left);
+              { this will be complicated as
+               a lot of code below assumes that
+               location and left.location are the same }
+
+{$ifdef test_dest_loc}
+              if dest_loc_known and (dest_loc_tree=p) and
+                 ((dest_loc.loc=LOC_REGISTER) or (dest_loc.loc=LOC_CREGISTER)) then
+                begin
+                   set_location(location,dest_loc);
+                   in_dest_loc:=true;
+                   is_in_dest:=true;
+                end
+              else
+{$endif test_dest_loc}
+                set_location(location,left.location);
+
+              { are too few registers free? }
+              pushed:=maybe_push(right.registers32,p,is_64bitint(left.resulttype));
+              secondpass(right);
+              if pushed then
+                begin
+                  restore(p,is_64bitint(left.resulttype));
+                  set_location(left.location,location);
+                end;
+
+              if (left.resulttype^.deftype=pointerdef) or
+
+                 (right.resulttype^.deftype=pointerdef) or
+
+                 ((right.resulttype^.deftype=objectdef) and
+                  pobjectdef(right.resulttype)^.is_class and
+                 (left.resulttype^.deftype=objectdef) and
+                  pobjectdef(left.resulttype)^.is_class
+                 ) or
+
+                 (left.resulttype^.deftype=classrefdef) or
+
+                 (left.resulttype^.deftype=procvardef) or
+
+                 ((left.resulttype^.deftype=enumdef) and
+                  (left.resulttype^.size=4)) or
+
+                 ((left.resulttype^.deftype=orddef) and
+                 (porddef(left.resulttype)^.typ=s32bit)) or
+                 ((right.resulttype^.deftype=orddef) and
+                 (porddef(right.resulttype)^.typ=s32bit)) or
+
+                ((left.resulttype^.deftype=orddef) and
+                 (porddef(left.resulttype)^.typ=u32bit)) or
+                 ((right.resulttype^.deftype=orddef) and
+                 (porddef(right.resulttype)^.typ=u32bit)) or
+
+                { as well as small sets }
+                 is_set then
+                begin
+          do_normal:
+                   mboverflow:=false;
+                   cmpop:=false;
+{$ifndef cardinalmulfix}
+                   unsigned :=
+                     (left.resulttype^.deftype=pointerdef) or
+                     (right.resulttype^.deftype=pointerdef) or
+                     ((left.resulttype^.deftype=orddef) and
+                      (porddef(left.resulttype)^.typ=u32bit)) or
+                     ((right.resulttype^.deftype=orddef) and
+                      (porddef(right.resulttype)^.typ=u32bit));
+{$else cardinalmulfix}
+                   unsigned := not(is_signed(left.resulttype)) or
+                               not(is_signed(right.resulttype));
+{$endif cardinalmulfix}
+                   case treetype of
+                      addn : begin
+                               { this is a really ugly hack!!!!!!!!!! }
+                               { this could be done later using EDI   }
+                               { as it is done for subn               }
+                               { instead of two registers!!!!         }
+                               if is_set then
+                                begin
+                                { adding elements is not commutative }
+                                  if swaped and (left.treetype=setelementn) then
+                                   swaptree(p);
+                                { are we adding set elements ? }
+                                  if right.treetype=setelementn then
+                                   begin
+                                   { no range support for smallsets! }
+                                     if assigned(right.right) then
+                                      internalerror(43244);
+                                   { bts requires both elements to be registers }
+                                     if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
+                                      begin
+                                        ungetiftemp(left.location.reference);
+                                        del_location(left.location);
+{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
+                                        hregister:=getregister32;
+                                        emit_ref_reg(A_MOV,opsize,
+                                          newreference(left.location.reference),hregister);
+                                        clear_location(left.location);
+                                        left.location.loc:=LOC_REGISTER;
+                                        left.location.register:=hregister;
+                                        set_location(location,left.location);
+                                      end;
+                                     if right.location.loc in [LOC_MEM,LOC_REFERENCE] then
+                                      begin
+                                        ungetiftemp(right.location.reference);
+                                        del_location(right.location);
+                                        hregister:=getregister32;
+                                        emit_ref_reg(A_MOV,opsize,
+                                          newreference(right.location.reference),hregister);
+                                        clear_location(right.location);
+                                        right.location.loc:=LOC_REGISTER;
+                                        right.location.register:=hregister;
+                                      end;
+                                     op:=A_BTS;
+                                     noswap:=true;
+                                   end
+                                  else
+                                   op:=A_OR;
+                                  mboverflow:=false;
+                                  unsigned:=false;
+                                end
+                               else
+                                begin
+                                  op:=A_ADD;
+                                  mboverflow:=true;
+                                end;
+                             end;
+                   symdifn : begin
+                               { the symetric diff is only for sets }
+                               if is_set then
+                                begin
+                                  op:=A_XOR;
+                                  mboverflow:=false;
+                                  unsigned:=false;
+                                end
+                               else
+                                CGMessage(type_e_mismatch);
+                             end;
+                      muln : begin
+                               if is_set then
+                                begin
+                                  op:=A_AND;
+                                  mboverflow:=false;
+                                  unsigned:=false;
+                                end
+                               else
+                                begin
+                                  if unsigned then
+                                   op:=A_MUL
+                                  else
+                                   op:=A_IMUL;
+                                  mboverflow:=true;
+                                end;
+                             end;
+                      subn : begin
+                               if is_set then
+                                begin
+                                  op:=A_AND;
+                                  mboverflow:=false;
+                                  unsigned:=false;
+{$IfNDef NoSetConstNot}
+                                  If (right.treetype = setconstn) then
+                                    right.location.reference.offset := not(right.location.reference.offset)
+                                  Else
+{$EndIf NoNosetConstNot}
+                                    extra_not:=true;
+                                end
+                               else
+                                begin
+                                  op:=A_SUB;
+                                  mboverflow:=true;
+                                end;
+                             end;
+                  ltn,lten,
+                  gtn,gten,
+           equaln,unequaln : begin
+{$IfNDef NoSetInclusion}
+                               If is_set Then
+                                 Case treetype of
+                                   lten,gten:
+                                     Begin
+                                      If treetype = lten then
+                                        swaptree(p);
+                                      if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
+                                        begin
+                                         ungetiftemp(left.location.reference);
+                                         del_reference(left.location.reference);
+                                         hregister:=getregister32;
+                                         emit_ref_reg(A_MOV,opsize,
+                                           newreference(left.location.reference),hregister);
+                                         clear_location(left.location);
+                                         left.location.loc:=LOC_REGISTER;
+                                         left.location.register:=hregister;
+                                         set_location(location,left.location);
+                                       end
+                                      else
+                                       if left.location.loc = LOC_CREGISTER Then
+                                        {save the register var in a temp register, because
+                                          its value is going to be modified}
+                                          begin
+                                            hregister := getregister32;
+                                            emit_reg_reg(A_MOV,opsize,
+                                              left.location.register,hregister);
+                                             clear_location(left.location);
+                                             left.location.loc:=LOC_REGISTER;
+                                             left.location.register:=hregister;
+                                             set_location(location,left.location);
+                                           end;
+                                     {here, left.location should be LOC_REGISTER}
+                                      If right.location.loc in [LOC_MEM,LOC_REFERENCE] Then
+                                         emit_ref_reg(A_AND,opsize,
+                                           newreference(right.location.reference),left.location.register)
+                                      Else
+                                        emit_reg_reg(A_AND,opsize,
+                                          right.location.register,left.location.register);
+                {warning: ugly hack ahead: we need a "jne" after the cmp, so
+                 change the treetype from lten/gten to equaln}
+                                      treetype := equaln
+                                     End;
+                           {no < or > support for sets}
+                                   ltn,gtn: CGMessage(type_e_mismatch);
+                                 End;
+{$EndIf NoSetInclusion}
+                               op:=A_CMP;
+                               cmpop:=true;
+                             end;
+                      xorn : op:=A_XOR;
+                       orn : op:=A_OR;
+                      andn : op:=A_AND;
+                   else
+                     CGMessage(type_e_mismatch);
+                   end;
+
+                   { filter MUL, which requires special handling }
+                   if op=A_MUL then
+                     begin
+                       popeax:=false;
+                       popedx:=false;
+                       { here you need to free the symbol first }
+                       { left.location and right.location must }
+                       { only be freed when they are really released,  }
+                       { because the optimizer NEEDS correct regalloc  }
+                       { info!!! (JM)                                  }
+                       clear_location(location);
+
+                 { the location.register will be filled in later (JM) }
+                       location.loc:=LOC_REGISTER;
+{$IfNDef NoShlMul}
+                       if right.treetype=ordconstn then
+                        swaptree(p);
+                       If (left.treetype = ordconstn) and
+                          ispowerof2(left.value, power) and
+                          not(cs_check_overflow in aktlocalswitches) then
+                         Begin
+                           { This release will be moved after the next }
+                           { instruction by the optimizer. No need to  }
+                           { release left.location, since it's a   }
+                           { constant (JM)                             }
+                           release_loc(right.location);
+                           location.register := getregister32;
+                           emitloadord2reg(right.location,u32bitdef,location.register,false);
+                           emit_const_reg(A_SHL,S_L,power,location.register)
+                         End
+                       Else
+                        Begin
+{$EndIf NoShlMul}
+                         regstopush := $ff;
+                         remove_non_regvars_from_loc(right.location,regstopush);
+                         remove_non_regvars_from_loc(left.location,regstopush);
+                         { now, regstopush does NOT contain EAX and/or EDX if they are }
+                         { used in either the left or the right location, excepts if   }
+                         {they are regvars. It DOES contain them if they are used in   }
+                         { another location (JM)                                       }
+                         if not(R_EAX in unused) and ((regstopush and ($80 shr byte(R_EAX))) <> 0) then
+                          begin
+                           emit_reg(A_PUSH,S_L,R_EAX);
+                           popeax:=true;
+                          end;
+                         if not(R_EDX in unused) and ((regstopush and ($80 shr byte(R_EDX))) <> 0) then
+                          begin
+                           emit_reg(A_PUSH,S_L,R_EDX);
+                           popedx:=true;
+                          end;
+                         { left.location can be R_EAX !!! }
+{$ifndef noAllocEdi}
+                         getexplicitregister32(R_EDI);
+{$endif noAllocEdi}
+                         { load the left value }
+                         emitloadord2reg(left.location,u32bitdef,R_EDI,true);
+                         release_loc(left.location);
+                         { allocate EAX }
+                         if R_EAX in unused then
+                           exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
+                         { load he right value }
+                         emitloadord2reg(right.location,u32bitdef,R_EAX,true);
+                         release_loc(right.location);
+                         { allocate EAX if it isn't yet allocated (JM) }
+                         if (R_EAX in unused) then
+                           exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
+{$ifndef noAllocEdi}
+                         { also allocate EDX, since it is also modified by }
+                         { a mul (JM)                                      }
+                         if R_EDX in unused then
+                           exprasmlist^.concat(new(pairegalloc,alloc(R_EDX)));
+{$endif noAllocEdi}
+                         emit_reg(A_MUL,S_L,R_EDI);
+{$ifndef noAllocEdi}
+                         ungetregister32(R_EDI);
+                         if R_EDX in unused then
+                           exprasmlist^.concat(new(pairegalloc,dealloc(R_EDX)));
+{$endif noAllocEdi}
+                         if R_EAX in unused then
+                           exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
+                         location.register := getregister32;
+                         emit_reg_reg(A_MOV,S_L,R_EAX,location.register);
+                         if popedx then
+                          emit_reg(A_POP,S_L,R_EDX);
+                         if popeax then
+                          emit_reg(A_POP,S_L,R_EAX);
+{$IfNDef NoShlMul}
+                        End;
+{$endif NoShlMul}
+                       SetResultLocation(false,true,p);
+                       exit;
+                     end;
+
+                   { Convert flags to register first }
+                   if (left.location.loc=LOC_FLAGS) then
+                    locflags2reg(left.location,opsize);
+                   if (right.location.loc=LOC_FLAGS) then
+                    locflags2reg(right.location,opsize);
+
+                   { left and right no register?  }
+                   { then one must be demanded    }
+                   if (left.location.loc<>LOC_REGISTER) and
+                      (right.location.loc<>LOC_REGISTER) then
+                     begin
+                        { register variable ? }
+                        if (left.location.loc=LOC_CREGISTER) then
+                          begin
+                             { it is OK if this is the destination }
+                             if is_in_dest then
+                               begin
+                                  hregister:=location.register;
+                                  emit_reg_reg(A_MOV,opsize,left.location.register,
+                                    hregister);
+                               end
+                             else
+                             if cmpop then
+                               begin
+                                  { do not disturb the register }
+                                  hregister:=location.register;
+                               end
+                             else
+                               begin
+                                  case opsize of
+                                     S_L : hregister:=getregister32;
+                                     S_B : hregister:=reg32toreg8(getregister32);
+                                  end;
+                                  emit_reg_reg(A_MOV,opsize,left.location.register,
+                                    hregister);
+                               end
+                          end
+                        else
+                          begin
+                             ungetiftemp(left.location.reference);
+                             del_reference(left.location.reference);
+                             if is_in_dest then
+                               begin
+                                  hregister:=location.register;
+                                  emit_ref_reg(A_MOV,opsize,
+                                    newreference(left.location.reference),hregister);
+                               end
+                             else
+                               begin
+                                  { first give free, then demand new register }
+                                  case opsize of
+                                     S_L : hregister:=getregister32;
+                                     S_W : hregister:=reg32toreg16(getregister32);
+                                     S_B : hregister:=reg32toreg8(getregister32);
+                                  end;
+                                  emit_ref_reg(A_MOV,opsize,
+                                    newreference(left.location.reference),hregister);
+                               end;
+                          end;
+                        clear_location(location);
+                        location.loc:=LOC_REGISTER;
+                        location.register:=hregister;
+                     end
+                   else
+                     { if on the right the register then swap }
+                     if not(noswap) and (right.location.loc=LOC_REGISTER) then
+                       begin
+                          swap_location(location,right.location);
+
+                          { newly swapped also set swapped flag }
+                          swaped:=not(swaped);
+                       end;
+                   { at this point, location.loc should be LOC_REGISTER }
+                   { and location.register should be a valid register   }
+                   { containing the left result                     }
+
+                    if right.location.loc<>LOC_REGISTER then
+                     begin
+                        if (treetype=subn) and swaped then
+                          begin
+                             if right.location.loc=LOC_CREGISTER then
+                               begin
+                                  if extra_not then
+                                    emit_reg(A_NOT,opsize,location.register);
+{$ifndef noAllocEdi}
+                                  getexplicitregister32(R_EDI);
+{$endif noAllocEdi}
+                                  emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
+                                  emit_reg_reg(op,opsize,location.register,R_EDI);
+                                  emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
+{$ifndef noAllocEdi}
+                                  ungetregister32(R_EDI);
+{$endif noAllocEdi}
+                               end
+                             else
+                               begin
+                                  if extra_not then
+                                    emit_reg(A_NOT,opsize,location.register);
+
+{$ifndef noAllocEdi}
+                                  getexplicitregister32(R_EDI);
+{$endif noAllocEdi}
+                                  emit_ref_reg(A_MOV,opsize,
+                                    newreference(right.location.reference),R_EDI);
+                                  emit_reg_reg(op,opsize,location.register,R_EDI);
+                                  emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
+{$ifndef noAllocEdi}
+                                  ungetregister32(R_EDI);
+{$endif noAllocEdi}
+                                  ungetiftemp(right.location.reference);
+                                  del_reference(right.location.reference);
+                               end;
+                          end
+                        else
+                          begin
+                             if (right.treetype=ordconstn) and
+                                (op=A_CMP) and
+                                (right.value=0) then
+                               begin
+                                  emit_reg_reg(A_TEST,opsize,location.register,
+                                    location.register);
+                               end
+                             else if (right.treetype=ordconstn) and
+                                (op=A_ADD) and
+                                (right.value=1) and
+                                not(cs_check_overflow in aktlocalswitches) then
+                               begin
+                                  emit_reg(A_INC,opsize,
+                                    location.register);
+                               end
+                             else if (right.treetype=ordconstn) and
+                                (op=A_SUB) and
+                                (right.value=1) and
+                                not(cs_check_overflow in aktlocalswitches) then
+                               begin
+                                  emit_reg(A_DEC,opsize,
+                                    location.register);
+                               end
+                             else if (right.treetype=ordconstn) and
+                                (op=A_IMUL) and
+                                (ispowerof2(right.value,power)) and
+                                not(cs_check_overflow in aktlocalswitches) then
+                               begin
+                                  emit_const_reg(A_SHL,opsize,power,
+                                    location.register);
+                               end
+                             else
+                               begin
+                                  if (right.location.loc=LOC_CREGISTER) then
+                                    begin
+                                       if extra_not then
+                                         begin
+{$ifndef noAllocEdi}
+                                            getexplicitregister32(R_EDI);
+{$endif noAllocEdi}
+                                            emit_reg_reg(A_MOV,S_L,right.location.register,R_EDI);
+                                            emit_reg(A_NOT,S_L,R_EDI);
+                                            emit_reg_reg(A_AND,S_L,R_EDI,
+                                              location.register);
+{$ifndef noAllocEdi}
+                                            ungetregister32(R_EDI);
+{$endif noAllocEdi}
+                                         end
+                                       else
+                                         begin
+                                            emit_reg_reg(op,opsize,right.location.register,
+                                              location.register);
+                                         end;
+                                    end
+                                  else
+                                    begin
+                                       if extra_not then
+                                         begin
+{$ifndef noAllocEdi}
+                                            getexplicitregister32(R_EDI);
+{$endif noAllocEdi}
+                                            emit_ref_reg(A_MOV,S_L,newreference(
+                                              right.location.reference),R_EDI);
+                                            emit_reg(A_NOT,S_L,R_EDI);
+                                            emit_reg_reg(A_AND,S_L,R_EDI,
+                                              location.register);
+{$ifndef noAllocEdi}
+                                            ungetregister32(R_EDI);
+{$endif noAllocEdi}
+                                         end
+                                       else
+                                         begin
+                                            emit_ref_reg(op,opsize,newreference(
+                                              right.location.reference),location.register);
+                                         end;
+                                       ungetiftemp(right.location.reference);
+                                       del_reference(right.location.reference);
+                                    end;
+                               end;
+                          end;
+                     end
+                   else
+                     begin
+                        { when swapped another result register }
+                        if (treetype=subn) and swaped then
+                          begin
+                             if extra_not then
+                               emit_reg(A_NOT,S_L,location.register);
+
+                             emit_reg_reg(op,opsize,
+                               location.register,right.location.register);
+                               swap_location(location,right.location);
+                               { newly swapped also set swapped flag }
+                               { just to maintain ordering         }
+                               swaped:=not(swaped);
+                          end
+                        else
+                          begin
+                             if extra_not then
+                               emit_reg(A_NOT,S_L,right.location.register);
+                             emit_reg_reg(op,opsize,
+                               right.location.register,
+                               location.register);
+                          end;
+                        case opsize of
+                           S_L : ungetregister32(right.location.register);
+                           S_B : ungetregister32(reg8toreg32(right.location.register));
+                        end;
+                     end;
+
+                   if cmpop then
+                     case opsize of
+                        S_L : ungetregister32(location.register);
+                        S_B : ungetregister32(reg8toreg32(location.register));
+                     end;
+
+                   { only in case of overflow operations }
+                   { produce overflow code }
+                   { we must put it here directly, because sign of operation }
+                   { is in unsigned VAR!!                                   }
+                   if mboverflow then
+                    begin
+                      if cs_check_overflow in aktlocalswitches  then
+                       begin
+                         getlabel(hl4);
+                         if unsigned then
+                          emitjmp(C_NB,hl4)
+                         else
+                          emitjmp(C_NO,hl4);
+                         emitcall('FPC_OVERFLOW');
+                         emitlab(hl4);
+                       end;
+                    end;
+                end
+              else
+
+              { Char type }
+                if ((left.resulttype^.deftype=orddef) and
+                    (porddef(left.resulttype)^.typ=uchar)) or
+              { enumeration type 16 bit }
+                   ((left.resulttype^.deftype=enumdef) and
+                    (left.resulttype^.size=1)) then
+                 begin
+                   case treetype of
+                      ltn,lten,gtn,gten,
+                      equaln,unequaln :
+                                cmpop:=true;
+                      else CGMessage(type_e_mismatch);
+                   end;
+                   unsigned:=true;
+                   { left and right no register? }
+                   { the one must be demanded    }
+                   if (location.loc<>LOC_REGISTER) and
+                     (right.location.loc<>LOC_REGISTER) then
+                     begin
+                        if location.loc=LOC_CREGISTER then
+                          begin
+                             if cmpop then
+                               { do not disturb register }
+                               hregister:=location.register
+                             else
+                               begin
+                                  hregister:=reg32toreg8(getregister32);
+                                  emit_reg_reg(A_MOV,S_B,location.register,
+                                    hregister);
+                               end;
+                          end
+                        else
+                          begin
+                             del_reference(location.reference);
+
+                             { first give free then demand new register }
+                             hregister:=reg32toreg8(getregister32);
+                             emit_ref_reg(A_MOV,S_B,newreference(location.reference),
+                               hregister);
+                          end;
+                        clear_location(location);
+                        location.loc:=LOC_REGISTER;
+                        location.register:=hregister;
+                     end;
+
+                   { now p always a register }
+
+                   if (right.location.loc=LOC_REGISTER) and
+                      (location.loc<>LOC_REGISTER) then
+                     begin
+                       swap_location(location,right.location);
+                       { newly swapped also set swapped flag }
+                       swaped:=not(swaped);
+                     end;
+
+                   if right.location.loc<>LOC_REGISTER then
+                     begin
+                        if right.location.loc=LOC_CREGISTER then
+                          begin
+                             emit_reg_reg(A_CMP,S_B,
+                                right.location.register,location.register);
+                          end
+                        else
+                          begin
+                             emit_ref_reg(A_CMP,S_B,newreference(
+                                right.location.reference),location.register);
+                             del_reference(right.location.reference);
+                          end;
+                     end
+                   else
+                     begin
+                        emit_reg_reg(A_CMP,S_B,right.location.register,
+                          location.register);
+                        ungetregister32(reg8toreg32(right.location.register));
+                     end;
+                   ungetregister32(reg8toreg32(location.register));
+                end
+              else
+              { 16 bit enumeration type }
+                if ((left.resulttype^.deftype=enumdef) and
+                    (left.resulttype^.size=2)) then
+                 begin
+                   case treetype of
+                      ltn,lten,gtn,gten,
+                      equaln,unequaln :
+                                cmpop:=true;
+                      else CGMessage(type_e_mismatch);
+                   end;
+                   unsigned:=true;
+                   { left and right no register? }
+                   { the one must be demanded    }
+                   if (location.loc<>LOC_REGISTER) and
+                     (right.location.loc<>LOC_REGISTER) then
+                     begin
+                        if location.loc=LOC_CREGISTER then
+                          begin
+                             if cmpop then
+                               { do not disturb register }
+                               hregister:=location.register
+                             else
+                               begin
+                                  hregister:=reg32toreg16(getregister32);
+                                  emit_reg_reg(A_MOV,S_W,location.register,
+                                    hregister);
+                               end;
+                          end
+                        else
+                          begin
+                             del_reference(location.reference);
+
+                             { first give free then demand new register }
+                             hregister:=reg32toreg16(getregister32);
+                             emit_ref_reg(A_MOV,S_W,newreference(location.reference),
+                               hregister);
+                          end;
+                        clear_location(location);
+                        location.loc:=LOC_REGISTER;
+                        location.register:=hregister;
+                     end;
+
+                   { now p always a register }
+
+                   if (right.location.loc=LOC_REGISTER) and
+                      (location.loc<>LOC_REGISTER) then
+                     begin
+                       swap_location(location,right.location);
+                       { newly swapped also set swapped flag }
+                       swaped:=not(swaped);
+                     end;
+
+                   if right.location.loc<>LOC_REGISTER then
+                     begin
+                        if right.location.loc=LOC_CREGISTER then
+                          begin
+                             emit_reg_reg(A_CMP,S_W,
+                                right.location.register,location.register);
+                          end
+                        else
+                          begin
+                             emit_ref_reg(A_CMP,S_W,newreference(
+                                right.location.reference),location.register);
+                             del_reference(right.location.reference);
+                          end;
+                     end
+                   else
+                     begin
+                        emit_reg_reg(A_CMP,S_W,right.location.register,
+                          location.register);
+                        ungetregister32(reg16toreg32(right.location.register));
+                     end;
+                   ungetregister32(reg16toreg32(location.register));
+                end
+              else
+              { 64 bit types }
+              if is_64bitint(left.resulttype) then
+                begin
+                   mboverflow:=false;
+                   cmpop:=false;
+                   unsigned:=((left.resulttype^.deftype=orddef) and
+                       (porddef(left.resulttype)^.typ=u64bit)) or
+                      ((right.resulttype^.deftype=orddef) and
+                       (porddef(right.resulttype)^.typ=u64bit));
+                   case treetype of
+                      addn : begin
+                                begin
+                                  op:=A_ADD;
+                                  op2:=A_ADC;
+                                  mboverflow:=true;
+                                end;
+                             end;
+                      subn : begin
+                                op:=A_SUB;
+                                op2:=A_SBB;
+                                mboverflow:=true;
+                             end;
+                      ltn,lten,
+                      gtn,gten,
+                      equaln,unequaln:
+                             begin
+                               op:=A_CMP;
+                               op2:=A_CMP;
+                               cmpop:=true;
+                             end;
+
+                      xorn:
+                        begin
+                           op:=A_XOR;
+                           op2:=A_XOR;
+                        end;
+
+                      orn:
+                        begin
+                           op:=A_OR;
+                           op2:=A_OR;
+                        end;
+
+                      andn:
+                        begin
+                           op:=A_AND;
+                           op2:=A_AND;
+                        end;
+                      muln:
+                        ;
+                   else
+                     CGMessage(type_e_mismatch);
+                   end;
+
+                   if treetype=muln then
+                     begin
+                        { save lcoation, because we change it now }
+                        set_location(hloc,location);
+                        release_qword_loc(location);
+                        release_qword_loc(right.location);
+                        location.registerlow:=getexplicitregister32(R_EAX);
+                        location.registerhigh:=getexplicitregister32(R_EDX);
+                        pushusedregisters(pushedreg,$ff
+                          and not($80 shr byte(location.registerlow))
+                          and not($80 shr byte(location.registerhigh)));
+                        if cs_check_overflow in aktlocalswitches then
+                          push_int(1)
+                        else
+                          push_int(0);
+                        { the left operand is in hloc, because the
+                          location of left is location but location
+                          is already destroyed
+                        }
+                        emit_pushq_loc(hloc);
+                        clear_location(hloc);
+                        emit_pushq_loc(right.location);
+                        if porddef(resulttype)^.typ=u64bit then
+                          emitcall('FPC_MUL_QWORD')
+                        else
+                          emitcall('FPC_MUL_INT64');
+                        emit_reg_reg(A_MOV,S_L,R_EAX,location.registerlow);
+                        emit_reg_reg(A_MOV,S_L,R_EDX,location.registerhigh);
+                        popusedregisters(pushedreg);
+                        location.loc:=LOC_REGISTER;
+                     end
+                   else
+                     begin
+                        { left and right no register?  }
+                        { then one must be demanded    }
+                        if (left.location.loc<>LOC_REGISTER) and
+                           (right.location.loc<>LOC_REGISTER) then
+                          begin
+                             { register variable ? }
+                             if (left.location.loc=LOC_CREGISTER) then
+                               begin
+                                  { it is OK if this is the destination }
+                                  if is_in_dest then
+                                    begin
+                                       hregister:=location.registerlow;
+                                       hregister2:=location.registerhigh;
+                                       emit_reg_reg(A_MOV,S_L,left.location.registerlow,
+                                         hregister);
+                                       emit_reg_reg(A_MOV,S_L,left.location.registerlow,
+                                         hregister2);
+                                    end
+                                  else
+                                  if cmpop then
+                                    begin
+                                       { do not disturb the register }
+                                       hregister:=location.registerlow;
+                                       hregister2:=location.registerhigh;
+                                    end
+                                  else
+                                    begin
+                                       hregister:=getregister32;
+                                       hregister2:=getregister32;
+                                       emit_reg_reg(A_MOV,S_L,left.location.registerlow,
+                                         hregister);
+                                       emit_reg_reg(A_MOV,S_L,left.location.registerhigh,
+                                         hregister2);
+                                    end
+                               end
+                             else
+                               begin
+                                  ungetiftemp(left.location.reference);
+                                  del_reference(left.location.reference);
+                                  if is_in_dest then
+                                    begin
+                                       hregister:=location.registerlow;
+                                       hregister2:=location.registerhigh;
+                                       emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
+                                    end
+                                  else
+                                    begin
+                                       hregister:=getregister32;
+                                       hregister2:=getregister32;
+                                       emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
+                                    end;
+                               end;
+                             clear_location(location);
+                             location.loc:=LOC_REGISTER;
+                             location.registerlow:=hregister;
+                             location.registerhigh:=hregister2;
+                          end
+                        else
+                          { if on the right the register then swap }
+                          if not(noswap) and (right.location.loc=LOC_REGISTER) then
+                            begin
+                               swap_location(location,right.location);
+
+                               { newly swapped also set swapped flag }
+                               swaped:=not(swaped);
+                            end;
+                        { at this point, location.loc should be LOC_REGISTER }
+                        { and location.register should be a valid register   }
+                        { containing the left result                        }
+
+                        if right.location.loc<>LOC_REGISTER then
+                          begin
+                             if (treetype=subn) and swaped then
+                               begin
+                                  if right.location.loc=LOC_CREGISTER then
+                                    begin
+{$ifndef noAllocEdi}
+                                       getexplicitregister32(R_EDI);
+{$endif noAllocEdi}
+                                       emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
+                                       emit_reg_reg(op,opsize,location.register,R_EDI);
+                                       emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
+{$ifndef noAllocEdi}
+                                       ungetregister32(R_EDI);
+                                       getexplicitregister32(R_EDI);
+{$endif noAllocEdi}
+                                       emit_reg_reg(A_MOV,opsize,right.location.registerhigh,R_EDI);
+                                       { the carry flag is still ok }
+                                       emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
+                                       emit_reg_reg(A_MOV,opsize,R_EDI,location.registerhigh);
+{$ifndef noAllocEdi}
+                                       ungetregister32(R_EDI);
+{$endif noAllocEdi}
+                                    end
+                                  else
+                                    begin
+{$ifndef noAllocEdi}
+                                       getexplicitregister32(R_EDI);
+{$endif noAllocEdi}
+                                       emit_ref_reg(A_MOV,opsize,
+                                         newreference(right.location.reference),R_EDI);
+                                       emit_reg_reg(op,opsize,location.registerlow,R_EDI);
+                                       emit_reg_reg(A_MOV,opsize,R_EDI,location.registerlow);
+{$ifndef noAllocEdi}
+                                       ungetregister32(R_EDI);
+                                       getexplicitregister32(R_EDI);
+{$endif noAllocEdi}
+                                       hr:=newreference(right.location.reference);
+                                       inc(hr^.offset,4);
+                                       emit_ref_reg(A_MOV,opsize,
+                                         hr,R_EDI);
+                                       { here the carry flag is still preserved }
+                                       emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
+                                       emit_reg_reg(A_MOV,opsize,R_EDI,
+                                         location.registerhigh);
+{$ifndef noAllocEdi}
+                                       ungetregister32(R_EDI);
+{$endif noAllocEdi}
+                                       ungetiftemp(right.location.reference);
+                                       del_reference(right.location.reference);
+                                    end;
+                               end
+                             else if cmpop then
+                               begin
+                                  if (right.location.loc=LOC_CREGISTER) then
+                                    begin
+                                       emit_reg_reg(A_CMP,S_L,right.location.registerhigh,
+                                          location.registerhigh);
+                                       firstjmp64bitcmp;
+                                       emit_reg_reg(A_CMP,S_L,right.location.registerlow,
+                                          location.registerlow);
+                                       secondjmp64bitcmp;
+                                    end
+                                  else
+                                    begin
+                                       hr:=newreference(right.location.reference);
+                                       inc(hr^.offset,4);
+
+                                       emit_ref_reg(A_CMP,S_L,
+                                         hr,location.registerhigh);
+                                       firstjmp64bitcmp;
+
+                                       emit_ref_reg(A_CMP,S_L,newreference(
+                                         right.location.reference),location.registerlow);
+                                       secondjmp64bitcmp;
+
+                                       emitjmp(C_None,falselabel);
+
+                                       ungetiftemp(right.location.reference);
+                                       del_reference(right.location.reference);
+                                    end;
+                               end
+                             else
+                               begin
+                                  {
+                                  if (right.treetype=ordconstn) and
+                                     (op=A_CMP) and
+                                     (right.value=0) then
+                                    begin
+                                       emit_reg_reg(A_TEST,opsize,location.register,
+                                         location.register);
+                                    end
+                                  else if (right.treetype=ordconstn) and
+                                     (op=A_IMUL) and
+                                     (ispowerof2(right.value,power)) then
+                                    begin
+                                       emit_const_reg(A_SHL,opsize,power,
+                                         location.register);
+                                    end
+                                  else
+                                  }
+                                    begin
+                                       if (right.location.loc=LOC_CREGISTER) then
+                                         begin
+                                            emit_reg_reg(op,S_L,right.location.registerlow,
+                                               location.registerlow);
+                                            emit_reg_reg(op2,S_L,right.location.registerhigh,
+                                               location.registerhigh);
+                                         end
+                                       else
+                                         begin
+                                            emit_ref_reg(op,S_L,newreference(
+                                              right.location.reference),location.registerlow);
+                                            hr:=newreference(right.location.reference);
+                                            inc(hr^.offset,4);
+                                            emit_ref_reg(op2,S_L,
+                                              hr,location.registerhigh);
+                                            ungetiftemp(right.location.reference);
+                                            del_reference(right.location.reference);
+                                         end;
+                                    end;
+                               end;
+                          end
+                        else
+                          begin
+                             { when swapped another result register }
+                             if (treetype=subn) and swaped then
+                               begin
+                                 emit_reg_reg(op,S_L,
+                                    location.registerlow,
+                                    right.location.registerlow);
+                                 emit_reg_reg(op2,S_L,
+                                    location.registerhigh,
+                                    right.location.registerhigh);
+                                  swap_location(location,right.location);
+                                  { newly swapped also set swapped flag }
+                                  { just to maintain ordering           }
+                                  swaped:=not(swaped);
+                               end
+                             else if cmpop then
+                               begin
+                                  emit_reg_reg(A_CMP,S_L,
+                                    right.location.registerhigh,
+                                    location.registerhigh);
+                                  firstjmp64bitcmp;
+                                  emit_reg_reg(A_CMP,S_L,
+                                    right.location.registerlow,
+                                    location.registerlow);
+                                  secondjmp64bitcmp;
+                               end
+                             else
+                               begin
+                                  emit_reg_reg(op,S_L,
+                                    right.location.registerlow,
+                                    location.registerlow);
+                                  emit_reg_reg(op2,S_L,
+                                    right.location.registerhigh,
+                                    location.registerhigh);
+                               end;
+                             ungetregister32(right.location.registerlow);
+                             ungetregister32(right.location.registerhigh);
+                          end;
+
+                        if cmpop then
+                          begin
+                             ungetregister32(location.registerlow);
+                             ungetregister32(location.registerhigh);
+                          end;
+
+                        { only in case of overflow operations }
+                        { produce overflow code }
+                        { we must put it here directly, because sign of operation }
+                        { is in unsigned VAR!!                              }
+                        if mboverflow then
+                         begin
+                           if cs_check_overflow in aktlocalswitches  then
+                            begin
+                              getlabel(hl4);
+                              if unsigned then
+                               emitjmp(C_NB,hl4)
+                              else
+                               emitjmp(C_NO,hl4);
+                              emitcall('FPC_OVERFLOW');
+                              emitlab(hl4);
+                            end;
+                         end;
+                        { we have LOC_JUMP as result }
+                        if cmpop then
+                          begin
+                             clear_location(location);
+                             location.loc:=LOC_JUMP;
+                             cmpop:=false;
+                          end;
+                     end;
+                end
+              else
+              { Floating point }
+               if (left.resulttype^.deftype=floatdef) and
+                  (pfloatdef(left.resulttype)^.typ<>f32bit) then
+                 begin
+                    { real constants to the right, but only if it
+                      isn't on the FPU stack, i.e. 1.0 or 0.0! }
+                    if (left.treetype=realconstn) and
+                      (left.location.loc<>LOC_FPU) then
+                      swaptree(p);
+                    cmpop:=false;
+                    case treetype of
+                       addn : op:=A_FADDP;
+                       muln : op:=A_FMULP;
+                       subn : op:=A_FSUBP;
+                       slashn : op:=A_FDIVP;
+                       ltn,lten,gtn,gten,
+                       equaln,unequaln : begin
+                                            op:=A_FCOMPP;
+                                            cmpop:=true;
+                                         end;
+                       else CGMessage(type_e_mismatch);
+                    end;
+
+                    if (right.location.loc<>LOC_FPU) then
+                      begin
+                         if right.location.loc=LOC_CFPUREGISTER then
+                           begin
+                              emit_reg( A_FLD,S_NO,
+                                correct_fpuregister(right.location.register,fpuvaroffset));
+                              inc(fpuvaroffset);
+                            end
+                         else
+                           floatload(pfloatdef(right.resulttype)^.typ,right.location.reference);
+                         if (left.location.loc<>LOC_FPU) then
+                           begin
+                              if left.location.loc=LOC_CFPUREGISTER then
+                                begin
+                                   emit_reg( A_FLD,S_NO,
+                                     correct_fpuregister(left.location.register,fpuvaroffset));
+                                   inc(fpuvaroffset);
+                                end
+                              else
+                                floatload(pfloatdef(left.resulttype)^.typ,left.location.reference)
+                           end
+                         { left was on the stack => swap }
+                         else
+                           swaped:=not(swaped);
+
+                         { releases the right reference }
+                         del_reference(right.location.reference);
+                      end
+                    { the nominator in st0 }
+                    else if (left.location.loc<>LOC_FPU) then
+                      begin
+                         if left.location.loc=LOC_CFPUREGISTER then
+                           begin
+                              emit_reg( A_FLD,S_NO,
+                                correct_fpuregister(left.location.register,fpuvaroffset));
+                              inc(fpuvaroffset);
+                           end
+                         else
+                           floatload(pfloatdef(left.resulttype)^.typ,left.location.reference)
+                      end
+                    { fpu operands are always in the wrong order on the stack }
+                    else
+                      swaped:=not(swaped);
+
+                    { releases the left reference }
+                    if (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
+                      del_reference(left.location.reference);
+
+                    { if we swaped the tree nodes, then use the reverse operator }
+                    if swaped then
+                      begin
+                         if (treetype=slashn) then
+                           op:=A_FDIVRP
+                         else if (treetype=subn) then
+                           op:=A_FSUBRP;
+                      end;
+                    { to avoid the pentium bug
+                    if (op=FDIVP) and (opt_processors=pentium) then
+                      emitcall('EMUL_FDIVP')
+                    else
+                    }
+                    { the Intel assemblers want operands }
+                    if op<>A_FCOMPP then
+                      begin
+                         emit_reg_reg(op,S_NO,R_ST,R_ST1);
+                         dec(fpuvaroffset);
+                      end
+                    else
+                      begin
+                         emit_none(op,S_NO);
+                         dec(fpuvaroffset,2);
+                      end;
+
+                    { on comparison load flags }
+                    if cmpop then
+                     begin
+                       if not(R_EAX in unused) then
+                         begin
+{$ifndef noAllocEdi}
+                           getexplicitregister32(R_EDI);
+{$endif noAllocEdi}
+                           emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
+                         end;
+                       emit_reg(A_FNSTSW,S_NO,R_AX);
+                       emit_none(A_SAHF,S_NO);
+                       if not(R_EAX in unused) then
+                         begin
+                           emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
+{$ifndef noAllocEdi}
+                           ungetregister32(R_EDI);
+{$endif noAllocEdi}
+                         end;
+                       if swaped then
+                        begin
+                          case 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;
+                        end
+                       else
+                        begin
+                          case 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;
+                       clear_location(location);
+                       location.loc:=LOC_FLAGS;
+                       location.resflags:=flags;
+                       cmpop:=false;
+                     end
+                    else
+                     begin
+                        clear_location(location);
+                        location.loc:=LOC_FPU;
+                     end;
+                 end
+{$ifdef SUPPORT_MMX}
+               else
+
+               { MMX Arrays }
+                if is_mmx_able_array(left.resulttype) then
+                 begin
+                   cmpop:=false;
+                   mmxbase:=mmx_type(left.resulttype);
+                   case treetype of
+                      addn : begin
+                                if (cs_mmx_saturation in aktlocalswitches) then
+                                  begin
+                                     case mmxbase of
+                                        mmxs8bit:
+                                          op:=A_PADDSB;
+                                        mmxu8bit:
+                                          op:=A_PADDUSB;
+                                        mmxs16bit,mmxfixed16:
+                                          op:=A_PADDSB;
+                                        mmxu16bit:
+                                          op:=A_PADDUSW;
+                                     end;
+                                  end
+                                else
+                                  begin
+                                     case mmxbase of
+                                        mmxs8bit,mmxu8bit:
+                                          op:=A_PADDB;
+                                        mmxs16bit,mmxu16bit,mmxfixed16:
+                                          op:=A_PADDW;
+                                        mmxs32bit,mmxu32bit:
+                                          op:=A_PADDD;
+                                     end;
+                                  end;
+                             end;
+                      muln : begin
+                                case mmxbase of
+                                   mmxs16bit,mmxu16bit:
+                                     op:=A_PMULLW;
+                                   mmxfixed16:
+                                     op:=A_PMULHW;
+                                end;
+                             end;
+                      subn : begin
+                                if (cs_mmx_saturation in aktlocalswitches) then
+                                  begin
+                                     case mmxbase of
+                                        mmxs8bit:
+                                          op:=A_PSUBSB;
+                                        mmxu8bit:
+                                          op:=A_PSUBUSB;
+                                        mmxs16bit,mmxfixed16:
+                                          op:=A_PSUBSB;
+                                        mmxu16bit:
+                                          op:=A_PSUBUSW;
+                                     end;
+                                  end
+                                else
+                                  begin
+                                     case mmxbase of
+                                        mmxs8bit,mmxu8bit:
+                                          op:=A_PSUBB;
+                                        mmxs16bit,mmxu16bit,mmxfixed16:
+                                          op:=A_PSUBW;
+                                        mmxs32bit,mmxu32bit:
+                                          op:=A_PSUBD;
+                                     end;
+                                  end;
+                             end;
+                      {
+                      ltn,lten,gtn,gten,
+                      equaln,unequaln :
+                             begin
+                                op:=A_CMP;
+                                cmpop:=true;
+                             end;
+                      }
+                      xorn:
+                        op:=A_PXOR;
+                      orn:
+                        op:=A_POR;
+                      andn:
+                        op:=A_PAND;
+                      else CGMessage(type_e_mismatch);
+                   end;
+                   { left and right no register?  }
+                   { then one must be demanded    }
+                   if (left.location.loc<>LOC_MMXREGISTER) and
+                     (right.location.loc<>LOC_MMXREGISTER) then
+                     begin
+                        { register variable ? }
+                        if (left.location.loc=LOC_CMMXREGISTER) then
+                          begin
+                             { it is OK if this is the destination }
+                             if is_in_dest then
+                               begin
+                                  hregister:=location.register;
+                                  emit_reg_reg(A_MOVQ,S_NO,left.location.register,
+                                    hregister);
+                               end
+                             else
+                               begin
+                                  hregister:=getregistermmx;
+                                  emit_reg_reg(A_MOVQ,S_NO,left.location.register,
+                                    hregister);
+                               end
+                          end
+                        else
+                          begin
+                             del_reference(left.location.reference);
+
+                             if is_in_dest then
+                               begin
+                                  hregister:=location.register;
+                                  emit_ref_reg(A_MOVQ,S_NO,
+                                    newreference(left.location.reference),hregister);
+                               end
+                             else
+                               begin
+                                  hregister:=getregistermmx;
+                                  emit_ref_reg(A_MOVQ,S_NO,
+                                    newreference(left.location.reference),hregister);
+                               end;
+                          end;
+                        clear_location(location);
+                        location.loc:=LOC_MMXREGISTER;
+                        location.register:=hregister;
+                     end
+                   else
+                     { if on the right the register then swap }
+                     if (right.location.loc=LOC_MMXREGISTER) then
+                       begin
+                          swap_location(location,right.location);
+                          { newly swapped also set swapped flag }
+                          swaped:=not(swaped);
+                       end;
+                   { at this point, location.loc should be LOC_MMXREGISTER }
+                   { and location.register should be a valid register      }
+                   { containing the left result                        }
+                   if right.location.loc<>LOC_MMXREGISTER then
+                     begin
+                        if (treetype=subn) and swaped then
+                          begin
+                             if right.location.loc=LOC_CMMXREGISTER then
+                               begin
+                                  emit_reg_reg(A_MOVQ,S_NO,right.location.register,R_MM7);
+                                  emit_reg_reg(op,S_NO,location.register,R_MM0);
+                                  emit_reg_reg(A_MOVQ,S_NO,R_MM7,location.register);
+                               end
+                             else
+                               begin
+                                  emit_ref_reg(A_MOVQ,S_NO,
+                                    newreference(right.location.reference),R_MM7);
+                                  emit_reg_reg(op,S_NO,location.register,
+                                    R_MM7);
+                                  emit_reg_reg(A_MOVQ,S_NO,
+                                    R_MM7,location.register);
+                                  del_reference(right.location.reference);
+                               end;
+                          end
+                        else
+                          begin
+                             if (right.location.loc=LOC_CREGISTER) then
+                               begin
+                                  emit_reg_reg(op,S_NO,right.location.register,
+                                    location.register);
+                               end
+                             else
+                               begin
+                                  emit_ref_reg(op,S_NO,newreference(
+                                    right.location.reference),location.register);
+                                  del_reference(right.location.reference);
+                               end;
+                          end;
+                     end
+                   else
+                     begin
+                        { when swapped another result register }
+                        if (treetype=subn) and swaped then
+                          begin
+                             emit_reg_reg(op,S_NO,
+                               location.register,right.location.register);
+                             swap_location(location,right.location);
+                             { newly swapped also set swapped flag }
+                             { just to maintain ordering         }
+                             swaped:=not(swaped);
+                          end
+                        else
+                          begin
+                             emit_reg_reg(op,S_NO,
+                               right.location.register,
+                               location.register);
+                          end;
+                        ungetregistermmx(right.location.register);
+                     end;
+                end
+{$endif SUPPORT_MMX}
+              else CGMessage(type_e_mismatch);
+           end;
+       SetResultLocation(cmpop,unsigned,p);
+    end;
+
+    procedure ti386addnode.pass_2;
+
+      begin
+      end;
+
+begin
+   caddnode:=ti386addnode;
+end.
+{
+  $Log$
+  Revision 1.1  2000-09-20 21:23:32  florian
+    * initial revision
+
+}