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:
Christoffer Lerno
2022-07-06 16:41:52 +02:00
committed by GitHub
parent bb28f6e61c
commit c8a614e43f
30 changed files with 1099 additions and 365 deletions

View File

@@ -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
View 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
View 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);
}

View File

@@ -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:

View File

@@ -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);

View File

@@ -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:

View File

@@ -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

View File

@@ -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
{

View File

@@ -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)

View File

@@ -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:

View File

@@ -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);
}
}

View File

@@ -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)
{

View File

@@ -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];

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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");

View File

@@ -37,7 +37,6 @@ static void type_dump(LLVMTargetDataRef llvm_target_data, LLVMTypeRef type)
}
void llvm_dump(void)
{
static char* archs[] = {

View File

@@ -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
}

View File

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

View File

@@ -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
}

View File

@@ -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
}

View 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
}

View File

@@ -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 {

View File

@@ -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
}
}

View File

@@ -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
}

View 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
}

View File

@@ -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 {