| ... | @@ -2332,6 +2332,9 @@ const DeclGen = struct { | ... | @@ -2332,6 +2332,9 @@ const DeclGen = struct { |
| 2332 | | 2332 | |
| 2333 | .mul_add => try self.airMulAdd(inst), | 2333 | .mul_add => try self.airMulAdd(inst), |
| 2334 | | 2334 | |
| | 2335 | .ctz => try self.airClzCtz(inst, .ctz), |
| | 2336 | .clz => try self.airClzCtz(inst, .clz), |
| | 2337 | |
| 2335 | .splat => try self.airSplat(inst), | 2338 | .splat => try self.airSplat(inst), |
| 2336 | .reduce, .reduce_optimized => try self.airReduce(inst), | 2339 | .reduce, .reduce_optimized => try self.airReduce(inst), |
| 2337 | .shuffle => try self.airShuffle(inst), | 2340 | .shuffle => try self.airShuffle(inst), |
| ... | @@ -3029,6 +3032,83 @@ const DeclGen = struct { | ... | @@ -3029,6 +3032,83 @@ const DeclGen = struct { |
| 3029 | return try wip.finalize(); | 3032 | return try wip.finalize(); |
| 3030 | } | 3033 | } |
| 3031 | | 3034 | |
| | 3035 | fn airClzCtz(self: *DeclGen, inst: Air.Inst.Index, op: enum { clz, ctz }) !?IdRef { |
| | 3036 | if (self.liveness.isUnused(inst)) return null; |
| | 3037 | |
| | 3038 | const mod = self.module; |
| | 3039 | const target = self.getTarget(); |
| | 3040 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| | 3041 | const result_ty = self.typeOfIndex(inst); |
| | 3042 | const operand_ty = self.typeOf(ty_op.operand); |
| | 3043 | const operand = try self.resolve(ty_op.operand); |
| | 3044 | |
| | 3045 | const info = self.arithmeticTypeInfo(operand_ty); |
| | 3046 | switch (info.class) { |
| | 3047 | .composite_integer => unreachable, // TODO |
| | 3048 | .integer, .strange_integer => {}, |
| | 3049 | .float, .bool => unreachable, |
| | 3050 | } |
| | 3051 | |
| | 3052 | var wip = try self.elementWise(result_ty, false); |
| | 3053 | defer wip.deinit(); |
| | 3054 | |
| | 3055 | const elem_ty = if (wip.is_array) operand_ty.scalarType(mod) else operand_ty; |
| | 3056 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); |
| | 3057 | const elem_ty_id = self.typeId(elem_ty_ref); |
| | 3058 | |
| | 3059 | for (wip.results, 0..) |*result_id, i| { |
| | 3060 | const elem = try wip.elementAt(operand_ty, operand, i); |
| | 3061 | |
| | 3062 | switch (target.os.tag) { |
| | 3063 | .opencl => { |
| | 3064 | const set = try self.spv.importInstructionSet(.@"OpenCL.std"); |
| | 3065 | const ext_inst: u32 = switch (op) { |
| | 3066 | .clz => 151, // clz |
| | 3067 | .ctz => 152, // ctz |
| | 3068 | }; |
| | 3069 | |
| | 3070 | // Note: result of OpenCL ctz/clz returns operand_ty, and we want result_ty. |
| | 3071 | // result_ty is always large enough to hold the result, so we might have to down |
| | 3072 | // cast it. |
| | 3073 | const tmp = self.spv.allocId(); |
| | 3074 | try self.func.body.emit(self.spv.gpa, .OpExtInst, .{ |
| | 3075 | .id_result_type = elem_ty_id, |
| | 3076 | .id_result = tmp, |
| | 3077 | .set = set, |
| | 3078 | .instruction = .{ .inst = ext_inst }, |
| | 3079 | .id_ref_4 = &.{elem}, |
| | 3080 | }); |
| | 3081 | |
| | 3082 | if (wip.ty_id == elem_ty_id) { |
| | 3083 | result_id.* = tmp; |
| | 3084 | continue; |
| | 3085 | } |
| | 3086 | |
| | 3087 | result_id.* = self.spv.allocId(); |
| | 3088 | if (result_ty.scalarType(mod).isSignedInt(mod)) { |
| | 3089 | assert(elem_ty.scalarType(mod).isSignedInt(mod)); |
| | 3090 | try self.func.body.emit(self.spv.gpa, .OpSConvert, .{ |
| | 3091 | .id_result_type = wip.ty_id, |
| | 3092 | .id_result = result_id.*, |
| | 3093 | .signed_value = tmp, |
| | 3094 | }); |
| | 3095 | } else { |
| | 3096 | assert(elem_ty.scalarType(mod).isUnsignedInt(mod)); |
| | 3097 | try self.func.body.emit(self.spv.gpa, .OpUConvert, .{ |
| | 3098 | .id_result_type = wip.ty_id, |
| | 3099 | .id_result = result_id.*, |
| | 3100 | .unsigned_value = tmp, |
| | 3101 | }); |
| | 3102 | } |
| | 3103 | }, |
| | 3104 | .vulkan => unreachable, // TODO |
| | 3105 | else => unreachable, |
| | 3106 | } |
| | 3107 | } |
| | 3108 | |
| | 3109 | return try wip.finalize(); |
| | 3110 | } |
| | 3111 | |
| 3032 | fn airSplat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3112 | fn airSplat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3033 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 3113 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3034 | const operand_id = try self.resolve(ty_op.operand); | 3114 | const operand_id = try self.resolve(ty_op.operand); |