Compare commits

...

12 Commits

Author SHA1 Message Date
Christoffer Lerno
cf99c2be5c Fix of ordering. 2022-04-24 23:46:09 +02:00
Christoffer Lerno
50f43b3c71 Some conversions cleaned up. 2022-04-24 23:43:54 +02:00
Christoffer Lerno
40a0e71b24 More win tests. 2022-04-24 23:36:22 +02:00
Christoffer Lerno
bbb4bbe570 More win tests. 2022-04-24 23:04:34 +02:00
Christoffer Lerno
54422fd5e5 More win tests. 2022-04-24 22:52:19 +02:00
Christoffer Lerno
e08bac422a More win tests. 2022-04-24 22:50:46 +02:00
Christoffer Lerno
e86cf074c8 More win tests. 2022-04-24 22:31:57 +02:00
Christoffer Lerno
26cc87d3fc More win tests. 2022-04-24 22:22:14 +02:00
Christoffer Lerno
0bb2afb0ed More win tests. 2022-04-24 21:59:39 +02:00
Christoffer Lerno
633eb65e18 More win tests. 2022-04-24 21:57:18 +02:00
Christoffer Lerno
b717b84046 Build system improvements. Target changes x64-windows -> windows-x64, x64-darwin -> macos-x64. Improved mac support. LLD linking for Mac, Windows, Linux. Cross linking for Mac, Windows. Clean up string use. 2022-04-24 21:10:21 +02:00
Christoffer Lerno
0cf110f763 Build system improvements. Target changes x64-windows -> windows-x64, x64-darwin -> macos-x64. Improved mac support. LLD linking for Mac, Windows, Linux. Cross linking for Mac, Windows. Clean up string use. 2022-04-22 18:02:11 +02:00
212 changed files with 2393 additions and 1314 deletions

View File

@@ -7,6 +7,36 @@ on:
branches: [ master ]
jobs:
build-msvc:
runs-on: windows-latest
strategy:
# Don't abort runners if a single one fails
fail-fast: false
matrix:
build_type: [ Release, Debug ]
defaults:
run:
shell: cmd
steps:
- uses: actions/checkout@v3
- name: CMake
run: |
cmake -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
cmake --build build
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c run --debug-log
- name: run compiler tests
run: |
cd test
python3 src/tester.py ../build/c3c.exe test_suite/
build-msys2-mingw:
runs-on: windows-latest
strategy:
@@ -38,13 +68,14 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c build --debug-log
../../build/c3c run --debug-log
- name: run compiler tests
run: |
cd test
python3 src/tester.py ../build/c3c.exe test_suite/
build-msys2-clang:
runs-on: windows-latest
#if: ${{ false }}
@@ -73,7 +104,7 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c build --debug-log
../../build/c3c run --debug-log
- name: run compiler tests
run: |
@@ -118,7 +149,12 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c build --debug-log
../../build/c3c run --debug-log
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run --debug-log --forcelinker
- name: run compiler tests
run: |
@@ -150,7 +186,12 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c build --debug-log
../../build/c3c run --debug-log
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run --debug-log --forcelinker
- name: run compiler tests
run: |

View File

@@ -1,10 +1,17 @@
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.14)
project(c3c)
include(FetchContent)
include(FeatureSummary)
set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3")
set(C3_LLVM_VERSION "auto" CACHE STRING "Use LLVM version [default: auto]")
option(C3_USE_MIMALLOC "Use built-in mimalloc" OFF)
set(C3_MIMALLOC_TAG "v1.7.3" CACHE STRING "Used version of mimalloc")
@@ -23,29 +30,49 @@ if(C3_USE_MIMALLOC)
FetchContent_MakeAvailable(mimalloc)
endif()
if(NOT C3_LLVM_VERSION STREQUAL "auto")
if(${C3_LLVM_VERSION} VERSION_LESS 12 OR ${C3_LLVM_VERSION} VERSION_GREATER 15)
if (NOT C3_LLVM_VERSION STREQUAL "auto")
if (${C3_LLVM_VERSION} VERSION_LESS 12 OR ${C3_LLVM_VERSION} VERSION_GREATER 15)
message(FATAL_ERROR "LLVM ${C3_LLVM_VERSION} is not supported!")
endif()
find_package(LLVM ${C3_LLVM_VERSION} REQUIRED CONFIG)
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
if (C3_LLVM_VERSION STREQUAL "auto")
set(C3_LLVM_VERSION "13")
endif()
FetchContent_Declare(
LLVM_Windows
URL https://github.com/c3lang/win-llvm/releases/download/lld-llvm${C3_LLVM_VERSION}-release/llvm-${C3_LLVM_VERSION}.0.0-windows-amd64-msvc16-msvcrt.7z
)
FetchContent_Declare(
LLVM_Windows_debug
URL https://github.com/c3lang/win-llvm/releases/download/lld-llvm${C3_LLVM_VERSION}-release/llvm-${C3_LLVM_VERSION}.0.0-windows-amd64-msvc16-msvcrt-dbg.7z
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message("Loading Windows LLVM debug libraries...")
FetchContent_MakeAvailable(LLVM_Windows_debug)
set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_windows_debug_SOURCE_DIR} ${CMAKE_SYSTEM_PREFIX_PATH})
else()
message("Loading Windows LLVM libraries...")
FetchContent_MakeAvailable(LLVM_Windows)
set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_windows_SOURCE_DIR} ${CMAKE_SYSTEM_PREFIX_PATH})
endif()
find_package(LLVM REQUIRED CONFIG)
find_package(LLD REQUIRED CONFIG)
else()
find_package(LLVM REQUIRED CONFIG)
if (NOT C3_LLVM_VERSION STREQUAL "auto")
find_package(LLVM ${C3_LLVM_VERSION} REQUIRED CONFIG)
else()
find_package(LLVM REQUIRED CONFIG)
endif()
endif()
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
message(STATUS "Libraries located in: ${LLVM_LIBRARY_DIRS}")
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3")
set(LLVM_LINK_COMPONENTS
AllTargetsAsmParsers
AllTargetsCodeGens
@@ -73,7 +100,7 @@ set(LLVM_LINK_COMPONENTS
Target
TransformUtils
WindowsManifest
)
)
if (${LLVM_PACKAGE_VERSION} VERSION_GREATER 14.1)
set(LLVM_LINK_COMPONENTS ${LLVM_LINK_COMPONENTS} WindowsDriver)
@@ -83,22 +110,27 @@ llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS})
file(COPY ${CMAKE_SOURCE_DIR}/lib DESTINATION ${CMAKE_BINARY_DIR})
# These don't seem to be reliable on windows.
if(UNIX)
if(true)
message(STATUS "using find_library")
# find_library(TB_LIB NAMES tinybackend.a PATHS ${CMAKE_SOURCE_DIR}/resources/tblib)
find_library(LLD_COFF NAMES lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_COMMON NAMES lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_ELF NAMES lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_MACHO NAMES lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_MINGW NAMES lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_WASM NAMES lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_COFF NAMES lldCOFF.lib lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_COMMON NAMES lldCommon.lib lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_ELF NAMES lldELF.lib lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS})
if (${LLVM_PACKAGE_VERSION} VERSION_LESS 14)
find_library(LLD_MACHO NAMES lldMachO2.lib lldMachO2.a liblldMachO2.a PATHS ${LLVM_LIBRARY_DIRS})
else()
find_library(LLD_MACHO NAMES lldMachO.lib lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS})
endif()
find_library(LLD_MINGW NAMES lldMinGW.lib lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_WASM NAMES lldWasm.lib lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS})
if (${LLVM_PACKAGE_VERSION} VERSION_LESS 14)
find_library(LLD_CORE NAMES lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_DRIVER NAMES lldDriver.a liblldDriver.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_READER_WRITER NAMES lldReaderWriter.a liblldReaderWriter.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_YAML NAMES lldYAML.a liblldYAML.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_CORE NAMES lldCore.lib lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_DRIVER NAMES lldDriver.lib lldDriver.a liblldDriver.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_READER_WRITER NAMES lldReaderWriter.lib lldReaderWriter.a liblldReaderWriter.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_YAML NAMES lldYAML.lib lldYAML.a liblldYAML.a PATHS ${LLVM_LIBRARY_DIRS})
endif()
set(lld_libs
@@ -113,9 +145,18 @@ if(UNIX)
${LLD_YAML}
${LLD_CORE}
)
message(STATUS "linking to llvm libs ${llvm_libs} ${lld_libs}")
endif()
if(APPLE)
set(lld_libs ${lld_libs} xar)
endif()
message(STATUS "linking to llvm libs ${llvm_libs} ${lld_libs}")
else()
if(${LLVM_PACKAGE_VERSION} VERSION_LESS 14)
set(lld_libs lldCommon lldCore lldCOFF lldWASM lldMinGW lldELF lldDriver lldReaderWriter lldMachO2 lldYAML)
else()
set(lld_libs lldCommon lldCore lldCOFF lldWASM lldMinGW lldELF lldDriver lldReaderWriter lldMachO lldYAML)
endif()
endif()
message(STATUS "Found LLD ${lld_libs}")
add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp)
@@ -138,6 +179,7 @@ add_executable(c3c
src/compiler/float.c
src/compiler/headers.c
src/compiler/lexer.c
src/compiler/libraries.c
src/compiler/linker.c
src/compiler/llvm_codegen.c
src/compiler/llvm_codegen_c_abi_aarch64.c
@@ -196,11 +238,12 @@ add_executable(c3c
src/utils/vmem.h
src/utils/whereami.c
src/compiler/decltable.c
src/compiler/mac_support.c
src/compiler/tilde_codegen_storeload.c
src/compiler/llvm_codegen_storeload.c
src/compiler/tilde_codegen_expr.c
src/compiler/tilde_codegen_stmt.c
src/compiler/tilde_codegen_type.c)
src/compiler/tilde_codegen_type.c src/compiler/windows_support.c)
if(NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC")
message(STATUS "using gcc/clang warning switches")
@@ -219,20 +262,15 @@ target_include_directories(c3c_wrappers PRIVATE
if(UNIX)
target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs})
target_link_libraries(c3c m ${llvm_libs} c3c_wrappers ${lld_libs})
target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs})
target_link_libraries(c3c ${llvm_libs} c3c_wrappers ${lld_libs})
# target_link_libraries(c3c m ${llvm_libs} c3c_wrappers ${TB_LIB} ${lld_libs})
if(C3_USE_MIMALLOC)
target_link_libraries(c3c m mimalloc-static)
endif()
else()
# todo: maybe get this from llvm-config somehow? it should be in LLVM_DIR\..\..\..\bin I think.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -LIBPATH:C:\\llvm\\llvm\\build\\Release\\lib") # needed for lldCommon.lib
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -LIBPATH:${LLVM_LIBPATH}") # This doesn't seem to work for some reason
message(STATUS "${LLVM_LIBPATH}")
target_link_libraries(c3c debug ${llvm_libs} c3c_wrappers lldCommon lldCore lldCOFF lldWASM lldMinGW lldELF lldDriver lldReaderWriter lldMachO lldYAML Advapi32)
target_link_libraries(c3c optimized ${llvm_libs} c3c_wrappers lldCommon lldCore lldCOFF lldWASM lldMinGW lldELF lldDriver lldReaderWriter lldMachO lldYAML Advapi32)
if(C3_USE_MIMALLOC)
target_link_libraries(c3c m mimalloc-static)
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
target_link_libraries(c3c Advapi32)
target_link_options(c3c_wrappers PRIVATE nowarn)
endif()
if (WIN32)

View File

@@ -129,7 +129,7 @@ fn void test()
### Current status
The current version of the compiler is alpha release 0.1.0.
The current version of the compiler is alpha release 0.1.
It's possible to try out the current C3 compiler in the browser: https://ide.judge0.com/ this is courtesy of the
developer of Judge0.

View File

@@ -0,0 +1,167 @@
module foo;
extern fn void printf(char*, ...);
enum Foo : int (int offset, char* extra_name, double x)
{
BAZ(12, "hello", 3.0),
BOO(33, "oekfe", 4.0) = 3,
}
fn void main()
{
int screenWidth = 800;
int screenHeight = 450;
raylib::init_window(screenWidth, screenHeight, "raylib [core] example - keyboard input");
Vector2 ballPosition = { (float)screenWidth/2, (float)screenHeight/2 };
raylib::set_target_fps(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
foo2::tester(screenHeight);
// Main game loop
while (!raylib::window_should_close()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (raylib::is_key_down(KeyboardKey.RIGHT)) ballPosition.x += 2.0f;
if (raylib::is_key_down(KeyboardKey.LEFT)) ballPosition.x -= 2.0f;
if (raylib::is_key_down(KeyboardKey.UP)) ballPosition.y -= 2.0f;
if (raylib::is_key_down(KeyboardKey.DOWN)) ballPosition.y += 2.0f;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
raylib::begin_drawing();
raylib::clear_background(raylib::RAYWHITE);
raylib::draw_text("move the ball with arrow keys", 10, 10, 20, raylib::DARKGRAY);
raylib::draw_circle_v(ballPosition, 50, raylib::MAROON);
raylib::end_drawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
raylib::close_window(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
}
/*
struct Game
{
int answer;
bool done;
int guesses;
int high;
}
int err_count = 0;
import "core:bufio"
import "core:fmt"
import "core:io"
import "core:mem"
import "core:os"
import "core:strconv"
import "core:time"
import "core:math/rand"
Game :: struct {
answer: int,
done: bool,
guesses: int,
high: int,
}
int err_count = 0;
*/
/*
fn int ask_guess(int high)
{
libc::printf("Guess a number between 1 and %d: ", high);
}
ask_guess :: proc(high: int) -> (result: int, ok: bool) {
fmt.printf("Guess a number between 1 and %d: ", high)
if text, ok := read_line(); ok {
defer mem.delete(text)
return strconv.parse_int(s = text, base = 10)
}
return
}
ask_guess_multi :: proc(high: int) -> int {
for {
if result, ok := ask_guess(high); ok {
return result
}
fmt.println("I didn't understand")
err_count += 1
}
}
pick_answer :: proc(high: int, r: ^rand.Rand) -> int {
return rand.int_max(high, r) + 1
}
play :: proc(game: ^Game) {
for !game.done {
guess := ask_guess_multi(game.high)
report(game^, guess)
game^ = update(game^, guess)
}
}
read_line :: proc() -> (result: string, ok: bool) {
// See also:
// - https://github.com/odin-lang/Odin/issues/1214
// - https://p.teknik.io/Raw/IT996
s := os.stream_from_handle(os.stdin)
r: bufio.Reader
bufio.reader_init(&r, io.Reader{s})
defer bufio.reader_destroy(&r)
if line, err := bufio.reader_read_string(&r, '\n'); err == .None {
return line[:len(line) - 1], true
}
return
}
report :: proc(game: Game, guess: int) {
// game.done = true
// fmt.println(&game)
description := (
"too low" if guess < game.answer else
"too high" if guess > game.answer else
"the answer!"
)
fmt.println(guess, "is", description)
}
update :: proc(game: Game, guess: int) -> (next: Game) {
next = game
next.done = guess == game.answer
next.guesses += 1
return
}
main :: proc() {
high :: 100
r := rand.create(transmute(u64)time.now())
// Or use nil for default random.
answer := pick_answer(high, &r)
game := Game {answer = answer, done = false, guesses = 0, high = high}
play(&game)
fmt.println("Finished in", game.guesses, "guesses");
fmt.println("Total input errors:", err_count)
}
*/
module foo2;
fn void tester(int x)
{
assert(x > 1000, "Shit!");
}

View File

@@ -9,5 +9,5 @@ fn int main()
printf("Hello World!\n");
bar::test();
printf("Hello double: %d\n", test_doubler(11));
return 1;
return 17;
}

View File

@@ -14,6 +14,7 @@
#include <utils/lib.h>
#include "../utils/whereami.h"
extern int llvm_version_major;
static int arg_index;
static int arg_count;
@@ -23,30 +24,30 @@ extern const char* llvm_version;
extern const char* llvm_target;
char *arch_os_target[ARCH_OS_TARGET_LAST + 1] = {
[X86_FREEBSD] = "x86-freebsd",
[X86_OPENBSD] = "x86-openbsd",
[X86_NETBSD] = "x86-netbsd",
[X86_MCU] = "x86-mcu",
[X86_ELF] = "x86-elf",
[X86_WINDOWS] = "x86-windows",
[X86_LINUX] = "x86-linux",
[X64_DARWIN] = "x64-darwin",
[X64_LINUX] = "x64-linux",
[X64_WINDOWS] = "x64-windows",
[X64_WINDOWS_GNU] = "x64-mingw",
[X64_FREEBSD] = "x64-freebsd",
[X64_OPENBSD] = "x64-openbsd",
[X64_NETBSD] = "x64-netbsd",
[X64_ELF] = "x64-elf",
[AARCH64_LINUX] = "aarch64-linux",
[AARCH64_DARWIN] = "aarch64-darwin",
[AARCH64_ELF] = "aarch64-elf",
[RISCV32_LINUX] = "riscv32-linux",
[RISCV32_ELF] = "riscv32-elf",
[RISCV64_LINUX] = "riscv64-linux",
[RISCV64_ELF] = "riscv64-elf",
[WINDOWS_X86] = "windows-x86",
[WINDOWS_X64] = "windows-x64",
[MINGW_X64] = "mingw-x64",
[MACOS_X64] = "macos-x64",
[MACOS_AARCH64] = "macos-aarch64",
[LINUX_X86] = "linux-x86",
[LINUX_X64] = "linux-x64",
[LINUX_AARCH64] = "linux-aarch64",
[LINUX_RISCV32] = "linux-riscv32",
[LINUX_RISCV64] = "linux-riscv64",
[WASM32] = "wasm32",
[WASM64] = "wasm64",
[ELF_X86] = "elf-x86",
[ELF_X64] = "elf-x64",
[ELF_AARCH64] = "elf-aarch64",
[ELF_RISCV32] = "elf-riscv32",
[ELF_RISCV64] = "elf-riscv64",
[FREEBSD_X86] = "freebsd-x86",
[FREEBSD_X64] = "freebsd-x64",
[OPENBSD_X86] = "openbsd-x86",
[OPENBSD_X64] = "openbsd-x64",
[NETBSD_X86] = "netbsd-x86",
[NETBSD_X64] = "netbsd-x64",
[MCU_X86] = "mcu-x86",
};
#define EOUTPUT(string, ...) fprintf(stderr, string "\n", ##__VA_ARGS__)
@@ -74,7 +75,8 @@ static void usage(void)
OUTPUT("Options:");
OUTPUT(" --tinybackend - Use the TinyBackend for compilation.");
OUTPUT(" --stdlib <dir> - Use this directory as the C3 standard library path.");
OUTPUT(" --lib <dir> - Use this directory as the C3 library path.");
OUTPUT(" --libdir <dir> - Add this directory to the C3 library search paths.");
OUTPUT(" --lib <name> - Add this library to the compilation.");
OUTPUT(" --path <dir> - Use this as the base directory for the current command.");
OUTPUT(" --template <template> - Use a different template: \"lib\", \"static-lib\" or a path.");
OUTPUT(" --about - Prints a short description of C3.");
@@ -103,6 +105,7 @@ static void usage(void)
OUTPUT(" -l <library> - Link with the library provided.");
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(" --forcelinker - Force linker usage over using when doing non-cross linking.");
OUTPUT("");
OUTPUT(" --reloc=<option> - Relocation model: none, pic, PIC, pie, PIE");
OUTPUT(" --x86vec=<option> - Set max level of vector instructions: none, mmx, sse, avx, avx512.");
@@ -114,6 +117,12 @@ static void usage(void)
OUTPUT(" --list-attributes - List all attributes.");
OUTPUT(" --list-builtins - List all builtins.");
OUTPUT(" --list-precedence - List operator precedence order.");
OUTPUT("");
OUTPUT(" --winsdk <dir> - Set the directory for Windows system library files for cross compilation.");
OUTPUT(" --wincrt=<option> - Windows CRT linking: none, static, dynamic (default).");
OUTPUT("");
OUTPUT(" --macossdk <dir> - Set the directory for the MacOS SDK for cross compilation.");
#ifndef NDEBUG
OUTPUT(" --debug-log - Print debug logging to stdout.");
#endif
@@ -315,7 +324,7 @@ static void add_linker_arg(BuildOptions *options, const char *arg)
static int parse_multi_option(const char *start, unsigned count, const char** elements)
{
const char *arg = current_arg;
int select = str_in_list(start, count, elements);
int select = str_findlist(start, count, elements);
if (select < 0) error_exit("error: %.*s invalid option '%s' given.", (int)(start - arg), start, arg);
return select;
}
@@ -416,7 +425,7 @@ static void parse_option(BuildOptions *options)
{
if (at_end() || next_is_opt()) error_exit("error: -l needs a library name.");
const char *lib = next_arg();
const char *framework = str_without_suffix(lib, ".framework");
const char *framework = str_remove_suffix(lib, ".framework");
if (framework)
{
add_linker_arg(options, "-framework");
@@ -462,6 +471,18 @@ static void parse_option(BuildOptions *options)
options->symtab_size = next_highest_power_of_2(symtab);
return;
}
if (match_longopt("forcelinker"))
{
if (llvm_version_major > 12)
{
options->force_linker = true;
}
else
{
printf("Force linking ignored on LLVM 12 and earlier.\n");
}
return;
}
if (match_longopt("version"))
{
print_version();
@@ -580,11 +601,41 @@ static void parse_option(BuildOptions *options)
options->panicfn = next_arg();
return;
}
if (match_longopt("macossdk"))
{
if (at_end() || next_is_opt()) error_exit("error: --macossdk needs a directory.");
options->macos.sdk = check_dir(next_arg());
return;
}
if (match_longopt("winsdk"))
{
if (at_end() || next_is_opt()) error_exit("error: --winsdk needs a directory.");
options->win.sdk = check_dir(next_arg());
return;
}
if ((argopt = match_argopt("wincrt")))
{
options->win.crt_linking = (WinCrtLinking)parse_multi_option(argopt, 3, wincrt_linking);
return;
}
if (match_longopt("lib"))
{
if (at_end() || next_is_opt()) error_exit("error: --lib needs a directory.");
if (options->lib_count == MAX_LIB_DIRS) error_exit("Max %d libraries may be specified.", MAX_LIB_DIRS);
options->lib_dir[options->lib_count++] = check_dir(next_arg());
if (at_end() || next_is_opt()) error_exit("error: --lib needs a name.");
const char *name = next_arg();
if (!str_is_valid_lowercase_name(name))
{
char *name_copy = strdup(name);
str_ellide_in_place(name_copy, 32);
error_exit("Invalid library name '%s', it should be something like 'foo_lib'.", name_copy);
}
options->libs[options->lib_count++] = name;
return;
}
if (match_longopt("libdir"))
{
if (at_end() || next_is_opt()) error_exit("error: --libdir needs a directory.");
if (options->lib_dir_count == MAX_LIB_DIRS) error_exit("Max %d library directories may be specified.", MAX_LIB_DIRS);
options->lib_dir[options->lib_dir_count++] = check_dir(next_arg());
return;
}
if (match_longopt("test"))
@@ -645,6 +696,7 @@ BuildOptions parse_arguments(int argc, const char *argv[])
.reloc_model = RELOC_DEFAULT,
.backend = BACKEND_LLVM,
.x86_vector_capability = X86VECTOR_DEFAULT,
.win.crt_linking = WIN_CRT_DEFAULT,
.files = NULL
};
for (int i = DIAG_NONE; i < DIAG_WARNING_TYPE; i++)

View File

@@ -144,6 +144,20 @@ static const char *vector_capability[5] = {
[X86VECTOR_AVX512] = "avx512",
};
typedef enum
{
WIN_CRT_DEFAULT = -1,
WIN_CRT_NONE = 0,
WIN_CRT_DYNAMIC = 1,
WIN_CRT_STATIC = 2,
} WinCrtLinking;
static const char *wincrt_linking[3] = {
[WIN_CRT_NONE] = "none",
[WIN_CRT_DYNAMIC] = "dynamic",
[WIN_CRT_STATIC] = "static",
};
typedef enum
{
RELOC_DEFAULT = -1,
@@ -173,44 +187,53 @@ typedef enum
typedef enum
{
ARCH_OS_TARGET_DEFAULT = 0,
X86_FREEBSD,
X86_OPENBSD,
X86_NETBSD,
X86_LINUX,
X86_WINDOWS,
X86_MCU,
X86_ELF,
X64_DARWIN,
X64_LINUX,
X64_NETBSD,
X64_FREEBSD,
X64_OPENBSD,
X64_WINDOWS,
X64_WINDOWS_GNU,
X64_ELF,
AARCH64_LINUX,
AARCH64_DARWIN,
AARCH64_ELF,
RISCV32_LINUX,
RISCV32_ELF,
RISCV64_LINUX,
RISCV64_ELF,
LINUX_X86,
LINUX_X64,
WINDOWS_X86,
WINDOWS_X64,
MINGW_X64,
MACOS_X64,
MACOS_AARCH64,
LINUX_AARCH64,
LINUX_RISCV32,
LINUX_RISCV64,
WASM32,
WASM64,
ARCH_OS_TARGET_LAST = WASM64
ELF_X86,
ELF_X64,
ELF_AARCH64,
ELF_RISCV32,
ELF_RISCV64,
FREEBSD_X86,
FREEBSD_X64,
OPENBSD_X86,
OPENBSD_X64,
NETBSD_X86,
NETBSD_X64,
MCU_X86,
ARCH_OS_TARGET_LAST = MCU_X86
} ArchOsTarget;
typedef struct BuildOptions_
{
const char* lib_dir[MAX_LIB_DIRS];
const char* linker_args[MAX_LIB_DIRS];
const char* linker_lib_dir[MAX_LIB_DIRS];
const char* linker_libs[MAX_LIB_DIRS];
const char* std_lib_dir;
const char *lib_dir[MAX_LIB_DIRS];
int lib_dir_count;
const char *libs[MAX_LIB_DIRS];
int lib_count;
const char* linker_args[MAX_LIB_DIRS];
int linker_arg_count;
const char* linker_lib_dir[MAX_LIB_DIRS];
int linker_lib_dir_count;
const char* linker_libs[MAX_LIB_DIRS];
int linker_lib_count;
const char* std_lib_dir;
struct {
const char *sdk;
WinCrtLinking crt_linking;
} win;
struct {
const char *sdk;
} macos;
int build_threads;
const char** files;
const char* output_name;
@@ -231,6 +254,7 @@ typedef struct BuildOptions_
bool emit_bitcode;
bool test_mode;
bool no_stdlib;
bool force_linker;
const char *panicfn;
RelocModel reloc_model;
X86VectorCapability x86_vector_capability;
@@ -253,15 +277,35 @@ typedef enum
TARGET_TYPE_TEST
} TargetType;
typedef struct
{
ArchOsTarget arch_os;
const char **link_flags;
const char **linked_libs;
const char **depends;
} LibraryTarget;
typedef struct
{
const char *dir;
const char *provides;
const char **depends;
LibraryTarget *target_used;
LibraryTarget **targets;
} Library;
typedef struct
{
TargetType type;
Library **library_list;
const char *name;
const char *version;
const char *langrev;
const char **source_dirs;
const char **sources;
const char **libraries;
const char **libdirs;
const char **libs;
const char **linker_libdirs;
const char *cpu;
const char **link_args;
bool run_after_compile : 1;
@@ -275,6 +319,7 @@ typedef struct
bool no_stdlib : 1;
bool emit_object_files : 1;
bool no_link : 1;
bool force_linker : 1;
OptimizationLevel optimization_level;
SizeOptimizationLevel size_optimization_level;
DebugInfo debug_info;
@@ -296,6 +341,15 @@ typedef struct
bool trap_on_wrap : 1;
bool safe_mode : 1;
} feature;
struct
{
const char *sdk;
} macos;
struct
{
const char *sdk;
WinCrtLinking crt_linking;
} win;
} BuildTarget;

View File

@@ -14,58 +14,54 @@ void load_library_files(void) {}
void load_files(void) {}
#if defined(_M_X64) || defined(_M_AMD64)
#if defined(__MINGW32__)
ArchOsTarget default_target = X64_WINDOWS_GNU;
#else
ArchOsTarget default_target = X64_WINDOWS;
#endif
ArchOsTarget default_target = WINDOWS_X64;
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
#if defined(__MACH__)
ArchOsTarget default_target = X64_DARWIN;
ArchOsTarget default_target = MACOS_X64;
#elif defined(__linux__) && __linux__
ArchOsTarget default_target = X64_LINUX;
ArchOsTarget default_target = LINUX_X64;
#elif defined(__NetBSD__)
ArchOsTarget default_target = X64_NETBSD;
ArchOsTarget default_target = NETBSD_X64;
#elif defined(__FreeBSD__)
ArchOsTarget default_target = X64_FREEBSD;
ArchOsTarget default_target = FREEBSD_X64;
#elif defined(__OpenBSD__)
ArchOsTarget default_target = X64_OPENBSD;
ArchOsTarget default_target = OPENBSD_X64;
#else
ArchOsTarget default_target = X64_ELF;
ArchOsTarget default_target = ELF_X64;
#endif
#elif defined(__aarch64__) || defined(_M_ARM64)
#if defined(__MACH__)
ArchOsTarget default_target = AARCH64_DARWIN;
ArchOsTarget default_target = MACOS_AARCH64;
#elif defined(__linux__) && __linux__
ArchOsTarget default_target = AARCH64_LINUX;
ArchOsTarget default_target = LINUX_AARCH64;
#else
ArchOsTarget default_target = AARCH64_ELF;
ArchOsTarget default_target = ELF_AARCH64;
#endif
#elif defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
#if defined(__linux__) && __linux__
ArchOsTarget default_target = X86_LINUX;
ArchOsTarget default_target = LINUX_X86;
#elif defined(__FreeBSD__)
ArchOsTarget default_target = X86_FREEBSD;
ArchOsTarget default_target = FREEBSD_X86;
#elif defined(__OpenBSD__)
ArchOsTarget default_target = X86_OPENBSD;
ArchOsTarget default_target = OPENBSD_X86;
#elif defined(__NetBSD__)
ArchOsTarget default_target = X86_NETBSD;
ArchOsTarget default_target = NETBSD_X86;
#elif defined(_MSC_VER) && _MSC_VER
ArchOsTarget default_target = X86_WINDOWS;
ArchOsTarget default_target = WINDOWS_X86;
#else
ArchOsTarget default_target = X86_ELF;
ArchOsTarget default_target = ELF_X86;
#endif
#elif defined(__riscv32)
#if defined(__linux__) && __linux__
ArchOsTarget default_target = RISCV32_LINUX;
ArchOsTarget default_target = LINUX_RISCV32;
#else
ArchOsTarget default_target = RISCV32_ELF;
ArchOsTarget default_target = ELF_RISCV32;
#endif
#elif defined(__riscv64)
#if defined(__linux__) && __linux__
ArchOsTarget default_target = RISCV64_LINUX;
ArchOsTarget default_target = LINUX_RISCV64;
#else
ArchOsTarget default_target = RISCV64_ELF;
ArchOsTarget default_target = ELF_RISCV64;
#endif
#else
ArchOsTarget default_target = ARCH_OS_TARGET_DEFAULT;
@@ -163,7 +159,11 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
}
target->no_stdlib = options->no_stdlib;
target->emit_llvm = options->emit_llvm;
target->force_linker = options->force_linker;
target->panicfn = options->panicfn;
if (options->macos.sdk) target->macos.sdk = options->macos.sdk;
if (options->win.sdk) target->win.sdk = options->win.sdk;
if (options->win.crt_linking != WIN_CRT_DEFAULT) target->win.crt_linking = options->win.crt_linking;
if (options->x86_vector_capability != X86VECTOR_DEFAULT)
{
target->feature.x86_vector_capability = options->x86_vector_capability;
@@ -198,6 +198,14 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
target->emit_llvm = false;
target->emit_object_files = false;
}
for (int i = 0; i < options->lib_dir_count; i++)
{
vec_add(target->libdirs, options->lib_dir[i]);
}
for (int i = 0; i < options->lib_count; i++)
{
vec_add(target->libs, options->libs[i]);
}
}
void init_default_build_target(BuildTarget *target, BuildOptions *options)
@@ -214,6 +222,7 @@ void init_default_build_target(BuildTarget *target, BuildOptions *options)
.arch_os_target = ARCH_OS_TARGET_DEFAULT,
.reloc_model = RELOC_DEFAULT,
.feature.x86_vector_capability = X86VECTOR_DEFAULT,
.win.crt_linking = WIN_CRT_DEFAULT,
};
update_build_target_from_options(target, options);
}

View File

@@ -47,7 +47,7 @@ static int get_valid_string_setting(JSONObject *json, const char *key, const cha
}
if (value->type == J_STRING)
{
int res = str_in_list(value->str, count, values);
int res = str_findlist(value->str, count, values);
if (res >= 0) return res + first_result;
}
error_exit("%s had an invalid value for '%s', expected %s", category, key, expected);
@@ -109,6 +109,17 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
const char *langrev = get_valid_string(json, "langrev", type, false);
const char **source_dirs = get_valid_array(json, "sources", type, target->source_dirs == NULL);
const char **libraries = get_valid_array(json, "libs", type, false);
VECEACH(libraries, i)
{
if (!str_is_valid_lowercase_name(libraries[i]))
{
char *name = strdup(libraries[i]);
str_ellide_in_place(name, 32);
error_exit("Error reading %s: invalid library target '%s'.", PROJECT_JSON, name);
}
}
const char **libdirs = get_valid_array(json, "libdir", type, false);
static const char *debug_infos[3] = {
[DEBUG_INFO_FULL] = "full",
[DEBUG_INFO_NONE] = "none",
@@ -119,9 +130,11 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
long symtab_size = get_valid_integer(json, "symtab", type, false);
const char *cpu = get_valid_string(json, "cpu", type, false);
int reloc = get_valid_string_setting(json, "reloc", type, reloc_models, 0, 5, "'none', 'pic', 'PIC', 'pie' or 'PIE'.");
int wincrt = get_valid_string_setting(json, "wincrt", type, wincrt_linking, 0, 5, "'none', 'static' or 'dynamic'.");
int x86vec = get_valid_string_setting(json, "x86vec", type, vector_capability, 0, 5, "none, mmx, sse, avx or avx512");
const char *panicfn = get_valid_string(json, "panicfn", type, false);
target->win.sdk = get_valid_string(json, "winsdk", type, false);
target->macos.sdk = get_valid_string(json, "macossdk", type, false);
target->panicfn = panicfn;
if (cc) target->cc = cc;
if (cflags) target->cflags = cflags;
@@ -129,9 +142,11 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
if (version) target->version = version;
if (langrev) target->langrev = langrev;
if (source_dirs) target->source_dirs = source_dirs;
if (libraries) target->libraries = libraries;
if (libdirs) target->libdirs = libdirs;
if (libraries) target->libs = libraries;
if (info > -1) target->debug_info = info;
if (cpu) target->cpu = cpu;
if (wincrt > -1) target->win.crt_linking = (WinCrtLinking)wincrt;
if (reloc > -1) target->reloc_model = (RelocModel)reloc;
if (x86vec > -1) target->feature.x86_vector_capability = x86vec;
@@ -177,7 +192,7 @@ static void project_add_target(Project *project, BuildTarget *default_target, J
error_exit("More %s contained more than one target with the name %s. Please make all target names unique.", PROJECT_JSON, target->name);
}
}
type = strformat("%s %s", type, target->name);
type = str_printf("%s %s", type, target->name);
load_into_build_target(json, type, target);
}
@@ -209,6 +224,7 @@ static void project_add_targets(Project *project, JSONObject *project_data)
.feature.trap_on_wrap = false,
.feature.x86_vector_capability = X86VECTOR_DEFAULT,
.feature.safe_mode = true,
.win.crt_linking = WIN_CRT_DEFAULT,
};
load_into_build_target(project_data, "default target", &default_target);
JSONObject *targets_json = json_obj_get(project_data, "targets");
@@ -266,7 +282,7 @@ Project *project_load(void)
{
Project *project = CALLOCS(Project);
size_t size;
char *read = read_file(PROJECT_JSON, &size);
char *read = file_read_all(PROJECT_JSON, &size);
JsonParser parser;
json_init_string(&parser, read, &malloc_arena);
JSONObject *json = json_parse(&parser);

View File

@@ -76,7 +76,7 @@ void create_project(BuildOptions *build_options)
{
char c = build_options->project_name[i];
if (c == '\0') break;
if (!is_alphanum_(c))
if (!char_is_alphanum_(c))
{
fprintf(stderr, "'%s' is not a valid project name.\n", build_options->project_name);
exit_compiler(EXIT_FAILURE);

View File

@@ -112,7 +112,7 @@ UNUSED Int128 i128_from_hexstrl(const char *str, const char *end)
while (str != end)
{
c = *(str++);
x = i128_add64(i128_shl64(x, 4), (uint64_t)hex_nibble(c));
x = i128_add64(i128_shl64(x, 4), (uint64_t)char_hex_to_nibble(c));
}
return x;
}

View File

@@ -126,14 +126,18 @@ void thread_compile_task_tb(void *compile_data)
static const char *active_target_name(void)
{
if (active_target.name) return active_target.name;
switch (active_target.arch_os_target)
{
case X86_WINDOWS:
case X64_WINDOWS:
case X64_WINDOWS_GNU:
case WINDOWS_X86:
case WINDOWS_X64:
case MINGW_X64:
if (active_target.name)
{
return str_cat(active_target.name, ".exe");
}
return "a.exe";
default:
if (active_target.name) return active_target.name;
return "a.out";
}
}
@@ -271,7 +275,7 @@ void compiler_compile(void)
for (int i = 0; i < cfiles; i++)
{
char *filename = NULL;
bool split_worked = filenamesplit(active_target.csources[i], &filename, NULL);
bool split_worked = file_namesplit(active_target.csources[i], &filename, NULL);
assert(split_worked);
size_t len = strlen(filename);
// .c -> .o (quick hack to fix the name on linux)
@@ -308,7 +312,7 @@ void compiler_compile(void)
if (create_exe)
{
const char *output_name = active_target_name();
if (active_target.arch_os_target == default_target)
if (platform_target.os != OS_TYPE_WIN32 && active_target.arch_os_target == default_target && !active_target.force_linker)
{
platform_linker(output_name, obj_files, output_file_count);
compiler_link_time = bench_mark();
@@ -327,8 +331,9 @@ void compiler_compile(void)
if (active_target.run_after_compile)
{
DEBUG_LOG("Will run");
printf("Launching %s...\n", output_name);
int ret = system(strformat("./%s", output_name));
int ret = system(platform_target.os == OS_TYPE_WIN32 ? output_name : str_printf("./%s", output_name));
printf("Program finished with exit code %d.", ret);
}
}
@@ -348,14 +353,14 @@ static const char **target_expand_source_names(const char** dirs, const char **s
{
if (name_len == 1 || name[name_len - 2] == '/')
{
char *path = copy_string(name, name_len - 1);
char *path = str_copy(name, name_len - 1);
file_add_wildcard_files(&files, path, false, suffix_list, suffix_count);
continue;
}
if (name[name_len - 2] != '*') goto INVALID_NAME;
if (name_len == 2 || name[name_len - 3] == '/')
{
char *path = copy_string(name, name_len - 2);
char *path = str_copy(name, name_len - 2);
file_add_wildcard_files(&files, path, true, suffix_list, suffix_count);
continue;
}
@@ -490,8 +495,11 @@ void print_syntax(BuildOptions *options)
}
void resolve_libraries(void);
void compile()
{
symtab_init(active_target.symtab_size);
active_target.sources = target_expand_source_names(active_target.source_dirs, c3_suffix_list, 3, true);
if (active_target.csource_dirs)
{
@@ -499,8 +507,8 @@ void compile()
active_target.csources = target_expand_source_names(active_target.csource_dirs, c_suffix_list, 1, false);
}
global_context.sources = active_target.sources;
symtab_init(active_target.symtab_size);
target_setup(&active_target);
resolve_libraries();
setup_int_define("C_SHORT_SIZE", platform_target.width_c_short, type_long);
setup_int_define("C_INT_SIZE", platform_target.width_c_int, type_long);
@@ -559,9 +567,9 @@ const char *get_object_extension(void)
{
switch (active_target.arch_os_target)
{
case X64_WINDOWS:
case X86_WINDOWS:
case X64_WINDOWS_GNU:
case WINDOWS_X64:
case WINDOWS_X86:
case MINGW_X64:
return ".obj";
default:
return ".o";
@@ -600,69 +608,11 @@ Module *compiler_find_or_create_module(Path *module_name, const char **parameter
return module;
}
void scratch_buffer_clear(void)
{
global_context.scratch_buffer_len = 0;
}
void scratch_buffer_append_len(const char *string, size_t len)
{
if (len + global_context.scratch_buffer_len > MAX_STRING_BUFFER - 1)
{
error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1);
}
memcpy(global_context.scratch_buffer + global_context.scratch_buffer_len, string, len);
global_context.scratch_buffer_len += len;
}
void scratch_buffer_append(const char *string)
{
scratch_buffer_append_len(string, strlen(string));
}
void scratch_buffer_append_signed_int(int64_t i)
{
uint32_t len_needed = (uint32_t)sprintf(&global_context.scratch_buffer[global_context.scratch_buffer_len], "%lld", (long long)i);
if (global_context.scratch_buffer_len + len_needed > MAX_STRING_BUFFER - 1)
{
error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1);
}
global_context.scratch_buffer_len += len_needed;
}
void scratch_buffer_append_unsigned_int(uint64_t i)
{
uint32_t len_needed = (uint32_t)sprintf(&global_context.scratch_buffer[global_context.scratch_buffer_len], "%llu", (unsigned long long)i);
if (global_context.scratch_buffer_len + len_needed > MAX_STRING_BUFFER - 1)
{
error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1);
}
global_context.scratch_buffer_len += len_needed;
}
void scratch_buffer_append_char(char c)
{
if (global_context.scratch_buffer_len + 1 > MAX_STRING_BUFFER - 1)
{
error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1);
}
global_context.scratch_buffer[global_context.scratch_buffer_len++] = c;
}
char *scratch_buffer_to_string(void)
{
global_context.scratch_buffer[global_context.scratch_buffer_len] = '\0';
return global_context.scratch_buffer;
}
const char *scratch_buffer_interned(void)
{
TokenType type = TOKEN_INVALID_TOKEN;
return symtab_add(global_context.scratch_buffer, global_context.scratch_buffer_len,
fnv1a(global_context.scratch_buffer, global_context.scratch_buffer_len), &type);
return symtab_add(scratch_buffer.str, scratch_buffer.len,
fnv1a(scratch_buffer.str, scratch_buffer.len), &type);
}
char *scratch_buffer_copy(void)
{
return copy_string(global_context.scratch_buffer, global_context.scratch_buffer_len);
}

View File

@@ -22,4 +22,5 @@ extern double compiler_sema_time;
extern double compiler_ir_gen_time;
extern double compiler_codegen_time;
extern double compiler_link_time;
extern const char* c3_suffix_list[3];
extern const char* c3_suffix_list[3];
extern char *arch_os_target[ARCH_OS_TARGET_LAST + 1];

View File

@@ -51,6 +51,7 @@ typedef unsigned ExprId;
typedef unsigned DeclId;
typedef unsigned TypeInfoId;
typedef struct Int128_
{
uint64_t high;
@@ -1435,9 +1436,7 @@ typedef struct
bool in_test_mode : 1;
unsigned errors_found;
unsigned warnings_found;
char scratch_buffer[MAX_STRING_BUFFER];
Decl ***locals_list;
uint32_t scratch_buffer_len;
HTable compiler_defines;
Module std_module;
DeclTable symbols;
@@ -1554,6 +1553,7 @@ typedef struct
} NameResolve;
extern GlobalContext global_context;
extern BuildTarget active_target;
extern Ast *poisoned_ast;
@@ -1989,15 +1989,7 @@ void decltable_init(DeclTable *table, uint32_t initial_size);
DeclId decltable_get(DeclTable *table, const char *name);
void decltable_set(DeclTable *table, Decl *decl);
void scratch_buffer_clear(void);
void scratch_buffer_append(const char *string);
void scratch_buffer_append_len(const char *string, size_t len);
void scratch_buffer_append_char(char c);
void scratch_buffer_append_signed_int(int64_t i);
UNUSED void scratch_buffer_append_unsigned_int(uint64_t i);
char *scratch_buffer_to_string(void);
const char *scratch_buffer_interned(void);
char *scratch_buffer_copy(void);
const char *symtab_add(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type);
const char *symtab_find(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type);
@@ -2005,13 +1997,15 @@ void *llvm_target_machine_create(void);
void target_setup(BuildTarget *build_target);
int target_alloca_addr_space();
const char *macos_sysroot(void);
MacSDK *macos_sysroot_sdk_information(const char *sdk_path);
WindowsSDK *windows_get_sdk(void);
void c_abi_func_create(FunctionPrototype *proto);
bool token_is_any_type(TokenType type);
const char *token_type_to_string(TokenType type);
AlignSize type_abi_alignment(Type *type);
AlignSize type_alloca_alignment(Type *type);
@@ -2486,6 +2480,7 @@ bool obj_format_linking_supported(ObjectFormatType format_type);
bool linker(const char *output_file, const char **files, unsigned file_count);
void platform_linker(const char *output_file, const char **files, unsigned file_count);
void platform_compiler(const char **files, unsigned file_count, const char* flags);
const char *arch_to_linker_arch(ArchType arch);
#define CAT(a,b) CAT2(a,b) // force expand
#define CAT2(a,b) a##b // actually concatenate

View File

@@ -66,9 +66,9 @@ static bool filename_to_module_in_buffer(const char *path)
for (int i = last_slash + 1; i < last_dot; i++)
{
char c = path[i];
if (is_letter(c) || is_digit(c))
if (char_is_letter(c) || char_is_digit(c))
{
c = (char)(is_upper(c) ? c + 'a' - 'A' : c);
c = (char)(char_is_upper(c) ? c + 'a' - 'A' : c);
}
else
{
@@ -89,9 +89,9 @@ bool context_set_module_from_filename(ParseContext *context)
}
TokenType type = TOKEN_IDENT;
const char *module_name = symtab_add(global_context.scratch_buffer,
global_context.scratch_buffer_len,
fnv1a(global_context.scratch_buffer, (uint32_t) global_context.scratch_buffer_len),
const char *module_name = symtab_add(scratch_buffer.str,
scratch_buffer.len,
fnv1a(scratch_buffer.str, (uint32_t) scratch_buffer.len),
&type);
if (type != TOKEN_IDENT)
@@ -103,14 +103,14 @@ bool context_set_module_from_filename(ParseContext *context)
Path *path = CALLOCS(Path);
path->span = INVALID_SPAN;
path->module = module_name;
path->len = global_context.scratch_buffer_len;
path->len = scratch_buffer.len;
return create_module_or_check_name(context->unit, path, NULL, true);
}
bool context_set_module(ParseContext *context, Path *path, const char **generic_parameters, bool is_private)
{
// Note that we allow the illegal name for now, to be able to parse further.
if (!is_all_lower(path->module))
if (!str_has_no_uppercase(path->module))
{
SEMA_ERROR(path, "A module name may not have any upper case characters.");
return false;
@@ -277,8 +277,7 @@ bool unit_add_import(CompilationUnit *unit, Path *path, bool private_import)
{
DEBUG_LOG("SEMA: Add import of '%s'.", path->module);
if (!is_all_lower(path->module))
if (!str_has_no_uppercase(path->module))
{
SEMA_ERROR(path, "A module is not expected to have any upper case characters, please change it.");
return false;

View File

@@ -35,7 +35,7 @@ static inline void decltable_resize(DeclTable *table)
*dest = id;
}
table->entries = new_data;
table->max_load = new_capacity * TABLE_MAX_LOAD;
table->max_load = (uint32_t)(new_capacity * TABLE_MAX_LOAD);
table->capacity = new_capacity;
}
@@ -87,6 +87,6 @@ void decltable_init(DeclTable *table, uint32_t initial_size)
DeclId *entries = CALLOC(initial_size * sizeof(DeclId));
table->count = 0;
table->capacity = initial_size;
table->max_load = initial_size * TABLE_MAX_LOAD;
table->max_load = (uint32_t)(initial_size * TABLE_MAX_LOAD);
table->entries = entries;
}

View File

@@ -66,7 +66,7 @@ static void print_error(SourceSpan location, const char *message, PrintType prin
{
current += row_len + 1;
row_len = 0;
while (current[row_len] != '\n') row_len++;
while (current[row_len] != '\n' && current[row_len]) row_len++;
if (row_len > max_lines_for_display)
{
eprintf(number_buffer_elided, row, max_lines_for_display - 1, current);
@@ -148,15 +148,7 @@ static void print_error(SourceSpan location, const char *message, PrintType prin
static void vprint_error(SourceSpan location, const char *message, va_list args)
{
#define MAX_ERROR_LEN 4096
char buffer[MAX_ERROR_LEN];
size_t written = vsnprintf(buffer, MAX_ERROR_LEN - 1, message, args);
if (written > MAX_ERROR_LEN - 2)
{
print_error(location, "<Error message was too long>", PRINT_TYPE_ERROR);
return;
}
print_error(location, buffer, PRINT_TYPE_ERROR);
print_error(location, str_vprintf(message, args), PRINT_TYPE_ERROR);
}
@@ -251,7 +243,7 @@ const char *span_to_string(SourceSpan span)
}
assert(row == row_to_find);
const char *start = current + col - 1;
return copy_string(start, length);
return str_copy(start, length);
}

View File

@@ -178,7 +178,7 @@ Float float_from_string(const char *string, char **error)
if (error) *error = err_float_out_of_range;
return (Float){ .type = TYPE_POISONED };
}
char *expected_end = global_context.scratch_buffer + global_context.scratch_buffer_len;
char *expected_end = scratch_buffer.str + scratch_buffer.len;
if (d == 0 && end != expected_end)
{
if (error) *error = err_float_format_invalid;
@@ -200,7 +200,7 @@ Float float_from_hex(const char *string, char **error)
char c;
scratch_buffer_clear();
scratch_buffer_append("0x");
while ((c = *(index++)) && (c == '_' || is_hex(c)))
while ((c = *(index++)) && (c == '_' || char_is_hex(c)))
{
if (c == '_') continue;
scratch_buffer_append_char(c);
@@ -208,7 +208,7 @@ Float float_from_hex(const char *string, char **error)
if (c == '.')
{
scratch_buffer_append_char(c);
while ((c = *(index++)) && (c == '_' || is_hex(c)))
while ((c = *(index++)) && (c == '_' || char_is_hex(c)))
{
if (c == '_') continue;
scratch_buffer_append_char(c);
@@ -271,7 +271,7 @@ Float float_from_hex(const char *string, char **error)
if (error) *error = err_float_out_of_range;
return (Float){ .type = TYPE_POISONED };
}
if (d == 0 && end != global_context.scratch_buffer + global_context.scratch_buffer_len)
if (d == 0 && end != scratch_buffer.str + scratch_buffer.len)
{
if (error) *error = err_float_format_invalid;
return (Float){ .type = TYPE_POISONED };

View File

@@ -227,7 +227,7 @@ void header_gen(Module *module)
{
TODO
CompilationUnit *unit = module->units[0];
const char *filename = strcat_arena(unit->file->name, ".h");
const char *filename = str_cat(unit->file->name, ".h");
FILE *file = fopen(filename, "w");
OUTPUT("#include <stdint.h>\n");
OUTPUT("#ifndef __c3__\n");

View File

@@ -378,7 +378,7 @@ static inline bool scan_ident(Lexer *lexer, TokenType normal, TokenType const_to
static bool scan_number_suffix(Lexer *lexer, bool *is_float)
{
char c = peek(lexer);
if (!is_alphanum_(c)) return true;
if (!char_is_alphanum_(c)) return true;
switch (c)
{
case 'u':
@@ -390,17 +390,17 @@ static bool scan_number_suffix(Lexer *lexer, bool *is_float)
return add_error_token_at_current(lexer, "Integer suffix '%c' is not valid for a floating point literal.", c);
}
next(lexer);
while (is_number(c = peek(lexer))) next(lexer);
while (char_is_digit(c = peek(lexer))) next(lexer);
break;
case 'f':
next(lexer);
*is_float = true;
while (is_number(c = peek(lexer))) next(lexer);
while (char_is_digit(c = peek(lexer))) next(lexer);
break;
default:
break;
}
if (is_alphanum_(c))
if (char_is_alphanum_(c))
{
next(lexer);
return add_error_token(lexer, "This doesn't seem to be a valid literal.");
@@ -414,13 +414,13 @@ static bool scan_number_suffix(Lexer *lexer, bool *is_float)
*/
static bool scan_oct(Lexer *lexer)
{
if (!is_oct(peek(lexer)))
if (!char_is_oct(peek(lexer)))
{
return add_error_token_at_current(lexer, "An expression starting with '0o' should be followed by octal numbers (0-7).");
}
next(lexer);
while (is_oct_or_(peek(lexer))) next(lexer);
if (is_number(peek(lexer)))
while (char_is_oct_or_(peek(lexer))) next(lexer);
if (char_is_digit(peek(lexer)))
{
return add_error_token_at_current(lexer, "An expression starting with '0o' should be followed by octal numbers (0-7).");
}
@@ -438,13 +438,13 @@ static bool scan_oct(Lexer *lexer)
**/
static bool scan_binary(Lexer *lexer)
{
if (!is_binary(peek(lexer)))
if (!char_is_binary(peek(lexer)))
{
return add_error_token_at_current(lexer, "An expression starting with '0b' should be followed by binary digits (0-1).");
}
next(lexer);
while (is_binary_or_(peek(lexer))) next(lexer);
if (is_number(peek((lexer))))
while (char_is_binary_or_(peek(lexer))) next(lexer);
if (char_is_digit(peek((lexer))))
{
return add_error_token_at_current(lexer, "An expression starting with '0b' should be followed by binary digits (0-1).");
}
@@ -475,7 +475,7 @@ static inline bool scan_exponent(Lexer *lexer)
next(lexer);
}
// Now we need at least one digit
if (!is_digit(c))
if (!char_is_digit(c))
{
if (c == 0)
{
@@ -487,7 +487,7 @@ static inline bool scan_exponent(Lexer *lexer)
return add_error_token(lexer, "Parsing the floating point exponent failed, because '%c' is not a number.", c);
}
// Walk through all of the digits.
while (is_digit(peek(lexer))) next(lexer);
while (char_is_digit(peek(lexer))) next(lexer);
return true;
}
@@ -497,12 +497,12 @@ static inline bool scan_exponent(Lexer *lexer)
**/
static inline bool scan_hex(Lexer *lexer)
{
if (!is_hex(peek(lexer)))
if (!char_is_hex(peek(lexer)))
{
return add_error_token_at_current(lexer, "'0x' starts a hexadecimal number, so the next character should be 0-9, a-f or A-F.");
}
next(lexer);
while (is_hex_or_(peek(lexer))) next(lexer);
while (char_is_hex_or_(peek(lexer))) next(lexer);
bool is_float = false;
if (peek(lexer) == '.' && peek_next(lexer) != '.')
{
@@ -510,8 +510,8 @@ static inline bool scan_hex(Lexer *lexer)
next(lexer);
char c = peek(lexer);
if (c == '_') return add_error_token_at_current(lexer, "'_' is not allowed directly after decimal point, try removing it.");
if (is_hex(c)) next(lexer);
while (is_hex_or_(peek(lexer))) next(lexer);
if (char_is_hex(c)) next(lexer);
while (char_is_hex_or_(peek(lexer))) next(lexer);
}
char c = peek(lexer);
if (c == 'p' || c == 'P')
@@ -533,11 +533,11 @@ static inline bool scan_hex(Lexer *lexer)
*/
static inline bool scan_dec(Lexer *lexer)
{
assert(is_digit(peek(lexer)));
assert(char_is_digit(peek(lexer)));
// Walk through the digits, we don't need to worry about
// initial _ because we only call this if we have a digit initially.
while (is_digit_or_(peek(lexer))) next(lexer);
while (char_is_digit_or_(peek(lexer))) next(lexer);
// Assume no float.
bool is_float = false;
@@ -555,7 +555,7 @@ static inline bool scan_dec(Lexer *lexer)
if (c == '_') return add_error_token_at_current(lexer, "'_' is not allowed directly after decimal point, try removing it.");
// Now walk until we see no more digits.
// This allows 123. as a floating point number.
while (is_digit_or_(peek(lexer))) next(lexer);
while (char_is_digit_or_(peek(lexer))) next(lexer);
}
char c = peek(lexer);
// We might have an exponential. We allow 123e1 and 123.e1 as floating point, so
@@ -619,7 +619,7 @@ static inline int64_t scan_hex_literal(Lexer *lexer, int positions)
for (int j = 0; j < positions; j++)
{
hex <<= 4U;
int i = char_to_nibble(peek(lexer));
int i = char_hex_to_nibble(peek(lexer));
if (i < 0)
{
return -1;
@@ -739,7 +739,7 @@ static inline bool scan_char(Lexer *lexer)
{
assert(c == '\\');
c = peek(lexer);
escape = is_valid_escape(c);
escape = char_is_valid_escape(c);
if (escape == -1)
{
lexer->lexing_start += 1;
@@ -826,15 +826,15 @@ static int append_esc_string_token(char *restrict dest, const char *restrict src
{
int scanned;
uint64_t unicode_char;
signed char scanned_char = is_valid_escape(src[0]);
signed char scanned_char = char_is_valid_escape(src[0]);
if (scanned_char < 0) return -1;
switch (scanned_char)
{
case 'x':
{
int h = char_to_nibble(src[1]);
int h = char_hex_to_nibble(src[1]);
if (h < 0) return -1;
int l = char_to_nibble(src[2]);
int l = char_hex_to_nibble(src[2]);
if (l < 0) return -1;
unicode_char = ((unsigned) h << 4U) + (unsigned)l;
scanned = 3;
@@ -842,13 +842,13 @@ static int append_esc_string_token(char *restrict dest, const char *restrict src
}
case 'u':
{
int x1 = char_to_nibble(src[1]);
int x1 = char_hex_to_nibble(src[1]);
if (x1 < 0) return -1;
int x2 = char_to_nibble(src[2]);
int x2 = char_hex_to_nibble(src[2]);
if (x2 < 0) return -1;
int x3 = char_to_nibble(src[3]);
int x3 = char_hex_to_nibble(src[3]);
if (x3 < 0) return -1;
int x4 = char_to_nibble(src[4]);
int x4 = char_hex_to_nibble(src[4]);
if (x4 < 0) return -1;
unicode_char = ((unsigned) x1 << 12U) + ((unsigned) x2 << 8U) + ((unsigned) x3 << 4U) + (unsigned)x4;
scanned = 5;
@@ -856,21 +856,21 @@ static int append_esc_string_token(char *restrict dest, const char *restrict src
}
case 'U':
{
int x1 = char_to_nibble(src[1]);
int x1 = char_hex_to_nibble(src[1]);
if (x1 < 0) return -1;
int x2 = char_to_nibble(src[2]);
int x2 = char_hex_to_nibble(src[2]);
if (x2 < 0) return -1;
int x3 = char_to_nibble(src[3]);
int x3 = char_hex_to_nibble(src[3]);
if (x3 < 0) return -1;
int x4 = char_to_nibble(src[4]);
int x4 = char_hex_to_nibble(src[4]);
if (x4 < 0) return -1;
int x5 = char_to_nibble(src[5]);
int x5 = char_hex_to_nibble(src[5]);
if (x5 < 0) return -1;
int x6 = char_to_nibble(src[6]);
int x6 = char_hex_to_nibble(src[6]);
if (x6 < 0) return -1;
int x7 = char_to_nibble(src[7]);
int x7 = char_hex_to_nibble(src[7]);
if (x7 < 0) return -1;
int x8 = char_to_nibble(src[8]);
int x8 = char_hex_to_nibble(src[8]);
if (x8 < 0) return -1;
unicode_char = ((unsigned) x1 << 28U) + ((unsigned) x2 << 24U) + ((unsigned) x3 << 20U) + ((unsigned) x4 << 16U) +
((unsigned) x5 << 12U) + ((unsigned) x6 << 8U) + ((unsigned) x7 << 4U) + (unsigned)x8;
@@ -1031,13 +1031,13 @@ static inline bool scan_hex_array(Lexer *lexer)
return add_error_token_at_current(lexer, "The hex string seems to be missing a terminating '%c'", start_char);
}
if (c == start_char) break;
if (is_hex(c))
if (char_is_hex(c))
{
next(lexer);
len++;
continue;
}
if (is_whitespace(c))
if (char_is_whitespace(c))
{
next(lexer);
continue;
@@ -1080,7 +1080,7 @@ static inline bool scan_base64(Lexer *lexer)
}
next(lexer);
if (c == start_char) break;
if (is_base64(c))
if (char_is_base64(c))
{
if (end_len)
{
@@ -1098,7 +1098,7 @@ static inline bool scan_base64(Lexer *lexer)
end_len++;
continue;
}
if (!is_whitespace(c))
if (!char_is_whitespace(c))
{
if (c < ' ' || c > 127)
{
@@ -1297,7 +1297,7 @@ static bool lexer_scan_token_inner(Lexer *lexer)
case '$':
if (match(lexer, '$'))
{
if (is_letter(peek(lexer)))
if (char_is_letter(peek(lexer)))
{
return return_token(lexer, TOKEN_BUILTIN, "$$");
}

190
src/compiler/libraries.c Normal file
View File

@@ -0,0 +1,190 @@
#include "compiler_internal.h"
#include "../utils/json.h"
#define MANIFEST_FILE "manifest.json"
static inline JSONObject *get_mandatory(Library *library, JSONObject *object, const char *key)
{
JSONObject *value = json_obj_get(object, key);
if (!value) error_exit("The mandatory '%s' field was missing in '%s'.", library->dir);
return value;
}
static inline const char *get_mandatory_string(Library *library, JSONObject *object, const char *key)
{
JSONObject *value = get_mandatory(library, object, key);
if (value->type != J_STRING) error_exit("Expected string value for '%s' in '%s'.", library->dir);
return value->str;
}
static inline JSONObject *get_optional_string_array(Library *library, JSONObject *object, const char *key)
{
JSONObject *value = json_obj_get(object, key);
if (!value) return NULL;
if (value->type != J_ARRAY) error_exit("Expected an array value for '%s' in '%s'.", library->dir);
for (int i = 0; i < value->array_len; i++)
{
JSONObject *val = value->elements[i];
if (val->type != J_STRING) error_exit("Expected only strings in array '%s' in '%s'.", library->dir);
}
return value;
}
static inline const char **get_optional_string_array_as_array(Library *library, JSONObject *object, const char *key)
{
JSONObject *array = get_optional_string_array(library, object, key);
if (!array || !array->array_len) return NULL;
const char **array_result = VECNEW(const char*, array->array_len);
for (size_t i = 0; i < array->array_len; i++)
{
vec_add(array_result, array->elements[i]->str);
}
return array_result;
}
static inline void parse_provides(Library *library, JSONObject *object)
{
const char *provides = get_mandatory_string(library, object, "provides");
if (!str_is_valid_lowercase_name(provides))
{
char *res = strdup(provides);
str_ellide_in_place(res, 32);
error_exit("Invalid 'provides' module name in %s, was '%s'.", library->dir, json_obj_get(object, "provides")->str);
}
library->provides = provides;
}
static inline void parse_depends(Library *library, JSONObject *object)
{
JSONObject *depends = get_optional_string_array(library, object, "depends");
if (!depends) return;
TODO
}
static inline void parse_library_target(Library *library, LibraryTarget *target, JSONObject *object)
{
target->link_flags = get_optional_string_array_as_array(library, object, "linkflags");
target->linked_libs = get_optional_string_array_as_array(library, object, "linked-libs");
target->depends = get_optional_string_array_as_array(library, object, "depends");
}
static inline void parse_library_type(Library *library, LibraryTarget ***target_group, JSONObject *object)
{
if (!object) return;
if (object->type != J_OBJECT) error_exit("Expected a set of targets in %s.", library->dir);
for (size_t i = 0; i < object->member_len; i++)
{
JSONObject *member = object->members[i];
const char *key = object->keys[i];
if (member->type != J_OBJECT) error_exit("Expected a list of properties for a target in %s.", library->dir);
LibraryTarget *library_target = CALLOCS(LibraryTarget);
ArchOsTarget target = arch_os_target_from_string(key);
if (target == ARCH_OS_TARGET_DEFAULT)
{
error_exit("Invalid arch/os '%s' in %s.", key, library->dir);
}
library_target->arch_os = target;
vec_add(*target_group, library_target);
parse_library_target(library, library_target, member);
}
}
static Library *add_library(JSONObject *object, const char *dir)
{
Library *library = CALLOCS(Library);
library->dir = dir;
parse_provides(library, object);
parse_depends(library, object);
parse_library_type(library, &library->targets, json_obj_get(object, "targets"));
return library;
}
static Library *find_library(Library **libs, size_t lib_count, const char *name)
{
for (size_t i = 0; i < lib_count; i++)
{
if (strcmp(libs[i]->provides, name) == 0)
{
return libs[i];
break;
}
}
error_exit("Required library '%s' could not be found.\n", name);
}
static void add_library_dependency(Library *library, Library **library_list, size_t lib_count)
{
if (library->target_used) return;
LibraryTarget *target_found = NULL;
VECEACH(library->targets, j)
{
LibraryTarget *target = library->targets[j];
if (target->arch_os == active_target.arch_os_target)
{
target_found = target;
break;
}
}
if (!target_found)
{
error_exit("Library '%s' cannot be used with arch/os '%s'.", library->provides, arch_os_target[active_target.arch_os_target]);
}
library->target_used = target_found;
VECEACH(library->depends, i)
{
add_library_dependency(find_library(library_list, lib_count, library->depends[i]), library_list, lib_count);
}
VECEACH(target_found->depends, i)
{
add_library_dependency(find_library(library_list, lib_count, target_found->depends[i]),
library_list,
lib_count);
}
}
void resolve_libraries(void)
{
static const char *c3lib_suffix = ".c3l";
const char **c3_libs = NULL;
VECEACH(active_target.libdirs, i)
{
file_add_wildcard_files(&c3_libs, active_target.libdirs[i], false, &c3lib_suffix, 1);
}
JsonParser parser;
Library *libraries[MAX_LIB_DIRS * 2];
size_t lib_count = 0;
VECEACH(c3_libs, i)
{
size_t size;
const char *lib = c3_libs[i];
if (!file_is_dir(lib))
{
error_exit("Packaged .c3l are not supported yet.");
}
const char *manifest_path = file_append_path(lib, MANIFEST_FILE);
char *read = file_read_all(manifest_path, &size);
json_init_string(&parser, read, &malloc_arena);
JSONObject *json = json_parse(&parser);
if (parser.error_message)
{
error_exit("Error on line %d reading '%s':'%s'", parser.line, manifest_path, parser.error_message);
}
if (lib_count == MAX_LIB_DIRS * 2) error_exit("Too many libraries added, exceeded %d.", MAX_LIB_DIRS * 2);
libraries[lib_count++] = add_library(json, lib);
}
VECEACH(active_target.libs, i)
{
const char *lib_name = active_target.libs[i];
add_library_dependency(find_library(libraries, lib_count, lib_name), libraries, lib_count);
}
for (size_t i = 0; i < lib_count; i++)
{
Library *library = libraries[i];
LibraryTarget *target = library->target_used;
if (!target) continue;
file_add_wildcard_files(&active_target.sources, library->dir, false, c3_suffix_list, 3);
vec_add(active_target.library_list, library);
vec_add(active_target.linker_libdirs, file_append_path(library->dir, arch_os_target[active_target.arch_os_target]));
}
}

View File

@@ -2,12 +2,6 @@
#include <llvm/Config/llvm-config.h> // for LLVM_VERSION_STRING
#ifdef PLATFORM_WINDOWS
#include "utils/find_msvc.h"
#endif
extern bool llvm_link_elf(const char **args, int arg_count, const char **error_string);
extern bool llvm_link_macho(const char **args, int arg_count, const char **error_string);
extern bool llvm_link_coff(const char **args, int arg_count, const char **error_string);
@@ -27,29 +21,181 @@ static const char *join_strings(const char **args, unsigned count)
char *res = "";
for (unsigned i = 0; i < count; ++i)
{
res = strcat_arena(res, args[i]);
res = str_cat(res, args[i]);
}
return res;
}
static void prepare_msys2_linker_flags(const char ***args, const char **files_to_link, unsigned file_count)
typedef enum
{
LINKER_LINK_EXE,
LINKER_LD,
LINKER_LD64,
LINKER_WASM,
LINKER_CC,
} LinkerType;
#define add_arg(arg_) vec_add(*args_ref, (arg_))
#define add_arg2(arg_, arg_2) vec_add(*args_ref, str_cat((arg_), (arg_2)))
static inline bool is_no_pie(RelocModel reloc)
{
return reloc == RELOC_NONE;
}
static inline bool is_pie(RelocModel reloc)
{
return reloc == RELOC_BIG_PIE || reloc == RELOC_BIG_PIE;
}
static const char *ld_target(ArchType arch_type)
{
switch (platform_target.arch)
{
case ARCH_TYPE_X86_64:
return "elf_x86_64";
case ARCH_TYPE_X86:
return "elf_i386";
case ARCH_TYPE_AARCH64:
return "aarch64elf";
case ARCH_TYPE_RISCV32:
return "elf32lriscv";
case ARCH_TYPE_RISCV64:
return "elf64lriscv";
default:
error_exit("Architecture currently not available for cross linking.");
}
}
static const char *string_esc(const char *str)
{
scratch_buffer_clear();
size_t len = strlen(str);
for (size_t i = 0; i < len; i++)
{
if (i > 3 && !char_is_alphanum_(str[i])) scratch_buffer_append_char('\\');
scratch_buffer_append_char(str[i]);
}
return strdup(scratch_buffer_to_string());
}
static void linker_setup_windows(const char ***args_ref, LinkerType linker_type)
{
if (linker_type == LINKER_CC) return;
//add_arg("/MACHINE:X64");
if (active_target.win.sdk)
{
add_arg(str_printf("/LIBPATH:%s", active_target.win.sdk));
}
else
{
WindowsSDK *windows_sdk = windows_get_sdk();
if (!windows_sdk) error_exit("Windows applications cannot be cross compiled without --winsdk.");
if (!file_is_dir(windows_sdk->vs_library_path)) error_exit("Failed to find windows sdk.");
add_arg(str_printf("/LIBPATH:%s", windows_sdk->windows_sdk_um_library_path));
add_arg(str_printf("/LIBPATH:%s", windows_sdk->windows_sdk_ucrt_library_path));
add_arg(str_printf("/LIBPATH:%s", windows_sdk->vs_library_path));
}
// Do not link any.
if (active_target.win.crt_linking == WIN_CRT_NONE) return;
add_arg("kernel32.lib");
add_arg("ntdll.lib");
add_arg("legacy_stdio_definitions.lib");
if (active_target.win.crt_linking == WIN_CRT_STATIC)
{
add_arg("libucrt.lib");
add_arg("libvcruntimed.lib");
add_arg("libcmt.lib");
add_arg("libcpmt.lib");
}
else
{
add_arg("ucrt.lib");
add_arg("vcruntime.lib");
add_arg("msvcrt.lib");
add_arg("msvcprt.lib");
}
add_arg("/NOLOGO");
}
#ifdef mingw64_support
static void linker_setup_mingw64_gcc(const char ***args_ref)
{
const char *root = getenv("MSYSTEM_PREFIX");
#define add_arg(opt) vec_add(*args, opt)
add_arg("-m");
add_arg("i386pep");
add_arg("-Bdynamic");
add_arg(join_strings((const char *[]){ root, "\\x86_64-w64-mingw32\\lib\\crt2.o" }, 2));
add_arg(join_strings((const char *[]){ root, "\\x86_64-w64-mingw32\\lib\\crtbegin.o" }, 2));
add_arg(join_strings((const char *[]){ "-L", root, "\\x86_64-w64-mingw32\\lib" }, 3));
add_arg(join_strings((const char *[]){ "-L", root, "\\lib" }, 3));
add_arg(join_strings((const char *[]){ "-L", root, "\\x86_64-w64-mingw32\\sys-root\\mingw\\lib" }, 3));
add_arg(join_strings((const char *[]){ "-L", root, "\\lib\\clang\\", LLVM_VERSION_STRING, "\\lib\\windows" }, 5));
add_files(args, files_to_link, file_count);
const char *root = getenv("MSYSTEM_PREFIX");
const char *gcc_base = strformat("%s/lib/gcc/x86_64-w64-mingw32", root);
if (!file_exists(gcc_base)) error_exit("Missing GCC");
const char *name = file_first(gcc_base);
const char *gcc_path = strformat("%s/%s/", gcc_base, name);
add_arg(strformat("-L%s/x86_64-w64-mingw32/lib", root));
add_arg(strformat("-L%s/lib", root));
add_arg2(gcc_path, "crtbegin.o");
add_arg(strformat("%s/lib/crt2.o", root));
add_arg(strformat("%s/lib/default-manifest.o", root));
add_arg2("-L", gcc_path);
add_arg("-lkernel32");
add_arg("-lmingw32");
add_arg(join_strings((const char *[]){ root, "\\lib\\clang\\", LLVM_VERSION_STRING,
"\\lib\\windows\\libclang_rt.builtins-x86_64.a" }, 4));
add_arg("-lunwind");
add_arg("-lgcc");
add_arg("-lgcc_eh");
add_arg("-lmoldname");
add_arg("-lmingwex");
add_arg("-lmsvcrt");
add_arg("-ladvapi32");
add_arg("-lshell32");
add_arg("-luser32");
add_arg("-lpthread");
add_arg2(gcc_path, "crtend.o");
}
static void linker_setup_windows_gnu(const char ***args_ref, LinkerType linker_type)
{
if (linker_type == LINKER_CC) return;
bool is_clang = strcmp(getenv("MSYSTEM"), "CLANG64") == 0;
bool is_mingw = strcmp(getenv("MSYSTEM"), "MINGW64") == 0;
if (!is_clang && !is_mingw)
{
error_exit("Crosslinking MSYS is not yet supported.");
}
if (is_mingw)
{
linker_setup_mingw64_gcc(args_ref);
return;
}
const char *root = getenv("MSYSTEM_PREFIX");
const char *compiler_prefix;
if (is_clang)
{
char *filename;
char *dir;
path_get_dir_and_filename_from_full(root, &filename, &dir);
compiler_prefix = filename;
root = dir;
}
else
{
compiler_prefix = "x86_64-w64-mingw32";
}
add_arg("-m");
add_arg("i386pep");
add_arg("-Bdynamic");
const char *lib = strformat("%s/%s/lib", root, compiler_prefix);
if (!file_exists(lib))
{
error_exit("Cannot find '%s'.", lib);
}
add_arg2(lib, "/crt2.o");
add_arg2(lib, "/crtbegin.o");
add_arg2("-L", lib);
add_arg(strformat("-L%s/lib", root));
add_arg(strformat("-L%s/%s/sys-root/mingw/lib", root, compiler_prefix));
const char *clang_dir = strformat("%s/lib/clang/" LLVM_VERSION_STRING, root);
add_arg(strformat("-L%s/lib/windows", clang_dir));
add_arg("-lmingw32");
add_arg(strformat("%s/lib/windows/libclang_rt.builtins-x86_64.a", clang_dir));
add_arg("-lmoldname");
add_arg("-lmingwex");
add_arg("-lmsvcrt");
@@ -58,36 +204,179 @@ static void prepare_msys2_linker_flags(const char ***args, const char **files_to
add_arg("-luser32");
add_arg("-lkernel32");
add_arg("-lmingw32");
add_arg(join_strings((const char *[]){ root, "\\lib\\clang\\", LLVM_VERSION_STRING,
"\\lib\\windows\\libclang_rt.builtins-x86_64.a" }, 4));
add_arg("-lunwind");
add_arg("-lmoldname");
add_arg("-lmingwex");
add_arg("-lmsvcrt");
add_arg("-lkernel32");
add_arg(join_strings((const char *[]){ root, "\\x86_64-w64-mingw32\\lib\\crtend.o" }, 2));
#undef add_arg
add_arg2(lib, "\\crtend.o");
}
*/
#endif
static void linker_setup_macos(const char ***args_ref, LinkerType linker_type)
{
if (linker_type == LINKER_CC) return;
const char *sysroot = active_target.macos.sdk ? active_target.macos.sdk : macos_sysroot();
if (!sysroot)
{
error_exit("Cannot crosslink MacOS without providing --macossdk.");
}
DEBUG_LOG("Macos SDK: %s", sysroot);
MacSDK *mac_sdk = macos_sysroot_sdk_information(sysroot);
add_arg("-arch");
add_arg(arch_to_linker_arch(platform_target.arch));
add_arg("-lSystem");
add_arg("-lm");
add_arg("-syslibroot");
add_arg(sysroot);
if (is_no_pie(platform_target.reloc_model)) add_arg("-no_pie");
if (is_pie(platform_target.reloc_model)) add_arg("-pie");
add_arg("-platform_version");
add_arg("macos");
add_arg(str_printf("%d.0.0", mac_sdk->macos_deploy_target.major));
add_arg(str_printf("%d.%d", mac_sdk->macos_deploy_target.major, mac_sdk->macos_deploy_target.minor));
}
static void append_linker_pie_options(RelocModel reloc, const char ***args_ref)
static const char *find_linux_crt(void)
{
switch (reloc)
if (file_exists("/usr/lib/x86_64-linux-gnu/crt1.o"))
{
case RELOC_DEFAULT:
UNREACHABLE
case RELOC_NONE:
vec_add(*args_ref, "-no_pie");
break;
case RELOC_SMALL_PIC:
case RELOC_BIG_PIC:
break;
case RELOC_SMALL_PIE:
case RELOC_BIG_PIE:
vec_add(*args_ref, "-pie");
break;
return "/usr/lib/x86_64-linux-gnu/";
}
return NULL;
}
static const char *find_linux_crt_begin(void)
{
if (file_exists("/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o"))
{
return "/usr/lib/gcc/x86_64-linux-gnu/10/";
}
return NULL;
}
static void linker_setup_linux(const char ***args_ref, LinkerType linker_type)
{
if (linker_type == LINKER_CC) return;
if (is_no_pie(platform_target.reloc_model)) add_arg("-no-pie");
if (is_pie(platform_target.reloc_model)) add_arg("-pie");
if (platform_target.arch == ARCH_TYPE_X86_64) add_arg("--eh-frame-hdr");
const char *crt_begin_dir = find_linux_crt_begin();
const char *crt_dir = find_linux_crt();
if (!crt_begin_dir || !crt_dir)
{
error_exit("Failed to find the C runtime at link time.");
}
if (is_pie_pic(platform_target.reloc_model))
{
add_arg("-pie");
add_arg2(crt_dir, "Scrt1.o");
add_arg2(crt_begin_dir, "crtbeginS.o");
add_arg2(crt_dir, "crti.o");
add_arg2(crt_begin_dir, "crtendS.o");
}
else
{
add_arg2(crt_dir, "crt1.o");
add_arg2(crt_begin_dir, "crtbegin.o");
add_arg2(crt_dir, "crti.o");
add_arg2(crt_begin_dir, "crtend.o");
}
add_arg2(crt_dir, "crtn.o");
add_arg2("-L", crt_dir);
add_arg("--dynamic-linker=/lib64/ld-linux-x86-64.so.2");
add_arg("-lc");
add_arg("-lm");
add_arg("-L/usr/lib/");
add_arg("-L/lib/");
add_arg("-m");
add_arg(ld_target(platform_target.arch));
}
static bool linker_setup(const char ***args_ref, const char **files_to_link, unsigned file_count,
const char *output_file, LinkerType linker_type)
{
bool use_win = linker_type == LINKER_LINK_EXE;
if (use_win)
{
add_arg2("/OUT:", output_file);
}
else
{
add_arg("-o");
add_arg(output_file);
}
const char *lib_path_opt = use_win ? "/LIBPATH:" : "-L";
switch (platform_target.os)
{
case OS_UNSUPPORTED:
UNREACHABLE
case OS_TYPE_WIN32:
linker_setup_windows(args_ref, linker_type);
break;
case OS_TYPE_MACOSX:
linker_setup_macos(args_ref, linker_type);
break;
case OS_TYPE_WATCHOS:
case OS_TYPE_IOS:
case OS_TYPE_OPENBSD:
case OS_TYPE_NETBSD:
case OS_TYPE_TVOS:
case OS_TYPE_FREE_BSD:
return false;
case OS_TYPE_WASI:
return false;
case OS_TYPE_LINUX:
linker_setup_linux(args_ref, linker_type);
break;
case OS_TYPE_UNKNOWN:
error_exit("Linking is not supported for unknown OS.");
case OS_TYPE_NONE:
error_exit("Linking is not supported for freestanding.");
}
for (unsigned i = 0; i < file_count; i++)
{
add_arg(files_to_link[i]);
}
VECEACH(active_target.linker_libdirs, i)
{
add_arg2(lib_path_opt, active_target.linker_libdirs[i]);
}
VECEACH(active_target.link_args, i)
{
add_arg(active_target.link_args[i]);
}
VECEACH(active_target.library_list, i)
{
Library *library = active_target.library_list[i];
LibraryTarget *target = library->target_used;
VECEACH(target->link_flags, j)
{
add_arg(target->link_flags[j]);
}
VECEACH(target->linked_libs, j)
{
const char *lib = target->linked_libs[j];
const char *framework = str_remove_suffix(lib, ".framework");
if (framework)
{
add_arg("-framework");
add_arg(framework);
continue;
}
if (use_win)
{
add_arg2(lib, ".lib");
}
else
{
add_arg2("-l", lib);
}
}
}
return true;
}
#undef add_arg2
#undef add_arg
static void append_fpie_pic_options(RelocModel reloc, const char ***args_ref)
{
switch (reloc)
@@ -117,166 +406,57 @@ static void append_fpie_pic_options(RelocModel reloc, const char ***args_ref)
}
}
LinkerType linker_find_linker_type(void)
{
switch (platform_target.os)
{
case OS_UNSUPPORTED:
case OS_TYPE_UNKNOWN:
case OS_TYPE_NONE:
case OS_TYPE_FREE_BSD:
case OS_TYPE_LINUX:
case OS_TYPE_NETBSD:
case OS_TYPE_OPENBSD:
return LINKER_LD;
case OS_TYPE_IOS:
case OS_TYPE_MACOSX:
case OS_TYPE_TVOS:
case OS_TYPE_WATCHOS:
return LINKER_LD64;
case OS_TYPE_WIN32:
return LINKER_LINK_EXE;
case OS_TYPE_WASI:
return LINKER_WASM;
}
UNREACHABLE
}
static bool link_exe(const char *output_file, const char **files_to_link, unsigned file_count)
{
DEBUG_LOG("Using linker directly.");
const char **args = NULL;
#ifdef _MSC_VER
if (platform_target.os == OS_TYPE_WIN32)
{
vec_add(args, join_strings((const char* []) {"/out:", output_file}, 2));
}
else
{
#endif
vec_add(args, "-o");
vec_add(args, output_file);
#ifdef _MSC_VER
}
#endif
LinkerType linker_type = linker_find_linker_type();
linker_setup(&args, files_to_link, file_count, output_file, linker_type);
VECEACH(active_target.link_args, i)
{
vec_add(args, active_target.link_args[i]);
}
const char *error = NULL;
// This isn't used in most cases, but its contents should get freed after linking.
WindowsLinkPathsUTF8 windows_paths = { 0 };
switch (platform_target.os)
{
case OS_TYPE_WIN32:
// TODO: properly detect if llvm-lld is available
// TODO: check if running inside MSYS2, it could be done via getting MSYSTEM environment variable
// https://stackoverflow.com/questions/65527286/how-to-check-if-my-program-is-running-on-mingwor-msys-shell-or-on-cmd
if (NULL == getenv("MSYSTEM"))
{
// "native" windows
// find paths to library directories.
// ex:
// C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\lib\\x64
// C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\atlmfc\\lib\\x64
// C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.19041.0\\ucrt\\x64
// C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.19041.0\\um\\x64
#ifdef _MSC_VER
windows_paths = get_windows_link_paths();
vec_add(args, join_strings((const char* []) { "-libpath:", windows_paths.windows_sdk_um_library_path }, 2));
vec_add(args, join_strings((const char* []) { "-libpath:", windows_paths.windows_sdk_ucrt_library_path }, 2));
vec_add(args, join_strings((const char* []) { "-libpath:", windows_paths.vs_library_path }, 2));
vec_add(args, "-defaultlib:libcmt");
vec_add(args, "-nologo");
add_files(&args, files_to_link, file_count);
#else
error_exit("ERROR - c3c must be compiled with MSVC to target x64-windows\n");
#endif
}
else
{
if (!strcmp(getenv("MSYSTEM"), "CLANG64") || !strcmp(getenv("MSYSTEM"), "MINGW64"))
{
prepare_msys2_linker_flags(&args, files_to_link, file_count);
}
else
{
return false;
}
}
break;
case OS_TYPE_MACOSX:
add_files(&args, files_to_link, file_count);
vec_add(args, "-lSystem");
vec_add(args, "-lm");
vec_add(args, "-syslibroot");
vec_add(args, "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk");
append_linker_pie_options(platform_target.reloc_model, &args);
if (platform_target.reloc_model == RELOC_SMALL_PIE || platform_target.reloc_model == RELOC_BIG_PIE)
{
vec_add(args, "-macosx_version_min");
vec_add(args, platform_target.arch == ARCH_TYPE_AARCH64 ? "11.0" : "10.8");
}
break;
case OS_TYPE_WATCHOS:
case OS_TYPE_IOS:
return false;
case OS_TYPE_WASI:
return false;
case OS_TYPE_OPENBSD:
case OS_TYPE_NETBSD:
case OS_TYPE_FREE_BSD:
return false;
case OS_TYPE_LINUX:
vec_add(args, "-m");
switch (platform_target.arch)
{
case ARCH_TYPE_X86_64:
vec_add(args, "elf_x86_64");
append_linker_pie_options(platform_target.reloc_model, &args);
if (is_pie_pic(platform_target.reloc_model))
{
vec_add(args, "--eh-frame-hdr");
vec_add(args, "/usr/lib/x86_64-linux-gnu/crt1.o");
vec_add(args, "/usr/lib/gcc/x86_64-linux-gnu/10/crtbeginS.o");
add_files(&args, files_to_link, file_count);
vec_add(args, "/usr/lib/x86_64-linux-gnu/crti.o");
vec_add(args, "/usr/lib/gcc/x86_64-linux-gnu/10/crtendS.o");
}
else
{
vec_add(args, "/usr/lib/x86_64-linux-gnu/Scrt1.o");
vec_add(args, "/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o");
add_files(&args, files_to_link, file_count);
vec_add(args, "-lc");
vec_add(args, "-lm");
vec_add(args, "/usr/lib/x86_64-linux-gnu/crti.o");
vec_add(args, "/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o");
}
vec_add(args, "/usr/lib/x86_64-linux-gnu/crtn.o");
vec_add(args, "-L/usr/lib/x86_64-linux-gnu/");
vec_add(args, "--dynamic-linker=/lib64/ld-linux-x86-64.so.2");
break;
case ARCH_TYPE_X86:
// vec_add(args, "elf_i386");
return false;
case ARCH_TYPE_AARCH64:
vec_add(args, "aarch64elf");
return false;
case ARCH_TYPE_RISCV32:
vec_add(args, "elf32lriscv");
return false;
case ARCH_TYPE_RISCV64:
vec_add(args, "elf64lriscv");
return false;
default:
UNREACHABLE
}
vec_add(args, "-L/usr/lib/");
vec_add(args, "-L/lib/");
break;
default:
add_files(&args, files_to_link, file_count);
append_linker_pie_options(platform_target.reloc_model, &args);
return false;
}
bool success;
const char *arg_list = "";
VECEACH(args, i)
{
arg_list = str_cat(arg_list, " ");
arg_list = str_cat(arg_list, args[i]);
}
DEBUG_LOG("Linker arguments: %s to %d", arg_list, platform_target.object_format);
switch (platform_target.object_format)
{
case OBJ_FORMAT_COFF:
if (platform_target.x64.is_mingw64)
{
success = llvm_link_mingw(args, (int)vec_size(args), &error);
}
else
{
success = llvm_link_coff(args, (int)vec_size(args), &error);
}
// This is only defined if compiling with MSVC
#ifdef _MSC_VER
if (windows_paths.windows_sdk_um_library_path) {
free_windows_link_paths(&windows_paths);
}
#endif
success = llvm_link_coff(args, (int)vec_size(args), &error);
break;
case OBJ_FORMAT_ELF:
success = llvm_link_elf(args, (int)vec_size(args), &error);
@@ -294,6 +474,7 @@ static bool link_exe(const char *output_file, const char **files_to_link, unsign
{
error_exit("Failed to create an executable: %s", error);
}
DEBUG_LOG("Linking complete.");
return true;
}
@@ -338,19 +519,11 @@ const char *concat_string_parts(const char **args)
void platform_linker(const char *output_file, const char **files, unsigned file_count)
{
DEBUG_LOG("Using cc linker.");
const char **parts = NULL;
vec_add(parts, active_target.cc ? active_target.cc : "cc");
VECEACH(active_target.link_args, i)
{
vec_add(parts, active_target.link_args[i]);
}
append_fpie_pic_options(platform_target.reloc_model, &parts);
vec_add(parts, "-o");
vec_add(parts, output_file);
for (unsigned i = 0; i < file_count; i++)
{
vec_add(parts, files[i]);
}
linker_setup(&parts, files, file_count, output_file, LINKER_CC);
vec_add(parts, "-lm");
const char *output = concat_string_parts(parts);
if (system(output) != 0)

View File

@@ -472,9 +472,11 @@ static void gencontext_verify_ir(GenContext *context)
}
}
void gencontext_emit_object_file(GenContext *context)
{
char *err = "";
DEBUG_LOG("Target: %s", platform_target.target_triple);
LLVMSetTarget(context->module, platform_target.target_triple);
char *layout = LLVMCopyStringRepOfTargetData(context->target_data);
LLVMSetDataLayout(context->module, layout);
@@ -666,12 +668,33 @@ void llvm_codegen_setup()
intrinsics_setup = true;
}
void llvm_set_comdat(GenContext *c, LLVMValueRef global)
{
if (!platform_target.use_comdat) return;
LLVMComdatRef comdat = LLVMGetOrInsertComdat(c->module, LLVMGetValueName(global));
LLVMSetComdatSelectionKind(comdat, LLVMAnyComdatSelectionKind);
LLVMSetComdat(global, comdat);
}
void llvm_set_linkonce(GenContext *c, LLVMValueRef global)
{
LLVMSetLinkage(global, LLVMLinkOnceAnyLinkage);
LLVMSetVisibility(global, LLVMDefaultVisibility);
llvm_set_comdat(c, global);
}
void llvm_set_weak(GenContext *c, LLVMValueRef global)
{
LLVMSetLinkage(global, LLVMWeakAnyLinkage);
LLVMSetVisibility(global, LLVMDefaultVisibility);
llvm_set_comdat(c, global);
}
void llvm_set_linkage(GenContext *c, Decl *decl, LLVMValueRef value)
{
if (decl->module != c->code_module)
{
LLVMSetLinkage(value, LLVMLinkOnceODRLinkage);
LLVMSetVisibility(value, LLVMDefaultVisibility);
llvm_set_linkonce(c, value);
return;
}
Visibility visibility = decl->visibility;
@@ -680,8 +703,7 @@ void llvm_set_linkage(GenContext *c, Decl *decl, LLVMValueRef value)
{
case VISIBLE_MODULE:
case VISIBLE_PUBLIC:
LLVMSetLinkage(value, LLVMLinkOnceODRLinkage);
LLVMSetVisibility(value, LLVMDefaultVisibility);
llvm_set_linkonce(c, value);
break;
case VISIBLE_EXTERN:
case VISIBLE_LOCAL:
@@ -725,7 +747,10 @@ void llvm_emit_introspection_type_from_decl(GenContext *c, Decl *decl)
decl->enums.values[i]->backend_ref = llvm_emit_array_gep_raw(c, enum_elements, elements_type, i, alignment, &store_align);
}
}
LLVMValueRef global_name = LLVMAddGlobal(c->module, llvm_get_type(c, type_char), decl->name ? decl->name : "anon");
scratch_buffer_clear();
scratch_buffer_append("introspect.");
scratch_buffer_append(decl->name ? decl->name : "anon");
LLVMValueRef global_name = LLVMAddGlobal(c->module, llvm_get_type(c, type_char), scratch_buffer_to_string());
LLVMSetGlobalConstant(global_name, 1);
LLVMSetInitializer(global_name, LLVMConstInt(llvm_get_type(c, type_char), 1, false));
decl->type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid));

View File

@@ -18,6 +18,7 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, AlignSi
static inline void llvm_emit_const_initialize_reference(GenContext *c, BEValue *ref, Expr *expr);
static inline void llvm_emit_initialize_reference(GenContext *c, BEValue *ref, Expr *expr);
BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValueRef failable)
{
assert(ref->kind == BE_ADDRESS || ref->kind == BE_ADDRESS_FAILABLE);
@@ -3281,7 +3282,6 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu
llvm_value_set(be_value, val, expr->type);
}
static void llvm_emit_post_unary_expr(GenContext *context, BEValue *be_value, Expr *expr)
{
@@ -3343,8 +3343,7 @@ void llvm_emit_derived_backend_type(GenContext *c, Type *type)
return;
PRIMITIVE:
LLVMSetLinkage(global_name, LLVMWeakAnyLinkage);
LLVMSetVisibility(global_name, LLVMDefaultVisibility);
llvm_set_weak(c, global_name);
}
void llvm_emit_typeid(GenContext *c, BEValue *be_value, Type *type)
@@ -3855,12 +3854,8 @@ static LLVMValueRef llvm_emit_real(LLVMTypeRef type, Float f)
return LLVMConstRealOfString(type, f.f < 0 ? "-inf" : "inf");
}
scratch_buffer_clear();
#if LONG_DOUBLE
global_context.scratch_buffer_len = sprintf(global_context.scratch_buffer, "%La", f.f);
#else
global_context.scratch_buffer_len = (uint32_t)sprintf(global_context.scratch_buffer, "%a", f.f);
#endif
return LLVMConstRealOfStringAndSize(type, global_context.scratch_buffer, global_context.scratch_buffer_len);
scratch_buffer_printf("%a", f.f);
return LLVMConstRealOfStringAndSize(type, scratch_buffer.str, scratch_buffer.len);
}
static inline void llvm_emit_const_initializer_list_expr(GenContext *c, BEValue *value, Expr *expr)

View File

@@ -457,11 +457,11 @@ void llvm_emit_function_body(GenContext *c, Decl *decl)
LLVMTypeRef ptr_to_slot_type = LLVMPointerType(slot_type, 0);
if (!c->debug.last_ptr)
{
LLVMValueRef last_stack = c->debug.last_ptr = LLVMAddGlobal(c->module, ptr_to_slot_type, ".$last_stack");
const char *name = ".$last_stack";
LLVMValueRef last_stack = c->debug.last_ptr = LLVMAddGlobal(c->module, ptr_to_slot_type, name);
LLVMSetThreadLocal(last_stack, true);
LLVMSetInitializer(last_stack, LLVMConstNull(ptr_to_slot_type));
LLVMSetVisibility(last_stack, LLVMDefaultVisibility);
LLVMSetLinkage(last_stack, LLVMWeakODRLinkage);
llvm_set_weak(c, last_stack);
}
AlignSize alignment = llvm_abi_alignment(c, slot_type);
c->debug.stack_slot = llvm_emit_alloca(c, slot_type, alignment, ".$stackslot");
@@ -651,7 +651,15 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
switch (visibility)
{
case VISIBLE_EXTERN:
LLVMSetLinkage(function, decl->func_decl.attr_weak ? LLVMExternalWeakLinkage : LLVMExternalLinkage);
if (decl->func_decl.attr_weak)
{
LLVMSetLinkage(function, LLVMExternalWeakLinkage);
llvm_set_comdat(c, function);
}
else
{
LLVMSetLinkage(function, LLVMExternalLinkage);
}
LLVMSetVisibility(function, LLVMDefaultVisibility);
if (prototype->call_abi == CALL_X86_STD && platform_target.os == OS_TYPE_WIN32)
{
@@ -660,8 +668,7 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
break;
case VISIBLE_PUBLIC:
case VISIBLE_MODULE:
if (decl->func_decl.attr_weak) LLVMSetLinkage(function, LLVMWeakAnyLinkage);
LLVMSetVisibility(function, LLVMDefaultVisibility);
if (decl->func_decl.attr_weak) llvm_set_weak(c, function);
break;
case VISIBLE_LOCAL:
LLVMSetLinkage(function, decl->func_decl.attr_weak ? LLVMLinkerPrivateWeakLinkage : LLVMInternalLinkage);

View File

@@ -263,6 +263,9 @@ void llvm_emit_coerce_store(GenContext *c, LLVMValueRef addr, AlignSize alignmen
void llvm_emit_function_body(GenContext *context, Decl *decl);
void llvm_emit_function_decl(GenContext *c, Decl *decl);
void llvm_emit_introspection_type_from_decl(GenContext *c, Decl *decl);
void llvm_set_weak(GenContext *c, LLVMValueRef global);
void llvm_set_linkonce(GenContext *c, LLVMValueRef global);
void llvm_set_comdat(GenContext *c, LLVMValueRef global);
LLVMValueRef llvm_emit_call_intrinsic(GenContext *c, unsigned intrinsic, LLVMTypeRef *types, unsigned type_count, LLVMValueRef *values, unsigned arg_count);
void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_type, Type *from_type);

View File

@@ -10,8 +10,8 @@ void gencontext_begin_module(GenContext *c)
assert(!c->module && "Expected no module");
const char *result = module_create_object_file_name(c->code_module);
c->ir_filename = strformat("%s.ll", result);
c->object_filename = strformat("%s%s", result, get_object_extension());
c->ir_filename = str_printf("%s.ll", result);
c->object_filename = str_printf("%s%s", result, get_object_extension());
c->panicfn = global_context.panic_fn;
c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context);

View File

@@ -1018,7 +1018,7 @@ static inline void llvm_emit_asm_stmt(GenContext *c, Ast *ast)
LLVMValueRef asm_fn = LLVMGetInlineAsm(asm_fn_type,
(char *)ast->asm_stmt.body->const_expr.string.chars,
ast->asm_stmt.body->const_expr.string.len,
scratch_buffer_to_string(), global_context.scratch_buffer_len,
scratch_buffer_to_string(), scratch_buffer.len,
ast->asm_stmt.is_volatile,
true,
LLVMInlineAsmDialectIntel

View File

@@ -0,0 +1,46 @@
#include "compiler_internal.h"
#include "utils/json.h"
const char *macos_sysroot(void)
{
#if __APPLE__
static const char *xcode_sysroot = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk";
static const char *commandline_tool_sysroot = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk";
if (file_is_dir(xcode_sysroot)) return xcode_sysroot;
if (file_is_dir(commandline_tool_sysroot)) return commandline_tool_sysroot;
#endif
return NULL;
}
void parse_version(const char *version_string, Version *version)
{
StringSlice slice = slice_from_string(version_string);
StringSlice first = slice_next_token(&slice, '.');
version->major = atoi(first.ptr);
version->minor = atoi(slice.ptr);
}
MacSDK *macos_sysroot_sdk_information(const char *sdk_path)
{
JsonParser parser;
size_t len;
scratch_buffer_clear();
scratch_buffer_printf("%s/SDKSettings.json", sdk_path);
const char *settings_json_path = scratch_buffer_to_string();
if (!file_exists(settings_json_path)) error_exit("Invalid MacOS SDK path: '%s'.", sdk_path);
const char *file = file_read_all(settings_json_path, &len);
json_init_string(&parser, file, &malloc_arena);
MacSDK *sdk = CALLOCS(MacSDK);
JSONObject *top_object = json_parse(&parser);
JSONObject *supported_targets = json_obj_get(top_object, "SupportedTargets");
JSONObject *macosx_target = json_obj_get(supported_targets, "macosx");
const char *default_deploy_target = json_obj_get(macosx_target, "DefaultDeploymentTarget")->str;
parse_version(default_deploy_target, &sdk->macos_deploy_target);
const char *min_deploy_target = json_obj_get(macosx_target, "MinimumDeploymentTarget")->str;
parse_version(min_deploy_target, &sdk->macos_min_deploy_target);
return sdk;
}

View File

@@ -12,10 +12,10 @@ Decl *module_find_symbol(Module *module, const char *symbol)
const char *module_create_object_file_name(Module *module)
{
scratch_buffer_clear();
StringSlice slice = strtoslice(module->name->module);
StringSlice slice = slice_from_string(module->name->module);
while (true)
{
StringSlice part = strnexttok(&slice, ':');
StringSlice part = slice_next_token(&slice, ':');
scratch_buffer_append_len(part.ptr, part.len);
if (!slice.len) break;
slice.ptr++;

View File

@@ -224,15 +224,9 @@ const char *expr_const_to_error_string(const ExprConst *expr)
case CONST_INTEGER:
return int_to_str(expr->ixx, 10);
case CONST_FLOAT:
#if LONG_DOUBLE
asprintf(&buff, "%Lg", expr->fxx.f);
#else
asprintf(&buff, "%g", expr->fxx.f);
#endif
return buff;
return str_printf("%g", expr->fxx.f);
case CONST_STRING:
asprintf(&buff, "\"%*.s\"", expr->string.len, expr->string.chars);
return buff;
return str_printf("\"%*.s\"", expr->string.len, expr->string.chars);
case CONST_BYTES:
return "<binary data>";
case CONST_ENUM:

View File

@@ -456,7 +456,7 @@ static Expr *parse_ct_stringify(ParseContext *c, Expr *left)
return expr;
}
size_t len = end - start;
const char *content = copy_string(start, len);
const char *content = str_copy(start, len);
Expr *expr = expr_new(EXPR_CONST, start_span);
expr->const_expr.const_kind = CONST_STRING;
expr->const_expr.string.chars = content;
@@ -1153,7 +1153,7 @@ static Expr *parse_integer(ParseContext *c, Expr *left)
if (ch == '_') continue;
if (i.high > max) wrapped = true;
i = i128_shl64(i, 4);
i = i128_add64(i, (uint64_t) hex_nibble(ch));
i = i128_add64(i, (uint64_t) char_hex_to_nibble(ch));
hex_characters++;
}
break;
@@ -1322,8 +1322,8 @@ static void parse_hex(char *result_pointer, const char *data, const char *end)
{
int val;
int val2;
while ((val = char_to_nibble(*(data++))) < 0) if (data == end) goto DONE;
while ((val2 = char_to_nibble(*(data++))) < 0);
while ((val = char_hex_to_nibble(*(data++))) < 0) if (data == end) goto DONE;
while ((val2 = char_hex_to_nibble(*(data++))) < 0);
*(data_current++) = (char)((val << 4) | val2);
}
@@ -1496,14 +1496,14 @@ static int append_esc_string_token(char *restrict dest, const char *restrict src
{
int scanned;
uint64_t unicode_char;
signed char scanned_char = is_valid_escape(src[0]);
signed char scanned_char = char_is_valid_escape(src[0]);
if (scanned_char < 0) return -1;
switch (scanned_char)
{
case 'x':
{
int h = char_to_nibble(src[1]);
int l = char_to_nibble(src[2]);
int h = char_hex_to_nibble(src[1]);
int l = char_hex_to_nibble(src[2]);
if (h < 0 || l < 0) return -1;
unicode_char = ((unsigned) h << 4U) + (unsigned)l;
scanned = 3;
@@ -1511,10 +1511,10 @@ static int append_esc_string_token(char *restrict dest, const char *restrict src
}
case 'u':
{
int x1 = char_to_nibble(src[1]);
int x2 = char_to_nibble(src[2]);
int x3 = char_to_nibble(src[3]);
int x4 = char_to_nibble(src[4]);
int x1 = char_hex_to_nibble(src[1]);
int x2 = char_hex_to_nibble(src[2]);
int x3 = char_hex_to_nibble(src[3]);
int x4 = char_hex_to_nibble(src[4]);
if (x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0) return -1;
unicode_char = ((unsigned) x1 << 12U) + ((unsigned) x2 << 8U) + ((unsigned) x3 << 4U) + (unsigned)x4;
scanned = 5;
@@ -1522,14 +1522,14 @@ static int append_esc_string_token(char *restrict dest, const char *restrict src
}
case 'U':
{
int x1 = char_to_nibble(src[1]);
int x2 = char_to_nibble(src[2]);
int x3 = char_to_nibble(src[3]);
int x4 = char_to_nibble(src[4]);
int x5 = char_to_nibble(src[5]);
int x6 = char_to_nibble(src[6]);
int x7 = char_to_nibble(src[7]);
int x8 = char_to_nibble(src[8]);
int x1 = char_hex_to_nibble(src[1]);
int x2 = char_hex_to_nibble(src[2]);
int x3 = char_hex_to_nibble(src[3]);
int x4 = char_hex_to_nibble(src[4]);
int x5 = char_hex_to_nibble(src[5]);
int x6 = char_hex_to_nibble(src[6]);
int x7 = char_hex_to_nibble(src[7]);
int x8 = char_hex_to_nibble(src[8]);
if (x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || x5 < 0 || x6 < 0 || x7 < 0 || x8 < 0) return -1;
unicode_char = ((unsigned) x1 << 28U) + ((unsigned) x2 << 24U) + ((unsigned) x3 << 20U) + ((unsigned) x4 << 16U) +
((unsigned) x5 << 12U) + ((unsigned) x6 << 8U) + ((unsigned) x7 << 4U) + (unsigned)x8;

View File

@@ -243,7 +243,7 @@ static inline Path *parse_module_path(ParseContext *c)
}
scratch_buffer_append("::");
}
return path_create_from_string(scratch_buffer_to_string(), global_context.scratch_buffer_len, span);
return path_create_from_string(scratch_buffer_to_string(), scratch_buffer.len, span);
}
@@ -417,7 +417,7 @@ Path *parse_path_prefix(ParseContext *c, bool *had_error)
*had_error = false;
if (!tok_is(c, TOKEN_IDENT) || peek(c) != TOKEN_SCOPE) return NULL;
char *scratch_ptr = global_context.scratch_buffer;
char *scratch_ptr = scratch_buffer.str;
uint32_t offset = 0;
Path *path = CALLOCS(Path);

View File

@@ -661,11 +661,7 @@ bool may_convert_float_const_implicit(Expr *expr, Type *to_type)
{
if (!float_const_fits_type(&expr->const_expr, type_flatten(to_type)->type_kind))
{
#if LONG_DOUBLE
ERROR_NODE(expr, "The value '%Lg' is out of range for %s, so you need an explicit cast to truncate the value.", expr->const_expr.fxx.f, type_quoted_error_string(to_type));
#else
SEMA_ERROR(expr, "The value '%g' is out of range for %s, so you need an explicit cast to truncate the value.", expr->const_expr.fxx.f, type_quoted_error_string(to_type));
#endif
return false;
}
return true;

View File

@@ -17,23 +17,23 @@ static bool sema_check_section(SemaContext *context, Decl *decl, Attr *attr)
return true;
}
scratch_buffer_clear();
StringSlice slice = strtoslice(section_string);
StringSlice segment = strnexttok(&slice, ',');
StringSlice section = strnexttok(&slice, ',');
StringSlice attrs = strnexttok(&slice, ',');
StringSlice stub_size_str = strnexttok(&slice, ',');
StringSlice slice = slice_from_string(section_string);
StringSlice segment = slice_next_token(&slice, ',');
StringSlice section = slice_next_token(&slice, ',');
StringSlice attrs = slice_next_token(&slice, ',');
StringSlice stub_size_str = slice_next_token(&slice, ',');
if (slice.len)
{
SEMA_ERROR(attr->expr, "Too many parts to the Mach-o section description.");
}
slicetrim(&segment);
slice_trim(&segment);
if (segment.len == 0)
{
SEMA_ERROR(attr->expr, "The segment is missing, did you type it correctly?");
return false;
}
slicetrim(&section);
slice_trim(&section);
if (section.len == 0)
{
SEMA_ERROR(attr->expr, "Mach-o requires 'segment,section' as the format, did you type it correctly?");
@@ -2172,7 +2172,7 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
Path *path = CALLOCS(Path);
path->module = path_string;
path->span = module->name->span;
path->len = global_context.scratch_buffer_len;
path->len = scratch_buffer.len;
instantiated_module = module_instantiate_generic(module, path, decl->define_decl.generic_params);
sema_analyze_stage(instantiated_module, c->unit->module->stage);
}

View File

@@ -3083,11 +3083,7 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
{
expr->expr_kind = EXPR_CONST;
expr->const_expr.const_kind = CONST_FLOAT;
#if LONG_DOUBLE
expr->const_expr.fxx = (Float) { nanl(""), canonical->type_kind };
#else
expr->const_expr.fxx = (Float) { nan(""), canonical->type_kind };
#endif
expr->type = parent->type;
expr->resolve_status = RESOLVE_DONE;
return true;
@@ -7376,7 +7372,7 @@ bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char
for (ArraySize i = 0; i < len; i++)
{
char ch = string[i];
if (!is_alphanum_(ch))
if (!char_is_alphanum_(ch))
{
if (ch == ':' && i > 0 && string[i + 1] == ':')
{
@@ -7407,7 +7403,7 @@ bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char
for (size_t i = 0; i < len; i++)
{
char c = string[i];
if (!is_alphanum_(c)) return false;
if (!char_is_alphanum_(c)) return false;
hash = FNV1a(c, hash);
}
*ident_ref = symtab_find(string, len, hash, type_ref);

View File

@@ -47,12 +47,12 @@ File *source_file_load(const char *filename, bool *already_loaded)
}
size_t size;
const char* source_text = read_file(filename, &size);
const char* source_text = file_read_all(filename, &size);
File *file = CALLOCS(File);
file->file_id = vec_size(global_context.loaded_sources);
file->full_path = full_path;
file->contents = source_text;
path_get_dir_and_filename_from_full(file->full_path, &file->name, &file->dir_path);
file_get_dir_and_filename_from_full(file->full_path, &file->name, &file->dir_path);
vec_add(global_context.loaded_sources, file);
return file;
}

View File

@@ -100,9 +100,9 @@ void symtab_init(uint32_t capacity)
{
const char* name = token_type_to_string((TokenType)i);
// Skip non-keywords
if (!is_lower(name[0]))
if (!char_is_lower(name[0]))
{
if ((name[0] != '@' && name[0] != '$') || !is_lower(name[1])) continue;
if ((name[0] != '@' && name[0] != '$') || !char_is_lower(name[1])) continue;
}
uint32_t len = (uint32_t)strlen(name);
TokenType type = (TokenType)i;
@@ -239,7 +239,7 @@ const char *symtab_add(const char *data, uint32_t len, uint32_t fnv1hash, TokenT
node->next = NULL;
node->index = fnv1hash;
node->type = *type;
return node->symbol = copy_string(data, len);
return node->symbol = str_copy(data, len);
}
SymtabEntry *bucket = first_bucket;
do
@@ -257,7 +257,7 @@ const char *symtab_add(const char *data, uint32_t len, uint32_t fnv1hash, TokenT
node->key_len = len;
node->index = fnv1hash;
node->type = *type;
return node->symbol = copy_string(data, len);
return node->symbol = str_copy(data, len);
}

View File

@@ -174,8 +174,7 @@ void llvm_dump(void)
}
LLVMTargetRef target;
char *error;
char *triplet = NULL;
asprintf(&triplet, "%s-unknown-%s-unknown", archs[i], os[j]);
char *triplet = str_printf("%s-unknown-%s-unknown", archs[i], os[j]);
if (LLVMGetTargetFromTriple(triplet, &target, &error)) continue;
LLVMTargetMachineRef machine = NULL;
if (!(machine = LLVMCreateTargetMachine(target, triplet, "", "", 0, LLVMRelocDefault, LLVMCodeModelDefault))) {
@@ -461,7 +460,9 @@ static inline void target_setup_x64_abi(BuildTarget *target)
if (target->feature.soft_float == SOFT_FLOAT_YES) platform_target.x64.soft_float = true;
if (platform_target.environment_type == ENV_TYPE_GNU)
{
platform_target.x64.is_mingw64 = platform_target.x64.is_win64;
//platform_target.x64.is_mingw64 = platform_target.x64.is_win64;
if (platform_target.x64.is_win64) DEBUG_LOG("Mingw");
}
if (platform_target.os == OS_TYPE_LINUX || platform_target.os == OS_TYPE_NETBSD)
{
@@ -484,29 +485,70 @@ static inline void target_setup_x64_abi(BuildTarget *target)
}
}
const char *arch_to_linker_arch(ArchType arch)
{
switch (arch)
{
case ARCH_UNSUPPORTED:
case ARCH_TYPE_UNKNOWN:
return "unknown";
case ARCH_TYPE_ARM:
return "arm";
case ARCH_TYPE_ARMB:
return "armeb";
case ARCH_TYPE_AARCH64:
return "aarch64";
case ARCH_TYPE_AARCH64_BE:
return "aarch64_be";
case ARCH_TYPE_PPC:
return "ppc";
case ARCH_TYPE_PPC64:
return "ppc64";
case ARCH_TYPE_PPC64LE:
return "ppc64le";
case ARCH_TYPE_RISCV32:
return "riscv32";
case ARCH_TYPE_RISCV64:
return "riscv64";
case ARCH_TYPE_THUMB:
return "thumb";
case ARCH_TYPE_THUMBEB:
return "thumbeb";
case ARCH_TYPE_X86:
return "i386";
case ARCH_TYPE_X86_64:
return "x86_64";
case ARCH_TYPE_WASM32:
return "wasm32";
case ARCH_TYPE_WASM64:
return "wasm64";
}
UNREACHABLE;
}
static char *arch_to_target_triple[ARCH_OS_TARGET_LAST + 1] = {
[X86_FREEBSD] = "i386-unknown-freebsd",
[X86_OPENBSD] = "i386-unknown-openbsd",
[X86_NETBSD] = "i386-unknown-netbsd",
[X86_MCU] = "i386-pc-elfiamcu",
[X86_WINDOWS] = "i386-pc-win32",
[X86_LINUX] = "i386-unknown-linux",
[X86_ELF] = "i386-unknown-elf",
[X64_DARWIN] = "x86_64-apple-darwin-1",
[X64_LINUX] = "x86_64-pc-linux-gnu",
[X64_WINDOWS] = "x86_64-pc-windows-msvc",
[X64_WINDOWS_GNU] = "x86_64-w64-windows-gnu",
[X64_NETBSD] = "x86_64-pc-netbsd",
[X64_FREEBSD] = "x86_64-pc-freebsd",
[X64_OPENBSD] = "x86_64-pc-openbsd",
[X64_ELF] = "x86_64-unknown-elf",
[AARCH64_LINUX] = "aarch64-unknown-linux-gnu",
[AARCH64_DARWIN] = "aarch64-apple-darwin",
[AARCH64_ELF] = "aarch64-unknown-elf",
[RISCV32_LINUX] = "riscv32-unknown-linux",
[RISCV32_ELF] = "riscv32-unknown-elf",
[RISCV64_LINUX] = "riscv64-unknown-linux",
[RISCV64_ELF] = "riscv64-unknown-elf",
[FREEBSD_X86] = "i386-unknown-freebsd",
[OPENBSD_X86] = "i386-unknown-openbsd",
[NETBSD_X86] = "i386-unknown-netbsd",
[MCU_X86] = "i386-pc-elfiamcu",
[WINDOWS_X86] = "i386-pc-win32",
[LINUX_X86] = "i386-unknown-linux",
[ELF_X86] = "i386-unknown-elf",
[MACOS_X64] = "x86_64-apple-darwin",
[LINUX_X64] = "x86_64-pc-linux-gnu",
[WINDOWS_X64] = "x86_64-pc-windows-msvc",
[MINGW_X64] = "x86_64-w64-windows-gnu",
[NETBSD_X64] = "x86_64-pc-netbsd",
[FREEBSD_X64] = "x86_64-pc-freebsd",
[OPENBSD_X64] = "x86_64-pc-openbsd",
[ELF_X64] = "x86_64-unknown-elf",
[LINUX_AARCH64] = "aarch64-unknown-linux-gnu",
[MACOS_AARCH64] = "aarch64-apple-darwin",
[ELF_AARCH64] = "aarch64-unknown-elf",
[LINUX_RISCV32] = "riscv32-unknown-linux",
[ELF_RISCV32] = "riscv32-unknown-elf",
[LINUX_RISCV64] = "riscv64-unknown-linux",
[ELF_RISCV64] = "riscv64-unknown-elf",
[WASM32] = "wasm32-unknown-unknown",
[WASM64] = "wasm64-unknown-unknown",
};
@@ -530,9 +572,10 @@ static bool arch_is_supported(ArchType arch)
return false;
}
}
static ArchType arch_from_llvm_string(StringSlice slice)
{
#define STRCASE(_str, _arch) if (slicestrcmp(slice, _str)) return _arch;
#define STRCASE(_str, _arch) if (slice_strcmp(slice, _str)) return _arch;
STRCASE("i386", ARCH_TYPE_X86)
STRCASE("i486", ARCH_TYPE_X86)
STRCASE("i586", ARCH_TYPE_X86)
@@ -635,28 +678,28 @@ static EnvironmentType environment_type_from_llvm_string(StringSlice env)
}
}
#define STRCASE(_str, _arch) if (slicestrcmp(env, _str)) return _arch;
STRCASE("gnu", ENV_TYPE_GNU)
STRCASE("gnuabin32", ENV_TYPE_GNUABIN32)
STRCASE("gnuabi64", ENV_TYPE_GNUABI64)
STRCASE("gnueabihf", ENV_TYPE_GNUEABIHF)
STRCASE("gnueabi", ENV_TYPE_GNUEABI)
STRCASE("gnux32", ENV_TYPE_GNUX32)
STRCASE("code16", ENV_TYPE_CODE16)
STRCASE("eabi", ENV_TYPE_EABI)
STRCASE("eabihf", ENV_TYPE_EABIHF)
STRCASE("elfv1", ENV_TYPE_ELFV1)
STRCASE("elfv2", ENV_TYPE_ELFV2)
STRCASE("android", ENV_TYPE_ANDROID)
STRCASE("musl", ENV_TYPE_MUSL)
STRCASE("musleabi", ENV_TYPE_MUSLEABI)
STRCASE("musleabihf", ENV_TYPE_MUSLEABIHF)
STRCASE("msvc", ENV_TYPE_MSVC)
STRCASE("itanium", ENV_TYPE_ITANIUM)
STRCASE("cygnus", ENV_TYPE_CYGNUS)
STRCASE("coreclr", ENV_TYPE_CORECLR)
STRCASE("simulator", ENV_TYPE_SIMULATOR)
STRCASE("macabi", ENV_TYPE_MACABI)
#define STRCASE(_str, _arch) if (slice_strcmp(env, _str)) return _arch;
STRCASE("gnu", ENV_TYPE_GNU)
STRCASE("gnuabin32", ENV_TYPE_GNUABIN32)
STRCASE("gnuabi64", ENV_TYPE_GNUABI64)
STRCASE("gnueabihf", ENV_TYPE_GNUEABIHF)
STRCASE("gnueabi", ENV_TYPE_GNUEABI)
STRCASE("gnux32", ENV_TYPE_GNUX32)
STRCASE("code16", ENV_TYPE_CODE16)
STRCASE("eabi", ENV_TYPE_EABI)
STRCASE("eabihf", ENV_TYPE_EABIHF)
STRCASE("elfv1", ENV_TYPE_ELFV1)
STRCASE("elfv2", ENV_TYPE_ELFV2)
STRCASE("android", ENV_TYPE_ANDROID)
STRCASE("musl", ENV_TYPE_MUSL)
STRCASE("musleabi", ENV_TYPE_MUSLEABI)
STRCASE("musleabihf", ENV_TYPE_MUSLEABIHF)
STRCASE("msvc", ENV_TYPE_MSVC)
STRCASE("itanium", ENV_TYPE_ITANIUM)
STRCASE("cygnus", ENV_TYPE_CYGNUS)
STRCASE("coreclr", ENV_TYPE_CORECLR)
STRCASE("simulator", ENV_TYPE_SIMULATOR)
STRCASE("macabi", ENV_TYPE_MACABI)
return ENV_TYPE_UNKNOWN;
#undef STRCASE
}
@@ -672,7 +715,7 @@ static OsType os_from_llvm_string(StringSlice os_string)
break;
}
}
#define STRCASE(_str, _os) if (slicestrcmp(os_string, _str)) return _os;
#define STRCASE(_str, _os) if (slice_strcmp(os_string, _str)) return _os;
STRCASE("ananas", OS_TYPE_ANANAS)
STRCASE("cloudabi", OS_TYPE_CLOUD_ABI)
STRCASE("darwin", OS_TYPE_MACOSX)
@@ -715,7 +758,7 @@ static OsType os_from_llvm_string(StringSlice os_string)
static VendorType vendor_from_llvm_string(StringSlice slice)
{
#define STRCASE(_str, _vendor) if (slicestrcmp(slice, _str)) return _vendor;
#define STRCASE(_str, _vendor) if (slice_strcmp(slice, _str)) return _vendor;
STRCASE("apple", VENDOR_APPLE)
STRCASE("pc", VENDOR_PC)
STRCASE("scei", VENDOR_SCEI)
@@ -1256,14 +1299,7 @@ void target_setup(BuildTarget *target)
if (target->arch_os_target == ARCH_OS_TARGET_DEFAULT) target->arch_os_target = default_target;
if (target->arch_os_target == ARCH_OS_TARGET_DEFAULT)
{
platform_target.target_triple = LLVM_DEFAULT_TARGET_TRIPLE;
}
else
{
platform_target.target_triple = arch_to_target_triple[target->arch_os_target];
}
platform_target.target_triple = arch_to_target_triple[target->arch_os_target];
platform_target.alloca_address_space = 0;
@@ -1299,18 +1335,18 @@ void target_setup(BuildTarget *target)
LLVMTargetMachineRef machine = llvm_target_machine_create();
char *target_triple = LLVMGetTargetMachineTriple(machine);
platform_target.target_triple = copy_string(target_triple, strlen(target_triple));
platform_target.target_triple = str_copy(target_triple, strlen(target_triple));
LLVMDisposeMessage(target_triple);
LLVMDisposeTargetMachine(machine);
StringSlice target_triple_string = strtoslice(platform_target.target_triple);
platform_target.arch = arch_from_llvm_string(strnexttok(&target_triple_string, '-'));
StringSlice target_triple_string = slice_from_string(platform_target.target_triple);
platform_target.arch = arch_from_llvm_string(slice_next_token(&target_triple_string, '-'));
if (!arch_is_supported(platform_target.arch))
{
printf("WARNING! This architecture is not supported.\n");
}
platform_target.vendor = vendor_from_llvm_string(strnexttok(&target_triple_string, '-'));
platform_target.os = os_from_llvm_string(strnexttok(&target_triple_string, '-'));
platform_target.vendor = vendor_from_llvm_string(slice_next_token(&target_triple_string, '-'));
platform_target.os = os_from_llvm_string(slice_next_token(&target_triple_string, '-'));
platform_target.environment_type = environment_type_from_llvm_string(target_triple_string);
platform_target.float_abi = false;
@@ -1322,6 +1358,17 @@ void target_setup(BuildTarget *target)
platform_target.width_pointer = arch_pointer_bit_width(platform_target.os, platform_target.arch);
platform_target.alloca_address_space = 0;
platform_target.object_format = object_format_from_os(platform_target.os);
switch (platform_target.object_format)
{
case OBJ_FORMAT_COFF:
case OBJ_FORMAT_ELF:
case OBJ_FORMAT_WASM:
platform_target.use_comdat = true;
break;
default:
break;
}
platform_target.int128 = os_target_supports_int128(platform_target.os, platform_target.arch);
platform_target.vec128f = os_target_supports_vec(platform_target.os, platform_target.arch, 128, false);
@@ -1422,7 +1469,6 @@ void target_setup(BuildTarget *target)
platform_target.environment_type,
active_target.type != TARGET_TYPE_EXECUTABLE);
platform_target.pic_required = arch_os_pic_default_forced(platform_target.arch, platform_target.os);
// Override PIC, but only if the platform does not require PIC
if (target->reloc_model != RELOC_DEFAULT
&& (target->reloc_model != RELOC_NONE || !platform_target.pic_required))

View File

@@ -266,6 +266,7 @@ typedef struct
bool signed_c_char : 1;
FloatABI float_abi : 3;
unsigned default_number_regs_x86 : 8;
bool use_comdat : 1;
union
{
struct

View File

@@ -91,14 +91,11 @@ Type *type_int_unsigned_by_bitsize(unsigned bytesize)
const char *type_quoted_error_string(Type *type)
{
char *buffer = NULL;
if (type->canonical != type)
{
asprintf(&buffer, "'%s' (%s)", type_to_error_string(type), type_to_error_string(type->canonical));
return buffer;
return str_printf("'%s' (%s)", type_to_error_string(type), type_to_error_string(type->canonical));
}
asprintf(&buffer, "'%s'", type_to_error_string(type));
return buffer;
return str_printf("'%s'", type_to_error_string(type));
}
static void type_append_func_to_scratch(FunctionPrototype *prototype);
@@ -208,7 +205,6 @@ static void type_append_func_to_scratch(FunctionPrototype *prototype)
const char *type_to_error_string(Type *type)
{
char *buffer = NULL;
switch (type->type_kind)
{
case TYPE_POISONED:
@@ -231,11 +227,9 @@ const char *type_to_error_string(Type *type)
case TYPE_FUNC:
scratch_buffer_clear();
type_append_func_to_scratch(type->func.prototype);
asprintf(&buffer, "fn %s", scratch_buffer_to_string());
return buffer;
return str_printf("fn %s", scratch_buffer_to_string());
case TYPE_VECTOR:
asprintf(&buffer, "%s[<%llu>]", type_to_error_string(type->array.base), (unsigned long long)type->array.len);
return buffer;
return str_printf("%s[<%llu>]", type_to_error_string(type->array.base), (unsigned long long)type->array.len);
case TYPE_TYPEINFO:
return "typeinfo";
case TYPE_TYPEID:
@@ -247,22 +241,17 @@ const char *type_to_error_string(Type *type)
{
return type_to_error_string(type->pointer);
}
asprintf(&buffer, "%s*", type_to_error_string(type->pointer));
return buffer;
return str_printf("%s*", type_to_error_string(type->pointer));
case TYPE_FAILABLE:
if (!type->failable) return "void!";
asprintf(&buffer, "%s!", type_to_error_string(type->failable));
return buffer;
return str_printf("%s!", type_to_error_string(type->failable));
case TYPE_ARRAY:
asprintf(&buffer, "%s[%llu]", type_to_error_string(type->array.base), (unsigned long long)type->array.len);
return buffer;
return str_printf("%s[%llu]", type_to_error_string(type->array.base), (unsigned long long)type->array.len);
case TYPE_INFERRED_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
asprintf(&buffer, "%s[*]", type_to_error_string(type->array.base));
return buffer;
return str_printf("%s[*]", type_to_error_string(type->array.base));
case TYPE_SUBARRAY:
asprintf(&buffer, "%s[]", type_to_error_string(type->array.base));
return buffer;
return str_printf("%s[]", type_to_error_string(type->array.base));
}
UNREACHABLE
}
@@ -555,7 +544,7 @@ static Type *type_generate_ptr(Type *ptr_type, bool canonical)
Type *ptr = ptr_type->type_cache[PTR_OFFSET];
if (ptr == NULL)
{
ptr = type_new(TYPE_POINTER, strformat("%s*", ptr_type->name));
ptr = type_new(TYPE_POINTER, str_printf("%s*", ptr_type->name));
ptr->pointer = ptr_type;
ptr_type->type_cache[PTR_OFFSET] = ptr;
if (ptr_type == ptr_type->canonical)
@@ -580,7 +569,7 @@ static Type *type_generate_failable(Type *failable_type, bool canonical)
Type *failable = failable_type->type_cache[FAILABLE_OFFSET];
if (failable == NULL)
{
failable = type_new(TYPE_FAILABLE, strformat("%s!", failable_type->name));
failable = type_new(TYPE_FAILABLE, str_printf("%s!", failable_type->name));
failable->pointer = failable_type;
failable_type->type_cache[FAILABLE_OFFSET] = failable;
if (failable_type == failable_type->canonical)
@@ -606,7 +595,7 @@ static Type *type_generate_subarray(Type *arr_type, bool canonical)
Type *arr = arr_type->type_cache[SUB_ARRAY_OFFSET];
if (arr == NULL)
{
arr = type_new(TYPE_SUBARRAY, strformat("%s[]", arr_type->name));
arr = type_new(TYPE_SUBARRAY, str_printf("%s[]", arr_type->name));
arr->array.base = arr_type;
arr_type->type_cache[SUB_ARRAY_OFFSET] = arr;
if (arr_type == arr_type->canonical)
@@ -632,7 +621,7 @@ static Type *type_generate_inferred_array(Type *arr_type, bool canonical)
Type *arr = arr_type->type_cache[INFERRED_ARRAY_OFFSET];
if (arr == NULL)
{
arr = type_new(TYPE_INFERRED_ARRAY, strformat("%s[*]", arr_type->name));
arr = type_new(TYPE_INFERRED_ARRAY, str_printf("%s[*]", arr_type->name));
arr->array.base = arr_type;
arr_type->type_cache[INFERRED_ARRAY_OFFSET] = arr;
if (arr_type == arr_type->canonical)
@@ -658,7 +647,7 @@ static Type *type_generate_flexible_array(Type *arr_type, bool canonical)
Type *arr = arr_type->type_cache[FLEXIBLE_ARRAY_OFFSET];
if (arr == NULL)
{
arr = type_new(TYPE_FLEXIBLE_ARRAY, strformat("%s[*]", arr_type->name));
arr = type_new(TYPE_FLEXIBLE_ARRAY, str_printf("%s[*]", arr_type->name));
arr->array.base = arr_type;
arr->array.len = 0;
arr_type->type_cache[FLEXIBLE_ARRAY_OFFSET] = arr;
@@ -869,13 +858,13 @@ static Type *type_create_array(Type *element_type, ArraySize len, bool vector, b
Type *vec_arr;
if (vector)
{
vec_arr = type_new(TYPE_VECTOR, strformat("%s[<%u>]", element_type->name, len));
vec_arr = type_new(TYPE_VECTOR, str_printf("%s[<%u>]", element_type->name, len));
vec_arr->array.base = element_type;
vec_arr->array.len = len;
}
else
{
vec_arr = type_new(TYPE_ARRAY, strformat("%s[%u]", element_type->name, len));
vec_arr = type_new(TYPE_ARRAY, str_printf("%s[%u]", element_type->name, len));
vec_arr->array.base = element_type;
vec_arr->array.len = len;
}
@@ -995,7 +984,7 @@ void type_func_prototype_init(uint32_t capacity)
assert(is_power_of_two(capacity) && capacity > 1);
map.entries = CALLOC(capacity * sizeof(FuncTypeEntry));
map.capacity = capacity;
map.max_load = TABLE_MAX_LOAD * capacity;
map.max_load = (uint32_t)(TABLE_MAX_LOAD * capacity);
}
static uint32_t hash_function(FunctionSignature *sig)
@@ -1073,10 +1062,10 @@ static inline Type *func_create_new_func_proto(FunctionSignature *sig, CallABI a
FuncTypeEntry *entries = map.entries;
uint32_t old_capacity = map.capacity;
uint32_t new_capacity = map.capacity = old_capacity << 2;
map.max_load = new_capacity * TABLE_MAX_LOAD;
map.max_load = (uint32_t)(new_capacity * TABLE_MAX_LOAD);
FuncTypeEntry *new_map = CALLOC(new_capacity * sizeof(FuncTypeEntry));
uint32_t new_mask = new_capacity - 1;
for (int i = 0; i < old_capacity; i++)
for (uint32_t i = 0; i < old_capacity; i++)
{
uint32_t key = entries[i].key;
if (!key) continue;

View File

@@ -0,0 +1,40 @@
// Copyright (c) 2022 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a LGPLv3.0
// a copy of which can be found in the LICENSE file.
#include "compiler_internal.h"
static WindowsSDK *sdk = NULL;
// find paths to library directories.
// ex:
// C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\lib\\x64
// C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\atlmfc\\lib\\x64
// C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.19041.0\\ucrt\\x64
// C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.19041.0\\um\\x64
#if PLATFORM_WINDOWS
WindowsSDK get_windows_link_paths(void);
void free_windows_link_paths(WindowsSDK* obj);
static WindowsSDK loaded;
WindowsSDK *windows_get_sdk(void)
{
if (!sdk)
{
loaded = get_windows_link_paths();
sdk = &loaded;
}
return sdk;
}
#else
WindowsSDK *windows_get_sdk(void)
{
return NULL;
}
#endif

View File

@@ -20,9 +20,7 @@
#define MAX_IDENTIFIER_LENGTH 31
#define MAX_SOURCE_LOCATION_LEN 255
#define PROJECT_JSON "project.c3p"
#ifndef __unused
#define __unused
#endif
#if defined( _WIN32 ) || defined( __WIN32__ ) || defined( _WIN64 )
#define PLATFORM_WINDOWS 1
@@ -50,4 +48,13 @@
#undef IS_GCC
#define IS_GCC 1
#endif
#endif
#endif
#ifndef __printflike
#define __printflike(x, y)
#endif
#ifndef __unused
#define __unused
#endif

View File

@@ -33,7 +33,7 @@
#define INLINE __attribute__((always_inline)) static inline
#elif defined(_MSC_VER)
#define FALLTHROUGH ((void)0)
#define INLINE __forceinline static inline
#define INLINE static __forceinline
#define NORETURN __declspec(noreturn)
#define UNUSED
#else
@@ -48,7 +48,7 @@
#define TODO FATAL_ERROR("TODO reached");
#define TEST_ASSERT(condition_, string_) while (!(condition_)) { FATAL_ERROR(string_); }
#define TEST_ASSERTF(condition_, string_, ...) while (!(condition_)) { char* str_; asprintf(&str_, string_, __VA_ARGS__); FATAL_ERROR(str_); }
#define TEST_ASSERTF(condition_, string_, ...) while (!(condition_)) { char* str_ = str_printf(string_, __VA_ARGS__); FATAL_ERROR(str_); }
#define EXPECT(_string, _value, _expected) \
do { long long __tempval1 = _value; long long __tempval2 = _expected; \

View File

@@ -90,7 +90,7 @@ static inline bool is_path_separator(char c)
* @param directory_ptr the pointer to return the directory in.
* @return false if only a directory could be found, true otherwise
*/
bool filenamesplit(const char *path, char** filename_ptr, char** directory_ptr)
bool file_namesplit(const char *path, char** filename_ptr, char** directory_ptr)
{
size_t len = strlen(path);
if (len == 0) return false;
@@ -107,12 +107,12 @@ bool filenamesplit(const char *path, char** filename_ptr, char** directory_ptr)
if (file_len == 1 && path[0] == '.') return false;
if (file_len == 2 && path[0] == '.' && path[1] == '.') return false;
if (!file_len) return false;
*filename_ptr = copy_string(&path[len - file_len], file_len);
*filename_ptr = str_copy(&path[len - file_len], file_len);
if (!directory_ptr) return true;
if (file_len < len)
{
size_t dir_len = len - file_len;
*directory_ptr = copy_string(path, dir_len - 1);
*directory_ptr = str_copy(path, dir_len - 1);
}
else
{
@@ -124,21 +124,19 @@ bool filenamesplit(const char *path, char** filename_ptr, char** directory_ptr)
const char *expand_path(const char *path)
const char *file_expand_path(const char *path)
{
if (path[0] == '~' && path[1] == '/')
{
// Ignore leak.
char *ret = NULL;
char *home = getenv("HOME");
if (!home || asprintf(&ret, "%s%s", home, &path[1]) == -1) return &path[2];
return ret;
if (!home) return &path[2];
return str_printf("%s%s", home, &path[1]);
}
return path;
}
char *read_file(const char *path, size_t *return_size)
char *file_read_all(const char *path, size_t *return_size)
{
FILE *file = fopen(path, "rb");
@@ -190,21 +188,20 @@ char *read_file(const char *path, size_t *return_size)
static inline const char *lib_find(const char *exe_path, const char *rel_path)
{
struct stat info;
char *lib_path = NULL;
asprintf(&lib_path, "%s%sstd", exe_path, rel_path);
DEBUG_LOG("Checking %s", lib_path);
int err = stat(lib_path, &info);
scratch_buffer_clear();
scratch_buffer_printf("%s%sstd", exe_path, rel_path);
DEBUG_LOG("Checking %s", scratch_buffer_to_string());
int err = stat(scratch_buffer_to_string(), &info);
// Not a dir or had error?
if (err || !S_ISDIR(info.st_mode)) return NULL;
char *check_path = NULL;
asprintf(&check_path, "%s/libc.c3", lib_path);
DEBUG_LOG("Potential lib found, sanity check for libc...");
err = stat(check_path, &info);
scratch_buffer_append("/libc.c3");
err = stat(scratch_buffer_to_string(), &info);
if (err || !S_ISREG(info.st_mode)) return NULL;
asprintf(&lib_path, "%s%s", exe_path, rel_path);
const char *lib_path = str_printf("%s%s", exe_path, rel_path);
DEBUG_LOG("Library path found at %s", lib_path);
return lib_path;
}
@@ -233,9 +230,9 @@ const char *find_lib_dir(void)
return NULL;
}
void path_get_dir_and_filename_from_full(const char *full_path, char **filename, char **dir_path)
void file_get_dir_and_filename_from_full(const char *full_path, char **filename, char **dir_path)
{
if (!filenamesplit(full_path, filename, dir_path))
if (!file_namesplit(full_path, filename, dir_path))
{
error_exit("The filename could not be extracted from '%s'.", full_path);
}
@@ -285,6 +282,48 @@ bool file_has_suffix_in_list(const char *file_name, int name_len, const char **s
return false;
}
bool file_is_dir(const char *file)
{
struct stat st;
if (stat(file, &st)) return false;
return S_ISDIR(st.st_mode);
}
bool file_exists(const char *path)
{
struct stat st;
if (stat(path, &st)) return false;
return S_ISDIR(st.st_mode) || S_ISREG(st.st_mode) || S_ISREG(st.st_mode);
}
const char *file_append_path(const char *path, const char *name)
{
size_t path_len = strlen(path);
if (!path_len) return name;
if (path[path_len - 1] == '/') return str_cat(path, name);
return str_printf("%s/%s", path, name);
}
const char *file_first(const char *path)
{
#ifdef _MSC_VER
DIR *dir = opendir(strip_drive_prefix(path));
#else
DIR *dir = opendir(path);
#endif
if (!dir) return NULL;
struct dirent *ent;
while ((ent = readdir(dir)))
{
size_t name_len = strlen(ent->d_name);
if (name_len > 2)
{
return str_printf("%.*s", (int)name_len, ent->d_name);
}
}
return NULL;
}
void file_add_wildcard_files(const char ***files, const char *path, bool recursive, const char **suffix_list, int suffix_count)
{
#ifdef _MSC_VER
@@ -305,12 +344,8 @@ void file_add_wildcard_files(const char ***files, const char *path, bool recursi
if (namelen < 3 || !file_has_suffix_in_list(ent->d_name, namelen, suffix_list, suffix_count))
{
char *new_path = NULL;
char *format = path_ends_with_slash ? "%s%s" : "%s/%s";
if (asprintf(&new_path, format, path, ent->d_name) == -1)
{
error_exit("Failed to allocate path.");
}
char *new_path = str_printf(format, path, ent->d_name);
bool is_directory;
struct stat st;
if (stat(new_path, &st))
@@ -323,15 +358,57 @@ void file_add_wildcard_files(const char ***files, const char *path, bool recursi
{
file_add_wildcard_files(files, new_path, recursive, suffix_list, suffix_count);
}
free(new_path);
continue;
}
char *format = path_ends_with_slash ? "%s%s" : "%s/%s";
vec_add(*files, strformat(format, path, ent->d_name));
vec_add(*files, str_printf(format, path, ent->d_name));
}
closedir(dir);
}
#if PLATFORM_WINDOWS
const char *execute_cmd(const char *cmd)
{
FATAL_ERROR("Not implemented");
}
#else
#define BUFSIZE 1024
const char *execute_cmd(const char *cmd)
{
char buffer[BUFSIZE];
char *output = "";
FILE *process = NULL;
if (!(process = popen(cmd, "r")))
{
error_exit("Failed to open a pipe for command '%s'.", cmd);
}
while (fgets(buffer, BUFSIZE - 1, process))
{
output = str_cat(output, buffer);
}
if (pclose(process))
{
error_exit("Failed to execute '%s'.", cmd);
}
while (output[0] != 0)
{
switch (output[0])
{
case ' ':
case '\t':
case '\n':
case '\r':
output++;
continue;
default:
break;
}
break;
}
return str_trim(output);
}
#endif
#if PLATFORM_WINDOWS
char *realpath(const char *path, char *const resolved_path)

View File

@@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "lib.h"
#include "find_msvc.h"
#if PLATFORM_WINDOWS
#include <windows.h>
#include <string.h>
@@ -25,10 +25,10 @@ typedef struct
Find_Result find_visual_studio_and_windows_sdk();
void free_resources(Find_Result* result);
WindowsLinkPathsUTF8 get_windows_link_paths() {
WindowsSDK get_windows_link_paths() {
Find_Result paths = find_visual_studio_and_windows_sdk();
WindowsLinkPathsUTF8 out = { 0 };
WindowsSDK out = { 0 };
// note: WideCharToMultiByte doesn't seem to do null termination.
// I'm wary of manually adding a null terminator, so hopefully this is reliable.
@@ -75,7 +75,7 @@ WindowsLinkPathsUTF8 get_windows_link_paths() {
return out;
}
void free_windows_link_paths(WindowsLinkPathsUTF8* obj) {
void free_windows_link_paths(WindowsSDK* obj) {
free(obj->vs_library_path);
free(obj->windows_sdk_ucrt_library_path);
free(obj->windows_sdk_um_library_path);
@@ -95,6 +95,22 @@ void free_resources(Find_Result* result) {
free(result->vs_library_path);
}
#ifndef _Out_
#define _Out_
#endif
#ifndef _In_
#define _In_
#endif
#ifndef _Out_writes_to_
#define _Out_writes_to_(a, b)
#endif
#ifndef _Deref_out_opt_
#define _Deref_out_opt_
#endif
#ifndef _In_z_
#define _In_z_
#endif
#undef INTERFACE
#define INTERFACE ISetupInstance
DECLARE_INTERFACE_(ISetupInstance, IUnknown)
@@ -169,7 +185,7 @@ typedef struct {
bool os_file_exists(wchar_t* name) {
// @Robustness: What flags do we really want to check here?
auto attrib = GetFileAttributesW(name);
DWORD attrib = GetFileAttributesW(name);
if (attrib == INVALID_FILE_ATTRIBUTES) return false;
if (attrib & FILE_ATTRIBUTE_DIRECTORY) return false;
@@ -184,13 +200,13 @@ wchar_t* concat(wchar_t* a, wchar_t* b, wchar_t* c, wchar_t* d) {
// If you don't like that, use a programming language that actually
// helps you with using custom allocators. Or just edit the code.
auto len_a = wcslen(a);
auto len_b = wcslen(b);
size_t len_a = wcslen(a);
size_t len_b = wcslen(b);
auto len_c = 0;
size_t len_c = 0;
if (c) len_c = wcslen(c);
auto len_d = 0;
size_t len_d = 0;
if (d) len_d = wcslen(d);
wchar_t* result = (wchar_t*)malloc((len_a + len_b + len_c + len_d + 1) * 2);
@@ -242,7 +258,7 @@ wchar_t* find_windows_kit_root_with_key(HKEY key, wchar_t* version) {
// If that's not the right terminology, hey, I never do registry stuff.
DWORD required_length;
auto rc = RegQueryValueExW(key, version, NULL, NULL, NULL, &required_length);
LSTATUS rc = RegQueryValueExW(key, version, NULL, NULL, NULL, &required_length);
if (rc != 0) return NULL;
DWORD length = required_length + 2; // The +2 is for the maybe optional zero later on. Probably we are over-allocating.
@@ -264,7 +280,7 @@ void win10_best(wchar_t* short_name, wchar_t* full_name, Version_Data* data) {
// Find the Windows 10 subdirectory with the highest version number.
int i0, i1, i2, i3;
auto success = swscanf_s(short_name, L"%d.%d.%d.%d", &i0, &i1, &i2, &i3);
int success = swscanf_s(short_name, L"%d.%d.%d.%d", &i0, &i1, &i2, &i3);
if (success < 4) return;
if (i0 < data->best_version[0]) return;
@@ -295,7 +311,7 @@ void win8_best(wchar_t* short_name, wchar_t* full_name, Version_Data* data) {
// Find the Windows 8 subdirectory with the highest version number.
int i0, i1;
auto success = swscanf_s(short_name, L"winv%d.%d", &i0, &i1);
int success = swscanf_s(short_name, L"winv%d.%d", &i0, &i1);
if (success < 2) return;
if (i0 < data->best_version[0]) return;

View File

@@ -1,10 +0,0 @@
#pragma once
typedef struct {
char* windows_sdk_um_library_path;
char* windows_sdk_ucrt_library_path;
char* vs_library_path;
} WindowsLinkPathsUTF8;
WindowsLinkPathsUTF8 get_windows_link_paths();
void free_windows_link_paths(WindowsLinkPathsUTF8* obj);

View File

@@ -165,12 +165,12 @@ static void json_parse_string(JsonParser *parser)
char u2 = parser->current++[0];
char u3 = parser->current++[0];
char u4 = parser->current++[0];
if (!is_hex(u1) || !is_hex(u2) || !is_hex(u3) || !is_hex(u4))
if (!char_is_hex(u1) || !char_is_hex(u2) || !char_is_hex(u3) || !char_is_hex(u4))
{
json_error(parser, "Invalid hex in \\u escape sequence.");
return;
}
c = (hex_nibble(u1) << 12) + (hex_nibble(u2) << 8) + (hex_nibble(u3) << 4) + hex_nibble(u4);
c = (char_hex_to_nibble(u1) << 12) + (char_hex_to_nibble(u2) << 8) + (char_hex_to_nibble(u3) << 4) + char_hex_to_nibble(u4);
break;
}
default:

View File

@@ -64,4 +64,4 @@ typedef struct
void json_init_string(JsonParser *parser, const char *str, JsonAllocator *allocator);
JSONObject *json_parse(JsonParser *parser);
JSONObject *json_obj_get(JSONObject *obj, const char *key);
JSONObject *json_obj_get(JSONObject *obj, const char *key);

View File

@@ -11,14 +11,42 @@
#include "direct.h"
#endif
typedef struct StringSlice_
{
const char *ptr;
size_t len;
} StringSlice;
typedef struct
{
int major;
int minor;
} Version;
typedef struct
{
Version macos_deploy_target;
Version macos_min_deploy_target;
} MacSDK;
typedef struct {
char* windows_sdk_um_library_path;
char* windows_sdk_ucrt_library_path;
char* vs_library_path;
} WindowsSDK;
#define MAX_STRING_BUFFER 0x10000
#define COMPILER_SUCCESS_EXIT -1000
NORETURN void exit_compiler(int exit_value);
extern jmp_buf on_err_jump;
extern bool debug_log;
extern bool debug_stats;
extern uintptr_t arena_zero;
struct ScratchBuf { char str[MAX_STRING_BUFFER]; uint32_t len; };
extern struct ScratchBuf scratch_buffer;
NORETURN void exit_compiler(int exit_value);
typedef struct Task_
{
@@ -28,15 +56,20 @@ typedef struct Task_
typedef void *TaskQueueRef;
const char *str_without_suffix(const char *name, const char *suffix);
bool filenamesplit(const char *path, char** filename_ptr, char** directory_ptr);
const char* expand_path(const char* path);
bool file_namesplit(const char *path, char** filename_ptr, char** directory_ptr);
const char* file_expand_path(const char* path);
const char* find_lib_dir(void);
char *read_file(const char *path, size_t *return_size);
void path_get_dir_and_filename_from_full(const char *full_path, char **filename, char **dir_path);
bool file_is_dir(const char *file);
bool file_exists(const char *path);
char *file_read_all(const char *path, size_t *return_size);
void file_get_dir_and_filename_from_full(const char *full_path, char **filename, char **dir_path);
void file_find_top_dir();
bool file_has_suffix_in_list(const char *file_name, int name_len, const char **suffix_list, int suffix_count);
void file_add_wildcard_files(const char ***files, const char *path, bool recursive, const char **suffix_list, int suffix_count);
const char *file_first(const char *path);
const char *file_append_path(const char *path, const char *name);
const char *execute_cmd(const char *cmd);
void *cmalloc(size_t size);
void *ccalloc(size_t size, size_t elements);
void memory_init(void);
@@ -46,7 +79,6 @@ void memory_release();
#define idptr(id_) ((void*)(((uintptr_t)id_) * 16 + arena_zero))
void *calloc_arena(size_t mem);
char *calloc_string(size_t len);
char *copy_string(const char *start, size_t str_len);
#define malloc_string calloc_string
#define malloc_arena calloc_arena
void free_arena(void);
@@ -57,6 +89,78 @@ void taskqueue_add(TaskQueueRef queue, Task *task);
void taskqueue_destroy(TaskQueueRef queue);
void taskqueue_wait_for_completion(TaskQueueRef queue);
const char *str_remove_suffix(const char *name, const char *suffix);
char *str_trim(char *str);
const char *str_trim_start(const char *str);
void str_trim_end(char *str);
char *str_cat(const char *a, const char *b);
// Search a list of strings and return the matching element or -1 if none found.
int str_findlist(const char *value, unsigned count, const char** elements);
// Sprintf style, saved to an arena allocated string
char *str_printf(const char *var, ...) __printflike(1, 2);
char *str_vprintf(const char *var, va_list list);
void str_ellide_in_place(char *string, size_t max_size_shown);
bool str_is_valid_lowercase_name(const char *string);
bool str_has_no_uppercase(const char *string);
char *str_copy(const char *start, size_t str_len);
StringSlice slice_next_token(StringSlice *slice, char separator);
static inline bool slice_strcmp(StringSlice slice, const char *other);
static inline StringSlice slice_from_string(const char *data);
void slice_trim(StringSlice *slice);
void scratch_buffer_clear(void);
void scratch_buffer_append(const char *string);
void scratch_buffer_append_len(const char *string, size_t len);
void scratch_buffer_append_char(char c);
void scratch_buffer_append_signed_int(int64_t i);
UNUSED void scratch_buffer_append_unsigned_int(uint64_t i);
void scratch_buffer_printf(const char *format, ...);
char *scratch_buffer_to_string(void);
char *scratch_buffer_copy(void);
static inline bool is_power_of_two(uint64_t x);
static inline uint32_t next_highest_power_of_2(uint32_t v);
static inline bool char_is_lower(char c);
static inline bool char_is_lower_(char c);
static inline bool char_is_upper(char c);
static inline bool char_is_oct(char c);
static inline bool char_is_oct_or_(char c);
static inline bool char_is_binary(char c);
static inline bool char_is_binary_or_(char c);
static inline bool char_is_digit_or_(char c);
static inline bool char_is_digit(char c);
static inline bool char_is_hex(char c);
static inline bool char_is_hex_or_(char c);
static inline bool char_is_base64(char c);
static inline bool char_is_letter(char c);
static inline bool char_is_letter_(char c);
static inline bool char_is_alphanum_(char c);
static inline bool char_is_lower_alphanum_(char c);
static inline bool char_is_whitespace(char c);
static inline signed char char_is_valid_escape(char c);
// Hex to nibble, -1 if invalid
static inline int char_hex_to_nibble(char c);
static inline char char_nibble_to_hex(int c);
static inline uint32_t fnv1a(const char *key, uint32_t len);
static inline uint32_t vec_size(const void *vec);
static inline void vec_resize(void *vec, uint32_t new_size);
static inline void vec_pop(void *vec);
#define NUMBER_CHAR_CASE '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
#define UPPER_CHAR_CASE 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': \
case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': \
case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z'
#define LOWER_CHAR_CASE 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': \
case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': \
case 'u': case 'v': case 'w': case 'x': case 'y': case 'z'
#define HEX_CHAR_CASE 'a': case 'b': case 'c': case 'd': case 'e': case 'f': \
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F'
#if MEM_PRINT
#define MALLOC(mem) (printf("Alloc at %s %zu\n", __FUNCTION__, (size_t)(mem)), malloc_arena(mem))
#define MALLOCS(type) (printf("calloc at %s %zu\n", __FUNCTION__, sizeof(type)), malloc_arena(sizeof(type)))
@@ -74,297 +178,6 @@ void taskqueue_wait_for_completion(TaskQueueRef queue);
#define CALLOCS(type) calloc_arena(sizeof(type))
#endif
#define NUMBER_CHAR_CASE '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
static inline bool is_power_of_two(uint64_t x)
{
return x != 0 && (x & (x - 1)) == 0;
}
static inline uint32_t next_highest_power_of_2(uint32_t v)
{
v--;
v |= v >> 1U;
v |= v >> 2U;
v |= v >> 4U;
v |= v >> 8U;
v |= v >> 16U;
v++;
return v;
}
static inline bool is_lower(char c)
{
return c >= 'a' && c <= 'z';
}
static inline bool is_lower_(char c)
{
return c == '_' || (c >= 'a' && c <= 'z');
}
static inline bool is_upper(char c)
{
return c >= 'A' && c <= 'Z';
}
static inline bool is_oct(char c)
{
return c >= '0' && c <= '7';
}
static inline bool is_oct_or_(char c)
{
switch (c)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '_':
return true;
default:
return false;
}
}
static inline bool is_binary(char c)
{
return c == '0' || c == '1';
}
static inline bool is_binary_or_(char c)
{
switch (c)
{
case '0': case '1': case '_':
return true;
default:
return false;
}
}
static inline bool is_digit_or_(char c)
{
switch (c)
{
case NUMBER_CHAR_CASE:
case '_':
return true;
default:
return false;
}
}
static inline bool is_digit(char c)
{
return c >= '0' && c <= '9';
}
/**
* Convert hex character to nibble
* @param c
* @return value or -1 if invalid.
*/
static inline int char_to_nibble(char c)
{
char conv[256] = {
['0'] = 1,
['1'] = 2,
['2'] = 3,
['3'] = 4,
['4'] = 5,
['5'] = 6,
['6'] = 7,
['7'] = 8,
['8'] = 9,
['9'] = 10,
['A'] = 11,
['B'] = 12,
['C'] = 13,
['D'] = 14,
['E'] = 15,
['F'] = 16,
['a'] = 11,
['b'] = 12,
['c'] = 13,
['d'] = 14,
['e'] = 15,
['f'] = 16,
};
return conv[(unsigned)c] - 1;
}
static inline bool is_hex_or_(char c)
{
switch (c)
{
case NUMBER_CHAR_CASE:
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f':
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F':
case '_':
return true;
default:
return false;
}
}
static inline signed char is_valid_escape(char c)
{
switch (c)
{
case 'a':
return '\a';
case 'b':
return '\b';
case 'e':
return 0x1B;
case 'f':
return '\f';
case 'n':
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
case 'v':
return '\v';
case 'x':
return 'x';
case 'u':
return 'u';
case 'U':
return 'U';
case '\'':
return '\'';
case '"':
return '"';
case '\\':
return '\\';
case '0':
return '\0';
case 's':
return ' ';
default:
return -1;
}
}
static inline bool is_base64(char c)
{
return (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9')
|| c == '+' || c == '/';
}
static inline bool is_hex(char c)
{
switch (c)
{
case NUMBER_CHAR_CASE:
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f':
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F':
return true;
default:
return false;
}
}
static inline int hex_nibble(char c)
{
static int conv[256] = {
['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4,
['5'] = 5, ['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9,
['A'] = 10, ['B'] = 11, ['C'] = 12, ['D'] = 13, ['E'] = 14, ['F'] = 15,
['a'] = 10, ['b'] = 11, ['c'] = 12, ['d'] = 13, ['e'] = 14, ['f'] = 15,
};
return conv[(unsigned char)c];
}
static inline char nibble_hex(int c)
{
static const char *conv = "0123456789ABCDEF";
return conv[c];
}
static inline bool is_whitespace(char c)
{
switch (c)
{
case ' ':
case '\t':
case '\n':
return true;
case '\r':
UNREACHABLE
default:
return false;
}
}
static inline bool is_alphanum_(char c)
{
switch (c)
{
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'Z':
case NUMBER_CHAR_CASE:
case '_':
return true;
default:
return false;
}
}
static inline bool is_letter(char c)
{
switch (c)
{
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'Z':
return true;
default:
return false;
}
}
INLINE bool is_letter_(char c)
{
return is_letter(c) || c == '_';
}
static inline bool is_number(char c)
{
return c >= '0' && c <= '9';
}
#define FNV1_PRIME 0x01000193u
#define FNV1_SEED 0x811C9DC5u
@@ -396,12 +209,6 @@ static inline VHeader_* vec_new_(size_t element_size, size_t capacity)
return header;
}
static inline uint32_t vec_size(const void *vec)
{
if (!vec) return 0;
const VHeader_ *header = vec;
return header[-1].size;
}
static inline void vec_resize(void *vec, uint32_t new_size)
{
@@ -409,6 +216,7 @@ static inline void vec_resize(void *vec, uint32_t new_size)
VHeader_ *header = vec;
header[-1].size = new_size;
}
static inline void vec_pop(void *vec)
{
assert(vec);
@@ -416,6 +224,7 @@ static inline void vec_pop(void *vec)
VHeader_ *header = vec;
header[-1].size--;
}
static inline void* expand_(void *vec, size_t element_size)
{
VHeader_ *header;
@@ -476,54 +285,6 @@ static inline void* expand_(void *vec, size_t element_size)
#define VECLAST(_vec) (vec_size(_vec) ? (_vec)[vec_size(_vec) - 1] : NULL)
#endif
static inline bool is_all_upper(const char* string)
{
char c;
while ((c = *(string++)) != '\0')
{
if (is_lower(c)) return false;
}
return true;
}
static inline bool is_all_lower(const char* string)
{
char c;
while ((c = *(string++)) != '\0')
{
if (is_upper(c)) return false;
}
return true;
}
#ifndef __printflike
#define __printflike(x, y)
#endif
typedef struct StringSlice_
{
const char *ptr;
size_t len;
} StringSlice;
char *strcat_arena(const char *a, const char *b);
int str_in_list(const char *value, unsigned count, const char** elements);
char *strformat(const char *var, ...) __printflike(1, 2);
StringSlice strnexttok(StringSlice *slice, char separator);
static inline bool slicestrcmp(StringSlice slice, const char *other)
{
if (strlen(other) != slice.len) return false;
return strncmp(slice.ptr, other, slice.len) == 0;
}
static inline StringSlice strtoslice(const char *data)
{
return (StringSlice) { data, strlen(data) };
}
void slicetrim(StringSlice *slice);
#if IS_GCC || IS_CLANG
#define MAX(_a, _b) ({ \
@@ -545,11 +306,258 @@ void slicetrim(StringSlice *slice);
#if PLATFORM_WINDOWS
int asprintf(char **strp, const char *fmt, ...);
int vasprintf(char **strp, const char *fmt, va_list ap);
char *realpath(const char *path, char *resolved_path);
#define mkdir(name, unused) _mkdir(name)
#endif
static inline bool slice_strcmp(StringSlice slice, const char *other)
{
if (strlen(other) != slice.len) return false;
return strncmp(slice.ptr, other, slice.len) == 0;
}
static inline StringSlice slice_from_string(const char *data)
{
return (StringSlice) { data, strlen(data) };
}
static inline uint32_t vec_size(const void *vec)
{
if (!vec) return 0;
const VHeader_ *header = vec;
return header[-1].size;
}
static inline bool is_power_of_two(uint64_t x)
{
return x != 0 && (x & (x - 1)) == 0;
}
static inline uint32_t next_highest_power_of_2(uint32_t v)
{
v--;
v |= v >> 1U;
v |= v >> 2U;
v |= v >> 4U;
v |= v >> 8U;
v |= v >> 16U;
v++;
return v;
}
static inline bool char_is_lower(char c)
{
return c >= 'a' && c <= 'z';
}
static inline bool char_is_lower_(char c)
{
return c == '_' || (c >= 'a' && c <= 'z');
}
static inline bool char_is_upper(char c)
{
return c >= 'A' && c <= 'Z';
}
static inline bool char_is_oct(char c)
{
return c >= '0' && c <= '7';
}
static inline bool char_is_oct_or_(char c)
{
return c == '_' || (c >= '0' && c <= '7');
}
static inline bool char_is_binary(char c)
{
return c == '0' || c == '1';
}
static inline bool char_is_binary_or_(char c)
{
return c == '0' || c == '1' || c == '_';
}
static inline bool char_is_digit_or_(char c)
{
return c == '_' || (c >= '0' && c <= '9');
}
static inline bool char_is_digit(char c)
{
return c >= '0' && c <= '9';
}
static char hex_conv[256] = {
['0'] = 1,
['1'] = 2,
['2'] = 3,
['3'] = 4,
['4'] = 5,
['5'] = 6,
['6'] = 7,
['7'] = 8,
['8'] = 9,
['9'] = 10,
['A'] = 11,
['B'] = 12,
['C'] = 13,
['D'] = 14,
['E'] = 15,
['F'] = 16,
['a'] = 11,
['b'] = 12,
['c'] = 13,
['d'] = 14,
['e'] = 15,
['f'] = 16,
};
static inline int char_hex_to_nibble(char c)
{
return hex_conv[(unsigned)c] - 1;
}
static inline bool char_is_hex_or_(char c)
{
switch (c)
{
case NUMBER_CHAR_CASE:
case HEX_CHAR_CASE:
case '_':
return true;
default:
return false;
}
}
static inline signed char char_is_valid_escape(char c)
{
switch (c)
{
case 'a':
return '\a';
case 'b':
return '\b';
case 'e':
return 0x1B;
case 'f':
return '\f';
case 'n':
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
case 'v':
return '\v';
case 'x':
return 'x';
case 'u':
return 'u';
case 'U':
return 'U';
case '\'':
return '\'';
case '"':
return '"';
case '\\':
return '\\';
case '0':
return '\0';
case 's':
return ' ';
default:
return -1;
}
}
static inline bool char_is_base64(char c)
{
return (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9')
|| c == '+' || c == '/';
}
static inline bool char_is_hex(char c)
{
return hex_conv[(unsigned char)c] != 0;
}
static inline char char_nibble_to_hex(int c)
{
static const char *conv = "0123456789ABCDEF";
return conv[c];
}
static inline bool char_is_whitespace(char c)
{
switch (c)
{
case ' ':
case '\t':
case '\n':
return true;
case '\r':
UNREACHABLE
default:
return false;
}
}
static inline bool char_is_alphanum_(char c)
{
switch (c)
{
case LOWER_CHAR_CASE:
case UPPER_CHAR_CASE:
case NUMBER_CHAR_CASE:
case '_':
return true;
default:
return false;
}
}
static inline bool char_is_lower_alphanum_(char c)
{
switch (c)
{
case LOWER_CHAR_CASE:
case NUMBER_CHAR_CASE:
case '_':
return true;
default:
return false;
}
}
static inline bool char_is_letter(char c)
{
switch (c)
{
case LOWER_CHAR_CASE:
case UPPER_CHAR_CASE:
return true;
default:
return false;
}
}
static inline bool char_is_letter_(char c)
{
switch (c)
{
case LOWER_CHAR_CASE:
case UPPER_CHAR_CASE:
case '_':
return true;
default:
return false;
}
}

View File

@@ -37,13 +37,6 @@ void *calloc_string(size_t len)
return vmem_alloc(&char_arena, len);
}
char *copy_string(const char *start, size_t str_len)
{
char *dst = calloc_string(str_len + 1);
memcpy(dst, start, str_len);
// No need to set the end
return dst;
}
// Simple bump allocator with buckets.
void *calloc_arena(size_t mem)

View File

@@ -8,7 +8,9 @@
#include "lib.h"
#include "stdio.h"
int str_in_list(const char *value, unsigned count, const char** elements)
struct ScratchBuf scratch_buffer;
int str_findlist(const char *value, unsigned count, const char** elements)
{
for (unsigned i = 0; i < count; i++)
{
@@ -17,23 +19,68 @@ int str_in_list(const char *value, unsigned count, const char** elements)
return -1;
}
char *strformat(const char *var, ...)
bool str_has_no_uppercase(const char *string)
{
va_list list;
va_start(list, var);
int len = vsnprintf(NULL, 0, var, list);
va_end(list);
if (len < 1) return "";
va_start(list, var);
char c;
while ((c = *(string++)) != '\0')
{
if (char_is_upper(c)) return false;
}
return true;
}
bool str_is_valid_lowercase_name(const char *string)
{
char c;
// Must start with a lower case
if (!char_is_lower(string[0])) return false;
int length = 0;
while ((c = *(string++)) != '\0')
{
if (!char_is_lower_alphanum_(c)) return false;
if (++length > 127) return false;
}
return true;
}
void str_ellide_in_place(char *string, size_t max_size_shown)
{
size_t len = strlen(string);
if (max_size_shown > len) return;
for (int i = 0; i < 3; i++)
{
string[max_size_shown - i] = '.';
}
string[max_size_shown + 1] = 0;
}
char *str_vprintf(const char *var, va_list list)
{
va_list copy;
va_copy(copy, list);
int len = vsnprintf(NULL, 0, var, copy);
va_end(copy);
if (len < 1)
{
return "";
}
char *buffer = malloc_string((uint32_t)len + 1);
int new_len = vsnprintf(buffer, len + 1, var, list);
va_end(list);
assert(len == new_len);
(void)new_len;
return buffer;
}
const char *str_without_suffix(const char *name, const char *suffix)
char *str_printf(const char *var, ...)
{
va_list list;
va_start(list, var);
char *res = str_vprintf(var, list);
va_end(list);
return res;
}
const char *str_remove_suffix(const char *name, const char *suffix)
{
size_t name_len = strlen(name);
size_t suffix_len = strlen(suffix);
@@ -47,7 +94,7 @@ const char *str_without_suffix(const char *name, const char *suffix)
}
StringSlice strnexttok(StringSlice *slice, char separator)
StringSlice slice_next_token(StringSlice *slice, char separator)
{
for (size_t i = 0; i < slice->len; i++)
{
@@ -65,7 +112,7 @@ StringSlice strnexttok(StringSlice *slice, char separator)
return result;
}
void slicetrim(StringSlice *slice)
void slice_trim(StringSlice *slice)
{
size_t i;
for (i = 0; i < slice->len; i++)
@@ -81,9 +128,54 @@ void slicetrim(StringSlice *slice)
slice->len = i;
}
char *str_trim(char *str)
{
str_trim_end(str);
return (char *)str_trim_start(str);
}
const char *str_trim_start(const char *str)
{
while (str[0] != 0)
{
switch (str[0])
{
case ' ':
case '\t':
case '\n':
case '\r':
str++;
continue;
default:
break;
}
break;
}
return str;
}
char *strcat_arena(const char *a, const char *b)
void str_trim_end(char *str)
{
size_t len = strlen(str);
char *end = str + len - 1;
while (len > 0)
{
switch (*end)
{
case ' ':
case '\t':
case '\n':
case '\r':
len--;
end--;
continue;
default:
end[1] = 0;
return;
}
}
}
char *str_cat(const char *a, const char *b)
{
unsigned a_len = (unsigned)strlen(a);
unsigned b_len = (unsigned)strlen(b);
@@ -94,46 +186,86 @@ char *strcat_arena(const char *a, const char *b)
return buffer;
}
#if PLATFORM_WINDOWS
char *str_copy(const char *start, size_t str_len)
{
char *dst = calloc_string(str_len + 1);
memcpy(dst, start, str_len);
// No need to set the end
return dst;
}
int asprintf(char **strp, const char *fmt, ...)
void scratch_buffer_clear(void)
{
scratch_buffer.len = 0;
}
void scratch_buffer_append_len(const char *string, size_t len)
{
if (len + scratch_buffer.len > MAX_STRING_BUFFER - 1)
{
error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1);
}
memcpy(scratch_buffer.str + scratch_buffer.len, string, len);
scratch_buffer.len += (uint32_t)len;
}
void scratch_buffer_append(const char *string)
{
scratch_buffer_append_len(string, strlen(string));
}
void scratch_buffer_append_signed_int(int64_t i)
{
uint32_t len_needed = (uint32_t)sprintf(&scratch_buffer.str[scratch_buffer.len], "%lld", (long long)i);
if (scratch_buffer.len + len_needed > MAX_STRING_BUFFER - 1)
{
error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1);
}
scratch_buffer.len += len_needed;
}
void scratch_buffer_append_unsigned_int(uint64_t i)
{
uint32_t len_needed = (uint32_t)sprintf(&scratch_buffer.str[scratch_buffer.len], "%llu", (unsigned long long)i);
if (scratch_buffer.len + len_needed > MAX_STRING_BUFFER - 1)
{
error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1);
}
scratch_buffer.len += len_needed;
}
void scratch_buffer_printf(const char *format, ...)
{
va_list args;
va_start(args, fmt);
int res = vasprintf(strp, fmt, args);
va_start(args, format);
uint32_t len_needed = (uint32_t)vsprintf(&scratch_buffer.str[scratch_buffer.len], format, args);
if (scratch_buffer.len + len_needed > MAX_STRING_BUFFER - 1)
{
error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1);
}
va_end(args);
return res;
scratch_buffer.len += len_needed;
}
int vasnprintf(char **strp, const char *fmt, va_list args)
void scratch_buffer_append_char(char c)
{
va_list args_copy;
va_copy(args_copy, args);
int res = vsprintf(NULL, fmt, args);
if (res < 0) goto END;
char *buf = ccalloc(res + 1, 1);
if (NULL == buf) goto END;
sprintf(buf, fmt, args_copy); // this can't fail, right?
*strp = buf;
END:
va_end(args_copy);
return res;
if (scratch_buffer.len + 1 > MAX_STRING_BUFFER - 1)
{
error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1);
}
scratch_buffer.str[scratch_buffer.len++] = c;
}
int vasprintf(char** ret, const char* fmt, va_list args) {
int length = _vsnprintf(NULL, 0, fmt, args);
if (length < 0) { // check if _vsnprintf failed
return -1;
}
*ret = cmalloc(length + 1);
if (!*ret) { // check if malloc failed
return -1;
}
// Write String
_vsnprintf(*ret, length + 1, fmt, args);
(*ret)[length] = '\0'; // make sure there is a null terminator
return length;
char *scratch_buffer_to_string(void)
{
scratch_buffer.str[scratch_buffer.len] = '\0';
return scratch_buffer.str;
}
char *scratch_buffer_copy(void)
{
return str_copy(scratch_buffer.str, scratch_buffer.len);
}
#endif

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.1.1"
#define COMPILER_VERSION "0.1.2"

View File

@@ -1,4 +1,4 @@
// #target: aarch64-darwin
// #target: macos-aarch64
module test;
struct Large {

View File

@@ -1,4 +1,4 @@
// #target: aarch64-darwin
// #target: macos-aarch64
module test;
define Int8x16 = ichar[<16>];
define Float32x3 = float[<3>];

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
// #opt: --x86vec=avx
module test;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
// #opt: --x86vec=avx512
module test;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
// #opt: --x86vec=sse
module test;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;
fn char f0() {

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;
struct St12

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
struct Test
{

View File

@@ -1,4 +1,4 @@
// #target: aarch64-linux
// #target: linux-aarch64
module literal_load;
struct Test

View File

@@ -1,4 +1,4 @@
// #target: x64-mingw
// #target: mingw-x64
module literal_load;
struct Test

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
int foo @section("foo, 12345678901234567 "); // #error: Mach-o requires the section to be at the most 16 characters
int bar @section("foo, "); // #error: Mach-o requires 'segment,section' as the format, did you type it correctly?

View File

@@ -1,4 +1,4 @@
// #target: aarch64-linux
// #target: linux-aarch64
module pass_large;

View File

@@ -1,4 +1,4 @@
// #target: x64-mingw
// #target: mingw-x64
module test;
extern fn void printf(char*, ...);
@@ -21,12 +21,12 @@ fn int main()
%Foo = type { [2 x float] }
@Foo = linkonce_odr constant i8 1
$introspect.Foo = comdat any
@introspect.Foo = linkonce constant i8 1
; Function Attrs: nounwind
declare void @printf(i8*, ...) #0
; Function Attrs: nounwind
define x86_regcallcc void @test.test(float %0, float %1) #0 {
entry:
%x = alloca %Foo, align 4

View File

@@ -1,4 +1,4 @@
// #target: riscv64-linux
// #target: linux-riscv64
module test;
struct Large {

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;
struct Foo
{

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
struct Abc {
long a;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module unionx64;

View File

@@ -1,4 +1,4 @@
// #target: aarch64-linux
// #target: linux-aarch64
module abi;
struct Vector2 {

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module abi;
struct Vector2 {

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;
extern fn void test1_f(void *);

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module array_casts;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module array_literal;
fn double test(uint x)

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;
struct Foo

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;
struct Connection

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;

View File

@@ -1,4 +1,4 @@
// #target: x64-windows
// #target: windows-x64
fn int foo()
{

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;
module foo;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;
fn int foo(double b)

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;
struct Foo { int x, y; }

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;
fn int strcmp(char *s1, char *s2);

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;
extern fn int printf(char *, ...);
extern fn int foo();

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;
char[8192] stack;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module foo;
int x1 = 2 ^ 4;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;
extern fn void printf(char*, ...);

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;
extern fn void printf(char*, ...);

View File

@@ -1,4 +1,4 @@
// #target: x64-darwin
// #target: macos-x64
module test;

Some files were not shown because too many files have changed in this diff Show More