comptime support for pointer arithmetic with hard coded addresses

This commit is contained in:
Andrew Kelley 2019-02-11 19:12:01 -05:00
parent 90b8cd4a45
commit 57a7ab0d33
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
2 changed files with 109 additions and 40 deletions

View File

@ -11682,19 +11682,20 @@ static IrInstruction *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
}
static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {
if (op_id == IrBinOpCmpEq) {
switch (op_id) {
case IrBinOpCmpEq:
return cmp == CmpEQ;
} else if (op_id == IrBinOpCmpNotEq) {
case IrBinOpCmpNotEq:
return cmp != CmpEQ;
} else if (op_id == IrBinOpCmpLessThan) {
case IrBinOpCmpLessThan:
return cmp == CmpLT;
} else if (op_id == IrBinOpCmpGreaterThan) {
case IrBinOpCmpGreaterThan:
return cmp == CmpGT;
} else if (op_id == IrBinOpCmpLessOrEq) {
case IrBinOpCmpLessOrEq:
return cmp != CmpGT;
} else if (op_id == IrBinOpCmpGreaterOrEq) {
case IrBinOpCmpGreaterOrEq:
return cmp != CmpLT;
} else {
default:
zig_unreachable();
}
}
@ -11702,8 +11703,13 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {
static bool optional_value_is_null(ConstExprValue *val) {
assert(val->special == ConstValSpecialStatic);
if (get_codegen_ptr_type(val->type) != nullptr) {
return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
val->data.x_ptr.data.hard_coded_addr.addr == 0;
if (val->data.x_ptr.special == ConstPtrSpecialNull) {
return true;
} else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
return val->data.x_ptr.data.hard_coded_addr.addr == 0;
} else {
return false;
}
} else if (is_opt_err_set(val->type)) {
return val->data.x_err_set == nullptr;
} else {
@ -11879,7 +11885,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
break;
case ZigTypeIdPointer:
operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len != PtrLenSingle);
operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len == PtrLenC);
break;
case ZigTypeIdUnreachable:
@ -11929,15 +11935,38 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
if (op2_val == nullptr)
return ira->codegen->invalid_instruction;
bool answer;
if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) {
Cmp cmp_result = float_cmp(op1_val, op2_val);
answer = resolve_cmp_op_id(op_id, cmp_result);
bool answer = resolve_cmp_op_id(op_id, cmp_result);
return ir_const_bool(ira, &bin_op_instruction->base, answer);
} else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) {
Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);
answer = resolve_cmp_op_id(op_id, cmp_result);
bool answer = resolve_cmp_op_id(op_id, cmp_result);
return ir_const_bool(ira, &bin_op_instruction->base, answer);
} else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) {
if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
op1_val->data.x_ptr.special == ConstPtrSpecialNull) &&
(op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
op2_val->data.x_ptr.special == ConstPtrSpecialNull))
{
uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ?
0 : op1_val->data.x_ptr.data.hard_coded_addr.addr;
uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ?
0 : op2_val->data.x_ptr.data.hard_coded_addr.addr;
Cmp cmp_result;
if (op1_addr > op2_addr) {
cmp_result = CmpGT;
} else if (op1_addr < op2_addr) {
cmp_result = CmpLT;
} else {
cmp_result = CmpEQ;
}
bool answer = resolve_cmp_op_id(op_id, cmp_result);
return ir_const_bool(ira, &bin_op_instruction->base, answer);
}
} else {
bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val);
bool answer;
if (op_id == IrBinOpCmpEq) {
answer = are_equal;
} else if (op_id == IrBinOpCmpNotEq) {
@ -11945,10 +11974,9 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
} else {
zig_unreachable();
}
}
return ir_const_bool(ira, &bin_op_instruction->base, answer);
}
}
// some comparisons with unsigned numbers can be evaluated
if (resolved_type->id == ZigTypeIdInt && !resolved_type->data.integral.is_signed) {
@ -12363,6 +12391,8 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
}
static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) {
Error err;
IrInstruction *op1 = instruction->op1->child;
if (type_is_invalid(op1->value.type))
return ira->codegen->invalid_instruction;
@ -12376,9 +12406,42 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
// look for pointer math
if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) {
IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize);
if (casted_op2 == ira->codegen->invalid_instruction)
if (type_is_invalid(casted_op2->value.type))
return ira->codegen->invalid_instruction;
if (op1->value.special == ConstValSpecialUndef || casted_op2->value.special == ConstValSpecialUndef) {
IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type);
result->value.special = ConstValSpecialUndef;
return result;
}
if (casted_op2->value.special == ConstValSpecialStatic && op1->value.special == ConstValSpecialStatic &&
(op1->value.data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
op1->value.data.x_ptr.special == ConstPtrSpecialNull))
{
uint64_t start_addr = (op1->value.data.x_ptr.special == ConstPtrSpecialNull) ?
0 : op1->value.data.x_ptr.data.hard_coded_addr.addr;
uint64_t elem_offset;
if (!ir_resolve_usize(ira, casted_op2, &elem_offset))
return ira->codegen->invalid_instruction;
ZigType *elem_type = op1->value.type->data.pointer.child_type;
if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
return ira->codegen->invalid_instruction;
uint64_t byte_offset = type_size(ira->codegen, elem_type) * elem_offset;
uint64_t new_addr;
if (op_id == IrBinOpAdd) {
new_addr = start_addr + byte_offset;
} else if (op_id == IrBinOpSub) {
new_addr = start_addr - byte_offset;
} else {
zig_unreachable();
}
IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type);
result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
result->value.data.x_ptr.data.hard_coded_addr.addr = new_addr;
return result;
}
IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope,
instruction->base.source_node, op_id, op1, casted_op2, true);
result->value.type = op1->value.type;

View File

@ -58,8 +58,10 @@ test "implicit cast single item pointer to C pointer and back" {
}
test "C pointer comparison and arithmetic" {
const S = struct {
fn doTheTest() void {
var one: usize = 1;
var ptr1: [*c]u8 = 0;
var ptr1: [*c]u32 = 0;
var ptr2 = ptr1 + 10;
expect(ptr1 == 0);
expect(ptr1 >= 0);
@ -70,9 +72,13 @@ test "C pointer comparison and arithmetic" {
expect(one > ptr1);
expect(ptr1 < ptr2);
expect(ptr2 > ptr1);
expect(ptr2 >= 10);
expect(ptr2 == 10);
expect(ptr2 <= 10);
expect(ptr2 >= 40);
expect(ptr2 == 40);
expect(ptr2 <= 40);
ptr2 -= 10;
expect(ptr1 == ptr2);
}
};
S.doTheTest();
comptime S.doTheTest();
}