From c098a8f5223855b410895b5396948e3e2b3aacba Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 6 May 2016 23:10:14 -0700 Subject: [PATCH] add frame_address and return_address builtins --- src/all_types.hpp | 3 +++ src/analyze.cpp | 18 ++++++++++++++++++ src/codegen.cpp | 27 +++++++++++++++++++++++++++ src/eval.cpp | 2 ++ 4 files changed, 50 insertions(+) diff --git a/src/all_types.hpp b/src/all_types.hpp index ecd34a10be..49e1cb510f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1055,6 +1055,7 @@ struct FnTableEntry { bool is_test; bool is_pure; bool safety_off; + bool is_noinline; BlockContext *parent_block_context; FnAnalState anal_state; @@ -1116,6 +1117,8 @@ enum BuiltinFnId { BuiltinFnIdCImport, BuiltinFnIdErrName, BuiltinFnIdBreakpoint, + BuiltinFnIdReturnAddress, + BuiltinFnIdFrameAddress, BuiltinFnIdEmbedFile, BuiltinFnIdCmpExchange, BuiltinFnIdFence, diff --git a/src/analyze.cpp b/src/analyze.cpp index 4d1dc181a0..928f576947 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -980,6 +980,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t bool is_cold = false; bool is_naked = false; bool is_test = false; + bool is_noinline = false; if (fn_proto->top_level_decl.directives) { for (int i = 0; i < fn_proto->top_level_decl.directives->length; i += 1) { @@ -993,6 +994,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t if (attr_name) { if (buf_eql_str(attr_name, "naked")) { is_naked = true; + } else if (buf_eql_str(attr_name, "noinline")) { + is_noinline = true; } else if (buf_eql_str(attr_name, "cold")) { is_cold = true; } else if (buf_eql_str(attr_name, "test")) { @@ -1062,12 +1065,20 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t fn_table_entry->type_entry = fn_type; fn_table_entry->is_test = is_test; + fn_table_entry->is_noinline = is_noinline; if (fn_type->id == TypeTableEntryIdInvalid) { fn_proto->skip = true; return; } + if (fn_table_entry->is_inline && fn_table_entry->is_noinline) { + add_node_error(g, node, buf_sprintf("function is both inline and noinline")); + fn_proto->skip = true; + return; + } + + Buf *symbol_name; if (is_c_compat) { symbol_name = &fn_table_entry->symbol_name; @@ -1081,6 +1092,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t if (fn_table_entry->is_inline) { LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute); } + if (fn_table_entry->is_noinline) { + LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoInlineAttribute); + } if (fn_type->data.fn.fn_type_id.is_naked) { LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute); } @@ -4866,6 +4880,10 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry case BuiltinFnIdBreakpoint: mark_impure_fn(context); return g->builtin_types.entry_void; + case BuiltinFnIdReturnAddress: + case BuiltinFnIdFrameAddress: + mark_impure_fn(context); + return builtin_fn->return_type; case BuiltinFnIdEmbedFile: return analyze_embed_file(g, import, context, node); case BuiltinFnIdCmpExchange: diff --git a/src/codegen.cpp b/src/codegen.cpp index 9e2f2bc91f..8ecdd36358 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -634,6 +634,13 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { case BuiltinFnIdBreakpoint: set_debug_source_node(g, node); return LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, ""); + case BuiltinFnIdFrameAddress: + case BuiltinFnIdReturnAddress: + { + LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); + set_debug_source_node(g, node); + return LLVMBuildCall(g->builder, builtin_fn->fn_val, &zero, 1, ""); + } case BuiltinFnIdCmpExchange: return gen_cmp_exchange(g, node); case BuiltinFnIdFence: @@ -4330,6 +4337,26 @@ static void define_builtin_fns(CodeGen *g) { g->trap_fn_val = builtin_fn->fn_val; } + { + BuiltinFnEntry *builtin_fn = create_builtin_fn_with_arg_count(g, BuiltinFnIdReturnAddress, + "return_address", 0); + builtin_fn->return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); + + LLVMTypeRef fn_type = LLVMFunctionType(builtin_fn->return_type->type_ref, + &g->builtin_types.entry_i32->type_ref, 1, false); + builtin_fn->fn_val = LLVMAddFunction(g->module, "llvm.returnaddress", fn_type); + assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); + } + { + BuiltinFnEntry *builtin_fn = create_builtin_fn_with_arg_count(g, BuiltinFnIdFrameAddress, + "frame_address", 0); + builtin_fn->return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); + + LLVMTypeRef fn_type = LLVMFunctionType(builtin_fn->return_type->type_ref, + &g->builtin_types.entry_i32->type_ref, 1, false); + builtin_fn->fn_val = LLVMAddFunction(g->module, "llvm.frameaddress", fn_type); + assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); + } { BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy"); builtin_fn->return_type = g->builtin_types.entry_void; diff --git a/src/eval.cpp b/src/eval.cpp index 3befeb2d83..f7c4f5e2a6 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -787,6 +787,8 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_ zig_panic("TODO"); case BuiltinFnIdBreakpoint: case BuiltinFnIdInvalid: + case BuiltinFnIdFrameAddress: + case BuiltinFnIdReturnAddress: zig_unreachable(); }