Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
jemc committed Aug 19, 2024
1 parent c0ece23 commit bd3eb31
Show file tree
Hide file tree
Showing 23 changed files with 3,294 additions and 0 deletions.
22 changes: 22 additions & 0 deletions manifest.savi
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
:manifest lib LLVM
:sources "src/*.savi"

:manifest bin "spec"
:copies LLVM
:sources "spec/*.savi"

:dependency Spec v0
:from "github:savi-lang/Spec"
:depends on Map
:depends on Time
:depends on Timer

:transitive dependency Map v0
:from "github:savi-lang/Map"

:transitive dependency Time v0
:from "github:savi-lang/Time"

:transitive dependency Timer v0
:from "github:savi-lang/Timer"
:depends on Time
6 changes: 6 additions & 0 deletions spec/LLVM.Spec.savi
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
:class LLVM.Spec
:is Spec
:const describes: "LLVM"

:it "has placeholder tests which do nothing"
llvm = LLVM.new
5 changes: 5 additions & 0 deletions spec/Main.savi
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
:actor Main
:new (env Env)
Spec.Process.run(env, [
Spec.Run(LLVM.Spec).new(env)
])
88 changes: 88 additions & 0 deletions src/LLVM.Atomic.savi
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
:enum LLVM.Atomic.Ordering
:: A load or store which is not atomic.
:member NotAtomic 0

:: Lowest level of atomicity, guarantees somewhat sane results, lock free.
:member Unordered 1

:: Guarantees that if you take all the operations affecting a specific
:: address, a consistent ordering exists.
:member Monotonic 2

:: Acquire provides a barrier of the sort necessary to acquire a lock
:: to access other memory with normal loads and stores.
:member Acquire 4

:: Release is similar to Acquire, but with a barrier of the sort necessary
:: to release a lock.
:member Release 5

:: Provides both an Acquire and a Release barrier (for fences and
:: operatios which both read and write memory).
:member AcquireRelease 6

:: Provides Acquire semantics for loads and Release semantics for stores.
:: Additionally it guarantees that a total ordering exists between all
:: SequentiallyConsistent operations.
:member SequentiallyConsistent 7

:enum LLVM.Atomic.RMWBinOp
:: Set the new value and return the one old.
:member Xchg 0

:: Add a value and return the old one.
:member Add 1

:: Subtract a value and return the old one.
:member Sub 2

:: And a value and return the old one.
:member And 3

:: Not-And a value and return the old one.
:member Nand 4

:: Or a value and return the old one.
:member Or 5

:: Xor a value and return the old one.
:member Xor 6

:: Sets the value if it's greater than the original using a signed comparison
:: and return the old one.
:member Max 7

:: Sets the value if it's lesser than the original using a signed comparison
:: and return the old one.
:member Min 8

:: Sets the value if it's greater than the original using an unsigned
:: comparison and return the old one.
:member UMax 9

:: Sets the value if it's lesser than the original using an unsigned
:: comparison and return the old one.
:member UMin 10

:: Add a floating point value and return the old one.
:member FAdd 11

:: Subtract a floating point value and return the old one.
:member FSub 12

:: Sets the value if it's greater than the original using a floating point
:: comparison and return the old one.
:member FMax 13

:: Sets the value if it's lesser than the original using a floating point
:: comparison and return the old one.
:member FMin 14

:: Increments the value, wrapping back to zero when incremented
:: above input value.
:member UIncWrap 15

:: Decrements the value, wrapping back to the input value when decremented
:: below zero.
:member UDecWrap 16

22 changes: 22 additions & 0 deletions src/LLVM.Block.savi
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
:struct LLVM.Block
:let _ptr CPointer(None)
:new _from_ptr(@_ptr)

:: Convert the block into a value (for instructions which take a block value).
:fun as_value @->(LLVM.Value)
_FFI.Cast(LLVM.Value, @->(LLVM.Value)).pointer(_FFI.basic_block_as_value(@))

:: Get the name of the block.
:fun name: _FFI.string(_FFI.get_basic_block_name(@))

:: Get the function to which the block belongs.
:fun parent: _FFI.get_basic_block_parent(@)

:: Check if the block has a terminator instruction.
:fun has_terminator: _FFI.get_basic_block_terminator(@)._ptr.is_not_null

:: Get the terminator instruction of the block.
:fun terminator!
terminator = _FFI.get_basic_block_terminator(@)
error! if terminator._ptr.is_null
terminator
237 changes: 237 additions & 0 deletions src/LLVM.Builder.savi
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
:struct LLVM.Builder
:let _ptr CPointer(None) // opaque
:new _from_ptr(@_ptr)

:fun ref at(block LLVM.Block) None
_FFI.position_builder_at_end(@, block)

:fun ref before(instruction LLVM.Value) None
_FFI.position_builder_before_instr_and_dbg_records(@, instruction)

:fun ref ret_void: _FFI.build_ret_void(@)

:fun ref ret(value LLVM.Value): _FFI.build_ret(@, value)

:fun ref aggregate_ret(values Array(LLVM.Value))
_FFI.build_aggregate_ret(@, values.cpointer, values.size.u32)

:fun ref br(block LLVM.Block): _FFI.build_br(@, block)

:fun ref cond_br(
if_value LLVM.Value
then_block LLVM.Block
else_block LLVM.Block
)
_FFI.build_cond_br(@, if_value, then_block, else_block)

// TODO: :fun ref switch
// TODO: :fun ref indirect_br
// TODO: :fun ref invoke

:fun ref unreachable: _FFI.build_unreachable(@)

// TODO: :fun ref resume
// TODO: :fun ref landing_pad
// TODO: :fun ref cleanup_ret
// TODO: :fun ref catch_ret
// TODO: :fun ref catch_switch

:fun ref add(lhs, rhs, name = ""): _FFI.build_add(@, lhs, rhs, name.cstring)
:fun ref nsw_add(lhs, rhs, name = ""): _FFI.build_nsw_add(@, lhs, rhs, name.cstring)
:fun ref nuw_add(lhs, rhs, name = ""): _FFI.build_nuw_add(@, lhs, rhs, name.cstring)
:fun ref fadd(lhs, rhs, name = ""): _FFI.build_fadd(@, lhs, rhs, name.cstring)
:fun ref sub(lhs, rhs, name = ""): _FFI.build_sub(@, lhs, rhs, name.cstring)
:fun ref nsw_sub(lhs, rhs, name = ""): _FFI.build_nsw_sub(@, lhs, rhs, name.cstring)
:fun ref nuw_sub(lhs, rhs, name = ""): _FFI.build_nuw_sub(@, lhs, rhs, name.cstring)
:fun ref fsub(lhs, rhs, name = ""): _FFI.build_fsub(@, lhs, rhs, name.cstring)
:fun ref mul(lhs, rhs, name = ""): _FFI.build_mul(@, lhs, rhs, name.cstring)
:fun ref nsw_mul(lhs, rhs, name = ""): _FFI.build_nsw_mul(@, lhs, rhs, name.cstring)
:fun ref nuw_mul(lhs, rhs, name = ""): _FFI.build_nuw_mul(@, lhs, rhs, name.cstring)
:fun ref fmul(lhs, rhs, name = ""): _FFI.build_fmul(@, lhs, rhs, name.cstring)
:fun ref udiv(lhs, rhs, name = ""): _FFI.build_udiv(@, lhs, rhs, name.cstring)
:fun ref exact_udiv(lhs, rhs, name = ""): _FFI.build_exact_udiv(@, lhs, rhs, name.cstring)
:fun ref sdiv(lhs, rhs, name = ""): _FFI.build_sdiv(@, lhs, rhs, name.cstring)
:fun ref exact_sdiv(lhs, rhs, name = ""): _FFI.build_exact_sdiv(@, lhs, rhs, name.cstring)
:fun ref fdiv(lhs, rhs, name = ""): _FFI.build_fdiv(@, lhs, rhs, name.cstring)
:fun ref urem(lhs, rhs, name = ""): _FFI.build_urem(@, lhs, rhs, name.cstring)
:fun ref srem(lhs, rhs, name = ""): _FFI.build_srem(@, lhs, rhs, name.cstring)
:fun ref frem(lhs, rhs, name = ""): _FFI.build_frem(@, lhs, rhs, name.cstring)
:fun ref shl(lhs, rhs, name = ""): _FFI.build_shl(@, lhs, rhs, name.cstring)
:fun ref lshr(lhs, rhs, name = ""): _FFI.build_lshr(@, lhs, rhs, name.cstring)
:fun ref ashr(lhs, rhs, name = ""): _FFI.build_ashr(@, lhs, rhs, name.cstring)
:fun ref and(lhs, rhs, name = ""): _FFI.build_and(@, lhs, rhs, name.cstring)
:fun ref or(lhs, rhs, name = ""): _FFI.build_or(@, lhs, rhs, name.cstring)
:fun ref xor(lhs, rhs, name = ""): _FFI.build_xor(@, lhs, rhs, name.cstring)
:fun ref neg(value, name = ""): _FFI.build_neg(@, value, name.cstring)
:fun ref nsw_neg(value, name = ""): _FFI.build_nsw_neg(@, value, name.cstring)
:fun ref fneg(value, name = ""): _FFI.build_fneg(@, value, name.cstring)
:fun ref not(value, name = ""): _FFI.build_not(@, value, name.cstring)

:fun ref malloc(type, name = "")
_FFI.build_malloc(@, type, name.cstring)

:fun ref array_malloc(type, size, name = "")
_FFI.build_array_malloc(@, type, size, name.cstring)

:fun ref memset(pointer, value, size, align)
_FFI.build_memset(@, pointer, value, size, align)

:fun ref memcpy(dst, dst_align, src, src_align, size)
_FFI.build_memcpy(@, dst, dst_align, src, src_align, size)

:fun ref memmove(dst, dst_align, src, src_align, size)
_FFI.build_memmove(@, dst, dst_align, src, src_align, size)

:fun ref alloca(type, name = "")
_FFI.build_alloca(@, type, name.cstring)

:fun ref array_alloca(type, size, name = "")
_FFI.build_array_alloca(@, type, size, name.cstring)

:fun ref free(pointer)
_FFI.build_free(@, pointer)

:fun ref load(type, pointer, name = "")
_FFI.build_load_2(@, type, pointer, name.cstring)

:fun ref store(value, pointer)
_FFI.build_store(@, value, pointer)

:fun ref gep(type, pointer, indices Array(LLVM.Value)'box, name = "")
_FFI.build_gep_2(@
type, pointer, indices.cpointer, indices.size.u32, name.cstring
)

:fun ref in_bounds_gep(
type, pointer, indices Array(LLVM.Value)'box, name = ""
)
_FFI.build_in_bounds_gep_2(@
type, pointer, indices.cpointer, indices.size.u32, name.cstring
)

// TODO: gep_with_no_wrap_flags

:fun ref struct_gep(type, pointer, index, name = "")
_FFI.build_struct_gep_2(@, type, pointer, index, name.cstring)

:fun ref trunc(value, dest_type, name = "")
_FFI.build_trunc(@, value, dest_type, name.cstring)

:fun ref z_ext(value, dest_type, name = "")
_FFI.build_z_ext(@, value, dest_type, name.cstring)

:fun ref s_ext(value, dest_type, name = "")
_FFI.build_s_ext(@, value, dest_type, name.cstring)

:fun ref fp_to_ui(value, dest_type, name = "")
_FFI.build_fp_to_ui(@, value, dest_type, name.cstring)

:fun ref fp_to_si(value, dest_type, name = "")
_FFI.build_fp_to_si(@, value, dest_type, name.cstring)

:fun ref ui_to_fp(value, dest_type, name = "")
_FFI.build_ui_to_fp(@, value, dest_type, name.cstring)

:fun ref si_to_fp(value, dest_type, name = "")
_FFI.build_si_to_fp(@, value, dest_type, name.cstring)

:fun ref fp_trunc(value, dest_type, name = "")
_FFI.build_fp_trunc(@, value, dest_type, name.cstring)

:fun ref ptr_to_int(value, dest_type, name = "")
_FFI.build_ptr_to_int(@, value, dest_type, name.cstring)

:fun ref int_to_ptr(value, dest_type, name = "")
_FFI.build_int_to_ptr(@, value, dest_type, name.cstring)

:fun ref bit_cast(value, dest_type, name = "")
_FFI.build_bit_cast(@, value, dest_type, name.cstring)

:fun ref addr_space_cast(value, dest_type, name = "")
_FFI.build_addr_space_cast(@, value, dest_type, name.cstring)

:fun ref z_ext_or_bit_cast(value, dest_type, name = "")
_FFI.build_z_ext_or_bit_cast(@, value, dest_type, name.cstring)

:fun ref s_ext_or_bit_cast(value, dest_type, name = "")
_FFI.build_s_ext_or_bit_cast(@, value, dest_type, name.cstring)

:fun ref trunc_or_bit_cast(value, dest_type, name = "")
_FFI.build_trunc_or_bit_cast(@, value, dest_type, name.cstring)

:fun ref pointer_cast(value, dest_type, name = "")
_FFI.build_pointer_cast(@, value, dest_type, name.cstring)

// TODO: int_cast
// TODO: fp_cast

:fun ref i_cmp(predicate, lhs, rhs, name = "")
_FFI.build_i_cmp(@, predicate, lhs, rhs, name.cstring)

:fun ref f_cmp(predicate, lhs, rhs, name = "")
_FFI.build_f_cmp(@, predicate, lhs, rhs, name.cstring)

// TODO: phi

:fun ref call(
function LLVM.Function
args Array(LLVM.Value)
name = ""
)
@virtual_call(function.type, function.as_value, args, name)

:fun ref virtual_call(
function_type LLVM.Type.Function
function LLVM.Value
args Array(LLVM.Value)
name = ""
)
_FFI.build_call_2(
@, function_type, function, args.cpointer, args.size.u32, name.cstring
)

// TODO: select
// TODO: va_arg

:fun ref vector_extract(vector, index, name = "")
_FFI.build_extract_element(@, vector, index, name.cstring)

:fun ref vector_insert(vector, element, index, name = "")
_FFI.build_insert_element(@, vector, element, index, name.cstring)

:fun ref vector_shuffle(vector_1, vector_2, mask, name = "")
_FFI.build_shuffle_vector(@, vector_1, vector_2, mask, name.cstring)

:fun ref extract_value(aggregate, index, name = "")
_FFI.build_extract_value(@, aggregate, index, name.cstring)

:fun ref insert_value(aggregate, element, index, name = "")
_FFI.build_insert_value(@, aggregate, element, index, name.cstring)

// TODO: freeze

:fun ref is_null(value, name = "")
_FFI.build_is_null(@, value, name.cstring)

:fun ref is_not_null(value, name = "")
_FFI.build_is_not_null(@, value, name.cstring)

:fun ref ptr_diff(element_type, lhs, rhs, name = "")
_FFI.build_ptr_diff_2(@, element_type, lhs, rhs, name.cstring)

:fun ref fence(ordering, single_thread = False, name = "")
_FFI.build_fence(@, ordering, _FFI.Bool.from(single_thread), name.cstring)

:fun ref atomic_rmw(op, pointer, value, ordering, single_thread = False)
_FFI.build_atomic_rmw(
@, op, pointer, value, ordering, _FFI.Bool.from(single_thread)
)

:fun ref atomic_cmp_xchg(
pointer, cmp, new, success_ordering, failure_ordering, single_thread = False
)
_FFI.build_atomic_cmp_xchg(
@, pointer, cmp, new
success_ordering, failure_ordering
_FFI.Bool.from(single_thread)
)
Loading

0 comments on commit bd3eb31

Please sign in to comment.