Move self-hosted tests to self-hosted compiler
All checks were successful
CI / ci (MinSizeRel, ubuntu-latest) (pull_request) Successful in 31s
CI / ci (RelWithDebInfo, ubuntu-latest) (pull_request) Successful in 35s
CI / ci (Release, ubuntu-latest) (pull_request) Successful in 30s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 2m53s
CI / ci (Release, ubuntu-latest) (push) Successful in 33s
CI / ci (MinSizeRel, ubuntu-latest) (push) Successful in 36s
CI / ci (RelWithDebInfo, ubuntu-latest) (push) Successful in 40s
CI / ci (Debug, ubuntu-latest) (push) Successful in 2m53s
All checks were successful
CI / ci (MinSizeRel, ubuntu-latest) (pull_request) Successful in 31s
CI / ci (RelWithDebInfo, ubuntu-latest) (pull_request) Successful in 35s
CI / ci (Release, ubuntu-latest) (pull_request) Successful in 30s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 2m53s
CI / ci (Release, ubuntu-latest) (push) Successful in 33s
CI / ci (MinSizeRel, ubuntu-latest) (push) Successful in 36s
CI / ci (RelWithDebInfo, ubuntu-latest) (push) Successful in 40s
CI / ci (Debug, ubuntu-latest) (push) Successful in 2m53s
This commit is contained in:
parent
4bb8f8f973
commit
09c92d666c
284
src/compiler.bbb
284
src/compiler.bbb
@ -77,10 +77,17 @@ O = bits u32
|
||||
|
||||
[extern] open = fn [cc(c)] (path: &u8, o: O, ...) int;
|
||||
[extern] close = fn [cc(c)] (fd: File) int;
|
||||
[extern] dup2 = fn [cc(c)] (old_fd: s32, new_fd: s32) s32;
|
||||
[extern] pipe = fn [cc(c)] (fd: &[2]s32) s32;
|
||||
|
||||
[extern] fstat = fn [cc(c)] (fd: File, s: &Stat) int;
|
||||
[extern] write = fn [cc(c)] (fd: File, pointer: &u8, byte_count: u64) ssize;
|
||||
[extern] read = fn [cc(c)] (fd: File, pointer: &u8, byte_count: u64) ssize;
|
||||
|
||||
[extern] fork = fn [cc(c)] () s32;
|
||||
[extern] execve = fn [cc(c)] (name: &u8, arguments: &&u8, environment: &&u8) s32;
|
||||
[extern] waitpid = fn [cc(c)] (pid: s32, wait_status: &u32, options: s32) s32;
|
||||
|
||||
assert = macro (ok: u1) void
|
||||
{
|
||||
if (!ok)
|
||||
@ -517,6 +524,217 @@ arena_join_string = fn (arena: &Arena, pieces: [][]u8) []u8
|
||||
return pointer[..size];
|
||||
}
|
||||
|
||||
exit_status = fn (s: u32) u8
|
||||
{
|
||||
return #truncate((s & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
term_sig = fn (s: u32) u32
|
||||
{
|
||||
return s & 0x7f;
|
||||
}
|
||||
|
||||
stop_sig = fn (s: u32) u32
|
||||
{
|
||||
return #extend(exit_status(s));
|
||||
}
|
||||
|
||||
if_exited = fn (s: u32) u1
|
||||
{
|
||||
return term_sig(s) == 0;
|
||||
}
|
||||
|
||||
if_stopped = fn (s: u32) u1
|
||||
{
|
||||
>v: u16 = #truncate(((s & 0xffff) * 0x10001) >> 8);
|
||||
return v > 0x7f00;
|
||||
}
|
||||
|
||||
if_signaled = fn (s: u32) u1
|
||||
{
|
||||
return (s & 0xffff) - 1 < 0xff;
|
||||
}
|
||||
|
||||
TerminationKind = enum
|
||||
{
|
||||
unknown,
|
||||
exit,
|
||||
signal,
|
||||
stop,
|
||||
}
|
||||
|
||||
Execution = struct
|
||||
{
|
||||
streams: [2][]u8,
|
||||
termination_kind: TerminationKind,
|
||||
termination_code: u32,
|
||||
}
|
||||
|
||||
StreamPolicy = enum
|
||||
{
|
||||
inherit,
|
||||
pipe,
|
||||
ignore,
|
||||
}
|
||||
|
||||
ExecutionOptions = struct
|
||||
{
|
||||
policies: [2]StreamPolicy,
|
||||
null_fd: s32,
|
||||
null_fd_valid: u1,
|
||||
}
|
||||
|
||||
os_execute = fn (arena: &Arena, arguments: []&u8, environment: &&u8, options: ExecutionOptions) Execution
|
||||
{
|
||||
assert(arguments.pointer[arguments.length] == zero);
|
||||
|
||||
>result: Execution = zero;
|
||||
|
||||
>null_file_descriptor: s32 = -1;
|
||||
if (options.null_fd_valid)
|
||||
{
|
||||
null_file_descriptor = options.null_fd;
|
||||
assert(null_file_descriptor >= 0);
|
||||
}
|
||||
else if (options.policies[0] == .ignore or options.policies[1] == .ignore)
|
||||
{
|
||||
null_file_descriptor = open("/dev/null", { .access_mode = .write_only, zero });
|
||||
assert(null_file_descriptor >= 0);
|
||||
}
|
||||
|
||||
>pipes: [2][2]s32 = undefined;
|
||||
|
||||
for (i: 0..2)
|
||||
{
|
||||
if (options.policies[i] == .pipe)
|
||||
{
|
||||
if (pipe(&pipes[i]) == -1)
|
||||
{
|
||||
#trap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>pid = fork();
|
||||
|
||||
switch (pid)
|
||||
{
|
||||
-1 =>
|
||||
{
|
||||
#trap();
|
||||
},
|
||||
0 =>
|
||||
{
|
||||
for (i: 0..2)
|
||||
{
|
||||
>fd: s32 = #truncate(i + 1);
|
||||
|
||||
switch (options.policies[i])
|
||||
{
|
||||
.inherit => {},
|
||||
.pipe =>
|
||||
{
|
||||
close(pipes[i][0]);
|
||||
dup2(pipes[i][1], fd);
|
||||
close(pipes[i][1]);
|
||||
},
|
||||
.ignore =>
|
||||
{
|
||||
dup2(null_file_descriptor, fd);
|
||||
close(null_file_descriptor);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
>result = execve(arguments[0], arguments.pointer, environment);
|
||||
|
||||
if (result != -1)
|
||||
{
|
||||
unreachable;
|
||||
}
|
||||
|
||||
#trap();
|
||||
},
|
||||
else =>
|
||||
{
|
||||
for (i: 0..2)
|
||||
{
|
||||
if (options.policies[i] == .pipe)
|
||||
{
|
||||
close(pipes[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: better allocation strategy
|
||||
>allocation_size: u64 = 1024 * 1024;
|
||||
>allocation: []u8 = zero;
|
||||
>is_pipe0 = options.policies[0] == .pipe;
|
||||
>is_pipe1 = options.policies[1] == .pipe;
|
||||
if (is_pipe0 or is_pipe1)
|
||||
{
|
||||
allocation = arena_allocate_slice[u8](arena, allocation_size * (#extend(is_pipe0) + #extend(is_pipe1)));
|
||||
}
|
||||
|
||||
>offset: u64 = 0;
|
||||
|
||||
for (i: 0..2)
|
||||
{
|
||||
if (options.policies[i] == .pipe)
|
||||
{
|
||||
>buffer = allocation[offset..offset + allocation_size];
|
||||
>byte_count = read(pipes[i][0], buffer.pointer, buffer.length);
|
||||
assert(byte_count >= 0);
|
||||
result.streams[i] = buffer[..#extend(byte_count)];
|
||||
close(pipes[i][0]);
|
||||
|
||||
offset += allocation_size;
|
||||
}
|
||||
}
|
||||
|
||||
>status: u32 = 0;
|
||||
>waitpid_result = waitpid(pid, &status, 0);
|
||||
|
||||
if (waitpid_result == pid)
|
||||
{
|
||||
if (if_exited(status))
|
||||
{
|
||||
result.termination_kind = .exit;
|
||||
result.termination_code = #extend(exit_status(status));
|
||||
}
|
||||
else if (if_signaled(status))
|
||||
{
|
||||
result.termination_kind = .signal;
|
||||
result.termination_code = term_sig(status);
|
||||
}
|
||||
else if (if_stopped(status))
|
||||
{
|
||||
result.termination_kind = .stop;
|
||||
result.termination_code = stop_sig(status);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.termination_kind = .unknown;
|
||||
}
|
||||
|
||||
if (!options.null_fd_valid and null_file_descriptor > 0)
|
||||
{
|
||||
close(null_file_descriptor);
|
||||
}
|
||||
}
|
||||
else if (waitpid_result == -1)
|
||||
{
|
||||
#trap();
|
||||
}
|
||||
else
|
||||
{
|
||||
#trap();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
file_read = fn (arena: &Arena, path: []u8) []u8
|
||||
{
|
||||
>fd = os_file_open(path.pointer, { .read = 1, zero }, { .read = 1, zero });
|
||||
@ -5420,7 +5638,7 @@ compile = fn (arena: &Arena, options: CompileOptions) void
|
||||
emit(&module);
|
||||
}
|
||||
|
||||
compile_file = fn (arena: &Arena, compile_options: CompileFile) void
|
||||
compile_file = fn (arena: &Arena, compile_options: CompileFile) []u8
|
||||
{
|
||||
>relative_file_path = compile_options.relative_file_path;
|
||||
if (relative_file_path.length < 5)
|
||||
@ -5514,19 +5732,26 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
|
||||
};
|
||||
|
||||
compile(arena, options);
|
||||
|
||||
return output_executable_path;
|
||||
}
|
||||
|
||||
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8) s32
|
||||
names: [_][]u8 = [
|
||||
"minimal",
|
||||
];
|
||||
|
||||
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32
|
||||
{
|
||||
global_state_initialize();
|
||||
>arena = global_state.arena;
|
||||
|
||||
if (argument_count < 2)
|
||||
>arguments = argv[..#extend(argument_count)];
|
||||
if (arguments.length < 2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
>command_string = c_string_to_slice(argv[1]);
|
||||
>command_string = c_string_to_slice(arguments[1]);
|
||||
|
||||
>command_string_to_enum = #string_to_enum(CompilerCommand, command_string);
|
||||
if (!command_string_to_enum.is_valid)
|
||||
@ -5539,7 +5764,7 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
|
||||
{
|
||||
.compile =>
|
||||
{
|
||||
if (argument_count < 3)
|
||||
if (arguments.length < 3)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@ -5549,7 +5774,7 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
|
||||
|
||||
if (argument_count >= 4)
|
||||
{
|
||||
>build_mode_string_to_enum = #string_to_enum(BuildMode, c_string_to_slice(argv[3]));
|
||||
>build_mode_string_to_enum = #string_to_enum(BuildMode, c_string_to_slice(arguments[3]));
|
||||
if (!build_mode_string_to_enum.is_valid)
|
||||
{
|
||||
return 1;
|
||||
@ -5559,7 +5784,7 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
|
||||
|
||||
if (argument_count >= 5)
|
||||
{
|
||||
>has_debug_info_string = c_string_to_slice(argv[4]);
|
||||
>has_debug_info_string = c_string_to_slice(arguments[4]);
|
||||
if (string_equal(has_debug_info_string, "true"))
|
||||
{
|
||||
has_debug_info = 1;
|
||||
@ -5574,7 +5799,7 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
|
||||
}
|
||||
}
|
||||
|
||||
>relative_file_path_pointer = argv[2];
|
||||
>relative_file_path_pointer = arguments[2];
|
||||
if (!relative_file_path_pointer)
|
||||
{
|
||||
return 1;
|
||||
@ -5591,8 +5816,47 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
|
||||
},
|
||||
.test =>
|
||||
{
|
||||
// TODO
|
||||
#trap();
|
||||
if (arguments.length != 2)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
|
||||
>debug_info_array: [_]u1 = [1, 0];
|
||||
for (name: names)
|
||||
{
|
||||
for (build_mode: #enum_values(BuildMode))
|
||||
{
|
||||
for (has_debug_info: debug_info_array)
|
||||
{
|
||||
>position = arena.position;
|
||||
|
||||
>relative_file_path = arena_join_string(arena, [ "tests/", name, ".bbb" ][..]);
|
||||
>compiler_path = compile_file(arena, {
|
||||
.relative_file_path = relative_file_path,
|
||||
.build_mode = build_mode,
|
||||
.has_debug_info = has_debug_info,
|
||||
.silent = 1,
|
||||
});
|
||||
|
||||
>arguments: [_]&u8 = [
|
||||
compiler_path.pointer,
|
||||
"test",
|
||||
zero,
|
||||
];
|
||||
>args = arguments[..arguments.length - 1];
|
||||
>execution = os_execute(arena, args, envp, zero);
|
||||
|
||||
>success = execution.termination_kind == .exit and execution.termination_code == 0;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
#trap();
|
||||
}
|
||||
|
||||
arena.position = position;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -599,75 +599,22 @@ void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
|
||||
.silent = true,
|
||||
});
|
||||
|
||||
Slice<String> name_slice = array_to_slice(names);
|
||||
for (auto name: name_slice(0, 1))
|
||||
char* const compiler_arguments[] =
|
||||
{
|
||||
for (BuildMode build_mode = BuildMode::debug_none; build_mode < BuildMode::count; build_mode = (BuildMode)((backing_type(BuildMode))build_mode + 1))
|
||||
{
|
||||
for (bool has_debug_info : has_debug_info_array)
|
||||
{
|
||||
// COMPILATION START
|
||||
|
||||
String relative_file_path_parts[] = { string_literal("tests/"), name, string_literal(".bbb") };
|
||||
auto relative_file_path = arena_join_string(arena, array_to_slice(relative_file_path_parts));
|
||||
char* const compiler_arguments[] =
|
||||
{
|
||||
(char*)compiler.pointer,
|
||||
(char*)"compile",
|
||||
(char*)relative_file_path.pointer,
|
||||
(char*)build_mode_to_string(build_mode).pointer,
|
||||
(char*)(has_debug_info ? "true" : "false"),
|
||||
0,
|
||||
};
|
||||
Slice<char* const> arg_slice = array_to_slice(compiler_arguments);
|
||||
arg_slice.length -= 1;
|
||||
auto execution = os_execute(arena, arg_slice, environment, {});
|
||||
auto success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0;
|
||||
if (!success)
|
||||
{
|
||||
print(string_literal("Self-hosted test failed to compile: "));
|
||||
print(name);
|
||||
print(string_literal("\n"));
|
||||
bb_fail();
|
||||
}
|
||||
|
||||
// COMPILATION END
|
||||
|
||||
// RUN START
|
||||
|
||||
String exe_parts[] = {
|
||||
string_literal("self-hosted-bb-cache/"),
|
||||
build_mode_to_string(compiler_build_mode),
|
||||
string_literal("_"),
|
||||
compiler_has_debug_info ? string_literal("di") : string_literal("nodi"),
|
||||
string_literal("/"),
|
||||
build_mode_to_string(build_mode),
|
||||
string_literal("_"),
|
||||
has_debug_info ? string_literal("di") : string_literal("nodi"),
|
||||
string_literal("/"),
|
||||
name,
|
||||
};
|
||||
String exe_path = arena_join_string(arena, array_to_slice(exe_parts));
|
||||
char* const run_arguments[] =
|
||||
{
|
||||
(char*)exe_path.pointer,
|
||||
0,
|
||||
};
|
||||
arg_slice = array_to_slice(run_arguments);
|
||||
arg_slice.length -= 1;
|
||||
execution = os_execute(arena, arg_slice, environment, {});
|
||||
success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0;
|
||||
if (!success)
|
||||
{
|
||||
print(string_literal("Self-hosted test failed to run: "));
|
||||
print(name);
|
||||
print(string_literal("\n"));
|
||||
bb_fail();
|
||||
}
|
||||
|
||||
// RUN END
|
||||
}
|
||||
}
|
||||
(char*)compiler.pointer,
|
||||
(char*)"test",
|
||||
0,
|
||||
};
|
||||
Slice<char* const> arg_slice = array_to_slice(compiler_arguments);
|
||||
arg_slice.length -= 1;
|
||||
auto execution = os_execute(arena, arg_slice, environment, {});
|
||||
auto success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0;
|
||||
if (!success)
|
||||
{
|
||||
print(string_literal("Self-hosted tests failed to compile: "));
|
||||
print(build_mode_to_string(compiler_build_mode));
|
||||
print(compiler_has_debug_info ? string_literal(" with debug info\n") : string_literal(" with no debug info\n"));
|
||||
bb_fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -895,6 +895,7 @@ enum class UnaryTypeId
|
||||
{
|
||||
align_of,
|
||||
byte_size,
|
||||
enum_values,
|
||||
integer_max,
|
||||
};
|
||||
|
||||
|
161
src/emitter.cpp
161
src/emitter.cpp
@ -1215,6 +1215,7 @@ fn Type* resolve_type(Module* module, Type* type)
|
||||
} break;
|
||||
case TypeId::void_type:
|
||||
case TypeId::integer:
|
||||
case TypeId::enumerator:
|
||||
{
|
||||
result = type;
|
||||
} break;
|
||||
@ -3054,43 +3055,79 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
|
||||
value->unary_type.type = unary_type;
|
||||
auto unary_type_id = value->unary_type.id;
|
||||
|
||||
if (expected_type)
|
||||
if (unary_type_id == UnaryTypeId::enum_values)
|
||||
{
|
||||
value_type = expected_type;
|
||||
auto element_type = unary_type;
|
||||
|
||||
if (element_type->id != TypeId::enumerator)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
|
||||
auto fields = unary_type->enumerator.fields;
|
||||
auto element_count = fields.length;
|
||||
if (element_count == 0)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
|
||||
auto array_type = get_array_type(module, element_type, element_count);
|
||||
switch (value->kind)
|
||||
{
|
||||
case ValueKind::right:
|
||||
{
|
||||
value_type = array_type;
|
||||
} break;
|
||||
case ValueKind::left:
|
||||
{
|
||||
value_type = get_pointer_type(module, array_type);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value_type = unary_type;
|
||||
}
|
||||
if (expected_type)
|
||||
{
|
||||
value_type = expected_type;
|
||||
}
|
||||
else
|
||||
{
|
||||
value_type = unary_type;
|
||||
}
|
||||
|
||||
assert(value_type);
|
||||
if (value_type->id != TypeId::integer)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
assert(value_type);
|
||||
if (value_type->id != TypeId::integer)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
|
||||
u64 value;
|
||||
auto max_value = integer_max_value(value_type->integer.bit_count, value_type->integer.is_signed);
|
||||
switch (unary_type_id)
|
||||
{
|
||||
case UnaryTypeId::align_of:
|
||||
{
|
||||
value = get_byte_alignment(unary_type);
|
||||
} break;
|
||||
case UnaryTypeId::byte_size:
|
||||
{
|
||||
u64 value;
|
||||
auto max_value = integer_max_value(value_type->integer.bit_count, value_type->integer.is_signed);
|
||||
switch (unary_type_id)
|
||||
{
|
||||
case UnaryTypeId::align_of:
|
||||
{
|
||||
value = get_byte_alignment(unary_type);
|
||||
} break;
|
||||
case UnaryTypeId::byte_size:
|
||||
{
|
||||
|
||||
value = get_byte_size(unary_type);
|
||||
} break;
|
||||
case UnaryTypeId::integer_max:
|
||||
{
|
||||
value = integer_max_value(unary_type->integer.bit_count, unary_type->integer.is_signed);
|
||||
} break;
|
||||
}
|
||||
value = get_byte_size(unary_type);
|
||||
} break;
|
||||
case UnaryTypeId::integer_max:
|
||||
{
|
||||
value = integer_max_value(unary_type->integer.bit_count, unary_type->integer.is_signed);
|
||||
} break;
|
||||
case UnaryTypeId::enum_values:
|
||||
{
|
||||
unreachable();
|
||||
} break;
|
||||
}
|
||||
|
||||
if (value > max_value)
|
||||
{
|
||||
report_error();
|
||||
if (value > max_value)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
}
|
||||
|
||||
typecheck(module, expected_type, value_type);
|
||||
@ -4827,6 +4864,7 @@ fn void invalidate_analysis(Module* module, Value* value)
|
||||
{
|
||||
case ValueId::variable_reference:
|
||||
case ValueId::constant_integer:
|
||||
case ValueId::unary_type:
|
||||
break;
|
||||
case ValueId::aggregate_initialization:
|
||||
{
|
||||
@ -6953,6 +6991,43 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
|
||||
auto constant_integer = LLVMConstInt(resolved_value_type->llvm.abi, max_value, is_signed);
|
||||
llvm_value = constant_integer;
|
||||
} break;
|
||||
case UnaryTypeId::enum_values:
|
||||
{
|
||||
LLVMValueRef buffer[64];
|
||||
assert(type_kind == TypeKind::memory);
|
||||
assert(unary_type->id == TypeId::enumerator);
|
||||
auto fields = unary_type->enumerator.fields;
|
||||
auto llvm_enum_type = unary_type->llvm.memory;
|
||||
u64 i = 0;
|
||||
for (auto& field : fields)
|
||||
{
|
||||
auto v = field.value;
|
||||
buffer[i] = LLVMConstInt(llvm_enum_type, v, false);
|
||||
i += 1;
|
||||
}
|
||||
auto array_value = LLVMConstArray2(llvm_enum_type, buffer, i);
|
||||
|
||||
switch (value->kind)
|
||||
{
|
||||
case ValueKind::right:
|
||||
{
|
||||
llvm_value = array_value;
|
||||
} break;
|
||||
case ValueKind::left:
|
||||
{
|
||||
auto is_constant = true;
|
||||
assert(resolved_value_type->id == TypeId::pointer);
|
||||
auto array_type = resolved_value_type->pointer.element_type;
|
||||
assert(array_type->id == TypeId::array);
|
||||
resolve_type_in_place(module, array_type);
|
||||
auto value_array_variable = llvm_module_create_global_variable(module->llvm.module, array_type->llvm.memory, is_constant, LLVMInternalLinkage, array_value, string_literal("enum.values"), 0, LLVMNotThreadLocal, 0, 0);
|
||||
auto alignment = get_byte_alignment(resolved_value_type);
|
||||
LLVMSetAlignment(value_array_variable, alignment);
|
||||
LLVMSetUnnamedAddress(value_array_variable, LLVMGlobalUnnamedAddr);
|
||||
llvm_value = value_array_variable;
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
case ValueId::binary:
|
||||
@ -7542,6 +7617,21 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
|
||||
{
|
||||
field_value = value->constant_integer.value;
|
||||
} break;
|
||||
case ValueId::enum_literal:
|
||||
{
|
||||
auto enum_name = value->enum_literal;
|
||||
auto value_type = value->type;
|
||||
assert(value_type->id == TypeId::enumerator);
|
||||
|
||||
for (auto& field: value_type->enumerator.fields)
|
||||
{
|
||||
if (enum_name.equal(field.name))
|
||||
{
|
||||
field_value = field.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default: unreachable();
|
||||
}
|
||||
|
||||
@ -8228,6 +8318,14 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
|
||||
|
||||
analyze_type(module, right, 0, {});
|
||||
|
||||
if (right->kind == ValueKind::right)
|
||||
{
|
||||
if (!is_slice(right->type))
|
||||
{
|
||||
reanalyze_type_as_left_value(module, right);
|
||||
}
|
||||
}
|
||||
|
||||
Type* aggregate_type = 0;
|
||||
|
||||
switch (right->kind)
|
||||
@ -8235,10 +8333,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
|
||||
case ValueKind::right:
|
||||
{
|
||||
aggregate_type = right->type;
|
||||
if (!is_slice(aggregate_type))
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
assert(is_slice(aggregate_type));
|
||||
} break;
|
||||
case ValueKind::left:
|
||||
{
|
||||
|
@ -7,6 +7,7 @@ enum class ValueIntrinsic
|
||||
byte_size,
|
||||
enum_from_int,
|
||||
enum_name,
|
||||
enum_values,
|
||||
extend,
|
||||
has_debug_info,
|
||||
integer_max,
|
||||
@ -1159,6 +1160,7 @@ fn Token tokenize(Module* module)
|
||||
string_literal("byte_size"),
|
||||
string_literal("enum_from_int"),
|
||||
string_literal("enum_name"),
|
||||
string_literal("enum_values"),
|
||||
string_literal("extend"),
|
||||
string_literal("has_debug_info"),
|
||||
string_literal("integer_max"),
|
||||
@ -1711,6 +1713,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
||||
} break;
|
||||
case ValueIntrinsic::align_of:
|
||||
case ValueIntrinsic::byte_size:
|
||||
case ValueIntrinsic::enum_values:
|
||||
case ValueIntrinsic::integer_max:
|
||||
{
|
||||
skip_space(module);
|
||||
@ -1726,6 +1729,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
||||
{
|
||||
case ValueIntrinsic::align_of: id = UnaryTypeId::align_of; break;
|
||||
case ValueIntrinsic::byte_size: id = UnaryTypeId::byte_size; break;
|
||||
case ValueIntrinsic::enum_values: id = UnaryTypeId::enum_values; break;
|
||||
case ValueIntrinsic::integer_max: id = UnaryTypeId::integer_max; break;
|
||||
default: unreachable();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user