authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-07 18:45:28-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-07 18:45:28-07:00
log9d29674711dc4d1b11d4efdad8d0f5a40f56d673
tree4f4808cc82e64e2c3696b76b243abb837bf3bc62
parent9e0165147e18ffb36bcaf09112c72f4cb397d563

ability to cast slice to u8 slice


6 files changed, 84 insertions(+), 8 deletions(-)

src/all_types.hpp+1
......@@ -382,6 +382,7 @@ enum CastOp {
382382 CastOpIntToFloat,
383383 CastOpFloatToInt,
384384 CastOpBoolToInt,
385 CastOpResizeSlice,
385386};
386387
387388struct AstNodeFnCallExpr {
src/analyze.cpp+30-8
......@@ -219,6 +219,23 @@ static bool type_is_complete(TypeTableEntry *type_entry) {
219219 zig_unreachable();
220220}
221221
222uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
223 if (type_has_bits(type_entry)) {
224 return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
225 } else {
226 return 0;
227 }
228}
229
230static bool is_u8(TypeTableEntry *type) {
231 return type->id == TypeTableEntryIdInt &&
232 !type->data.integral.is_signed && type->data.integral.bit_count == 8;
233}
234
235static bool is_slice(TypeTableEntry *type) {
236 return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice;
237}
238
222239TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
223240 return get_int_type(g, false, false, bits_needed_for_unsigned(x));
224241}
......@@ -4215,8 +4232,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
42154232 }
42164233
42174234 // explicit cast from array to slice
4218 if (wanted_type->id == TypeTableEntryIdStruct &&
4219 wanted_type->data.structure.is_slice &&
4235 if (is_slice(wanted_type) &&
42204236 actual_type->id == TypeTableEntryIdArray &&
42214237 types_match_const_cast_only(
42224238 wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type,
......@@ -4225,6 +4241,17 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
42254241 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpToUnknownSizeArray, true);
42264242 }
42274243
4244 // explicit cast from []T to []u8
4245 if (is_slice(wanted_type) &&
4246 is_u8(wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type) &&
4247 is_slice(actual_type) &&
4248 (wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
4249 !actual_type->data.structure.fields[0].type_entry->data.pointer.is_const))
4250 {
4251 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true);
4252 }
4253
4254
42284255 // explicit cast from pointer to another pointer
42294256 if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
42304257 (wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
......@@ -4757,12 +4784,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
47574784 buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
47584785 return g->builtin_types.entry_invalid;
47594786 } else {
4760 uint64_t size_in_bytes;
4761 if (type_has_bits(type_entry)) {
4762 size_in_bytes = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
4763 } else {
4764 size_in_bytes = 0;
4765 }
4787 uint64_t size_in_bytes = type_size(g, type_entry);
47664788 return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, size_in_bytes);
47674789 }
47684790 }
src/analyze.hpp+1
......@@ -18,6 +18,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
1818BlockContext *new_block_context(AstNode *node, BlockContext *parent);
1919Expr *get_resolved_expr(AstNode *node);
2020bool is_node_void_expr(AstNode *node);
21uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
2122TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits);
2223TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits);
2324TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
src/codegen.cpp+37
......@@ -860,6 +860,43 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
860860 actual_type->data.array.len, false);
861861 LLVMBuildStore(g->builder, len_val, len_ptr);
862862
863 return cast_expr->tmp_ptr;
864 }
865 case CastOpResizeSlice:
866 {
867 assert(cast_expr->tmp_ptr);
868 assert(wanted_type->id == TypeTableEntryIdStruct);
869 assert(wanted_type->data.structure.is_slice);
870 assert(actual_type->id == TypeTableEntryIdStruct);
871 assert(actual_type->data.structure.is_slice);
872
873 TypeTableEntry *actual_pointer_type = actual_type->data.structure.fields[0].type_entry;
874 TypeTableEntry *actual_child_type = actual_pointer_type->data.pointer.child_type;
875
876 set_debug_source_node(g, node);
877
878 int actual_ptr_index = actual_type->data.structure.fields[0].gen_index;
879 int actual_len_index = actual_type->data.structure.fields[1].gen_index;
880 int wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index;
881 int wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
882
883 LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_len_index, "");
884 LLVMValueRef src_len = LLVMBuildLoad(g->builder, src_len_ptr, "");
885 LLVMValueRef src_size = LLVMConstInt(g->builtin_types.entry_isize->type_ref,
886 type_size(g, actual_child_type), false);
887 LLVMValueRef new_len = LLVMBuildMul(g->builder, src_len, src_size, "");
888 LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr,
889 wanted_len_index, "");
890 LLVMBuildStore(g->builder, new_len, dest_len_ptr);
891
892 LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_ptr_index, "");
893 LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, "");
894 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr,
895 wanted_type->data.structure.fields[0].type_entry->type_ref, "");
896 LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr,
897 wanted_ptr_index, "");
898 LLVMBuildStore(g->builder, src_ptr_casted, dest_ptr_ptr);
899
863900 return cast_expr->tmp_ptr;
864901 }
865902 case CastOpIntToFloat:
src/eval.cpp+1
......@@ -600,6 +600,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
600600 break;
601601 case CastOpPtrToInt:
602602 case CastOpIntToPtr:
603 case CastOpResizeSlice:
603604 // can't do it
604605 break;
605606 case CastOpToUnknownSizeArray:
test/self_hosted.zig+14
......@@ -1580,3 +1580,17 @@ struct GenNode(T: type) {
15801580 next: ?&GenNode(T),
15811581 fn get_val(n: &const GenNode(T)) -> T { n.value }
15821582}
1583
1584#attribute("test")
1585fn cast_slice_to_u8_slice() {
1586 assert(@sizeof(i32) == 4);
1587 var big_thing_array = []i32{1, 2, 3, 4};
1588 const big_thing_slice: []i32 = big_thing_array;
1589 const bytes = ([]u8)(big_thing_slice);
1590 assert(bytes.len == 4 * 4);
1591 bytes[4] = 0;
1592 bytes[5] = 0;
1593 bytes[6] = 0;
1594 bytes[7] = 0;
1595 assert(big_thing_slice[1] == 0);
1596}