authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-11 15:31:09-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-11 15:31:09-05:00
log342bca7f4627454435e9f6c2d12b099f95a2fd47
tree01b42262415f9cc16348bfaf3741e139527be790
parentd9e01be97386f008e4a4b4281658f25b50ff80f1
signature Commit is signed but in an unrecognized format.

C pointer comparison and arithmetic

See #1059

6 files changed, 78 insertions(+), 20 deletions(-)

src/analyze.cpp+1-1
...@@ -434,7 +434,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons...@@ -434,7 +434,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
434 uint32_t bit_offset_in_host, uint32_t host_int_bytes)434 uint32_t bit_offset_in_host, uint32_t host_int_bytes)
435{435{
436 assert(!type_is_invalid(child_type));436 assert(!type_is_invalid(child_type));
437 assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);437 assert(ptr_len != PtrLenUnknown || child_type->id != ZigTypeIdOpaque);
438438
439 if (byte_alignment != 0) {439 if (byte_alignment != 0) {
440 uint32_t abi_alignment = get_abi_alignment(g, child_type);440 uint32_t abi_alignment = get_abi_alignment(g, child_type);
src/codegen.cpp+2-2
...@@ -2657,7 +2657,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2657,7 +2657,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2657 (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) ||2657 (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) ||
2658 (op1->value.type->id == ZigTypeIdPointer &&2658 (op1->value.type->id == ZigTypeIdPointer &&
2659 (op_id == IrBinOpAdd || op_id == IrBinOpSub) &&2659 (op_id == IrBinOpAdd || op_id == IrBinOpSub) &&
2660 op1->value.type->data.pointer.ptr_len == PtrLenUnknown)2660 op1->value.type->data.pointer.ptr_len != PtrLenSingle)
2661 );2661 );
2662 ZigType *operand_type = op1->value.type;2662 ZigType *operand_type = op1->value.type;
2663 ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;2663 ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
...@@ -2716,7 +2716,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2716,7 +2716,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2716 AddSubMulMul;2716 AddSubMulMul;
27172717
2718 if (scalar_type->id == ZigTypeIdPointer) {2718 if (scalar_type->id == ZigTypeIdPointer) {
2719 assert(scalar_type->data.pointer.ptr_len == PtrLenUnknown);2719 assert(scalar_type->data.pointer.ptr_len != PtrLenSingle);
2720 LLVMValueRef subscript_value;2720 LLVMValueRef subscript_value;
2721 if (operand_type->id == ZigTypeIdVector)2721 if (operand_type->id == ZigTypeIdVector)
2722 zig_panic("TODO: Implement vector operations on pointers.");2722 zig_panic("TODO: Implement vector operations on pointers.");
src/ir.cpp+41-5
...@@ -8943,7 +8943,9 @@ static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *...@@ -8943,7 +8943,9 @@ static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *
8943 *errors = reallocate(*errors, old_errors_count, *errors_count);8943 *errors = reallocate(*errors, old_errors_count, *errors_count);
8944}8944}
89458945
8946static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type, IrInstruction **instructions, size_t instruction_count) {8946static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type,
8947 IrInstruction **instructions, size_t instruction_count)
8948{
8947 Error err;8949 Error err;
8948 assert(instruction_count >= 1);8950 assert(instruction_count >= 1);
8949 IrInstruction *prev_inst = instructions[0];8951 IrInstruction *prev_inst = instructions[0];
...@@ -9260,6 +9262,19 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT...@@ -9260,6 +9262,19 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
9260 continue;9262 continue;
9261 }9263 }
92629264
9265 if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenC &&
9266 (cur_type->id == ZigTypeIdComptimeInt || cur_type->id == ZigTypeIdInt))
9267 {
9268 continue;
9269 }
9270
9271 if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenC &&
9272 (prev_type->id == ZigTypeIdComptimeInt || prev_type->id == ZigTypeIdInt))
9273 {
9274 prev_inst = cur_inst;
9275 continue;
9276 }
9277
9263 if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) {9278 if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) {
9264 continue;9279 continue;
9265 }9280 }
...@@ -11852,7 +11867,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -11852,7 +11867,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
11852 case ZigTypeIdBool:11867 case ZigTypeIdBool:
11853 case ZigTypeIdMetaType:11868 case ZigTypeIdMetaType:
11854 case ZigTypeIdVoid:11869 case ZigTypeIdVoid:
11855 case ZigTypeIdPointer:
11856 case ZigTypeIdErrorSet:11870 case ZigTypeIdErrorSet:
11857 case ZigTypeIdFn:11871 case ZigTypeIdFn:
11858 case ZigTypeIdOpaque:11872 case ZigTypeIdOpaque:
...@@ -11864,6 +11878,10 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -11864,6 +11878,10 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
11864 operator_allowed = is_equality_cmp;11878 operator_allowed = is_equality_cmp;
11865 break;11879 break;
1186611880
11881 case ZigTypeIdPointer:
11882 operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len != PtrLenSingle);
11883 break;
11884
11867 case ZigTypeIdUnreachable:11885 case ZigTypeIdUnreachable:
11868 case ZigTypeIdArray:11886 case ZigTypeIdArray:
11869 case ZigTypeIdStruct:11887 case ZigTypeIdStruct:
...@@ -12324,6 +12342,26 @@ static bool ok_float_op(IrBinOp op) {...@@ -12324,6 +12342,26 @@ static bool ok_float_op(IrBinOp op) {
12324 zig_unreachable();12342 zig_unreachable();
12325}12343}
1232612344
12345static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
12346 if (lhs_type->id != ZigTypeIdPointer)
12347 return false;
12348 switch (op) {
12349 case IrBinOpAdd:
12350 case IrBinOpSub:
12351 break;
12352 default:
12353 return false;
12354 }
12355 switch (lhs_type->data.pointer.ptr_len) {
12356 case PtrLenSingle:
12357 return false;
12358 case PtrLenUnknown:
12359 case PtrLenC:
12360 break;
12361 }
12362 return true;
12363}
12364
12327static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) {12365static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) {
12328 IrInstruction *op1 = instruction->op1->child;12366 IrInstruction *op1 = instruction->op1->child;
12329 if (type_is_invalid(op1->value.type))12367 if (type_is_invalid(op1->value.type))
...@@ -12336,9 +12374,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -12336,9 +12374,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
12336 IrBinOp op_id = instruction->op_id;12374 IrBinOp op_id = instruction->op_id;
1233712375
12338 // look for pointer math12376 // look for pointer math
12339 if (op1->value.type->id == ZigTypeIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenUnknown &&12377 if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) {
12340 (op_id == IrBinOpAdd || op_id == IrBinOpSub))
12341 {
12342 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize);12378 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize);
12343 if (casted_op2 == ira->codegen->invalid_instruction)12379 if (casted_op2 == ira->codegen->invalid_instruction)
12344 return ira->codegen->invalid_instruction;12380 return ira->codegen->invalid_instruction;
src/translate_c.cpp+5-3
...@@ -1677,7 +1677,7 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im...@@ -1677,7 +1677,7 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im
1677 return node;1677 return node;
1678 }1678 }
1679 case CK_NullToPointer:1679 case CK_NullToPointer:
1680 return trans_create_node(c, NodeTypeNullLiteral);1680 return trans_create_node_unsigned(c, 0);
1681 case CK_Dependent:1681 case CK_Dependent:
1682 emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent");1682 emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent");
1683 return nullptr;1683 return nullptr;
...@@ -2409,7 +2409,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *...@@ -2409,7 +2409,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *
2409 case BuiltinType::Float16:2409 case BuiltinType::Float16:
2410 return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false));2410 return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false));
2411 case BuiltinType::NullPtr:2411 case BuiltinType::NullPtr:
2412 return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral));2412 return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq,
2413 trans_create_node_unsigned(c, 0));
24132414
2414 case BuiltinType::Void:2415 case BuiltinType::Void:
2415 case BuiltinType::Half:2416 case BuiltinType::Half:
...@@ -2494,7 +2495,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *...@@ -2494,7 +2495,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *
2494 break;2495 break;
2495 }2496 }
2496 case Type::Pointer:2497 case Type::Pointer:
2497 return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral));2498 return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq,
2499 trans_create_node_unsigned(c, 0));
24982500
2499 case Type::Typedef:2501 case Type::Typedef:
2500 {2502 {
test/stage1/behavior/pointers.zig+20
...@@ -56,3 +56,23 @@ test "implicit cast single item pointer to C pointer and back" {...@@ -56,3 +56,23 @@ test "implicit cast single item pointer to C pointer and back" {
56 z.* += 1;56 z.* += 1;
57 expect(y == 12);57 expect(y == 12);
58}58}
59
60test "C pointer comparison and arithmetic" {
61 var one: usize = 1;
62 var ptr1: [*c]u8 = 0;
63 var ptr2 = ptr1 + 10;
64 expect(ptr1 == 0);
65 expect(ptr1 >= 0);
66 expect(ptr1 <= 0);
67 expect(ptr1 < 1);
68 expect(ptr1 < one);
69 expect(1 > ptr1);
70 expect(one > ptr1);
71 expect(ptr1 < ptr2);
72 expect(ptr2 > ptr1);
73 expect(ptr2 >= 10);
74 expect(ptr2 == 10);
75 expect(ptr2 <= 10);
76 ptr2 -= 10;
77 expect(ptr1 == ptr2);
78}
test/translate_c.zig+9-9
...@@ -610,11 +610,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -610,11 +610,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
610 ,610 ,
611 \\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {611 \\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {
612 \\ if ((a != 0) and (b != 0)) return 0;612 \\ if ((a != 0) and (b != 0)) return 0;
613 \\ if ((b != 0) and (c != null)) return 1;613 \\ if ((b != 0) and (c != 0)) return 1;
614 \\ if ((a != 0) and (c != null)) return 2;614 \\ if ((a != 0) and (c != 0)) return 2;
615 \\ if ((a != 0) or (b != 0)) return 3;615 \\ if ((a != 0) or (b != 0)) return 3;
616 \\ if ((b != 0) or (c != null)) return 4;616 \\ if ((b != 0) or (c != 0)) return 4;
617 \\ if ((a != 0) or (c != null)) return 5;617 \\ if ((a != 0) or (c != 0)) return 5;
618 \\ return 6;618 \\ return 6;
619 \\}619 \\}
620 );620 );
...@@ -778,7 +778,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -778,7 +778,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
778 \\}778 \\}
779 ,779 ,
780 \\pub export fn foo() [*c]c_int {780 \\pub export fn foo() [*c]c_int {
781 \\ return null;781 \\ return 0;
782 \\}782 \\}
783 );783 );
784784
...@@ -1280,7 +1280,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1280,7 +1280,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1280 \\ return !(a == 0);1280 \\ return !(a == 0);
1281 \\ return !(a != 0);1281 \\ return !(a != 0);
1282 \\ return !(b != 0);1282 \\ return !(b != 0);
1283 \\ return !(c != null);1283 \\ return !(c != 0);
1284 \\}1284 \\}
1285 );1285 );
12861286
...@@ -1337,7 +1337,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1337,7 +1337,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1337 \\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int {1337 \\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int {
1338 \\ if (a != 0) return 0;1338 \\ if (a != 0) return 0;
1339 \\ if (b != 0) return 1;1339 \\ if (b != 0) return 1;
1340 \\ if (c != null) return 2;1340 \\ if (c != 0) return 2;
1341 \\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3;1341 \\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3;
1342 \\ return 4;1342 \\ return 4;
1343 \\}1343 \\}
...@@ -1354,7 +1354,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1354,7 +1354,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1354 \\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {1354 \\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {
1355 \\ while (a != 0) return 0;1355 \\ while (a != 0) return 0;
1356 \\ while (b != 0) return 1;1356 \\ while (b != 0) return 1;
1357 \\ while (c != null) return 2;1357 \\ while (c != 0) return 2;
1358 \\ return 3;1358 \\ return 3;
1359 \\}1359 \\}
1360 );1360 );
...@@ -1370,7 +1370,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1370,7 +1370,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1370 \\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {1370 \\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {
1371 \\ while (a != 0) return 0;1371 \\ while (a != 0) return 0;
1372 \\ while (b != 0) return 1;1372 \\ while (b != 0) return 1;
1373 \\ while (c != null) return 2;1373 \\ while (c != 0) return 2;
1374 \\ return 3;1374 \\ return 3;
1375 \\}1375 \\}
1376 );1376 );