Skip to content

Commit 62c25af

Browse files
committedDec 6, 2017
add higher level arg-parsing API + misc. changes
* add @noInlineCall - see #640 This fixes a crash in --release-safe and --release-fast modes where the optimizer inlines everything into _start and clobbers the command line argument data. If we were able to verify that the user's code never reads command line args, we could leave off this "no inline" attribute. * add i29 and u29 primitive types. u29 is the type of alignment, so it makes sense to be a primitive. probably in the future we'll make any `i` or `u` followed by digits into a primitive. * add `aligned` functions to Allocator interface * add `os.argsAlloc` and `os.argsFree` so that you can get a `[]const []u8`, do whatever arg parsing you want, and then free it. For now this uses the other API under the hood, but it could be reimplemented to do a single allocation. * add tests to make sure command line argument parsing works.
·
0.15.20.2.0
1 parent 249cb2a commit 62c25af

File tree

13 files changed

+249
-58
lines changed

13 files changed

+249
-58
lines changed
 

‎src/all_types.hpp‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,7 @@ enum BuiltinFnId {
12701270
BuiltinFnIdFieldParentPtr,
12711271
BuiltinFnIdOffsetOf,
12721272
BuiltinFnIdInlineCall,
1273+
BuiltinFnIdNoInlineCall,
12731274
BuiltinFnIdTypeId,
12741275
BuiltinFnIdShlExact,
12751276
BuiltinFnIdShrExact,
@@ -1439,7 +1440,7 @@ struct CodeGen {
14391440

14401441
struct {
14411442
TypeTableEntry *entry_bool;
1442-
TypeTableEntry *entry_int[2][11]; // [signed,unsigned][2,3,4,5,6,7,8,16,32,64,128]
1443+
TypeTableEntry *entry_int[2][12]; // [signed,unsigned][2,3,4,5,6,7,8,16,29,32,64,128]
14431444
TypeTableEntry *entry_c_int[CIntTypeCount];
14441445
TypeTableEntry *entry_c_longdouble;
14451446
TypeTableEntry *entry_c_void;
@@ -2102,7 +2103,7 @@ struct IrInstructionCall {
21022103
IrInstruction **args;
21032104
bool is_comptime;
21042105
LLVMValueRef tmp_ptr;
2105-
bool is_inline;
2106+
FnInline fn_inline;
21062107
};
21072108

21082109
struct IrInstructionConst {

‎src/analyze.cpp‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3818,12 +3818,14 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_b
38183818
index = 6;
38193819
} else if (size_in_bits == 16) {
38203820
index = 7;
3821-
} else if (size_in_bits == 32) {
3821+
} else if (size_in_bits == 29) {
38223822
index = 8;
3823-
} else if (size_in_bits == 64) {
3823+
} else if (size_in_bits == 32) {
38243824
index = 9;
3825-
} else if (size_in_bits == 128) {
3825+
} else if (size_in_bits == 64) {
38263826
index = 10;
3827+
} else if (size_in_bits == 128) {
3828+
index = 11;
38273829
} else {
38283830
return nullptr;
38293831
}

‎src/codegen.cpp‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {
839839
assert(g->panic_fn != nullptr);
840840
LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
841841
LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
842-
ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, llvm_cc, false, "");
842+
ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, llvm_cc, ZigLLVM_FnInlineAuto, "");
843843
LLVMBuildUnreachable(g->builder);
844844
}
845845

@@ -988,7 +988,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
988988
static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
989989
LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
990990
ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified),
991-
false, "");
991+
ZigLLVM_FnInlineAuto, "");
992992
LLVMBuildUnreachable(g->builder);
993993
}
994994

@@ -2316,12 +2316,22 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
23162316
}
23172317
}
23182318

2319-
bool want_always_inline = (instruction->fn_entry != nullptr &&
2320-
instruction->fn_entry->fn_inline == FnInlineAlways) || instruction->is_inline;
2319+
ZigLLVM_FnInline fn_inline;
2320+
switch (instruction->fn_inline) {
2321+
case FnInlineAuto:
2322+
fn_inline = ZigLLVM_FnInlineAuto;
2323+
break;
2324+
case FnInlineAlways:
2325+
fn_inline = (instruction->fn_entry == nullptr) ? ZigLLVM_FnInlineAuto : ZigLLVM_FnInlineAlways;
2326+
break;
2327+
case FnInlineNever:
2328+
fn_inline = ZigLLVM_FnInlineNever;
2329+
break;
2330+
}
23212331

23222332
LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
23232333
LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
2324-
gen_param_values, (unsigned)gen_param_index, llvm_cc, want_always_inline, "");
2334+
gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
23252335

23262336
for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
23272337
FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
@@ -4634,6 +4644,7 @@ static const uint8_t int_sizes_in_bits[] = {
46344644
7,
46354645
8,
46364646
16,
4647+
29,
46374648
32,
46384649
64,
46394650
128,
@@ -4971,6 +4982,7 @@ static void define_builtin_fns(CodeGen *g) {
49714982
create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);
49724983
create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
49734984
create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
4985+
create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
49744986
create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
49754987
create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
49764988
create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);

‎src/ir.cpp‎

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -928,13 +928,13 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
928928

929929
static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
930930
FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
931-
bool is_comptime, bool is_inline)
931+
bool is_comptime, FnInline fn_inline)
932932
{
933933
IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
934934
call_instruction->fn_entry = fn_entry;
935935
call_instruction->fn_ref = fn_ref;
936936
call_instruction->is_comptime = is_comptime;
937-
call_instruction->is_inline = is_inline;
937+
call_instruction->fn_inline = fn_inline;
938938
call_instruction->args = args;
939939
call_instruction->arg_count = arg_count;
940940

@@ -948,10 +948,10 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
948948

949949
static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
950950
FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
951-
bool is_comptime, bool is_inline)
951+
bool is_comptime, FnInline fn_inline)
952952
{
953953
IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,
954-
old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, is_inline);
954+
old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline);
955955
ir_link_new_instruction(new_instruction, old_instruction);
956956
return new_instruction;
957957
}
@@ -4672,6 +4672,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
46724672
return ir_build_offset_of(irb, scope, node, arg0_value, arg1_value);
46734673
}
46744674
case BuiltinFnIdInlineCall:
4675+
case BuiltinFnIdNoInlineCall:
46754676
{
46764677
if (node->data.fn_call_expr.params.length == 0) {
46774678
add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));
@@ -4692,8 +4693,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
46924693
if (args[i] == irb->codegen->invalid_instruction)
46934694
return args[i];
46944695
}
4696+
FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
46954697

4696-
return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, true);
4698+
return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline);
46974699
}
46984700
case BuiltinFnIdTypeId:
46994701
{
@@ -4804,7 +4806,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
48044806
return args[i];
48054807
}
48064808

4807-
return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, false);
4809+
return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto);
48084810
}
48094811

48104812
static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -10617,7 +10619,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
1061710619

1061810620
static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
1061910621
FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref,
10620-
IrInstruction *first_arg_ptr, bool comptime_fn_call, bool inline_fn_call)
10622+
IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline)
1062110623
{
1062210624
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
1062310625
size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0;
@@ -10876,7 +10878,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1087610878

1087710879
if (type_requires_comptime(return_type)) {
1087810880
// Throw out our work and call the function as if it were comptime.
10879-
return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, false);
10881+
return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);
1088010882
}
1088110883
}
1088210884

@@ -10900,7 +10902,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1090010902

1090110903
size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;
1090210904
IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
10903-
impl_fn, nullptr, impl_param_count, casted_args, false, inline_fn_call);
10905+
impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline);
1090410906

1090510907
TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
1090610908
ir_add_alloca(ira, new_call_instruction, return_type);
@@ -10959,7 +10961,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1095910961
return ira->codegen->builtin_types.entry_invalid;
1096010962

1096110963
IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
10962-
fn_entry, fn_ref, call_param_count, casted_args, false, inline_fn_call);
10964+
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline);
1096310965

1096410966
ir_add_alloca(ira, new_call_instruction, return_type);
1096510967
return ir_finish_anal(ira, return_type);
@@ -10998,13 +11000,13 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
1099811000
} else if (fn_ref->value.type->id == TypeTableEntryIdFn) {
1099911001
FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref);
1100011002
return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,
11001-
fn_ref, nullptr, is_comptime, call_instruction->is_inline);
11003+
fn_ref, nullptr, is_comptime, call_instruction->fn_inline);
1100211004
} else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) {
1100311005
assert(fn_ref->value.special == ConstValSpecialStatic);
1100411006
FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn;
1100511007
IrInstruction *first_arg_ptr = fn_ref->value.data.x_bound_fn.first_arg;
1100611008
return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,
11007-
nullptr, first_arg_ptr, is_comptime, call_instruction->is_inline);
11009+
nullptr, first_arg_ptr, is_comptime, call_instruction->fn_inline);
1100811010
} else {
1100911011
ir_add_error_node(ira, fn_ref->source_node,
1101011012
buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name)));
@@ -11014,7 +11016,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
1101411016

1101511017
if (fn_ref->value.type->id == TypeTableEntryIdFn) {
1101611018
return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->value.type,
11017-
fn_ref, nullptr, false, false);
11019+
fn_ref, nullptr, false, FnInlineAuto);
1101811020
} else {
1101911021
ir_add_error_node(ira, fn_ref->source_node,
1102011022
buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name)));

‎src/zig_llvm.cpp‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,19 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
175175

176176

177177
LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
178-
unsigned NumArgs, unsigned CC, bool always_inline, const char *Name)
178+
unsigned NumArgs, unsigned CC, ZigLLVM_FnInline fn_inline, const char *Name)
179179
{
180180
CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name);
181181
call_inst->setCallingConv(CC);
182-
if (always_inline) {
183-
call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::AlwaysInline);
182+
switch (fn_inline) {
183+
case ZigLLVM_FnInlineAuto:
184+
break;
185+
case ZigLLVM_FnInlineAlways:
186+
call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::AlwaysInline);
187+
break;
188+
case ZigLLVM_FnInlineNever:
189+
call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::NoInline);
190+
break;
184191
}
185192
return wrap(unwrap(B)->Insert(call_inst));
186193
}

‎src/zig_llvm.hpp‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,13 @@ enum ZigLLVM_EmitOutputType {
4545
bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
4646
const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);
4747

48+
enum ZigLLVM_FnInline {
49+
ZigLLVM_FnInlineAuto,
50+
ZigLLVM_FnInlineAlways,
51+
ZigLLVM_FnInlineNever,
52+
};
4853
LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
49-
unsigned NumArgs, unsigned CC, bool always_inline, const char *Name);
54+
unsigned NumArgs, unsigned CC, ZigLLVM_FnInline fn_inline, const char *Name);
5055

5156
LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
5257
LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,

‎std/debug.zig‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,7 @@ var some_mem_index: usize = 0;
977977

978978
error OutOfMemory;
979979

980-
fn globalAlloc(self: &mem.Allocator, n: usize, alignment: usize) -> %[]u8 {
980+
fn globalAlloc(self: &mem.Allocator, n: usize, alignment: u29) -> %[]u8 {
981981
const addr = @ptrToInt(&some_mem[some_mem_index]);
982982
const rem = @rem(addr, alignment);
983983
const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
@@ -991,7 +991,7 @@ fn globalAlloc(self: &mem.Allocator, n: usize, alignment: usize) -> %[]u8 {
991991
return result;
992992
}
993993

994-
fn globalRealloc(self: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {
994+
fn globalRealloc(self: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
995995
if (new_size <= old_mem.len) {
996996
return old_mem[0..new_size];
997997
} else {

‎std/heap.zig‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ pub var c_allocator = Allocator {
1616
.freeFn = cFree,
1717
};
1818

19-
fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {
19+
fn cAlloc(self: &Allocator, n: usize, alignment: u29) -> %[]u8 {
2020
if (c.malloc(usize(n))) |buf| {
2121
@ptrCast(&u8, buf)[0..n]
2222
} else {
2323
error.OutOfMemory
2424
}
2525
}
2626

27-
fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {
27+
fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
2828
if (new_size <= old_mem.len) {
2929
old_mem[0..new_size]
3030
} else {
@@ -106,7 +106,7 @@ pub const IncrementingAllocator = struct {
106106
return self.bytes.len - self.end_index;
107107
}
108108

109-
fn alloc(allocator: &Allocator, n: usize, alignment: usize) -> %[]u8 {
109+
fn alloc(allocator: &Allocator, n: usize, alignment: u29) -> %[]u8 {
110110
const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
111111
const addr = @ptrToInt(&self.bytes[self.end_index]);
112112
const rem = @rem(addr, alignment);
@@ -121,7 +121,7 @@ pub const IncrementingAllocator = struct {
121121
return result;
122122
}
123123

124-
fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {
124+
fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
125125
if (new_size <= old_mem.len) {
126126
return old_mem[0..new_size];
127127
} else {

0 commit comments

Comments
 (0)
Please sign in to comment.