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 }