Fixes to wasm and function attributes.

This commit is contained in:
Christoffer Lerno
2023-01-28 00:37:46 +01:00
parent 445239b418
commit 9a08c9d821
14 changed files with 200 additions and 114 deletions

View File

@@ -59,7 +59,63 @@ enum OsType
EMSCRIPTEN,
}
enum ArchType
{
UNKNOWN,
ARM, // ARM (little endian): arm, armv.*, xscale
ARMB, // ARM (big endian): armeb
AARCH64, // AArch64 (little endian): aarch64
AARCH64_BE, // AArch64 (big endian): aarch64_be
AARCH64_32, // AArch64 (little endian) ILP32: aarch64_32
ARC, // ARC: Synopsys ARC
AVR, // AVR: Atmel AVR microcontroller
BPFEL, // eBPF or extended BPF or 64-bit BPF (little endian)
BPFEB, // eBPF or extended BPF or 64-bit BPF (big endian)
HEXAGON, // Hexagon: hexagon
MIPS, // MIPS: mips, mipsallegrex, mipsr6
MIPSEL, // MIPSEL: mipsel, mipsallegrexe, mipsr6el
MIPS64, // MIPS64: mips64, mips64r6, mipsn32, mipsn32r6
MIPS64EL, // MIPS64EL: mips64el, mips64r6el, mipsn32el, mipsn32r6el
MSP430, // MSP430: msp430
PPC, // PPC: powerpc
PPC64, // PPC64: powerpc64, ppu
PPC64LE, // PPC64LE: powerpc64le
R600, // R600: AMD GPUs HD2XXX - HD6XXX
AMDGCN, // AMDGCN: AMD GCN GPUs
RISCV32, // RISC-V (32-bit): riscv32
RISCV64, // RISC-V (64-bit): riscv64
SPARC, // Sparc: sparc
SPARCV9, // Sparcv9: Sparcv9
SPARCEL, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant
SYSTEMZ, // SystemZ: s390x
TCE, // TCE (http://tce.cs.tut.fi/): tce
TCELE, // TCE little endian (http://tce.cs.tut.fi/): tcele
THUMB, // Thumb (little endian): thumb, thumbv.*
THUMBEB, // Thumb (big endian): thumbeb
X86, // X86: i[3-9]86
X86_64, // X86-64: amd64, x86_64
XCORE, // XCore: xcore
NVPTX, // NVPTX: 32-bit
NVPTX64, // NVPTX: 64-bit
LE32, // le32: generic little-endian 32-bit CPU (PNaCl)
LE64, // le64: generic little-endian 64-bit CPU (PNaCl)
AMDIL, // AMDIL
AMDIL64, // AMDIL with 64-bit pointers
HSAIL, // AMD HSAIL
HSAIL64, // AMD HSAIL with 64-bit pointers
SPIR, // SPIR: standard portable IR for OpenCL 32-bit version
SPIR64, // SPIR: standard portable IR for OpenCL 64-bit version
KALIMBA, // Kalimba: generic kalimba
SHAVE, // SHAVE: Movidius vector VLIW processors
LANAI, // Lanai: Lanai 32-bit
WASM32, // WebAssembly with 32-bit pointers
WASM64, // WebAssembly with 64-bit pointers
RSCRIPT32, // 32-bit RenderScript
RSCRIPT64, // 64-bit RenderScript
}
const OsType OS_TYPE = (OsType)$$OS_TYPE;
const ArchType ARCH_TYPE = (ArchType)$$ARCH_TYPE;
const bool COMPILER_LIBC_AVAILABLE = $$COMPILER_LIBC_AVAILABLE;
const CompilerOptLevel COMPILER_OPT_LEVEL = (CompilerOptLevel)$$COMPILER_OPT_LEVEL;
const bool BIG_ENDIAN = $$PLATFORM_BIG_ENDIAN;

View File

@@ -294,6 +294,15 @@ macro Allocator* current_allocator()
return thread_allocator;
}
$if (!env::COMPILER_LIBC_AVAILABLE && env::ARCH_TYPE == ArchType.WASM32 || env::ARCH_TYPE == ArchType.WASM64):
private SimpleHeapAllocator wasm_allocator;
static initialize @priority(1)
{
allocator::wasm_memory.allocate_block(allocator::DEFAULT_MEM_ALIGNMENT)!!; // Give us a valid null.
wasm_allocator.init(fn (x) => allocator::wasm_memory.allocate_block(x));
thread_allocator = &wasm_allocator;
}
$endif;

View File

@@ -190,7 +190,7 @@ struct WasmMemory
uptr use;
}
fn void*! WasmMemory.allocate_block(WasmMemory* this, usz bytes)
fn char[]! WasmMemory.allocate_block(WasmMemory* this, usz bytes)
{
if (!this.allocation)
{
@@ -200,11 +200,12 @@ fn void*! WasmMemory.allocate_block(WasmMemory* this, usz bytes)
if (bytes_required <= 0)
{
defer this.use += bytes;
return (void*)this.use;
return ((char*)this.use)[:bytes];
}
usz blocks_required = (bytes_required + WASM_BLOCK_SIZE + 1) / WASM_BLOCK_SIZE;
if (!$$wasm_memory_grow(0, blocks_required)) return AllocationFailure.OUT_OF_MEMORY!;
if ($$wasm_memory_grow(0, blocks_required) == -1) return AllocationFailure.OUT_OF_MEMORY!;
this.allocation = $$wasm_memory_size(0) * WASM_BLOCK_SIZE;
defer this.use += bytes;
return (void*)this.use;
return ((char*)this.use)[:bytes];
}

View File

@@ -2,12 +2,12 @@ module std::math::nolibc;
$if (!env::COMPILER_LIBC_AVAILABLE):
fn float powf_broken(float x) @extname("powf") @weak
fn float powf_broken(float x, float f) @extname("powf") @weak
{
unreachable("'powf' not supported");
}
fn float pow_broken(float x) @extname("pow") @weak
fn double pow_broken(double x, double y) @extname("pow") @weak
{
unreachable("'pow' not supported");
}

View File

@@ -96,4 +96,14 @@ fn bool TestRunner.run(TestRunner* runner)
fn bool __run_default_test_runner()
{
return test_runner_create().run();
}
}
$if (!env::COMPILER_LIBC_AVAILABLE && env::ARCH_TYPE == ArchType.WASM32 || env::ARCH_TYPE == ArchType.WASM64):
extern fn void __wasm_call_ctors();
fn void wasm_initialize() @extname("_initialize") @wasm
{
// The linker synthesizes this to call constructors.
__wasm_call_ctors();
}
$endif;

View File

@@ -773,6 +773,7 @@ void compile()
setup_bool_define("PLATFORM_I128_SUPPORTED", platform_target.int128);
setup_bool_define("PLATFORM_F128_SUPPORTED", platform_target.float128);
setup_bool_define("PLATFORM_F16_SUPPORTED", platform_target.float16);
setup_int_define("ARCH_TYPE", (uint64_t)platform_target.arch, type_int);
setup_int_define("MEMORY_ENVIRONMENT", (uint64_t)active_target.memory_environment, type_int);
setup_bool_define("COMPILER_LIBC_AVAILABLE", !active_target.no_libc);
setup_int_define("COMPILER_OPT_LEVEL", (uint64_t)active_target.optimization_level, type_int);

View File

@@ -673,7 +673,7 @@ typedef struct Decl_
bool obfuscate : 1;
bool is_dynamic : 1;
bool is_synthetic : 1;
bool is_wasm_export : 1;
bool is_wasm_interface : 1;
OperatorOverload operator : 4;
union
{

View File

@@ -407,6 +407,7 @@ static void linker_setup_linux(const char ***args_ref, LinkerType linker_type)
add_arg("--dynamic-linker=/lib64/ld-linux-x86-64.so.2");
add_arg("-lc");
add_arg("-lm");
add_arg("-lpthread");
add_arg("-L/usr/lib/");
add_arg("-L/lib/");
add_arg("-m");
@@ -636,10 +637,6 @@ static bool link_exe(const char *output_file, const char **files_to_link, unsign
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.

View File

@@ -947,6 +947,107 @@ LLVMValueRef llvm_get_opt_ref(GenContext *c, Decl *decl)
return decl->var.optional_ref;
}
static void llvm_emit_param_attributes(GenContext *c, LLVMValueRef function, ABIArgInfo *info, bool is_return, int index, int last_index)
{
assert(last_index == index || info->kind == ABI_ARG_DIRECT_PAIR || info->kind == ABI_ARG_IGNORE
|| info->kind == ABI_ARG_EXPAND || info->kind == ABI_ARG_DIRECT || info->kind == ABI_ARG_DIRECT_COERCE
|| info->kind == ABI_ARG_DIRECT_COERCE_INT
|| info->kind == ABI_ARG_DIRECT_SPLIT_STRUCT);
if (info->attributes.zeroext)
{
// Direct only
assert(index == last_index);
llvm_attribute_add(c, function, attribute_id.zext, index);
}
if (info->attributes.signext)
{
// Direct only
assert(index == last_index);
llvm_attribute_add(c, function, attribute_id.sext, index);
}
if (info->attributes.by_reg)
{
llvm_attribute_add_range(c, function, attribute_id.inreg, index, last_index);
}
switch (info->kind)
{
case ABI_ARG_EXPAND:
case ABI_ARG_IGNORE:
case ABI_ARG_DIRECT_SPLIT_STRUCT:
case ABI_ARG_DIRECT_COERCE:
case ABI_ARG_DIRECT_COERCE_INT:
case ABI_ARG_DIRECT_PAIR:
case ABI_ARG_DIRECT:
case ABI_ARG_EXPAND_COERCE:
break;
case ABI_ARG_INDIRECT:
if (is_return)
{
assert(info->indirect.type);
llvm_attribute_add_type(c, function, attribute_id.sret, llvm_get_type(c, info->indirect.type), 1);
llvm_attribute_add(c, function, attribute_id.noalias, 1);
llvm_attribute_add_int(c, function, attribute_id.align, info->indirect.alignment, 1);
}
else
{
if (info->attributes.by_val) llvm_attribute_add_type(c, function, attribute_id.byval, llvm_get_type(c, info->indirect.type), index);
llvm_attribute_add_int(c, function, attribute_id.align, info->indirect.alignment, index);
}
break;
}
}
void llvm_append_function_attributes(GenContext *c, Decl *decl)
{
FunctionPrototype *prototype = decl->type->function.prototype;
LLVMValueRef function = decl->backend_ref;
ABIArgInfo *ret_abi_info = prototype->ret_abi_info;
llvm_emit_param_attributes(c, function, ret_abi_info, true, 0, 0);
unsigned params = vec_size(prototype->param_types);
if (prototype->ret_by_ref)
{
ABIArgInfo *info = prototype->ret_by_ref_abi_info;
llvm_emit_param_attributes(c, function, prototype->ret_by_ref_abi_info, false, info->param_index_start + 1, info->param_index_end);
}
for (unsigned i = 0; i < params; i++)
{
ABIArgInfo *info = prototype->abi_args[i];
llvm_emit_param_attributes(c, function, info, false, info->param_index_start + 1, info->param_index_end);
}
// We ignore decl->func_decl.attr_inline and place it in every call instead.
if (decl->func_decl.attr_noinline)
{
llvm_attribute_add(c, function, attribute_id.noinline, -1);
}
if (decl->func_decl.signature.attrs.noreturn)
{
llvm_attribute_add(c, function, attribute_id.noreturn, -1);
}
if (decl->is_wasm_interface && arch_is_wasm(platform_target.arch))
{
if (decl->visibility == VISIBLE_EXTERN)
{
llvm_attribute_add_string(c, function, "wasm-import-name", decl_get_extname(decl), -1);
}
else if (c->code_module == decl->unit->module)
{
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);
}
llvm_attribute_add(c, function, attribute_id.nounwind, -1);
if (decl->func_decl.attr_naked)
{
llvm_attribute_add(c, function, attribute_id.naked, -1);
}
LLVMSetFunctionCallConv(function, llvm_call_convention_from_call(prototype->call_abi));
}
LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
{
LLVMValueRef backend_ref = decl->backend_ref;
@@ -966,6 +1067,7 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
return decl->backend_ref;
case DECL_FUNC:
backend_ref = decl->backend_ref = LLVMAddFunction(c->module, decl_get_extname(decl), llvm_get_type(c, decl->type));
llvm_append_function_attributes(c, decl);
if (decl->unit->module == c->code_module && !decl->is_external_visible && !visible_external(decl->visibility))
{
llvm_set_internal_linkage(backend_ref);

View File

@@ -582,58 +582,6 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_nam
c->function = prev_function;
}
static void llvm_emit_param_attributes(GenContext *c, LLVMValueRef function, ABIArgInfo *info, bool is_return, int index, int last_index)
{
assert(last_index == index || info->kind == ABI_ARG_DIRECT_PAIR || info->kind == ABI_ARG_IGNORE
|| info->kind == ABI_ARG_EXPAND || info->kind == ABI_ARG_DIRECT || info->kind == ABI_ARG_DIRECT_COERCE
|| info->kind == ABI_ARG_DIRECT_COERCE_INT
|| info->kind == ABI_ARG_DIRECT_SPLIT_STRUCT);
if (info->attributes.zeroext)
{
// Direct only
assert(index == last_index);
llvm_attribute_add(c, function, attribute_id.zext, index);
}
if (info->attributes.signext)
{
// Direct only
assert(index == last_index);
llvm_attribute_add(c, function, attribute_id.sext, index);
}
if (info->attributes.by_reg)
{
llvm_attribute_add_range(c, function, attribute_id.inreg, index, last_index);
}
switch (info->kind)
{
case ABI_ARG_EXPAND:
case ABI_ARG_IGNORE:
case ABI_ARG_DIRECT_SPLIT_STRUCT:
case ABI_ARG_DIRECT_COERCE:
case ABI_ARG_DIRECT_COERCE_INT:
case ABI_ARG_DIRECT_PAIR:
case ABI_ARG_DIRECT:
case ABI_ARG_EXPAND_COERCE:
break;
case ABI_ARG_INDIRECT:
if (is_return)
{
assert(info->indirect.type);
llvm_attribute_add_type(c, function, attribute_id.sret, llvm_get_type(c, info->indirect.type), 1);
llvm_attribute_add(c, function, attribute_id.noalias, 1);
llvm_attribute_add_int(c, function, attribute_id.align, info->indirect.alignment, 1);
}
else
{
if (info->attributes.by_val) llvm_attribute_add_type(c, function, attribute_id.byval, llvm_get_type(c, info->indirect.type), index);
llvm_attribute_add_int(c, function, attribute_id.align, info->indirect.alignment, index);
}
break;
}
}
void llvm_emit_xxlizer(GenContext *c, Decl *decl)
{
@@ -690,48 +638,14 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
LLVMValueRef function = llvm_get_ref(c, decl);
decl->backend_ref = function;
FunctionPrototype *prototype = decl->type->function.prototype;
ABIArgInfo *ret_abi_info = prototype->ret_abi_info;
llvm_emit_param_attributes(c, function, ret_abi_info, true, 0, 0);
unsigned params = vec_size(prototype->param_types);
if (prototype->ret_by_ref)
{
ABIArgInfo *info = prototype->ret_by_ref_abi_info;
llvm_emit_param_attributes(c, function, prototype->ret_by_ref_abi_info, false, info->param_index_start + 1, info->param_index_end);
}
for (unsigned i = 0; i < params; i++)
{
ABIArgInfo *info = prototype->abi_args[i];
llvm_emit_param_attributes(c, function, info, false, info->param_index_start + 1, info->param_index_end);
}
// We ignore decl->func_decl.attr_inline and place it in every call instead.
if (decl->func_decl.attr_noinline)
{
llvm_attribute_add(c, function, attribute_id.noinline, -1);
}
if (decl->func_decl.signature.attrs.noreturn)
{
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);
}
if (decl->section)
{
LLVMSetSection(function, decl->section);
}
llvm_attribute_add(c, function, attribute_id.nounwind, -1);
if (decl->func_decl.attr_naked)
if (llvm_use_debug(c))
{
llvm_attribute_add(c, function, attribute_id.naked, -1);
llvm_emit_debug_function(c, decl);
}
LLVMSetFunctionCallConv(function, llvm_call_convention_from_call(prototype->call_abi));
Visibility visibility = decl->visibility;
if (decl->is_external_visible) visibility = VISIBLE_PUBLIC;
@@ -748,7 +662,7 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
LLVMSetLinkage(function, LLVMExternalLinkage);
}
LLVMSetVisibility(function, LLVMDefaultVisibility);
if (prototype->call_abi == CALL_X86_STD && platform_target.os == OS_TYPE_WIN32)
if (decl->type->function.prototype->call_abi == CALL_X86_STD && platform_target.os == OS_TYPE_WIN32)
{
LLVMSetDLLStorageClass(function, LLVMDLLImportStorageClass);
}
@@ -762,10 +676,6 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
LLVMSetVisibility(function, LLVMDefaultVisibility);
break;;
}
if (llvm_use_debug(c))
{
llvm_emit_debug_function(c, decl);
}
}

View File

@@ -1646,7 +1646,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
decl->is_weak = true;
break;
case ATTRIBUTE_WASM:
decl->is_wasm_export = true;
decl->is_wasm_interface = true;
break;
case ATTRIBUTE_NAKED:
assert(domain == ATTR_FUNC);

View File

@@ -6537,7 +6537,7 @@ static inline bool sema_expr_analyse_lambda(SemaContext *context, Type *func_typ
if (!decl_ok(decl)) return false;
if (decl->resolve_status == RESOLVE_DONE)
{
expr->type = expr->type = type_get_ptr(decl->type);
expr->type = type_get_ptr(decl->type);
return true;
}
bool in_macro = context->current_macro;

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.26"
#define COMPILER_VERSION "0.4.27"

View File

@@ -74,9 +74,9 @@ if.exit: ; preds = %if.then, %entry
ret void
}
declare void @"std_map$$typeid.p$std_io$ToStringFunction_HashMap_init"(%HashMap*, i32, float, %Allocator*)
declare void @"std_map$$typeid.p$std_io$ToStringFunction_HashMap_init"(%HashMap*, i32, float, %Allocator*) #0
declare i8 @"std_map$$typeid.p$std_io$ToStringFunction_HashMap_set"(%HashMap*, i64, { i8*, i64 } (i8*, %Allocator*)*)
declare zeroext i8 @"std_map$$typeid.p$std_io$ToStringFunction_HashMap_set"(%HashMap*, i64, { i8*, i64 } (i8*, %Allocator*)*) #0
; Function Attrs: nounwind
define { i8*, i64 } @test_Foo_to_string(%Foo* %0, %Allocator* %1) #0 {
@@ -574,14 +574,14 @@ declare void @"std_map$$int.test_Foo_HashMap_tinit"(%HashMap.0*, i32, float)
declare i64 @std_io_printfn(i64*, i8*, i64, i8*, i64)
declare i8 @"std_map$$int.test_Foo_HashMap_set"(%HashMap.0*, i32, i64, i8*)
declare zeroext i8 @"std_map$$int.test_Foo_HashMap_set"(%HashMap.0*, i32, i64, i8*)
declare i64 @"std_map$$int.test_Foo_HashMap_get"(%Foo*, %HashMap.0*, i32)
declare i8 @"std_map$$int.test_Foo_HashMap_has_key"(%HashMap.0*, i32)
declare zeroext i8 @"std_map$$int.test_Foo_HashMap_has_key"(%HashMap.0*, i32)
declare { i8*, i64 } @"std_map$$int.test_Foo_HashMap_value_list"(%HashMap.0*, %Allocator*)
declare void @"std_map$$int.double_HashMap_tinit"(%HashMap.3*, i32, float)
declare i8 @"std_map$$int.double_HashMap_set"(%HashMap.3*, i32, double)
declare zeroext i8 @"std_map$$int.double_HashMap_set"(%HashMap.3*, i32, double)