--- OpenCL/gengetinfo 2011/11/20 10:25:17 1.2 +++ OpenCL/gengetinfo 2012/04/19 14:36:46 1.9 @@ -14,6 +14,7 @@ profiling Event mem Memory image Image + gl_texture Image sampler Sampler program Program program_build Program @@ -78,12 +79,13 @@ rename "$file~", $file; } -for my $CLASS (qw(platform device context command_queue mem image sampler program program_build kernel kernel_work_group event profiling)) { +for my $CLASS (qw(platform device context command_queue mem image sampler program program_build kernel kernel_work_group event profiling gl_texture)) { open my $fh, ") { chomp; @@ -97,6 +99,7 @@ my $cbase = $class; $cbase =~ s/_(.)/\U$1/g; + $cbase =~ s/Gl(?=[A-Z])/GL/g; $cbase =~ s/^cl//; $cbase =~ s/Info$//; $cbase = "MemObject" if $cbase eq "Mem"; @@ -123,7 +126,7 @@ } my $dynamic; - my $nelem = "size / sizeof (value [0])"; + my $nelem = "size / sizeof (*value)"; if ($ctype eq "STRING_CLASS") { $ctype = "VECTOR_CLASS"; @@ -153,29 +156,34 @@ $perltype = "\$$perltype"; } - $POD .= "=item $perltype = \$$real_class->$perl_name$extra_perl_args\n\nCalls C with C<$name> and returns the result(s).\n\n"; + $POD .= "=item $perltype = \$$real_class->$perl_name$extra_perl_args\n\nCalls C with C<$name> and returns the result.\n\n"; - $XS .= "void\n" - . "$perl_name (OpenCL::$classmap{$real_class} this$extra_xs_args)\n" - . " PPCODE:\n"; + # XS1 contains the function before ALIAS, XS2 the function afterwards (the body) + # after we generate the bdoy we look for an identical body generated earlier + # and simply alias us to the earlier xs function, to save text size. + my ($XS1, $XS2); + + $XS1 = "void\n" + . "XXXNAMEXXX (OpenCL::$classmap{$real_class} self$extra_xs_args)\n"; + $XS2 = " PPCODE:\n"; if ($dynamic) { - $XS .= " size_t size;\n" - . " NEED_SUCCESS (Get${cbase}Info, (this$extra_args, $name, 0, 0, &size));\n" - . " $type->[0] *value = tmpbuf (size);\n" - . " NEED_SUCCESS (Get${cbase}Info, (this$extra_args, $name, size, value, 0));\n"; + $XS2 .= " size_t size;\n" + . " NEED_SUCCESS (Get${cbase}Info, (self$extra_args, ix, 0, 0, &size));\n" + . " $type->[0] *value = tmpbuf (size);\n" + . " NEED_SUCCESS (Get${cbase}Info, (self$extra_args, ix, size, value, 0));\n"; } else { - $XS .= " $type->[0] value [1];\n" - . " NEED_SUCCESS (Get${cbase}Info, (this$extra_args, $name, sizeof (value), value, 0));\n"; + $XS2 .= " $type->[0] value [1];\n" + . " NEED_SUCCESS (Get${cbase}Info, (self$extra_args, ix, sizeof (value), value, 0));\n"; } - if ($array) { - $XS .= " int i, n = $nelem;\n" - . " EXTEND (SP, n);\n" - . " for (i = 0; i < n; ++i)\n"; + if ($array && $nelem ne "1") { + $XS2 .= " int i, n = $nelem;\n" + . " EXTEND (SP, n);\n" + . " for (i = 0; i < n; ++i)\n"; } else { - $XS .= " EXTEND (SP, 1);\n" - . " const int i = 0;\n" + $XS2 .= " EXTEND (SP, 1);\n" + . " const int i = 0;\n" } if ($type->[1] =~ /^OpenCL::(\S+)$/) { @@ -183,17 +191,41 @@ $oclass = "MemObject" if $oclass eq "Memory"; $oclass = "CommandQueue" if $oclass eq "Queue"; - $XS .= " {\n"; - $XS .= " NEED_SUCCESS (Retain$oclass, (value [i]));\n" unless $1 eq "Platform" || $1 eq "Device"; - $XS .= " PUSHs (NEW_MORTAL_OBJ (\"$type->[1]\", value [i]));\n"; - $XS .= " }\n"; + $XS2 .= " {\n"; + $XS2 .= " NEED_SUCCESS (Retain$oclass, (value [i]));\n" unless $1 eq "Platform" || $1 eq "Device"; + $XS2 .= " PUSHs (NEW_MORTAL_OBJ (\"$type->[1]\", value [i]));\n"; + $XS2 .= " }\n"; + } else { + $XS2 .= " PUSHs (sv_2mortal ($type->[1]));\n"; + } + + $XS2 .= "\n"; + + if (my $alias = $alias{"$XS1$XS2"}) { + push @$alias, [$perl_name, $name]; } else { - $XS .= " PUSHs (sv_2mortal ($type->[1]));\n"; + push @funcs, [$XS1, (my $alias = [[$perl_name, $name]]), $XS2]; + $alias{"$XS1$XS2"} = $alias; } + } + + my $XS; - $XS .= "\n"; + # this very dirty and ugly code is a very dirty and ugly code size optimisation. + for (@funcs) { + $_->[0] =~s /^XXXNAMEXXX/$_->[1][0][0]/m; + + if (@{ $_->[1] } == 1) { # undo ALIAS + $_->[2] =~ s/\bix\b/$_->[1][0][1]/g; + $_->[1] = ""; + } else { + $_->[1] = " ALIAS:\n" . join "", map " $_->[0] = $_->[1]\n", @{ $_->[1] }; + } + $XS .= join "", @$_; } + warn "patching class $CLASS\n"; + patch "OpenCL.xs", "#BEGIN:$CLASS" , "#END:$CLASS" , $XS; patch "OpenCL.pm", "=for gengetinfo begin $CLASS", "=for gengetinfo end $CLASS", $POD; }