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
2 changes: 1 addition & 1 deletion libs/vulcan-gpu/abi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ pub fn layoutSharedFrame(allocator: std.mem.Allocator, func: *const Function, a:
const al = switch (func.opcode(inst)) {
.alloca => |al| al,
.iconst, .fconst, .fconst128, .arith, .arith_imm, .icmp, .select => continue,
.struct_new, .extract, .convert, .unary, .global_addr => continue,
.struct_new, .extract, .convert, .decode_low_float, .encode_low_float, .dequantize_nvfp4, .quantize_nvfp4, .unary, .global_addr => continue,
.call, .call_indirect, .load, .store, .prefetch, .@"if" => continue,
.va_start, .va_arg, .va_end, .dot, .matmul, .barrier, .atomic_rmw => continue,
};
Expand Down
59 changes: 59 additions & 0 deletions libs/vulcan-gpu/offload.zig
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ pub fn lowerToLoopNest(
block: [3]u32,
) Error!Function {
if (func.blockCount() == 0) return error.Unsupported;
for (0..func.blockCount()) |bi| {
for (func.blockInsts(@enumFromInt(bi))) |inst| switch (func.opcode(inst)) {
.decode_low_float, .encode_low_float => return error.Unsupported,
.dequantize_nvfp4, .quantize_nvfp4 => return error.Unsupported,
else => {},
};
}
if (returnsValue(func)) return error.Unsupported;
if (entryIsBranchTarget(func)) return error.Unsupported;
if (hasBlockAttribute(func)) return error.Unsupported;
Expand Down Expand Up @@ -726,6 +733,58 @@ test "a value-returning kernel is rejected" {
);
}

test "both low float directions are rejected before loop-nest construction" {
const allocator = std.testing.allocator;
inline for (.{ true, false }) |decode_direction| {
var kernel = Function.init(allocator);
defer kernel.deinit();
const u16_t = try kernel.types.intern(.{ .int = .{ .signedness = .unsigned, .bits = 16 } });
const f32_t = try kernel.types.intern(.{ .float = .f32 });
const ptr_t = try kernel.types.ptrGlobal();
const entry = try kernel.appendBlock();
const source = try kernel.appendBlockParam(entry, if (decode_direction) u16_t else f32_t);
const output = try kernel.appendBlockParam(entry, ptr_t);
const conversion: ir.function.LowFloatConvert = .{ .value = source, .format = .bf16 };
const result = try kernel.appendInst(entry, if (decode_direction) f32_t else u16_t, if (decode_direction) .{ .decode_low_float = conversion } else .{ .encode_low_float = conversion });
try kernel.appendStore(entry, result, output);
kernel.setTerminator(entry, .{ .ret = ir.function.Ret.none() });
try std.testing.expectError(error.Unsupported, lowerToLoopNest(allocator, &kernel, .{ 1, 1, 1 }));
}
}

test "both nvfp4 directions are rejected before loop-nest construction" {
const allocator = std.testing.allocator;
inline for (.{ true, false }) |dequantize| {
var kernel = Function.init(allocator);
defer kernel.deinit();
const u8_t = try kernel.types.intern(.{ .int = .{ .signedness = .unsigned, .bits = 8 } });
const f32_t = try kernel.types.intern(.{ .float = .f32 });
const ptr_t = try kernel.types.ptrGlobal();
const entry = try kernel.appendBlock();
const payload = try kernel.appendBlockParam(entry, u8_t);
const block_scale = try kernel.appendBlockParam(entry, u8_t);
const value = try kernel.appendBlockParam(entry, f32_t);
const global_scale = try kernel.appendBlockParam(entry, f32_t);
const output = try kernel.appendBlockParam(entry, ptr_t);
const conversion: ir.function.NvFp4Convert = .{
.value = if (dequantize) payload else value,
.block_scale = block_scale,
.global_scale = global_scale,
.block_application = .multiply,
.global_application = .divide,
};
const result = try kernel.appendInst(entry, if (dequantize) f32_t else u8_t, if (dequantize) .{ .dequantize_nvfp4 = conversion } else .{ .quantize_nvfp4 = conversion });
try kernel.appendStore(entry, result, output);
kernel.setTerminator(entry, .{ .ret = ir.function.Ret.none() });
const before = try ir.bitcode.encode(allocator, &kernel);
defer allocator.free(before);
try std.testing.expectError(error.Unsupported, lowerToLoopNest(allocator, &kernel, .{ 1, 1, 1 }));
const after = try ir.bitcode.encode(allocator, &kernel);
defer allocator.free(after);
try std.testing.expectEqualSlices(u8, before, after);
}
}

test "a builtin parameter that is not a 32-bit integer is rejected" {
// The induction variables are i32, and an arithmetic op needs both operands to share a
// type, so a wider builtin has no correct lowering here.
Expand Down
2 changes: 2 additions & 0 deletions libs/vulcan-ir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const std = @import("std");

pub const entity = @import("vulcan-ir/entity.zig");
pub const types = @import("vulcan-ir/types.zig");
pub const low_float = @import("vulcan-ir/low_float.zig");
pub const nvfp4 = @import("vulcan-ir/nvfp4.zig");
pub const function = @import("vulcan-ir/function.zig");
pub const builder = @import("vulcan-ir/builder.zig");
pub const parser = @import("vulcan-ir/parser.zig");
Expand Down
Loading
Loading