Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some tests. #2

Merged
merged 1 commit into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion spec/LLVM.Spec.savi
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,34 @@
:is Spec
:const describes: "LLVM"

:it "has placeholder tests which do nothing"
:it "can build a basic program"
llvm = LLVM.new
module = llvm.create_module("hello")

puts = module.add_function("puts"
llvm.types.function(llvm.types.i32, [llvm.types.ptr])
)
hello_world = module.add_global_with_value(
llvm.const.string("Hello, world!")
).as_value

main = module.add_function("main"
llvm.types.function(llvm.types.i32)
)
llvm.build.at(main.add_block("entry"))
llvm.build.call(puts, [hello_world])
llvm.build.ret(llvm.const.i32(0))

assert: "\(module)" == "; ModuleID = 'hello'\n\(<<<
source_filename = "hello"

@0 = global [14 x i8] c"Hello, world!\00"

declare i32 @puts(ptr)

define i32 @main() {
entry:
%0 = call i32 @puts(ptr @0)
ret i32 0
}
>>>)\n"
140 changes: 140 additions & 0 deletions spec/LLVM.Types.Spec.savi
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
:class LLVM.Types.Spec
:is Spec
:const describes: "LLVM.Types"

:it "has various pre-instantiated types, each equatable with itself"
llvm = LLVM.new

assert: "\(llvm.types.void)" == "void"
assert: "\(llvm.types.ptr)" == "ptr"
assert: "\(llvm.types.i1)" == "i1"
assert: "\(llvm.types.i8)" == "i8"
assert: "\(llvm.types.i16)" == "i16"
assert: "\(llvm.types.i32)" == "i32"
assert: "\(llvm.types.i64)" == "i64"
assert: "\(llvm.types.i128)" == "i128"
assert: "\(llvm.types.f16)" == "half"
assert: "\(llvm.types.bf16)" == "bfloat"
assert: "\(llvm.types.f32)" == "float"
assert: "\(llvm.types.f64)" == "double"

assert: llvm.types.void == llvm.types.void
assert: llvm.types.ptr == llvm.types.ptr
assert: llvm.types.i1 == llvm.types.i1
assert: llvm.types.i8 == llvm.types.i8
assert: llvm.types.i16 == llvm.types.i16
assert: llvm.types.i32 == llvm.types.i32
assert: llvm.types.i64 == llvm.types.i64
assert: llvm.types.i128 == llvm.types.i128
assert: llvm.types.f16 == llvm.types.f16
assert: llvm.types.bf16 == llvm.types.bf16
assert: llvm.types.f32 == llvm.types.f32
assert: llvm.types.f64 == llvm.types.f64

assert: llvm.types.i32 != llvm.types.f32

assert: llvm.types.void.kind.is_void
assert: llvm.types.ptr.kind.is_pointer
assert: llvm.types.i1.kind.is_integer
assert: llvm.types.i8.kind.is_integer
assert: llvm.types.i16.kind.is_integer
assert: llvm.types.i32.kind.is_integer
assert: llvm.types.i64.kind.is_integer
assert: llvm.types.i128.kind.is_integer
assert: llvm.types.f16.kind.is_real
assert: llvm.types.bf16.kind.is_real
assert: llvm.types.f32.kind.is_real
assert: llvm.types.f64.kind.is_real

assert: llvm.types.i1.as_integer_type!.bit_width == 1
assert: llvm.types.i8.as_integer_type!.bit_width == 8
assert: llvm.types.i16.as_integer_type!.bit_width == 16
assert: llvm.types.i32.as_integer_type!.bit_width == 32
assert: llvm.types.i64.as_integer_type!.bit_width == 64
assert: llvm.types.i128.as_integer_type!.bit_width == 128

:it "can create various composite types, which are structurally equatable"
llvm = LLVM.new
types = llvm.types
void = types.void
i64 = llvm.types.i64
i32 = llvm.types.i32
i8 = llvm.types.i8

assert: "\(types.array(i64, 10))" == "[10 x i64]"
assert: "\(types.vector(i64, 4))" == "<4 x i64>"
assert: "\(types.literal_struct([i64, i8]))" == "{ i64, i8 }"
assert: "\(types.literal_struct([i32]).set_body([i64, i8]))" == "{ i64, i8 }"
assert: "\(types.function(i32))" == "i32 ()"
assert: "\(types.function(i32, [i64, i8]))" == "i32 (i64, i8)"
assert: "\(types.function(i32, [i64, i8], True))" == "i32 (i64, i8, ...)"

assert: types.array(i64, 10) == types.array(i64, 10)
assert: types.array(i64, 10) != types.array(i64, 9)
assert: types.vector(i64, 4) == types.vector(i64, 4)
assert: types.vector(i64, 4) != types.vector(i64, 3)
assert: types.literal_struct([i64, i8]) == types.literal_struct([i64, i8])
assert: types.function(i32, [i64, i8]) == types.function(i32, [i64, i8])

a1 = types.array(i64, 10)
a2 = types.array(i32, 9)

assert: a1.element_type == i64
assert: a2.element_type == i32
assert: a1.size == 10
assert: a2.size == 9

fn1 = types.function(i32)
fn2 = types.function(void, [i64, i8])
fn3 = types.function(i32, [i64, i8], True)

assert: fn1.return_type == i32
assert: fn2.return_type == void
assert: fn3.return_type == i32
assert: fn1.param_types_size == 0
assert: fn1.param_types.size == 0
assert: fn2.param_types_size == 2
assert: fn2.param_types.size == 2
assert: fn2.param_types[0]! == i64
assert: fn2.param_types[1]! == i8
assert: fn1.is_variadic == False
assert: fn2.is_variadic == False
assert: fn3.is_variadic

:it "can create named structs, which are nominally equatable"
llvm = LLVM.new

foo = llvm.types.struct("foo")
bar = llvm.types.struct("bar").set_body([llvm.types.i64, llvm.types.i8])
baz = llvm.types.struct("baz").set_body([llvm.types.i64, llvm.types.i8], True)

assert: "\(foo)" == "%foo = type opaque"
assert: "\(bar)" == "%bar = type { i64, i8 }"
assert: "\(baz)" == "%baz = type <{ i64, i8 }>"

assert: foo.element_types_size == 0
assert: foo.element_types.size == 0
assert: bar.element_types_size == 2
assert: bar.element_types.size == 2
assert: bar.element_types[0]! == llvm.types.i64
assert: bar.element_types[1]! == llvm.types.i8

assert: foo.is_packed == False
assert: bar.is_packed == False
assert: baz.is_packed

assert: foo.is_opaque
assert: bar.is_opaque == False
assert: baz.is_opaque == False

assert: foo.is_literal == False
assert: bar.is_literal == False
assert: baz.is_literal == False
assert: llvm.types.literal_struct([llvm.types.i64, llvm.types.i8]).is_literal

s1 = llvm.types.struct("s").set_body([llvm.types.i64, llvm.types.i8])
s2 = llvm.types.struct("s").set_body([llvm.types.i64, llvm.types.i8])
assert: "\(s1)" == "%s = type { i64, i8 }"
assert: "\(s2)" == "%s.0 = type { i64, i8 }"
assert: s1 == s1
assert: s1 != s2
2 changes: 2 additions & 0 deletions spec/Main.savi
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@

:actor Main
:new (env Env)
Spec.Process.run(env, [
Spec.Run(LLVM.Spec).new(env)
Spec.Run(LLVM.Types.Spec).new(env)
])
4 changes: 2 additions & 2 deletions src/LLVM.Const.savi
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@

:fun f32(value F32)
_FFI.const_real(
_FFI.Cast(LLVM.Type'box, LLVM.Type.FloatingPoint'box).pointer(@_types.f32)
_FFI.Cast(LLVM.Type'box, LLVM.Type.Real'box).pointer(@_types.f32)
value.f64
)

:fun f64(value F64)
_FFI.const_real(
_FFI.Cast(LLVM.Type'box, LLVM.Type.FloatingPoint'box).pointer(@_types.f64)
_FFI.Cast(LLVM.Type'box, LLVM.Type.Real'box).pointer(@_types.f64)
value.f64
)

Expand Down
11 changes: 11 additions & 0 deletions src/LLVM.Module.savi
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@
g.initializer = value
g

:is IntoString
:fun into_string_space USize
string = _FFI.string(_FFI.print_module_to_string(@_ptr))
space = string.size
_FFI.dispose_message(string.cpointer)
space
:fun into_string(out String'ref) None
string = _FFI.string(_FFI.print_module_to_string(@_ptr))
string.into_string(out)
_FFI.dispose_message(string.cpointer)

:fun print_to_file!(filename String) None
error = CPointer(U8).null
is_error = _FFI.print_module_to_file(
Expand Down
49 changes: 40 additions & 9 deletions src/LLVM.Type.savi
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

:fun is_void: @ == LLVM.Type.Kind.Void
:fun is_integer: @ == LLVM.Type.Kind.Integer
:fun is_float: @ == LLVM.Type.Kind.BFloat || (
:fun is_real: @ == LLVM.Type.Kind.BFloat || (
@ <= LLVM.Type.Kind.PPC_FP128 && @ >= LLVM.Type.Kind.Half
)
:fun is_array: @ == LLVM.Type.Kind.Array
Expand All @@ -38,6 +38,9 @@

:fun kind LLVM.Type.Kind: _FFI.get_type_kind(@)

:is Equatable(@'box)
:fun "=="(other @'box): @_ptr.address == other._ptr.address

:fun into_string_space USize
string = _FFI.string(_FFI.print_type_to_string(@))
space = string.size
Expand All @@ -52,9 +55,9 @@
error! unless @kind.is_integer
_FFI.Cast(@, @->(LLVM.Type.Integer)).pointer(@)

:fun as_floating_point_type! @->(LLVM.Type.FloatingPoint)
error! unless @kind.is_floating_point
_FFI.Cast(@, @->(LLVM.Type.FloatingPoint)).pointer(@)
:fun as_real_type! @->(LLVM.Type.Real)
error! unless @kind.is_real
_FFI.Cast(@, @->(LLVM.Type.Real)).pointer(@)

:fun as_array_type! @->(LLVM.Type.Array)
error! unless @kind.is_array
Expand Down Expand Up @@ -84,17 +87,23 @@
:fun into_string_space: @as_type.into_string_space
:fun into_string(out String'ref): @as_type.into_string(out)

:is Equatable(@'box)
:fun "=="(other @'box): @_ptr.address == other._ptr.address

:: Get the bit width of the integer type.
:fun bit_width: _FFI.get_int_type_width(@)

:struct LLVM.Type.FloatingPoint
:struct LLVM.Type.Real
:let _ptr CPointer(None)
:new _from_ptr(@_ptr)
:fun as_type
_FFI.Cast(LLVM.Type, @->(LLVM.Type)).pointer(LLVM.Type._from_ptr(@_ptr))
:fun into_string_space: @as_type.into_string_space
:fun into_string(out String'ref): @as_type.into_string(out)

:is Equatable(@'box)
:fun "=="(other @'box): @_ptr.address == other._ptr.address

:struct LLVM.Type.Array
:let _ptr CPointer(None)
:new _from_ptr(@_ptr)
Expand All @@ -103,6 +112,9 @@
:fun into_string_space: @as_type.into_string_space
:fun into_string(out String'ref): @as_type.into_string(out)

:is Equatable(@'box)
:fun "=="(other @'box): @_ptr.address == other._ptr.address

:: Get the type of elements in the array type.
:fun element_type @->(LLVM.Type)
_FFI.Cast(LLVM.Type'box, @->(LLVM.Type)).pointer(_FFI.get_array_element_type(@))
Expand All @@ -118,6 +130,9 @@
:fun into_string_space: @as_type.into_string_space
:fun into_string(out String'ref): @as_type.into_string(out)

:is Equatable(@'box)
:fun "=="(other @'box): @_ptr.address == other._ptr.address

:: Get the type of elements in the vector type.
:fun element_type @->(LLVM.Type)
_FFI.Cast(LLVM.Type'box, @->(LLVM.Type)).pointer(_FFI.get_vector_element_type(@))
Expand All @@ -133,6 +148,9 @@
:fun into_string_space: @as_type.into_string_space
:fun into_string(out String'ref): @as_type.into_string(out)

:is Equatable(@'box)
:fun "=="(other @'box): @_ptr.address == other._ptr.address

:: Get the address space of the pointer type.
:fun address_space U32: _FFI.get_pointer_address_space(@)

Expand All @@ -144,6 +162,9 @@
:fun into_string_space: @as_type.into_string_space
:fun into_string(out String'ref): @as_type.into_string(out)

:is Equatable(@'box)
:fun "=="(other @'box): @_ptr.address == other._ptr.address

:: Get the name of the struct type.
:fun name: _FFI.string(_FFI.get_struct_name(@))

Expand Down Expand Up @@ -187,6 +208,9 @@
:fun into_string_space: @as_type.into_string_space
:fun into_string(out String'ref): @as_type.into_string(out)

:is Equatable(@'box)
:fun "=="(other @'box): @_ptr.address == other._ptr.address

:: Get the return type of the function type.
:fun return_type @->(LLVM.Type)
_FFI.Cast(LLVM.Type'box, @->(LLVM.Type)).pointer(_FFI.get_return_type(@))
Expand Down Expand Up @@ -238,10 +262,10 @@
@i32 = _FFI.Cast(LLVM.Type.Integer, LLVM.Type).pointer(_FFI.int32_type_in_context(@_ptr))
@i64 = _FFI.Cast(LLVM.Type.Integer, LLVM.Type).pointer(_FFI.int64_type_in_context(@_ptr))
@i128 = _FFI.Cast(LLVM.Type.Integer, LLVM.Type).pointer(_FFI.int128_type_in_context(@_ptr))
@f16 = _FFI.Cast(LLVM.Type.FloatingPoint, LLVM.Type).pointer(_FFI.half_type_in_context(@_ptr))
@bf16 = _FFI.Cast(LLVM.Type.FloatingPoint, LLVM.Type).pointer(_FFI.b_float_type_in_context(@_ptr))
@f32 = _FFI.Cast(LLVM.Type.FloatingPoint, LLVM.Type).pointer(_FFI.float_type_in_context(@_ptr))
@f64 = _FFI.Cast(LLVM.Type.FloatingPoint, LLVM.Type).pointer(_FFI.double_type_in_context(@_ptr))
@f16 = _FFI.Cast(LLVM.Type.Real, LLVM.Type).pointer(_FFI.half_type_in_context(@_ptr))
@bf16 = _FFI.Cast(LLVM.Type.Real, LLVM.Type).pointer(_FFI.b_float_type_in_context(@_ptr))
@f32 = _FFI.Cast(LLVM.Type.Real, LLVM.Type).pointer(_FFI.float_type_in_context(@_ptr))
@f64 = _FFI.Cast(LLVM.Type.Real, LLVM.Type).pointer(_FFI.double_type_in_context(@_ptr))

:fun ref array(element_type LLVM.Type'box, size USize)
_FFI.array_type2(element_type, size.u64)
Expand All @@ -264,3 +288,10 @@
:fun ref struct(name String)
_FFI.struct_create_named(@_ptr, name.cstring)

:fun ref literal_struct(element_types Array(LLVM.Type'box), packed = False)
_FFI.struct_type_in_context(
@_ptr
element_types.cpointer
element_types.size.u32
_FFI.Bool.from(packed)
)
1 change: 1 addition & 0 deletions src/LLVM.Value.savi
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
cpointer = _FFI.get_value_name_2(@, stack_address_of_variable size)
String.val_from_cpointer(cpointer, size, size)

:is IntoString
:fun into_string_space USize
string = _FFI.string(_FFI.print_value_to_string(@))
space = string.size
Expand Down
Loading
Loading