Skip to content

Commit

Permalink
Add support for LLVM 13 (#11302)
Browse files Browse the repository at this point in the history
  • Loading branch information
maxfierke committed Oct 20, 2021
1 parent 120f0ab commit 0dc389f
Show file tree
Hide file tree
Showing 19 changed files with 213 additions and 118 deletions.
1 change: 1 addition & 0 deletions spec/compiler/parser/parser_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,7 @@ module Crystal
it_parses %(asm("nop" :: "b"(1), "c"(2) : "eax", "ebx" : "volatile", "alignstack", "intel")), Asm.new("nop", inputs: [AsmOperand.new("b", 1.int32), AsmOperand.new("c", 2.int32)], clobbers: %w(eax ebx), volatile: true, alignstack: true, intel: true)
it_parses %(asm("nop" :: "b"(1), "c"(2) : "eax", "ebx"\n: "volatile", "alignstack"\n,\n"intel"\n)), Asm.new("nop", inputs: [AsmOperand.new("b", 1.int32), AsmOperand.new("c", 2.int32)], clobbers: %w(eax ebx), volatile: true, alignstack: true, intel: true)
it_parses %(asm("nop" :::: "volatile")), Asm.new("nop", volatile: true)
it_parses %(asm("bl trap" :::: "unwind")), Asm.new("bl trap", can_throw: true)

assert_syntax_error %q(asm("nop" ::: "#{foo}")), "interpolation not allowed in asm clobber"
assert_syntax_error %q(asm("nop" :::: "#{volatile}")), "interpolation not allowed in asm option"
Expand Down
1 change: 1 addition & 0 deletions spec/compiler/parser/to_s_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ describe "ASTNode#to_s" do
expect_to_s %(asm("nop" :::: "volatile"))
expect_to_s %(asm("nop" :: "a"(1) :: "volatile"))
expect_to_s %(asm("nop" ::: "e" : "volatile"))
expect_to_s %(asm("bl trap" :::: "unwind"))
expect_to_s %[(1..)]
expect_to_s %[..3]
expect_to_s "offsetof(Foo, @bar)"
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/crystal/codegen/asm.cr
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class Crystal::CodeGenVisitor
fun_type = LLVM::Type.function(input_types, output_type)
constraints = constraints.to_s

value = fun_type.inline_asm(node.text, constraints, node.volatile?, node.alignstack?)
value = fun_type.inline_asm(node.text, constraints, node.volatile?, node.alignstack?, node.can_throw?)
value = LLVM::Function.from_value(value)
asm_value = call value, input_values

Expand Down
2 changes: 0 additions & 2 deletions src/compiler/crystal/codegen/codegen.cr
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ module Crystal
@main_ret_type : Type
@argc : LLVM::Value
@argv : LLVM::Value
@empty_md_list : LLVM::Value
@rescue_block : LLVM::BasicBlock?
@catch_pad : LLVM::Value?
@malloc_fun : LLVM::Function?
Expand Down Expand Up @@ -235,7 +234,6 @@ module Crystal
# are not going to be used.
@needs_value = true

@empty_md_list = metadata([] of Int32)
@unused_fun_defs = [] of FunDef
@proc_counts = Hash(String, Int32).new(0)

Expand Down
2 changes: 1 addition & 1 deletion src/compiler/crystal/codegen/context.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ require "./codegen"
class Crystal::CodeGenVisitor
class Context
property fun : LLVM::Function
property fun_debug_params = [] of LibLLVMExt::Metadata
property fun_debug_params = [] of LibLLVM::MetadataRef
property type : Type
property vars : Hash(String, LLVMVar)
property return_type : Type?
Expand Down
91 changes: 48 additions & 43 deletions src/compiler/crystal/codegen/debug.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ module Crystal
#
CPP_LANG_DEBUG_IDENTIFIER = 0x0004_u32

record FunMetadata, filename : String, metadata : LibLLVMExt::Metadata
record FunMetadata, filename : String, metadata : LibLLVM::MetadataRef

alias DebugFilename = Crystal::VirtualFile | String?

@current_debug_location : Location?
@debug_files = {} of Crystal::VirtualFile | String? => LibLLVMExt::Metadata
@current_debug_file : LibLLVMExt::Metadata?

# We cache these either for performance, memory use, or protection from the GC
@debug_files_per_module = {} of LLVM::Module => Hash(DebugFilename, LibLLVM::MetadataRef)
@debug_types_per_module = {} of LLVM::Module => Hash(Type, LibLLVM::MetadataRef?)

def di_builder(llvm_module = @llvm_mod || @main_mod)
di_builders = @di_builders ||= {} of LLVM::Module => LLVM::DIBuilder
Expand All @@ -32,19 +36,25 @@ module Crystal
# DebugInfo generation in LLVM by default uses a higher version of dwarf
# than OS X currently understands. Android has the same problem.
if @program.has_flag?("osx") || @program.has_flag?("android")
mod.add_named_metadata_operand("llvm.module.flags",
metadata([LLVM::ModuleFlag::Warning.value, "Dwarf Version", 2]))
mod.add_flag(
LLVM::ModuleFlag::Warning,
"Dwarf Version",
mod.context.int32.const_int(2)
)
end

mod.add_named_metadata_operand("llvm.module.flags",
metadata([LLVM::ModuleFlag::Warning.value, "Debug Info Version", LLVM::DEBUG_METADATA_VERSION]))
mod.add_flag(
LLVM::ModuleFlag::Warning,
"Debug Info Version",
mod.context.int32.const_int(LLVM::DEBUG_METADATA_VERSION)
)
end

def fun_metadatas
@fun_metadatas ||= {} of LLVM::Function => Array(FunMetadata)
end

def fun_metadata_type(debug_types = [] of LibLLVMExt::Metadata)
def fun_metadata_type(debug_types = [] of LibLLVM::MetadataRef)
if debug_types.empty?
int = di_builder.create_basic_type("int", 32, 32, LLVM::DwarfTypeEncoding::Signed)
debug_types << int
Expand All @@ -56,11 +66,22 @@ module Crystal
def debug_type_cache
# We must cache debug types per module so metadata of a type
# from one module isn't incorrectly used in another module.
debug_types_per_module =
@debug_types_per_module ||=
{} of LLVM::Module => Hash(Type, LibLLVMExt::Metadata?)
@debug_types_per_module[@llvm_mod] ||= {} of Type => LibLLVM::MetadataRef?
end

debug_types_per_module[@llvm_mod] ||= {} of Type => LibLLVMExt::Metadata?
def debug_files_cache
# We must cache debug files per module so metadata of a type
# from one module isn't incorrectly used in another module.
@debug_files_per_module[@llvm_mod] ||= {} of DebugFilename => LibLLVM::MetadataRef
end

def current_debug_file
if location = @current_debug_location
debug_files_cache[location.filename || "??"] ||= begin
file, dir = file_and_dir(location.filename)
di_builder.create_file(file, dir)
end
end
end

def get_debug_type(type, original_type : Type)
Expand Down Expand Up @@ -112,10 +133,10 @@ module Crystal

def create_debug_type(type : InstanceVarContainer, original_type : Type)
ivars = type.all_instance_vars
element_types = [] of LibLLVMExt::Metadata
element_types = [] of LibLLVM::MetadataRef
struct_type = llvm_struct_type(type)

tmp_debug_type = di_builder.create_replaceable_composite_type(nil, original_type.to_s, nil, 1, llvm_context)
tmp_debug_type = di_builder.create_replaceable_composite_type(nil, original_type.to_s, nil, 1)
debug_type_cache[original_type] = tmp_debug_type

ivars.each_with_index do |(name, ivar), idx|
Expand Down Expand Up @@ -148,12 +169,12 @@ module Crystal
end

def create_debug_type(type : MixedUnionType, original_type : Type)
element_types = [] of LibLLVMExt::Metadata
element_types = [] of LibLLVM::MetadataRef
struct_type = llvm_type(type)
struct_type_size = @program.target_machine.data_layout.size_in_bits(struct_type)
is_struct = struct_type.struct_element_types.size == 1

tmp_debug_type = di_builder.create_replaceable_composite_type(nil, original_type.to_s, nil, 1, llvm_context)
tmp_debug_type = di_builder.create_replaceable_composite_type(nil, original_type.to_s, nil, 1)
debug_type_cache[original_type] = tmp_debug_type

type.expand_union_types.each do |ivar_type|
Expand All @@ -169,7 +190,7 @@ module Crystal

size = @program.target_machine.data_layout.size_in_bits(struct_type.struct_element_types[is_struct ? 0 : 1])
offset = @program.target_machine.data_layout.offset_of_element(struct_type, 1) * 8u64
debug_type = di_builder.create_union_type(nil, nil, @current_debug_file.not_nil!, 1, size, size, LLVM::DIFlags::Zero, di_builder.get_or_create_type_array(element_types))
debug_type = di_builder.create_union_type(nil, nil, current_debug_file.not_nil!, 1, size, size, LLVM::DIFlags::Zero, di_builder.get_or_create_type_array(element_types))
unless is_struct
element_types.clear
element_types << di_builder.create_member_type(nil, "type_id", nil, 1, 32, 32, 0, LLVM::DIFlags::Zero, get_debug_type(@program.uint32))
Expand All @@ -181,9 +202,9 @@ module Crystal
end

def create_debug_type(type : NilableReferenceUnionType | ReferenceUnionType, original_type : Type)
element_types = [] of LibLLVMExt::Metadata
element_types = [] of LibLLVM::MetadataRef
struct_type = llvm_type(type)
tmp_debug_type = di_builder.create_replaceable_composite_type(nil, original_type.to_s, nil, 1, llvm_context)
tmp_debug_type = di_builder.create_replaceable_composite_type(nil, original_type.to_s, nil, 1)
debug_type_cache[original_type] = tmp_debug_type

type.expand_union_types.each do |ivar_type|
Expand All @@ -197,7 +218,7 @@ module Crystal
end

size = @program.target_machine.data_layout.size_in_bits(struct_type)
debug_type = di_builder.create_union_type(nil, original_type.to_s, @current_debug_file.not_nil!, 1, size, size, LLVM::DIFlags::Zero, di_builder.get_or_create_type_array(element_types))
debug_type = di_builder.create_union_type(nil, original_type.to_s, current_debug_file.not_nil!, 1, size, size, LLVM::DIFlags::Zero, di_builder.get_or_create_type_array(element_types))
di_builder.replace_temporary(tmp_debug_type, debug_type)
debug_type
end
Expand All @@ -219,10 +240,10 @@ module Crystal

def create_debug_type(type : TupleInstanceType, original_type : Type)
ivars = type.tuple_types
element_types = [] of LibLLVMExt::Metadata
element_types = [] of LibLLVM::MetadataRef
struct_type = llvm_struct_type(type)

tmp_debug_type = di_builder.create_replaceable_composite_type(nil, original_type.to_s, nil, 1, llvm_context)
tmp_debug_type = di_builder.create_replaceable_composite_type(nil, original_type.to_s, nil, 1)
debug_type_cache[original_type] = tmp_debug_type

ivars.each_with_index do |ivar_type, idx|
Expand All @@ -247,10 +268,10 @@ module Crystal

def create_debug_type(type : NamedTupleInstanceType, original_type : Type)
ivars = type.entries
element_types = [] of LibLLVMExt::Metadata
element_types = [] of LibLLVM::MetadataRef
struct_type = llvm_struct_type(type)

tmp_debug_type = di_builder.create_replaceable_composite_type(nil, original_type.to_s, nil, 1, llvm_context)
tmp_debug_type = di_builder.create_replaceable_composite_type(nil, original_type.to_s, nil, 1)
debug_type_cache[original_type] = tmp_debug_type

ivars.each_with_index do |ivar, idx|
Expand Down Expand Up @@ -318,7 +339,7 @@ module Crystal
return false unless location

file, dir = file_and_dir(location.filename)
@current_debug_file = file = @debug_files[location.filename] ||= di_builder.create_file(file, dir)
file = debug_files_cache[location.filename] ||= di_builder.create_file(file, dir)

debug_type = get_debug_type(type)
return false unless debug_type
Expand Down Expand Up @@ -381,22 +402,6 @@ module Crystal
}
end

def metadata(args)
values = args.map do |value|
case value
when String then llvm_context.md_string(value.to_s)
when Symbol then llvm_context.md_string(value.to_s)
when Number then int32(value)
when Bool then int1(value ? 1 : 0)
when LLVM::Value then value
when LLVM::Function then value.to_value
when Nil then LLVM::Value.null
else raise "Unsupported value type: #{value.class}"
end
end
llvm_context.md_node(values)
end

def set_current_debug_location(node : ASTNode)
location = node.location
if location
Expand All @@ -408,7 +413,7 @@ module Crystal

def get_current_debug_scope(location)
if context.fun.name == MAIN_NAME
main_scopes = (@main_scopes ||= {} of {String, String} => LibLLVMExt::Metadata)
main_scopes = (@main_scopes ||= {} of {String, String} => LibLLVM::MetadataRef)
file, dir = file_and_dir(location.filename)
main_scope = main_scopes[{file, dir}] ||= begin
di_builder = di_builder(@main_mod)
Expand Down Expand Up @@ -453,7 +458,7 @@ module Crystal
builder.set_current_debug_location(0, 0, nil)
end

def emit_fun_debug_metadata(func, fun_name, location, *, debug_types = [] of LibLLVMExt::Metadata, is_optimized = false)
def emit_fun_debug_metadata(func, fun_name, location, *, debug_types = [] of LibLLVM::MetadataRef, is_optimized = false)
filename = location.try(&.original_filename) || "??"
line_number = location.try(&.line_number) || 0

Expand Down
7 changes: 4 additions & 3 deletions src/compiler/crystal/syntax/ast.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2254,8 +2254,9 @@ module Crystal
property? volatile : Bool
property? alignstack : Bool
property? intel : Bool
property? can_throw : Bool

def initialize(@text, @outputs = nil, @inputs = nil, @clobbers = nil, @volatile = false, @alignstack = false, @intel = false)
def initialize(@text, @outputs = nil, @inputs = nil, @clobbers = nil, @volatile = false, @alignstack = false, @intel = false, @can_throw = false)
end

def accept_children(visitor)
Expand All @@ -2264,10 +2265,10 @@ module Crystal
end

def clone_without_location
Asm.new(@text, @outputs.clone, @inputs.clone, @clobbers, @volatile, @alignstack, @intel)
Asm.new(@text, @outputs.clone, @inputs.clone, @clobbers, @volatile, @alignstack, @intel, @can_throw)
end

def_equals_and_hash text, outputs, inputs, clobbers, volatile?, alignstack?, intel?
def_equals_and_hash text, outputs, inputs, clobbers, volatile?, alignstack?, intel?, can_throw?
end

class AsmOperand < ASTNode
Expand Down
10 changes: 7 additions & 3 deletions src/compiler/crystal/syntax/parser.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5202,6 +5202,7 @@ module Crystal
volatile = false
alignstack = false
intel = false
can_throw = false

part_index = 0
until @token.type == :")"
Expand Down Expand Up @@ -5230,7 +5231,7 @@ module Crystal
end
when 4
if @token.type == :DELIMITER_START
volatile, alignstack, intel = parse_asm_options
volatile, alignstack, intel, can_throw = parse_asm_options
end
else break
end
Expand All @@ -5240,7 +5241,7 @@ module Crystal

next_token_skip_space

Asm.new(text, outputs, inputs, clobbers, volatile, alignstack, intel)
Asm.new(text, outputs, inputs, clobbers, volatile, alignstack, intel, can_throw)
end

def parse_asm_operands
Expand Down Expand Up @@ -5282,6 +5283,7 @@ module Crystal
volatile = false
alignstack = false
intel = false
can_throw = false
while true
location = @token.location
option = parse_string_without_interpolation("asm option")
Expand All @@ -5293,6 +5295,8 @@ module Crystal
alignstack = true
when "intel"
intel = true
when "unwind"
can_throw = true
else
raise "unknown asm option: #{option}", location
end
Expand All @@ -5302,7 +5306,7 @@ module Crystal
end
break unless @token.type == :DELIMITER_START
end
{volatile, alignstack, intel}
{volatile, alignstack, intel, can_throw}
end

def parse_yield_with_scope
Expand Down
6 changes: 5 additions & 1 deletion src/compiler/crystal/syntax/to_s.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,7 @@ module Crystal
@str << ' '
end
@str << ":"
if node.volatile? || node.alignstack? || node.intel?
if node.volatile? || node.alignstack? || node.intel? || node.can_throw?
@str << ' '
comma = false
if node.volatile?
Expand All @@ -1509,6 +1509,10 @@ module Crystal
@str << %("intel")
comma = true
end
if node.can_throw?
@str << ", " if comma
@str << %("unwind")
end
end
@str << ')'
false
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/crystal/tools/formatter.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4269,7 +4269,7 @@ module Crystal

skip_space_or_newline

if node.volatile? || node.alignstack? || node.intel?
if node.volatile? || node.alignstack? || node.intel? || node.can_throw?
expected_parts = 4
elsif node.clobbers
expected_parts = 3
Expand Down Expand Up @@ -4315,7 +4315,7 @@ module Crystal
end
end
when 4
parts = [node.volatile?, node.alignstack?, node.intel?].select(&.itself)
parts = [node.volatile?, node.alignstack?, node.intel?, node.can_throw?].select(&.itself)
visit_asm_parts parts, colon_column do
accept StringLiteral.new("")
end
Expand Down

0 comments on commit 0dc389f

Please sign in to comment.