Do not link with debug libc on win32 when using cross compile libs. Add delete methods to dstring. Fixes to macOS aarch64 codegen. Use glibc backtrace when available. Add load_* methods to file. The cast (int[8])int_slice[:8] now works.

This commit is contained in:
Christoffer Lerno
2023-11-27 11:18:42 +01:00
committed by Christoffer Lerno
parent a50c5f4f7c
commit 1d61ace302
25 changed files with 312 additions and 20 deletions

View File

@@ -99,8 +99,8 @@ jobs:
install: git binutils mingw-w64-x86_64-clang mingw-w64-x86_64-ninja mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-python
- shell: msys2 {0}
run: |
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-17.0.4-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-17.0.4-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-17.0.6-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-17.0.6-1-any.pkg.tar.zst
- name: CMake
run: |
cmake -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}

View File

@@ -280,6 +280,37 @@ fn void DString.append_char(&self, char c)
data.chars[data.len++] = c;
}
/**
* @require start < self.len()
* @require end < self.len()
* @require end >= start "End must be same or equal to the start"
**/
fn void DString.delete_range(&self, usz start, usz end)
{
self.delete(start, end - start + 1);
}
/**
* @require start < self.len()
* @require start + len <= self.len()
**/
fn void DString.delete(&self, usz start, usz len = 1)
{
if (!len) return;
StringData* data = self.data();
usz new_len = data.len - len;
if (new_len == 0)
{
data.len = 0;
return;
}
usz len_after = data.len - start - len;
if (len_after > 0)
{
data.chars[start:len_after] = data.chars[start + len:len_after];
}
data.len = new_len;
}
macro void DString.append(&self, value)
{

View File

@@ -444,6 +444,11 @@ fn String String.new_ascii_to_upper(s, Allocator* allocator = mem::heap())
return copy;
}
fn StringIterator String.iterator(s)
{
return { s, 0 };
}
fn String String.temp_ascii_to_upper(s)
{
return s.new_ascii_to_upper(mem::temp());
@@ -575,3 +580,38 @@ fn char! String.to_uchar(s) => s.to_integer(char);
fn double! String.to_double(s) => s.to_real(double);
fn float! String.to_float(s) => s.to_real(float);
fn Splitter String.splitter(self, String split)
{
return Splitter { self, split, 0 };
}
struct Splitter
{
String string;
String split;
usz current;
}
fn void Splitter.reset(&self)
{
self.current = 0;
}
fn String! Splitter.next(&self)
{
usz len = self.string.len;
usz current = self.current;
if (current >= len) return IteratorResult.NO_MORE_ELEMENT?;
String remaining = self.string[current..];
usz! next = remaining.index_of(self.split);
if (try next)
{
defer self.current = current + next + self.split.len;
return remaining[:next];
}
self.current = len;
return remaining;
}

View File

@@ -20,4 +20,4 @@ fn Char32! StringIterator.next(&self)
Char32 res = conv::utf8_to_char32(&self.utf8[current], &read)!;
self.current += read;
return res;
}
}

View File

@@ -138,6 +138,50 @@ fn char! File.read_byte(&self) @dynamic
return (char)c;
}
/**
* Load up to buffer.len characters. Returns IoError.OVERFLOW if the file is longer
* than the buffer.
*
* @param filename "The path to the file to read"
* @param [in] buffer "The buffer to read to"
**/
fn char[]! load_buffer(String filename, char[] buffer)
{
File file = open(filename, "rb")!;
defer (void)file.close();
usz len = file.seek(0, END)!;
if (len > buffer.len) return IoError.OVERFLOW?;
file.seek(0, SET)!;
usz read = 0;
while (read < len)
{
read += file.read(buffer[read:len - read])!;
}
return buffer[:len];
}
fn char[]! load_new(String filename, Allocator* allocator = mem::heap())
{
File file = open(filename, "rb")!;
defer (void)file.close();
usz len = file.seek(0, END)!;
file.seek(0, SET)!;
char* data = allocator.alloc_checked(len)!;
defer catch allocator.free(data);
usz read = 0;
while (read < len)
{
read += file.read(data[read:len - read])!;
}
return data[:len];
}
fn char[]! load_temp(String filename)
{
return load_new(filename, mem::temp());
}
/**
* @require self.file `File must be initialized`
*/

View File

@@ -49,7 +49,7 @@ fault IoError
* @param stream
* @require @is_instream(stream)
**/
macro String! readline(stream = io::stdin(), Allocator* allocator = mem::heap())
macro String! readline(stream = io::stdin(), Allocator* allocator = mem::heap())
{
bool $is_stream = @typeid(stream) == InStream*.typeid;
$if $is_stream:

View File

@@ -1,5 +1,15 @@
module libc @if(env::POSIX);
extern fn void* dlopen(ZString path, int flags);
extern fn CInt dlclose(void*);
extern fn void* dlsym(void* handle, ZString symbol);
const int RTLD_LAZY = 0x1;
const int RTLD_NOW = 0x2;
const int RTLD_LOCAL = 0x4;
const int RTLD_GLOBAL = 0x8;
def Pid_t = int;
def Uid_t = uint;
def Gid_t = uint;

View File

@@ -56,10 +56,21 @@ const CInt WNOHANG = 1;
const CInt WUNTRACES = 2;
JmpBuf backtrace_jmpbuf @local;
fn CInt backtrace(void** buffer, CInt size) @extern("backtrace") @weak
def BacktraceFn = fn CInt(void** buffer, CInt size);
fn CInt backtrace(void** buffer, CInt size)
{
if (size < 1) return 0;
void* handle = libc::dlopen("libc.so.6", libc::RTLD_LAZY);
if (handle)
{
BacktraceFn backtrace_fn = libc::dlsym(handle, "backtrace");
libc::dlclose(handle);
if (backtrace_fn)
{
return backtrace_fn(buffer, size);
}
}
// Loop through the return addresses until we hit a signal.
// This avoids using the frame address.
SignalFunction restore_backtrace = fn void(CInt) {

View File

@@ -1,5 +1,27 @@
# C3C Release Notes
## 0.5.1 Change list
### Changes / improvements
- Improved error messages for const errors.
- Do not link with debug libraries unless using static libraries.
- Add 'print-linking' build option.
- System linker may be used even if the target arch is different from current.
- Slice -> array/vector works for constant slice lenghts.
### Fixes
- On Aarch64 use the correct frame pointer type.
- On Aarch64 macOS, ensure the minimum version is 11.0 (Big Sur)
- Fixes to the yacc grammar.
- Dsym generation on macOS will correctly emit -arch.
- Stacktrace on signals on Linux when backtrace is available.
### Stdlib changes
- `delete` and `delete_range` added to DString.
- `Splitter` iterator added.
- `splitter` and `iterator` String methods.
- `load_new`, `load_buffer` and `load_temp` std::io::file functions.
## 0.5.0 Change List
### Changes / improvements

View File

@@ -379,6 +379,7 @@ typedef struct BuildOptions_
bool print_project_properties;
bool print_precedence;
bool print_build_settings;
bool print_linking;
bool benchmarking;
bool testing;
} BuildOptions;
@@ -450,6 +451,7 @@ typedef struct
bool testing;
bool read_stdin;
bool print_output;
bool print_linking;
bool no_entry;
int build_threads;
TrustLevel trust_level;

View File

@@ -123,6 +123,7 @@ static void usage(void)
OUTPUT(" -L <library dir> - Append the directory to the linker search paths.");
OUTPUT(" -z <argument> - Send the <argument> as a parameter to the linker.");
OUTPUT(" --system-linker=<yes|no> - Use the system linker (default: no for cross compilation, yes otherwise).");
OUTPUT(" --cc <path> - Set C compiler (for C files in projects and use as system linker).");
OUTPUT("");
OUTPUT(" --use-stdlib=<yes|no> - Include the standard library (default: yes).");
OUTPUT(" --link-libc=<yes|no> - Link libc other default libraries (default: yes).");
@@ -140,6 +141,7 @@ static void usage(void)
OUTPUT(" --fp-math=<option> - FP math behaviour: strict, relaxed, fast.");
OUTPUT("");
OUTPUT(" --debug-stats - Print debug statistics.");
OUTPUT(" --print-linking - Print linker arguments.");
#ifndef NDEBUG
OUTPUT(" --debug-log - Print debug logging to stdout.");
#endif
@@ -747,6 +749,11 @@ static void parse_option(BuildOptions *options)
debug_stats = true;
return;
}
if (match_longopt("print-linking"))
{
options->print_linking = true;
return;
}
if (match_longopt("list-keywords"))
{
options->print_keywords = true;

View File

@@ -252,6 +252,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
{
target->arch_os_target = options->arch_os_target_override;
}
target->print_linking = options->print_linking;
if (options->reloc_model != RELOC_DEFAULT) target->reloc_model = options->reloc_model;
if (options->symtab_size) target->symtab_size = options->symtab_size;

View File

@@ -490,8 +490,25 @@ void compiler_compile(void)
{
error_exit("Cannot create exe with the name '%s' - there is already a directory with that name.", output_exe);
}
if (link_libc() && platform_target.os != OS_TYPE_WIN32
&& active_target.arch_os_target == default_target && active_target.system_linker != SYSTEM_LINKER_OFF)
bool system_linker_available = link_libc() && platform_target.os != OS_TYPE_WIN32;
bool use_system_linker = system_linker_available && active_target.arch_os_target == default_target;
switch (active_target.system_linker)
{
case SYSTEM_LINKER_ON:
if (!system_linker_available)
{
eprintf("System linker is not supported, defaulting to built-in linker\n");
break;
}
use_system_linker = true;
break;
case SYSTEM_LINKER_OFF:
use_system_linker = false;
break;
default:
break;
}
if (use_system_linker)
{
platform_linker(output_exe, obj_files, output_file_count);
compiler_link_time = bench_mark();
@@ -504,7 +521,7 @@ void compiler_compile(void)
if (!obj_format_linking_supported(platform_target.object_format) || !linker(output_exe, obj_files,
output_file_count))
{
printf("No linking is performed due to missing linker support.\n");
eprintf("No linking is performed due to missing linker support.\n");
active_target.run_after_compile = false;
}
else

View File

@@ -113,6 +113,7 @@ typedef enum
CAST_SABOOL,
CAST_SAPTR,
CAST_SASA,
CAST_SAARR,
CAST_STRPTR,
CAST_STINLINE,
CAST_VECARR,

View File

@@ -380,8 +380,10 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_
case CAST_IDINT:
case CAST_INTARRBS:
case CAST_BSINTARR:
case CAST_SAARR:
if (eval_kind == CONSTANT_EVAL_CONSTANT_VALUE) return false;
return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind);
}
UNREACHABLE
}

View File

@@ -98,6 +98,12 @@ static void linker_setup_windows(const char ***args_ref, LinkerType linker_type,
UNREACHABLE
}
if (!link_libc()) return;
bool link_with_dynamic_debug_libc = true;
#if !PLATFORM_WINDOWS
// The debug version of libc is usually not available on target machines,
// so we do not link with debug dll versions of libc.
link_with_dynamic_debug_libc = false;
#endif
if (!active_target.win.sdk)
{
const char *path = windows_cross_compile_library();
@@ -123,6 +129,9 @@ static void linker_setup_windows(const char ***args_ref, LinkerType linker_type,
if (file_exists(scratch_buffer_to_string()))
{
active_target.win.sdk = scratch_buffer_copy();
// If we only use the msvc cross compile on windows, we
// avoid linking with dynamic debug dlls.
link_with_dynamic_debug_libc = false;
}
}
}
@@ -171,7 +180,9 @@ static void linker_setup_windows(const char ***args_ref, LinkerType linker_type,
}
else
{
if (is_debug)
// When cross compiling we might not have the relevant debug libraries.
// if so, then exclude them.
if (is_debug && link_with_dynamic_debug_libc)
{
vec_add(*additional_linked_ref, "ucrtd");
vec_add(*additional_linked_ref, "vcruntimed");
@@ -284,6 +295,8 @@ static void linker_setup_macos(const char ***args_ref, LinkerType linker_type)
add_arg("CoreFoundation");
if (linker_type == LINKER_CC)
{
add_arg("-target");
add_arg(platform_target.target_triple);
return;
}
add_arg("-arch");
@@ -774,6 +787,7 @@ void platform_linker(const char *output_file, const char **files, unsigned file_
vec_add(parts, "-lm");
}
const char *output = concat_string_parts(parts);
if (active_target.print_linking) puts(output);
if (system(output) != 0)
{
error_exit("Failed to link executable '%s' using command '%s'.\n", output_file, output);
@@ -782,7 +796,8 @@ void platform_linker(const char *output_file, const char **files, unsigned file_
{
// Create .dSYM
scratch_buffer_clear();
scratch_buffer_printf("dsymutil %s", output_file);
scratch_buffer_printf("dsymutil -arch %s %s", arch_to_linker_arch(platform_target.arch), output_file);
if (active_target.print_linking) puts(scratch_buffer_to_string());
if (system(scratch_buffer_to_string()) != 0)
{
puts("Failed to create .dSYM files, debugging will be impacted.");

View File

@@ -1067,7 +1067,7 @@ void llvm_append_function_attributes(GenContext *c, Decl *decl)
llvm_set_alignment(function, decl->alignment);
}
llvm_attribute_add(c, function, attribute_id.nounwind, -1);
llvm_attribute_add_int(c, function, attribute_id.uwtable, 2, -1);
llvm_attribute_add_int(c, function, attribute_id.uwtable, UWTABLE, -1);
if (decl->func_decl.attr_naked)
{

View File

@@ -1236,6 +1236,22 @@ void llvm_emit_array_to_vector_cast(GenContext *c, BEValue *value, Type *to_type
}
void llvm_emit_subarray_to_vec_array_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type)
{
BEValue pointer;
Type *base = type_lowering(from_type)->array.base;
AlignSize element_alignment = type_abi_alignment(base);
llvm_emit_subarray_pointer(c, value, &pointer);
llvm_value_rvalue(c, &pointer);
LLVMTypeRef type = llvm_get_type(c, to_type);
AlignSize alignment = llvm_abi_alignment(c, type);
LLVMValueRef temp = llvm_emit_alloca(c, type, alignment, ".temp");
unsigned elements = LLVMGetTypeKind(type) == LLVMVectorTypeKind
? LLVMGetVectorSize(type) : LLVMGetArrayLength(type);
llvm_emit_memcpy(c, temp, alignment, pointer.value, element_alignment, elements);
llvm_value_set_address(value, temp, to_type, alignment);
}
void llvm_emit_expand_to_vec_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type)
{
llvm_value_rvalue(c, value);
@@ -1356,6 +1372,9 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu
switch (cast_kind)
{
case CAST_SAARR:
llvm_emit_subarray_to_vec_array_cast(c, value, to_type, from_type);
return;
case CAST_EXPVEC:
llvm_emit_expand_to_vec_cast(c, value, to_type, from_type);
return;

View File

@@ -522,6 +522,8 @@ void llvm_emit_debug_parameter(GenContext *c, Decl *parameter, unsigned index);
void llvm_emit_debug_local_var(GenContext *c, Decl *var);
void llvm_emit_debug_global_var(GenContext *c, Decl *global);
#define FRAMEPOINTER (platform_target.arch == ARCH_TYPE_AARCH64 ? 1 : 2)
#define UWTABLE (active_target.arch_os_target == MACOS_AARCH64 ? 1 : 2)
#define EMIT_LOC(c, x) do { if (c->debug.builder) llvm_emit_debug_location(c, x->span); } while (0)
#define EMIT_SPAN(c, x) do { if (c->debug.builder) llvm_emit_debug_location(c, x); } while (0)

View File

@@ -152,9 +152,9 @@ void gencontext_begin_module(GenContext *c)
{
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "Dwarf Version", 4, type_uint);
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "Debug Info Version", 3, type_uint);
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "frame-pointer", 2, type_uint);
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "frame-pointer", FRAMEPOINTER, type_uint);
}
llvm_set_module_flag(c, LLVMModuleFlagBehaviorError, "uwtable", 2, type_uint);
llvm_set_module_flag(c, LLVMModuleFlagBehaviorError, "uwtable", UWTABLE, type_uint);
c->debug.runtime_version = 1;
c->debug.builder = LLVMCreateDIBuilder(c->module);

View File

@@ -1859,10 +1859,24 @@ static void cast_sa_to_vecarr(SemaContext *context, Expr *expr, Type *to_type)
{
if (!expr_is_const(expr))
{
switch (expr->expr_kind)
{
case EXPR_CAST:
{
Expr *inner = exprptr(expr->cast_expr.expr)->unary_expr.expr;
expr_replace(expr, inner);
cast_no_check(context, expr, to_type, false);
return;
}
case EXPR_SLICE:
{
insert_runtime_cast(expr, CAST_SAARR, to_type);
return;
}
default:
UNREACHABLE;
}
assert(expr->expr_kind == EXPR_CAST);
Expr *inner = exprptr(expr->cast_expr.expr)->unary_expr.expr;
expr_replace(expr, inner);
cast_no_check(context, expr, to_type, false);
return;
}
assert(expr_is_const(expr));

View File

@@ -4484,12 +4484,12 @@ static inline IndexDiff range_const_len(Range *range)
{
Expr *start = exprptr(range->start);
Expr *end = exprptrzero(range->end);
if (!expr_is_const_int(start)) return -1;
if (!end || !expr_is_const_int(end)) return -1;
if (!int_fits(end->const_expr.ixx, TYPE_I32)) return -1;
if (!int_fits(start->const_expr.ixx, TYPE_I32)) return -1;
IndexDiff end_val = (IndexDiff)int_to_i64(end->const_expr.ixx);
if (range->is_len) return end_val;
if (!expr_is_const_int(start)) return -1;
if (!int_fits(start->const_expr.ixx, TYPE_I32)) return -1;
IndexDiff start_val = (IndexDiff)int_to_i64(start->const_expr.ixx);
if (range->start_from_end && range->end_from_end) return start_val - end_val + 1;
if (range->start_from_end != range->end_from_end) return -1;
@@ -8387,7 +8387,11 @@ MemberIndex sema_len_from_const(Expr *expr)
// We also handle the case where we have a cast from a const array.
if (!expr_is_const(expr))
{
if (expr->type->type_kind != TYPE_SUBARRAY) return -1;
if (type_flatten(expr->type)->type_kind != TYPE_SUBARRAY) return -1;
if (expr->expr_kind == EXPR_SLICE)
{
return range_const_len(&expr->subscript_expr.range);
}
if (expr->expr_kind != EXPR_CAST) return -1;
if (expr->cast_expr.kind != CAST_APTSA) return -1;
Expr *inner = exprptr(expr->cast_expr.expr);

View File

@@ -1948,6 +1948,17 @@ void target_setup(BuildTarget *target)
{
DEBUG_LOG("Macos SDK: %s", sysroot);
active_target.macos.sdk = macos_sysroot_sdk_information(sysroot);
if (platform_target.arch == ARCH_TYPE_AARCH64)
{
if (active_target.macos.sdk->macos_min_deploy_target.major < 11)
{
active_target.macos.sdk->macos_min_deploy_target = (Version) { 11, 0 };
}
if (active_target.macos.sdk->macos_deploy_target.major < 11)
{
active_target.macos.sdk->macos_deploy_target = (Version) { 11, 0 };
}
}
}
platform_target.target_triple = strdup(llvm_macos_target_triple(platform_target.target_triple));

View File

@@ -0,0 +1,17 @@
module slice_to_arr @test;
fn void to_arr()
{
int[] x = { 1, 2, 3, 4, 5 };
int z = 2;
int[2] y = x[z:2];
assert(y == int[2]{ 3, 4 });
}
fn void to_vec()
{
int[] x = { 1, 2, 3, 4, 5 };
int z = 2;
int[<2>] y = x[z:2];
assert(y == { 3, 4 });
}

View File

@@ -2,6 +2,28 @@ module std::core::dstring2 @test;
const TEST_STRING = "hello world";
fn void test_delete()
{
{
DString d;
d.append("Hello cruel world.");
d.delete_range(5, 10);
assert(d.str_view() == "Hello world.");
}
DString d;
d.append("Hello cruel world.");
d.delete(0, 2);
assert(d.str_view() == "llo cruel world.");
d.delete(14, 2);
assert(d.str_view() == "llo cruel worl");
d.delete(7);
assert(d.str_view() == "llo crul worl");
d.delete(2, 0);
assert(d.str_view() == "llo crul worl");
d.delete(0, 1);
assert(d.str_view() == "lo crul worl");
}
fn void test_append()
{
DString str = dstring::new(TEST_STRING);