╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Value.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
2398 .@"struct" => |@"struct"| switch (interpret_mode) { 2399 .direct => { 2400 if (ty.structFieldCount(zcu) != @"struct".field_names.len) return error.TypeMismatch; 2401 var field_vals: [@"struct".field_names.len]InternPool.Index = undefined; 2402 inline for (&field_vals, @"struct".field_names, 0..) |*field_val, field_name, field_idx| { 2403 const field_ty = ty.fieldType(field_idx, zcu); 2404 field_val.* = (try uninterpret(@field(val, field_name), field_ty, pt)).toIntern(); 2405 } 2406 return pt.aggregateValue(ty, &field_vals); 2407 }, 2408 .by_name => { 2409 const struct_obj = zcu.typeToStruct(ty) orelse return error.TypeMismatch; 2410 const want_fields_len = struct_obj.field_types.len; 2411 const field_vals = try zcu.gpa.alloc(InternPool.Index, want_fields_len); 2412 defer zcu.gpa.free(field_vals); 2413 @memset(field_vals, .none); 2414 inline for (@"struct".field_names) |field_name| { 2415 const field_name_ip = try ip.getOrPutString(zcu.gpa, io, pt.tid, field_name, .no_embedded_nulls); 2416 if (struct_obj.nameIndex(ip, field_name_ip)) |field_idx| { 2417 const field_ty = ty.fieldType(field_idx, zcu); 2418 field_vals[field_idx] = (try uninterpret(@field(val, field_name), field_ty, pt)).toIntern(); 2419 } 2420 } 2421 for (field_vals, 0..) |*field_val, field_idx| { 2422 if (field_val.* == .none) { 2423 const default_init = struct_obj.field_defaults.get(ip)[field_idx]; 2424 if (default_init == .none) return error.TypeMismatch; 2425 field_val.* = default_init; 2426 } 2427 } 2428 return pt.aggregateValue(ty, field_vals); 2429 }, 2430 }, 2431 }; 2432 } 2433 2434 /// Returns whether `ptr_val_a[0..elem_count]` and `ptr_val_b[0..elem_count]` overlap. 2435 /// `ptr_val_a` and `ptr_val_b` are indexable pointers (not slices) whose element types are in-memory coercible. 2436 pub fn doPointersOverlap(ptr_val_a: Value, ptr_val_b: Value, elem_count: u64, zcu: *const Zcu) bool { 2437 const ip = &zcu.intern_pool; 2438 2439 const a_elem_ty = ptr_val_a.typeOf(zcu).indexableElem(zcu); 2440 const b_elem_ty = ptr_val_b.typeOf(zcu).indexableElem(zcu); 2441 2442 const a_ptr = ip.indexToKey(ptr_val_a.toIntern()).ptr; 2443 const b_ptr = ip.indexToKey(ptr_val_b.toIntern()).ptr; 2444 2445 // If `a_elem_ty` is not comptime-only, then overlapping pointers have identical 2446 // `base_addr`, and we just need to look at the byte offset. If it *is* comptime-only, 2447 // then `base_addr` may be an `arr_elem`, and we'll have to consider the element index. 2448 if (a_elem_ty.comptimeOnly(zcu)) { 2449 assert(a_elem_ty.toIntern() == b_elem_ty.toIntern()); // IMC comptime-only types are equivalent 2450 2451 const a_base_addr: InternPool.Key.Ptr.BaseAddr, const a_idx: u64 = switch (a_ptr.base_addr) { 2452 else => .{ a_ptr.base_addr, 0 }, 2453 .arr_elem => |arr_elem| a: { 2454 const base_ptr = Value.fromInterned(arr_elem.base); 2455 const base_child_ty = base_ptr.typeOf(zcu).childType(zcu); 2456 if (base_child_ty.toIntern() == a_elem_ty.toIntern()) { 2457 // This `arr_elem` is indexing into the element type we want. 2458 const base_ptr_info = ip.indexToKey(base_ptr.toIntern()).ptr; 2459 if (base_ptr_info.byte_offset != 0) { 2460 return false; // this pointer is invalid, just let the access fail 2461 } 2462 break :a .{ base_ptr_info.base_addr, arr_elem.index }; 2463 } 2464 break :a .{ a_ptr.base_addr, 0 }; 2465 }, 2466 }; 2467 const b_base_addr: InternPool.Key.Ptr.BaseAddr, const b_idx: u64 = switch (a_ptr.base_addr) { 2468 else => .{ b_ptr.base_addr, 0 }, 2469 .arr_elem => |arr_elem| b: { 2470 const base_ptr = Value.fromInterned(arr_elem.base); 2471 const base_child_ty = base_ptr.typeOf(zcu).childType(zcu); 2472 if (base_child_ty.toIntern() == b_elem_ty.toIntern()) { 2473 // This `arr_elem` is indexing into the element type we want. 2474 const base_ptr_info = ip.indexToKey(base_ptr.toIntern()).ptr; 2475 if (base_ptr_info.byte_offset != 0) { 2476 return false; // this pointer is invalid, just let the access fail 2477 } 2478 break :b .{ base_ptr_info.base_addr, arr_elem.index }; 2479 } 2480 break :b .{ b_ptr.base_addr, 0 }; 2481 }, 2482 }; 2483 if (!std.meta.eql(a_base_addr, b_base_addr)) return false; 2484 const diff = if (a_idx >= b_idx) a_idx - b_idx else b_idx - a_idx; 2485 return diff < elem_count; 2486 } else { 2487 assert(a_elem_ty.abiSize(zcu) == b_elem_ty.abiSize(zcu)); 2488 2489 if (!std.meta.eql(a_ptr.base_addr, b_ptr.base_addr)) return false; 2490 2491 const bytes_diff = if (a_ptr.byte_offset >= b_ptr.byte_offset) 2492 a_ptr.byte_offset - b_ptr.byte_offset 2493 else 2494 b_ptr.byte_offset - a_ptr.byte_offset; 2495 2496 const need_bytes_diff = elem_count * a_elem_ty.abiSize(zcu); 2497 return bytes_diff < need_bytes_diff; 2498 } 2499 } 2500 2501 /// `lhs` and `rhs` are both scalar numeric values (int or float). 2502 /// Supports comparisons between heterogeneous types. 2503 /// If `lhs` or `rhs` is undef, returns `false`. 2504 pub fn eqlScalarNum(lhs: Value, rhs: Value, zcu: *Zcu) bool { 2505 if (lhs.isUndef(zcu)) return false; 2506 if (rhs.isUndef(zcu)) return false; 2507 2508 if (lhs.isFloat(zcu) or rhs.isFloat(zcu)) { 2509 const lhs_f128 = lhs.toFloat(f128, zcu); 2510 const rhs_f128 = rhs.toFloat(f128, zcu); 2511 return lhs_f128 == rhs_f128; 2512 } 2513 2514 if (lhs.getUnsignedInt(zcu)) |lhs_u64| { 2515 if (rhs.getUnsignedInt(zcu)) |rhs_u64| { 2516 return lhs_u64 == rhs_u64; 2517 } 2518 } 2519 2520 var lhs_bigint_space: BigIntSpace = undefined; 2521 var rhs_bigint_space: BigIntSpace = undefined; 2522 const lhs_bigint = lhs.toBigInt(&lhs_bigint_space, zcu); 2523 const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, zcu); 2524 return lhs_bigint.eql(rhs_bigint); 2525 } 2526 2527 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int. 2528 /// Vectors are also accepted. Vector results are reduced with AND. 2529 /// 2530 /// If provided, `vector_index` reports the first element that failed the range check. 2531 pub fn intFitsInType( 2532 val: Value, 2533 ty: Type, 2534 vector_index: ?*usize, 2535 zcu: *const Zcu, 2536 ) bool { 2537 if (ty.toIntern() == .comptime_int_type) return true; 2538 const info = ty.intInfo(zcu); 2539 switch (val.toIntern()) { 2540 .zero_usize, .zero_u8 => return true, 2541 else => switch (zcu.intern_pool.indexToKey(val.toIntern())) { 2542 .undef => return true, 2543 .@"extern", .func, .ptr => { 2544 const target = zcu.getTarget(); 2545 const ptr_bits = target.ptrBitWidth(); 2546 return switch (info.signedness) { 2547 .signed => info.bits > ptr_bits, 2548 .unsigned => info.bits >= ptr_bits, 2549 }; 2550 }, 2551 .int => |int| { 2552 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; 2553 const big_int = int.storage.toBigInt(&buffer); 2554 return big_int.fitsInTwosComp(info.signedness, info.bits); 2555 }, 2556 .aggregate => |aggregate| { 2557 assert(ty.zigTypeTag(zcu) == .vector); 2558 return switch (aggregate.storage) { 2559 .bytes => |bytes| for (bytes.toSlice(ty.vectorLen(zcu), &zcu.intern_pool), 0..) |byte, i| { 2560 if (byte == 0) continue; 2561 const actual_needed_bits = std.math.log2(byte) + 1 + @intFromBool(info.signedness == .signed); 2562 if (info.bits >= actual_needed_bits) continue; 2563 if (vector_index) |vi| vi.* = i; 2564 break false; 2565 } else true, 2566 .elems, .repeated_elem => for (switch (aggregate.storage) { 2567 .bytes => unreachable, 2568 .elems => |elems| elems, 2569 .repeated_elem => |elem| @as(*const [1]InternPool.Index, &elem), 2570 }, 0..) |elem, i| { 2571 if (Value.fromInterned(elem).intFitsInType(ty.scalarType(zcu), null, zcu)) continue; 2572 if (vector_index) |vi| vi.* = i; 2573 break false; 2574 } else true, 2575 }; 2576 }, 2577 else => unreachable, 2578 }, 2579 } 2580 } 2581