lib/choir/src/dialects/builtin.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const alloc_arena = @import("alloc_arena");
  3 const ir = @import("../core/root.zig");
  4 
  5 pub const BuiltinDialect = struct {
  6     pub const name = "builtin";
  7     const op_templates = ir.dialects.operationTemplate.dialect(@This());
  8     pub const spec = ir.dialects.dialectSpec(@This(), .{});
  9 
 10     pub const ModuleOp = struct {
 11         op: *ir.Operation,
 12 
 13         const def = op_templates.explicit(@This(), .{
 14             .mnemonic = "module",
 15             .operands = 0,
 16             .results = 0,
 17             .regions = .{"body"},
 18             .successors = 0,
 19             .dynamic_traits = .{ ir.traits.SymbolTable, ir.traits.IsolatedFromAbove, ir.traits.NoTerminator, ir.traits.SingleBlock },
 20         });
 21         pub const operation_spec = def.operation_spec;
 22         pub const operation_name = def.operation_name;
 23         pub const createOperation = def.createOperation;
 24         pub const getRegion = def.getRegion;
 25 
 26         pub fn create(ctx: *ir.Context, loc: ir.Location) !ModuleOp {
 27             try loadSpec(ctx);
 28             var body = ir.context.initRegion(ctx);
 29             defer body.deinit();
 30             var body_builder = ir.OperationBuilder.init(ctx);
 31             _ = try body_builder.createBlock(&body, &.{}, &.{});
 32             return try @This().createOperation(ctx, loc, &.{}, &.{}, &.{&body}, &.{});
 33         }
 34 
 35         pub fn getBody(self: ModuleOp) *ir.Region {
 36             return self.getRegion("body");
 37         }
 38 
 39         pub fn getBodyBlock(self: ModuleOp) *ir.Block {
 40             return self.getBody().getEntryBlock().?;
 41         }
 42     };
 43 
 44     fn loadSpec(ctx: *ir.Context) !void {
 45         ir.dialects.loadDialectSpec(ctx, spec) catch |err| switch (err) {
 46             error.ContextFrozen => {},
 47             else => return err,
 48         };
 49     }
 50 };
 51 
 52 test "BuiltinDialect.ModuleOp creates container with region" {
 53     const testing = std.testing;
 54     var arena = alloc_arena.Arena.init(std.testing.allocator);
 55     defer arena.deinit();
 56     const allocator = arena.allocator();
 57 
 58     var ctx = try ir.Context.init(allocator, ir.Context.Limits.testing);
 59     defer ctx.deinit(allocator);
 60 
 61     const loc = ir.Location.getUnknown();
 62     const module = try BuiltinDialect.ModuleOp.create(&ctx, loc);
 63 
 64     try testing.expectEqualStrings("builtin.module", module.op.name.name);
 65     const body = module.getBody();
 66     try testing.expect(body.getEntryBlock() != null);
 67     try testing.expect(module.op.hasTraitId(ir.traits.SymbolTable.id));
 68     try testing.expect(module.op.hasTraitId(ir.traits.IsolatedFromAbove.id));
 69     try testing.expect(module.op.hasTraitId(ir.traits.NoTerminator.id));
 70     try testing.expect(module.op.hasTraitId(ir.traits.SingleBlock.id));
 71 
 72     const info = ctx.lookupOperation(BuiltinDialect.ModuleOp.operation_name).?;
 73     try testing.expect(info.shape.regions.allows(1));
 74     try testing.expect(!info.shape.regions.allows(0));
 75     try testing.expect(info.shape.successors.allows(0));
 76     try testing.expect(!info.shape.successors.allows(1));
 77 }
 78 
 79 test "Operations attach to module block" {
 80     const testing = std.testing;
 81     var arena = alloc_arena.Arena.init(std.testing.allocator);
 82     defer arena.deinit();
 83     const allocator = arena.allocator();
 84 
 85     var ctx = try ir.Context.init(allocator, ir.Context.Limits.testing);
 86     defer ctx.deinit(allocator);
 87 
 88     const loc = ir.Location.getUnknown();
 89     const module = try BuiltinDialect.ModuleOp.create(&ctx, loc);
 90     const block = module.getBodyBlock();
 91 
 92     var builder = ir.OperationBuilder.init(&ctx);
 93     builder.setInsertionPoint(block);
 94 
 95     const arith = @import("arith/root.zig").ArithDialect;
 96     const i64_type = try arith.getScalarType(&ctx, .i64);
 97     var state = ir.Operation.State.init("arith.constant", loc);
 98     state.addTypes(&.{i64_type});
 99     const op = try builder.create(state);
100 
101     try testing.expect(op.parent_block == block);
102     try testing.expect(!block.operations.isEmpty());
103     try testing.expect(block.operations.head == @as(?*anyopaque, op));
104 }