diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-02-03 13:56:56 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-02-03 13:56:56 -0500 |
| commit | 8c9016b6d1a62da847faf95b6124515cdcd9fe0b (patch) | |
| tree | 315daeb2627a150321bc2af9a1ab9563b041fc81 /src | |
| parent | 3be4b6434c0d96f8f6975c13c1a84f06a9857ed8 (diff) | |
| download | zig-8c9016b6d1a62da847faf95b6124515cdcd9fe0b.tar.gz zig-8c9016b6d1a62da847faf95b6124515cdcd9fe0b.zip | |
add setGlobalAlign and setGlobalSection builtin functions
closes #241
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 22 | ||||
| -rw-r--r-- | src/codegen.cpp | 40 | ||||
| -rw-r--r-- | src/ir.cpp | 139 | ||||
| -rw-r--r-- | src/ir_print.cpp | 32 |
4 files changed, 215 insertions, 18 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index 2a1c4d7bd6..99032e8f43 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1107,6 +1107,8 @@ enum BuiltinFnId { BuiltinFnIdIsInteger, BuiltinFnIdIsFloat, BuiltinFnIdCanImplicitCast, + BuiltinFnIdSetGlobalAlign, + BuiltinFnIdSetGlobalSection, }; struct BuiltinFnEntry { @@ -1304,6 +1306,10 @@ struct VariableTableEntry { size_t mem_slot_index; size_t ref_count; VarLinkage linkage; + AstNode *set_global_align_node; + uint64_t alignment; + AstNode *set_global_section_node; + Buf *section_name; }; struct ErrorTableEntry { @@ -1540,6 +1546,8 @@ enum IrInstructionId { IrInstructionIdTestType, IrInstructionIdTypeName, IrInstructionIdCanImplicitCast, + IrInstructionIdSetGlobalAlign, + IrInstructionIdSetGlobalSection, }; struct IrInstruction { @@ -2243,6 +2251,20 @@ struct IrInstructionCanImplicitCast { IrInstruction *target_value; }; +struct IrInstructionSetGlobalAlign { + IrInstruction base; + + VariableTableEntry *var; + IrInstruction *value; +}; + +struct IrInstructionSetGlobalSection { + IrInstruction base; + + VariableTableEntry *var; + IrInstruction *value; +}; + enum LValPurpose { LValPurposeNone, LValPurposeAssign, diff --git a/src/codegen.cpp b/src/codegen.cpp index dc496b9857..8ebee75ac0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -231,7 +231,7 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script) { static void render_const_val(CodeGen *g, ConstExprValue *const_val); -static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, bool is_export); +static void render_const_val_global(CodeGen *g, ConstExprValue *const_val); static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { if (fn_table_entry->llvm_value) @@ -686,7 +686,7 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { // we might have to do some pointer casting here due to the way union // values are rendered with a type other than the one we expect if (handle_is_ptr(instruction->value.type)) { - render_const_val_global(g, &instruction->value, false); + render_const_val_global(g, &instruction->value); TypeTableEntry *ptr_type = get_pointer_to_type(g, instruction->value.type, true); instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.llvm_global, ptr_type->type_ref, ""); } else if (instruction->value.type->id == TypeTableEntryIdPointer) { @@ -2282,6 +2282,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdTestType: case IrInstructionIdTypeName: case IrInstructionIdCanImplicitCast: + case IrInstructionIdSetGlobalAlign: + case IrInstructionIdSetGlobalSection: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); @@ -2420,7 +2422,7 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar base_ptr = gen_const_ptr_array_recursive(g, parent_array, parent_array_index); } else { render_const_val(g, array_const_val); - render_const_val_global(g, array_const_val, false); + render_const_val_global(g, array_const_val); base_ptr = array_const_val->llvm_global; } TypeTableEntry *usize = g->builtin_types.entry_usize; @@ -2568,16 +2570,16 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { return fn_llvm_value(g, const_val->data.x_fn); case TypeTableEntryIdPointer: { - render_const_val_global(g, const_val, false); + render_const_val_global(g, const_val); size_t index = const_val->data.x_ptr.index; ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr; if (base_ptr) { if (index == SIZE_MAX) { render_const_val(g, base_ptr); - render_const_val_global(g, base_ptr, false); + render_const_val_global(g, base_ptr); ConstExprValue *other_val = base_ptr; const_val->llvm_value = LLVMConstBitCast(other_val->llvm_global, const_val->type->type_ref); - render_const_val_global(g, const_val, false); + render_const_val_global(g, const_val); return const_val->llvm_value; } else { ConstExprValue *array_const_val = base_ptr; @@ -2587,19 +2589,19 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { TypeTableEntry *usize = g->builtin_types.entry_usize; const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), const_val->type->type_ref); - render_const_val_global(g, const_val, false); + render_const_val_global(g, const_val); return const_val->llvm_value; } LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, index); LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); const_val->llvm_value = ptr_val; - render_const_val_global(g, const_val, false); + render_const_val_global(g, const_val); return ptr_val; } } else { TypeTableEntry *usize = g->builtin_types.entry_usize; const_val->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, index, false), const_val->type->type_ref); - render_const_val_global(g, const_val, false); + render_const_val_global(g, const_val); return const_val->llvm_value; } } @@ -2654,11 +2656,11 @@ static void render_const_val(CodeGen *g, ConstExprValue *const_val) { LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value); } -static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, bool is_export) { +static void render_const_val_global(CodeGen *g, ConstExprValue *const_val) { if (!const_val->llvm_global) { LLVMTypeRef type_ref = const_val->llvm_value ? LLVMTypeOf(const_val->llvm_value) : const_val->type->type_ref; LLVMValueRef global_value = LLVMAddGlobal(g->module, type_ref, ""); - LLVMSetLinkage(global_value, is_export ? LLVMExternalLinkage : LLVMInternalLinkage); + LLVMSetLinkage(global_value, LLVMInternalLinkage); LLVMSetGlobalConstant(global_value, true); LLVMSetUnnamedAddr(global_value, true); @@ -2840,10 +2842,20 @@ static void do_code_gen(CodeGen *g) { LLVMSetLinkage(global_value, LLVMExternalLinkage); } else { - bool is_export = (var->linkage == VarLinkageExport); render_const_val(g, &var->value); - render_const_val_global(g, &var->value, is_export); + render_const_val_global(g, &var->value); global_value = var->value.llvm_global; + + if (var->linkage == VarLinkageExport) { + LLVMSetLinkage(global_value, LLVMExternalLinkage); + } + if (var->section_name) { + LLVMSetSection(global_value, buf_ptr(var->section_name)); + } + if (var->alignment) { + LLVMSetAlignment(global_value, var->alignment); + } + // TODO debug info for function pointers if (var->gen_is_const && var->value.type->id != TypeTableEntryIdFn) { gen_global_var(g, var, var->value.llvm_value, var->value.type); @@ -3672,6 +3684,8 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdSetFnVisible, "setFnVisible", 2); create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); create_builtin_fn(g, BuiltinFnIdAlloca, "alloca", 2); + create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2); + create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2); } static void init(CodeGen *g, Buf *source_path) { diff --git a/src/ir.cpp b/src/ir.cpp index e6c29bf8df..751f4760c1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -507,6 +507,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast return IrInstructionIdCanImplicitCast; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalAlign *) { + return IrInstructionIdSetGlobalAlign; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalSection *) { + return IrInstructionIdSetGlobalSection; +} + template<typename T> static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate<T>(1); @@ -2052,6 +2060,32 @@ static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, A return &instruction->base; } +static IrInstruction *ir_build_set_global_align(IrBuilder *irb, Scope *scope, AstNode *source_node, + VariableTableEntry *var, IrInstruction *value) +{ + IrInstructionSetGlobalAlign *instruction = ir_build_instruction<IrInstructionSetGlobalAlign>( + irb, scope, source_node); + instruction->var = var; + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_set_global_section(IrBuilder *irb, Scope *scope, AstNode *source_node, + VariableTableEntry *var, IrInstruction *value) +{ + IrInstructionSetGlobalSection *instruction = ir_build_instruction<IrInstructionSetGlobalSection>( + irb, scope, source_node); + instruction->var = var; + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { return nullptr; } @@ -2678,6 +2712,20 @@ static IrInstruction *ir_instruction_canimplicitcast_get_dep(IrInstructionCanImp } } +static IrInstruction *ir_instruction_setglobalalign_get_dep(IrInstructionSetGlobalAlign *instruction, size_t index) { + switch (index) { + case 0: return instruction->value; + default: return nullptr; + } +} + +static IrInstruction *ir_instruction_setglobalsection_get_dep(IrInstructionSetGlobalSection *instruction, size_t index) { + switch (index) { + case 0: return instruction->value; + default: return nullptr; + } +} + static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -2856,6 +2904,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_typename_get_dep((IrInstructionTypeName *) instruction, index); case IrInstructionIdCanImplicitCast: return ir_instruction_canimplicitcast_get_dep((IrInstructionCanImplicitCast *) instruction, index); + case IrInstructionIdSetGlobalAlign: + return ir_instruction_setglobalalign_get_dep((IrInstructionSetGlobalAlign *) instruction, index); + case IrInstructionIdSetGlobalSection: + return ir_instruction_setglobalsection_get_dep((IrInstructionSetGlobalSection *) instruction, index); } zig_unreachable(); } @@ -4113,6 +4165,40 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value); } + case BuiltinFnIdSetGlobalAlign: + case BuiltinFnIdSetGlobalSection: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + if (arg0_node->type != NodeTypeSymbol) { + add_node_error(irb->codegen, arg0_node, buf_sprintf("expected identifier")); + return irb->codegen->invalid_instruction; + } + Buf *variable_name = arg0_node->data.symbol_expr.symbol; + Tld *tld = find_decl(scope, variable_name); + if (!tld) { + add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", + buf_ptr(variable_name))); + return irb->codegen->invalid_instruction; + } + if (tld->id != TldIdVar) { + add_node_error(irb->codegen, node, buf_sprintf("'%s' is not a global variable", + buf_ptr(variable_name))); + return irb->codegen->invalid_instruction; + } + TldVar *tld_var = (TldVar *)tld; + VariableTableEntry *var = tld_var->var; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + if (builtin_fn->id == BuiltinFnIdSetGlobalAlign) { + return ir_build_set_global_align(irb, scope, node, var, arg1_value); + } else { + return ir_build_set_global_section(irb, scope, node, var, arg1_value); + } + } } zig_unreachable(); } @@ -9350,6 +9436,53 @@ static TypeTableEntry *ir_analyze_instruction_set_fn_visible(IrAnalyze *ira, return ira->codegen->builtin_types.entry_void; } +static TypeTableEntry *ir_analyze_instruction_set_global_align(IrAnalyze *ira, + IrInstructionSetGlobalAlign *instruction) +{ + VariableTableEntry *var = instruction->var; + IrInstruction *align_value = instruction->value->other; + + uint64_t scalar_align; + if (!ir_resolve_usize(ira, align_value, &scalar_align)) + return ira->codegen->builtin_types.entry_invalid; + + AstNode *source_node = instruction->base.source_node; + if (var->set_global_align_node) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("alignment set twice")); + add_error_note(ira->codegen, msg, var->set_global_align_node, buf_sprintf("first set here")); + return ira->codegen->builtin_types.entry_invalid; + } + var->set_global_align_node = source_node; + var->alignment = scalar_align; + + ir_build_const_from(ira, &instruction->base, false); + return ira->codegen->builtin_types.entry_void; +} + +static TypeTableEntry *ir_analyze_instruction_set_global_section(IrAnalyze *ira, + IrInstructionSetGlobalSection *instruction) +{ + VariableTableEntry *var = instruction->var; + IrInstruction *section_value = instruction->value->other; + + Buf *section_name = ir_resolve_str(ira, section_value); + if (!section_name) + return ira->codegen->builtin_types.entry_invalid; + + AstNode *source_node = instruction->base.source_node; + if (var->set_global_section_node) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("section set twice")); + add_error_note(ira->codegen, msg, var->set_global_section_node, buf_sprintf("first set here")); + return ira->codegen->builtin_types.entry_invalid; + } + var->set_global_section_node = source_node; + var->section_name = section_name; + + ir_build_const_from(ira, &instruction->base, false); + return ira->codegen->builtin_types.entry_void; +} + static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, IrInstructionSetDebugSafety *set_debug_safety_instruction) { @@ -11779,6 +11912,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_set_fn_test(ira, (IrInstructionSetFnTest *)instruction); case IrInstructionIdSetFnVisible: return ir_analyze_instruction_set_fn_visible(ira, (IrInstructionSetFnVisible *)instruction); + case IrInstructionIdSetGlobalAlign: + return ir_analyze_instruction_set_global_align(ira, (IrInstructionSetGlobalAlign *)instruction); + case IrInstructionIdSetGlobalSection: + return ir_analyze_instruction_set_global_section(ira, (IrInstructionSetGlobalSection *)instruction); case IrInstructionIdSetDebugSafety: return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction); case IrInstructionIdSliceType: @@ -11993,6 +12130,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdBreakpoint: case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free case IrInstructionIdCheckSwitchProngs: + case IrInstructionIdSetGlobalAlign: + case IrInstructionIdSetGlobalSection: return true; case IrInstructionIdPhi: case IrInstructionIdUnOp: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 79e0bdb895..fa7ff97d81 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -233,11 +233,15 @@ static void ir_print_phi(IrPrint *irp, IrInstructionPhi *phi_instruction) { static void ir_print_container_init_list(IrPrint *irp, IrInstructionContainerInitList *instruction) { ir_print_other_instruction(irp, instruction->container_type); fprintf(irp->f, "{"); - for (size_t i = 0; i < instruction->item_count; i += 1) { - IrInstruction *item = instruction->items[i]; - if (i != 0) - fprintf(irp->f, ", "); - ir_print_other_instruction(irp, item); + if (instruction->item_count > 50) { + fprintf(irp->f, "...(%zu items)...", instruction->item_count); + } else { + for (size_t i = 0; i < instruction->item_count; i += 1) { + IrInstruction *item = instruction->items[i]; + if (i != 0) + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, item); + } } fprintf(irp->f, "}"); } @@ -827,6 +831,18 @@ static void ir_print_can_implicit_cast(IrPrint *irp, IrInstructionCanImplicitCas fprintf(irp->f, ")"); } +static void ir_print_set_global_align(IrPrint *irp, IrInstructionSetGlobalAlign *instruction) { + fprintf(irp->f, "@setGlobalAlign(%s,", buf_ptr(&instruction->var->name)); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + +static void ir_print_set_global_section(IrPrint *irp, IrInstructionSetGlobalSection *instruction) { + fprintf(irp->f, "@setGlobalSection(%s,", buf_ptr(&instruction->var->name)); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1093,6 +1109,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdCanImplicitCast: ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction); break; + case IrInstructionIdSetGlobalAlign: + ir_print_set_global_align(irp, (IrInstructionSetGlobalAlign *)instruction); + break; + case IrInstructionIdSetGlobalSection: + ir_print_set_global_section(irp, (IrInstructionSetGlobalSection *)instruction); + break; } fprintf(irp->f, "\n"); } |
