Skip to content

Commit

Permalink
Add --frame-pointers to control preservation of frame pointers (#13860
Browse files Browse the repository at this point in the history
)

Co-authored-by: Sijawusz Pur Rahnama <sija@sija.pl>
Co-authored-by: Quinton Miller <nicetas.c@gmail.com>
  • Loading branch information
3 people committed Jan 27, 2024
1 parent ac895ff commit 7628de6
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 5 deletions.
2 changes: 2 additions & 0 deletions man/crystal.1
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ Generate the output without any symbolic debug symbols.
Define a compile-time flag. This is useful to conditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with --target-triple or the hosts default, if none is given.
.It Fl -emit Op asm|llvm-bc|llvm-ir|obj
Comma separated list of types of output for the compiler to emit. You can use this to see the generated LLVM IR, LLVM bitcode, assembly, and object files.
.It Fl -frame-pointers Op auto|always|non-leaf
Control the preservation of frame pointers. The default value, --frame-pointers=auto, will preserve frame pointers on debug builds and try to omit them on release builds (certain platforms require them to stay enabled). --frame-pointers=always will always preserve them, and non-leaf will only force their preservation on non-leaf functions.
.It Fl f Ar text|json, Fl -format Ar text|json
Format of output. Defaults to text. The json format can be used to get a more parser-friendly output.
.It Fl -error-trace
Expand Down
11 changes: 8 additions & 3 deletions src/compiler/crystal/codegen/codegen.cr
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ module Crystal
end
end

def codegen(node, single_module = false, debug = Debug::Default)
visitor = CodeGenVisitor.new self, node, single_module: single_module, debug: debug
def codegen(node, single_module = false, debug = Debug::Default,
frame_pointers = FramePointers::Auto)
visitor = CodeGenVisitor.new self, node, single_module: single_module,
debug: debug, frame_pointers: frame_pointers
visitor.accept node
visitor.process_finished_hooks
visitor.finish
Expand Down Expand Up @@ -190,7 +192,10 @@ module Crystal
@c_malloc_fun : LLVMTypedFunction?
@c_realloc_fun : LLVMTypedFunction?

def initialize(@program : Program, @node : ASTNode, @single_module : Bool = false, @debug = Debug::Default)
def initialize(@program : Program, @node : ASTNode,
@single_module : Bool = false,
@debug = Debug::Default,
@frame_pointers : FramePointers = :auto)
@abi = @program.target_machine.abi
@llvm_context = LLVM::Context.new
# LLVM::Context.register(@llvm_context, "main")
Expand Down
6 changes: 5 additions & 1 deletion src/compiler/crystal/codegen/fun.cr
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,13 @@ class Crystal::CodeGenVisitor
context.fun.add_attribute LLVM::Attribute::UWTable, value: @program.has_flag?("aarch64") ? LLVM::UWTableKind::Sync : LLVM::UWTableKind::Async
{% end %}

if @program.has_flag?("darwin")
if @frame_pointers.always?
context.fun.add_attribute "frame-pointer", value: "all"
elsif @program.has_flag?("darwin")
# Disable frame pointer elimination in Darwin, as it causes issues during stack unwind
context.fun.add_target_dependent_attribute "frame-pointer", "all"
elsif @frame_pointers.non_leaf?
context.fun.add_attribute "frame-pointer", value: "non-leaf"
end

new_entry_block
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/crystal/command.cr
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,14 @@ class Crystal::Command
opts.on("--no-debug", "Skip any symbolic debug info") do
compiler.debug = Crystal::Debug::None
end

opts.on("--frame-pointers auto|always|non-leaf", "Control the preservation of frame pointers") do |value|
if frame_pointers = FramePointers.parse?(value)
compiler.frame_pointers = frame_pointers
else
error "Invalid value `#{value}` for frame-pointers"
end
end
end

opts.on("-D FLAG", "--define FLAG", "Define a compile-time flag") do |flag|
Expand Down
12 changes: 11 additions & 1 deletion src/compiler/crystal/compiler.cr
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ module Crystal
Default = LineNumbers
end

enum FramePointers
Auto
Always
NonLeaf
end

# Main interface to the compiler.
#
# A Compiler parses source code, type checks it and
Expand Down Expand Up @@ -45,6 +51,9 @@ module Crystal
# code by the `flag?(...)` macro method.
property flags = [] of String

# Controls generation of frame pointers.
property frame_pointers = FramePointers::Auto

# If `true`, the executable will be generated with debug code
# that can be understood by `gdb` and `lldb`.
property debug = Debug::Default
Expand Down Expand Up @@ -297,7 +306,8 @@ module Crystal

private def codegen(program, node : ASTNode, sources, output_filename)
llvm_modules = @progress_tracker.stage("Codegen (crystal)") do
program.codegen node, debug: debug, single_module: @single_module || @cross_compile || !@emit_targets.none?
program.codegen node, debug: debug, frame_pointers: frame_pointers,
single_module: @single_module || @cross_compile || !@emit_targets.none?
end

output_dir = CacheDir.instance.directory_for(sources)
Expand Down
7 changes: 7 additions & 0 deletions src/llvm/function.cr
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ struct LLVM::Function
end
end

def add_attribute(attribute : String, index = AttributeIndex::FunctionIndex, *, value : String)
context = LibLLVM.get_module_context(LibLLVM.get_global_parent(self))
attribute_ref = LibLLVM.create_string_attribute(context, attribute, attribute.bytesize,
value, value.bytesize)
LibLLVM.add_attribute_at_index(self, index, attribute_ref)
end

def add_attribute(attribute : Attribute, index = AttributeIndex::FunctionIndex, *, value)
return if attribute.value == 0

Expand Down
1 change: 1 addition & 0 deletions src/llvm/lib_llvm/core.cr
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ lib LibLLVM
fun get_enum_attribute_kind_for_name = LLVMGetEnumAttributeKindForName(name : Char*, s_len : SizeT) : UInt
fun get_last_enum_attribute_kind = LLVMGetLastEnumAttributeKind : UInt
fun create_enum_attribute = LLVMCreateEnumAttribute(c : ContextRef, kind_id : UInt, val : UInt64) : AttributeRef
fun create_string_attribute = LLVMCreateStringAttribute(c : ContextRef, k : Char*, k_length : UInt, v : Char*, v_length : UInt) : AttributeRef
{% unless LibLLVM::IS_LT_120 %}
fun create_type_attribute = LLVMCreateTypeAttribute(c : ContextRef, kind_id : UInt, type_ref : TypeRef) : AttributeRef
{% end %}
Expand Down

0 comments on commit 7628de6

Please sign in to comment.