mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
- Circumvent Aarch64 miscompilations of atomics.
- Fixes to ByteBuffer allocation/free. - Fix issue where compiling both for asm and object file would corrupt the obj file output.
This commit is contained in:
13
.github/workflows/main.yml
vendored
13
.github/workflows/main.yml
vendored
@@ -87,15 +87,16 @@ jobs:
|
|||||||
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib5 --print-linking examples\raylib\raylib_snake.c3
|
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib5 --print-linking examples\raylib\raylib_snake.c3
|
||||||
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib5 --print-linking examples\raylib\raylib_tetris.c3
|
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib5 --print-linking examples\raylib\raylib_tetris.c3
|
||||||
|
|
||||||
|
- name: Compile run unit tests
|
||||||
|
run: |
|
||||||
|
cd test
|
||||||
|
..\build\${{ matrix.build_type }}\c3c.exe compile-test unit -O1
|
||||||
|
|
||||||
- name: run compiler tests
|
- name: run compiler tests
|
||||||
run: |
|
run: |
|
||||||
cd test
|
cd test
|
||||||
python3.exe src/tester.py ..\build\${{ matrix.build_type }}\c3c.exe test_suite/
|
python3.exe src/tester.py ..\build\${{ matrix.build_type }}\c3c.exe test_suite/
|
||||||
|
|
||||||
- name: Compile run unit tests
|
|
||||||
run: |
|
|
||||||
cd test
|
|
||||||
..\build\${{ matrix.build_type }}\c3c.exe compile-test unit -O1
|
|
||||||
|
|
||||||
- name: Test python script
|
- name: Test python script
|
||||||
run: |
|
run: |
|
||||||
@@ -486,7 +487,7 @@ jobs:
|
|||||||
- name: Compile run unit tests
|
- name: Compile run unit tests
|
||||||
run: |
|
run: |
|
||||||
cd test
|
cd test
|
||||||
../build/c3c compile-test unit
|
../build/c3c compile-test unit --sanitize=address
|
||||||
|
|
||||||
- name: Build testproject
|
- name: Build testproject
|
||||||
run: |
|
run: |
|
||||||
@@ -660,7 +661,7 @@ jobs:
|
|||||||
- name: Compile run unit tests
|
- name: Compile run unit tests
|
||||||
run: |
|
run: |
|
||||||
cd test
|
cd test
|
||||||
../build/c3c compile-test unit
|
../build/c3c compile-test unit -O1
|
||||||
|
|
||||||
- name: Test WASM
|
- name: Test WASM
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -16,15 +16,15 @@ struct ByteBuffer (InStream, OutStream)
|
|||||||
max_read defines how many bytes might be kept before its internal buffer is shrinked.
|
max_read defines how many bytes might be kept before its internal buffer is shrinked.
|
||||||
@require self.bytes.len == 0 "Buffer already initialized."
|
@require self.bytes.len == 0 "Buffer already initialized."
|
||||||
*>
|
*>
|
||||||
fn ByteBuffer*! ByteBuffer.new_init(&self, usz max_read, usz initial_capacity = 16, Allocator allocator = allocator::heap())
|
fn ByteBuffer* ByteBuffer.new_init(&self, usz max_read, usz initial_capacity = 16, Allocator allocator = allocator::heap())
|
||||||
{
|
{
|
||||||
*self = { .allocator = allocator, .max_read = max_read };
|
*self = { .allocator = allocator, .max_read = max_read };
|
||||||
initial_capacity = max(initial_capacity, 16);
|
initial_capacity = max(initial_capacity, 16);
|
||||||
self.grow(initial_capacity)!;
|
self.grow(initial_capacity);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ByteBuffer*! ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity = 16)
|
fn ByteBuffer* ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity = 16)
|
||||||
{
|
{
|
||||||
return self.new_init(max_read, initial_capacity, allocator::temp());
|
return self.new_init(max_read, initial_capacity, allocator::temp());
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ fn ByteBuffer*! ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity =
|
|||||||
@require buf.len > 0
|
@require buf.len > 0
|
||||||
@require self.bytes.len == 0 "Buffer already initialized."
|
@require self.bytes.len == 0 "Buffer already initialized."
|
||||||
*>
|
*>
|
||||||
fn ByteBuffer*! ByteBuffer.init_with_buffer(&self, char[] buf)
|
fn ByteBuffer* ByteBuffer.init_with_buffer(&self, char[] buf)
|
||||||
{
|
{
|
||||||
*self = { .max_read = buf.len, .bytes = buf };
|
*self = { .max_read = buf.len, .bytes = buf };
|
||||||
return self;
|
return self;
|
||||||
@@ -48,7 +48,7 @@ fn void ByteBuffer.free(&self)
|
|||||||
fn usz! ByteBuffer.write(&self, char[] bytes) @dynamic
|
fn usz! ByteBuffer.write(&self, char[] bytes) @dynamic
|
||||||
{
|
{
|
||||||
usz cap = self.bytes.len - self.write_idx;
|
usz cap = self.bytes.len - self.write_idx;
|
||||||
if (cap < bytes.len) self.grow(bytes.len)!;
|
if (cap < bytes.len) self.grow(bytes.len);
|
||||||
self.bytes[self.write_idx:bytes.len] = bytes[..];
|
self.bytes[self.write_idx:bytes.len] = bytes[..];
|
||||||
self.write_idx += bytes.len;
|
self.write_idx += bytes.len;
|
||||||
return bytes.len;
|
return bytes.len;
|
||||||
@@ -57,7 +57,7 @@ fn usz! ByteBuffer.write(&self, char[] bytes) @dynamic
|
|||||||
fn void! ByteBuffer.write_byte(&self, char c) @dynamic
|
fn void! ByteBuffer.write_byte(&self, char c) @dynamic
|
||||||
{
|
{
|
||||||
usz cap = self.bytes.len - self.write_idx;
|
usz cap = self.bytes.len - self.write_idx;
|
||||||
if (cap == 0) self.grow(1)!;
|
if (cap == 0) self.grow(1);
|
||||||
self.bytes[self.write_idx] = c;
|
self.bytes[self.write_idx] = c;
|
||||||
self.write_idx++;
|
self.write_idx++;
|
||||||
}
|
}
|
||||||
@@ -128,10 +128,10 @@ fn usz! ByteBuffer.available(&self) @inline @dynamic
|
|||||||
return self.write_idx - self.read_idx;
|
return self.write_idx - self.read_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void! ByteBuffer.grow(&self, usz n)
|
fn void ByteBuffer.grow(&self, usz n)
|
||||||
{
|
{
|
||||||
n = math::next_power_of_2(n);
|
n = math::next_power_of_2(n);
|
||||||
char* p = allocator::realloc_aligned(self.allocator, self.bytes, n, alignment: char.alignof)!;
|
char* p = allocator::realloc(self.allocator, self.bytes, n);
|
||||||
self.bytes = p[:n];
|
self.bytes = p[:n];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,9 @@
|
|||||||
- Fix issue where aligned bitstructs did not store/load with the given alignment.
|
- Fix issue where aligned bitstructs did not store/load with the given alignment.
|
||||||
- Fix issue in GrowableBitSet with sanitizers.
|
- Fix issue in GrowableBitSet with sanitizers.
|
||||||
- Fix issue in List with sanitizers.
|
- Fix issue in List with sanitizers.
|
||||||
|
- Circumvent Aarch64 miscompilations of atomics.
|
||||||
|
- Fixes to ByteBuffer allocation/free.
|
||||||
|
- Fix issue where compiling both for asm and object file would corrupt the obj file output.
|
||||||
|
|
||||||
### Stdlib changes
|
### Stdlib changes
|
||||||
- Added '%h' and '%H' for printing out binary data in hexadecimal using the formatter.
|
- Added '%h' and '%H' for printing out binary data in hexadecimal using the formatter.
|
||||||
|
|||||||
@@ -664,47 +664,48 @@ static void gencontext_verify_ir(GenContext *context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void llvm_emit_file(GenContext *c, const char *filename, LLVMCodeGenFileType llvm_codegen_type, bool clone_module)
|
||||||
static void gencontext_emit_object_file(GenContext *context)
|
|
||||||
{
|
{
|
||||||
char *err = "";
|
|
||||||
DEBUG_LOG("Target: %s", compiler.platform.target_triple);
|
DEBUG_LOG("Target: %s", compiler.platform.target_triple);
|
||||||
LLVMSetTarget(context->module, compiler.platform.target_triple);
|
LLVMModuleRef module = clone_module ? LLVMCloneModule(c->module) : c->module;
|
||||||
char *layout = LLVMCopyStringRepOfTargetData(context->target_data);
|
LLVMSetTarget(module, compiler.platform.target_triple);
|
||||||
LLVMSetDataLayout(context->module, layout);
|
char *layout = LLVMCopyStringRepOfTargetData(c->target_data);
|
||||||
|
LLVMSetDataLayout(module, layout);
|
||||||
LLVMDisposeMessage(layout);
|
LLVMDisposeMessage(layout);
|
||||||
|
|
||||||
if (context->asm_filename)
|
char *err = "";
|
||||||
|
FILE *file = NULL;
|
||||||
|
LLVMMemoryBufferRef buffer = NULL;
|
||||||
|
if (LLVMTargetMachineEmitToMemoryBuffer(c->machine, module, llvm_codegen_type, &err, &buffer))
|
||||||
{
|
{
|
||||||
// Generate .s file
|
goto ERR;
|
||||||
if (LLVMTargetMachineEmitToFile(context->machine, context->module, (char *)context->asm_filename, LLVMAssemblyFile, &err))
|
}
|
||||||
|
file = fopen(filename, "wb");
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
err = "File could not be opened";
|
||||||
|
goto ERR;
|
||||||
|
}
|
||||||
|
size_t len = LLVMGetBufferSize(buffer);
|
||||||
|
const char *ptr = LLVMGetBufferStart(buffer);
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
size_t written = fwrite(ptr, 1, len, file);
|
||||||
|
if (written == 0)
|
||||||
{
|
{
|
||||||
error_exit("Could not emit asm file: %s", err);
|
err = "Failed to write to file";
|
||||||
|
goto ERR;
|
||||||
}
|
}
|
||||||
|
ptr += written;
|
||||||
|
len -= written;
|
||||||
}
|
}
|
||||||
|
fclose(file);
|
||||||
// Generate .o or .obj file
|
LLVMDisposeMemoryBuffer(buffer);
|
||||||
if (LLVMTargetMachineEmitToFile(context->machine, context->module, (char *)context->object_filename, LLVMObjectFile, &err))
|
return;
|
||||||
{
|
ERR:
|
||||||
error_exit("Could not emit object file: %s", err);
|
if (file) fclose(file);
|
||||||
}
|
if (buffer) LLVMDisposeMemoryBuffer(buffer);
|
||||||
|
error_exit("Could not emit '%s': %s", filename, err);
|
||||||
}
|
|
||||||
|
|
||||||
static void llvm_emit_asm_file(GenContext *context)
|
|
||||||
{
|
|
||||||
char *err = "";
|
|
||||||
DEBUG_LOG("Target: %s", compiler.platform.target_triple);
|
|
||||||
LLVMSetTarget(context->module, compiler.platform.target_triple);
|
|
||||||
char *layout = LLVMCopyStringRepOfTargetData(context->target_data);
|
|
||||||
LLVMSetDataLayout(context->module, layout);
|
|
||||||
LLVMDisposeMessage(layout);
|
|
||||||
|
|
||||||
// Generate .s file
|
|
||||||
if (LLVMTargetMachineEmitToFile(context->machine, context->module, (char *)context->asm_filename, LLVMAssemblyFile, &err))
|
|
||||||
{
|
|
||||||
error_exit("Could not emit asm file: %s", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gencontext_print_llvm_ir(GenContext *context)
|
void gencontext_print_llvm_ir(GenContext *context)
|
||||||
@@ -1067,15 +1068,16 @@ const char *llvm_codegen(void *context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *object_name = NULL;
|
const char *object_name = NULL;
|
||||||
if (compiler.build.emit_object_files)
|
|
||||||
{
|
|
||||||
gencontext_emit_object_file(c);
|
|
||||||
object_name = c->object_filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compiler.build.emit_asm)
|
if (compiler.build.emit_asm)
|
||||||
{
|
{
|
||||||
llvm_emit_asm_file(context);
|
// Clone if there will be object file output.
|
||||||
|
llvm_emit_file(c, c->asm_filename, LLVMAssemblyFile, compiler.build.emit_object_files);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compiler.build.emit_object_files)
|
||||||
|
{
|
||||||
|
llvm_emit_file(c, c->object_filename, LLVMObjectFile, false);
|
||||||
|
object_name = c->object_filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
gencontext_end_module(c);
|
gencontext_end_module(c);
|
||||||
|
|||||||
@@ -159,6 +159,16 @@ static bool os_target_signed_c_char_type(OsType os, ArchType arch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void target_setup_aarch64_abi(void)
|
||||||
|
{
|
||||||
|
compiler.platform.aarch.is_darwin = os_is_apple(compiler.platform.os);
|
||||||
|
compiler.platform.aarch.is_win32 = compiler.platform.os == OS_TYPE_WIN32;
|
||||||
|
compiler.platform.abi = ABI_AARCH64;
|
||||||
|
// TODO improve Aarch64 functionality support.
|
||||||
|
scratch_buffer_clear();
|
||||||
|
scratch_buffer_append("+crc,+lse,+rdm,+fp-armv8,+neon");
|
||||||
|
compiler.platform.features = scratch_buffer_copy();
|
||||||
|
}
|
||||||
static inline void target_setup_arm_abi(void)
|
static inline void target_setup_arm_abi(void)
|
||||||
{
|
{
|
||||||
compiler.platform.abi = ABI_ARM;
|
compiler.platform.abi = ABI_ARM;
|
||||||
@@ -836,8 +846,7 @@ static void x86_features_from_host(X86Features *cpu_features)
|
|||||||
#if LLVM_AVAILABLE
|
#if LLVM_AVAILABLE
|
||||||
char *features = LLVMGetHostCPUFeatures();
|
char *features = LLVMGetHostCPUFeatures();
|
||||||
INFO_LOG("Detected the following host features: %s", features);
|
INFO_LOG("Detected the following host features: %s", features);
|
||||||
INFO_LOG("For %s",
|
INFO_LOG("For %s", LLVMGetHostCPUName());
|
||||||
LLVMGetHostCPUName());
|
|
||||||
|
|
||||||
char *tok = strtok(features, ",");
|
char *tok = strtok(features, ",");
|
||||||
*cpu_features = x86_feature_zero;
|
*cpu_features = x86_feature_zero;
|
||||||
@@ -1994,9 +2003,7 @@ void target_setup(BuildTarget *target)
|
|||||||
break;
|
break;
|
||||||
case ARCH_TYPE_AARCH64:
|
case ARCH_TYPE_AARCH64:
|
||||||
case ARCH_TYPE_AARCH64_BE:
|
case ARCH_TYPE_AARCH64_BE:
|
||||||
compiler.platform.aarch.is_darwin = os_is_apple(compiler.platform.os);
|
target_setup_aarch64_abi();
|
||||||
compiler.platform.aarch.is_win32 = compiler.platform.os == OS_TYPE_WIN32;
|
|
||||||
compiler.platform.abi = ABI_AARCH64;
|
|
||||||
break;
|
break;
|
||||||
case ARCH_TYPE_XTENSA:
|
case ARCH_TYPE_XTENSA:
|
||||||
compiler.platform.abi = ABI_XTENSA;
|
compiler.platform.abi = ABI_XTENSA;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import std::io;
|
|||||||
fn void write_read()
|
fn void write_read()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer;
|
ByteBuffer buffer;
|
||||||
buffer.new_init(0)!!;
|
buffer.new_init(0);
|
||||||
defer buffer.free();
|
defer buffer.free();
|
||||||
buffer.write("hello")!!;
|
buffer.write("hello")!!;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import std::io;
|
|||||||
fn void write_read()
|
fn void write_read()
|
||||||
{
|
{
|
||||||
ByteBuffer buf;
|
ByteBuffer buf;
|
||||||
buf.temp_init(16)!!;
|
buf.temp_init(16);
|
||||||
usz n;
|
usz n;
|
||||||
uint x;
|
uint x;
|
||||||
uint y;
|
uint y;
|
||||||
|
|||||||
Reference in New Issue
Block a user