| ... | @@ -171,6 +171,67 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { | ... | @@ -171,6 +171,67 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 171 | | 171 | |
| 172 | return overflow_bit; | 172 | return overflow_bit; |
| 173 | } | 173 | } |
| | 174 | case BuiltinFnIdMemcpy: |
| | 175 | { |
| | 176 | int fn_call_param_count = node->data.fn_call_expr.params.length; |
| | 177 | assert(fn_call_param_count == 3); |
| | 178 | |
| | 179 | AstNode *dest_node = node->data.fn_call_expr.params.at(0); |
| | 180 | TypeTableEntry *dest_type = get_expr_type(dest_node); |
| | 181 | |
| | 182 | LLVMValueRef dest_ptr = gen_expr(g, dest_node); |
| | 183 | LLVMValueRef src_ptr = gen_expr(g, node->data.fn_call_expr.params.at(1)); |
| | 184 | LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2)); |
| | 185 | |
| | 186 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); |
| | 187 | |
| | 188 | add_debug_source_node(g, node); |
| | 189 | LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); |
| | 190 | LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, ""); |
| | 191 | |
| | 192 | uint64_t align_in_bytes = dest_type->data.pointer.child_type->align_in_bits / 8; |
| | 193 | |
| | 194 | LLVMValueRef params[] = { |
| | 195 | dest_ptr_casted, // dest pointer |
| | 196 | src_ptr_casted, // source pointer |
| | 197 | len_val, // byte count |
| | 198 | LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes |
| | 199 | LLVMConstNull(LLVMInt1Type()), // is volatile |
| | 200 | }; |
| | 201 | |
| | 202 | LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, ""); |
| | 203 | return nullptr; |
| | 204 | } |
| | 205 | case BuiltinFnIdMemset: |
| | 206 | { |
| | 207 | int fn_call_param_count = node->data.fn_call_expr.params.length; |
| | 208 | assert(fn_call_param_count == 3); |
| | 209 | |
| | 210 | AstNode *dest_node = node->data.fn_call_expr.params.at(0); |
| | 211 | TypeTableEntry *dest_type = get_expr_type(dest_node); |
| | 212 | |
| | 213 | LLVMValueRef dest_ptr = gen_expr(g, dest_node); |
| | 214 | LLVMValueRef char_val = gen_expr(g, node->data.fn_call_expr.params.at(1)); |
| | 215 | LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2)); |
| | 216 | |
| | 217 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); |
| | 218 | |
| | 219 | add_debug_source_node(g, node); |
| | 220 | LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); |
| | 221 | |
| | 222 | uint64_t align_in_bytes = dest_type->data.pointer.child_type->align_in_bits / 8; |
| | 223 | |
| | 224 | LLVMValueRef params[] = { |
| | 225 | dest_ptr_casted, // dest pointer |
| | 226 | char_val, // source pointer |
| | 227 | len_val, // byte count |
| | 228 | LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes |
| | 229 | LLVMConstNull(LLVMInt1Type()), // is volatile |
| | 230 | }; |
| | 231 | |
| | 232 | LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, ""); |
| | 233 | return nullptr; |
| | 234 | } |
| 174 | } | 235 | } |
| 175 | zig_unreachable(); | 236 | zig_unreachable(); |
| 176 | } | 237 | } |
| ... | @@ -1376,23 +1437,35 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { | ... | @@ -1376,23 +1437,35 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { |
| 1376 | assert(node->data.while_expr.condition); | 1437 | assert(node->data.while_expr.condition); |
| 1377 | assert(node->data.while_expr.body); | 1438 | assert(node->data.while_expr.body); |
| 1378 | | 1439 | |
| 1379 | if (get_expr_type(node)->id == TypeTableEntryIdUnreachable) { | 1440 | bool condition_always_true = node->codegen_node->data.while_node.condition_always_true; |
| 1380 | // generate a forever loop. guarantees no break statements | 1441 | bool contains_break = node->codegen_node->data.while_node.contains_break; |
| | 1442 | if (condition_always_true) { |
| | 1443 | // generate a forever loop |
| 1381 | | 1444 | |
| 1382 | LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody"); | 1445 | LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody"); |
| | 1446 | LLVMBasicBlockRef end_block = nullptr; |
| | 1447 | if (contains_break) { |
| | 1448 | end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd"); |
| | 1449 | } |
| 1383 | | 1450 | |
| 1384 | add_debug_source_node(g, node); | 1451 | add_debug_source_node(g, node); |
| 1385 | LLVMBuildBr(g->builder, body_block); | 1452 | LLVMBuildBr(g->builder, body_block); |
| 1386 | | 1453 | |
| 1387 | LLVMPositionBuilderAtEnd(g->builder, body_block); | 1454 | LLVMPositionBuilderAtEnd(g->builder, body_block); |
| | 1455 | g->break_block_stack.append(end_block); |
| 1388 | g->continue_block_stack.append(body_block); | 1456 | g->continue_block_stack.append(body_block); |
| 1389 | gen_expr(g, node->data.while_expr.body); | 1457 | gen_expr(g, node->data.while_expr.body); |
| | 1458 | g->break_block_stack.pop(); |
| 1390 | g->continue_block_stack.pop(); | 1459 | g->continue_block_stack.pop(); |
| 1391 | | 1460 | |
| 1392 | if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) { | 1461 | if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) { |
| 1393 | add_debug_source_node(g, node); | 1462 | add_debug_source_node(g, node); |
| 1394 | LLVMBuildBr(g->builder, body_block); | 1463 | LLVMBuildBr(g->builder, body_block); |
| 1395 | } | 1464 | } |
| | 1465 | |
| | 1466 | if (contains_break) { |
| | 1467 | LLVMPositionBuilderAtEnd(g->builder, end_block); |
| | 1468 | } |
| 1396 | } else { | 1469 | } else { |
| 1397 | // generate a normal while loop | 1470 | // generate a normal while loop |
| 1398 | | 1471 | |
| ... | @@ -1755,20 +1828,6 @@ static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) { | ... | @@ -1755,20 +1828,6 @@ static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) { |
| 1755 | static void do_code_gen(CodeGen *g) { | 1828 | static void do_code_gen(CodeGen *g) { |
| 1756 | assert(!g->errors.length); | 1829 | assert(!g->errors.length); |
| 1757 | | 1830 | |
| 1758 | { | | |
| 1759 | LLVMTypeRef param_types[] = { | | |
| 1760 | LLVMPointerType(LLVMInt8Type(), 0), | | |
| 1761 | LLVMPointerType(LLVMInt8Type(), 0), | | |
| 1762 | LLVMIntType(g->pointer_size_bytes * 8), | | |
| 1763 | LLVMInt32Type(), | | |
| 1764 | LLVMInt1Type(), | | |
| 1765 | }; | | |
| 1766 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 5, false); | | |
| 1767 | Buf *name = buf_sprintf("llvm.memcpy.p0i8.p0i8.i%d", g->pointer_size_bytes * 8); | | |
| 1768 | g->memcpy_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); | | |
| 1769 | assert(LLVMGetIntrinsicID(g->memcpy_fn_val)); | | |
| 1770 | } | | |
| 1771 | | | |
| 1772 | // Generate module level variables | 1831 | // Generate module level variables |
| 1773 | for (int i = 0; i < g->global_vars.length; i += 1) { | 1832 | for (int i = 0; i < g->global_vars.length; i += 1) { |
| 1774 | VariableTableEntry *var = g->global_vars.at(i); | 1833 | VariableTableEntry *var = g->global_vars.at(i); |
| ... | @@ -2267,6 +2326,57 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -2267,6 +2326,57 @@ static void define_builtin_fns(CodeGen *g) { |
| 2267 | define_builtin_fns_int(g, g->builtin_types.entry_i16); | 2326 | define_builtin_fns_int(g, g->builtin_types.entry_i16); |
| 2268 | define_builtin_fns_int(g, g->builtin_types.entry_i32); | 2327 | define_builtin_fns_int(g, g->builtin_types.entry_i32); |
| 2269 | define_builtin_fns_int(g, g->builtin_types.entry_i64); | 2328 | define_builtin_fns_int(g, g->builtin_types.entry_i64); |
| | 2329 | { |
| | 2330 | BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1); |
| | 2331 | buf_init_from_str(&builtin_fn->name, "memcpy"); |
| | 2332 | builtin_fn->id = BuiltinFnIdMemcpy; |
| | 2333 | builtin_fn->return_type = g->builtin_types.entry_void; |
| | 2334 | builtin_fn->param_count = 3; |
| | 2335 | builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count); |
| | 2336 | builtin_fn->param_types[0] = nullptr; // manually checked later |
| | 2337 | builtin_fn->param_types[1] = nullptr; // manually checked later |
| | 2338 | builtin_fn->param_types[2] = g->builtin_types.entry_usize; |
| | 2339 | |
| | 2340 | LLVMTypeRef param_types[] = { |
| | 2341 | LLVMPointerType(LLVMInt8Type(), 0), |
| | 2342 | LLVMPointerType(LLVMInt8Type(), 0), |
| | 2343 | LLVMIntType(g->pointer_size_bytes * 8), |
| | 2344 | LLVMInt32Type(), |
| | 2345 | LLVMInt1Type(), |
| | 2346 | }; |
| | 2347 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 5, false); |
| | 2348 | Buf *name = buf_sprintf("llvm.memcpy.p0i8.p0i8.i%d", g->pointer_size_bytes * 8); |
| | 2349 | g->memcpy_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); |
| | 2350 | builtin_fn->fn_val = g->memcpy_fn_val; |
| | 2351 | assert(LLVMGetIntrinsicID(g->memcpy_fn_val)); |
| | 2352 | |
| | 2353 | g->builtin_fn_table.put(&builtin_fn->name, builtin_fn); |
| | 2354 | } |
| | 2355 | { |
| | 2356 | BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1); |
| | 2357 | buf_init_from_str(&builtin_fn->name, "memset"); |
| | 2358 | builtin_fn->id = BuiltinFnIdMemset; |
| | 2359 | builtin_fn->return_type = g->builtin_types.entry_void; |
| | 2360 | builtin_fn->param_count = 3; |
| | 2361 | builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count); |
| | 2362 | builtin_fn->param_types[0] = nullptr; // manually checked later |
| | 2363 | builtin_fn->param_types[1] = g->builtin_types.entry_u8; |
| | 2364 | builtin_fn->param_types[2] = g->builtin_types.entry_usize; |
| | 2365 | |
| | 2366 | LLVMTypeRef param_types[] = { |
| | 2367 | LLVMPointerType(LLVMInt8Type(), 0), |
| | 2368 | LLVMInt8Type(), |
| | 2369 | LLVMIntType(g->pointer_size_bytes * 8), |
| | 2370 | LLVMInt32Type(), |
| | 2371 | LLVMInt1Type(), |
| | 2372 | }; |
| | 2373 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 5, false); |
| | 2374 | Buf *name = buf_sprintf("llvm.memset.p0i8.i%d", g->pointer_size_bytes * 8); |
| | 2375 | builtin_fn->fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); |
| | 2376 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); |
| | 2377 | |
| | 2378 | g->builtin_fn_table.put(&builtin_fn->name, builtin_fn); |
| | 2379 | } |
| 2270 | } | 2380 | } |
| 2271 | | 2381 | |
| 2272 | | 2382 | |