authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-11 19:12:01-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-11 19:12:01-05:00
log57a7ab0d330416f15c0288004b67101c1c3e9629
tree952ac83874f06875719e6fde2ebe24b407db5b67
parent90b8cd4a45bcb2ca131b6ed6466f799aaa162d13
signature Commit is signed but in an unrecognized format.

comptime support for pointer arithmetic with hard coded addresses


2 files changed, 109 insertions(+), 40 deletions(-)

src/ir.cpp+86-23
......@@ -11682,28 +11682,34 @@ static IrInstruction *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
1168211682}
1168311683
1168411684static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {
11685 if (op_id == IrBinOpCmpEq) {
11686 return cmp == CmpEQ;
11687 } else if (op_id == IrBinOpCmpNotEq) {
11688 return cmp != CmpEQ;
11689 } else if (op_id == IrBinOpCmpLessThan) {
11690 return cmp == CmpLT;
11691 } else if (op_id == IrBinOpCmpGreaterThan) {
11692 return cmp == CmpGT;
11693 } else if (op_id == IrBinOpCmpLessOrEq) {
11694 return cmp != CmpGT;
11695 } else if (op_id == IrBinOpCmpGreaterOrEq) {
11696 return cmp != CmpLT;
11697 } else {
11698 zig_unreachable();
11685 switch (op_id) {
11686 case IrBinOpCmpEq:
11687 return cmp == CmpEQ;
11688 case IrBinOpCmpNotEq:
11689 return cmp != CmpEQ;
11690 case IrBinOpCmpLessThan:
11691 return cmp == CmpLT;
11692 case IrBinOpCmpGreaterThan:
11693 return cmp == CmpGT;
11694 case IrBinOpCmpLessOrEq:
11695 return cmp != CmpGT;
11696 case IrBinOpCmpGreaterOrEq:
11697 return cmp != CmpLT;
11698 default:
11699 zig_unreachable();
1169911700 }
1170011701}
1170111702
1170211703static bool optional_value_is_null(ConstExprValue *val) {
1170311704 assert(val->special == ConstValSpecialStatic);
1170411705 if (get_codegen_ptr_type(val->type) != nullptr) {
11705 return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
11706 val->data.x_ptr.data.hard_coded_addr.addr == 0;
11706 if (val->data.x_ptr.special == ConstPtrSpecialNull) {
11707 return true;
11708 } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
11709 return val->data.x_ptr.data.hard_coded_addr.addr == 0;
11710 } else {
11711 return false;
11712 }
1170711713 } else if (is_opt_err_set(val->type)) {
1170811714 return val->data.x_err_set == nullptr;
1170911715 } else {
......@@ -11879,7 +11885,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1187911885 break;
1188011886
1188111887 case ZigTypeIdPointer:
11882 operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len != PtrLenSingle);
11888 operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len == PtrLenC);
1188311889 break;
1188411890
1188511891 case ZigTypeIdUnreachable:
......@@ -11929,15 +11935,38 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1192911935 if (op2_val == nullptr)
1193011936 return ira->codegen->invalid_instruction;
1193111937
11932 bool answer;
1193311938 if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) {
1193411939 Cmp cmp_result = float_cmp(op1_val, op2_val);
11935 answer = resolve_cmp_op_id(op_id, cmp_result);
11940 bool answer = resolve_cmp_op_id(op_id, cmp_result);
11941 return ir_const_bool(ira, &bin_op_instruction->base, answer);
1193611942 } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) {
1193711943 Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);
11938 answer = resolve_cmp_op_id(op_id, cmp_result);
11944 bool answer = resolve_cmp_op_id(op_id, cmp_result);
11945 return ir_const_bool(ira, &bin_op_instruction->base, answer);
11946 } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) {
11947 if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
11948 op1_val->data.x_ptr.special == ConstPtrSpecialNull) &&
11949 (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
11950 op2_val->data.x_ptr.special == ConstPtrSpecialNull))
11951 {
11952 uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ?
11953 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr;
11954 uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ?
11955 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr;
11956 Cmp cmp_result;
11957 if (op1_addr > op2_addr) {
11958 cmp_result = CmpGT;
11959 } else if (op1_addr < op2_addr) {
11960 cmp_result = CmpLT;
11961 } else {
11962 cmp_result = CmpEQ;
11963 }
11964 bool answer = resolve_cmp_op_id(op_id, cmp_result);
11965 return ir_const_bool(ira, &bin_op_instruction->base, answer);
11966 }
1193911967 } else {
1194011968 bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val);
11969 bool answer;
1194111970 if (op_id == IrBinOpCmpEq) {
1194211971 answer = are_equal;
1194311972 } else if (op_id == IrBinOpCmpNotEq) {
......@@ -11945,9 +11974,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1194511974 } else {
1194611975 zig_unreachable();
1194711976 }
11977 return ir_const_bool(ira, &bin_op_instruction->base, answer);
1194811978 }
11949
11950 return ir_const_bool(ira, &bin_op_instruction->base, answer);
1195111979 }
1195211980
1195311981 // some comparisons with unsigned numbers can be evaluated
......@@ -12363,6 +12391,8 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
1236312391}
1236412392
1236512393static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) {
12394 Error err;
12395
1236612396 IrInstruction *op1 = instruction->op1->child;
1236712397 if (type_is_invalid(op1->value.type))
1236812398 return ira->codegen->invalid_instruction;
......@@ -12376,9 +12406,42 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1237612406 // look for pointer math
1237712407 if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) {
1237812408 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize);
12379 if (casted_op2 == ira->codegen->invalid_instruction)
12409 if (type_is_invalid(casted_op2->value.type))
1238012410 return ira->codegen->invalid_instruction;
1238112411
12412 if (op1->value.special == ConstValSpecialUndef || casted_op2->value.special == ConstValSpecialUndef) {
12413 IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type);
12414 result->value.special = ConstValSpecialUndef;
12415 return result;
12416 }
12417 if (casted_op2->value.special == ConstValSpecialStatic && op1->value.special == ConstValSpecialStatic &&
12418 (op1->value.data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
12419 op1->value.data.x_ptr.special == ConstPtrSpecialNull))
12420 {
12421 uint64_t start_addr = (op1->value.data.x_ptr.special == ConstPtrSpecialNull) ?
12422 0 : op1->value.data.x_ptr.data.hard_coded_addr.addr;
12423 uint64_t elem_offset;
12424 if (!ir_resolve_usize(ira, casted_op2, &elem_offset))
12425 return ira->codegen->invalid_instruction;
12426 ZigType *elem_type = op1->value.type->data.pointer.child_type;
12427 if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
12428 return ira->codegen->invalid_instruction;
12429 uint64_t byte_offset = type_size(ira->codegen, elem_type) * elem_offset;
12430 uint64_t new_addr;
12431 if (op_id == IrBinOpAdd) {
12432 new_addr = start_addr + byte_offset;
12433 } else if (op_id == IrBinOpSub) {
12434 new_addr = start_addr - byte_offset;
12435 } else {
12436 zig_unreachable();
12437 }
12438 IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type);
12439 result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
12440 result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
12441 result->value.data.x_ptr.data.hard_coded_addr.addr = new_addr;
12442 return result;
12443 }
12444
1238212445 IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope,
1238312446 instruction->base.source_node, op_id, op1, casted_op2, true);
1238412447 result->value.type = op1->value.type;
test/stage1/behavior/pointers.zig+23-17
......@@ -58,21 +58,27 @@ test "implicit cast single item pointer to C pointer and back" {
5858}
5959
6060test "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);
61 const S = struct {
62 fn doTheTest() void {
63 var one: usize = 1;
64 var ptr1: [*c]u32 = 0;
65 var ptr2 = ptr1 + 10;
66 expect(ptr1 == 0);
67 expect(ptr1 >= 0);
68 expect(ptr1 <= 0);
69 expect(ptr1 < 1);
70 expect(ptr1 < one);
71 expect(1 > ptr1);
72 expect(one > ptr1);
73 expect(ptr1 < ptr2);
74 expect(ptr2 > ptr1);
75 expect(ptr2 >= 40);
76 expect(ptr2 == 40);
77 expect(ptr2 <= 40);
78 ptr2 -= 10;
79 expect(ptr1 == ptr2);
80 }
81 };
82 S.doTheTest();
83 comptime S.doTheTest();
7884}