mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fixes to or/and with rethrow.
This commit is contained in:
@@ -447,7 +447,7 @@ BinaryOp binary_op[TOKEN_LAST + 1] = {
|
||||
[TOKEN_SHR] = BINARYOP_SHR,
|
||||
[TOKEN_AND] = BINARYOP_AND,
|
||||
[TOKEN_OR] = BINARYOP_OR,
|
||||
[TOKEN_QUESTQUEST] = BINARYOP_OR_ERR,
|
||||
[TOKEN_QUESTQUEST] = BINARYOP_ELSE,
|
||||
[TOKEN_AMP] = BINARYOP_BIT_AND,
|
||||
[TOKEN_BIT_OR] = BINARYOP_BIT_OR,
|
||||
[TOKEN_BIT_XOR] = BINARYOP_BIT_XOR,
|
||||
|
||||
@@ -19,7 +19,7 @@ typedef enum
|
||||
BINARYOP_BIT_AND,
|
||||
BINARYOP_AND,
|
||||
BINARYOP_OR,
|
||||
BINARYOP_OR_ERR,
|
||||
BINARYOP_ELSE,
|
||||
// Don't change the ordering for GT to EQ or things will break
|
||||
BINARYOP_GT,
|
||||
BINARYOP_GE,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "llvm_codegen_internal.h"
|
||||
#include <math.h>
|
||||
|
||||
void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs_loaded, BinaryOp binary_op);
|
||||
static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs_loaded, BinaryOp binary_op);
|
||||
static void llvm_emit_any_pointer(GenContext *c, BEValue *any, BEValue *pointer);
|
||||
static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr);
|
||||
static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr);
|
||||
@@ -120,32 +120,9 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline LLVMValueRef llvm_emit_extract_value(GenContext *c, LLVMValueRef agg, unsigned index)
|
||||
{
|
||||
if (LLVMGetTypeKind(LLVMTypeOf(agg)) == LLVMVectorTypeKind)
|
||||
{
|
||||
return LLVMBuildExtractElement(c->builder, agg, llvm_const_int(c, type_usize, index), "");
|
||||
}
|
||||
return LLVMBuildExtractValue(c->builder, agg, index, "");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline LLVMValueRef llvm_zext_trunc(GenContext *c, LLVMValueRef data, LLVMTypeRef type)
|
||||
{
|
||||
LLVMTypeRef current_type = LLVMTypeOf(data);
|
||||
if (current_type == type) return data;
|
||||
assert(LLVMGetTypeKind(type) == LLVMIntegerTypeKind);
|
||||
assert(LLVMGetTypeKind(current_type) == LLVMIntegerTypeKind);
|
||||
if (llvm_bitsize(c, current_type) < llvm_bitsize(c, type))
|
||||
{
|
||||
return LLVMBuildZExt(c->builder, data, type, "zext");
|
||||
}
|
||||
assert(llvm_bitsize(c, current_type) > llvm_bitsize(c, type));
|
||||
return LLVMBuildTrunc(c->builder, data, type, "ztrunc");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void llvm_convert_vector_comparison(GenContext *c, BEValue *be_value, LLVMValueRef val, Type *vector_type)
|
||||
{
|
||||
@@ -270,15 +247,6 @@ void llvm_enter_struct_for_coerce(GenContext *c, LLVMValueRef *struct_ptr, LLVMT
|
||||
}
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_int_resize(GenContext *c, LLVMValueRef value, LLVMTypeRef from, LLVMTypeRef to)
|
||||
{
|
||||
if (llvm_store_size(c, from) >= llvm_store_size(c, to))
|
||||
{
|
||||
return LLVMBuildTruncOrBitCast(c->builder, value, to, "trunc");
|
||||
}
|
||||
return LLVMBuildZExt(c->builder, value, to, "ext");
|
||||
}
|
||||
|
||||
/**
|
||||
* General functionality to convert int <-> int ptr <-> int
|
||||
*/
|
||||
@@ -352,7 +320,7 @@ LLVMValueRef llvm_emit_coerce(GenContext *c, LLVMTypeRef coerced, BEValue *value
|
||||
&& LLVMGetTypeKind(coerced) == LLVMIntegerTypeKind
|
||||
&& LLVMGetTypeKind(llvm_source_type) == LLVMIntegerTypeKind)
|
||||
{
|
||||
return llvm_int_resize(c, value->value, llvm_source_type, coerced);
|
||||
return llvm_zext_trunc(c, value->value, coerced);
|
||||
}
|
||||
|
||||
// 2. From now on we need th address.
|
||||
@@ -2539,21 +2507,29 @@ static void llvm_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
|
||||
}
|
||||
|
||||
static void gencontext_emit_logical_and_or(GenContext *c, BEValue *be_value, Expr *expr, BinaryOp op)
|
||||
static void llvm_emit_logical_and_or(GenContext *c, BEValue *be_value, Expr *expr, BinaryOp op)
|
||||
{
|
||||
// Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E)
|
||||
// For vector implementation.
|
||||
|
||||
// Set up basic blocks, following Cone
|
||||
LLVMBasicBlockRef start_block;
|
||||
LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, op == BINARYOP_AND ? "and.phi" : "or.phi");
|
||||
LLVMBasicBlockRef rhs_block = llvm_basic_block_new(c, op == BINARYOP_AND ? "and.rhs" : "or.rhs");
|
||||
LLVMBasicBlockRef lhs_end_block;
|
||||
|
||||
// Generate left-hand condition and conditional branch
|
||||
llvm_emit_expr(c, be_value, exprptr(expr->binary_expr.left));
|
||||
llvm_value_rvalue(c, be_value);
|
||||
|
||||
start_block = c->current_block;
|
||||
lhs_end_block = llvm_get_current_block_if_in_use(c);
|
||||
|
||||
LLVMValueRef result_on_skip = LLVMConstInt(c->bool_type, op == BINARYOP_AND ? 0 : 1, 0);
|
||||
|
||||
// We might end this with a jump, eg (foo()? || bar()) where foo() is a macro and guaranteed not to exit.
|
||||
if (!lhs_end_block)
|
||||
{
|
||||
// Just set any value.
|
||||
llvm_value_set_bool(be_value, result_on_skip);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up basic blocks, following Cone
|
||||
LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, op == BINARYOP_AND ? "and.phi" : "or.phi");
|
||||
LLVMBasicBlockRef rhs_block = llvm_basic_block_new(c, op == BINARYOP_AND ? "and.rhs" : "or.rhs");
|
||||
|
||||
if (op == BINARYOP_AND)
|
||||
{
|
||||
@@ -2569,24 +2545,25 @@ static void gencontext_emit_logical_and_or(GenContext *c, BEValue *be_value, Exp
|
||||
llvm_emit_expr(c, &rhs_value, exprptr(expr->binary_expr.right));
|
||||
llvm_value_rvalue(c, &rhs_value);
|
||||
|
||||
LLVMBasicBlockRef end_block = c->current_block;
|
||||
llvm_emit_br(c, phi_block);
|
||||
LLVMBasicBlockRef rhs_end_block = llvm_get_current_block_if_in_use(c);
|
||||
|
||||
if (rhs_end_block)
|
||||
{
|
||||
llvm_emit_br(c, phi_block);
|
||||
}
|
||||
|
||||
// Generate phi
|
||||
llvm_emit_block(c, phi_block);
|
||||
|
||||
// Simplify for LLVM by entering the constants we already know of.
|
||||
LLVMValueRef result_on_skip = LLVMConstInt(c->bool_type, op == BINARYOP_AND ? 0 : 1, 0);
|
||||
|
||||
// One possibility here is that a return happens inside of the expression.
|
||||
if (!end_block)
|
||||
if (!rhs_end_block)
|
||||
{
|
||||
llvm_value_set_bool(be_value, result_on_skip);
|
||||
return;
|
||||
}
|
||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, c->bool_type, "val");
|
||||
LLVMValueRef logic_values[2] = { result_on_skip, rhs_value.value };
|
||||
LLVMBasicBlockRef blocks[2] = { start_block, end_block };
|
||||
LLVMBasicBlockRef blocks[2] = { lhs_end_block, rhs_end_block };
|
||||
LLVMAddIncoming(phi, logic_values, blocks, 2);
|
||||
|
||||
llvm_value_set_bool(be_value, phi);
|
||||
@@ -3016,21 +2993,22 @@ void llvm_emit_comp(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs,
|
||||
TODO
|
||||
}
|
||||
|
||||
static void gencontext_emit_or_error(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
static void llvm_emit_else(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
{
|
||||
LLVMBasicBlockRef else_block = llvm_basic_block_new(c, "else_block");
|
||||
LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "phi_block");
|
||||
|
||||
// Store catch/error var
|
||||
// Store catch/opt var
|
||||
PUSH_OPT();
|
||||
|
||||
// Set the catch/error var
|
||||
// Set the catch/opt var
|
||||
c->opt_var = NULL;
|
||||
c->catch_block = else_block;
|
||||
|
||||
BEValue normal_value;
|
||||
llvm_emit_exprid(c, &normal_value, expr->binary_expr.left);
|
||||
llvm_value_rvalue(c, &normal_value);
|
||||
// Emit the real value, this will cause an implicit jump to the else block on failure.
|
||||
BEValue real_value;
|
||||
llvm_emit_exprid(c, &real_value, expr->binary_expr.left);
|
||||
llvm_value_rvalue(c, &real_value);
|
||||
|
||||
// Restore.
|
||||
POP_OPT();
|
||||
@@ -3038,66 +3016,65 @@ static void gencontext_emit_or_error(GenContext *c, BEValue *be_value, Expr *exp
|
||||
// Emit success and jump to phi.
|
||||
LLVMBasicBlockRef success_end_block = llvm_get_current_block_if_in_use(c);
|
||||
|
||||
// Only jump to phi if we didn't have an immediate jump. That would
|
||||
// for example happen on "{| defer foo(); return Foo.ERR! |} ?? 123"
|
||||
if (success_end_block) llvm_emit_br(c, phi_block);
|
||||
|
||||
// Emit else
|
||||
llvm_emit_block(c, else_block);
|
||||
|
||||
// Emit the value here
|
||||
BEValue else_value;
|
||||
llvm_emit_exprid(c, &else_value, expr->binary_expr.right);
|
||||
llvm_value_rvalue(c, &else_value);
|
||||
|
||||
LLVMBasicBlockRef else_block_exit = llvm_get_current_block_if_in_use(c);
|
||||
|
||||
// While the value may not be an optional, we may get a jump
|
||||
// from this construction: foo() ?? (bar()?)
|
||||
// In this case the else block is empty.
|
||||
if (else_block_exit) llvm_emit_br(c, phi_block);
|
||||
|
||||
llvm_emit_block(c, phi_block);
|
||||
|
||||
if (!else_block_exit)
|
||||
{
|
||||
*be_value = normal_value;
|
||||
*be_value = real_value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!success_end_block)
|
||||
{
|
||||
*be_value = else_value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (expr->type->type_kind == TYPE_BOOL)
|
||||
{
|
||||
|
||||
}
|
||||
LLVMValueRef logic_values[2] = { normal_value.value, else_value.value };
|
||||
LLVMValueRef logic_values[2] = { real_value.value, else_value.value };
|
||||
LLVMBasicBlockRef blocks[2] = { success_end_block, else_block_exit };
|
||||
|
||||
|
||||
if (expr->type->type_kind == TYPE_BOOL)
|
||||
// Special handling of bool, since we need the "set_bool" function.
|
||||
if (real_value.type == type_bool)
|
||||
{
|
||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, c->bool_type, "val");
|
||||
LLVMAddIncoming(phi, logic_values, blocks, 2);
|
||||
llvm_value_set_bool(be_value, phi);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val");
|
||||
LLVMAddIncoming(phi, logic_values, blocks, 2);
|
||||
llvm_value_set(be_value, phi, expr->type);
|
||||
}
|
||||
|
||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val");
|
||||
LLVMAddIncoming(phi, logic_values, blocks, 2);
|
||||
llvm_value_set(be_value, phi, expr->type);
|
||||
}
|
||||
|
||||
void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs_loaded, BinaryOp binary_op)
|
||||
{
|
||||
if (binary_op == BINARYOP_OR_ERR)
|
||||
if (binary_op == BINARYOP_ELSE)
|
||||
{
|
||||
gencontext_emit_or_error(c, be_value, expr);
|
||||
llvm_emit_else(c, be_value, expr);
|
||||
return;
|
||||
}
|
||||
if (binary_op == BINARYOP_AND || binary_op == BINARYOP_OR)
|
||||
{
|
||||
gencontext_emit_logical_and_or(c, be_value, expr, binary_op);
|
||||
llvm_emit_logical_and_or(c, be_value, expr, binary_op);
|
||||
return;
|
||||
}
|
||||
BEValue lhs;
|
||||
@@ -3132,7 +3109,7 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu
|
||||
switch (binary_op)
|
||||
{
|
||||
case BINARYOP_ERROR:
|
||||
case BINARYOP_OR_ERR:
|
||||
case BINARYOP_ELSE:
|
||||
UNREACHABLE
|
||||
case BINARYOP_MULT:
|
||||
if (is_float)
|
||||
@@ -4999,23 +4976,24 @@ static inline void gencontext_emit_expression_list_expr(GenContext *context, BEV
|
||||
}
|
||||
}
|
||||
|
||||
static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value, Type *type, AstId current, BlockExit **block_exit)
|
||||
static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type *type, AstId current, BlockExit **block_exit)
|
||||
{
|
||||
Type *type_lowered = type_lowering(type);
|
||||
|
||||
// First case - an empty block
|
||||
if (!current)
|
||||
{
|
||||
llvm_value_set(be_value, NULL, type_void);
|
||||
llvm_value_set(be_value, llvm_get_undef(c, type_lowered), type_lowered);
|
||||
return;
|
||||
}
|
||||
|
||||
Type *type_lowered = type_lowering(type);
|
||||
LLVMValueRef old_ret_out = context->return_out;
|
||||
context->in_block++;
|
||||
LLVMValueRef old_ret_out = c->return_out;
|
||||
c->in_block++;
|
||||
|
||||
LLVMValueRef error_out = context->opt_var;
|
||||
LLVMBasicBlockRef error_block = context->catch_block;
|
||||
LLVMValueRef error_out = c->opt_var;
|
||||
LLVMBasicBlockRef error_block = c->catch_block;
|
||||
LLVMValueRef return_out = NULL;
|
||||
LLVMBasicBlockRef expr_block = llvm_basic_block_new(context, "expr_block.exit");
|
||||
LLVMBasicBlockRef expr_block = llvm_basic_block_new(c, "expr_block.exit");
|
||||
|
||||
BlockExit exit = {
|
||||
.block_return_exit = expr_block,
|
||||
@@ -5028,16 +5006,16 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
|
||||
|
||||
if (type_no_optional(type_lowered) != type_void)
|
||||
{
|
||||
exit.block_return_out = llvm_emit_alloca_aligned(context, type_lowered, "blockret");
|
||||
exit.block_return_out = llvm_emit_alloca_aligned(c, type_lowered, "blockret");
|
||||
}
|
||||
context->opt_var = NULL;
|
||||
context->catch_block = NULL;
|
||||
c->opt_var = NULL;
|
||||
c->catch_block = NULL;
|
||||
|
||||
// Process all but the last statement.
|
||||
Ast *value = ast_next(¤t);
|
||||
while (value->next)
|
||||
{
|
||||
llvm_emit_stmt(context, value);
|
||||
llvm_emit_stmt(c, value);
|
||||
value = ast_next(¤t);
|
||||
}
|
||||
|
||||
@@ -5068,7 +5046,7 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
|
||||
if (IS_OPTIONAL(ret_expr)) break;
|
||||
|
||||
// Optimization, emit directly to value
|
||||
llvm_emit_expr(context, be_value, ret_expr);
|
||||
llvm_emit_expr(c, be_value, ret_expr);
|
||||
// And remove the alloca
|
||||
LLVMInstructionEraseFromParent(exit.block_return_out);
|
||||
goto DONE;
|
||||
@@ -5076,20 +5054,20 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
|
||||
} while (0);
|
||||
|
||||
// Emit the last statement
|
||||
llvm_emit_stmt(context, value);
|
||||
llvm_emit_stmt(c, value);
|
||||
|
||||
// In the case of a void with no return, then this may be true.
|
||||
if (llvm_basic_block_is_unused(expr_block))
|
||||
{
|
||||
// Skip the expr block.
|
||||
llvm_value_set(be_value, NULL, type_void);
|
||||
llvm_value_set(be_value, llvm_get_undef(c, type_lowered), type_lowered);
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
llvm_emit_br(context, expr_block);
|
||||
llvm_emit_br(c, expr_block);
|
||||
|
||||
// Emit the exit block.
|
||||
llvm_emit_block(context, expr_block);
|
||||
llvm_emit_block(c, expr_block);
|
||||
|
||||
if (exit.block_return_out)
|
||||
{
|
||||
@@ -5101,10 +5079,10 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
|
||||
}
|
||||
|
||||
DONE:
|
||||
context->return_out = old_ret_out;
|
||||
context->catch_block = error_block;
|
||||
context->opt_var = error_out;
|
||||
context->in_block--;
|
||||
c->return_out = old_ret_out;
|
||||
c->catch_block = error_block;
|
||||
c->opt_var = error_out;
|
||||
c->in_block--;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -300,6 +300,7 @@ INLINE AlignSize llvm_type_or_alloca_align(GenContext *c, LLVMValueRef dest, Typ
|
||||
// -- Bitcast --
|
||||
static inline LLVMValueRef llvm_emit_bitcast(GenContext *c, LLVMValueRef value, Type *type);
|
||||
INLINE LLVMValueRef llvm_emit_bitcast_ptr(GenContext *c, LLVMValueRef value, Type *type);
|
||||
INLINE LLVMValueRef llvm_zext_trunc(GenContext *c, LLVMValueRef data, LLVMTypeRef type);
|
||||
|
||||
// -- Constants --
|
||||
void llvm_emit_typeid(GenContext *c, BEValue *be_value, Type *type);
|
||||
@@ -365,7 +366,7 @@ void llvm_store_to_ptr_zero(GenContext *context, LLVMValueRef pointer, Type *typ
|
||||
TypeSize llvm_store_size(GenContext *c, LLVMTypeRef type);
|
||||
|
||||
/// -- Aggregates --
|
||||
static inline LLVMValueRef llvm_emit_insert_value(GenContext *c, LLVMValueRef agg, LLVMValueRef new_value, ArraySize index);
|
||||
INLINE LLVMValueRef llvm_emit_insert_value(GenContext *c, LLVMValueRef agg, LLVMValueRef new_value, ArraySize index);
|
||||
LLVMValueRef llvm_emit_aggregate_two(GenContext *c, Type *type, LLVMValueRef value1, LLVMValueRef value2);
|
||||
LLVMValueRef llvm_emit_struct_gep_raw(GenContext *context, LLVMValueRef ptr, LLVMTypeRef struct_type, unsigned index,
|
||||
unsigned struct_alignment, AlignSize *alignment);
|
||||
@@ -375,6 +376,8 @@ LLVMValueRef llvm_emit_pointer_gep_raw(GenContext *c, LLVMTypeRef pointee_type,
|
||||
LLVMValueRef llvm_emit_pointer_inbounds_gep_raw(GenContext *c, LLVMTypeRef pointee_type, LLVMValueRef ptr, LLVMValueRef offset);
|
||||
void llvm_emit_ptr_from_array(GenContext *c, BEValue *value);
|
||||
void llvm_emit_struct_member_ref(GenContext *c, BEValue *struct_ref, BEValue *member_ref, unsigned member_id);
|
||||
INLINE LLVMValueRef llvm_emit_extract_value(GenContext *c, LLVMValueRef agg, unsigned index);
|
||||
|
||||
|
||||
// -- Int operations ---
|
||||
LLVMValueRef llvm_emit_shl_fixed(GenContext *c, LLVMValueRef data, int shift);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
static inline LLVMValueRef llvm_emit_insert_value(GenContext *c, LLVMValueRef agg, LLVMValueRef new_value, ArraySize index)
|
||||
INLINE LLVMValueRef llvm_emit_insert_value(GenContext *c, LLVMValueRef agg, LLVMValueRef new_value, ArraySize index)
|
||||
{
|
||||
if (LLVMGetTypeKind(LLVMTypeOf(agg)) == LLVMVectorTypeKind)
|
||||
{
|
||||
@@ -8,6 +8,22 @@ static inline LLVMValueRef llvm_emit_insert_value(GenContext *c, LLVMValueRef ag
|
||||
return LLVMBuildInsertValue(c->builder, agg, new_value, index, "");
|
||||
}
|
||||
|
||||
|
||||
INLINE LLVMValueRef llvm_zext_trunc(GenContext *c, LLVMValueRef data, LLVMTypeRef type)
|
||||
{
|
||||
LLVMTypeRef current_type = LLVMTypeOf(data);
|
||||
if (current_type == type) return data;
|
||||
assert(LLVMGetTypeKind(type) == LLVMIntegerTypeKind);
|
||||
assert(LLVMGetTypeKind(current_type) == LLVMIntegerTypeKind);
|
||||
if (llvm_bitsize(c, current_type) < llvm_bitsize(c, type))
|
||||
{
|
||||
return LLVMBuildZExt(c->builder, data, type, "zext");
|
||||
}
|
||||
assert(llvm_bitsize(c, current_type) > llvm_bitsize(c, type));
|
||||
return LLVMBuildTrunc(c->builder, data, type, "ztrunc");
|
||||
}
|
||||
|
||||
|
||||
INLINE LLVMValueRef llvm_store_decl(GenContext *c, Decl *decl, BEValue *value)
|
||||
{
|
||||
BEValue ref;
|
||||
@@ -94,6 +110,15 @@ INLINE LLVMValueRef llvm_emit_trunc(GenContext *c, LLVMValueRef value, Type *typ
|
||||
return LLVMBuildTrunc(c->builder, value, llvm_get_type(c, type), "");
|
||||
}
|
||||
|
||||
INLINE LLVMValueRef llvm_emit_extract_value(GenContext *c, LLVMValueRef agg, unsigned index)
|
||||
{
|
||||
if (LLVMGetTypeKind(LLVMTypeOf(agg)) == LLVMVectorTypeKind)
|
||||
{
|
||||
return LLVMBuildExtractElement(c->builder, agg, llvm_const_int(c, type_usize, index), "");
|
||||
}
|
||||
return LLVMBuildExtractValue(c->builder, agg, index, "");
|
||||
}
|
||||
|
||||
INLINE bool llvm_use_debug(GenContext *context) { return context->debug.builder != NULL; }
|
||||
|
||||
INLINE bool llvm_basic_block_is_unused(LLVMBasicBlockRef block)
|
||||
|
||||
@@ -739,7 +739,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
|
||||
case BINARYOP_ADD:
|
||||
case BINARYOP_DIV:
|
||||
case BINARYOP_MOD:
|
||||
case BINARYOP_OR_ERR:
|
||||
case BINARYOP_ELSE:
|
||||
{
|
||||
Expr *res = recursive_may_narrow_float(exprptr(expr->binary_expr.left), type);
|
||||
if (res) return res;
|
||||
@@ -898,7 +898,7 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
|
||||
case BINARYOP_BIT_OR:
|
||||
case BINARYOP_BIT_XOR:
|
||||
case BINARYOP_BIT_AND:
|
||||
case BINARYOP_OR_ERR:
|
||||
case BINARYOP_ELSE:
|
||||
{
|
||||
Expr *res = recursive_may_narrow_int(exprptr(expr->binary_expr.left), type);
|
||||
if (res) return res;
|
||||
|
||||
@@ -6657,11 +6657,16 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr)
|
||||
|
||||
type = type_is_optional_any(type) ? else_type : type->failable;
|
||||
|
||||
if (else_type->type_kind == TYPE_FAILABLE)
|
||||
if (type_is_optional(else_type))
|
||||
{
|
||||
SEMA_ERROR(rhs, "The default value may not be a failable.");
|
||||
SEMA_ERROR(rhs, "The default value may not be an optional.");
|
||||
return false;
|
||||
}
|
||||
if (lhs->expr_kind == EXPR_FAILABLE)
|
||||
{
|
||||
expr_replace(expr, rhs);
|
||||
return true;
|
||||
}
|
||||
Type *common = type_find_max_type(type, else_type);
|
||||
if (!common)
|
||||
{
|
||||
@@ -6671,18 +6676,13 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr)
|
||||
}
|
||||
if (!cast_implicit(lhs, common)) return false;
|
||||
if (!cast_implicit(rhs, common)) return false;
|
||||
if (IS_OPTIONAL(rhs))
|
||||
{
|
||||
SEMA_ERROR(rhs, "The expression must be a non-failable.");
|
||||
return false;
|
||||
}
|
||||
expr->type = common;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr)
|
||||
{
|
||||
if (expr->binary_expr.operator == BINARYOP_OR_ERR) return sema_expr_analyse_or_error(context, expr);
|
||||
if (expr->binary_expr.operator == BINARYOP_ELSE) return sema_expr_analyse_or_error(context, expr);
|
||||
assert(expr->resolve_status == RESOLVE_RUNNING);
|
||||
Expr *left = exprptr(expr->binary_expr.left);
|
||||
Expr *right = exprptr(expr->binary_expr.right);
|
||||
@@ -6694,7 +6694,7 @@ static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr)
|
||||
}
|
||||
switch (expr->binary_expr.operator)
|
||||
{
|
||||
case BINARYOP_OR_ERR:
|
||||
case BINARYOP_ELSE:
|
||||
UNREACHABLE // Handled previously
|
||||
case BINARYOP_ASSIGN:
|
||||
return sema_expr_analyse_assign(context, expr, left, right);
|
||||
@@ -8069,7 +8069,7 @@ void insert_widening_type(Expr *expr, Type *infer_type)
|
||||
case BINARYOP_BIT_OR:
|
||||
case BINARYOP_BIT_XOR:
|
||||
case BINARYOP_BIT_AND:
|
||||
case BINARYOP_OR_ERR:
|
||||
case BINARYOP_ELSE:
|
||||
if (!expr_is_simple(exprptr(expr->binary_expr.left)) || !expr_is_simple(exprptr(expr->binary_expr.right))) return;
|
||||
expr->type = infer_type;
|
||||
expr->binary_expr.widen = true;
|
||||
|
||||
13
test/test_suite/errors/more_optional_tests.c3
Normal file
13
test/test_suite/errors/more_optional_tests.c3
Normal file
@@ -0,0 +1,13 @@
|
||||
module foo;
|
||||
|
||||
fault Foo { ABC }
|
||||
|
||||
fn void test()
|
||||
{
|
||||
int x = Foo.ABC! ?? 123;
|
||||
}
|
||||
|
||||
fn void test2()
|
||||
{
|
||||
int! y = Foo.ABC! ?? Foo.ABC!; // #error: The default value may not be an optional
|
||||
}
|
||||
200
test/test_suite/errors/or_and_rethrow.c3t
Normal file
200
test/test_suite/errors/or_and_rethrow.c3t
Normal file
@@ -0,0 +1,200 @@
|
||||
// #target: macos-x64
|
||||
module foo;
|
||||
import std::io;
|
||||
|
||||
fault Foo { ABC }
|
||||
|
||||
fn void blurb() { io::println("Blurb");}
|
||||
|
||||
macro int! tester()
|
||||
{
|
||||
defer blurb();
|
||||
return Foo.ABC!;
|
||||
}
|
||||
fn void! test(int x)
|
||||
{
|
||||
io::printfln("test(%d)", x);
|
||||
if (x || (tester()?)) io::println("Ok1");
|
||||
io::println("Test next");
|
||||
if (tester()? || x) io::println("Ok?");
|
||||
io::println("Test ok");
|
||||
}
|
||||
|
||||
fn void! test2(int x)
|
||||
{
|
||||
io::printfln("test2(%d)", x);
|
||||
if (x && (tester()?)) io::println("Ok1");
|
||||
io::println("Test next");
|
||||
if ((tester()?) && x) io::println("Ok?");
|
||||
io::println("Test ok");
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
anyerr a = test(0);
|
||||
anyerr b = test(1);
|
||||
anyerr c = test2(0);
|
||||
anyerr d = test2(1);
|
||||
}
|
||||
|
||||
/* #expect: foo.ll
|
||||
|
||||
define i64 @foo_test(i32 %0) #0 {
|
||||
entry:
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%taddr1 = alloca i32, align 4
|
||||
%error_var = alloca i64, align 8
|
||||
%blockret = alloca i32, align 4
|
||||
%error_var4 = alloca i64, align 8
|
||||
%blockret5 = alloca i32, align 4
|
||||
%reterr = alloca i64, align 8
|
||||
store %"char[]" { i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.1, i32 0, i32 0), i64 8 }, %"char[]"* %taddr, align 8
|
||||
%1 = bitcast %"char[]"* %taddr to { i8*, i64 }*
|
||||
%2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %1, i32 0, i32 0
|
||||
%lo = load i8*, i8** %2, align 8
|
||||
%3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %1, i32 0, i32 1
|
||||
%hi = load i64, i64* %3, align 8
|
||||
store i32 %0, i32* %taddr1, align 4
|
||||
%4 = bitcast i32* %taddr1 to i8*
|
||||
%5 = insertvalue %variant undef, i8* %4, 0
|
||||
%6 = insertvalue %variant %5, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%7 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots, i64 0, i64 0
|
||||
store %variant %6, %variant* %7, align 16
|
||||
%8 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1
|
||||
store i64 1, i64* %8, align 8
|
||||
%9 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 0
|
||||
%10 = bitcast [1 x %variant]* %varargslots to %variant*
|
||||
store %variant* %10, %variant** %9, align 8
|
||||
%11 = bitcast %"variant[]"* %vararg to { i8*, i64 }*
|
||||
%12 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %11, i32 0, i32 0
|
||||
%lo2 = load i8*, i8** %12, align 8
|
||||
%13 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %11, i32 0, i32 1
|
||||
%hi3 = load i64, i64* %13, align 8
|
||||
%14 = call i64 @std_io_printfln(i64* %retparam, i8* %lo, i64 %hi, i8* %lo2, i64 %hi3)
|
||||
%not_err = icmp eq i64 %14, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %entry
|
||||
%intbool = icmp ne i32 %0, 0
|
||||
br i1 %intbool, label %or.phi, label %or.rhs
|
||||
|
||||
or.rhs: ; preds = %voiderr
|
||||
store i64 ptrtoint (%.fault* @"foo_Foo$ABC" to i64), i64* %error_var, align 8
|
||||
br label %opt_block_cleanup
|
||||
|
||||
opt_block_cleanup: ; preds = %or.rhs
|
||||
call void @foo_blurb()
|
||||
br label %guard_block
|
||||
|
||||
guard_block: ; preds = %opt_block_cleanup
|
||||
%15 = load i64, i64* %error_var, align 8
|
||||
ret i64 %15
|
||||
|
||||
or.phi: ; preds = %voiderr
|
||||
br label %if.then
|
||||
|
||||
if.then: ; preds = %or.phi
|
||||
%16 = call i32 @std_io_println(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i32 0, i32 0)) #1
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %if.then
|
||||
%17 = call i32 @std_io_println(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.3, i32 0, i32 0)) #1
|
||||
store i64 ptrtoint (%.fault* @"foo_Foo$ABC" to i64), i64* %error_var4, align 8
|
||||
br label %opt_block_cleanup6
|
||||
|
||||
opt_block_cleanup6: ; preds = %if.exit
|
||||
call void @foo_blurb()
|
||||
br label %guard_block7
|
||||
|
||||
guard_block7: ; preds = %opt_block_cleanup6
|
||||
%18 = load i64, i64* %error_var4, align 8
|
||||
ret i64 %18
|
||||
|
||||
if.exit9: ; No predecessors!
|
||||
%19 = call i32 @std_io_println(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.5, i32 0, i32 0)) #1
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
define i64 @foo_test2(i32 %0) #0 {
|
||||
entry:
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%taddr1 = alloca i32, align 4
|
||||
%error_var = alloca i64, align 8
|
||||
%blockret = alloca i32, align 4
|
||||
%error_var4 = alloca i64, align 8
|
||||
%blockret5 = alloca i32, align 4
|
||||
%reterr = alloca i64, align 8
|
||||
store %"char[]" { i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.6, i32 0, i32 0), i64 9 }, %"char[]"* %taddr, align 8
|
||||
%1 = bitcast %"char[]"* %taddr to { i8*, i64 }*
|
||||
%2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %1, i32 0, i32 0
|
||||
%lo = load i8*, i8** %2, align 8
|
||||
%3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %1, i32 0, i32 1
|
||||
%hi = load i64, i64* %3, align 8
|
||||
store i32 %0, i32* %taddr1, align 4
|
||||
%4 = bitcast i32* %taddr1 to i8*
|
||||
%5 = insertvalue %variant undef, i8* %4, 0
|
||||
%6 = insertvalue %variant %5, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%7 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots, i64 0, i64 0
|
||||
store %variant %6, %variant* %7, align 16
|
||||
%8 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1
|
||||
store i64 1, i64* %8, align 8
|
||||
%9 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 0
|
||||
%10 = bitcast [1 x %variant]* %varargslots to %variant*
|
||||
store %variant* %10, %variant** %9, align 8
|
||||
%11 = bitcast %"variant[]"* %vararg to { i8*, i64 }*
|
||||
%12 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %11, i32 0, i32 0
|
||||
%lo2 = load i8*, i8** %12, align 8
|
||||
%13 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %11, i32 0, i32 1
|
||||
%hi3 = load i64, i64* %13, align 8
|
||||
%14 = call i64 @std_io_printfln(i64* %retparam, i8* %lo, i64 %hi, i8* %lo2, i64 %hi3)
|
||||
%not_err = icmp eq i64 %14, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %entry
|
||||
%intbool = icmp ne i32 %0, 0
|
||||
br i1 %intbool, label %and.rhs, label %and.phi
|
||||
|
||||
and.rhs: ; preds = %voiderr
|
||||
store i64 ptrtoint (%.fault* @"foo_Foo$ABC" to i64), i64* %error_var, align 8
|
||||
br label %opt_block_cleanup
|
||||
|
||||
opt_block_cleanup: ; preds = %and.rhs
|
||||
call void @foo_blurb()
|
||||
br label %guard_block
|
||||
|
||||
guard_block: ; preds = %opt_block_cleanup
|
||||
%15 = load i64, i64* %error_var, align 8
|
||||
ret i64 %15
|
||||
|
||||
and.phi: ; preds = %voiderr
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %and.phi
|
||||
%16 = call i32 @std_io_println(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.7, i32 0, i32 0)) #1
|
||||
store i64 ptrtoint (%.fault* @"foo_Foo$ABC" to i64), i64* %error_var4, align 8
|
||||
br label %opt_block_cleanup6
|
||||
|
||||
opt_block_cleanup6: ; preds = %if.exit
|
||||
call void @foo_blurb()
|
||||
br label %guard_block7
|
||||
|
||||
guard_block7: ; preds = %opt_block_cleanup6
|
||||
%17 = load i64, i64* %error_var4, align 8
|
||||
ret i64 %17
|
||||
|
||||
if.exit8: ; No predecessors!
|
||||
%18 = call i32 @std_io_println(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.8, i32 0, i32 0)) #1
|
||||
ret i64 0
|
||||
}
|
||||
13
test/test_suite2/errors/more_optional_tests.c3
Normal file
13
test/test_suite2/errors/more_optional_tests.c3
Normal file
@@ -0,0 +1,13 @@
|
||||
module foo;
|
||||
|
||||
fault Foo { ABC }
|
||||
|
||||
fn void test()
|
||||
{
|
||||
int x = Foo.ABC! ?? 123;
|
||||
}
|
||||
|
||||
fn void test2()
|
||||
{
|
||||
int! y = Foo.ABC! ?? Foo.ABC!; // #error: The default value may not be an optional
|
||||
}
|
||||
192
test/test_suite2/errors/or_and_rethrow.c3t
Normal file
192
test/test_suite2/errors/or_and_rethrow.c3t
Normal file
@@ -0,0 +1,192 @@
|
||||
// #target: macos-x64
|
||||
module foo;
|
||||
import std::io;
|
||||
|
||||
fault Foo { ABC }
|
||||
|
||||
fn void blurb() { io::println("Blurb");}
|
||||
|
||||
macro int! tester()
|
||||
{
|
||||
defer blurb();
|
||||
return Foo.ABC!;
|
||||
}
|
||||
fn void! test(int x)
|
||||
{
|
||||
io::printfln("test(%d)", x);
|
||||
if (x || (tester()?)) io::println("Ok1");
|
||||
io::println("Test next");
|
||||
if (tester()? || x) io::println("Ok?");
|
||||
io::println("Test ok");
|
||||
}
|
||||
|
||||
fn void! test2(int x)
|
||||
{
|
||||
io::printfln("test2(%d)", x);
|
||||
if (x && (tester()?)) io::println("Ok1");
|
||||
io::println("Test next");
|
||||
if ((tester()?) && x) io::println("Ok?");
|
||||
io::println("Test ok");
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
anyerr a = test(0);
|
||||
anyerr b = test(1);
|
||||
anyerr c = test2(0);
|
||||
anyerr d = test2(1);
|
||||
}
|
||||
|
||||
/* #expect: foo.ll
|
||||
|
||||
define i64 @foo_test(i32 %0) #0 {
|
||||
entry:
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%taddr1 = alloca i32, align 4
|
||||
%error_var = alloca i64, align 8
|
||||
%blockret = alloca i32, align 4
|
||||
%error_var4 = alloca i64, align 8
|
||||
%blockret5 = alloca i32, align 4
|
||||
%reterr = alloca i64, align 8
|
||||
store %"char[]" { ptr @.str.1, i64 8 }, ptr %taddr, align 8
|
||||
%1 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0
|
||||
%lo = load ptr, ptr %1, align 8
|
||||
%2 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1
|
||||
%hi = load i64, ptr %2, align 8
|
||||
store i32 %0, ptr %taddr1, align 4
|
||||
%3 = insertvalue %variant undef, ptr %taddr1, 0
|
||||
%4 = insertvalue %variant %3, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%5 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0
|
||||
store %variant %4, ptr %5, align 16
|
||||
%6 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 1
|
||||
store i64 1, ptr %6, align 8
|
||||
%7 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 0
|
||||
store ptr %varargslots, ptr %7, align 8
|
||||
%8 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 0
|
||||
%lo2 = load ptr, ptr %8, align 8
|
||||
%9 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 1
|
||||
%hi3 = load i64, ptr %9, align 8
|
||||
%10 = call i64 @std_io_printfln(ptr %retparam, ptr %lo, i64 %hi, ptr %lo2, i64 %hi3)
|
||||
%not_err = icmp eq i64 %10, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %entry
|
||||
%intbool = icmp ne i32 %0, 0
|
||||
br i1 %intbool, label %or.phi, label %or.rhs
|
||||
|
||||
or.rhs: ; preds = %voiderr
|
||||
store i64 ptrtoint (ptr @"foo_Foo$ABC" to i64), ptr %error_var, align 8
|
||||
br label %opt_block_cleanup
|
||||
|
||||
opt_block_cleanup: ; preds = %or.rhs
|
||||
call void @foo_blurb()
|
||||
br label %guard_block
|
||||
|
||||
guard_block: ; preds = %opt_block_cleanup
|
||||
%11 = load i64, ptr %error_var, align 8
|
||||
ret i64 %11
|
||||
|
||||
or.phi: ; preds = %voiderr
|
||||
br label %if.then
|
||||
|
||||
if.then: ; preds = %or.phi
|
||||
%12 = call i32 @std_io_println(ptr @.str.2) #1
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %if.then
|
||||
%13 = call i32 @std_io_println(ptr @.str.3) #1
|
||||
store i64 ptrtoint (ptr @"foo_Foo$ABC" to i64), ptr %error_var4, align 8
|
||||
br label %opt_block_cleanup6
|
||||
|
||||
opt_block_cleanup6: ; preds = %if.exit
|
||||
call void @foo_blurb()
|
||||
br label %guard_block7
|
||||
|
||||
guard_block7: ; preds = %opt_block_cleanup6
|
||||
%14 = load i64, ptr %error_var4, align 8
|
||||
ret i64 %14
|
||||
|
||||
if.exit9: ; No predecessors!
|
||||
%15 = call i32 @std_io_println(ptr @.str.5) #1
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
define i64 @foo_test2(i32 %0) #0 {
|
||||
entry:
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%taddr1 = alloca i32, align 4
|
||||
%error_var = alloca i64, align 8
|
||||
%blockret = alloca i32, align 4
|
||||
%error_var4 = alloca i64, align 8
|
||||
%blockret5 = alloca i32, align 4
|
||||
%reterr = alloca i64, align 8
|
||||
store %"char[]" { ptr @.str.6, i64 9 }, ptr %taddr, align 8
|
||||
%1 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0
|
||||
%lo = load ptr, ptr %1, align 8
|
||||
%2 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1
|
||||
%hi = load i64, ptr %2, align 8
|
||||
store i32 %0, ptr %taddr1, align 4
|
||||
%3 = insertvalue %variant undef, ptr %taddr1, 0
|
||||
%4 = insertvalue %variant %3, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%5 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0
|
||||
store %variant %4, ptr %5, align 16
|
||||
%6 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 1
|
||||
store i64 1, ptr %6, align 8
|
||||
%7 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 0
|
||||
store ptr %varargslots, ptr %7, align 8
|
||||
%8 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 0
|
||||
%lo2 = load ptr, ptr %8, align 8
|
||||
%9 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 1
|
||||
%hi3 = load i64, ptr %9, align 8
|
||||
%10 = call i64 @std_io_printfln(ptr %retparam, ptr %lo, i64 %hi, ptr %lo2, i64 %hi3)
|
||||
%not_err = icmp eq i64 %10, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %entry
|
||||
%intbool = icmp ne i32 %0, 0
|
||||
br i1 %intbool, label %and.rhs, label %and.phi
|
||||
|
||||
and.rhs: ; preds = %voiderr
|
||||
store i64 ptrtoint (ptr @"foo_Foo$ABC" to i64), ptr %error_var, align 8
|
||||
br label %opt_block_cleanup
|
||||
|
||||
opt_block_cleanup: ; preds = %and.rhs
|
||||
call void @foo_blurb()
|
||||
br label %guard_block
|
||||
|
||||
guard_block: ; preds = %opt_block_cleanup
|
||||
%11 = load i64, ptr %error_var, align 8
|
||||
ret i64 %11
|
||||
|
||||
and.phi: ; preds = %voiderr
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %and.phi
|
||||
%12 = call i32 @std_io_println(ptr @.str.7) #1
|
||||
store i64 ptrtoint (ptr @"foo_Foo$ABC" to i64), ptr %error_var4, align 8
|
||||
br label %opt_block_cleanup6
|
||||
|
||||
opt_block_cleanup6: ; preds = %if.exit
|
||||
call void @foo_blurb()
|
||||
br label %guard_block7
|
||||
|
||||
guard_block7: ; preds = %opt_block_cleanup6
|
||||
%13 = load i64, ptr %error_var4, align 8
|
||||
ret i64 %13
|
||||
|
||||
if.exit8: ; No predecessors!
|
||||
%14 = call i32 @std_io_println(ptr @.str.8) #1
|
||||
ret i64 0
|
||||
}
|
||||
Reference in New Issue
Block a user