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 }