From fad7c79c50a95b556f4d8b66bb420151ed77bf35 Mon Sep 17 00:00:00 2001 From: Max Fierke Date: Thu, 22 Apr 2021 00:02:04 -0500 Subject: [PATCH 1/6] Add support for LLVM 12 Fixes #10434 --- src/llvm/ext/llvm-versions.txt | 2 +- src/llvm/ext/llvm_ext.cc | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/llvm/ext/llvm-versions.txt b/src/llvm/ext/llvm-versions.txt index 2fdbdf9a1c98..7a8af33aa8b5 100644 --- a/src/llvm/ext/llvm-versions.txt +++ b/src/llvm/ext/llvm-versions.txt @@ -1 +1 @@ -11.1 11.0 10.0 9.0 8.0 7.1 6.0 5.0 4.0 3.9 3.8 +12.0 11.1 11.0 10.0 9.0 8.0 7.1 6.0 5.0 4.0 3.9 3.8 diff --git a/src/llvm/ext/llvm_ext.cc b/src/llvm/ext/llvm_ext.cc index 4d2b13cf4193..3a30bd54b6c2 100644 --- a/src/llvm/ext/llvm_ext.cc +++ b/src/llvm/ext/llvm_ext.cc @@ -351,9 +351,19 @@ void LLVMMetadataReplaceAllUsesWith2( void LLVMExtSetCurrentDebugLocation( LLVMBuilderRef Bref, unsigned Line, unsigned Col, LLVMMetadataRef Scope, LLVMMetadataRef InlinedAt) { +#if LLVM_VERSION_GE(12, 0) + if (!Scope) + unwrap(Bref)->SetCurrentDebugLocation(DebugLoc()); + else + unwrap(Bref)->SetCurrentDebugLocation( + DILocation::get(unwrap(Scope)->getContext(), Line, Col, + unwrapDI(Scope), + unwrapDI(InlinedAt))); +#else unwrap(Bref)->SetCurrentDebugLocation( DebugLoc::get(Line, Col, Scope ? unwrap(Scope) : nullptr, InlinedAt ? unwrap(InlinedAt) : nullptr)); +#endif } LLVMValueRef LLVMExtBuildCmpxchg( From 31a8aa265ddbd861268d985e27535b7da2d72251 Mon Sep 17 00:00:00 2001 From: Max Fierke Date: Sat, 24 Jul 2021 18:09:07 -0500 Subject: [PATCH 2/6] Pass types for byval and sret on LLVM 12+ byval supports types back to LLVM 9, so enabled that piece too. --- .../codegen/c_abi/c_abi_x86_64_spec.cr | 7 ++++++- src/compiler/crystal/codegen/call.cr | 6 +++--- src/compiler/crystal/codegen/fun.cr | 4 ++-- src/llvm/enums.cr | 21 +++++++++++++++++++ src/llvm/ext/llvm_ext.cc | 15 +++++++++++++ src/llvm/function.cr | 8 +++++-- src/llvm/lib_llvm.cr | 3 +++ src/llvm/lib_llvm_ext.cr | 5 +++++ src/llvm/value_methods.cr | 9 ++++++-- 9 files changed, 68 insertions(+), 10 deletions(-) diff --git a/spec/compiler/codegen/c_abi/c_abi_x86_64_spec.cr b/spec/compiler/codegen/c_abi/c_abi_x86_64_spec.cr index 84a92e7075f6..5383e1030efa 100644 --- a/spec/compiler/codegen/c_abi/c_abi_x86_64_spec.cr +++ b/spec/compiler/codegen/c_abi/c_abi_x86_64_spec.cr @@ -153,7 +153,12 @@ require "../../../spec_helper" )) str = mod.to_s str.scan(/sret/).size.should eq(2) - str.should contain("sret, i32") # sret goes as first argument + + if LibLLVM::IS_LT_120 + str.should contain("sret, i32") # sret goes as first argument + else + str.should contain("sret(%\"struct.LibFoo::Struct\") %0, i32") # sret goes as first argument + end end end {% end %} diff --git a/src/compiler/crystal/codegen/call.cr b/src/compiler/crystal/codegen/call.cr index 4523c7a965ef..22366b095874 100644 --- a/src/compiler/crystal/codegen/call.cr +++ b/src/compiler/crystal/codegen/call.cr @@ -586,12 +586,12 @@ class Crystal::CodeGenVisitor abi_arg_type = abi_info.arg_types[i]? if abi_arg_type && (attr = abi_arg_type.attr) - @last.add_instruction_attribute(i + arg_offset, attr, llvm_context) + @last.add_instruction_attribute(i + arg_offset, attr, llvm_context, abi_arg_type.type) end end if sret - @last.add_instruction_attribute(1, LLVM::Attribute::StructRet, llvm_context) + @last.add_instruction_attribute(1, LLVM::Attribute::StructRet, llvm_context, abi_info.return_type.type) end end @@ -605,7 +605,7 @@ class Crystal::CodeGenVisitor arg_types = fun_type.try(&.arg_types) || target_def.try &.args.map &.type arg_types.try &.each_with_index do |arg_type, i| if abi_info && (abi_arg_type = abi_info.arg_types[i]?) && (attr = abi_arg_type.attr) - @last.add_instruction_attribute(i + arg_offset, attr, llvm_context) + @last.add_instruction_attribute(i + arg_offset, attr, llvm_context, abi_arg_type.type) end end end diff --git a/src/compiler/crystal/codegen/fun.cr b/src/compiler/crystal/codegen/fun.cr index 38609fc93a01..deb168395ade 100644 --- a/src/compiler/crystal/codegen/fun.cr +++ b/src/compiler/crystal/codegen/fun.cr @@ -365,7 +365,7 @@ class Crystal::CodeGenVisitor abi_arg_type = abi_info.arg_types[i] if attr = abi_arg_type.attr - context.fun.add_attribute(attr, i + offset + 1) + context.fun.add_attribute(attr, i + offset + 1, abi_arg_type.type) end i += 1 unless abi_arg_type.kind == LLVM::ABI::ArgKind::Ignore @@ -373,7 +373,7 @@ class Crystal::CodeGenVisitor # This is for sret if (attr = abi_info.return_type.attr) && attr == LLVM::Attribute::StructRet - context.fun.add_attribute(attr, 1) + context.fun.add_attribute(attr, 1, abi_info.return_type.type) end args diff --git a/src/llvm/enums.cr b/src/llvm/enums.cr index 275c8dd8f8a1..61adc68c0e1b 100644 --- a/src/llvm/enums.cr +++ b/src/llvm/enums.cr @@ -60,6 +60,7 @@ module LLVM ZExt @@kind_ids = load_llvm_kinds_from_names.as(Hash(Attribute, UInt32)) + @@typed_attrs = load_llvm_typed_attributes.as(Array(Attribute)) def each_kind(&block) return if value == 0 @@ -137,6 +138,21 @@ module LLVM kinds end + private def self.load_llvm_typed_attributes + typed_attrs = [] of Attribute + + unless LibLLVM::IS_LT_90 + typed_attrs << ByVal + end + + unless LibLLVM::IS_LT_120 + # LLVM 12 introduced mandatory type parameters for byval and sret + typed_attrs << StructRet + end + + typed_attrs + end + def self.kind_for(member) @@kind_ids[member] end @@ -144,6 +160,11 @@ module LLVM def self.from_kind(kind) @@kind_ids.key_for(kind) end + + def self.requires_type?(kind) + member = from_kind(kind) + @@typed_attrs.includes?(member) + end end {% else %} @[Flags] diff --git a/src/llvm/ext/llvm_ext.cc b/src/llvm/ext/llvm_ext.cc index 3a30bd54b6c2..bd82f564a903 100644 --- a/src/llvm/ext/llvm_ext.cc +++ b/src/llvm/ext/llvm_ext.cc @@ -366,6 +366,21 @@ void LLVMExtSetCurrentDebugLocation( #endif } +#if LLVM_VERSION_GE(3, 9) +// A backported LLVMCreateTypeAttribute for LLVM < 13 +// from https://github.com/llvm/llvm-project/blob/bb8ce25e88218be60d2a4ea9c9b0b721809eff27/llvm/lib/IR/Core.cpp#L167 +LLVMAttributeRef LLVMExtCreateTypeAttribute( + LLVMContextRef C, unsigned KindID, LLVMTypeRef Ty) { + auto &Ctx = *unwrap(C); + auto AttrKind = (Attribute::AttrKind)KindID; +#if LLVM_VERSION_GE(12, 0) + return wrap(Attribute::get(Ctx, AttrKind, unwrap(Ty))); +#else + return wrap(Attribute::get(Ctx, AttrKind)); +#endif +} +#endif + LLVMValueRef LLVMExtBuildCmpxchg( LLVMBuilderRef B, LLVMValueRef PTR, LLVMValueRef Cmp, LLVMValueRef New, LLVMAtomicOrdering SuccessOrdering, LLVMAtomicOrdering FailureOrdering) { diff --git a/src/llvm/function.cr b/src/llvm/function.cr index 7ffa10cb688e..acac5435c8d6 100644 --- a/src/llvm/function.cr +++ b/src/llvm/function.cr @@ -19,12 +19,16 @@ struct LLVM::Function LibLLVM.set_function_call_convention(self, cc) end - def add_attribute(attribute : Attribute, index = AttributeIndex::FunctionIndex) + def add_attribute(attribute : Attribute, index = AttributeIndex::FunctionIndex, type : Type? = nil) return if attribute.value == 0 {% if LibLLVM.has_constant?(:AttributeRef) %} context = LibLLVM.get_module_context(LibLLVM.get_global_parent(self)) attribute.each_kind do |kind| - attribute_ref = LibLLVM.create_enum_attribute(context, kind, 0) + if LLVM::Attribute.requires_type?(kind) && type + attribute_ref = LibLLVMExt.create_type_attribute(context, kind, type) + else + attribute_ref = LibLLVM.create_enum_attribute(context, kind, 0) + end LibLLVM.add_attribute_at_index(self, index, attribute_ref) end {% else %} diff --git a/src/llvm/lib_llvm.cr b/src/llvm/lib_llvm.cr index 857987d0a36e..c9275d0bdc7d 100644 --- a/src/llvm/lib_llvm.cr +++ b/src/llvm/lib_llvm.cr @@ -19,6 +19,7 @@ end {% begin %} lib LibLLVM + IS_120 = {{LibLLVM::VERSION.starts_with?("12.0")}} IS_110 = {{LibLLVM::VERSION.starts_with?("11.0")}} IS_100 = {{LibLLVM::VERSION.starts_with?("10.0")}} IS_90 = {{LibLLVM::VERSION.starts_with?("9.0")}} @@ -33,7 +34,9 @@ end IS_LT_70 = IS_38 || IS_39 || IS_40 || IS_50 || IS_60 IS_LT_80 = IS_LT_70 || IS_70 || IS_71 + IS_LT_90 = IS_LT_80 || IS_80 IS_LT_110 = IS_LT_80 || IS_90 || IS_100 + IS_LT_120 = IS_LT_110 || IS_110 end {% end %} diff --git a/src/llvm/lib_llvm_ext.cr b/src/llvm/lib_llvm_ext.cr index a9d0dd9c7eed..3de606aa064a 100644 --- a/src/llvm/lib_llvm_ext.cr +++ b/src/llvm/lib_llvm_ext.cr @@ -165,4 +165,9 @@ lib LibLLVMExt fun target_machine_enable_global_isel = LLVMExtTargetMachineEnableGlobalIsel(machine : LibLLVM::TargetMachineRef, enable : Bool) fun create_mc_jit_compiler_for_module = LLVMExtCreateMCJITCompilerForModule(jit : LibLLVM::ExecutionEngineRef*, m : LibLLVM::ModuleRef, options : LibLLVM::JITCompilerOptions*, options_length : UInt32, enable_global_isel : Bool, error : UInt8**) : Int32 + + {% unless LibLLVM::IS_38 %} + # LLVMCreateTypeAttribute is implemented in LLVM 13, but needed in 12 + fun create_type_attribute = LLVMExtCreateTypeAttribute(ctx : LibLLVM::ContextRef, kind_id : LibC::UInt, ty : LibLLVM::TypeRef): LibLLVM::AttributeRef + {% end %} end diff --git a/src/llvm/value_methods.cr b/src/llvm/value_methods.cr index bab4569638ba..2ee13f556b07 100644 --- a/src/llvm/value_methods.cr +++ b/src/llvm/value_methods.cr @@ -14,11 +14,16 @@ module LLVM::ValueMethods LibLLVM.get_value_kind(self) end - def add_instruction_attribute(index : Int, attribute : LLVM::Attribute, context : LLVM::Context) + def add_instruction_attribute(index : Int, attribute : LLVM::Attribute, context : LLVM::Context, type : LLVM::Type? = nil) return if attribute.value == 0 {% if LibLLVM.has_constant?(:AttributeRef) %} attribute.each_kind do |kind| - attribute_ref = LibLLVM.create_enum_attribute(context, kind, 0) + if LLVM::Attribute.requires_type?(kind) && type + attribute_ref = LibLLVMExt.create_type_attribute(context, kind, type) + else + attribute_ref = LibLLVM.create_enum_attribute(context, kind, 0) + end + LibLLVM.add_call_site_attribute(self, index, attribute_ref) end {% else %} From 1f0c8fa890bd9ed335272e912de42658ded19680 Mon Sep 17 00:00:00 2001 From: Max Fierke Date: Sat, 24 Jul 2021 18:13:47 -0500 Subject: [PATCH 3/6] Fix formatting in lib_llvm_ext.cr --- src/llvm/lib_llvm_ext.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm/lib_llvm_ext.cr b/src/llvm/lib_llvm_ext.cr index 3de606aa064a..c14e6f3ebc97 100644 --- a/src/llvm/lib_llvm_ext.cr +++ b/src/llvm/lib_llvm_ext.cr @@ -168,6 +168,6 @@ lib LibLLVMExt {% unless LibLLVM::IS_38 %} # LLVMCreateTypeAttribute is implemented in LLVM 13, but needed in 12 - fun create_type_attribute = LLVMExtCreateTypeAttribute(ctx : LibLLVM::ContextRef, kind_id : LibC::UInt, ty : LibLLVM::TypeRef): LibLLVM::AttributeRef + fun create_type_attribute = LLVMExtCreateTypeAttribute(ctx : LibLLVM::ContextRef, kind_id : LibC::UInt, ty : LibLLVM::TypeRef) : LibLLVM::AttributeRef {% end %} end From 8811771bfe6d6400eb47a1c8e0ed51f640d67ab0 Mon Sep 17 00:00:00 2001 From: Max Fierke Date: Sun, 25 Jul 2021 12:57:17 -0500 Subject: [PATCH 4/6] Specify type for byval only on LLVM 12+ Despite the LLVM docs specifying byval having an optional type back to 9.0, it seems it didn't validate on LLVM 10, so playing safe and leaving for LLVM 12+ only. --- src/llvm/enums.cr | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/llvm/enums.cr b/src/llvm/enums.cr index 61adc68c0e1b..a604d1d7d7ce 100644 --- a/src/llvm/enums.cr +++ b/src/llvm/enums.cr @@ -141,12 +141,9 @@ module LLVM private def self.load_llvm_typed_attributes typed_attrs = [] of Attribute - unless LibLLVM::IS_LT_90 - typed_attrs << ByVal - end - unless LibLLVM::IS_LT_120 # LLVM 12 introduced mandatory type parameters for byval and sret + typed_attrs << ByVal typed_attrs << StructRet end From 867fa5ce929c1e8acefd5253ae7aa8ec8be14b21 Mon Sep 17 00:00:00 2001 From: Max Fierke Date: Thu, 29 Jul 2021 10:00:04 -0500 Subject: [PATCH 5/6] Fix LibLLVM::IS_LT_110 to include LLVM 8.0 Co-authored-by: Sijawusz Pur Rahnama --- src/llvm/lib_llvm.cr | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/llvm/lib_llvm.cr b/src/llvm/lib_llvm.cr index c9275d0bdc7d..694d1767a63a 100644 --- a/src/llvm/lib_llvm.cr +++ b/src/llvm/lib_llvm.cr @@ -35,7 +35,8 @@ end IS_LT_70 = IS_38 || IS_39 || IS_40 || IS_50 || IS_60 IS_LT_80 = IS_LT_70 || IS_70 || IS_71 IS_LT_90 = IS_LT_80 || IS_80 - IS_LT_110 = IS_LT_80 || IS_90 || IS_100 + IS_LT_100 = IS_LT_90 || IS_90 + IS_LT_110 = IS_LT_100 || IS_100 IS_LT_120 = IS_LT_110 || IS_110 end {% end %} From a5c7ffe9f100ee8baea7fbbb7e8afd17985fefaa Mon Sep 17 00:00:00 2001 From: Max Fierke Date: Thu, 29 Jul 2021 12:59:20 -0500 Subject: [PATCH 6/6] Short-circuit type attribute type checking by ensuring we have type first Co-authored-by: Sijawusz Pur Rahnama --- src/llvm/function.cr | 2 +- src/llvm/value_methods.cr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm/function.cr b/src/llvm/function.cr index acac5435c8d6..13d6af5ca5cd 100644 --- a/src/llvm/function.cr +++ b/src/llvm/function.cr @@ -24,7 +24,7 @@ struct LLVM::Function {% if LibLLVM.has_constant?(:AttributeRef) %} context = LibLLVM.get_module_context(LibLLVM.get_global_parent(self)) attribute.each_kind do |kind| - if LLVM::Attribute.requires_type?(kind) && type + if type && LLVM::Attribute.requires_type?(kind) attribute_ref = LibLLVMExt.create_type_attribute(context, kind, type) else attribute_ref = LibLLVM.create_enum_attribute(context, kind, 0) diff --git a/src/llvm/value_methods.cr b/src/llvm/value_methods.cr index 2ee13f556b07..30a2e2bb7df1 100644 --- a/src/llvm/value_methods.cr +++ b/src/llvm/value_methods.cr @@ -18,7 +18,7 @@ module LLVM::ValueMethods return if attribute.value == 0 {% if LibLLVM.has_constant?(:AttributeRef) %} attribute.each_kind do |kind| - if LLVM::Attribute.requires_type?(kind) && type + if type && LLVM::Attribute.requires_type?(kind) attribute_ref = LibLLVMExt.create_type_attribute(context, kind, type) else attribute_ref = LibLLVM.create_enum_attribute(context, kind, 0)