| author | |
| committer | |
| log | 09588c795c08064971f61ee147d06972f0add94e |
| tree | d7d2af6503aea7aa499c1a5eabf3c2f5a3591d3a |
| parent | 68fe391de02fd4c99f39bd6e0af643e1e327e52a |
Also support `one` and `int_big_positive` tags for const pointers.5 files changed, 52 insertions(+), 11 deletions(-)
src/codegen/c.zig+5-3| ... | ... | @@ -279,7 +279,7 @@ pub const DeclGen = struct { |
| 279 | 279 | ty: Type, |
| 280 | 280 | val: Value, |
| 281 | 281 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 282 | if (val.isUndef()) { | |
| 282 | if (val.isUndefDeep()) { | |
| 283 | 283 | switch (ty.zigTypeTag()) { |
| 284 | 284 | // Using '{}' for integer and floats seemed to error C compilers (both GCC and Clang) |
| 285 | 285 | // with 'error: expected expression' (including when built with 'zig cc') |
| ... | ... | @@ -1049,7 +1049,7 @@ pub fn genDecl(o: *Object) !void { |
| 1049 | 1049 | } |
| 1050 | 1050 | try fwd_decl_writer.writeAll(";\n"); |
| 1051 | 1051 | |
| 1052 | if (variable.init.isUndef()) { | |
| 1052 | if (variable.init.isUndefDeep()) { | |
| 1053 | 1053 | return; |
| 1054 | 1054 | } |
| 1055 | 1055 | |
| ... | ... | @@ -1602,8 +1602,10 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1602 | 1602 | const src_val = try f.resolveInst(bin_op.rhs); |
| 1603 | 1603 | const lhs_type = f.air.typeOf(bin_op.lhs); |
| 1604 | 1604 | |
| 1605 | // TODO Sema should emit a different instruction when the store should | |
| 1606 | // possibly do the safety 0xaa bytes for undefined. | |
| 1605 | 1607 | const src_val_is_undefined = |
| 1606 | if (f.air.value(bin_op.rhs)) |v| v.isUndef() else false; | |
| 1608 | if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; | |
| 1607 | 1609 | if (src_val_is_undefined) |
| 1608 | 1610 | return try airStoreUndefined(f, dest_ptr, lhs_type); |
| 1609 | 1611 |
src/codegen/llvm.zig+26-4| ... | ... | @@ -1078,7 +1078,7 @@ pub const DeclGen = struct { |
| 1078 | 1078 | }; |
| 1079 | 1079 | return self.context.constStruct(&fields, fields.len, .False); |
| 1080 | 1080 | }, |
| 1081 | .int_u64 => { | |
| 1081 | .int_u64, .one, .int_big_positive => { | |
| 1082 | 1082 | const llvm_usize = try self.llvmType(Type.usize); |
| 1083 | 1083 | const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False); |
| 1084 | 1084 | return llvm_int.constIntToPtr(try self.llvmType(tv.ty)); |
| ... | ... | @@ -3464,8 +3464,30 @@ pub const FuncGen = struct { |
| 3464 | 3464 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 3465 | 3465 | const dest_ptr = try self.resolveInst(bin_op.lhs); |
| 3466 | 3466 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 3467 | const src_operand = try self.resolveInst(bin_op.rhs); | |
| 3468 | self.store(dest_ptr, ptr_ty, src_operand, .NotAtomic); | |
| 3467 | ||
| 3468 | // TODO Sema should emit a different instruction when the store should | |
| 3469 | // possibly do the safety 0xaa bytes for undefined. | |
| 3470 | const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false; | |
| 3471 | if (val_is_undef) { | |
| 3472 | const elem_ty = ptr_ty.childType(); | |
| 3473 | const target = self.dg.module.getTarget(); | |
| 3474 | const elem_size = elem_ty.abiSize(target); | |
| 3475 | const u8_llvm_ty = self.context.intType(8); | |
| 3476 | const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0); | |
| 3477 | const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, ""); | |
| 3478 | const fill_char = u8_llvm_ty.constInt(0xaa, .False); | |
| 3479 | const dest_ptr_align = ptr_ty.ptrAlignment(target); | |
| 3480 | const usize_llvm_ty = try self.dg.llvmType(Type.usize); | |
| 3481 | const len = usize_llvm_ty.constInt(elem_size, .False); | |
| 3482 | _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr()); | |
| 3483 | if (self.dg.module.comp.bin_file.options.valgrind) { | |
| 3484 | // TODO generate valgrind client request to mark byte range as undefined | |
| 3485 | // see gen_valgrind_undef() in codegen.cpp | |
| 3486 | } | |
| 3487 | } else { | |
| 3488 | const src_operand = try self.resolveInst(bin_op.rhs); | |
| 3489 | self.store(dest_ptr, ptr_ty, src_operand, .NotAtomic); | |
| 3490 | } | |
| 3469 | 3491 | return null; |
| 3470 | 3492 | } |
| 3471 | 3493 | |
| ... | ... | @@ -3651,7 +3673,7 @@ pub const FuncGen = struct { |
| 3651 | 3673 | const dest_ptr = try self.resolveInst(pl_op.operand); |
| 3652 | 3674 | const ptr_ty = self.air.typeOf(pl_op.operand); |
| 3653 | 3675 | const value = try self.resolveInst(extra.lhs); |
| 3654 | const val_is_undef = if (self.air.value(extra.lhs)) |val| val.isUndef() else false; | |
| 3676 | const val_is_undef = if (self.air.value(extra.lhs)) |val| val.isUndefDeep() else false; | |
| 3655 | 3677 | const len = try self.resolveInst(extra.rhs); |
| 3656 | 3678 | const u8_llvm_ty = self.context.intType(8); |
| 3657 | 3679 | const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0); |
src/value.zig+7| ... | ... | @@ -1802,6 +1802,13 @@ pub const Value = extern union { |
| 1802 | 1802 | return self.tag() == .undef; |
| 1803 | 1803 | } |
| 1804 | 1804 | |
| 1805 | /// TODO: check for cases such as array that is not marked undef but all the element | |
| 1806 | /// values are marked undef, or struct that is not marked undef but all fields are marked | |
| 1807 | /// undef, etc. | |
| 1808 | pub fn isUndefDeep(self: Value) bool { | |
| 1809 | return self.isUndef(); | |
| 1810 | } | |
| 1811 | ||
| 1805 | 1812 | /// Asserts the value is not undefined and not unreachable. |
| 1806 | 1813 | /// Integer value 0 is considered null because of C pointers. |
| 1807 | 1814 | pub fn isNull(self: Value) bool { |
test/behavior/cast.zig+7-2| ... | ... | @@ -251,8 +251,13 @@ test "*const ?[*]const T to [*c]const [*c]const T" { |
| 251 | 251 | test "array coersion to undefined at runtime" { |
| 252 | 252 | @setRuntimeSafety(true); |
| 253 | 253 | |
| 254 | // setRuntimeSafety isn't recognized on stage2 | |
| 255 | if (@import("builtin").zig_is_stage2 and @import("builtin").mode != .Debug and @import("builtin").mode != .ReleaseSafe) return error.SkipZigTest; | |
| 254 | // TODO implement @setRuntimeSafety in stage2 | |
| 255 | if (@import("builtin").zig_is_stage2 and | |
| 256 | @import("builtin").mode != .Debug and | |
| 257 | @import("builtin").mode != .ReleaseSafe) | |
| 258 | { | |
| 259 | return error.SkipZigTest; | |
| 260 | } | |
| 256 | 261 | |
| 257 | 262 | var array = [4]u8{ 3, 4, 5, 6 }; |
| 258 | 263 | var undefined_val = [4]u8{ 0xAA, 0xAA, 0xAA, 0xAA }; |
test/behavior/int128.zig+7-2| ... | ... | @@ -20,8 +20,13 @@ test "uint128" { |
| 20 | 20 | test "undefined 128 bit int" { |
| 21 | 21 | @setRuntimeSafety(true); |
| 22 | 22 | |
| 23 | // setRuntimeSafety isn't recognized on stage2 | |
| 24 | if (@import("builtin").zig_is_stage2 and @import("builtin").mode != .Debug and @import("builtin").mode != .ReleaseSafe) return error.SkipZigTest; | |
| 23 | // TODO implement @setRuntimeSafety in stage2 | |
| 24 | if (@import("builtin").zig_is_stage2 and | |
| 25 | @import("builtin").mode != .Debug and | |
| 26 | @import("builtin").mode != .ReleaseSafe) | |
| 27 | { | |
| 28 | return error.SkipZigTest; | |
| 29 | } | |
| 25 | 30 | |
| 26 | 31 | var undef: u128 = undefined; |
| 27 | 32 | var undef_signed: i128 = undefined; |