I can now successfully pass doubles to/from C functions on armhf. I've
written a test program that passes lots of different combinations of
single/double/longint/int64 to C code and all combinations that do not
involve singles are working.

  It would also be helpful to add this test to the testsuite
we do have some tests in test/cg
but it wouldn't hurt to add more of that type!
I've attatched the program that generates the test program, if you need it under a
specific license just ask.

Currently it is set up to test all combinations of up to four parameters and a more limited set of combinations up to 17 parameters but these are both easilly adjusted
to suit.

The generator has two modes, if the letter c is passed as the first command line
parameter it operates in "pascal calling c" mode. Otherwise it operates in
"pascal calling pascal mode".

In "pascal calling c" mode two files are generated. testfp.dpr and testfpfunctions.c
in "pascal calling pascal" mode only one file is generated.

Note that "pascal calling c" mode makes some assumptions about the equivilence
of pascal and c basic types. These assumptions should hold on most platforms
but there may be some where they do not.
program gentestfp;
uses
  sysutils,classes;
type 
  ttype = (sin,dou,int,i64);
const
  typenames: array[ttype] of string = ('single','double','longint','int64');
  ctypenames: array[ttype] of string = ('float','double','int','long long');
  printfspecifiers: array[ttype] of string = ('%f','%f','%ld','%lld');
var
  paramcount : longint;
  param: longint;
  paramcombination: longint;
  paramcombinationinner: longint;
  returntype : ttype;
  paramtype : ttype;
  t: text;
  c: text;
  paramtypes : array[1..17] of ttype;
  mainparamtype, lastparamtype : ttype;
  calls: tstringlist;
  callsofcalls : tstringlist;
  cmode : boolean;
procedure genfunction;
var
  definitionstring : string;
  callstring: string;
  cstring: string;
  functionname : string;
begin

  //generate function name
  functionname := 'z';
  for param := 1 to paramcount do begin
    functionname := functionname + typenames[paramtypes[param]][1];
  end;
  functionname := functionname + typenames[returntype][1];
  definitionstring := 'function ' + functionname;

  if paramcount > 0 then begin 
    definitionstring := definitionstring + '(';
    for param := 1 to paramcount do begin
      definitionstring := definitionstring +char(param-1+byte('a')) + ':' + 
typenames[paramtypes[param]];
      definitionstring := definitionstring + ';';
    end;
    definitionstring[length(definitionstring)] := ')';
  end;

  definitionstring := definitionstring + ':'+typenames[returntype]+';';

  if cmode then begin
    definitionstring := definitionstring+'cdecl;external;';
    cstring := ctypenames[returntype] + ' ' + functionname;
    if paramcount > 0 then begin
      cstring := cstring + '(';
      for param := 1 to paramcount do begin
        cstring := cstring + ctypenames[paramtypes[param]] +' ' 
+char(param-1+byte('a'));
        cstring := cstring + ',';
      end;
      cstring[length(cstring)] := ')';
    end else begin
      cstring := cstring + '(void)';
    end;
    cstring := cstring +'{ ';
    
    if paramcount = 0 then begin
      cstring := cstring + 'return 0x12beef;';
    end else begin
      cstring := cstring +'printf("';
      for param := 1 to paramcount do begin
        cstring := cstring + printfspecifiers[paramtypes[param]] + ' ';
      end;
      cstring[length(cstring)] := '\';
      cstring := cstring + 'n"';
      for param := 1 to paramcount do begin
        cstring :=  cstring + ',' + char(param-1+byte('a'));
      end;
      cstring := cstring + ');';
      cstring := cstring + 'fflush(stdout);';
      cstring := cstring + 'return ';
      for param := 1 to paramcount do begin
        cstring := cstring + char(param-1+byte('a')) + '+';
      end;
      cstring[length(cstring)] := ';';
    end;
    cstring := cstring + '}';
    writeln(c,cstring);
  end else begin

    definitionstring := definitionstring +'begin ';
    if paramcount = 0 then begin
      definitionstring := definitionstring + 'result := $12beef;';
    end else begin
      definitionstring := definitionstring +'writeln(';
      for param := 1 to paramcount do begin
        definitionstring :=  definitionstring + char(param-1+byte('a')) + ','' 
'',';
      end;
      setlength(definitionstring,length(definitionstring)-5);
      definitionstring := definitionstring + ');';

      definitionstring := definitionstring + 'result := trunc(';
      for param := 1 to paramcount do begin
        definitionstring := definitionstring + char(param-1+byte('a')) + '+';
      end;
      definitionstring[length(definitionstring)] := ')';
      definitionstring := definitionstring + ';';
    end;
    definitionstring := definitionstring + ' end;';
    
  end;
  writeln(t,definitionstring);
 
  callstring := 'if '+functionname;
  
  callstring := 'd := '+functionname;
  if paramcount > 0 then begin 
    callstring := callstring + '(';
    for param := 1 to paramcount do begin
      callstring := callstring +inttostr(param);
      callstring := callstring + ',';
    end;
    callstring[length(callstring)] := ')';
  end else begin
    callstring := callstring + '()';
  end;
  callstring := callstring + ';';
  calls.add(callstring);
  
  if paramcount > 0 then begin   
    callstring :=  'if d='+ inttostr((paramcount+1)*paramcount div 2);
  end else begin
    callstring :=  'if d=$12beef';
  end;


  callstring := callstring + ' then writeln('''+functionname+' pass'') else 
begin writeln('''+functionname+' fail d='',d) ; {halt} end;';
  calls.add(callstring);
  calls.add('flush(output);');
end;
var
  i : integer;
begin
  cmode := paramstr(1)='c';
  calls := tstringlist.create;
  assignfile(t,'testfp.dpr');
  rewrite(t);
  if cmode then begin
    assignfile(c,'testfpfunctions.c');
    rewrite(c);
    writeln(c,'#include <stdio.h>');
  end;
  
  
  writeln(t,'program testfp;');
  if cmode then writeln(t,'{$linklib gcc}');
  if cmode then writeln(t,'{$linklib c}');
  if cmode then writeln(t,'{$link testfpfunctions}');
  
  //test all combinations up to four parameters.
  for paramcount := 0 to 4 do begin
    for returntype := sin to i64 do begin
      for paramcombination := 0 to (1 shl (paramcount*2))-1 do begin
        paramcombinationinner := paramcombination;
        for param := 1 to paramcount do begin
          paramtypes[param] := ttype(paramcombinationinner and 3);
          paramcombinationinner := paramcombinationinner shr 2;
        end;
        genfunction;
        
        //writeln(typenames[returntype]);
      end;
    end;
  end; 

  //test up to 17 parameters with one type for the bulk of parameters and 
another for the last parameters
  for paramcount := 5 to 17 do begin
    for returntype := sin to i64 do begin
      for mainparamtype := sin to i64 do begin
        for lastparamtype := sin to i64 do begin
          for param := 1 to paramcount-1 do begin
            paramtypes[param] := mainparamtype;
          end;
          paramtypes[paramcount] := lastparamtype;
          genfunction;
          
        end;
      end;
    end;
  end;

  //individually test "zssssssssssssssssd"
  {paramcount := 16;
  returntype := dou;
  for param := 1 to 16 do begin
    paramtypes[param] := sin;
  end;
  //paramtypes[15] := dou;
  genfunction;}

  
  writeln(t,'var d: double;');

  //group calls into procedures with 256 calls each to avoid "procedure too 
complex" error.
  callsofcalls := tstringlist.create;
  for i := 0 to calls.count - 1 do begin
    if i and $ff = 0 then begin
      if i <> 0 then writeln(t,'end;');
      writeln(t,'procedure g'+inttostr(i shr 8)+'; begin');
      callsofcalls.add('g'+inttostr(i shr 8)+';');
    end;
    writeln(t,calls[i]);
  end;
  writeln(t,'end;');
  calls.free;

  writeln(t,'begin');
  for i := 0 to callsofcalls.count - 1 do begin
    writeln(t,callsofcalls[i]);
  end;
  writeln(t,'end.');
  close(t);
  if cmode then begin
    close(c);
  end;
  callsofcalls.free;
end.
_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply via email to