| ... | @@ -459,6 +459,34 @@ static LLVMValueRef gen_fence(CodeGen *g, AstNode *node) { | ... | @@ -459,6 +459,34 @@ static LLVMValueRef gen_fence(CodeGen *g, AstNode *node) { |
| 459 | return nullptr; | 459 | return nullptr; |
| 460 | } | 460 | } |
| 461 | | 461 | |
| | 462 | static LLVMValueRef gen_shl_with_overflow(CodeGen *g, AstNode *node) { |
| | 463 | assert(node->type == NodeTypeFnCallExpr); |
| | 464 | |
| | 465 | int fn_call_param_count = node->data.fn_call_expr.params.length; |
| | 466 | assert(fn_call_param_count == 4); |
| | 467 | |
| | 468 | TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0)); |
| | 469 | assert(int_type->id == TypeTableEntryIdInt); |
| | 470 | |
| | 471 | LLVMValueRef val1 = gen_expr(g, node->data.fn_call_expr.params.at(1)); |
| | 472 | LLVMValueRef val2 = gen_expr(g, node->data.fn_call_expr.params.at(2)); |
| | 473 | LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(3)); |
| | 474 | |
| | 475 | set_debug_source_node(g, node); |
| | 476 | LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, ""); |
| | 477 | LLVMValueRef orig_val; |
| | 478 | if (int_type->data.integral.is_signed) { |
| | 479 | orig_val = LLVMBuildAShr(g->builder, result, val2, ""); |
| | 480 | } else { |
| | 481 | orig_val = LLVMBuildLShr(g->builder, result, val2, ""); |
| | 482 | } |
| | 483 | LLVMValueRef overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, val1, orig_val, ""); |
| | 484 | |
| | 485 | LLVMBuildStore(g->builder, result, ptr_result); |
| | 486 | |
| | 487 | return overflow_bit; |
| | 488 | } |
| | 489 | |
| 462 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { | 490 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 463 | assert(node->type == NodeTypeFnCallExpr); | 491 | assert(node->type == NodeTypeFnCallExpr); |
| 464 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; | 492 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; |
| ... | @@ -527,6 +555,8 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { | ... | @@ -527,6 +555,8 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 527 | | 555 | |
| 528 | return overflow_bit; | 556 | return overflow_bit; |
| 529 | } | 557 | } |
| | 558 | case BuiltinFnIdShlWithOverflow: |
| | 559 | return gen_shl_with_overflow(g, node); |
| 530 | case BuiltinFnIdMemcpy: | 560 | case BuiltinFnIdMemcpy: |
| 531 | { | 561 | { |
| 532 | int fn_call_param_count = node->data.fn_call_expr.params.length; | 562 | int fn_call_param_count = node->data.fn_call_expr.params.length; |
| ... | @@ -4357,6 +4387,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -4357,6 +4387,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 4357 | create_builtin_fn_with_arg_count(g, BuiltinFnIdAddWithOverflow, "add_with_overflow", 4); | 4387 | create_builtin_fn_with_arg_count(g, BuiltinFnIdAddWithOverflow, "add_with_overflow", 4); |
| 4358 | create_builtin_fn_with_arg_count(g, BuiltinFnIdSubWithOverflow, "sub_with_overflow", 4); | 4388 | create_builtin_fn_with_arg_count(g, BuiltinFnIdSubWithOverflow, "sub_with_overflow", 4); |
| 4359 | create_builtin_fn_with_arg_count(g, BuiltinFnIdMulWithOverflow, "mul_with_overflow", 4); | 4389 | create_builtin_fn_with_arg_count(g, BuiltinFnIdMulWithOverflow, "mul_with_overflow", 4); |
| | 4390 | create_builtin_fn_with_arg_count(g, BuiltinFnIdShlWithOverflow, "shl_with_overflow", 4); |
| 4360 | create_builtin_fn_with_arg_count(g, BuiltinFnIdCInclude, "c_include", 1); | 4391 | create_builtin_fn_with_arg_count(g, BuiltinFnIdCInclude, "c_include", 1); |
| 4361 | create_builtin_fn_with_arg_count(g, BuiltinFnIdCDefine, "c_define", 2); | 4392 | create_builtin_fn_with_arg_count(g, BuiltinFnIdCDefine, "c_define", 2); |
| 4362 | create_builtin_fn_with_arg_count(g, BuiltinFnIdCUndef, "c_undef", 1); | 4393 | create_builtin_fn_with_arg_count(g, BuiltinFnIdCUndef, "c_undef", 1); |