diff --git a/include/PTO/IR/PTOOps.td b/include/PTO/IR/PTOOps.td index 70ade82bb..1ac150e59 100644 --- a/include/PTO/IR/PTOOps.td +++ b/include/PTO/IR/PTOOps.td @@ -1526,6 +1526,10 @@ def PointerCastOp : PTO_Op<"pointer_cast", [AttrSizedOperandSegments, Pure]> { $_builder.getDenseI32ArrayAttr({addrsSize, vRowSize, vColSize})); }]> ]; + + let extraClassDeclaration = [{ + ::mlir::LogicalResult verify(); + }]; } def SlotMarkerOp : PTO_Op<"slot_marker", [ diff --git a/lib/PTO/IR/PTO.cpp b/lib/PTO/IR/PTO.cpp index 3b50fff4c..6ed4c2dcf 100644 --- a/lib/PTO/IR/PTO.cpp +++ b/lib/PTO/IR/PTO.cpp @@ -2835,12 +2835,77 @@ void mlir::pto::annotatePTOEntryFunctions(ModuleOp module) { return success(); } +static std::optional +getLocalAddressAlignmentBytes(Attribute memorySpace) { + auto addrSpace = dyn_cast_or_null(memorySpace); + if (!addrSpace) + return std::nullopt; + + // Keep this verifier as a conservative front-line guard for explicit local + // tile addresses. PTO-ISA's buffer_limits.hpp defines the baseline + // TASSIGN alignment as 32 bytes for local tile memories. For L0 tile + // bases, PTOAS level3/manual IR historically uses a 4096-bit (512-byte) + // granularity; fuller per-arch/per-layout bounds checks belong in PTO-ISA. + switch (addrSpace.getAddressSpace()) { + case AddressSpace::VEC: + case AddressSpace::MAT: + case AddressSpace::BIAS: + case AddressSpace::SCALING: + return 32; + case AddressSpace::LEFT: + case AddressSpace::RIGHT: + case AddressSpace::ACC: + return 512; + case AddressSpace::GM: + case AddressSpace::Zero: + return std::nullopt; + } + return std::nullopt; +} + +static LogicalResult verifyConstantLocalAddress(Operation *op, Value addr, + Attribute memorySpace, + int addrIndex = -1) { + std::optional alignment = + getLocalAddressAlignmentBytes(memorySpace); + if (!alignment || *alignment == 0) + return success(); + + std::optional constantAddr = mlir::getConstantIntValue(addr); + if (!constantAddr) + return success(); + + auto emitAddrError = [&]() { + InFlightDiagnostic diag = op->emitOpError(); + if (addrIndex >= 0) + diag << "addr[" << addrIndex << "]"; + else + diag << "addr"; + return diag; + }; + + if (*constantAddr < 0) + return emitAddrError() << " must be non-negative, got " << *constantAddr; + + uint64_t unsignedAddr = static_cast(*constantAddr); + if ((unsignedAddr % *alignment) != 0) + return emitAddrError() + << " must be aligned to " << *alignment + << " bytes for local tile memory space, got " << unsignedAddr; + + return success(); +} + LogicalResult AllocTileOp::verify() { auto ty = getResult().getType(); // TileBufType if (failed(verifyTileBufLayoutConstraints(*this, ty, "result"))) return failure(); + if (failed(verifyConstantLocalAddress(getOperation(), getAddr(), + ty.getMemorySpace()))) + return failure(); + // op 上有没有传 operands bool hasVR = getValidRow() != nullptr; bool hasVC = getValidCol() != nullptr; @@ -2969,6 +3034,21 @@ LogicalResult MultiTileGetOp::verify() { return success(); } +LogicalResult PointerCastOp::verify() { + auto memRefTy = dyn_cast(getResult().getType()); + if (!memRefTy) + return emitOpError("result must be a memref type"); + + for (auto [idx, addr] : llvm::enumerate(getAddrs())) { + if (failed(verifyConstantLocalAddress(getOperation(), addr, + memRefTy.getMemorySpace(), + static_cast(idx)))) + return failure(); + } + + return success(); +} + LogicalResult MaterializeTileOp::verify() { auto sourceTy = cast(getSource().getType()); auto resultTy = cast(getResult().getType()); @@ -3016,6 +3096,15 @@ LogicalResult TAssignOp::verify() { if (getTile().getType() != getResult().getType()) { return emitOpError("result type must match tile operand type"); } + + auto tileTy = dyn_cast(getTile().getType()); + if (!tileTy) + return emitOpError("tile operand must be !pto.tile_buf"); + + if (failed(verifyConstantLocalAddress(getOperation(), getAddr(), + tileTy.getMemorySpace()))) + return failure(); + return success(); } diff --git a/test/lit/pto/alloc_tile_addr_alignment_invalid.pto b/test/lit/pto/alloc_tile_addr_alignment_invalid.pto new file mode 100644 index 000000000..bd485d469 --- /dev/null +++ b/test/lit/pto/alloc_tile_addr_alignment_invalid.pto @@ -0,0 +1,11 @@ +// RUN: ptoas --pto-level=level3 %s 2>&1 | FileCheck %s + +module { + func.func @unaligned_alloc_tile_addr() { + %bad = arith.constant 70660 : i64 + // CHECK: pto.alloc_tile + // CHECK: addr must be aligned to 32 bytes for local tile memory space, got 70660 + %tile = pto.alloc_tile addr = %bad : !pto.tile_buf + return + } +} diff --git a/test/lit/pto/alloc_tile_addr_alignment_valid.pto b/test/lit/pto/alloc_tile_addr_alignment_valid.pto new file mode 100644 index 000000000..3c3df1d9c --- /dev/null +++ b/test/lit/pto/alloc_tile_addr_alignment_valid.pto @@ -0,0 +1,9 @@ +// RUN: ptoas --pto-level=level3 %s >/dev/null + +module { + func.func @aligned_alloc_tile_addr() { + %ok = arith.constant 71232 : i64 + %tile = pto.alloc_tile addr = %ok : !pto.tile_buf + return + } +} diff --git a/test/lit/pto/pointer_cast_addr_alignment_gm_ignored.pto b/test/lit/pto/pointer_cast_addr_alignment_gm_ignored.pto new file mode 100644 index 000000000..e5b1591cb --- /dev/null +++ b/test/lit/pto/pointer_cast_addr_alignment_gm_ignored.pto @@ -0,0 +1,9 @@ +// RUN: ptoas --pto-level=level3 %s >/dev/null + +module { + func.func @gm_pointer_cast_addr_is_ignored() { + %neg = arith.constant -1 : i64 + %buf = pto.pointer_cast(%neg) : memref<32x64xf16, #pto.address_space> + return + } +} diff --git a/test/lit/pto/pointer_cast_addr_alignment_invalid.pto b/test/lit/pto/pointer_cast_addr_alignment_invalid.pto new file mode 100644 index 000000000..79115ff93 --- /dev/null +++ b/test/lit/pto/pointer_cast_addr_alignment_invalid.pto @@ -0,0 +1,11 @@ +// RUN: ptoas --pto-level=level3 %s 2>&1 | FileCheck %s + +module { + func.func @unaligned_pointer_cast_addr() { + %bad = arith.constant 70660 : i64 + // CHECK: pto.pointer_cast + // CHECK: addr[0] must be aligned to 32 bytes for local tile memory space, got 70660 + %buf = pto.pointer_cast(%bad) : memref<32x64xf16, #pto.address_space> + return + } +} diff --git a/test/lit/pto/tassign_addr_alignment_invalid.pto b/test/lit/pto/tassign_addr_alignment_invalid.pto new file mode 100644 index 000000000..028edf5e8 --- /dev/null +++ b/test/lit/pto/tassign_addr_alignment_invalid.pto @@ -0,0 +1,16 @@ +// RUN: ptoas --pto-level=level3 %s 2>&1 | FileCheck %s + +module { + func.func @unaligned_tassign_addr() attributes {pto.entry} { + %base = arith.constant 0 : i64 + %bad = arith.constant 70660 : i64 + %tile = pto.alloc_tile addr = %base + : !pto.tile_buf + // CHECK: pto.tassign + // CHECK: addr must be aligned to 32 bytes for local tile memory space, got 70660 + %rebased = pto.tassign %tile, %bad + : !pto.tile_buf + -> !pto.tile_buf + return + } +}