Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ check:
python3 test/test_pto0585_layout_interfaces.py
python3 test/test_version_header.py
python3 test/test_element_tile_api.py
$(CXX) -std=c++20 -Iinclude test/test_sync_core_launch_contract.cpp \
-o /tmp/pto_test_sync_core_launch_contract
/tmp/pto_test_sync_core_launch_contract
$(CXX) -std=c++20 -D__linx -include test/linx_host_type_shim.hpp \
-fsyntax-only -Iinclude test/ptoas_linx_type_compat.cpp
$(CXX) -std=c++20 -D__linx -include test/linx_host_type_shim.hpp \
Expand Down Expand Up @@ -50,6 +53,7 @@ install:
echo '#define PTO_TILEOP_API_HAS_ELEMENT_TILE 1'; \
echo '#define PTO_TILEOP_API_HAS_ELEMENT_VIEW_METADATA 1'; \
echo '#define PTO_TILEOP_API_HAS_TYPED_ELEMENT_VIEWS 1'; \
echo '#define PTO_TILEOP_API_HAS_SYNC_CORE 1'; \
echo ''; \
echo '#endif'; \
} > $(INSTALL_DIR)/common/pto_tileop_api_revision.hpp
Expand Down
10 changes: 10 additions & 0 deletions docs/tileop-usage/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ PTO `main` 是开发分支;需要可复现构建时应锁定上面的 release
的是架构规范和本仓库 wrapper 的交集,并不表示 wrapper 已实现 0.58.7 的全部操作。
每个操作页中的 C++ 签名以本仓库头文件为准,PTO ASL/NDF 是架构合法性的权威来源。

PE 拓扑、`THREAD_ID`、`SYNC_CORE()` 以及启动 context 合同以
[PTO-ISA/pto-spec commit `3c1657c43d212d0cd8a2c3c017da4ad42bec0112`](https://github.com/PTO-ISA/pto-spec/tree/3c1657c43d212d0cd8a2c3c017da4ad42bec0112)
为语义参考;相关运行时约束见 [PE runtime 与 Core 同步](concepts/pe-runtime-and-sync.md)。
该规范快照规定 `THREAD_ID` SSR 地址为 `0x0026`,PE ID 为 `0..3`。版本化 release
信息和该规范快照可能不同步时,编码与版本兼容性仍需同时核对工具链和目标运行环境。

[0.58.3 迁移说明](migration/pto-0583-migration.md)是历史文档,保留用于迁移旧
kernel;其中的旧版本数量、旧 engine inventory 和旧 encoding identity 不能当作
当前规范。不要混用历史 headers、compiler 和规范内容;出现汇编编码、SizeCode
Expand All @@ -30,6 +36,8 @@ kernel;其中的旧版本数量、旧 engine inventory 和旧 encoding identit
- `PTO_TILEOP_API_REVISION`:`make install` 时实际 checkout 的 Git commit;
- `PTO_TILEOP_API_REVISION_IS_EXACT`:revision 是否来自干净 checkout;
- `PTO_TILEOP_API_HAS_LOCAL_B_KN_FIX`:local Right B 使用逻辑 `[K,N]` 契约。
- `PTO_TILEOP_API_HAS_SYNC_CORE`:提供 `SYNC_CORE()` 及其 single-context 保护;
该宏不代表运行时已经启动四个 PE。

当前 wrapper 与 PTO 0.58.7 catalog 的覆盖边界见
[统一支持状态表](support-status.md)。该表区分“已实现”“仅部分 layout 支持”“尚无
Expand Down Expand Up @@ -119,6 +127,8 @@ clang++ --target=linx64v5-unknown-linux-musl -mlxbc -fenable-matrix \
## 阅读路径

- 先了解 [Tile 约束、location、shape 和 bundle](concepts/README.md)。
- 涉及多 PE 启动、`THREAD_ID` 或 `SYNC_CORE()` 时,先阅读
[PE runtime 与 Core 同步](concepts/pe-runtime-and-sync.md)。
- 需要从 GM 传输数据时,阅读 [TLSU load/store/move](tlsu/load-store-move/TLOAD.md)。
其中卷积权重 GM 到 Shared NK 的 `OHWI2NK`/`OIHW2NK` 专用 `TLOAD` overload
也在该页面说明。
Expand Down
1 change: 1 addition & 0 deletions docs/tileop-usage/concepts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [Local 与 Shared Tile](local-and-shared-tile.md)
- [Shape、valid region 与 SizeCode](tile-shape-and-valid-region.md)
- [统一 Local layout 模型(PTO-ISA #291)](local-layout.md)
- [PE runtime 与 Core 同步](pe-runtime-and-sync.md)

Tile partition/assembly 的高层 C++ 接口在上述 shape/valid-region 章节说明;
`B.SUBVIEW/B.ASSEMBLE` 的 C++ 接口与 modifier 生命周期见
Expand Down
75 changes: 75 additions & 0 deletions docs/tileop-usage/concepts/pe-runtime-and-sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# PE runtime 与 Core 同步

本页说明 TileOP API 与 PTO-ISA 规范之间的 PE 启动合同。规范语义以
[PTO-ISA/pto-spec commit `3c1657c43d212d0cd8a2c3c017da4ad42bec0112`](https://github.com/PTO-ISA/pto-spec/tree/3c1657c43d212d0cd8a2c3c017da4ad42bec0112)
为准;本页不把 Linux CPU、CPU simulator 或 pthread 数量当作 PTO PE context 数量。

## PE 身份

`get_thread_idx()` 和 `get_thread_id()` 返回当前 PE 的 `THREAD_ID`。按照当前
PTO-ISA 规范,`THREAD_ID` 是只读 SSR,地址为 `0x0026`,合法值为 `0..3`:

```cpp
#include <common/pto_tileop.hpp>

uint32_t pe_id = get_thread_idx();
// pe_id 必须为 0、1、2 或 3
```

两个函数是 API 别名,不会创建 context,也不会启动其他 PE。

## `SYNC_CORE()`

`SYNC_CORE()` 对应 `SYNC.CORE`,用于当前 Core 中 PE0、PE1、PE2、PE3 的固定集合
rendezvous:

```cpp
// 只有在四个 PE 都执行到同一个静态同步点时才允许调用
SYNC_CORE();
```

调用合同如下:

- 四个 PE 必须以相同的动态顺序到达同一个 `SYNC_CORE()`;
- `PE_MASK` 不会改变 `SYNC.CORE` 的参与者集合;
- 不得在分歧路径、只启动部分 PE 或单 context 进程中调用;
- API 会在发出硬件指令前检查 runtime context 数和 `THREAD_ID`;
- context 数不是 4,或 `THREAD_ID` 不在 `0..3` 时,调用会进入 trap,不会执行
`SYNC.CORE`。

因此,single-context 模式不会因为误执行 `SYNC.CORE` 而永久等待。

## 启动合同

普通 musl `_start`、`crt1`/`rcrt1` 和 TileOP 测试 `_start.s` 都是 single-context
入口,默认报告一个 context:

```text
__pto_runtime_pe_context_count() == 1
```

它们不会自动创建四个 PE,也不会设置四个 PE 的独立栈或 `THREAD_ID`。需要使用
`SYNC_CORE()` 的专用 launcher 必须在调用 kernel 前完成以下工作:

1. 创建四个相互独立的 PE context;
2. 为每个 context 设置独立的启动状态和栈;
3. 分别建立 `THREAD_ID = 0、1、2、3`;
4. 提供强符号 `__pto_runtime_pe_context_count()`,返回 `4`;
5. 让四个 context 从同一个 kernel 入口开始执行。

只有 launcher 明确满足上述合同后,`SYNC_CORE()` 才会发出硬件同步指令。仓库外
的 QEMU 或硬件 launcher 需要单独验证这些条件;Linux SMP、pthread、CPU hart 或
四次普通函数调用都不能替代四个 PTO PE context。

## 编译期 feature 检查

安装后的 `common/pto_tileop_api_revision.hpp` 提供:

```cpp
#if !PTO_TILEOP_API_HAS_SYNC_CORE
#error "SYNC_CORE is required"
#endif
```

该宏表示 wrapper 已提供 `SYNC_CORE()` API 和启动合同保护;它不表示运行时已经
启动了四个 PE。context 数量和 PE ID 仍由实际 launcher 在运行时建立并验证。
76 changes: 76 additions & 0 deletions include/common/pto_pe_runtime.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#ifndef PTO_PE_RUNTIME_HPP
#define PTO_PE_RUNTIME_HPP

#include <stdint.h>

enum {
PTO_RUNTIME_SINGLE_CONTEXTS = 1,
PTO_RUNTIME_CORE_PE_CONTEXTS = 4,
};

// Returns the current PE ID (0..3). The compiler lowers this to SSR_GET of
// the read-only THREAD_ID SSR at the PTO ISA specified address 0x0026.
inline uint32_t get_thread_idx()
{
return __builtin_linx_get_thread_idx();
}

// API convenience alias; this is not a separate architectural operation.
inline uint32_t get_thread_id()
{
return get_thread_idx();
}

// Launch-contract hook. Normal musl startup returns 1. A dedicated launcher
// must define a strong implementation returning 4 only after it has created
// PE0..PE3 as four independent contexts. An absent hook means one context.
extern "C" unsigned __pto_runtime_pe_context_count(void)
__attribute__((weak));

#ifndef PTO_TILEOP_SYNC_CORE_VIOLATION
#define PTO_TILEOP_SYNC_CORE_VIOLATION() __builtin_trap()
#endif

// Keep this header consumable by older Linx compilers used for API-surface
// checks. Such compilers know THREAD_ID but do not yet declare the SYNC.CORE
// builtin. A real Linx build may emit the instruction only when the frontend
// advertises that builtin; otherwise the call fails closed through the same
// violation path as an invalid launch contract.
#if defined(__linx) && defined(__clang__)
#if __has_builtin(__builtin_linx_sync_core)
#define PTO_TILEOP_COMPILER_HAS_SYNC_CORE 1
#endif
#endif

#ifndef PTO_TILEOP_COMPILER_HAS_SYNC_CORE
#define PTO_TILEOP_COMPILER_HAS_SYNC_CORE 0
#endif

#ifndef PTO_TILEOP_SYNC_CORE_EMIT
#if PTO_TILEOP_COMPILER_HAS_SYNC_CORE
#define PTO_TILEOP_SYNC_CORE_EMIT() __builtin_linx_sync_core()
#else
#define PTO_TILEOP_SYNC_CORE_EMIT() PTO_TILEOP_SYNC_CORE_VIOLATION()
#endif
#endif

/// Rendezvous PE0..PE3 in the current Core.
///
/// Every PE in the active kernel invocation must reach the same static call
/// in the same dynamic order. PE_MASK does not change the participant set.
/// The instruction is never issued for single-context or invalid-ID launches.
__attribute__((always_inline)) inline void SYNC_CORE()
{
const unsigned contexts = __pto_runtime_pe_context_count
? __pto_runtime_pe_context_count()
: 1;
const unsigned pe_id = get_thread_idx();
if (contexts != PTO_RUNTIME_CORE_PE_CONTEXTS ||
pe_id >= PTO_RUNTIME_CORE_PE_CONTEXTS) {
PTO_TILEOP_SYNC_CORE_VIOLATION();
return;
}
PTO_TILEOP_SYNC_CORE_EMIT();
}

#endif
13 changes: 1 addition & 12 deletions include/common/pto_tileop.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define PTO_TILEOP_HPP

#include "common/pto_tileop_api_revision.hpp"
#include "common/pto_pe_runtime.hpp"
#include "common/pto_tile.hpp"
#include "common/pto_tile_region.hpp"
#include "common/tileop_api.hpp"
Expand All @@ -13,16 +14,4 @@
#include "common/pto_tile_region_inline_asm.hpp"
#endif

// Returns the current PE ID (0..3).
// Aligned with website manual get_thread_idx(). Lowered to SSR_GET reading
// the read-only PEID SSR (0x0802).
inline uint32_t get_thread_idx() {
return __builtin_linx_get_thread_idx();
}

// API convenience alias; this is not a separate architectural operation.
inline uint32_t get_thread_id() {
return get_thread_idx();
}

#endif
1 change: 1 addition & 0 deletions include/common/pto_tileop_api_revision.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
#define PTO_TILEOP_API_HAS_ELEMENT_TILE 1
#define PTO_TILEOP_API_HAS_ELEMENT_VIEW_METADATA 1
#define PTO_TILEOP_API_HAS_TYPED_ELEMENT_VIEWS 1
#define PTO_TILEOP_API_HAS_SYNC_CORE 1

#endif
5 changes: 4 additions & 1 deletion test/common/_start.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
.type _start,@function
.text
_start:
# This test entry point starts one context. A four-PE launcher must provide
# its own strong __pto_runtime_pe_context_count returning 4 and establish
# PE IDs 0..3 before invoking code that calls SYNC_CORE.
bstart.std call main
c.setret 2, ->ra
_end:
bstart.aux fall
acrc 3
c.bstop
c.bstop
4 changes: 4 additions & 0 deletions test/linx_host_type_shim.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
#define PTO_LINX_COMPAT_TYPES_PROVIDED 1
#define PTO_LINX_HOST_CXX 1

#ifndef PTO_TEST_CUSTOM_THREAD_BUILTINS
inline unsigned __builtin_linx_get_thread_idx() { return 0; }
inline unsigned pto_test_sync_core_calls = 0;
inline void __builtin_linx_sync_core() { ++pto_test_sync_core_calls; }
#endif

// The production Linx compiler provides these scalar types and the tile_size
// type modifier. Define layout-compatible host substitutes so a normal C++
Expand Down
50 changes: 50 additions & 0 deletions test/test_sync_core_launch_contract.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <cstdlib>

static unsigned test_context_count;
static unsigned test_pe_id;
static unsigned test_sync_calls;
static unsigned test_violations;

extern "C" unsigned __pto_runtime_pe_context_count(void)
{
return test_context_count;
}

inline unsigned __builtin_linx_get_thread_idx()
{
return test_pe_id;
}

#define PTO_TILEOP_SYNC_CORE_VIOLATION() (++test_violations)
#define PTO_TILEOP_SYNC_CORE_EMIT() (++test_sync_calls)
#include <common/pto_pe_runtime.hpp>

static void reset(unsigned contexts, unsigned pe_id)
{
test_context_count = contexts;
test_pe_id = pe_id;
test_sync_calls = 0;
test_violations = 0;
}

int main()
{
reset(1, 0);
SYNC_CORE();
if (test_sync_calls != 0 || test_violations != 1)
return EXIT_FAILURE;

reset(4, 4);
SYNC_CORE();
if (test_sync_calls != 0 || test_violations != 1)
return EXIT_FAILURE;

for (unsigned pe_id = 0; pe_id != 4; ++pe_id) {
reset(4, pe_id);
SYNC_CORE();
if (test_sync_calls != 1 || test_violations != 0)
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}
2 changes: 2 additions & 0 deletions test/tileop_api/src/ThreadId.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@

uint32_t read_pe_id() { return get_thread_idx(); }
uint32_t read_pe_id_alias() { return get_thread_id(); }

void rendezvous_core_pes() { SYNC_CORE(); }
Loading