Skip to content

Tutorial

Yuki Kimoto edited this page Feb 23, 2024 · 11 revisions

This tutorial describes how to use the SPVM language for beginners.

Installing SPVM

SPVM is a CPAN module. SPVM can be installed from CPAN.

cpanm SPVM

or

cpan SPVM

Getting Started

Creating SPVM classes

Create a SPVM class. The name is "SPVM::MyMath".

Create "SPVM/MyMath.spvm" in the "lib" directory. The extension of a SPVM class is "spvm".

Write the following code.

# lib/SPVM/MyMath.spvm
class MyMath {
  static method sum : int ($nums : int[]) {
    
    my $total = 0;
    for (my $i = 0; $i < @$nums; $i++) {
      $total += $nums->[$i];
    }
    
    return $total;
  }
}

Class Definition

The class keyword defines a class.

# Class Definition
class MyMath {

}

See also Class in SPVM document.

Method Definition

The method keyword defines a method.

Define a class method using the static attribute.

class MyMath {
  # Class method definition
  static method sum : int ($nums : int[]) {
    
  }
}

Numeric Types

The sum method returns a value of the int type. The int type is signed 32bit integer type.

int

See also Types in SPVM document.

Array Types

int[] type in arguments in the sum method is the int array type.

int[]

Local Variable Declaration

The my keyword declare a local variable(a lexical variable in Perl).

my $total : int = 0;

SPVM has type inference, so you can omit types.

my $total = 0;

Integer Literal

0 is an integer literal.

my $total = 0;

SPVM has the following literals.

# Integer literal
123
123_456_789

# Floating point literal
1.32
1.32f

# Character literal
'a'
'c'

# String literal
"Hello World!"

See also Lexical Tokenization in SPVM document.

Getting Array Length

Look at the condition part @$nums in the for loop.

for (my $i = 0; $i < @$nums; $i++) {
  $total += $nums->[$i];
}

@ is the array length operator to get the length of an array.

Increment Operator

The incremental operator ++ increments a value by 1.

$i++

Getting Array Element

The syntax of getting array element gets an element in an array.

$nums->[$i]

Addition Operator

See the following code.

$total += $nums->[$i];

This is same as the following the additon operator and the assignment Operator.

$total = $total + $nums->[$i];

for Statement

See the for Statement.

for (my $i = 0; $i < @$nums; $i++) {
  $total += $nums->[$i];
}

See also Statements in SPVM document.

return Statement

See the return statement.

return $total;

Call SPVM Methods from Perl

Create "sum.pl" file and write the following code. This is a Perl program.

use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";

use SPVM 'MyMath';

# Call method
my $total = SPVM::MyMath->sum([3, 6, 8, 9]);

print "Total: $total\n";

# Call method with packed data
my $nums_packed = pack('l*', 3, 6, 8, 9);
my $api = SPVM::api();
my $sp_nums = $api->new_int_array_from_bin($nums_packed);
my $total_packed = SPVM::MyMath->sum($sp_nums);

print "Total Packed: $total_packed\n";

Add library path

The followings are the conventions and add current script directry's "lib" directory to library path .

use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";

use SPVM class

use SPVM class.

use SPVM 'MyMath';

In this place, compilation is not done. Collect SPVM classes.

Call SPVM Method

Call SPVM Method. It's amazing that SPVM method can be called as Perl method.

# Call method
my $total = SPVM::MyMath->sum([3, 6, 8, 9]);

Perl array reference is converted to SPVM int array.

See also Exchange API in SPVM document.

SPVM int return value is converted to Perl Scalar.

Call SPVM Method with packed data

you can pass packed binary data. The new_int_array_from_bin method creates SPVM int array from packed binary data. This is efficient.

# Call method with packed data
my $nums_packed = pack('l*', 3, 6, 8, 9);
my $api = SPVM::api();
my $sp_nums = $api->new_int_array_from_bin($nums_packed);
my $total_packed = SPVM::MyMath->sum($sp_nums);

How to improve SPVM Performance

See How to improve SPVM Performance.

If you're searching SPVM for performance reasons, here's what you really want to see.

How To Improve SPVM Performance using SPVM Precompile and SPVM Native API

SPVM Module:

# lib/SPVM/MyMath.spvm
class MyMath {
  static method sum : int ($nums : int[]) {
    
    my $total = 0;
    for (my $i = 0; $i < @$nums; $i++) {
      $total += $nums->[$i];
    }
    
    return $total;
  }
}

Use SPVM Module from Perl

# sum.pl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";

use SPVM 'MyMath';

# Call method
my $total = SPVM::MyMath->sum([3, 6, 8, 9]);

print "Total: $total\n";

# Call method with packed data
my $nums_packed = pack('l*', 3, 6, 8, 9);
my $api = SPVM::api();
my $sp_nums = $api->new_int_array_from_bin($nums_packed);
my $total_packed = SPVM::MyMath->sum($sp_nums);

print "Total Packed: $total_packed\n";

Precompiled SPVM Method. This means SPVM code is converted to Machine Code:

# lib/SPVM/MyMath.spvm
class MyMath : precompile {
  static method sum_precompile : int ($nums : int[]) {
    
    my $total = 0;
    for (my $i = 0; $i < @$nums; $i++) {
      $total += $nums->[$i];
    }
    
    return $total;
  }
}

Call SPVM Precompile Method from Perl

# sum_precompile.pl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";

use SPVM 'MyMath';

# Call precompile method
my $total_precompile = SPVM::MyMath->sum_precompile([3, 6, 8, 9]);

print "Total Precompile: $total_precompile\n";

SPVM Native Method. This means SPVM method call C/C++ native method:

# lib/SPVM/MyMath.spvm
class MyMath {
  native static method sum_native : int ($nums : int[]);
}

// lib/SPVM/MyMath.c
#include "spvm_native.h"

int32_t SPVM__SPVM__MyMath__sum_native(SPVM_ENV* env, SPVM_VALUE* stack) {
  
  void* sv_nums = stack[0].oval;
  
  int32_t length = env->length(env, stack, sv_nums);
  
  int32_t* nums = env->get_elems_int(env, stack, sv_nums);
  
  int32_t total = 0;
  for (int32_t i = 0; i < length; i++) {
    total += nums[i];
  }
  
  stack[0].ival = total;
  
  return 0;
}

# lib/SPVM/MyMath.config

use strict;
use warnings;

use SPVM::Builder::Config;
my $config = SPVM::Builder::Config->new_c99;

$config;

Use SPVM Native Method from Perl

# sum_native.pl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";

use SPVM 'MyMath';

# Call native method
my $total_native = SPVM::MyMath->sum_native([3, 6, 8, 9]);

print "Total Native: $total_native\n";

Environment Variable "SPVM_BUILD_DIR" must be set for precompile and native method

# bash example
export SPVM_BUILD_DIR=~/.spvm_build

How To Bind C/C++/CUDA Library to SPVM

The advantage of SPVM is that you can easily bind C/C++/CUDA.

Methods bound with SPVM can be easily called from Perl.

Before reading this page, you need to understand Native API.

Binding your own C language library

First, let's bind our own C library.

The following source code is the completed source code.

I will explain using this source code.

See also NativeClass in SPVM document.

Create a C language library for summation and call it from Perl.

# bind_clib.pl
use strict;
use warnings;

use FindBin;
use lib "$FindBin::Bin/lib";

use SPVM 'BindCLib';

my $total = SPVM::BindCLib->sum([1, 2, 3, 4]);

print "Total: $total\n";

SPVM Method Definition.

# lib/SPVM/BindCLib.spvm
class BindCLib {
  native static method sum : int ($nums : int[]);
}

Native Config.

# lib/SPVM/BindCLib.config
use strict;
use warnings;

use SPVM::Builder::Config;
my $config = SPVM::Builder::Config->new_c99;

$config;

Call C library from C program.

// lib/SPVM/BindCLib.c
#include "spvm_native.h"

#include "bind_clib.h"

int32_t SPVM__SPVM__BindCLib__sum(SPVM_ENV* env, SPVM_VALUE* stack) {
  
  void* sv_nums = stack[0].oval;
  
  int32_t length = env->length(env, stack, sv_nums);
  
  int32_t* nums = env->get_elems_int(env, stack, sv_nums);
  
  int32_t total = bind_clib_sum(nums, length);
  
  stack[0].ival = total;
  
  return 0;
}

Notice the line reading the header.

#include "bind_clib.h"

This header is included from "lib/SPVM/BindCLib.native/include/bind_clib.h". This is pure C header file.

#include <inttypes.h>

int32_t bind_clib_sum(int32_t* nums, int32_t length);

SPVM sets the include directory("SPVM/BindCLib.native/include") as the default header file read path.

C library source file is "lib/SPVM/BindCLib.native/src/bind_clib.c". This is pure C source file.

#include "bind_clib.h"

int32_t bind_clib_sum(int32_t* nums, int32_t length) {
  
  int32_t total = 0;
  for (int32_t i = 0; i < length; i++) {
    total += nums[i];
  }
  
  return total;
}

SPVM compiles all source files in the source directory("SPVM/BindCLib.native/src"). It can contain multiple source files.

See SPVM:Document::NativeAPI about the details of the native APIs.

How to bind other C Library to SPVM

If you want to know more about the bindings of other C libraries, see the example below.

How to bind C++ Library to SPVM

If you want to know more about the bindings of C++ libraries to SPVM, see the example below.

How to bind CUDA to SPVM

If you want to know more about the bindings of CUDA to SPVM, see the example below.

Complex Numbers

Complex Numbers

Copyright & License

Copyright (c) 2023 Yuki Kimoto

MIT License