Skip to content

Commit 342bca7

Browse files
committed
C pointer comparison and arithmetic
See #1059
1 parent d9e01be commit 342bca7

File tree

6 files changed

+78
-20
lines changed

6 files changed

+78
-20
lines changed

src/analyze.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
434434
uint32_t bit_offset_in_host, uint32_t host_int_bytes)
435435
{
436436
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

439439
if (byte_alignment != 0) {
440440
uint32_t abi_alignment = get_abi_alignment(g, child_type);

src/codegen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2657,7 +2657,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
26572657
(op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) ||
26582658
(op1->value.type->id == ZigTypeIdPointer &&
26592659
(op_id == IrBinOpAdd || op_id == IrBinOpSub) &&
2660-
op1->value.type->data.pointer.ptr_len == PtrLenUnknown)
2660+
op1->value.type->data.pointer.ptr_len != PtrLenSingle)
26612661
);
26622662
ZigType *operand_type = op1->value.type;
26632663
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,
27162716
AddSubMulMul;
27172717

27182718
if (scalar_type->id == ZigTypeIdPointer) {
2719-
assert(scalar_type->data.pointer.ptr_len == PtrLenUnknown);
2719+
assert(scalar_type->data.pointer.ptr_len != PtrLenSingle);
27202720
LLVMValueRef subscript_value;
27212721
if (operand_type->id == ZigTypeIdVector)
27222722
zig_panic("TODO: Implement vector operations on pointers.");

src/ir.cpp

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8943,7 +8943,9 @@ static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *
89438943
*errors = reallocate(*errors, old_errors_count, *errors_count);
89448944
}
89458945

8946-
static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type, IrInstruction **instructions, size_t instruction_count) {
8946+
static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type,
8947+
IrInstruction **instructions, size_t instruction_count)
8948+
{
89478949
Error err;
89488950
assert(instruction_count >= 1);
89498951
IrInstruction *prev_inst = instructions[0];
@@ -9260,6 +9262,19 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
92609262
continue;
92619263
}
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+
92639278
if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) {
92649279
continue;
92659280
}
@@ -11852,7 +11867,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1185211867
case ZigTypeIdBool:
1185311868
case ZigTypeIdMetaType:
1185411869
case ZigTypeIdVoid:
11855-
case ZigTypeIdPointer:
1185611870
case ZigTypeIdErrorSet:
1185711871
case ZigTypeIdFn:
1185811872
case ZigTypeIdOpaque:
@@ -11864,6 +11878,10 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1186411878
operator_allowed = is_equality_cmp;
1186511879
break;
1186611880

11881+
case ZigTypeIdPointer:
11882+
operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len != PtrLenSingle);
11883+
break;
11884+
1186711885
case ZigTypeIdUnreachable:
1186811886
case ZigTypeIdArray:
1186911887
case ZigTypeIdStruct:
@@ -12324,6 +12342,26 @@ static bool ok_float_op(IrBinOp op) {
1232412342
zig_unreachable();
1232512343
}
1232612344

12345+
static 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+
1232712365
static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) {
1232812366
IrInstruction *op1 = instruction->op1->child;
1232912367
if (type_is_invalid(op1->value.type))
@@ -12336,9 +12374,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1233612374
IrBinOp op_id = instruction->op_id;
1233712375

1233812376
// look for pointer math
12339-
if (op1->value.type->id == ZigTypeIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenUnknown &&
12340-
(op_id == IrBinOpAdd || op_id == IrBinOpSub))
12341-
{
12377+
if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) {
1234212378
IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize);
1234312379
if (casted_op2 == ira->codegen->invalid_instruction)
1234412380
return ira->codegen->invalid_instruction;

src/translate_c.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,7 +1677,7 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im
16771677
return node;
16781678
}
16791679
case CK_NullToPointer:
1680-
return trans_create_node(c, NodeTypeNullLiteral);
1680+
return trans_create_node_unsigned(c, 0);
16811681
case CK_Dependent:
16821682
emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent");
16831683
return nullptr;
@@ -2409,7 +2409,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *
24092409
case BuiltinType::Float16:
24102410
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false));
24112411
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

24142415
case BuiltinType::Void:
24152416
case BuiltinType::Half:
@@ -2494,7 +2495,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *
24942495
break;
24952496
}
24962497
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

24992501
case Type::Typedef:
25002502
{

test/stage1/behavior/pointers.zig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,23 @@ test "implicit cast single item pointer to C pointer and back" {
5656
z.* += 1;
5757
expect(y == 12);
5858
}
59+
60+
test "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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -610,11 +610,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
610610
,
611611
\\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {
612612
\\ if ((a != 0) and (b != 0)) return 0;
613-
\\ if ((b != 0) and (c != null)) return 1;
614-
\\ if ((a != 0) and (c != null)) return 2;
613+
\\ if ((b != 0) and (c != 0)) return 1;
614+
\\ if ((a != 0) and (c != 0)) return 2;
615615
\\ if ((a != 0) or (b != 0)) return 3;
616-
\\ if ((b != 0) or (c != null)) return 4;
617-
\\ if ((a != 0) or (c != null)) return 5;
616+
\\ if ((b != 0) or (c != 0)) return 4;
617+
\\ if ((a != 0) or (c != 0)) return 5;
618618
\\ return 6;
619619
\\}
620620
);
@@ -778,7 +778,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
778778
\\}
779779
,
780780
\\pub export fn foo() [*c]c_int {
781-
\\ return null;
781+
\\ return 0;
782782
\\}
783783
);
784784

@@ -1280,7 +1280,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
12801280
\\ return !(a == 0);
12811281
\\ return !(a != 0);
12821282
\\ return !(b != 0);
1283-
\\ return !(c != null);
1283+
\\ return !(c != 0);
12841284
\\}
12851285
);
12861286

@@ -1337,7 +1337,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
13371337
\\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int {
13381338
\\ if (a != 0) return 0;
13391339
\\ if (b != 0) return 1;
1340-
\\ if (c != null) return 2;
1340+
\\ if (c != 0) return 2;
13411341
\\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3;
13421342
\\ return 4;
13431343
\\}
@@ -1354,7 +1354,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
13541354
\\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {
13551355
\\ while (a != 0) return 0;
13561356
\\ while (b != 0) return 1;
1357-
\\ while (c != null) return 2;
1357+
\\ while (c != 0) return 2;
13581358
\\ return 3;
13591359
\\}
13601360
);
@@ -1370,7 +1370,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
13701370
\\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {
13711371
\\ while (a != 0) return 0;
13721372
\\ while (b != 0) return 1;
1373-
\\ while (c != null) return 2;
1373+
\\ while (c != 0) return 2;
13741374
\\ return 3;
13751375
\\}
13761376
);

0 commit comments

Comments
 (0)