| ... | ... | @@ -171,6 +171,67 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 171 | 171 | |
| 172 | 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 | 236 | zig_unreachable(); |
| 176 | 237 | } |
| ... | ... | @@ -1376,23 +1437,35 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { |
| 1376 | 1437 | assert(node->data.while_expr.condition); |
| 1377 | 1438 | assert(node->data.while_expr.body); |
| 1378 | 1439 | |
| 1379 | | if (get_expr_type(node)->id == TypeTableEntryIdUnreachable) { |
| 1380 | | // generate a forever loop. guarantees no break statements |
| 1440 | bool condition_always_true = node->codegen_node->data.while_node.condition_always_true; |
| 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 | 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 | 1451 | add_debug_source_node(g, node); |
| 1385 | 1452 | LLVMBuildBr(g->builder, body_block); |
| 1386 | 1453 | |
| 1387 | 1454 | LLVMPositionBuilderAtEnd(g->builder, body_block); |
| 1455 | g->break_block_stack.append(end_block); |
| 1388 | 1456 | g->continue_block_stack.append(body_block); |
| 1389 | 1457 | gen_expr(g, node->data.while_expr.body); |
| 1458 | g->break_block_stack.pop(); |
| 1390 | 1459 | g->continue_block_stack.pop(); |
| 1391 | 1460 | |
| 1392 | 1461 | if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) { |
| 1393 | 1462 | add_debug_source_node(g, node); |
| 1394 | 1463 | LLVMBuildBr(g->builder, body_block); |
| 1395 | 1464 | } |
| 1465 | |
| 1466 | if (contains_break) { |
| 1467 | LLVMPositionBuilderAtEnd(g->builder, end_block); |
| 1468 | } |
| 1396 | 1469 | } else { |
| 1397 | 1470 | // generate a normal while loop |
| 1398 | 1471 | |
| ... | ... | @@ -1755,20 +1828,6 @@ static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) { |
| 1755 | 1828 | static void do_code_gen(CodeGen *g) { |
| 1756 | 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 | 1831 | // Generate module level variables |
| 1773 | 1832 | for (int i = 0; i < g->global_vars.length; i += 1) { |
| 1774 | 1833 | VariableTableEntry *var = g->global_vars.at(i); |
| ... | ... | @@ -2267,6 +2326,57 @@ static void define_builtin_fns(CodeGen *g) { |
| 2267 | 2326 | define_builtin_fns_int(g, g->builtin_types.entry_i16); |
| 2268 | 2327 | define_builtin_fns_int(g, g->builtin_types.entry_i32); |
| 2269 | 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 | |