mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
LLVM 15 compatibility fixes (#465)
More variant code. Fixes to typekind. Fixes to macro with failable returns. Remove use of LLVMConstInsert etc. Version 0.2.8
This commit is contained in:
committed by
GitHub
parent
bb28f6e61c
commit
c8a614e43f
@@ -81,29 +81,6 @@ macro unreachable($string = "Unreachable statement reached.") @autoimport @noret
|
||||
$$unreachable();
|
||||
}
|
||||
|
||||
enum TypeKind : char
|
||||
{
|
||||
VOID, // 0
|
||||
BOOL, // 1
|
||||
FLOAT, // 2
|
||||
INTEGER,// 3
|
||||
STRUCT, // 4
|
||||
UNION, // 5
|
||||
ENUM, // 6
|
||||
FAULT, // 7
|
||||
ARRAY,
|
||||
POINTER,
|
||||
VAR_ARRAY,
|
||||
SUBARRAY,
|
||||
OPAQUE
|
||||
// ALIAS,
|
||||
}
|
||||
|
||||
struct TypeEnum
|
||||
{
|
||||
TypeKind type;
|
||||
usize elements;
|
||||
}
|
||||
/*
|
||||
enum TypeKind
|
||||
{
|
||||
|
||||
109
lib/std/core/types.c3
Normal file
109
lib/std/core/types.c3
Normal file
@@ -0,0 +1,109 @@
|
||||
module std::core::types;
|
||||
|
||||
macro bool kind_is_int(TypeKind kind)
|
||||
{
|
||||
return kind == TypeKind.SIGNED_INT || kind == TypeKind.UNSIGNED_INT;
|
||||
}
|
||||
|
||||
fault ConversionResult
|
||||
{
|
||||
VALUE_OUT_OF_RANGE,
|
||||
VALUE_OUT_OF_UNSIGNED_RANGE,
|
||||
}
|
||||
/**
|
||||
* @require type.typeid == SIGNED_INT || type.typeid == UNSIGNED_INT, "Argument was not an integer"
|
||||
**/
|
||||
macro variant_to_int(variant v, $Type)
|
||||
{
|
||||
bool is_mixed_signed = $Type.typeid.kind != v.type.kind;
|
||||
$Type max = $Type.max;
|
||||
$Type min = $Type.min;
|
||||
switch (v)
|
||||
{
|
||||
case ichar:
|
||||
ichar c = *v;
|
||||
if (is_mixed_signed && c < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
return ($Type)c;
|
||||
case short:
|
||||
short s = *v;
|
||||
if (is_mixed_signed && s < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)s;
|
||||
case int:
|
||||
int i = *v;
|
||||
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
case long:
|
||||
long l = *v;
|
||||
if (is_mixed_signed && l < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)l;
|
||||
case int128:
|
||||
$if (env::I128_SUPPORT):
|
||||
int128 i = *v;
|
||||
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
$else:
|
||||
unreachable();
|
||||
$endif;
|
||||
case char:
|
||||
char c = *v;
|
||||
if (c > max) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)c;
|
||||
case ushort:
|
||||
ushort s = *v;
|
||||
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)s;
|
||||
case uint:
|
||||
uint i = *v;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
case ulong:
|
||||
ulong l = *v;
|
||||
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)l;
|
||||
case uint128:
|
||||
$if (env::I128_SUPPORT):
|
||||
uint128 i = *v;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
$else:
|
||||
unreachable();
|
||||
$endif;
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
enum TypeKind : char
|
||||
{
|
||||
VOID,
|
||||
BOOL,
|
||||
SIGNED_INT,
|
||||
UNSIGNED_INT,
|
||||
FLOAT,
|
||||
TYPEID,
|
||||
ANYERR,
|
||||
ANY,
|
||||
ENUM,
|
||||
FAULT,
|
||||
STRUCT,
|
||||
UNION,
|
||||
BITSTRUCT,
|
||||
FUNC,
|
||||
FAILABLE,
|
||||
ARRAY,
|
||||
SUBARRAY,
|
||||
VECTOR,
|
||||
DISTINCT,
|
||||
POINTER,
|
||||
VARIANT
|
||||
}
|
||||
|
||||
struct TypeEnum
|
||||
{
|
||||
TypeKind type;
|
||||
usize elements;
|
||||
}
|
||||
450
lib/std/io_printf.c3
Normal file
450
lib/std/io_printf.c3
Normal file
@@ -0,0 +1,450 @@
|
||||
module std::io;
|
||||
import libc;
|
||||
|
||||
const PRINTF_NTOA_BUFFER_SIZE = 123;
|
||||
|
||||
bitstruct PrintFlags : uint
|
||||
{
|
||||
bool zeropad : 0;
|
||||
bool left : 1;
|
||||
bool plus : 2;
|
||||
bool space : 3;
|
||||
bool hash : 4;
|
||||
bool uppercase : 5;
|
||||
bool precision : 6;
|
||||
bool adapt_exp : 7;
|
||||
}
|
||||
|
||||
/*
|
||||
private macro usize out_rev(#output, usize idx, char* buf, uint len, uint width, PrintFlags flags)
|
||||
{
|
||||
usize start_idx = idx;
|
||||
// pad spaces up to given width
|
||||
if (!flags.left && !flags.zeropad)
|
||||
{
|
||||
for (usize i = len; i < width; i++)
|
||||
{
|
||||
output(' ');
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
while (len)
|
||||
{
|
||||
output(buf[--len]);
|
||||
idx++;
|
||||
}
|
||||
|
||||
// append pad spaces up to given width
|
||||
if (flags & FLAGS_LEFT)
|
||||
{
|
||||
while (idx - start_idx < width)
|
||||
{
|
||||
output(' ');
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
private macro usize ntoa_format(#output, uint idx, uint len, char* buf, uint prec, bool is_negative, PrintFlags flags)
|
||||
{
|
||||
if (!flags.left)
|
||||
{
|
||||
if (width && flags.zeropad && (is_negative || flags.plus || flags.space))
|
||||
{
|
||||
width--;
|
||||
}
|
||||
while (len < prec && len < PRINTF_NTOA_BUFFER_SIZE) buf[len++] = '0';
|
||||
if (flags.zeropad)
|
||||
{
|
||||
while (len < width && len < PRINTF_NTOA_BUFFER_SIZE) buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
if (flags.hash)
|
||||
{
|
||||
if (!flags.precision && len && (len == prec || len == width))
|
||||
{
|
||||
len--;
|
||||
if (len && base == 16)
|
||||
{
|
||||
len--;
|
||||
}
|
||||
}
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE)
|
||||
{
|
||||
switch (base)
|
||||
{
|
||||
case 16:
|
||||
buf[len++] = flags.uppercase ? 'X' : 'x';
|
||||
case 8:
|
||||
buf[len++] = flags.uppercase ? 'O' : 'o';
|
||||
case 2:
|
||||
buf[len++] = flags.uppercase ? 'B' : 'b';
|
||||
default:
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE)
|
||||
{
|
||||
switch (true)
|
||||
{
|
||||
case is_negative:
|
||||
buf[len++] = '-';
|
||||
case flags.plus:
|
||||
buf[len++] = '+';
|
||||
case flags.space:
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
return out_rev(#output, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
*/
|
||||
|
||||
private macro usize! @printf_integer(#output, variant, usize idx, uint precision, uint width, PrintFlags flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private macro usize! @printf_efloat(#output, variant, usize idx, uint precision, uint width, PrintFlags flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private macro usize! @printf_char(#output, variant, usize idx, uint precision, uint width, PrintFlags flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private macro usize! @printf_ptr(#output, variant, usize idx, uint precision, uint width, PrintFlags flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private macro usize! @printf_str(#output, variant, usize idx, uint precision, uint width, PrintFlags flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private macro void @format_print_str_variant(#output, variant arg)
|
||||
{
|
||||
if (arg.type.kind == TypeKind.POINTER)
|
||||
{
|
||||
libc::printf("%p", *((void**)arg));
|
||||
return;
|
||||
}
|
||||
switch (arg)
|
||||
{
|
||||
case char[]:
|
||||
@format_print(#output, *arg);
|
||||
case bool:
|
||||
@format_print(#output, *arg ? (char[])"true" : (char[])"false");
|
||||
case long:
|
||||
libc::printf("%lld", (CLongLong)*arg);
|
||||
case int:
|
||||
libc::printf("%d", *arg);
|
||||
case short:
|
||||
libc::printf("%d", *arg);
|
||||
case ichar:
|
||||
libc::printf("%d", *arg);
|
||||
case char:
|
||||
libc::printf("%u", *arg);
|
||||
default:
|
||||
print("Invalid type");
|
||||
}
|
||||
}
|
||||
|
||||
private macro void @format_print(#output, char[] str)
|
||||
{
|
||||
foreach (char c : str) #output(c);
|
||||
}
|
||||
|
||||
private fn uint simple_atoi(char* buf, usize maxlen, usize* len_ptr) @inline
|
||||
{
|
||||
uint i = 0;
|
||||
usize len = *len_ptr;
|
||||
while (len < maxlen)
|
||||
{
|
||||
char c = buf[len];
|
||||
if (c < '0' || c > '9') break;
|
||||
i = i * 10 + c - '0';
|
||||
len++;
|
||||
}
|
||||
*len_ptr = len;
|
||||
return i;
|
||||
}
|
||||
|
||||
fault FormattingFault
|
||||
{
|
||||
UNTERMINATED_FORMAT,
|
||||
MISSING_ARG,
|
||||
INVALID_WIDTH_ARG,
|
||||
INVALID_FORMAT_TYPE,
|
||||
}
|
||||
|
||||
private fn void! printf_advance_format(usize format_len, usize *index_ptr) @inline
|
||||
{
|
||||
usize val = ++(*index_ptr);
|
||||
if (val <= format_len) return FormattingFault.UNTERMINATED_FORMAT!;
|
||||
}
|
||||
|
||||
private fn variant! next_variant(variant* args_ptr, usize args_len, usize* arg_index_ptr) @inline
|
||||
{
|
||||
if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG!;
|
||||
return args_ptr[(*arg_index_ptr)++];
|
||||
}
|
||||
|
||||
private fn uint! printf_parse_format_field(variant* args_ptr, usize args_len, usize* args_index_ptr, char* format_ptr, usize format_len, usize* index_ptr) @inline
|
||||
{
|
||||
char c = format_ptr[*index_ptr];
|
||||
if (c >= '0' && c <= '9') return simple_atoi(format_ptr, format_len, index_ptr);
|
||||
if (c != '*') return 0;
|
||||
printf_advance_format(format_len, index_ptr)?;
|
||||
variant val = next_variant(args_ptr, args_len, args_index_ptr)?;
|
||||
if (!types::kind_is_int(val.type.kind)) return FormattingFault.INVALID_WIDTH_ARG!;
|
||||
uint! intval = types::variant_to_int(val, uint);
|
||||
if (catch intval) return FormattingFault.INVALID_WIDTH_ARG!;
|
||||
return intval;
|
||||
}
|
||||
|
||||
private macro usize! @printf_generic(#output, char[] format, variant[] args)
|
||||
{
|
||||
usize idx = 0;
|
||||
char* format_ptr = format.ptr;
|
||||
usize format_len = format.len;
|
||||
usize arg_index = 0;
|
||||
for (usize i = 0; i < format_len; i++)
|
||||
{
|
||||
char c = format_ptr[i];
|
||||
if (c != '%')
|
||||
{
|
||||
#output(c);
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
printf_advance_format(format_len, &i)?;
|
||||
c = format_ptr[i];
|
||||
if (c == '%')
|
||||
{
|
||||
#output(c);
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
// format specifier? %[flags][width][.precision][length]
|
||||
PrintFlags flags;
|
||||
while FLAG_EVAL: (1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '0':
|
||||
flags.zeropad = true;
|
||||
case '-':
|
||||
flags.left = true;
|
||||
case '+':
|
||||
flags.plus = true;
|
||||
case ' ':
|
||||
flags.space = true;
|
||||
case '#':
|
||||
flags.hash = true;
|
||||
default:
|
||||
break FLAG_EVAL;
|
||||
}
|
||||
printf_advance_format(format_len, &i)?;
|
||||
c = format_ptr[i];
|
||||
}
|
||||
// evaluate width field
|
||||
uint width = printf_parse_format_field(args.ptr, args.len, &arg_index, format_ptr, format_len, &i)?;
|
||||
c = format_ptr[i];
|
||||
uint precision = 0;
|
||||
if (c == '.')
|
||||
{
|
||||
flags.precision = true;
|
||||
printf_advance_format(format_len, &i)?;
|
||||
precision = printf_parse_format_field(args.ptr, args.len, &arg_index, format_ptr, format_len, &i)?;
|
||||
c = format_ptr[i];
|
||||
}
|
||||
|
||||
uint base = void;
|
||||
switch (c)
|
||||
{
|
||||
case 'd':
|
||||
flags.hash = false;
|
||||
base = 10;
|
||||
case 'X':
|
||||
flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'x':
|
||||
base = 16;
|
||||
case 'o':
|
||||
base = 8;
|
||||
case 'b':
|
||||
base = 2;
|
||||
case 'F':
|
||||
flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'f':
|
||||
idx = @printf_efloat(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?;
|
||||
continue;
|
||||
case 'E':
|
||||
flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'e':
|
||||
idx = @printf_efloat(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?;
|
||||
continue;
|
||||
case 'G':
|
||||
flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'g':
|
||||
flags.adapt_exp = true;
|
||||
nextcase 'e';
|
||||
case 'c':
|
||||
idx = @printf_char(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?;
|
||||
continue;
|
||||
case 'p':
|
||||
idx = @printf_ptr(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?;
|
||||
continue;
|
||||
case 's':
|
||||
idx = @printf_str(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?;
|
||||
continue;
|
||||
case 'n':
|
||||
idx = @printf_str(#output, &&"\n", idx, precision, width, flags)?;
|
||||
continue;
|
||||
|
||||
default:
|
||||
return FormattingFault.INVALID_FORMAT_TYPE!;
|
||||
}
|
||||
if (base != 10)
|
||||
{
|
||||
flags.plus = false;
|
||||
flags.space = false;
|
||||
}
|
||||
if (flags.precision) flags.zeropad = false;
|
||||
idx = @printf_integer(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?;
|
||||
}
|
||||
return idx;
|
||||
/*
|
||||
precision = 0U;
|
||||
|
||||
|
||||
case 'c' : {
|
||||
unsigned int l = 1U;
|
||||
// pre padding
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// char output
|
||||
out((char)va_arg(va, int), buffer, idx++, maxlen);
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's' : {
|
||||
const char* p = va_arg(va, char*);
|
||||
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
|
||||
// pre padding
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
l = (l < precision ? l : precision);
|
||||
}
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// string output
|
||||
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
||||
out(*(p++), buffer, idx++, maxlen);
|
||||
}
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p' : {
|
||||
width = sizeof(void*) * 2U;
|
||||
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||
if (is_ll) {
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
}
|
||||
#endif
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case '%' :
|
||||
out('%', buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
|
||||
default :
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// termination
|
||||
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
return (int)idx;*/
|
||||
}
|
||||
|
||||
private macro void @formatting(#output, char[] format, variant[] args)
|
||||
{
|
||||
usize len = format.len;
|
||||
usize arg_len = args.len;
|
||||
usize current_arg = 0;
|
||||
for (usize i = 0; i < len; i++)
|
||||
{
|
||||
char c = format[i];
|
||||
if (c != '%' || i == len - 1)
|
||||
{
|
||||
#output(c);
|
||||
continue;
|
||||
}
|
||||
c = format[++i];
|
||||
switch (c)
|
||||
{
|
||||
case 's':
|
||||
if (current_arg >= arg_len)
|
||||
{
|
||||
@format_print(#output, "<missing arg>");
|
||||
continue;
|
||||
}
|
||||
@format_print_str_variant(#output, args[current_arg++]);
|
||||
default:
|
||||
@format_print(#output, "Unknown specifier");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void printf2(char[] format, args...)
|
||||
{
|
||||
@printf_generic(putchar, format, args)!!;
|
||||
}
|
||||
|
||||
fn void printf(char[] format, args... )
|
||||
{
|
||||
@formatting(putchar, format, args);
|
||||
}
|
||||
@@ -228,6 +228,7 @@ bool expr_is_pure(Expr *expr)
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_BUILTIN:
|
||||
case EXPR_TYPEID_KIND:
|
||||
return false;
|
||||
case EXPR_COMPILER_CONST:
|
||||
case EXPR_CONST:
|
||||
|
||||
@@ -236,7 +236,6 @@ struct Type_
|
||||
const char *name;
|
||||
Type **type_cache;
|
||||
void *backend_type;
|
||||
void *backend_aux_type;
|
||||
void *backend_typeid;
|
||||
void *backend_debug_type;
|
||||
union
|
||||
@@ -1576,6 +1575,8 @@ extern const char *attribute_list[NUMBER_OF_ATTRIBUTES];
|
||||
extern const char *builtin_list[NUMBER_OF_BUILTINS];
|
||||
|
||||
extern const char *kw_std__core;
|
||||
extern const char *kw_std__core__types;
|
||||
extern const char *kw_typekind;
|
||||
|
||||
extern const char *kw_std;
|
||||
extern const char *kw_max;
|
||||
@@ -1591,6 +1592,7 @@ extern const char *kw_deprecated;
|
||||
extern const char *kw_distinct;
|
||||
extern const char *kw_inline;
|
||||
extern const char *kw_inf;
|
||||
extern const char *kw_kind;
|
||||
extern const char *kw_elementat;
|
||||
extern const char *kw_elementref;
|
||||
extern const char *kw_elementset;
|
||||
@@ -1598,6 +1600,8 @@ extern const char *kw_len;
|
||||
extern const char *kw_nan;
|
||||
extern const char *kw_noinline;
|
||||
extern const char *kw_main;
|
||||
extern const char *kw_max;
|
||||
extern const char *kw_min;
|
||||
extern const char *kw_ordinal;
|
||||
extern const char *kw_pure;
|
||||
extern const char *kw_ptr;
|
||||
@@ -2019,9 +2023,11 @@ AlignSize type_alloca_alignment(Type *type);
|
||||
static inline bool type_convert_will_trunc(Type *destination, Type *source);
|
||||
bool type_is_comparable(Type *type);
|
||||
bool type_is_ordered(Type *type);
|
||||
unsigned type_get_introspection_kind(TypeKind kind);
|
||||
Type *type_find_common_ancestor(Type *left, Type *right);
|
||||
Type *type_find_largest_union_element(Type *type);
|
||||
Type *type_find_max_type(Type *type, Type *other);
|
||||
Type *type_find_max_type_may_fail(Type *type, Type *other);
|
||||
Type *type_abi_find_single_struct_element(Type *type);
|
||||
bool type_is_valid_for_vector(Type *type);
|
||||
Type *type_get_array(Type *arr_type, ArraySize len);
|
||||
|
||||
@@ -241,6 +241,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
case EXPR_PTR:
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_TYPEID_KIND:
|
||||
MACRO_COPY_EXPR(expr->inner_expr);
|
||||
return expr;
|
||||
case EXPR_COND:
|
||||
|
||||
@@ -188,7 +188,9 @@ typedef enum
|
||||
INTROSPECT_TYPE_ARRAY = 15,
|
||||
INTROSPECT_TYPE_SUBARRAY = 16,
|
||||
INTROSPECT_TYPE_VECTOR = 17,
|
||||
INTROSPECT_TYPE_DISTINCT = 18
|
||||
INTROSPECT_TYPE_DISTINCT = 18,
|
||||
INTROSPECT_TYPE_POINTER = 19,
|
||||
INTROSPECT_TYPE_VARIANT = 20,
|
||||
} IntrospectType;
|
||||
|
||||
typedef enum
|
||||
@@ -245,6 +247,7 @@ typedef enum
|
||||
EXPR_UNARY,
|
||||
EXPR_VARIANTSWITCH,
|
||||
EXPR_NOP,
|
||||
EXPR_TYPEID_KIND,
|
||||
} ExprKind;
|
||||
|
||||
typedef enum
|
||||
|
||||
@@ -8,23 +8,7 @@ extern bool llvm_link_coff(const char **args, int arg_count, const char **error_
|
||||
extern bool llvm_link_wasm(const char **args, int arg_count, const char **error_string);
|
||||
extern bool llvm_link_mingw(const char **args, int arg_count, const char **error_string);
|
||||
|
||||
static void add_files(const char ***args, const char **files_to_link, unsigned file_count)
|
||||
{
|
||||
for (unsigned i = 0; i < file_count; i++)
|
||||
{
|
||||
vec_add(*args, files_to_link[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *join_strings(const char **args, unsigned count)
|
||||
{
|
||||
char *res = "";
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
{
|
||||
res = str_cat(res, args[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
const char* llvm_version = LLVM_VERSION_STRING;
|
||||
const char* llvm_target = LLVM_DEFAULT_TARGET_TRIPLE;
|
||||
|
||||
void llvm_emit_local_global_variable_definition(GenContext *c, Decl *decl);
|
||||
|
||||
static void diagnostics_handler(LLVMDiagnosticInfoRef ref, void *context)
|
||||
{
|
||||
char *message = LLVMGetDiagInfoDescription(ref);
|
||||
@@ -255,28 +253,6 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
|
||||
}
|
||||
|
||||
|
||||
void llvm_emit_local_global_variable_definition(GenContext *c, Decl *decl)
|
||||
{
|
||||
assert(decl->var.kind == VARDECL_GLOBAL || decl->var.kind == VARDECL_CONST);
|
||||
|
||||
// Skip real constants.
|
||||
if (!decl->type) return;
|
||||
|
||||
if (decl->type != type_void)
|
||||
{
|
||||
decl->backend_ref = llvm_add_global_var(c, "tempglobal", decl->type, decl->alignment);
|
||||
}
|
||||
if (IS_FAILABLE(decl))
|
||||
{
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append(decl->extname);
|
||||
scratch_buffer_append(".f");
|
||||
decl->var.failable_ref = llvm_add_global_var(c, scratch_buffer_to_string(), type_anyerr, 0);
|
||||
LLVMSetUnnamedAddress(decl->var.failable_ref, LLVMGlobalUnnamedAddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void llvm_emit_ptr_from_array(GenContext *c, BEValue *value)
|
||||
{
|
||||
switch (value->type->type_kind)
|
||||
|
||||
@@ -90,39 +90,14 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue
|
||||
|
||||
static inline LLVMValueRef llvm_emit_extract_value(GenContext *c, LLVMValueRef agg, unsigned index)
|
||||
{
|
||||
if (LLVMIsConstant(agg))
|
||||
if (LLVMGetTypeKind(LLVMTypeOf(agg)) == LLVMVectorTypeKind)
|
||||
{
|
||||
return LLVMConstExtractValue(agg, &index, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LLVMBuildExtractValue(c->builder, agg, index, "");
|
||||
return LLVMBuildExtractElement(c->builder, agg, llvm_const_int(c, type_usize, index), "");
|
||||
}
|
||||
return LLVMBuildExtractValue(c->builder, agg, index, "");
|
||||
}
|
||||
|
||||
static inline LLVMValueRef llvm_emit_extract_element(GenContext *c, LLVMValueRef vector, unsigned index)
|
||||
{
|
||||
if (LLVMIsConstant(vector))
|
||||
{
|
||||
return LLVMConstExtractElement(vector, llvm_const_int(c, type_usize, index));
|
||||
}
|
||||
else
|
||||
{
|
||||
return LLVMBuildExtractElement(c->builder, vector, llvm_const_int(c, type_usize, index), "");
|
||||
}
|
||||
}
|
||||
|
||||
static inline LLVMValueRef llvm_emit_insert_value(GenContext *c, LLVMValueRef agg, LLVMValueRef new_value, unsigned index)
|
||||
{
|
||||
if (LLVMIsConstant(agg) && LLVMIsConstant(new_value))
|
||||
{
|
||||
return LLVMConstInsertValue(agg, new_value, &index, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LLVMBuildInsertValue(c->builder, agg, new_value, index, "");
|
||||
}
|
||||
}
|
||||
|
||||
static inline LLVMValueRef llvm_zext_trunc(GenContext *c, LLVMValueRef data, LLVMTypeRef type)
|
||||
{
|
||||
@@ -170,39 +145,22 @@ LLVMValueRef llvm_emit_coerce_alignment(GenContext *c, BEValue *be_value, LLVMTy
|
||||
return LLVMBuildBitCast(c->builder, be_value->value, LLVMPointerType(coerce_type, 0), "");
|
||||
}
|
||||
|
||||
|
||||
LLVMValueRef llvm_emit_aggregate_value(GenContext *c, Type *type, ...)
|
||||
LLVMValueRef llvm_emit_aggregate_two(GenContext *c, Type *type, LLVMValueRef value1, LLVMValueRef value2)
|
||||
{
|
||||
LLVMValueRef result = LLVMGetUndef(llvm_get_type(c, type));
|
||||
va_list args;
|
||||
va_start(args, type);
|
||||
LLVMValueRef val;
|
||||
bool is_constant = true;
|
||||
while (is_constant && (val = va_arg(args, LLVMValueRef)) != NULL)
|
||||
{
|
||||
if (!LLVMIsConstant(val)) is_constant = false;
|
||||
}
|
||||
va_end(args);
|
||||
va_start(args, type);
|
||||
unsigned index = 0;
|
||||
bool is_constant = LLVMIsConstant(value1) && LLVMIsConstant(value2);
|
||||
if (is_constant)
|
||||
{
|
||||
while ((val = va_arg(args, LLVMValueRef)) != NULL)
|
||||
{
|
||||
result = LLVMConstInsertValue(result, val, &index, 1);
|
||||
index++;
|
||||
}
|
||||
LLVMValueRef two[2] = { value1, value2 };
|
||||
return LLVMConstNamedStruct(llvm_get_type(c, type), two, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(c->builder);
|
||||
while ((val = va_arg(args, LLVMValueRef)) != NULL)
|
||||
{
|
||||
result = LLVMBuildInsertValue(c->builder, result, val, index++, "");
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
return result;
|
||||
LLVMValueRef result = LLVMGetUndef(llvm_get_type(c, type));
|
||||
result = llvm_emit_insert_value(c, result, value1, 0);
|
||||
return llvm_emit_insert_value(c, result, value2, 1);
|
||||
}
|
||||
|
||||
void llvm_set_aggregate_two(GenContext *c, BEValue *value, Type *type, LLVMValueRef value1, LLVMValueRef value2)
|
||||
{
|
||||
llvm_value_set(value, llvm_emit_aggregate_two(c, type, value1, value2), type);
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_const_low_bitmask(LLVMTypeRef type, int type_bits, int low_bits)
|
||||
@@ -261,8 +219,8 @@ static inline LLVMValueRef llvm_emit_add_int(GenContext *c, Type *type, LLVMValu
|
||||
{
|
||||
add_res = llvm_emit_call_intrinsic(c, intrinsic_id.sadd_overflow, &type_to_use, 1, args, 2);
|
||||
}
|
||||
LLVMValueRef result = LLVMBuildExtractValue(c->builder, add_res, 0, "");
|
||||
LLVMValueRef ok = LLVMBuildExtractValue(c->builder, add_res, 1, "");
|
||||
LLVMValueRef result = llvm_emit_extract_value(c, add_res, 0);
|
||||
LLVMValueRef ok = llvm_emit_extract_value(c, add_res, 1);
|
||||
llvm_emit_panic_on_true(c, ok, "Addition overflow", loc);
|
||||
return result;
|
||||
}
|
||||
@@ -487,8 +445,8 @@ static inline LLVMValueRef llvm_emit_sub_int(GenContext *c, Type *type, LLVMValu
|
||||
{
|
||||
add_res = llvm_emit_call_intrinsic(c, intrinsic_id.ssub_overflow, &type_to_use, 1, args, 2);
|
||||
}
|
||||
LLVMValueRef result = LLVMBuildExtractValue(c->builder, add_res, 0, "");
|
||||
LLVMValueRef ok = LLVMBuildExtractValue(c->builder, add_res, 1, "");
|
||||
LLVMValueRef result = llvm_emit_extract_value(c, add_res, 0);
|
||||
LLVMValueRef ok = llvm_emit_extract_value(c, add_res, 1);
|
||||
llvm_emit_panic_on_true(c, ok, "Subtraction overflow", loc);
|
||||
return result;
|
||||
}
|
||||
@@ -573,14 +531,7 @@ static inline void llvm_emit_vector_subscript(GenContext *c, BEValue *value, Exp
|
||||
{
|
||||
index = LLVMBuildNUWSub(c->builder, llvm_const_int(c, value->type, vec->array.len), index, "");
|
||||
}
|
||||
if (LLVMIsAConstant(index) && LLVMIsAConstant(vector))
|
||||
{
|
||||
llvm_value_set(value, LLVMConstExtractElement(vector, index), element);
|
||||
}
|
||||
else
|
||||
{
|
||||
llvm_value_set(value, LLVMBuildExtractElement(c->builder, vector, index, ""), element);
|
||||
}
|
||||
llvm_value_set(value, LLVMBuildExtractElement(c->builder, vector, index, ""), element);
|
||||
}
|
||||
|
||||
|
||||
@@ -1115,8 +1066,7 @@ static void llvm_emit_arr_to_subarray_cast(GenContext *c, BEValue *value, Type *
|
||||
LLVMTypeRef subarray_type = llvm_get_type(c, to_type);
|
||||
LLVMValueRef pointer = llvm_emit_bitcast(c, value->value, type_get_ptr(array_type));
|
||||
LLVMValueRef len = llvm_const_int(c, type_usize, size);
|
||||
value->type = to_type;
|
||||
value->value = llvm_emit_aggregate_value(c, to_type, pointer, len, NULL);
|
||||
llvm_set_aggregate_two(c, value, to_type, pointer, len);
|
||||
}
|
||||
|
||||
|
||||
@@ -1128,13 +1078,8 @@ void llvm_emit_vector_to_array_cast(GenContext *c, BEValue *value, Type *to_type
|
||||
bool is_const = LLVMIsConstant(value->value);
|
||||
for (unsigned i = 0; i < to_type->array.len; i++)
|
||||
{
|
||||
LLVMValueRef element = llvm_emit_extract_element(c, value->value, i);
|
||||
if (is_const)
|
||||
{
|
||||
array = LLVMConstInsertValue(array, element, &i, 1);
|
||||
continue;
|
||||
}
|
||||
array = LLVMBuildInsertValue(c->builder, array, element, i, "");
|
||||
LLVMValueRef element = llvm_emit_extract_value(c, value->value, i);
|
||||
array = llvm_emit_insert_value(c, array, element, i);
|
||||
}
|
||||
llvm_value_set(value, array, to_type);
|
||||
}
|
||||
@@ -1144,16 +1089,10 @@ void llvm_emit_array_to_vector_cast(GenContext *c, BEValue *value, Type *to_type
|
||||
llvm_value_rvalue(c, value);
|
||||
LLVMTypeRef vector_type = llvm_get_type(c, to_type);
|
||||
LLVMValueRef vector = LLVMGetUndef(vector_type);
|
||||
bool is_const = LLVMIsConstant(value->value);
|
||||
for (unsigned i = 0; i < to_type->array.len; i++)
|
||||
{
|
||||
LLVMValueRef element = llvm_emit_extract_value(c, value->value, i);
|
||||
if (is_const)
|
||||
{
|
||||
vector = LLVMConstInsertElement(vector, element, llvm_const_int(c, type_usize, i));
|
||||
continue;
|
||||
}
|
||||
vector = LLVMBuildInsertElement(c->builder, vector, element, llvm_const_int(c, type_usize, i), "");
|
||||
vector = llvm_emit_insert_value(c, vector, element, i);
|
||||
}
|
||||
llvm_value_set(value, vector, to_type);
|
||||
}
|
||||
@@ -1175,7 +1114,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
|
||||
LLVMValueRef pointer = llvm_emit_bitcast(c, value->value, type_voidptr);
|
||||
BEValue typeid;
|
||||
llvm_emit_typeid(c, &typeid, from_type->pointer);
|
||||
llvm_value_set(value, llvm_emit_aggregate_value(c, to_type, pointer, typeid.value, NULL), to_type);
|
||||
llvm_set_aggregate_two(c, value, to_type, pointer, typeid.value);
|
||||
return;
|
||||
}
|
||||
case CAST_BSARRY:
|
||||
@@ -1228,18 +1167,18 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
|
||||
case CAST_STRPTR:
|
||||
case CAST_PTRPTR:
|
||||
llvm_value_rvalue(c, value);
|
||||
if (c->builder)
|
||||
if (LLVMIsConstant(value->value))
|
||||
{
|
||||
value->value = LLVMBuildPointerCast(c->builder, value->value, llvm_get_type(c, to_type), "ptrptr");
|
||||
value->value = LLVMConstPointerCast(value->value, llvm_get_type(c, to_type));
|
||||
}
|
||||
else
|
||||
{
|
||||
value->value = LLVMConstPointerCast(value->value, llvm_get_type(c, to_type));
|
||||
value->value = LLVMBuildPointerCast(c->builder, value->value, llvm_get_type(c, to_type), "ptrptr");
|
||||
}
|
||||
break;
|
||||
case CAST_PTRXI:
|
||||
llvm_value_rvalue(c, value);
|
||||
if (c->builder)
|
||||
if (!LLVMIsConstant(value->value))
|
||||
{
|
||||
value->value = LLVMBuildPtrToInt(c->builder, value->value, llvm_get_type(c, to_type), "ptrxi");
|
||||
}
|
||||
@@ -1377,7 +1316,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
|
||||
}
|
||||
else
|
||||
{
|
||||
value->value = LLVMBuildExtractValue(c->builder, value->value, 1, "");
|
||||
value->value = llvm_emit_extract_value(c, value->value, 1);
|
||||
}
|
||||
value->type = type_usize->canonical;
|
||||
llvm_value_rvalue(c, value);
|
||||
@@ -1405,18 +1344,17 @@ static LLVMValueRef llvm_recursive_set_value(GenContext *c, DesignatorElement **
|
||||
{
|
||||
BEValue res;
|
||||
llvm_emit_expr(c, &res, value);
|
||||
unsigned index = (unsigned)current_element->index;
|
||||
ArraySize index = (ArraySize)current_element->index;
|
||||
LLVMValueRef val = llvm_load_value_store(c, &res);
|
||||
switch (current_element->kind)
|
||||
{
|
||||
case DESIGNATOR_FIELD:
|
||||
return LLVMConstInsertValue(parent, val, &index, 1);
|
||||
case DESIGNATOR_ARRAY:
|
||||
return LLVMConstInsertElement(parent, val, llvm_const_int(c, type_isize, (unsigned)current_element->index));
|
||||
return llvm_emit_insert_value(c, parent, val, index);
|
||||
case DESIGNATOR_RANGE:
|
||||
for (MemberIndex i = current_element->index; i <= current_element->index_end; i++)
|
||||
{
|
||||
parent = LLVMConstInsertElement(parent, val, llvm_const_int(c, type_isize, (uint64_t)i));
|
||||
parent = llvm_emit_insert_value(c, parent, val, i);
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
@@ -1428,24 +1366,20 @@ static LLVMValueRef llvm_recursive_set_value(GenContext *c, DesignatorElement **
|
||||
case DESIGNATOR_FIELD:
|
||||
{
|
||||
unsigned index = (unsigned)current_element->index;
|
||||
current_val = LLVMConstExtractValue(parent, &index, 1);
|
||||
current_val = llvm_emit_extract_value(c, parent, index);
|
||||
current_val = llvm_recursive_set_value(c, current_element_ptr + 1, current_val, last_element_ptr, value);
|
||||
return LLVMConstInsertValue(parent, current_val, &index, 1);
|
||||
return llvm_emit_insert_value(c, parent, current_val, index);
|
||||
}
|
||||
case DESIGNATOR_ARRAY:
|
||||
{
|
||||
LLVMValueRef index = llvm_const_int(c, type_isize, (uint64_t)current_element->index);
|
||||
current_val = LLVMConstExtractElement(parent, index);
|
||||
current_val = llvm_emit_extract_value(c, parent, current_element->index);
|
||||
current_val = llvm_recursive_set_value(c, current_element_ptr + 1, current_val, last_element_ptr, value);
|
||||
return LLVMConstInsertElement(parent, current_val, index);
|
||||
}
|
||||
return llvm_emit_insert_value(c, parent, current_val, current_element->index);
|
||||
case DESIGNATOR_RANGE:
|
||||
for (MemberIndex i = current_element->index; i <= current_element->index_end; i++)
|
||||
{
|
||||
LLVMValueRef index = llvm_const_int(c, type_isize, (uint64_t)i);
|
||||
current_val = LLVMConstExtractElement(parent, index);
|
||||
current_val = llvm_emit_extract_value(c, parent, i);
|
||||
current_val = llvm_recursive_set_value(c, current_element_ptr + 1, current_val, last_element_ptr, value);
|
||||
parent = LLVMConstInsertElement(parent, current_val, index);
|
||||
parent = llvm_emit_insert_value(c, parent, current_val, i);
|
||||
}
|
||||
return parent;
|
||||
default:
|
||||
@@ -1761,6 +1695,9 @@ static inline void llvm_emit_initialize_reference_designated(GenContext *c, BEVa
|
||||
llvm_emit_initialize_designated(c, ref, 0, designator->designator_expr.path, last_element, designator->designator_expr.value, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_AGG 16
|
||||
|
||||
LLVMValueRef llvm_emit_const_bitstruct_array(GenContext *c, ConstInitializer *initializer)
|
||||
{
|
||||
Decl *decl = initializer->type->decl;
|
||||
@@ -1768,7 +1705,13 @@ LLVMValueRef llvm_emit_const_bitstruct_array(GenContext *c, ConstInitializer *in
|
||||
bool big_endian = platform_target.big_endian;
|
||||
if (decl->bitstruct.big_endian) big_endian = true;
|
||||
if (decl->bitstruct.little_endian) big_endian = false;
|
||||
LLVMValueRef data = LLVMConstNull(llvm_get_type(c, base_type));
|
||||
unsigned elements = base_type->array.len;
|
||||
LLVMValueRef stack_data[MAX_AGG];
|
||||
LLVMValueRef* slots = elements > MAX_AGG ? MALLOC(elements * sizeof(LLVMValueRef)) : stack_data;
|
||||
for (unsigned i = 0; i < elements; i++)
|
||||
{
|
||||
slots[i] = LLVMConstNull(c->byte_type);
|
||||
}
|
||||
Decl **members = decl->strukt.members;
|
||||
MemberIndex count = (MemberIndex)vec_size(members);
|
||||
for (MemberIndex i = 0; i < count; i++)
|
||||
@@ -1791,8 +1734,8 @@ LLVMValueRef llvm_emit_const_bitstruct_array(GenContext *c, ConstInitializer *in
|
||||
|
||||
LLVMValueRef bit = llvm_emit_shl_fixed(c, LLVMConstInt(c->byte_type, 1, 0), start_bit % 8);
|
||||
unsigned byte = start_bit / 8;
|
||||
LLVMValueRef current_value = llvm_emit_extract_value(c, data, byte);
|
||||
data = llvm_emit_insert_value(c, data, LLVMConstOr(current_value, bit), byte);
|
||||
LLVMValueRef current_value = slots[byte];
|
||||
slots[byte] = LLVMConstOr(current_value, bit);
|
||||
continue;
|
||||
}
|
||||
unsigned bit_size = end_bit - start_bit + 1;
|
||||
@@ -1826,11 +1769,11 @@ LLVMValueRef llvm_emit_const_bitstruct_array(GenContext *c, ConstInitializer *in
|
||||
to_or = llvm_mask_low_bits(c, to_or, end_bit % 8 + 1);
|
||||
}
|
||||
if (member_type_bitsize > 8) to_or = LLVMConstTrunc(to_or, c->byte_type);
|
||||
LLVMValueRef current_value = llvm_emit_extract_value(c, data, (unsigned)j);
|
||||
data = llvm_emit_insert_value(c, data, LLVMConstOr(to_or, current_value), (unsigned)j);
|
||||
LLVMValueRef current_value = slots[(unsigned)j];
|
||||
slots[(unsigned)j] = LLVMConstOr(to_or, current_value);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
return LLVMConstArray(c->byte_type, slots, elements);
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_emit_const_bitstruct(GenContext *c, ConstInitializer *initializer)
|
||||
@@ -2006,7 +1949,7 @@ static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue
|
||||
LLVMValueRef val = LLVMGetUndef(llvm_get_type(c, type));
|
||||
for (ArraySize i = 0; i < width; i++)
|
||||
{
|
||||
val = LLVMConstInsertElement(val, diff_value, llvm_const_int(c, type_usize, i));
|
||||
val = llvm_emit_insert_value(c, val, diff_value, i);
|
||||
}
|
||||
if (is_integer)
|
||||
{
|
||||
@@ -2125,7 +2068,7 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
}
|
||||
else
|
||||
{
|
||||
llvm_value = LLVMBuildExtractValue(c->builder, value->value, 1, "len");
|
||||
llvm_value = llvm_emit_extract_value(c, value->value, 1);
|
||||
}
|
||||
llvm_value = LLVMBuildIsNull(c->builder, llvm_value, "not");
|
||||
break;
|
||||
@@ -2164,8 +2107,8 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
LLVMValueRef args[2] = { zero, value->value };
|
||||
LLVMValueRef call_res = llvm_emit_call_intrinsic(c, intrinsic_id.ssub_overflow,
|
||||
&type_to_use, 1, args, 2);
|
||||
value->value = LLVMBuildExtractValue(c->builder, call_res, 0, "");
|
||||
LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, "");
|
||||
value->value = llvm_emit_extract_value(c, call_res, 0);
|
||||
LLVMValueRef ok = llvm_emit_extract_value(c, call_res, 1);
|
||||
llvm_emit_panic_on_true(c, ok, "Signed negation overflow", expr->span);
|
||||
return;
|
||||
}
|
||||
@@ -2201,7 +2144,7 @@ void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_l
|
||||
llvm_value_fold_failable(c, be_value);
|
||||
if (expr_to_len->kind == BE_VALUE)
|
||||
{
|
||||
llvm_value_set(be_value, LLVMBuildExtractValue(c->builder, expr_to_len->value, 1, ""), type_usize);
|
||||
llvm_value_set(be_value, llvm_emit_extract_value(c, expr_to_len->value, 1), type_usize);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2338,7 +2281,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
|
||||
break;
|
||||
case TYPE_SUBARRAY:
|
||||
parent_load_value = LLVMBuildLoad2(c->builder, llvm_get_type(c, parent_type), parent_addr, "");
|
||||
parent_base = LLVMBuildExtractValue(c->builder, parent_load_value, 0, "");
|
||||
parent_base = llvm_emit_extract_value(c, parent_load_value, 0);
|
||||
break;
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
case TYPE_ARRAY:
|
||||
@@ -2367,7 +2310,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
|
||||
break;
|
||||
case TYPE_SUBARRAY:
|
||||
assert(parent_load_value);
|
||||
llvm_value_set(&len, LLVMBuildExtractValue(c->builder, parent_load_value, 1, ""), type_usize);
|
||||
llvm_value_set(&len, llvm_emit_extract_value(c, parent_load_value, 1), type_usize);
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
llvm_value_set_int(c, &len, type_usize, parent_type->array.len);
|
||||
@@ -2483,8 +2426,7 @@ static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
}
|
||||
|
||||
// Create a new subarray type
|
||||
Type *expr_type = type_lowering(expr->type);
|
||||
llvm_value_set(be_value, llvm_emit_aggregate_value(c, expr_type, start_pointer, size, NULL), expr_type);
|
||||
llvm_set_aggregate_two(c, be_value, type_lowering(expr->type), start_pointer, size);
|
||||
}
|
||||
|
||||
static void llvm_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
@@ -2904,8 +2846,8 @@ static inline LLVMValueRef llvm_emit_mult_int(GenContext *c, Type *type, LLVMVal
|
||||
1,
|
||||
args,
|
||||
2);
|
||||
LLVMValueRef val = LLVMBuildExtractValue(c->builder, call_res, 0, "mul");
|
||||
LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, "");
|
||||
LLVMValueRef val = llvm_emit_extract_value(c, call_res, 0);
|
||||
LLVMValueRef ok = llvm_emit_extract_value(c, call_res, 1);
|
||||
llvm_emit_panic_on_true(c, ok, "Integer multiplication overflow", loc);
|
||||
return val;
|
||||
}
|
||||
@@ -2932,12 +2874,12 @@ static void llvm_emit_subarray_comp(GenContext *c, BEValue *be_value, BEValue *l
|
||||
llvm_value_rvalue(c, rhs);
|
||||
BEValue lhs_len;
|
||||
BEValue rhs_len;
|
||||
llvm_value_set(&lhs_len, LLVMBuildExtractValue(c->builder, lhs->value, 1, ""), type_usize);
|
||||
llvm_value_set(&rhs_len, LLVMBuildExtractValue(c->builder, rhs->value, 1, ""), type_usize);
|
||||
llvm_value_set(&lhs_len, llvm_emit_extract_value(c, lhs->value, 1), type_usize);
|
||||
llvm_value_set(&rhs_len, llvm_emit_extract_value(c, rhs->value, 1), type_usize);
|
||||
BEValue lhs_value;
|
||||
BEValue rhs_value;
|
||||
llvm_value_set(&lhs_value, LLVMBuildExtractValue(c->builder, lhs->value, 0, ""), array_base_pointer);
|
||||
llvm_value_set(&rhs_value, LLVMBuildExtractValue(c->builder, rhs->value, 0, ""), array_base_pointer);
|
||||
llvm_value_set(&lhs_value, llvm_emit_extract_value(c, lhs->value, 0), array_base_pointer);
|
||||
llvm_value_set(&rhs_value, llvm_emit_extract_value(c, rhs->value, 0), array_base_pointer);
|
||||
BEValue len_match;
|
||||
llvm_emit_comparison(c, &len_match, &lhs_len, &rhs_len, BINARYOP_EQ);
|
||||
|
||||
@@ -3527,7 +3469,7 @@ static inline void llvm_emit_typeofany(GenContext *c, BEValue *be_value, Expr *e
|
||||
}
|
||||
else
|
||||
{
|
||||
llvm_value_set(be_value, LLVMBuildExtractValue(c->builder, be_value->value, 1, ""), type_typeid);
|
||||
llvm_value_set(be_value, llvm_emit_extract_value(c, be_value->value, 1), type_typeid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4082,13 +4024,6 @@ LLVMValueRef llvm_emit_array_gep_raw(GenContext *c, LLVMValueRef ptr, LLVMTypeRe
|
||||
return llvm_emit_array_gep_raw_index(c, ptr, array_type, llvm_const_int(c, type_usize, index), array_alignment, alignment);
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_emit_array_load(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, unsigned index, AlignSize array_alignment)
|
||||
{
|
||||
AlignSize alignment;
|
||||
LLVMValueRef element_ptr = llvm_emit_array_gep_raw_index(c, ptr, array_type, llvm_const_int(c, type_usize, index), array_alignment, &alignment);
|
||||
return llvm_load(c, LLVMGetElementType(array_type), element_ptr, alignment, "");
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_emit_pointer_gep_raw(GenContext *c, LLVMTypeRef pointee_type, LLVMValueRef ptr, LLVMValueRef offset)
|
||||
{
|
||||
if (LLVMIsConstant(ptr) && LLVMIsConstant(offset))
|
||||
@@ -4848,8 +4783,8 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
|
||||
}
|
||||
|
||||
// 15g. We can now extract { lo, hi } to lo_value and hi_value.
|
||||
LLVMValueRef lo_value = LLVMBuildExtractValue(c->builder, call_value, 0, "");
|
||||
LLVMValueRef hi_value = LLVMBuildExtractValue(c->builder, call_value, 1, "");
|
||||
LLVMValueRef lo_value = llvm_emit_extract_value(c, call_value, 0);
|
||||
LLVMValueRef hi_value = llvm_emit_extract_value(c, call_value, 1);
|
||||
|
||||
// 15h. Store lo_value into the { pad, lo, pad, hi } struct.
|
||||
llvm_store(c, lo, lo_value, alignment);
|
||||
@@ -5171,18 +5106,10 @@ static inline void llvm_emit_failable(GenContext *c, BEValue *be_value, Expr *ex
|
||||
llvm_value_set(be_value, LLVMGetUndef(llvm_get_type(c, type)), type);
|
||||
}
|
||||
|
||||
static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, MemberIndex index, bool *is_const)
|
||||
static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, MemberIndex index)
|
||||
{
|
||||
LLVMValueRef index_value = llvm_const_int(c, type_usize, (uint64_t)index);
|
||||
if (*is_const && LLVMIsConstant(value))
|
||||
{
|
||||
return LLVMConstInsertElement(vector, value, index_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
*is_const = false;
|
||||
return LLVMBuildInsertElement(c->builder, vector, value, index_value, "");
|
||||
}
|
||||
return LLVMBuildInsertElement(c->builder, vector, value, index_value, "");
|
||||
|
||||
}
|
||||
static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *value, Expr *expr)
|
||||
@@ -5195,7 +5122,6 @@ static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *val
|
||||
BEValue val;
|
||||
LLVMValueRef vec_value;
|
||||
|
||||
bool is_const = true;
|
||||
if (expr->expr_kind == EXPR_INITIALIZER_LIST)
|
||||
{
|
||||
vec_value = LLVMGetUndef(llvm_type);
|
||||
@@ -5207,7 +5133,7 @@ static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *val
|
||||
Expr *element = elements[i];
|
||||
llvm_emit_expr(c, &val, element);
|
||||
llvm_value_rvalue(c, &val);
|
||||
vec_value = llvm_update_vector(c, vec_value, val.value, (MemberIndex)i, &is_const);
|
||||
vec_value = llvm_update_vector(c, vec_value, val.value, (MemberIndex)i);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -5226,13 +5152,13 @@ static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *val
|
||||
{
|
||||
case DESIGNATOR_ARRAY:
|
||||
{
|
||||
vec_value = llvm_update_vector(c, vec_value, val.value, element->index, &is_const);
|
||||
vec_value = llvm_update_vector(c, vec_value, val.value, element->index);
|
||||
break;
|
||||
}
|
||||
case DESIGNATOR_RANGE:
|
||||
for (MemberIndex idx = element->index; idx <= element->index_end; idx++)
|
||||
{
|
||||
vec_value = llvm_update_vector(c, vec_value, val.value, idx, &is_const);
|
||||
vec_value = llvm_update_vector(c, vec_value, val.value, idx);
|
||||
}
|
||||
break;
|
||||
case DESIGNATOR_FIELD:
|
||||
@@ -5357,6 +5283,15 @@ static inline void llvm_emit_ptr(GenContext *c, BEValue *value, Expr *expr)
|
||||
llvm_emit_subarray_pointer(c, value, value);
|
||||
}
|
||||
|
||||
static inline void llvm_emit_typeid_kind(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
llvm_emit_expr(c, value, expr->inner_expr);
|
||||
llvm_value_rvalue(c, value);
|
||||
LLVMValueRef ref = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_ptr_type(c, type_char), "");
|
||||
LLVMValueRef kind = llvm_load(c, c->byte_type, ref, 1, "");
|
||||
llvm_value_set(value, kind, expr->type);
|
||||
}
|
||||
|
||||
void llvm_emit_try_unwrap_chain(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
Expr **exprs = expr->try_unwrap_chain_expr;
|
||||
@@ -5428,10 +5363,7 @@ static inline void llvm_emit_argv_to_subarray(GenContext *c, BEValue *value, Exp
|
||||
LLVMTypeRef loop_type = llvm_get_type(c, type_usize);
|
||||
LLVMTypeRef char_ptr_type = llvm_get_ptr_type(c, type_char);
|
||||
LLVMValueRef size = llvm_zext_trunc(c, count, loop_type);
|
||||
LLVMValueRef result = LLVMGetUndef(temp_type);
|
||||
result = LLVMBuildInsertValue(c->builder, result, size, 1, "");
|
||||
result = LLVMBuildInsertValue(c->builder, result, arg_array, 0, "");
|
||||
llvm_value_set(value, result, expr->type);
|
||||
llvm_set_aggregate_two(c, value, expr->type, arg_array, size);
|
||||
|
||||
// Check if zero:
|
||||
BEValue cond;
|
||||
@@ -5518,6 +5450,9 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
case EXPR_PTR:
|
||||
llvm_emit_ptr(c, value, expr);
|
||||
return;
|
||||
case EXPR_TYPEID_KIND:
|
||||
llvm_emit_typeid_kind(c, value, expr);
|
||||
return;
|
||||
case EXPR_BUILTIN:
|
||||
UNREACHABLE;
|
||||
case EXPR_DECL:
|
||||
|
||||
@@ -348,8 +348,8 @@ void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failabl
|
||||
LLVMTypeRef unpadded_type = llvm_get_twostruct(c, lo_type, hi_type);
|
||||
LLVMValueRef composite = LLVMGetUndef(unpadded_type);
|
||||
|
||||
composite = LLVMBuildInsertValue(c->builder, composite, lo_val, 0, "");
|
||||
composite = LLVMBuildInsertValue(c->builder, composite, hi_val, 1, "");
|
||||
composite = llvm_emit_insert_value(c, composite, lo_val, 0);
|
||||
composite = llvm_emit_insert_value(c, composite, hi_val, 1);
|
||||
|
||||
// And return that unpadded result
|
||||
llvm_emit_return_value(c, composite);
|
||||
@@ -682,13 +682,3 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
|
||||
}
|
||||
|
||||
|
||||
void llvm_emit_methods(GenContext *c, Decl **methods)
|
||||
{
|
||||
VECEACH(methods, i)
|
||||
{
|
||||
Decl *decl = methods[i];
|
||||
if (decl->decl_kind == DECL_MACRO) continue;
|
||||
llvm_emit_function_decl(c, decl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -285,7 +285,7 @@ INLINE void llvm_emit_exprid(GenContext *c, BEValue *value, ExprId expr)
|
||||
assert(expr);
|
||||
llvm_emit_expr(c, value, exprptr(expr));
|
||||
}
|
||||
void llvm_emit_local_global_variable_definition(GenContext *c, Decl *decl);
|
||||
|
||||
void llvm_emit_typeid(GenContext *c, BEValue *be_value, Type *type);
|
||||
void llvm_emit_global_variable_init(GenContext *c, Decl *decl);
|
||||
void llvm_set_private_linkage(LLVMValueRef alloc);
|
||||
@@ -321,7 +321,10 @@ LLVMValueRef llvm_emit_lshr_fixed(GenContext *c, LLVMValueRef data, int shift);
|
||||
// -- general --
|
||||
void llvm_emit_local_var_alloca(GenContext *c, Decl *decl);
|
||||
void llvm_emit_local_decl(GenContext *c, Decl *decl, BEValue *value);
|
||||
LLVMValueRef llvm_emit_aggregate_value(GenContext *c, Type *type, ...);
|
||||
|
||||
void llvm_set_aggregate_two(GenContext *c, BEValue *value, Type *type, LLVMValueRef value1, LLVMValueRef value2);
|
||||
LLVMValueRef llvm_emit_aggregate_two(GenContext *c, Type *type, LLVMValueRef value1, LLVMValueRef value2);
|
||||
|
||||
LLVMValueRef llvm_emit_memclear_size_align(GenContext *c, LLVMValueRef ref, uint64_t size, AlignSize align, bool bitcast);
|
||||
void llvm_store_zero(GenContext *c, BEValue *ref);
|
||||
void llvm_emit_memcpy(GenContext *c, LLVMValueRef dest, unsigned dest_align, LLVMValueRef source, unsigned src_align, uint64_t len);
|
||||
@@ -340,7 +343,7 @@ LLVMValueRef llvm_emit_struct_gep_raw(GenContext *context, LLVMValueRef ptr, LLV
|
||||
unsigned struct_alignment, AlignSize *alignment);
|
||||
LLVMValueRef llvm_emit_array_gep_raw(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, unsigned index, AlignSize array_alignment, AlignSize *alignment);
|
||||
LLVMValueRef llvm_emit_array_gep_raw_index(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, LLVMValueRef index, AlignSize array_alignment, AlignSize *alignment);
|
||||
LLVMValueRef llvm_emit_array_load(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, unsigned index, AlignSize array_alignment);
|
||||
|
||||
LLVMValueRef llvm_emit_pointer_gep_raw(GenContext *c, LLVMTypeRef pointee_type, LLVMValueRef ptr, LLVMValueRef offset);
|
||||
|
||||
LLVMValueRef llvm_emit_pointer_inbounds_gep_raw(GenContext *c, LLVMTypeRef pointee_type, LLVMValueRef ptr, LLVMValueRef offset);
|
||||
@@ -386,6 +389,15 @@ static inline LLVMValueRef decl_failable_ref(Decl *decl)
|
||||
}
|
||||
|
||||
|
||||
static inline LLVMValueRef llvm_emit_insert_value(GenContext *c, LLVMValueRef agg, LLVMValueRef new_value, ArraySize index)
|
||||
{
|
||||
if (LLVMGetTypeKind(LLVMTypeOf(agg)) == LLVMVectorTypeKind)
|
||||
{
|
||||
LLVMValueRef index_val = llvm_const_int(c, type_usize, index);
|
||||
return LLVMBuildInsertElement(c->builder, agg, new_value, index_val, "");
|
||||
}
|
||||
return LLVMBuildInsertValue(c->builder, agg, new_value, index, "");
|
||||
}
|
||||
|
||||
static inline LLVMValueRef llvm_emit_store(GenContext *c, Decl *decl, LLVMValueRef value)
|
||||
{
|
||||
|
||||
@@ -55,7 +55,6 @@ void gencontext_begin_module(GenContext *c)
|
||||
|
||||
c->block_global_unique_count = 0;
|
||||
c->ast_alloca_addr_space = target_alloca_addr_space();
|
||||
|
||||
VECEACH(global_context.type, i)
|
||||
{
|
||||
Type *type = global_context.type[i];
|
||||
|
||||
@@ -681,14 +681,14 @@ static LLVMValueRef llvm_get_introspection_for_fault(GenContext *c, Type *type)
|
||||
val->backend_ref = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid));
|
||||
}
|
||||
LLVMTypeRef element_type = llvm_get_type(c, type_typeid);
|
||||
LLVMTypeRef elements_type = LLVMArrayType(element_type, elements);
|
||||
LLVMValueRef start = LLVMConstNull(elements_type);
|
||||
LLVMValueRef* values = elements ? MALLOC(sizeof(LLVMValueRef) * elements) : NULL;
|
||||
for (unsigned i = 0; i < elements; i++)
|
||||
{
|
||||
start = LLVMConstInsertValue(start, LLVMConstBitCast(fault_vals[i]->backend_ref, element_type), &i, 1);
|
||||
values[i] = LLVMConstBitCast(fault_vals[i]->backend_ref, element_type);
|
||||
}
|
||||
LLVMValueRef values[] = { llvm_const_int(c, type_char, INTROSPECT_TYPE_FAULT ), llvm_const_int(c, type_usize, elements), start };
|
||||
LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, 3, false);
|
||||
LLVMValueRef svalues[] = { llvm_const_int(c, type_char, INTROSPECT_TYPE_FAULT ), llvm_const_int(c, type_usize, elements),
|
||||
LLVMConstArray(element_type, values, elements) };
|
||||
LLVMValueRef strukt = LLVMConstStructInContext(c->context, svalues, 3, false);
|
||||
return llvm_get_introspection_weak(c, type, decl_get_extname(decl), strukt);
|
||||
}
|
||||
|
||||
@@ -711,9 +711,9 @@ LLVMValueRef llvm_get_typeid(GenContext *c, Type *type)
|
||||
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->array.base,
|
||||
llvm_const_int(c, type_usize, type->array.len));
|
||||
case TYPE_SUBARRAY:
|
||||
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->array.base, NULL);
|
||||
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_SUBARRAY, type, type->array.base, NULL);
|
||||
case TYPE_POINTER:
|
||||
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->pointer, NULL);
|
||||
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_POINTER, type, type->pointer, NULL);
|
||||
case TYPE_DISTINCT:
|
||||
return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_DISTINCT, type, type->decl->distinct_decl.base_type, NULL);
|
||||
case TYPE_ENUM:
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#define IF_TRY_CATCH_PREC (PREC_AND + 1)
|
||||
typedef Expr *(*ParseFn)(ParseContext *context, Expr *);
|
||||
static Expr *parse_rethrow_expr(ParseContext *c, Expr *left);
|
||||
static Expr *parse_expr_or_type_prec(ParseContext *c, TypeInfo **type_ref, Precedence prec);
|
||||
|
||||
typedef struct
|
||||
|
||||
@@ -835,6 +835,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
|
||||
case EXPR_COMPILER_CONST:
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_TYPEID_KIND:
|
||||
UNREACHABLE
|
||||
case EXPR_POST_UNARY:
|
||||
return recursive_may_narrow_float(expr->unary_expr.expr, type);
|
||||
@@ -987,6 +988,7 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
|
||||
case EXPR_COMPILER_CONST:
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_TYPEID_KIND:
|
||||
UNREACHABLE
|
||||
case EXPR_POST_UNARY:
|
||||
return recursive_may_narrow_int(expr->unary_expr.expr, type);
|
||||
@@ -1158,6 +1160,27 @@ bool cast_implicit(Expr *expr, Type *to_type)
|
||||
if (expr->expr_kind == EXPR_CAST) expr->cast_expr.implicit = true;
|
||||
return true;
|
||||
}
|
||||
static bool arr_to_vec(Expr *expr, Type *to_type)
|
||||
{
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_ARRVEC, to_type)) return true;
|
||||
|
||||
assert(expr->const_expr.const_kind == CONST_LIST);
|
||||
ConstInitializer *list = expr->const_expr.list;
|
||||
list->type = to_type;
|
||||
expr->type = to_type;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool vec_to_arr(Expr *expr, Type *to_type)
|
||||
{
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_VECARR, to_type)) return true;
|
||||
|
||||
assert(expr->const_expr.const_kind == CONST_LIST);
|
||||
ConstInitializer *list = expr->const_expr.list;
|
||||
list->type = to_type;
|
||||
expr->type = to_type;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool err_to_anyerr(Expr *expr, Type *to_type)
|
||||
{
|
||||
@@ -1280,7 +1303,7 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type)
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
return false;
|
||||
case TYPE_ARRAY:
|
||||
if (to->type_kind == TYPE_VECTOR) return insert_cast(expr, CAST_ARRVEC, to_type);
|
||||
if (to->type_kind == TYPE_VECTOR) return arr_to_vec(expr, to_type);
|
||||
FALLTHROUGH;
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
@@ -1295,7 +1318,7 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type)
|
||||
if (to->type_kind == TYPE_BOOL) return subarray_to_bool(expr);
|
||||
break;
|
||||
case TYPE_VECTOR:
|
||||
if (to->type_kind == TYPE_ARRAY) return insert_cast(expr, CAST_VECARR, to);
|
||||
if (to->type_kind == TYPE_ARRAY) return vec_to_arr(expr, to_type);
|
||||
break;
|
||||
}
|
||||
UNREACHABLE
|
||||
|
||||
@@ -372,6 +372,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
||||
return expr_list_is_constant_eval(expr->expression_list, eval_kind);
|
||||
case EXPR_FAILABLE:
|
||||
case EXPR_GROUP:
|
||||
case EXPR_TYPEID_KIND:
|
||||
expr = expr->inner_expr;
|
||||
goto RETRY;
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
@@ -1030,7 +1031,7 @@ static inline bool sema_expr_analyse_hash_identifier(SemaContext *context, Expr
|
||||
|
||||
expr_replace(expr, expr_macro_copy(decl->var.init_expr));
|
||||
REMINDER("Remove analysis for hash");
|
||||
if (!sema_analyse_expr(decl->var.hash_var.context, expr))
|
||||
if (!sema_analyse_expr_lvalue(decl->var.hash_var.context, expr))
|
||||
{
|
||||
// Poison the decl so we don't evaluate twice.
|
||||
decl_poison(decl);
|
||||
@@ -1635,20 +1636,30 @@ static inline Type *unify_returns(SemaContext *context)
|
||||
bool all_returns_need_casts = false;
|
||||
Type *common_type = NULL;
|
||||
|
||||
bool only_has_rethrow = true;
|
||||
bool failable = false;
|
||||
bool no_return = true;
|
||||
// 1. Loop through the returns.
|
||||
VECEACH(context->returns, i)
|
||||
{
|
||||
Ast *return_stmt = context->returns[i];
|
||||
if (!return_stmt)
|
||||
{
|
||||
common_type = common_type ? type_find_max_type(common_type, type_anyfail) : type_anyfail;
|
||||
failable = true;
|
||||
continue;
|
||||
}
|
||||
only_has_rethrow = false;
|
||||
no_return = false;
|
||||
Expr *ret_expr = return_stmt->return_stmt.expr;
|
||||
Type *rtype = ret_expr ? ret_expr->type : type_void;
|
||||
|
||||
if (type_is_failable_any(rtype))
|
||||
{
|
||||
failable = true;
|
||||
continue;
|
||||
}
|
||||
if (type_is_failable(rtype))
|
||||
{
|
||||
failable = true;
|
||||
rtype = type_no_fail(rtype);
|
||||
}
|
||||
// 2. If we have no common type, set to the return type.
|
||||
if (!common_type)
|
||||
{
|
||||
@@ -1676,19 +1687,31 @@ static inline Type *unify_returns(SemaContext *context)
|
||||
all_returns_need_casts = true;
|
||||
}
|
||||
|
||||
// If we have no return and only rethrows, then the type is "void!"
|
||||
if (common_type == type_anyfail && only_has_rethrow) common_type = type_get_failable(type_void);
|
||||
// If we have no return (or only anyfail)
|
||||
if (!common_type)
|
||||
{
|
||||
assert(!all_returns_need_casts && "We should never need casts here.");
|
||||
// A failable?
|
||||
if (failable)
|
||||
{
|
||||
// If there are only implicit returns, then we assume void!, otherwise it's an "anyfail"
|
||||
return no_return ? type_get_failable(type_void) : type_anyfail;
|
||||
}
|
||||
// No failable => void.
|
||||
return type_void;
|
||||
}
|
||||
|
||||
// 7. Insert casts.
|
||||
if (all_returns_need_casts)
|
||||
{
|
||||
assert(!type_is_failable_type(common_type));
|
||||
VECEACH(context->returns, i)
|
||||
{
|
||||
Ast *return_stmt = context->returns[i];
|
||||
if (!return_stmt) continue;
|
||||
Expr *ret_expr = return_stmt->return_stmt.expr;
|
||||
// 8. All casts should work.
|
||||
if (!cast_implicit(ret_expr, type_no_fail(common_type)))
|
||||
if (!cast_implicit(ret_expr, common_type))
|
||||
{
|
||||
assert(false);
|
||||
return NULL;
|
||||
@@ -1696,8 +1719,7 @@ static inline Type *unify_returns(SemaContext *context)
|
||||
}
|
||||
}
|
||||
|
||||
// 8. On no common type -> return void
|
||||
return common_type ? common_type : type_void;
|
||||
return type_get_opt_fail(common_type, failable);
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_func_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool failable)
|
||||
@@ -1834,6 +1856,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
{
|
||||
if (type_is_failable(rtype))
|
||||
{
|
||||
failable = true;
|
||||
rtype = type_no_fail(rtype);
|
||||
}
|
||||
else
|
||||
@@ -3007,6 +3030,84 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_const && type_is_integer(canonical))
|
||||
{
|
||||
TypeKind kind = canonical->type_kind;
|
||||
if (name == kw_min)
|
||||
{
|
||||
expr->expr_kind = EXPR_CONST;
|
||||
expr->const_expr.const_kind = CONST_INTEGER;
|
||||
expr->type = parent->type;
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
expr->const_expr.ixx.type = kind;
|
||||
switch (kind)
|
||||
{
|
||||
case TYPE_I8:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0xFF };
|
||||
break;
|
||||
case TYPE_I16:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0xFFFF };
|
||||
break;
|
||||
case TYPE_I32:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0xFFFFFFFFLL };
|
||||
break;
|
||||
case TYPE_I64:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, ~((uint64_t)0) };
|
||||
break;
|
||||
case TYPE_I128:
|
||||
expr->const_expr.ixx.i = (Int128){ ~((uint64_t)0), ~((uint64_t)0) };
|
||||
break;
|
||||
default:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0 };
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (name == kw_max)
|
||||
{
|
||||
expr->expr_kind = EXPR_CONST;
|
||||
expr->const_expr.const_kind = CONST_INTEGER;
|
||||
expr->type = parent->type;
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
expr->const_expr.ixx.type = kind;
|
||||
switch (kind)
|
||||
{
|
||||
case TYPE_I8:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0x7F };
|
||||
break;
|
||||
case TYPE_I16:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0x7FFF };
|
||||
break;
|
||||
case TYPE_I32:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0x7FFFFFFFLL };
|
||||
break;
|
||||
case TYPE_I64:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0x7FFFFFFFFFFFFFFFLL };
|
||||
break;
|
||||
case TYPE_I128:
|
||||
expr->const_expr.ixx.i = (Int128){ 0x7FFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL };
|
||||
break;
|
||||
case TYPE_U8:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0xFF };
|
||||
break;
|
||||
case TYPE_U16:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0xFFFF };
|
||||
break;
|
||||
case TYPE_U32:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0xFFFFFFFFLL };
|
||||
break;
|
||||
case TYPE_U64:
|
||||
expr->const_expr.ixx.i = (Int128){ 0, 0xFFFFFFFFFFFFFFFFLL };
|
||||
break;
|
||||
case TYPE_U128:
|
||||
expr->const_expr.ixx.i = (Int128){ 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL };
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 3. Handle float.nan, double.inf etc
|
||||
if (!is_const && type_is_float(canonical))
|
||||
{
|
||||
@@ -3226,6 +3327,22 @@ CHECK_DEEPER:
|
||||
}
|
||||
}
|
||||
|
||||
if (kw == kw_kind && flat_type->type_kind == TYPE_TYPEID)
|
||||
{
|
||||
Module *module = global_context_find_module(kw_std__core__types);
|
||||
Decl *type_kind = module ? module_find_symbol(module, kw_typekind) : NULL;
|
||||
Type *type_for_kind = type_kind ? type_kind->type : type_char;
|
||||
if (current_parent->expr_kind == EXPR_CONST)
|
||||
{
|
||||
unsigned val = type_get_introspection_kind(current_parent->const_expr.typeid->type_kind);
|
||||
expr_rewrite_to_int_const(expr, type_for_kind, val, false);
|
||||
return true;
|
||||
}
|
||||
expr->expr_kind = EXPR_TYPEID_KIND;
|
||||
expr->inner_expr = parent;
|
||||
expr->type = type_for_kind;
|
||||
return true;
|
||||
}
|
||||
// Hard coded ptr on subarrays and variant
|
||||
if (kw == kw_ptr)
|
||||
{
|
||||
@@ -4844,7 +4961,7 @@ static bool sema_expr_analyse_add(SemaContext *context, Expr *expr, Expr *left,
|
||||
right_type = type_no_fail(right->type)->canonical;
|
||||
|
||||
assert(!cast_to_iptr);
|
||||
// 4. Do an binary arithmetic promotion
|
||||
// 4. Do a binary arithmetic promotion
|
||||
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot do the addition %s + %s."))
|
||||
{
|
||||
return false;
|
||||
@@ -6006,16 +6123,19 @@ static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context->rtype && context->rtype->type_kind != TYPE_FAILABLE)
|
||||
{
|
||||
SEMA_ERROR(expr, "This expression implicitly returns with a failable result, but the function does not allow failable results. Did you mean to use 'else' instead?");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context->active_scope.flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO))
|
||||
{
|
||||
vec_add(context->returns, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context->rtype && context->rtype->type_kind != TYPE_FAILABLE)
|
||||
{
|
||||
SEMA_ERROR(expr, "This expression implicitly returns with a failable result, but the function does not allow failable results. Did you mean to use 'else' instead?");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -6823,6 +6943,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
|
||||
case EXPR_CATCH_UNWRAP:
|
||||
case EXPR_PTR:
|
||||
case EXPR_VARIANTSWITCH:
|
||||
case EXPR_TYPEID_KIND:
|
||||
UNREACHABLE
|
||||
case EXPR_STRINGIFY:
|
||||
if (!sema_expr_analyse_ct_stringify(context, expr)) return false;
|
||||
|
||||
@@ -1677,24 +1677,6 @@ static inline bool sema_check_type_case(SemaContext *context, Type *switch_type,
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline ExprConst *flatten_enum_const(Expr *expr)
|
||||
{
|
||||
ExprConst *const_expr = &expr->const_expr;
|
||||
if (const_expr->const_kind == CONST_ENUM)
|
||||
{
|
||||
const_expr->const_kind = CONST_INTEGER;
|
||||
|
||||
Decl *enum_val = const_expr->enum_val;
|
||||
TODO
|
||||
/*
|
||||
Expr *enum_expr = exprptr(enum_val->enum_constant.ordinal2);
|
||||
assert(enum_expr->expr_kind == EXPR_CONST);
|
||||
ExprConst *enum_const = &enum_expr->const_expr;
|
||||
assert(enum_const->const_kind == CONST_INTEGER);
|
||||
*const_expr = *enum_const;*/
|
||||
}
|
||||
return const_expr;
|
||||
}
|
||||
static inline bool sema_check_value_case(SemaContext *context, Type *switch_type, Ast *case_stmt, Ast **cases, unsigned index, bool *if_chained, bool *max_ranged)
|
||||
{
|
||||
assert(switch_type);
|
||||
|
||||
@@ -40,6 +40,9 @@ const char *attribute_list[NUMBER_OF_ATTRIBUTES];
|
||||
const char *builtin_list[NUMBER_OF_BUILTINS];
|
||||
|
||||
const char *kw_std__core;
|
||||
const char *kw_std__core__types;
|
||||
const char *kw_typekind;
|
||||
|
||||
const char *kw_in;
|
||||
const char *kw_out;
|
||||
const char *kw_inout;
|
||||
@@ -51,6 +54,7 @@ const char *kw_return;
|
||||
const char *kw_type;
|
||||
const char *kw_inf;
|
||||
const char *kw_inline;
|
||||
const char *kw_kind;
|
||||
const char *kw_elementat;
|
||||
const char *kw_elementref;
|
||||
const char *kw_elementset;
|
||||
@@ -127,8 +131,12 @@ void symtab_init(uint32_t capacity)
|
||||
kw_FILE = KW_DEF("FILE");
|
||||
kw_FUNC = KW_DEF("FUNC");
|
||||
|
||||
type = TOKEN_TYPE_IDENT;
|
||||
kw_typekind = KW_DEF("TypeKind");
|
||||
|
||||
type = TOKEN_IDENT;
|
||||
kw_std__core = KW_DEF("std::core");
|
||||
kw_std__core__types = KW_DEF("std::core::types");
|
||||
kw_sizeof = KW_DEF("sizeof");
|
||||
kw_in = KW_DEF("in");
|
||||
kw_out = KW_DEF("out");
|
||||
@@ -140,6 +148,7 @@ void symtab_init(uint32_t capacity)
|
||||
kw_type = KW_DEF("type");
|
||||
kw_inf = KW_DEF("inf");
|
||||
kw_inline = KW_DEF("inline");
|
||||
kw_kind = KW_DEF("kind");
|
||||
kw_elementat = KW_DEF("elementat");
|
||||
kw_elementref = KW_DEF("elementref");
|
||||
kw_elementset = KW_DEF("elementset");
|
||||
|
||||
@@ -37,7 +37,6 @@ static void type_dump(LLVMTargetDataRef llvm_target_data, LLVMTypeRef type)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void llvm_dump(void)
|
||||
{
|
||||
static char* archs[] = {
|
||||
|
||||
@@ -1456,15 +1456,6 @@ Type *type_decay_array_pointer(Type *type)
|
||||
}
|
||||
Type *type_find_max_type(Type *type, Type *other)
|
||||
{
|
||||
if (type == type_anyfail)
|
||||
{
|
||||
return type_get_opt_fail(other, true);
|
||||
}
|
||||
if (other == type_anyfail)
|
||||
{
|
||||
return type_get_failable(type);
|
||||
}
|
||||
|
||||
type = type->canonical;
|
||||
other = other->canonical;
|
||||
|
||||
@@ -1597,4 +1588,73 @@ Type *type_find_common_ancestor(Type *left, Type *right)
|
||||
if (right == left_types[i]) return right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned type_get_introspection_kind(TypeKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case TYPE_POISONED:
|
||||
return 0;
|
||||
case TYPE_VOID:
|
||||
return INTROSPECT_TYPE_VOID;
|
||||
case TYPE_BOOL:
|
||||
return INTROSPECT_TYPE_BOOL;
|
||||
case TYPE_I8:
|
||||
case TYPE_I16:
|
||||
case TYPE_I32:
|
||||
case TYPE_I64:
|
||||
case TYPE_I128:
|
||||
return INTROSPECT_TYPE_SIGNED_INT;
|
||||
case TYPE_U8:
|
||||
case TYPE_U16:
|
||||
case TYPE_U32:
|
||||
case TYPE_U64:
|
||||
case TYPE_U128:
|
||||
return INTROSPECT_TYPE_UNSIGNED_INT;
|
||||
case TYPE_F16:
|
||||
case TYPE_F32:
|
||||
case TYPE_F64:
|
||||
case TYPE_F128:
|
||||
return INTROSPECT_TYPE_FLOAT;
|
||||
case TYPE_ANY:
|
||||
return INTROSPECT_TYPE_VARIANT;
|
||||
case TYPE_ANYERR:
|
||||
return INTROSPECT_TYPE_ANYERR;
|
||||
case TYPE_TYPEID:
|
||||
return INTROSPECT_TYPE_TYPEID;
|
||||
case TYPE_POINTER:
|
||||
return INTROSPECT_TYPE_POINTER;
|
||||
case TYPE_ENUM:
|
||||
return INTROSPECT_TYPE_ENUM;
|
||||
case TYPE_FUNC:
|
||||
return INTROSPECT_TYPE_FUNC;
|
||||
case TYPE_STRUCT:
|
||||
return INTROSPECT_TYPE_STRUCT;
|
||||
case TYPE_UNION:
|
||||
return INTROSPECT_TYPE_UNION;
|
||||
case TYPE_BITSTRUCT:
|
||||
return INTROSPECT_TYPE_BITSTRUCT;
|
||||
case TYPE_FAULTTYPE:
|
||||
return INTROSPECT_TYPE_FAULT;
|
||||
case TYPE_TYPEDEF:
|
||||
UNREACHABLE
|
||||
case TYPE_DISTINCT:
|
||||
return INTROSPECT_TYPE_DISTINCT;
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
return INTROSPECT_TYPE_ARRAY;
|
||||
case TYPE_SUBARRAY:
|
||||
return INTROSPECT_TYPE_SUBARRAY;
|
||||
case TYPE_VECTOR:
|
||||
return INTROSPECT_TYPE_VECTOR;
|
||||
case TYPE_UNTYPED_LIST:
|
||||
case TYPE_FAILABLE_ANY:
|
||||
case TYPE_TYPEINFO:
|
||||
case TYPE_FAILABLE:
|
||||
UNREACHABLE
|
||||
return 0;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.2.7"
|
||||
#define COMPILER_VERSION "0.2.8"
|
||||
@@ -76,27 +76,27 @@ entry:
|
||||
%5 = bitcast [3 x i32]* %literal to i32*
|
||||
%6 = insertvalue %"int[]" undef, i32* %5, 0
|
||||
%7 = insertvalue %"int[]" %6, i64 3, 1
|
||||
%len = extractvalue %"int[]" %7, 1
|
||||
%not = icmp eq i64 %len, 0
|
||||
%8 = zext i1 %not to i8
|
||||
store i8 %8, i8* %x, align 1
|
||||
%9 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 0
|
||||
store i32 0, i32* %9, align 4
|
||||
%10 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 1
|
||||
%8 = extractvalue %"int[]" %7, 1
|
||||
%not = icmp eq i64 %8, 0
|
||||
%9 = zext i1 %not to i8
|
||||
store i8 %9, i8* %x, align 1
|
||||
%10 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 0
|
||||
store i32 0, i32* %10, align 4
|
||||
%11 = bitcast %Baz* %z to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %11, i8 0, i64 8, i1 false)
|
||||
%11 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 1
|
||||
store i32 0, i32* %11, align 4
|
||||
%12 = bitcast %Baz* %z to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %12, i8 0, i64 8, i1 false)
|
||||
store [0 x i32] zeroinitializer, [0 x i32]* %literal1, align 4
|
||||
%12 = bitcast [0 x i32]* %literal1 to i32*
|
||||
%13 = insertvalue %"int[]" undef, i32* %12, 0
|
||||
%14 = insertvalue %"int[]" %13, i64 0, 1
|
||||
store %"int[]" %14, %"int[]"* %sub, align 8
|
||||
%13 = bitcast [0 x i32]* %literal1 to i32*
|
||||
%14 = insertvalue %"int[]" undef, i32* %13, 0
|
||||
%15 = insertvalue %"int[]" %14, i64 0, 1
|
||||
store %"int[]" %15, %"int[]"* %sub, align 8
|
||||
store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal2, align 4
|
||||
%15 = bitcast [0 x %Bar]* %literal2 to %Bar*
|
||||
%16 = insertvalue %"Bar[]" undef, %Bar* %15, 0
|
||||
%17 = insertvalue %"Bar[]" %16, i64 0, 1
|
||||
store %"Bar[]" %17, %"Bar[]"* %foo, align 8
|
||||
%18 = bitcast [3 x %Baz]* %baz to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 16 %18, i8 0, i64 24, i1 false)
|
||||
%16 = bitcast [0 x %Bar]* %literal2 to %Bar*
|
||||
%17 = insertvalue %"Bar[]" undef, %Bar* %16, 0
|
||||
%18 = insertvalue %"Bar[]" %17, i64 0, 1
|
||||
store %"Bar[]" %18, %"Bar[]"* %foo, align 8
|
||||
%19 = bitcast [3 x %Baz]* %baz to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 16 %19, i8 0, i64 24, i1 false)
|
||||
ret i32 1
|
||||
}
|
||||
@@ -144,37 +144,37 @@ entry:
|
||||
%34 = bitcast [3 x i32]* %literal6 to i32*
|
||||
%35 = insertvalue %"int[]" undef, i32* %34, 0
|
||||
%36 = insertvalue %"int[]" %35, i64 3, 1
|
||||
%len = extractvalue %"int[]" %36, 1
|
||||
%not = icmp eq i64 %len, 0
|
||||
%37 = zext i1 %not to i8
|
||||
store i8 %37, i8* %xy, align 1
|
||||
%38 = load i8, i8* %xy, align 1
|
||||
%39 = trunc i8 %38 to i1
|
||||
%not7 = xor i1 %39, true
|
||||
%37 = extractvalue %"int[]" %36, 1
|
||||
%not = icmp eq i64 %37, 0
|
||||
%38 = zext i1 %not to i8
|
||||
store i8 %38, i8* %xy, align 1
|
||||
%39 = load i8, i8* %xy, align 1
|
||||
%40 = trunc i8 %39 to i1
|
||||
%not7 = xor i1 %40, true
|
||||
br i1 %not7, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%40 = call i32 @"std::io.println"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0)) #3
|
||||
%41 = call i32 @"std::io.println"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0)) #3
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %if.then, %entry
|
||||
%41 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 0
|
||||
store i32 0, i32* %41, align 4
|
||||
%42 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 1
|
||||
%42 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 0
|
||||
store i32 0, i32* %42, align 4
|
||||
%43 = bitcast %Baz* %z to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %43, i8 0, i64 8, i1 false)
|
||||
%43 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 1
|
||||
store i32 0, i32* %43, align 4
|
||||
%44 = bitcast %Baz* %z to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %44, i8 0, i64 8, i1 false)
|
||||
store [0 x i32] zeroinitializer, [0 x i32]* %literal8, align 4
|
||||
%44 = bitcast [0 x i32]* %literal8 to i32*
|
||||
%45 = insertvalue %"int[]" undef, i32* %44, 0
|
||||
%46 = insertvalue %"int[]" %45, i64 0, 1
|
||||
store %"int[]" %46, %"int[]"* %sub, align 8
|
||||
%45 = bitcast [0 x i32]* %literal8 to i32*
|
||||
%46 = insertvalue %"int[]" undef, i32* %45, 0
|
||||
%47 = insertvalue %"int[]" %46, i64 0, 1
|
||||
store %"int[]" %47, %"int[]"* %sub, align 8
|
||||
store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal9, align 4
|
||||
%47 = bitcast [0 x %Bar]* %literal9 to %Bar*
|
||||
%48 = insertvalue %"Bar[]" undef, %Bar* %47, 0
|
||||
%49 = insertvalue %"Bar[]" %48, i64 0, 1
|
||||
store %"Bar[]" %49, %"Bar[]"* %foo, align 8
|
||||
%50 = bitcast [3 x %Baz]* %baz to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 16 %50, i8 0, i64 24, i1 false)
|
||||
%48 = bitcast [0 x %Bar]* %literal9 to %Bar*
|
||||
%49 = insertvalue %"Bar[]" undef, %Bar* %48, 0
|
||||
%50 = insertvalue %"Bar[]" %49, i64 0, 1
|
||||
store %"Bar[]" %50, %"Bar[]"* %foo, align 8
|
||||
%51 = bitcast [3 x %Baz]* %baz to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 16 %51, i8 0, i64 24, i1 false)
|
||||
ret i32 1
|
||||
}
|
||||
|
||||
49
test/test_suite/macros/macro_failable_return_rethrow.c3t
Normal file
49
test/test_suite/macros/macro_failable_return_rethrow.c3t
Normal file
@@ -0,0 +1,49 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
fn int! xy()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
macro int! foo()
|
||||
{
|
||||
xy()?;
|
||||
return 1;
|
||||
}
|
||||
fn void main()
|
||||
{
|
||||
foo()!!;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test.main() #0 {
|
||||
entry:
|
||||
%error_var = alloca i64, align 8
|
||||
%blockret = alloca i32, align 4
|
||||
%error_var1 = alloca i64, align 8
|
||||
%retparam = alloca i32, align 4
|
||||
%0 = call i64 @test.xy(i32* %retparam)
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after.errcheck, label %error
|
||||
|
||||
error: ; preds = %entry
|
||||
store i64 %0, i64* %error_var1, align 8
|
||||
br label %guard_block
|
||||
|
||||
after.errcheck: ; preds = %entry
|
||||
br label %noerr_block
|
||||
|
||||
guard_block: ; preds = %error
|
||||
ret void
|
||||
|
||||
noerr_block: ; preds = %after.errcheck
|
||||
store i32 1, i32* %blockret, align 4
|
||||
br label %expr_block.exit
|
||||
|
||||
expr_block.exit: ; preds = %noerr_block
|
||||
%1 = load i32, i32* %blockret, align 4
|
||||
br label %noerr_block2
|
||||
|
||||
noerr_block2: ; preds = %expr_block.exit
|
||||
ret void
|
||||
}
|
||||
@@ -70,7 +70,7 @@ fn void main()
|
||||
@.typeid.int = linkonce constant { i8, i16 } { i8 2, i16 32 }, align 2
|
||||
@.typeid.double = linkonce constant { i8, i16 } { i8 4, i16 64 }, align 2
|
||||
@.typeid.variant = linkonce constant { i8 } { i8 7 }, align 1
|
||||
@".typeid.int*" = linkonce constant { i8, i64 } { i8 15, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64) }, align 8
|
||||
@".typeid.int*" = linkonce constant { i8, i64 } { i8 19, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64) }, align 8
|
||||
@.typeid.bool = linkonce constant { i8 } { i8 1 }, align 1
|
||||
|
||||
define void @foo.test(i64 %0, i8* %1) #0 {
|
||||
|
||||
@@ -74,23 +74,23 @@ entry:
|
||||
store i32 3, ptr %3, align 4
|
||||
%4 = insertvalue %"int[]" undef, ptr %literal, 0
|
||||
%5 = insertvalue %"int[]" %4, i64 3, 1
|
||||
%len = extractvalue %"int[]" %5, 1
|
||||
%not = icmp eq i64 %len, 0
|
||||
%6 = zext i1 %not to i8
|
||||
store i8 %6, ptr %x, align 1
|
||||
%7 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 0
|
||||
store i32 0, ptr %7, align 4
|
||||
%8 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 1
|
||||
%6 = extractvalue %"int[]" %5, 1
|
||||
%not = icmp eq i64 %6, 0
|
||||
%7 = zext i1 %not to i8
|
||||
store i8 %7, ptr %x, align 1
|
||||
%8 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 0
|
||||
store i32 0, ptr %8, align 4
|
||||
%9 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 1
|
||||
store i32 0, ptr %9, align 4
|
||||
call void @llvm.memset.p0.i64(ptr align 8 %z, i8 0, i64 8, i1 false)
|
||||
store [0 x i32] zeroinitializer, ptr %literal1, align 4
|
||||
%9 = insertvalue %"int[]" undef, ptr %literal1, 0
|
||||
%10 = insertvalue %"int[]" %9, i64 0, 1
|
||||
store %"int[]" %10, ptr %sub, align 8
|
||||
%10 = insertvalue %"int[]" undef, ptr %literal1, 0
|
||||
%11 = insertvalue %"int[]" %10, i64 0, 1
|
||||
store %"int[]" %11, ptr %sub, align 8
|
||||
store [0 x %Bar] zeroinitializer, ptr %literal2, align 4
|
||||
%11 = insertvalue %"Bar[]" undef, ptr %literal2, 0
|
||||
%12 = insertvalue %"Bar[]" %11, i64 0, 1
|
||||
store %"Bar[]" %12, ptr %foo, align 8
|
||||
%12 = insertvalue %"Bar[]" undef, ptr %literal2, 0
|
||||
%13 = insertvalue %"Bar[]" %12, i64 0, 1
|
||||
store %"Bar[]" %13, ptr %foo, align 8
|
||||
call void @llvm.memset.p0.i64(ptr align 16 %baz, i8 0, i64 24, i1 false)
|
||||
ret i32 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,33 +138,33 @@ entry:
|
||||
store i32 3, ptr %29, align 4
|
||||
%30 = insertvalue %"int[]" undef, ptr %literal6, 0
|
||||
%31 = insertvalue %"int[]" %30, i64 3, 1
|
||||
%len = extractvalue %"int[]" %31, 1
|
||||
%not = icmp eq i64 %len, 0
|
||||
%32 = zext i1 %not to i8
|
||||
store i8 %32, ptr %xy, align 1
|
||||
%33 = load i8, ptr %xy, align 1
|
||||
%34 = trunc i8 %33 to i1
|
||||
%not7 = xor i1 %34, true
|
||||
%32 = extractvalue %"int[]" %31, 1
|
||||
%not = icmp eq i64 %32, 0
|
||||
%33 = zext i1 %not to i8
|
||||
store i8 %33, ptr %xy, align 1
|
||||
%34 = load i8, ptr %xy, align 1
|
||||
%35 = trunc i8 %34 to i1
|
||||
%not7 = xor i1 %35, true
|
||||
br i1 %not7, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%35 = call i32 @"std::io.println"(ptr @.str.9) #3
|
||||
%36 = call i32 @"std::io.println"(ptr @.str.9) #3
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %if.then, %entry
|
||||
%36 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 0
|
||||
store i32 0, ptr %36, align 4
|
||||
%37 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 1
|
||||
%37 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 0
|
||||
store i32 0, ptr %37, align 4
|
||||
%38 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 1
|
||||
store i32 0, ptr %38, align 4
|
||||
call void @llvm.memset.p0.i64(ptr align 8 %z, i8 0, i64 8, i1 false)
|
||||
store [0 x i32] zeroinitializer, ptr %literal8, align 4
|
||||
%38 = insertvalue %"int[]" undef, ptr %literal8, 0
|
||||
%39 = insertvalue %"int[]" %38, i64 0, 1
|
||||
store %"int[]" %39, ptr %sub, align 8
|
||||
%39 = insertvalue %"int[]" undef, ptr %literal8, 0
|
||||
%40 = insertvalue %"int[]" %39, i64 0, 1
|
||||
store %"int[]" %40, ptr %sub, align 8
|
||||
store [0 x %Bar] zeroinitializer, ptr %literal9, align 4
|
||||
%40 = insertvalue %"Bar[]" undef, ptr %literal9, 0
|
||||
%41 = insertvalue %"Bar[]" %40, i64 0, 1
|
||||
store %"Bar[]" %41, ptr %foo, align 8
|
||||
%41 = insertvalue %"Bar[]" undef, ptr %literal9, 0
|
||||
%42 = insertvalue %"Bar[]" %41, i64 0, 1
|
||||
store %"Bar[]" %42, ptr %foo, align 8
|
||||
call void @llvm.memset.p0.i64(ptr align 16 %baz, i8 0, i64 24, i1 false)
|
||||
ret i32 1
|
||||
}
|
||||
|
||||
49
test/test_suite2/macros/macro_failable_return_rethrow.c3t
Normal file
49
test/test_suite2/macros/macro_failable_return_rethrow.c3t
Normal file
@@ -0,0 +1,49 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
fn int! xy()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
macro int! foo()
|
||||
{
|
||||
xy()?;
|
||||
return 1;
|
||||
}
|
||||
fn void main()
|
||||
{
|
||||
foo()!!;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test.main() #0 {
|
||||
entry:
|
||||
%error_var = alloca i64, align 8
|
||||
%blockret = alloca i32, align 4
|
||||
%error_var1 = alloca i64, align 8
|
||||
%retparam = alloca i32, align 4
|
||||
%0 = call i64 @test.xy(ptr %retparam)
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after.errcheck, label %error
|
||||
|
||||
error: ; preds = %entry
|
||||
store i64 %0, ptr %error_var1, align 8
|
||||
br label %guard_block
|
||||
|
||||
after.errcheck: ; preds = %entry
|
||||
br label %noerr_block
|
||||
|
||||
guard_block: ; preds = %error
|
||||
ret void
|
||||
|
||||
noerr_block: ; preds = %after.errcheck
|
||||
store i32 1, ptr %blockret, align 4
|
||||
br label %expr_block.exit
|
||||
|
||||
expr_block.exit: ; preds = %noerr_block
|
||||
%1 = load i32, ptr %blockret, align 4
|
||||
br label %noerr_block2
|
||||
|
||||
noerr_block2: ; preds = %expr_block.exit
|
||||
ret void
|
||||
}
|
||||
@@ -70,7 +70,7 @@ fn void main()
|
||||
@.typeid.int = linkonce constant { i8, i16 } { i8 2, i16 32 }, align 2
|
||||
@.typeid.double = linkonce constant { i8, i16 } { i8 4, i16 64 }, align 2
|
||||
@.typeid.variant = linkonce constant { i8 } { i8 7 }, align 1
|
||||
@".typeid.int*" = linkonce constant { i8, i64 } { i8 15, i64 ptrtoint (ptr @.typeid.int to i64) }, align 8
|
||||
@".typeid.int*" = linkonce constant { i8, i64 } { i8 19, i64 ptrtoint (ptr @.typeid.int to i64) }, align 8
|
||||
@.typeid.bool = linkonce constant { i8 } { i8 1 }, align 1
|
||||
|
||||
define void @foo.test(i64 %0, ptr %1) #0 {
|
||||
|
||||
Reference in New Issue
Block a user