#!/usr/bin/env perl
# Generate honest fail-closed C stubs for HSA APIs SoftGPU does not implement.
use strict;
use warnings;

my $header = $ARGV[0] // die "usage: $0 <header.h> <out.c> <include-line>\n";
my $out    = $ARGV[1] // die "usage: $0 <header.h> <out.c> <include-line>\n";
my $inc    = $ARGV[2] // '#include "hsa/hsa.h"';

my %implemented = map { $_ => 1 } qw(
  hsa_init
  hsa_shut_down
  hsa_iterate_agents
  hsa_agent_get_info
  hsa_status_string
  hsa_system_get_info
  hsa_agent_iterate_regions
  hsa_region_get_info
  hsa_memory_allocate
  hsa_memory_free
  hsa_memory_copy
  hsa_amd_agent_iterate_memory_pools
  hsa_amd_memory_pool_get_info
  hsa_amd_memory_pool_allocate
  hsa_amd_memory_pool_free
  hsa_amd_agents_allow_access
  hsa_amd_agent_memory_pool_get_info
  hsa_signal_create
  hsa_signal_destroy
  hsa_signal_load_scacquire
  hsa_signal_load_relaxed
  hsa_signal_store_screlease
  hsa_signal_store_relaxed
  hsa_signal_wait_scacquire
  hsa_signal_wait_relaxed
  hsa_queue_create
  hsa_queue_destroy
  hsa_queue_load_read_index_scacquire
  hsa_queue_load_read_index_relaxed
  hsa_queue_load_write_index_scacquire
  hsa_queue_load_write_index_relaxed
  hsa_queue_store_write_index_relaxed
  hsa_queue_store_write_index_screlease
  hsa_queue_store_read_index_relaxed
  hsa_queue_store_read_index_screlease
);

open my $fh, '<', $header or die "read $header: $!";
local $/;
my $text = <$fh>;
close $fh;

$text =~ s{/\*.*?\*/}{}gs;
$text =~ s{//.*?$}{}gm;

my @stubs;
while ($text =~ /
  ((?:hsa_status_t|void|hsa_signal_value_t|uint64_t|uint32_t|int|bool|hsa_amd_pointer_status_t)\s+)
  HSA_API\s+
  (hsa_[A-Za-z0-9_]+)\s*
  (\([^;]*\))\s*;
/gx) {
  my ($ret, $name, $args) = ($1, $2, $3);
  $ret =~ s/\s+$//;
  next if $implemented{$name};
  my $body;
  if ($ret eq 'void') {
    $body = "{\n  /* SoftGPU: unsupported void API */\n}\n";
  } elsif ($ret eq 'hsa_status_t' || $ret eq 'hsa_amd_pointer_status_t') {
    $body = "{\n  return HSA_STATUS_ERROR;\n}\n";
  } elsif ($ret eq 'bool') {
    $body = "{\n  return false;\n}\n";
  } else {
    $body = "{\n  return ($ret)0;\n}\n";
  }
  push @stubs, "/* auto-stub */\n$ret HSA_API $name$args\n$body";
}

open my $outfh, '>', $out or die "write $out: $!";
print $outfh <<"HDR";
/* Generated by tools/generate-hsa-stubs.pl — do not edit by hand.
 * Source header: $header
 */
#define HSA_EXPORT
$inc

HDR
print $outfh join("\n", @stubs);
print $outfh "\n/* generated stub count: ", scalar(@stubs), " */\n";
close $outfh;
print "wrote $out (", scalar(@stubs), " stubs)\n";
