已合并
flexattention: port flex attention overflow fixes to master #45274
a_knight创建于 8月25日
flexattention: port flex attention overflow fixes to master #45274
已合并
a_knight创建于 8月25日
共 4 个文件变更+152-50
@@ -171,6 +171,45 @@ def _is_named_ir_node(value: Any) -> bool:
171_EXPLICIT_SCORE_MOD_OPTION = "_NPU_EXPLICIT_SCORE_MOD"171_EXPLICIT_SCORE_MOD_OPTION = "_NPU_EXPLICIT_SCORE_MOD"
172_STREAMING_BLOCK_MASK_TARGET_BYTES = 256 * 1024 * 1024172_STREAMING_BLOCK_MASK_TARGET_BYTES = 256 * 1024 * 1024
173_STREAMING_BLOCK_MASK_BYTES_PER_ELEMENT = 8173_STREAMING_BLOCK_MASK_BYTES_PER_ELEMENT = 8
174+_TASKLIST_REDUCE_UB_BUDGET_NUMERATOR = 4
175+_TASKLIST_REDUCE_UB_BUDGET_DENOMINATOR = 5
176+_TASKLIST_REDUCE_FP32_TILE_COUNT = 3
177+_TASKLIST_REDUCE_FP32_BYTES = 4
178+ 
179+ 
180+def _filter_dkdv_tasklist_reduce_configs(
181+ configs: list[dict[str, Any]],
182+ qk_head_dim: int,
183+ v_head_dim: int,
184+) -> list[dict[str, Any]]:
185+ """Keep dK/dV tiles whose tasklist reduction fits in UB."""
186+ max_head_dim = max(int(qk_head_dim), int(v_head_dim))
187+ ub_budget = (
188+ int(npu_config.ub_size) * _TASKLIST_REDUCE_UB_BUDGET_NUMERATOR
189+ // _TASKLIST_REDUCE_UB_BUDGET_DENOMINATOR
190+ )
191+ 
192+ safe_configs = []
193+ for cfg in configs:
194+ reduce_ub_bytes = (
195+ _TASKLIST_REDUCE_FP32_TILE_COUNT
196+ * int(cfg["BLOCK_N1"])
197+ * max_head_dim
198+ * _TASKLIST_REDUCE_FP32_BYTES
199+ )
200+ if reduce_ub_bytes <= ub_budget:
201+ safe_configs.append(cfg)
202+ 
203+ log.info(
204+ "tasklist-reduce UB filter: kept=%d/%d qk_head_dim=%d "
205+ "v_head_dim=%d budget_bytes=%d",
206+ len(safe_configs),
207+ len(configs),
208+ int(qk_head_dim),
209+ int(v_head_dim),
210+ ub_budget,
211+ )
212+ return safe_configs
174 213 
175 214 
176def create_zero_int_tensor_fake(x) -> torch.Tensor:215def create_zero_int_tensor_fake(x) -> torch.Tensor:
@@ -652,16 +691,10 @@ def _get_flex_attention_additional_lowerings():
652 These lowerings allow supported fallback operations to be lowered as pointwise691 These lowerings allow supported fallback operations to be lowered as pointwise
653 ops in the score_mod and mask_mod subgraphs.692 ops in the score_mod and mask_mod subgraphs.
654 """693 """
655- from torch._inductor.lowering import make_pointwise, index_impl694+ from torch._inductor.lowering import make_pointwise
656 695 
657 additional_lowerings = {}696 additional_lowerings = {}
658 697 
659- def index_pointwise(x, indices):
660- return index_impl(x, indices, check=True)
661- 
662- additional_lowerings[aten.index] = index_pointwise
663- additional_lowerings[aten.index.Tensor] = index_pointwise
664- 
665 bitwise_and_fn = make_pointwise(ops.bitwise_and)698 bitwise_and_fn = make_pointwise(ops.bitwise_and)
666 699 
667 def bitwise_and_tensor(a, b):700 def bitwise_and_tensor(a, b):
@@ -2688,6 +2721,26 @@ def _register_npu_inductor_flex_attention():
2688 mode=FlexMode.BWDDKDV,2721 mode=FlexMode.BWDDKDV,
2689 )2722 )
2690 2723 
2724+ tasklist_reduce_ub_safe = True
2725+ if (
2726+ flexattention_mask_out
2727+ and npu_config.flex_attention.bwd_dkdv_tasklist
2728+ and not bwd_has_dynamic_shape
2729+ ):
2730+ tasklist_safe_dkdv_configs = _filter_dkdv_tasklist_reduce_configs(
2731+ bwd_dkdv_dict_configs,
2732+ qk_head_dim=kernel_options["QK_HEAD_DIM"],
2733+ v_head_dim=kernel_options["V_HEAD_DIM"],
2734+ )
2735+ if tasklist_safe_dkdv_configs:
2736+ bwd_dkdv_dict_configs = tasklist_safe_dkdv_configs
2737+ else:
2738+ tasklist_reduce_ub_safe = False
2739+ log.warning(
2740+ "No dK/dV config satisfies the tasklist-reduce UB "
2741+ "constraint; disabling tasklist codegen for this graph."
2742+ )
2743+ 
2691 log.debug(2744 log.debug(
2692 "bwd dict_configs count: dq=%d dkdv=%d",2745 "bwd dict_configs count: dq=%d dkdv=%d",
2693 len(bwd_dq_dict_configs),2746 len(bwd_dq_dict_configs),
@@ -2848,6 +2901,7 @@ def _register_npu_inductor_flex_attention():
2848 not flexattention_mask_out2901 not flexattention_mask_out
2849 or not npu_config.flex_attention.bwd_dkdv_tasklist2902 or not npu_config.flex_attention.bwd_dkdv_tasklist
2850 or bwd_has_dynamic_shape2903 or bwd_has_dynamic_shape
2904+ or not tasklist_reduce_ub_safe
2851 ):2905 ):
2852 return {}2906 return {}
2853 2907 
@@ -162,8 +162,8 @@ class FlexAttentionConfigGenerator:
162 and self.sparse_kv_block_size is not None162 and self.sparse_kv_block_size is not None
163 ):163 ):
164 return (164 return (
165- block_m == self.sparse_q_block_size165+ self.sparse_q_block_size % block_m == 0
166- and block_n == self.sparse_kv_block_size166+ and self.sparse_kv_block_size % block_n == 0
167 )167 )
168 return True168 return True
169 169 
@@ -210,6 +210,12 @@ def build_sparse_mask_candidate_configs(
210 for block in (128, 64)210 for block in (128, 64)
211 if block <= sparse_kv_block_size and sparse_kv_block_size % block == 0211 if block <= sparse_kv_block_size and sparse_kv_block_size % block == 0
212 ]212 ]
213+ if not mask_block_m_candidates or not mask_block_n_candidates:
214+ raise ValueError(
215+ "Q and KV block size must be divisible by BLOCK_M and BLOCK_N. We "
216+ f"got Q_BLOCK_SIZE={sparse_q_block_size} and "
217+ f"KV_BLOCK_SIZE={sparse_kv_block_size}."
218+ )
213 return [219 return [
214 {220 {
215 "MASK_BLOCK_M": block_m,221 "MASK_BLOCK_M": block_m,
@@ -551,8 +551,9 @@ compute_flex_attention_sparse_mask_in_loop_no_load_balance = r"""
551 NUM_Q_TILES = tl.cdiv(Q_LEN, BLOCK_M)551 NUM_Q_TILES = tl.cdiv(Q_LEN, BLOCK_M)
552 552 
553 for tile_id in range(tl.program_id(0), NUM_Q_TILES * ZQ * HQ, tl.num_programs(0)):553 for tile_id in range(tl.program_id(0), NUM_Q_TILES * ZQ * HQ, tl.num_programs(0)):
554- q_start = tile_id % NUM_Q_TILES554+ tile_id_index = tile_id.to(INDEX_DTYPE)
555- off_zh = tile_id // NUM_Q_TILES555+ q_start = tile_id_index % NUM_Q_TILES
556+ off_zh = tile_id_index // NUM_Q_TILES
556 off_zq = off_zh // HQ557 off_zq = off_zh // HQ
557 off_hq = off_zh % HQ558 off_hq = off_zh % HQ
558 off_zkv = off_zq % ZKV559 off_zkv = off_zq % ZKV
@@ -894,8 +895,10 @@ flex_attention_backward_qmajor_dq_source = r"""
894 KV_LEN = {{size("K", 2)}}895 KV_LEN = {{size("K", 2)}}
895 MATMUL_PRECISION = Q.dtype.element_ty896 MATMUL_PRECISION = Q.dtype.element_ty
896 897 
897- tl.static_assert(BLOCK_M2 == SPARSE_Q_BLOCK_SIZE)898+ tl.static_assert(SPARSE_Q_BLOCK_SIZE % BLOCK_M2 == 0)
898- tl.static_assert(BLOCK_N2 == SPARSE_KV_BLOCK_SIZE)899+ tl.static_assert(SPARSE_KV_BLOCK_SIZE % BLOCK_N2 == 0)
900+ SPARSE_Q_MULTIPLE: tl.constexpr = SPARSE_Q_BLOCK_SIZE // BLOCK_M2
901+ SPARSE_KV_MULTIPLE: tl.constexpr = SPARSE_KV_BLOCK_SIZE // BLOCK_N2
899 902 
900 pid = tl.program_id(0).to(tl.int32)903 pid = tl.program_id(0).to(tl.int32)
901 num_core = tl.num_programs(0).to(tl.int32)904 num_core = tl.num_programs(0).to(tl.int32)
@@ -924,15 +927,17 @@ flex_attention_backward_qmajor_dq_source = r"""
924 stride_full_kv_idx_blk = {{stride("FULL_KV_IDX", 3)}}927 stride_full_kv_idx_blk = {{stride("FULL_KV_IDX", 3)}}
925 928 
926 for task_id in range(pid, DQ_NUM_TASKS, num_core):929 for task_id in range(pid, DQ_NUM_TASKS, num_core):
927- q_block = task_id % DQ_NUM_Q_BLOCKS930+ task_id_index = task_id.to(INDEX_DTYPE)
928- off_zq = (task_id // DQ_NUM_Q_BLOCKS) // HQ931+ q_block = task_id_index % DQ_NUM_Q_BLOCKS
929- off_hq = (task_id // DQ_NUM_Q_BLOCKS) % HQ932+ off_zq = (task_id_index // DQ_NUM_Q_BLOCKS) // HQ
933+ off_hq = (task_id_index // DQ_NUM_Q_BLOCKS) % HQ
930 off_hkv = off_hq // GQA_SHARED_HEADS934 off_hkv = off_hq // GQA_SHARED_HEADS
931 off_zkv = off_zq % ZKV935 off_zkv = off_zq % ZKV
932 sparse_idx_z = off_zq % SPARSE_Z936 sparse_idx_z = off_zq % SPARSE_Z
933 sparse_h = off_hq % SPARSE_HQ937 sparse_h = off_hq % SPARSE_HQ
934 938 
935 q_start = q_block * BLOCK_M2939 q_start = q_block * BLOCK_M2
940+ sparse_q_block = q_block // SPARSE_Q_MULTIPLE
936 offs_m = q_start + tl.arange(0, BLOCK_M2)941 offs_m = q_start + tl.arange(0, BLOCK_M2)
937 942 
938 q_base = Q + stride_qz * off_zq + stride_qh * off_hq943 q_base = Q + stride_qz * off_zq + stride_qh * off_hq
@@ -940,7 +945,7 @@ flex_attention_backward_qmajor_dq_source = r"""
940 v_base = V + stride_vz * off_zkv + stride_vh * off_hkv945 v_base = V + stride_vz * off_zkv + stride_vh * off_hkv
941 do_base = DO + stride_doz * off_zq + stride_doh * off_hq946 do_base = DO + stride_doz * off_zq + stride_doh * off_hq
942 dq_base = DQ + stride_dqz * off_zq + stride_dqh * off_hq947 dq_base = DQ + stride_dqz * off_zq + stride_dqh * off_hq
943- off_chz = ((off_zq * HQ + off_hq) * Q_LEN).to(tl.int64)948+ off_chz = ((off_zq * HQ + off_hq) * Q_LEN).to(INDEX_DTYPE)
944 lse_base = LSE + off_chz949 lse_base = LSE + off_chz
945 delta_base = DELTA + off_chz950 delta_base = DELTA + off_chz
946 951 
@@ -964,12 +969,12 @@ flex_attention_backward_qmajor_dq_source = r"""
964 kv_num_offset = (969 kv_num_offset = (
965 sparse_idx_z * stride_kv_num_blks_z970 sparse_idx_z * stride_kv_num_blks_z
966 + sparse_h * stride_kv_num_blks_h971 + sparse_h * stride_kv_num_blks_h
967- + q_block * stride_kv_num_blks_m972+ + sparse_q_block * stride_kv_num_blks_m
968 )973 )
969 kv_idx_offset = (974 kv_idx_offset = (
970 sparse_idx_z * stride_kv_idx_z975 sparse_idx_z * stride_kv_idx_z
971 + sparse_h * stride_kv_idx_h976 + sparse_h * stride_kv_idx_h
972- + q_block * stride_kv_idx_m977+ + sparse_q_block * stride_kv_idx_m
973 )978 )
974{% if TORCHINDUCTOR_FLEXATTENTION_MASKOUT %}979{% if TORCHINDUCTOR_FLEXATTENTION_MASKOUT %}
975 stride_q_offsets_z = {{stride("Q_OFFSETS", 0)}}980 stride_q_offsets_z = {{stride("Q_OFFSETS", 0)}}
@@ -978,15 +983,21 @@ flex_attention_backward_qmajor_dq_source = r"""
978 q_offsets_idx = (983 q_offsets_idx = (
979 sparse_idx_z * stride_q_offsets_z984 sparse_idx_z * stride_q_offsets_z
980 + sparse_h * stride_q_offsets_h985 + sparse_h * stride_q_offsets_h
981- + q_block * stride_q_offsets_q986+ + sparse_q_block * stride_q_offsets_q
982 )987 )
983 q_offset_base = tl.load(arg_Q_OFFSETS + q_offsets_idx)988 q_offset_base = tl.load(arg_Q_OFFSETS + q_offsets_idx)
984{% endif %}989{% endif %}
985 990 
986 kv_num_blocks = tl.load(arg_KV_NUM_BLKS + kv_num_offset)991 kv_num_blocks = tl.load(arg_KV_NUM_BLKS + kv_num_offset)
987- for blk_pos in range(0, kv_num_blocks):992+ for kv_work_pos in range(0, kv_num_blocks * SPARSE_KV_MULTIPLE):
993+ blk_pos = kv_work_pos // SPARSE_KV_MULTIPLE
994+ kv_sub_block = kv_work_pos % SPARSE_KV_MULTIPLE
988 kv_sparse_idx = tl.load(arg_KV_IDX + kv_idx_offset + blk_pos * stride_kv_idx_blk)995 kv_sparse_idx = tl.load(arg_KV_IDX + kv_idx_offset + blk_pos * stride_kv_idx_blk)
989- offs_n = kv_sparse_idx * SPARSE_KV_BLOCK_SIZE + tl.arange(0, BLOCK_N2)996+ offs_n = (
997+ kv_sparse_idx * SPARSE_KV_BLOCK_SIZE
998+ + kv_sub_block * BLOCK_N2
999+ + tl.arange(0, BLOCK_N2)
1000+ )
990 k = tl.load(1001 k = tl.load(
991 k_base + offs_n[:, None] * stride_kn + offs_k[None, :] * stride_kd,1002 k_base + offs_n[:, None] * stride_kn + offs_k[None, :] * stride_kd,
992 mask=offs_n[:, None] < KV_LEN,1003 mask=offs_n[:, None] < KV_LEN,
@@ -1005,7 +1016,7 @@ flex_attention_backward_qmajor_dq_source = r"""
1005 n = get_bounded_indices(offs_n[None, :], KV_LEN if (not IS_DIVISIBLE or not SAFE_HEAD_DIM) else None)1016 n = get_bounded_indices(offs_n[None, :], KV_LEN if (not IS_DIVISIBLE or not SAFE_HEAD_DIM) else None)
1006{% if TORCHINDUCTOR_FLEXATTENTION_MASKOUT %}1017{% if TORCHINDUCTOR_FLEXATTENTION_MASKOUT %}
1007 flat_blk = q_offset_base + blk_pos1018 flat_blk = q_offset_base + blk_pos
1008- offs_m_local = offs_m[:, None] - q_block * SPARSE_Q_BLOCK_SIZE1019+ offs_m_local = offs_m[:, None] - sparse_q_block * SPARSE_Q_BLOCK_SIZE
1009 offs_n_local = offs_n[None, :] - kv_sparse_idx * SPARSE_KV_BLOCK_SIZE1020 offs_n_local = offs_n[None, :] - kv_sparse_idx * SPARSE_KV_BLOCK_SIZE
1010 mask_offsets = offs_m_local * SPARSE_MASK_STRIDE_M + offs_n_local1021 mask_offsets = offs_m_local * SPARSE_MASK_STRIDE_M + offs_n_local
1011 mask_mod_output = tl.load(1022 mask_mod_output = tl.load(
@@ -1064,17 +1075,23 @@ flex_attention_backward_qmajor_dq_source = r"""
1064 full_kv_num_offset = (1075 full_kv_num_offset = (
1065 sparse_idx_z * stride_full_kv_num_blks_z1076 sparse_idx_z * stride_full_kv_num_blks_z
1066 + sparse_h * stride_full_kv_num_blks_h1077 + sparse_h * stride_full_kv_num_blks_h
1067- + q_block * stride_full_kv_num_blks_m1078+ + sparse_q_block * stride_full_kv_num_blks_m
1068 )1079 )
1069 full_kv_idx_offset = (1080 full_kv_idx_offset = (
1070 sparse_idx_z * stride_full_kv_idx_z1081 sparse_idx_z * stride_full_kv_idx_z
1071 + sparse_h * stride_full_kv_idx_h1082 + sparse_h * stride_full_kv_idx_h
1072- + q_block * stride_full_kv_idx_m1083+ + sparse_q_block * stride_full_kv_idx_m
1073 )1084 )
1074 full_kv_num_blocks = tl.load(arg_FULL_KV_NUM_BLKS + full_kv_num_offset)1085 full_kv_num_blocks = tl.load(arg_FULL_KV_NUM_BLKS + full_kv_num_offset)
1075- for blk_pos in range(0, full_kv_num_blocks):1086+ for kv_work_pos in range(0, full_kv_num_blocks * SPARSE_KV_MULTIPLE):
1087+ blk_pos = kv_work_pos // SPARSE_KV_MULTIPLE
1088+ kv_sub_block = kv_work_pos % SPARSE_KV_MULTIPLE
1076 kv_sparse_idx = tl.load(arg_FULL_KV_IDX + full_kv_idx_offset + blk_pos * stride_full_kv_idx_blk)1089 kv_sparse_idx = tl.load(arg_FULL_KV_IDX + full_kv_idx_offset + blk_pos * stride_full_kv_idx_blk)
1077- offs_n = kv_sparse_idx * SPARSE_KV_BLOCK_SIZE + tl.arange(0, BLOCK_N2)1090+ offs_n = (
1091+ kv_sparse_idx * SPARSE_KV_BLOCK_SIZE
1092+ + kv_sub_block * BLOCK_N2
1093+ + tl.arange(0, BLOCK_N2)
1094+ )
1078 k = tl.load(1095 k = tl.load(
1079 k_base + offs_n[:, None] * stride_kn + offs_k[None, :] * stride_kd,1096 k_base + offs_n[:, None] * stride_kn + offs_k[None, :] * stride_kd,
1080 mask=offs_n[:, None] < KV_LEN,1097 mask=offs_n[:, None] < KV_LEN,
@@ -1210,7 +1227,7 @@ flex_attention_backward_dkdv_only_source = r"""
1210 MATMUL_PRECISION = Q.dtype.element_ty1227 MATMUL_PRECISION = Q.dtype.element_ty
1211 1228 
1212 NUM_KV_BLOCKS = tl.cdiv(KV_LEN, BLOCK_N1)1229 NUM_KV_BLOCKS = tl.cdiv(KV_LEN, BLOCK_N1)
1213- NUM_TASKS = NUM_KV_BLOCKS * ZKV * HKV1230+ NUM_TASKS = NUM_KV_BLOCKS * ZQ * HKV
1214 1231 
1215 pid = tl.program_id(0).to(tl.int32)1232 pid = tl.program_id(0).to(tl.int32)
1216 num_core = tl.num_programs(0).to(tl.int32)1233 num_core = tl.num_programs(0).to(tl.int32)
@@ -1229,9 +1246,10 @@ flex_attention_backward_dkdv_only_source = r"""
1229 stride_q_idx_n = {{stride("Q_IDX", 2)}}1246 stride_q_idx_n = {{stride("Q_IDX", 2)}}
1230 1247 
1231 for task_id in range(pid, NUM_TASKS, num_core):1248 for task_id in range(pid, NUM_TASKS, num_core):
1232- kv_start_block = task_id % NUM_KV_BLOCKS1249+ task_id_index = task_id.to(INDEX_DTYPE)
1233- off_zq = (task_id // NUM_KV_BLOCKS) // HKV1250+ kv_start_block = task_id_index % NUM_KV_BLOCKS
1234- off_hkv = (task_id // NUM_KV_BLOCKS) % HKV1251+ off_zq = (task_id_index // NUM_KV_BLOCKS) // HKV
1252+ off_hkv = (task_id_index // NUM_KV_BLOCKS) % HKV
1235 off_zkv = off_zq % ZKV1253 off_zkv = off_zq % ZKV
1236 sparse_idx_z = off_zq % SPARSE_Z1254 sparse_idx_z = off_zq % SPARSE_Z
1237 1255 
@@ -1239,9 +1257,9 @@ flex_attention_backward_dkdv_only_source = r"""
1239 offs_n1 = start_n1 + tl.arange(0, BLOCK_N1)1257 offs_n1 = start_n1 + tl.arange(0, BLOCK_N1)
1240 pid_mask = kv_start_block // SPARSE_KV_MULTIPLE1258 pid_mask = kv_start_block // SPARSE_KV_MULTIPLE
1241 1259 
1242- k_adj = (stride_kh * off_hkv + stride_kz * off_zkv).to(tl.int64)1260+ k_adj = (stride_kh * off_hkv + stride_kz * off_zkv).to(INDEX_DTYPE)
1243- v_adj = (stride_vh * off_hkv + stride_vz * off_zkv).to(tl.int64)1261+ v_adj = (stride_vh * off_hkv + stride_vz * off_zkv).to(INDEX_DTYPE)
1244- dv_adj = (stride_dvh * off_hkv + stride_dvz * off_zq).to(tl.int64)1262+ dv_adj = (stride_dvh * off_hkv + stride_dvz * off_zq).to(INDEX_DTYPE)
1245 1263 
1246 K1 = K + k_adj1264 K1 = K + k_adj
1247 V1 = V + v_adj1265 V1 = V + v_adj
@@ -1263,9 +1281,9 @@ flex_attention_backward_dkdv_only_source = r"""
1263 for off_g in range(0, GQA_SHARED_HEADS):1281 for off_g in range(0, GQA_SHARED_HEADS):
1264 off_hq1 = off_hkv * GQA_SHARED_HEADS + off_g1282 off_hq1 = off_hkv * GQA_SHARED_HEADS + off_g
1265 1283 
1266- q_adj1 = (stride_qh * off_hq1 + stride_qz * off_zq).to(tl.int64)1284+ q_adj1 = (stride_qh * off_hq1 + stride_qz * off_zq).to(INDEX_DTYPE)
1267- do_adj1 = (stride_doh * off_hq1 + stride_doz * off_zq).to(tl.int64)1285+ do_adj1 = (stride_doh * off_hq1 + stride_doz * off_zq).to(INDEX_DTYPE)
1268- off_chz1 = ((off_zq * HQ + off_hq1) * Q_LEN).to(tl.int64)1286+ off_chz1 = ((off_zq * HQ + off_hq1) * Q_LEN).to(INDEX_DTYPE)
1269 1287 
1270 Q1 = Q + q_adj11288 Q1 = Q + q_adj1
1271 DO1 = DO + do_adj11289 DO1 = DO + do_adj1
@@ -1707,7 +1725,7 @@ flex_attention_backward_dkdv_tasklist_source = (
1707 work_start = tl.load(TASK_OFFSETS + meta_id)1725 work_start = tl.load(TASK_OFFSETS + meta_id)
1708 work_end = tl.load(TASK_OFFSETS + meta_id + 1)1726 work_end = tl.load(TASK_OFFSETS + meta_id + 1)
1709 for work_idx in range(work_start, work_end):1727 for work_idx in range(work_start, work_end):
1710- off_hkv = tl.load(WORK_ITEMS + work_idx * 5 + 0).to(tl.int64)1728+ off_hkv = tl.load(WORK_ITEMS + work_idx * 5 + 0).to(INDEX_DTYPE)
1711 kv_start_block = tl.load(WORK_ITEMS + work_idx * 5 + 1)1729 kv_start_block = tl.load(WORK_ITEMS + work_idx * 5 + 1)
1712{% if not TASKLIST_NO_SPLIT %}1730{% if not TASKLIST_NO_SPLIT %}
1713 sub_id = tl.load(WORK_ITEMS + work_idx * 5 + 2)1731 sub_id = tl.load(WORK_ITEMS + work_idx * 5 + 2)
@@ -1722,9 +1740,9 @@ flex_attention_backward_dkdv_tasklist_source = (
1722 start_n1 = kv_start_block * BLOCK_N11740 start_n1 = kv_start_block * BLOCK_N1
1723 offs_n1 = start_n1 + tl.arange(0, BLOCK_N1)1741 offs_n1 = start_n1 + tl.arange(0, BLOCK_N1)
1724 1742 
1725- k_adj = (stride_kh * off_hkv + stride_kz * off_zkv).to(tl.int64)1743+ k_adj = (stride_kh * off_hkv + stride_kz * off_zkv).to(INDEX_DTYPE)
1726- v_adj = (stride_vh * off_hkv + stride_vz * off_zkv).to(tl.int64)1744+ v_adj = (stride_vh * off_hkv + stride_vz * off_zkv).to(INDEX_DTYPE)
1727- dv_adj = (stride_dvh * off_hkv + stride_dvz * off_zq).to(tl.int64)1745+ dv_adj = (stride_dvh * off_hkv + stride_dvz * off_zq).to(INDEX_DTYPE)
1728 K1 = K + k_adj1746 K1 = K + k_adj
1729 V1 = V + v_adj1747 V1 = V + v_adj
1730{% if TASKLIST_NO_SPLIT %}1748{% if TASKLIST_NO_SPLIT %}
@@ -1751,9 +1769,9 @@ flex_attention_backward_dkdv_tasklist_source = (
1751 for off_g in range(0, GQA_SHARED_HEADS):1769 for off_g in range(0, GQA_SHARED_HEADS):
1752 off_hq1 = off_hkv * GQA_SHARED_HEADS + off_g1770 off_hq1 = off_hkv * GQA_SHARED_HEADS + off_g
1753 sparse_idx_hq1 = off_hq1 % SPARSE_HQ1771 sparse_idx_hq1 = off_hq1 % SPARSE_HQ
1754- q_adj1 = (stride_qh * off_hq1 + stride_qz * off_zq).to(tl.int64)1772+ q_adj1 = (stride_qh * off_hq1 + stride_qz * off_zq).to(INDEX_DTYPE)
1755- do_adj1 = (stride_doh * off_hq1 + stride_doz * off_zq).to(tl.int64)1773+ do_adj1 = (stride_doh * off_hq1 + stride_doz * off_zq).to(INDEX_DTYPE)
1756- off_chz1 = ((off_zq * HQ + off_hq1) * Q_LEN).to(tl.int64)1774+ off_chz1 = ((off_zq * HQ + off_hq1) * Q_LEN).to(INDEX_DTYPE)
1757 Q1 = Q + q_adj11775 Q1 = Q + q_adj1
1758 DO1 = DO + do_adj11776 DO1 = DO + do_adj1
1759 LSE1 = LSE + off_chz11777 LSE1 = LSE + off_chz1
@@ -1959,7 +1977,7 @@ flex_attention_backward_dkdv_reduce_source = r"""
1959 KV_LEN = {{size("DK", 2)}}1977 KV_LEN = {{size("DK", 2)}}
1960 1978 
1961 split_base_id = tl.program_id(0).to(tl.int32)1979 split_base_id = tl.program_id(0).to(tl.int32)
1962- off_hkv = tl.load(SPLIT_BASES + split_base_id * 3 + 0).to(tl.int64)1980+ off_hkv = tl.load(SPLIT_BASES + split_base_id * 3 + 0).to(INDEX_DTYPE)
1963 kv_block = tl.load(SPLIT_BASES + split_base_id * 3 + 1)1981 kv_block = tl.load(SPLIT_BASES + split_base_id * 3 + 1)
1964 split_count = tl.load(SPLIT_BASES + split_base_id * 3 + 2)1982 split_count = tl.load(SPLIT_BASES + split_base_id * 3 + 2)
1965 off_z = tl.zeros_like(off_hkv)1983 off_z = tl.zeros_like(off_hkv)
@@ -395,6 +395,24 @@ class NPUTritonTemplate(TritonTemplate):
395 self.codegen_kernel_name = codegen_kernel_name or f"triton_{name}"395 self.codegen_kernel_name = codegen_kernel_name or f"triton_{name}"
396 self.compile_options = compile_options or NPUTemplateCompileOption()396 self.compile_options = compile_options or NPUTemplateCompileOption()
397 397 
398+ def _write_index_dtype_define(
399+ self,
400+ defines: StringIO,
401+ numel: sympy.Expr,
402+ buffers: Any,
403+ ) -> None:
404+ can_use_32bit_indexing = TritonScheduling.can_use_32bit_indexing(
405+ numel, buffers
406+ )
407+ is_flex_attention = self.name.startswith("flex_attention")
408+ if not can_use_32bit_indexing and not is_flex_attention:
409+ raise NotImplementedError(
410+ "64-bit indexing is not yet implemented for triton templates"
411+ )
412+ if is_flex_attention:
413+ index_dtype = "tl.int32" if can_use_32bit_indexing else "tl.int64"
414+ defines.write(f"INDEX_DTYPE : tl.constexpr = {index_dtype}\n")
415+ 
398 def make_runtime_renderer_factory(416 def make_runtime_renderer_factory(
399 self,417 self,
400 *,418 *,
@@ -421,6 +439,14 @@ class NPUTritonTemplate(TritonTemplate):
421 if self.name.startswith("flex_attention") and name == "generate_with_caching":439 if self.name.startswith("flex_attention") and name == "generate_with_caching":
422 continue440 continue
423 defines.write(f"{name} : tl.constexpr = {value}\n")441 defines.write(f"{name} : tl.constexpr = {value}\n")
442+ fake_out = ir.Buffer(name="buf_out", layout=layout)
443+ numel = sympy_product(layout.size)
444+ if self.manual_output_buffer is None:
445+ buffers = itertools.chain(input_nodes, (fake_out,))
446+ else:
447+ buffers = input_nodes
448+ numel = sympy_product(call_sizes)
449+ self._write_index_dtype_define(defines, numel, buffers)
424 kernel_options = {450 kernel_options = {
425 "defines": defines.getvalue(),451 "defines": defines.getvalue(),
426 "num_stages": num_stages,452 "num_stages": num_stages,
@@ -547,12 +573,10 @@ class NPUTritonTemplate(TritonTemplate):
547 else:573 else:
548 buffers = checked_input_nodes574 buffers = checked_input_nodes
549 numel = sympy_product(call_sizes or layout.size)575 numel = sympy_product(call_sizes or layout.size)
550- if not TritonScheduling.can_use_32bit_indexing(numel, buffers):576+ self._write_index_dtype_define(defines, numel, buffers)
551- raise NotImplementedError(
552- "64-bit indexing is not yet implemented for triton templates"
553- )
554 577 
555- defines.write("INDEX_DTYPE : tl.constexpr = tl.int32\n")578+ if not self.name.startswith("flex_attention"):
579+ defines.write("INDEX_DTYPE : tl.constexpr = tl.int32\n")
556 defines = defines.getvalue()580 defines = defines.getvalue()
557 581 
558 if call_sizes is None:582 if call_sizes is None: