lib/chant/src/lower/memory.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const choir = @import("choir");
3 const ast = @import("../ast/root.zig");
4 const context = @import("context.zig");
5 const convert = @import("convert.zig");
6 const emit = @import("emit.zig");
7 const Error = @import("error.zig").Error;
8
9 const MemrefDialect = choir.dialects.MemrefDialect;
10 const Lowerer = context.Lowerer;
11
12 pub const Place = struct {
13 memref: *choir.Value,
14 index: *choir.Value,
15 c_type: *const ast.Type,
16 };
17
18 pub fn allocaScalar(lowerer: *Lowerer, c_type: *const ast.Type) Error!*choir.Value {
19 const scalar = try convert.scalarType(lowerer, c_type);
20 const memref_type = MemrefDialect.getMemrefType1D(lowerer.ctx, 1, scalar, .host) catch return error.OutOfMemory;
21 const alloca = MemrefDialect.AllocaOp.createStatic(lowerer.ctx, lowerer.loc, memref_type) catch return error.OutOfMemory;
22 try emit.append(lowerer, alloca.op);
23 var mutable = alloca;
24 return mutable.getResult();
25 }
26
27 pub fn allocaObject(lowerer: *Lowerer, c_type: *const ast.Type, requested_alignment: ?u64) Error!*choir.Value {
28 const scalar = try scalarElement(c_type);
29 const count = try staticElementCount(c_type);
30 const scalar_type = try convert.scalarType(lowerer, scalar);
31 const memref_type = MemrefDialect.getMemrefType1DWithAttrs(lowerer.ctx, count, scalar_type, .host, .{
32 .alignment = objectAlignment(c_type, requested_alignment),
33 }) catch return error.OutOfMemory;
34 const alloca = MemrefDialect.AllocaOp.createStatic(lowerer.ctx, lowerer.loc, memref_type) catch return error.OutOfMemory;
35 try emit.append(lowerer, alloca.op);
36 var mutable = alloca;
37 return mutable.getResult();
38 }
39
40 fn objectAlignment(c_type: *const ast.Type, requested_alignment: ?u64) ?u64 {
41 const requested = requested_alignment orelse return null;
42 const natural = ast.types.byteAlign(c_type) orelse 1;
43 return @max(natural, requested);
44 }
45
46 pub fn loadScalar(lowerer: *Lowerer, memref: *choir.Value, c_type: *const ast.Type) Error!*choir.Value {
47 const zero = try emit.indexConstant(lowerer, 0);
48 return loadElement(lowerer, .{ .memref = memref, .index = zero, .c_type = c_type });
49 }
50
51 pub fn loadElement(lowerer: *Lowerer, place: Place) Error!*choir.Value {
52 const scalar = try convert.scalarType(lowerer, place.c_type);
53 const load = MemrefDialect.LoadOp.create(lowerer.ctx, lowerer.loc, place.memref, place.index, scalar) catch return error.OutOfMemory;
54 try emit.append(lowerer, load.op);
55 var mutable = load;
56 return mutable.getResult();
57 }
58
59 pub fn storeElement(lowerer: *Lowerer, place: Place, value: *choir.Value) Error!void {
60 const store = MemrefDialect.StoreOp.create(lowerer.ctx, lowerer.loc, value, place.memref, place.index) catch return error.OutOfMemory;
61 try emit.append(lowerer, store.op);
62 }
63
64 pub fn scalarElement(c_type: *const ast.Type) Error!*const ast.Type {
65 var current = c_type;
66 while (current.kind == .array) {
67 current = current.child orelse return error.UnsupportedType;
68 }
69 if (!ast.types.isArithmetic(current)) return error.UnsupportedType;
70 return current;
71 }
72
73 pub fn staticElementCount(c_type: *const ast.Type) Error!u64 {
74 if (c_type.kind != .array) return 1;
75 const len = c_type.array_len orelse return error.UnsupportedConstruct;
76 const child = c_type.child orelse return error.UnsupportedType;
77 const child_count = try staticElementCount(child);
78 return std.math.mul(u64, len, child_count) catch return error.UnsupportedConstruct;
79 }