@@ -8,6 +8,7 @@ const ir = @import("ir.zig");
8
8
const Value = @import ("value.zig" ).Value ;
9
9
const Type = @import ("type.zig" ).Type ;
10
10
const event = std .event ;
11
+ const assert = std .debug .assert ;
11
12
12
13
pub async fn renderToLlvm (comp : * Compilation , fn_val : * Value.Fn , code : * ir.Code ) ! void {
13
14
fn_val .base .ref ();
@@ -35,9 +36,23 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
35
36
36
37
try renderToLlvmModule (& ofile , fn_val , code );
37
38
39
+ // TODO module level assembly
40
+ //if (buf_len(&g->global_asm) != 0) {
41
+ // LLVMSetModuleInlineAsm(g->module, buf_ptr(&g->global_asm));
42
+ //}
43
+
44
+ // TODO
45
+ //ZigLLVMDIBuilderFinalize(g->dbuilder);
46
+
38
47
if (comp .verbose_llvm_ir ) {
39
48
llvm .DumpModule (ofile .module );
40
49
}
50
+
51
+ // verify the llvm module when safety is on
52
+ if (std .debug .runtime_safety ) {
53
+ var error_ptr : ? [* ]u8 = null ;
54
+ _ = llvm .VerifyModule (ofile .module , llvm .AbortProcessAction , & error_ptr );
55
+ }
41
56
}
42
57
43
58
pub const ObjectFile = struct {
@@ -55,5 +70,146 @@ pub const ObjectFile = struct {
55
70
pub fn renderToLlvmModule (ofile : * ObjectFile , fn_val : * Value.Fn , code : * ir.Code ) ! void {
56
71
// TODO audit more of codegen.cpp:fn_llvm_value and port more logic
57
72
const llvm_fn_type = try fn_val .base .typeof .getLlvmType (ofile );
58
- const llvm_fn = llvm .AddFunction (ofile .module , fn_val .symbol_name .ptr (), llvm_fn_type );
73
+ const llvm_fn = llvm .AddFunction (
74
+ ofile .module ,
75
+ fn_val .symbol_name .ptr (),
76
+ llvm_fn_type ,
77
+ ) orelse return error .OutOfMemory ;
78
+
79
+ const want_fn_safety = fn_val .block_scope .safety .get (ofile .comp );
80
+ if (want_fn_safety and ofile .comp .haveLibC ()) {
81
+ try addLLVMFnAttr (ofile , llvm_fn , "sspstrong" );
82
+ try addLLVMFnAttrStr (ofile , llvm_fn , "stack-protector-buffer-size" , "4" );
83
+ }
84
+
85
+ // TODO
86
+ //if (fn_val.align_stack) |align_stack| {
87
+ // try addLLVMFnAttrInt(ofile, llvm_fn, "alignstack", align_stack);
88
+ //}
89
+
90
+ const fn_type = fn_val .base .typeof .cast (Type .Fn ).? ;
91
+
92
+ try addLLVMFnAttr (ofile , llvm_fn , "nounwind" );
93
+ //add_uwtable_attr(g, fn_table_entry->llvm_value);
94
+ try addLLVMFnAttr (ofile , llvm_fn , "nobuiltin" );
95
+
96
+ //if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {
97
+ // ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
98
+ // ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);
99
+ //}
100
+
101
+ //if (fn_table_entry->section_name) {
102
+ // LLVMSetSection(fn_table_entry->llvm_value, buf_ptr(fn_table_entry->section_name));
103
+ //}
104
+ //if (fn_table_entry->align_bytes > 0) {
105
+ // LLVMSetAlignment(fn_table_entry->llvm_value, (unsigned)fn_table_entry->align_bytes);
106
+ //} else {
107
+ // // We'd like to set the best alignment for the function here, but on Darwin LLVM gives
108
+ // // "Cannot getTypeInfo() on a type that is unsized!" assertion failure when calling
109
+ // // any of the functions for getting alignment. Not specifying the alignment should
110
+ // // use the ABI alignment, which is fine.
111
+ //}
112
+
113
+ //if (!type_has_bits(return_type)) {
114
+ // // nothing to do
115
+ //} else if (type_is_codegen_pointer(return_type)) {
116
+ // addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
117
+ //} else if (handle_is_ptr(return_type) &&
118
+ // calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
119
+ //{
120
+ // addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
121
+ // addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
122
+ //}
123
+
124
+ // TODO set parameter attributes
125
+
126
+ // TODO
127
+ //uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
128
+ //if (err_ret_trace_arg_index != UINT32_MAX) {
129
+ // addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
130
+ //}
131
+
132
+ const cur_ret_ptr = if (fn_type .return_type .handleIsPtr ()) llvm .GetParam (llvm_fn , 0 ) else null ;
133
+
134
+ // build all basic blocks
135
+ for (code .basic_block_list .toSlice ()) | bb | {
136
+ bb .llvm_block = llvm .AppendBasicBlockInContext (
137
+ ofile .context ,
138
+ llvm_fn ,
139
+ bb .name_hint ,
140
+ ) orelse return error .OutOfMemory ;
141
+ }
142
+ const entry_bb = code .basic_block_list .at (0 );
143
+ llvm .PositionBuilderAtEnd (ofile .builder , entry_bb .llvm_block );
144
+
145
+ llvm .ClearCurrentDebugLocation (ofile .builder );
146
+
147
+ // TODO set up error return tracing
148
+ // TODO allocate temporary stack values
149
+ // TODO create debug variable declarations for variables and allocate all local variables
150
+ // TODO finishing error return trace setup. we have to do this after all the allocas.
151
+ // TODO create debug variable declarations for parameters
152
+
153
+ for (code .basic_block_list .toSlice ()) | current_block | {
154
+ llvm .PositionBuilderAtEnd (ofile .builder , current_block .llvm_block );
155
+ for (current_block .instruction_list .toSlice ()) | instruction | {
156
+ if (instruction .ref_count == 0 and ! instruction .hasSideEffects ()) continue ;
157
+
158
+ instruction .llvm_value = try instruction .render (ofile , fn_val );
159
+ }
160
+ current_block .llvm_exit_block = llvm .GetInsertBlock (ofile .builder );
161
+ }
162
+ }
163
+
164
+ fn addLLVMAttr (
165
+ ofile : * ObjectFile ,
166
+ val : llvm.ValueRef ,
167
+ attr_index : llvm.AttributeIndex ,
168
+ attr_name : []const u8 ,
169
+ ) ! void {
170
+ const kind_id = llvm .GetEnumAttributeKindForName (attr_name .ptr , attr_name .len );
171
+ assert (kind_id != 0 );
172
+ const llvm_attr = llvm .CreateEnumAttribute (ofile .context , kind_id , 0 ) orelse return error .OutOfMemory ;
173
+ llvm .AddAttributeAtIndex (val , attr_index , llvm_attr );
174
+ }
175
+
176
+ fn addLLVMAttrStr (
177
+ ofile : * ObjectFile ,
178
+ val : llvm.ValueRef ,
179
+ attr_index : llvm.AttributeIndex ,
180
+ attr_name : []const u8 ,
181
+ attr_val : []const u8 ,
182
+ ) ! void {
183
+ const llvm_attr = llvm .CreateStringAttribute (
184
+ ofile .context ,
185
+ attr_name .ptr ,
186
+ @intCast (c_uint , attr_name .len ),
187
+ attr_val .ptr ,
188
+ @intCast (c_uint , attr_val .len ),
189
+ ) orelse return error .OutOfMemory ;
190
+ llvm .AddAttributeAtIndex (val , attr_index , llvm_attr );
191
+ }
192
+
193
+ fn addLLVMAttrInt (
194
+ val : llvm.ValueRef ,
195
+ attr_index : llvm.AttributeIndex ,
196
+ attr_name : []const u8 ,
197
+ attr_val : u64 ,
198
+ ) ! void {
199
+ const kind_id = llvm .GetEnumAttributeKindForName (attr_name .ptr , attr_name .len );
200
+ assert (kind_id != 0 );
201
+ const llvm_attr = llvm .CreateEnumAttribute (ofile .context , kind_id , attr_val ) orelse return error .OutOfMemory ;
202
+ llvm .AddAttributeAtIndex (val , attr_index , llvm_attr );
203
+ }
204
+
205
+ fn addLLVMFnAttr (ofile : * ObjectFile , fn_val : llvm.ValueRef , attr_name : []const u8 ) ! void {
206
+ return addLLVMAttr (ofile , fn_val , @maxValue (llvm .AttributeIndex ), attr_name );
207
+ }
208
+
209
+ fn addLLVMFnAttrStr (ofile : * ObjectFile , fn_val : llvm.ValueRef , attr_name : []const u8 , attr_val : []const u8 ) ! void {
210
+ return addLLVMAttrStr (ofile , fn_val , @maxValue (llvm .AttributeIndex ), attr_name , attr_val );
211
+ }
212
+
213
+ fn addLLVMFnAttrInt (ofile : * ObjectFile , fn_val : llvm.ValueRef , attr_name : []const u8 , attr_val : u64 ) ! void {
214
+ return addLLVMAttrInt (ofile , fn_val , @maxValue (llvm .AttributeIndex ), attr_name , attr_val );
59
215
}
0 commit comments