diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-10-22 17:36:18 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-22 17:36:18 -0400 |
| commit | e6ac082437b87fccf6a7e592f813d3403427e512 (patch) | |
| tree | 4c61a3a5d19afd57cf1b20010179ccbf538347c2 /src/stage1/ir.cpp | |
| parent | 78199a684f50f37f652dabcc88b02e8b998ab5fa (diff) | |
| parent | 475fc2934b9bb4c0c10ca213c4322cc902c4b303 (diff) | |
| download | zig-e6ac082437b87fccf6a7e592f813d3403427e512.tar.gz zig-e6ac082437b87fccf6a7e592f813d3403427e512.zip | |
Merge pull request #6744 from LemonBoy/intcast-vec
stage1: Implement `@intCast` between vectors
Diffstat (limited to 'src/stage1/ir.cpp')
| -rw-r--r-- | src/stage1/ir.cpp | 150 |
1 files changed, 129 insertions, 21 deletions
diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index dc482a9dd6..00600c7e43 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -86,6 +86,8 @@ enum ConstCastResultId { ConstCastResultIdCV, ConstCastResultIdPtrSentinel, ConstCastResultIdIntShorten, + ConstCastResultIdVectorLength, + ConstCastResultIdVectorChild, }; struct ConstCastOnly; @@ -912,6 +914,7 @@ static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expecte if (is_opt_err_set(expected) && is_opt_err_set(actual)) return true; + // XXX: Vectors and arrays are interchangeable at comptime if (expected->id != actual->id) return false; @@ -945,9 +948,11 @@ static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expecte case ZigTypeIdErrorUnion: case ZigTypeIdEnum: case ZigTypeIdUnion: - case ZigTypeIdVector: case ZigTypeIdFnFrame: return false; + case ZigTypeIdVector: + return expected->data.vector.len == actual->data.vector.len && + types_have_same_zig_comptime_repr(codegen, expected->data.vector.elem_type, actual->data.vector.elem_type); case ZigTypeIdArray: return expected->data.array.len == actual->data.array.len && expected->data.array.child_type == actual->data.array.child_type && @@ -12172,6 +12177,24 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted return result; } + if (wanted_type->id == ZigTypeIdVector && actual_type->id == ZigTypeIdVector) { + if (actual_type->data.vector.len != wanted_type->data.vector.len) { + result.id = ConstCastResultIdVectorLength; + return result; + } + + ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.vector.elem_type, + actual_type->data.vector.elem_type, source_node, false); + if (child.id == ConstCastResultIdInvalid) + return child; + if (child.id != ConstCastResultIdOk) { + result.id = ConstCastResultIdVectorChild; + return result; + } + + return result; + } + result.id = ConstCastResultIdType; result.data.type_mismatch = heap::c_allocator.allocate_nonzero<ConstCastTypeMismatch>(1); result.data.type_mismatch->wanted_type = wanted_type; @@ -14288,37 +14311,62 @@ static IrInstGen *ir_analyze_enum_to_union(IrAnalyze *ira, IrInst* source_instr, return ira->codegen->invalid_inst_gen; } +static bool value_numeric_fits_in_type(ZigValue *value, ZigType *type_entry); + static IrInstGen *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInst* source_instr, IrInstGen *target, ZigType *wanted_type) { - assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdFloat); + ZigType *wanted_scalar_type = (target->value->type->id == ZigTypeIdVector) ? + wanted_type->data.vector.elem_type : wanted_type; + + assert(wanted_scalar_type->id == ZigTypeIdInt || wanted_scalar_type->id == ZigTypeIdFloat); if (instr_is_comptime(target)) { ZigValue *val = ir_resolve_const(ira, target, UndefBad); if (!val) return ira->codegen->invalid_inst_gen; - if (wanted_type->id == ZigTypeIdInt) { - if (bigint_cmp_zero(&val->data.x_bigint) == CmpLT && !wanted_type->data.integral.is_signed) { + + if (wanted_scalar_type->id == ZigTypeIdInt) { + if (!wanted_scalar_type->data.integral.is_signed && value_cmp_numeric_val_any(val, CmpLT, nullptr)) { ir_add_error(ira, source_instr, buf_sprintf("attempt to cast negative value to unsigned integer")); return ira->codegen->invalid_inst_gen; } - if (!bigint_fits_in_bits(&val->data.x_bigint, wanted_type->data.integral.bit_count, - wanted_type->data.integral.is_signed)) - { + if (!value_numeric_fits_in_type(val, wanted_scalar_type)) { ir_add_error(ira, source_instr, buf_sprintf("cast from '%s' to '%s' truncates bits", - buf_ptr(&target->value->type->name), buf_ptr(&wanted_type->name))); + buf_ptr(&target->value->type->name), buf_ptr(&wanted_scalar_type->name))); return ira->codegen->invalid_inst_gen; } } + IrInstGen *result = ir_const(ira, source_instr, wanted_type); result->value->type = wanted_type; - if (wanted_type->id == ZigTypeIdInt) { - bigint_init_bigint(&result->value->data.x_bigint, &val->data.x_bigint); + + if (wanted_type->id == ZigTypeIdVector) { + result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate<ZigValue>(wanted_type->data.vector.len); + + for (size_t i = 0; i < wanted_type->data.vector.len; i++) { + ZigValue *scalar_dest_value = &result->value->data.x_array.data.s_none.elements[i]; + ZigValue *scalar_src_value = &val->data.x_array.data.s_none.elements[i]; + + scalar_dest_value->type = wanted_scalar_type; + scalar_dest_value->special = ConstValSpecialStatic; + + if (wanted_scalar_type->id == ZigTypeIdInt) { + bigint_init_bigint(&scalar_dest_value->data.x_bigint, &scalar_src_value->data.x_bigint); + } else { + float_init_float(scalar_dest_value, scalar_src_value); + } + } } else { - float_init_float(result->value, val); + if (wanted_type->id == ZigTypeIdInt) { + bigint_init_bigint(&result->value->data.x_bigint, &val->data.x_bigint); + } else { + float_init_float(result->value, val); + } } + return result; } @@ -14761,6 +14809,8 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa actual_signed, actual_type->data.integral.bit_count)); break; } + case ConstCastResultIdVectorLength: // TODO + case ConstCastResultIdVectorChild: // TODO case ConstCastResultIdFnAlign: // TODO case ConstCastResultIdFnVarArgs: // TODO case ConstCastResultIdFnReturnType: // TODO @@ -15444,12 +15494,35 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr, } // @Vector(N,T1) to @Vector(N,T2) - if (actual_type->id == ZigTypeIdVector && wanted_type->id == ZigTypeIdVector) { - if (actual_type->data.vector.len == wanted_type->data.vector.len && - types_match_const_cast_only(ira, wanted_type->data.vector.elem_type, - actual_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) + if (actual_type->id == ZigTypeIdVector && wanted_type->id == ZigTypeIdVector && + actual_type->data.vector.len == wanted_type->data.vector.len) + { + ZigType *scalar_actual_type = actual_type->data.vector.elem_type; + ZigType *scalar_wanted_type = wanted_type->data.vector.elem_type; + + // widening conversion + if (scalar_wanted_type->id == ZigTypeIdInt && + scalar_actual_type->id == ZigTypeIdInt && + scalar_wanted_type->data.integral.is_signed == scalar_actual_type->data.integral.is_signed && + scalar_wanted_type->data.integral.bit_count >= scalar_actual_type->data.integral.bit_count) + { + return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); + } + + // small enough unsigned ints can get casted to large enough signed ints + if (scalar_wanted_type->id == ZigTypeIdInt && scalar_wanted_type->data.integral.is_signed && + scalar_actual_type->id == ZigTypeIdInt && !scalar_actual_type->data.integral.is_signed && + scalar_wanted_type->data.integral.bit_count > scalar_actual_type->data.integral.bit_count) + { + return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); + } + + // float widening conversion + if (scalar_wanted_type->id == ZigTypeIdFloat && + scalar_actual_type->id == ZigTypeIdFloat && + scalar_wanted_type->data.floating.bit_count >= scalar_actual_type->data.floating.bit_count) { - return ir_analyze_bit_cast(ira, source_instr, value, wanted_type); + return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); } } @@ -17710,6 +17783,33 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) { zig_unreachable(); } +// Returns true if integer `value` can be converted to `type_entry` without +// losing data. +// If `value` is a vector the function returns true if this is valid for every +// element. +static bool value_numeric_fits_in_type(ZigValue *value, ZigType *type_entry) { + assert(value->special == ConstValSpecialStatic); + assert(type_entry->id == ZigTypeIdInt); + + switch (value->type->id) { + case ZigTypeIdComptimeInt: + case ZigTypeIdInt: { + return bigint_fits_in_bits(&value->data.x_bigint, type_entry->data.integral.bit_count, + type_entry->data.integral.is_signed); + } + case ZigTypeIdVector: { + for (size_t i = 0; i < value->type->data.vector.len; i++) { + ZigValue *scalar_value = &value->data.x_array.data.s_none.elements[i]; + const bool result = bigint_fits_in_bits(&scalar_value->data.x_bigint, + type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); + if (!result) return false; + } + return true; + } + default: zig_unreachable(); + } +} + static bool value_cmp_numeric_val(ZigValue *left, Cmp predicate, ZigValue *right, bool any) { assert(left->special == ConstValSpecialStatic); assert(right == nullptr || right->special == ConstValSpecialStatic); @@ -27132,8 +27232,12 @@ static IrInstGen *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstSrcIntCa if (type_is_invalid(dest_type)) return ira->codegen->invalid_inst_gen; - if (dest_type->id != ZigTypeIdInt && dest_type->id != ZigTypeIdComptimeInt) { - ir_add_error(ira, &instruction->dest_type->base, buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); + ZigType *scalar_dest_type = (dest_type->id == ZigTypeIdVector) ? + dest_type->data.vector.elem_type : dest_type; + + if (scalar_dest_type->id != ZigTypeIdInt && scalar_dest_type->id != ZigTypeIdComptimeInt) { + ir_add_error(ira, &instruction->dest_type->base, + buf_sprintf("expected integer type, found '%s'", buf_ptr(&scalar_dest_type->name))); return ira->codegen->invalid_inst_gen; } @@ -27141,13 +27245,16 @@ static IrInstGen *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstSrcIntCa if (type_is_invalid(target->value->type)) return ira->codegen->invalid_inst_gen; - if (target->value->type->id != ZigTypeIdInt && target->value->type->id != ZigTypeIdComptimeInt) { + ZigType *scalar_target_type = (target->value->type->id == ZigTypeIdVector) ? + target->value->type->data.vector.elem_type : target->value->type; + + if (scalar_target_type->id != ZigTypeIdInt && scalar_target_type->id != ZigTypeIdComptimeInt) { ir_add_error(ira, &instruction->target->base, buf_sprintf("expected integer type, found '%s'", - buf_ptr(&target->value->type->name))); + buf_ptr(&scalar_target_type->name))); return ira->codegen->invalid_inst_gen; } - if (instr_is_comptime(target) || dest_type->id == ZigTypeIdComptimeInt) { + if (scalar_dest_type->id == ZigTypeIdComptimeInt) { ZigValue *val = ir_resolve_const(ira, target, UndefBad); if (val == nullptr) return ira->codegen->invalid_inst_gen; @@ -27200,6 +27307,7 @@ static IrInstGen *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstSrcFlo if (val == nullptr) return ira->codegen->invalid_inst_gen; + // XXX: This will trigger an assertion failure if dest_type is comptime_float return ir_analyze_widen_or_shorten(ira, &instruction->target->base, target, dest_type); } |
