#!/usr/bin/perl -w # -*- tab-width: 4; indent-tabs-mode: nil; cperl-indent-level: 4 -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#

my $nFunIndexes = 8;
my $nVtableOffsets = 4;

sub gen_arm ($$)
{
    my ($funIndex, $vtableOffset) = @_;
    if ($funIndex & 0x80000000) {
        printf ("#ifndef __arm64\n");
    }
    printf ("codeSnippet_%08x_%d:\n", $funIndex, $vtableOffset);
    printf ("#ifdef __arm\n");
    # Note: pc is the address of instruction being executed plus 8
    printf ("    mov ip, pc\n");
    printf ("#else\n");
    printf ("    adr x15, .+8\n");
    printf ("#endif\n");
    printf ("    b _privateSnippetExecutor\n");
    printf ("    .long %#08x\n", $funIndex);
    printf ("    .long %d\n", $vtableOffset);
    if ($funIndex & 0x80000000) {
        printf ("#endif\n");
    }
}

sub gen_x86 ($$$)
{
    my ($funIndex, $vtableOffset, $executor) = @_;
    printf ("codeSnippet_%08x_%d_%s:\n", $funIndex, $vtableOffset, $executor);
    printf ("    movl \$%#08x, %%eax\n", $funIndex);
    printf ("    movl \$%d, %%edx\n", $vtableOffset);
    printf ("    jmp _privateSnippetExecutor%s\n", $executor);
}

printf (".text\n");

printf ("#if defined(__arm) || defined(__arm64)\n");

printf ("\n");
printf ("// Each codeSnippetX function stores into ip (arm64: x15) an address and branches to _privateSnippetExecutor\n");
printf ("// The address is that following the branch instruction, containing two 32-bit ints:\n");
printf ("// - the function index, which for 32-bit can have the 0x80000000 bit set\n");
printf ("//   to indicate that a hidden parameter is used for returning large values\n");
printf ("// - the vtable offset\n");
printf ("\n");

printf ("    .align 4\n");
printf ("\n");

foreach my $funIndex (0 .. $nFunIndexes-1)
{
   foreach my $vtableOffset (0 .. $nVtableOffsets-1)
   {
       gen_arm ($funIndex, $vtableOffset);
       gen_arm ($funIndex|0x80000000, $vtableOffset);
   }
}

printf ("#else\n");
printf ("    .align 1, 0x90\n");

foreach my $funIndex (0 .. $nFunIndexes-1)
{
    foreach my $vtableOffset (0 .. $nVtableOffsets-1)
    {
        foreach my $executor ('General', 'Void', 'Hyper', 'Float', 'Double', 'Class')
        {
            gen_x86 ($funIndex, $vtableOffset, $executor);
            gen_x86 ($funIndex|0x80000000, $vtableOffset, $executor);
        }
    }
  }

printf ("#endif\n");

printf ("    .globl _nFunIndexes\n");
printf ("_nFunIndexes:\n");
printf ("    .long %d\n", $nFunIndexes);

printf ("    .globl _nVtableOffsets\n");
printf ("_nVtableOffsets:\n");
printf ("    .long %d\n", $nVtableOffsets);

printf ("    .globl _codeSnippets\n");
printf ("_codeSnippets:\n");

foreach my $funIndex (0 .. $nFunIndexes-1)
{
    foreach my $vtableOffset (0 .. $nVtableOffsets-1)
    {
        printf ("#if defined(__arm) || defined(__arm64)\n");
        printf ("    .long codeSnippet_%08x_%d - _codeSnippets\n", $funIndex, $vtableOffset);
        printf ("#ifndef __arm64\n");
        printf ("    .long codeSnippet_%08x_%d - _codeSnippets\n", $funIndex|0x80000000, $vtableOffset);
        printf ("#endif\n");
        printf ("#else\n");
        foreach my $executor ('General', 'Void', 'Hyper', 'Float', 'Double', 'Class')
        {
            printf ("    .long codeSnippet_%08x_%d_%s - _codeSnippets\n", $funIndex, $vtableOffset, $executor);
            printf ("    .long codeSnippet_%08x_%d_%s - _codeSnippets\n", $funIndex|0x80000000, $vtableOffset, $executor);
        }
        printf ("#endif\n");
    }
}

# vim:set shiftwidth=4 softtabstop=4 expandtab:
