lib/chant/src/lower/convert.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const choir = @import("choir");
 2 const ast = @import("../ast/root.zig");
 3 const context = @import("context.zig");
 4 const emit = @import("emit.zig");
 5 const Error = @import("error.zig").Error;
 6 
 7 const ArithDialect = choir.dialects.ArithDialect;
 8 const MemrefDialect = choir.dialects.MemrefDialect;
 9 const Lowerer = context.Lowerer;
10 
11 pub fn scalarKind(c_type: *const ast.Type) Error!choir.dialects.arith.ScalarKind {
12     return switch (c_type.kind) {
13         .enum_type => try scalarKind(c_type.child orelse &ast.types.int_type),
14         .char_type => if (c_type.is_unsigned) .u8 else .i8,
15         .short_type => if (c_type.is_unsigned) .u16 else .i16,
16         .int_type => if (c_type.is_unsigned) .u32 else .i32,
17         .long_type => if (c_type.is_unsigned) .u64 else .i64,
18         .bitint_type => try bitintScalarKind(c_type.bit_width, c_type.is_unsigned),
19         .float_type => .f32,
20         .double_type => .f64,
21         .decimal32_type => .f32,
22         .decimal64_type => .f64,
23         .decimal128_type => error.UnsupportedType,
24         else => error.UnsupportedType,
25     };
26 }
27 
28 fn bitintScalarKind(width: u16, is_unsigned: bool) Error!choir.dialects.arith.ScalarKind {
29     if (width <= 8) return if (is_unsigned) .u8 else .i8;
30     if (width <= 16) return if (is_unsigned) .u16 else .i16;
31     if (width <= 32) return if (is_unsigned) .u32 else .i32;
32     if (width <= 64) return if (is_unsigned) .u64 else .i64;
33     return error.UnsupportedType;
34 }
35 
36 pub fn scalarType(lowerer: *Lowerer, c_type: *const ast.Type) Error!choir.Type {
37     const kind = try scalarKind(c_type);
38     return ArithDialect.getScalarType(lowerer.ctx, kind) catch return error.OutOfMemory;
39 }
40 
41 pub fn pointerElement(c_type: *const ast.Type) Error!*const ast.Type {
42     var current = ast.types.element(c_type) orelse return error.UnsupportedType;
43     while (current.kind == .array) {
44         current = ast.types.element(current) orelse return error.UnsupportedType;
45     }
46     if (!ast.types.isArithmetic(current)) return error.UnsupportedType;
47     return current;
48 }
49 
50 pub fn valueType(lowerer: *Lowerer, c_type: *const ast.Type) Error!choir.Type {
51     if (ast.types.isPointerLike(c_type)) {
52         const element = try pointerElement(c_type);
53         const element_type = try scalarType(lowerer, element);
54         return MemrefDialect.getMemrefTypeDynamic(lowerer.ctx, element_type, .host) catch return error.OutOfMemory;
55     }
56     return scalarType(lowerer, c_type);
57 }
58 
59 pub fn sameScalar(lhs: *const ast.Type, rhs: *const ast.Type) bool {
60     if (lhs.kind == .enum_type and rhs.kind == .enum_type) {
61         return sameScalar(lhs.child orelse &ast.types.int_type, rhs.child orelse &ast.types.int_type);
62     }
63     return lhs.kind == rhs.kind and lhs.is_unsigned == rhs.is_unsigned and lhs.bit_width == rhs.bit_width;
64 }
65 
66 pub fn promote(c_type: *const ast.Type) *const ast.Type {
67     if (c_type.kind == .bitint_type) return c_type;
68     if (c_type.kind == .enum_type) return promote(c_type.child orelse &ast.types.int_type);
69     if (ast.types.isInteger(c_type) and ast.types.integerRank(c_type) < ast.types.integerRank(&ast.types.int_type)) {
70         return &ast.types.int_type;
71     }
72     return c_type;
73 }
74 
75 pub fn convert(
76     lowerer: *Lowerer,
77     value: *choir.Value,
78     from: *const ast.Type,
79     to: *const ast.Type,
80 ) Error!*choir.Value {
81     if (sameScalar(from, to)) return value;
82     if (!ast.types.isArithmetic(from) or !ast.types.isArithmetic(to)) return error.UnsupportedType;
83     const target = try scalarType(lowerer, to);
84     const cast = ArithDialect.CastOp.create(lowerer.ctx, lowerer.loc, value, target) catch return error.OutOfMemory;
85     try emit.append(lowerer, cast.op);
86     var mutable = cast;
87     return mutable.getResult();
88 }
89 
90 pub fn toIndex(lowerer: *Lowerer, value: *choir.Value, from: *const ast.Type) Error!*choir.Value {
91     if (!ast.types.isInteger(from)) return error.UnsupportedType;
92     const index_type = ArithDialect.getIndexType(lowerer.ctx) catch return error.OutOfMemory;
93     const cast = ArithDialect.CastOp.create(lowerer.ctx, lowerer.loc, value, index_type) catch return error.OutOfMemory;
94     try emit.append(lowerer, cast.op);
95     var mutable = cast;
96     return mutable.getResult();
97 }