| author | |
| committer | |
| log | 2cdbb5f47260d2510ce478c77fa9c3c7c29fb671 |
| tree | 6bebbf19524eaad49c86dbfd8cbc43e2e27375bb |
| parent | 0746028a2a6caf28e396f042be0b23c8d6fb7a5e |
8 files changed, 303 insertions(+), 174 deletions(-)
lib/std/math/big/int.zig+1-1| ... | @@ -237,7 +237,7 @@ pub const Int = struct { | ... | @@ -237,7 +237,7 @@ pub const Int = struct { |
| 237 | return bits; | 237 | return bits; |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | fn fitsInTwosComp(self: Int, is_signed: bool, bit_count: usize) bool { | 240 | pub fn fitsInTwosComp(self: Int, is_signed: bool, bit_count: usize) bool { |
| 241 | if (self.eqZero()) { | 241 | if (self.eqZero()) { |
| 242 | return true; | 242 | return true; |
| 243 | } | 243 | } |
lib/std/target.zig+1-1| ... | @@ -761,7 +761,7 @@ pub const Target = struct { | ... | @@ -761,7 +761,7 @@ pub const Target = struct { |
| 761 | }; | 761 | }; |
| 762 | } | 762 | } |
| 763 | 763 | ||
| 764 | pub fn ptrBitWidth(arch: Arch) u32 { | 764 | pub fn ptrBitWidth(arch: Arch) u16 { |
| 765 | switch (arch) { | 765 | switch (arch) { |
| 766 | .avr, | 766 | .avr, |
| 767 | .msp430, | 767 | .msp430, |
src-self-hosted/c_int.zig deleted-169| ... | @@ -1,169 +0,0 @@ | ||
| 1 | const Target = @import("std").Target; | ||
| 2 | |||
| 3 | pub const CInt = struct { | ||
| 4 | id: Id, | ||
| 5 | zig_name: []const u8, | ||
| 6 | c_name: []const u8, | ||
| 7 | is_signed: bool, | ||
| 8 | |||
| 9 | pub const Id = enum { | ||
| 10 | Short, | ||
| 11 | UShort, | ||
| 12 | Int, | ||
| 13 | UInt, | ||
| 14 | Long, | ||
| 15 | ULong, | ||
| 16 | LongLong, | ||
| 17 | ULongLong, | ||
| 18 | }; | ||
| 19 | |||
| 20 | pub const list = [_]CInt{ | ||
| 21 | CInt{ | ||
| 22 | .id = .Short, | ||
| 23 | .zig_name = "c_short", | ||
| 24 | .c_name = "short", | ||
| 25 | .is_signed = true, | ||
| 26 | }, | ||
| 27 | CInt{ | ||
| 28 | .id = .UShort, | ||
| 29 | .zig_name = "c_ushort", | ||
| 30 | .c_name = "unsigned short", | ||
| 31 | .is_signed = false, | ||
| 32 | }, | ||
| 33 | CInt{ | ||
| 34 | .id = .Int, | ||
| 35 | .zig_name = "c_int", | ||
| 36 | .c_name = "int", | ||
| 37 | .is_signed = true, | ||
| 38 | }, | ||
| 39 | CInt{ | ||
| 40 | .id = .UInt, | ||
| 41 | .zig_name = "c_uint", | ||
| 42 | .c_name = "unsigned int", | ||
| 43 | .is_signed = false, | ||
| 44 | }, | ||
| 45 | CInt{ | ||
| 46 | .id = .Long, | ||
| 47 | .zig_name = "c_long", | ||
| 48 | .c_name = "long", | ||
| 49 | .is_signed = true, | ||
| 50 | }, | ||
| 51 | CInt{ | ||
| 52 | .id = .ULong, | ||
| 53 | .zig_name = "c_ulong", | ||
| 54 | .c_name = "unsigned long", | ||
| 55 | .is_signed = false, | ||
| 56 | }, | ||
| 57 | CInt{ | ||
| 58 | .id = .LongLong, | ||
| 59 | .zig_name = "c_longlong", | ||
| 60 | .c_name = "long long", | ||
| 61 | .is_signed = true, | ||
| 62 | }, | ||
| 63 | CInt{ | ||
| 64 | .id = .ULongLong, | ||
| 65 | .zig_name = "c_ulonglong", | ||
| 66 | .c_name = "unsigned long long", | ||
| 67 | .is_signed = false, | ||
| 68 | }, | ||
| 69 | }; | ||
| 70 | |||
| 71 | pub fn sizeInBits(cint: CInt, self: Target) u32 { | ||
| 72 | const arch = self.cpu.arch; | ||
| 73 | switch (self.os.tag) { | ||
| 74 | .freestanding, .other => switch (self.cpu.arch) { | ||
| 75 | .msp430 => switch (cint.id) { | ||
| 76 | .Short, | ||
| 77 | .UShort, | ||
| 78 | .Int, | ||
| 79 | .UInt, | ||
| 80 | => return 16, | ||
| 81 | .Long, | ||
| 82 | .ULong, | ||
| 83 | => return 32, | ||
| 84 | .LongLong, | ||
| 85 | .ULongLong, | ||
| 86 | => return 64, | ||
| 87 | }, | ||
| 88 | else => switch (cint.id) { | ||
| 89 | .Short, | ||
| 90 | .UShort, | ||
| 91 | => return 16, | ||
| 92 | .Int, | ||
| 93 | .UInt, | ||
| 94 | => return 32, | ||
| 95 | .Long, | ||
| 96 | .ULong, | ||
| 97 | => return self.cpu.arch.ptrBitWidth(), | ||
| 98 | .LongLong, | ||
| 99 | .ULongLong, | ||
| 100 | => return 64, | ||
| 101 | }, | ||
| 102 | }, | ||
| 103 | |||
| 104 | .linux, | ||
| 105 | .macosx, | ||
| 106 | .freebsd, | ||
| 107 | .openbsd, | ||
| 108 | => switch (cint.id) { | ||
| 109 | .Short, | ||
| 110 | .UShort, | ||
| 111 | => return 16, | ||
| 112 | .Int, | ||
| 113 | .UInt, | ||
| 114 | => return 32, | ||
| 115 | .Long, | ||
| 116 | .ULong, | ||
| 117 | => return self.cpu.arch.ptrBitWidth(), | ||
| 118 | .LongLong, | ||
| 119 | .ULongLong, | ||
| 120 | => return 64, | ||
| 121 | }, | ||
| 122 | |||
| 123 | .windows, .uefi => switch (cint.id) { | ||
| 124 | .Short, | ||
| 125 | .UShort, | ||
| 126 | => return 16, | ||
| 127 | .Int, | ||
| 128 | .UInt, | ||
| 129 | => return 32, | ||
| 130 | .Long, | ||
| 131 | .ULong, | ||
| 132 | .LongLong, | ||
| 133 | .ULongLong, | ||
| 134 | => return 64, | ||
| 135 | }, | ||
| 136 | |||
| 137 | .ananas, | ||
| 138 | .cloudabi, | ||
| 139 | .dragonfly, | ||
| 140 | .fuchsia, | ||
| 141 | .ios, | ||
| 142 | .kfreebsd, | ||
| 143 | .lv2, | ||
| 144 | .netbsd, | ||
| 145 | .solaris, | ||
| 146 | .haiku, | ||
| 147 | .minix, | ||
| 148 | .rtems, | ||
| 149 | .nacl, | ||
| 150 | .cnk, | ||
| 151 | .aix, | ||
| 152 | .cuda, | ||
| 153 | .nvcl, | ||
| 154 | .amdhsa, | ||
| 155 | .ps4, | ||
| 156 | .elfiamcu, | ||
| 157 | .tvos, | ||
| 158 | .watchos, | ||
| 159 | .mesa3d, | ||
| 160 | .contiki, | ||
| 161 | .amdpal, | ||
| 162 | .hermit, | ||
| 163 | .hurd, | ||
| 164 | .wasi, | ||
| 165 | .emscripten, | ||
| 166 | => @panic("TODO specify the C integer type sizes for this OS"), | ||
| 167 | } | ||
| 168 | } | ||
| 169 | }; | ||
src-self-hosted/ir.zig+49| ... | @@ -6,6 +6,7 @@ const Type = @import("type.zig").Type; | ... | @@ -6,6 +6,7 @@ const Type = @import("type.zig").Type; |
| 6 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 7 | const text = @import("ir/text.zig"); | 7 | const text = @import("ir/text.zig"); |
| 8 | const BigInt = std.math.big.Int; | 8 | const BigInt = std.math.big.Int; |
| 9 | const Target = std.Target; | ||
| 9 | 10 | ||
| 10 | /// These are in-memory, analyzed instructions. See `text.Inst` for the representation | 11 | /// These are in-memory, analyzed instructions. See `text.Inst` for the representation |
| 11 | /// of instructions that correspond to the ZIR text format. | 12 | /// of instructions that correspond to the ZIR text format. |
| ... | @@ -99,6 +100,8 @@ pub const ErrorMsg = struct { | ... | @@ -99,6 +100,8 @@ pub const ErrorMsg = struct { |
| 99 | }; | 100 | }; |
| 100 | 101 | ||
| 101 | pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module { | 102 | pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module { |
| 103 | const native_info = try std.zig.system.NativeTargetInfo.detect(allocator, .{}); | ||
| 104 | |||
| 102 | var ctx = Analyze{ | 105 | var ctx = Analyze{ |
| 103 | .allocator = allocator, | 106 | .allocator = allocator, |
| 104 | .arena = std.heap.ArenaAllocator.init(allocator), | 107 | .arena = std.heap.ArenaAllocator.init(allocator), |
| ... | @@ -107,6 +110,7 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module { | ... | @@ -107,6 +110,7 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module { |
| 107 | .decl_table = std.AutoHashMap(*text.Inst, Analyze.NewDecl).init(allocator), | 110 | .decl_table = std.AutoHashMap(*text.Inst, Analyze.NewDecl).init(allocator), |
| 108 | .exports = std.ArrayList(Module.Export).init(allocator), | 111 | .exports = std.ArrayList(Module.Export).init(allocator), |
| 109 | .fns = std.ArrayList(Module.Fn).init(allocator), | 112 | .fns = std.ArrayList(Module.Fn).init(allocator), |
| 113 | .target = native_info.target, | ||
| 110 | }; | 114 | }; |
| 111 | defer ctx.errors.deinit(); | 115 | defer ctx.errors.deinit(); |
| 112 | defer ctx.decl_table.deinit(); | 116 | defer ctx.decl_table.deinit(); |
| ... | @@ -135,6 +139,7 @@ const Analyze = struct { | ... | @@ -135,6 +139,7 @@ const Analyze = struct { |
| 135 | decl_table: std.AutoHashMap(*text.Inst, NewDecl), | 139 | decl_table: std.AutoHashMap(*text.Inst, NewDecl), |
| 136 | exports: std.ArrayList(Module.Export), | 140 | exports: std.ArrayList(Module.Export), |
| 137 | fns: std.ArrayList(Module.Fn), | 141 | fns: std.ArrayList(Module.Fn), |
| 142 | target: Target, | ||
| 138 | 143 | ||
| 139 | const NewDecl = struct { | 144 | const NewDecl = struct { |
| 140 | /// null means a semantic analysis error happened | 145 | /// null means a semantic analysis error happened |
| ... | @@ -336,6 +341,7 @@ const Analyze = struct { | ... | @@ -336,6 +341,7 @@ const Analyze = struct { |
| 336 | .@"export" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 341 | .@"export" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 337 | .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?), | 342 | .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?), |
| 338 | .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?), | 343 | .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?), |
| 344 | .intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?), | ||
| 339 | } | 345 | } |
| 340 | } | 346 | } |
| 341 | 347 | ||
| ... | @@ -402,6 +408,38 @@ const Analyze = struct { | ... | @@ -402,6 +408,38 @@ const Analyze = struct { |
| 402 | return self.coerce(dest_type, new_inst); | 408 | return self.coerce(dest_type, new_inst); |
| 403 | } | 409 | } |
| 404 | 410 | ||
| 411 | fn analyzeInstIntCast(self: *Analyze, func: ?*Fn, intcast: *text.Inst.IntCast) InnerError!*Inst { | ||
| 412 | const dest_type = try self.resolveType(func, intcast.positionals.dest_type); | ||
| 413 | const new_inst = try self.resolveInst(func, intcast.positionals.value); | ||
| 414 | |||
| 415 | const dest_is_comptime_int = switch (dest_type.zigTypeTag()) { | ||
| 416 | .ComptimeInt => true, | ||
| 417 | .Int => false, | ||
| 418 | else => return self.fail( | ||
| 419 | intcast.positionals.dest_type.src, | ||
| 420 | "expected integer type, found '{}'", | ||
| 421 | .{ | ||
| 422 | dest_type, | ||
| 423 | }, | ||
| 424 | ), | ||
| 425 | }; | ||
| 426 | |||
| 427 | switch (new_inst.ty.zigTypeTag()) { | ||
| 428 | .ComptimeInt, .Int => {}, | ||
| 429 | else => return self.fail( | ||
| 430 | intcast.positionals.value.src, | ||
| 431 | "expected integer type, found '{}'", | ||
| 432 | .{new_inst.ty}, | ||
| 433 | ), | ||
| 434 | } | ||
| 435 | |||
| 436 | if (dest_is_comptime_int or new_inst.value() != null) { | ||
| 437 | return self.coerce(dest_type, new_inst); | ||
| 438 | } | ||
| 439 | |||
| 440 | return self.fail(intcast.base.src, "TODO implement analyze widen or shorten int", .{}); | ||
| 441 | } | ||
| 442 | |||
| 405 | fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { | 443 | fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { |
| 406 | const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty); | 444 | const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty); |
| 407 | if (in_memory_result == .ok) { | 445 | if (in_memory_result == .ok) { |
| ... | @@ -420,6 +458,17 @@ const Analyze = struct { | ... | @@ -420,6 +458,17 @@ const Analyze = struct { |
| 420 | return self.coerceArrayPtrToSlice(dest_type, inst); | 458 | return self.coerceArrayPtrToSlice(dest_type, inst); |
| 421 | } | 459 | } |
| 422 | } | 460 | } |
| 461 | |||
| 462 | // comptime_int to fixed-width integer | ||
| 463 | if (inst.ty.zigTypeTag() == .ComptimeInt and dest_type.zigTypeTag() == .Int) { | ||
| 464 | // The representation is already correct; we only need to make sure it fits in the destination type. | ||
| 465 | const val = inst.value().?; // comptime_int always has comptime known value | ||
| 466 | if (!val.intFitsInType(dest_type, self.target)) { | ||
| 467 | return self.fail(inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val }); | ||
| 468 | } | ||
| 469 | return self.constInst(inst.src, .{ .ty = dest_type, .val = val }); | ||
| 470 | } | ||
| 471 | |||
| 423 | return self.fail(inst.src, "TODO implement type coercion", .{}); | 472 | return self.fail(inst.src, "TODO implement type coercion", .{}); |
| 424 | } | 473 | } |
| 425 | 474 |
src-self-hosted/ir/text.zig+14| ... | @@ -28,6 +28,7 @@ pub const Inst = struct { | ... | @@ -28,6 +28,7 @@ pub const Inst = struct { |
| 28 | @"export", | 28 | @"export", |
| 29 | primitive, | 29 | primitive, |
| 30 | fntype, | 30 | fntype, |
| 31 | intcast, | ||
| 31 | }; | 32 | }; |
| 32 | 33 | ||
| 33 | pub fn TagToType(tag: Tag) type { | 34 | pub fn TagToType(tag: Tag) type { |
| ... | @@ -44,6 +45,7 @@ pub const Inst = struct { | ... | @@ -44,6 +45,7 @@ pub const Inst = struct { |
| 44 | .@"export" => Export, | 45 | .@"export" => Export, |
| 45 | .primitive => Primitive, | 46 | .primitive => Primitive, |
| 46 | .fntype => FnType, | 47 | .fntype => FnType, |
| 48 | .intcast => IntCast, | ||
| 47 | }; | 49 | }; |
| 48 | } | 50 | } |
| 49 | 51 | ||
| ... | @@ -243,6 +245,17 @@ pub const Inst = struct { | ... | @@ -243,6 +245,17 @@ pub const Inst = struct { |
| 243 | cc: std.builtin.CallingConvention = .Unspecified, | 245 | cc: std.builtin.CallingConvention = .Unspecified, |
| 244 | }, | 246 | }, |
| 245 | }; | 247 | }; |
| 248 | |||
| 249 | pub const IntCast = struct { | ||
| 250 | pub const base_tag = Tag.intcast; | ||
| 251 | base: Inst, | ||
| 252 | |||
| 253 | positionals: struct { | ||
| 254 | dest_type: *Inst, | ||
| 255 | value: *Inst, | ||
| 256 | }, | ||
| 257 | kw_args: struct {}, | ||
| 258 | }; | ||
| 246 | }; | 259 | }; |
| 247 | 260 | ||
| 248 | pub const ErrorMsg = struct { | 261 | pub const ErrorMsg = struct { |
| ... | @@ -315,6 +328,7 @@ pub const Module = struct { | ... | @@ -315,6 +328,7 @@ pub const Module = struct { |
| 315 | .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", decl, inst_table), | 328 | .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", decl, inst_table), |
| 316 | .primitive => return self.writeInstToStreamGeneric(stream, .primitive, decl, inst_table), | 329 | .primitive => return self.writeInstToStreamGeneric(stream, .primitive, decl, inst_table), |
| 317 | .fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table), | 330 | .fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table), |
| 331 | .intcast => return self.writeInstToStreamGeneric(stream, .intcast, decl, inst_table), | ||
| 318 | } | 332 | } |
| 319 | } | 333 | } |
| 320 | 334 |
src-self-hosted/type.zig+162| ... | @@ -2,6 +2,7 @@ const std = @import("std"); | ... | @@ -2,6 +2,7 @@ const std = @import("std"); |
| 2 | const Value = @import("value.zig").Value; | 2 | const Value = @import("value.zig").Value; |
| 3 | const assert = std.debug.assert; | 3 | const assert = std.debug.assert; |
| 4 | const Allocator = std.mem.Allocator; | 4 | const Allocator = std.mem.Allocator; |
| 5 | const Target = std.Target; | ||
| 5 | 6 | ||
| 6 | /// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication. | 7 | /// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication. |
| 7 | /// It's important for this struct to be small. | 8 | /// It's important for this struct to be small. |
| ... | @@ -333,6 +334,44 @@ pub const Type = extern union { | ... | @@ -333,6 +334,44 @@ pub const Type = extern union { |
| 333 | }; | 334 | }; |
| 334 | } | 335 | } |
| 335 | 336 | ||
| 337 | /// Asserts the type is a fixed-width integer. | ||
| 338 | pub fn intInfo(self: Type, target: Target) struct { signed: bool, bits: u16 } { | ||
| 339 | return switch (self.tag()) { | ||
| 340 | .@"f16", | ||
| 341 | .@"f32", | ||
| 342 | .@"f64", | ||
| 343 | .@"f128", | ||
| 344 | .@"c_longdouble", | ||
| 345 | .@"c_void", | ||
| 346 | .@"bool", | ||
| 347 | .@"void", | ||
| 348 | .@"type", | ||
| 349 | .@"anyerror", | ||
| 350 | .@"comptime_int", | ||
| 351 | .@"comptime_float", | ||
| 352 | .@"noreturn", | ||
| 353 | .fn_naked_noreturn_no_args, | ||
| 354 | .array, | ||
| 355 | .single_const_pointer, | ||
| 356 | .array_u8_sentinel_0, | ||
| 357 | .const_slice_u8, | ||
| 358 | => unreachable, | ||
| 359 | |||
| 360 | .@"u8" => .{ .signed = false, .bits = 8 }, | ||
| 361 | .@"i8" => .{ .signed = true, .bits = 8 }, | ||
| 362 | .@"usize" => .{ .signed = false, .bits = target.cpu.arch.ptrBitWidth() }, | ||
| 363 | .@"isize" => .{ .signed = true, .bits = target.cpu.arch.ptrBitWidth() }, | ||
| 364 | .@"c_short" => .{ .signed = true, .bits = CInteger.short.sizeInBits(target) }, | ||
| 365 | .@"c_ushort" => .{ .signed = false, .bits = CInteger.ushort.sizeInBits(target) }, | ||
| 366 | .@"c_int" => .{ .signed = true, .bits = CInteger.int.sizeInBits(target) }, | ||
| 367 | .@"c_uint" => .{ .signed = false, .bits = CInteger.uint.sizeInBits(target) }, | ||
| 368 | .@"c_long" => .{ .signed = true, .bits = CInteger.long.sizeInBits(target) }, | ||
| 369 | .@"c_ulong" => .{ .signed = false, .bits = CInteger.ulong.sizeInBits(target) }, | ||
| 370 | .@"c_longlong" => .{ .signed = true, .bits = CInteger.longlong.sizeInBits(target) }, | ||
| 371 | .@"c_ulonglong" => .{ .signed = false, .bits = CInteger.ulonglong.sizeInBits(target) }, | ||
| 372 | }; | ||
| 373 | } | ||
| 374 | |||
| 336 | /// This enum does not directly correspond to `std.builtin.TypeId` because | 375 | /// This enum does not directly correspond to `std.builtin.TypeId` because |
| 337 | /// it has extra enum tags in it, as a way of using less memory. For example, | 376 | /// it has extra enum tags in it, as a way of using less memory. For example, |
| 338 | /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types | 377 | /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types |
| ... | @@ -401,3 +440,126 @@ pub const Type = extern union { | ... | @@ -401,3 +440,126 @@ pub const Type = extern union { |
| 401 | }; | 440 | }; |
| 402 | }; | 441 | }; |
| 403 | }; | 442 | }; |
| 443 | |||
| 444 | pub const CInteger = enum { | ||
| 445 | short, | ||
| 446 | ushort, | ||
| 447 | int, | ||
| 448 | uint, | ||
| 449 | long, | ||
| 450 | ulong, | ||
| 451 | longlong, | ||
| 452 | ulonglong, | ||
| 453 | |||
| 454 | pub fn sizeInBits(self: CInteger, target: Target) u16 { | ||
| 455 | const arch = target.cpu.arch; | ||
| 456 | switch (target.os.tag) { | ||
| 457 | .freestanding, .other => switch (target.cpu.arch) { | ||
| 458 | .msp430 => switch (self) { | ||
| 459 | .short, | ||
| 460 | .ushort, | ||
| 461 | .int, | ||
| 462 | .uint, | ||
| 463 | => return 16, | ||
| 464 | .long, | ||
| 465 | .ulong, | ||
| 466 | => return 32, | ||
| 467 | .longlong, | ||
| 468 | .ulonglong, | ||
| 469 | => return 64, | ||
| 470 | }, | ||
| 471 | else => switch (self) { | ||
| 472 | .short, | ||
| 473 | .ushort, | ||
| 474 | => return 16, | ||
| 475 | .int, | ||
| 476 | .uint, | ||
| 477 | => return 32, | ||
| 478 | .long, | ||
| 479 | .ulong, | ||
| 480 | => return target.cpu.arch.ptrBitWidth(), | ||
| 481 | .longlong, | ||
| 482 | .ulonglong, | ||
| 483 | => return 64, | ||
| 484 | }, | ||
| 485 | }, | ||
| 486 | |||
| 487 | .linux, | ||
| 488 | .macosx, | ||
| 489 | .freebsd, | ||
| 490 | .netbsd, | ||
| 491 | .dragonfly, | ||
| 492 | .openbsd, | ||
| 493 | .wasi, | ||
| 494 | .emscripten, | ||
| 495 | => switch (self) { | ||
| 496 | .short, | ||
| 497 | .ushort, | ||
| 498 | => return 16, | ||
| 499 | .int, | ||
| 500 | .uint, | ||
| 501 | => return 32, | ||
| 502 | .long, | ||
| 503 | .ulong, | ||
| 504 | => return target.cpu.arch.ptrBitWidth(), | ||
| 505 | .longlong, | ||
| 506 | .ulonglong, | ||
| 507 | => return 64, | ||
| 508 | }, | ||
| 509 | |||
| 510 | .windows, .uefi => switch (self) { | ||
| 511 | .short, | ||
| 512 | .ushort, | ||
| 513 | => return 16, | ||
| 514 | .int, | ||
| 515 | .uint, | ||
| 516 | .long, | ||
| 517 | .ulong, | ||
| 518 | => return 32, | ||
| 519 | .longlong, | ||
| 520 | .ulonglong, | ||
| 521 | => return 64, | ||
| 522 | }, | ||
| 523 | |||
| 524 | .ios => switch (self) { | ||
| 525 | .short, | ||
| 526 | .ushort, | ||
| 527 | => return 16, | ||
| 528 | .int, | ||
| 529 | .uint, | ||
| 530 | => return 32, | ||
| 531 | .long, | ||
| 532 | .ulong, | ||
| 533 | .longlong, | ||
| 534 | .ulonglong, | ||
| 535 | => return 64, | ||
| 536 | }, | ||
| 537 | |||
| 538 | .ananas, | ||
| 539 | .cloudabi, | ||
| 540 | .fuchsia, | ||
| 541 | .kfreebsd, | ||
| 542 | .lv2, | ||
| 543 | .solaris, | ||
| 544 | .haiku, | ||
| 545 | .minix, | ||
| 546 | .rtems, | ||
| 547 | .nacl, | ||
| 548 | .cnk, | ||
| 549 | .aix, | ||
| 550 | .cuda, | ||
| 551 | .nvcl, | ||
| 552 | .amdhsa, | ||
| 553 | .ps4, | ||
| 554 | .elfiamcu, | ||
| 555 | .tvos, | ||
| 556 | .watchos, | ||
| 557 | .mesa3d, | ||
| 558 | .contiki, | ||
| 559 | .amdpal, | ||
| 560 | .hermit, | ||
| 561 | .hurd, | ||
| 562 | => @panic("TODO specify the C integer type sizes for this OS"), | ||
| 563 | } | ||
| 564 | } | ||
| 565 | }; |
src-self-hosted/value.zig+73| ... | @@ -3,6 +3,7 @@ const Type = @import("type.zig").Type; | ... | @@ -3,6 +3,7 @@ const Type = @import("type.zig").Type; |
| 3 | const log2 = std.math.log2; | 3 | const log2 = std.math.log2; |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | const BigInt = std.math.big.Int; | 5 | const BigInt = std.math.big.Int; |
| 6 | const Target = std.Target; | ||
| 6 | 7 | ||
| 7 | /// This is the raw data, with no bookkeeping, no memory awareness, | 8 | /// This is the raw data, with no bookkeeping, no memory awareness, |
| 8 | /// no de-duplication, and no type system awareness. | 9 | /// no de-duplication, and no type system awareness. |
| ... | @@ -198,6 +199,78 @@ pub const Value = extern union { | ... | @@ -198,6 +199,78 @@ pub const Value = extern union { |
| 198 | }; | 199 | }; |
| 199 | } | 200 | } |
| 200 | 201 | ||
| 202 | /// Asserts the value is an integer, and the destination type is ComptimeInt or Int. | ||
| 203 | pub fn intFitsInType(self: Value, ty: Type, target: Target) bool { | ||
| 204 | switch (self.tag()) { | ||
| 205 | .ty, | ||
| 206 | .u8_type, | ||
| 207 | .i8_type, | ||
| 208 | .isize_type, | ||
| 209 | .usize_type, | ||
| 210 | .c_short_type, | ||
| 211 | .c_ushort_type, | ||
| 212 | .c_int_type, | ||
| 213 | .c_uint_type, | ||
| 214 | .c_long_type, | ||
| 215 | .c_ulong_type, | ||
| 216 | .c_longlong_type, | ||
| 217 | .c_ulonglong_type, | ||
| 218 | .c_longdouble_type, | ||
| 219 | .f16_type, | ||
| 220 | .f32_type, | ||
| 221 | .f64_type, | ||
| 222 | .f128_type, | ||
| 223 | .c_void_type, | ||
| 224 | .bool_type, | ||
| 225 | .void_type, | ||
| 226 | .type_type, | ||
| 227 | .anyerror_type, | ||
| 228 | .comptime_int_type, | ||
| 229 | .comptime_float_type, | ||
| 230 | .noreturn_type, | ||
| 231 | .fn_naked_noreturn_no_args_type, | ||
| 232 | .const_slice_u8_type, | ||
| 233 | .void_value, | ||
| 234 | .noreturn_value, | ||
| 235 | .bool_true, | ||
| 236 | .bool_false, | ||
| 237 | .function, | ||
| 238 | .ref, | ||
| 239 | .bytes, | ||
| 240 | => unreachable, | ||
| 241 | |||
| 242 | .int_u64 => switch (ty.zigTypeTag()) { | ||
| 243 | .Int => { | ||
| 244 | const x = self.cast(Payload.Int_u64).?.int; | ||
| 245 | const info = ty.intInfo(target); | ||
| 246 | const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signed); | ||
| 247 | return info.bits >= needed_bits; | ||
| 248 | }, | ||
| 249 | .ComptimeInt => return true, | ||
| 250 | else => unreachable, | ||
| 251 | }, | ||
| 252 | .int_i64 => switch (ty.zigTypeTag()) { | ||
| 253 | .Int => { | ||
| 254 | const x = self.cast(Payload.Int_i64).?.int; | ||
| 255 | const info = ty.intInfo(target); | ||
| 256 | if (!info.signed and x < 0) | ||
| 257 | return false; | ||
| 258 | @panic("TODO implement i64 intFitsInType"); | ||
| 259 | }, | ||
| 260 | .ComptimeInt => return true, | ||
| 261 | else => unreachable, | ||
| 262 | }, | ||
| 263 | .int_big => switch (ty.zigTypeTag()) { | ||
| 264 | .Int => { | ||
| 265 | const info = ty.intInfo(target); | ||
| 266 | return self.cast(Payload.IntBig).?.big_int.fitsInTwosComp(info.signed, info.bits); | ||
| 267 | }, | ||
| 268 | .ComptimeInt => return true, | ||
| 269 | else => unreachable, | ||
| 270 | }, | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 201 | /// This type is not copyable since it may contain pointers to its inner data. | 274 | /// This type is not copyable since it may contain pointers to its inner data. |
| 202 | pub const Payload = struct { | 275 | pub const Payload = struct { |
| 203 | tag: Tag, | 276 | tag: Tag, |
src/ir.cpp+3-3| ... | @@ -11289,9 +11289,9 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstGen *instruction | ... | @@ -11289,9 +11289,9 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstGen *instruction |
| 11289 | Buf *val_buf = buf_alloc(); | 11289 | Buf *val_buf = buf_alloc(); |
| 11290 | bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); | 11290 | bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); |
| 11291 | ir_add_error_node(ira, instruction->base.source_node, | 11291 | ir_add_error_node(ira, instruction->base.source_node, |
| 11292 | buf_sprintf("integer value %s has no representation in type '%s'", | 11292 | buf_sprintf("type %s cannot represent integer value %s", |
| 11293 | buf_ptr(val_buf), | 11293 | buf_ptr(&other_type->name), |
| 11294 | buf_ptr(&other_type->name))); | 11294 | buf_ptr(val_buf))); |
| 11295 | return false; | 11295 | return false; |
| 11296 | } | 11296 | } |
| 11297 | if (other_type->data.floating.bit_count >= const_val->type->data.floating.bit_count) { | 11297 | if (other_type->data.floating.bit_count >= const_val->type->data.floating.bit_count) { |