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...@@ -11682,28 +11682,34 @@ static IrInstruction *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
11682}11682}
1168311683
11684static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {11684static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {
11685 if (op_id == IrBinOpCmpEq) {11685 switch (op_id) {
11686 return cmp == CmpEQ;11686 case IrBinOpCmpEq:
11687 } else if (op_id == IrBinOpCmpNotEq) {11687 return cmp == CmpEQ;
11688 return cmp != CmpEQ;11688 case IrBinOpCmpNotEq:
11689 } else if (op_id == IrBinOpCmpLessThan) {11689 return cmp != CmpEQ;
11690 return cmp == CmpLT;11690 case IrBinOpCmpLessThan:
11691 } else if (op_id == IrBinOpCmpGreaterThan) {11691 return cmp == CmpLT;
11692 return cmp == CmpGT;11692 case IrBinOpCmpGreaterThan:
11693 } else if (op_id == IrBinOpCmpLessOrEq) {11693 return cmp == CmpGT;
11694 return cmp != CmpGT;11694 case IrBinOpCmpLessOrEq:
11695 } else if (op_id == IrBinOpCmpGreaterOrEq) {11695 return cmp != CmpGT;
11696 return cmp != CmpLT;11696 case IrBinOpCmpGreaterOrEq:
11697 } else {11697 return cmp != CmpLT;
11698 zig_unreachable();11698 default:
11699 zig_unreachable();
11699 }11700 }
11700}11701}
1170111702
11702static bool optional_value_is_null(ConstExprValue *val) {11703static bool optional_value_is_null(ConstExprValue *val) {
11703 assert(val->special == ConstValSpecialStatic);11704 assert(val->special == ConstValSpecialStatic);
11704 if (get_codegen_ptr_type(val->type) != nullptr) {11705 if (get_codegen_ptr_type(val->type) != nullptr) {
11705 return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&11706 if (val->data.x_ptr.special == ConstPtrSpecialNull) {
11706 val->data.x_ptr.data.hard_coded_addr.addr == 0;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 }
11707 } else if (is_opt_err_set(val->type)) {11713 } else if (is_opt_err_set(val->type)) {
11708 return val->data.x_err_set == nullptr;11714 return val->data.x_err_set == nullptr;
11709 } else {11715 } else {
...@@ -11879,7 +11885,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -11879,7 +11885,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
11879 break;11885 break;
1188011886
11881 case ZigTypeIdPointer:11887 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);
11883 break;11889 break;
1188411890
11885 case ZigTypeIdUnreachable:11891 case ZigTypeIdUnreachable:
...@@ -11929,15 +11935,38 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -11929,15 +11935,38 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
11929 if (op2_val == nullptr)11935 if (op2_val == nullptr)
11930 return ira->codegen->invalid_instruction;11936 return ira->codegen->invalid_instruction;
1193111937
11932 bool answer;
11933 if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) {11938 if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) {
11934 Cmp cmp_result = float_cmp(op1_val, op2_val);11939 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);
11936 } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) {11942 } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) {
11937 Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);11943 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 }
11939 } else {11967 } else {
11940 bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val);11968 bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val);
11969 bool answer;
11941 if (op_id == IrBinOpCmpEq) {11970 if (op_id == IrBinOpCmpEq) {
11942 answer = are_equal;11971 answer = are_equal;
11943 } else if (op_id == IrBinOpCmpNotEq) {11972 } else if (op_id == IrBinOpCmpNotEq) {
...@@ -11945,9 +11974,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -11945,9 +11974,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
11945 } else {11974 } else {
11946 zig_unreachable();11975 zig_unreachable();
11947 }11976 }
11977 return ir_const_bool(ira, &bin_op_instruction->base, answer);
11948 }11978 }
11949
11950 return ir_const_bool(ira, &bin_op_instruction->base, answer);
11951 }11979 }
1195211980
11953 // some comparisons with unsigned numbers can be evaluated11981 // some comparisons with unsigned numbers can be evaluated
...@@ -12363,6 +12391,8 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {...@@ -12363,6 +12391,8 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
12363}12391}
1236412392
12365static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) {12393static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) {
12394 Error err;
12395
12366 IrInstruction *op1 = instruction->op1->child;12396 IrInstruction *op1 = instruction->op1->child;
12367 if (type_is_invalid(op1->value.type))12397 if (type_is_invalid(op1->value.type))
12368 return ira->codegen->invalid_instruction;12398 return ira->codegen->invalid_instruction;
...@@ -12376,9 +12406,42 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -12376,9 +12406,42 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
12376 // look for pointer math12406 // look for pointer math
12377 if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) {12407 if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) {
12378 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize);12408 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))
12380 return ira->codegen->invalid_instruction;12410 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
12382 IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope,12445 IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope,
12383 instruction->base.source_node, op_id, op1, casted_op2, true);12446 instruction->base.source_node, op_id, op1, casted_op2, true);
12384 result->value.type = op1->value.type;12447 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" {...@@ -58,21 +58,27 @@ test "implicit cast single item pointer to C pointer and back" {
58}58}
5959
60test "C pointer comparison and arithmetic" {60test "C pointer comparison and arithmetic" {
61 var one: usize = 1;61 const S = struct {
62 var ptr1: [*c]u8 = 0;62 fn doTheTest() void {
63 var ptr2 = ptr1 + 10;63 var one: usize = 1;
64 expect(ptr1 == 0);64 var ptr1: [*c]u32 = 0;
65 expect(ptr1 >= 0);65 var ptr2 = ptr1 + 10;
66 expect(ptr1 <= 0);66 expect(ptr1 == 0);
67 expect(ptr1 < 1);67 expect(ptr1 >= 0);
68 expect(ptr1 < one);68 expect(ptr1 <= 0);
69 expect(1 > ptr1);69 expect(ptr1 < 1);
70 expect(one > ptr1);70 expect(ptr1 < one);
71 expect(ptr1 < ptr2);71 expect(1 > ptr1);
72 expect(ptr2 > ptr1);72 expect(one > ptr1);
73 expect(ptr2 >= 10);73 expect(ptr1 < ptr2);
74 expect(ptr2 == 10);74 expect(ptr2 > ptr1);
75 expect(ptr2 <= 10);75 expect(ptr2 >= 40);
76 ptr2 -= 10;76 expect(ptr2 == 40);
77 expect(ptr1 == ptr2);77 expect(ptr2 <= 40);
78 ptr2 -= 10;
79 expect(ptr1 == ptr2);
80 }
81 };
82 S.doTheTest();
83 comptime S.doTheTest();
78}84}