| ... | @@ -844,15 +844,77 @@ pub const DeclGen = struct { | ... | @@ -844,15 +844,77 @@ pub const DeclGen = struct { |
| 844 | var llvm_field_types = try std.ArrayListUnmanaged(*const llvm.Type).initCapacity(gpa, struct_obj.fields.count()); | 844 | var llvm_field_types = try std.ArrayListUnmanaged(*const llvm.Type).initCapacity(gpa, struct_obj.fields.count()); |
| 845 | defer llvm_field_types.deinit(gpa); | 845 | defer llvm_field_types.deinit(gpa); |
| 846 | | 846 | |
| 847 | for (struct_obj.fields.values()) |field| { | 847 | if (struct_obj.layout == .Packed) { |
| 848 | if (!field.ty.hasCodeGenBits()) continue; | 848 | const target = dg.module.getTarget(); |
| 849 | llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty)); | 849 | comptime assert(Type.packed_struct_layout_version == 1); |
| | 850 | var offset: u64 = 0; |
| | 851 | var running_bits: u16 = 0; |
| | 852 | for (struct_obj.fields.values()) |field| { |
| | 853 | if (!field.ty.hasCodeGenBits()) continue; |
| | 854 | |
| | 855 | const field_align = field.packedAlignment(); |
| | 856 | if (field_align == 0) { |
| | 857 | running_bits += @intCast(u16, field.ty.bitSize(target)); |
| | 858 | } else { |
| | 859 | if (running_bits != 0) { |
| | 860 | var int_payload: Type.Payload.Bits = .{ |
| | 861 | .base = .{ .tag = .int_unsigned }, |
| | 862 | .data = running_bits, |
| | 863 | }; |
| | 864 | const int_ty: Type = .{ .ptr_otherwise = &int_payload.base }; |
| | 865 | const int_align = int_ty.abiAlignment(target); |
| | 866 | const llvm_int_ty = try dg.llvmType(int_ty); |
| | 867 | const prev_offset = offset; |
| | 868 | offset = std.mem.alignForwardGeneric(u64, offset, int_align); |
| | 869 | const padding_bytes = @intCast(c_uint, offset - prev_offset); |
| | 870 | if (padding_bytes != 0) { |
| | 871 | const padding = dg.context.intType(8).arrayType(padding_bytes); |
| | 872 | llvm_field_types.appendAssumeCapacity(padding); |
| | 873 | } |
| | 874 | llvm_field_types.appendAssumeCapacity(llvm_int_ty); |
| | 875 | offset += int_ty.abiSize(target); |
| | 876 | running_bits = 0; |
| | 877 | } |
| | 878 | const prev_offset = offset; |
| | 879 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| | 880 | const padding_bytes = @intCast(c_uint, offset - prev_offset); |
| | 881 | if (padding_bytes != 0) { |
| | 882 | const padding = dg.context.intType(8).arrayType(padding_bytes); |
| | 883 | llvm_field_types.appendAssumeCapacity(padding); |
| | 884 | } |
| | 885 | llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty)); |
| | 886 | offset += field.ty.abiSize(target); |
| | 887 | } |
| | 888 | } |
| | 889 | |
| | 890 | if (running_bits != 0) { |
| | 891 | var int_payload: Type.Payload.Bits = .{ |
| | 892 | .base = .{ .tag = .int_unsigned }, |
| | 893 | .data = running_bits, |
| | 894 | }; |
| | 895 | const int_ty: Type = .{ .ptr_otherwise = &int_payload.base }; |
| | 896 | const int_align = int_ty.abiAlignment(target); |
| | 897 | const prev_offset = offset; |
| | 898 | offset = std.mem.alignForwardGeneric(u64, offset, int_align); |
| | 899 | const padding_bytes = @intCast(c_uint, offset - prev_offset); |
| | 900 | if (padding_bytes != 0) { |
| | 901 | const padding = dg.context.intType(8).arrayType(padding_bytes); |
| | 902 | llvm_field_types.appendAssumeCapacity(padding); |
| | 903 | } |
| | 904 | const llvm_int_ty = try dg.llvmType(int_ty); |
| | 905 | llvm_field_types.appendAssumeCapacity(llvm_int_ty); |
| | 906 | } |
| | 907 | } else { |
| | 908 | for (struct_obj.fields.values()) |field| { |
| | 909 | if (!field.ty.hasCodeGenBits()) continue; |
| | 910 | llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty)); |
| | 911 | } |
| 850 | } | 912 | } |
| 851 | | 913 | |
| 852 | llvm_struct_ty.structSetBody( | 914 | llvm_struct_ty.structSetBody( |
| 853 | llvm_field_types.items.ptr, | 915 | llvm_field_types.items.ptr, |
| 854 | @intCast(c_uint, llvm_field_types.items.len), | 916 | @intCast(c_uint, llvm_field_types.items.len), |
| 855 | llvm.Bool.fromBool(struct_obj.layout == .Packed), | 917 | .False, |
| 856 | ); | 918 | ); |
| 857 | | 919 | |
| 858 | return llvm_struct_ty; | 920 | return llvm_struct_ty; |
| ... | @@ -980,23 +1042,23 @@ pub const DeclGen = struct { | ... | @@ -980,23 +1042,23 @@ pub const DeclGen = struct { |
| 980 | } | 1042 | } |
| 981 | } | 1043 | } |
| 982 | | 1044 | |
| 983 | fn genTypedValue(self: *DeclGen, tv: TypedValue) Error!*const llvm.Value { | 1045 | fn genTypedValue(dg: *DeclGen, tv: TypedValue) Error!*const llvm.Value { |
| 984 | if (tv.val.isUndef()) { | 1046 | if (tv.val.isUndef()) { |
| 985 | const llvm_type = try self.llvmType(tv.ty); | 1047 | const llvm_type = try dg.llvmType(tv.ty); |
| 986 | return llvm_type.getUndef(); | 1048 | return llvm_type.getUndef(); |
| 987 | } | 1049 | } |
| 988 | | 1050 | |
| 989 | switch (tv.ty.zigTypeTag()) { | 1051 | switch (tv.ty.zigTypeTag()) { |
| 990 | .Bool => { | 1052 | .Bool => { |
| 991 | const llvm_type = try self.llvmType(tv.ty); | 1053 | const llvm_type = try dg.llvmType(tv.ty); |
| 992 | return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(); | 1054 | return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(); |
| 993 | }, | 1055 | }, |
| 994 | .Int => { | 1056 | .Int => { |
| 995 | var bigint_space: Value.BigIntSpace = undefined; | 1057 | var bigint_space: Value.BigIntSpace = undefined; |
| 996 | const bigint = tv.val.toBigInt(&bigint_space); | 1058 | const bigint = tv.val.toBigInt(&bigint_space); |
| 997 | const target = self.module.getTarget(); | 1059 | const target = dg.module.getTarget(); |
| 998 | const int_info = tv.ty.intInfo(target); | 1060 | const int_info = tv.ty.intInfo(target); |
| 999 | const llvm_type = self.context.intType(int_info.bits); | 1061 | const llvm_type = dg.context.intType(int_info.bits); |
| 1000 | | 1062 | |
| 1001 | const unsigned_val = v: { | 1063 | const unsigned_val = v: { |
| 1002 | if (bigint.limbs.len == 1) { | 1064 | if (bigint.limbs.len == 1) { |
| ... | @@ -1022,9 +1084,9 @@ pub const DeclGen = struct { | ... | @@ -1022,9 +1084,9 @@ pub const DeclGen = struct { |
| 1022 | var bigint_space: Value.BigIntSpace = undefined; | 1084 | var bigint_space: Value.BigIntSpace = undefined; |
| 1023 | const bigint = int_val.toBigInt(&bigint_space); | 1085 | const bigint = int_val.toBigInt(&bigint_space); |
| 1024 | | 1086 | |
| 1025 | const target = self.module.getTarget(); | 1087 | const target = dg.module.getTarget(); |
| 1026 | const int_info = tv.ty.intInfo(target); | 1088 | const int_info = tv.ty.intInfo(target); |
| 1027 | const llvm_type = self.context.intType(int_info.bits); | 1089 | const llvm_type = dg.context.intType(int_info.bits); |
| 1028 | | 1090 | |
| 1029 | const unsigned_val = v: { | 1091 | const unsigned_val = v: { |
| 1030 | if (bigint.limbs.len == 1) { | 1092 | if (bigint.limbs.len == 1) { |
| ... | @@ -1044,8 +1106,8 @@ pub const DeclGen = struct { | ... | @@ -1044,8 +1106,8 @@ pub const DeclGen = struct { |
| 1044 | return unsigned_val; | 1106 | return unsigned_val; |
| 1045 | }, | 1107 | }, |
| 1046 | .Float => { | 1108 | .Float => { |
| 1047 | const llvm_ty = try self.llvmType(tv.ty); | 1109 | const llvm_ty = try dg.llvmType(tv.ty); |
| 1048 | if (tv.ty.floatBits(self.module.getTarget()) <= 64) { | 1110 | if (tv.ty.floatBits(dg.module.getTarget()) <= 64) { |
| 1049 | return llvm_ty.constReal(tv.val.toFloat(f64)); | 1111 | return llvm_ty.constReal(tv.val.toFloat(f64)); |
| 1050 | } | 1112 | } |
| 1051 | | 1113 | |
| ... | @@ -1056,18 +1118,18 @@ pub const DeclGen = struct { | ... | @@ -1056,18 +1118,18 @@ pub const DeclGen = struct { |
| 1056 | std.mem.swap(u64, &buf[0], &buf[1]); | 1118 | std.mem.swap(u64, &buf[0], &buf[1]); |
| 1057 | } | 1119 | } |
| 1058 | | 1120 | |
| 1059 | const int = self.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf); | 1121 | const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf); |
| 1060 | return int.constBitCast(llvm_ty); | 1122 | return int.constBitCast(llvm_ty); |
| 1061 | }, | 1123 | }, |
| 1062 | .Pointer => switch (tv.val.tag()) { | 1124 | .Pointer => switch (tv.val.tag()) { |
| 1063 | .decl_ref_mut => return lowerDeclRefValue(self, tv, tv.val.castTag(.decl_ref_mut).?.data.decl), | 1125 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl), |
| 1064 | .decl_ref => return lowerDeclRefValue(self, tv, tv.val.castTag(.decl_ref).?.data), | 1126 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), |
| 1065 | .variable => { | 1127 | .variable => { |
| 1066 | const decl = tv.val.castTag(.variable).?.data.owner_decl; | 1128 | const decl = tv.val.castTag(.variable).?.data.owner_decl; |
| 1067 | decl.alive = true; | 1129 | decl.alive = true; |
| 1068 | const val = try self.resolveGlobalDecl(decl); | 1130 | const val = try dg.resolveGlobalDecl(decl); |
| 1069 | const llvm_var_type = try self.llvmType(tv.ty); | 1131 | const llvm_var_type = try dg.llvmType(tv.ty); |
| 1070 | const llvm_addrspace = self.llvmAddressSpace(decl.@"addrspace"); | 1132 | const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace"); |
| 1071 | const llvm_type = llvm_var_type.pointerType(llvm_addrspace); | 1133 | const llvm_type = llvm_var_type.pointerType(llvm_addrspace); |
| 1072 | return val.constBitCast(llvm_type); | 1134 | return val.constBitCast(llvm_type); |
| 1073 | }, | 1135 | }, |
| ... | @@ -1075,26 +1137,26 @@ pub const DeclGen = struct { | ... | @@ -1075,26 +1137,26 @@ pub const DeclGen = struct { |
| 1075 | const slice = tv.val.castTag(.slice).?.data; | 1137 | const slice = tv.val.castTag(.slice).?.data; |
| 1076 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1138 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1077 | const fields: [2]*const llvm.Value = .{ | 1139 | const fields: [2]*const llvm.Value = .{ |
| 1078 | try self.genTypedValue(.{ | 1140 | try dg.genTypedValue(.{ |
| 1079 | .ty = tv.ty.slicePtrFieldType(&buf), | 1141 | .ty = tv.ty.slicePtrFieldType(&buf), |
| 1080 | .val = slice.ptr, | 1142 | .val = slice.ptr, |
| 1081 | }), | 1143 | }), |
| 1082 | try self.genTypedValue(.{ | 1144 | try dg.genTypedValue(.{ |
| 1083 | .ty = Type.usize, | 1145 | .ty = Type.usize, |
| 1084 | .val = slice.len, | 1146 | .val = slice.len, |
| 1085 | }), | 1147 | }), |
| 1086 | }; | 1148 | }; |
| 1087 | return self.context.constStruct(&fields, fields.len, .False); | 1149 | return dg.context.constStruct(&fields, fields.len, .False); |
| 1088 | }, | 1150 | }, |
| 1089 | .int_u64, .one, .int_big_positive => { | 1151 | .int_u64, .one, .int_big_positive => { |
| 1090 | const llvm_usize = try self.llvmType(Type.usize); | 1152 | const llvm_usize = try dg.llvmType(Type.usize); |
| 1091 | const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False); | 1153 | const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False); |
| 1092 | return llvm_int.constIntToPtr(try self.llvmType(tv.ty)); | 1154 | return llvm_int.constIntToPtr(try dg.llvmType(tv.ty)); |
| 1093 | }, | 1155 | }, |
| 1094 | .field_ptr => { | 1156 | .field_ptr => { |
| 1095 | const field_ptr = tv.val.castTag(.field_ptr).?.data; | 1157 | const field_ptr = tv.val.castTag(.field_ptr).?.data; |
| 1096 | const parent_ptr = try self.lowerParentPtr(field_ptr.container_ptr); | 1158 | const parent_ptr = try dg.lowerParentPtr(field_ptr.container_ptr); |
| 1097 | const llvm_u32 = self.context.intType(32); | 1159 | const llvm_u32 = dg.context.intType(32); |
| 1098 | const indices: [2]*const llvm.Value = .{ | 1160 | const indices: [2]*const llvm.Value = .{ |
| 1099 | llvm_u32.constInt(0, .False), | 1161 | llvm_u32.constInt(0, .False), |
| 1100 | llvm_u32.constInt(field_ptr.field_index, .False), | 1162 | llvm_u32.constInt(field_ptr.field_index, .False), |
| ... | @@ -1103,8 +1165,8 @@ pub const DeclGen = struct { | ... | @@ -1103,8 +1165,8 @@ pub const DeclGen = struct { |
| 1103 | }, | 1165 | }, |
| 1104 | .elem_ptr => { | 1166 | .elem_ptr => { |
| 1105 | const elem_ptr = tv.val.castTag(.elem_ptr).?.data; | 1167 | const elem_ptr = tv.val.castTag(.elem_ptr).?.data; |
| 1106 | const parent_ptr = try self.lowerParentPtr(elem_ptr.array_ptr); | 1168 | const parent_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr); |
| 1107 | const llvm_usize = try self.llvmType(Type.usize); | 1169 | const llvm_usize = try dg.llvmType(Type.usize); |
| 1108 | if (parent_ptr.typeOf().getElementType().getTypeKind() == .Array) { | 1170 | if (parent_ptr.typeOf().getElementType().getTypeKind() == .Array) { |
| 1109 | const indices: [2]*const llvm.Value = .{ | 1171 | const indices: [2]*const llvm.Value = .{ |
| 1110 | llvm_usize.constInt(0, .False), | 1172 | llvm_usize.constInt(0, .False), |
| ... | @@ -1119,15 +1181,15 @@ pub const DeclGen = struct { | ... | @@ -1119,15 +1181,15 @@ pub const DeclGen = struct { |
| 1119 | } | 1181 | } |
| 1120 | }, | 1182 | }, |
| 1121 | .null_value, .zero => { | 1183 | .null_value, .zero => { |
| 1122 | const llvm_type = try self.llvmType(tv.ty); | 1184 | const llvm_type = try dg.llvmType(tv.ty); |
| 1123 | return llvm_type.constNull(); | 1185 | return llvm_type.constNull(); |
| 1124 | }, | 1186 | }, |
| 1125 | else => |tag| return self.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }), | 1187 | else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }), |
| 1126 | }, | 1188 | }, |
| 1127 | .Array => switch (tv.val.tag()) { | 1189 | .Array => switch (tv.val.tag()) { |
| 1128 | .bytes => { | 1190 | .bytes => { |
| 1129 | const bytes = tv.val.castTag(.bytes).?.data; | 1191 | const bytes = tv.val.castTag(.bytes).?.data; |
| 1130 | return self.context.constString( | 1192 | return dg.context.constString( |
| 1131 | bytes.ptr, | 1193 | bytes.ptr, |
| 1132 | @intCast(c_uint, bytes.len), | 1194 | @intCast(c_uint, bytes.len), |
| 1133 | .True, // don't null terminate. bytes has the sentinel, if any. | 1195 | .True, // don't null terminate. bytes has the sentinel, if any. |
| ... | @@ -1136,13 +1198,13 @@ pub const DeclGen = struct { | ... | @@ -1136,13 +1198,13 @@ pub const DeclGen = struct { |
| 1136 | .array => { | 1198 | .array => { |
| 1137 | const elem_vals = tv.val.castTag(.array).?.data; | 1199 | const elem_vals = tv.val.castTag(.array).?.data; |
| 1138 | const elem_ty = tv.ty.elemType(); | 1200 | const elem_ty = tv.ty.elemType(); |
| 1139 | const gpa = self.gpa; | 1201 | const gpa = dg.gpa; |
| 1140 | const llvm_elems = try gpa.alloc(*const llvm.Value, elem_vals.len); | 1202 | const llvm_elems = try gpa.alloc(*const llvm.Value, elem_vals.len); |
| 1141 | defer gpa.free(llvm_elems); | 1203 | defer gpa.free(llvm_elems); |
| 1142 | for (elem_vals) |elem_val, i| { | 1204 | for (elem_vals) |elem_val, i| { |
| 1143 | llvm_elems[i] = try self.genTypedValue(.{ .ty = elem_ty, .val = elem_val }); | 1205 | llvm_elems[i] = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_val }); |
| 1144 | } | 1206 | } |
| 1145 | const llvm_elem_ty = try self.llvmType(elem_ty); | 1207 | const llvm_elem_ty = try dg.llvmType(elem_ty); |
| 1146 | return llvm_elem_ty.constArray( | 1208 | return llvm_elem_ty.constArray( |
| 1147 | llvm_elems.ptr, | 1209 | llvm_elems.ptr, |
| 1148 | @intCast(c_uint, llvm_elems.len), | 1210 | @intCast(c_uint, llvm_elems.len), |
| ... | @@ -1154,16 +1216,16 @@ pub const DeclGen = struct { | ... | @@ -1154,16 +1216,16 @@ pub const DeclGen = struct { |
| 1154 | const sentinel = tv.ty.sentinel(); | 1216 | const sentinel = tv.ty.sentinel(); |
| 1155 | const len = @intCast(usize, tv.ty.arrayLen()); | 1217 | const len = @intCast(usize, tv.ty.arrayLen()); |
| 1156 | const len_including_sent = len + @boolToInt(sentinel != null); | 1218 | const len_including_sent = len + @boolToInt(sentinel != null); |
| 1157 | const gpa = self.gpa; | 1219 | const gpa = dg.gpa; |
| 1158 | const llvm_elems = try gpa.alloc(*const llvm.Value, len_including_sent); | 1220 | const llvm_elems = try gpa.alloc(*const llvm.Value, len_including_sent); |
| 1159 | defer gpa.free(llvm_elems); | 1221 | defer gpa.free(llvm_elems); |
| 1160 | for (llvm_elems[0..len]) |*elem| { | 1222 | for (llvm_elems[0..len]) |*elem| { |
| 1161 | elem.* = try self.genTypedValue(.{ .ty = elem_ty, .val = val }); | 1223 | elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val }); |
| 1162 | } | 1224 | } |
| 1163 | if (sentinel) |sent| { | 1225 | if (sentinel) |sent| { |
| 1164 | llvm_elems[len] = try self.genTypedValue(.{ .ty = elem_ty, .val = sent }); | 1226 | llvm_elems[len] = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent }); |
| 1165 | } | 1227 | } |
| 1166 | const llvm_elem_ty = try self.llvmType(elem_ty); | 1228 | const llvm_elem_ty = try dg.llvmType(elem_ty); |
| 1167 | return llvm_elem_ty.constArray( | 1229 | return llvm_elem_ty.constArray( |
| 1168 | llvm_elems.ptr, | 1230 | llvm_elems.ptr, |
| 1169 | @intCast(c_uint, llvm_elems.len), | 1231 | @intCast(c_uint, llvm_elems.len), |
| ... | @@ -1172,9 +1234,9 @@ pub const DeclGen = struct { | ... | @@ -1172,9 +1234,9 @@ pub const DeclGen = struct { |
| 1172 | .empty_array_sentinel => { | 1234 | .empty_array_sentinel => { |
| 1173 | const elem_ty = tv.ty.elemType(); | 1235 | const elem_ty = tv.ty.elemType(); |
| 1174 | const sent_val = tv.ty.sentinel().?; | 1236 | const sent_val = tv.ty.sentinel().?; |
| 1175 | const sentinel = try self.genTypedValue(.{ .ty = elem_ty, .val = sent_val }); | 1237 | const sentinel = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent_val }); |
| 1176 | const llvm_elems: [1]*const llvm.Value = .{sentinel}; | 1238 | const llvm_elems: [1]*const llvm.Value = .{sentinel}; |
| 1177 | const llvm_elem_ty = try self.llvmType(elem_ty); | 1239 | const llvm_elem_ty = try dg.llvmType(elem_ty); |
| 1178 | return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len); | 1240 | return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len); |
| 1179 | }, | 1241 | }, |
| 1180 | else => unreachable, | 1242 | else => unreachable, |
| ... | @@ -1182,7 +1244,7 @@ pub const DeclGen = struct { | ... | @@ -1182,7 +1244,7 @@ pub const DeclGen = struct { |
| 1182 | .Optional => { | 1244 | .Optional => { |
| 1183 | var buf: Type.Payload.ElemType = undefined; | 1245 | var buf: Type.Payload.ElemType = undefined; |
| 1184 | const payload_ty = tv.ty.optionalChild(&buf); | 1246 | const payload_ty = tv.ty.optionalChild(&buf); |
| 1185 | const llvm_i1 = self.context.intType(1); | 1247 | const llvm_i1 = dg.context.intType(1); |
| 1186 | const is_pl = !tv.val.isNull(); | 1248 | const is_pl = !tv.val.isNull(); |
| 1187 | const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull(); | 1249 | const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull(); |
| 1188 | if (!payload_ty.hasCodeGenBits()) { | 1250 | if (!payload_ty.hasCodeGenBits()) { |
| ... | @@ -1190,22 +1252,22 @@ pub const DeclGen = struct { | ... | @@ -1190,22 +1252,22 @@ pub const DeclGen = struct { |
| 1190 | } | 1252 | } |
| 1191 | if (tv.ty.isPtrLikeOptional()) { | 1253 | if (tv.ty.isPtrLikeOptional()) { |
| 1192 | if (tv.val.castTag(.opt_payload)) |payload| { | 1254 | if (tv.val.castTag(.opt_payload)) |payload| { |
| 1193 | return self.genTypedValue(.{ .ty = payload_ty, .val = payload.data }); | 1255 | return dg.genTypedValue(.{ .ty = payload_ty, .val = payload.data }); |
| 1194 | } else if (is_pl) { | 1256 | } else if (is_pl) { |
| 1195 | return self.genTypedValue(.{ .ty = payload_ty, .val = tv.val }); | 1257 | return dg.genTypedValue(.{ .ty = payload_ty, .val = tv.val }); |
| 1196 | } else { | 1258 | } else { |
| 1197 | const llvm_ty = try self.llvmType(tv.ty); | 1259 | const llvm_ty = try dg.llvmType(tv.ty); |
| 1198 | return llvm_ty.constNull(); | 1260 | return llvm_ty.constNull(); |
| 1199 | } | 1261 | } |
| 1200 | } | 1262 | } |
| 1201 | const fields: [2]*const llvm.Value = .{ | 1263 | const fields: [2]*const llvm.Value = .{ |
| 1202 | try self.genTypedValue(.{ | 1264 | try dg.genTypedValue(.{ |
| 1203 | .ty = payload_ty, | 1265 | .ty = payload_ty, |
| 1204 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), | 1266 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), |
| 1205 | }), | 1267 | }), |
| 1206 | non_null_bit, | 1268 | non_null_bit, |
| 1207 | }; | 1269 | }; |
| 1208 | return self.context.constStruct(&fields, fields.len, .False); | 1270 | return dg.context.constStruct(&fields, fields.len, .False); |
| 1209 | }, | 1271 | }, |
| 1210 | .Fn => { | 1272 | .Fn => { |
| 1211 | const fn_decl = switch (tv.val.tag()) { | 1273 | const fn_decl = switch (tv.val.tag()) { |
| ... | @@ -1214,14 +1276,14 @@ pub const DeclGen = struct { | ... | @@ -1214,14 +1276,14 @@ pub const DeclGen = struct { |
| 1214 | else => unreachable, | 1276 | else => unreachable, |
| 1215 | }; | 1277 | }; |
| 1216 | fn_decl.alive = true; | 1278 | fn_decl.alive = true; |
| 1217 | return self.resolveLlvmFunction(fn_decl); | 1279 | return dg.resolveLlvmFunction(fn_decl); |
| 1218 | }, | 1280 | }, |
| 1219 | .ErrorSet => { | 1281 | .ErrorSet => { |
| 1220 | const llvm_ty = try self.llvmType(tv.ty); | 1282 | const llvm_ty = try dg.llvmType(tv.ty); |
| 1221 | switch (tv.val.tag()) { | 1283 | switch (tv.val.tag()) { |
| 1222 | .@"error" => { | 1284 | .@"error" => { |
| 1223 | const err_name = tv.val.castTag(.@"error").?.data.name; | 1285 | const err_name = tv.val.castTag(.@"error").?.data.name; |
| 1224 | const kv = try self.module.getErrorValue(err_name); | 1286 | const kv = try dg.module.getErrorValue(err_name); |
| 1225 | return llvm_ty.constInt(kv.value, .False); | 1287 | return llvm_ty.constInt(kv.value, .False); |
| 1226 | }, | 1288 | }, |
| 1227 | else => { | 1289 | else => { |
| ... | @@ -1238,76 +1300,138 @@ pub const DeclGen = struct { | ... | @@ -1238,76 +1300,138 @@ pub const DeclGen = struct { |
| 1238 | if (!payload_type.hasCodeGenBits()) { | 1300 | if (!payload_type.hasCodeGenBits()) { |
| 1239 | // We use the error type directly as the type. | 1301 | // We use the error type directly as the type. |
| 1240 | const err_val = if (!is_pl) tv.val else Value.initTag(.zero); | 1302 | const err_val = if (!is_pl) tv.val else Value.initTag(.zero); |
| 1241 | return self.genTypedValue(.{ .ty = error_type, .val = err_val }); | 1303 | return dg.genTypedValue(.{ .ty = error_type, .val = err_val }); |
| 1242 | } | 1304 | } |
| 1243 | | 1305 | |
| 1244 | const fields: [2]*const llvm.Value = .{ | 1306 | const fields: [2]*const llvm.Value = .{ |
| 1245 | try self.genTypedValue(.{ | 1307 | try dg.genTypedValue(.{ |
| 1246 | .ty = error_type, | 1308 | .ty = error_type, |
| 1247 | .val = if (is_pl) Value.initTag(.zero) else tv.val, | 1309 | .val = if (is_pl) Value.initTag(.zero) else tv.val, |
| 1248 | }), | 1310 | }), |
| 1249 | try self.genTypedValue(.{ | 1311 | try dg.genTypedValue(.{ |
| 1250 | .ty = payload_type, | 1312 | .ty = payload_type, |
| 1251 | .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), | 1313 | .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), |
| 1252 | }), | 1314 | }), |
| 1253 | }; | 1315 | }; |
| 1254 | return self.context.constStruct(&fields, fields.len, .False); | 1316 | return dg.context.constStruct(&fields, fields.len, .False); |
| 1255 | }, | 1317 | }, |
| 1256 | .Struct => { | 1318 | .Struct => { |
| 1257 | const llvm_struct_ty = try self.llvmType(tv.ty); | 1319 | const llvm_struct_ty = try dg.llvmType(tv.ty); |
| 1258 | const field_vals = tv.val.castTag(.@"struct").?.data; | 1320 | const field_vals = tv.val.castTag(.@"struct").?.data; |
| 1259 | const gpa = self.gpa; | 1321 | const gpa = dg.gpa; |
| 1260 | | 1322 | |
| 1261 | var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, field_vals.len); | 1323 | var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, field_vals.len); |
| 1262 | defer llvm_fields.deinit(gpa); | 1324 | defer llvm_fields.deinit(gpa); |
| 1263 | | 1325 | |
| 1264 | for (field_vals) |field_val, i| { | 1326 | const struct_obj = tv.ty.castTag(.@"struct").?.data; |
| 1265 | const field_ty = tv.ty.structFieldType(i); | 1327 | if (struct_obj.layout == .Packed) { |
| 1266 | if (!field_ty.hasCodeGenBits()) continue; | 1328 | const target = dg.module.getTarget(); |
| 1267 | | 1329 | const fields = struct_obj.fields.values(); |
| 1268 | llvm_fields.appendAssumeCapacity(try self.genTypedValue(.{ | 1330 | comptime assert(Type.packed_struct_layout_version == 1); |
| 1269 | .ty = field_ty, | 1331 | var offset: u64 = 0; |
| 1270 | .val = field_val, | 1332 | var running_bits: u16 = 0; |
| 1271 | })); | 1333 | var running_int: *const llvm.Value = llvm_struct_ty.structGetTypeAtIndex(0).constNull(); |
| | 1334 | for (field_vals) |field_val, i| { |
| | 1335 | const field = fields[i]; |
| | 1336 | if (!field.ty.hasCodeGenBits()) continue; |
| | 1337 | |
| | 1338 | const field_align = field.packedAlignment(); |
| | 1339 | if (field_align == 0) { |
| | 1340 | const non_int_val = try dg.genTypedValue(.{ |
| | 1341 | .ty = field.ty, |
| | 1342 | .val = field_val, |
| | 1343 | }); |
| | 1344 | const ty_bit_size = @intCast(u16, field.ty.bitSize(target)); |
| | 1345 | const llvm_int_ty = dg.context.intType(ty_bit_size); |
| | 1346 | const int_val = non_int_val.constBitCast(llvm_int_ty); |
| | 1347 | const shift_rhs = llvm_int_ty.constInt(running_bits, .False); |
| | 1348 | const shifted = int_val.constShl(shift_rhs); |
| | 1349 | running_int = running_int.constOr(shifted); |
| | 1350 | running_bits += ty_bit_size; |
| | 1351 | } else { |
| | 1352 | if (running_bits != 0) { |
| | 1353 | var int_payload: Type.Payload.Bits = .{ |
| | 1354 | .base = .{ .tag = .int_unsigned }, |
| | 1355 | .data = running_bits, |
| | 1356 | }; |
| | 1357 | const int_ty: Type = .{ .ptr_otherwise = &int_payload.base }; |
| | 1358 | const int_align = int_ty.abiAlignment(target); |
| | 1359 | const prev_offset = offset; |
| | 1360 | offset = std.mem.alignForwardGeneric(u64, offset, int_align); |
| | 1361 | const padding_bytes = @intCast(c_uint, offset - prev_offset); |
| | 1362 | if (padding_bytes != 0) { |
| | 1363 | const padding = dg.context.intType(8).arrayType(padding_bytes); |
| | 1364 | llvm_fields.appendAssumeCapacity(padding.getUndef()); |
| | 1365 | } |
| | 1366 | llvm_fields.appendAssumeCapacity(running_int); |
| | 1367 | running_int = llvm_struct_ty.structGetTypeAtIndex(@intCast(c_uint, llvm_fields.items.len)).constNull(); |
| | 1368 | offset += int_ty.abiSize(target); |
| | 1369 | running_bits = 0; |
| | 1370 | } |
| | 1371 | const prev_offset = offset; |
| | 1372 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| | 1373 | const padding_bytes = @intCast(c_uint, offset - prev_offset); |
| | 1374 | if (padding_bytes != 0) { |
| | 1375 | const padding = dg.context.intType(8).arrayType(padding_bytes); |
| | 1376 | llvm_fields.appendAssumeCapacity(padding.getUndef()); |
| | 1377 | } |
| | 1378 | llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{ |
| | 1379 | .ty = field.ty, |
| | 1380 | .val = field_val, |
| | 1381 | })); |
| | 1382 | offset += field.ty.abiSize(target); |
| | 1383 | } |
| | 1384 | } |
| | 1385 | } else { |
| | 1386 | for (field_vals) |field_val, i| { |
| | 1387 | const field_ty = tv.ty.structFieldType(i); |
| | 1388 | if (!field_ty.hasCodeGenBits()) continue; |
| | 1389 | |
| | 1390 | llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{ |
| | 1391 | .ty = field_ty, |
| | 1392 | .val = field_val, |
| | 1393 | })); |
| | 1394 | } |
| 1272 | } | 1395 | } |
| | 1396 | |
| 1273 | return llvm_struct_ty.constNamedStruct( | 1397 | return llvm_struct_ty.constNamedStruct( |
| 1274 | llvm_fields.items.ptr, | 1398 | llvm_fields.items.ptr, |
| 1275 | @intCast(c_uint, llvm_fields.items.len), | 1399 | @intCast(c_uint, llvm_fields.items.len), |
| 1276 | ); | 1400 | ); |
| 1277 | }, | 1401 | }, |
| 1278 | .Union => { | 1402 | .Union => { |
| 1279 | const llvm_union_ty = try self.llvmType(tv.ty); | 1403 | const llvm_union_ty = try dg.llvmType(tv.ty); |
| 1280 | const tag_and_val = tv.val.castTag(.@"union").?.data; | 1404 | const tag_and_val = tv.val.castTag(.@"union").?.data; |
| 1281 | | 1405 | |
| 1282 | const target = self.module.getTarget(); | 1406 | const target = dg.module.getTarget(); |
| 1283 | const layout = tv.ty.unionGetLayout(target); | 1407 | const layout = tv.ty.unionGetLayout(target); |
| 1284 | | 1408 | |
| 1285 | if (layout.payload_size == 0) { | 1409 | if (layout.payload_size == 0) { |
| 1286 | return genTypedValue(self, .{ .ty = tv.ty.unionTagType().?, .val = tag_and_val.tag }); | 1410 | return genTypedValue(dg, .{ .ty = tv.ty.unionTagType().?, .val = tag_and_val.tag }); |
| 1287 | } | 1411 | } |
| 1288 | const field_ty = tv.ty.unionFieldType(tag_and_val.tag); | 1412 | const field_ty = tv.ty.unionFieldType(tag_and_val.tag); |
| 1289 | const payload = p: { | 1413 | const payload = p: { |
| 1290 | if (!field_ty.hasCodeGenBits()) { | 1414 | if (!field_ty.hasCodeGenBits()) { |
| 1291 | const padding_len = @intCast(c_uint, layout.payload_size); | 1415 | const padding_len = @intCast(c_uint, layout.payload_size); |
| 1292 | break :p self.context.intType(8).arrayType(padding_len).getUndef(); | 1416 | break :p dg.context.intType(8).arrayType(padding_len).getUndef(); |
| 1293 | } | 1417 | } |
| 1294 | const field = try genTypedValue(self, .{ .ty = field_ty, .val = tag_and_val.val }); | 1418 | const field = try genTypedValue(dg, .{ .ty = field_ty, .val = tag_and_val.val }); |
| 1295 | const field_size = field_ty.abiSize(target); | 1419 | const field_size = field_ty.abiSize(target); |
| 1296 | if (field_size == layout.payload_size) { | 1420 | if (field_size == layout.payload_size) { |
| 1297 | break :p field; | 1421 | break :p field; |
| 1298 | } | 1422 | } |
| 1299 | const padding_len = @intCast(c_uint, layout.payload_size - field_size); | 1423 | const padding_len = @intCast(c_uint, layout.payload_size - field_size); |
| 1300 | const fields: [2]*const llvm.Value = .{ | 1424 | const fields: [2]*const llvm.Value = .{ |
| 1301 | field, self.context.intType(8).arrayType(padding_len).getUndef(), | 1425 | field, dg.context.intType(8).arrayType(padding_len).getUndef(), |
| 1302 | }; | 1426 | }; |
| 1303 | break :p self.context.constStruct(&fields, fields.len, .False); | 1427 | break :p dg.context.constStruct(&fields, fields.len, .False); |
| 1304 | }; | 1428 | }; |
| 1305 | if (layout.tag_size == 0) { | 1429 | if (layout.tag_size == 0) { |
| 1306 | const llvm_payload_ty = llvm_union_ty.structGetTypeAtIndex(0); | 1430 | const llvm_payload_ty = llvm_union_ty.structGetTypeAtIndex(0); |
| 1307 | const fields: [1]*const llvm.Value = .{payload.constBitCast(llvm_payload_ty)}; | 1431 | const fields: [1]*const llvm.Value = .{payload.constBitCast(llvm_payload_ty)}; |
| 1308 | return llvm_union_ty.constNamedStruct(&fields, fields.len); | 1432 | return llvm_union_ty.constNamedStruct(&fields, fields.len); |
| 1309 | } | 1433 | } |
| 1310 | const llvm_tag_value = try genTypedValue(self, .{ | 1434 | const llvm_tag_value = try genTypedValue(dg, .{ |
| 1311 | .ty = tv.ty.unionTagType().?, | 1435 | .ty = tv.ty.unionTagType().?, |
| 1312 | .val = tag_and_val.tag, | 1436 | .val = tag_and_val.tag, |
| 1313 | }); | 1437 | }); |
| ... | @@ -1329,15 +1453,15 @@ pub const DeclGen = struct { | ... | @@ -1329,15 +1453,15 @@ pub const DeclGen = struct { |
| 1329 | assert(vector_len == bytes.len or vector_len + 1 == bytes.len); | 1453 | assert(vector_len == bytes.len or vector_len + 1 == bytes.len); |
| 1330 | | 1454 | |
| 1331 | const elem_ty = tv.ty.elemType(); | 1455 | const elem_ty = tv.ty.elemType(); |
| 1332 | const llvm_elems = try self.gpa.alloc(*const llvm.Value, vector_len); | 1456 | const llvm_elems = try dg.gpa.alloc(*const llvm.Value, vector_len); |
| 1333 | defer self.gpa.free(llvm_elems); | 1457 | defer dg.gpa.free(llvm_elems); |
| 1334 | for (llvm_elems) |*elem, i| { | 1458 | for (llvm_elems) |*elem, i| { |
| 1335 | var byte_payload: Value.Payload.U64 = .{ | 1459 | var byte_payload: Value.Payload.U64 = .{ |
| 1336 | .base = .{ .tag = .int_u64 }, | 1460 | .base = .{ .tag = .int_u64 }, |
| 1337 | .data = bytes[i], | 1461 | .data = bytes[i], |
| 1338 | }; | 1462 | }; |
| 1339 | | 1463 | |
| 1340 | elem.* = try self.genTypedValue(.{ | 1464 | elem.* = try dg.genTypedValue(.{ |
| 1341 | .ty = elem_ty, | 1465 | .ty = elem_ty, |
| 1342 | .val = Value.initPayload(&byte_payload.base), | 1466 | .val = Value.initPayload(&byte_payload.base), |
| 1343 | }); | 1467 | }); |
| ... | @@ -1354,10 +1478,10 @@ pub const DeclGen = struct { | ... | @@ -1354,10 +1478,10 @@ pub const DeclGen = struct { |
| 1354 | const vector_len = @intCast(usize, tv.ty.arrayLen()); | 1478 | const vector_len = @intCast(usize, tv.ty.arrayLen()); |
| 1355 | assert(vector_len == elem_vals.len or vector_len + 1 == elem_vals.len); | 1479 | assert(vector_len == elem_vals.len or vector_len + 1 == elem_vals.len); |
| 1356 | const elem_ty = tv.ty.elemType(); | 1480 | const elem_ty = tv.ty.elemType(); |
| 1357 | const llvm_elems = try self.gpa.alloc(*const llvm.Value, vector_len); | 1481 | const llvm_elems = try dg.gpa.alloc(*const llvm.Value, vector_len); |
| 1358 | defer self.gpa.free(llvm_elems); | 1482 | defer dg.gpa.free(llvm_elems); |
| 1359 | for (llvm_elems) |*elem, i| { | 1483 | for (llvm_elems) |*elem, i| { |
| 1360 | elem.* = try self.genTypedValue(.{ .ty = elem_ty, .val = elem_vals[i] }); | 1484 | elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_vals[i] }); |
| 1361 | } | 1485 | } |
| 1362 | return llvm.constVector( | 1486 | return llvm.constVector( |
| 1363 | llvm_elems.ptr, | 1487 | llvm_elems.ptr, |
| ... | @@ -1369,10 +1493,10 @@ pub const DeclGen = struct { | ... | @@ -1369,10 +1493,10 @@ pub const DeclGen = struct { |
| 1369 | const val = tv.val.castTag(.repeated).?.data; | 1493 | const val = tv.val.castTag(.repeated).?.data; |
| 1370 | const elem_ty = tv.ty.elemType(); | 1494 | const elem_ty = tv.ty.elemType(); |
| 1371 | const len = @intCast(usize, tv.ty.arrayLen()); | 1495 | const len = @intCast(usize, tv.ty.arrayLen()); |
| 1372 | const llvm_elems = try self.gpa.alloc(*const llvm.Value, len); | 1496 | const llvm_elems = try dg.gpa.alloc(*const llvm.Value, len); |
| 1373 | defer self.gpa.free(llvm_elems); | 1497 | defer dg.gpa.free(llvm_elems); |
| 1374 | for (llvm_elems) |*elem| { | 1498 | for (llvm_elems) |*elem| { |
| 1375 | elem.* = try self.genTypedValue(.{ .ty = elem_ty, .val = val }); | 1499 | elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val }); |
| 1376 | } | 1500 | } |
| 1377 | return llvm.constVector( | 1501 | return llvm.constVector( |
| 1378 | llvm_elems.ptr, | 1502 | llvm_elems.ptr, |
| ... | @@ -1395,7 +1519,7 @@ pub const DeclGen = struct { | ... | @@ -1395,7 +1519,7 @@ pub const DeclGen = struct { |
| 1395 | | 1519 | |
| 1396 | .Frame, | 1520 | .Frame, |
| 1397 | .AnyFrame, | 1521 | .AnyFrame, |
| 1398 | => return self.todo("implement const of type '{}'", .{tv.ty}), | 1522 | => return dg.todo("implement const of type '{}'", .{tv.ty}), |
| 1399 | } | 1523 | } |
| 1400 | } | 1524 | } |
| 1401 | | 1525 | |
| ... | @@ -2403,26 +2527,28 @@ pub const FuncGen = struct { | ... | @@ -2403,26 +2527,28 @@ pub const FuncGen = struct { |
| 2403 | | 2527 | |
| 2404 | assert(isByRef(struct_ty)); | 2528 | assert(isByRef(struct_ty)); |
| 2405 | | 2529 | |
| 2406 | const field_ptr = switch (struct_ty.zigTypeTag()) { | 2530 | const target = self.dg.module.getTarget(); |
| 2407 | .Struct => blk: { | 2531 | switch (struct_ty.zigTypeTag()) { |
| 2408 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index); | 2532 | .Struct => { |
| 2409 | break :blk self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, ""); | 2533 | var ptr_ty_buf: Type.Payload.Pointer = undefined; |
| | 2534 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf); |
| | 2535 | const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, ""); |
| | 2536 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); |
| | 2537 | return self.load(field_ptr, field_ptr_ty); |
| 2410 | }, | 2538 | }, |
| 2411 | .Union => blk: { | 2539 | .Union => { |
| 2412 | const llvm_field_ty = try self.dg.llvmType(field_ty); | 2540 | const llvm_field_ty = try self.dg.llvmType(field_ty); |
| 2413 | const target = self.dg.module.getTarget(); | | |
| 2414 | const layout = struct_ty.unionGetLayout(target); | 2541 | const layout = struct_ty.unionGetLayout(target); |
| 2415 | const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); | 2542 | const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); |
| 2416 | const union_field_ptr = self.builder.buildStructGEP(struct_llvm_val, payload_index, ""); | 2543 | const union_field_ptr = self.builder.buildStructGEP(struct_llvm_val, payload_index, ""); |
| 2417 | break :blk self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), ""); | 2544 | const field_ptr = self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), ""); |
| | 2545 | if (isByRef(field_ty)) { |
| | 2546 | return field_ptr; |
| | 2547 | } else { |
| | 2548 | return self.builder.buildLoad(field_ptr, ""); |
| | 2549 | } |
| 2418 | }, | 2550 | }, |
| 2419 | else => unreachable, | 2551 | else => unreachable, |
| 2420 | }; | | |
| 2421 | | | |
| 2422 | if (isByRef(field_ty)) { | | |
| 2423 | return field_ptr; | | |
| 2424 | } else { | | |
| 2425 | return self.builder.buildLoad(field_ptr, ""); | | |
| 2426 | } | 2552 | } |
| 2427 | } | 2553 | } |
| 2428 | | 2554 | |
| ... | @@ -3730,11 +3856,11 @@ pub const FuncGen = struct { | ... | @@ -3730,11 +3856,11 @@ pub const FuncGen = struct { |
| 3730 | if (opt_abi_ty) |abi_ty| { | 3856 | if (opt_abi_ty) |abi_ty| { |
| 3731 | // operand needs widening and truncating | 3857 | // operand needs widening and truncating |
| 3732 | const casted_ptr = self.builder.buildBitCast(ptr, abi_ty.pointerType(0), ""); | 3858 | const casted_ptr = self.builder.buildBitCast(ptr, abi_ty.pointerType(0), ""); |
| 3733 | const load_inst = self.load(casted_ptr, ptr_ty).?; | 3859 | const load_inst = (try self.load(casted_ptr, ptr_ty)).?; |
| 3734 | load_inst.setOrdering(ordering); | 3860 | load_inst.setOrdering(ordering); |
| 3735 | return self.builder.buildTrunc(load_inst, try self.dg.llvmType(operand_ty), ""); | 3861 | return self.builder.buildTrunc(load_inst, try self.dg.llvmType(operand_ty), ""); |
| 3736 | } | 3862 | } |
| 3737 | const load_inst = self.load(ptr, ptr_ty).?; | 3863 | const load_inst = (try self.load(ptr, ptr_ty)).?; |
| 3738 | load_inst.setOrdering(ordering); | 3864 | load_inst.setOrdering(ordering); |
| 3739 | return load_inst; | 3865 | return load_inst; |
| 3740 | } | 3866 | } |
| ... | @@ -3997,7 +4123,9 @@ pub const FuncGen = struct { | ... | @@ -3997,7 +4123,9 @@ pub const FuncGen = struct { |
| 3997 | const struct_ty = struct_ptr_ty.childType(); | 4123 | const struct_ty = struct_ptr_ty.childType(); |
| 3998 | switch (struct_ty.zigTypeTag()) { | 4124 | switch (struct_ty.zigTypeTag()) { |
| 3999 | .Struct => { | 4125 | .Struct => { |
| 4000 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index); | 4126 | const target = self.dg.module.getTarget(); |
| | 4127 | var ty_buf: Type.Payload.Pointer = undefined; |
| | 4128 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ty_buf); |
| 4001 | return self.builder.buildStructGEP(struct_ptr, llvm_field_index, ""); | 4129 | return self.builder.buildStructGEP(struct_ptr, llvm_field_index, ""); |
| 4002 | }, | 4130 | }, |
| 4003 | .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index), | 4131 | .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index), |
| ... | @@ -4041,15 +4169,52 @@ pub const FuncGen = struct { | ... | @@ -4041,15 +4169,52 @@ pub const FuncGen = struct { |
| 4041 | return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len); | 4169 | return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len); |
| 4042 | } | 4170 | } |
| 4043 | | 4171 | |
| 4044 | fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) ?*const llvm.Value { | 4172 | fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value { |
| 4045 | const pointee_ty = ptr_ty.childType(); | 4173 | const info = ptr_ty.ptrInfo().data; |
| 4046 | if (!pointee_ty.hasCodeGenBits()) return null; | 4174 | if (!info.pointee_type.hasCodeGenBits()) return null; |
| 4047 | if (isByRef(pointee_ty)) return ptr; | 4175 | |
| 4048 | const llvm_inst = self.builder.buildLoad(ptr, ""); | | |
| 4049 | const target = self.dg.module.getTarget(); | 4176 | const target = self.dg.module.getTarget(); |
| 4050 | llvm_inst.setAlignment(ptr_ty.ptrAlignment(target)); | 4177 | const ptr_alignment = ptr_ty.ptrAlignment(target); |
| 4051 | llvm_inst.setVolatile(llvm.Bool.fromBool(ptr_ty.isVolatilePtr())); | 4178 | const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr()); |
| 4052 | return llvm_inst; | 4179 | if (info.host_size == 0) { |
| | 4180 | if (isByRef(info.pointee_type)) return ptr; |
| | 4181 | const llvm_inst = self.builder.buildLoad(ptr, ""); |
| | 4182 | llvm_inst.setAlignment(ptr_alignment); |
| | 4183 | llvm_inst.setVolatile(ptr_volatile); |
| | 4184 | return llvm_inst; |
| | 4185 | } |
| | 4186 | |
| | 4187 | const int_ptr_ty = self.context.intType(info.host_size * 8).pointerType(0); |
| | 4188 | const int_ptr = self.builder.buildBitCast(ptr, int_ptr_ty, ""); |
| | 4189 | const containing_int = self.builder.buildLoad(int_ptr, ""); |
| | 4190 | containing_int.setAlignment(ptr_alignment); |
| | 4191 | containing_int.setVolatile(ptr_volatile); |
| | 4192 | |
| | 4193 | const elem_bits = @intCast(c_uint, ptr_ty.elemType().bitSize(target)); |
| | 4194 | const shift_amt = containing_int.typeOf().constInt(info.bit_offset, .False); |
| | 4195 | const shifted_value = self.builder.buildLShr(containing_int, shift_amt, ""); |
| | 4196 | const elem_llvm_ty = try self.dg.llvmType(info.pointee_type); |
| | 4197 | |
| | 4198 | if (isByRef(info.pointee_type)) { |
| | 4199 | const result_align = info.pointee_type.abiAlignment(target); |
| | 4200 | const result_ptr = self.buildAlloca(elem_llvm_ty); |
| | 4201 | result_ptr.setAlignment(result_align); |
| | 4202 | |
| | 4203 | const same_size_int = self.context.intType(elem_bits); |
| | 4204 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); |
| | 4205 | const bitcasted_ptr = self.builder.buildBitCast(result_ptr, same_size_int.pointerType(0), ""); |
| | 4206 | const store_inst = self.builder.buildStore(truncated_int, bitcasted_ptr); |
| | 4207 | store_inst.setAlignment(result_align); |
| | 4208 | return result_ptr; |
| | 4209 | } |
| | 4210 | |
| | 4211 | if (info.pointee_type.zigTypeTag() == .Float) { |
| | 4212 | const same_size_int = self.context.intType(elem_bits); |
| | 4213 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); |
| | 4214 | return self.builder.buildBitCast(truncated_int, elem_llvm_ty, ""); |
| | 4215 | } |
| | 4216 | |
| | 4217 | return self.builder.buildTrunc(shifted_value, elem_llvm_ty, ""); |
| 4053 | } | 4218 | } |
| 4054 | | 4219 | |
| 4055 | fn store( | 4220 | fn store( |
| ... | @@ -4059,16 +4224,50 @@ pub const FuncGen = struct { | ... | @@ -4059,16 +4224,50 @@ pub const FuncGen = struct { |
| 4059 | elem: *const llvm.Value, | 4224 | elem: *const llvm.Value, |
| 4060 | ordering: llvm.AtomicOrdering, | 4225 | ordering: llvm.AtomicOrdering, |
| 4061 | ) void { | 4226 | ) void { |
| 4062 | const elem_ty = ptr_ty.childType(); | 4227 | const info = ptr_ty.ptrInfo().data; |
| | 4228 | const elem_ty = info.pointee_type; |
| 4063 | if (!elem_ty.hasCodeGenBits()) { | 4229 | if (!elem_ty.hasCodeGenBits()) { |
| 4064 | return; | 4230 | return; |
| 4065 | } | 4231 | } |
| 4066 | const target = self.dg.module.getTarget(); | 4232 | const target = self.dg.module.getTarget(); |
| | 4233 | const ptr_alignment = ptr_ty.ptrAlignment(target); |
| | 4234 | const ptr_volatile = llvm.Bool.fromBool(info.@"volatile"); |
| | 4235 | if (info.host_size != 0) { |
| | 4236 | const int_ptr_ty = self.context.intType(info.host_size * 8).pointerType(0); |
| | 4237 | const int_ptr = self.builder.buildBitCast(ptr, int_ptr_ty, ""); |
| | 4238 | const containing_int = self.builder.buildLoad(int_ptr, ""); |
| | 4239 | assert(ordering == .NotAtomic); |
| | 4240 | containing_int.setAlignment(ptr_alignment); |
| | 4241 | containing_int.setVolatile(ptr_volatile); |
| | 4242 | const elem_bits = @intCast(c_uint, ptr_ty.elemType().bitSize(target)); |
| | 4243 | const containing_int_ty = containing_int.typeOf(); |
| | 4244 | const shift_amt = containing_int_ty.constInt(info.bit_offset, .False); |
| | 4245 | // Convert to equally-sized integer type in order to perform the bit |
| | 4246 | // operations on the value to store |
| | 4247 | const value_bits_type = self.context.intType(elem_bits); |
| | 4248 | const value_bits = self.builder.buildBitCast(elem, value_bits_type, ""); |
| | 4249 | |
| | 4250 | var mask_val = value_bits_type.constAllOnes(); |
| | 4251 | mask_val = mask_val.constZExt(containing_int_ty); |
| | 4252 | mask_val = mask_val.constShl(shift_amt); |
| | 4253 | mask_val = mask_val.constNot(); |
| | 4254 | |
| | 4255 | const anded_containing_int = self.builder.buildAnd(containing_int, mask_val, ""); |
| | 4256 | const extended_value = self.builder.buildZExt(value_bits, containing_int_ty, ""); |
| | 4257 | const shifted_value = self.builder.buildShl(extended_value, shift_amt, ""); |
| | 4258 | const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, ""); |
| | 4259 | |
| | 4260 | const store_inst = self.builder.buildStore(ored_value, int_ptr); |
| | 4261 | assert(ordering == .NotAtomic); |
| | 4262 | store_inst.setAlignment(ptr_alignment); |
| | 4263 | store_inst.setVolatile(ptr_volatile); |
| | 4264 | return; |
| | 4265 | } |
| 4067 | if (!isByRef(elem_ty)) { | 4266 | if (!isByRef(elem_ty)) { |
| 4068 | const store_inst = self.builder.buildStore(elem, ptr); | 4267 | const store_inst = self.builder.buildStore(elem, ptr); |
| 4069 | store_inst.setOrdering(ordering); | 4268 | store_inst.setOrdering(ordering); |
| 4070 | store_inst.setAlignment(ptr_ty.ptrAlignment(target)); | 4269 | store_inst.setAlignment(ptr_alignment); |
| 4071 | store_inst.setVolatile(llvm.Bool.fromBool(ptr_ty.isVolatilePtr())); | 4270 | store_inst.setVolatile(ptr_volatile); |
| 4072 | return; | 4271 | return; |
| 4073 | } | 4272 | } |
| 4074 | assert(ordering == .NotAtomic); | 4273 | assert(ordering == .NotAtomic); |
| ... | @@ -4080,7 +4279,7 @@ pub const FuncGen = struct { | ... | @@ -4080,7 +4279,7 @@ pub const FuncGen = struct { |
| 4080 | self.builder.buildBitCast(elem, llvm_ptr_u8, ""), | 4279 | self.builder.buildBitCast(elem, llvm_ptr_u8, ""), |
| 4081 | elem_ty.abiAlignment(target), | 4280 | elem_ty.abiAlignment(target), |
| 4082 | self.context.intType(Type.usize.intInfo(target).bits).constInt(size_bytes, .False), | 4281 | self.context.intType(Type.usize.intInfo(target).bits).constInt(size_bytes, .False), |
| 4083 | ptr_ty.isVolatilePtr(), | 4282 | info.@"volatile", |
| 4084 | ); | 4283 | ); |
| 4085 | } | 4284 | } |
| 4086 | }; | 4285 | }; |
| ... | @@ -4323,15 +4522,104 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca | ... | @@ -4323,15 +4522,104 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca |
| 4323 | } | 4522 | } |
| 4324 | | 4523 | |
| 4325 | /// Take into account 0 bit fields. | 4524 | /// Take into account 0 bit fields. |
| 4326 | fn llvmFieldIndex(ty: Type, index: u32) c_uint { | 4525 | fn llvmFieldIndex( |
| | 4526 | ty: Type, |
| | 4527 | field_index: u32, |
| | 4528 | target: std.Target, |
| | 4529 | ptr_pl_buf: *Type.Payload.Pointer, |
| | 4530 | ) c_uint { |
| 4327 | const struct_obj = ty.castTag(.@"struct").?.data; | 4531 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 4328 | var result: c_uint = 0; | 4532 | if (struct_obj.layout != .Packed) { |
| 4329 | for (struct_obj.fields.values()[0..index]) |field| { | 4533 | var llvm_field_index: c_uint = 0; |
| 4330 | if (field.ty.hasCodeGenBits()) { | 4534 | for (struct_obj.fields.values()) |field, i| { |
| 4331 | result += 1; | 4535 | if (!field.ty.hasCodeGenBits()) continue; |
| | 4536 | |
| | 4537 | if (i == field_index) { |
| | 4538 | ptr_pl_buf.* = .{ |
| | 4539 | .data = .{ |
| | 4540 | .pointee_type = field.ty, |
| | 4541 | .@"align" = field.normalAlignment(target), |
| | 4542 | .@"addrspace" = .generic, |
| | 4543 | }, |
| | 4544 | }; |
| | 4545 | return llvm_field_index; |
| | 4546 | } |
| | 4547 | llvm_field_index += 1; |
| | 4548 | } |
| | 4549 | unreachable; |
| | 4550 | } |
| | 4551 | |
| | 4552 | // Our job here is to return the host integer field index. |
| | 4553 | comptime assert(Type.packed_struct_layout_version == 1); |
| | 4554 | var offset: u64 = 0; |
| | 4555 | var running_bits: u16 = 0; |
| | 4556 | var llvm_field_index: c_uint = 0; |
| | 4557 | for (struct_obj.fields.values()) |field, i| { |
| | 4558 | if (!field.ty.hasCodeGenBits()) continue; |
| | 4559 | |
| | 4560 | const field_align = field.packedAlignment(); |
| | 4561 | if (field_align == 0) { |
| | 4562 | if (i == field_index) { |
| | 4563 | ptr_pl_buf.* = .{ |
| | 4564 | .data = .{ |
| | 4565 | .pointee_type = field.ty, |
| | 4566 | .bit_offset = running_bits, |
| | 4567 | .@"addrspace" = .generic, |
| | 4568 | }, |
| | 4569 | }; |
| | 4570 | } |
| | 4571 | running_bits += @intCast(u16, field.ty.bitSize(target)); |
| | 4572 | } else { |
| | 4573 | if (running_bits != 0) { |
| | 4574 | var int_payload: Type.Payload.Bits = .{ |
| | 4575 | .base = .{ .tag = .int_unsigned }, |
| | 4576 | .data = running_bits, |
| | 4577 | }; |
| | 4578 | const int_ty: Type = .{ .ptr_otherwise = &int_payload.base }; |
| | 4579 | if (i > field_index) { |
| | 4580 | ptr_pl_buf.data.host_size = @intCast(u16, int_ty.abiSize(target)); |
| | 4581 | return llvm_field_index; |
| | 4582 | } |
| | 4583 | |
| | 4584 | const int_align = int_ty.abiAlignment(target); |
| | 4585 | const prev_offset = offset; |
| | 4586 | offset = std.mem.alignForwardGeneric(u64, offset, int_align); |
| | 4587 | const padding_bytes = @intCast(c_uint, offset - prev_offset); |
| | 4588 | if (padding_bytes != 0) { |
| | 4589 | llvm_field_index += 1; |
| | 4590 | } |
| | 4591 | llvm_field_index += 1; |
| | 4592 | offset += int_ty.abiSize(target); |
| | 4593 | running_bits = 0; |
| | 4594 | } |
| | 4595 | const prev_offset = offset; |
| | 4596 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| | 4597 | const padding_bytes = @intCast(c_uint, offset - prev_offset); |
| | 4598 | if (padding_bytes != 0) { |
| | 4599 | llvm_field_index += 1; |
| | 4600 | } |
| | 4601 | if (i == field_index) { |
| | 4602 | ptr_pl_buf.* = .{ |
| | 4603 | .data = .{ |
| | 4604 | .pointee_type = field.ty, |
| | 4605 | .@"align" = field_align, |
| | 4606 | .@"addrspace" = .generic, |
| | 4607 | }, |
| | 4608 | }; |
| | 4609 | return llvm_field_index; |
| | 4610 | } |
| | 4611 | llvm_field_index += 1; |
| | 4612 | offset += field.ty.abiSize(target); |
| 4332 | } | 4613 | } |
| 4333 | } | 4614 | } |
| 4334 | return result; | 4615 | assert(running_bits != 0); |
| | 4616 | var int_payload: Type.Payload.Bits = .{ |
| | 4617 | .base = .{ .tag = .int_unsigned }, |
| | 4618 | .data = running_bits, |
| | 4619 | }; |
| | 4620 | const int_ty: Type = .{ .ptr_otherwise = &int_payload.base }; |
| | 4621 | ptr_pl_buf.data.host_size = @intCast(u16, int_ty.abiSize(target)); |
| | 4622 | return llvm_field_index; |
| 4335 | } | 4623 | } |
| 4336 | | 4624 | |
| 4337 | fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool { | 4625 | fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool { |