Compare commits

..

14 Commits

Author SHA1 Message Date
Christoffer Lerno
0de47d7c83 Ensure panic functions are never stripped. 2023-06-02 23:19:54 +02:00
Christoffer Lerno
cfd21f8ca2 Windows thread pool. 2023-06-02 23:19:54 +02:00
Christoffer Lerno
d0e8944c56 Updated task pool. 2023-06-02 21:58:25 +02:00
Christoffer Lerno
3e54d13b62 Prefer def 2023-06-02 20:08:45 +02:00
Christoffer Lerno
b30d130d92 Configurable Linux crt/crtbegin paths. 2023-05-31 21:26:23 +02:00
Christoffer Lerno
4cf98dab93 Add special ubuntu-20 release 2023-05-31 12:42:31 +02:00
Christoffer Lerno
ea1a5435bb Dead strip on "strip unused" 2023-05-30 16:42:15 +02:00
Christoffer Lerno
275e3c6a09 Update with CPU type. 2023-05-30 16:42:15 +02:00
Christoffer Lerno
9de02efa01 Exclude main methods from dllexport. 2023-05-28 15:59:15 +02:00
Christoffer Lerno
e0cfb39d79 Add DLL export for exported functions on win32. 2023-05-28 15:00:46 +02:00
Christoffer Lerno
d4259368a2 Remove call convention. 2023-05-26 14:22:50 +02:00
Christoffer Lerno
07b107ff5e Better handling of attribute definition errors. Resolves #753 2023-05-26 11:31:27 +02:00
Christoffer Lerno
b794c893d6 Dynamic dispatch. 2023-05-25 22:28:45 +02:00
Christoffer Lerno
2e498a426e Improved the README example somewhat. 2023-05-22 09:47:46 +02:00
127 changed files with 1811 additions and 756 deletions

View File

@@ -283,6 +283,111 @@ jobs:
name: c3-linux-${{matrix.build_type}}
path: c3-linux-${{matrix.build_type}}.tar.gz
build-linux-ubuntu20:
runs-on: ubuntu-20.04
strategy:
# Don't abort runners if a single one fails
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [16]
steps:
- uses: actions/checkout@v3
- name: Install common deps
run: |
sudo apt-get install zlib1g zlib1g-dev python3 ninja-build curl
- name: Install Clang ${{matrix.llvm_version}}
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
if [[ "${{matrix.llvm_version}}" < 17 ]]; then
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{matrix.llvm_version}} main"
else
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main"
fi
sudo apt-get update
sudo apt-get install -y clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev
sudo apt-get install -y libmlir-${{matrix.llvm_version}} libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
sudo apt-get install -y libpolly-${{matrix.llvm_version}}-dev
- name: CMake
run: |
cmake -B build \
-G Ninja \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DCMAKE_C_COMPILER=clang-${{matrix.llvm_version}} \
-DCMAKE_CXX_COMPILER=clang++-${{matrix.llvm_version}} \
-DCMAKE_LINKER=lld-link-${{matrix.llvm_version}} \
-DCMAKE_OBJCOPY=llvm-objcopy-${{matrix.llvm_version}} \
-DCMAKE_STRIP=llvm-strip-${{matrix.llvm_version}} \
-DCMAKE_DLLTOOL=llvm-dlltool-${{matrix.llvm_version}} \
-DC3_LLVM_VERSION=${{matrix.llvm_version}}
cmake --build build
- name: Compile and run some examples
run: |
cd resources
../build/c3c compile examples/base64.c3
../build/c3c compile examples/binarydigits.c3
../build/c3c compile examples/brainfk.c3
../build/c3c compile examples/factorial_macro.c3
../build/c3c compile examples/fasta.c3
../build/c3c compile examples/gameoflife.c3
../build/c3c compile examples/hash.c3
../build/c3c compile examples/levenshtein.c3
../build/c3c compile examples/load_world.c3
../build/c3c compile examples/map.c3
../build/c3c compile examples/mandelbrot.c3
../build/c3c compile examples/plus_minus.c3
../build/c3c compile examples/nbodies.c3
../build/c3c compile examples/spectralnorm.c3
../build/c3c compile examples/swap.c3
../build/c3c compile examples/contextfree/boolerr.c3
../build/c3c compile examples/contextfree/dynscope.c3
../build/c3c compile examples/contextfree/guess_number.c3
../build/c3c compile examples/contextfree/multi.c3
../build/c3c compile examples/contextfree/cleanup.c3
../build/c3c compile-run examples/hello_world_many.c3
../build/c3c compile-run examples/time.c3
../build/c3c compile-run examples/fannkuch-redux.c3
../build/c3c compile-run examples/contextfree/boolerr.c3
../build/c3c compile-run examples/load_world.c3
- name: Compile run unit tests
run: |
cd test
../build/c3c compile-test unit -g1 --safe
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c run --debug-log
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run --debug-log --forcelinker
- name: run compiler tests
run: |
cd test
python3 src/tester.py ../build/c3c test_suite/
- name: bundle_output
if: matrix.llvm_version == 16
run: |
mkdir linux
cp -r lib linux
cp msvc_build_libraries.py linux
cp build/c3c linux
tar czf c3-ubuntu-20-${{matrix.build_type}}.tar.gz linux
- name: upload artifacts
if: matrix.llvm_version == 16
uses: actions/upload-artifact@v3
with:
name: c3-ubuntu-20-${{matrix.build_type}}
path: c3-ubuntu-20-${{matrix.build_type}}.tar.gz
build-mac:
runs-on: macos-latest
@@ -450,6 +555,27 @@ jobs:
asset_name: c3-linux-debug.tar.gz
asset_content_type: application/gzip
- name: upload ubuntu 20
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: c3-ubuntu-20-Release/c3-ubuntu-20-Release.tar.gz
asset_name: c3-ubuntu-20.tar.gz
asset_content_type: application/gzip
- name: upload ubuntu 20 debug
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: c3-ubuntu-20-Debug/c3-ubuntu-20-Debug.tar.gz
asset_name: c3-ubuntu-20-debug.tar.gz
asset_content_type: application/gzip
- name: upload macos
uses: actions/upload-release-asset@v1
env:

View File

@@ -79,9 +79,9 @@ import stack;
// Define our new types, the first will implicitly create
// a complete copy of the entire Stack module with "Type" set to "int"
typedef IntStack = Stack<int>;
def IntStack = Stack<int>;
// The second creates another copy with "Type" set to "double"
typedef DoubleStack = Stack<double>;
def DoubleStack = Stack<double>;
// If we had added "define IntStack2 = Stack<int>"
// no additional copy would have been made (since we already
@@ -92,7 +92,7 @@ typedef DoubleStack = Stack<double>;
// here is an example of importing libc's printf:
extern fn int printf(char* format, ...);
fn void test()
fn void main()
{
IntStack stack;
// Note that C3 uses zero initialization by default
@@ -112,7 +112,7 @@ fn void test()
dstack.push(2.3);
dstack.push(3.141);
dstack.push(1.1235);
// Prints pop: 1.1235
// Prints pop: 1.123500
printf("pop: %f\n", dstack.pop());
}
```

View File

@@ -26,12 +26,8 @@ struct Object
}
}
static initialize
{
io::formatter_register_type(Object);
}
fn void! Object.to_format(Object* o, Formatter* formatter)
fn void! Object.to_format(Object* o, Formatter* formatter) @dynamic
{
switch (o.type)
{

View File

@@ -22,10 +22,11 @@ fault FormattingFault
}
def OutputFn = fn void!(char c, void* buffer);
def ToStringFunction = fn String(void* value, Allocator *using);
def ToFormatFunction = fn void!(void* value, Formatter* formatter);
def FloatType = double;
fn String any.to_string(void* value, Allocator *using) @interface;
fn void! any.to_format(void* value, Formatter* formatter) @interface;
fn usz! printf(String format, args...) @maydiscard
{
Formatter formatter;
@@ -102,41 +103,6 @@ fn void Formatter.init(Formatter* this, OutputFn out_fn, void* data = null)
*this = { .data = data, .out_fn = out_fn};
}
/**
* @require $checks($Type a, a.to_string()) || $checks($Type a, a.to_format(&&Formatter{})) "Expected a type with 'to_string' or 'to_format' defined"
* @require !$checks($Type a, a.to_string()) || $checks($Type a, a.to_string(&&Allocator{})) "Expected 'to_string' to take an allocator as argument."
* @require !$checks($Type a, a.to_format(&&Formatter{})) || $checks($Type a, Formatter b, a.to_format(&b)) "Expected 'to_format' to take a Formatter as argument."
*/
macro void formatter_register_type($Type)
{
$if $checks($Type a, a.to_format(&&Formatter {})):
if (!toformat_functions.table.len)
{
toformat_functions.init(64);
}
toformat_functions.set($Type.typeid, (ToFormatFunction)&$Type.to_format);
$else
if (!tostring_functions.table.len)
{
tostring_functions.init(64);
}
tostring_functions.set($Type.typeid, (ToStringFunction)&$Type.to_string);
$endif
}
static initialize @priority(101)
{
if (!toformat_functions.table.len)
{
toformat_functions.init(64);
}
if (!tostring_functions.table.len)
{
tostring_functions.init(64);
}
}
fn void! Formatter.out(Formatter* this, char c) @private
{
this.out_fn(c, this.data)!;
@@ -144,7 +110,7 @@ fn void! Formatter.out(Formatter* this, char c) @private
macro bool! Formatter.print_with_function(Formatter* this, any arg)
{
if (try to_format = toformat_functions.get(arg.type))
if (&arg.to_format)
{
PrintFlags old = this.flags;
uint old_width = this.width;
@@ -155,10 +121,10 @@ macro bool! Formatter.print_with_function(Formatter* this, any arg)
this.width = old_width;
this.prec = old_prec;
}
to_format(arg.ptr, this)!;
arg.to_format(this)!;
return true;
}
if (try to_string = tostring_functions.get(arg.type))
}
if (&arg.to_string)
{
PrintFlags old = this.flags;
uint old_width = this.width;
@@ -171,7 +137,7 @@ macro bool! Formatter.print_with_function(Formatter* this, any arg)
}
@pool()
{
this.out_substr(to_string(arg.ptr, mem::temp()))!;
this.out_substr(arg.to_string(mem::temp()))!;
return true;
};
}
@@ -277,21 +243,8 @@ fn void! Formatter.out_str(Formatter* this, any arg) @private
}
this.out(']')!;
case BOOL:
if (*(bool*)arg.ptr)
{
return this.out_substr("true");
}
else
{
return this.out_substr("false");
}
return this.out_substr(*(bool*)arg.ptr ? "true" : "false");
default:
switch (arg)
{
case Object:
arg.to_format(this)!;
return;
}
if (this.print_with_function(arg)!) return;
return this.out_substr("Invalid type");
}
@@ -472,8 +425,3 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
return this.idx;
}
def StringFunctionMap @private = HashMap<typeid, ToStringFunction>;
def FormatterFunctionMap @private = HashMap<typeid, ToFormatFunction>;
FormatterFunctionMap toformat_functions @private;
StringFunctionMap tostring_functions @private;

View File

@@ -37,12 +37,8 @@ struct InetAddress
}
}
static initialize
{
io::formatter_register_type(InetAddress);
}
fn void! InetAddress.to_format(InetAddress* addr, Formatter* formatter)
fn void! InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic
{
if (addr.is_ipv6)
{
@@ -54,7 +50,7 @@ fn void! InetAddress.to_format(InetAddress* addr, Formatter* formatter)
formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!;
}
fn String! InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap())
fn String! InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap()) @dynamic
{
if (addr.is_ipv6)
{

View File

@@ -2,7 +2,7 @@ module std::thread::os;
$if thread::THREAD_MODEL == ThreadModel.WIN32:
typedef NativeThread = Win32_HANDLE;
def NativeThread = Win32_HANDLE;
struct NativeMutex
{

View File

@@ -8,8 +8,8 @@ struct Darwin_mach_timebase_info
uint denom;
}
typedef Darwin_mach_timebase_info_t = Darwin_mach_timebase_info;
typedef Darwin_mach_timebase_info_data_t = Darwin_mach_timebase_info;
def Darwin_mach_timebase_info_t = Darwin_mach_timebase_info;
def Darwin_mach_timebase_info_data_t = Darwin_mach_timebase_info;
extern fn void mach_timebase_info(Darwin_mach_timebase_info_data_t* timebase);
extern fn ulong mach_absolute_time();

View File

@@ -1,9 +1,9 @@
module std::time;
typedef Time @inline = distinct long;
typedef TimeDuration @inline = distinct long;
typedef Clock @inline = distinct ulong;
typedef NanoDuration @inline = distinct long;
def Time @inline = distinct long;
def TimeDuration @inline = distinct long;
def Clock @inline = distinct ulong;
def NanoDuration @inline = distinct long;
const TimeDuration MICROSECONDS_PER_SECOND = 1_000_000;
const TimeDuration MICROSECONDS_PER_MINUTE = MICROSECONDS_PER_SECOND * 60;

View File

@@ -3,10 +3,12 @@
## 0.5.0 Change List
### Changes / improvements
- `@dynamic` and `@interface` for dynamic dispatch.
- `$if` now uses `$if <expr>:` syntax.
- `$assert` now uses `$assert <expr> : <optional message>`
- `$error` is syntax sugar for `$assert false : "Some message"`
- `$include`, `$echo` no longer has mandatory `()` around the arguments.
- Updated cpu arguments for x86
- Dropped support for LLVM 13-14.
- Updated grammar and lexer definition.
- Removal of `$elif`.
@@ -22,7 +24,7 @@
- Allow getting the underlying type of anyfault.
- De-duplicate string constants.
- Change @extname => @extern.
- `define Type = int` is replaced by `typedef Type = int`.
- `define` is replaced by `def`.
- LLVM "wrapper" library compilation is exception free.
- `private` is replaced by attribute `@private`.
- Addition of `@local` for file local visibility.

View File

@@ -95,9 +95,9 @@ int comment_level = 0;
"char" { count(); return(CHAR); }
"const" { count(); return(CONST); }
"continue" { count(); return(CONTINUE); }
"def" { count(); return(DEF); }
"default" { count(); return(DEFAULT); }
"defer" { count(); return(DEFER); }
"define" { count(); return(DEFINE); }
"distinct" { count(); return(DISTINCT); }
"do" { count(); return(DO); }
"double" { count(); return(DOUBLE); }
@@ -137,7 +137,6 @@ int comment_level = 0;
"tlocal" { count(); return(TLOCAL); }
"true" { count(); return(TRUE); }
"try" { count(); return(TRY); }
"typedef" { count(); return(TYPEDEF); }
"typeid" { count(); return(TYPEID); }
"uint" { count(); return(UINT); }
"uint128" { count(); return(UINT128); }

View File

@@ -17,7 +17,7 @@ void yyerror(char *s);
%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
%token SUB_ASSIGN SHL_ASSIGN SHR_ASSIGN AND_ASSIGN
%token XOR_ASSIGN OR_ASSIGN VAR NUL ELVIS NEXTCASE ANYFAULT
%token TYPEDEF MODULE IMPORT DEFINE EXTERN
%token MODULE IMPORT DEF EXTERN
%token CHAR SHORT INT LONG FLOAT DOUBLE CONST VOID USZ ISZ UPTR IPTR ANY
%token ICHAR USHORT UINT ULONG BOOL INT128 UINT128 FLOAT16 FLOAT128 BFLOAT16
%token TYPEID BITSTRUCT STATIC BANGBANG AT_CONST_IDENT HASH_TYPE_IDENT
@@ -1110,9 +1110,6 @@ typedef_type
| type opt_generic_parameters
;
typedef_declaration
: TYPEDEF TYPE_IDENT opt_attributes '=' opt_distinct_inline typedef_type ';'
;
multi_declaration
@@ -1166,8 +1163,9 @@ define_ident
;
define_declaration
: DEFINE define_ident ';'
| DEFINE define_attribute ';'
: DEF define_ident ';'
| DEF define_attribute ';'
| DEF TYPE_IDENT opt_attributes '=' opt_distinct_inline typedef_type ';'
;
tl_ct_if
@@ -1233,7 +1231,6 @@ top_level
| fault_declaration
| enum_declaration
| macro_declaration
| typedef_declaration
| define_declaration
| static_declaration
| bitstruct_declaration

View File

@@ -231,8 +231,8 @@ fn void hello() throws Errors
return;
}
typedef Foo* as Bar;
typedef fn void(int, Foo*) as Zoo;
def Foo* as Bar;
def fn void(int, Foo*) as Zoo;

View File

@@ -103,7 +103,7 @@ const uint SDL_WINDOWPOS_UNDEFINED = UndefinedDisplay(x);
#define SDL_WINDOWPOS_ISCENTERED(X) \
(((X)&0xFFFF0000) == SDL_WINDOWPOS_CENTERED_MASK)
typedef enum
def enum
{
SDL_ORIENTATION_UNKNOWN, /**< The display orientation can't be determined */
SDL_ORIENTATION_LANDSCAPE, /**< The display is in landscape mode, with the right side up, relative to portrait mode */
@@ -115,7 +115,7 @@ typedef enum
/**
* \brief An opaque handle to an OpenGL context.
*/
typedef void *SDL_GLContext;
def void *SDL_GLContext;
enum GLAttr
@@ -149,14 +149,14 @@ enum GLAttr
GL_CONTEXT_NO_ERROR
}
typedef enum
def enum
{
SDL_GL_CONTEXT_PROFILE_CORE = 0x0001,
SDL_GL_CONTEXT_PROFILE_COMPATIBILITY = 0x0002,
SDL_GL_CONTEXT_PROFILE_ES = 0x0004 /**< GLX_CONTEXT_ES2_PROFILE_BIT_EXT */
} SDL_GLprofile;
typedef enum
def enum
{
SDL_GL_CONTEXT_DEBUG_FLAG = 0x0001,
SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG = 0x0002,
@@ -164,13 +164,13 @@ typedef enum
SDL_GL_CONTEXT_RESET_ISOLATION_FLAG = 0x0008
} SDL_GLcontextFlag;
typedef enum
def enum
{
SDL_GL_CONTEXT_RELEASE_BEHAVIOR_NONE = 0x0000,
SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH = 0x0001
} SDL_GLcontextReleaseFlag;
typedef enum
def enum
{
SDL_GL_CONTEXT_RESET_NO_NOTIFICATION = 0x0000,
SDL_GL_CONTEXT_RESET_LOSE_CONTEXT = 0x0001
@@ -810,7 +810,7 @@ extern DECLSPEC int SDLCALL SDL_GetWindowGammaRamp(SDL_Window * window,
*
* \sa SDL_HitTest
*/
typedef enum
def enum
{
SDL_HITTEST_NORMAL, /**< Region is normal. No special properties. */
SDL_HITTEST_DRAGGABLE, /**< Region can drag entire window. */
@@ -829,7 +829,7 @@ typedef enum
*
* \sa SDL_SetWindowHitTest
*/
typedef SDL_HitTestResult (SDLCALL *SDL_HitTest)(SDL_Window *win,
def SDL_HitTestResult (SDLCALL *SDL_HitTest)(SDL_Window *win,
const SDL_Point *area,
void *data);

View File

@@ -130,7 +130,8 @@ static void usage(void)
OUTPUT(" --forcelinker - Force built in linker usage when doing non-cross linking.");
OUTPUT("");
OUTPUT(" --reloc=<option> - Relocation model: none, pic, PIC, pie, PIE.");
OUTPUT(" --x86vec=<option> - Set max level of vector instructions: none, native, mmx, sse, avx, avx512.");
OUTPUT(" --x86cpu=<option> - Set general level of x64 cpu: baseline, ssse3, sse4, avx1, avx2-v1, avx2-v2 (Skylake/Zen1+), avx512 (Icelake/Zen4+), native.");
OUTPUT(" --x86vec=<option> - Set max type of vector use: none, mmx, sse, avx, avx512, native.");
OUTPUT(" --riscvfloat=<option> - Set type of RISC-V float support: none, float, double");
OUTPUT(" --memory-env=<option> - Set the memory environment: normal, small, tiny, none.");
OUTPUT(" --strip-unused - Strip unused code and globals from the output (experimental)");
@@ -158,7 +159,11 @@ static void usage(void)
OUTPUT(" --wincrt=<option> - Windows CRT linking: none, static, dynamic (default).");
OUTPUT("");
OUTPUT(" --macossdk <dir> - Set the directory for the MacOS SDK for cross compilation.");
OUTPUT(" --macos-min-version <ver> - Set the minimum MacOS version to compile for.");
OUTPUT(" --macos-sdk-version <ver> - Set the MacOS SDK compiled for.");
OUTPUT("");
OUTPUT(" --linux-crt <dir> - Set the directory to use for finding crt1.o and related files.");
OUTPUT(" --linux-crtbegin <dir> - Set the directory to use for finding crtbegin.o and related files.");
}
@@ -551,7 +556,12 @@ static void parse_option(BuildOptions *options)
}
if ((argopt = match_argopt("x86vec")))
{
options->x86_vector_capability = (X86VectorCapability)parse_multi_option(argopt, 6, vector_capability);
options->x86_vector_capability = (X86VectorCapability)parse_multi_option(argopt, 6, x86_vector_capability);
return;
}
if ((argopt = match_argopt("x86cpu")))
{
options->x86_cpu_set = (X86CpuSet)parse_multi_option(argopt, 8, x86_cpu_set);
return;
}
if ((argopt = match_argopt("riscvfloat")))
@@ -801,6 +811,18 @@ static void parse_option(BuildOptions *options)
options->path = check_dir(next_arg());
return;
}
if (match_longopt("linux-crt"))
{
if (at_end() || next_is_opt()) error_exit("error: --linux-crt needs a directory.");
options->linuxpaths.crt = check_dir(next_arg());
return;
}
if (match_longopt("linux-crtbegin"))
{
if (at_end() || next_is_opt()) error_exit("error: --linux-crtbegin needs a directory.");
options->linuxpaths.crtbegin = check_dir(next_arg());
return;
}
if (match_longopt("safe"))
{
options->safe_mode = 1;
@@ -858,6 +880,7 @@ BuildOptions parse_arguments(int argc, const char *argv[])
.reloc_model = RELOC_DEFAULT,
.backend = BACKEND_LLVM,
.x86_vector_capability = X86VECTOR_DEFAULT,
.x86_cpu_set = X86CPU_DEFAULT,
.riscv_float_capability = RISCVFLOAT_DEFAULT,
.memory_environment = MEMORY_ENV_NOT_SET,
.win.crt_linking = WIN_CRT_DEFAULT,

View File

@@ -141,6 +141,18 @@ typedef enum
X86VECTOR_NATIVE = 5,
} X86VectorCapability;
typedef enum
{
X86CPU_DEFAULT = -1,
X86CPU_BASELINE = 0,
X86CPU_SSSE3 = 1,
X86CPU_SSE4 = 2,
X86CPU_AVX1 = 3,
X86CPU_AVX2_V1 = 4,
X86CPU_AVX2_V2 = 5,
X86CPU_AVX512 = 6,
X86CPU_NATIVE = 7,
} X86CpuSet;
typedef enum
{
@@ -151,7 +163,7 @@ typedef enum
} RiscvFloatCapability;
static const char *vector_capability[6] = {
static const char *x86_vector_capability[6] = {
[X86VECTOR_NONE] = "none",
[X86VECTOR_MMX] = "mmx",
[X86VECTOR_SSE] = "sse",
@@ -160,6 +172,17 @@ static const char *vector_capability[6] = {
[X86VECTOR_NATIVE] = "native"
};
static const char *x86_cpu_set[8] = {
[X86CPU_BASELINE] = "baseline",
[X86CPU_SSSE3] = "ssse3",
[X86CPU_SSE4] = "sse4",
[X86CPU_AVX1] = "avx1",
[X86CPU_AVX2_V1] = "avx2-v1",
[X86CPU_AVX2_V2] = "avx2-v2",
[X86CPU_AVX512] = "avx512",
[X86CPU_NATIVE] = "native"
};
static const char *riscv_capability[3] = {
[RISCVFLOAT_NONE] = "none",
[RISCVFLOAT_FLOAT] = "float",
@@ -274,6 +297,10 @@ typedef struct BuildOptions_
const char *min_version;
const char *sdk_version;
} macos;
struct {
const char *crt;
const char *crtbegin;
} linuxpaths;
int build_threads;
const char** libraries_to_fetch;
const char** files;
@@ -310,6 +337,7 @@ typedef struct BuildOptions_
const char *obj_out;
RelocModel reloc_model;
X86VectorCapability x86_vector_capability;
X86CpuSet x86_cpu_set;
RiscvFloatCapability riscv_float_capability;
MemoryEnvironment memory_environment;
bool strip_unused;
@@ -354,6 +382,7 @@ typedef struct
LibraryTarget **targets;
} Library;
typedef struct
{
TargetType type;
@@ -417,6 +446,7 @@ typedef struct
RiscvFloatCapability riscv_float_capability : 4;
bool trap_on_wrap : 1;
bool safe_mode : 1;
X86CpuSet x86_cpu_set;
} feature;
struct
{
@@ -430,6 +460,11 @@ typedef struct
WinCrtLinking crt_linking;
bool use_win_subsystem;
} win;
struct
{
const char *crt;
const char *crtbegin;
} linuxpaths;
} BuildTarget;

View File

@@ -243,10 +243,16 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
if (options->macos.min_version) target->macos.min_version = options->macos.min_version;
if (options->macos.sdk_version) target->macos.sdk_version = options->macos.sdk_version;
if (options->win.crt_linking != WIN_CRT_DEFAULT) target->win.crt_linking = options->win.crt_linking;
if (options->linuxpaths.crt) target->linuxpaths.crt = options->linuxpaths.crt;
if (options->linuxpaths.crtbegin) target->linuxpaths.crtbegin = options->linuxpaths.crtbegin;
if (options->x86_vector_capability != X86VECTOR_DEFAULT)
{
target->feature.x86_vector_capability = options->x86_vector_capability;
}
if (options->x86_cpu_set != X86CPU_DEFAULT)
{
target->feature.x86_cpu_set = options->x86_cpu_set;
}
if (options->riscv_float_capability != RISCVFLOAT_DEFAULT)
{
target->feature.riscv_float_capability = options->riscv_float_capability;
@@ -322,6 +328,7 @@ void init_default_build_target(BuildTarget *target, BuildOptions *options)
.arch_os_target = ARCH_OS_TARGET_DEFAULT,
.reloc_model = RELOC_DEFAULT,
.feature.x86_vector_capability = X86VECTOR_DEFAULT,
.feature.x86_cpu_set = X86CPU_DEFAULT,
.feature.riscv_float_capability = RISCVFLOAT_DEFAULT,
.win.crt_linking = WIN_CRT_DEFAULT,
.feature.safe_mode = true,

View File

@@ -351,9 +351,13 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
if (wincrt > -1) target->win.crt_linking = (WinCrtLinking)wincrt;
// x86vec
int x86vec = get_valid_string_setting(json, "x86vec", type, vector_capability, 0, 6, "none, native, mmx, sse, avx or avx512");
int x86vec = get_valid_string_setting(json, "x86vec", type, x86_vector_capability, 0, 6, "none, native, mmx, sse, avx or avx512");
if (x86vec > -1) target->feature.x86_vector_capability = x86vec;
// x86vec
int x86cpu = get_valid_string_setting(json, "x86cpu", type, x86_cpu_set, 0, 8, "baseline, ssse3, sse4, avx1, avx2-v1, avx2-v2, avx512 or native");
if (x86cpu > -1) target->feature.x86_cpu_set = x86cpu;
// riscvfloat
int riscv_float = get_valid_string_setting(json, "riscvfloat", type, riscv_capability, 0, 3, "none, float or double");
if (riscv_float > -1) target->feature.riscv_float_capability = riscv_float;
@@ -370,6 +374,12 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
// macos-sdk-version
target->macos.sdk_version = get_valid_string(json, "macos-sdk-version", type, false);
// Linux crt
target->linuxpaths.crt = get_valid_string(json, "linux-crt", type, false);
// Linux crtbegin
target->linuxpaths.crtbegin = get_valid_string(json, "linux-crtbegin", type, false);
// version
const char *version = get_valid_string(json, "version", type, false);
if (version) target->version = version;
@@ -450,6 +460,7 @@ static void project_add_targets(Project *project, JSONObject *project_data)
.feature.soft_float = SOFT_FLOAT_DEFAULT,
.feature.trap_on_wrap = false,
.feature.x86_vector_capability = X86VECTOR_DEFAULT,
.feature.x86_cpu_set = X86CPU_DEFAULT,
.feature.safe_mode = true,
.win.crt_linking = WIN_CRT_DEFAULT,
};

View File

@@ -3,10 +3,11 @@
enum IntrospectIndex
{
INTROSPECT_INDEX_KIND = 0,
INTROSPECT_INDEX_SIZEOF = 1,
INTROSPECT_INDEX_INNER = 2,
INTROSPECT_INDEX_LEN = 3,
INTROSPECT_INDEX_ADDITIONAL = 4,
INTROSPECT_INDEX_DTABLE = 1,
INTROSPECT_INDEX_SIZEOF = 2,
INTROSPECT_INDEX_INNER = 3,
INTROSPECT_INDEX_LEN = 4,
INTROSPECT_INDEX_ADDITIONAL = 5,
INTROSPECT_INDEX_TOTAL,
};

View File

@@ -432,8 +432,7 @@ void compiler_compile(void)
}
else if (task_count > 1)
{
TaskQueueRef queue = taskqueue_create(active_target.build_threads > task_count ? task_count : active_target.build_threads, tasks);
taskqueue_wait_for_completion(queue);
taskqueue_run(active_target.build_threads > task_count ? task_count : active_target.build_threads, tasks);
}
if (active_target.print_output)

View File

@@ -558,8 +558,10 @@ typedef struct
bool attr_naked : 1;
bool attr_test : 1;
bool attr_winmain : 1;
bool has_faults : 1;
Decl** generated_lambda;
bool attr_dynamic : 1;
bool attr_interface : 1;
DeclId any_prototype;
Decl **generated_lambda;
};
struct
{
@@ -650,7 +652,6 @@ typedef struct
} InitializerDecl;
typedef struct Decl_
{
const char *name;
@@ -793,6 +794,7 @@ typedef struct
bool attr_pure : 1;
bool result_unused : 1;
bool no_return : 1;
bool is_dynamic_dispatch : 1;
AstId body;
union
{

View File

@@ -762,10 +762,12 @@ typedef enum
ATTRIBUTE_BUILTIN,
ATTRIBUTE_CDECL,
ATTRIBUTE_DEPRECATED,
ATTRIBUTE_DYNAMIC,
ATTRIBUTE_EXPORT,
ATTRIBUTE_EXTERN,
ATTRIBUTE_EXTNAME,
ATTRIBUTE_INLINE,
ATTRIBUTE_INTERFACE,
ATTRIBUTE_LITTLEENDIAN,
ATTRIBUTE_LOCAL,
ATTRIBUTE_MAYDISCARD,

View File

@@ -286,6 +286,11 @@ static void linker_setup_macos(const char ***args_ref, LinkerType linker_type)
}
add_arg("-arch");
add_arg(arch_to_linker_arch(platform_target.arch));
if (active_target.strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
{
add_arg("-no_exported_symbols");
add_arg("-dead_strip");
}
// Skip if no libc.
if (active_target.no_libc) return;
@@ -335,6 +340,7 @@ static const char *find_freebsd_crt(void)
static const char *find_linux_crt(void)
{
if (active_target.linuxpaths.crt) return active_target.linuxpaths.crt;
#if PLATFORM_POSIX
glob_t globbuf;
if (!glob("/usr/lib/*/crt1.o", 0, NULL, &globbuf) && globbuf.gl_pathc)
@@ -357,6 +363,7 @@ static const char *find_linux_crt(void)
static const char *find_linux_crt_begin(void)
{
if (active_target.linuxpaths.crtbegin) return active_target.linuxpaths.crtbegin;
#if PLATFORM_POSIX
glob_t globbuf;
if (!glob("/usr/lib/gcc/*/*/crtbegin.o", 0, NULL, &globbuf) && globbuf.gl_pathc)
@@ -379,13 +386,23 @@ static const char *find_linux_crt_begin(void)
static void linker_setup_linux(const char ***args_ref, LinkerType linker_type)
{
if (linker_type == LINKER_CC) return;
if (linker_type == LINKER_CC)
{
add_arg("-pthread");
return;
}
if (is_no_pie(platform_target.reloc_model)) add_arg("-no-pie");
if (is_pie(platform_target.reloc_model)) add_arg("-pie");
if (platform_target.arch == ARCH_TYPE_X86_64) add_arg("--eh-frame-hdr");
if (active_target.no_libc) return;
const char *crt_begin_dir = find_linux_crt_begin();
const char *crt_dir = find_linux_crt();
if (active_target.strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
{
add_arg("-dead_strip");
}
if (!crt_begin_dir || !crt_dir)
{
error_exit("Failed to find the C runtime at link time.");
@@ -408,9 +425,9 @@ static void linker_setup_linux(const char ***args_ref, LinkerType linker_type)
add_arg2(crt_dir, "crtn.o");
add_arg2("-L", crt_dir);
add_arg("--dynamic-linker=/lib64/ld-linux-x86-64.so.2");
add_arg("-lc");
add_arg("-lm");
add_arg("-lpthread");
add_arg("-lc");
add_arg("-L/usr/lib/");
add_arg("-L/lib/");
add_arg("-m");
@@ -431,6 +448,11 @@ static void linker_setup_freebsd(const char ***args_ref, LinkerType linker_type)
{
error_exit("Failed to find the C runtime at link time.");
}
if (active_target.strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
{
add_arg("-dead_strip");
}
if (is_pie_pic(platform_target.reloc_model))
{
add_arg("-pie");

View File

@@ -724,6 +724,7 @@ static void llvm_codegen_setup()
attribute_id.uwtable = lookup_attribute("uwtable");
attribute_id.writeonly = lookup_attribute("writeonly");
attribute_id.zext = lookup_attribute("zeroext");
attribute_id.target_features = lookup_attribute("target-features");
intrinsics_setup = true;
}
@@ -755,14 +756,11 @@ void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i)
llvm_value_set(value, llvm_const_int(c, type, i), type);
}
bool llvm_value_is_const(BEValue *value)
{
return LLVMIsConstant(value->value);
}
void llvm_value_set_decl(GenContext *c, BEValue *value, Decl *decl)
{
decl = decl_flatten(decl);
@@ -775,11 +773,6 @@ void llvm_value_set_decl(GenContext *c, BEValue *value, Decl *decl)
}
LLVMBasicBlockRef llvm_basic_block_new(GenContext *c, const char *name)
{
return LLVMCreateBasicBlockInContext(c->context, name);
@@ -1042,10 +1035,29 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
}
assert(decl->var.kind == VARDECL_GLOBAL || decl->var.kind == VARDECL_CONST);
llvm_add_global_decl(c, decl);
if (decl->is_export && platform_target.os == OS_TYPE_WIN32)
{
LLVMSetDLLStorageClass(decl->backend_ref, LLVMDLLExportStorageClass);
}
return decl->backend_ref;
case DECL_FUNC:
if (decl->func_decl.attr_interface)
{
size_t name_len = strlen(decl->name);
LLVMTypeRef char_array_type = LLVMArrayType(c->byte_type, name_len + 1);
LLVMValueRef selector = llvm_add_global_raw(c, decl_get_extname(decl), char_array_type, 0);
LLVMSetGlobalConstant(selector, 1);
LLVMSetInitializer(selector, llvm_get_zstring(c, decl->name, name_len));
LLVMSetLinkage(selector, LLVMLinkOnceODRLinkage);
llvm_set_comdat(c, selector);
return decl->backend_ref = selector;
}
backend_ref = decl->backend_ref = LLVMAddFunction(c->module, decl_get_extname(decl), llvm_get_type(c, decl->type));
llvm_append_function_attributes(c, decl);
if (decl->is_export && platform_target.os == OS_TYPE_WIN32 && decl->name != kw_main && decl->name != kw_mainstub)
{
LLVMSetDLLStorageClass(backend_ref, LLVMDLLExportStorageClass);
}
if (decl_is_local(decl))
{
assert(decl->unit->module == c->code_module);
@@ -1301,6 +1313,7 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
llvm_emit_function_decl(gen_context, func);
FOREACH_END();
FOREACH_BEGIN(Decl *func, unit->lambdas)
if (only_used && !func->is_live) continue;
has_elements = true;
@@ -1367,6 +1380,8 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
FOREACH_END();
llvm_emit_dynamic_functions(gen_context, gen_context->dynamic_functions);
llvm_emit_constructors_and_destructors(gen_context);
// EmitDeferred()

View File

@@ -116,7 +116,7 @@ INLINE void llvm_emit_compare_exchange(GenContext *c, BEValue *result_value, Exp
llvm_value_set(result_value, llvm_emit_extract_value(c, result, 0), type);
}
INLINE void llvm_emit_unreachable(GenContext *c, BEValue *result_value, Expr *expr)
INLINE void llvm_emit_unreachable_stmt(GenContext *c, BEValue *result_value, Expr *expr)
{
llvm_value_set(result_value, LLVMBuildUnreachable(c->builder), type_void);
c->current_block = NULL;
@@ -622,7 +622,7 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
switch (func)
{
case BUILTIN_UNREACHABLE:
llvm_emit_unreachable(c, result_value, expr);
llvm_emit_unreachable_stmt(c, result_value, expr);
return;
case BUILTIN_SWIZZLE:
llvm_emit_swizzle(c, result_value, expr, false);

View File

@@ -13,7 +13,7 @@ static inline LLVMValueRef llvm_emit_expr_to_rvalue(GenContext *c, Expr *expr);
static inline LLVMValueRef llvm_emit_exprid_to_rvalue(GenContext *c, ExprId expr_id);
static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, MemberIndex index);
static inline void llvm_emit_expression_list_expr(GenContext *c, BEValue *be_value, Expr *expr);
static LLVMValueRef llvm_emit_dynamic_search(GenContext *c, LLVMValueRef type_id_ptr, LLVMValueRef selector);
static inline void llvm_emit_bitassign_array(GenContext *c, BEValue *result, BEValue parent, Decl *parent_decl, Decl *member);
static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Expr *expr);
static inline void llvm_emit_const_initialize_reference(GenContext *c, BEValue *ref, Expr *expr);
@@ -35,6 +35,7 @@ static inline void llvm_emit_try_unwrap(GenContext *c, BEValue *value, Expr *exp
static inline void llvm_emit_any(GenContext *c, BEValue *value, Expr *expr);
static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *value, Expr *expr);
static inline void llvm_extract_bitvalue_from_array(GenContext *c, BEValue *be_value, Decl *member, Decl *parent_decl);
static inline void llvm_emit_type_from_any(GenContext *c, BEValue *be_value);
static void llvm_convert_vector_comparison(GenContext *c, BEValue *be_value, LLVMValueRef val, Type *vector_type,
bool is_equals);
static void llvm_emit_any_pointer(GenContext *c, BEValue *any, BEValue *pointer);
@@ -2446,6 +2447,19 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e
llvm_emit_inc_dec_change(c, &addr, NULL, value, expr, diff);
}
static void llvm_emit_dynamic_method_addr(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_expr(c, value, expr->access_expr.parent);
llvm_emit_type_from_any(c, value);
llvm_value_rvalue(c, value);
LLVMValueRef introspect = LLVMBuildIntToPtr(c->builder, value->value, c->ptr_type, "");
AlignSize align;
Decl *dyn_fn = expr->access_expr.ref;
LLVMValueRef func = llvm_emit_dynamic_search(c, introspect, llvm_get_ref(c, dyn_fn));
llvm_value_set(value, func, type_get_ptr(dyn_fn->type));
}
static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
{
@@ -2553,8 +2567,14 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
}
value->value = LLVMBuildNeg(c->builder, value->value, "neg");
return;
case UNARYOP_TADDR:
case UNARYOP_ADDR:
if (inner->expr_kind == EXPR_ACCESS && inner->access_expr.ref->decl_kind == DECL_FUNC)
{
llvm_emit_dynamic_method_addr(c, value, inner);
return;
}
FALLTHROUGH;
case UNARYOP_TADDR:
llvm_emit_expr(c, value, inner);
// Create an addr
llvm_value_addr(c, value);
@@ -4158,9 +4178,7 @@ static inline void llvm_emit_force_unwrap_expr(GenContext *c, BEValue *be_value,
llvm_emit_any_from_value(c, &fault_arg, type_anyfault);
vec_add(varargs, fault_arg);
llvm_emit_panic(c, "Force unwrap failed!", loc, "Unexpected fault '%s' was unwrapped!", varargs);
LLVMBuildUnreachable(c->builder);
c->current_block = NULL;
c->current_block_is_target = false;
llvm_emit_unreachable(c);
}
llvm_emit_block(c, no_err_block);
@@ -4978,11 +4996,6 @@ static void llvm_emit_splatted_variadic_arg(GenContext *c, Expr *expr, Type *var
}
}
void llvm_add_abi_call_attributes(GenContext *c, LLVMValueRef call_value, int count, ABIArgInfo **infos)
{
for (unsigned i = 0; i < count; i++)
@@ -5255,6 +5268,105 @@ void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype
// 17i. The simple case here is where there is a normal return.
// In this case be_value already holds the result
}
static LLVMValueRef llvm_emit_dynamic_search(GenContext *c, LLVMValueRef type_id_ptr, LLVMValueRef selector)
{
LLVMTypeRef type = c->dyn_find_function_type;
LLVMValueRef func = c->dyn_find_function;
if (!c->dyn_find_function)
{
LLVMTypeRef types[2] = { c->ptr_type, c->ptr_type };
type = c->dyn_find_function_type = LLVMFunctionType(c->ptr_type, types, 2, false);
func = c->dyn_find_function = LLVMAddFunction(c->module, ".dyn_seach", c->dyn_find_function_type);
LLVMSetUnnamedAddress(func, LLVMGlobalUnnamedAddr);
LLVMSetLinkage(func, LLVMWeakODRLinkage);
LLVMBuilderRef builder = LLVMCreateBuilderInContext(c->context);
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, func, "entry");
LLVMPositionBuilderAtEnd(builder, entry);
AlignSize align;
LLVMValueRef dtable_ptr_in = LLVMGetParam(func, 0);
LLVMValueRef func_ref = LLVMGetParam(func, 1);
LLVMBasicBlockRef check = llvm_basic_block_new(c, "check");
LLVMBasicBlockRef missing_function = llvm_basic_block_new(c, "missing_function");
LLVMBasicBlockRef compare = llvm_basic_block_new(c, "compare");
LLVMBasicBlockRef match = llvm_basic_block_new(c, "match");
LLVMBasicBlockRef no_match = llvm_basic_block_new(c, "no_match");
LLVMBuildBr(builder, check);
// check: dtable_ptr = phi
LLVMAppendExistingBasicBlock(func, check);
LLVMPositionBuilderAtEnd(builder, check);
LLVMValueRef dtable_ptr = LLVMBuildPhi(builder, c->ptr_type, "");
// dtable_ptr == null
LLVMValueRef cmp = LLVMBuildICmp(builder, LLVMIntEQ, dtable_ptr, LLVMConstNull(c->ptr_type), "");
// if (cmp) goto missing_function else compare
LLVMBuildCondBr(builder, cmp, missing_function, compare);
// missing_function: return null
LLVMAppendExistingBasicBlock(func, missing_function);
LLVMPositionBuilderAtEnd(builder, missing_function);
LLVMBuildRet(builder, LLVMConstNull(c->ptr_type));
// function_type = dtable_ptr.function_type
LLVMAppendExistingBasicBlock(func, compare);
LLVMPositionBuilderAtEnd(builder, compare);
LLVMValueRef function_type = LLVMBuildStructGEP2(builder, c->dtable_type, dtable_ptr, 1, "");
function_type = LLVMBuildLoad2(builder, c->ptr_type, function_type, "");
LLVMSetAlignment(function_type, llvm_abi_alignment(c, c->ptr_type));
// function_type == func_ref
cmp = LLVMBuildICmp(builder, LLVMIntEQ, function_type, func_ref, "");
// if (cmp) goto match else no_match
LLVMBuildCondBr(builder, cmp, match, no_match);
// match: function_ptr = dtable_ptr.function_ptr
LLVMAppendExistingBasicBlock(func, match);
LLVMPositionBuilderAtEnd(builder, match);
// Offset = 0
LLVMValueRef function_ptr = LLVMBuildLoad2(builder, c->ptr_type, dtable_ptr, "");
LLVMSetAlignment(function_ptr, llvm_abi_alignment(c, c->ptr_type));
LLVMBuildRet(builder, function_ptr);
// no match: next = dtable_ptr.next
LLVMAppendExistingBasicBlock(func, no_match);
LLVMPositionBuilderAtEnd(builder, no_match);
LLVMValueRef next = LLVMBuildStructGEP2(builder, c->dtable_type, dtable_ptr, 2, "");
next = LLVMBuildLoad2(builder, c->ptr_type, next, "");
LLVMSetAlignment(next, llvm_abi_alignment(c, c->ptr_type));
// goto check
LLVMBuildBr(builder, check);
LLVMBasicBlockRef block_in[2] = { entry, no_match };
LLVMValueRef value_in[2] = { dtable_ptr_in, next };
LLVMAddIncoming(dtable_ptr, value_in, block_in, 2);
LLVMDisposeBuilder(builder);
}
AlignSize align;
LLVMValueRef dtable_ref = llvm_emit_struct_gep_raw(c,
type_id_ptr,
c->introspect_type,
INTROSPECT_INDEX_DTABLE,
llvm_abi_alignment(c, c->introspect_type),
&align);
LLVMValueRef dtable_ptr = llvm_load(c, c->ptr_type, dtable_ref, align, "");
LLVMValueRef params[2] = { dtable_ptr, selector };
LLVMValueRef call = LLVMBuildCall2(c->builder, type, func, params, 2, "");
return call;
}
static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr, BEValue *target)
{
if (expr->call_expr.is_builtin)
@@ -5278,9 +5390,46 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
bool always_inline = false;
FunctionPrototype *prototype;
// 1. Call through a pointer.
if (!expr->call_expr.is_func_ref)
Expr **args = expr->call_expr.arguments;
BEValue arg0_pointer = { .value = NULL };
// 1. Dynamic dispatch.
if (expr->call_expr.is_dynamic_dispatch)
{
assert(vec_size(args));
Expr *any_val = args[0];
assert(any_val->expr_kind == EXPR_CAST);
any_val = exprptr(any_val->cast_expr.expr)->unary_expr.expr;
BEValue result;
llvm_emit_expr(c, &result, any_val);
BEValue typeid = result;
llvm_emit_type_from_any(c, &typeid);
llvm_value_rvalue(c, &typeid);
llvm_emit_any_pointer(c, &result, &arg0_pointer);
LLVMValueRef introspect = LLVMBuildIntToPtr(c->builder, typeid.value, c->ptr_type, "");
LLVMBasicBlockRef missing_function = llvm_basic_block_new(c, "missing_function");
LLVMBasicBlockRef match = llvm_basic_block_new(c, "match");
AlignSize align;
Decl *dyn_fn = declptr(expr->call_expr.func_ref);
func = llvm_emit_dynamic_search(c, introspect, llvm_get_ref(c, dyn_fn));
LLVMValueRef cmp = LLVMBuildICmp(c->builder, LLVMIntEQ, func, LLVMConstNull(c->ptr_type), "");
llvm_emit_cond_br_raw(c, cmp, missing_function, match);
llvm_emit_block(c, missing_function);
scratch_buffer_clear();
scratch_buffer_printf("No method '%s' could be found on target", dyn_fn->name);
llvm_emit_panic(c, scratch_buffer_to_string(), expr->span, NULL, NULL);
llvm_emit_unreachable(c);
llvm_emit_block(c, match);
prototype = type_get_resolved_prototype(dyn_fn->type);
func_type = llvm_get_type(c, dyn_fn->type);
}
else if (!expr->call_expr.is_func_ref)
{
// Call through a pointer.
Expr *function = exprptr(expr->call_expr.function);
// 1a. Find the pointee type for the function pointer:
@@ -5312,13 +5461,11 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
assert(func);
func_type = llvm_get_type(c, function_decl->type);
}
LLVMValueRef arg_values[512];
unsigned arg_count = 0;
Type **params = prototype->param_types;
ABIArgInfo **abi_args = prototype->abi_args;
unsigned param_count = vec_size(params);
Expr **args = expr->call_expr.arguments;
Expr **varargs = NULL;
Expr *vararg_splat = NULL;
if (expr->call_expr.splat_vararg)
@@ -5428,7 +5575,14 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
if (arg_expr)
{
llvm_emit_expr(c, &temp_value, arg_expr);
if (i == 0 && arg0_pointer.value)
{
temp_value = arg0_pointer;
}
else
{
llvm_emit_expr(c, &temp_value, arg_expr);
}
}
else
{
@@ -5931,9 +6085,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
llvm_emit_block(c, next);
}
llvm_emit_panic(c, "Attempted to access 'inner' on non composite type", expr->span, NULL, NULL);
c->current_block = NULL;
c->current_block_is_target = false;
LLVMBuildUnreachable(c->builder);
llvm_emit_unreachable(c);
llvm_emit_block(c, exit);
}
{
@@ -5962,9 +6114,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
llvm_emit_block(c, next);
}
llvm_emit_panic(c, "Attempted to access 'names' on non enum/fault type.", expr->span, NULL, NULL);
c->current_block = NULL;
c->current_block_is_target = false;
LLVMBuildUnreachable(c->builder);
llvm_emit_unreachable(c);
llvm_emit_block(c, exit);
}
{
@@ -5997,9 +6147,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
llvm_emit_block(c, next);
}
llvm_emit_panic(c, "Attempted to access 'len' on non array type", expr->span, NULL, NULL);
c->current_block = NULL;
c->current_block_is_target = false;
LLVMBuildUnreachable(c->builder);
llvm_emit_unreachable(c);
llvm_emit_block(c, exit);
}
{
@@ -6101,6 +6249,25 @@ static inline void llvm_emit_any(GenContext *c, BEValue *value, Expr *expr)
llvm_value_set(value, var, type_any);
}
static inline void llvm_emit_type_from_any(GenContext *c, BEValue *be_value)
{
if (llvm_value_is_addr(be_value))
{
AlignSize alignment = 0;
LLVMValueRef pointer_addr = llvm_emit_struct_gep_raw(c,
be_value->value,
llvm_get_type(c, type_any),
1,
be_value->alignment,
&alignment);
llvm_value_set_address(be_value, pointer_addr, type_typeid, alignment);
}
else
{
llvm_value_set(be_value, llvm_emit_extract_value(c, be_value->value, 1), type_typeid);
}
}
static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Expr *expr)
{
Expr *inner = exprptr(expr->builtin_access_expr.inner);
@@ -6204,21 +6371,7 @@ static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Ex
return;
}
case ACCESS_TYPEOFANY:
if (llvm_value_is_addr(be_value))
{
AlignSize alignment = 0;
LLVMValueRef pointer_addr = llvm_emit_struct_gep_raw(c,
be_value->value,
llvm_get_type(c, type_any),
1,
be_value->alignment,
&alignment);
llvm_value_set_address(be_value, pointer_addr, type_typeid, alignment);
}
else
{
llvm_value_set(be_value, llvm_emit_extract_value(c, be_value->value, 1), type_typeid);
}
llvm_emit_type_from_any(c, be_value);
return;
}
UNREACHABLE

View File

@@ -5,6 +5,7 @@
#include "llvm_codegen_internal.h"
static LLVMValueRef llvm_add_xxlizer(GenContext *c, unsigned priority, bool is_finalizer);
static void llvm_emit_param_attributes(GenContext *c, LLVMValueRef function, ABIArgInfo *info, bool is_return, int index, int last_index);
static inline void llvm_emit_return_value(GenContext *context, LLVMValueRef value);
static void llvm_expand_from_args(GenContext *c, Type *type, LLVMValueRef ref, unsigned *index, AlignSize alignment);
@@ -404,6 +405,7 @@ void llvm_emit_return_implicit(GenContext *c)
void llvm_emit_function_body(GenContext *c, Decl *decl)
{
DEBUG_LOG("Generating function %s.", decl->extname);
if (decl->func_decl.attr_dynamic) vec_add(c->dynamic_functions, decl);
assert(decl->backend_ref);
llvm_emit_body(c,
decl->backend_ref,
@@ -568,6 +570,18 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_nam
c->function = prev_function;
}
static LLVMValueRef llvm_add_xxlizer(GenContext *c, unsigned priority, bool is_initializer)
{
LLVMTypeRef initializer_type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), NULL, 0, false);
LLVMValueRef **array_ref = is_initializer ? &c->constructors : &c->destructors;
scratch_buffer_clear();
scratch_buffer_printf(is_initializer ? ".static_initialize.%u" : ".static_finalize.%u", vec_size(*array_ref));
LLVMValueRef function = LLVMAddFunction(c->module, scratch_buffer_to_string(), initializer_type);
LLVMSetLinkage(function, LLVMInternalLinkage);
LLVMValueRef vals[3] = { llvm_const_int(c, type_int, priority), function, llvm_get_zero(c, type_voidptr) };
vec_add(*array_ref, LLVMConstStructInContext(c->context, vals, 3, false));
return function;
}
void llvm_emit_xxlizer(GenContext *c, Decl *decl)
{
@@ -577,13 +591,8 @@ void llvm_emit_xxlizer(GenContext *c, Decl *decl)
// Skip if it doesn't have a body.
return;
}
LLVMTypeRef initializer_type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), NULL, 0, false);
bool is_finalizer = decl->decl_kind == DECL_FINALIZE;
LLVMValueRef **array_ref = is_finalizer ? &c->destructors : &c->constructors;
scratch_buffer_clear();
scratch_buffer_printf(is_finalizer ? ".static_finalize.%u" : ".static_initialize.%u", vec_size(*array_ref));
LLVMValueRef function = LLVMAddFunction(c->module, scratch_buffer_to_string(), initializer_type);
LLVMSetLinkage(function, LLVMInternalLinkage);
bool is_initializer = decl->decl_kind == DECL_INITIALIZE;
LLVMValueRef function = llvm_add_xxlizer(c, decl->xxlizer.priority, is_initializer);
if (llvm_use_debug(c))
{
uint32_t row = decl->span.row;
@@ -607,16 +616,67 @@ void llvm_emit_xxlizer(GenContext *c, Decl *decl)
llvm_emit_body(c,
function,
decl->unit->module->name->module,
is_finalizer ? "[static finalizer]" : "[static initializer]",
is_initializer ? "[static initializer]" : "[static finalizer]",
decl->span.file_id,
NULL,
NULL,
body);
unsigned priority = decl->xxlizer.priority;
LLVMValueRef vals[3] = { llvm_const_int(c, type_int, priority), function, llvm_get_zero(c, type_voidptr) };
vec_add(*array_ref, LLVMConstStructInContext(c->context, vals, 3, false));
}
static void llvm_generate_dyn_proto(GenContext *c, LLVMValueRef proto_ref)
{
LLVMBuilderRef builder = LLVMCreateBuilderInContext(c->context);
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, proto_ref, "never");
LLVMPositionBuilderAtEnd(builder, entry);
LLVMBuildUnreachable(builder);
LLVMDisposeBuilder(builder);
}
void llvm_emit_dynamic_functions(GenContext *c, Decl **funcs)
{
if (!vec_size(funcs)) return;
LLVMValueRef initializer = llvm_add_xxlizer(c, 1, true);
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, initializer, "entry");
LLVMBuilderRef builder = LLVMCreateBuilderInContext(c->context);
LLVMPositionBuilderAtEnd(builder, entry);
LLVMBasicBlockRef last_block = entry;
FOREACH_BEGIN(Decl *decl, funcs)
Type *type = typeinfotype(decl->func_decl.type_parent);
scratch_buffer_clear();
scratch_buffer_append("$ct.dyn.");
scratch_buffer_append(decl_get_extname(decl));
LLVMValueRef global = llvm_add_global_raw(c, scratch_buffer_to_string(), c->dtable_type, 0);
Decl *proto = declptr(decl->func_decl.any_prototype);
LLVMValueRef proto_ref = llvm_get_ref(c, proto);
LLVMValueRef vals[3] = { llvm_get_ref(c, decl), proto_ref, LLVMConstNull(c->ptr_type) };
LLVMSetInitializer(global, LLVMConstNamedStruct(c->dtable_type, vals, 3));
LLVMValueRef type_id_ptr = LLVMBuildIntToPtr(builder, llvm_get_typeid(c, type), c->ptr_type, "");
LLVMValueRef dtable_ref = LLVMBuildStructGEP2(builder, c->introspect_type, type_id_ptr, INTROSPECT_INDEX_DTABLE, "");
LLVMBasicBlockRef check = LLVMAppendBasicBlockInContext(c->context, initializer, "dtable_check");
LLVMBuildBr(builder, check);
LLVMPositionBuilderAtEnd(builder, check);
LLVMValueRef phi = LLVMBuildPhi(builder, c->ptr_type, "dtable_ref");
LLVMValueRef load_dtable = LLVMBuildLoad2(builder, c->ptr_type, phi, "dtable_ptr");
LLVMValueRef is_not_null = LLVMBuildICmp(builder, LLVMIntEQ, load_dtable, LLVMConstNull(c->ptr_type), "");
LLVMBasicBlockRef after_check = llvm_basic_block_new(c, "dtable_found");
LLVMBasicBlockRef next = llvm_basic_block_new(c, "dtable_next");
LLVMBuildCondBr(builder, is_not_null, after_check, next);
LLVMAppendExistingBasicBlock(initializer, next);
LLVMPositionBuilderAtEnd(builder, next);
LLVMValueRef next_ptr = LLVMBuildStructGEP2(builder, c->dtable_type, load_dtable, 2, "next_dtable_ref");
LLVMValueRef phi_in[2] = { dtable_ref, next_ptr };
LLVMBasicBlockRef phi_in_block[2] = { last_block, next };
LLVMAddIncoming(phi, phi_in, phi_in_block, 2);
LLVMBuildBr(builder, check);
LLVMAppendExistingBasicBlock(initializer, after_check);
LLVMPositionBuilderAtEnd(builder, after_check);
LLVMBuildStore(builder, global, phi);
last_block = after_check;
FOREACH_END();
LLVMBuildRet(builder, NULL);
LLVMDisposeBuilder(builder);
}
void llvm_emit_function_decl(GenContext *c, Decl *decl)
{
assert(decl->decl_kind == DECL_FUNC);

View File

@@ -102,6 +102,7 @@ typedef struct GenContext_
LLVMTypeRef fault_type;
LLVMTypeRef size_type;
LLVMTypeRef typeid_type;
LLVMTypeRef dtable_type;
LLVMTypeRef char_ptr_type;
LLVMTypeRef ptr_type;
LLVMTypeRef chars_type;
@@ -128,6 +129,9 @@ typedef struct GenContext_
bool current_block_is_target : 1;
LLVMTypeRef type_data_definitions[TYPE_KINDS];
SourceSpan last_emitted_loc;
Decl **dynamic_functions;
LLVMValueRef dyn_find_function;
LLVMTypeRef dyn_find_function_type;
} GenContext;
// LLVM Intrinsics
@@ -244,6 +248,7 @@ typedef struct
unsigned uwtable;
unsigned writeonly; // No writes on pointer
unsigned zext; // zero extend
unsigned target_features; // target-features for function compilation
} LLVMAttributes;
extern LLVMAttributes attribute_id;
@@ -462,6 +467,7 @@ void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *pani
void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_name, SourceSpan loc, const char *fmt, BEValue *value_1,
BEValue *value_2);
void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc, const char *fmt, BEValue *args);
void llvm_emit_unreachable(GenContext *c);
void llvm_emit_any_from_value(GenContext *c, BEValue *value, Type *type);
void llvm_emit_subarray_len(GenContext *context, BEValue *subarray, BEValue *len);
@@ -469,6 +475,7 @@ void llvm_emit_subarray_pointer(GenContext *context, BEValue *subarray, BEValue
void llvm_emit_compound_stmt(GenContext *c, Ast *ast);
LLVMValueRef llvm_emit_const_bitstruct(GenContext *c, ConstInitializer *initializer);
void llvm_emit_function_body(GenContext *context, Decl *decl);
void llvm_emit_dynamic_functions(GenContext *context, Decl **funcs);
BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValueRef optional);
INLINE void llvm_emit_exprid(GenContext *c, BEValue *value, ExprId expr);
INLINE void llvm_emit_statement_chain(GenContext *c, AstId current);

View File

@@ -11,6 +11,7 @@ static inline LLVMTypeRef create_introspection_type(GenContext *c)
LLVMTypeRef type = LLVMStructCreateNamed(c->context, ".introspect");
LLVMTypeRef introspect_type[INTROSPECT_INDEX_TOTAL] = {
[INTROSPECT_INDEX_KIND] = c->byte_type,
[INTROSPECT_INDEX_DTABLE] = c->ptr_type,
[INTROSPECT_INDEX_SIZEOF] = c->size_type,
[INTROSPECT_INDEX_INNER] = c->typeid_type,
[INTROSPECT_INDEX_LEN] = c->size_type,
@@ -44,6 +45,7 @@ void gencontext_begin_module(GenContext *c)
c->panicf = global_context.panicf;
c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context);
c->machine = llvm_target_machine_create();
c->target_data = LLVMCreateTargetDataLayout(c->machine);
LLVMSetModuleDataLayout(c->module, c->target_data);
@@ -102,7 +104,7 @@ void gencontext_begin_module(GenContext *c)
type->decl->backend_ref = NULL;
break;
case TYPE_FUNC:
REMINDER("Clear func when it has reflection");
//REMINDER("Clear func when it has reflection");
break;
default:
break;
@@ -113,6 +115,8 @@ void gencontext_begin_module(GenContext *c)
c->ptr_type = LLVMPointerType(c->byte_type, 0);
c->size_type = llvm_get_type(c, type_usz);
c->typeid_type = llvm_get_type(c, type_typeid);
LLVMTypeRef dtable_type[3] = { c->ptr_type, c->ptr_type, c->ptr_type };
c->dtable_type = LLVMStructTypeInContext(c->context, dtable_type, 3, false);
c->chars_type = llvm_get_type(c, type_chars);
c->introspect_type = create_introspection_type(c);
c->fault_type = create_fault_type(c);

View File

@@ -470,10 +470,8 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast)
SourceSpan loc = ast->span;
llvm_emit_panic(c, "Infinite loop found", loc, NULL, NULL);
LLVMBuildUnreachable(c->builder);
llvm_emit_unreachable(c);
LLVMBasicBlockRef block = llvm_basic_block_new(c, "unreachable_block");
c->current_block = NULL;
c->current_block_is_target = false;
llvm_emit_block(c, block);
return;
}
@@ -1274,6 +1272,12 @@ LLVMValueRef llvm_emit_zstring_named(GenContext *c, const char *str, const char
return string;
}
void llvm_emit_unreachable(GenContext *c)
{
LLVMBuildUnreachable(c->builder);
c->current_block = NULL;
c->current_block_is_target = false;
}
void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc, const char *fmt, BEValue *varargs)
{

View File

@@ -439,6 +439,7 @@ static inline LLVMValueRef llvm_generate_introspection_global(GenContext *c, LLV
}
LLVMValueRef values[INTROSPECT_INDEX_TOTAL] = {
[INTROSPECT_INDEX_KIND] = LLVMConstInt(c->byte_type, introspect_type, false),
[INTROSPECT_INDEX_DTABLE] = LLVMConstNull(c->ptr_type),
[INTROSPECT_INDEX_SIZEOF] = LLVMConstInt(c->size_type, type_size(type), false),
[INTROSPECT_INDEX_INNER] = inner ? llvm_get_typeid(c, inner) : llvm_get_zero(c, type_typeid),
[INTROSPECT_INDEX_LEN] = LLVMConstInt(c->size_type,len, false),
@@ -461,7 +462,7 @@ static inline LLVMValueRef llvm_generate_introspection_global(GenContext *c, LLV
LLVMSetInitializer(global_name, strukt);
}
LLVMSetAlignment(global_name, llvm_abi_alignment(c, c->introspect_type));
LLVMSetGlobalConstant(global_name, 1);
LLVMSetGlobalConstant(global_name, 0);
if (is_external)
{
LLVMSetLinkage(global_name, LLVMExternalLinkage);

View File

@@ -1745,7 +1745,11 @@ static inline void decl_add_type(Decl *decl, TypeKind kind)
*/
static inline Decl *parse_typedef_declaration(ParseContext *c)
{
if (!try_consume(c, TOKEN_DEF)) advance_and_verify(c, TOKEN_TYPEDEF);
if (!try_consume(c, TOKEN_DEF))
{
sema_warning_at(c->span, "The use of 'typedef' is deprecated, please use 'def'.");
advance_and_verify(c, TOKEN_TYPEDEF);
}
Decl *decl = decl_new(DECL_POISONED, symstr(c), c->span);
DEBUG_LOG("Parse typedef %s", decl->name);
@@ -1849,20 +1853,28 @@ static inline Decl *parse_typedef_declaration(ParseContext *c)
static inline Decl *parse_define_ident(ParseContext *c)
{
// 1. Store the beginning of the "define".
if (!try_consume(c, TOKEN_DEF)) advance_and_verify(c, TOKEN_DEFINE);
if (!try_consume(c, TOKEN_DEF))
{
sema_warning_at(c->span, "The use of 'define' is deprecated, please use 'def'.");
advance_and_verify(c, TOKEN_DEFINE);
}
// 2. At this point we expect an ident or a const token.
// since the Type is handled.
TokenType alias_type = c->tok;
if (alias_type != TOKEN_IDENT && alias_type != TOKEN_CONST_IDENT && alias_type != TOKEN_AT_IDENT)
{
if (alias_type == TOKEN_TYPE_IDENT)
if (token_is_keyword_ident(alias_type) && alias_type != TOKEN_FN)
{
SEMA_ERROR_HERE("'%s' is a reserved keyword, try another name.", token_type_to_string(alias_type));
}
else if (alias_type == TOKEN_TYPE_IDENT)
{
SEMA_ERROR_HERE("A variable, constant or attribute name was expected here. If you want to define a new type, use 'typedef' instead.");
}
else
{
SEMA_ERROR_HERE("A variable, constant or attribute name was expected here.");
SEMA_ERROR_HERE("A type, variable, constant or attribute name was expected here.");
}
return poisoned_decl;
}
@@ -2306,10 +2318,9 @@ static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, bool
return func;
}
if (tok_is(c, TOKEN_EOS))
if (try_consume(c, TOKEN_EOS))
{
SEMA_ERROR_HERE("Expected a function body, if you want to declare an extern function use 'extern' or place it in an .c3i file.");
return poisoned_decl;
return func;
}
if (tok_is(c, TOKEN_IMPLIES))

View File

@@ -13,7 +13,7 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl);
static inline bool sema_check_param_uniqueness_and_type(Decl **decls, Decl *current, unsigned current_index, unsigned count);
static inline bool sema_analyse_method(SemaContext *context, Decl *decl);
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type);
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type, bool is_dynamic, bool is_interface);
static inline bool sema_analyse_macro_method(SemaContext *context, Decl *decl);
static inline bool unit_add_base_extension_method(CompilationUnit *unit, Type *parent_type, Decl *method_like);
static inline bool unit_add_method_like(CompilationUnit *unit, Type *parent_type, Decl *method_like);
@@ -701,6 +701,7 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig)
return false;
}
// Check parameters
for (unsigned i = 0; i < param_count; i++)
{
@@ -1417,13 +1418,15 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl)
if (!sema_resolve_type_info(context, parent_type)) return false;
Type *type = parent_type->type->canonical;
Decl **params = decl->func_decl.signature.params;
if (!vec_size(params))
bool is_dynamic = decl->func_decl.attr_dynamic;
bool is_interface = decl->func_decl.attr_interface;
if (is_interface && type != type_any) RETURN_SEMA_ERROR(decl, "Only 'any' methods may use '@interface'.");
if (!sema_is_valid_method_param(context, params[0], type, is_dynamic, is_interface)) return false;
if (is_dynamic)
{
SEMA_ERROR(decl, "A method must start with a parameter of type %s or %s.",
type_quoted_error_string(parent_type->type), type_quoted_error_string(type_get_ptr(parent_type->type)));
return false;
if (is_interface) RETURN_SEMA_ERROR(decl, "An interface method cannot be '@dynamic'.");
}
if (!sema_is_valid_method_param(context, params[0], type)) return false;
return unit_add_method_like(context->unit, type, decl);
}
@@ -1484,6 +1487,8 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
[ATTRIBUTE_BUILTIN] = ATTR_MACRO | ATTR_FUNC,
[ATTRIBUTE_CDECL] = ATTR_FUNC,
[ATTRIBUTE_DEPRECATED] = USER_DEFINED_TYPES | ATTR_FUNC | ATTR_MACRO | ATTR_CONST | ATTR_GLOBAL | ATTR_MEMBER,
[ATTRIBUTE_DYNAMIC] = ATTR_FUNC,
[ATTRIBUTE_INTERFACE] = ATTR_FUNC,
[ATTRIBUTE_EXPORT] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES,
[ATTRIBUTE_NOSTRIP] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES,
[ATTRIBUTE_EXTNAME] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_DEFINE | ATTR_MACRO | ATTR_XXLIZER),
@@ -1579,6 +1584,12 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
case ATTRIBUTE_TEST:
decl->func_decl.attr_test = true;
break;
case ATTRIBUTE_INTERFACE:
decl->func_decl.attr_interface = true;
break;
case ATTRIBUTE_DYNAMIC:
decl->func_decl.attr_dynamic = true;
break;
case ATTRIBUTE_STDCALL:
assert(decl->decl_kind == DECL_FUNC);
if (platform_target.arch == ARCH_TYPE_ARM || platform_target.arch == ARCH_TYPE_ARMB)
@@ -1828,12 +1839,8 @@ static bool sema_analyse_attributes_inner(SemaContext *context, Decl *decl, Attr
// Custom attributes.
// First find it.
Decl *attr_decl = sema_find_symbol(context, attr->name);
if (!attr_decl || attr_decl->decl_kind != DECL_ATTRIBUTE)
{
SEMA_ERROR(attr, "The attribute '%s' could not be found.", attr->name);
return false;
}
Decl *attr_decl = sema_resolve_symbol(context, attr->name, attr->path, attr->span);
if (!attr_decl) return false;
// Detect direct cycles @Foo = @Bar @Bar = @Foo
if (attr_decl == top)
@@ -2377,6 +2384,16 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
}
else
{
if (decl->func_decl.attr_dynamic)
{
SEMA_ERROR(decl, "Only methods may be annotated '@dynamic'.");
return decl_poison(decl);
}
if (decl->func_decl.attr_interface)
{
SEMA_ERROR(decl, "Only methods to 'any' may be annotated '@interface'.");
return decl_poison(decl);
}
if (decl->name == kw_main)
{
if (is_test) SEMA_ERROR(decl, "Main functions may not be annotated @test.");
@@ -2385,6 +2402,15 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
decl_set_external_name(decl);
}
bool is_any_interface = decl->func_decl.attr_interface && decl->func_decl.type_parent && typeinfotype(decl->func_decl.type_parent) == type_any;
// Do we have fn void any.foo(void*) { ... }?
if (decl->func_decl.body && is_any_interface) RETURN_SEMA_ERROR(decl, "Interface methods declarations may not have a body.");
if (!decl->func_decl.body && !decl->is_extern && !decl->unit->is_interface_file && !is_any_interface)
{
SEMA_ERROR(decl, "Expected a function body, if you want to declare an extern function use 'extern' or place it in an .c3i file.");
return false;
}
bool pure = false;
if (!sema_analyse_doc_header(decl->func_decl.docs, decl->func_decl.signature.params, NULL, &pure)) return decl_poison(decl);
decl->func_decl.signature.attrs.is_pure = pure;
@@ -2393,15 +2419,32 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
return true;
}
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type)
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type, bool is_dynamic, bool is_interface)
{
assert(parent_type->canonical == parent_type && "Expected already the canonical version.");
Type *param_type = param->type;
if (!param_type) goto ERROR;
param_type = param_type->canonical;
if (is_interface)
{
if (param_type != type_voidptr) RETURN_SEMA_ERROR(param, "The first parameter of an interface must be of type 'void*'.");
return true;
}
if (is_dynamic)
{
if (param_type->type_kind != TYPE_POINTER || param_type->pointer != parent_type)
{
RETURN_SEMA_ERROR(param, "The fist parameter must be of type %s", type_quoted_error_string(type_get_ptr(parent_type)));
}
return true;
}
// 1. Same type ok!
if (param_type == parent_type) return true;
// 2. A pointer is ok!
if (param_type->type_kind == TYPE_POINTER && param_type->pointer == parent_type) return true;
ERROR:
@@ -2433,7 +2476,7 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl)
SEMA_ERROR(decl, "The first parameter to this method must be of type '%s'.", type_to_error_string(parent_type));
return false;
}
if (!sema_is_valid_method_param(context, first_param, parent_type->canonical)) return false;
if (!sema_is_valid_method_param(context, first_param, parent_type->canonical, false, false)) return false;
if (first_param->var.kind != VARDECL_PARAM_REF && first_param->var.kind != VARDECL_PARAM)
{

View File

@@ -1660,6 +1660,9 @@ static inline bool sema_expr_analyse_func_call(SemaContext *context, Expr *expr,
}
sema_display_deprecated_warning_on_use(context, decl, expr->span);
// Tag dynamic dispatch.
if (struct_var && decl->func_decl.attr_interface) expr->call_expr.is_dynamic_dispatch = true;
return sema_call_analyse_func_invocation(context,
decl->type,
expr,
@@ -5466,11 +5469,15 @@ static const char *sema_addr_check_may_take(Expr *inner)
if (inner->unary_expr.operator == UNARYOP_DEREF) return NULL;
break;
case EXPR_ACCESS:
if (inner->access_expr.ref->decl_kind == DECL_FUNC)
{
Decl *decl = inner->access_expr.ref;
if (decl->decl_kind == DECL_FUNC)
{
if (decl->func_decl.attr_interface) return NULL;
return "Taking the address of a method should be done through the type e.g. '&Foo.method' not through the value.";
}
return sema_addr_check_may_take(inner->access_expr.parent);
}
case EXPR_GROUP:
return sema_addr_check_may_take(inner->inner_expr);
case EXPR_SUBSCRIPT:

View File

@@ -2916,6 +2916,19 @@ bool sema_analyse_contracts(SemaContext *context, AstId doc, AstId **asserts, So
bool sema_analyse_function_body(SemaContext *context, Decl *func)
{
if (!decl_ok(func)) return false;
if (func->func_decl.attr_dynamic)
{
Decl *ambiguous = NULL;
Decl *private = NULL;
Decl *any = sema_resolve_type_method(context->unit, type_any, func->name, &ambiguous, &private);
if (!any)
{
SEMA_ERROR(func, "To define a '@dynamic' method, the prototype method 'any.%s(...)' must exist. Did you spell the method name right?",
func->name);
return false;
}
func->func_decl.any_prototype = declid(any);
}
Signature *signature = &func->func_decl.signature;
FunctionPrototype *prototype = func->type->function.prototype;
context->call_env = (CallEnv) {

View File

@@ -261,6 +261,8 @@ static void assign_panicfn(void)
error_exit("Expected panic function to have the signature fn void(String, String, String, uint).");
}
global_context.panic_var = decl;
decl->no_strip = true;
if (active_target.no_stdlib) return;
const char *panicf = "std::core::builtin::panicf";
@@ -275,6 +277,8 @@ static void assign_panicfn(void)
return;
}
panicf_decl->no_strip = true;
Type *panicf_fn_type = panicf_decl->type->canonical;
if (panicf_decl->decl_kind != DECL_FUNC)
{

View File

@@ -297,10 +297,12 @@ void symtab_init(uint32_t capacity)
attribute_list[ATTRIBUTE_BUILTIN] = KW_DEF("@builtin");
attribute_list[ATTRIBUTE_CDECL] = KW_DEF("@cdecl");
attribute_list[ATTRIBUTE_DEPRECATED] = KW_DEF("@deprecated");
attribute_list[ATTRIBUTE_DYNAMIC] = KW_DEF("@dynamic");
attribute_list[ATTRIBUTE_EXPORT] = KW_DEF("@export");
attribute_list[ATTRIBUTE_EXTERN] = KW_DEF("@extern");
attribute_list[ATTRIBUTE_EXTNAME] = KW_DEF("@extname");
attribute_list[ATTRIBUTE_INLINE] = KW_DEF("@inline");
attribute_list[ATTRIBUTE_INTERFACE] = KW_DEF("@interface");
attribute_list[ATTRIBUTE_LITTLEENDIAN] = KW_DEF("@littleendian");
attribute_list[ATTRIBUTE_LOCAL] = KW_DEF("@local");
attribute_list[ATTRIBUTE_MAYDISCARD] = KW_DEF("@maydiscard");

File diff suppressed because it is too large Load Diff

View File

@@ -246,12 +246,18 @@ typedef enum
BITSIZES_LEN
} BitSizes;
typedef struct X86Features
{
unsigned long long bits[2];
const char *as_string;
} X86Features;
typedef struct
{
const char *target_triple;
int llvm_opt_level;
const char *features;
const char *cpu;
const char *features;
ArchType arch;
OsType os;
VendorType vendor;
@@ -277,8 +283,8 @@ typedef struct
} x86;
struct
{
X86Features features;
unsigned align_simd_default : 16;
X86VectorCapability x86_vector_capability : 4;
bool soft_float : 1;
bool is_win64 : 1;
bool is_mingw64 : 1;
@@ -373,4 +379,110 @@ static inline bool is_pie_pic(RelocModel reloc)
UNREACHABLE
}
typedef enum X64Feature
{
X86_FEAT_CMOV,
X86_FEAT_MMX,
X86_FEAT_POPCNT,
X86_FEAT_SSE,
X86_FEAT_SSE2,
X86_FEAT_SSE3,
X86_FEAT_SSSE3,
X86_FEAT_SSE4_1,
X86_FEAT_SSE4_2,
X86_FEAT_AVX,
X86_FEAT_AVX2,
X86_FEAT_SSE4_A,
X86_FEAT_FMA4,
X86_FEAT_XOP,
X86_FEAT_FMA,
X86_FEAT_AVX512F,
X86_FEAT_BMI,
X86_FEAT_BMI2,
X86_FEAT_AES,
X86_FEAT_PCLMUL,
X86_FEAT_AVX512VL,
X86_FEAT_AVX512BW,
X86_FEAT_AVX512DQ,
X86_FEAT_AVX512CD,
X86_FEAT_AVX512ER,
X86_FEAT_AVX512PF,
X86_FEAT_AVX512VBMI,
X86_FEAT_AVX512IFMA,
X86_FEAT_AVX5124VNNIW,
X86_FEAT_AVX5124FMAPS,
X86_FEAT_AVX512VPOPCNTDQ,
X86_FEAT_AVX512VBMI2,
X86_FEAT_GFNI,
X86_FEAT_VPCLMULQDQ,
X86_FEAT_AVX512VNNI,
X86_FEAT_AVX512BITALG,
X86_FEAT_AVX512BF16,
X86_FEAT_AVX512VP2INTERSECT,
X86_FEAT_ADX,
X86_FEAT_AMX_BF16,
X86_FEAT_AMX_INT8,
X86_FEAT_AMX_TILE,
X86_FEAT_CLDEMOTE,
X86_FEAT_CLFLUSHOPT,
X86_FEAT_CLWB,
X86_FEAT_CLZERO,
X86_FEAT_CMPXCHG16B,
X86_FEAT_CMPXCHG8B,
X86_FEAT_CRC32,
X86_FEAT_ENQCMD,
X86_FEAT_F16C,
X86_FEAT_FSGSBASE,
X86_FEAT_FXSR,
X86_FEAT_INVPCID,
X86_FEAT_KL,
X86_FEAT_WIDEKL,
X86_FEAT_LWP,
X86_FEAT_LZCNT,
X86_FEAT_MOVBE,
X86_FEAT_MOVDIR64B,
X86_FEAT_MOVDIRI,
X86_FEAT_MWAITX,
X86_FEAT_PCONFIG,
X86_FEAT_PKU,
X86_FEAT_PREFETCHI,
X86_FEAT_PREFETCHWT1,
X86_FEAT_PRFCHW,
X86_FEAT_PTWRITE,
X86_FEAT_RDPID,
X86_FEAT_RDPRU,
X86_FEAT_RDRND,
X86_FEAT_RDSEED,
X86_FEAT_RTM,
X86_FEAT_SAHF,
X86_FEAT_SERIALIZE,
X86_FEAT_SGX,
X86_FEAT_SHA,
X86_FEAT_SHSTK,
X86_FEAT_TBM,
X86_FEAT_TSXLDTRK,
X86_FEAT_UINTR,
X86_FEAT_VAES,
X86_FEAT_VZEROUPPER,
X86_FEAT_WAITPKG,
X86_FEAT_WBNOINVD,
X86_FEAT_X87,
X86_FEAT_XSAVE,
X86_FEAT_XSAVEC,
X86_FEAT_XSAVEOPT,
X86_FEAT_XSAVES,
X86_FEAT_HRESET,
X86_FEAT_RAOINT,
X86_FEAT_AVX512FP16,
X86_FEAT_AMX_FP16,
X86_FEAT_CMPCCXADD,
X86_FEAT_AVXNECONVERT,
X86_FEAT_AVXVNNI,
X86_FEAT_AVXIFMA,
X86_FEAT_AVXVNNIINT8,
X86_FEATURE_LAST = X86_FEAT_AVXVNNIINT8,
} X86Feature;
extern PlatformTarget platform_target;

View File

@@ -57,8 +57,6 @@ typedef struct Task_
void *arg;
} Task;
typedef void *TaskQueueRef;
uint16_t *win_utf8to16(const char *name);
char *win_utf16to8(const uint16_t *name);
// Use as if it was mkdir(..., 0755) == 0
@@ -98,8 +96,7 @@ char *calloc_string(size_t len);
void free_arena(void);
void print_arena_status(void);
void run_arena_allocator_tests(void);
TaskQueueRef taskqueue_create(int threads, Task **task_list);
void taskqueue_wait_for_completion(TaskQueueRef queue);
void taskqueue_run(int threads, Task **task_list);
int cpus(void);
const char *date_get(void);
const char *time_get(void);

View File

@@ -9,8 +9,6 @@
typedef struct TaskQueue_
{
pthread_t *threads;
int thread_count;
pthread_mutex_t lock;
Task **queue;
} TaskQueue;
@@ -35,48 +33,80 @@ SHUTDOWN:
return NULL;
}
TaskQueueRef taskqueue_create(int threads, Task **task_list)
void taskqueue_run(int threads, Task **task_list)
{
assert(threads > 0);
TaskQueue *queue = CALLOCS(TaskQueue);
queue->threads = MALLOC(sizeof(pthread_t) * (unsigned)threads);
queue->thread_count = threads;
queue->queue = task_list;
if (pthread_mutex_init(&queue->lock, NULL)) error_exit("Failed to set up mutex");
pthread_t *pthreads = malloc(sizeof(pthread_t) * (unsigned)threads);
TaskQueue queue = { .queue = task_list };
if (pthread_mutex_init(&queue.lock, NULL)) error_exit("Failed to set up mutex");
for (int i = 0; i < threads; i++)
{
if (pthread_create(queue->threads + i, NULL, taskqueue_thread, queue)) error_exit("Fail to set up thread pool");
if (pthread_create(&pthreads[i], NULL, taskqueue_thread, &queue)) error_exit("Fail to set up thread pool");
}
return queue;
}
void taskqueue_wait_for_completion(TaskQueueRef queue_ref)
{
assert(queue_ref);
TaskQueue *queue = queue_ref;
for (int i = 0; i < queue->thread_count; i++)
for (int i = 0; i < threads; i++)
{
if (pthread_join(queue->threads[i], NULL) != 0) error_exit("Failed to join thread.");
if (pthread_join(pthreads[i], NULL) != 0) error_exit("Failed to join thread.");
}
pthread_mutex_destroy(&queue->lock);
free(pthreads);
pthread_mutex_destroy(&queue.lock);
}
#elif PLATFORM_WINDOWS
#include <Windows.h>
#include <process.h>
typedef struct TaskQueue_
{
CRITICAL_SECTION lock;
Task **queue;
} TaskQueue;
static DWORD WINAPI taskqueue_thread(LPVOID lpParam)
{
TaskQueue *task_queue = (TaskQueue *)lpParam;
bool is_active = false;
while (1)
{
EnterCriticalSection(&task_queue->lock);
unsigned task_count = vec_size(task_queue->queue);
if (!task_count) goto SHUTDOWN;
Task *task = (Task*)task_queue->queue[task_count - 1];
vec_pop(task_queue->queue);
LeaveCriticalSection(&task_queue->lock);
task->task(task->arg);
}
SHUTDOWN:
LeaveCriticalSection(&task_queue->lock);
return 0;
}
void taskqueue_run(int threads, Task **task_list)
{
assert(threads > 0);
HANDLE *handles = malloc(sizeof(HANDLE) * (unsigned)threads);
TaskQueue queue = { .queue = task_list };
InitializeCriticalSection(&queue.lock);
for (int i = 0; i < threads; i++)
{
handles[i] = (HANDLE)_beginthreadex(NULL, 0, taskqueue_thread, &queue, 0, NULL);
if (handles[i] == NULL) error_exit("Fail to set up thread pool");
}
WaitForMultipleObjects(threads, handles, TRUE, INFINITE);
for (int i = 0; i < threads; i++)
{
CloseHandle(handles[i]);
}
free((void*)handles);
DeleteCriticalSection(&queue.lock);
}
#else
void taskqueue_add(TaskQueueRef queue_ref, Task *task)
void taskqueue_run(int threads, Task **task_list)
{
}
TaskQueueRef taskqueue_create(int threads, Task **tasks)
{
return tasks;
}
void taskqueue_wait_for_completion(TaskQueueRef queue)
{
Task **tasks = queue;
FOREACH_BEGIN(Task *task, tasks)
FOREACH_BEGIN(Task *task, task_list)
task->task(task->arg);
FOREACH_END();
}

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.513"
#define COMPILER_VERSION "0.4.522"

View File

@@ -1,7 +1,7 @@
// #target: macos-aarch64
module test;
typedef Int8x16 = ichar[<16>];
typedef Float32x3 = float[<3>];
def Int8x16 = ichar[<16>];
def Float32x3 = float[<3>];
struct HFAv3
{

View File

@@ -1,5 +1,5 @@
// #target: macos-x64
// #opt: --x86vec=avx512
// #opt: --x86cpu=avx512
module abi;
struct Half1 {

View File

@@ -1,8 +1,8 @@
// #target: macos-x64
// #opt: --x86vec=avx
// #opt: --x86cpu=avx1
module test;
typedef Mm256 = float[<8>];
def Mm256 = float[<8>];
struct St256 {
Mm256 m;
}
@@ -19,7 +19,7 @@ fn void f39() { f38(x38); f37(x37); }
// CHECK: declare void @func40(%struct.t128* byval(%struct.t128) align 16)
typedef Mm128 = float[<4>];
def Mm128 = float[<4>];
struct Two128 {
Mm128 m;
Mm128 n;
@@ -44,7 +44,7 @@ fn void func43(Sa s) {
}
typedef Vec46 = float[<2>];
def 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); }
@@ -69,7 +69,7 @@ fn void test54() {
test54_helper(x54, x54, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, Complex { 0, 1.0 });
}
typedef Mm512 = float[<16>];
def Mm512 = float[<16>];
struct St512 {
Mm512 m;
}

View File

@@ -1,9 +1,9 @@
// #target: macos-x64
// #opt: --x86vec=avx512
// #opt: --x86cpu=avx512
module test;
typedef Mm256 = float[<8>];
typedef Mm512 = float[<16>];
def Mm256 = float[<8>];
def Mm512 = float[<16>];
struct St512 {
Mm512 m;
}

View File

@@ -1,8 +1,8 @@
// #target: macos-x64
// #opt: --x86vec=sse
// #opt: --x86cpu=sse4
module test;
typedef Mm256 = float[<8>];
def Mm256 = float[<8>];
struct St256 {
Mm256 m;
}
@@ -19,7 +19,7 @@ fn void f39() { f38(x38); f37(x37); }
// CHECK: declare void @func40(%struct.t128* byval(%struct.t128) align 16)
typedef Mm128 = float[<4>];
def Mm128 = float[<4>];
struct Two128 {
Mm128 m;
Mm128 n;

View File

@@ -86,7 +86,7 @@ fn V4f32wrapper f27(V4f32wrapper x) {
// PR22563 - We should unwrap simple structs and arrays to pass
// and return them in the appropriate vector registers if possible.
typedef V8f32 = float[<8>];
def V8f32 = float[<8>];
struct V8f32wrapper {
V8f32 v;
}
@@ -133,15 +133,15 @@ fn float f31(F31foo x) {
return x.c;
}
typedef V1i64 = ulong[<1>];
def V1i64 = ulong[<1>];
fn V1i64 f34(V1i64 arg) { return arg; }
typedef V1i64_2 = uint[<2>];
def V1i64_2 = uint[<2>];
fn V1i64_2 f35(V1i64_2 arg) { return arg+arg; }
typedef V2i32 = float[<2>];
def V2i32 = float[<2>];
fn V2i32 f36(V2i32 arg) { return arg; }

View File

@@ -5,7 +5,7 @@ struct Large {
long a, b, c, d;
}
typedef V32i8 = char[<32>];
def 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) {

View File

@@ -20,10 +20,10 @@ fn Foo getFoo(Foo f)
/* #expect: test.ll
%.introspect = type { i8, i64, i64, i64, [0 x i64] }
%.introspect = type { i8, ptr, i64, i64, i64, [0 x i64] }
%Foo = type { i8, i8, i8 }
@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 3, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 3, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8
; Function Attrs: nounwind
define i32 @test.testing() #0 {

View File

@@ -1,5 +1,5 @@
// #target: linux-x64
// #opt: --x86vec=avx512
// #opt: --x86cpu=avx512
module foo;
struct StringRef

View File

@@ -15,7 +15,7 @@ Connection[3] link @private
/* #expect: test.ll
@"$ct.test.Connection" = linkonce constant %.introspect { i8 10, i64 24, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Connection" = linkonce global %.introspect { i8 10, ptr null, i64 24, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [6 x i8] c"link1\00", align 1
@.str.1 = private unnamed_addr constant [6 x i8] c"link2\00", align 1
@.str.2 = private unnamed_addr constant [6 x i8] c"link3\00", align 1

View File

@@ -0,0 +1,7 @@
module abc;
def @Foo = { @inline };
module bar;
fn void test() abc::@Foo {} // #error: Did you mean the attribute

View File

@@ -1,7 +1,7 @@
// #target: macos-x64
module test;
const int FOO @private = 4;
define @Align(x) = { @align(x * FOO) };
def @Align(x) = { @align(x * FOO) };
module test2;
import test;

View File

@@ -2,12 +2,12 @@
module test;
define @Foo = { @noreturn @weak };
def @Foo = { @noreturn @weak };
define @Align(y) = { @align(y) };
define @Align16(x) @private = { @Align(8 * x) @align(1024) };
define @Test = { @noinline };
define @TestZero = { };
def @Align(y) = { @align(y) };
def @Align16(x) @private = { @Align(8 * x) @align(1024) };
def @Test = { @noinline };
def @TestZero = { };
struct Foo
{
int z;
@@ -32,7 +32,7 @@ fn void main() @TestZero
/* #expect: test.ll
%Foo = type { i32, [1020 x i8], i32, [1020 x i8] }
@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 2048, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 2048, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@test.f = local_unnamed_addr global %Foo zeroinitializer, align 1024
define weak void @test.testme2() #0 {

View File

@@ -5,8 +5,8 @@ bitstruct Test : int
float a : 1..3; // #error: 'float' is not supported in a bitstruct, only enums, integer and boolean values may be used.
}
typedef Baz = distinct float;
typedef Foo = distinct bool;
def Baz = distinct float;
def Foo = distinct bool;
enum Boo
{
BAR

View File

@@ -22,8 +22,8 @@ fn void test1()
$endswitch
}
typedef Foo = int;
typedef Bar = double;
def Foo = int;
def Bar = double;
fn void test2()
{
$switch (int.typeid)

View File

@@ -24,26 +24,27 @@ fn void main()
/* #expect: test.ll
%.introspect = type { i8, i64, i64, i64, [0 x i64] }
%.introspect = type { i8, ptr, i64, i64, i64, [0 x i64] }
%Foo = type { i32, i32 }
%"int[]" = type { ptr, i64 }
%any = type { ptr, i64 }
@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [9 x i8] c"%s %s %s\00", align 1
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.a2$int" = linkonce constant %.introspect { i8 15, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$int" = linkonce constant %.introspect { i8 16, i64 16, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.v2$int" = linkonce constant %.introspect { i8 17, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.a2$int" = linkonce global %.introspect { i8 15, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$int" = linkonce global %.introspect { i8 16, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.v2$int" = linkonce global %.introspect { i8 17, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@.__const = private unnamed_addr constant [1 x %Foo] [%Foo { i32 1, i32 2 }], align 4
@.__const.1 = private unnamed_addr constant %Foo { i32 1, i32 2 }, align 4
@.__const.2 = private unnamed_addr constant [1 x [2 x i32]] [[2 x i32] [i32 1, i32 2]], align 4
@.__const.3 = private unnamed_addr constant [1 x [2 x double]] [[2 x double] [double 1.000000e+00, double 2.000000e+00]], align 16
@.str.4 = private unnamed_addr constant [15 x i8] c"%s %s {%s, %s}\00", align 1
@"$ct.a1$a2$int" = linkonce constant %.introspect { i8 15, i64 8, i64 ptrtoint (ptr @"$ct.a2$int" to i64), i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.double" = linkonce constant %.introspect { i8 4, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.a2$double" = linkonce constant %.introspect { i8 15, i64 16, i64 ptrtoint (ptr @"$ct.double" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.a1$a2$double" = linkonce constant %.introspect { i8 15, i64 16, i64 ptrtoint (ptr @"$ct.a2$double" to i64), i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.a1$a2$int" = linkonce global %.introspect { i8 15, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.a2$int" to i64), i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.double" = linkonce global %.introspect { i8 4, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.a2$double" = linkonce global %.introspect { i8 15, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.double" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.a1$a2$double" = linkonce global %.introspect { i8 15, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.a2$double" to i64), i64 1, [0 x i64] zeroinitializer }, align 8
; Function Attrs: nounwind
define void @test.test(i64 %0, ptr %1, i64 %2, double %3) #0 {

View File

@@ -22,7 +22,7 @@ fn void main()
/* #expect: qnametest.ll
@"$ct.qnametest.Blob" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.qnametest.Blob" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@qnametest.x = local_unnamed_addr global i32 0, align 4
@.str = private unnamed_addr constant [12 x i8] c"printf: %s\0A\00", align 1
@.str.1 = private unnamed_addr constant [7 x i8] c"printf\00", align 1

View File

@@ -1,13 +1,13 @@
module foo;
// define <name> = <name>
// def <name> = <name>
def standard_foo = __stdin;
def someFunctionIntBool = someFunction<int, bool>;
def FooInt = Foo<int>;
def A_CONST_INT = A_CONST<int>;
def standard_foo<int> = ofke; // #error: Expected '='
def fn foo = fef; // #error: A variable, constant or attribute name was expected here.
def fn foo = fef; // #error: A type, variable, constant or attribute name was expected here
def feokfe = fn void(int); // #error: Expected a function or variable name here
def AOFKE = ofek; // #error: Expected a constant name here
def okfoe = OFKEOK; // #error: Expected a function or variable name here

View File

@@ -1,9 +1,9 @@
typedef int = int; // #error: 'int' is the name of a built-in type and can't be used as an alias.
def int = int; // #error: 'int' is a reserved keyword, try another name
def main = foo; // #error: 'main' is reserved and cannot be used as an alias.
typedef hello = int; // #error: uppercase letter
typedef hello = Foo; // #error: uppercase letter
def hello = int; // #error: uppercase letter
def hello = Foo; // #error: uppercase letter
typedef HELLO = int; // #error: uppercase letter
typedef HELLO = Foo; // #error: uppercase letter
def HELLO = int; // #error: uppercase letter
def HELLO = Foo; // #error: uppercase letter

View File

@@ -1,3 +1,3 @@
typedef Abc = int[*]; // #error: Inferred array types can only
typedef Bcd = anyfault; // #error: 'anyfault' may not be aliased.
typedef Efd = any; // #error: 'any' may not be aliased.
def Abc = int[*]; // #error: Inferred array types can only
def Bcd = anyfault; // #error: 'anyfault' may not be aliased.
def Efd = any; // #error: 'any' may not be aliased.

View File

@@ -3,8 +3,8 @@ fault Error
ABC
}
typedef Foo1 = distinct Error; // #error: You cannot create a distinct type
def Foo1 = distinct Error; // #error: You cannot create a distinct type
typedef Foo3 = distinct void; // #error: create a distinct type from 'void'
def Foo3 = distinct void; // #error: create a distinct type from 'void'
typedef Foo4 = distinct typeid; // #error: create a distinct type from 'typeid'
def Foo4 = distinct typeid; // #error: create a distinct type from 'typeid'

View File

@@ -1,4 +1,4 @@
typedef Foo = distinct double[];
def Foo = distinct double[];
fn void main()
{

View File

@@ -5,7 +5,7 @@ struct Struct
double y;
}
typedef Foo = distinct Struct;
def Foo = distinct Struct;
struct Struct2
{

View File

@@ -1,6 +1,6 @@
module test;
typedef Foo = distinct int;
def Foo = distinct int;
struct Struct
{
@@ -8,8 +8,8 @@ struct Struct
int y;
}
typedef Struct2 = distinct Struct;
typedef StructArr = distinct Struct2[3];
def Struct2 = distinct Struct;
def StructArr = distinct Struct2[3];
fn void test(int x)
{

View File

@@ -6,7 +6,7 @@ union Union
double y;
}
typedef Foo = distinct Union;
def Foo = distinct Union;
union Union2
{
@@ -19,9 +19,9 @@ union Union2
}
Foo f = { .x = 1 };
typedef Union3 = distinct Union2;
def Union3 = distinct Union2;
typedef UnionArr = distinct Union3[3];
def UnionArr = distinct Union3[3];
fn void test(int x)
{

View File

@@ -1,6 +1,6 @@
module test;
typedef Int2 = distinct int;
def Int2 = distinct int;
fn void test()
{

View File

@@ -1,6 +1,6 @@
module test;
typedef Foo = distinct int;
def Foo = distinct int;
fn int test1()
{

View File

@@ -6,7 +6,7 @@ struct Struct
double y;
}
typedef Foo = distinct Struct;
def Foo = distinct Struct;
struct Struct2
{

View File

@@ -18,8 +18,8 @@ fn void main()
/* #expect: test.ll
@"$ct.uint" = linkonce constant %.introspect { i8 3, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce constant { i8, i64, i64, i64, [2 x %"char[]"] } { i8 8, i64 4, i64 ptrtoint (ptr @"$ct.uint" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 1 }, %"char[]" { ptr @.enum.1, i64 1 }] }, align 8
@"$ct.uint" = linkonce global %.introspect { i8 3, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce global { i8, ptr, i64, i64, i64, [2 x %"char[]"] } { i8 8, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.uint" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 1 }, %"char[]" { ptr @.enum.1, i64 1 }] }, 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

View File

@@ -24,11 +24,11 @@ enum Foo : int(String val)
/* #expect: abc.ll
@"$ct.abc.Abc" = linkonce constant %.introspect { i8 10, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Abc" = linkonce global %.introspect { i8 10, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@.enum.0 = internal constant [4 x i8] c"ABC\00", align 1
@.enum.1 = internal constant [4 x i8] c"DEF\00", align 1
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Foo" = linkonce constant { i8, i64, i64, i64, [2 x %"char[]"] } { i8 8, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 3 }, %"char[]" { ptr @.enum.1, i64 3 }] }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Foo" = linkonce global { i8, ptr, i64, i64, i64, [2 x %"char[]"] } { i8 8, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 3 }, %"char[]" { ptr @.enum.1, i64 3 }] }, align 8
@.str = private unnamed_addr constant [6 x i8] c"hello\00", align 1
@.str.1 = private unnamed_addr constant [6 x i8] c"world\00", align 1
@"abc.Foo$val" = linkonce constant [2 x %"char[]"] [%"char[]" { ptr @.str, i64 5 }, %"char[]" { ptr @.str.1, i64 5 }], align 8
@@ -37,18 +37,19 @@ enum Foo : int(String val)
// #expect: test.ll
@"$ct.abc.Abc" = linkonce constant %.introspect { i8 10, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Abc" = linkonce global %.introspect { i8 10, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@abc.dabc = external global i32, align 4
@.enum.0 = internal constant [4 x i8] c"ABC\00", align 1
@.enum.1 = internal constant [4 x i8] c"DEF\00", align 1
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Foo" = linkonce constant { i8, i64, i64, i64, [2 x %"char[]"] } { i8 8, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 3 }, %"char[]" { ptr @.enum.1, i64 3 }] }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Foo" = linkonce global { i8, ptr, i64, i64, i64, [2 x %"char[]"] } { i8 8, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 3 }, %"char[]" { ptr @.enum.1, i64 3 }] }, align 8
@.str = private unnamed_addr constant [6 x i8] c"hello\00", align 1
@.str.1 = private unnamed_addr constant [6 x i8] c"world\00", align 1
@"abc.Foo$val" = linkonce constant [2 x %"char[]"] [%"char[]" { ptr @.str, i64 5 }, %"char[]" { ptr @.str.1, i64 5 }], align 8
@.str.2 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
@"$ct.char" = linkonce constant %.introspect { i8 3, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce constant %.introspect { i8 16, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.char" = linkonce global %.introspect { i8 3, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce global %.introspect { i8 16, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
define void @test.main(ptr %0, i64 %1) #0 {
entry:

View File

@@ -22,18 +22,18 @@ fn void main()
@.fault = internal constant [4 x i8] c"BAR\00", align 1
@"foo.Foo$BAZ" = linkonce constant %.fault { i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), %"char[]" { ptr @.fault.1, i64 3 }, i64 2 }, align 8
@.fault.1 = internal constant [4 x i8] c"BAZ\00", align 1
@"$ct.foo.Foo" = linkonce constant %.introspect { i8 9, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.Foo" = linkonce global %.introspect { i8 9, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [4 x i8] c"BAR\00", align 1
@.str.2 = private unnamed_addr constant [4 x i8] c"BAZ\00", align 1
@.str.3 = private unnamed_addr constant [14 x i8] c"Foo.names: %s\00", align 1
@"$ct.char" = linkonce constant %.introspect { i8 3, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce constant %.introspect { i8 16, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.String" = linkonce constant %.introspect { i8 18, i64 16, i64 ptrtoint (ptr @"$ct.sa$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$String" = linkonce constant %.introspect { i8 16, i64 16, i64 ptrtoint (ptr @"$ct.String" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.char" = linkonce global %.introspect { i8 3, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce global %.introspect { i8 16, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.String" = linkonce global %.introspect { i8 18, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.sa$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$String" = linkonce global %.introspect { i8 16, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.String" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@.str.4 = private unnamed_addr constant [15 x i8] c"Foo.values: %s\00", align 1
@"$ct.a2$foo.Foo" = linkonce constant %.introspect { i8 15, i64 16, i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.a2$foo.Foo" = linkonce global %.introspect { i8 15, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@.str.5 = private unnamed_addr constant [17 x i8] c"Foo.elements: %s\00", align 1
@"$ct.long" = linkonce constant %.introspect { i8 2, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.long" = linkonce global %.introspect { i8 2, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
entry:
%x = alloca %"char[][]", align 8

View File

@@ -27,9 +27,10 @@ fn void main()
%Foo = type { i32, i32 }
@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"test.MyErr$FOO" = linkonce constant %.fault { i64 ptrtoint (ptr @"$ct.test.MyErr" to i64), %"char[]" { ptr @.fault, i64 3 }, i64 1 }, align 8
@"$ct.test.MyErr" = linkonce constant %.introspect { i8 9, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@.fault = internal constant [4 x i8] c"FOO\00", align 1
@"$ct.test.MyErr" = linkonce global %.introspect { i8 9, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, 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

View File

@@ -60,8 +60,8 @@ fn void test6()
int[]* e = &arr[1..2]; // #error: To take the address of a temporary value, use '&&' instead of '&'
}
typedef Baz = Foo;
typedef Bar = distinct int;
def Baz = Foo;
def Bar = distinct int;
fault Err { FOO }
union Un { int x; }
enum MyEnum { BAR }

View File

@@ -1,4 +1,4 @@
typedef Number = int;
def Number = int;
fn void test1()
{

View File

@@ -2,7 +2,7 @@ enum Foo
{
ABC
}
typedef Abc = distinct int;
def Abc = distinct int;
fn void main()
{
Abc d = Foo.ABC; // #error: Implicitly casting

View File

@@ -13,7 +13,7 @@ enum EnumB : char
C, D
}
typedef Func = fn void(Enum);
def Func = fn void(Enum);
fn void test1(Enum e)
{

View File

@@ -1,3 +1,4 @@
// #target: macos-x64
module cast_expr;
fn int main(int argc, char** argv)

View File

@@ -8,9 +8,9 @@ enum Enum : uptr
A, B
}
typedef Func = fn void(int);
typedef FuncOther = fn bool(char*);
typedef FuncSame = fn void(int);
def Func = fn void(int);
def FuncOther = fn bool(char*);
def FuncSame = fn void(int);
fn void test1(Func arg)

View File

@@ -1,4 +1,4 @@
typedef Number = int;
def Number = int;
fn void test1()
{

View File

@@ -1,6 +1,6 @@
typedef Number8 = char;
typedef Number32 = int;
typedef DNumber32 = distinct int;
def Number8 = char;
def Number32 = int;
def DNumber32 = distinct int;
fn void test1()
{
int a = (ichar)(10);

View File

@@ -1,5 +1,5 @@
typedef Foo = distinct double;
typedef Bar = distinct void*;
def Foo = distinct double;
def Bar = distinct void*;
fn int main()
{
float f = 1;

View File

@@ -1,6 +1,6 @@
module test;
typedef Foo = distinct int;
def Foo = distinct int;
fn void test1()
{

View File

@@ -42,10 +42,10 @@ fn void testSimple()
%.anon = type { i32, i32 }
%.anon.0 = type { double }
@"$ct.pointer_access.c" = linkonce constant %.introspect { i8 10, i64 40, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.$anon" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.$anon.4" = linkonce constant %.introspect { i8 11, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.ExtraSimple" = linkonce constant %.introspect { i8 10, i64 72, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.c" = linkonce global %.introspect { i8 10, ptr null, i64 40, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.$anon" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.$anon.4" = linkonce global %.introspect { i8 11, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.ExtraSimple" = linkonce global %.introspect { i8 10, ptr null, i64 72, i64 0, i64 6, [0 x i64] zeroinitializer }, 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

@@ -1,4 +1,4 @@
typedef Callback = fn int(char c);
def Callback = fn int(char c);
struct Person { int i; }
struct Company { int j; }
enum Status : int

View File

@@ -32,14 +32,14 @@ fn void main()
/* #expect: test.ll
@.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@.str.1 = private unnamed_addr constant [3 x i8] c"%d\00", align 1
@.str.2 = private unnamed_addr constant [3 x i8] c"%d\00", align 1
@.str.3 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
@.str.4 = private unnamed_addr constant [13 x i8] c"fn int(int)*\00", align 1
@"$ct.char" = linkonce constant %.introspect { i8 3, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce constant %.introspect { i8 16, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.String" = linkonce constant %.introspect { i8 18, i64 16, i64 ptrtoint (ptr @"$ct.sa$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.char" = linkonce global %.introspect { i8 3, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce global %.introspect { i8 16, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.String" = linkonce global %.introspect { i8 18, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.sa$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@.str.5 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
@.str.6 = private unnamed_addr constant [13 x i8] c"fn int(int)*\00", align 1
@.str.7 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
@@ -48,8 +48,9 @@ fn void main()
@.str.10 = private unnamed_addr constant [7 x i8] c"test2*\00", align 1
@.str.11 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
@.str.12 = private unnamed_addr constant [14 x i8] c"fn int!(int)*\00", align 1
@"$ct.fn$int$int$" = linkonce constant %.introspect { i8 13, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.p$fn$int$int$" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (ptr @"$ct.fn$int$int$" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.fn$int$int$" = linkonce global %.introspect { i8 13, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.p$fn$int$int$" = linkonce global %.introspect { i8 19, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.fn$int$int$" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
define void @test.main() #0 {
entry:

View File

@@ -65,8 +65,8 @@ fn int Foo2.mutate(Foo2 *foo)
return ++foo.x;
}
define oopsInt = test2::argh<int>;
define oopsDouble = test2::argh<int>;
def oopsInt = test2::argh<int>;
def oopsDouble = test2::argh<int>;
typedef Argh = fn int(double, Bobo);
typedef Argh2 = fn int(double, Bobo);
@@ -95,12 +95,12 @@ struct Foo
int b;
}
define getValueInt = test2::getValue<int>;
define getValueDouble = test2::getValue<double>;
def getValueInt = test2::getValue<int>;
def getValueDouble = test2::getValue<double>;
typedef IntBlob = test2::Blob<int>;
typedef DoubleBlob = Blob<double>;
define getMultInt = test2::getMult<int>;
define getMultDouble = test2::getMult<double>;
def getMultInt = test2::getMult<int>;
def getMultDouble = test2::getMult<double>;
typedef IntArray = List<int>;
typedef IntList = LinkedList<int>;
@@ -173,7 +173,7 @@ module hello_world;
import foo;
extern fn int printf(char *, ...);
define doubleMult = foo::check<double>;
def doubleMult = foo::check<double>;
fn void hello()
{
@@ -219,8 +219,8 @@ macro Hello wut()
}
typedef Bye = Hello;
define wat = wut;
define byebye = hello;
def wat = wut;
def byebye = hello;
fn int hello()
{
@@ -243,13 +243,13 @@ fn Type getValue(Blob blob)
%List = type { i64, i64, ptr, ptr }
%Foo = type { i32, i32 }
@"$ct.test.Bobo" = linkonce constant %.introspect { i8 10, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Blob" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foor" = linkonce constant %.introspect { i8 11, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo2" = linkonce constant %.introspect { i8 10, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Bobo" = linkonce global %.introspect { i8 10, ptr null, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Blob" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foor" = linkonce global %.introspect { i8 11, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo2" = linkonce global %.introspect { i8 10, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.test.MyEnum" = linkonce constant { i8, i64, i64, i64, [3 x %"char[]"] } { i8 8, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [3 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 4 }, %"char[]" { ptr @.enum.1, i64 5 }, %"char[]" { ptr @.enum.2, i64 3 }] }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.test.MyEnum" = linkonce global { i8, ptr, i64, i64, i64, [3 x %"char[]"] } { i8 8, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [3 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 4 }, %"char[]" { ptr @.enum.1, i64 5 }, %"char[]" { ptr @.enum.2, i64 3 }] }, align 8
@"test_static$x" = internal unnamed_addr global i32 1, align 4
define void @test.Foo2.printme(ptr %0) #0 {

View File

@@ -67,8 +67,8 @@ fn int Foo2.mutate(Foo2 *foo)
define oopsInt = test2::argh<int>;
define oopsDouble = test2::argh<int>;
def oopsInt = test2::argh<int>;
def oopsDouble = test2::argh<int>;
typedef Argh = fn int(double, Bobo);
typedef Argh2 = fn int(double, Bobo);
@@ -97,12 +97,12 @@ struct Foo
int b;
}
define getValueInt = test2::getValue<int>;
define getValueDouble = test2::getValue<double>;
def getValueInt = test2::getValue<int>;
def getValueDouble = test2::getValue<double>;
typedef IntBlob = test2::Blob<int>;
typedef DoubleBlob = Blob<double>;
define getMultInt = test2::getMult<int>;
define getMultDouble = test2::getMult<double>;
def getMultInt = test2::getMult<int>;
def getMultDouble = test2::getMult<double>;
typedef IntArray = List<int>;
typedef IntList = LinkedList<int>;
@@ -175,7 +175,7 @@ module hello_world;
import foo;
extern fn int printf(char *, ...);
define doubleMult = foo::check<double>;
def doubleMult = foo::check<double>;
fn void hello()
{
@@ -221,8 +221,8 @@ macro Hello wut()
}
typedef Bye = Hello;
define wat = wut;
define byebye = hello;
def wat = wut;
def byebye = hello;
fn int hello()
{
@@ -259,13 +259,13 @@ $"$ct.int" = comdat any
$"$ct.test.MyEnum" = comdat any
@"$ct.test.Bobo" = linkonce constant %.introspect { i8 10, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Blob" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foor" = linkonce constant %.introspect { i8 11, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foo2" = linkonce constant %.introspect { i8 10, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.MyEnum" = linkonce constant { i8, i64, i64, i64, [3 x %"char[]"] } { i8 8, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [3 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 4 }, %"char[]" { ptr @.enum.1, i64 5 }, %"char[]" { ptr @.enum.2, i64 3 }] }, comdat, align 8
@"$ct.test.Bobo" = linkonce global %.introspect { i8 10, ptr null, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Blob" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foor" = linkonce global %.introspect { i8 11, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foo2" = linkonce global %.introspect { i8 10, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.MyEnum" = linkonce global { i8, ptr, i64, i64, i64, [3 x %"char[]"] } { i8 8, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [3 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 4 }, %"char[]" { ptr @.enum.1, i64 5 }, %"char[]" { ptr @.enum.2, i64 3 }] }, 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

View File

@@ -1,5 +1,5 @@
import std::io;
typedef Tester = fn int(int x, int y, int z);
def Tester = fn int(int x, int y, int z);
fn int test1(
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 20

View File

@@ -22,7 +22,8 @@ fn int main()
/* #expect: test.ll
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
define void @test.retest(ptr %0, i64 %1) #0 {
entry:

View File

@@ -9,4 +9,4 @@ fn void abc()
module tester;
import foo;
define abc_my = foo::abc<int>;
def abc_my = foo::abc<int>;

View File

@@ -2,7 +2,7 @@
module test;
import bar;
typedef BazTest = Baz<Test>;
def BazTest = Baz<Test>;
struct Test // #error: Recursive definition of 'Test'
{

View File

@@ -13,8 +13,8 @@ fn Type addMult(Type x, Type a, Type b)
module test;
import gen;
define intMult = gen::mult<int>;
define doubleAddMult = gen::addMult<double>;
def intMult = gen::mult<int>;
def doubleAddMult = gen::addMult<double>;
fn int getIt(int i)
{

View File

@@ -8,7 +8,7 @@ fn Type x(Type t)
module test;
import hello;
define xint = hello::x<int, -123>;
def xint = hello::x<int, -123>;
import std::io;

View File

@@ -37,8 +37,8 @@ fn int test()
%"int[]" = type { ptr, i64 }
%"Bar[]" = type { ptr, i64 }
@"$ct.general_tests.Baz" = linkonce constant %.introspect { i8 11, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.general_tests.Bar" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.general_tests.Baz" = linkonce global %.introspect { i8 11, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.general_tests.Bar" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, 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

@@ -35,8 +35,8 @@ fn int main()
%Bar = type { i32, i32 }
%"Bar[]" = type { ptr, i64 }
@"$ct.statics.Baz" = linkonce constant %.introspect { i8 11, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.statics.Bar" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.statics.Baz" = linkonce global %.introspect { i8 11, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.statics.Bar" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@.taddr = private global [1 x %Bar] [%Bar { i32 1, i32 2 }], align 8
@"test$c" = internal unnamed_addr global %"Bar[]" { ptr @.taddr, i64 1 }, align 8
@.str = private unnamed_addr constant [7 x i8] c"%d %d\0A\00", align 1

View File

@@ -52,8 +52,8 @@ fn int main()
%File = type { ptr }
%Baz = type { double }
@"$ct.subarrays.Baz" = linkonce constant %.introspect { i8 11, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.subarrays.Bar" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.subarrays.Baz" = linkonce global %.introspect { i8 11, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.subarrays.Bar" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, 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[]" { ptr @.taddr, i64 2 }, align 8
@.taddr.3 = private global [2 x i32] [i32 1, i32 2], align 4
@@ -68,6 +68,7 @@ fn int main()
@.__const = private unnamed_addr constant { i32, [4 x i8] } { i32 1, [4 x i8] undef }, align 8
@.str.9 = private unnamed_addr constant [3 x i8] c"Ok\00", align 1
; Function Attrs: nounwind
define i32 @main() #0 {
entry:
%w = alloca %Bar, align 4

View File

@@ -79,7 +79,7 @@ fn void main()
%Foo = type { i16, i8, i8, i16, i16 }
@"$ct.userland_bitcast.Foo" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8
@"$ct.userland_bitcast.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 5, [0 x i64] zeroinitializer }, 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

View File

@@ -10,7 +10,7 @@ struct An3
An2 y;
}
typedef AnCall = fn void();
def AnCall = fn void();
struct An2
{

View File

@@ -1,4 +1,4 @@
typedef NodeNotifyHandler = fn void(TreeView* this, TreeNode* node, String prop, void* data);
def NodeNotifyHandler = fn void(TreeView* this, TreeNode* node, String prop, void* data);
fn void TreeView.nodeNotifyHandler(TreeView* this, TreeNode* node, String prop, void* data) @private {}
struct TreeNode { int abc; NodeNotifyHandler notifyHandler; }

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