Panic function that may be redefined. Trap and stacktrace builtins. Bug using builtin fixed. Fixes to using $$LINE and friends. Produces a stacktrace on error.

This commit is contained in:
Christoffer Lerno
2022-03-18 08:57:15 +01:00
committed by Christoffer Lerno
parent 3490814d73
commit 6789fab93c
26 changed files with 433 additions and 311 deletions

View File

@@ -10,9 +10,44 @@ macro scope(&variable; @body) @autoimport
@body();
}
extern fn void printf(char*, ...);
struct CallstackElement
{
CallstackElement* prev;
char* function;
char* file;
uint line;
}
fn void panic(char* message, char *file, char *function, uint line) @autoimport
{
CallstackElement* stack = $$stacktrace();
$if ($defined(libc::stderr) && $defined(libc::fprintf)):
if (stack) stack = stack.prev;
if (stack)
{
libc::fprintf(@libc::stderr(), "\nERROR: '%s'\n", message);
}
else
{
libc::fprintf(@libc::stderr(), "\nERROR: '%s', function %s (%s:%d)\n", message, function, file, line);
}
while (stack)
{
libc::fprintf(@libc::stderr(), " at function %s (%s:%u)\n", stack.function, stack.file, stack.line);
stack = stack.prev;
}
$endif;
$$trap();
}
macro unreachable($string = "Unreachable statement reached.") @autoimport @noreturn
{
assert(false, $string);
panic($string, $$FILE, $$FUNC, $$LINE);
$$unreachable();
}
/*

View File

@@ -26,6 +26,5 @@ struct VarArrayHeader
usize size;
usize capacity;
void *allocator;
}

View File

@@ -540,6 +540,12 @@ static void parse_option(BuildOptions *options)
options->no_stdlib = true;
return;
}
if (match_longopt("panicfn"))
{
if (at_end() || next_is_opt()) error_exit("error: --panicfn needs a function name.");
options->panicfn = next_arg();
return;
}
if (match_longopt("lib"))
{
if (at_end() || next_is_opt()) error_exit("error: --lib needs a directory.");

View File

@@ -227,6 +227,7 @@ typedef struct BuildOptions_
bool emit_bitcode;
bool test_mode;
bool no_stdlib;
const char *panicfn;
RelocModel reloc_model;
X86VectorCapability x86_vector_capability;
bool print_keywords;
@@ -278,6 +279,7 @@ typedef struct
CompilerBackend backend;
uint32_t symtab_size;
uint32_t switchrange_max_size;
const char *panicfn;
const char *cc;
const char *cflags;
const char **csource_dirs;

View File

@@ -163,6 +163,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
}
target->no_stdlib = options->no_stdlib;
target->emit_llvm = options->emit_llvm;
target->panicfn = options->panicfn;
if (options->x86_vector_capability != X86VECTOR_DEFAULT)
{
target->feature.x86_vector_capability = options->x86_vector_capability;

View File

@@ -120,7 +120,9 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
const char *cpu = get_valid_string(json, "cpu", type, false);
int reloc = get_valid_string_setting(json, "reloc", type, reloc_models, 0, 5, "'none', 'pic', 'PIC', 'pie' or 'PIE'.");
int x86vec = get_valid_string_setting(json, "x86vec", type, vector_capability, 0, 5, "none, mmx, sse, avx or avx512");
const char *panicfn = get_valid_string(json, "panicfn", type, false);
target->panicfn = panicfn;
if (cc) target->cc = cc;
if (cflags) target->cflags = cflags;
if (csource_dirs) target->csource_dirs = csource_dirs;
@@ -156,6 +158,7 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
// Use the fact that they correspond to 0, 1, -1
target->feature.x86_struct_return = get_valid_bool(json, "x86-stack-struct-return", type, target->feature.x86_struct_return);
target->feature.soft_float = get_valid_bool(json, "soft-float", type, target->feature.soft_float);
target->no_stdlib = get_valid_bool(json, "nostdlib", type, false);
}
static void project_add_target(Project *project, BuildTarget *default_target, JSONObject *json, const char *name, const char *type)

View File

@@ -1465,6 +1465,7 @@ typedef struct
DeclTable symbols;
DeclTable generic_symbols;
Path std_module_path;
Decl *panic_fn;
} GlobalContext;
@@ -1645,21 +1646,6 @@ extern const char *kw_LINE;
extern const char *kw_LINEREAL;
extern const char *kw_incr;
extern const char *kw_check_assign;
extern const char *kw_builtin_ceil;
extern const char *kw_builtin_trunc;
extern const char *kw_builtin_sqrt;
extern const char *kw_builtin_cos;
extern const char *kw_builtin_sin;
extern const char *kw_builtin_log;
extern const char *kw_builtin_log2;
extern const char *kw_builtin_log10;
extern const char *kw_builtin_max;
extern const char *kw_builtin_min;
extern const char *kw_builtin_pow;
extern const char *kw_builtin_exp;
extern const char *kw_builtin_fabs;
extern const char *kw_builtin_fma;
extern const char *kw_builtin_cmpxchg;
extern const char *kw_argc;
extern const char *kw_argv;
extern const char *kw_mainstub;
@@ -1675,6 +1661,11 @@ INLINE Expr *exprptrzero(ExprId id)
return id ? exprptr(id) : NULL;
}
INLINE Type *typeinfotype(TypeInfoId id_)
{
return type_infoptr(id_)->type;
}
static inline bool ast_ok(Ast *ast) { return ast == NULL || ast->ast_kind != AST_POISONED; }
static inline bool ast_poison(Ast *ast) { ast->ast_kind = AST_POISONED; return false; }
bool ast_is_not_empty(Ast *ast);
@@ -1987,6 +1978,7 @@ bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type
bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool is_macro, bool failable);
Decl *sema_resolve_symbol_in_current_dynamic_scope(SemaContext *context, const char *symbol);
Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name);
Decl *unit_resolve_parameterized_symbol(CompilationUnit *unit, NameResolve *name_resolve);
Decl *sema_resolve_method(CompilationUnit *unit, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
Decl *sema_find_extension_method_in_module(Module *module, Type *type, const char *method_name);

View File

@@ -133,7 +133,7 @@ void unit_register_external_symbol(CompilationUnit *unit, Decl *decl)
void decl_register(Decl *decl)
{
if (decl->visibility != VISIBLE_PUBLIC) return;
if (decl->visibility != VISIBLE_PUBLIC && decl->visibility != VISIBLE_EXTERN) return;
switch (decl->decl_kind)
{
case DECL_POISONED:

View File

@@ -706,6 +706,9 @@ typedef enum
typedef enum
{
BUILTIN_UNREACHABLE,
BUILTIN_TRAP,
BUILTIN_STACKTRACE,
BUILTIN_CEIL,
BUILTIN_TRUNC,
BUILTIN_SQRT,

View File

@@ -850,6 +850,13 @@ void *llvm_gen(Module *module)
gencontext_init(gen_context, module);
gencontext_begin_module(gen_context);
// Declare the panic function implicitly
Decl *panicfn = gen_context->panicfn;
if (panicfn && panicfn->module != module)
{
llvm_emit_extern_decl(gen_context, panicfn);
}
VECEACH(module->units, j)
{
CompilationUnit *unit = module->units[j];
@@ -857,11 +864,13 @@ void *llvm_gen(Module *module)
gen_context->debug.compile_unit = unit->llvm.debug_compile_unit;
gen_context->debug.file = unit->llvm.debug_file;
VECEACH(unit->external_symbol_list, i)
{
Decl *d = unit->external_symbol_list[i];
// Avoid duplicating symbol
if (d->module == unit->module) continue;
if (d == panicfn) continue;
llvm_emit_extern_decl(gen_context, unit->external_symbol_list[i]);
}
VECEACH(unit->methods, i)

View File

@@ -3590,8 +3590,7 @@ static inline void llvm_emit_force_unwrap_expr(GenContext *c, BEValue *be_value,
// TODO, we should add info about the error.
SourceSpan loc = expr->span;
File *file = source_file_by_id(loc.file_id);
llvm_emit_debug_output(c, "Runtime error force unwrap!", file->name, c->cur_func_decl->extname, loc.row ? loc.row : 1);
llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0);
llvm_emit_panic(c, "Runtime error force unwrap!", file->name, c->cur_func_decl->extname, loc.row ? loc.row : 1);
LLVMBuildUnreachable(c->builder);
c->current_block = NULL;
c->current_block_is_target = NULL;
@@ -4213,12 +4212,12 @@ static void llvm_emit_intrinsic_expr(GenContext *c, unsigned intrinsic, BEValue
LLVMValueRef arg_results[4];
for (unsigned i = 0; i < arguments; i++)
{
llvm_emit_expr(c, be_value, expr->call_expr.arguments[0]);
llvm_emit_expr(c, be_value, expr->call_expr.arguments[i]);
llvm_value_rvalue(c, be_value);
arg_results[i] = be_value->value;
}
LLVMTypeRef call_type = llvm_get_type(c, expr->type);
LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic, &call_type, 1, arg_results, arguments);
LLVMTypeRef call_type = expr->type == type_void ? NULL : llvm_get_type(c, expr->type);
LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic, &call_type, call_type ? 1 : 0, arg_results, arguments);
llvm_value_set(be_value, result, expr->type);
}
@@ -4377,7 +4376,11 @@ unsigned llvm_get_intrinsic(BuiltinFunction func)
switch (func)
{
case BUILTIN_NONE:
case BUILTIN_UNREACHABLE:
case BUILTIN_STACKTRACE:
UNREACHABLE
case BUILTIN_TRAP:
return intrinsic_id.trap;
case BUILTIN_CEIL:
return intrinsic_id.ceil;
case BUILTIN_TRUNC:
@@ -4431,6 +4434,25 @@ LLVMAtomicOrdering llvm_atomic_ordering(Atomicity atomicity)
void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
{
BuiltinFunction func = exprptr(expr->call_expr.function)->builtin_expr.builtin;
if (func == BUILTIN_UNREACHABLE)
{
llvm_value_set(result_value, LLVMBuildUnreachable(c->builder), type_void);
c->current_block = NULL;
c->current_block_is_target = NULL;
LLVMBasicBlockRef after_unreachable = llvm_basic_block_new(c, "after.unreachable");
llvm_emit_block(c, after_unreachable);
return;
}
if (func == BUILTIN_STACKTRACE)
{
if (!c->debug.enable_stacktrace)
{
llvm_value_set(result_value, llvm_get_zero(c, type_voidptr), type_voidptr);
return;
}
llvm_value_set(result_value, llvm_emit_bitcast(c, c->debug.stack_slot, type_voidptr), type_voidptr);
return;
}
if (func == BUILTIN_VOLATILE_STORE)
{
BEValue value;
@@ -4482,11 +4504,18 @@ void llvm_add_call_attributes(GenContext *c, LLVMValueRef call_value, int start_
}
void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
{
if (expr->call_expr.is_builtin)
{
llvm_emit_builtin_call(c, result_value, expr);
return;
}
if (c->debug.stack_slot_row)
{
llvm_store(c, c->debug.stack_slot_row, llvm_const_int(c, type_uint, expr->span.row), type_abi_alignment(type_uint));
}
LLVMTypeRef func_type;
LLVMValueRef func;
BEValue temp_value;

View File

@@ -402,62 +402,98 @@ void llvm_emit_return_implicit(GenContext *c)
llvm_emit_return_abi(c, NULL, &value);
}
void llvm_emit_function_body(GenContext *context, Decl *decl)
void llvm_emit_function_body(GenContext *c, Decl *decl)
{
DEBUG_LOG("Generating function %s.", decl->extname);
assert(decl->backend_ref);
bool emit_debug = llvm_use_debug(context);
LLVMValueRef prev_function = context->function;
LLVMBuilderRef prev_builder = context->builder;
bool emit_debug = llvm_use_debug(c);
LLVMValueRef prev_function = c->function;
LLVMBuilderRef prev_builder = c->builder;
context->error_var = NULL;
context->catch_block = NULL;
context->function = decl->backend_ref;
c->error_var = NULL;
c->catch_block = NULL;
c->function = decl->backend_ref;
if (emit_debug)
{
context->debug.function = LLVMGetSubprogram(context->function);
c->debug.function = LLVMGetSubprogram(c->function);
if (c->debug.enable_stacktrace)
{
scratch_buffer_clear();
scratch_buffer_append(decl->module->name->module);
scratch_buffer_append("::");
scratch_buffer_append(decl->name ? decl->name : "anon");
c->debug.func_name = llvm_emit_zstring(c, scratch_buffer_to_string());
File *file = source_file_by_id(decl->span.file_id);
c->debug.file_name = llvm_emit_zstring(c, file->name);
}
}
context->cur_func_decl = decl;
c->cur_func_decl = decl;
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(context->context, context->function, "entry");
context->current_block = entry;
context->current_block_is_target = true;
context->block_return_exit = NULL;
context->in_block = 0;
context->builder = LLVMCreateBuilderInContext(context->context);
LLVMPositionBuilderAtEnd(context->builder, entry);
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, c->function, "entry");
c->current_block = entry;
c->current_block_is_target = true;
c->block_return_exit = NULL;
c->in_block = 0;
c->builder = LLVMCreateBuilderInContext(c->context);
LLVMPositionBuilderAtEnd(c->builder, entry);
LLVMValueRef alloca_point = LLVMBuildAlloca(context->builder, LLVMInt32TypeInContext(context->context), "alloca_point");
context->alloca_point = alloca_point;
LLVMValueRef alloca_point = LLVMBuildAlloca(c->builder, LLVMInt32TypeInContext(c->context), "alloca_point");
c->alloca_point = alloca_point;
FunctionPrototype *prototype = decl->type->func.prototype;
unsigned arg = 0;
if (emit_debug)
{
llvm_debug_scope_push(context, context->debug.function);
llvm_debug_scope_push(c, c->debug.function);
if (c->debug.enable_stacktrace)
{
LLVMTypeRef slot_type = c->debug.stack_type;
LLVMTypeRef ptr_to_slot_type = LLVMPointerType(slot_type, 0);
if (!c->debug.last_ptr)
{
LLVMValueRef last_stack = c->debug.last_ptr = LLVMAddGlobal(c->module, ptr_to_slot_type, ".$last_stack");
LLVMSetThreadLocal(last_stack, true);
LLVMSetInitializer(last_stack, LLVMConstNull(ptr_to_slot_type));
LLVMSetVisibility(last_stack, LLVMDefaultVisibility);
LLVMSetLinkage(last_stack, LLVMWeakODRLinkage);
}
AlignSize alignment = llvm_abi_alignment(c, slot_type);
c->debug.stack_slot = llvm_emit_alloca(c, slot_type, alignment, ".$stackslot");
AlignSize align_to_use;
LLVMValueRef prev_ptr = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 0, alignment, &align_to_use);
llvm_store(c, prev_ptr, LLVMBuildLoad2(c->builder, ptr_to_slot_type, c->debug.last_ptr, ""), align_to_use);
LLVMValueRef func_name = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 1, alignment, &align_to_use);
llvm_store(c, func_name, c->debug.func_name, align_to_use);
LLVMValueRef file_name = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 2, alignment, &align_to_use);
llvm_store(c, file_name, c->debug.file_name, align_to_use);
c->debug.stack_slot_row = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 3, alignment, &align_to_use);
llvm_store(c, c->debug.last_ptr, c->debug.stack_slot, type_alloca_alignment(type_voidptr));
}
}
context->failable_out = NULL;
context->return_out = NULL;
c->failable_out = NULL;
c->return_out = NULL;
if (prototype->ret_abi_info->kind == ABI_ARG_INDIRECT)
{
if (prototype->is_failable)
{
context->failable_out = LLVMGetParam(context->function, arg++);
c->failable_out = LLVMGetParam(c->function, arg++);
}
else
{
context->return_out = LLVMGetParam(context->function, arg++);
c->return_out = LLVMGetParam(c->function, arg++);
}
}
if (prototype->ret_by_ref_abi_info)
{
assert(!context->return_out);
context->return_out = LLVMGetParam(context->function, arg++);
assert(!c->return_out);
c->return_out = LLVMGetParam(c->function, arg++);
}
@@ -466,49 +502,49 @@ void llvm_emit_function_body(GenContext *context, Decl *decl)
// Generate LLVMValueRef's for all parameters, so we can use them as local vars in code
VECEACH(decl->func_decl.function_signature.params, i)
{
llvm_emit_parameter(context, decl->func_decl.function_signature.params[i], prototype->abi_args[i], &arg, i);
llvm_emit_parameter(c, decl->func_decl.function_signature.params[i], prototype->abi_args[i], &arg, i);
}
}
LLVMSetCurrentDebugLocation2(context->builder, NULL);
LLVMSetCurrentDebugLocation2(c->builder, NULL);
assert(decl->func_decl.body);
AstId current = astptr(decl->func_decl.body)->compound_stmt.first_stmt;
while (current)
{
llvm_emit_stmt(context, ast_next(&current));
llvm_emit_stmt(c, ast_next(&current));
}
if (context->current_block && llvm_basic_block_is_unused(context->current_block))
if (c->current_block && llvm_basic_block_is_unused(c->current_block))
{
LLVMBasicBlockRef prev_block = LLVMGetPreviousBasicBlock(context->current_block);
LLVMDeleteBasicBlock(context->current_block);
context->current_block = prev_block;
LLVMPositionBuilderAtEnd(context->builder, context->current_block);
LLVMBasicBlockRef prev_block = LLVMGetPreviousBasicBlock(c->current_block);
LLVMDeleteBasicBlock(c->current_block);
c->current_block = prev_block;
LLVMPositionBuilderAtEnd(c->builder, c->current_block);
}
// Insert a return (and defer) if needed.
if (context->current_block && !LLVMGetBasicBlockTerminator(context->current_block))
if (c->current_block && !LLVMGetBasicBlockTerminator(c->current_block))
{
llvm_emit_return_implicit(context);
llvm_emit_return_implicit(c);
}
// erase alloca point
if (LLVMGetInstructionParent(alloca_point))
{
context->alloca_point = NULL;
c->alloca_point = NULL;
LLVMInstructionEraseFromParent(alloca_point);
}
LLVMDisposeBuilder(context->builder);
context->builder = NULL;
LLVMDisposeBuilder(c->builder);
c->builder = NULL;
if (llvm_use_debug(context))
if (llvm_use_debug(c))
{
llvm_debug_scope_pop(context);
llvm_debug_scope_pop(c);
}
context->builder = prev_builder;
context->function = prev_function;
c->builder = prev_builder;
c->function = prev_function;
}
static void llvm_emit_param_attributes(GenContext *c, LLVMValueRef function, ABIArgInfo *info, bool is_return, int index, int last_index)

View File

@@ -51,6 +51,7 @@ typedef struct
typedef struct
{
unsigned runtime_version : 8;
bool enable_stacktrace : 1;
LLVMDIBuilderRef builder;
LLVMMetadataRef file;
LLVMMetadataRef compile_unit;
@@ -58,6 +59,12 @@ typedef struct
SourceSpan current_range;
LLVMMetadataRef *lexical_block_stack;
LLVMMetadataRef inlined_at;
LLVMValueRef func_name;
LLVMValueRef file_name;
LLVMValueRef last_ptr;
LLVMTypeRef stack_type;
LLVMValueRef stack_slot;
LLVMValueRef stack_slot_row;
} DebugContext;
@@ -78,6 +85,7 @@ typedef struct
LLVMValueRef error_var;
LLVMTypeRef bool_type;
LLVMTypeRef byte_type;
Decl *panicfn;
Decl *cur_code_decl;
Decl *cur_func_decl;
TypeInfo *current_return_type;
@@ -97,7 +105,6 @@ typedef struct
BEValue retval;
int in_block;
bool current_block_is_target : 1;
bool did_call_stack_save : 1;
LLVMTypeRef type_data_definitions[TYPE_KINDS];
SourceSpan last_emitted_loc;
} GenContext;
@@ -202,6 +209,7 @@ LLVMAttributeRef LLVMCreateTypeAttribute(LLVMContextRef C, unsigned KindID,
LLVMTypeRef type_ref);
#endif
// BE value
void llvm_value_addr(GenContext *c, BEValue *value);
static inline bool llvm_value_is_addr(BEValue *value) { return value->kind == BE_ADDRESS || value->kind == BE_ADDRESS_FAILABLE; }
@@ -305,11 +313,12 @@ 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);
void llvm_emit_memcpy_to_decl(GenContext *c, Decl *decl, LLVMValueRef source, unsigned source_alignment);
void llvm_emit_stmt(GenContext *c, Ast *ast);
LLVMValueRef llvm_emit_zstring(GenContext *c, const char *str);
static inline LLVMValueRef llvm_emit_store(GenContext *context, Decl *decl, LLVMValueRef value);
void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *panic_name, SourceSpan loc);
void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_name, SourceSpan loc);
void llvm_emit_ptr_from_array(GenContext *c, BEValue *value);
void llvm_emit_debug_output(GenContext *c, const char *message, const char *file, const char *func, unsigned line);
void llvm_emit_panic(GenContext *c, const char *message, const char *file, const char *func, unsigned line);
void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failable);
void llvm_emit_return_implicit(GenContext *c);
void llvm_emit_struct_member_ref(GenContext *c, BEValue *struct_ref, BEValue *member_ref, unsigned member_id);

View File

@@ -13,6 +13,7 @@ void gencontext_begin_module(GenContext *c)
c->ir_filename = strformat("%s.ll", result);
c->object_filename = strformat("%s%s", result, get_object_extension());
c->panicfn = global_context.panic_fn;
c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context);
c->machine = llvm_target_machine_create();
c->target_data = LLVMCreateTargetDataLayout(c->machine);
@@ -60,10 +61,23 @@ void gencontext_begin_module(GenContext *c)
global_context.type[i]->backend_debug_type = NULL;
global_context.type[i]->backend_typeid = NULL;
}
if (c->panicfn) c->panicfn->backend_ref = NULL;
if (active_target.debug_info != DEBUG_INFO_NONE)
{
c->debug.runtime_version = 1;
c->debug.builder = LLVMCreateDIBuilder(c->module);
if (active_target.debug_info == DEBUG_INFO_FULL && active_target.feature.safe_mode)
{
c->debug.stack_type = LLVMStructCreateNamed(c->context, ".$callstack");
LLVMTypeRef types[4] = { LLVMPointerType(c->debug.stack_type, 0),
LLVMPointerType(c->byte_type, 0),
LLVMPointerType(c->byte_type, 0),
llvm_get_type(c, type_uint) };
LLVMStructSetBody(c->debug.stack_type, types, 4, false);
c->debug.last_ptr = NULL;
c->debug.enable_stacktrace = true;
}
}
}

View File

@@ -420,7 +420,8 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast)
{
SourceSpan loc = ast->span;
File *file = source_file_by_id(loc.file_id);
llvm_emit_debug_output(c, "Infinite loop found", file->name, c->cur_func_decl->extname, loc.row ? loc.row : 1);
llvm_emit_panic(c, "Infinite loop found", file->name, c->cur_func_decl->extname, loc.row ? loc.row : 1);
LLVMBuildUnreachable(c->builder);
LLVMBasicBlockRef block = llvm_basic_block_new(c, "unreachable_block");
c->current_block = NULL;
@@ -928,19 +929,6 @@ static inline void llvm_emit_assume(GenContext *c, Expr *expr)
static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast)
{
ExprId exprid = ast->assert_stmt.expr;
if (!exprid)
{
File *file = source_file_by_id(ast->span.file_id);
unsigned row = ast->span.row;
llvm_emit_debug_output(c, "Unreachable statement reached.", file->name, c->cur_func_decl->extname, row ? row : 1);
llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0);
LLVMBuildUnreachable(c->builder);
LLVMBasicBlockRef block = llvm_basic_block_new(c, "unreachable_block");
c->current_block = NULL;
c->current_block_is_target = false;
llvm_emit_block(c, block);
return;
}
Expr *assert_expr = exprptr(exprid);
if (active_target.feature.safe_mode)
@@ -964,8 +952,7 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast)
error = "Assert violation";
}
File *file = source_file_by_id(loc.file_id);
llvm_emit_debug_output(c, error, file->name, c->cur_func_decl->name, loc.row ? loc.row : 1);
llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0);
llvm_emit_panic(c, error, file->name, c->cur_func_decl->name, loc.row ? loc.row : 1);
llvm_emit_br(c, on_ok);
llvm_emit_block(c, on_ok);
}
@@ -1032,7 +1019,7 @@ void gencontext_emit_expr_stmt(GenContext *c, Ast *ast)
llvm_emit_expr(c, &value, ast->expr_stmt);
}
static LLVMValueRef llvm_emit_string(GenContext *c, const char *str)
LLVMValueRef llvm_emit_zstring(GenContext *c, const char *str)
{
LLVMTypeRef char_type = llvm_get_type(c, type_char);
unsigned len = (unsigned)strlen(str);
@@ -1047,129 +1034,30 @@ static LLVMValueRef llvm_emit_string(GenContext *c, const char *str)
1, &alignment);
return LLVMBuildBitCast(c->builder, string, LLVMPointerType(char_type, 0), "");
}
void llvm_emit_debug_output(GenContext *c, const char *message, const char *file, const char *func, unsigned line)
void llvm_emit_panic(GenContext *c, const char *message, const char *file, const char *func, unsigned line)
{
if (c->debug.stack_slot_row)
{
llvm_store(c, c->debug.stack_slot_row, llvm_const_int(c, type_uint, line), type_abi_alignment(type_uint));
}
Decl *panicfn = c->panicfn;
if (!panicfn)
{
llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0);
return;
}
LLVMTypeRef char_ptr_type = llvm_get_ptr_type(c, type_char);
LLVMTypeRef cint_type = llvm_get_type(c, type_cint);
const char *name;
int file_index;
int line_index;
int expr_index;
int func_index = -1;
OsType os = platform_target.os;
if (platform_target.arch == ARCH_TYPE_WASM32 || platform_target.arch == ARCH_TYPE_WASM64) os = OS_TYPE_WASI;
switch (os)
{
case OS_TYPE_WIN32:
name = "_assert";
expr_index = 0;
file_index = 1;
line_index = 2;
break;
case OS_DARWIN_TYPES:
name = "__assert_rtn";
func_index = 0;
expr_index = 3;
file_index = 1;
line_index = 2;
break;
case OS_TYPE_SOLARIS:
name = "__assert_c99";
expr_index = 0;
file_index = 1;
line_index = 2;
func_index = 3;
break;
case OS_TYPE_LINUX:
case OS_TYPE_WASI:
name = "__assert_fail";
expr_index = 0;
file_index = 1;
line_index = 2;
func_index = 3;
break;
case OS_TYPE_OPENBSD:
name = "__assert2";
file_index = 0;
line_index = 1;
func_index = 2;
expr_index = 3;
break;
default:
name = "__assert";
expr_index = 0;
file_index = 1;
line_index = 2;
func_index = -1;
break;
}
LLVMTypeRef type;
LLVMTypeRef void_type = LLVMVoidTypeInContext(c->context);
switch (os)
{
case OS_TYPE_WIN32:
case OS_TYPE_FREE_BSD:
case OS_TYPE_DRAGON_FLY:
{
LLVMTypeRef args[3] = { char_ptr_type, char_ptr_type, cint_type };
type = LLVMFunctionType(void_type, args, 3, false);
break;
}
case OS_DARWIN_TYPES:
case OS_TYPE_WASI:
case OS_TYPE_LINUX:
case OS_TYPE_SOLARIS:
{
LLVMTypeRef args[4] = { char_ptr_type, char_ptr_type, cint_type, char_ptr_type };
type = LLVMFunctionType(void_type, args, 4, false);
break;
}
case OS_TYPE_OPENBSD:
{
LLVMTypeRef args[4] = { char_ptr_type, cint_type, char_ptr_type, char_ptr_type };
type = LLVMFunctionType(void_type, args, 4, false);
break;
}
case OS_TYPE_NETBSD:
{
LLVMTypeRef args[3] = { char_ptr_type, cint_type, char_ptr_type };
type = LLVMFunctionType(void_type, args, 3, false);
break;
}
default:
{
LLVMTypeRef args[3] = { char_ptr_type, char_ptr_type, cint_type };
type = LLVMFunctionType(void_type, args, 3, false);
break;
}
}
LLVMValueRef assert_func = LLVMGetNamedFunction(c->module, name);
if (!assert_func)
{
assert_func = LLVMAddFunction(c->module, name, type);
}
LLVMValueRef args[4];
if (func_index == -1)
{
scratch_buffer_clear();
scratch_buffer_append(file);
scratch_buffer_append(" : ");
scratch_buffer_append(func);
file = scratch_buffer_to_string();
}
else
{
args[func_index] = llvm_emit_string(c, func);
}
args[file_index] = llvm_emit_string(c, file);
args[expr_index] = llvm_emit_string(c, message);
args[line_index] = llvm_const_int(c, type_cint, line);
LLVMBuildCall2(c->builder, type, assert_func, args, func_index > -1 ? 4 : 3, "");
LLVMValueRef args[4] = {
llvm_emit_zstring(c, message),
llvm_emit_zstring(c, file),
func ? llvm_emit_zstring(c, func) : LLVMConstNull(char_ptr_type),
llvm_const_int(c, type_uint, line)
};
LLVMBuildCall2(c->builder, llvm_get_type(c, panicfn->type), panicfn->backend_ref, args, 4, "");
}
void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_name, SourceSpan loc)
@@ -1180,8 +1068,7 @@ void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_na
llvm_emit_cond_br(c, value, panic_block, ok_block);
llvm_emit_block(c, panic_block);
File *file = source_file_by_id(loc.file_id);
llvm_emit_debug_output(c, panic_name, file->name, c->cur_func_decl->name, loc.row);
llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0);
llvm_emit_panic(c, panic_name, file->name, c->cur_func_decl->name, loc.row);
llvm_emit_br(c, ok_block);
llvm_emit_block(c, ok_block);
}
@@ -1195,8 +1082,7 @@ void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *pani
llvm_value_set_bool(&be_value, value);
llvm_emit_cond_br(c, &be_value, panic_block, ok_block);
llvm_emit_block(c, panic_block);
llvm_emit_debug_output(c, panic_name, file->name, c->cur_func_decl->name, loc.row ? loc.row : 1);
llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0);
llvm_emit_panic(c, panic_name, file->name, c->cur_func_decl->name, loc.row ? loc.row : 1);
llvm_emit_br(c, ok_block);
llvm_emit_block(c, ok_block);
}

View File

@@ -2092,7 +2092,6 @@ static inline bool parse_doc_contract(ParseContext *c, AstId **docs_ref, DocDire
ASSIGN_EXPR_OR_RET(ast->doc_stmt.contract.decl_exprs, parse_expression_list(c, kind == DOC_DIRECTIVE_CHECKED), false);
const char *end = start;
while (*++end != '\n' && *end != '\0') end++;
end--;
if (end > c->data.lex_start) end = c->data.lex_start;
while (end[-1] == ' ') end--;
scratch_buffer_clear();

View File

@@ -67,51 +67,18 @@ const char *ct_eval_expr(SemaContext *c, const char *expr_type, Expr *inner, Tok
SEMA_ERROR(inner, "'%s' expects a constant string as the argument.", expr_type);
return ct_eval_error;
}
const char *string = inner->const_expr.string.chars;
ArraySize len = inner->const_expr.string.len;
ArraySize path_end = 0;
for (ArraySize i = 0; i < len; i++)
{
char ch = string[i];
if (!is_alphanum_(ch))
{
if (ch == ':' && i > 0 && string[i + 1] == ':')
{
path_end = i;
i++;
}
else
{
SEMA_ERROR(inner, "A valid name was expected here.");
return ct_eval_error;
}
}
}
if (path_end > 0)
{
*path_ref = path_create_from_string(string, path_end, inner->span);
string += path_end + 2;
len -= path_end + 2;
}
if (len == 0)
const char *interned_version = NULL;
if (!splitpathref(inner->const_expr.string.chars, inner->const_expr.string.len, path_ref, &interned_version, type))
{
SEMA_ERROR(inner, "A valid name was expected here.");
return ct_eval_error;
}
const char *interned_version = symtab_find(string, len, fnv1a(string, len), type);
if (!interned_version)
if (*path_ref) (*path_ref)->span = inner->span;
if (*type == TOKEN_INVALID_TOKEN)
{
if (report_missing)
{
if (*path_ref)
{
SEMA_ERROR(inner, "'%s::%.*s' could not be found, did you spell it right?", (*path_ref)->module, (int)len, string);
}
else
{
SEMA_ERROR(inner, "'%.*s' could not be found, did you spell it right?", (int)len, string);
}
SEMA_ERROR(inner, "'%s' could not be found, did you spell it right?", interned_version);
return ct_eval_error;
}
return NULL;
@@ -2209,6 +2176,10 @@ static inline unsigned builtin_expected_args(BuiltinFunction func)
{
switch (func)
{
case BUILTIN_UNREACHABLE:
case BUILTIN_TRAP:
case BUILTIN_STACKTRACE:
return 0;
case BUILTIN_CEIL:
case BUILTIN_TRUNC:
case BUILTIN_SQRT:
@@ -2271,6 +2242,13 @@ static inline bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *ex
Type *rtype = NULL;
switch (func)
{
case BUILTIN_UNREACHABLE:
case BUILTIN_TRAP:
rtype = type_void;
break;
case BUILTIN_STACKTRACE:
rtype = type_voidptr;
break;
case BUILTIN_CEIL:
case BUILTIN_TRUNC:
case BUILTIN_SQRT:
@@ -6221,7 +6199,7 @@ static inline bool sema_expr_analyse_compiler_const(SemaContext *context, Expr *
const char *string = expr->builtin_expr.ident;
if (string == kw_FILE)
{
expr_rewrite_to_string(expr, context->unit->file->name);
expr_rewrite_to_string(expr, context->compilation_unit->file->name);
return true;
}
if (string == kw_FUNC)
@@ -7314,3 +7292,59 @@ bool sema_analyse_inferred_expr(SemaContext *context, Type *infer_type, Expr *ex
return true;
}
bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char **ident_ref, TokenType *type_ref)
{
ArraySize path_end = 0;
*path_ref = NULL;
for (ArraySize i = 0; i < len; i++)
{
char ch = string[i];
if (!is_alphanum_(ch))
{
if (ch == ':' && i > 0 && string[i + 1] == ':')
{
path_end = i;
i++;
}
else
{
return false;
}
}
}
if (path_end > 0)
{
*path_ref = path_create_from_string(string, path_end, INVALID_SPAN);
string += path_end + 2;
len -= path_end + 2;
}
while (len > 0)
{
char c = string[0];
if (c != ' ' && c != '\t') break;
len--;
string++;
}
if (len == 0) return false;
uint32_t hash = FNV1_SEED;
for (size_t i = 0; i < len; i++)
{
char c = string[i];
if (!is_alphanum_(c)) return false;
hash = FNV1a(c, hash);
}
*ident_ref = symtab_find(string, len, hash, type_ref);
if (!*ident_ref)
{
scratch_buffer_clear();
if (*path_ref)
{
scratch_buffer_append_len((*path_ref)->module, (*path_ref)->len);
scratch_buffer_append("::");
}
scratch_buffer_append_len(string, len);
*ident_ref = scratch_buffer_to_string();
*type_ref = TOKEN_INVALID_TOKEN;
}
return true;
}

View File

@@ -42,6 +42,7 @@ void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast);
void context_change_scope_for_label(SemaContext *context, Decl *label);
void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags);
bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *body);
bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char **ident_ref, TokenType *type_ref);
#define PUSH_X(ast, X) AstId _old_##X##_defer = context->X##_defer; AstId _old_##X = context->X##_target; context->X##_target = ast ? astid(ast) : 0; context->X##_defer = context->active_scope.defer_last
#define POP_X(X) context->X##_target = _old_##X; context->X##_defer = _old_##X##_defer

View File

@@ -104,6 +104,17 @@ static inline bool sema_is_path_found(Module **modules, Path *path, bool want_ge
return false;
}
Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name)
{
bool path_found = false;
VECEACH(module_list, i)
{
Module *module = module_list[i];
Decl *decl = sema_find_decl_in_module(module, path, interned_name, &path_found);
if (decl) return decl;
}
return NULL;
}
static Decl *sema_find_decl_in_global(DeclTable *table, Module **module_list, NameResolve *name_resolve, bool want_generic)
{
const char *symbol = name_resolve->symbol;

View File

@@ -2159,8 +2159,6 @@ bool sema_analyse_assert_stmt(SemaContext *context, Ast *statement)
}
return false;
}
statement->assert_stmt.expr = 0;
context->active_scope.jump_end = true;
}
}

View File

@@ -318,6 +318,41 @@ void sema_analysis_run(void)
{
sema_analyze_to_stage(stage);
}
if (active_target.panicfn || !active_target.no_stdlib)
{
const char *panicfn = active_target.panicfn ? active_target.panicfn : "std::builtin::panic";
Path *path;
const char *ident;
TokenType type;
if (!splitpathref(panicfn, strlen(panicfn), &path, &ident, &type) || path == NULL)
{
error_exit("'%s' is not a valid panic function.", panicfn);
}
Decl *decl = sema_find_decl_in_modules(global_context.module_list, path, ident);
if (!decl)
{
error_exit("Panic function '%s::%s' could not be found.", path->module, ident);
}
if (decl->decl_kind != DECL_FUNC)
{
error_exit("'%s::%s' is not a function.", path->module, ident);
}
Decl **params = decl->func_decl.function_signature.params;
if (vec_size(params) != 4 || params[0]->type != type_get_ptr(type_char)
|| params[1]->type != type_get_ptr(type_char)
|| params[2]->type != type_get_ptr(type_char)
|| params[3]->type != type_uint
|| typeinfotype(decl->func_decl.function_signature.returntype) != type_void)
{
error_exit("Expected panic function to have the signature fn void(char*, char*, uint, uint).");
}
global_context.panic_fn = decl;
}
else
{
global_context.panic_fn = NULL;
}
compiler_sema_time = bench_mark();
}

View File

@@ -83,21 +83,6 @@ const char *kw_LINE;
const char *kw_LINEREAL;
const char *kw_incr;
const char *kw_check_assign;
const char *kw_builtin_ceil;
const char *kw_builtin_trunc;
const char *kw_builtin_sqrt;
const char *kw_builtin_cos;
const char *kw_builtin_sin;
const char *kw_builtin_log;
const char *kw_builtin_log2;
const char *kw_builtin_log10;
const char *kw_builtin_max;
const char *kw_builtin_min;
const char *kw_builtin_pow;
const char *kw_builtin_exp;
const char *kw_builtin_fabs;
const char *kw_builtin_fma;
const char *kw_builtin_cmpxchg;
const char *kw_argc;
const char *kw_argv;
const char *kw_mainstub;;
@@ -140,8 +125,14 @@ void symtab_init(uint32_t capacity)
}
// Init some constant idents
TokenType type = TOKEN_IDENT;
#define KW_DEF(x) symtab_add(x, sizeof(x) - 1, fnv1a(x, sizeof(x) - 1), &type)
TokenType type = TOKEN_CONST_IDENT;
kw_LINE = KW_DEF("LINE");
kw_LINEREAL = KW_DEF("LINEREAL");
kw_FILE = KW_DEF("FILE");
kw_FUNC = KW_DEF("FUNC");
type = TOKEN_IDENT;
kw_sizeof = KW_DEF("sizeof");
kw_in = KW_DEF("in");
kw_out = KW_DEF("out");
@@ -171,10 +162,6 @@ void symtab_init(uint32_t capacity)
kw_require = KW_DEF("require");
kw_std = KW_DEF("std");
kw_values = KW_DEF("values");
kw_LINE = KW_DEF("LINE");
kw_LINEREAL = KW_DEF("LINEREAL");
kw_FILE = KW_DEF("FILE");
kw_FUNC = KW_DEF("FUNC");
kw_incr = KW_DEF("incr");
kw_check_assign = KW_DEF("check_assign");
@@ -182,6 +169,9 @@ void symtab_init(uint32_t capacity)
kw_argv = KW_DEF("_$argv");
kw_mainstub = KW_DEF("_$mainstub");
builtin_list[BUILTIN_TRAP] = KW_DEF("trap");
builtin_list[BUILTIN_UNREACHABLE] = KW_DEF("unreachable");
builtin_list[BUILTIN_STACKTRACE] = KW_DEF("stacktrace");
builtin_list[BUILTIN_CEIL] = KW_DEF("ceil");
builtin_list[BUILTIN_TRUNC] = KW_DEF("trunc");
builtin_list[BUILTIN_SIN] = KW_DEF("sin");

View File

@@ -263,6 +263,30 @@ static AlignSize os_arch_max_alignment_of_tls(OsType os, ArchType arch, Environm
return 0;
}
static bool os_target_use_thread_local(OsType os)
{
switch (os)
{
case OS_UNSUPPORTED:
return false;
case OS_TYPE_UNKNOWN:
case OS_TYPE_NONE:
return false;
case OS_TYPE_FREE_BSD:
case OS_TYPE_IOS:
case OS_TYPE_LINUX:
case OS_TYPE_MACOSX:
case OS_TYPE_NETBSD:
case OS_TYPE_OPENBSD:
case OS_TYPE_WIN32:
case OS_TYPE_TVOS:
case OS_TYPE_WATCHOS:
case OS_TYPE_WASI:
return true;
}
UNREACHABLE
}
static bool os_target_signed_c_char_type(OsType os, ArchType arch)
{
switch (arch)
@@ -1293,11 +1317,10 @@ void target_setup(BuildTarget *target)
// TLS should not be supported for:
// ARM Cygwin
// NVPTX
platform_target.tls_supported = true;
platform_target.tls_supported = os_target_use_thread_local(platform_target.os);
platform_target.big_endian = arch_big_endian(platform_target.arch);
platform_target.width_pointer = arch_pointer_bit_width(platform_target.os, platform_target.arch);
platform_target.alloca_address_space = 0;
platform_target.object_format = object_format_from_os(platform_target.os);
platform_target.int128 = os_target_supports_int128(platform_target.os, platform_target.arch);

View File

@@ -15,22 +15,27 @@ fn void test()
// #expect: unreachable.ll
%x = alloca i32
%0 = call i32 @unreachable.foo()
store i32 %0, i32* %x
%1 = load i32, i32* %x
%gt = icmp sgt i32 %1, 0
br i1 %gt, label %if.then, label %if.exit
if.then:
ret void
define void @unreachable.test() #0 {
entry:
%x = alloca i32, align 4
%0 = call i32 @unreachable.foo()
store i32 %0, i32* %x, align 4
%1 = load i32, i32* %x, align 4
%gt = icmp sgt i32 %1, 0
br i1 %gt, label %if.then, label %if.exit
if.exit:
call void @llvm.trap()
unreachable
if.then: ; preds = %entry
ret void
if.exit: ; preds = %entry
call void @"std::builtin.panic"(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0), i32 11)
unreachable
after.unreachable: ; No predecessors!
%2 = load i32, i32* %x, align 4
%add = add i32 %2, 1
store i32 %add, i32* %x, align 4
ret void
}
unreachable_block:
%2 = load i32, i32* %x
%add = add i32 %2, 1
store i32 %add, i32* %x
ret void

View File

@@ -28,31 +28,30 @@ entry:
%sy = alloca i32, align 4
%1 = call double @llvm.ceil.f64(double %0)
store double %1, double* %d, align 8
%2 = call double @llvm.maxnum.f64(double 1.000000e+00, double 1.000000e+00)
store double %2, double* %e, align 8
%3 = load double, double* %d, align 8
%2 = load double, double* %d, align 8
%3 = call double @llvm.maxnum.f64(double 1.000000e+00, double %2)
store double %3, double* %e, align 8
%4 = load double, double* %d, align 8
%5 = load double, double* %d, align 8
%6 = call double @llvm.fma.f64(double %3, double %4, double %5)
store double %6, double* %f, align 8
%5 = call double @llvm.fma.f64(double %4, double 2.000000e+00, double 3.000000e+00)
store double %5, double* %f, align 8
store i32 13, i32* %xeb, align 4
%7 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 0
%6 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 0
store i32 0, i32* %6, align 4
%7 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 1
store i32 0, i32* %7, align 4
%8 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 1
%8 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2
store i32 0, i32* %8, align 4
%9 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2
store i32 0, i32* %9, align 4
%10 = load volatile i32, i32* %xeb, align 4
store i32 %10, i32* %sy, align 4
%11 = load i32, i32* %sy, align 4
%add = add i32 %11, 1
%9 = load volatile i32, i32* %xeb, align 4
store i32 %9, i32* %sy, align 4
%10 = load i32, i32* %sy, align 4
%add = add i32 %10, 1
store volatile i32 %add, i32* %xeb, align 4
%12 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2
%13 = load i32, i32* %sy, align 4
%add1 = add i32 %13, 2
store volatile i32 %add1, i32* %12, align 4
%14 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2
%15 = load volatile i32, i32* %14, align 4
store i32 %15, i32* %sy, align 4
%11 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2
%12 = load i32, i32* %sy, align 4
%add1 = add i32 %12, 2
store volatile i32 %add1, i32* %11, align 4
%13 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2
%14 = load volatile i32, i32* %13, align 4
store i32 %14, i32* %sy, align 4
ret i32 1
}
}

View File

@@ -110,8 +110,11 @@ loop.body: ; preds = %loop.cond
br label %loop.cond
loop.exit: ; preds = %loop.cond
call void @__assert_rtn(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @0, i64 0, i64 0), i8* getelementptr inbounds ([22 x i8], [22 x i8]* @1, i64 0, i64 0), i32 14, i8* getelementptr inbounds ([20 x i8], [20 x i8]* @2, i64 0, i64 0))
call void @"std::builtin.panic"(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @0, i64 0, i64 0), i8* getelementptr inbounds ([22 x i8], [22 x i8]* @1, i64 0, i64 0), i8* getelementptr inbounds ([21 x i8], [21 x i8]* @2, i64 0, i64 0), i32 14)
unreachable
unreachable_block: ; No predecessors!
ret void
}
; Function Attrs: nounwind