@@ -819,7 +819,9 @@ class Savi::Compiler::CodeGen
819819 return gen_intrinsic(gtype, gfunc, llvm_func) if gfunc.func.has_tag?(:compiler_intrinsic )
820820
821821 if gfunc.func.has_tag?(:ffi )
822- if gfunc.func.has_tag?(:ffi_global_getter )
822+ if gfunc.func.has_tag?(:ffi_global_cpointer_getter )
823+ return gen_ffi_global_cpointer_getter_impl(gtype, gfunc, llvm_func)
824+ elsif gfunc.func.has_tag?(:ffi_global_getter )
823825 return gen_ffi_global_getter_impl(gtype, gfunc, llvm_func)
824826 elsif gfunc.func.has_tag?(:ffi_global_setter )
825827 return gen_ffi_global_setter_impl(gtype, gfunc, llvm_func)
@@ -967,15 +969,44 @@ class Savi::Compiler::CodeGen
967969 end
968970
969971 def gen_ffi_global_decl (gfunc )
970- llvm_type = llvm_type_of(gfunc.func.ret.not_nil!, gfunc)
972+ global_name = gfunc.func.metadata[:ffi_link_name ].as(String )
973+
974+ # Determine the type of the global variable value.
975+ # If this is a cpointer getter we need to unwrap its type arg.
976+ t = type_of(gfunc.func.ret.not_nil!, gfunc)
977+ if gfunc.func.has_tag?(:ffi_global_cpointer_getter )
978+ t = gtype_of(t).type_def.cpointer_type_arg(ctx)
979+ end
980+ llvm_type = llvm_type_of(t)
981+
982+ # If the global already exists, check that it has a compatible llvm_type
983+ # or give a compilation error, but always return the existing global,
984+ # rather than creating another global with an implicitly incremented name.
985+ existing = @mod .globals[global_name]?
986+ if existing
987+ existing_llvm_type = LLVM ::Type .new(LibLLVM .global_get_value_type(existing))
988+ raise Error .at gfunc.func.ident.pos, " FFI global #{ global_name } already exists with a different type" \
989+ unless existing_llvm_type.kind == llvm_type.kind \
990+ && abi_size_of(existing_llvm_type) == abi_size_of(llvm_type)
991+ return existing
992+ end
971993
972- global = @mod .globals.add(llvm_type, gfunc.func.metadata[ :ffi_link_name ].as( String ) )
994+ global = @mod .globals.add(llvm_type, global_name )
973995 global.linkage = LLVM ::Linkage ::External
974996 global.global_constant = gfunc.func.has_tag?(:ffi_global_constant )
975997 global.externally_initialized = true # TODO: false and set an initializer if this ffi var has an initializer
976998 global
977999 end
9781000
1001+ def gen_ffi_global_cpointer_getter_impl (gtype, gfunc, llvm_func)
1002+ gen_func_start(llvm_func, gtype, gfunc)
1003+
1004+ global = gen_ffi_global_decl(gfunc)
1005+ @builder .ret(global)
1006+
1007+ gen_func_end(gfunc)
1008+ end
1009+
9791010 def gen_ffi_global_getter_impl (gtype, gfunc, llvm_func)
9801011 gen_func_start(llvm_func, gtype, gfunc)
9811012
@@ -992,8 +1023,7 @@ class Savi::Compiler::CodeGen
9921023 def gen_ffi_global_setter_impl (gtype, gfunc, llvm_func)
9931024 gen_func_start(llvm_func, gtype, gfunc)
9941025
995- global = @mod .globals[gfunc.func.metadata[:ffi_link_name ]]
996-
1026+ global = gen_ffi_global_decl(gfunc)
9971027 value = llvm_func.params[0 ]
9981028 @builder .store(value, global)
9991029
0 commit comments