Summary
On Ascend950PR camodel (Bisheng + llvm.hivm.vci), a non-zero scalar base passed to pto.vci is ignored. The hardware/backend always behaves as vci(0) and emits lane ids [0..N), even when LLVM IR correctly carries the base immediate.
This breaks absolute index generation such as vci(i * 64) for multi-vreg expert indexing (e.g. TileLang topk_gate).
Spec expectation
For ASC order:
So pto.vci %c64 on !pto.vreg<64xi32> should yield [64, 65, ..., 127].
Observed
Camodel returns [0, 1, ..., 63].
End-to-end symptom in TileLang topk_gate (E=384): top-1 expert 144 was reported as 16 (144 % 64), and 292 as 36, until indices were materialized as vci(0) + vadds(base).
Minimal repro (legacy VPTO)
// kernel.pto — expected [64..127], observed [0..63]
module attributes {pto.target_arch = "a5", pto.backend = "vpto"} {
func.func @vci_nonzero_base(%arg0: !pto.ptr<i32, gm>)
attributes {pto.entry, pto.kernel_kind = #pto.kernel_kind<vector>} {
%c0_i64 = arith.constant 0 : i64
%ub = pto.castptr %c0_i64 : i64 -> !pto.ptr<i32, ub>
%c0 = arith.constant 0 : index
%c64_i32 = arith.constant 64 : i32
pto.vecscope {
%mask = pto.pset_b32 "PAT_ALL" : !pto.mask<b32>
%idx = pto.vci %c64_i32 {order = "ASC"} : i32 -> !pto.vreg<64xi32>
pto.vsts %idx, %ub[%c0], %mask
: !pto.vreg<64xi32>, !pto.ptr<i32, ub>, !pto.mask<b32>
}
pto.set_flag["PIPE_V", "PIPE_MTE3", "EVENT_ID0"]
pto.wait_flag["PIPE_V", "PIPE_MTE3", "EVENT_ID0"]
%c1 = arith.constant 1 : i64
%c64 = arith.constant 64 : i64
%c0b = arith.constant 0 : i64
pto.set_loop_size_ubtoout %c1, %c1 : i64, i64
pto.copy_ubuf_to_gm %ub, %arg0, %c0b, %c1, %c64, %c0b, %c64, %c64
: !pto.ptr<i32, ub>, !pto.ptr<i32, gm>, i64, i64, i64, i64, i64, i64
pto.barrier #pto.pipe<PIPE_ALL>
return
}
}
PTOAS still emits the base into LLVM correctly:
declare <64 x i32> @llvm.hivm.vci.v64s32(i32, i32)
%7 = call <64 x i32> @llvm.hivm.vci.v64s32(i32 64, i32 0)
So this looks like a Bisheng / HIVM intrinsic / camodel bug (or undocumented encoding) rather than PTOAS dropping the operand in IR.
VMI form
pto.vmi.vci %c64 (size 64, contiguous) currently lowers through contiguous iota to a single pto.vci %c64, which hits the same backend bug.
Workaround
Materialize absolute indices as:
lanes = vci(0)
result = vadds(lanes, base) # or ASC: vci(0)+vadds; DESC: vdup(base)-vci(0)
TileLang ASC already used vci(0) + vadds(i*64) for this reason. A local PTOAS workaround rewrites contiguous VMI iota the same way; ideally the backend honors the intrinsic base so that rewrite can be removed.
Environment
- Soc:
Ascend950PR_9599 camodel via msprof op simulator
- PTOAS built against llvm-vpto (HIVM) + CANN 9.0.0
- Reproduced via TileLang
examples/ascend/vmi/topk_gate before the vci(0)+vadds rewrite
Ask
- Confirm whether
llvm.hivm.vci.*(base, order) is supposed to honor a non-zero base.
- If yes, fix Bisheng/HIVM lowering / camodel so
vci(64) yields [64..127].
- If the intrinsic is lane-only by design, please document that and keep the
vci(0)+vadds(base) materialization as the supported pattern (and update ISA docs / gym cases that pass non-zero bases).
Summary
On Ascend950PR camodel (Bisheng +
llvm.hivm.vci), a non-zero scalar base passed topto.vciis ignored. The hardware/backend always behaves asvci(0)and emits lane ids[0..N), even when LLVM IR correctly carries the base immediate.This breaks absolute index generation such as
vci(i * 64)for multi-vreg expert indexing (e.g. TileLangtopk_gate).Spec expectation
For ASC order:
So
pto.vci %c64on!pto.vreg<64xi32>should yield[64, 65, ..., 127].Observed
Camodel returns
[0, 1, ..., 63].End-to-end symptom in TileLang topk_gate (E=384): top-1 expert 144 was reported as 16 (
144 % 64), and 292 as 36, until indices were materialized asvci(0) + vadds(base).Minimal repro (legacy VPTO)
PTOAS still emits the base into LLVM correctly:
So this looks like a Bisheng / HIVM intrinsic / camodel bug (or undocumented encoding) rather than PTOAS dropping the operand in IR.
VMI form
pto.vmi.vci %c64(size 64, contiguous) currently lowers through contiguous iota to a singlepto.vci %c64, which hits the same backend bug.Workaround
Materialize absolute indices as:
TileLang ASC already used
vci(0) + vadds(i*64)for this reason. A local PTOAS workaround rewrites contiguous VMI iota the same way; ideally the backend honors the intrinsic base so that rewrite can be removed.Environment
Ascend950PR_9599camodel viamsprof op simulatorexamples/ascend/vmi/topk_gatebefore thevci(0)+vaddsrewriteAsk
llvm.hivm.vci.*(base, order)is supposed to honor a non-zerobase.vci(64)yields[64..127].vci(0)+vadds(base)materialization as the supported pattern (and update ISA docs / gym cases that pass non-zero bases).