Auto-import std::core. Fix module assignment of declarations. Introspection improvements. Deref null error panics in safe mode. Support for LLVM 15

This commit is contained in:
Christoffer Lerno
2022-06-21 14:44:28 +02:00
committed by Christoffer Lerno
parent df41caabdd
commit b1d83e2ccd
519 changed files with 26866 additions and 638 deletions

View File

@@ -159,7 +159,11 @@ jobs:
- name: run compiler tests
run: |
cd test
python3 src/tester.py ../build/c3c test_suite/
if [[ "${{matrix.llvm_version}}" < 15 ]]; then
python3 src/tester.py ../build/c3c test_suite/
else
python3 src/tester.py ../build/c3c test_suite2/
fi
build-mac:
runs-on: macos-latest
@@ -168,7 +172,7 @@ jobs:
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [12, 13]
llvm_version: [12, 13, 14]
steps:
- uses: actions/checkout@v3
- name: Download LLVM

View File

@@ -8,9 +8,14 @@ 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_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3")
#set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1 -fsanitize=undefined")
#set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O1 -fsanitize=undefined")
#set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3 -fsanitize=undefined")
#set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3 -fsanitize=undefined")
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined")
option(C3_USE_TB "Enable TB" OFF)
set(C3_LLVM_VERSION "auto" CACHE STRING "Use LLVM version [default: auto]")

View File

@@ -2,7 +2,6 @@
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::array;
import std::mem;
/**
* @require elements > 0

View File

@@ -1,9 +1,14 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::builtin;
module std::core::builtin;
import libc;
fault IteratorResult
{
NO_MORE_ELEMENT
}
fault VarCastResult
{
TYPE_MISMATCH
@@ -76,6 +81,29 @@ macro unreachable($string = "Unreachable statement reached.") @autoimport @noret
$$unreachable();
}
enum TypeKind : char
{
VOID, // 0
BOOL, // 1
FLOAT, // 2
INTEGER,// 3
STRUCT, // 4
UNION, // 5
ENUM, // 6
FAULT, // 7
ARRAY,
POINTER,
VAR_ARRAY,
SUBARRAY,
OPAQUE
// ALIAS,
}
struct TypeEnum
{
TypeKind type;
usize elements;
}
/*
enum TypeKind
{

View File

@@ -1,7 +1,7 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::cinterop;
module std::core::cinterop;
const C_INT_SIZE = $$C_INT_SIZE;
const C_LONG_SIZE = $$C_LONG_SIZE;

View File

@@ -1,7 +1,7 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::env;
module std::core::env;
enum CompilerOptLevel
{

View File

@@ -1,7 +1,7 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::mem;
module std::core::mem;
macro @volatile_load(&x)
{
@@ -77,6 +77,11 @@ fault AllocationFailure
private tlocal Allocator thread_allocator = { null, SYSTEM_ALLOCATOR };
macro Allocator current_allocator()
{
return thread_allocator;
}
struct Allocator
{
void* data;

View File

@@ -1,4 +1,4 @@
module std::mem;
module std::core::mem;
define AllocatorFunction = fn void*!(void* alloc_data, usize new_size, usize alignment, void* old_pointer, AllocationKind kind);

View File

@@ -1,4 +1,4 @@
module std::mem;
module std::core::mem;
import libc;
private fn void*! null_allocator_fn(void *data, usize bytes, usize alignment, void* old_pointer, AllocationKind kind)

View File

@@ -1,4 +1,4 @@
module std::mem;
module std::core::mem;
const TEMP_BLOCK_SIZE = 1024;
const TEMP_PAGES = 64;

View File

@@ -1,5 +1,4 @@
module std::os::linux;
import std::env;
module std::core::os::linux;
$if (env::OS_TYPE == OsType.LINUX):

View File

@@ -1,6 +1,4 @@
module std::os::macos;
import std::env;
module std::core::os::macos;
$if (env::OS_TYPE == OsType.MACOSX):
extern fn int* __error();

View File

@@ -1,5 +1,4 @@
module std::os::windows;
import std::env;
module std::core::os::windows;
$if (env::OS_TYPE == OsType.WIN32):

166
lib/std/core/str.c3 Normal file
View File

@@ -0,0 +1,166 @@
module std::core::str;
define ZString = distinct char*;
define Char32 = uint;
fn String join(char[][] s, char[] joiner)
{
if (!s.len) return (String)null;
usize total_size = joiner.len * s.len;
foreach (char[]* &str : s)
{
total_size += str.len;
}
String res = string::new_with_capacity(total_size);
res.append(s[0]);
foreach (char[]* &str : s[1..])
{
res.append(joiner);
res.append(*str);
}
return res;
}
fn ZString copy_zstring(char[] s)
{
usize len = s.len;
char* str = mem::alloc(len + 1);
mem::copy(str, s.ptr, len);
str[len] = 0;
return (ZString)str;
}
fn ZString tcopy_zstring(char[] s)
{
usize len = s.len;
char* str = mem::talloc(len + 1)!!;
mem::copy(str, s.ptr, len);
str[len] = 0;
return (ZString)str;
}
fault UnicodeResult
{
INVALID_UTF8
}
fn Char32! utf8CharTo32(char* ptr, int* size)
{
int max_size = *size;
if (max_size < 1) return UnicodeResult.INVALID_UTF8!;
char c = (ptr++)[0];
if ((c & 0x80) == 0)
{
*size = 1;
return c;
}
if ((c & 0xE0) == 0xC0)
{
if (max_size < 2) return UnicodeResult.INVALID_UTF8!;
*size = 2;
Char32 uc = (c & 0x1F) << 6;
c = *ptr;
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
return uc + c & 0x3F;
}
if ((c & 0xF0) == 0xE0)
{
if (max_size < 3) return UnicodeResult.INVALID_UTF8!;
*size = 3;
Char32 uc = (c & 0x0F) << 12;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
uc += (c & 0x3F) << 6;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
return uc + c & 0x3F;
}
if (max_size < 4) return UnicodeResult.INVALID_UTF8!;
*size = 4;
Char32 uc = (c & 0x07) << 18;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
uc += (c & 0x3F) << 12;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
uc += (c & 0x3F) << 6;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
return uc + c & 0x3F;
}
fn usize utf8_codepoints(char[] utf8)
{
usize len = 0;
foreach (char c : utf8)
{
if (c & 0xC0 != 0x80) len++;
}
return len;
}
fn Char32[]! utf8to32(char[] utf8, Allocator allocator = { null, null })
{
if (!allocator.function) allocator = mem::current_allocator();
usize len = utf8.len;
Char32* data = allocator.alloc((len + 1) * Char32.sizeof)?;
usize len32 = 0;
for (usize i = 0; i < len;)
{
int width = (int)min(len - i, 4);
Char32 uc = utf8CharTo32(&utf8[i], &width) @inline?;
i += width;
data[len32++] = uc;
}
return data[0 .. len32 - 1];
}
fn char[] copy(char[] s)
{
usize len = s.len;
ZString str_copy = copy_zstring(s) @inline;
return str_copy[..len];
}
fn char[] tcopy(char[] s)
{
usize len = s.len;
ZString str_copy = tcopy_zstring(s) @inline;
return str_copy[..len];
}
fn char[] tconcat(char[] s1, char[] s2)
{
usize full_len = s1.len + s2.len;
char* str = mem::talloc(full_len + 1)!!;
usize s1_len = s1.len;
mem::copy(str, s1.ptr, s1_len);
mem::copy(str + s1_len, s2.ptr, s2.len);
str[full_len] = 0;
return str[..full_len];
}
fn char[] concat(char[] s1, char[] s2)
{
usize full_len = s1.len + s2.len;
char* str = mem::alloc(full_len + 1);
usize s1_len = s1.len;
mem::copy(str, s1.ptr, s1_len);
mem::copy(str + s1_len, s2.ptr, s2.len);
str[full_len] = 0;
return str[..full_len];
}
fn usize ZString.len(ZString *str)
{
usize len = 0;
char* ptr = (char*)*str;
while (char c = ptr++[0])
{
if (c & 0xC0 != 0x80) len++;
}
return len;
}

255
lib/std/core/string.c3 Normal file
View File

@@ -0,0 +1,255 @@
module std::core::string;
import libc;
define String = distinct void*;
private struct StringData
{
Allocator allocator;
usize len;
usize capacity;
char[*] chars;
}
const usize MIN_CAPACITY = 16;
fn String new_with_capacity(usize capacity, Allocator allocator = { null, null })
{
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
if (!allocator.function)
{
allocator = mem::current_allocator();
}
assert(allocator.function, "Expected an allocator to be present.");
StringData* data = allocator.alloc(StringData.sizeof + capacity)!!;
data.allocator = allocator;
data.len = 0;
data.capacity = capacity;
return (String)data;
}
fn String new(char[] c)
{
usize len = c.len;
String str = new_with_capacity(len);
StringData* data = str.data();
if (len)
{
data.len = len;
mem::copy(&data.chars, c.ptr, len);
}
return (String)data;
}
fn ZString String.zstr(String* str)
{
StringData* data = str.data();
if (!str) return (ZString)"";
if (data.capacity == data.len)
{
libc::printf("feofk\n");
str.reserve(1);
data.chars[data.len] = 0;
}
else if (data.chars[data.len] != 0)
{
data.chars[data.len] = 0;
}
return (ZString)&data.chars[0];
}
fn usize String.len(String* this)
{
if (!*this) return 0;
return this.data().len;
}
/**
* @require new_size <= this.len()
*/
fn void String.chop(String* this, usize new_size)
{
if (!*this) return;
this.data().len = new_size;
}
fn char[] String.str(String* str)
{
StringData* data = (StringData*)*str;
return data.chars[0..data.len - 1];
}
fn void String.append_utf32(String* str, Char32[] chars)
{
str.reserve(chars.len);
foreach (Char32 c : chars)
{
str.append_char32(c);
}
}
/**
* @require c < 0x10ffff
*/
fn void String.append_char32(String* str, Char32 c)
{
if (c < 0x7f)
{
str.reserve(1);
StringData* data = str.data();
data.chars[data.len++] = (char)c;
return;
}
if (c < 0x7ff)
{
str.reserve(2);
StringData* data = str.data();
data.chars[data.len++] = (char)(0xC0 | c >> 6);
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
return;
}
if (c < 0xffff)
{
str.reserve(3);
StringData* data = str.data();
data.chars[data.len++] = (char)(0xE0 | c >> 12);
data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F));
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
return;
}
str.reserve(4);
StringData* data = str.data();
data.chars[data.len++] = (char)(0xF0 | c >> 18);
data.chars[data.len++] = (char)(0x80 | (c >> 12 & 0x3F));
data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F));
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
}
fn String String.copy(String* str, Allocator allocator = { null, null })
{
if (!*str)
{
if (allocator.function) return new_with_capacity(0, allocator);
return (String)null;
}
if (!allocator.function) allocator = mem::current_allocator();
StringData* data = str.data();
String new_string = new_with_capacity(data.capacity, allocator);
mem::copy((char*)new_string.data(), (char*)data, StringData.sizeof + data.len);
return new_string;
}
fn ZString String.copy_zstr(String* str, Allocator allocator = { null, null })
{
usize str_len = str.len();
if (!str_len)
{
if (allocator.function) return (ZString)allocator.calloc(1, 1)!!;
return (ZString)mem::calloc(1, 1);
}
if (!allocator.function) allocator = mem::current_allocator();
char* zstr = allocator.alloc(str_len + 1)!!;
StringData* data = str.data();
mem::copy(zstr, &data.chars, str_len);
zstr[str_len] = 0;
return (ZString)zstr;
}
fn bool String.equals(String* str, String other_string)
{
StringData *str1 = str.data();
StringData *str2 = other_string.data();
if (str1 == str2) return true;
if (!str1) return str2.len == 0;
if (!str2) return str1.len == 0;
usize str1_len = str1.len;
if (str1_len != str2.len) return false;
for (int i = 0; i < str1_len; i++)
{
if (str1.chars[i] != str2.chars[i]) return false;
}
return true;
}
fn void String.destroy(String* str)
{
if (!*str) return;
StringData* data = str.data();
data.allocator.free(data);
*str = (String)null;
}
fn bool String.less_than(String* str, String other_string)
{
StringData* str1 = str.data();
StringData* str2 = other_string.data();
if (str1 == str2) return false;
if (!str1) return str2.len != 0;
if (!str2) return str1.len == 0;
usize str1_len = str1.len;
usize str2_len = str2.len;
if (str1_len != str2_len) return str1_len < str2_len;
for (int i = 0; i < str1_len; i++)
{
if (str1.chars[i] >= str2.chars[i]) return false;
}
return true;
}
fn void String.append(String* this, char[] str)
{
usize other_len = str.len;
if (!other_len) return;
if (!*this)
{
*this = new(str);
return;
}
this.reserve(other_len);
StringData* data = (StringData*)*this;
mem::copy(&data.chars[data.len], str.ptr, other_len);
data.len += other_len;
}
fn Char32[] String.copy_utf32(String* this, Allocator allocator = { null, null })
{
return str::utf8to32(this.str(), allocator) @inline!!;
}
fn void String.append_string(String* this, String str)
{
StringData* other = (StringData*)str;
if (!other) return;
this.append(str.str());
}
fn void String.append_char(String* str, char c)
{
if (!*str)
{
*str = new_with_capacity(MIN_CAPACITY);
}
str.reserve(1);
StringData* data = (StringData*)*str;
data.chars[data.len++] = c;
}
private fn StringData* String.data(String* str) @inline
{
return (StringData*)*str;
}
private fn void String.reserve(String* str, usize addition)
{
StringData* data = str.data();
if (!data)
{
*str = string::new_with_capacity(addition);
return;
}
usize len = data.len + addition;
if (data.capacity >= len) return;
usize new_capacity = data.capacity * 2;
if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY;
*str = (String)data.allocator.realloc(data, StringData.sizeof + new_capacity)!!;
}

View File

@@ -0,0 +1,25 @@
module std::core::string::iterator;
struct StringIterator
{
char[] utf8;
usize current;
}
fn void StringIterator.reset(StringIterator* this)
{
this.current = 0;
}
fn Char32! StringIterator.next(StringIterator* this)
{
usize len = this.utf8.len;
usize current = this.current;
if (current >= len) return IteratorResult.NO_MORE_ELEMENT!;
int read = (int)(len - current < 4 ? len - current : 4);
Char32 res = str::utf8CharTo32(&this.utf8[current], &read)?;
this.current += read;
return res;
}

View File

@@ -2,9 +2,7 @@
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::io;
import std::mem;
import libc;
import std::env;
struct File
{

View File

@@ -2,11 +2,6 @@
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module libc;
import std::cinterop;
import std::env;
import std::os::linux;
import std::os::macos;
import std::os::windows;
// stdlib

View File

@@ -2,7 +2,6 @@
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::array::linkedlist<Type>;
import std::mem;
private struct Node
{

View File

@@ -2,7 +2,6 @@
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::array::list<Type>;
import std::mem;
struct List
{

View File

@@ -1,59 +0,0 @@
module std::str;
import std::mem;
define ZString = char*;
define String = char[];
fn ZString copy_zstring(String s)
{
usize len = s.len;
char* str = mem::alloc(len + 1);
mem::copy(str, s.ptr, len);
str[len] = 0;
return str;
}
fn ZString tcopy_zstring(String s)
{
usize len = s.len;
char* str = mem::talloc(len + 1)!!;
mem::copy(str, s.ptr, len);
str[len] = 0;
return str;
}
fn String copy(String s)
{
usize len = s.len;
ZString str_copy = copy_zstring(s) @inline;
return str_copy[..len];
}
fn String tcopy(String s)
{
usize len = s.len;
ZString str_copy = tcopy_zstring(s) @inline;
return str_copy[..len];
}
fn String tconcat(String s1, String s2)
{
usize full_len = s1.len + s2.len;
char* str = mem::talloc(full_len + 1)!!;
usize s1_len = s1.len;
mem::copy(str, s1.ptr, s1_len);
mem::copy(str + s1_len, s2.ptr, s2.len);
str[full_len] = 0;
return str[..full_len];
}
fn String concat(String s1, String s2)
{
usize full_len = s1.len + s2.len;
char* str = mem::alloc(full_len + 1);
usize s1_len = s1.len;
mem::copy(str, s1.ptr, s1_len);
mem::copy(str + s1_len, s2.ptr, s2.len);
str[full_len] = 0;
return str[..full_len];
}

View File

@@ -91,6 +91,9 @@ static void usage(void)
OUTPUT(" -O2 - Default optimization level.");
OUTPUT(" -Os - Optimize for size.");
OUTPUT(" -O3 - Aggressive optimization.");
OUTPUT(" --build-dir <dir> - Override build output directory.");
OUTPUT(" --obj-out <dir> - Override object file output directory.");
OUTPUT(" --llvm-out <dir> - Override llvm output directory for '--emit-llvm'.");
OUTPUT(" --emit-llvm - Emit LLVM IR as a .ll file per module.");
OUTPUT(" --target <target> - Compile for a particular architecture + OS target.");
OUTPUT(" --threads <number> - Set the number of threads to use for compilation.");
@@ -612,6 +615,24 @@ static void parse_option(BuildOptions *options)
options->win.crt_linking = (WinCrtLinking)parse_multi_option(argopt, 3, wincrt_linking);
return;
}
if (match_longopt("build-dir"))
{
if (at_end() || next_is_opt()) error_exit("error: --build-dir needs a directory.");
options->build_dir = next_arg();
return;
}
if (match_longopt("obj-out"))
{
if (at_end() || next_is_opt()) error_exit("error: --obj-out needs a directory.");
options->obj_out = next_arg();
return;
}
if (match_longopt("llvm-out"))
{
if (at_end() || next_is_opt()) error_exit("error: --llvm-out needs a directory.");
options->llvm_out = next_arg();
return;
}
if (match_longopt("lib"))
{
if (at_end() || next_is_opt()) error_exit("error: --lib needs a name.");
@@ -691,7 +712,9 @@ BuildOptions parse_arguments(int argc, const char *argv[])
.backend = BACKEND_LLVM,
.x86_vector_capability = X86VECTOR_DEFAULT,
.win.crt_linking = WIN_CRT_DEFAULT,
.files = NULL
.files = NULL,
.build_dir = NULL,
};
for (int i = DIAG_NONE; i < DIAG_WARNING_TYPE; i++)
{

View File

@@ -256,6 +256,9 @@ typedef struct BuildOptions_
bool force_linker;
const char *panicfn;
const char *cc;
const char *build_dir;
const char *llvm_out;
const char *obj_out;
RelocModel reloc_model;
X86VectorCapability x86_vector_capability;
bool print_keywords;
@@ -309,6 +312,8 @@ typedef struct
const char *cpu;
const char **link_args;
const char *build_dir;
const char *object_file_dir;
const char *llvm_file_dir;
bool run_after_compile : 1;
bool test_output : 1;
bool output_headers : 1;

View File

@@ -61,6 +61,30 @@ ArchOsTarget default_target = ELF_RISCV64;
ArchOsTarget default_target = ARCH_OS_TARGET_DEFAULT;
#endif
static bool command_is_compile(CompilerCommand command)
{
switch (command)
{
case COMMAND_COMPILE:
case COMMAND_COMPILE_ONLY:
case COMMAND_COMPILE_RUN:
return true;
case COMMAND_MISSING:
case COMMAND_GENERATE_HEADERS:
case COMMAND_INIT:
case COMMAND_BUILD:
case COMMAND_RUN:
case COMMAND_CLEAN_RUN:
case COMMAND_CLEAN:
case COMMAND_DIST:
case COMMAND_DOCS:
case COMMAND_BENCH:
case COMMAND_UNIT_TEST:
case COMMAND_PRINT_SYNTAX:
return false;
}
UNREACHABLE
}
static void update_build_target_from_options(BuildTarget *target, BuildOptions *options)
{
switch (options->command)
@@ -163,6 +187,18 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
{
target->feature.x86_vector_capability = options->x86_vector_capability;
}
if (command_is_compile(options->command))
{
target->build_dir = options->build_dir ? options->build_dir : NULL;
target->object_file_dir = options->obj_out ? options->obj_out : target->build_dir;
target->llvm_file_dir = options->llvm_out ? options->llvm_out : target->build_dir;
}
else
{
target->build_dir = options->build_dir ? options->build_dir : "build";
target->object_file_dir = options->obj_out ? options->obj_out : file_append_path(target->build_dir, "tmp");
target->llvm_file_dir = options->llvm_out ? options->llvm_out : file_append_path(target->build_dir, "llvm_ir");
}
switch (options->compile_option)
{
case COMPILE_NORMAL:
@@ -231,7 +267,6 @@ void init_build_target(BuildTarget *target, BuildOptions *options)
Project *project = project_load();
*target = *project_select_target(project, options->target_select);
target->build_dir = "build";
update_build_target_from_options(target, options);
if (target->build_dir && !file_exists(target->build_dir))
{

View File

@@ -222,6 +222,27 @@ void compiler_compile(void)
void **gen_contexts = VECNEW(void*, module_count);
void (*task)(void *);
if (active_target.llvm_file_dir || active_target.emit_object_files)
{
if (active_target.build_dir && !file_exists(active_target.build_dir) && !dir_make(active_target.build_dir))
{
error_exit("Failed to create build directory '%s'.", active_target.build_dir);
}
}
if (active_target.llvm_file_dir && active_target.emit_llvm)
{
if (!file_exists(active_target.llvm_file_dir) && !dir_make(active_target.llvm_file_dir))
{
error_exit("Failed to create output directory '%s'.", active_target.llvm_file_dir);
}
}
if (active_target.object_file_dir && active_target.emit_object_files)
{
if (!file_exists(active_target.object_file_dir) && !dir_make(active_target.object_file_dir))
{
error_exit("Failed to create output directory '%s'.", active_target.object_file_dir);
}
}
switch (active_target.backend)
{
case BACKEND_LLVM:

View File

@@ -583,6 +583,7 @@ typedef struct Decl_
bool is_maybe_unused : 1;
bool is_must_use : 1;
bool will_reflect : 1;
bool is_dynamic : 1;
OperatorOverload operator : 4;
union
{
@@ -616,8 +617,9 @@ typedef struct Decl_
Decl **methods;
union
{
// Unions, Fault and Struct use strukt
// Unions, Struct use strukt
StructDecl strukt;
// Enums and Fault
EnumDecl enums;
DistinctDecl distinct_decl;
BitStructDecl bitstruct;
@@ -1573,7 +1575,7 @@ extern Type *type_cuint;
extern const char *attribute_list[NUMBER_OF_ATTRIBUTES];
extern const char *builtin_list[NUMBER_OF_BUILTINS];
extern const char *kw_std__builtin;
extern const char *kw_std__core;
extern const char *kw_std;
extern const char *kw_max;

View File

@@ -166,7 +166,9 @@ void decl_register(Decl *decl)
void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
{
assert(!decl->module || decl->module->is_generic);
decl->module = unit->module;
switch (decl->decl_kind)
{
case DECL_POISONED:

View File

@@ -168,6 +168,29 @@ typedef enum
DOC_DIRECTIVE_ENSURE,
} DocDirectiveKind;
typedef enum
{
INTROSPECT_TYPE_VOID = 0,
INTROSPECT_TYPE_BOOL = 1,
INTROSPECT_TYPE_SIGNED_INT = 2,
INTROSPECT_TYPE_UNSIGNED_INT = 3,
INTROSPECT_TYPE_FLOAT = 4,
INTROSPECT_TYPE_TYPEID = 5,
INTROSPECT_TYPE_ANYERR = 6,
INTROSPECT_TYPE_ANY = 7,
INTROSPECT_TYPE_ENUM = 8,
INTROSPECT_TYPE_FAULT = 9,
INTROSPECT_TYPE_STRUCT = 10,
INTROSPECT_TYPE_UNION = 11,
INTROSPECT_TYPE_BITSTRUCT = 12,
INTROSPECT_TYPE_FUNC = 13,
INTROSPECT_TYPE_FAILABLE = 14,
INTROSPECT_TYPE_ARRAY = 15,
INTROSPECT_TYPE_SUBARRAY = 16,
INTROSPECT_TYPE_VECTOR = 17,
INTROSPECT_TYPE_DISTINCT = 18
} IntrospectType;
typedef enum
{
EXPR_POISONED,

View File

@@ -482,7 +482,7 @@ void gencontext_emit_object_file(GenContext *context)
LLVMDisposeMessage(layout);
// Generate .o or .obj file
if (LLVMTargetMachineEmitToFile(context->machine, context->module, context->object_filename, LLVMObjectFile, &err))
if (LLVMTargetMachineEmitToFile(context->machine, context->module, (char *)context->object_filename, LLVMObjectFile, &err))
{
error_exit("Could not emit object file: %s", err);
}
@@ -712,96 +712,11 @@ void llvm_set_linkage(GenContext *c, Decl *decl, LLVMValueRef value)
}
}
void llvm_emit_introspection_type_from_decl(GenContext *c, Decl *decl)
{
llvm_get_type(c, decl->type);
if (decl_is_struct_type(decl))
{
Decl **decls = decl->strukt.members;
VECEACH(decls, i)
{
Decl *member_decl = decls[i];
if (decl_is_struct_type(member_decl))
{
llvm_emit_introspection_type_from_decl(c, member_decl);
}
}
}
if (decl_is_enum_kind(decl))
{
Decl **enum_vals = decl->enums.values;
unsigned elements = vec_size(enum_vals);
LLVMTypeRef element_type = llvm_get_type(c, type_voidptr);
LLVMTypeRef elements_type = LLVMArrayType(element_type, elements);
scratch_buffer_clear();
scratch_buffer_append(decl->extname);
scratch_buffer_append("$elements");
LLVMValueRef enum_elements = llvm_add_global_type(c, scratch_buffer_to_string(), elements_type, 0);
LLVMSetGlobalConstant(enum_elements, 1);
llvm_set_linkage(c, decl, enum_elements);
LLVMSetInitializer(enum_elements, LLVMConstNull(elements_type));
AlignSize alignment = type_alloca_alignment(type_voidptr);
for (unsigned i = 0; i < elements; i++)
{
AlignSize store_align;
enum_vals[i]->backend_ref = llvm_emit_array_gep_raw(c, enum_elements, elements_type, i, alignment, &store_align);
}
Decl **associated_values = decl->enums.parameters;
unsigned associated_value_count = vec_size(associated_values);
if (associated_value_count && elements)
{
LLVMValueRef *values = malloc_arena(elements * sizeof(LLVMValueRef));
LLVMTypeRef val_type;
VECEACH(associated_values, ai)
{
val_type = NULL;
bool mixed = false;
for (unsigned i = 0; i < elements; i++)
{
BEValue value;
llvm_emit_expr(c, &value, enum_vals[i]->enum_constant.args[ai]);
assert(!llvm_value_is_addr(&value));
LLVMValueRef llvm_value = llvm_value_is_bool(&value) ? LLVMConstZExt(value.value, c->byte_type) : value.value;
values[i] = llvm_value;
if (!val_type)
{
val_type = LLVMTypeOf(llvm_value);
continue;
}
if (val_type != LLVMTypeOf(llvm_value)) mixed = true;
}
Decl *associated_value = associated_values[ai];
LLVMValueRef associated_value_arr = mixed ? LLVMConstStruct(values, elements, true) : LLVMConstArray(val_type, values, elements);
scratch_buffer_clear();
scratch_buffer_append(decl->extname);
scratch_buffer_append("$$");
scratch_buffer_append(associated_value->name);
LLVMValueRef global_ref = llvm_add_global_type(c, scratch_buffer_to_string(), LLVMTypeOf(associated_value_arr), 0);
LLVMSetInitializer(global_ref, associated_value_arr);
LLVMSetGlobalConstant(global_ref, true);
if (mixed)
{
LLVMTypeRef cast_type = llvm_get_ptr_type(c, type_get_array(associated_value->type, elements));
associated_value->backend_ref = LLVMConstBitCast(global_ref, cast_type);
}
else
{
associated_value->backend_ref = global_ref;
}
}
}
}
scratch_buffer_clear();
scratch_buffer_append("introspect.");
scratch_buffer_append(decl->name ? decl->name : "anon");
LLVMValueRef global_name = llvm_add_global_var(c, scratch_buffer_to_string(), type_char, 0);
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));
llvm_set_linkage(c, decl, global_name);
}
void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value)
@@ -847,9 +762,6 @@ LLVMBasicBlockRef llvm_basic_block_new(GenContext *c, const char *name)
return LLVMCreateBasicBlockInContext(c->context, name);
}
static void llvm_emit_type_decls(GenContext *context, Decl *decl)
{
switch (decl->decl_kind)
@@ -864,19 +776,17 @@ static void llvm_emit_type_decls(GenContext *context, Decl *decl)
break;
case DECL_TYPEDEF:
break;
case DECL_DISTINCT:
// TODO
break;
case DECL_ENUM_CONSTANT:
case DECL_FAULTVALUE:
// TODO
break;;
case DECL_DISTINCT:
case DECL_STRUCT:
case DECL_UNION:
case DECL_ENUM:
case DECL_FAULT:
case DECL_BITSTRUCT:
llvm_emit_introspection_type_from_decl(context, decl);
llvm_get_typeid(context, decl->type);
break;
case DECL_BODYPARAM:
case NON_TYPE_DECLS:
@@ -999,7 +909,10 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
if (decl->define_decl.define_kind != DEFINE_TYPE_GENERIC) return llvm_get_ref(c, decl->define_decl.alias);
UNREACHABLE
case DECL_FAULTVALUE:
llvm_emit_introspection_type_from_decl(c, declptr(decl->enum_constant.parent));
if (!decl->backend_ref)
{
llvm_get_typeid(c, declptr(decl->enum_constant.parent)->type);
}
assert(decl->backend_ref);
return decl->backend_ref;
case DECL_POISONED:
@@ -1036,7 +949,6 @@ void *llvm_gen(Module *module)
gencontext_init(gen_context, module);
gencontext_begin_module(gen_context);
VECEACH(module->units, j)
{
CompilationUnit *unit = module->units[j];

View File

@@ -8,7 +8,7 @@
void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs_loaded, BinaryOp binary_op);
static void llvm_emit_any_pointer(GenContext *c, BEValue *any, BEValue *pointer);
static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr);
static void gencontext_emit_unary_expr(GenContext *context, BEValue *value, Expr *expr);
static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr);
static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff, bool use_mod);
static inline void llvm_emit_pre_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff, bool use_mod);
static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue *addr, BEValue *after, BEValue *before, Expr *expr, int diff);
@@ -2044,6 +2044,21 @@ static inline void llvm_emit_pre_inc_dec(GenContext *c, BEValue *value, Expr *ex
llvm_emit_inc_dec_change(c, use_mod, &addr, value, NULL, expr, diff);
}
static inline void llvm_emit_deref(GenContext *c, BEValue *value, Expr *inner, Type *type)
{
llvm_emit_expr(c, value, inner);
llvm_value_rvalue(c, value);
if (active_target.feature.safe_mode)
{
LLVMValueRef check = LLVMBuildICmp(c->builder, LLVMIntEQ, value->value, llvm_get_zero(c, inner->type), "checknull");
llvm_emit_panic_on_true(c, check, "Dereference of null pointer", inner->span);
}
// Load the pointer value.
llvm_value_rvalue(c, value);
// Convert pointer to address
value->kind = BE_ADDRESS;
value->type = type;
}
/**
* Emit the common x++ and x-- operations.
@@ -2063,7 +2078,7 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e
}
static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
{
Type *type = type_reduced_from_expr(expr->unary_expr.expr);
Expr *inner = expr->unary_expr.expr;
@@ -2166,13 +2181,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
value->type = type_lowering(expr->type);
return;
case UNARYOP_DEREF:
REMINDER("insert a check for deref in debug mode");
llvm_emit_expr(c, value, inner);
// Load the pointer value.
llvm_value_rvalue(c, value);
// Convert pointer to address
value->kind = BE_ADDRESS;
value->type = type_lowering(expr->type);
llvm_emit_deref(c, value, inner, type_lowering(expr->type));
return;
case UNARYOP_INC:
llvm_emit_pre_inc_dec(c, value, inner, 1, false);
@@ -2313,7 +2322,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
Expr *start = exprptr(slice->slice_expr.start);
Expr *end = exprptrzero(slice->slice_expr.end);
Type *parent_type = parent_expr->type->canonical;
Type *parent_type = type_flatten_distinct(parent_expr->type);
BEValue parent_addr_x;
llvm_emit_expr(c, &parent_addr_x, parent_expr);
llvm_value_addr(c, &parent_addr_x);
@@ -2325,12 +2334,13 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
switch (parent_type->type_kind)
{
case TYPE_POINTER:
parent_load_value = parent_base = gencontext_emit_load(c, parent_type, parent_addr);
parent_load_value = parent_base = LLVMBuildLoad2(c->builder, llvm_get_type(c, parent_type), parent_addr, "");
break;
case TYPE_SUBARRAY:
parent_load_value = gencontext_emit_load(c, parent_type, parent_addr);
parent_load_value = LLVMBuildLoad2(c->builder, llvm_get_type(c, parent_type), parent_addr, "");
parent_base = LLVMBuildExtractValue(c->builder, parent_load_value, 0, "");
break;
case TYPE_FLEXIBLE_ARRAY:
case TYPE_ARRAY:
parent_base = parent_addr;
break;
@@ -2345,12 +2355,15 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
llvm_value_rvalue(c, &start_index);
BEValue len = { .value = NULL };
bool check_end = true;
if (!end || slice->slice_expr.start_from_back || slice->slice_expr.end_from_back || active_target.feature.safe_mode)
{
switch (parent_type->type_kind)
{
case TYPE_POINTER:
case TYPE_FLEXIBLE_ARRAY:
len.value = NULL;
check_end = false;
break;
case TYPE_SUBARRAY:
assert(parent_load_value);
@@ -2371,7 +2384,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
}
// Check that index does not extend beyond the length.
if (parent_type->type_kind != TYPE_POINTER && active_target.feature.safe_mode)
if (check_end && active_target.feature.safe_mode)
{
assert(len.value);
BEValue exceeds_size;
@@ -2448,6 +2461,7 @@ static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr)
switch (type->type_kind)
{
case TYPE_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
{
Type *pointer_type = type_get_ptr(parent.type->array.base);
// Move pointer
@@ -2462,7 +2476,6 @@ static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr)
case TYPE_POINTER:
start_pointer = llvm_emit_pointer_inbounds_gep_raw(c, llvm_get_pointee_type(c, parent.type), parent.value, start.value);
break;
case TYPE_FLEXIBLE_ARRAY:
case TYPE_VECTOR:
TODO
default:
@@ -3299,77 +3312,11 @@ static void llvm_emit_post_unary_expr(GenContext *context, BEValue *be_value, Ex
false);
}
void llvm_emit_derived_backend_type(GenContext *c, Type *type)
{
llvm_get_type(c, type);
LLVMValueRef global_name = llvm_add_global_type(c, type->name, llvm_get_type(c, type_char), 0);
LLVMSetGlobalConstant(global_name, 1);
LLVMSetInitializer(global_name, LLVMConstInt(llvm_get_type(c, type_char), 1, false));
type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid));
Decl *origin = NULL;
Type *original_type = type;
while (!origin)
{
switch (original_type->type_kind)
{
case TYPE_FAILABLE:
original_type = type->failable;
continue;
case TYPE_VECTOR:
original_type = type->array.base;
continue;
case TYPE_ARRAY:
case TYPE_SUBARRAY:
original_type = original_type->array.base;
continue;
case TYPE_POINTER:
original_type = original_type->pointer;
continue;
case TYPE_ENUM:
case TYPE_FUNC:
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_BITSTRUCT:
case TYPE_FAULTTYPE:
case TYPE_DISTINCT:
origin = type->decl;
continue;
case TYPE_TYPEDEF:
original_type = original_type->canonical;
continue;
case TYPE_INFERRED_ARRAY:
case TYPE_UNTYPED_LIST:
case TYPE_FAILABLE_ANY:
case TYPE_TYPEINFO:
UNREACHABLE
default:
goto PRIMITIVE;
}
}
llvm_set_linkage(c, origin, global_name);
return;
PRIMITIVE:
llvm_set_weak(c, global_name);
}
void llvm_emit_typeid(GenContext *c, BEValue *be_value, Type *type)
{
LLVMValueRef value;
type = type->canonical;
if (type_is_builtin(type->type_kind))
{
value = llvm_const_int(c, type_usize, type->type_kind);
}
else
{
if (!type->backend_typeid)
{
llvm_emit_derived_backend_type(c, type);
}
value = type->backend_typeid;
}
llvm_value_set(be_value, value, type_typeid);
llvm_value_set(be_value, llvm_get_typeid(c, type), type_typeid);
}
void llvm_emit_try_assign_try_catch(GenContext *c, bool is_try, BEValue *be_value, BEValue *var_addr, BEValue *catch_addr, Expr *rhs)
@@ -4818,7 +4765,8 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
}
}
llvm_add_abi_call_attributes(c, call_value, 1, non_variadic_params, params, abi_args);
assert(!prototype->ret_by_ref || prototype->ret_by_ref_abi_info->kind != ABI_ARG_INDIRECT);
llvm_add_abi_call_attributes(c, call_value, prototype->ret_by_ref ? 2 : 1, non_variadic_params, params, abi_args);
if (prototype->abi_varargs)
{
llvm_add_abi_call_attributes(c,
@@ -5346,7 +5294,7 @@ void llvm_emit_try_unwrap(GenContext *c, BEValue *value, Expr *expr)
}
else
{
llvm_emit_local_decl(c, expr->try_unwrap_expr.decl);
llvm_emit_local_decl(c, expr->try_unwrap_expr.decl, &addr);
llvm_value_set_decl_address(c, &addr, expr->try_unwrap_expr.decl);
}
assert(llvm_value_is_addr(&addr));
@@ -5362,7 +5310,7 @@ void llvm_emit_catch_unwrap(GenContext *c, BEValue *value, Expr *expr)
}
else if (expr->catch_unwrap_expr.decl)
{
llvm_emit_local_decl(c, expr->catch_unwrap_expr.decl);
llvm_emit_local_decl(c, expr->catch_unwrap_expr.decl, &addr);
llvm_value_set_decl_address(c, &addr, expr->catch_unwrap_expr.decl);
}
else
@@ -5573,8 +5521,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
case EXPR_BUILTIN:
UNREACHABLE;
case EXPR_DECL:
llvm_emit_local_decl(c, expr->decl_expr);
llvm_value_set_decl_address(c, value, expr->decl_expr);
llvm_emit_local_decl(c, expr->decl_expr, value);
return;
case EXPR_SLICE_ASSIGN:
llvm_emit_slice_assign(c, value, expr);
@@ -5610,7 +5557,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_emit_expr_block(c, value, expr);
return;
case EXPR_UNARY:
gencontext_emit_unary_expr(c, value, expr);
llvm_emit_unary_expr(c, value, expr);
return;
case EXPR_CONST:
llvm_emit_const_expr(c, value, expr);

View File

@@ -79,8 +79,8 @@ typedef struct
LLVMBuilderRef builder;
LLVMBasicBlockRef current_block;
LLVMBasicBlockRef catch_block;
char *ir_filename;
char *object_filename;
const char *ir_filename;
const char *object_filename;
// The recipient of the error value in a catch(err = ...) expression.
LLVMValueRef error_var;
LLVMTypeRef bool_type;
@@ -234,6 +234,7 @@ void llvm_value_set_decl(GenContext *c, BEValue *value, Decl *decl);
void llvm_value_fold_failable(GenContext *c, BEValue *value);
void llvm_value_struct_gep(GenContext *c, BEValue *element, BEValue *struct_pointer, unsigned index);
LLVMValueRef llvm_get_typeid(GenContext *context, Type *type);
LLVMTypeRef llvm_abi_type(GenContext *c, AbiType type);
TypeSize llvm_abi_size(GenContext *c, LLVMTypeRef type);
BitSize llvm_bitsize(GenContext *c, LLVMTypeRef type);
@@ -262,7 +263,6 @@ void llvm_emit_convert_value_from_coerced(GenContext *c, BEValue *result, LLVMTy
void llvm_emit_coerce_store(GenContext *c, LLVMValueRef addr, AlignSize alignment, LLVMTypeRef coerced, LLVMValueRef value, LLVMTypeRef target_type);
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);
@@ -320,7 +320,7 @@ LLVMValueRef llvm_emit_lshr_fixed(GenContext *c, LLVMValueRef data, int shift);
// -- general --
void llvm_emit_local_var_alloca(GenContext *c, Decl *decl);
LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl);
void llvm_emit_local_decl(GenContext *c, Decl *decl, BEValue *value);
LLVMValueRef llvm_emit_aggregate_value(GenContext *c, Type *type, ...);
LLVMValueRef llvm_emit_memclear_size_align(GenContext *c, LLVMValueRef ref, uint64_t size, AlignSize align, bool bitcast);
void llvm_store_zero(GenContext *c, BEValue *ref);
@@ -377,13 +377,6 @@ void llvm_store_decl_raw(GenContext *context, Decl *decl, LLVMValueRef value);
LLVMTypeRef llvm_get_twostruct(GenContext *context, LLVMTypeRef lo, LLVMTypeRef hi);
LLVMValueRef llvm_emit_coerce(GenContext *c, LLVMTypeRef coerced, BEValue *value, Type *original_type);
static inline LLVMValueRef gencontext_emit_load(GenContext *c, Type *type, LLVMValueRef value)
{
assert(llvm_get_type(c, type) == LLVMGetElementType(LLVMTypeOf(value)));
return LLVMBuildLoad2(c->builder, llvm_get_type(c, type), value, "");
}
static inline LLVMValueRef decl_failable_ref(Decl *decl)
{
assert(decl->decl_kind == DECL_VAR);
@@ -494,7 +487,6 @@ static inline LLVMValueRef llvm_const_int(GenContext *c, Type *type, uint64_t va
static inline LLVMValueRef llvm_add_global_var(GenContext *c, const char *name, Type *type, AlignSize alignment)
{
printf("Adding %s with %d\n", name, (int)alignment);
type = type_lowering(type_no_fail(type));
LLVMValueRef ref = LLVMAddGlobal(c->module, llvm_get_type(c, type), name);
LLVMSetAlignment(ref, (unsigned)alignment ? alignment : type_alloca_alignment(type));
@@ -503,7 +495,6 @@ static inline LLVMValueRef llvm_add_global_var(GenContext *c, const char *name,
static inline LLVMValueRef llvm_add_global_type(GenContext *c, const char *name, LLVMTypeRef type, AlignSize alignment)
{
printf("Adding %s with %d\n", name, (int)alignment);
LLVMValueRef ref = LLVMAddGlobal(c->module, type, name);
LLVMSetAlignment(ref, (unsigned)alignment ? alignment : LLVMPreferredAlignmentOfGlobal(c->target_data, ref));
return ref;

View File

@@ -11,8 +11,9 @@ void gencontext_begin_module(GenContext *c)
const char *result = module_create_object_file_name(c->code_module);
c->ir_filename = str_printf("%s.ll", result);
if (active_target.llvm_file_dir) c->ir_filename = file_append_path(active_target.llvm_file_dir, c->ir_filename);
c->object_filename = str_printf("%s%s", result, get_object_extension());
if (active_target.object_file_dir) c->object_filename = file_append_path(active_target.object_file_dir, c->object_filename);
c->panicfn = global_context.panic_fn;
c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context);
c->machine = llvm_target_machine_create();
@@ -57,9 +58,32 @@ void gencontext_begin_module(GenContext *c)
VECEACH(global_context.type, i)
{
global_context.type[i]->backend_type = NULL;
global_context.type[i]->backend_debug_type = NULL;
global_context.type[i]->backend_typeid = NULL;
Type *type = global_context.type[i];
type->backend_type = NULL;
type->backend_debug_type = NULL;
type->backend_typeid = NULL;
switch (type->type_kind)
{
case TYPE_ENUM:
case TYPE_FAULTTYPE:
{
Decl **values = type->decl->enums.values;
VECEACH(values, j)
{
values[j]->backend_ref = NULL;
}
FALLTHROUGH;
}
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_DISTINCT:
type->decl->backend_ref = NULL;
break;
case TYPE_FUNC:
// TODO
default:
break;
}
}
if (c->panicfn) c->panicfn->backend_ref = NULL;

View File

@@ -24,7 +24,7 @@ void llvm_emit_compound_stmt(GenContext *c, Ast *ast)
/**
* This emits a local declaration.
*/
LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
void llvm_emit_local_decl(GenContext *c, Decl *decl, BEValue *value)
{
// 1. Get the declaration and the LLVM type.
Type *var_type = type_lowering(type_no_fail(decl->type));
@@ -35,7 +35,11 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
if (decl->var.is_static)
{
// In defers we might already have generated this variable.
if (decl->backend_ref) return decl->backend_ref;
if (decl->backend_ref)
{
llvm_value_set_decl(c, value, decl);
return;
}
void *builder = c->builder;
c->builder = NULL;
decl->backend_ref = llvm_add_global_var(c, "tempglobal", var_type, decl->alignment);
@@ -48,12 +52,14 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
}
llvm_emit_global_variable_init(c, decl);
c->builder = builder;
return decl->backend_ref;
llvm_value_set_decl(c, value, decl);
return;
}
assert(!decl->backend_ref);
llvm_emit_local_var_alloca(c, decl);
Expr *init = decl->var.init_expr;
if (IS_FAILABLE(decl))
bool is_failable = IS_FAILABLE(decl);
if (is_failable)
{
scratch_buffer_clear();
scratch_buffer_append(decl->name);
@@ -64,15 +70,18 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
if (init)
{
// If we don't have undef, then make an assign.
if (!decl->var.no_init)
llvm_value_set_decl_address(c, value, decl);
value->kind = BE_ADDRESS;
BEValue res = llvm_emit_assign_expr(c, value, decl->var.init_expr, decl->var.failable_ref);
if (!is_failable) *value = res;
}
else if (decl->var.no_init)
{
llvm_value_set(value, LLVMGetUndef(alloc_type), decl->type);
if (decl->var.failable_ref)
{
BEValue value;
llvm_value_set_decl_address(c, &value, decl);
value.kind = BE_ADDRESS;
llvm_emit_assign_expr(c, &value, decl->var.init_expr, decl->var.failable_ref);
LLVMBuildStore(c->builder, LLVMGetUndef(llvm_get_type(c, type_anyerr)), decl->var.failable_ref);
}
// TODO trap on undef in debug mode.
}
else
{
@@ -86,16 +95,16 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
if (type_is_builtin(type->type_kind) || type->type_kind == TYPE_POINTER)
{
llvm_emit_store(c, decl, LLVMConstNull(alloc_type));
llvm_value_set(value, LLVMConstNull(alloc_type), type);
}
else
{
BEValue value;
llvm_value_set_decl_address(c, &value, decl);
value.kind = BE_ADDRESS;
llvm_store_zero(c, &value);
llvm_value_set_decl_address(c, value, decl);
value->kind = BE_ADDRESS;
llvm_store_zero(c, value);
llvm_value_set(value, llvm_get_zero(c, type), type);
}
}
return decl->backend_ref;
}
void llvm_emit_decl_expr_list_ignore_result(GenContext *context, Expr *expr)
@@ -124,7 +133,8 @@ void llvm_emit_decl_expr_list(GenContext *context, BEValue *be_value, Expr *expr
if (last->expr_kind == EXPR_DECL)
{
type = last->decl_expr->var.type_info->type;
LLVMValueRef decl_value = llvm_emit_local_decl(context, last->decl_expr);
LLVMValueRef decl_value = llvm_get_ref(context, last->decl_expr);
if (bool_cast && last->decl_expr->var.unwrap)
{
llvm_value_set_bool(be_value, LLVMConstInt(context->bool_type, 1, false));
@@ -1134,8 +1144,11 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
gencontext_emit_expr_stmt(c, ast);
break;
case AST_DECLARE_STMT:
llvm_emit_local_decl(c, ast->declare_stmt);
{
BEValue value;
llvm_emit_local_decl(c, ast->declare_stmt, &value);
break;
}
case AST_BREAK_STMT:
llvm_emit_break(c, ast);
break;

View File

@@ -447,3 +447,327 @@ LLVMTypeRef llvm_abi_type(GenContext *c, AbiType type)
if (abi_type_is_type(type)) return llvm_get_type(c, type.type);
return LLVMIntTypeInContext(c->context, type.int_bits_plus_1 - 1);
}
static inline Module *type_base_module(Type *type)
{
RETRY:
switch (type->type_kind)
{
case TYPE_POISONED:
case TYPE_VOID:
case ALL_INTS:
case ALL_FLOATS:
case TYPE_BOOL:
case TYPE_ANY:
case TYPE_ANYERR:
case TYPE_TYPEID:
return NULL;
case TYPE_POINTER:
type = type->pointer;
goto RETRY;
case TYPE_ENUM:
case TYPE_FUNC:
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_BITSTRUCT:
case TYPE_FAULTTYPE:
case TYPE_DISTINCT:
return type->decl->module;
case TYPE_TYPEDEF:
type = type->canonical;
goto RETRY;
case TYPE_ARRAY:
case TYPE_SUBARRAY:
case TYPE_INFERRED_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
case TYPE_VECTOR:
type = type->array.base;
goto RETRY;
case TYPE_FAILABLE:
type = type->failable;
goto RETRY;
case TYPE_UNTYPED_LIST:
case TYPE_FAILABLE_ANY:
case TYPE_TYPEINFO:
UNREACHABLE
}
UNREACHABLE
}
LLVMValueRef llvm_get_introspection_for_derived_type(GenContext *c, IntrospectType kind, Type *type, Type *inner, LLVMValueRef extra)
{
LLVMValueRef value = llvm_get_typeid(c, inner);
LLVMValueRef values[3] = { llvm_const_int(c, type_char, kind), value };
int count = 2;
if (extra)
{
values[2] = extra;
count = 3;
}
LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, count, false);
scratch_buffer_clear();
scratch_buffer_append(".typeid.");
Module *module = type_base_module(inner);
if (module)
{
scratch_buffer_append(module->name->module);
scratch_buffer_append_char('.');
}
scratch_buffer_append(type->name);
LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMTypeOf(strukt), scratch_buffer_to_string());
LLVMSetAlignment(global_name, llvm_abi_alignment(c, LLVMTypeOf(strukt)));
LLVMSetGlobalConstant(global_name, 1);
LLVMSetInitializer(global_name, strukt);
llvm_set_linkonce(c, global_name);
return type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid));
}
static LLVMValueRef llvm_get_introspection_for_builtin_type(GenContext *c, Type *type, IntrospectType introspect_type, int bits)
{
LLVMValueRef values[2];
int count = 1;
values[0] = llvm_const_int(c, type_char, introspect_type);
if (bits)
{
values[1] = llvm_const_int(c, type_ushort, bits);
count = 2;
}
LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, count, false);
scratch_buffer_clear();
scratch_buffer_append(".typeid.");
scratch_buffer_append(type->name);
LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMTypeOf(strukt), scratch_buffer_to_string());
LLVMSetAlignment(global_name, llvm_abi_alignment(c, LLVMTypeOf(strukt)));
LLVMSetGlobalConstant(global_name, 1);
LLVMSetInitializer(global_name, strukt);
llvm_set_linkonce(c, global_name);
return type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid));
}
static LLVMValueRef llvm_get_introspection_weak(GenContext *c, Type *type, const char *name, LLVMValueRef data)
{
scratch_buffer_clear();
scratch_buffer_append(".typeid.");
scratch_buffer_append(name);
LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMTypeOf(data), scratch_buffer_to_string());
LLVMSetAlignment(global_name, llvm_abi_alignment(c, LLVMTypeOf(data)));
LLVMSetGlobalConstant(global_name, 1);
LLVMSetInitializer(global_name, data);
llvm_set_linkonce(c, global_name);
return type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid));
}
static LLVMValueRef llvm_get_introspection_external(GenContext *c, Type *type, LLVMValueRef data)
{
scratch_buffer_clear();
scratch_buffer_append(".typeid.");
scratch_buffer_append(type->name);
LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMTypeOf(data), scratch_buffer_to_string());
LLVMSetAlignment(global_name, llvm_abi_alignment(c, LLVMTypeOf(data)));
LLVMSetLinkage(global_name, LLVMExternalLinkage);
return type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid));
}
static LLVMValueRef llvm_get_introspection_for_enum(GenContext *c, Type *type)
{
Decl *decl = type->decl;
bool is_external = decl->module != c->code_module;
bool is_dynamic = decl->is_dynamic;
Decl **enum_vals = decl->enums.values;
unsigned elements = vec_size(enum_vals);
Decl **associated_values = decl->enums.parameters;
unsigned associated_value_count = vec_size(associated_values);
if (is_external && is_dynamic)
{
elements = 0;
}
LLVMValueRef en_values[] = { llvm_const_int(c, type_char, INTROSPECT_TYPE_ENUM ),
llvm_const_int(c, type_usize, elements),
llvm_const_int(c, type_usize, associated_value_count) };
LLVMValueRef strukt = LLVMConstStructInContext(c->context, en_values, 3, false);
if (is_external && !is_dynamic)
{
return llvm_get_introspection_external(c, type, strukt);
}
LLVMValueRef val = llvm_get_introspection_weak(c, type, decl_get_extname(decl), strukt);
if (!associated_value_count) return val;
LLVMValueRef *values = elements ? malloc_arena(elements * sizeof(LLVMValueRef)) : NULL;
LLVMTypeRef val_type;
VECEACH(associated_values, ai)
{
val_type = NULL;
bool mixed = false;
for (unsigned i = 0; i < elements; i++)
{
BEValue value;
llvm_emit_expr(c, &value, enum_vals[i]->enum_constant.args[ai]);
assert(!llvm_value_is_addr(&value));
LLVMValueRef llvm_value = llvm_value_is_bool(&value) ? LLVMConstZExt(value.value, c->byte_type)
: value.value;
values[i] = llvm_value;
if (!val_type)
{
val_type = LLVMTypeOf(llvm_value);
continue;
}
if (val_type != LLVMTypeOf(llvm_value)) mixed = true;
}
Decl *associated_value = associated_values[ai];
LLVMValueRef associated_value_arr = mixed ? LLVMConstStruct(values, elements, true) : LLVMConstArray(val_type,
values,
elements);
scratch_buffer_clear();
scratch_buffer_append(decl->extname);
scratch_buffer_append(".");
scratch_buffer_append(associated_value->name);
LLVMValueRef global_ref = llvm_add_global_type(c,
scratch_buffer_to_string(),
LLVMTypeOf(associated_value_arr),
0);
llvm_set_linkonce(c, global_ref);
LLVMSetInitializer(global_ref, associated_value_arr);
LLVMSetGlobalConstant(global_ref, true);
if (mixed)
{
LLVMTypeRef cast_type = llvm_get_ptr_type(c, type_get_array(associated_value->type, elements));
associated_value->backend_ref = LLVMConstBitCast(global_ref, cast_type);
}
else
{
associated_value->backend_ref = global_ref;
}
}
return val;
}
static LLVMValueRef llvm_get_introspection_for_struct_union(GenContext *c, Type *type)
{
Decl *decl = type->decl;
Decl **decls = decl->strukt.members;
VECEACH(decls, i)
{
Decl *member_decl = decls[i];
if (decl_is_struct_type(member_decl))
{
llvm_get_typeid(c, member_decl->type);
}
}
LLVMValueRef values[] = { llvm_const_int(c, type_char, decl->decl_kind == DECL_STRUCT ? INTROSPECT_TYPE_STRUCT : INTROSPECT_TYPE_UNION ),
llvm_const_int(c, type_usize, vec_size(decls)) };
LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, 2, false);
return llvm_get_introspection_weak(c, type, decl_get_extname(decl), strukt);
}
static LLVMValueRef llvm_get_introspection_for_fault(GenContext *c, Type *type)
{
Decl *decl = type->decl;
Decl **fault_vals = decl->enums.values;
unsigned elements = vec_size(fault_vals);
AlignSize store_align;
for (unsigned i = 0; i < elements; i++)
{
scratch_buffer_clear();
scratch_buffer_append(decl_get_extname(decl));
scratch_buffer_append_char('.');
Decl *val = fault_vals[i];
scratch_buffer_append(val->name);
LLVMValueRef global_name = llvm_add_global_var(c, scratch_buffer_to_string(), type_char, 0);
LLVMSetGlobalConstant(global_name, 1);
LLVMSetInitializer(global_name, LLVMConstInt(llvm_get_type(c, type_char), 1, false));
llvm_set_linkonce(c, global_name);
val->backend_ref = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid));
}
LLVMTypeRef element_type = llvm_get_type(c, type_typeid);
LLVMTypeRef elements_type = LLVMArrayType(element_type, elements);
LLVMValueRef start = LLVMConstNull(elements_type);
for (unsigned i = 0; i < elements; i++)
{
start = LLVMConstInsertValue(start, LLVMConstBitCast(fault_vals[i]->backend_ref, element_type), &i, 1);
}
LLVMValueRef values[] = { llvm_const_int(c, type_char, INTROSPECT_TYPE_FAULT ), llvm_const_int(c, type_usize, elements), start };
LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, 3, false);
return llvm_get_introspection_weak(c, type, decl_get_extname(decl), strukt);
}
LLVMValueRef llvm_get_typeid(GenContext *c, Type *type)
{
if (type->backend_typeid) return type->backend_typeid;
switch (type->type_kind)
{
case TYPE_FAILABLE:
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_FAILABLE, type, type->failable, NULL);
case TYPE_FLEXIBLE_ARRAY:
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->array.base,
llvm_const_int(c, type_usize, 0));
case TYPE_VECTOR:
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_VECTOR, type, type->array.base,
llvm_const_int(c, type_usize, type->array.len));
case TYPE_ARRAY:
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->array.base,
llvm_const_int(c, type_usize, type->array.len));
case TYPE_SUBARRAY:
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->array.base, NULL);
case TYPE_POINTER:
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->pointer, NULL);
case TYPE_DISTINCT:
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_DISTINCT, type, type->decl->distinct_decl.base_type, NULL);
case TYPE_ENUM:
return llvm_get_introspection_for_enum(c, type);
case TYPE_FAULTTYPE:
return llvm_get_introspection_for_fault(c, type);
case TYPE_STRUCT:
case TYPE_UNION:
return llvm_get_introspection_for_struct_union(c, type);
case TYPE_FUNC:
{
LLVMValueRef values[] = { llvm_const_int(c, type_char, INTROSPECT_TYPE_FUNC ) };
LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, 1, false);
return llvm_get_introspection_weak(c, type, decl_get_extname(type->decl), strukt);
}
case TYPE_BITSTRUCT:
{
LLVMValueRef values[] = { llvm_const_int(c, type_char, INTROSPECT_TYPE_BITSTRUCT ) };
LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, 1, false);
return llvm_get_introspection_weak(c, type, decl_get_extname(type->decl), strukt);
}
case TYPE_TYPEDEF:
return llvm_get_typeid(c, type->canonical);
case TYPE_INFERRED_ARRAY:
case TYPE_UNTYPED_LIST:
case TYPE_FAILABLE_ANY:
case TYPE_TYPEINFO:
UNREACHABLE
case TYPE_VOID:
return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_VOID, 0);
case TYPE_BOOL:
return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_BOOL, 0);
case ALL_SIGNED_INTS:
return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_SIGNED_INT,
type_kind_bitsize(type->type_kind));
case ALL_UNSIGNED_INTS:
return llvm_get_introspection_for_builtin_type(c,
type,
INTROSPECT_TYPE_UNSIGNED_INT,
type_kind_bitsize(type->type_kind));
case ALL_FLOATS:
return llvm_get_introspection_for_builtin_type(c,
type,
INTROSPECT_TYPE_FLOAT,
type_kind_bitsize(type->type_kind));
case TYPE_ANYERR:
return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_ANYERR, 0);
case TYPE_ANY:
return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_ANY, 0);
case TYPE_TYPEID:
return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_TYPEID, 0);
case TYPE_POISONED:
UNREACHABLE
}
UNREACHABLE
}

View File

@@ -617,7 +617,7 @@ bool cast_may_implicit(Type *from_type, Type *to_type, bool is_simple_expr, bool
if (to == type_voidptr || from == type_voidptr) return true;
// Special handling of int* = int[4]*
if (from->pointer->type_kind == TYPE_ARRAY)
if (from->pointer->type_kind == TYPE_ARRAY || from->pointer->type_kind == TYPE_FLEXIBLE_ARRAY)
{
if (type_is_subtype(to->pointer, from->pointer->array.base))
{

View File

@@ -68,8 +68,10 @@ static inline bool sema_check_no_duplicate_parameter(Decl **decls, Decl *current
static inline bool sema_analyse_struct_member(SemaContext *context, Decl *decl)
static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent, Decl *decl)
{
assert(!decl->module || decl->module->is_generic);
decl->module = parent->module;
if (decl->name)
{
Decl *other = sema_resolve_symbol_in_current_dynamic_scope(context, decl->name);
@@ -125,7 +127,7 @@ static bool sema_analyse_union_members(SemaContext *context, Decl *decl, Decl **
decl_poison(decl);
continue;
}
if (!sema_analyse_struct_member(context, member))
if (!sema_analyse_struct_member(context, decl, member))
{
if (decl_ok(decl))
{
@@ -224,7 +226,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl *
decl_poison(decl);
continue;
}
if (!sema_analyse_struct_member(context, member))
if (!sema_analyse_struct_member(context, decl, member))
{
if (decl_ok(decl))
{
@@ -1614,6 +1616,7 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl)
}
Decl *function = decl_new(DECL_FUNC, NULL, decl->span, VISIBLE_EXTERN);
function->name = kw_mainstub;
function->module = decl->module;
function->extname = kw_main;
function->has_extname = true;
function->func_decl.function_signature.returntype = type_infoid(type_info_new_base(type_cint, decl->span));
@@ -2286,7 +2289,7 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl)
}
decl->resolve_status = RESOLVE_RUNNING;
decl->module = context->unit->module;
assert(decl->module);
switch (decl->decl_kind)
{
case DECL_BITSTRUCT:

View File

@@ -882,6 +882,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
Decl *ambiguous_decl = NULL;
Decl *private_symbol = NULL;
assert(expr && expr->identifier_expr.ident);
DEBUG_LOG("Now resolving %s", expr->identifier_expr.ident);
DeclId body_param;
@@ -992,6 +993,8 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
static inline bool sema_expr_analyse_ct_identifier(SemaContext *context, Expr *expr)
{
assert(expr && expr->ct_ident_expr.identifier);
DEBUG_LOG("Now resolving %s", expr->ct_ident_expr.identifier);
Decl *decl = sema_resolve_symbol(context, expr->ct_ident_expr.identifier, NULL, expr->span);
@@ -1012,6 +1015,7 @@ static inline bool sema_expr_analyse_ct_identifier(SemaContext *context, Expr *e
static inline bool sema_expr_analyse_hash_identifier(SemaContext *context, Expr *expr)
{
assert(expr && expr->hash_ident_expr.identifier);
DEBUG_LOG("Now resolving %s", expr->hash_ident_expr.identifier);
Decl *decl = sema_resolve_symbol(context, expr->hash_ident_expr.identifier, NULL, expr->span);
@@ -4292,6 +4296,7 @@ static inline bool sema_expr_analyse_ct_identifier_lvalue(SemaContext *context,
Decl *ambiguous_decl = NULL;
Decl *private_symbol = NULL;
assert(expr && expr->ct_ident_expr.identifier);
DEBUG_LOG("Now resolving %s", expr->ct_ident_expr.identifier);
Decl *decl = sema_find_symbol(context, expr->ct_ident_expr.identifier);
@@ -7277,11 +7282,6 @@ bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char
if (!*ident_ref)
{
scratch_buffer_clear();
if (*path_ref)
{
scratch_buffer_append_len((*path_ref)->module, (*path_ref)->len);
scratch_buffer_append("::");
}
scratch_buffer_append_len(string, len);
*ident_ref = scratch_buffer_to_string();
*type_ref = TOKEN_INVALID_TOKEN;

View File

@@ -165,11 +165,11 @@ static bool decl_is_visible(CompilationUnit *unit, Decl *decl)
// 2. Same top module as unit -> ok
if (top == unit->module->top_module) return true;
// 3. We want to check std::builtin
// 3. We want to check std::core
Module *lookup = module;
while (lookup)
{
if (lookup->name->module == kw_std__builtin) return true;
if (lookup->name->module == kw_std__core) return true;
lookup = lookup->parent_module;
}

View File

@@ -304,7 +304,7 @@ void sema_analysis_run(void)
if (active_target.panicfn || !active_target.no_stdlib)
{
const char *panicfn = active_target.panicfn ? active_target.panicfn : "std::builtin::panic";
const char *panicfn = active_target.panicfn ? active_target.panicfn : "std::core::builtin::panic";
Path *path;
const char *ident;
TokenType type;

View File

@@ -39,7 +39,7 @@ static SymTab symtab;
const char *attribute_list[NUMBER_OF_ATTRIBUTES];
const char *builtin_list[NUMBER_OF_BUILTINS];
const char *kw_std__builtin;
const char *kw_std__core;
const char *kw_in;
const char *kw_out;
const char *kw_inout;
@@ -128,7 +128,7 @@ void symtab_init(uint32_t capacity)
kw_FUNC = KW_DEF("FUNC");
type = TOKEN_IDENT;
kw_std__builtin = KW_DEF("std::builtin");
kw_std__core = KW_DEF("std::core");
kw_sizeof = KW_DEF("sizeof");
kw_in = KW_DEF("in");
kw_out = KW_DEF("out");
@@ -152,7 +152,6 @@ void symtab_init(uint32_t capacity)
kw_ordinal = KW_DEF("ordinal");
kw_ptr = KW_DEF("ptr");
kw_pure = KW_DEF("pure");
KW_DEF("require");
kw_std = KW_DEF("std");
kw_values = KW_DEF("values");
kw_incr = KW_DEF("incr");

View File

@@ -1049,7 +1049,6 @@ static inline Type *func_create_new_func_proto(FunctionSignature *sig, CallABI a
}
c_abi_func_create(proto);
Type *type = type_new(TYPE_FUNC, "#Function");
type->func.prototype = proto;
type->canonical = type;

View File

@@ -27,6 +27,8 @@ int main_real(int argc, const char *argv[])
{
bench_begin();
// Setjmp will allow us to add things like fuzzing with
// easy restarts.
int result = setjmp(on_error_jump);
if (result)
{

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.2.6"
#define COMPILER_VERSION "0.2.7"

View File

@@ -229,8 +229,14 @@ class Issues:
lines = reader.read().splitlines()
searched_line = 0
current_line = 0
while searched_line < len(file.expected_lines):
total_lines = len(file.expected_lines)
while searched_line < total_lines:
line = file.expected_lines[searched_line].strip()
next_line = None
if searched_line + 1 < total_lines:
alt_line = file.expected_lines[searched_line + 1].strip()
if alt_line.startswith("??"):
next_line = alt_line[2:].strip()
if line == "":
searched_line += 1
continue
@@ -243,8 +249,11 @@ class Issues:
current_line += 1
searched_line += 1
continue
if next_line != None and next_line in lines[current_line]:
current_line += 1
searched_line += 2
continue
current_line += 1
if not self.has_errors:
self.conf.numsuccess += 1
print(" Passed.")

View File

@@ -21,9 +21,9 @@ fn int main()
%Foo = type { [2 x float] }
$introspect.Foo = comdat any
$.typeid.test.Foo = comdat any
@introspect.Foo = linkonce constant i8 1
@.typeid.test.Foo = linkonce constant { i8, i64 } { i8 10, i64 1 }, comdat, align 8
declare void @printf(i8*, ...) #0

View File

@@ -28,7 +28,7 @@ if.then: ; preds = %entry
ret void
if.exit: ; preds = %entry
call void @"std::builtin.panic"(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0), i32 10)
call void @"std::core::builtin.panic"(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0), i32 10)
unreachable
after.unreachable: ; No predecessors!

View File

@@ -28,7 +28,7 @@ fn void main() @TestZero
%Foo = type { i32, [1020 x i8], i32, [1020 x i8] }
@introspect.Foo = linkonce constant i8 1
@.typeid.test.Foo = linkonce constant { i8, i64 } { i8 10, i64 2 }, align 8
@test.f = local_unnamed_addr global %Foo zeroinitializer, align 1024
define void @test.testme() #0 {

View File

@@ -18,12 +18,11 @@ fn void main()
/* #expect: test.ll
@"test.Foo$elements" = linkonce constant [2 x i8*] zeroinitializer
@"test.Foo$$val" = constant [2 x i32] [i32 123, i32 333]
@.typeid.test.Foo = linkonce constant { i8, i64, i64 } { i8 8, i64 2, i64 2 }, align 8
@test.Foo.val = linkonce constant [2 x i32] [i32 123, i32 333], align 4
@.str = private unnamed_addr constant [9 x i8] c"Number A\00", align 1
@.str.1 = private unnamed_addr constant [9 x i8] c"Number B\00", align 1
@"test.Foo$$testme" = constant [2 x i8*] [i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.1, i32 0, i32 0)]
@introspect.Foo = linkonce constant i8 1
@test.Foo.testme = linkonce constant [2 x i8*] [i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.1, i32 0, i32 0)], align 8
@.str.2 = private unnamed_addr constant [17 x i8] c"%d (%s) %d (%s)\0A\00", align 1
; Function Attrs: nounwind
@@ -36,16 +35,16 @@ entry:
store i32 1, i32* %f, align 4
store i32 0, i32* %g, align 4
%0 = load i32, i32* %f, align 4
%1 = getelementptr inbounds [2 x i32], [2 x i32]* @"test.Foo$$val", i32 0, i32 %0
%1 = getelementptr inbounds [2 x i32], [2 x i32]* @test.Foo.val, i32 0, i32 %0
%2 = load i32, i32* %1, align 4
%3 = load i32, i32* %f, align 4
%4 = getelementptr inbounds [2 x i8*], [2 x i8*]* @"test.Foo$$testme", i32 0, i32 %3
%4 = getelementptr inbounds [2 x i8*], [2 x i8*]* @test.Foo.testme, i32 0, i32 %3
%5 = load i8*, i8** %4, align 8
%6 = load i32, i32* %g, align 4
%7 = getelementptr inbounds [2 x i32], [2 x i32]* @"test.Foo$$val", i32 0, i32 %6
%7 = getelementptr inbounds [2 x i32], [2 x i32]* @test.Foo.val, i32 0, i32 %6
%8 = load i32, i32* %7, align 4
%9 = load i32, i32* %g, align 4
%10 = getelementptr inbounds [2 x i8*], [2 x i8*]* @"test.Foo$$testme", i32 0, i32 %9
%10 = getelementptr inbounds [2 x i8*], [2 x i8*]* @test.Foo.testme, i32 0, i32 %9
%11 = load i8*, i8** %10, align 8
%12 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.2, i32 0, i32 0), i32 %2, i8* %5, i32 %8, i8* %11)
ret void

View File

@@ -29,7 +29,7 @@ fn void main()
; Function Attrs: nounwind
define i64 @anyerr_void.errorThing() #0 {
entry:
ret i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"anyerr_void.MyError$elements", i64 0, i64 1) to i64)
ret i64 ptrtoint (i8* @anyerr_void.MyError.BAR to i64)
}
; Function Attrs: nounwind
@@ -65,8 +65,8 @@ noerr_block: ; preds = %after.errcheck, %er
store i64 %1, i64* %z, align 8
%2 = load i64, i64* %z, align 8
call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), i64 %2)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"anyerr_void.MyError$elements", i64 0, i64 1) to i64))
call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), i64 ptrtoint ([2 x i8*]* @"anyerr_void.MyError$elements" to i64))
call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), i64 ptrtoint (i8* @anyerr_void.MyError.BAR to i64))
call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), i64 ptrtoint (i8* @anyerr_void.MyError.FOO to i64))
store i64 0, i64* %error_var1, align 8
%3 = call i64 @anyerr_void.errorThing2()
%not_err2 = icmp eq i64 %3, 0

View File

@@ -0,0 +1,22 @@
module foo;
fault Baz
{
TEST
}
module bar;
import foo;
fn int! abc()
{
return Baz.TEST!;
}
module baz;
import foo;
fn int! abc()
{
return Baz.TEST!;
}

View File

@@ -318,7 +318,7 @@ entry:
br i1 %12, label %if.then, label %if.exit
if.then: ; preds = %entry
ret i64 ptrtoint ([2 x i8*]* @"test.ReadError$elements" to i64)
ret i64 ptrtoint (i8* @test.ReadError.BAD_READ to i64)
if.exit: ; preds = %entry
%13 = bitcast %"char[]"* %url to { i8*, i64 }*
@@ -366,7 +366,7 @@ if.then15: ; preds = %if.exit9
store %"char[]"* null, %"char[]"** %33, align 8
%34 = load %Head, %Head* %literal18, align 8
store %Head %34, %Head* %value, align 8
%35 = call i8* @"std::mem.alloc"(i64 8, i64 0)
%35 = call i8* @"std::core::mem.alloc"(i64 8, i64 0)
%ptrptr = bitcast i8* %35 to %Head*
store %Head* %ptrptr, %Head** %temp, align 8
%36 = load %Head*, %Head** %temp, align 8
@@ -374,7 +374,7 @@ if.then15: ; preds = %if.exit9
br i1 %not, label %if.then19, label %if.exit20
if.then19: ; preds = %if.then15
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var, align 8
store i64 ptrtoint (i8* @test.ReadError.OUT_OF_MEMORY to i64), i64* %error_var, align 8
br label %guard_block
if.exit20: ; preds = %if.then15
@@ -418,7 +418,7 @@ if.then27: ; preds = %if.exit21
store %"char[]"* null, %"char[]"** %53, align 8
%54 = getelementptr inbounds %Head, %Head* %literal32, i32 0, i32 0
store %"char[]" { i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.4, i32 0, i32 0), i64 0 }, %"char[]"* %value34, align 8
%55 = call i8* @"std::mem.alloc"(i64 16, i64 0)
%55 = call i8* @"std::core::mem.alloc"(i64 16, i64 0)
%ptrptr36 = bitcast i8* %55 to %"char[]"*
store %"char[]"* %ptrptr36, %"char[]"** %temp35, align 8
%56 = load %"char[]"*, %"char[]"** %temp35, align 8
@@ -426,7 +426,7 @@ if.then27: ; preds = %if.exit21
br i1 %not37, label %if.then38, label %if.exit39
if.then38: ; preds = %if.then27
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var33, align 8
store i64 ptrtoint (i8* @test.ReadError.OUT_OF_MEMORY to i64), i64* %error_var33, align 8
br label %guard_block40
if.exit39: ; preds = %if.then27
@@ -445,7 +445,7 @@ noerr_block41: ; preds = %if.exit39
store %"char[]"* %61, %"char[]"** %54, align 8
%62 = load %Head, %Head* %literal32, align 8
store %Head %62, %Head* %value31, align 8
%63 = call i8* @"std::mem.alloc"(i64 8, i64 0)
%63 = call i8* @"std::core::mem.alloc"(i64 8, i64 0)
%ptrptr43 = bitcast i8* %63 to %Head*
store %Head* %ptrptr43, %Head** %temp42, align 8
%64 = load %Head*, %Head** %temp42, align 8
@@ -453,7 +453,7 @@ noerr_block41: ; preds = %if.exit39
br i1 %not44, label %if.then45, label %if.exit46
if.then45: ; preds = %noerr_block41
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var30, align 8
store i64 ptrtoint (i8* @test.ReadError.OUT_OF_MEMORY to i64), i64* %error_var30, align 8
br label %guard_block47
if.exit46: ; preds = %noerr_block41
@@ -486,14 +486,14 @@ if.exit49: ; preds = %if.exit21
%77 = load i32, i32* %len, align 4
%siuiext = sext i32 %77 to i64
%add = add i64 %siuiext, 1
%78 = call i8* @"std::mem.alloc"(i64 %add, i64 0)
%78 = call i8* @"std::core::mem.alloc"(i64 %add, i64 0)
store i8* %78, i8** %str, align 8
%79 = load i8*, i8** %str, align 8
%not50 = icmp eq i8* %79, null
br i1 %not50, label %if.then51, label %if.exit52
if.then51: ; preds = %if.exit49
ret i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64)
ret i64 ptrtoint (i8* @test.ReadError.OUT_OF_MEMORY to i64)
if.exit52: ; preds = %if.exit49
%80 = load i8*, i8** %str, align 8
@@ -520,7 +520,7 @@ if.exit52: ; preds = %if.exit49
%93 = insertvalue %"char[]" undef, i8* %ptroffset, 0
%94 = insertvalue %"char[]" %93, i64 %size, 1
store %"char[]" %94, %"char[]"* %value62, align 8
%95 = call i8* @"std::mem.alloc"(i64 16, i64 0)
%95 = call i8* @"std::core::mem.alloc"(i64 16, i64 0)
%ptrptr64 = bitcast i8* %95 to %"char[]"*
store %"char[]"* %ptrptr64, %"char[]"** %temp63, align 8
%96 = load %"char[]"*, %"char[]"** %temp63, align 8
@@ -528,7 +528,7 @@ if.exit52: ; preds = %if.exit49
br i1 %not65, label %if.then66, label %if.exit67
if.then66: ; preds = %if.exit52
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var61, align 8
store i64 ptrtoint (i8* @test.ReadError.OUT_OF_MEMORY to i64), i64* %error_var61, align 8
br label %guard_block68
if.exit67: ; preds = %if.exit52
@@ -547,7 +547,7 @@ noerr_block69: ; preds = %if.exit67
store %"char[]"* %101, %"char[]"** %89, align 8
%102 = load %Head, %Head* %literal60, align 8
store %Head %102, %Head* %value59, align 8
%103 = call i8* @"std::mem.alloc"(i64 8, i64 0)
%103 = call i8* @"std::core::mem.alloc"(i64 8, i64 0)
%ptrptr71 = bitcast i8* %103 to %Head*
store %Head* %ptrptr71, %Head** %temp70, align 8
%104 = load %Head*, %Head** %temp70, align 8
@@ -555,7 +555,7 @@ noerr_block69: ; preds = %if.exit67
br i1 %not72, label %if.then73, label %if.exit74
if.then73: ; preds = %noerr_block69
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var58, align 8
store i64 ptrtoint (i8* @test.ReadError.OUT_OF_MEMORY to i64), i64* %error_var58, align 8
br label %guard_block75
if.exit74: ; preds = %noerr_block69
@@ -683,7 +683,7 @@ entry:
br i1 %not, label %if.then, label %if.exit
if.then: ; preds = %entry
ret i64 ptrtoint ([1 x i8*]* @"test.TitleResult$elements" to i64)
ret i64 ptrtoint (i8* @test.TitleResult.TITLE_MISSING to i64)
if.exit: ; preds = %entry
%5 = getelementptr inbounds %Doc, %Doc* %doc, i32 0, i32 0
@@ -696,7 +696,7 @@ if.exit: ; preds = %entry
br i1 %not1, label %if.then2, label %if.exit3
if.then2: ; preds = %if.exit
ret i64 ptrtoint ([1 x i8*]* @"test.TitleResult$elements" to i64)
ret i64 ptrtoint (i8* @test.TitleResult.TITLE_MISSING to i64)
if.exit3: ; preds = %if.exit
%10 = load %"char[]"*, %"char[]"** %head, align 8
@@ -770,21 +770,21 @@ entry:
switch.entry: ; preds = %entry
%1 = load i64, i64* %switch, align 8
%eq = icmp eq i64 ptrtoint ([1 x i8*]* @"test.TitleResult$elements" to i64), %1
%eq = icmp eq i64 ptrtoint (i8* @test.TitleResult.TITLE_MISSING to i64), %1
br i1 %eq, label %switch.case, label %next_if
switch.case: ; preds = %switch.entry
ret i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.9, i32 0, i32 0)
next_if: ; preds = %switch.entry
%eq1 = icmp eq i64 ptrtoint ([2 x i8*]* @"test.ReadError$elements" to i64), %1
%eq1 = icmp eq i64 ptrtoint (i8* @test.ReadError.BAD_READ to i64), %1
br i1 %eq1, label %switch.case2, label %next_if3
switch.case2: ; preds = %next_if
ret i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.10, i32 0, i32 0)
next_if3: ; preds = %next_if
%eq4 = icmp eq i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), %1
%eq4 = icmp eq i64 ptrtoint (i8* @test.ReadError.OUT_OF_MEMORY to i64), %1
br i1 %eq4, label %switch.case5, label %next_if6
switch.case5: ; preds = %next_if3

View File

@@ -39,7 +39,8 @@ entry:
%x.f = alloca i64, align 8
%y = alloca %Bar, align 4
%error_var = alloca i64, align 8
store i64 ptrtoint ([2 x i8*]* @"test.Foo$elements" to i64), i64* %x.f, align 8
%reterr = alloca i64, align 8
store i64 ptrtoint (i8* @test.Foo.MY_VAL1 to i64), i64* %x.f, align 8
%0 = load i64, i64* %x.f, align 8
%not_err = icmp eq i64 %0, 0
br i1 %not_err, label %after_check, label %error
@@ -68,6 +69,7 @@ entry:
%x.f = alloca i64, align 8
%y = alloca %Bar, align 4
%error_var = alloca i64, align 8
%reterr = alloca i64, align 8
%0 = bitcast %Bar* %x to i32*
store i32 0, i32* %0, align 4
store i64 0, i64* %x.f, align 8

View File

@@ -27,9 +27,9 @@ fn void main()
%Foo = type { i32, i32 }
@introspect.Foo = linkonce constant i8 1
@"test.MyErr$elements" = linkonce constant [1 x i8*] zeroinitializer
@introspect.MyErr = linkonce constant i8 1
@.typeid.test.Foo = linkonce constant { i8, i64 } { i8 10, i64 2 }, align 8
@test.MyErr.FOO = linkonce constant i8 1, align 1
@.typeid.test.MyErr = linkonce constant { i8, i64, [1 x i64] } { i8 9, i64 1, [1 x i64] [i64 ptrtoint (i8* @test.MyErr.FOO to i64)] }, align 8
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
@.str.1 = private unnamed_addr constant [17 x i8] c"Not visible: %d\0A\00", align 1
@@ -78,7 +78,7 @@ after_check2: ; preds = %after_assign
br label %voiderr
voiderr: ; preds = %after_check2, %after_assign
store i64 ptrtoint ([1 x i8*]* @"test.MyErr$elements" to i64), i64* %z.f, align 8
store i64 ptrtoint (i8* @test.MyErr.FOO to i64), i64* %z.f, align 8
br label %voiderr3
voiderr3: ; preds = %voiderr

View File

@@ -70,7 +70,7 @@ fn void main()
a.hello();
}
// #expect: foo.ll
/* #expect: foo.ll
define void @foo.Foo__hello(i64* %0) #0 {
entry:
@@ -98,8 +98,8 @@ entry:
%z = alloca i64, align 8
%b = alloca i32, align 4
%a = alloca i32, align 4
store i64 ptrtoint ([5 x i8*]* @"foo.Foo$elements" to i64), i64* %f, align 8
store i64 ptrtoint (i8** getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 0, i64 1) to i64), i64* %ef, align 8
store i64 ptrtoint (i8* @foo.Foo.X to i64), i64* %f, align 8
store i64 ptrtoint (i8* @foo.Foo.Y to i64), i64* %ef, align 8
%0 = load i64, i64* %f, align 8
store i64 %0, i64* %x, align 8
%1 = load i64, i64* %x, align 8
@@ -112,22 +112,22 @@ entry:
store i64 %5, i64* %z, align 8
%6 = load i64, i64* %z, align 8
%7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0), i64 %6)
store i64 ptrtoint (i8** getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 0, i64 3) to i64), i64* %x, align 8
store i64 ptrtoint (i8* @foo.Foo.W to i64), i64* %x, align 8
%8 = load i64, i64* %x, align 8
store i64 %8, i64* %z, align 8
%9 = load i64, i64* %z, align 8
%10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.2, i32 0, i32 0), i64 %9)
store i64 ptrtoint (i8** getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 0, i64 4) to i64), i64* %x, align 8
store i64 ptrtoint (i8* @foo.Foo.W1 to i64), i64* %x, align 8
%11 = load i64, i64* %x, align 8
store i64 %11, i64* %z, align 8
%12 = load i64, i64* %z, align 8
%13 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i32 0, i32 0), i64 %12)
store i64 ptrtoint ([2 x i8*]* @"foo.Foob$elements" to i64), i64* %x, align 8
store i64 ptrtoint (i8* @foo.Foob.X1 to i64), i64* %x, align 8
%14 = load i64, i64* %x, align 8
store i64 %14, i64* %z, align 8
%15 = load i64, i64* %z, align 8
%16 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.4, i32 0, i32 0), i64 %15)
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"foo.Foob$elements", i64 0, i64 1) to i64), i64* %x, align 8
store i64 ptrtoint (i8* @foo.Foob.Y2 to i64), i64* %x, align 8
%17 = load i64, i64* %x, align 8
store i64 %17, i64* %z, align 8
%18 = load i64, i64* %z, align 8

View File

@@ -23,7 +23,7 @@ fn void main()
define i64 @test.abc(i32* %0) #0 {
entry:
ret i64 ptrtoint ([1 x i8*]* @"test.Tester$elements" to i64)
ret i64 ptrtoint (i8* @test.Tester.FOO to i64)
}
define void @test.main() #0 {

View File

@@ -13,12 +13,12 @@ fn void main()
int! i = Blurg.Y!;
}
// #expect: foo.ll
/* #expect: foo.ll
define void @foo.main() #0 {
entry:
%i = alloca i32, align 4
%i.f = alloca i64, align 8
store i64 ptrtoint ([1 x i8*]* @"foo.Blurg$elements" to i64), i64* %i.f, align 8
store i64 ptrtoint (i8* @foo.Blurg.Y to i64), i64* %i.f, align 8
ret void
}

View File

@@ -1,4 +1,4 @@
// #target: macos-x64
extern fn void printf(char* c, ...);
struct ExtraSimple
@@ -42,10 +42,10 @@ fn void testSimple()
%anon = type { i32, i32 }
%anon.0 = type { double }
@introspect.c = linkonce constant i8 1
@introspect.anon = linkonce constant i8 1
@introspect.anon.1 = linkonce constant i8 1
@introspect.ExtraSimple = linkonce constant i8 1
@.typeid.pointer_access.c = linkonce constant { i8, i64 } { i8 10, i64 5 }, align 8
@.typeid.pointer_access.anon = linkonce constant { i8, i64 } { i8 10, i64 2 }, align 8
@.typeid.pointer_access.anon.1 = linkonce constant { i8, i64 } { i8 11, i64 2 }, align 8
@.typeid.pointer_access.ExtraSimple = linkonce constant { i8, i64 } { i8 10, i64 6 }, align 8
@.str = private unnamed_addr constant [71 x i8] c"a = %d, c.e = %f, c.f = %f, c.j = %f, g = %d, o0 = %f, r = %d, s = %d\0A\00", align 1
define void @pointer_access.testSimple() #0 {

View File

@@ -33,144 +33,144 @@ fn int main()
define i32 @main() #0 {
entry:
%a = alloca i32, align 4
%a.f = alloca i64, align 8
%x = alloca i32, align 4
%blockret = alloca i32, align 4
%b = alloca i32, align 4
%b.f = alloca i64, align 8
%x1 = alloca i32, align 4
%blockret2 = alloca i32, align 4
%c = alloca i32, align 4
%c.f = alloca i64, align 8
%x8 = alloca i32, align 4
%blockret9 = alloca i32, align 4
store i32 1, i32* %x, align 4
%0 = load i32, i32* %x, align 4
%intbool = icmp ne i32 %0, 0
br i1 %intbool, label %if.then, label %if.exit
%a.f = alloca i64, align 8
%x = alloca i32, align 4
%blockret = alloca i32, align 4
%b = alloca i32, align 4
%b.f = alloca i64, align 8
%x1 = alloca i32, align 4
%blockret2 = alloca i32, align 4
%c = alloca i32, align 4
%c.f = alloca i64, align 8
%x8 = alloca i32, align 4
%blockret9 = alloca i32, align 4
store i32 1, i32* %x, align 4
%0 = load i32, i32* %x, align 4
%intbool = icmp ne i32 %0, 0
br i1 %intbool, label %if.then, label %if.exit
if.then: ; preds = %entry
%1 = load i32, i32* %x, align 4
store i32 %1, i32* %blockret, align 4
br label %expr_block.exit
if.then: ; preds = %entry
%1 = load i32, i32* %x, align 4
store i32 %1, i32* %blockret, align 4
br label %expr_block.exit
if.exit: ; preds = %entry
store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %a.f, align 8
br label %after_assign
if.exit: ; preds = %entry
store i64 ptrtoint (i8* @failable_catch.MyErr.TEST to i64), i64* %a.f, align 8
br label %after_assign
expr_block.exit: ; preds = %if.then
%2 = load i32, i32* %blockret, align 4
store i32 %2, i32* %a, align 4
store i64 0, i64* %a.f, align 8
br label %after_assign
expr_block.exit: ; preds = %if.then
%2 = load i32, i32* %blockret, align 4
store i32 %2, i32* %a, align 4
store i64 0, i64* %a.f, align 8
br label %after_assign
after_assign: ; preds = %expr_block.exit, %if.exit
%3 = load i64, i64* %a.f, align 8
%not_err = icmp eq i64 %3, 0
br i1 %not_err, label %after_check, label %else_block
after_assign: ; preds = %expr_block.exit, %if.exit
%3 = load i64, i64* %a.f, align 8
%not_err = icmp eq i64 %3, 0
br i1 %not_err, label %after_check, label %else_block
after_check: ; preds = %after_assign
%4 = load i32, i32* %a, align 4
%add = add i32 %4, 3
br label %phi_block
after_check: ; preds = %after_assign
%4 = load i32, i32* %a, align 4
%add = add i32 %4, 3
br label %phi_block
else_block: ; preds = %after_assign
br label %phi_block
else_block: ; preds = %after_assign
br label %phi_block
phi_block: ; preds = %else_block, %after_check
%val = phi i32 [ %add, %after_check ], [ 2, %else_block ]
store i32 %val, i32* %x1, align 4
%5 = load i32, i32* %x1, align 4
%intbool3 = icmp ne i32 %5, 0
br i1 %intbool3, label %if.then4, label %if.exit5
phi_block: ; preds = %else_block, %after_check
%val = phi i32 [ %add, %after_check ], [ 2, %else_block ]
store i32 %val, i32* %x1, align 4
%5 = load i32, i32* %x1, align 4
%intbool3 = icmp ne i32 %5, 0
br i1 %intbool3, label %if.then4, label %if.exit5
if.then4: ; preds = %phi_block
%6 = load i32, i32* %x1, align 4
store i32 %6, i32* %blockret2, align 4
br label %expr_block.exit6
if.then4: ; preds = %phi_block
%6 = load i32, i32* %x1, align 4
store i32 %6, i32* %blockret2, align 4
br label %expr_block.exit6
if.exit5: ; preds = %phi_block
store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %b.f, align 8
br label %after_assign7
if.exit5: ; preds = %phi_block
store i64 ptrtoint (i8* @failable_catch.MyErr.TEST to i64), i64* %b.f, align 8
br label %after_assign7
expr_block.exit6: ; preds = %if.then4
%7 = load i32, i32* %blockret2, align 4
store i32 %7, i32* %b, align 4
store i64 0, i64* %b.f, align 8
br label %after_assign7
expr_block.exit6: ; preds = %if.then4
%7 = load i32, i32* %blockret2, align 4
store i32 %7, i32* %b, align 4
store i64 0, i64* %b.f, align 8
br label %after_assign7
after_assign7: ; preds = %expr_block.exit6, %if.exit5
store i32 0, i32* %x8, align 4
%8 = load i32, i32* %x8, align 4
%intbool10 = icmp ne i32 %8, 0
br i1 %intbool10, label %if.then11, label %if.exit12
after_assign7: ; preds = %expr_block.exit6, %if.exit5
store i32 0, i32* %x8, align 4
%8 = load i32, i32* %x8, align 4
%intbool10 = icmp ne i32 %8, 0
br i1 %intbool10, label %if.then11, label %if.exit12
if.then11: ; preds = %after_assign7
%9 = load i32, i32* %x8, align 4
store i32 %9, i32* %blockret9, align 4
br label %expr_block.exit13
if.then11: ; preds = %after_assign7
%9 = load i32, i32* %x8, align 4
store i32 %9, i32* %blockret9, align 4
br label %expr_block.exit13
if.exit12: ; preds = %after_assign7
store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %c.f, align 8
br label %after_assign14
if.exit12: ; preds = %after_assign7
store i64 ptrtoint (i8* @failable_catch.MyErr.TEST to i64), i64* %c.f, align 8
br label %after_assign14
expr_block.exit13: ; preds = %if.then11
%10 = load i32, i32* %blockret9, align 4
store i32 %10, i32* %c, align 4
store i64 0, i64* %c.f, align 8
br label %after_assign14
expr_block.exit13: ; preds = %if.then11
%10 = load i32, i32* %blockret9, align 4
store i32 %10, i32* %c, align 4
store i64 0, i64* %c.f, align 8
br label %after_assign14
after_assign14: ; preds = %expr_block.exit13, %if.exit12
%11 = load i64, i64* %a.f, align 8
%not_err15 = icmp eq i64 %11, 0
br i1 %not_err15, label %after_check16, label %voiderr
after_assign14: ; preds = %expr_block.exit13, %if.exit12
%11 = load i64, i64* %a.f, align 8
%not_err15 = icmp eq i64 %11, 0
br i1 %not_err15, label %after_check16, label %voiderr
after_check16: ; preds = %after_assign14
%12 = load i32, i32* %a, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i32 %12)
br label %voiderr
after_check16: ; preds = %after_assign14
%12 = load i32, i32* %a, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i32 %12)
br label %voiderr
voiderr: ; preds = %after_check16, %after_assign14
%13 = load i64, i64* %b.f, align 8
%not_err17 = icmp eq i64 %13, 0
br i1 %not_err17, label %after_check18, label %voiderr19
voiderr: ; preds = %after_check16, %after_assign14
%13 = load i64, i64* %b.f, align 8
%not_err17 = icmp eq i64 %13, 0
br i1 %not_err17, label %after_check18, label %voiderr19
after_check18: ; preds = %voiderr
%14 = load i32, i32* %b, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.1, i32 0, i32 0), i32 %14)
br label %voiderr19
after_check18: ; preds = %voiderr
%14 = load i32, i32* %b, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.1, i32 0, i32 0), i32 %14)
br label %voiderr19
voiderr19: ; preds = %after_check18, %voiderr
%15 = load i64, i64* %c.f, align 8
%not_err20 = icmp eq i64 %15, 0
br i1 %not_err20, label %after_check21, label %voiderr22
voiderr19: ; preds = %after_check18, %voiderr
%15 = load i64, i64* %c.f, align 8
%not_err20 = icmp eq i64 %15, 0
br i1 %not_err20, label %after_check21, label %voiderr22
after_check21: ; preds = %voiderr19
%16 = load i32, i32* %c, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.2, i32 0, i32 0), i32 %16)
br label %voiderr22
after_check21: ; preds = %voiderr19
%16 = load i32, i32* %c, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.2, i32 0, i32 0), i32 %16)
br label %voiderr22
voiderr22: ; preds = %after_check21, %voiderr19
%17 = load i64, i64* %c.f, align 8
%neq = icmp ne i64 %17, 0
br i1 %neq, label %if.then23, label %if.exit24
voiderr22: ; preds = %after_check21, %voiderr19
%17 = load i64, i64* %c.f, align 8
%neq = icmp ne i64 %17, 0
br i1 %neq, label %if.then23, label %if.exit24
if.then23: ; preds = %voiderr22
call void (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.3, i32 0, i32 0))
br label %if.exit24
if.then23: ; preds = %voiderr22
call void (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.3, i32 0, i32 0))
br label %if.exit24
if.exit24: ; preds = %if.then23, %voiderr22
store i32 3, i32* %c, align 4
store i64 0, i64* %c.f, align 8
%18 = load i64, i64* %c.f, align 8
%not_err25 = icmp eq i64 %18, 0
br i1 %not_err25, label %after_check26, label %voiderr27
if.exit24: ; preds = %if.then23, %voiderr22
store i32 3, i32* %c, align 4
store i64 0, i64* %c.f, align 8
%18 = load i64, i64* %c.f, align 8
%not_err25 = icmp eq i64 %18, 0
br i1 %not_err25, label %after_check26, label %voiderr27
after_check26: ; preds = %if.exit24
%19 = load i32, i32* %c, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.4, i32 0, i32 0), i32 %19)
br label %voiderr27
after_check26: ; preds = %if.exit24
%19 = load i32, i32* %c, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.4, i32 0, i32 0), i32 %19)
br label %voiderr27
voiderr27: ; preds = %after_check26, %if.exit24
ret i32 0
}
voiderr27: ; preds = %after_check26, %if.exit24
ret i32 0
}

View File

@@ -1,7 +1,7 @@
// #target: macos-x64
module examples;
import libc;
import std;
import std::io;
fn void example_for()
{
@@ -110,7 +110,7 @@ loop.body: ; preds = %loop.cond
br label %loop.cond
loop.exit: ; preds = %loop.cond
call void @"std::builtin.panic"(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.zstr, i64 0, i64 0), i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.zstr.1, i64 0, i64 0), i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.zstr.2, i64 0, i64 0), i32 14)
call void @"std::core::builtin.panic"(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.zstr, i64 0, i64 0), i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.zstr.1, i64 0, i64 0), i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.zstr.2, i64 0, i64 0), i32 14)
unreachable
unreachable_block: ; No predecessors!

View File

@@ -54,7 +54,7 @@ entry:
br i1 %eq, label %if.then, label %if.exit
if.then: ; preds = %entry
ret i64 ptrtoint ([1 x i8*]* @"demo.MathError$elements" to i64)
ret i64 ptrtoint (i8* @demo.MathError.DIVISION_BY_ZERO to i64)
if.exit: ; preds = %entry
%sifp = sitofp i32 %1 to double
@@ -114,7 +114,6 @@ after.errcheck: ; preds = %entry
br label %after_assign
after_assign: ; preds = %after.errcheck, %error
store i64 0, i64* %err, align 8
br label %testblock
testblock: ; preds = %after_assign
@@ -141,7 +140,7 @@ if.then: ; preds = %end_block
switch.entry: ; preds = %if.then
%6 = load i64, i64* %switch, align 8
%eq = icmp eq i64 ptrtoint ([1 x i8*]* @"demo.MathError$elements" to i64), %6
%eq = icmp eq i64 ptrtoint (i8* @demo.MathError.DIVISION_BY_ZERO to i64), %6
br i1 %eq, label %switch.case, label %next_if
switch.case: ; preds = %switch.entry

View File

@@ -234,8 +234,8 @@ fn Type getValue(Blob blob)
/* #expect: test.ll
%Blob.0 = type { i32 }
%Blob.1 = type { double }
%Blob = type { i32 }
%Blob.0 = type { double }
%Foo2 = type { i32 }
%Bobo = type { i16, float, i16, i16, float, i16 }
%"int[]" = type { i32*, i64 }
@@ -244,6 +244,13 @@ fn Type getValue(Blob blob)
%List = type { i64, i64, i32* }
%Foo = type { i32, i32 }
@.typeid.test.Bobo = linkonce constant { i8, i64 } { i8 10, i64 6 }, align 8
@.typeid.test.Blob = linkonce constant { i8, i64 } { i8 10, i64 2 }, align 8
@.typeid.test.Foor = linkonce constant { i8, i64 } { i8 11, i64 2 }, align 8
@.typeid.test.Foo2 = linkonce constant { i8, i64 } { i8 10, i64 1 }, align 8
@.typeid.test.Foo = linkonce constant { i8, i64 } { i8 10, i64 2 }, align 8
@.typeid.test.MyEnum = linkonce constant { i8, i64, i64 } { i8 8, i64 3, i64 0 }, align 8
define void @test.Foo2__printme(%Foo2* %0) #0 {
entry:
%1 = getelementptr inbounds %Foo2, %Foo2* %0, i32 0, i32 0
@@ -432,8 +439,8 @@ entry:
%elements = alloca i32, align 4
%array = alloca %List, align 8
%i1 = alloca i32, align 4
%a = alloca %Blob.0, align 4
%b = alloca %Blob.1, align 8
%a = alloca %Blob, align 4
%b = alloca %Blob.0, align 8
%tempcoerce = alloca double, align 8
%ddx = alloca %Foo, align 4
%fro = alloca i32, align 4
@@ -515,15 +522,15 @@ loop.body5: ; preds = %loop.cond2
loop.exit8: ; preds = %loop.cond2
call void @"std::array::list.int.List__free"(%List* %array)
%21 = bitcast %Blob.0* %a to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %21, i8* align 4 bitcast (%Blob.0* @.__const.6 to i8*), i32 4, i1 false)
%22 = bitcast %Blob.1* %b to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %22, i8* align 8 bitcast (%Blob.1* @.__const.7 to i8*), i32 8, i1 false)
%23 = getelementptr inbounds %Blob.0, %Blob.0* %a, i32 0, i32 0
%21 = bitcast %Blob* %a to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %21, i8* align 4 bitcast (%Blob* @.__const.6 to i8*), i32 4, i1 false)
%22 = bitcast %Blob.0* %b to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %22, i8* align 8 bitcast (%Blob.0* @.__const.7 to i8*), i32 8, i1 false)
%23 = getelementptr inbounds %Blob, %Blob* %a, i32 0, i32 0
%24 = load i32, i32* %23, align 4
%25 = call i32 @test2.int.getValue(i32 %24)
%26 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.8, i32 0, i32 0), i32 %25)
%27 = getelementptr inbounds %Blob.1, %Blob.1* %b, i32 0, i32 0
%27 = getelementptr inbounds %Blob.0, %Blob.0* %b, i32 0, i32 0
%28 = bitcast double* %tempcoerce to i8*
%29 = bitcast double* %27 to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %28, i8* align 8 %29, i32 8, i1 false)

View File

@@ -236,8 +236,8 @@ fn Type getValue(Blob blob)
/* #expect: test.ll
%Blob.0 = type { i32 }
%Blob.1 = type { double }
%Blob = type { i32 }
%Blob.0 = type { double }
%Foo2 = type { i32 }
%Bobo = type { i16, float, i16, i16, float, i16 }
%"int[]" = type { i32*, i64 }
@@ -246,21 +246,24 @@ fn Type getValue(Blob blob)
%List = type { i64, i64, i32* }
%Foo = type { i32, i32 }
$introspect.Bobo = comdat any
$.typeid.test.Bobo = comdat any
$introspect.Blob = comdat any
$.typeid.test.Blob = comdat any
$introspect.Foor = comdat any
$.typeid.test.Foor = comdat any
$introspect.Foo2 = comdat any
$.typeid.test.Foo2 = comdat any
$introspect.Foo = comdat any
$.typeid.test.Foo = comdat any
@introspect.Bobo = linkonce constant i8 1, comdat
@introspect.Blob = linkonce constant i8 1, comdat
@introspect.Foor = linkonce constant i8 1, comdat
@introspect.Foo2 = linkonce constant i8 1, comdat
@introspect.Foo = linkonce constant i8 1, comdat
$.typeid.test.MyEnum = comdat any
@.typeid.test.Bobo = linkonce constant { i8, i64 } { i8 10, i64 6 }, comdat, align 8
@.typeid.test.Blob = linkonce constant { i8, i64 } { i8 10, i64 2 }, comdat, align 8
@.typeid.test.Foor = linkonce constant { i8, i64 } { i8 11, i64 2 }, comdat, align 8
@.typeid.test.Foo2 = linkonce constant { i8, i64 } { i8 10, i64 1 }, comdat, align 8
@.typeid.test.Foo = linkonce constant { i8, i64 } { i8 10, i64 2 }, comdat, align 8
@.typeid.test.MyEnum = linkonce constant { i8, i64, i64 } { i8 8, i64 3, i64 0 }, comdat, align 8
@.str = private unnamed_addr constant [13 x i8] c"helloWorld!\0A\00", align 1
@test_static.x = internal unnamed_addr global i32 1, align 4
@.str.1 = private unnamed_addr constant [16 x i8] c"Test static %d\0A\00", align 1
@@ -269,8 +272,8 @@ $introspect.Foo = comdat any
@.str.3 = private unnamed_addr constant [14 x i8] c"Elements: %d\0A\00", align 1
@.str.4 = private unnamed_addr constant [7 x i8] c"Hello\0A\00", align 1
@.str.5 = private unnamed_addr constant [17 x i8] c"Element[%d]: %d\0A\00", align 1
@.__const.6 = private unnamed_addr constant %Blob.0 { i32 42 }, align 4
@.__const.7 = private unnamed_addr constant %Blob.1 { double 3.330000e+01 }, align 8
@.__const.6 = private unnamed_addr constant %Blob { i32 42 }, align 4
@.__const.7 = private unnamed_addr constant %Blob.0 { double 3.330000e+01 }, align 8
@.str.8 = private unnamed_addr constant [10 x i8] c"a was %d\0A\00", align 1
@.str.9 = private unnamed_addr constant [10 x i8] c"b was %f\0A\00", align 1
@.str.10 = private unnamed_addr constant [17 x i8] c"Mult int was %d\0A\00", align 1
@@ -287,6 +290,7 @@ $introspect.Foo = comdat any
@.str.21 = private unnamed_addr constant [12 x i8] c"Foo is: %d\0A\00", align 1
@.str.22 = private unnamed_addr constant [9 x i8] c"Mutating\00", align 1
; Function Attrs: nounwind
define void @test.Foo2__printme(%Foo2* %0) #0 {
entry:
%1 = getelementptr inbounds %Foo2, %Foo2* %0, i32 0, i32 0
@@ -295,6 +299,7 @@ entry:
ret void
}
; Function Attrs: nounwind
define i32 @test.Foo2__mutate(%Foo2* %0) #0 {
entry:
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.22, i32 0, i32 0))
@@ -465,8 +470,8 @@ entry:
%elements = alloca i32, align 4
%array = alloca %List, align 8
%i1 = alloca i32, align 4
%a = alloca %Blob.0, align 4
%b = alloca %Blob.1, align 8
%a = alloca %Blob, align 4
%b = alloca %Blob.0, align 8
%tempcoerce = alloca i64, align 8
%ddx = alloca %Foo, align 4
%fro = alloca i32, align 4
@@ -554,15 +559,15 @@ loop.body5: ; preds = %loop.cond2
loop.exit8: ; preds = %loop.cond2
call void @"std::array::list.int.List__free"(%List* %array)
%21 = bitcast %Blob.0* %a to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %21, i8* align 4 bitcast (%Blob.0* @.__const.6 to i8*), i32 4, i1 false)
%22 = bitcast %Blob.1* %b to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %22, i8* align 8 bitcast (%Blob.1* @.__const.7 to i8*), i32 8, i1 false)
%23 = getelementptr inbounds %Blob.0, %Blob.0* %a, i32 0, i32 0
%21 = bitcast %Blob* %a to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %21, i8* align 4 bitcast (%Blob* @.__const.6 to i8*), i32 4, i1 false)
%22 = bitcast %Blob.0* %b to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %22, i8* align 8 bitcast (%Blob.0* @.__const.7 to i8*), i32 8, i1 false)
%23 = getelementptr inbounds %Blob, %Blob* %a, i32 0, i32 0
%24 = load i32, i32* %23, align 4
%25 = call i32 @test2.int.getValue(i32 %24)
%26 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.8, i32 0, i32 0), i32 %25)
%27 = getelementptr inbounds %Blob.1, %Blob.1* %b, i32 0, i32 0
%27 = getelementptr inbounds %Blob.0, %Blob.0* %b, i32 0, i32 0
%28 = bitcast i64* %tempcoerce to i8*
%29 = bitcast double* %27 to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %28, i8* align 8 %29, i32 8, i1 false)

View File

@@ -22,6 +22,8 @@ fn int main()
/* #expect: test.ll
@.typeid.int = linkonce constant { i8, i16 } { i8 2, i16 32 }, align 2
define void @test.retest(i8* %0, i64 %1) #0 {
entry:
%foo = alloca %"variant[]", align 8
@@ -74,7 +76,7 @@ entry:
store i32 1, i32* %taddr, align 4
%0 = bitcast i32* %taddr to i8*
%1 = insertvalue %variant undef, i8* %0, 0
%2 = insertvalue %variant %1, i64 5, 1
%2 = insertvalue %variant %1, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), 1
%3 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots, i64 0, i64 0
store %variant %2, %variant* %3, align 16
%4 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1
@@ -91,7 +93,7 @@ entry:
store i32 1, i32* %taddr3, align 4
%10 = bitcast i32* %taddr3 to i8*
%11 = insertvalue %variant undef, i8* %10, 0
%12 = insertvalue %variant %11, i64 5, 1
%12 = insertvalue %variant %11, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), 1
%13 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots2, i64 0, i64 0
store %variant %12, %variant* %13, align 16
%14 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg1, i32 0, i32 1

View File

@@ -1,5 +1,5 @@
module test;
import std::mem;
import std::core::mem;
import hello_world; // #error: No module named
import test; // #error: Importing the current

View File

@@ -1,3 +1,3 @@
import std::io, std::mem;
import std::io, std::core::mem;
int foo = 1;

View File

@@ -38,8 +38,8 @@ fn int test()
%"int[]" = type { i32*, i64 }
%"Bar[]" = type { %Bar*, i64 }
@introspect.Baz = linkonce constant i8 1
@introspect.Bar = linkonce constant i8 1
@.typeid.general_tests.Baz = linkonce constant { i8, i64 } { i8 11, i64 2 }, align 8
@.typeid.general_tests.Bar = linkonce constant { i8, i64 } { i8 10, i64 2 }, align 8
@.__const = private unnamed_addr constant { i32, [4 x i8] } { i32 1, [4 x i8] undef }, align 8
@test.foo1 = internal unnamed_addr global i32 22, align 4
@.str = private unnamed_addr constant [7 x i8] c"Hello!\00", align 1

View File

@@ -1,6 +1,5 @@
// #target: macos-x64
import std::io;
import std::mem;
import libc;
union Baz
{
@@ -36,8 +35,8 @@ fn int main()
%Bar = type { i32, i32 }
%"Bar[]" = type { %Bar*, i64 }
@introspect.Baz = linkonce constant i8 1, align 1
@introspect.Bar = linkonce constant i8 1, align 1
@.typeid.statics.Baz = linkonce constant { i8, i64 } { i8 11, i64 2 }, align 8
@.typeid.statics.Bar = linkonce constant { i8, i64 } { i8 10, i64 2 }, align 8
@.taddr = private global [1 x %Bar] [%Bar { i32 1, i32 2 }], align 8
@test.c = internal unnamed_addr global %"Bar[]" { %Bar* getelementptr inbounds ([1 x %Bar], [1 x %Bar]* @.taddr, i32 0, i32 0), i64 1 }, align 8
@.str = private unnamed_addr constant [7 x i8] c"%d %d\0A\00", align 1

View File

@@ -1,7 +1,7 @@
// #target: macos-x64
import std::io;
import std::mem;
import std::core::mem;
import libc;
union Baz
{
@@ -51,8 +51,8 @@ fn int main()
%"int[]" = type { i32*, i64 }
%Baz = type { double }
@introspect.Baz = linkonce constant i8 1, align 1
@introspect.Bar = linkonce constant i8 1, align 1
@.typeid.subarrays.Baz = linkonce constant { i8, i64 } { i8 11, i64 2 }, align 8
@.typeid.subarrays.Bar = linkonce constant { i8, i64 } { i8 10, i64 2 }, align 8
@.taddr = private global [2 x %Bar] [%Bar { i32 3, i32 4 }, %Bar { i32 8, i32 9 }], align 8
@subarrays.arrbar = local_unnamed_addr global %"Bar[]" { %Bar* getelementptr inbounds ([2 x %Bar], [2 x %Bar]* @.taddr, i32 0, i32 0), i64 2 }, align 8
@.taddr.3 = private global [2 x i32] [i32 1, i32 2], align 4

View File

@@ -78,7 +78,7 @@ fn void main()
%Foo = type { i16, i8, i8, i16, i16 }
@introspect.Foo = linkonce constant i8 1
@.typeid.userland_bitcast.Foo = linkonce constant { i8, i64 } { i8 10, i64 5 }, align 8
@.str = private unnamed_addr constant [16 x i8] c"%f => %d => %f\0A\00", align 1
@.str.1 = private unnamed_addr constant [18 x i8] c"%e => %llu => %e\0A\00", align 1
@@ -104,7 +104,6 @@ entry:
store i16 %0, i16* %6, align 2
%7 = load %Foo, %Foo* %z, align 2
store %Foo %7, %Foo* %expr, align 2
store i64 0, i64* %x, align 8
%ptrptr = bitcast %Foo* %expr to i16*
store i16* %ptrptr, i16** %b, align 8
%ptrptr1 = bitcast i64* %x to i16*
@@ -145,14 +144,6 @@ entry:
%i = alloca i64, align 8
%tempcoerce = alloca i32, align 4
store float %0, float* %expr, align 4
%1 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 0
store i8 0, i8* %1, align 1
%2 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 1
store i8 0, i8* %2, align 1
%3 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 2
store i8 0, i8* %3, align 1
%4 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 3
store i8 0, i8* %4, align 1
%ptrptr = bitcast float* %expr to i8*
store i8* %ptrptr, i8** %b, align 8
%ptrptr1 = bitcast [4 x i8]* %x to i8*
@@ -161,30 +152,30 @@ entry:
br label %loop.cond
loop.cond: ; preds = %loop.body, %entry
%5 = load i64, i64* %i, align 8
%lt = icmp ult i64 %5, 4
%1 = load i64, i64* %i, align 8
%lt = icmp ult i64 %1, 4
br i1 %lt, label %loop.body, label %loop.exit
loop.body: ; preds = %loop.cond
%6 = load i8*, i8** %to, align 8
%2 = load i8*, i8** %to, align 8
%3 = load i64, i64* %i, align 8
%ptroffset = getelementptr inbounds i8, i8* %2, i64 %3
%4 = load i8*, i8** %b, align 8
%5 = load i64, i64* %i, align 8
%ptroffset2 = getelementptr inbounds i8, i8* %4, i64 %5
%6 = load i8, i8* %ptroffset2, align 1
store i8 %6, i8* %ptroffset, align 1
%7 = load i64, i64* %i, align 8
%ptroffset = getelementptr inbounds i8, i8* %6, i64 %7
%8 = load i8*, i8** %b, align 8
%9 = load i64, i64* %i, align 8
%ptroffset2 = getelementptr inbounds i8, i8* %8, i64 %9
%10 = load i8, i8* %ptroffset2, align 1
store i8 %10, i8* %ptroffset, align 1
%11 = load i64, i64* %i, align 8
%add = add i64 %11, 1
%add = add i64 %7, 1
store i64 %add, i64* %i, align 8
br label %loop.cond
loop.exit: ; preds = %loop.cond
%12 = bitcast i32* %tempcoerce to i8*
%13 = bitcast [4 x i8]* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %12, i8* align 1 %13, i32 4, i1 false)
%14 = load i32, i32* %tempcoerce, align 4
ret i32 %14
%8 = bitcast i32* %tempcoerce to i8*
%9 = bitcast [4 x i8]* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %8, i8* align 1 %9, i32 4, i1 false)
%10 = load i32, i32* %tempcoerce, align 4
ret i32 %10
}
define void @userland_bitcast.main() #0 {
@@ -218,7 +209,6 @@ entry:
store float 0x4028B4BC60000000, float* %f, align 4
%0 = load float, float* %f, align 4
store float %0, float* %expr, align 4
store i32 0, i32* %x, align 4
%ptrptr = bitcast float* %expr to i32*
store i32* %ptrptr, i32** %b, align 8
store i32* %x, i32** %to, align 8
@@ -249,7 +239,6 @@ loop.exit: ; preds = %loop.cond
store i32 %8, i32* %i, align 4
%9 = load i32, i32* %i, align 4
store i32 %9, i32* %expr3, align 4
store float 0.000000e+00, float* %x4, align 4
store i32* %expr3, i32** %b5, align 8
%ptrptr7 = bitcast float* %x4 to i32*
store i32* %ptrptr7, i32** %to6, align 8
@@ -287,7 +276,6 @@ loop.exit15: ; preds = %loop.cond9
store double 1.235300e+268, double* %d, align 8
%21 = load double, double* %d, align 8
store double %21, double* %expr17, align 8
store i64 0, i64* %x18, align 8
%ptrptr20 = bitcast double* %expr17 to i64*
store i64* %ptrptr20, i64** %b19, align 8
store i64* %x18, i64** %to21, align 8
@@ -318,7 +306,6 @@ loop.exit29: ; preds = %loop.cond23
store i64 %29, i64* %l, align 8
%30 = load double, double* %d, align 8
store double %30, double* %expr30, align 8
store double 0.000000e+00, double* %x31, align 8
%ptrptr33 = bitcast double* %expr30 to i64*
store i64* %ptrptr33, i64** %b32, align 8
%ptrptr35 = bitcast double* %x31 to i64*

View File

@@ -26,6 +26,11 @@ fn void main()
/* #expect: foo.ll
%variant = type { i8*, i64 }
%"int[]" = type { i32*, i64 }
@.typeid.int = linkonce constant { i8, i16 } { i8 2, i16 32 }, align 2
define void @foo.test1(i64 %0, i8* %1) #0 {
entry:
%z = alloca %variant, align 8
@@ -76,7 +81,7 @@ entry:
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([2 x i32]* @.__const to i8*), i32 8, i1 false)
%1 = bitcast i32* %x to i8*
%2 = insertvalue %variant undef, i8* %1, 0
%3 = insertvalue %variant %2, i64 5, 1
%3 = insertvalue %variant %2, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), 1
store %variant %3, %variant* %taddr, align 8
%4 = bitcast %variant* %taddr to { i64, i8* }*
%5 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %4, i32 0, i32 0

View File

@@ -0,0 +1,29 @@
// #safe: yes
module foo;
fn void main()
{
int* x;
int y = *x;
}
/* #expect: foo.ll
define void @foo.main() #0 {
entry:
%x = alloca i32*, align 8
%y = alloca i32, align 4
store i32* null, i32** %x, align 8
%0 = load i32*, i32** %x, align 8
%checknull = icmp eq i32* %0, null
br i1 %checknull, label %panic, label %checkok
panic: ; preds = %entry
call void @"std::core::builtin.panic"(i8* getelementptr inbounds ([28 x i8], [28 x i8]* @.zstr, i64 0, i64 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.zstr.1, i64 0, i64 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.zstr.2, i64 0, i64 0), i32 6)
br label %checkok
checkok: ; preds = %panic, %entry
%1 = load i32, i32* %0, align 8
store i32 %1, i32* %y, align 4
ret void
}

View File

@@ -86,7 +86,7 @@ fn void main()
%Foo = type { [3 x i32] }
@introspect.Foo = linkonce constant i8 1
@.typeid.foo.Foo = linkonce constant { i8, i64 } { i8 10, i64 1 }, align 8
@.str = private unnamed_addr constant [11 x i8] c"getFields\0A\00", align 1
@.str.1 = private unnamed_addr constant [11 x i8] c"Call made\0A\00", align 1
@.__const = private unnamed_addr constant %Foo { [3 x i32] [i32 1, i32 5, i32 7] }, align 4

View File

@@ -13,15 +13,14 @@ fn Event test(int x)
return x ? foo : bar;
}
// #expect: test.ll
/* #expect: test.ll
%Event = type { i32 }
@introspect.Event = linkonce constant i8 1
@.typeid.test.Event = linkonce constant { i8, i64 } { i8 10, i64 1 }, align 8
@.__const = private unnamed_addr constant %Event { i32 1 }, align 4
@.__const.1 = private unnamed_addr constant %Event { i32 2 }, align 4
; Function Attrs: nounwind
define i32 @test.test(i32 %0) #0 {
entry:
%foo = alloca %Event, align 4

View File

@@ -1,4 +1,4 @@
// #target: macos-x64
module test;
struct Point
@@ -12,11 +12,11 @@ fn void test1()
Point p = { 5, 6 };
}
// #expect: test.ll
/* #expect: test.ll
%Point = type { i32, i32 }
@introspect.Point = linkonce constant i8 1
@.typeid.test.Point = linkonce constant { i8, i64 } { i8 10, i64 2 }, align 8
@.__const = private unnamed_addr constant %Point { i32 5, i32 6 }, align 4
define void @test.test1() #0 {

View File

@@ -1,3 +1,4 @@
// #target: macos-x64
struct StructA
{
int a;
@@ -20,7 +21,7 @@ fn void test()
StructB b3 = { .b = { } };
}
// #expect: struct_codegen_empty.ll
/* #expect: struct_codegen_empty.ll
%a = alloca %StructA, align 4
%a2 = alloca %StructA, align 4

View File

@@ -1,3 +1,4 @@
// #target: macos-x64
module structo;
struct Foo
@@ -21,7 +22,7 @@ private Foo foo8 = FOO7;
%Foo = type { i32, i64 }
@introspect.Foo = linkonce constant i8 1
@.typeid.structo.Foo = linkonce constant { i8, i64 } { i8 10, i64 2 }, align 8
@structo.x = protected unnamed_addr global i64 16, align 8
@structo.foo1 = protected unnamed_addr global %Foo { i32 1, i64 2 }, align 8
@structo.foo2 = protected unnamed_addr global %Foo { i32 2, i64 0 }, align 8
@@ -30,4 +31,4 @@ private Foo foo8 = FOO7;
@structo.foo5 = protected unnamed_addr global %Foo zeroinitializer, align 8
@structo.foo6 = protected unnamed_addr global %Foo zeroinitializer, align 8
@structo.FOO7 = protected unnamed_addr constant %Foo { i32 1, i64 2 }, align 8
@structo.foo8 = protected unnamed_addr global %Foo { i32 1, i64 2 }, align 8
@structo.foo8 = protected unnamed_addr global %Foo { i32 1, i64 2 }, align 8

View File

@@ -58,6 +58,10 @@ fn int main()
/* #expect: foo.ll
@.typeid.int = linkonce constant { i8, i16 } { i8 2, i16 32 }, align 2
@.typeid.double = linkonce constant { i8, i16 } { i8 4, i16 64 }, align 2
@.typeid.bool = linkonce constant { i8 } { i8 1 }, align 1
define void @foo.test(i64 %0, i8* %1) #0 {
entry:
%z = alloca %variant, align 8
@@ -76,7 +80,7 @@ entry:
switch.entry: ; preds = %entry
%6 = load i64, i64* %switch, align 8
%eq = icmp eq i64 5, %6
%eq = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), %6
br i1 %eq, label %switch.case, label %next_if
switch.case: ; preds = %switch.entry
@@ -90,7 +94,7 @@ switch.case: ; preds = %switch.entry
br label %switch.exit
next_if: ; preds = %switch.entry
%eq2 = icmp eq i64 15, %6
%eq2 = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), %6
br i1 %eq2, label %switch.case3, label %next_if5
switch.case3: ; preds = %next_if
@@ -130,14 +134,14 @@ entry:
%4 = bitcast %variant* %anon to i8*
%5 = bitcast %variant* %y to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %4, i8* align 8 %5, i32 16, i1 false)
%6 = getelementptr inbounds %variant, %variant* %anon, i32 0, i32 1
%6 = getelementptr inbounds %variant, %variant* %y, i32 0, i32 1
%7 = load i64, i64* %6, align 8
store i64 %7, i64* %switch, align 8
br label %switch.entry
switch.entry: ; preds = %entry
%8 = load i64, i64* %switch, align 8
%eq = icmp eq i64 5, %8
%eq = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), %8
br i1 %eq, label %switch.case, label %next_if
switch.case: ; preds = %switch.entry
@@ -148,7 +152,7 @@ switch.case: ; preds = %switch.entry
store i32 12, i32* %taddr, align 4
%12 = bitcast i32* %taddr to i8*
%13 = insertvalue %variant undef, i8* %12, 0
%14 = insertvalue %variant %13, i64 5, 1
%14 = insertvalue %variant %13, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), 1
store %variant %14, %variant* %y, align 8
%15 = load i32*, i32** %z, align 8
%16 = load i32, i32* %15, align 8
@@ -156,7 +160,7 @@ switch.case: ; preds = %switch.entry
br label %switch.exit
next_if: ; preds = %switch.entry
%eq1 = icmp eq i64 15, %8
%eq1 = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), %8
br i1 %eq1, label %switch.case2, label %next_if4
switch.case2: ; preds = %next_if
@@ -195,14 +199,14 @@ entry:
%4 = bitcast %variant* %anon to i8*
%5 = bitcast %variant* %y to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %4, i8* align 8 %5, i32 16, i1 false)
%6 = getelementptr inbounds %variant, %variant* %anon, i32 0, i32 1
%6 = getelementptr inbounds %variant, %variant* %y, i32 0, i32 1
%7 = load i64, i64* %6, align 8
store i64 %7, i64* %switch, align 8
br label %switch.entry
switch.entry: ; preds = %entry
%8 = load i64, i64* %switch, align 8
%eq = icmp eq i64 5, %8
%eq = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), %8
br i1 %eq, label %switch.case, label %next_if
switch.case: ; preds = %switch.entry
@@ -216,7 +220,7 @@ switch.case: ; preds = %switch.entry
br label %switch.exit
next_if: ; preds = %switch.entry
%eq1 = icmp eq i64 15, %8
%eq1 = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), %8
br i1 %eq1, label %switch.case2, label %next_if4
switch.case2: ; preds = %next_if
@@ -263,7 +267,7 @@ entry:
store double 1.230000e+02, double* %taddr, align 8
%0 = bitcast double* %taddr to i8*
%1 = insertvalue %variant undef, i8* %0, 0
%2 = insertvalue %variant %1, i64 15, 1
%2 = insertvalue %variant %1, i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), 1
store %variant %2, %variant* %taddr1, align 8
%3 = bitcast %variant* %taddr1 to { i64, i8* }*
%4 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %3, i32 0, i32 0
@@ -274,7 +278,7 @@ entry:
store i32 1, i32* %taddr2, align 4
%6 = bitcast i32* %taddr2 to i8*
%7 = insertvalue %variant undef, i8* %6, 0
%8 = insertvalue %variant %7, i64 5, 1
%8 = insertvalue %variant %7, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), 1
store %variant %8, %variant* %taddr3, align 8
%9 = bitcast %variant* %taddr3 to { i64, i8* }*
%10 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %9, i32 0, i32 0
@@ -284,7 +288,7 @@ entry:
call void @foo.test(i64 %lo4, i8* %hi5)
store i8 1, i8* %taddr6, align 1
%12 = insertvalue %variant undef, i8* %taddr6, 0
%13 = insertvalue %variant %12, i64 2, 1
%13 = insertvalue %variant %12, i64 ptrtoint ({ i8 }* @.typeid.bool to i64), 1
store %variant %13, %variant* %taddr7, align 8
%14 = bitcast %variant* %taddr7 to { i64, i8* }*
%15 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %14, i32 0, i32 0
@@ -295,7 +299,7 @@ entry:
store double 1.235000e+02, double* %taddr10, align 8
%17 = bitcast double* %taddr10 to i8*
%18 = insertvalue %variant undef, i8* %17, 0
%19 = insertvalue %variant %18, i64 15, 1
%19 = insertvalue %variant %18, i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), 1
store %variant %19, %variant* %taddr11, align 8
%20 = bitcast %variant* %taddr11 to { i64, i8* }*
%21 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %20, i32 0, i32 0
@@ -306,7 +310,7 @@ entry:
store i32 1, i32* %taddr14, align 4
%23 = bitcast i32* %taddr14 to i8*
%24 = insertvalue %variant undef, i8* %23, 0
%25 = insertvalue %variant %24, i64 5, 1
%25 = insertvalue %variant %24, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), 1
store %variant %25, %variant* %taddr15, align 8
%26 = bitcast %variant* %taddr15 to { i64, i8* }*
%27 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %26, i32 0, i32 0
@@ -316,7 +320,7 @@ entry:
call void @foo.test2(i64 %lo16, i8* %hi17)
store i8 1, i8* %taddr18, align 1
%29 = insertvalue %variant undef, i8* %taddr18, 0
%30 = insertvalue %variant %29, i64 2, 1
%30 = insertvalue %variant %29, i64 ptrtoint ({ i8 }* @.typeid.bool to i64), 1
store %variant %30, %variant* %taddr19, align 8
%31 = bitcast %variant* %taddr19 to { i64, i8* }*
%32 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %31, i32 0, i32 0
@@ -327,7 +331,7 @@ entry:
store double 1.240000e+02, double* %taddr22, align 8
%34 = bitcast double* %taddr22 to i8*
%35 = insertvalue %variant undef, i8* %34, 0
%36 = insertvalue %variant %35, i64 15, 1
%36 = insertvalue %variant %35, i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), 1
store %variant %36, %variant* %taddr23, align 8
%37 = bitcast %variant* %taddr23 to { i64, i8* }*
%38 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %37, i32 0, i32 0
@@ -338,7 +342,7 @@ entry:
store i32 2, i32* %taddr26, align 4
%40 = bitcast i32* %taddr26 to i8*
%41 = insertvalue %variant undef, i8* %40, 0
%42 = insertvalue %variant %41, i64 5, 1
%42 = insertvalue %variant %41, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), 1
store %variant %42, %variant* %taddr27, align 8
%43 = bitcast %variant* %taddr27 to { i64, i8* }*
%44 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %43, i32 0, i32 0
@@ -348,7 +352,7 @@ entry:
call void @foo.test3(i64 %lo28, i8* %hi29)
store i8 1, i8* %taddr30, align 1
%46 = insertvalue %variant undef, i8* %taddr30, 0
%47 = insertvalue %variant %46, i64 2, 1
%47 = insertvalue %variant %46, i64 ptrtoint ({ i8 }* @.typeid.bool to i64), 1
store %variant %47, %variant* %taddr31, align 8
%48 = bitcast %variant* %taddr31 to { i64, i8* }*
%49 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %48, i32 0, i32 0

View File

@@ -30,6 +30,10 @@ fn int main()
/* #expect: foo.ll
@.typeid.int = linkonce constant { i8, i16 } { i8 2, i16 32 }, align 2
@.typeid.double = linkonce constant { i8, i16 } { i8 4, i16 64 }, align 2
@.typeid.bool = linkonce constant { i8 } { i8 1 }, align 1
define void @foo.test(i64 %0, i8* %1) #0 {
entry:
%z = alloca %variant, align 8
@@ -48,7 +52,7 @@ entry:
switch.entry: ; preds = %entry
%6 = load i64, i64* %switch, align 8
%eq = icmp eq i64 5, %6
%eq = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), %6
br i1 %eq, label %switch.case, label %next_if
switch.case: ; preds = %switch.entry
@@ -64,7 +68,7 @@ switch.case: ; preds = %switch.entry
br label %switch.exit
next_if: ; preds = %switch.entry
%eq2 = icmp eq i64 15, %6
%eq2 = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), %6
br i1 %eq2, label %switch.case3, label %next_if5
switch.case3: ; preds = %next_if
@@ -87,7 +91,7 @@ switch.default: ; preds = %next_if5
switch.exit: ; preds = %switch.default, %switch.case3, %switch.case
%18 = getelementptr inbounds %variant, %variant* %z, i32 0, i32 1
%19 = load i64, i64* %18, align 8
%eq6 = icmp eq i64 %19, 5
%eq6 = icmp eq i64 %19, ptrtoint ({ i8, i16 }* @.typeid.int to i64)
br i1 %eq6, label %if.then, label %if.exit
if.then: ; preds = %switch.exit
@@ -114,7 +118,7 @@ entry:
store double 1.230000e+02, double* %taddr, align 8
%0 = bitcast double* %taddr to i8*
%1 = insertvalue %variant undef, i8* %0, 0
%2 = insertvalue %variant %1, i64 15, 1
%2 = insertvalue %variant %1, i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), 1
store %variant %2, %variant* %taddr1, align 8
%3 = bitcast %variant* %taddr1 to { i64, i8* }*
%4 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %3, i32 0, i32 0
@@ -125,7 +129,7 @@ entry:
store i32 1, i32* %taddr2, align 4
%6 = bitcast i32* %taddr2 to i8*
%7 = insertvalue %variant undef, i8* %6, 0
%8 = insertvalue %variant %7, i64 5, 1
%8 = insertvalue %variant %7, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), 1
store %variant %8, %variant* %taddr3, align 8
%9 = bitcast %variant* %taddr3 to { i64, i8* }*
%10 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %9, i32 0, i32 0
@@ -135,7 +139,7 @@ entry:
call void @foo.test(i64 %lo4, i8* %hi5)
store i8 1, i8* %taddr6, align 1
%12 = insertvalue %variant undef, i8* %taddr6, 0
%13 = insertvalue %variant %12, i64 2, 1
%13 = insertvalue %variant %12, i64 ptrtoint ({ i8 }* @.typeid.bool to i64), 1
store %variant %13, %variant* %taddr7, align 8
%14 = bitcast %variant* %taddr7 to { i64, i8* }*
%15 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %14, i32 0, i32 0

View File

@@ -67,7 +67,11 @@ fn void main()
%variant = type { i8*, i64 }
%"variant[]" = type { %variant*, i64 }
@"int*" = weak constant i8 1
@.typeid.int = linkonce constant { i8, i16 } { i8 2, i16 32 }, align 2
@.typeid.double = linkonce constant { i8, i16 } { i8 4, i16 64 }, align 2
@.typeid.variant = linkonce constant { i8 } { i8 7 }, align 1
@".typeid.int*" = linkonce constant { i8, i64 } { i8 15, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64) }, align 8
@.typeid.bool = linkonce constant { i8 } { i8 1 }, align 1
define void @foo.test(i64 %0, i8* %1) #0 {
entry:
@@ -85,7 +89,7 @@ entry:
switch.entry: ; preds = %entry
%6 = load i64, i64* %switch, align 8
%eq = icmp eq i64 5, %6
%eq = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), %6
br i1 %eq, label %switch.case, label %next_if
switch.case: ; preds = %switch.entry
@@ -93,7 +97,7 @@ switch.case: ; preds = %switch.entry
br label %switch.exit
next_if: ; preds = %switch.entry
%eq1 = icmp eq i64 15, %6
%eq1 = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), %6
br i1 %eq1, label %switch.case2, label %next_if3
switch.case2: ; preds = %next_if
@@ -101,7 +105,7 @@ switch.case2: ; preds = %next_if
br label %switch.exit
next_if3: ; preds = %next_if
%eq4 = icmp eq i64 17, %6
%eq4 = icmp eq i64 ptrtoint ({ i8 }* @.typeid.variant to i64), %6
br i1 %eq4, label %switch.case5, label %next_if6
switch.case5: ; preds = %next_if3
@@ -109,7 +113,7 @@ switch.case5: ; preds = %next_if3
br label %switch.exit
next_if6: ; preds = %next_if3
%eq7 = icmp eq i64 ptrtoint (i8* @"int*" to i64), %6
%eq7 = icmp eq i64 ptrtoint ({ i8, i64 }* @".typeid.int*" to i64), %6
br i1 %eq7, label %switch.case8, label %next_if9
switch.case8: ; preds = %next_if6
@@ -197,12 +201,12 @@ entry:
store i32 1, i32* %taddr, align 4
%0 = bitcast i32* %taddr to i8*
%1 = insertvalue %variant undef, i8* %0, 0
%2 = insertvalue %variant %1, i64 5, 1
%2 = insertvalue %variant %1, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), 1
store %variant %2, %variant* %x, align 8
store i32 0, i32* %z, align 4
%3 = bitcast i32* %z to i8*
%4 = insertvalue %variant undef, i8* %3, 0
%5 = insertvalue %variant %4, i64 5, 1
%5 = insertvalue %variant %4, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), 1
store %variant %5, %variant* %y, align 8
%6 = getelementptr inbounds %variant, %variant* %y, i32 0, i32 1
%7 = load i64, i64* %6, align 8
@@ -212,7 +216,7 @@ entry:
store i64 %9, i64* %h, align 8
%10 = getelementptr inbounds %variant, %variant* %y, i32 0, i32 1
%11 = load i64, i64* %10, align 8
%eq = icmp eq i64 %11, 5
%eq = icmp eq i64 %11, ptrtoint ({ i8, i16 }* @.typeid.int to i64)
br i1 %eq, label %if.then, label %if.exit
if.then: ; preds = %entry
@@ -222,7 +226,7 @@ if.then: ; preds = %entry
if.exit: ; preds = %if.then, %entry
%12 = getelementptr inbounds %variant, %variant* %x, i32 0, i32 1
%13 = load i64, i64* %12, align 8
%eq1 = icmp eq i64 %13, 5
%eq1 = icmp eq i64 %13, ptrtoint ({ i8, i16 }* @.typeid.int to i64)
br i1 %eq1, label %if.then2, label %if.exit3
if.then2: ; preds = %if.exit
@@ -233,15 +237,15 @@ if.exit3: ; preds = %if.then2, %if.exit
store double 1.000000e+00, double* %taddr4, align 8
%14 = bitcast double* %taddr4 to i8*
%15 = insertvalue %variant undef, i8* %14, 0
%16 = insertvalue %variant %15, i64 15, 1
%16 = insertvalue %variant %15, i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), 1
store %variant %16, %variant* %y, align 8
%17 = bitcast %variant* %x to i8*
%18 = insertvalue %variant undef, i8* %17, 0
%19 = insertvalue %variant %18, i64 17, 1
%19 = insertvalue %variant %18, i64 ptrtoint ({ i8 }* @.typeid.variant to i64), 1
store %variant %19, %variant* %x, align 8
%20 = getelementptr inbounds %variant, %variant* %y, i32 0, i32 1
%21 = load i64, i64* %20, align 8
%eq5 = icmp eq i64 %21, 5
%eq5 = icmp eq i64 %21, ptrtoint ({ i8, i16 }* @.typeid.int to i64)
br i1 %eq5, label %if.then6, label %if.exit7
if.then6: ; preds = %if.exit3
@@ -251,7 +255,7 @@ if.then6: ; preds = %if.exit3
if.exit7: ; preds = %if.then6, %if.exit3
%22 = getelementptr inbounds %variant, %variant* %x, i32 0, i32 1
%23 = load i64, i64* %22, align 8
%eq8 = icmp eq i64 %23, 5
%eq8 = icmp eq i64 %23, ptrtoint ({ i8, i16 }* @.typeid.int to i64)
br i1 %eq8, label %if.then9, label %if.exit10
if.then9: ; preds = %if.exit7
@@ -268,7 +272,7 @@ if.exit10: ; preds = %if.then9, %if.exit7
store double 1.000000e+00, double* %taddr11, align 8
%27 = bitcast double* %taddr11 to i8*
%28 = insertvalue %variant undef, i8* %27, 0
%29 = insertvalue %variant %28, i64 15, 1
%29 = insertvalue %variant %28, i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), 1
store %variant %29, %variant* %taddr12, align 8
%30 = bitcast %variant* %taddr12 to { i64, i8* }*
%31 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %30, i32 0, i32 0
@@ -279,7 +283,7 @@ if.exit10: ; preds = %if.then9, %if.exit7
store i32 1, i32* %taddr15, align 4
%33 = bitcast i32* %taddr15 to i8*
%34 = insertvalue %variant undef, i8* %33, 0
%35 = insertvalue %variant %34, i64 5, 1
%35 = insertvalue %variant %34, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), 1
store %variant %35, %variant* %taddr16, align 8
%36 = bitcast %variant* %taddr16 to { i64, i8* }*
%37 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %36, i32 0, i32 0
@@ -289,7 +293,7 @@ if.exit10: ; preds = %if.then9, %if.exit7
call void @foo.test(i64 %lo17, i8* %hi18)
store i8 1, i8* %taddr19, align 1
%39 = insertvalue %variant undef, i8* %taddr19, 0
%40 = insertvalue %variant %39, i64 2, 1
%40 = insertvalue %variant %39, i64 ptrtoint ({ i8 }* @.typeid.bool to i64), 1
store %variant %40, %variant* %taddr20, align 8
%41 = bitcast %variant* %taddr20 to { i64, i8* }*
%42 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %41, i32 0, i32 0
@@ -310,17 +314,17 @@ if.exit10: ; preds = %if.then9, %if.exit7
store double 1.000000e+00, double* %taddr23, align 8
%50 = bitcast double* %taddr23 to i8*
%51 = insertvalue %variant undef, i8* %50, 0
%52 = insertvalue %variant %51, i64 15, 1
%52 = insertvalue %variant %51, i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), 1
%53 = getelementptr inbounds [5 x %variant], [5 x %variant]* %varargslots, i64 0, i64 2
store %variant %52, %variant* %53, align 16
%54 = bitcast %variant* %x to i8*
%55 = insertvalue %variant undef, i8* %54, 0
%56 = insertvalue %variant %55, i64 17, 1
%56 = insertvalue %variant %55, i64 ptrtoint ({ i8 }* @.typeid.variant to i64), 1
%57 = getelementptr inbounds [5 x %variant], [5 x %variant]* %varargslots, i64 0, i64 3
store %variant %56, %variant* %57, align 16
%58 = bitcast i32** %df to i8*
%59 = insertvalue %variant undef, i8* %58, 0
%60 = insertvalue %variant %59, i64 ptrtoint (i8* @"int*" to i64), 1
%60 = insertvalue %variant %59, i64 ptrtoint ({ i8, i64 }* @".typeid.int*" to i64), 1
%61 = getelementptr inbounds [5 x %variant], [5 x %variant]* %varargslots, i64 0, i64 4
store %variant %60, %variant* %61, align 16
%62 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1

View File

@@ -149,7 +149,7 @@ entry:
br i1 %zero, label %panic, label %checkok
panic: ; preds = %entry
call void @"std::builtin.panic"(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.zstr, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.2, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.3, i64 0, i64 0), i32 12)
call void @"std::core::builtin.panic"(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.zstr, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.2, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.3, i64 0, i64 0), i32 12)
br label %checkok
checkok: ; preds = %panic, %entry
@@ -433,7 +433,7 @@ entry:
br i1 %zero, label %panic, label %checkok
panic: ; preds = %entry
call void @"std::builtin.panic"(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.zstr.20, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.21, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.22, i64 0, i64 0), i32 56)
call void @"std::core::builtin.panic"(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.zstr.20, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.21, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.22, i64 0, i64 0), i32 56)
br label %checkok
checkok: ; preds = %panic, %entry
@@ -468,7 +468,7 @@ checkok: ; preds = %panic, %entry
br i1 %shift_underflow, label %panic1, label %checkok2
panic1: ; preds = %checkok
call void @"std::builtin.panic"(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.zstr.25, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.26, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.27, i64 0, i64 0), i32 60)
call void @"std::core::builtin.panic"(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.zstr.25, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.26, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.27, i64 0, i64 0), i32 60)
br label %checkok2
checkok2: ; preds = %panic1, %checkok
@@ -477,7 +477,7 @@ checkok2: ; preds = %panic1, %checkok
br i1 %shift_exceeds, label %panic3, label %checkok4
panic3: ; preds = %checkok2
call void @"std::builtin.panic"(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.zstr.28, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.29, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.30, i64 0, i64 0), i32 60)
call void @"std::core::builtin.panic"(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.zstr.28, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.29, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.30, i64 0, i64 0), i32 60)
br label %checkok4
checkok4: ; preds = %panic3, %checkok2
@@ -500,7 +500,7 @@ checkok4: ; preds = %panic3, %checkok2
br i1 %shift_underflow5, label %panic6, label %checkok7
panic6: ; preds = %checkok4
call void @"std::builtin.panic"(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.zstr.32, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.33, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.34, i64 0, i64 0), i32 62)
call void @"std::core::builtin.panic"(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.zstr.32, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.33, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.34, i64 0, i64 0), i32 62)
br label %checkok7
checkok7: ; preds = %panic6, %checkok4
@@ -509,7 +509,7 @@ checkok7: ; preds = %panic6, %checkok4
br i1 %shift_exceeds8, label %panic9, label %checkok10
panic9: ; preds = %checkok7
call void @"std::builtin.panic"(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.zstr.35, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.36, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.37, i64 0, i64 0), i32 62)
call void @"std::core::builtin.panic"(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.zstr.35, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.zstr.36, i64 0, i64 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.zstr.37, i64 0, i64 0), i32 62)
br label %checkok10
checkok10: ; preds = %panic9, %checkok7

View File

@@ -0,0 +1,29 @@
// #target: macos-aarch64
module test;
struct Large {
void*[8] pointers;
}
extern fn void pass_large(Large);
fn void example() {
Large l = {};
pass_large(l);
pass_large(l);
}
/* #expect: test.ll
define void @test.example() #0 {
entry:
%l = alloca %Large, align 8
%indirectarg = alloca %Large, align 8
%indirectarg1 = alloca %Large, align 8
call void @llvm.memset.p0.i64(ptr align 8 %l, i8 0, i64 64, i1 false)
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %indirectarg, ptr align 8 %l, i32 64, i1 false)
call void @pass_large(ptr align 8 %indirectarg)
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %indirectarg1, ptr align 8 %l, i32 64, i1 false)
call void @pass_large(ptr align 8 %indirectarg1)
ret void
}

View File

@@ -0,0 +1,32 @@
// #target: macos-aarch64
module test;
define Int8x16 = ichar[<16>];
define Float32x3 = float[<3>];
struct HFAv3
{
Float32x3[4] arr;
}
struct MixedHFAv3
{
Float32x3[3] arr;
Int8x16 b;
}
fn HFAv3 test(HFAv3 a0, HFAv3 a1, HFAv3 a2) {
return a2;
}
fn MixedHFAv3 test_mixed(MixedHFAv3 a0, MixedHFAv3 a1, MixedHFAv3 a2) {
return a2;
}
/* #expect: test.ll
%HFAv3 = type { [4 x <3 x float>] }
%MixedHFAv3 = type { [3 x <3 x float>], <16 x i8> }
define %HFAv3 @test.test([4 x <4 x float>] %0, [4 x <4 x float>] %1, [4 x <4 x float>] %2)
define %MixedHFAv3 @test.test_mixed([4 x <4 x float>] %0, [4 x <4 x float>] %1, [4 x <4 x float>] %2) #0 {

View File

@@ -0,0 +1,141 @@
// #target: macos-x64
// #opt: --x86vec=avx
module test;
define Mm256 = float[<8>];
struct St256 {
Mm256 m;
}
St256 x38;
Mm256 x37;
extern fn void f38(St256 x);
extern fn void f37(Mm256 x);
fn void f39() { f38(x38); f37(x37); }
// The two next tests make sure that the struct below is passed
// in the same way regardless of avx being used
// CHECK: declare void @func40(%struct.t128* byval(%struct.t128) align 16)
define Mm128 = float[<4>];
struct Two128 {
Mm128 m;
Mm128 n;
}
extern fn void func40(Two128 s);
fn void func41(Two128 s) {
func40(s);
}
struct Atwo128 {
Mm128[2] array;
}
struct Sa {
Atwo128 x;
}
extern fn void func42(Sa s);
fn void func43(Sa s) {
func42(s);
}
define Vec46 = float[<2>];
extern fn void f46(Vec46,Vec46,Vec46,Vec46,Vec46,Vec46,Vec46,Vec46,Vec46,Vec46);
fn void test46() { Vec46 x = {1,2}; f46(x,x,x,x,x,x,x,x,x,x); }
struct Vec47 { uint a; }
extern fn void f47(int,int,int,int,int,int,Vec47);
fn void test47(int a, Vec47 b) { f47(a, a, a, a, a, a, b); }
fn void test49_helper(double, ...);
fn void test49(double d, double e) { test49_helper(d, e); }
struct Complex { double i; double c; }
extern fn void test52_helper(int, ...);
Mm256 x52;
fn void test52() {
test52_helper(0, x52, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, Complex { 0, 1.0 });
}
extern fn void test54_helper(Mm256, ...);
Mm256 x54;
fn void test54() {
test54_helper(x54, x54, 1.0, 1.0, 1.0, 1.0, 1.0, Complex { 0, 1.0 });
test54_helper(x54, x54, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, Complex { 0, 1.0 });
}
define Mm512 = float[<16>];
struct St512 {
Mm512 m;
}
St512 x55;
Mm512 x56;
extern fn void f55(St512 x);
extern fn void f56(Mm512 x);
fn void f57() { f55(x55); f56(x56); }
struct Two256 {
Mm256 m;
Mm256 n;
}
extern fn void f58(Two256 s);
fn void f59(Two256 s) {
f58(s);
}
struct Atwo256 {
Mm256[2] array;
}
struct SAtwo256 {
Atwo256 x;
}
extern fn void f60(SAtwo256 s);
fn void f61(SAtwo256 s) {
f60(s);
}
/* #expect: test.ll
declare void @f38(<8 x float>)
declare void @f37(<8 x float>)
declare void @func40(ptr byval(%Two128) align 16)
define void @test.func41(ptr byval(%Two128) align 16 %0)
declare void @func42(ptr byval(%Sa) align 16)
define void @test.func43(ptr byval(%Sa) align 16 %0)
declare void @f46(double, double, double, double, double, double, double, double, ptr byval(<2 x float>) align 8, ptr byval(<2 x float>) align 8) #0
declare void @f47(i32, i32, i32, i32, i32, i32, i32)
declare void @test.test49_helper(double, ...)
define void @test.test49(double %0, double %1)
entry:
call void (double, ...) @test.test49_helper(double %0, double %1)
ret void
call void (i32, ...) @test52_helper(i32 0, <8 x float> %0, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double %lo, double %hi)
call void (<8 x float>, ...) @test54_helper(<8 x float> %0, <8 x float> %1, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double %lo, double %hi)
call void (<8 x float>, ...) @test54_helper(<8 x float> %6, <8 x float> %7, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, ptr byval(%Complex) align 8 %indirectarg)
declare void @f55(ptr byval(%St512) align 64)
declare void @f56(ptr byval(<16 x float>) align 64)
declare void @f58(ptr byval(%Two256) align 32)
define void @test.f59(ptr byval(%Two256) align 32 %0)
declare void @f60(ptr byval(%SAtwo256) align 32)
define void @test.f61(ptr byval(%SAtwo256) align 32 %0) #0 {

View File

@@ -0,0 +1,74 @@
// #target: macos-x64
// #opt: --x86vec=avx512
module test;
define Mm256 = float[<8>];
define Mm512 = float[<16>];
struct St512 {
Mm512 m;
}
St512 x55;
Mm512 x56;
extern fn void f55(St512 x);
extern fn void f56(Mm512 x);
fn void f57() { f55(x55); f56(x56); }
struct Two256 {
Mm256 m;
Mm256 n;
}
extern fn void f58(Two256 s);
fn void f59(Two256 s) {
f58(s);
}
struct Atwo256 {
Mm256[2] array;
}
struct SAtwo256 {
Atwo256 x;
}
extern fn void f60(SAtwo256 s);
fn void f61(SAtwo256 s) {
f60(s);
}
struct Complex { double i; double c; }
// AVX512: @f62_helper(i32 0, <16 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double {{%[a-zA-Z0-9]+}}, double {{%[a-zA-Z0-9]+}})
fn void f62_helper(int, ...);
Mm512 x62;
fn void f62() {
f62_helper(0, x62, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, Complex { 1.0, 1.0 });
}
fn void f64_helper(Mm512, ...);
Mm512 x64;
fn void f64() {
f64_helper(x64, x64, 1.0, 1.0, 1.0, 1.0, 1.0, Complex { 1.0, 1.0 });
f64_helper(x64, x64, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, Complex { 1.0, 1.0 });
}
/* #expect: test.ll
declare void @f55(<16 x float>) #0
declare void @f56(<16 x float>) #0
declare void @f58(ptr byval(%Two256) align 32) #0
define void @test.f59(ptr byval(%Two256) align 32 %0) #0 {
declare void @f60(ptr byval(%SAtwo256) align 32) #0
define void @test.f61(ptr byval(%SAtwo256) align 32 %0) #0 {
define void @test.f62() #0 {
call void (i32, ...) @test.f62_helper(i32 0, <16 x float> %0, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double %lo, double %hi)
define void @test.f64() #0 {
call void (<16 x float>, ...) @test.f64_helper(<16 x float> %0, <16 x float> %1, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double %lo, double %hi)
call void (<16 x float>, ...) @test.f64_helper(<16 x float> %6, <16 x float> %7, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, ptr byval(%Complex) align 8 %indirectarg)

View File

@@ -0,0 +1,56 @@
// #target: macos-x64
// #opt: --x86vec=sse
module test;
define Mm256 = float[<8>];
struct St256 {
Mm256 m;
}
St256 x38;
Mm256 x37;
extern fn void f38(St256 x);
extern fn void f37(Mm256 x);
fn void f39() { f38(x38); f37(x37); }
// The two next tests make sure that the struct below is passed
// in the same way regardless of avx being used
// CHECK: declare void @func40(%struct.t128* byval(%struct.t128) align 16)
define Mm128 = float[<4>];
struct Two128 {
Mm128 m;
Mm128 n;
}
extern fn void func40(Two128 s);
fn void func41(Two128 s) {
func40(s);
}
struct Atwo128 {
Mm128[2] array;
}
struct Sa {
Atwo128 x;
}
extern fn void func42(Sa s);
fn void func43(Sa s) {
func42(s);
}
/* #expect: test.ll
declare void @f38(ptr byval(%St256) align 32)
declare void @f37(ptr byval(<8 x float>) align 32)
declare void @func40(ptr byval(%Two128) align 16)
define void @test.func41(ptr byval(%Two128) align 16 %0)
declare void @func42(ptr byval(%Sa) align 16)
define void @test.func43(ptr byval(%Sa) align 16 %0)

View File

@@ -0,0 +1,48 @@
// #target: macos-x64
module test;
fn char f0() {
return 0;
}
fn short f1() {
return 0;
}
fn int f2() {
return 0;
}
fn float f3() {
return 0;
}
fn double f4() {
return 0;
}
fn void f6(char a0, short a1, int a2, long a3, void *a4) {}
enum Enum7 : int { A, B, C }
fn void f7(Enum7 a0) {}
struct Struct8
{
int a;
int b;
}
fn Struct8 f8_1() { while (1) {} return Struct8 {}; }
fn void f8_2(Struct8 a0) {}
/* #expect: test.ll
define zeroext i8 @test.f0()
define signext i16 @test.f1()
define i32 @test.f2()
define float @test.f3()
define double @test.f4()
define void @test.f6(i8 zeroext %0, i16 signext %1, i32 %2, i64 %3, ptr %4)
define void @test.f7(i32 %0)
define i64 @test.f8_1()
define void @test.f8_2(i64 %0) #0 {

View File

@@ -0,0 +1,186 @@
// #target: macos-x64
module test;
import std;
struct St12
{
int a @align(16);
}
fn St12 f12_0(void) { while (1) {}; unreachable(); }
fn void f12_1(St12 a0) {}
struct St13_0 { long[3] f0; }
struct St13_1 { long[2] f0; }
fn St13_0 f13(int a, int b, int c, int d,
St13_1 e, int f) { while (1) {}; unreachable(); }
fn void f14(int a, int b, int c, int d, int e, int f, ichar x) {}
fn void f15(int a, int b, int c, int d, int e, int f, void *x) {}
fn void f16(float a, float b, float c, float d, float e, float f, float g, float h,
float x) {}
struct Fl18_s0 { int f0; }
fn void fl18(int a, Fl18_s0 f18_arg1) { while (1) {} }
struct St20 @align(32) {
int x;
int y;
}
fn void f20(St20 x) {}
struct StringRef
{
int x;
char* ptr;
}
fn char *f21(StringRef s) { return s.x+s.ptr; }
struct St22s @align(16)
{ ulong[2] x; }
fn void f22(St22s x, St22s y) { }
struct St23S {
short f0;
uint f1;
int f2;
}
fn void f23(int a, St23S b) {
}
struct St24s { int a; int b; }
fn St23S f24(St23S *x, St24s *p2)
{
return *x;
}
fn float[<4>] f25(float[<4>] x) {
return x+x;
}
struct Foo26 {
int *x;
float *y;
}
fn Foo26 f26(Foo26 *p) {
return *p;
}
struct V4f32wrapper {
float[<4>] v;
}
fn V4f32wrapper f27(V4f32wrapper x) {
return x;
}
// PR22563 - We should unwrap simple structs and arrays to pass
// and return them in the appropriate vector registers if possible.
define V8f32 = float[<8>];
struct V8f32wrapper {
V8f32 v;
}
fn V8f32wrapper f27a(V8f32wrapper x) {
return x;
}
struct V8f32wrapper_wrapper {
V8f32[1] v;
}
fn V8f32wrapper_wrapper f27b(V8f32wrapper_wrapper x) {
return x;
}
struct F28c {
double x;
int y;
}
fn void f28(F28c c) {
}
struct Inner
{
double x;
int y;
}
struct F29a
{
Inner[1] c;
}
fn void f29a(F29a a) {
}
struct St0 {
char[8] f0; char f2; char f3; char f4; }
fn void f30(St0 p_4) {
}
struct F31foo { float a, b, c; }
fn float f31(F31foo x) {
return x.c;
}
define V1i64 = ulong[<1>];
fn V1i64 f34(V1i64 arg) { return arg; }
define V1i64_2 = uint[<2>];
fn V1i64_2 f35(V1i64_2 arg) { return arg+arg; }
define V2i32 = float[<2>];
fn V2i32 f36(V2i32 arg) { return arg; }
/* #expect: test.ll
define i32 @test.f12_0()
define void @test.f12_1(i32 %0)
define void @test.f13(ptr noalias sret(%St13_0) align 8 %0, i32 %1, i32 %2, i32 %3, i32 %4, ptr byval(%St13_1) align 8 %5, i32 %6) #0 {
define void @test.f14(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i8 signext %6) #0 {
define void @test.f15(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, ptr %6)
define void @test.f16(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, float %8)
define void @test.fl18(i32 %0, i32 %1)
define void @test.f20(ptr byval(%St20) align 32 %0)
define ptr @test.f21(i64 %0, ptr %1)
define void @test.f22(i64 %0, i64 %1, i64 %2, i64 %3)
entry:
%x = alloca %St22s, align 16
%y = alloca %St22s, align 16
define void @test.f23(i32 %0, i64 %1, i32 %2)
define { i64, i32 } @test.f24(ptr %0, ptr %1)
define <4 x float> @test.f25(<4 x float> %0) #0 {
entry:
%fadd = fadd <4 x float> %0, %0
ret <4 x float> %fadd
}
define { ptr, ptr } @test.f26(ptr %0)
define <4 x float> @test.f27(<4 x float> %0)
define <8 x float> @test.f27a(<8 x float> %0)
define <8 x float> @test.f27b(<8 x float> %0)
define void @test.f28(double %0, i32 %1)
define void @test.f29a(double %0, i32 %1)
define void @test.f30(i64 %0, i24 %1)
define float @test.f31(<2 x float> %0, float %1)
define double @test.f34(double %0)
define double @test.f35(double %0)
define double @test.f36(double %0)

View File

@@ -0,0 +1,32 @@
// #target: macos-x64
struct Test
{
int x;
}
Test foo = {};
extern fn void blorg(Test t);
fn Test creator()
{
blorg(Test{});
return Test{};
}
/* #expect: literal_load.ll
define i32 @literal_load.creator() #0 {
entry:
%literal = alloca %Test, align 4
%literal1 = alloca %Test, align 4
store i32 0, ptr %literal, align 4
%0 = getelementptr inbounds %Test, ptr %literal, i32 0, i32 0
%1 = load i32, ptr %0, align 4
call void @blorg(i32 %1)
store i32 0, ptr %literal1, align 4
%2 = getelementptr inbounds %Test, ptr %literal1, i32 0, i32 0
%3 = load i32, ptr %2, align 4
ret i32 %3
}

View File

@@ -0,0 +1,36 @@
// #target: linux-aarch64
module literal_load;
struct Test
{
int x;
}
Test foo = {};
extern fn void blorg(Test t);
fn Test creator()
{
blorg(Test{});
return Test{};
}
/* #expect: literal_load.ll
declare void @blorg(i64) #0
define i32 @literal_load.creator() #0 {
entry:
%literal = alloca %Test, align 4
%literal1 = alloca %Test, align 4
store i32 0, ptr %literal, align 4
%0 = getelementptr inbounds %Test, ptr %literal, i32 0, i32 0
%1 = load i32, ptr %0, align 4
%2 = zext i32 %1 to i64
call void @blorg(i64 %2)
store i32 0, ptr %literal1, align 4
%3 = getelementptr inbounds %Test, ptr %literal1, i32 0, i32 0
%4 = load i32, ptr %3, align 4
ret i32 %4
}

View File

@@ -0,0 +1,33 @@
// #target: mingw-x64
module literal_load;
struct Test
{
int x;
}
Test foo = {};
extern fn void blorg(Test t);
fn Test creator()
{
blorg(Test{});
return Test{};
}
/* #expect: literal_load.ll
define i32 @literal_load.creator() #0 {
entry:
%literal = alloca %Test, align 4
%literal1 = alloca %Test, align 4
store i32 0, ptr %literal, align 4
%0 = getelementptr inbounds %Test, ptr %literal, i32 0, i32 0
%1 = load i32, ptr %0, align 4
call void @blorg(i32 %1)
store i32 0, ptr %literal1, align 4
%2 = getelementptr inbounds %Test, ptr %literal1, i32 0, i32 0
%3 = load i32, ptr %2, align 4
ret i32 %3
}

View File

@@ -0,0 +1,8 @@
// #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?
int baz @section("foo"); // #error: Mach-o requires 'segment,section' as the format, did you type it correctly?
int abc @section("foo,b,c,d,e,f"); // #error: Too many parts to the Mach-o section description.
int def @section("foo,b,c,d");

View File

@@ -0,0 +1,32 @@
// #target: linux-aarch64
module pass_large;
struct Large
{
void*[8] pointers;
}
extern fn void pass_large(Large large);
fn void example()
{
Large l = {};
pass_large(l);
pass_large(l);
}
/* #expect: pass_large.ll
define void @pass_large.example()
entry:
%l = alloca %Large, align 8
%indirectarg = alloca %Large, align 8
%indirectarg1 = alloca %Large, align 8
call void @llvm.memset.p0.i64(ptr align 8 %l, i8 0, i64 64, i1 false)
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %indirectarg, ptr align 8 %l, i32 64, i1 false)
call void @pass_large(ptr align 8 %indirectarg)
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %indirectarg1, ptr align 8 %l, i32 64, i1 false)
call void @pass_large(ptr align 8 %indirectarg1)
ret void

View File

@@ -0,0 +1,57 @@
// #target: mingw-x64
module test;
extern fn void printf(char*, ...);
struct Foo
{
float[2] x;
}
fn void test(Foo x) @regcall
{
}
fn int main()
{
test(Foo { });
return 0;
}
/* #expect: test.ll
%Foo = type { [2 x float] }
$.typeid.test.Foo = comdat any
@.typeid.test.Foo = linkonce constant { i8, i64 } { i8 10, i64 1 }, comdat, align 8
declare void @printf(ptr, ...) #0
define x86_regcallcc void @test.test(float %0, float %1) #0 {
entry:
%x = alloca %Foo, align 4
%2 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%3 = getelementptr inbounds [2 x float], ptr %2, i64 0, i64 0
store float %0, ptr %3, align 4
%4 = getelementptr inbounds [2 x float], ptr %2, i64 0, i64 1
store float %1, ptr %4, align 4
ret void
}
; Function Attrs: nounwind
define i32 @main() #0 {
entry:
%literal = alloca %Foo, align 4
%0 = getelementptr inbounds %Foo, ptr %literal, i32 0, i32 0
%1 = getelementptr inbounds [2 x float], ptr %0, i64 0, i64 0
store float 0.000000e+00, ptr %1, align 4
%2 = getelementptr inbounds [2 x float], ptr %0, i64 0, i64 1
store float 0.000000e+00, ptr %2, align 4
%3 = getelementptr inbounds %Foo, ptr %literal, i32 0, i32 0
%4 = getelementptr inbounds [2 x float], ptr %3, i64 0, i64 0
%loadexpanded = load float, ptr %4, align 4
%5 = getelementptr inbounds [2 x float], ptr %3, i64 0, i64 1
%loadexpanded1 = load float, ptr %5, align 4
call x86_regcallcc void @test.test(float %loadexpanded, float %loadexpanded1)
ret i32 0
}

View File

@@ -0,0 +1,51 @@
// #target: linux-riscv64
module test;
struct Large {
long a, b, c, d;
}
define V32i8 = char[<32>];
fn int f_scalar_stack_1(int a, int128 b, float c, float128 d, V32i8 e,
char f, char g, char h) {
return g + h;
}
fn Large f_scalar_stack_2(double a, int128 b, float128 c, V32i8 d,
char e, ichar f, char g) {
return Large {(long)(a), e, f, g};
}
/* #expect: test.ll
define signext i32 @test.f_scalar_stack_1(i32 signext %0, i128 %1, float %2, fp128 %3, ptr align 32 %4, i8 zeroext %5, i8 %6, i8 %7) #0 {
entry:
%e = alloca <32 x i8>, align 32
call void @llvm.memcpy.p0.p0.i32(ptr align 32 %e, ptr align 32 %4, i32 32, i1 false)
%uisiext = zext i8 %6 to i32
%uisiext1 = zext i8 %7 to i32
%add = add i32 %uisiext, %uisiext1
ret i32 %add
}
define void @test.f_scalar_stack_2(ptr noalias sret(%Large) align 8 %0, double %1, i128 %2, fp128 %3, ptr align 32 %4, i8 zeroext %5, i8 %6, i8 %7) #0 {
entry:
%d = alloca <32 x i8>, align 32
%literal = alloca %Large, align 8
call void @llvm.memcpy.p0.p0.i32(ptr align 32 %d, ptr align 32 %4, i32 32, i1 false)
%8 = getelementptr inbounds %Large, ptr %literal, i32 0, i32 0
%fpsi = fptosi double %1 to i64
store i64 %fpsi, ptr %8, align 8
%9 = getelementptr inbounds %Large, ptr %literal, i32 0, i32 1
%uisiext = zext i8 %5 to i64
store i64 %uisiext, ptr %9, align 8
%10 = getelementptr inbounds %Large, ptr %literal, i32 0, i32 2
%sisiext = sext i8 %6 to i64
store i64 %sisiext, ptr %10, align 8
%11 = getelementptr inbounds %Large, ptr %literal, i32 0, i32 3
%uisiext1 = zext i8 %7 to i64
store i64 %uisiext1, ptr %11, align 8
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal, i32 32, i1 false)
ret void
}

View File

@@ -0,0 +1,66 @@
// #target: macos-x64
module test;
struct Foo
{
char a;
char b;
char c;
}
fn int testing()
{
Foo y = getFoo(Foo { 4, 5, 6 });
return y.a + y.c;
}
fn Foo getFoo(Foo f)
{
return Foo { 1, 2, 3 };
}
/* #expect: test.ll
define i32 @test.testing() #0 {
entry:
%y = alloca %Foo, align 1
%literal = alloca %Foo, align 1
%tempcoerce = alloca i24, align 4
%result = alloca %Foo, align 1
%0 = getelementptr inbounds %Foo, ptr %literal, i32 0, i32 0
store i8 4, ptr %0, align 1
%1 = getelementptr inbounds %Foo, ptr %literal, i32 0, i32 1
store i8 5, ptr %1, align 1
%2 = getelementptr inbounds %Foo, ptr %literal, i32 0, i32 2
store i8 6, ptr %2, align 1
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %tempcoerce, ptr align 1 %literal, i32 3, i1 false)
%3 = load i24, ptr %tempcoerce, align 4
%4 = call i24 @test.getFoo(i24 %3)
store i24 %4, ptr %result, align 1
call void @llvm.memcpy.p0.p0.i32(ptr align 1 %y, ptr align 1 %result, i32 3, i1 false)
%5 = getelementptr inbounds %Foo, ptr %y, i32 0, i32 0
%6 = load i8, ptr %5, align 1
%uisiext = zext i8 %6 to i32
%7 = getelementptr inbounds %Foo, ptr %y, i32 0, i32 2
%8 = load i8, ptr %7, align 1
%uisiext1 = zext i8 %8 to i32
%add = add i32 %uisiext, %uisiext1
ret i32 %add
}
; Function Attrs: nounwind
define i24 @test.getFoo(i24 %0) #0 {
entry:
%f = alloca %Foo, align 1
%literal = alloca %Foo, align 1
%tempcoerce = alloca i24, align 4
store i24 %0, ptr %f, align 1
%1 = getelementptr inbounds %Foo, ptr %literal, i32 0, i32 0
store i8 1, ptr %1, align 1
%2 = getelementptr inbounds %Foo, ptr %literal, i32 0, i32 1
store i8 2, ptr %2, align 1
%3 = getelementptr inbounds %Foo, ptr %literal, i32 0, i32 2
store i8 3, ptr %3, align 1
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %tempcoerce, ptr align 1 %literal, i32 3, i1 false)
%4 = load i24, ptr %tempcoerce, align 4
ret i24 %4
}

View File

@@ -0,0 +1,43 @@
// #target: macos-x64
module foo;
struct Rectangle
{
float x; // Rectangle top-left corner position x
float y; // Rectangle top-left corner position y
float width; // Rectangle width
float height; // Rectangle height
}
fn void test(Rectangle r)
{
test(Rectangle { 1, 2, 3, 4 });
}
/* #expect: foo.ll
define void @foo.test(<2 x float> %0, <2 x float> %1) #0 {
entry:
%r = alloca %Rectangle, align 4
%literal = alloca %Rectangle, align 4
%coerce = alloca %Rectangle, align 8
%2 = getelementptr inbounds { <2 x float>, <2 x float> }, ptr %r, i32 0, i32 0
store <2 x float> %0, ptr %2, align 4
%3 = getelementptr inbounds { <2 x float>, <2 x float> }, ptr %r, i32 0, i32 1
store <2 x float> %1, ptr %3, align 4
%4 = getelementptr inbounds %Rectangle, ptr %literal, i32 0, i32 0
store float 1.000000e+00, ptr %4, align 4
%5 = getelementptr inbounds %Rectangle, ptr %literal, i32 0, i32 1
store float 2.000000e+00, ptr %5, align 4
%6 = getelementptr inbounds %Rectangle, ptr %literal, i32 0, i32 2
store float 3.000000e+00, ptr %6, align 4
%7 = getelementptr inbounds %Rectangle, ptr %literal, i32 0, i32 3
store float 4.000000e+00, ptr %7, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %coerce, ptr align 4 %literal, i32 16, i1 false)
%8 = getelementptr inbounds { <2 x float>, <2 x float> }, ptr %coerce, i32 0, i32 0
%lo = load <2 x float>, ptr %8, align 8
%9 = getelementptr inbounds { <2 x float>, <2 x float> }, ptr %coerce, i32 0, i32 1
%hi = load <2 x float>, ptr %9, align 8
call void @foo.test(<2 x float> %lo, <2 x float> %hi)
ret void
}

View File

@@ -0,0 +1,38 @@
// #target: macos-x64
struct Abc {
long a;
long b;
long c;
long d;
long e;
}
extern fn Abc foo1();
extern fn Abc foo2();
fn void bar() {
Abc dummy1 = foo1();
Abc dummy2 = foo2();
}
// Cleanup for this result, since it's creating an unnecessary sret.
/* #expect: test_sret.ll
declare void @foo1(ptr noalias sret(%Abc) align 8) #0
declare void @foo2(ptr noalias sret(%Abc) align 8) #0
define void @test_sret.bar() #0 {
entry:
%dummy1 = alloca %Abc, align 8
%sretparam = alloca %Abc, align 8
%dummy2 = alloca %Abc, align 8
%sretparam1 = alloca %Abc, align 8
call void @foo1(ptr sret(%Abc) align 8 %sretparam)
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %dummy1, ptr align 8 %sretparam, i32 40, i1 false)
call void @foo2(ptr sret(%Abc) align 8 %sretparam1)
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %dummy2, ptr align 8 %sretparam1, i32 40, i1 false)
ret void
}

View File

@@ -0,0 +1,37 @@
// #target: macos-x64
module unionx64;
union Foo
{
long a;
char[12] b;
}
extern fn void hello2(Foo f);
fn void hello(Foo f)
{
hello2(f);
}
/* #expect: unionx64.ll
%Foo = type { i64, [8 x i8] }
declare void @hello2(i64, i64) #0
define void @unionx64.hello(i64 %0, i64 %1) #0 {
entry:
%f = alloca %Foo, align 8
%2 = getelementptr inbounds { i64, i64 }, ptr %f, i32 0, i32 0
store i64 %0, ptr %2, align 8
%3 = getelementptr inbounds { i64, i64 }, ptr %f, i32 0, i32 1
store i64 %1, ptr %3, align 8
%4 = getelementptr inbounds { i64, i64 }, ptr %f, i32 0, i32 0
%lo = load i64, ptr %4, align 8
%5 = getelementptr inbounds { i64, i64 }, ptr %f, i32 0, i32 1
%hi = load i64, ptr %5, align 8
call void @hello2(i64 %lo, i64 %hi)
ret void
}

View File

@@ -0,0 +1,95 @@
// #target: linux-aarch64
module abi;
struct Vector2 {
float x;
float y;
}
extern fn Vector2 vector2_zero() { return Vector2 {}; }
extern fn Vector2 vector2_one() { return Vector2 {}; }
extern fn Vector2 vector2_add(Vector2 v1, Vector2 v2) { return Vector2 {}; }
extern fn Vector2 vector2_add_value(Vector2 v, float add) { return Vector2 {}; }
extern fn Vector2 vector2_subtract(Vector2 v1, Vector2 v2) { return Vector2 {}; }
extern fn Vector2 vector2_subtract_value(Vector2 v, float sub) { return Vector2 {}; }
/* #expect: abi.ll
%Vector2 = type { float, float }
define %Vector2 @vector2_zero() #0 {
entry:
%literal = alloca %Vector2, align 4
%0 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %0, align 4
%1 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %1, align 4
%2 = load %Vector2, ptr %literal, align 4
ret %Vector2 %2
}
define %Vector2 @vector2_one() #0 {
entry:
%literal = alloca %Vector2, align 4
%0 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %0, align 4
%1 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %1, align 4
%2 = load %Vector2, ptr %literal, align 4
ret %Vector2 %2
}
define %Vector2 @vector2_add([2 x float] %0, [2 x float] %1) #0 {
entry:
%v1 = alloca %Vector2, align 4
%v2 = alloca %Vector2, align 4
%literal = alloca %Vector2, align 4
store [2 x float] %0, ptr %v1, align 4
store [2 x float] %1, ptr %v2, align 4
%2 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %2, align 4
%3 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %3, align 4
%4 = load %Vector2, ptr %literal, align 4
ret %Vector2 %4
}
define %Vector2 @vector2_add_value([2 x float] %0, float %1) #0 {
entry:
%v = alloca %Vector2, align 4
%literal = alloca %Vector2, align 4
store [2 x float] %0, ptr %v, align 4
%2 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %2, align 4
%3 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %3, align 4
%4 = load %Vector2, ptr %literal, align 4
ret %Vector2 %4
}
define %Vector2 @vector2_subtract([2 x float] %0, [2 x float] %1) #0 {
entry:
%v1 = alloca %Vector2, align 4
%v2 = alloca %Vector2, align 4
%literal = alloca %Vector2, align 4
store [2 x float] %0, ptr %v1, align 4
store [2 x float] %1, ptr %v2, align 4
%2 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %2, align 4
%3 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %3, align 4
%4 = load %Vector2, ptr %literal, align 4
ret %Vector2 %4
}
define %Vector2 @vector2_subtract_value([2 x float] %0, float %1) #0 {
entry:
%v = alloca %Vector2, align 4
%literal = alloca %Vector2, align 4
store [2 x float] %0, ptr %v, align 4
%2 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %2, align 4
%3 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %3, align 4
%4 = load %Vector2, ptr %literal, align 4
ret %Vector2 %4
}

View File

@@ -0,0 +1,98 @@
// #target: wasm32
module abi;
struct Vector2 {
float x;
float y;
}
extern fn Vector2 vector2_zero() { return Vector2 {}; }
extern fn Vector2 vector2_one() { return Vector2 {}; }
extern fn Vector2 vector2_add(Vector2 v1, Vector2 v2) { return Vector2 {}; }
extern fn Vector2 vector2_add_value(Vector2 v, float add) { return Vector2 {}; }
extern fn Vector2 vector2_subtract(Vector2 v1, Vector2 v2) { return Vector2 {}; }
extern fn Vector2 vector2_subtract_value(Vector2 v, float sub) { return Vector2 {}; }
/* #expect: abi.ll
target triple = "wasm32-unknown-unknown"
%Vector2 = type { float, float }
define void @vector2_zero(ptr noalias sret(%Vector2) align 4 %0) #0 {
entry:
%literal = alloca %Vector2, align 4
%1 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %1, align 4
%2 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %2, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %0, ptr align 4 %literal, i32 8, i1 false)
ret void
}
define void @vector2_one(ptr noalias sret(%Vector2) align 4 %0) #0 {
entry:
%literal = alloca %Vector2, align 4
%1 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %1, align 4
%2 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %2, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %0, ptr align 4 %literal, i32 8, i1 false)
ret void
}
define void @vector2_add(ptr noalias sret(%Vector2) align 4 %0, ptr byval(%Vector2) align 4 %1, ptr byval(%Vector2) align 4 %2) #0 {
entry:
%v1 = alloca %Vector2, align 4
%v2 = alloca %Vector2, align 4
%literal = alloca %Vector2, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %v1, ptr align 4 %1, i32 8, i1 false)
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %v2, ptr align 4 %2, i32 8, i1 false)
%3 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %3, align 4
%4 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %4, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %0, ptr align 4 %literal, i32 8, i1 false)
ret void
}
define void @vector2_add_value(ptr noalias sret(%Vector2) align 4 %0, ptr byval(%Vector2) align 4 %1, float %2) #0 {
entry:
%v = alloca %Vector2, align 4
%literal = alloca %Vector2, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %v, ptr align 4 %1, i32 8, i1 false)
%3 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %3, align 4
%4 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %4, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %0, ptr align 4 %literal, i32 8, i1 false)
ret void
}
define void @vector2_subtract(ptr noalias sret(%Vector2) align 4 %0, ptr byval(%Vector2) align 4 %1, ptr byval(%Vector2) align 4 %2) #0 {
entry:
%v1 = alloca %Vector2, align 4
%v2 = alloca %Vector2, align 4
%literal = alloca %Vector2, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %v1, ptr align 4 %1, i32 8, i1 false)
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %v2, ptr align 4 %2, i32 8, i1 false)
%3 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %3, align 4
%4 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %4, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %0, ptr align 4 %literal, i32 8, i1 false)
ret void
}
define void @vector2_subtract_value(ptr noalias sret(%Vector2) align 4 %0, ptr byval(%Vector2) align 4 %1, float %2) #0 {
entry:
%v = alloca %Vector2, align 4
%literal = alloca %Vector2, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %v, ptr align 4 %1, i32 8, i1 false)
%3 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 0
store float 0.000000e+00, ptr %3, align 4
%4 = getelementptr inbounds %Vector2, ptr %literal, i32 0, i32 1
store float 0.000000e+00, ptr %4, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %0, ptr align 4 %literal, i32 8, i1 false)
ret void
}

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