| ... | ... | @@ -274,6 +274,13 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 274 | 274 | .storage_class = storage_class, |
| 275 | 275 | }); |
| 276 | 276 | |
| 277 | if (nav.getAlignment() != ty.abiAlignment(zcu)) { |
| 278 | if (target.os.tag != .opencl) return cg.fail("cannot apply alignment to variables", .{}); |
| 279 | try cg.module.decorate(result_id, .{ |
| 280 | .alignment = .{ .alignment = @intCast(nav.getAlignment().toByteUnits().?) }, |
| 281 | }); |
| 282 | } |
| 283 | |
| 277 | 284 | switch (target.os.tag) { |
| 278 | 285 | .vulkan, .opengl => { |
| 279 | 286 | if (ty.zigTypeTag(zcu) == .@"struct") { |
| ... | ... | @@ -348,7 +355,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 348 | 355 | .id_result_type = ptr_ty_id, |
| 349 | 356 | .id_result = result_id, |
| 350 | 357 | .set = try cg.module.importInstructionSet(.zig), |
| 351 | | .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere... |
| 358 | .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) }, |
| 352 | 359 | .id_ref_4 = &.{initializer_id}, |
| 353 | 360 | }); |
| 354 | 361 | } else { |
| ... | ... | @@ -356,7 +363,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 356 | 363 | .id_result_type = ptr_ty_id, |
| 357 | 364 | .id_result = result_id, |
| 358 | 365 | .set = try cg.module.importInstructionSet(.zig), |
| 359 | | .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere... |
| 366 | .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) }, |
| 360 | 367 | .id_ref_4 = &.{}, |
| 361 | 368 | }); |
| 362 | 369 | } |
| ... | ... | @@ -498,7 +505,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { |
| 498 | 505 | .id_result_type = fn_decl_ptr_ty_id, |
| 499 | 506 | .id_result = result_id, |
| 500 | 507 | .set = try cg.module.importInstructionSet(.zig), |
| 501 | | .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere... |
| 508 | .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) }, |
| 502 | 509 | .id_ref_4 = &.{initializer_id}, |
| 503 | 510 | }); |
| 504 | 511 | } |
| ... | ... | @@ -1037,9 +1044,18 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { |
| 1037 | 1044 | const gpa = cg.module.gpa; |
| 1038 | 1045 | const pt = cg.pt; |
| 1039 | 1046 | const zcu = cg.module.zcu; |
| 1047 | const target = zcu.getTarget(); |
| 1040 | 1048 | switch (derivation) { |
| 1041 | 1049 | .comptime_alloc_ptr, .comptime_field_ptr => unreachable, |
| 1042 | 1050 | .int => |int| { |
| 1051 | if (target.os.tag != .opencl) { |
| 1052 | if (int.ptr_ty.ptrAddressSpace(zcu) != .physical_storage_buffer) { |
| 1053 | return cg.fail( |
| 1054 | "cannot cast integer to pointer with address space '{s}'", |
| 1055 | .{@tagName(int.ptr_ty.ptrAddressSpace(zcu))}, |
| 1056 | ); |
| 1057 | } |
| 1058 | } |
| 1043 | 1059 | const result_ty_id = try cg.resolveType(int.ptr_ty, .direct); |
| 1044 | 1060 | // TODO: This can probably be an OpSpecConstantOp Bitcast, but |
| 1045 | 1061 | // that is not implemented by Mesa yet. Therefore, just generate it |
| ... | ... | @@ -1137,7 +1153,7 @@ fn constantUavRef( |
| 1137 | 1153 | // Uav refs are always generic. |
| 1138 | 1154 | assert(ty.ptrAddressSpace(zcu) == .generic); |
| 1139 | 1155 | const uav_ty_id = try cg.resolveType(uav_ty, .indirect); |
| 1140 | | const decl_ptr_ty_id = try cg.module.ptrType(uav_ty_id, .generic); |
| 1156 | const decl_ptr_ty_id = try cg.module.ptrType(uav_ty_id, .function); |
| 1141 | 1157 | const ptr_id = try cg.resolveUav(uav.val); |
| 1142 | 1158 | |
| 1143 | 1159 | if (decl_ptr_ty_id != ty_id) { |
| ... | ... | @@ -1327,7 +1343,10 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1327 | 1343 | }, |
| 1328 | 1344 | .void => switch (repr) { |
| 1329 | 1345 | .direct => return try cg.module.voidType(), |
| 1330 | | .indirect => return try cg.module.opaqueType("void"), |
| 1346 | .indirect => { |
| 1347 | if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{}); |
| 1348 | return try cg.module.opaqueType("void"); |
| 1349 | }, |
| 1331 | 1350 | }, |
| 1332 | 1351 | .bool => switch (repr) { |
| 1333 | 1352 | .direct => return try cg.module.boolType(), |
| ... | ... | @@ -1337,6 +1356,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1337 | 1356 | const int_info = ty.intInfo(zcu); |
| 1338 | 1357 | if (int_info.bits == 0) { |
| 1339 | 1358 | assert(repr == .indirect); |
| 1359 | if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{}); |
| 1340 | 1360 | return try cg.module.opaqueType("u0"); |
| 1341 | 1361 | } |
| 1342 | 1362 | return try cg.module.intType(int_info.signedness, int_info.bits); |
| ... | ... | @@ -1369,6 +1389,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1369 | 1389 | |
| 1370 | 1390 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 1371 | 1391 | assert(repr == .indirect); |
| 1392 | if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{}); |
| 1372 | 1393 | return try cg.module.opaqueType("zero-sized-array"); |
| 1373 | 1394 | } else if (total_len == 0) { |
| 1374 | 1395 | // The size of the array would be 0, but that is not allowed in SPIR-V. |
| ... | ... | @@ -1590,6 +1611,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1590 | 1611 | return try cg.module.structType(&member_types, &member_names, null, .none); |
| 1591 | 1612 | }, |
| 1592 | 1613 | .@"opaque" => { |
| 1614 | if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{}); |
| 1593 | 1615 | const type_name = try cg.resolveTypeName(ty); |
| 1594 | 1616 | defer gpa.free(type_name); |
| 1595 | 1617 | return try cg.module.opaqueType(type_name); |
| ... | ... | @@ -2510,11 +2532,7 @@ fn generateTestEntryPoint( |
| 2510 | 2532 | try cg.module.declareEntryPoint(spv_decl_index, test_name, execution_mode, null); |
| 2511 | 2533 | } |
| 2512 | 2534 | |
| 2513 | | fn intFromBool(cg: *CodeGen, value: Temporary) !Temporary { |
| 2514 | | return try cg.intFromBool2(value, Type.u1); |
| 2515 | | } |
| 2516 | | |
| 2517 | | fn intFromBool2(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary { |
| 2535 | fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary { |
| 2518 | 2536 | const zero_id = try cg.constInt(result_ty, 0); |
| 2519 | 2537 | const one_id = try cg.constInt(result_ty, 1); |
| 2520 | 2538 | |
| ... | ... | @@ -2558,7 +2576,7 @@ fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id { |
| 2558 | 2576 | const zcu = cg.module.zcu; |
| 2559 | 2577 | switch (ty.scalarType(zcu).zigTypeTag(zcu)) { |
| 2560 | 2578 | .bool => { |
| 2561 | | const result = try cg.intFromBool(Temporary.init(ty, operand_id)); |
| 2579 | const result = try cg.intFromBool(.init(ty, operand_id), .u1); |
| 2562 | 2580 | return try result.materialize(cg); |
| 2563 | 2581 | }, |
| 2564 | 2582 | else => return operand_id, |
| ... | ... | @@ -2958,7 +2976,7 @@ fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporar |
| 2958 | 2976 | .composite_integer, .integer, .bool, .float => return value, |
| 2959 | 2977 | .strange_integer => switch (info.signedness) { |
| 2960 | 2978 | .unsigned => { |
| 2961 | | const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1; |
| 2979 | const mask_value = @as(u64, std.math.maxInt(u64)) >> @as(u6, @intCast(64 - info.bits)); |
| 2962 | 2980 | const mask_id = try cg.constInt(ty.scalarType(zcu), mask_value); |
| 2963 | 2981 | return try cg.buildBinary(.OpBitwiseAnd, value, Temporary.init(ty.scalarType(zcu), mask_id)); |
| 2964 | 2982 | }, |
| ... | ... | @@ -2997,28 +3015,12 @@ fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 2997 | 3015 | |
| 2998 | 3016 | const div = try cg.buildBinary(.OpSDiv, lhs, rhs); |
| 2999 | 3017 | const rem = try cg.buildBinary(.OpSRem, lhs, rhs); |
| 3000 | | |
| 3001 | 3018 | const zero: Temporary = .init(lhs.ty, try cg.constInt(lhs.ty, 0)); |
| 3002 | | |
| 3003 | | const rem_is_not_zero = try cg.buildCmp(.OpINotEqual, rem, zero); |
| 3004 | | |
| 3005 | | const result_negative = try cg.buildCmp( |
| 3006 | | .OpLogicalNotEqual, |
| 3007 | | try cg.buildCmp(.OpSLessThan, lhs, zero), |
| 3008 | | try cg.buildCmp(.OpSLessThan, rhs, zero), |
| 3009 | | ); |
| 3010 | | const rem_is_not_zero_and_result_is_negative = try cg.buildBinary( |
| 3011 | | .OpLogicalAnd, |
| 3012 | | rem_is_not_zero, |
| 3013 | | result_negative, |
| 3014 | | ); |
| 3015 | | |
| 3016 | | const result = try cg.buildBinary( |
| 3017 | | .OpISub, |
| 3018 | | div, |
| 3019 | | try cg.intFromBool2(rem_is_not_zero_and_result_is_negative, div.ty), |
| 3020 | | ); |
| 3021 | | |
| 3019 | const rem_non_zero = try cg.buildCmp(.OpINotEqual, rem, zero); |
| 3020 | const lhs_rhs_xor = try cg.buildBinary(.OpBitwiseXor, lhs, rhs); |
| 3021 | const signs_differ = try cg.buildCmp(.OpSLessThan, lhs_rhs_xor, zero); |
| 3022 | const adjust = try cg.buildBinary(.OpLogicalAnd, rem_non_zero, signs_differ); |
| 3023 | const result = try cg.buildBinary(.OpISub, div, try cg.intFromBool(adjust, div.ty)); |
| 3022 | 3024 | return try result.materialize(cg); |
| 3023 | 3025 | }, |
| 3024 | 3026 | .float => { |
| ... | ... | @@ -3032,10 +3034,8 @@ fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3032 | 3034 | |
| 3033 | 3035 | fn airDivTrunc(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3034 | 3036 | const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 3035 | | |
| 3036 | 3037 | const lhs = try cg.temporary(bin_op.lhs); |
| 3037 | 3038 | const rhs = try cg.temporary(bin_op.rhs); |
| 3038 | | |
| 3039 | 3039 | const info = cg.arithmeticTypeInfo(lhs.ty); |
| 3040 | 3040 | switch (info.class) { |
| 3041 | 3041 | .composite_integer => unreachable, // TODO |
| ... | ... | @@ -3073,12 +3073,9 @@ fn airArithOp( |
| 3073 | 3073 | comptime uop: Opcode, |
| 3074 | 3074 | ) !?Id { |
| 3075 | 3075 | const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 3076 | | |
| 3077 | 3076 | const lhs = try cg.temporary(bin_op.lhs); |
| 3078 | 3077 | const rhs = try cg.temporary(bin_op.rhs); |
| 3079 | | |
| 3080 | 3078 | const info = cg.arithmeticTypeInfo(lhs.ty); |
| 3081 | | |
| 3082 | 3079 | const result = switch (info.class) { |
| 3083 | 3080 | .composite_integer => unreachable, // TODO |
| 3084 | 3081 | .integer, .strange_integer => switch (info.signedness) { |
| ... | ... | @@ -3088,7 +3085,6 @@ fn airArithOp( |
| 3088 | 3085 | .float => try cg.buildBinary(fop, lhs, rhs), |
| 3089 | 3086 | .bool => unreachable, |
| 3090 | 3087 | }; |
| 3091 | | |
| 3092 | 3088 | return try result.materialize(cg); |
| 3093 | 3089 | } |
| 3094 | 3090 | |
| ... | ... | @@ -3105,12 +3101,10 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary { |
| 3105 | 3101 | const zcu = cg.module.zcu; |
| 3106 | 3102 | const target = cg.module.zcu.getTarget(); |
| 3107 | 3103 | const operand_info = cg.arithmeticTypeInfo(value.ty); |
| 3108 | | |
| 3109 | 3104 | switch (operand_info.class) { |
| 3110 | 3105 | .float => return try cg.buildUnary(.f_abs, value), |
| 3111 | 3106 | .integer, .strange_integer => { |
| 3112 | 3107 | const abs_value = try cg.buildUnary(.i_abs, value); |
| 3113 | | |
| 3114 | 3108 | switch (target.os.tag) { |
| 3115 | 3109 | .vulkan, .opengl => { |
| 3116 | 3110 | if (value.ty.intInfo(zcu).signedness == .signed) { |
| ... | ... | @@ -3119,7 +3113,6 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary { |
| 3119 | 3113 | }, |
| 3120 | 3114 | else => {}, |
| 3121 | 3115 | } |
| 3122 | | |
| 3123 | 3116 | return try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty)); |
| 3124 | 3117 | }, |
| 3125 | 3118 | .composite_integer => unreachable, // TODO |
| ... | ... | @@ -3134,19 +3127,18 @@ fn airAddSubOverflow( |
| 3134 | 3127 | u_opcode: Opcode, |
| 3135 | 3128 | s_opcode: Opcode, |
| 3136 | 3129 | ) !?Id { |
| 3137 | | _ = s_opcode; |
| 3138 | 3130 | // Note: OpIAddCarry and OpISubBorrow are not really useful here: For unsigned numbers, |
| 3139 | 3131 | // there is in both cases only one extra operation required. For signed operations, |
| 3140 | 3132 | // the overflow bit is set then going from 0x80.. to 0x00.., but this doesn't actually |
| 3141 | 3133 | // normally set a carry bit. So the SPIR-V overflow operations are not particularly |
| 3142 | 3134 | // useful here. |
| 3143 | 3135 | |
| 3136 | _ = s_opcode; |
| 3137 | |
| 3144 | 3138 | const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3145 | 3139 | const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3146 | | |
| 3147 | 3140 | const lhs = try cg.temporary(extra.lhs); |
| 3148 | 3141 | const rhs = try cg.temporary(extra.rhs); |
| 3149 | | |
| 3150 | 3142 | const result_ty = cg.typeOfIndex(inst); |
| 3151 | 3143 | |
| 3152 | 3144 | const info = cg.arithmeticTypeInfo(lhs.ty); |
| ... | ... | @@ -3158,7 +3150,6 @@ fn airAddSubOverflow( |
| 3158 | 3150 | |
| 3159 | 3151 | const sum = try cg.buildBinary(add, lhs, rhs); |
| 3160 | 3152 | const result = try cg.normalize(sum, info); |
| 3161 | | |
| 3162 | 3153 | const overflowed = switch (info.signedness) { |
| 3163 | 3154 | // Overflow happened if the result is smaller than either of the operands. It doesn't matter which. |
| 3164 | 3155 | // For subtraction the conditions need to be swapped. |
| ... | ... | @@ -3173,38 +3164,31 @@ fn airAddSubOverflow( |
| 3173 | 3164 | // and the result's sign is different from the minuend's (a's) sign. |
| 3174 | 3165 | // (sign(a) != sign(b)) && (sign(a) != sign(result)) |
| 3175 | 3166 | const zero: Temporary = .init(rhs.ty, try cg.constInt(rhs.ty, 0)); |
| 3176 | | |
| 3177 | 3167 | const lhs_is_neg = try cg.buildCmp(.OpSLessThan, lhs, zero); |
| 3178 | 3168 | const rhs_is_neg = try cg.buildCmp(.OpSLessThan, rhs, zero); |
| 3179 | 3169 | const result_is_neg = try cg.buildCmp(.OpSLessThan, result, zero); |
| 3180 | | |
| 3181 | 3170 | const signs_match = try cg.buildCmp(.OpLogicalEqual, lhs_is_neg, rhs_is_neg); |
| 3182 | 3171 | const result_sign_differs = try cg.buildCmp(.OpLogicalNotEqual, lhs_is_neg, result_is_neg); |
| 3183 | | |
| 3184 | | const overflow_condition = if (add == .OpIAdd) |
| 3185 | | signs_match |
| 3186 | | else // .OpISub |
| 3187 | | try cg.buildUnary(.l_not, signs_match); |
| 3188 | | |
| 3172 | const overflow_condition = switch (add) { |
| 3173 | .OpIAdd => signs_match, |
| 3174 | .OpISub => try cg.buildUnary(.l_not, signs_match), |
| 3175 | else => unreachable, |
| 3176 | }; |
| 3189 | 3177 | break :blk try cg.buildCmp(.OpLogicalAnd, overflow_condition, result_sign_differs); |
| 3190 | 3178 | }, |
| 3191 | 3179 | }; |
| 3192 | 3180 | |
| 3193 | | const ov = try cg.intFromBool(overflowed); |
| 3194 | | |
| 3181 | const ov = try cg.intFromBool(overflowed, .u1); |
| 3195 | 3182 | const result_ty_id = try cg.resolveType(result_ty, .direct); |
| 3196 | 3183 | return try cg.constructComposite(result_ty_id, &.{ try result.materialize(cg), try ov.materialize(cg) }); |
| 3197 | 3184 | } |
| 3198 | 3185 | |
| 3199 | 3186 | fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3200 | 3187 | const pt = cg.pt; |
| 3201 | | |
| 3202 | 3188 | const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3203 | 3189 | const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3204 | | |
| 3205 | 3190 | const lhs = try cg.temporary(extra.lhs); |
| 3206 | 3191 | const rhs = try cg.temporary(extra.rhs); |
| 3207 | | |
| 3208 | 3192 | const result_ty = cg.typeOfIndex(inst); |
| 3209 | 3193 | |
| 3210 | 3194 | const info = cg.arithmeticTypeInfo(lhs.ty); |
| ... | ... | @@ -3237,20 +3221,15 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3237 | 3221 | const op_ty = try pt.intType(.unsigned, op_ty_bits); |
| 3238 | 3222 | const casted_lhs = try cg.buildConvert(op_ty, lhs); |
| 3239 | 3223 | const casted_rhs = try cg.buildConvert(op_ty, rhs); |
| 3240 | | |
| 3241 | 3224 | const full_result = try cg.buildBinary(.OpIMul, casted_lhs, casted_rhs); |
| 3242 | | |
| 3243 | 3225 | const low_bits = try cg.buildConvert(lhs.ty, full_result); |
| 3244 | 3226 | const result = try cg.normalize(low_bits, info); |
| 3245 | | |
| 3246 | 3227 | // Shift the result bits away to get the overflow bits. |
| 3247 | 3228 | const shift: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, info.bits)); |
| 3248 | 3229 | const overflow = try cg.buildBinary(.OpShiftRightLogical, full_result, shift); |
| 3249 | | |
| 3250 | 3230 | // Directly check if its zero in the op_ty without converting first. |
| 3251 | 3231 | const zero: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, 0)); |
| 3252 | 3232 | const overflowed = try cg.buildCmp(.OpINotEqual, zero, overflow); |
| 3253 | | |
| 3254 | 3233 | break :blk .{ result, overflowed }; |
| 3255 | 3234 | } |
| 3256 | 3235 | |
| ... | ... | @@ -3362,7 +3341,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3362 | 3341 | }, |
| 3363 | 3342 | }; |
| 3364 | 3343 | |
| 3365 | | const ov = try cg.intFromBool(overflowed); |
| 3344 | const ov = try cg.intFromBool(overflowed, .u1); |
| 3366 | 3345 | |
| 3367 | 3346 | const result_ty_id = try cg.resolveType(result_ty, .direct); |
| 3368 | 3347 | return try cg.constructComposite(result_ty_id, &.{ try result.materialize(cg), try ov.materialize(cg) }); |
| ... | ... | @@ -3403,7 +3382,7 @@ fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3403 | 3382 | }; |
| 3404 | 3383 | |
| 3405 | 3384 | const overflowed = try cg.buildCmp(.OpINotEqual, base, right); |
| 3406 | | const ov = try cg.intFromBool(overflowed); |
| 3385 | const ov = try cg.intFromBool(overflowed, .u1); |
| 3407 | 3386 | |
| 3408 | 3387 | const result_ty_id = try cg.resolveType(result_ty, .direct); |
| 3409 | 3388 | return try cg.constructComposite(result_ty_id, &.{ try result.materialize(cg), try ov.materialize(cg) }); |
| ... | ... | @@ -3931,6 +3910,7 @@ fn bitCast( |
| 3931 | 3910 | ) !Id { |
| 3932 | 3911 | const gpa = cg.module.gpa; |
| 3933 | 3912 | const zcu = cg.module.zcu; |
| 3913 | const target = zcu.getTarget(); |
| 3934 | 3914 | const src_ty_id = try cg.resolveType(src_ty, .direct); |
| 3935 | 3915 | const dst_ty_id = try cg.resolveType(dst_ty, .direct); |
| 3936 | 3916 | |
| ... | ... | @@ -3941,6 +3921,15 @@ fn bitCast( |
| 3941 | 3921 | // See fn bitCast in llvm.zig |
| 3942 | 3922 | |
| 3943 | 3923 | if (src_ty.zigTypeTag(zcu) == .int and dst_ty.isPtrAtRuntime(zcu)) { |
| 3924 | if (target.os.tag != .opencl) { |
| 3925 | if (dst_ty.ptrAddressSpace(zcu) != .physical_storage_buffer) { |
| 3926 | return cg.fail( |
| 3927 | "cannot cast integer to pointer with address space '{s}'", |
| 3928 | .{@tagName(dst_ty.ptrAddressSpace(zcu))}, |
| 3929 | ); |
| 3930 | } |
| 3931 | } |
| 3932 | |
| 3944 | 3933 | const result_id = cg.module.allocId(); |
| 3945 | 3934 | try cg.body.emit(gpa, .OpConvertUToPtr, .{ |
| 3946 | 3935 | .id_result_type = dst_ty_id, |
| ... | ... | @@ -3967,7 +3956,8 @@ fn bitCast( |
| 3967 | 3956 | |
| 3968 | 3957 | const dst_ptr_ty_id = try cg.module.ptrType(dst_ty_id, .function); |
| 3969 | 3958 | |
| 3970 | | const tmp_id = try cg.alloc(src_ty, .{ .storage_class = .function }); |
| 3959 | const src_ty_indirect_id = try cg.resolveType(src_ty, .indirect); |
| 3960 | const tmp_id = try cg.alloc(src_ty_indirect_id, null); |
| 3971 | 3961 | try cg.store(src_ty, tmp_id, src_id, .{}); |
| 3972 | 3962 | const casted_ptr_id = cg.module.allocId(); |
| 3973 | 3963 | try cg.body.emit(gpa, .OpBitcast, .{ |
| ... | ... | @@ -3997,7 +3987,7 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3997 | 3987 | const result_ty = cg.typeOfIndex(inst); |
| 3998 | 3988 | if (operand_ty.toIntern() == .bool_type) { |
| 3999 | 3989 | const operand = try cg.temporary(ty_op.operand); |
| 4000 | | const result = try cg.intFromBool(operand); |
| 3990 | const result = try cg.intFromBool(operand, .u1); |
| 4001 | 3991 | return try result.materialize(cg); |
| 4002 | 3992 | } |
| 4003 | 3993 | const operand_id = try cg.resolve(ty_op.operand); |
| ... | ... | @@ -4420,7 +4410,6 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4420 | 4410 | // TODO: This backend probably also should use isByRef from llvm... |
| 4421 | 4411 | |
| 4422 | 4412 | const is_vector = array_ty.isVector(zcu); |
| 4423 | | |
| 4424 | 4413 | const elem_repr: Repr = if (is_vector) .direct else .indirect; |
| 4425 | 4414 | const array_ty_id = try cg.resolveType(array_ty, .direct); |
| 4426 | 4415 | const elem_ty_id = try cg.resolveType(elem_ty, elem_repr); |
| ... | ... | @@ -4588,7 +4577,8 @@ fn unionInit( |
| 4588 | 4577 | return try cg.constInt(tag_ty, tag_int); |
| 4589 | 4578 | } |
| 4590 | 4579 | |
| 4591 | | const tmp_id = try cg.alloc(ty, .{ .storage_class = .function }); |
| 4580 | const ty_id = try cg.resolveType(ty, .indirect); |
| 4581 | const tmp_id = try cg.alloc(ty_id, null); |
| 4592 | 4582 | |
| 4593 | 4583 | if (layout.tag_size != 0) { |
| 4594 | 4584 | const tag_ty_id = try cg.resolveType(tag_ty, .indirect); |
| ... | ... | @@ -4709,7 +4699,8 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4709 | 4699 | const layout = cg.unionLayout(object_ty); |
| 4710 | 4700 | assert(layout.has_payload); |
| 4711 | 4701 | |
| 4712 | | const tmp_id = try cg.alloc(object_ty, .{ .storage_class = .function }); |
| 4702 | const object_ty_id = try cg.resolveType(object_ty, .indirect); |
| 4703 | const tmp_id = try cg.alloc(object_ty_id, null); |
| 4713 | 4704 | try cg.store(object_ty, tmp_id, object_id, .{}); |
| 4714 | 4705 | |
| 4715 | 4706 | const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect); |
| ... | ... | @@ -4733,13 +4724,16 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4733 | 4724 | |
| 4734 | 4725 | fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4735 | 4726 | const zcu = cg.module.zcu; |
| 4727 | const target = zcu.getTarget(); |
| 4736 | 4728 | const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 4737 | 4729 | const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 4738 | 4730 | |
| 4739 | | const parent_ty = ty_pl.ty.toType().childType(zcu); |
| 4740 | | const result_ty_id = try cg.resolveType(ty_pl.ty.toType(), .indirect); |
| 4731 | const parent_ptr_ty = ty_pl.ty.toType(); |
| 4732 | const parent_ty = parent_ptr_ty.childType(zcu); |
| 4733 | const result_ty_id = try cg.resolveType(parent_ptr_ty, .indirect); |
| 4741 | 4734 | |
| 4742 | 4735 | const field_ptr = try cg.resolve(extra.field_ptr); |
| 4736 | const field_ptr_ty = cg.typeOf(extra.field_ptr); |
| 4743 | 4737 | const field_ptr_int = try cg.intFromPtr(field_ptr); |
| 4744 | 4738 | const field_offset = parent_ty.structFieldOffset(extra.field_index, zcu); |
| 4745 | 4739 | |
| ... | ... | @@ -4753,6 +4747,15 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4753 | 4747 | break :base_ptr_int try result.materialize(cg); |
| 4754 | 4748 | }; |
| 4755 | 4749 | |
| 4750 | if (target.os.tag != .opencl) { |
| 4751 | if (field_ptr_ty.ptrAddressSpace(zcu) != .physical_storage_buffer) { |
| 4752 | return cg.fail( |
| 4753 | "cannot cast integer to pointer with address space '{s}'", |
| 4754 | .{@tagName(field_ptr_ty.ptrAddressSpace(zcu))}, |
| 4755 | ); |
| 4756 | } |
| 4757 | } |
| 4758 | |
| 4756 | 4759 | const base_ptr = cg.module.allocId(); |
| 4757 | 4760 | try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{ |
| 4758 | 4761 | .id_result_type = result_ty_id, |
| ... | ... | @@ -4821,46 +4824,33 @@ fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, field_index: u32) |
| 4821 | 4824 | return try cg.structFieldPtr(result_ptr_ty, struct_ptr_ty, struct_ptr, field_index); |
| 4822 | 4825 | } |
| 4823 | 4826 | |
| 4824 | | const AllocOptions = struct { |
| 4825 | | initializer: ?Id = null, |
| 4826 | | /// The final storage class of the pointer. This may be either `.Generic` or `.Function`. |
| 4827 | | /// In either case, the local is allocated in the `.Function` storage class, and optionally |
| 4828 | | /// cast back to `.Generic`. |
| 4829 | | storage_class: StorageClass, |
| 4830 | | }; |
| 4831 | | |
| 4832 | | // Allocate a function-local variable, with possible initializer. |
| 4833 | | // This function returns a pointer to a variable of type `ty`, |
| 4834 | | // which is in the Generic address space. The variable is actually |
| 4835 | | // placed in the Function address space. |
| 4836 | | fn alloc( |
| 4837 | | cg: *CodeGen, |
| 4838 | | ty: Type, |
| 4839 | | options: AllocOptions, |
| 4840 | | ) !Id { |
| 4841 | | const ty_id = try cg.resolveType(ty, .indirect); |
| 4842 | | const ptr_fn_ty_id = try cg.module.ptrType(ty_id, .function); |
| 4843 | | |
| 4844 | | // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to |
| 4845 | | // directly generate them into func.prologue instead of the body. |
| 4846 | | const var_id = cg.module.allocId(); |
| 4827 | fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id { |
| 4828 | const ptr_ty_id = try cg.module.ptrType(ty_id, .function); |
| 4829 | const result_id = cg.module.allocId(); |
| 4847 | 4830 | try cg.prologue.emit(cg.module.gpa, .OpVariable, .{ |
| 4848 | | .id_result_type = ptr_fn_ty_id, |
| 4849 | | .id_result = var_id, |
| 4831 | .id_result_type = ptr_ty_id, |
| 4832 | .id_result = result_id, |
| 4850 | 4833 | .storage_class = .function, |
| 4851 | | .initializer = options.initializer, |
| 4834 | .initializer = initializer, |
| 4852 | 4835 | }); |
| 4853 | | |
| 4854 | | return var_id; |
| 4836 | return result_id; |
| 4855 | 4837 | } |
| 4856 | 4838 | |
| 4857 | 4839 | fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4858 | 4840 | const zcu = cg.module.zcu; |
| 4841 | const target = zcu.getTarget(); |
| 4859 | 4842 | const ptr_ty = cg.typeOfIndex(inst); |
| 4860 | 4843 | const child_ty = ptr_ty.childType(zcu); |
| 4861 | | return try cg.alloc(child_ty, .{ |
| 4862 | | .storage_class = cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)), |
| 4863 | | }); |
| 4844 | const child_ty_id = try cg.resolveType(child_ty, .indirect); |
| 4845 | const ptr_align = ptr_ty.ptrAlignment(zcu); |
| 4846 | const result_id = try cg.alloc(child_ty_id, null); |
| 4847 | if (ptr_align != child_ty.abiAlignment(zcu)) { |
| 4848 | if (target.os.tag != .opencl) return cg.fail("cannot apply alignment to variables", .{}); |
| 4849 | try cg.module.decorate(result_id, .{ |
| 4850 | .alignment = .{ .alignment = @intCast(ptr_align.toByteUnits().?) }, |
| 4851 | }); |
| 4852 | } |
| 4853 | return result_id; |
| 4864 | 4854 | } |
| 4865 | 4855 | |
| 4866 | 4856 | fn airArg(cg: *CodeGen) Id { |
| ... | ... | @@ -5087,7 +5077,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) |
| 5087 | 5077 | }; |
| 5088 | 5078 | |
| 5089 | 5079 | const maybe_block_result_var_id = if (have_block_result) blk: { |
| 5090 | | const block_result_var_id = try cg.alloc(ty, .{ .storage_class = .function }); |
| 5080 | const ty_id = try cg.resolveType(ty, .indirect); |
| 5081 | const block_result_var_id = try cg.alloc(ty_id, null); |
| 5091 | 5082 | try cf.block_results.putNoClobber(gpa, inst, block_result_var_id); |
| 5092 | 5083 | break :blk block_result_var_id; |
| 5093 | 5084 | } else null; |