| author | |
| committer | |
| log | c098a8f5223855b410895b5396948e3e2b3aacba |
| tree | ac3c4e5fa9de71a1b703d52433e0e1cec3abe7cf |
| parent | 271a37b418828c8ee79402f97016be42c5fa2884 |
4 files changed, 50 insertions(+), 0 deletions(-)
src/all_types.hpp+3| ... | ... | @@ -1055,6 +1055,7 @@ struct FnTableEntry { |
| 1055 | 1055 | bool is_test; |
| 1056 | 1056 | bool is_pure; |
| 1057 | 1057 | bool safety_off; |
| 1058 | bool is_noinline; | |
| 1058 | 1059 | BlockContext *parent_block_context; |
| 1059 | 1060 | FnAnalState anal_state; |
| 1060 | 1061 | |
| ... | ... | @@ -1116,6 +1117,8 @@ enum BuiltinFnId { |
| 1116 | 1117 | BuiltinFnIdCImport, |
| 1117 | 1118 | BuiltinFnIdErrName, |
| 1118 | 1119 | BuiltinFnIdBreakpoint, |
| 1120 | BuiltinFnIdReturnAddress, | |
| 1121 | BuiltinFnIdFrameAddress, | |
| 1119 | 1122 | BuiltinFnIdEmbedFile, |
| 1120 | 1123 | BuiltinFnIdCmpExchange, |
| 1121 | 1124 | BuiltinFnIdFence, |
src/analyze.cpp+18| ... | ... | @@ -980,6 +980,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 980 | 980 | bool is_cold = false; |
| 981 | 981 | bool is_naked = false; |
| 982 | 982 | bool is_test = false; |
| 983 | bool is_noinline = false; | |
| 983 | 984 | |
| 984 | 985 | if (fn_proto->top_level_decl.directives) { |
| 985 | 986 | 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 |
| 993 | 994 | if (attr_name) { |
| 994 | 995 | if (buf_eql_str(attr_name, "naked")) { |
| 995 | 996 | is_naked = true; |
| 997 | } else if (buf_eql_str(attr_name, "noinline")) { | |
| 998 | is_noinline = true; | |
| 996 | 999 | } else if (buf_eql_str(attr_name, "cold")) { |
| 997 | 1000 | is_cold = true; |
| 998 | 1001 | } else if (buf_eql_str(attr_name, "test")) { |
| ... | ... | @@ -1062,12 +1065,20 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 1062 | 1065 | |
| 1063 | 1066 | fn_table_entry->type_entry = fn_type; |
| 1064 | 1067 | fn_table_entry->is_test = is_test; |
| 1068 | fn_table_entry->is_noinline = is_noinline; | |
| 1065 | 1069 | |
| 1066 | 1070 | if (fn_type->id == TypeTableEntryIdInvalid) { |
| 1067 | 1071 | fn_proto->skip = true; |
| 1068 | 1072 | return; |
| 1069 | 1073 | } |
| 1070 | 1074 | |
| 1075 | if (fn_table_entry->is_inline && fn_table_entry->is_noinline) { | |
| 1076 | add_node_error(g, node, buf_sprintf("function is both inline and noinline")); | |
| 1077 | fn_proto->skip = true; | |
| 1078 | return; | |
| 1079 | } | |
| 1080 | ||
| 1081 | ||
| 1071 | 1082 | Buf *symbol_name; |
| 1072 | 1083 | if (is_c_compat) { |
| 1073 | 1084 | symbol_name = &fn_table_entry->symbol_name; |
| ... | ... | @@ -1081,6 +1092,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 1081 | 1092 | if (fn_table_entry->is_inline) { |
| 1082 | 1093 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute); |
| 1083 | 1094 | } |
| 1095 | if (fn_table_entry->is_noinline) { | |
| 1096 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoInlineAttribute); | |
| 1097 | } | |
| 1084 | 1098 | if (fn_type->data.fn.fn_type_id.is_naked) { |
| 1085 | 1099 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute); |
| 1086 | 1100 | } |
| ... | ... | @@ -4866,6 +4880,10 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 4866 | 4880 | case BuiltinFnIdBreakpoint: |
| 4867 | 4881 | mark_impure_fn(context); |
| 4868 | 4882 | return g->builtin_types.entry_void; |
| 4883 | case BuiltinFnIdReturnAddress: | |
| 4884 | case BuiltinFnIdFrameAddress: | |
| 4885 | mark_impure_fn(context); | |
| 4886 | return builtin_fn->return_type; | |
| 4869 | 4887 | case BuiltinFnIdEmbedFile: |
| 4870 | 4888 | return analyze_embed_file(g, import, context, node); |
| 4871 | 4889 | case BuiltinFnIdCmpExchange: |
src/codegen.cpp+27| ... | ... | @@ -634,6 +634,13 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 634 | 634 | case BuiltinFnIdBreakpoint: |
| 635 | 635 | set_debug_source_node(g, node); |
| 636 | 636 | return LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, ""); |
| 637 | case BuiltinFnIdFrameAddress: | |
| 638 | case BuiltinFnIdReturnAddress: | |
| 639 | { | |
| 640 | LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); | |
| 641 | set_debug_source_node(g, node); | |
| 642 | return LLVMBuildCall(g->builder, builtin_fn->fn_val, &zero, 1, ""); | |
| 643 | } | |
| 637 | 644 | case BuiltinFnIdCmpExchange: |
| 638 | 645 | return gen_cmp_exchange(g, node); |
| 639 | 646 | case BuiltinFnIdFence: |
| ... | ... | @@ -4330,6 +4337,26 @@ static void define_builtin_fns(CodeGen *g) { |
| 4330 | 4337 | |
| 4331 | 4338 | g->trap_fn_val = builtin_fn->fn_val; |
| 4332 | 4339 | } |
| 4340 | { | |
| 4341 | BuiltinFnEntry *builtin_fn = create_builtin_fn_with_arg_count(g, BuiltinFnIdReturnAddress, | |
| 4342 | "return_address", 0); | |
| 4343 | builtin_fn->return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); | |
| 4344 | ||
| 4345 | LLVMTypeRef fn_type = LLVMFunctionType(builtin_fn->return_type->type_ref, | |
| 4346 | &g->builtin_types.entry_i32->type_ref, 1, false); | |
| 4347 | builtin_fn->fn_val = LLVMAddFunction(g->module, "llvm.returnaddress", fn_type); | |
| 4348 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); | |
| 4349 | } | |
| 4350 | { | |
| 4351 | BuiltinFnEntry *builtin_fn = create_builtin_fn_with_arg_count(g, BuiltinFnIdFrameAddress, | |
| 4352 | "frame_address", 0); | |
| 4353 | builtin_fn->return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); | |
| 4354 | ||
| 4355 | LLVMTypeRef fn_type = LLVMFunctionType(builtin_fn->return_type->type_ref, | |
| 4356 | &g->builtin_types.entry_i32->type_ref, 1, false); | |
| 4357 | builtin_fn->fn_val = LLVMAddFunction(g->module, "llvm.frameaddress", fn_type); | |
| 4358 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); | |
| 4359 | } | |
| 4333 | 4360 | { |
| 4334 | 4361 | BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy"); |
| 4335 | 4362 | builtin_fn->return_type = g->builtin_types.entry_void; |
src/eval.cpp+2| ... | ... | @@ -787,6 +787,8 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_ |
| 787 | 787 | zig_panic("TODO"); |
| 788 | 788 | case BuiltinFnIdBreakpoint: |
| 789 | 789 | case BuiltinFnIdInvalid: |
| 790 | case BuiltinFnIdFrameAddress: | |
| 791 | case BuiltinFnIdReturnAddress: | |
| 790 | 792 | zig_unreachable(); |
| 791 | 793 | } |
| 792 | 794 |