Commit 0ad580f001
Changed files (6)
src/all_types.hpp
@@ -1393,6 +1393,8 @@ enum IrInstructionId {
IrInstructionIdImport,
IrInstructionIdArrayLen,
IrInstructionIdRef,
+ IrInstructionIdMinValue,
+ IrInstructionIdMaxValue,
};
struct IrInstruction {
@@ -1791,6 +1793,18 @@ struct IrInstructionRef {
LLVMValueRef tmp_ptr;
};
+struct IrInstructionMinValue {
+ IrInstruction base;
+
+ IrInstruction *value;
+};
+
+struct IrInstructionMaxValue {
+ IrInstruction base;
+
+ IrInstruction *value;
+};
+
enum LValPurpose {
LValPurposeNone,
LValPurposeAssign,
src/codegen.cpp
@@ -1821,6 +1821,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdStaticEval:
case IrInstructionIdImport:
case IrInstructionIdContainerInitFields:
+ case IrInstructionIdMinValue:
+ case IrInstructionIdMaxValue:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
src/eval.cpp
@@ -431,6 +431,8 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
} else if (type_entry->id == TypeTableEntryIdBool) {
const_val->special = ConstValSpecialStatic;
const_val->data.x_bool = is_max;
+ } else if (type_entry->id == TypeTableEntryIdVoid) {
+ // nothing to do
} else {
zig_unreachable();
}
src/ir.cpp
@@ -306,6 +306,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) {
return IrInstructionIdStructInit;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) {
+ return IrInstructionIdMinValue;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionMaxValue *) {
+ return IrInstructionIdMaxValue;
+}
+
template<typename T>
static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@@ -1241,6 +1249,25 @@ static IrInstruction *ir_build_ref_from(IrBuilder *irb, IrInstruction *old_instr
return new_instruction;
}
+static IrInstruction *ir_build_min_value(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
+ IrInstructionMinValue *instruction = ir_build_instruction<IrInstructionMinValue>(irb, scope, source_node);
+ instruction->value = value;
+
+ ir_ref_instruction(value);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_max_value(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
+ IrInstructionMaxValue *instruction = ir_build_instruction<IrInstructionMaxValue>(irb, scope, source_node);
+ instruction->value = value;
+
+ ir_ref_instruction(value);
+
+ return &instruction->base;
+}
+
+
static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
bool gen_error_defers, bool gen_maybe_defers)
{
@@ -1879,11 +1906,27 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_import(irb, scope, node, arg0_value);
}
+ case BuiltinFnIdMaxValue:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ return ir_build_max_value(irb, scope, node, arg0_value);
+ }
+ case BuiltinFnIdMinValue:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ return ir_build_min_value(irb, scope, node, arg0_value);
+ }
case BuiltinFnIdMemcpy:
case BuiltinFnIdMemset:
case BuiltinFnIdAlignof:
- case BuiltinFnIdMaxValue:
- case BuiltinFnIdMinValue:
case BuiltinFnIdMemberCount:
case BuiltinFnIdAddWithOverflow:
case BuiltinFnIdSubWithOverflow:
@@ -4670,7 +4713,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
if (is_inline || fn_ref->static_value.special != ConstValSpecialRuntime) {
if (fn_ref->type_entry->id == TypeTableEntryIdMetaType) {
TypeTableEntry *dest_type = ir_resolve_type(ira, fn_ref);
- if (!dest_type)
+ if (dest_type->id == TypeTableEntryIdInvalid)
return ira->codegen->builtin_types.entry_invalid;
size_t actual_param_count = call_instruction->arg_count;
@@ -4958,6 +5001,48 @@ static TypeTableEntry *ir_analyze_unwrap_maybe(IrAnalyze *ira, IrInstructionUnOp
}
}
+static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
+ IrInstruction *value = un_op_instruction->value->other;
+ TypeTableEntry *expr_type = value->type_entry;
+ if (expr_type->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ bool is_wrap_op = (un_op_instruction->op_id == IrUnOpNegationWrap);
+
+ if ((expr_type->id == TypeTableEntryIdInt && expr_type->data.integral.is_signed) ||
+ expr_type->id == TypeTableEntryIdNumLitInt ||
+ ((expr_type->id == TypeTableEntryIdFloat || expr_type->id == TypeTableEntryIdNumLitFloat) &&
+ !is_wrap_op))
+ {
+ ConstExprValue *target_const_val = &value->static_value;
+ if (target_const_val->special != ConstValSpecialRuntime) {
+ bool depends_on_compile_var = value->static_value.depends_on_compile_var;
+ ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, depends_on_compile_var);
+ bignum_negate(&out_val->data.x_bignum, &target_const_val->data.x_bignum);
+ if (expr_type->id == TypeTableEntryIdFloat ||
+ expr_type->id == TypeTableEntryIdNumLitFloat ||
+ expr_type->id == TypeTableEntryIdNumLitInt)
+ {
+ return expr_type;
+ }
+
+ bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum, expr_type->data.integral.bit_count, true);
+ if (is_wrap_op) {
+ if (overflow)
+ out_val->data.x_bignum.is_negative = true;
+ } else if (overflow) {
+ ir_add_error(ira, &un_op_instruction->base, buf_sprintf("negation caused overflow"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ return expr_type;
+ }
+ }
+
+ const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";
+ ir_add_error(ira, &un_op_instruction->base, buf_sprintf(fmt, buf_ptr(&expr_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+}
+
static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
IrUnOp op_id = un_op_instruction->op_id;
switch (op_id) {
@@ -4983,51 +5068,7 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
//}
case IrUnOpNegation:
case IrUnOpNegationWrap:
- zig_panic("TODO analyze PrefixOpNegation[Wrap]");
- //{
- // TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
- // if (expr_type->id == TypeTableEntryIdInvalid) {
- // return expr_type;
- // } else if ((expr_type->id == TypeTableEntryIdInt &&
- // expr_type->data.integral.is_signed) ||
- // expr_type->id == TypeTableEntryIdNumLitInt ||
- // ((expr_type->id == TypeTableEntryIdFloat ||
- // expr_type->id == TypeTableEntryIdNumLitFloat) &&
- // prefix_op != PrefixOpNegationWrap))
- // {
- // ConstExprValue *target_const_val = &get_resolved_expr(*expr_node)->const_val;
- // if (!target_const_val->ok) {
- // return expr_type;
- // }
- // ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
- // const_val->ok = true;
- // const_val->depends_on_compile_var = target_const_val->depends_on_compile_var;
- // bignum_negate(&const_val->data.x_bignum, &target_const_val->data.x_bignum);
- // if (expr_type->id == TypeTableEntryIdFloat ||
- // expr_type->id == TypeTableEntryIdNumLitFloat ||
- // expr_type->id == TypeTableEntryIdNumLitInt)
- // {
- // return expr_type;
- // }
-
- // bool overflow = !bignum_fits_in_bits(&const_val->data.x_bignum,
- // expr_type->data.integral.bit_count, expr_type->data.integral.is_signed);
- // if (prefix_op == PrefixOpNegationWrap) {
- // if (overflow) {
- // const_val->data.x_bignum.is_negative = true;
- // }
- // } else if (overflow) {
- // add_node_error(g, *expr_node, buf_sprintf("negation caused overflow"));
- // return g->builtin_types.entry_invalid;
- // }
- // return expr_type;
- // } else {
- // const char *fmt = (prefix_op == PrefixOpNegationWrap) ?
- // "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";
- // add_node_error(g, node, buf_sprintf(fmt, buf_ptr(&expr_type->name)));
- // return g->builtin_types.entry_invalid;
- // }
- //}
+ return ir_analyze_negation(ira, un_op_instruction);
case IrUnOpAddressOf:
case IrUnOpConstAddressOf:
return ir_analyze_unary_address_of(ira, un_op_instruction, op_id == IrUnOpConstAddressOf);
@@ -6575,7 +6616,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) {
IrInstruction *container_type_value = instruction->container_type->other;
TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
- if (!container_type)
+ if (container_type->id == TypeTableEntryIdInvalid)
return ira->codegen->builtin_types.entry_invalid;
size_t elem_count = instruction->item_count;
@@ -6661,7 +6702,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
static TypeTableEntry *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) {
IrInstruction *container_type_value = instruction->container_type->other;
TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
- if (!container_type)
+ if (container_type->id == TypeTableEntryIdInvalid)
return ira->codegen->builtin_types.entry_invalid;
bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var;
@@ -6670,6 +6711,77 @@ static TypeTableEntry *ir_analyze_instruction_container_init_fields(IrAnalyze *i
instruction->field_count, instruction->fields, depends_on_compile_var);
}
+static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_instruction,
+ IrInstruction *target_type_value, bool is_max)
+{
+ TypeTableEntry *target_type = ir_resolve_type(ira, target_type_value);
+ bool depends_on_compile_var = target_type_value->static_value.depends_on_compile_var;
+ switch (target_type->id) {
+ case TypeTableEntryIdInvalid:
+ return ira->codegen->builtin_types.entry_invalid;
+ case TypeTableEntryIdInt:
+ {
+ ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var);
+ eval_min_max_value(ira->codegen, target_type, out_val, is_max);
+ return ira->codegen->builtin_types.entry_num_lit_int;
+ }
+ case TypeTableEntryIdFloat:
+ {
+ ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var);
+ eval_min_max_value(ira->codegen, target_type, out_val, is_max);
+ return ira->codegen->builtin_types.entry_num_lit_float;
+ }
+ case TypeTableEntryIdBool:
+ case TypeTableEntryIdVoid:
+ {
+ ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var);
+ eval_min_max_value(ira->codegen, target_type, out_val, is_max);
+ return target_type;
+ }
+ case TypeTableEntryIdVar:
+ case TypeTableEntryIdMetaType:
+ case TypeTableEntryIdUnreachable:
+ case TypeTableEntryIdPointer:
+ case TypeTableEntryIdArray:
+ case TypeTableEntryIdStruct:
+ case TypeTableEntryIdNumLitFloat:
+ case TypeTableEntryIdNumLitInt:
+ case TypeTableEntryIdUndefLit:
+ case TypeTableEntryIdNullLit:
+ case TypeTableEntryIdMaybe:
+ case TypeTableEntryIdErrorUnion:
+ case TypeTableEntryIdPureError:
+ case TypeTableEntryIdEnum:
+ case TypeTableEntryIdUnion:
+ case TypeTableEntryIdFn:
+ case TypeTableEntryIdTypeDecl:
+ case TypeTableEntryIdNamespace:
+ case TypeTableEntryIdBlock:
+ case TypeTableEntryIdBoundFn:
+ {
+ const char *err_format = is_max ?
+ "no max value available for type '%s'" :
+ "no min value available for type '%s'";
+ ir_add_error(ira, source_instruction,
+ buf_sprintf(err_format, buf_ptr(&target_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ }
+ zig_unreachable();
+}
+
+static TypeTableEntry *ir_analyze_instruction_min_value(IrAnalyze *ira,
+ IrInstructionMinValue *instruction)
+{
+ return ir_analyze_min_max(ira, &instruction->base, instruction->value->other, false);
+}
+
+static TypeTableEntry *ir_analyze_instruction_max_value(IrAnalyze *ira,
+ IrInstructionMaxValue *instruction)
+{
+ return ir_analyze_min_max(ira, &instruction->base, instruction->value->other, true);
+}
+
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -6754,6 +6866,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_container_init_list(ira, (IrInstructionContainerInitList *)instruction);
case IrInstructionIdContainerInitFields:
return ir_analyze_instruction_container_init_fields(ira, (IrInstructionContainerInitFields *)instruction);
+ case IrInstructionIdMinValue:
+ return ir_analyze_instruction_min_value(ira, (IrInstructionMinValue *)instruction);
+ case IrInstructionIdMaxValue:
+ return ir_analyze_instruction_max_value(ira, (IrInstructionMaxValue *)instruction);
case IrInstructionIdCast:
case IrInstructionIdStructFieldPtr:
case IrInstructionIdEnumFieldPtr:
@@ -6880,6 +6996,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdEnumTag:
case IrInstructionIdStaticEval:
case IrInstructionIdRef:
+ case IrInstructionIdMinValue:
+ case IrInstructionIdMaxValue:
return false;
case IrInstructionIdAsm:
{
@@ -6892,32 +7010,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
// TODO port over all this commented out code into new IR way of doing things
-//static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// AstNode *node, const char *err_format, bool is_max)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-// assert(node->data.fn_call_expr.params.length == 1);
-//
-// AstNode *type_node = node->data.fn_call_expr.params.at(0);
-// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
-//
-// if (type_entry->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// } else if (type_entry->id == TypeTableEntryIdInt) {
-// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
-// return g->builtin_types.entry_num_lit_int;
-// } else if (type_entry->id == TypeTableEntryIdFloat) {
-// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
-// return g->builtin_types.entry_num_lit_float;
-// } else if (type_entry->id == TypeTableEntryIdBool) {
-// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
-// return type_entry;
-// } else {
-// add_node_error(g, node,
-// buf_sprintf(err_format, buf_ptr(&type_entry->name)));
-// return g->builtin_types.entry_invalid;
-// }
-//}
//static TypeTableEntry *analyze_c_import(CodeGen *g, ImportTableEntry *parent_import,
// BlockContext *parent_context, AstNode *node)
@@ -7393,12 +7485,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
// align_in_bytes, false);
// }
// }
-// case BuiltinFnIdMaxValue:
-// return analyze_min_max_value(g, import, context, node,
-// "no max value available for type '%s'", true);
-// case BuiltinFnIdMinValue:
-// return analyze_min_max_value(g, import, context, node,
-// "no min value available for type '%s'", false);
// case BuiltinFnIdMemberCount:
// {
// AstNode *type_node = node->data.fn_call_expr.params.at(0);
src/ir_print.cpp
@@ -658,6 +658,18 @@ static void ir_print_ref(IrPrint *irp, IrInstructionRef *instruction) {
ir_print_other_instruction(irp, instruction->value);
}
+static void ir_print_min_value(IrPrint *irp, IrInstructionMinValue *instruction) {
+ fprintf(irp->f, "@minValue(");
+ ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_max_value(IrPrint *irp, IrInstructionMaxValue *instruction) {
+ fprintf(irp->f, "@maxValue(");
+ ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -795,6 +807,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdRef:
ir_print_ref(irp, (IrInstructionRef *)instruction);
break;
+ case IrInstructionIdMinValue:
+ ir_print_min_value(irp, (IrInstructionMinValue *)instruction);
+ break;
+ case IrInstructionIdMaxValue:
+ ir_print_max_value(irp, (IrInstructionMaxValue *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
test/self_hosted2.zig
@@ -204,6 +204,39 @@ fn testStaticAddOne() {
assert(should_be_1235 == 1235);
}
+fn gimme1or2(inline a: bool) -> i32 {
+ const x: i32 = 1;
+ const y: i32 = 2;
+ inline var z: i32 = inline if (a) x else y;
+ return z;
+}
+
+fn testInlineVarsAgain() {
+ assert(gimme1or2(true) == 1);
+ assert(gimme1or2(false) == 2);
+}
+
+fn testMinValueAndMaxValue() {
+ assert(@maxValue(u8) == 255);
+ assert(@maxValue(u16) == 65535);
+ assert(@maxValue(u32) == 4294967295);
+ assert(@maxValue(u64) == 18446744073709551615);
+
+ assert(@maxValue(i8) == 127);
+ assert(@maxValue(i16) == 32767);
+ assert(@maxValue(i32) == 2147483647);
+ assert(@maxValue(i64) == 9223372036854775807);
+
+ assert(@minValue(u8) == 0);
+ assert(@minValue(u16) == 0);
+ assert(@minValue(u32) == 0);
+ assert(@minValue(u64) == 0);
+
+ assert(@minValue(i8) == -128);
+ assert(@minValue(i16) == -32768);
+ assert(@minValue(i32) == -2147483648);
+ assert(@minValue(i64) == -9223372036854775808);
+}
fn assert(ok: bool) {
if (!ok)
@@ -228,6 +261,8 @@ fn runAllTests() {
shortCircuit();
testGotoLeaveDeferScope(true);
testStaticAddOne();
+ testInlineVarsAgain();
+ testMinValueAndMaxValue();
}
export nakedcc fn _start() -> unreachable {