| author | |
| committer | |
| log | c4ab8d9e12afbe07fc5b3cc4535a9fa2cfcad94d |
| tree | 87b00360b19a327864f09cfe12289650eb50650d |
| parent | 1cdc51ec1012bc2a6d1c115eaaeb24a2a93c26c5 |
| parent | 3871d5e55a6d52bacadd80163540a171e014605f |
| signature |
Stage2 bit_shifting.zig passing7 files changed, 171 insertions(+), 42 deletions(-)
src/Module.zig+42-1| ... | @@ -831,6 +831,10 @@ pub const Struct = struct { | ... | @@ -831,6 +831,10 @@ pub const Struct = struct { |
| 831 | have_field_types, | 831 | have_field_types, |
| 832 | layout_wip, | 832 | layout_wip, |
| 833 | have_layout, | 833 | have_layout, |
| 834 | fully_resolved_wip, | ||
| 835 | // The types and all its fields have had their layout resolved. Even through pointer, | ||
| 836 | // which `have_layout` does not ensure. | ||
| 837 | fully_resolved, | ||
| 834 | }, | 838 | }, |
| 835 | /// If true, definitely nonzero size at runtime. If false, resolving the fields | 839 | /// If true, definitely nonzero size at runtime. If false, resolving the fields |
| 836 | /// is necessary to determine whether it has bits at runtime. | 840 | /// is necessary to determine whether it has bits at runtime. |
| ... | @@ -889,6 +893,22 @@ pub const Struct = struct { | ... | @@ -889,6 +893,22 @@ pub const Struct = struct { |
| 889 | .have_field_types, | 893 | .have_field_types, |
| 890 | .layout_wip, | 894 | .layout_wip, |
| 891 | .have_layout, | 895 | .have_layout, |
| 896 | .fully_resolved_wip, | ||
| 897 | .fully_resolved, | ||
| 898 | => true, | ||
| 899 | }; | ||
| 900 | } | ||
| 901 | |||
| 902 | pub fn haveLayout(s: Struct) bool { | ||
| 903 | return switch (s.status) { | ||
| 904 | .none, | ||
| 905 | .field_types_wip, | ||
| 906 | .have_field_types, | ||
| 907 | .layout_wip, | ||
| 908 | => false, | ||
| 909 | .have_layout, | ||
| 910 | .fully_resolved_wip, | ||
| 911 | .fully_resolved, | ||
| 892 | => true, | 912 | => true, |
| 893 | }; | 913 | }; |
| 894 | } | 914 | } |
| ... | @@ -1003,6 +1023,10 @@ pub const Union = struct { | ... | @@ -1003,6 +1023,10 @@ pub const Union = struct { |
| 1003 | have_field_types, | 1023 | have_field_types, |
| 1004 | layout_wip, | 1024 | layout_wip, |
| 1005 | have_layout, | 1025 | have_layout, |
| 1026 | fully_resolved_wip, | ||
| 1027 | // The types and all its fields have had their layout resolved. Even through pointer, | ||
| 1028 | // which `have_layout` does not ensure. | ||
| 1029 | fully_resolved, | ||
| 1006 | }, | 1030 | }, |
| 1007 | 1031 | ||
| 1008 | pub const Field = struct { | 1032 | pub const Field = struct { |
| ... | @@ -1033,6 +1057,8 @@ pub const Union = struct { | ... | @@ -1033,6 +1057,8 @@ pub const Union = struct { |
| 1033 | .have_field_types, | 1057 | .have_field_types, |
| 1034 | .layout_wip, | 1058 | .layout_wip, |
| 1035 | .have_layout, | 1059 | .have_layout, |
| 1060 | .fully_resolved_wip, | ||
| 1061 | .fully_resolved, | ||
| 1036 | => true, | 1062 | => true, |
| 1037 | }; | 1063 | }; |
| 1038 | } | 1064 | } |
| ... | @@ -1102,8 +1128,22 @@ pub const Union = struct { | ... | @@ -1102,8 +1128,22 @@ pub const Union = struct { |
| 1102 | tag_size: u64, | 1128 | tag_size: u64, |
| 1103 | }; | 1129 | }; |
| 1104 | 1130 | ||
| 1131 | pub fn haveLayout(u: Union) bool { | ||
| 1132 | return switch (u.status) { | ||
| 1133 | .none, | ||
| 1134 | .field_types_wip, | ||
| 1135 | .have_field_types, | ||
| 1136 | .layout_wip, | ||
| 1137 | => false, | ||
| 1138 | .have_layout, | ||
| 1139 | .fully_resolved_wip, | ||
| 1140 | .fully_resolved, | ||
| 1141 | => true, | ||
| 1142 | }; | ||
| 1143 | } | ||
| 1144 | |||
| 1105 | pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout { | 1145 | pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout { |
| 1106 | assert(u.status == .have_layout); | 1146 | assert(u.haveLayout()); |
| 1107 | var most_aligned_field: u32 = undefined; | 1147 | var most_aligned_field: u32 = undefined; |
| 1108 | var most_aligned_field_size: u64 = undefined; | 1148 | var most_aligned_field_size: u64 = undefined; |
| 1109 | var biggest_field: u32 = undefined; | 1149 | var biggest_field: u32 = undefined; |
| ... | @@ -4397,6 +4437,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem | ... | @@ -4397,6 +4437,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem |
| 4397 | const arg = try sema.addConstant(param_type, opv); | 4437 | const arg = try sema.addConstant(param_type, opv); |
| 4398 | sema.inst_map.putAssumeCapacityNoClobber(inst, arg); | 4438 | sema.inst_map.putAssumeCapacityNoClobber(inst, arg); |
| 4399 | total_param_index += 1; | 4439 | total_param_index += 1; |
| 4440 | runtime_param_index += 1; | ||
| 4400 | continue; | 4441 | continue; |
| 4401 | } | 4442 | } |
| 4402 | const ty_ref = try sema.addType(param_type); | 4443 | const ty_ref = try sema.addType(param_type); |
src/Sema.zig+80-17| ... | @@ -4503,14 +4503,14 @@ fn analyzeCall( | ... | @@ -4503,14 +4503,14 @@ fn analyzeCall( |
| 4503 | const arg_src = call_src; // TODO: better source location | 4503 | const arg_src = call_src; // TODO: better source location |
| 4504 | if (i < fn_params_len) { | 4504 | if (i < fn_params_len) { |
| 4505 | const param_ty = func_ty.fnParamType(i); | 4505 | const param_ty = func_ty.fnParamType(i); |
| 4506 | try sema.resolveTypeForCodegen(block, arg_src, param_ty); | 4506 | try sema.resolveTypeFully(block, arg_src, param_ty); |
| 4507 | args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src); | 4507 | args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| 4508 | } else { | 4508 | } else { |
| 4509 | args[i] = uncasted_arg; | 4509 | args[i] = uncasted_arg; |
| 4510 | } | 4510 | } |
| 4511 | } | 4511 | } |
| 4512 | 4512 | ||
| 4513 | try sema.resolveTypeForCodegen(block, call_src, func_ty_info.return_type); | 4513 | try sema.resolveTypeFully(block, call_src, func_ty_info.return_type); |
| 4514 | 4514 | ||
| 4515 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len + | 4515 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 4516 | args.len); | 4516 | args.len); |
| ... | @@ -4580,7 +4580,7 @@ fn finishGenericCall( | ... | @@ -4580,7 +4580,7 @@ fn finishGenericCall( |
| 4580 | const param_ty = new_fn_ty.fnParamType(runtime_i); | 4580 | const param_ty = new_fn_ty.fnParamType(runtime_i); |
| 4581 | const arg_src = call_src; // TODO: better source location | 4581 | const arg_src = call_src; // TODO: better source location |
| 4582 | const uncasted_arg = uncasted_args[total_i]; | 4582 | const uncasted_arg = uncasted_args[total_i]; |
| 4583 | try sema.resolveTypeForCodegen(block, arg_src, param_ty); | 4583 | try sema.resolveTypeFully(block, arg_src, param_ty); |
| 4584 | const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); | 4584 | const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| 4585 | runtime_args[runtime_i] = casted_arg; | 4585 | runtime_args[runtime_i] = casted_arg; |
| 4586 | runtime_i += 1; | 4586 | runtime_i += 1; |
| ... | @@ -4588,7 +4588,7 @@ fn finishGenericCall( | ... | @@ -4588,7 +4588,7 @@ fn finishGenericCall( |
| 4588 | total_i += 1; | 4588 | total_i += 1; |
| 4589 | } | 4589 | } |
| 4590 | 4590 | ||
| 4591 | try sema.resolveTypeForCodegen(block, call_src, new_fn_ty.fnReturnType()); | 4591 | try sema.resolveTypeFully(block, call_src, new_fn_ty.fnReturnType()); |
| 4592 | } | 4592 | } |
| 4593 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + | 4593 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 4594 | runtime_args_len); | 4594 | runtime_args_len); |
| ... | @@ -7318,8 +7318,8 @@ fn zirShr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -7318,8 +7318,8 @@ fn zirShr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 7318 | const lhs = sema.resolveInst(extra.lhs); | 7318 | const lhs = sema.resolveInst(extra.lhs); |
| 7319 | const rhs = sema.resolveInst(extra.rhs); | 7319 | const rhs = sema.resolveInst(extra.rhs); |
| 7320 | 7320 | ||
| 7321 | if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { | 7321 | if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| { |
| 7322 | if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| { | 7322 | if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { |
| 7323 | const lhs_ty = sema.typeOf(lhs); | 7323 | const lhs_ty = sema.typeOf(lhs); |
| 7324 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | 7324 | if (lhs_val.isUndef() or rhs_val.isUndef()) { |
| 7325 | return sema.addConstUndef(lhs_ty); | 7325 | return sema.addConstUndef(lhs_ty); |
| ... | @@ -7331,6 +7331,12 @@ fn zirShr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -7331,6 +7331,12 @@ fn zirShr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 7331 | const val = try lhs_val.shr(rhs_val, sema.arena); | 7331 | const val = try lhs_val.shr(rhs_val, sema.arena); |
| 7332 | return sema.addConstant(lhs_ty, val); | 7332 | return sema.addConstant(lhs_ty, val); |
| 7333 | } | 7333 | } |
| 7334 | // Even if lhs is not comptime known, we can still deduce certain things based | ||
| 7335 | // on rhs. | ||
| 7336 | // If rhs is 0, return lhs without doing any calculations. | ||
| 7337 | else if (rhs_val.compareWithZero(.eq)) { | ||
| 7338 | return lhs; | ||
| 7339 | } | ||
| 7334 | } | 7340 | } |
| 7335 | 7341 | ||
| 7336 | try sema.requireRuntimeBlock(block, src); | 7342 | try sema.requireRuntimeBlock(block, src); |
| ... | @@ -15222,7 +15228,7 @@ fn resolveStructLayout( | ... | @@ -15222,7 +15228,7 @@ fn resolveStructLayout( |
| 15222 | .field_types_wip, .layout_wip => { | 15228 | .field_types_wip, .layout_wip => { |
| 15223 | return sema.fail(block, src, "struct {} depends on itself", .{ty}); | 15229 | return sema.fail(block, src, "struct {} depends on itself", .{ty}); |
| 15224 | }, | 15230 | }, |
| 15225 | .have_layout => return, | 15231 | .have_layout, .fully_resolved_wip, .fully_resolved => return, |
| 15226 | } | 15232 | } |
| 15227 | struct_obj.status = .layout_wip; | 15233 | struct_obj.status = .layout_wip; |
| 15228 | for (struct_obj.fields.values()) |field| { | 15234 | for (struct_obj.fields.values()) |field| { |
| ... | @@ -15244,7 +15250,7 @@ fn resolveUnionLayout( | ... | @@ -15244,7 +15250,7 @@ fn resolveUnionLayout( |
| 15244 | .field_types_wip, .layout_wip => { | 15250 | .field_types_wip, .layout_wip => { |
| 15245 | return sema.fail(block, src, "union {} depends on itself", .{ty}); | 15251 | return sema.fail(block, src, "union {} depends on itself", .{ty}); |
| 15246 | }, | 15252 | }, |
| 15247 | .have_layout => return, | 15253 | .have_layout, .fully_resolved_wip, .fully_resolved => return, |
| 15248 | } | 15254 | } |
| 15249 | union_obj.status = .layout_wip; | 15255 | union_obj.status = .layout_wip; |
| 15250 | for (union_obj.fields.values()) |field| { | 15256 | for (union_obj.fields.values()) |field| { |
| ... | @@ -15253,7 +15259,7 @@ fn resolveUnionLayout( | ... | @@ -15253,7 +15259,7 @@ fn resolveUnionLayout( |
| 15253 | union_obj.status = .have_layout; | 15259 | union_obj.status = .have_layout; |
| 15254 | } | 15260 | } |
| 15255 | 15261 | ||
| 15256 | fn resolveTypeForCodegen( | 15262 | fn resolveTypeFully( |
| 15257 | sema: *Sema, | 15263 | sema: *Sema, |
| 15258 | block: *Block, | 15264 | block: *Block, |
| 15259 | src: LazySrcLoc, | 15265 | src: LazySrcLoc, |
| ... | @@ -15262,20 +15268,67 @@ fn resolveTypeForCodegen( | ... | @@ -15262,20 +15268,67 @@ fn resolveTypeForCodegen( |
| 15262 | switch (ty.zigTypeTag()) { | 15268 | switch (ty.zigTypeTag()) { |
| 15263 | .Pointer => { | 15269 | .Pointer => { |
| 15264 | const child_ty = try sema.resolveTypeFields(block, src, ty.childType()); | 15270 | const child_ty = try sema.resolveTypeFields(block, src, ty.childType()); |
| 15265 | return resolveTypeForCodegen(sema, block, src, child_ty); | 15271 | return resolveTypeFully(sema, block, src, child_ty); |
| 15266 | }, | 15272 | }, |
| 15267 | .Struct => return resolveStructLayout(sema, block, src, ty), | 15273 | .Struct => return resolveStructFully(sema, block, src, ty), |
| 15268 | .Union => return resolveUnionLayout(sema, block, src, ty), | 15274 | .Union => return resolveUnionFully(sema, block, src, ty), |
| 15269 | .Array => return resolveTypeForCodegen(sema, block, src, ty.childType()), | 15275 | .Array => return resolveTypeFully(sema, block, src, ty.childType()), |
| 15270 | .Optional => { | 15276 | .Optional => { |
| 15271 | var buf: Type.Payload.ElemType = undefined; | 15277 | var buf: Type.Payload.ElemType = undefined; |
| 15272 | return resolveTypeForCodegen(sema, block, src, ty.optionalChild(&buf)); | 15278 | return resolveTypeFully(sema, block, src, ty.optionalChild(&buf)); |
| 15273 | }, | 15279 | }, |
| 15274 | .ErrorUnion => return resolveTypeForCodegen(sema, block, src, ty.errorUnionPayload()), | 15280 | .ErrorUnion => return resolveTypeFully(sema, block, src, ty.errorUnionPayload()), |
| 15275 | else => {}, | 15281 | else => {}, |
| 15276 | } | 15282 | } |
| 15277 | } | 15283 | } |
| 15278 | 15284 | ||
| 15285 | fn resolveStructFully( | ||
| 15286 | sema: *Sema, | ||
| 15287 | block: *Block, | ||
| 15288 | src: LazySrcLoc, | ||
| 15289 | ty: Type, | ||
| 15290 | ) CompileError!void { | ||
| 15291 | try resolveStructLayout(sema, block, src, ty); | ||
| 15292 | |||
| 15293 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); | ||
| 15294 | const struct_obj = resolved_ty.castTag(.@"struct").?.data; | ||
| 15295 | switch (struct_obj.status) { | ||
| 15296 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, | ||
| 15297 | .fully_resolved_wip, .fully_resolved => return, | ||
| 15298 | } | ||
| 15299 | |||
| 15300 | // After we have resolve struct layout we have to go over the fields again to | ||
| 15301 | // make sure pointer fields get their child types resolved as well | ||
| 15302 | struct_obj.status = .fully_resolved_wip; | ||
| 15303 | for (struct_obj.fields.values()) |field| { | ||
| 15304 | try sema.resolveTypeFully(block, src, field.ty); | ||
| 15305 | } | ||
| 15306 | struct_obj.status = .fully_resolved; | ||
| 15307 | } | ||
| 15308 | |||
| 15309 | fn resolveUnionFully( | ||
| 15310 | sema: *Sema, | ||
| 15311 | block: *Block, | ||
| 15312 | src: LazySrcLoc, | ||
| 15313 | ty: Type, | ||
| 15314 | ) CompileError!void { | ||
| 15315 | try resolveUnionLayout(sema, block, src, ty); | ||
| 15316 | |||
| 15317 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); | ||
| 15318 | const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; | ||
| 15319 | switch (union_obj.status) { | ||
| 15320 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, | ||
| 15321 | .fully_resolved_wip, .fully_resolved => return, | ||
| 15322 | } | ||
| 15323 | |||
| 15324 | // Same goes for unions (see comment about structs) | ||
| 15325 | union_obj.status = .fully_resolved_wip; | ||
| 15326 | for (union_obj.fields.values()) |field| { | ||
| 15327 | try sema.resolveTypeFully(block, src, field.ty); | ||
| 15328 | } | ||
| 15329 | union_obj.status = .fully_resolved; | ||
| 15330 | } | ||
| 15331 | |||
| 15279 | fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type { | 15332 | fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type { |
| 15280 | switch (ty.tag()) { | 15333 | switch (ty.tag()) { |
| 15281 | .@"struct" => { | 15334 | .@"struct" => { |
| ... | @@ -15285,7 +15338,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp | ... | @@ -15285,7 +15338,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp |
| 15285 | .field_types_wip => { | 15338 | .field_types_wip => { |
| 15286 | return sema.fail(block, src, "struct {} depends on itself", .{ty}); | 15339 | return sema.fail(block, src, "struct {} depends on itself", .{ty}); |
| 15287 | }, | 15340 | }, |
| 15288 | .have_field_types, .have_layout, .layout_wip => return ty, | 15341 | .have_field_types, |
| 15342 | .have_layout, | ||
| 15343 | .layout_wip, | ||
| 15344 | .fully_resolved_wip, | ||
| 15345 | .fully_resolved, | ||
| 15346 | => return ty, | ||
| 15289 | } | 15347 | } |
| 15290 | 15348 | ||
| 15291 | struct_obj.status = .field_types_wip; | 15349 | struct_obj.status = .field_types_wip; |
| ... | @@ -15318,7 +15376,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp | ... | @@ -15318,7 +15376,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp |
| 15318 | .field_types_wip => { | 15376 | .field_types_wip => { |
| 15319 | return sema.fail(block, src, "union {} depends on itself", .{ty}); | 15377 | return sema.fail(block, src, "union {} depends on itself", .{ty}); |
| 15320 | }, | 15378 | }, |
| 15321 | .have_field_types, .have_layout, .layout_wip => return ty, | 15379 | .have_field_types, |
| 15380 | .have_layout, | ||
| 15381 | .layout_wip, | ||
| 15382 | .fully_resolved_wip, | ||
| 15383 | .fully_resolved, | ||
| 15384 | => return ty, | ||
| 15322 | } | 15385 | } |
| 15323 | 15386 | ||
| 15324 | union_obj.status = .field_types_wip; | 15387 | union_obj.status = .field_types_wip; |
src/codegen/llvm.zig+35-19| ... | @@ -2647,7 +2647,7 @@ pub const FuncGen = struct { | ... | @@ -2647,7 +2647,7 @@ pub const FuncGen = struct { |
| 2647 | switch (struct_ty.zigTypeTag()) { | 2647 | switch (struct_ty.zigTypeTag()) { |
| 2648 | .Struct => { | 2648 | .Struct => { |
| 2649 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | 2649 | var ptr_ty_buf: Type.Payload.Pointer = undefined; |
| 2650 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf); | 2650 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?; |
| 2651 | const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, ""); | 2651 | const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, ""); |
| 2652 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); | 2652 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); |
| 2653 | return self.load(field_ptr, field_ptr_ty); | 2653 | return self.load(field_ptr, field_ptr_ty); |
| ... | @@ -4354,8 +4354,18 @@ pub const FuncGen = struct { | ... | @@ -4354,8 +4354,18 @@ pub const FuncGen = struct { |
| 4354 | .Struct => { | 4354 | .Struct => { |
| 4355 | const target = self.dg.module.getTarget(); | 4355 | const target = self.dg.module.getTarget(); |
| 4356 | var ty_buf: Type.Payload.Pointer = undefined; | 4356 | var ty_buf: Type.Payload.Pointer = undefined; |
| 4357 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ty_buf); | 4357 | if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| { |
| 4358 | return self.builder.buildStructGEP(struct_ptr, llvm_field_index, ""); | 4358 | return self.builder.buildStructGEP(struct_ptr, llvm_field_index, ""); |
| 4359 | } else { | ||
| 4360 | // If we found no index then this means this is a zero sized field at the | ||
| 4361 | // end of the struct. Treat our struct pointer as an array of two and get | ||
| 4362 | // the index to the element at index `1` to get a pointer to the end of | ||
| 4363 | // the struct. | ||
| 4364 | const llvm_usize = try self.dg.llvmType(Type.usize); | ||
| 4365 | const llvm_index = llvm_usize.constInt(1, .False); | ||
| 4366 | const indices: [1]*const llvm.Value = .{llvm_index}; | ||
| 4367 | return self.builder.buildInBoundsGEP(struct_ptr, &indices, indices.len, ""); | ||
| 4368 | } | ||
| 4359 | }, | 4369 | }, |
| 4360 | .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index), | 4370 | .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index), |
| 4361 | else => unreachable, | 4371 | else => unreachable, |
| ... | @@ -4750,32 +4760,37 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca | ... | @@ -4750,32 +4760,37 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca |
| 4750 | }; | 4760 | }; |
| 4751 | } | 4761 | } |
| 4752 | 4762 | ||
| 4753 | /// Take into account 0 bit fields. | 4763 | /// Take into account 0 bit fields. Returns null if an llvm field could not be found. This only |
| 4764 | /// happends if you want the field index of a zero sized field at the end of the struct. | ||
| 4754 | fn llvmFieldIndex( | 4765 | fn llvmFieldIndex( |
| 4755 | ty: Type, | 4766 | ty: Type, |
| 4756 | field_index: u32, | 4767 | field_index: u32, |
| 4757 | target: std.Target, | 4768 | target: std.Target, |
| 4758 | ptr_pl_buf: *Type.Payload.Pointer, | 4769 | ptr_pl_buf: *Type.Payload.Pointer, |
| 4759 | ) c_uint { | 4770 | ) ?c_uint { |
| 4760 | const struct_obj = ty.castTag(.@"struct").?.data; | 4771 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 4761 | if (struct_obj.layout != .Packed) { | 4772 | if (struct_obj.layout != .Packed) { |
| 4762 | var llvm_field_index: c_uint = 0; | 4773 | var llvm_field_index: c_uint = 0; |
| 4763 | for (struct_obj.fields.values()) |field, i| { | 4774 | for (struct_obj.fields.values()) |field, i| { |
| 4764 | if (!field.ty.hasCodeGenBits()) continue; | 4775 | if (!field.ty.hasCodeGenBits()) |
| 4765 | 4776 | continue; | |
| 4766 | if (i == field_index) { | 4777 | if (field_index > i) { |
| 4767 | ptr_pl_buf.* = .{ | 4778 | llvm_field_index += 1; |
| 4768 | .data = .{ | 4779 | continue; |
| 4769 | .pointee_type = field.ty, | ||
| 4770 | .@"align" = field.normalAlignment(target), | ||
| 4771 | .@"addrspace" = .generic, | ||
| 4772 | }, | ||
| 4773 | }; | ||
| 4774 | return llvm_field_index; | ||
| 4775 | } | 4780 | } |
| 4776 | llvm_field_index += 1; | 4781 | |
| 4782 | ptr_pl_buf.* = .{ | ||
| 4783 | .data = .{ | ||
| 4784 | .pointee_type = field.ty, | ||
| 4785 | .@"align" = field.normalAlignment(target), | ||
| 4786 | .@"addrspace" = .generic, | ||
| 4787 | }, | ||
| 4788 | }; | ||
| 4789 | return llvm_field_index; | ||
| 4790 | } else { | ||
| 4791 | // We did not find an llvm field that corrispons to this zig field. | ||
| 4792 | return null; | ||
| 4777 | } | 4793 | } |
| 4778 | unreachable; | ||
| 4779 | } | 4794 | } |
| 4780 | 4795 | ||
| 4781 | // Our job here is to return the host integer field index. | 4796 | // Our job here is to return the host integer field index. |
| ... | @@ -4784,7 +4799,8 @@ fn llvmFieldIndex( | ... | @@ -4784,7 +4799,8 @@ fn llvmFieldIndex( |
| 4784 | var running_bits: u16 = 0; | 4799 | var running_bits: u16 = 0; |
| 4785 | var llvm_field_index: c_uint = 0; | 4800 | var llvm_field_index: c_uint = 0; |
| 4786 | for (struct_obj.fields.values()) |field, i| { | 4801 | for (struct_obj.fields.values()) |field, i| { |
| 4787 | if (!field.ty.hasCodeGenBits()) continue; | 4802 | if (!field.ty.hasCodeGenBits()) |
| 4803 | continue; | ||
| 4788 | 4804 | ||
| 4789 | const field_align = field.packedAlignment(); | 4805 | const field_align = field.packedAlignment(); |
| 4790 | if (field_align == 0) { | 4806 | if (field_align == 0) { |
src/type.zig+3-3| ... | @@ -1916,7 +1916,7 @@ pub const Type = extern union { | ... | @@ -1916,7 +1916,7 @@ pub const Type = extern union { |
| 1916 | const fields = self.structFields(); | 1916 | const fields = self.structFields(); |
| 1917 | const is_packed = if (self.castTag(.@"struct")) |payload| p: { | 1917 | const is_packed = if (self.castTag(.@"struct")) |payload| p: { |
| 1918 | const struct_obj = payload.data; | 1918 | const struct_obj = payload.data; |
| 1919 | assert(struct_obj.status == .have_layout); | 1919 | assert(struct_obj.haveLayout()); |
| 1920 | break :p struct_obj.layout == .Packed; | 1920 | break :p struct_obj.layout == .Packed; |
| 1921 | } else false; | 1921 | } else false; |
| 1922 | 1922 | ||
| ... | @@ -2220,7 +2220,7 @@ pub const Type = extern union { | ... | @@ -2220,7 +2220,7 @@ pub const Type = extern union { |
| 2220 | if (field_count == 0) return 0; | 2220 | if (field_count == 0) return 0; |
| 2221 | 2221 | ||
| 2222 | const struct_obj = ty.castTag(.@"struct").?.data; | 2222 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 2223 | assert(struct_obj.status == .have_layout); | 2223 | assert(struct_obj.haveLayout()); |
| 2224 | 2224 | ||
| 2225 | var total: u64 = 0; | 2225 | var total: u64 = 0; |
| 2226 | for (struct_obj.fields.values()) |field| { | 2226 | for (struct_obj.fields.values()) |field| { |
| ... | @@ -3771,7 +3771,7 @@ pub const Type = extern union { | ... | @@ -3771,7 +3771,7 @@ pub const Type = extern union { |
| 3771 | switch (ty.tag()) { | 3771 | switch (ty.tag()) { |
| 3772 | .@"struct" => { | 3772 | .@"struct" => { |
| 3773 | const struct_obj = ty.castTag(.@"struct").?.data; | 3773 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 3774 | assert(struct_obj.status == .have_layout); | 3774 | assert(struct_obj.haveLayout()); |
| 3775 | const is_packed = struct_obj.layout == .Packed; | 3775 | const is_packed = struct_obj.layout == .Packed; |
| 3776 | if (!is_packed) { | 3776 | if (!is_packed) { |
| 3777 | var offset: u64 = 0; | 3777 | var offset: u64 = 0; |
src/value.zig+9-1| ... | @@ -2635,9 +2635,17 @@ pub const Value = extern union { | ... | @@ -2635,9 +2635,17 @@ pub const Value = extern union { |
| 2635 | var lhs_space: Value.BigIntSpace = undefined; | 2635 | var lhs_space: Value.BigIntSpace = undefined; |
| 2636 | const lhs_bigint = lhs.toBigInt(&lhs_space); | 2636 | const lhs_bigint = lhs.toBigInt(&lhs_space); |
| 2637 | const shift = @intCast(usize, rhs.toUnsignedInt()); | 2637 | const shift = @intCast(usize, rhs.toUnsignedInt()); |
| 2638 | |||
| 2639 | const result_limbs = lhs_bigint.limbs.len -| (shift / (@sizeOf(std.math.big.Limb) * 8)); | ||
| 2640 | if (result_limbs == 0) { | ||
| 2641 | // The shift is enough to remove all the bits from the number, which means the | ||
| 2642 | // result is zero. | ||
| 2643 | return Value.zero; | ||
| 2644 | } | ||
| 2645 | |||
| 2638 | const limbs = try allocator.alloc( | 2646 | const limbs = try allocator.alloc( |
| 2639 | std.math.big.Limb, | 2647 | std.math.big.Limb, |
| 2640 | lhs_bigint.limbs.len - (shift / (@sizeOf(std.math.big.Limb) * 8)), | 2648 | result_limbs, |
| 2641 | ); | 2649 | ); |
| 2642 | var result_bigint = BigIntMutable{ | 2650 | var result_bigint = BigIntMutable{ |
| 2643 | .limbs = limbs, | 2651 | .limbs = limbs, |
test/behavior.zig+1-1| ... | @@ -73,6 +73,7 @@ test { | ... | @@ -73,6 +73,7 @@ test { |
| 73 | _ = @import("behavior/array_llvm.zig"); | 73 | _ = @import("behavior/array_llvm.zig"); |
| 74 | _ = @import("behavior/atomics.zig"); | 74 | _ = @import("behavior/atomics.zig"); |
| 75 | _ = @import("behavior/basic_llvm.zig"); | 75 | _ = @import("behavior/basic_llvm.zig"); |
| 76 | _ = @import("behavior/bit_shifting.zig"); | ||
| 76 | _ = @import("behavior/bugs/394.zig"); | 77 | _ = @import("behavior/bugs/394.zig"); |
| 77 | _ = @import("behavior/bugs/656.zig"); | 78 | _ = @import("behavior/bugs/656.zig"); |
| 78 | _ = @import("behavior/bugs/1277.zig"); | 79 | _ = @import("behavior/bugs/1277.zig"); |
| ... | @@ -120,7 +121,6 @@ test { | ... | @@ -120,7 +121,6 @@ test { |
| 120 | _ = @import("behavior/async_fn.zig"); | 121 | _ = @import("behavior/async_fn.zig"); |
| 121 | } | 122 | } |
| 122 | _ = @import("behavior/await_struct.zig"); | 123 | _ = @import("behavior/await_struct.zig"); |
| 123 | _ = @import("behavior/bit_shifting.zig"); | ||
| 124 | _ = @import("behavior/bitcast_stage1.zig"); | 124 | _ = @import("behavior/bitcast_stage1.zig"); |
| 125 | _ = @import("behavior/bitreverse.zig"); | 125 | _ = @import("behavior/bitreverse.zig"); |
| 126 | _ = @import("behavior/bugs/421.zig"); | 126 | _ = @import("behavior/bugs/421.zig"); |
test/behavior/bit_shifting.zig+1| ... | @@ -72,6 +72,7 @@ test "sharded table" { | ... | @@ -72,6 +72,7 @@ test "sharded table" { |
| 72 | 72 | ||
| 73 | try testShardedTable(u0, 0, 1); | 73 | try testShardedTable(u0, 0, 1); |
| 74 | } | 74 | } |
| 75 | |||
| 75 | fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime node_count: comptime_int) !void { | 76 | fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime node_count: comptime_int) !void { |
| 76 | const Table = ShardedTable(Key, mask_bit_count, void); | 77 | const Table = ShardedTable(Key, mask_bit_count, void); |
| 77 | 78 |