소스 검색

* fixed handling of comp and currency when they have to be handled by the
fpu: treat them as extended when they are loaded into registers, and as
int64 when loading from/storing to memory

git-svn-id: branches/hlcgllvm@26048 -

Jonas Maebe 11 년 전
부모
커밋
80c6225bf4
3개의 변경된 파일58개의 추가작업 그리고 35개의 파일을 삭제
  1. 41 26
      compiler/llvm/hlcgllvm.pas
  2. 15 8
      compiler/llvm/nllvmadd.pas
  3. 2 1
      compiler/llvm/nllvmcon.pas

+ 41 - 26
compiler/llvm/hlcgllvm.pas

@@ -445,20 +445,33 @@ implementation
     var
        tmpreg: tregister;
        href: treference;
+       fromcompcurr,
+       tocompcurr: boolean;
      begin
+       { comp and currency are handled by the x87 in this case. They cannot
+         be represented directly in llvm, and llvmdef translates them into i64
+         (since that's their storage size and internally they also are int64).
+         Solve this by changing the type to s80real once they are loaded into
+         a register. }
+       fromcompcurr:=tfloatdef(fromsize).floattype in [s64comp,s64currency];
+       tocompcurr:=tfloatdef(tosize).floattype in [s64comp,s64currency];
+       if tocompcurr then
+         tosize:=s80floattype;
        href:=make_simple_ref(list,ref,fromsize);
        { don't generate different code for loading e.g. extended into cextended,
          but to take care of loading e.g. comp (=int64) into double }
-       if (fromsize.size<>tosize.size) or
-          ((tfloatdef(fromsize).floattype in [s64currency,s64comp])<>
-           (tfloatdef(tosize).floattype in [s64currency,s64comp])) then
+       if (fromsize.size<>tosize.size) then
          tmpreg:=getfpuregister(list,fromsize)
        else
          tmpreg:=reg;
        { %tmpreg = load size* %ref }
        list.concat(taillvm.op_reg_size_ref(la_load,tmpreg,getpointerdef(fromsize),href));
        if tmpreg<>reg then
-         a_loadfpu_reg_reg(list,fromsize,tosize,tmpreg,reg);
+         if fromcompcurr then
+           { treat as extended as long as it's in a register }
+           list.concat(taillvm.op_reg_size_reg_size(la_sitofp,reg,fromsize,tmpreg,tosize))
+         else
+           a_loadfpu_reg_reg(list,fromsize,tosize,tmpreg,reg);
      end;
 
 
@@ -466,16 +479,25 @@ implementation
     var
        tmpreg: tregister;
        href: treference;
+       fromcompcurr,
+       tocompcurr: boolean;
      begin
+       { see comment in a_loadfpu_ref_reg }
+       fromcompcurr:=tfloatdef(fromsize).floattype in [s64comp,s64currency];
+       tocompcurr:=tfloatdef(tosize).floattype in [s64comp,s64currency];
+       if fromcompcurr then
+         fromsize:=s80floattype;
        href:=make_simple_ref(list,ref,tosize);
        { don't generate different code for loading e.g. extended into cextended,
          but to take care of storing e.g. comp (=int64) into double  }
-       if (fromsize.size<>tosize.size) or
-          ((tfloatdef(fromsize).floattype in [s64currency,s64comp])<>
-           (tfloatdef(tosize).floattype in [s64currency,s64comp])) then
+       if (fromsize.size<>tosize.size) then
          begin
            tmpreg:=getfpuregister(list,tosize);
-           a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
+           if tocompcurr then
+             { store back an int64 rather than an extended }
+             list.concat(taillvm.op_reg_size_reg_size(la_fptosi,tmpreg,fromsize,reg,tosize))
+           else
+             a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
          end
        else
          tmpreg:=reg;
@@ -489,9 +511,13 @@ implementation
       op: tllvmop;
       intfromsize,
       inttosize: longint;
-      fromcompcurr,
-      tocompcurr: boolean;
     begin
+      { treat comp and currency as extended in registers (see comment at start
+        of a_loadfpu_ref_reg) }
+      if tfloatdef(fromsize).floattype in [s64comp,s64currency] then
+        fromsize:=sc80floattype;
+      if tfloatdef(tosize).floattype in [s64comp,s64currency] then
+        tosize:=sc80floattype;
       { at the value level, s80real and sc80real are the same }
       if fromsize<>s80floattype then
         intfromsize:=fromsize.size
@@ -502,23 +528,12 @@ implementation
       else
         inttosize:=sc80floattype.size;
 
-      { s64comp and s64real are handled as int64 by llvm, which complicates
-        things here for us }
-      fromcompcurr:=tfloatdef(fromsize).floattype in [s64comp,s64currency];
-      tocompcurr:=tfloatdef(tosize).floattype in [s64comp,s64currency];
-      if fromcompcurr=tocompcurr then
-        begin
-          if intfromsize<inttosize then
-            op:=la_fpext
-           else if intfromsize>inttosize then
-            op:=la_fptrunc
-          else
-            op:=la_bitcast
-        end
-      else if fromcompcurr then
-        op:=la_sitofp
+      if intfromsize<inttosize then
+        op:=la_fpext
+       else if intfromsize>inttosize then
+        op:=la_fptrunc
       else
-        op:=la_fptosi;
+        op:=la_bitcast;
       { reg2 = bitcast fromllsize reg1 to tollsize }
       list.concat(taillvm.op_reg_size_reg_size(op,reg2,fromsize,reg1,tosize));
     end;

+ 15 - 8
compiler/llvm/nllvmadd.pas

@@ -47,7 +47,7 @@ implementation
      uses
        verbose,globtype,
        aasmdata,
-       symdef,defutil,
+       symtype,symdef,defutil,
        llvmbase,aasmllvm,
        cgbase,cgutils,
        hlcgobj,
@@ -179,6 +179,7 @@ implementation
     var
       op    : tllvmop;
       llvmfpcmp : tllvmfpcmp;
+      size : tdef;
       cmpop,
       singleprec : boolean;
     begin
@@ -219,16 +220,16 @@ implementation
           internalerror(2013102401);
       end;
 
-      // get the operands in the correct order, there are no special cases
-      // here, everything is register-based
+      { get the operands in the correct order; there are no special cases here,
+        everything is register-based }
       if nf_swapped in flags then
         swapleftright;
 
-      // put both operands in a register
+      { put both operands in a register }
       hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true);
       hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
 
-      // initialize the result
+      { initialize the result location }
       if not cmpop then
         begin
           location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
@@ -240,16 +241,22 @@ implementation
           location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
         end;
 
-      // emit the actual operation
+      { see comment in thlcgllvm.a_loadfpu_ref_reg }
+      if tfloatdef(left.resultdef).floattype in [s64comp,s64currency] then
+        size:=sc80floattype
+      else
+        size:=left.resultdef;
+
+      { emit the actual operation }
       if not cmpop then
         begin
-          current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_reg_reg(op,location.register,resultdef,
+          current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_reg_reg(op,location.register,size,
             left.location.register,right.location.register))
         end
       else
         begin
           current_asmdata.CurrAsmList.concat(taillvm.op_reg_fpcond_size_reg_reg(op,
-            location.register,llvmfpcmp,left.resultdef,left.location.register,right.location.register))
+            location.register,llvmfpcmp,size,left.location.register,right.location.register))
         end;
     end;
 

+ 2 - 1
compiler/llvm/nllvmcon.pas

@@ -67,7 +67,8 @@ implementation
            { comp and currency are handled as int64 at the llvm level }
            s64comp,
            s64currency:
-             current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_const_size(la_bitcast,location.register,resultdef,trunc(value_real),resultdef));
+             { sc80floattype instead of resultdef, see comment in thlcgllvm.a_loadfpu_ref_reg }
+             current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_const_size(la_sitofp,location.register,s64inttype,trunc(value_real),sc80floattype));
 {$ifdef cpuextended}
            s80real,sc80real:
              current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_fpconst80_size(la_bitcast,location.register,resultdef,value_real,resultdef));