From 711a9ce801a3125bf5c3550491e2251aeed5562a Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Sat, 26 Mar 2022 09:43:52 -0300 Subject: [PATCH 1/6] Add 'wasm_import_module' option to the @[Link] annotation --- src/compiler/crystal/codegen/fun.cr | 4 ++++ src/compiler/crystal/codegen/link.cr | 11 ++++++++--- src/compiler/crystal/semantic/ast.cr | 1 + src/compiler/crystal/semantic/top_level_visitor.cr | 12 ++++++++++++ src/compiler/crystal/types.cr | 4 ++++ src/llvm/function.cr | 10 ++++++++++ src/llvm/lib_llvm.cr | 1 + 7 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/compiler/crystal/codegen/fun.cr b/src/compiler/crystal/codegen/fun.cr index cbdc9589cbc9..2dcdf7568da2 100644 --- a/src/compiler/crystal/codegen/fun.cr +++ b/src/compiler/crystal/codegen/fun.cr @@ -202,6 +202,10 @@ class Crystal::CodeGenVisitor end end + if target_def.is_a? External && (wasm_import_module = target_def.wasm_import_module) + context.fun.add_attribute("wasm-import-module", wasm_import_module) + end + context.fun end end diff --git a/src/compiler/crystal/codegen/link.cr b/src/compiler/crystal/codegen/link.cr index cc764678b990..dbda33033695 100644 --- a/src/compiler/crystal/codegen/link.cr +++ b/src/compiler/crystal/codegen/link.cr @@ -4,8 +4,9 @@ module Crystal getter pkg_config : String? getter ldflags : String? getter framework : String? + getter wasm_import_module : String? - def initialize(@lib = nil, @pkg_config = @lib, @ldflags = nil, @static = false, @framework = nil) + def initialize(@lib = nil, @pkg_config = @lib, @ldflags = nil, @static = false, @framework = nil, @wasm_import_module = nil) end def static? @@ -25,6 +26,7 @@ module Crystal lib_static = false lib_pkg_config = nil lib_framework = nil + lib_wasm_import_module = nil count = 0 args.each do |arg| @@ -71,12 +73,15 @@ module Crystal when "pkg_config" named_arg.raise "'pkg_config' link argument must be a String" unless value.is_a?(StringLiteral) lib_pkg_config = value.value + when "wasm_import_module" + named_arg.raise "'wasm_import_module' link argument must be a String" unless value.is_a?(StringLiteral) + lib_wasm_import_module = value.value else - named_arg.raise "unknown link argument: '#{named_arg.name}' (valid arguments are 'lib', 'ldflags', 'static', 'pkg_config' and 'framework')" + named_arg.raise "unknown link argument: '#{named_arg.name}' (valid arguments are 'lib', 'ldflags', 'static', 'pkg_config', 'framework', and 'wasm_import_module')" end end - new(lib_name, lib_pkg_config, lib_ldflags, lib_static, lib_framework) + new(lib_name, lib_pkg_config, lib_ldflags, lib_static, lib_framework, lib_wasm_import_module) end end diff --git a/src/compiler/crystal/semantic/ast.cr b/src/compiler/crystal/semantic/ast.cr index cc6cf95f95a5..b4f6318bbeb9 100644 --- a/src/compiler/crystal/semantic/ast.cr +++ b/src/compiler/crystal/semantic/ast.cr @@ -716,6 +716,7 @@ module Crystal property real_name : String property! fun_def : FunDef property call_convention : LLVM::CallConvention? + property wasm_import_module : String? property? dead = false property? used = false diff --git a/src/compiler/crystal/semantic/top_level_visitor.cr b/src/compiler/crystal/semantic/top_level_visitor.cr index 11d8d07deddb..7abd26e84811 100644 --- a/src/compiler/crystal/semantic/top_level_visitor.cr +++ b/src/compiler/crystal/semantic/top_level_visitor.cr @@ -483,6 +483,8 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor type.private = true if node.visibility.private? + wasm_import_module = nil + process_annotations(annotations) do |annotation_type, ann| case annotation_type when @program.link_annotation @@ -496,6 +498,12 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor @program.report_warning(ann, "using non-named arguments for Link annotations is deprecated") end + if wasm_import_module && link_annotation.wasm_import_module + ann.raise "multiple wasm import modules specified for lib #{node.name}" + end + + wasm_import_module = link_annotation.wasm_import_module + type.add_link_annotation(link_annotation) when @program.call_convention_annotation type.call_convention = parse_call_convention(ann, type.call_convention) @@ -903,6 +911,10 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor call_convention = scope.call_convention end + if scope.is_a?(LibType) + external.wasm_import_module = scope.wasm_import_module + end + # We fill the arguments and return type in TypeDeclarationVisitor external.doc = node.doc external.call_convention = call_convention diff --git a/src/compiler/crystal/types.cr b/src/compiler/crystal/types.cr index ad8b65270945..4f42fa6a4c1d 100644 --- a/src/compiler/crystal/types.cr +++ b/src/compiler/crystal/types.cr @@ -2600,6 +2600,10 @@ module Crystal def type_desc "lib" end + + def wasm_import_module + (@link_annotations.try &.find &.wasm_import_module).try &.wasm_import_module + end end # A `type` (typedef) type inside a `lib` declaration. diff --git a/src/llvm/function.cr b/src/llvm/function.cr index 13d6af5ca5cd..41da5adc5c88 100644 --- a/src/llvm/function.cr +++ b/src/llvm/function.cr @@ -19,6 +19,16 @@ struct LLVM::Function LibLLVM.set_function_call_convention(self, cc) end + def add_attribute(kind : String, value : String, index = AttributeIndex::FunctionIndex) + {% if LibLLVM.has_constant?(:AttributeRef) %} + context = LibLLVM.get_module_context(LibLLVM.get_global_parent(self)) + attribute_ref = LibLLVM.create_string_attribute(context, kind, kind.bytesize, value, value.bytesize) + LibLLVM.add_attribute_at_index(self, index, attribute_ref) + {% else %} + raise "Unsupported: can't set string attributes in LLVM < 3.9" + {% end %} + end + def add_attribute(attribute : Attribute, index = AttributeIndex::FunctionIndex, type : Type? = nil) return if attribute.value == 0 {% if LibLLVM.has_constant?(:AttributeRef) %} diff --git a/src/llvm/lib_llvm.cr b/src/llvm/lib_llvm.cr index d22e00b59fe2..33fffb81d152 100644 --- a/src/llvm/lib_llvm.cr +++ b/src/llvm/lib_llvm.cr @@ -372,6 +372,7 @@ lib LibLLVM fun get_last_enum_attribute_kind = LLVMGetLastEnumAttributeKind : UInt fun get_enum_attribute_kind_for_name = LLVMGetEnumAttributeKindForName(name : Char*, s_len : LibC::SizeT) : UInt fun create_enum_attribute = LLVMCreateEnumAttribute(c : ContextRef, kind_id : UInt, val : UInt64) : AttributeRef + fun create_string_attribute = LLVMCreateStringAttribute(c : ContextRef, kind : Char*, kind_len : UInt32, val : Char*, val_len : UInt32) : AttributeRef fun add_attribute_at_index = LLVMAddAttributeAtIndex(f : ValueRef, idx : AttributeIndex, a : AttributeRef) fun get_enum_attribute_at_index = LLVMGetEnumAttributeAtIndex(f : ValueRef, idx : AttributeIndex, kind_id : UInt) : AttributeRef fun add_call_site_attribute = LLVMAddCallSiteAttribute(f : ValueRef, idx : AttributeIndex, value : AttributeRef) From 912ecc3be381f79674831165327b35e28a8e8231 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Sat, 26 Mar 2022 10:43:57 -0300 Subject: [PATCH 2/6] fix: also set 'wasm-import-name' attribute --- src/compiler/crystal/codegen/fun.cr | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/crystal/codegen/fun.cr b/src/compiler/crystal/codegen/fun.cr index 2dcdf7568da2..8a98e15431d1 100644 --- a/src/compiler/crystal/codegen/fun.cr +++ b/src/compiler/crystal/codegen/fun.cr @@ -203,6 +203,7 @@ class Crystal::CodeGenVisitor end if target_def.is_a? External && (wasm_import_module = target_def.wasm_import_module) + context.fun.add_attribute("wasm-import-name", target_def.real_name) context.fun.add_attribute("wasm-import-module", wasm_import_module) end From 181d26df6223f4d1fb76a8437d2da87061da36c9 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Sat, 26 Mar 2022 11:51:05 -0300 Subject: [PATCH 3/6] fix: spec error message --- spec/compiler/semantic/lib_spec.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/compiler/semantic/lib_spec.cr b/spec/compiler/semantic/lib_spec.cr index e017ada7d511..5908a341d999 100644 --- a/spec/compiler/semantic/lib_spec.cr +++ b/spec/compiler/semantic/lib_spec.cr @@ -345,7 +345,7 @@ describe "Semantic: lib" do lib LibFoo end ), - "unknown link argument: 'boo' (valid arguments are 'lib', 'ldflags', 'static', 'pkg_config' and 'framework')" + "unknown link argument: 'boo' (valid arguments are 'lib', 'ldflags', 'static', 'pkg_config', 'framework', and 'wasm_import_module')" end it "errors if lib already specified with positional argument" do From f3364c775997cf717553136a9880389fe7819a09 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 29 Mar 2022 11:58:58 -0300 Subject: [PATCH 4/6] feat: export all top-level `fun` functions --- src/compiler/crystal/codegen/fun.cr | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/compiler/crystal/codegen/fun.cr b/src/compiler/crystal/codegen/fun.cr index 8a98e15431d1..50a546b3adee 100644 --- a/src/compiler/crystal/codegen/fun.cr +++ b/src/compiler/crystal/codegen/fun.cr @@ -202,9 +202,15 @@ class Crystal::CodeGenVisitor end end - if target_def.is_a? External && (wasm_import_module = target_def.wasm_import_module) - context.fun.add_attribute("wasm-import-name", target_def.real_name) - context.fun.add_attribute("wasm-import-module", wasm_import_module) + if @program.has_flag?("wasm32") + if target_def.is_a? External && (wasm_import_module = target_def.wasm_import_module) + context.fun.add_attribute("wasm-import-name", target_def.real_name) + context.fun.add_attribute("wasm-import-module", wasm_import_module) + end + + if is_exported_fun + context.fun.add_attribute("wasm-export-name", mangled_name) + end end context.fun From 30718b63a08911efa95beaac12c472651c94c7a7 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Sun, 3 Apr 2022 14:40:35 -0300 Subject: [PATCH 5/6] chore: use add_target_dependent_attribute instead of add_attribute. Same result, less code --- src/compiler/crystal/codegen/fun.cr | 6 +++--- src/llvm/function.cr | 10 ---------- src/llvm/lib_llvm.cr | 1 - 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/compiler/crystal/codegen/fun.cr b/src/compiler/crystal/codegen/fun.cr index 50a546b3adee..83205edc3ff4 100644 --- a/src/compiler/crystal/codegen/fun.cr +++ b/src/compiler/crystal/codegen/fun.cr @@ -204,12 +204,12 @@ class Crystal::CodeGenVisitor if @program.has_flag?("wasm32") if target_def.is_a? External && (wasm_import_module = target_def.wasm_import_module) - context.fun.add_attribute("wasm-import-name", target_def.real_name) - context.fun.add_attribute("wasm-import-module", wasm_import_module) + context.fun.add_target_dependent_attribute("wasm-import-name", target_def.real_name) + context.fun.add_target_dependent_attribute("wasm-import-module", wasm_import_module) end if is_exported_fun - context.fun.add_attribute("wasm-export-name", mangled_name) + context.fun.add_target_dependent_attribute("wasm-export-name", mangled_name) end end diff --git a/src/llvm/function.cr b/src/llvm/function.cr index 41da5adc5c88..13d6af5ca5cd 100644 --- a/src/llvm/function.cr +++ b/src/llvm/function.cr @@ -19,16 +19,6 @@ struct LLVM::Function LibLLVM.set_function_call_convention(self, cc) end - def add_attribute(kind : String, value : String, index = AttributeIndex::FunctionIndex) - {% if LibLLVM.has_constant?(:AttributeRef) %} - context = LibLLVM.get_module_context(LibLLVM.get_global_parent(self)) - attribute_ref = LibLLVM.create_string_attribute(context, kind, kind.bytesize, value, value.bytesize) - LibLLVM.add_attribute_at_index(self, index, attribute_ref) - {% else %} - raise "Unsupported: can't set string attributes in LLVM < 3.9" - {% end %} - end - def add_attribute(attribute : Attribute, index = AttributeIndex::FunctionIndex, type : Type? = nil) return if attribute.value == 0 {% if LibLLVM.has_constant?(:AttributeRef) %} diff --git a/src/llvm/lib_llvm.cr b/src/llvm/lib_llvm.cr index 33fffb81d152..d22e00b59fe2 100644 --- a/src/llvm/lib_llvm.cr +++ b/src/llvm/lib_llvm.cr @@ -372,7 +372,6 @@ lib LibLLVM fun get_last_enum_attribute_kind = LLVMGetLastEnumAttributeKind : UInt fun get_enum_attribute_kind_for_name = LLVMGetEnumAttributeKindForName(name : Char*, s_len : LibC::SizeT) : UInt fun create_enum_attribute = LLVMCreateEnumAttribute(c : ContextRef, kind_id : UInt, val : UInt64) : AttributeRef - fun create_string_attribute = LLVMCreateStringAttribute(c : ContextRef, kind : Char*, kind_len : UInt32, val : Char*, val_len : UInt32) : AttributeRef fun add_attribute_at_index = LLVMAddAttributeAtIndex(f : ValueRef, idx : AttributeIndex, a : AttributeRef) fun get_enum_attribute_at_index = LLVMGetEnumAttributeAtIndex(f : ValueRef, idx : AttributeIndex, kind_id : UInt) : AttributeRef fun add_call_site_attribute = LLVMAddCallSiteAttribute(f : ValueRef, idx : AttributeIndex, value : AttributeRef) From 5f88c65261c302ce5fdfc0abc561d5d10e1e9389 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Sun, 3 Apr 2022 15:56:03 -0300 Subject: [PATCH 6/6] Update src/compiler/crystal/codegen/fun.cr Co-authored-by: Sijawusz Pur Rahnama --- src/compiler/crystal/codegen/fun.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/crystal/codegen/fun.cr b/src/compiler/crystal/codegen/fun.cr index 83205edc3ff4..16d950f49bd3 100644 --- a/src/compiler/crystal/codegen/fun.cr +++ b/src/compiler/crystal/codegen/fun.cr @@ -203,7 +203,7 @@ class Crystal::CodeGenVisitor end if @program.has_flag?("wasm32") - if target_def.is_a? External && (wasm_import_module = target_def.wasm_import_module) + if target_def.is_a?(External) && (wasm_import_module = target_def.wasm_import_module) context.fun.add_target_dependent_attribute("wasm-import-name", target_def.real_name) context.fun.add_target_dependent_attribute("wasm-import-module", wasm_import_module) end