Browse Source

+ new llvmconvop() routine that determines the conversion operation to
convert one def to another, including information regarding whether
it should be done via an intermediate integer typecast
* use this routine in hlcgllvm

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

Jonas Maebe 11 năm trước cách đây
mục cha
commit
a8b2b576ca
4 tập tin đã thay đổi với 105 bổ sung27 xóa
  1. 27 24
      compiler/llvm/hlcgllvm.pas
  2. 3 1
      compiler/llvm/itllvm.pas
  3. 3 1
      compiler/llvm/llvmbase.pas
  4. 72 1
      compiler/llvm/llvmdef.pas

+ 27 - 24
compiler/llvm/hlcgllvm.pas

@@ -480,32 +480,35 @@ implementation
 
   procedure thlcgllvm.a_load_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
     var
-      fromregtyp,
-      toregtyp: tregistertype;
       op: tllvmop;
+      tmpreg: tregister;
+      tmpintdef: tdef;
     begin
-      fromregtyp:=def2regtyp(fromsize);
-      toregtyp:=def2regtyp(tosize);
-      { int to pointer or vice versa }
-      if (fromregtyp=R_ADDRESSREGISTER) and
-         (toregtyp=R_INTREGISTER) then
-        op:=la_ptrtoint
-      else if (fromregtyp=R_INTREGISTER) and
-         (toregtyp=R_ADDRESSREGISTER) then
-        op:=la_inttoptr
-      { int to int or ptr to ptr: need zero/sign extension, or plain bitcast? }
-      else if tosize.size<>fromsize.size then
-        begin
-          if tosize.size<fromsize.size then
-            op:=la_trunc
-          else if is_signed(fromsize) then
-            { fromsize is signed -> sign extension }
-            op:=la_sext
-          else
-            op:=la_zext;
-        end
-      else
-        op:=la_bitcast;
+      op:=llvmconvop(fromsize,tosize);
+      { converting from pointer to something else and vice versa is only
+        possible via an intermediate pass to integer. Same for "something else"
+        to pointer. }
+      case op of
+        la_ptrtoint_to_x,
+        la_x_to_inttoptr:
+          begin
+            { convert via an integer with the same size as "x" }
+            if op=la_ptrtoint_to_x then
+              begin
+                tmpintdef:=cgsize_orddef(def_cgsize(tosize));
+                op:=la_bitcast
+              end
+            else
+              begin
+                tmpintdef:=cgsize_orddef(def_cgsize(fromsize));
+                op:=la_inttoptr;
+              end;
+            tmpreg:=getintregister(list,tmpintdef);
+            a_load_reg_reg(list,fromsize,tmpintdef,reg1,tmpreg);
+            reg1:=tmpreg;
+            fromsize:=tmpintdef;
+          end;
+      end;
       { reg2 = bitcast fromsize reg1 to tosize }
       list.concat(taillvm.op_reg_size_reg_size(op,reg2,fromsize,reg1,tosize));
     end;

+ 3 - 1
compiler/llvm/itllvm.pas

@@ -58,7 +58,9 @@ interface
         'phi', 'select', 'call',
         'va_arg', 'landingpad',
         { fpc pseudo opcodes }
-        'type' { type definition }
+        'type', { type definition }
+        'invalid1', { la_x_to_inttoptr }
+        'invalid2'  { la_ptrtoint_to_x }
       );
 
       llvm_cond2str : array[topcmp] of ansistring = ('',

+ 3 - 1
compiler/llvm/llvmbase.pas

@@ -66,7 +66,9 @@ interface
       la_phi, la_select, la_call,
       la_va_arg, la_landingpad,
       { fpc pseudo opcodes }
-      la_type { type definition }
+      la_type, { type definition }
+      la_x_to_inttoptr, { have to convert something first to int before it can be converted to a pointer }
+      la_ptrtoint_to_x { have to convert a pointer first to int before it can be converted to something else }
     );
 
     tllvmvalueextension = (lve_none, lve_zeroext, lve_signext);

+ 72 - 1
compiler/llvm/llvmdef.pas

@@ -94,6 +94,8 @@ interface
       (struct, array) }
     function llvmaggregatetype(def: tdef): boolean;
 
+    function llvmconvop(fromsize, tosize: tdef): tllvmop;
+
 
 implementation
 
@@ -102,7 +104,7 @@ implementation
     verbose,systems,
     fmodule,
     symtable,symconst,symsym,
-    llvmsym,
+    llvmsym,hlcgobj,
     defutil,cgbase,paramgr;
 
 
@@ -125,6 +127,75 @@ implementation
     end;
 
 
+  function llvmconvop(fromsize, tosize: tdef): tllvmop;
+    var
+      fromregtyp,
+      toregtyp: tregistertype;
+      frombytesize,
+      tobytesize: asizeint;
+    begin
+      fromregtyp:=hlcg.def2regtyp(fromsize);
+      toregtyp:=hlcg.def2regtyp(tosize);
+      { int to pointer or vice versa }
+      if fromregtyp=R_ADDRESSREGISTER then
+        begin
+          case toregtyp of
+            R_INTREGISTER:
+              result:=la_ptrtoint;
+            R_ADDRESSREGISTER:
+              result:=la_bitcast;
+            else
+              result:=la_ptrtoint_to_x;
+            end;
+        end
+      else if toregtyp=R_ADDRESSREGISTER then
+        begin
+          case fromregtyp of
+            R_INTREGISTER:
+              result:=la_inttoptr;
+            R_ADDRESSREGISTER:
+              result:=la_bitcast;
+            else
+              result:=la_x_to_inttoptr;
+            end;
+        end
+      else
+        begin
+          frombytesize:=fromsize.size;
+          tobytesize:=tosize.size;
+          { need zero/sign extension, float truncation or plain bitcast? }
+          if tobytesize<>frombytesize then
+            begin
+              case fromregtyp of
+                R_FPUREGISTER,
+                R_MMREGISTER:
+                  begin
+                    { todo: update once we support vectors }
+                    if not(toregtyp in [R_FPUREGISTER,R_MMREGISTER]) then
+                      internalerror(2014062203);
+                    if tobytesize<frombytesize then
+                      result:=la_fptrunc
+                    else
+                      result:=la_fpext
+                  end;
+                else
+                  begin
+                    if tobytesize<frombytesize then
+                      result:=la_trunc
+                    else if is_signed(fromsize) then
+                      { fromsize is signed -> sign extension }
+                      result:=la_sext
+                    else
+                      result:=la_zext;
+                  end;
+              end;
+            end
+          else
+            result:=la_bitcast;
+        end;
+    end;
+
+
   function llvmbyvalparaloc(paraloc: pcgparalocation): boolean;
     begin
       { "byval" is broken for register paras on several platforms in llvm