Add no-entry to project/command line. Add "link-args" to project. Add @wasm and @extern attributes. Added $$wasm_memory_size and $$wasm_memory_grow builtins.

This commit is contained in:
Christoffer Lerno
2023-01-26 11:46:38 +01:00
committed by Christoffer Lerno
parent 39801a304d
commit a95710c93f
18 changed files with 153 additions and 19 deletions

View File

@@ -178,4 +178,33 @@ fn void ArenaAllocator.init(ArenaAllocator* this, char[] data)
fn void ArenaAllocator.reset(ArenaAllocator* this)
{
this.used = 0;
}
const usz WASM_BLOCK_SIZE = 65536;
WasmMemory wasm_memory;
struct WasmMemory
{
usz allocation;
uptr use;
}
fn void*! WasmMemory.allocate_block(WasmMemory* this, usz bytes)
{
if (!this.allocation)
{
this.allocation = $$wasm_memory_size(0) * WASM_BLOCK_SIZE;
}
isz bytes_required = bytes + this.use - this.allocation;
if (bytes_required <= 0)
{
defer this.use += bytes;
return (void*)this.use;
}
usz blocks_required = (bytes_required + WASM_BLOCK_SIZE + 1) / WASM_BLOCK_SIZE;
if (!$$wasm_memory_grow(0, blocks_required)) return AllocationFailure.OUT_OF_MEMORY!;
this.allocation = $$wasm_memory_size(0) * WASM_BLOCK_SIZE;
defer this.use += bytes;
return (void*)this.use;
}

View File

@@ -83,6 +83,7 @@ static void usage(void)
OUTPUT(" --stdlib <dir> - Use this directory as the C3 standard library path.");
OUTPUT(" --nostdlib - Do not include the standard library.");
OUTPUT(" --nolibc - Do not implicitly link libc nor any associated files.");
OUTPUT(" --no-entry - Do not generate (or require) a main function.");
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.");
@@ -658,6 +659,10 @@ static void parse_option(BuildOptions *options)
options->print_output = true;
return;
}
if (match_longopt("no-entry"))
{
options->no_entry = true;
}
if (match_longopt("cc"))
{
if (at_end() || next_is_opt()) error_exit("error: --cc needs a compiler name.");

View File

@@ -271,6 +271,7 @@ typedef struct BuildOptions_
bool emit_bitcode;
bool test_mode;
bool no_stdlib;
bool no_entry;
bool no_libc;
bool force_linker;
bool read_stdin;
@@ -361,6 +362,7 @@ typedef struct
bool testing;
bool read_stdin;
bool print_output;
bool no_entry;
int build_threads;
OptimizationLevel optimization_level;
SizeOptimizationLevel size_optimization_level;

View File

@@ -220,6 +220,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
}
if (options->no_stdlib) target->no_stdlib = true;
if (options->no_libc) target->no_libc = true;
if (options->no_entry) target->no_entry = true;
target->print_output = options->print_output;
target->emit_llvm = options->emit_llvm;
target->build_threads = options->build_threads;

View File

@@ -17,8 +17,10 @@ const char *project_default_keys[] = {
"langrev",
"dependency-search-paths",
"dependencies",
"link-args",
"linked-libraries",
"macossdk",
"no-entry",
"nolibc",
"nostdlib",
"panicfn",
@@ -50,11 +52,15 @@ const char* project_target_keys[] = {
"c-sources-override",
"debug-info",
"langrev",
"nolibc",
"no-entry",
"dependency-search-paths-add",
"dependency-search-paths-override",
"dependencies-add",
"dependencies-override",
"linked-libraries",
"link-args-override",
"link-args-add",
"macossdk",
"nolibc",
"nostdlib",
@@ -245,7 +251,6 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
target->cflags = cflags_add;
}
}
// C source dirs.
target_append_strings(json, type, &target->csource_dirs, "c-sources", "c-sources-override", "c-sources-add", is_default);
@@ -258,6 +263,9 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
// linker-search-paths libs dir - libraries to add at link time
target_append_strings(json, type, &target->linker_libdirs, "linker-search-paths", "linker-search-paths-override", "linker-search-paths-add", is_default);
// link-args - link args to add at link time
target_append_strings(json, type, &target->link_args, "link-args", "link-args-override", "link-args-add", is_default);
// dependency-search-paths - path to search for libraries
target_append_strings(json, type, &target->libdirs, "dependency-search-paths", "dependency-search-paths-override", "dependency-search-paths-add", is_default);
@@ -309,6 +317,7 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
int reloc = get_valid_string_setting(json, "reloc", type, reloc_models, 0, 5, "'none', 'pic', 'PIC', 'pie' or 'PIE'.");
if (reloc > -1) target->reloc_model = (RelocModel)reloc;
// Cpu
const char *cpu = get_valid_string(json, "cpu", type, false);
if (cpu) target->cpu = cpu;
@@ -348,6 +357,9 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
// nolibc
target->no_libc = get_valid_bool(json, "nolibc", type, target->no_libc);
// no-entry
target->no_entry = get_valid_bool(json, "no-entry", type, target->no_entry);
// nostdlib
target->no_stdlib = get_valid_bool(json, "nostdlib", type, target->no_stdlib);

View File

@@ -149,11 +149,11 @@ void **tilde_gen(Module** modules, unsigned module_count)
static const char *exe_name(void)
{
assert(global_context.main);
assert(global_context.main || active_target.no_entry);
const char *name;
if (active_target.name)
if (active_target.name || active_target.no_entry)
{
name = active_target.name;
name = active_target.name ? active_target.name : "out";
}
else
{
@@ -350,7 +350,7 @@ void compiler_compile(void)
output_exe = exe_name();
break;
case TARGET_TYPE_EXECUTABLE:
if (!global_context.main)
if (!global_context.main && !active_target.no_entry)
{
puts("No main function was found, compilation only object files are generated.");
}

View File

@@ -673,6 +673,7 @@ typedef struct Decl_
bool obfuscate : 1;
bool is_dynamic : 1;
bool is_synthetic : 1;
bool is_wasm_export : 1;
OperatorOverload operator : 4;
union
{
@@ -2299,6 +2300,7 @@ void codegen_setup_object_names(Module *module, const char **ir_filename, const
void target_setup(BuildTarget *build_target);
int target_alloca_addr_space();
bool os_is_apple(OsType os_type);
bool arch_is_wasm(ArchType type);
const char *macos_sysroot(void);
MacSDK *macos_sysroot_sdk_information(const char *sdk_path);

View File

@@ -762,6 +762,7 @@ typedef enum
ATTRIBUTE_BIGENDIAN,
ATTRIBUTE_BUILTIN,
ATTRIBUTE_CDECL,
ATTRIBUTE_EXTERN,
ATTRIBUTE_EXTNAME,
ATTRIBUTE_FASTCALL,
ATTRIBUTE_INLINE,
@@ -785,6 +786,7 @@ typedef enum
ATTRIBUTE_UNUSED,
ATTRIBUTE_USED,
ATTRIBUTE_VECCALL,
ATTRIBUTE_WASM,
ATTRIBUTE_WEAK,
ATTRIBUTE_NONE,
NUMBER_OF_ATTRIBUTES = ATTRIBUTE_NONE,
@@ -898,6 +900,8 @@ typedef enum
BUILTIN_VECCOMPNE,
BUILTIN_VOLATILE_LOAD,
BUILTIN_VOLATILE_STORE,
BUILTIN_WASM_MEMORY_SIZE,
BUILTIN_WASM_MEMORY_GROW,
BUILTIN_NONE,
NUMBER_OF_BUILTINS = BUILTIN_NONE,

View File

@@ -461,9 +461,11 @@ static bool linker_setup(const char ***args_ref, const char **files_to_link, uns
if (use_win)
{
add_arg2("/OUT:", output_file);
if (active_target.no_entry) add_arg("/NOENTRY");
}
else
{
if (active_target.no_entry) add_arg("--no-entry");
add_arg("-o");
add_arg(output_file);
}

View File

@@ -711,6 +711,8 @@ static void llvm_codegen_setup()
intrinsic_id.vector_reduce_and = lookup_intrinsic("llvm.vector.reduce.and");
intrinsic_id.vector_reduce_or = lookup_intrinsic("llvm.vector.reduce.or");
intrinsic_id.vector_reduce_xor = lookup_intrinsic("llvm.vector.reduce.xor");
intrinsic_id.wasm_memory_grow = lookup_intrinsic("llvm.wasm.memory.grow");
intrinsic_id.wasm_memory_size = lookup_intrinsic("llvm.wasm.memory.size");
attribute_id.align = lookup_attribute("align");
attribute_id.alwaysinline = lookup_attribute("alwaysinline");

View File

@@ -429,6 +429,23 @@ void llvm_emit_simple_builtin(GenContext *c, BEValue *be_value, Expr *expr, unsi
llvm_value_set(be_value, result, expr->type);
}
void llvm_emit_builtin_args_types3(GenContext *c, BEValue *be_value, Expr *expr, unsigned intrinsic, Type *type1, Type *type2, Type *type3)
{
Expr **args = expr->call_expr.arguments;
unsigned count = vec_size(args);
assert(count <= 3);
assert(count > 0);
LLVMValueRef arg_slots[3];
llvm_emit_intrinsic_args(c, args, arg_slots, count);
LLVMTypeRef call_type[3];
unsigned type_slots = 0;
if (type1) call_type[type_slots++] = llvm_get_type(c, type1);
if (type2) call_type[type_slots++] = llvm_get_type(c, type2);
if (type3) call_type[type_slots++] = llvm_get_type(c, type3);
LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic, call_type, type_slots, arg_slots, count);
llvm_value_set(be_value, result, expr->type);
}
static void llvm_emit_overflow_builtin(GenContext *c, BEValue *be_value, Expr *expr, unsigned intrinsic_signed, unsigned intrinsic_unsigned)
{
Expr **args = expr->call_expr.arguments;
@@ -793,6 +810,24 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
llvm_value_set(result_value, llvm_emit_call_intrinsic(c, intrinsic_id.set_rounding, NULL, 0, arg_slots, 1), type_void);
}
return;
case BUILTIN_WASM_MEMORY_GROW:
// -1 on non-wasm
if (!arch_is_wasm(platform_target.arch))
{
llvm_value_set(result_value, llvm_const_int(c, expr->type, -1), expr->type);
return;
}
llvm_emit_builtin_args_types3(c, result_value, expr, intrinsic_id.wasm_memory_grow, expr->type, NULL, NULL);
return;
case BUILTIN_WASM_MEMORY_SIZE:
if (!arch_is_wasm(platform_target.arch))
{
// 0 (no mem) on non-wasm.
llvm_value_set(result_value, llvm_const_int(c, expr->type, 0), expr->type);
return;
}
llvm_emit_builtin_args_types3(c, result_value, expr, intrinsic_id.wasm_memory_size, expr->type, NULL, NULL);
return;
case BUILTIN_SIN:
llvm_emit_simple_builtin(c, result_value, expr, intrinsic_id.sin);
return;

View File

@@ -714,6 +714,10 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
{
llvm_attribute_add(c, function, attribute_id.noreturn, -1);
}
if (decl->is_wasm_export && arch_is_wasm(platform_target.arch))
{
llvm_attribute_add_string(c, function, "wasm-export-name", decl_get_extname(decl), -1);
}
if (decl->alignment != type_abi_alignment(decl->type))
{
llvm_set_alignment(function, decl->alignment);

View File

@@ -198,6 +198,8 @@ typedef struct
unsigned vector_reduce_and;
unsigned vector_reduce_or;
unsigned vector_reduce_xor;
unsigned wasm_memory_size;
unsigned wasm_memory_grow;
} LLVMIntrinsics;
extern LLVMIntrinsics intrinsic_id;
@@ -221,7 +223,6 @@ typedef struct
unsigned sret; // struct return pointer
unsigned writeonly; // No writes on pointer
unsigned zext; // zero extend
} LLVMAttributes;
extern LLVMAttributes attribute_id;

View File

@@ -456,6 +456,15 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
arg_count)) return false;
rtype = args[0]->type;
break;
case BUILTIN_WASM_MEMORY_SIZE:
if (!cast_implicit(context, args[0], type_uint)) return false;
rtype = type_uptr;
break;
case BUILTIN_WASM_MEMORY_GROW:
if (!cast_implicit(context, args[0], type_uint)) return false;
if (!cast_implicit(context, args[1], type_uptr)) return false;
rtype = type_iptr;
break;
case BUILTIN_PREFETCH:
if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_POINTER, BA_INTEGER, BA_INTEGER }, arg_count)) return false;
for (unsigned i = 1; i < 3; i++)
@@ -635,6 +644,7 @@ static inline unsigned builtin_expected_args(BuiltinFunction func)
case BUILTIN_REDUCE_MAX:
case BUILTIN_REDUCE_MIN:
case BUILTIN_SET_ROUNDING_MODE:
case BUILTIN_WASM_MEMORY_SIZE:
return 1;
case BUILTIN_COPYSIGN:
case BUILTIN_EXACT_ADD:
@@ -658,6 +668,7 @@ static inline unsigned builtin_expected_args(BuiltinFunction func)
case BUILTIN_VECCOMPGE:
case BUILTIN_VECCOMPGT:
case BUILTIN_VECCOMPEQ:
case BUILTIN_WASM_MEMORY_GROW:
return 2;
case BUILTIN_FMA:
case BUILTIN_FSHL:

View File

@@ -1442,6 +1442,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
[ATTRIBUTE_BUILTIN] = ATTR_MACRO | ATTR_FUNC,
[ATTRIBUTE_CDECL] = ATTR_FUNC,
[ATTRIBUTE_EXTNAME] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_MACRO | ATTR_XXLIZER),
[ATTRIBUTE_EXTERN] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_MACRO | ATTR_XXLIZER),
[ATTRIBUTE_FASTCALL] = ATTR_FUNC,
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL,
[ATTRIBUTE_LITTLEENDIAN] = ATTR_BITSTRUCT,
@@ -1465,6 +1466,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
[ATTRIBUTE_USED] = (AttributeDomain)~(ATTR_CALL | ATTR_XXLIZER ),
[ATTRIBUTE_VECCALL] = ATTR_FUNC,
[ATTRIBUTE_WEAK] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL,
[ATTRIBUTE_WASM] = ATTR_FUNC,
};
if ((attribute_domain[type] & domain) != domain)
@@ -1590,10 +1592,11 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
return true;
}
case ATTRIBUTE_SECTION:
case ATTRIBUTE_EXTERN:
case ATTRIBUTE_EXTNAME:
if (context->unit->module->is_generic)
{
sema_error_at(attr->span, "'extname' attributes are not allowed in generic modules.");
sema_error_at(attr->span, "'%s' attributes are not allowed in generic modules.", attr->name);
return false;
}
if (!expr)
@@ -1607,15 +1610,19 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
SEMA_ERROR(expr, "Expected a constant string value as argument.");
return false;
}
if (type == ATTRIBUTE_SECTION)
switch (type)
{
if (!sema_check_section(context, attr)) return false;
decl->section = expr->const_expr.string.chars;
}
else
{
decl->has_extname = true;
decl->extname = expr->const_expr.string.chars;
case ATTRIBUTE_SECTION:
if (!sema_check_section(context, attr)) return false;
decl->section = expr->const_expr.string.chars;
break;
case ATTRIBUTE_EXTNAME:
case ATTRIBUTE_EXTERN:
decl->has_extname = true;
decl->extname = expr->const_expr.string.chars;
break;
default:
UNREACHABLE;
}
return true;
case ATTRIBUTE_NOINLINE:
@@ -1638,6 +1645,9 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
case ATTRIBUTE_WEAK:
decl->is_weak = true;
break;
case ATTRIBUTE_WASM:
decl->is_wasm_export = true;
break;
case ATTRIBUTE_NAKED:
assert(domain == ATTR_FUNC);
decl->func_decl.attr_naked = true;
@@ -1939,8 +1949,12 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl)
return false;
}
if (active_target.type == TARGET_TYPE_TEST) return true;
Decl *function;
if (active_target.no_entry)
{
function = decl;
goto REGISTER_MAIN;
}
if (!subarray_param && is_int_return)
{
// Int return is pass-through at the moment.

View File

@@ -259,6 +259,8 @@ void symtab_init(uint32_t capacity)
builtin_list[BUILTIN_UNREACHABLE] = KW_DEF("unreachable");
builtin_list[BUILTIN_VOLATILE_LOAD] = KW_DEF("volatile_load");
builtin_list[BUILTIN_VOLATILE_STORE] = KW_DEF("volatile_store");
builtin_list[BUILTIN_WASM_MEMORY_GROW] = KW_DEF("wasm_memory_grow");
builtin_list[BUILTIN_WASM_MEMORY_SIZE] = KW_DEF("wasm_memory_size");
for (unsigned i = 0; i < NUMBER_OF_BUILTINS; i++)
{
@@ -289,6 +291,7 @@ void symtab_init(uint32_t capacity)
attribute_list[ATTRIBUTE_BIGENDIAN] = KW_DEF("@bigendian");
attribute_list[ATTRIBUTE_BUILTIN] = KW_DEF("@builtin");
attribute_list[ATTRIBUTE_CDECL] = KW_DEF("@cdecl");
attribute_list[ATTRIBUTE_EXTERN] = KW_DEF("@extern");
attribute_list[ATTRIBUTE_EXTNAME] = KW_DEF("@extname");
attribute_list[ATTRIBUTE_FASTCALL] = KW_DEF("@fastcall");
attribute_list[ATTRIBUTE_INLINE] = KW_DEF("@inline");
@@ -312,6 +315,7 @@ void symtab_init(uint32_t capacity)
attribute_list[ATTRIBUTE_UNUSED] = KW_DEF("@unused");
attribute_list[ATTRIBUTE_USED] = KW_DEF("@used");
attribute_list[ATTRIBUTE_VECCALL] = KW_DEF("@veccall");
attribute_list[ATTRIBUTE_WASM] = KW_DEF("@wasm");
attribute_list[ATTRIBUTE_WEAK] = KW_DEF("@weak");
for (unsigned i = 0; i < NUMBER_OF_ATTRIBUTES; i++)

View File

@@ -207,6 +207,11 @@ bool os_is_apple(OsType os_type)
os_type == OS_TYPE_MACOSX || os_type == OS_TYPE_IOS;
}
bool arch_is_wasm(ArchType type)
{
return type == ARCH_TYPE_WASM32 || type == ARCH_TYPE_WASM64;
}
static AlignSize os_arch_max_alignment_of_vector(OsType os, ArchType arch, EnvironmentType type, ARMVariant variant)
{
switch (arch)
@@ -903,7 +908,7 @@ static ObjectFormatType object_format_from_os(OsType os, ArchType arch_type)
return OBJ_FORMAT_UNSUPPORTED;
case OS_TYPE_UNKNOWN:
case OS_TYPE_NONE:
if (arch_type == ARCH_TYPE_WASM64 || arch_type == ARCH_TYPE_WASM32) return OBJ_FORMAT_WASM;
if (arch_is_wasm(arch_type)) return OBJ_FORMAT_WASM;
FALLTHROUGH;
case OS_TYPE_LINUX:
case OS_TYPE_NETBSD:
@@ -927,8 +932,9 @@ static unsigned os_target_supports_int128(OsType os, ArchType arch)
switch (arch)
{
case ARCH_TYPE_RISCV64:
return true;
case ARCH_TYPE_AARCH64:
case ARCH_TYPE_WASM32:
case ARCH_TYPE_WASM64:
return true;
case ARCH_TYPE_PPC:
default:

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.22"
#define COMPILER_VERSION "0.4.23"