╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ codegen.zig ──────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
892 /// The bit-width of the immediate may be smaller than `u64`. For example, on 32-bit targets 893 /// such as ARM, the immediate will never exceed 32-bits. 894 immediate: u64, 895 /// Decl with address deferred until the linker allocates everything in virtual memory. 896 /// Payload is a symbol index. 897 load_direct: link.File.SymbolId, 898 /// Decl with address deferred until the linker allocates everything in virtual memory. 899 /// Payload is a symbol index. 900 lea_direct: link.File.SymbolId, 901 /// Decl referenced via GOT with address deferred until the linker allocates 902 /// everything in virtual memory. 903 /// Payload is a symbol index. 904 load_got: link.File.SymbolId, 905 /// Direct by-address reference to memory location. 906 memory: u64, 907 /// Reference to memory location but deferred until linker allocated the Decl in memory. 908 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file. 909 load_symbol: link.File.SymbolId, 910 /// Reference to memory location but deferred until linker allocated the Decl in memory. 911 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file. 912 lea_symbol: link.File.SymbolId, 913 }; 914 915 /// deprecated legacy code path 916 pub fn genTypedValue( 917 lf: *link.File, 918 pt: Zcu.PerThread, 919 val: Value, 920 target: *const std.Target, 921 ) Error!MCValue { 922 const res = try lowerValue(pt, val, target); 923 return switch (res) { 924 .none => .none, 925 .undef => .undef, 926 .immediate => |imm| .{ .immediate = imm }, 927 .lea_nav => |nav| .{ .lea_symbol = try genNavRef(lf, pt, nav) }, 928 .load_uav => |uav| .{ .load_symbol = try lf.lowerUav( 929 pt, 930 uav.val, 931 Type.fromInterned(uav.orig_ty).ptrAlignment(pt.zcu), 932 ) }, 933 .lea_uav => |uav| .{ .lea_symbol = try lf.lowerUav( 934 pt, 935 uav.val, 936 Type.fromInterned(uav.orig_ty).ptrAlignment(pt.zcu), 937 ) }, 938 }; 939 } 940 941 const LowerResult = union(enum) { 942 none, 943 undef, 944 /// The bit-width of the immediate may be smaller than `u64`. For example, on 32-bit targets 945 /// such as ARM, the immediate will never exceed 32-bits. 946 immediate: u64, 947 lea_nav: InternPool.Nav.Index, 948 load_uav: InternPool.Key.Ptr.BaseAddr.Uav, 949 lea_uav: InternPool.Key.Ptr.BaseAddr.Uav, 950 }; 951 952 pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allocator.Error!LowerResult { 953 const zcu = pt.zcu; 954 const ip = &zcu.intern_pool; 955 const ty = val.typeOf(zcu); 956 957 log.debug("lowerValue(@as({f}, {f}))", .{ ty.fmt(pt), val.fmtValue(pt) }); 958 959 if (val.isUndef(zcu)) return .undef; 960 961 switch (ty.zigTypeTag(zcu)) { 962 .void => return .none, 963 .bool => return .{ .immediate = @intFromBool(val.toBool()) }, 964 .pointer => switch (ty.ptrSize(zcu)) { 965 .slice => {}, 966 .one, .many, .c => { 967 const ptr = ip.indexToKey(val.toIntern()).ptr; 968 if (ptr.base_addr == .int) return .{ .immediate = ptr.byte_offset }; 969 if (ptr.byte_offset == 0) switch (ptr.base_addr) { 970 .int => unreachable, // handled above 971 972 .nav => |nav_index| { 973 const nav = ip.getNav(nav_index); 974 const nav_ty: Type = .fromInterned(nav.resolved.?.type); 975 if (nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) or nav.getExtern(ip) != null) { 976 return .{ .lea_nav = nav_index }; 977 } else { 978 // Create the 0xaa bit pattern... 979 const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3); 980 // ...but align the pointer 981 const alignment = zcu.navAlignment(nav_index); 982 return .{ .immediate = alignment.forward(undef_ptr_bits) }; 983 } 984 }, 985 986 .uav => |uav| if (Value.fromInterned(uav.val).typeOf(zcu).isRuntimeFnOrHasRuntimeBits(zcu)) { 987 return .{ .lea_uav = uav }; 988 } else { 989 // Create the 0xaa bit pattern... 990 const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3); 991 // ...but align the pointer 992 const alignment = Type.fromInterned(uav.orig_ty).ptrAlignment(zcu); 993 return .{ .immediate = alignment.forward(undef_ptr_bits) }; 994 }, 995 996 else => {}, 997 }; 998 }, 999 }, 1000 .int => { 1001 const info = ty.intInfo(zcu); 1002 if (info.bits <= target.ptrBitWidth()) { 1003 const unsigned: u64 = switch (info.signedness) { 1004 .signed => @bitCast(val.toSignedInt(zcu)), 1005 .unsigned => val.toUnsignedInt(zcu), 1006 }; 1007 return .{ .immediate = unsigned }; 1008 } 1009 }, 1010 .optional => { 1011 if (ty.isPtrLikeOptional(zcu)) { 1012 return lowerValue( 1013 pt, 1014 val.optionalValue(zcu) orelse return .{ .immediate = 0 }, 1015 target, 1016 ); 1017 } else if (ty.abiSize(zcu) == 1) { 1018 return .{ .immediate = @intFromBool(!val.isNull(zcu)) }; 1019 } 1020 }, 1021 .@"enum" => { 1022 const enum_tag = ip.indexToKey(val.toIntern()).enum_tag; 1023 return lowerValue( 1024 pt, 1025 Value.fromInterned(enum_tag.int), 1026 target, 1027 ); 1028 }, 1029 .@"struct", .@"union" => if (ty.containerLayout(zcu) == .@"packed") { 1030 const bitpack = ip.indexToKey(val.toIntern()).bitpack; 1031 return lowerValue(pt, .fromInterned(bitpack.backing_int_val), target); 1032 }, 1033 .error_set => { 1034 const err_name = ip.indexToKey(val.toIntern()).err.name; 1035 const error_index = ip.getErrorValueIfExists(err_name).?; 1036 return .{ .immediate = error_index }; 1037 }, 1038 .error_union => { 1039 const err_type = ty.errorUnionSet(zcu); 1040 const payload_type = ty.errorUnionPayload(zcu); 1041 if (!payload_type.hasRuntimeBits(zcu)) { 1042 // We use the error type directly as the type. 1043 const err_int_ty = try pt.errorIntType(); 1044 switch (ip.indexToKey(val.toIntern()).error_union.val) { 1045 .err_name => |err_name| return lowerValue( 1046 pt, 1047 Value.fromInterned(try pt.intern(.{ .err = .{ 1048 .ty = err_type.toIntern(), 1049 .name = err_name, 1050 } })), 1051 target, 1052 ), 1053 .payload => return lowerValue( 1054 pt, 1055 try pt.intValue(err_int_ty, 0), 1056 target, 1057 ), 1058 } 1059 } 1060 }, 1061 1062 .comptime_int => unreachable, 1063 .comptime_float => unreachable, 1064 .type => unreachable, 1065 .enum_literal => unreachable, 1066 .noreturn => unreachable, 1067 .undefined => unreachable, 1068 .null => unreachable, 1069 .@"opaque" => unreachable, 1070 1071 else => {}, 1072 } 1073 1074 return .{ .load_uav = .{ 1075 .val = val.toIntern(), 1076 .orig_ty = (try pt.singleConstPtrType(ty)).toIntern(), 1077 } }; 1078 } 1079 1080 pub fn errUnionPayloadOffset(payload_ty: Type, zcu: *Zcu) u64 { 1081 if (!payload_ty.hasRuntimeBits(zcu)) return 0; 1082 const payload_align = payload_ty.abiAlignment(zcu); 1083 const error_align = Type.anyerror.abiAlignment(zcu); 1084 if (payload_align.compare(.gte, error_align) or !payload_ty.hasRuntimeBits(zcu)) { 1085 return 0; 1086 } else { 1087 return payload_align.forward(Type.anyerror.abiSize(zcu)); 1088 } 1089 } 1090 1091 pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Zcu) u64 { 1092 if (!payload_ty.hasRuntimeBits(zcu)) return 0; 1093 const payload_align = payload_ty.abiAlignment(zcu); 1094 const error_align = Type.anyerror.abiAlignment(zcu); 1095 if (payload_align.compare(.gte, error_align) and payload_ty.hasRuntimeBits(zcu)) { 1096 return error_align.forward(payload_ty.abiSize(zcu)); 1097 } else { 1098 return 0; 1099 } 1100 } 1101 1102 pub fn fieldOffset(ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32, zcu: *Zcu) u64 { 1103 const agg_ty = ptr_agg_ty.childType(zcu); 1104 return switch (agg_ty.containerLayout(zcu)) { 1105 .auto, .@"extern" => agg_ty.structFieldOffset(field_index, zcu), 1106 .@"packed" => @divExact(@as(u64, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) + 1107 (if (zcu.typeToPackedStruct(agg_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0) - 1108 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), 1109 }; 1110 } 1111 1112 pub const FlattenedItem = struct { offset: u64, type: ?Type }; 1113 pub fn flattenType(items_buf: []FlattenedItem, ty: Type, zcu: *Zcu, opts: struct { 1114 offset: u64 = 0, 1115 allow_arrays: bool = true, 1116 fn increaseOffset(opts: @This(), offset: u64) @This() { 1117 return .{ 1118 .offset = opts.offset + offset, 1119 .allow_arrays = opts.allow_arrays, 1120 }; 1121 } 1122 }) ?[]FlattenedItem { 1123 const ip = &zcu.intern_pool; 1124 switch (ip.indexToKey(ty.toIntern())) { 1125 .int_type => |int_type| { 1126 if (int_type.bits == 0) return items_buf[0..0]; 1127 if (items_buf.len < 1) return null; 1128 const items = items_buf[0..1]; 1129 items.* = .{.{ .offset = opts.offset, .type = ty }}; 1130 return items; 1131 }, 1132 .ptr_type => |ptr_type| switch (ptr_type.flags.size) { 1133 .one, .many, .c => { 1134 if (items_buf.len < 1) return null; 1135 const items = items_buf[0..1]; 1136 items.* = .{.{ .offset = opts.offset, .type = ty }}; 1137 return items; 1138 }, 1139 .slice => { 1140 if (items_buf.len < 2) return null; 1141 const items = items_buf[0..2]; 1142 const ptr_field_ty = ty.slicePtrFieldType(zcu); 1143 items.* = .{ 1144 .{ .offset = opts.offset, .type = ptr_field_ty }, 1145 .{ .offset = opts.offset + ptr_field_ty.abiSize(zcu), .type = .usize }, 1146 }; 1147 return items; 1148 }, 1149 }, 1150 .array_type => |array_type| { 1151 const len = array_type.lenIncludingSentinel(); 1152 if (len == 0) return items_buf[0..0]; 1153 const elem_ty: Type = .fromInterned(array_type.child); 1154 const elem_items = flattenType(items_buf, elem_ty, zcu, opts) orelse return null; 1155 if (elem_items.len == 0) return items_buf[0..0]; 1156 if (!opts.allow_arrays) return null; 1157 const items_len, const items_overflow = @mulWithOverflow(elem_items.len, len); 1158 if (items_overflow != 0 or items_buf.len < items_len) return null; 1159 var items_index = elem_items.len; 1160 const elem_size = elem_ty.abiSize(zcu); 1161 var elem_offset: u64 = elem_size; 1162 while (items_index != items_len) : ({ 1163 items_index += elem_items.len; 1164 elem_offset += elem_size; 1165 }) for (items_buf[items_index..][0..elem_items.len], elem_items) |*item, elem_item| { 1166 item.* = .{ .offset = elem_offset + elem_item.offset, .type = elem_item.type }; 1167 }; 1168 return items_buf[0..@intCast(items_len)]; 1169 }, 1170 .vector_type => |vector_type| { 1171 if (vector_type.len == 0) return items_buf[0..0]; 1172 if (items_buf.len < 1) return null; 1173 const items = items_buf[0..1]; 1174 items.* = .{.{ .offset = opts.offset, .type = ty }}; 1175 return items; 1176 }, 1177 .opt_type, .error_union_type => return null, 1178 .simple_type => |simple_type| switch (simple_type) { 1179 .f16, 1180 .f32, 1181 .f64, 1182 .f80, 1183 .f128, 1184 .usize, 1185 .isize, 1186 .c_char, 1187 .c_short, 1188 .c_ushort, 1189 .c_int, 1190 .c_uint, 1191 .c_long, 1192 .c_ulong, 1193 .c_longlong, 1194 .c_ulonglong, 1195 .c_longdouble, 1196 .bool, 1197 .anyerror, 1198 => { 1199 if (items_buf.len < 1) return null; 1200 const items = items_buf[0..1]; 1201 items.* = .{.{ .offset = opts.offset, .type = ty }}; 1202 return items; 1203 }, 1204 .anyopaque, .noreturn => return null, 1205 .void, 1206 .type, 1207 .comptime_int, 1208 .comptime_float, 1209 .null, 1210 .undefined, 1211 .enum_literal, 1212 => return items_buf[0..0], 1213 .adhoc_inferred_error_set, .generic_poison => unreachable, 1214 }, 1215 .struct_type => { 1216 const loaded_struct = ip.loadStructType(ty.toIntern()); 1217 switch (loaded_struct.layout) { 1218 .auto, .@"extern" => {}, 1219 .@"packed" => return flattenType(items_buf, .fromInterned( 1220 loaded_struct.packed_backing_int_type, 1221 ), zcu, opts), 1222 } 1223 var items_len: usize = 0; 1224 var offset: u64 = 0; 1225 var field_it = loaded_struct.iterateRuntimeOrder(ip); 1226 while (field_it.next()) |field_index| { 1227 const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); 1228 const field_offset = loaded_struct.field_offsets.get(ip)[field_index]; 1229 if (field_offset - offset > 0 and 1230 (items_len == 0 or items_buf[items_len - 1].type != null)) 1231 { 1232 if (items_len == items_buf.len) return null; 1233 items_buf[items_len] = .{ .offset = offset, .type = null }; 1234 items_len += 1; 1235 } 1236 items_len += (flattenType(items_buf[items_len..], field_ty, zcu, opts.increaseOffset( 1237 field_offset, 1238 )) orelse return null).len; 1239 offset = field_offset + field_ty.abiSize(zcu); 1240 } 1241 if (ty.abiSize(zcu) - offset > 0 and 1242 (items_len == 0 or items_buf[items_len - 1].type != null)) 1243 { 1244 if (items_len == items_buf.len) return null; 1245 items_buf[items_len] = .{ .offset = offset, .type = null }; 1246 items_len += 1; 1247 } 1248 return items_buf[0..items_len]; 1249 }, 1250 .tuple_type => |tuple_type| { 1251 if (items_buf.len < tuple_type.types.len) return null; 1252 var items_len: usize = 0; 1253 var offset: u64 = 0; 1254 for (tuple_type.types.get(ip)) |field_ty_ip| { 1255 const field_ty: Type = .fromInterned(field_ty_ip); 1256 offset = field_ty.abiAlignment(zcu).forward(offset); 1257 items_len += (flattenType(items_buf[items_len..], field_ty, zcu, opts.increaseOffset( 1258 offset, 1259 )) orelse return null).len; 1260 offset += field_ty.abiSize(zcu); 1261 } 1262 return items_buf[0..items_len]; 1263 }, 1264 .union_type => { 1265 const loaded_union = ip.loadUnionType(ty.toIntern()); 1266 return switch (loaded_union.layout) { 1267 .auto, .@"extern" => return null, 1268 .@"packed" => return flattenType(items_buf, .fromInterned( 1269 loaded_union.packed_backing_int_type, 1270 ), zcu, opts), 1271 }; 1272 }, 1273 .opaque_type, .spirv_type, .func_type => return null, 1274 .enum_type => return flattenType(items_buf, .fromInterned( 1275 ip.loadEnumType(ty.toIntern()).int_tag_type, 1276 ), zcu, opts), 1277 .error_set_type, .inferred_error_set_type => { 1278 if (items_buf.len < 1) return null; 1279 const items = items_buf[0..1]; 1280 items.* = .{.{ .offset = opts.offset, .type = ty }}; 1281 return items; 1282 }, 1283 .anyframe_type, 1284 // values, not types 1285 .undef, 1286 .simple_value, 1287 .@"extern", 1288 .func, 1289 .int, 1290 .err, 1291 .error_union, 1292 .enum_literal, 1293 .enum_tag, 1294 .float, 1295 .ptr, 1296 .slice, 1297 .opt, 1298 .aggregate, 1299 .un, 1300 .bitpack, 1301 // memoization, not types 1302 .memoized_call, 1303 => unreachable, 1304 } 1305 } 1306 1307 test { 1308 _ = aarch64; 1309 _ = loongarch; 1310 } 1311