Skip to content

Commit 363f4fa

Browse files
committedJul 15, 2018
self-hosted: generate LLVM IR for simple function
·
0.15.10.3.0
1 parent 28c3d48 commit 363f4fa

File tree

8 files changed

+412
-11
lines changed

8 files changed

+412
-11
lines changed
 

‎src-self-hosted/codegen.zig‎

Lines changed: 157 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const ir = @import("ir.zig");
88
const Value = @import("value.zig").Value;
99
const Type = @import("type.zig").Type;
1010
const event = std.event;
11+
const assert = std.debug.assert;
1112

1213
pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) !void {
1314
fn_val.base.ref();
@@ -35,9 +36,23 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
3536

3637
try renderToLlvmModule(&ofile, fn_val, code);
3738

39+
// TODO module level assembly
40+
//if (buf_len(&g->global_asm) != 0) {
41+
// LLVMSetModuleInlineAsm(g->module, buf_ptr(&g->global_asm));
42+
//}
43+
44+
// TODO
45+
//ZigLLVMDIBuilderFinalize(g->dbuilder);
46+
3847
if (comp.verbose_llvm_ir) {
3948
llvm.DumpModule(ofile.module);
4049
}
50+
51+
// verify the llvm module when safety is on
52+
if (std.debug.runtime_safety) {
53+
var error_ptr: ?[*]u8 = null;
54+
_ = llvm.VerifyModule(ofile.module, llvm.AbortProcessAction, &error_ptr);
55+
}
4156
}
4257

4358
pub const ObjectFile = struct {
@@ -55,5 +70,146 @@ pub const ObjectFile = struct {
5570
pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) !void {
5671
// TODO audit more of codegen.cpp:fn_llvm_value and port more logic
5772
const llvm_fn_type = try fn_val.base.typeof.getLlvmType(ofile);
58-
const llvm_fn = llvm.AddFunction(ofile.module, fn_val.symbol_name.ptr(), llvm_fn_type);
73+
const llvm_fn = llvm.AddFunction(
74+
ofile.module,
75+
fn_val.symbol_name.ptr(),
76+
llvm_fn_type,
77+
) orelse return error.OutOfMemory;
78+
79+
const want_fn_safety = fn_val.block_scope.safety.get(ofile.comp);
80+
if (want_fn_safety and ofile.comp.haveLibC()) {
81+
try addLLVMFnAttr(ofile, llvm_fn, "sspstrong");
82+
try addLLVMFnAttrStr(ofile, llvm_fn, "stack-protector-buffer-size", "4");
83+
}
84+
85+
// TODO
86+
//if (fn_val.align_stack) |align_stack| {
87+
// try addLLVMFnAttrInt(ofile, llvm_fn, "alignstack", align_stack);
88+
//}
89+
90+
const fn_type = fn_val.base.typeof.cast(Type.Fn).?;
91+
92+
try addLLVMFnAttr(ofile, llvm_fn, "nounwind");
93+
//add_uwtable_attr(g, fn_table_entry->llvm_value);
94+
try addLLVMFnAttr(ofile, llvm_fn, "nobuiltin");
95+
96+
//if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {
97+
// ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
98+
// ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);
99+
//}
100+
101+
//if (fn_table_entry->section_name) {
102+
// LLVMSetSection(fn_table_entry->llvm_value, buf_ptr(fn_table_entry->section_name));
103+
//}
104+
//if (fn_table_entry->align_bytes > 0) {
105+
// LLVMSetAlignment(fn_table_entry->llvm_value, (unsigned)fn_table_entry->align_bytes);
106+
//} else {
107+
// // We'd like to set the best alignment for the function here, but on Darwin LLVM gives
108+
// // "Cannot getTypeInfo() on a type that is unsized!" assertion failure when calling
109+
// // any of the functions for getting alignment. Not specifying the alignment should
110+
// // use the ABI alignment, which is fine.
111+
//}
112+
113+
//if (!type_has_bits(return_type)) {
114+
// // nothing to do
115+
//} else if (type_is_codegen_pointer(return_type)) {
116+
// addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
117+
//} else if (handle_is_ptr(return_type) &&
118+
// calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
119+
//{
120+
// addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
121+
// addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
122+
//}
123+
124+
// TODO set parameter attributes
125+
126+
// TODO
127+
//uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
128+
//if (err_ret_trace_arg_index != UINT32_MAX) {
129+
// addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
130+
//}
131+
132+
const cur_ret_ptr = if (fn_type.return_type.handleIsPtr()) llvm.GetParam(llvm_fn, 0) else null;
133+
134+
// build all basic blocks
135+
for (code.basic_block_list.toSlice()) |bb| {
136+
bb.llvm_block = llvm.AppendBasicBlockInContext(
137+
ofile.context,
138+
llvm_fn,
139+
bb.name_hint,
140+
) orelse return error.OutOfMemory;
141+
}
142+
const entry_bb = code.basic_block_list.at(0);
143+
llvm.PositionBuilderAtEnd(ofile.builder, entry_bb.llvm_block);
144+
145+
llvm.ClearCurrentDebugLocation(ofile.builder);
146+
147+
// TODO set up error return tracing
148+
// TODO allocate temporary stack values
149+
// TODO create debug variable declarations for variables and allocate all local variables
150+
// TODO finishing error return trace setup. we have to do this after all the allocas.
151+
// TODO create debug variable declarations for parameters
152+
153+
for (code.basic_block_list.toSlice()) |current_block| {
154+
llvm.PositionBuilderAtEnd(ofile.builder, current_block.llvm_block);
155+
for (current_block.instruction_list.toSlice()) |instruction| {
156+
if (instruction.ref_count == 0 and !instruction.hasSideEffects()) continue;
157+
158+
instruction.llvm_value = try instruction.render(ofile, fn_val);
159+
}
160+
current_block.llvm_exit_block = llvm.GetInsertBlock(ofile.builder);
161+
}
162+
}
163+
164+
fn addLLVMAttr(
165+
ofile: *ObjectFile,
166+
val: llvm.ValueRef,
167+
attr_index: llvm.AttributeIndex,
168+
attr_name: []const u8,
169+
) !void {
170+
const kind_id = llvm.GetEnumAttributeKindForName(attr_name.ptr, attr_name.len);
171+
assert(kind_id != 0);
172+
const llvm_attr = llvm.CreateEnumAttribute(ofile.context, kind_id, 0) orelse return error.OutOfMemory;
173+
llvm.AddAttributeAtIndex(val, attr_index, llvm_attr);
174+
}
175+
176+
fn addLLVMAttrStr(
177+
ofile: *ObjectFile,
178+
val: llvm.ValueRef,
179+
attr_index: llvm.AttributeIndex,
180+
attr_name: []const u8,
181+
attr_val: []const u8,
182+
) !void {
183+
const llvm_attr = llvm.CreateStringAttribute(
184+
ofile.context,
185+
attr_name.ptr,
186+
@intCast(c_uint, attr_name.len),
187+
attr_val.ptr,
188+
@intCast(c_uint, attr_val.len),
189+
) orelse return error.OutOfMemory;
190+
llvm.AddAttributeAtIndex(val, attr_index, llvm_attr);
191+
}
192+
193+
fn addLLVMAttrInt(
194+
val: llvm.ValueRef,
195+
attr_index: llvm.AttributeIndex,
196+
attr_name: []const u8,
197+
attr_val: u64,
198+
) !void {
199+
const kind_id = llvm.GetEnumAttributeKindForName(attr_name.ptr, attr_name.len);
200+
assert(kind_id != 0);
201+
const llvm_attr = llvm.CreateEnumAttribute(ofile.context, kind_id, attr_val) orelse return error.OutOfMemory;
202+
llvm.AddAttributeAtIndex(val, attr_index, llvm_attr);
203+
}
204+
205+
fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8) !void {
206+
return addLLVMAttr(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name);
207+
}
208+
209+
fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: []const u8) !void {
210+
return addLLVMAttrStr(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name, attr_val);
211+
}
212+
213+
fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void {
214+
return addLLVMAttrInt(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name, attr_val);
59215
}

‎src-self-hosted/compilation.zig‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,10 @@ pub const Compilation = struct {
606606
return error.Todo;
607607
}
608608

609+
pub fn haveLibC(self: *Compilation) bool {
610+
return self.libc_link_lib != null;
611+
}
612+
609613
pub fn addLinkLib(self: *Compilation, name: []const u8, provided_explicitly: bool) !*LinkLib {
610614
const is_libc = mem.eql(u8, name, "c");
611615

@@ -741,7 +745,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
741745
analyzed_code.dump();
742746
}
743747

744-
// Kick off rendering to LLVM comp, but it doesn't block the fn decl
748+
// Kick off rendering to LLVM module, but it doesn't block the fn decl
745749
// analysis from being complete.
746750
try comp.build_group.call(codegen.renderToLlvm, comp, fn_val, analyzed_code);
747751
}

‎src-self-hosted/ir.zig‎

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const assert = std.debug.assert;
1010
const Token = std.zig.Token;
1111
const ParsedFile = @import("parsed_file.zig").ParsedFile;
1212
const Span = @import("errmsg.zig").Span;
13+
const llvm = @import("llvm.zig");
14+
const ObjectFile = @import("codegen.zig").ObjectFile;
1315

1416
pub const LVal = enum {
1517
None,
@@ -61,6 +63,9 @@ pub const Instruction = struct {
6163
/// the instruction that this one derives from in analysis
6264
parent: ?*Instruction,
6365

66+
/// populated durign codegen
67+
llvm_value: ?llvm.ValueRef,
68+
6469
pub fn cast(base: *Instruction, comptime T: type) ?*T {
6570
if (base.id == comptime typeToId(T)) {
6671
return @fieldParentPtr(T, "base", base);
@@ -108,14 +113,25 @@ pub const Instruction = struct {
108113
inline while (i < @memberCount(Id)) : (i += 1) {
109114
if (base.id == @field(Id, @memberName(Id, i))) {
110115
const T = @field(Instruction, @memberName(Id, i));
111-
const new_inst = try @fieldParentPtr(T, "base", base).analyze(ira);
112-
new_inst.linkToParent(base);
113-
return new_inst;
116+
return @fieldParentPtr(T, "base", base).analyze(ira);
114117
}
115118
}
116119
unreachable;
117120
}
118121

122+
pub fn render(base: *Instruction, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {
123+
switch (base.id) {
124+
Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
125+
Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
126+
Id.Ref => @panic("TODO"),
127+
Id.DeclVar => @panic("TODO"),
128+
Id.CheckVoidStmt => @panic("TODO"),
129+
Id.Phi => @panic("TODO"),
130+
Id.Br => @panic("TODO"),
131+
Id.AddImplicitReturnType => @panic("TODO"),
132+
}
133+
}
134+
119135
fn getAsParam(param: *Instruction) !*Instruction {
120136
const child = param.child orelse return error.SemanticAnalysisFailed;
121137
switch (child.val) {
@@ -186,6 +202,10 @@ pub const Instruction = struct {
186202
new_inst.val = IrVal{ .KnownValue = self.base.val.KnownValue.getRef() };
187203
return new_inst;
188204
}
205+
206+
pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
207+
return self.base.val.KnownValue.getLlvmConst(ofile);
208+
}
189209
};
190210

191211
pub const Return = struct {
@@ -214,6 +234,18 @@ pub const Instruction = struct {
214234

215235
return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });
216236
}
237+
238+
pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) ?llvm.ValueRef {
239+
const value = self.params.return_value.llvm_value;
240+
const return_type = self.params.return_value.getKnownType();
241+
242+
if (return_type.handleIsPtr()) {
243+
@panic("TODO");
244+
} else {
245+
_ = llvm.BuildRet(ofile.builder, value);
246+
}
247+
return null;
248+
}
217249
};
218250

219251
pub const Ref = struct {
@@ -387,12 +419,16 @@ pub const Variable = struct {
387419

388420
pub const BasicBlock = struct {
389421
ref_count: usize,
390-
name_hint: []const u8,
422+
name_hint: [*]const u8, // must be a C string literal
391423
debug_id: usize,
392424
scope: *Scope,
393425
instruction_list: std.ArrayList(*Instruction),
394426
ref_instruction: ?*Instruction,
395427

428+
/// for codegen
429+
llvm_block: llvm.BasicBlockRef,
430+
llvm_exit_block: llvm.BasicBlockRef,
431+
396432
/// the basic block that is derived from this one in analysis
397433
child: ?*BasicBlock,
398434

@@ -426,7 +462,7 @@ pub const Code = struct {
426462
pub fn dump(self: *Code) void {
427463
var bb_i: usize = 0;
428464
for (self.basic_block_list.toSliceConst()) |bb| {
429-
std.debug.warn("{}_{}:\n", bb.name_hint, bb.debug_id);
465+
std.debug.warn("{s}_{}:\n", bb.name_hint, bb.debug_id);
430466
for (bb.instruction_list.toSliceConst()) |instr| {
431467
std.debug.warn(" ");
432468
instr.dump();
@@ -475,7 +511,7 @@ pub const Builder = struct {
475511
}
476512

477513
/// No need to clean up resources thanks to the arena allocator.
478-
pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: []const u8) !*BasicBlock {
514+
pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*]const u8) !*BasicBlock {
479515
const basic_block = try self.arena().create(BasicBlock{
480516
.ref_count = 0,
481517
.name_hint = name_hint,
@@ -485,6 +521,8 @@ pub const Builder = struct {
485521
.child = null,
486522
.parent = null,
487523
.ref_instruction = null,
524+
.llvm_block = undefined,
525+
.llvm_exit_block = undefined,
488526
});
489527
self.next_debug_id += 1;
490528
return basic_block;
@@ -600,7 +638,7 @@ pub const Builder = struct {
600638
if (block.label) |label| {
601639
block_scope.incoming_values = std.ArrayList(*Instruction).init(irb.arena());
602640
block_scope.incoming_blocks = std.ArrayList(*BasicBlock).init(irb.arena());
603-
block_scope.end_block = try irb.createBasicBlock(parent_scope, "BlockEnd");
641+
block_scope.end_block = try irb.createBasicBlock(parent_scope, c"BlockEnd");
604642
block_scope.is_comptime = try irb.buildConstBool(
605643
parent_scope,
606644
Span.token(block.lbrace),
@@ -777,6 +815,7 @@ pub const Builder = struct {
777815
.span = span,
778816
.child = null,
779817
.parent = null,
818+
.llvm_value = undefined,
780819
},
781820
.params = params,
782821
});
@@ -968,7 +1007,7 @@ pub async fn gen(
9681007
var irb = try Builder.init(comp, parsed_file);
9691008
errdefer irb.abort();
9701009

971-
const entry_block = try irb.createBasicBlock(scope, "Entry");
1010+
const entry_block = try irb.createBasicBlock(scope, c"Entry");
9721011
entry_block.ref(); // Entry block gets a reference because we enter it to begin.
9731012
try irb.setCursorAtEndAndAppendBlock(entry_block);
9741013

@@ -1013,6 +1052,7 @@ pub async fn analyze(comp: *Compilation, parsed_file: *ParsedFile, old_code: *Co
10131052
}
10141053

10151054
const return_inst = try old_instruction.analyze(&ira);
1055+
return_inst.linkToParent(old_instruction);
10161056
// Note: if we ever modify the above to handle error.CompileError by continuing analysis,
10171057
// then here we want to check if ira.isCompTime() and return early if true
10181058

‎src-self-hosted/llvm.zig‎

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,91 @@ const builtin = @import("builtin");
22
const c = @import("c.zig");
33
const assert = @import("std").debug.assert;
44

5+
pub const AttributeIndex = c_uint;
6+
pub const Bool = c_int;
7+
58
pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
69
pub const ContextRef = removeNullability(c.LLVMContextRef);
710
pub const ModuleRef = removeNullability(c.LLVMModuleRef);
811
pub const ValueRef = removeNullability(c.LLVMValueRef);
912
pub const TypeRef = removeNullability(c.LLVMTypeRef);
13+
pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef);
14+
pub const AttributeRef = removeNullability(c.LLVMAttributeRef);
1015

16+
pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
1117
pub const AddFunction = c.LLVMAddFunction;
18+
pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
19+
pub const ConstInt = c.LLVMConstInt;
20+
pub const ConstStringInContext = c.LLVMConstStringInContext;
21+
pub const ConstStructInContext = c.LLVMConstStructInContext;
1222
pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext;
23+
pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute;
24+
pub const CreateStringAttribute = c.LLVMCreateStringAttribute;
1325
pub const DisposeBuilder = c.LLVMDisposeBuilder;
1426
pub const DisposeModule = c.LLVMDisposeModule;
27+
pub const DoubleTypeInContext = c.LLVMDoubleTypeInContext;
1528
pub const DumpModule = c.LLVMDumpModule;
29+
pub const FP128TypeInContext = c.LLVMFP128TypeInContext;
30+
pub const FloatTypeInContext = c.LLVMFloatTypeInContext;
31+
pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
32+
pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
33+
pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
34+
pub const InsertBasicBlockInContext = c.LLVMInsertBasicBlockInContext;
35+
pub const Int128TypeInContext = c.LLVMInt128TypeInContext;
36+
pub const Int16TypeInContext = c.LLVMInt16TypeInContext;
37+
pub const Int1TypeInContext = c.LLVMInt1TypeInContext;
38+
pub const Int32TypeInContext = c.LLVMInt32TypeInContext;
39+
pub const Int64TypeInContext = c.LLVMInt64TypeInContext;
40+
pub const Int8TypeInContext = c.LLVMInt8TypeInContext;
41+
pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext;
42+
pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext;
43+
pub const IntTypeInContext = c.LLVMIntTypeInContext;
44+
pub const LabelTypeInContext = c.LLVMLabelTypeInContext;
45+
pub const MDNodeInContext = c.LLVMMDNodeInContext;
46+
pub const MDStringInContext = c.LLVMMDStringInContext;
47+
pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
1648
pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
49+
pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
50+
pub const StructTypeInContext = c.LLVMStructTypeInContext;
51+
pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
1752
pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
53+
pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
54+
pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
55+
pub const ConstAllOnes = c.LLVMConstAllOnes;
56+
pub const ConstNull = c.LLVMConstNull;
57+
58+
pub const VerifyModule = LLVMVerifyModule;
59+
extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
60+
61+
pub const GetInsertBlock = LLVMGetInsertBlock;
62+
extern fn LLVMGetInsertBlock(Builder: BuilderRef) BasicBlockRef;
1863

1964
pub const FunctionType = LLVMFunctionType;
2065
extern fn LLVMFunctionType(
2166
ReturnType: TypeRef,
2267
ParamTypes: [*]TypeRef,
2368
ParamCount: c_uint,
24-
IsVarArg: c_int,
69+
IsVarArg: Bool,
2570
) ?TypeRef;
2671

72+
pub const GetParam = LLVMGetParam;
73+
extern fn LLVMGetParam(Fn: ValueRef, Index: c_uint) ValueRef;
74+
75+
pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext;
76+
extern fn LLVMAppendBasicBlockInContext(C: ContextRef, Fn: ValueRef, Name: [*]const u8) ?BasicBlockRef;
77+
78+
pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd;
79+
extern fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef) void;
80+
81+
pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction;
82+
pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction;
83+
pub const ReturnStatusAction = VerifierFailureAction.LLVMReturnStatusAction;
84+
pub const VerifierFailureAction = c.LLVMVerifierFailureAction;
85+
2786
fn removeNullability(comptime T: type) type {
2887
comptime assert(@typeId(T) == builtin.TypeId.Optional);
2988
return T.Child;
3089
}
90+
91+
pub const BuildRet = LLVMBuildRet;
92+
extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ValueRef;

‎src-self-hosted/scope.zig‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
const std = @import("std");
2+
const builtin = @import("builtin");
23
const Allocator = mem.Allocator;
34
const Decl = @import("decl.zig").Decl;
45
const Compilation = @import("compilation.zig").Compilation;
56
const mem = std.mem;
67
const ast = std.zig.ast;
78
const Value = @import("value.zig").Value;
89
const ir = @import("ir.zig");
10+
const Span = @import("errmsg.zig").Span;
911

1012
pub const Scope = struct {
1113
id: Id,
@@ -93,6 +95,35 @@ pub const Scope = struct {
9395
end_block: *ir.BasicBlock,
9496
is_comptime: *ir.Instruction,
9597

98+
safety: Safety,
99+
100+
const Safety = union(enum) {
101+
Auto,
102+
Manual: Manual,
103+
104+
const Manual = struct {
105+
/// the source span that disabled the safety value
106+
span: Span,
107+
108+
/// whether safety is enabled
109+
enabled: bool,
110+
};
111+
112+
fn get(self: Safety, comp: *Compilation) bool {
113+
return switch (self) {
114+
Safety.Auto => switch (comp.build_mode) {
115+
builtin.Mode.Debug,
116+
builtin.Mode.ReleaseSafe,
117+
=> true,
118+
builtin.Mode.ReleaseFast,
119+
builtin.Mode.ReleaseSmall,
120+
=> false,
121+
},
122+
@TagType(Safety).Manual => |man| man.enabled,
123+
};
124+
}
125+
};
126+
96127
/// Creates a Block scope with 1 reference
97128
pub fn create(comp: *Compilation, parent: ?*Scope) !*Block {
98129
const self = try comp.a().create(Block{
@@ -105,6 +136,7 @@ pub const Scope = struct {
105136
.incoming_blocks = undefined,
106137
.end_block = undefined,
107138
.is_comptime = undefined,
139+
.safety = Safety.Auto,
108140
});
109141
errdefer comp.a().destroy(self);
110142

‎src-self-hosted/type.zig‎

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,81 @@ pub const Type = struct {
7272
}
7373
}
7474

75+
pub fn handleIsPtr(base: *Type) bool {
76+
switch (base.id) {
77+
Id.Type,
78+
Id.ComptimeFloat,
79+
Id.ComptimeInt,
80+
Id.Undefined,
81+
Id.Null,
82+
Id.Namespace,
83+
Id.Block,
84+
Id.BoundFn,
85+
Id.ArgTuple,
86+
Id.Opaque,
87+
=> unreachable,
88+
89+
Id.NoReturn,
90+
Id.Void,
91+
Id.Bool,
92+
Id.Int,
93+
Id.Float,
94+
Id.Pointer,
95+
Id.ErrorSet,
96+
Id.Enum,
97+
Id.Fn,
98+
Id.Promise,
99+
=> return false,
100+
101+
Id.Struct => @panic("TODO"),
102+
Id.Array => @panic("TODO"),
103+
Id.Optional => @panic("TODO"),
104+
Id.ErrorUnion => @panic("TODO"),
105+
Id.Union => @panic("TODO"),
106+
}
107+
}
108+
109+
pub fn hasBits(base: *Type) bool {
110+
switch (base.id) {
111+
Id.Type,
112+
Id.ComptimeFloat,
113+
Id.ComptimeInt,
114+
Id.Undefined,
115+
Id.Null,
116+
Id.Namespace,
117+
Id.Block,
118+
Id.BoundFn,
119+
Id.ArgTuple,
120+
Id.Opaque,
121+
=> unreachable,
122+
123+
Id.Void,
124+
Id.NoReturn,
125+
=> return false,
126+
127+
Id.Bool,
128+
Id.Int,
129+
Id.Float,
130+
Id.Fn,
131+
Id.Promise,
132+
=> return true,
133+
134+
Id.ErrorSet => @panic("TODO"),
135+
Id.Enum => @panic("TODO"),
136+
Id.Pointer => @panic("TODO"),
137+
Id.Struct => @panic("TODO"),
138+
Id.Array => @panic("TODO"),
139+
Id.Optional => @panic("TODO"),
140+
Id.ErrorUnion => @panic("TODO"),
141+
Id.Union => @panic("TODO"),
142+
}
143+
}
144+
145+
pub fn cast(base: *Type, comptime T: type) ?*T {
146+
if (base.id != @field(Id, @typeName(T))) return null;
147+
return @fieldParentPtr(T, "base", base);
148+
}
149+
75150
pub fn dump(base: *const Type) void {
76151
std.debug.warn("{}", @tagName(base.id));
77152
}

‎src-self-hosted/value.zig‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ const std = @import("std");
22
const builtin = @import("builtin");
33
const Scope = @import("scope.zig").Scope;
44
const Compilation = @import("compilation.zig").Compilation;
5+
const ObjectFile = @import("codegen.zig").ObjectFile;
6+
const llvm = @import("llvm.zig");
57

68
/// Values are ref-counted, heap-allocated, and copy-on-write
79
/// If there is only 1 ref then write need not copy
@@ -39,6 +41,17 @@ pub const Value = struct {
3941
std.debug.warn("{}", @tagName(base.id));
4042
}
4143

44+
pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) {
45+
switch (base.id) {
46+
Id.Type => unreachable,
47+
Id.Fn => @panic("TODO"),
48+
Id.Void => return null,
49+
Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile),
50+
Id.NoReturn => unreachable,
51+
Id.Ptr => @panic("TODO"),
52+
}
53+
}
54+
4255
pub const Id = enum {
4356
Type,
4457
Fn,
@@ -123,6 +136,15 @@ pub const Value = struct {
123136
pub fn destroy(self: *Bool, comp: *Compilation) void {
124137
comp.a().destroy(self);
125138
}
139+
140+
pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef {
141+
const llvm_type = llvm.Int1TypeInContext(ofile.context);
142+
if (self.x) {
143+
return llvm.ConstAllOnes(llvm_type);
144+
} else {
145+
return llvm.ConstNull(llvm_type);
146+
}
147+
}
126148
};
127149

128150
pub const NoReturn = struct {

‎std/event/future.zig‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ pub fn Future(comptime T: type) type {
4040
return &self.data;
4141
}
4242

43+
/// Gets the data without waiting for it. If it's available, a pointer is
44+
/// returned. Otherwise, null is returned.
45+
pub fn getOrNull(self: *Self) ?*T {
46+
if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 1) {
47+
return &self.data;
48+
} else {
49+
return null;
50+
}
51+
}
52+
4353
/// Make the data become available. May be called only once.
4454
/// Before calling this, modify the `data` property.
4555
pub fn resolve(self: *Self) void {

0 commit comments

Comments
 (0)
Please sign in to comment.